(account, modelKey)
| 543 | * at selector time even though `account.capabilities` already says yes. |
| 544 | */ |
| 545 | export function isModelAllowedForAccount(account, modelKey) { |
| 546 | const blocked = account.blockedModels || []; |
| 547 | if (blocked.includes(modelKey)) return false; |
| 548 | // tierManual is the operator escape hatch: when set, trust the manual |
| 549 | // tier table over GetUserStatus's per-account allowlist. Useful when |
| 550 | // probe-based detection misclassified a Pro/Trial account as free |
| 551 | // (issue #8) and the operator manually flips it back to Pro. |
| 552 | if (!account.tierManual) { |
| 553 | // GetUserStatus writes both arms — `user_status` for allowed and |
| 554 | // `not_entitled` for denied — into capabilities, keyed by enum. |
| 555 | // Either reason means the upstream allowlist has already spoken. |
| 556 | const cap = account.capabilities?.[modelKey]; |
| 557 | if (cap?.reason === 'user_status' || cap?.reason === 'not_entitled') { |
| 558 | return cap.ok === true; |
| 559 | } |
| 560 | } |
| 561 | const tierModels = getTierModels(account.tier || 'unknown'); |
| 562 | return tierModels.includes(modelKey); |
| 563 | } |
| 564 | |
| 565 | /** List of model keys this account is currently allowed to call. */ |
| 566 | export function getAvailableModelsForAccount(account) { |
no test coverage detected