import type { Auth } from "@opencode-ai/sdk"; import { type AccountStorageV3, type CooldownReason, type RateLimitStateV3 } from "./storage.js"; import type { AccountIdSource, OAuthAuthDetails } from "./types.js"; import { type ModelFamily } from "./prompts/codex.js"; import { type HybridSelectionOptions } from "./rotation.js"; export { extractAccountId, extractAccountEmail, getAccountIdCandidates, selectBestAccountCandidate, shouldUpdateAccountIdFromToken, resolveRequestAccountId, sanitizeEmail, type AccountIdCandidate, } from "./auth/token-utils.js"; export { parseRateLimitReason, getQuotaKey, clampNonNegativeInt, clearExpiredRateLimits, isRateLimitedForQuotaKey, isRateLimitedForFamily, formatWaitTime, type QuotaKey, type BaseQuotaKey, type RateLimitReason, type RateLimitState, type RateLimitedEntity, } from "./accounts/rate-limits.js"; import { type RateLimitReason } from "./accounts/rate-limits.js"; export type CodexCliTokenCacheEntry = { accessToken: string; expiresAt?: number; refreshToken?: string; accountId?: string; }; export declare function lookupCodexCliTokensByEmail(email: string | undefined): Promise; export interface ManagedAccount { index: number; accountId?: string; organizationId?: string; accountIdSource?: AccountIdSource; accountLabel?: string; accountTags?: string[]; accountNote?: string; email?: string; refreshToken: string; enabled?: boolean; access?: string; expires?: number; addedAt: number; lastUsed: number; lastSwitchReason?: "rate-limit" | "initial" | "rotation"; lastRateLimitReason?: RateLimitReason; rateLimitResetTimes: RateLimitStateV3; coolingDownUntil?: number; cooldownReason?: CooldownReason; } export interface AccountSelectionExplainability { index: number; enabled: boolean; isCurrentForFamily: boolean; eligible: boolean; reasons: string[]; healthScore: number; tokensAvailable: number; rateLimitedUntil?: number; coolingDownUntil?: number; cooldownReason?: CooldownReason; lastUsed: number; } export declare class AccountManager { private accounts; private cursorByFamily; private currentAccountIndexByFamily; private lastToastAccountIndex; private lastToastTime; private saveDebounceTimer; private pendingSave; private authFailuresByRefreshToken; static loadFromDisk(authFallback?: OAuthAuthDetails): Promise; hasRefreshToken(refreshToken: string): boolean; private hydrateFromCodexCli; constructor(authFallback?: OAuthAuthDetails, stored?: AccountStorageV3 | null); getAccountCount(): number; getActiveIndex(): number; getActiveIndexForFamily(family: ModelFamily): number; getAccountsSnapshot(): ManagedAccount[]; getSelectionExplainability(family: ModelFamily, model?: string | null, now?: number): AccountSelectionExplainability[]; setActiveIndex(index: number): ManagedAccount | null; getCurrentAccount(): ManagedAccount | null; getCurrentAccountForFamily(family: ModelFamily): ManagedAccount | null; getCurrentOrNext(): ManagedAccount | null; getCurrentOrNextForFamily(family: ModelFamily, model?: string | null): ManagedAccount | null; getNextForFamily(family: ModelFamily, model?: string | null): ManagedAccount | null; getCurrentOrNextForFamilyHybrid(family: ModelFamily, model?: string | null, options?: HybridSelectionOptions): ManagedAccount | null; recordSuccess(account: ManagedAccount, family: ModelFamily, model?: string | null): void; recordRateLimit(account: ManagedAccount, family: ModelFamily, model?: string | null): void; recordFailure(account: ManagedAccount, family: ModelFamily, model?: string | null): void; consumeToken(account: ManagedAccount, family: ModelFamily, model?: string | null): boolean; /** * Refund a token consumed within the refund window (30 seconds). * Use this when a request fails due to network errors (not rate limits). * @returns true if refund was successful, false if no valid consumption found */ refundToken(account: ManagedAccount, family: ModelFamily, model?: string | null): boolean; markSwitched(account: ManagedAccount, reason: "rate-limit" | "initial" | "rotation", family: ModelFamily): void; markRateLimited(account: ManagedAccount, retryAfterMs: number, family: ModelFamily, model?: string | null): void; markRateLimitedWithReason(account: ManagedAccount, retryAfterMs: number, family: ModelFamily, reason: RateLimitReason, model?: string | null): void; markAccountCoolingDown(account: ManagedAccount, cooldownMs: number, reason: CooldownReason): void; /** * Mark every in-memory account sharing a refresh token as cooling down. * @returns Number of live accounts updated. */ markAccountsWithRefreshTokenCoolingDown(refreshToken: string, cooldownMs: number, reason: CooldownReason): number; isAccountCoolingDown(account: ManagedAccount): boolean; clearAccountCooldown(account: ManagedAccount): void; incrementAuthFailures(account: ManagedAccount): number; /** * Clear the authentication failure counter for the given account's refresh token. * * Notes: * - Failure counts are tracked per refresh token (not per account), so this clears * shared failure state for all org variants that reuse the same token. * - Failure counts are in-memory only for the current AccountManager instance. */ clearAuthFailures(account: ManagedAccount): void; shouldShowAccountToast(accountIndex: number, debounceMs?: number): boolean; markToastShown(accountIndex: number): void; updateFromAuth(account: ManagedAccount, auth: OAuthAuthDetails): void; toAuthDetails(account: ManagedAccount): Auth; getMinWaitTime(): number; getMinWaitTimeForFamily(family: ModelFamily, model?: string | null): number; removeAccount(account: ManagedAccount): boolean; removeAccountByIndex(index: number): boolean; /** * Remove all accounts that share the same refreshToken as the given account. * This is used when auth refresh fails to remove all org variants together. * @returns Number of accounts removed */ removeAccountsWithSameRefreshToken(account: ManagedAccount): number; setAccountEnabled(index: number, enabled: boolean): ManagedAccount | null; saveToDisk(): Promise; saveToDiskDebounced(delayMs?: number): void; flushPendingSave(): Promise; } export declare function formatAccountLabel(account: { email?: string; accountId?: string; accountLabel?: string; } | undefined, index: number): string; export declare function formatCooldown(account: { coolingDownUntil?: number; cooldownReason?: string; }, now?: number): string | null; //# sourceMappingURL=accounts.d.ts.map