dsh-subscriptions 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (150) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +129 -0
  3. package/cordis.patch.yml +12 -0
  4. package/lib/auth/claude-code-creds.d.ts +23 -0
  5. package/lib/auth/claude-code-creds.js +172 -0
  6. package/lib/auth/device-flow.d.ts +55 -0
  7. package/lib/auth/device-flow.js +177 -0
  8. package/lib/auth/jwt.d.ts +10 -0
  9. package/lib/auth/jwt.js +25 -0
  10. package/lib/auth/oauth-flow.d.ts +91 -0
  11. package/lib/auth/oauth-flow.js +227 -0
  12. package/lib/auth/pkce.d.ts +31 -0
  13. package/lib/auth/pkce.js +35 -0
  14. package/lib/auth/rpc.d.ts +209 -0
  15. package/lib/auth/rpc.js +386 -0
  16. package/lib/auth/store.d.ts +196 -0
  17. package/lib/auth/store.js +468 -0
  18. package/lib/client/CursorCard.d.ts +9 -0
  19. package/lib/client/CursorCard.js +113 -0
  20. package/lib/client/ExternalUsageCards.d.ts +9 -0
  21. package/lib/client/ExternalUsageCards.js +72 -0
  22. package/lib/client/ImageGallery.d.ts +54 -0
  23. package/lib/client/ImageGallery.js +112 -0
  24. package/lib/client/ImageGenerateToolview.d.ts +48 -0
  25. package/lib/client/ImageGenerateToolview.js +133 -0
  26. package/lib/client/ProviderAccountManager.d.ts +13 -0
  27. package/lib/client/ProviderAccountManager.js +147 -0
  28. package/lib/client/ProviderModelEditor.d.ts +39 -0
  29. package/lib/client/ProviderModelEditor.js +107 -0
  30. package/lib/client/SpeedSelect.d.ts +71 -0
  31. package/lib/client/SpeedSelect.js +177 -0
  32. package/lib/client/SubscriptionUsageBadge.d.ts +116 -0
  33. package/lib/client/SubscriptionUsageBadge.js +543 -0
  34. package/lib/client/SubscriptionsSection.d.ts +140 -0
  35. package/lib/client/SubscriptionsSection.js +544 -0
  36. package/lib/client/UsageBadgeDisplaySetting.d.ts +7 -0
  37. package/lib/client/UsageBadgeDisplaySetting.js +36 -0
  38. package/lib/client/VideoGenerateToolview.d.ts +42 -0
  39. package/lib/client/VideoGenerateToolview.js +175 -0
  40. package/lib/client/account-preferences.d.ts +24 -0
  41. package/lib/client/account-preferences.js +21 -0
  42. package/lib/client/fast-command.d.ts +2 -0
  43. package/lib/client/fast-command.js +4 -0
  44. package/lib/client/host-contract.d.ts +90 -0
  45. package/lib/client/host-contract.js +101 -0
  46. package/lib/client/host-icons.d.ts +24 -0
  47. package/lib/client/host-icons.js +21 -0
  48. package/lib/client/index.d.ts +27 -0
  49. package/lib/client/index.js +136 -0
  50. package/lib/client/locales.d.ts +297 -0
  51. package/lib/client/locales.js +295 -0
  52. package/lib/client/subscription-card-styles.d.ts +3 -0
  53. package/lib/client/subscription-card-styles.js +53 -0
  54. package/lib/client/subscriptions-rpc.d.ts +14 -0
  55. package/lib/client/subscriptions-rpc.js +34 -0
  56. package/lib/client/usage-badge-preferences.d.ts +11 -0
  57. package/lib/client/usage-badge-preferences.js +41 -0
  58. package/lib/client.js +4472 -0
  59. package/lib/client.js.map +1 -0
  60. package/lib/compat.d.ts +36 -0
  61. package/lib/compat.js +20 -0
  62. package/lib/http.d.ts +6 -0
  63. package/lib/http.js +15 -0
  64. package/lib/index.d.ts +80 -0
  65. package/lib/index.js +14018 -0
  66. package/lib/model-defaults.d.ts +23 -0
  67. package/lib/model-defaults.js +237 -0
  68. package/lib/provider-settings.d.ts +39 -0
  69. package/lib/provider-settings.js +151 -0
  70. package/lib/providers/account-preferences.d.ts +41 -0
  71. package/lib/providers/account-preferences.js +153 -0
  72. package/lib/providers/accounts.d.ts +112 -0
  73. package/lib/providers/accounts.js +142 -0
  74. package/lib/providers/antigravity-oauth-client.d.ts +7 -0
  75. package/lib/providers/antigravity-oauth-client.js +7 -0
  76. package/lib/providers/antigravity.d.ts +110 -0
  77. package/lib/providers/antigravity.js +516 -0
  78. package/lib/providers/catalog-store.d.ts +48 -0
  79. package/lib/providers/catalog-store.js +243 -0
  80. package/lib/providers/claude-cli-version.d.ts +15 -0
  81. package/lib/providers/claude-cli-version.js +24 -0
  82. package/lib/providers/claude.d.ts +181 -0
  83. package/lib/providers/claude.js +680 -0
  84. package/lib/providers/codex-client-version.d.ts +8 -0
  85. package/lib/providers/codex-client-version.js +17 -0
  86. package/lib/providers/codex-search.d.ts +29 -0
  87. package/lib/providers/codex-search.js +198 -0
  88. package/lib/providers/codex.d.ts +229 -0
  89. package/lib/providers/codex.js +821 -0
  90. package/lib/providers/common.d.ts +389 -0
  91. package/lib/providers/common.js +656 -0
  92. package/lib/providers/copilot.d.ts +344 -0
  93. package/lib/providers/copilot.js +888 -0
  94. package/lib/providers/cursor-adapter.d.ts +15 -0
  95. package/lib/providers/cursor-adapter.js +39 -0
  96. package/lib/providers/cursor-auth.d.ts +43 -0
  97. package/lib/providers/cursor-auth.js +169 -0
  98. package/lib/providers/cursor-model-settings.d.ts +15 -0
  99. package/lib/providers/cursor-model-settings.js +51 -0
  100. package/lib/providers/cursor-usage.d.ts +9 -0
  101. package/lib/providers/cursor-usage.js +112 -0
  102. package/lib/providers/external-usage-controller.d.ts +19 -0
  103. package/lib/providers/external-usage-controller.js +32 -0
  104. package/lib/providers/external-usage.d.ts +8 -0
  105. package/lib/providers/external-usage.js +82 -0
  106. package/lib/providers/grok.d.ts +205 -0
  107. package/lib/providers/grok.js +713 -0
  108. package/lib/providers/image-pool.d.ts +30 -0
  109. package/lib/providers/image-pool.js +89 -0
  110. package/lib/providers/npm-cli-version.d.ts +56 -0
  111. package/lib/providers/npm-cli-version.js +98 -0
  112. package/lib/providers/pool-family.d.ts +56 -0
  113. package/lib/providers/pool-family.js +45 -0
  114. package/lib/providers/pool-health.d.ts +74 -0
  115. package/lib/providers/pool-health.js +150 -0
  116. package/lib/providers/pool-usage.d.ts +86 -0
  117. package/lib/providers/pool-usage.js +223 -0
  118. package/lib/providers/pool.d.ts +108 -0
  119. package/lib/providers/pool.js +368 -0
  120. package/lib/providers/rate-limit.d.ts +192 -0
  121. package/lib/providers/rate-limit.js +338 -0
  122. package/lib/tools/image-generate.d.ts +128 -0
  123. package/lib/tools/image-generate.js +438 -0
  124. package/lib/tools/registration.d.ts +15 -0
  125. package/lib/tools/registration.js +24 -0
  126. package/lib/tools/video-generate.d.ts +89 -0
  127. package/lib/tools/video-generate.js +257 -0
  128. package/lib/tools/x-search.d.ts +58 -0
  129. package/lib/tools/x-search.js +197 -0
  130. package/lib/translate/anthropic.d.ts +161 -0
  131. package/lib/translate/anthropic.js +515 -0
  132. package/lib/translate/antigravity-schema.d.ts +4 -0
  133. package/lib/translate/antigravity-schema.js +145 -0
  134. package/lib/translate/antigravity-thinking.d.ts +5 -0
  135. package/lib/translate/antigravity-thinking.js +44 -0
  136. package/lib/translate/antigravity.d.ts +114 -0
  137. package/lib/translate/antigravity.js +366 -0
  138. package/lib/translate/chat-completions.d.ts +120 -0
  139. package/lib/translate/chat-completions.js +382 -0
  140. package/lib/translate/resolved.d.ts +80 -0
  141. package/lib/translate/resolved.js +118 -0
  142. package/lib/translate/responses.d.ts +179 -0
  143. package/lib/translate/responses.js +408 -0
  144. package/lib/translate/sse.d.ts +21 -0
  145. package/lib/translate/sse.js +56 -0
  146. package/package.json +114 -0
  147. package/vendor/cursor/LICENSE +21 -0
  148. package/vendor/cursor/index.d.ts +18 -0
  149. package/vendor/cursor/index.js +3574 -0
  150. package/vendor/cursor/proto.js +254 -0
@@ -0,0 +1,389 @@
1
+ /**
2
+ * Plumbing shared by the subscription adapters: HTTP error mapping, a
3
+ * stream idle watchdog, fetch failure classification, OAuth endpoint errors,
4
+ * and the per-provider {@link TokenManager} that owns session freshness.
5
+ * Concurrent refreshes for one provider coalesce behind a single in-flight
6
+ * promise (`inflight`), so a rotating refresh token is never spent twice.
7
+ */
8
+ import { LlmError, ReasoningEffortId } from '@deepseek-ai/dsh-llm';
9
+ import type { RateLimitResetReader } from './rate-limit.js';
10
+ /** One configured model catalog entry. */
11
+ export interface ModelEntry {
12
+ /** Wire model id; must be non-empty. */
13
+ id: string;
14
+ /** Selector label; defaults to the id. */
15
+ name?: string;
16
+ /** Known combined request/response context capacity. */
17
+ contextWindow?: number;
18
+ /** Per-request output cap for this model. */
19
+ maxTokens?: number;
20
+ /** Accepted request modalities; when set, wins over the provider default. */
21
+ inputModalities?: ('text' | 'image')[];
22
+ /**
23
+ * Force this model's upstream protocol. Only the copilot adapter consumes
24
+ * the semantics; the union is inlined here to avoid a circular import of
25
+ * the copilot module's `CopilotWire`.
26
+ */
27
+ wire?: 'chat-completions' | 'responses';
28
+ }
29
+ /**
30
+ * Validate a configured model catalog (mirrors llm-deepseek's resolveModels).
31
+ * @param models - raw configured entries.
32
+ * @param label - diagnostic prefix naming the provider.
33
+ * @returns the validated entries.
34
+ */
35
+ export declare function validateModels(models: readonly ModelEntry[], label: string): ModelEntry[];
36
+ /** Optional per-call hooks {@link httpLlmError} uses to read a rate-limit window. */
37
+ export interface HttpLlmErrorOptions {
38
+ /**
39
+ * The calling provider's reader for the instant its rate-limit window
40
+ * reopens. Consulted on a 429 only, and there ahead of the generic
41
+ * `retry-after` header, because a provider's own field names the window while
42
+ * `retry-after` often names a short backoff.
43
+ */
44
+ rateLimitReset?: RateLimitResetReader;
45
+ /** Diagnostic sink for a 429 that disclosed no reset instant this code recognizes. */
46
+ onWarn?: (message: string) => void;
47
+ }
48
+ /**
49
+ * Build an LlmError from a non-2xx provider response, mapping the status to a
50
+ * stable code and, for a rate-limited request, the disclosed reset instant to
51
+ * the `providerRetryAfterMs` the retry plugin waits out.
52
+ *
53
+ * A 429 classifies as `RATE_LIMIT` on the strength of the status alone, ahead
54
+ * of the quota-wording check. On these routes there is no terminal quota to
55
+ * distinguish: a subscription has no balance to top up, only a window that
56
+ * reopens, and providers announce an exhausted window with wording
57
+ * (`usage_limit_reached`) the shared classifier reads as permanent.
58
+ * @param response - the failed response.
59
+ * @param label - diagnostic prefix naming the provider API.
60
+ * @param options - the calling provider's rate-limit reader and warning sink.
61
+ * @returns the classified error.
62
+ */
63
+ export declare function httpLlmError(response: Response, label: string, options?: HttpLlmErrorOptions): Promise<LlmError>;
64
+ /** An idle watchdog: aborts its signal when no SSE activity arrives within the timeout. */
65
+ export interface IdleWatchdog {
66
+ /** Signal to pass to fetch and body reads; aborts on caller cancel or idle expiry. */
67
+ readonly signal: AbortSignal;
68
+ /** Reset the idle timer (call on every received SSE event). */
69
+ pulse(): void;
70
+ /** Stop the timer and detach from the caller signal. */
71
+ stop(): void;
72
+ /** Whether the last abort came from idle expiry rather than caller cancellation. */
73
+ timedOut(): boolean;
74
+ }
75
+ /**
76
+ * Create an idle watchdog chained to the caller's signal.
77
+ * @param caller - the request's own abort signal, when present.
78
+ * @param timeoutMs - maximum idle interval while a stream read is outstanding.
79
+ * @returns the watchdog; always {@link IdleWatchdog.stop} it when the stream ends.
80
+ */
81
+ export declare function idleWatchdog(caller: AbortSignal | undefined, timeoutMs: number): IdleWatchdog;
82
+ /**
83
+ * Classify a thrown fetch failure. Caller cancellation maps to ABORTED, idle
84
+ * expiry to TIMEOUT, and everything else (DNS, TLS, refused connection) to
85
+ * TRANSPORT with the cause chained.
86
+ * @param label - diagnostic prefix naming the provider API.
87
+ * @param error - the thrown value.
88
+ * @param watchdog - the request's idle watchdog.
89
+ * @param caller - the request's own abort signal, when present.
90
+ * @returns the classified error.
91
+ */
92
+ export declare function mapFetchFailure(label: string, error: unknown, watchdog: IdleWatchdog, caller: AbortSignal | undefined): LlmError;
93
+ /** OAuth token-endpoint failure carrying the provider's `error` code when it sent one. */
94
+ export declare class OAuthEndpointError extends Error {
95
+ /** HTTP status of the token endpoint response. */
96
+ readonly status: number;
97
+ /** The provider's OAuth `error` code (e.g. `invalid_grant`), when present. */
98
+ readonly oauthCode: string | undefined;
99
+ /**
100
+ * The endpoint's `retry-after`, in ms, when it sent one. Usage/models
101
+ * endpoints reuse this error type and can rate-limit progressively (each
102
+ * hit within the window extends the next one), so a caller retrying on a
103
+ * fixed schedule instead of honoring this can keep an account locked out
104
+ * indefinitely.
105
+ */
106
+ readonly retryAfterMs: number | undefined;
107
+ constructor(message: string, status: number, oauthCode?: string, retryAfterMs?: number);
108
+ }
109
+ /**
110
+ * Read an OAuth JSON error body into an {@link OAuthEndpointError}. Two body
111
+ * shapes are understood: RFC 6749 (`{ error: "invalid_grant", error_description }`)
112
+ * and the OpenAI API envelope the auth.openai.com token endpoint now answers
113
+ * with (`{ error: { code: "refresh_token_reused", message } }`). The code
114
+ * must land in `oauthCode` either way — the permanent-failure classifiers
115
+ * key on it, and an unrecognized shape would keep a dead login forever.
116
+ * @param response - the failed token-endpoint response.
117
+ * @param label - diagnostic prefix naming the provider.
118
+ * @returns the error to throw.
119
+ */
120
+ export declare function oauthEndpointError(response: Response, label: string): Promise<OAuthEndpointError>;
121
+ /** A session fresh enough to serve a request without a refresh. */
122
+ interface TimedSession {
123
+ accessToken: string;
124
+ refreshToken: string;
125
+ expiresAt: number;
126
+ }
127
+ /** Provider hooks the token manager needs. */
128
+ export interface TokenManagerOptions<S extends TimedSession> {
129
+ /** Human-readable provider name for error messages. */
130
+ displayName: string;
131
+ /** Refresh this long before `expiresAt`. */
132
+ preemptMs: number;
133
+ load(): Promise<S | undefined>;
134
+ save(session: S): Promise<void>;
135
+ remove(): Promise<void>;
136
+ /** Perform the provider's refresh-token grant. */
137
+ refresh(session: S): Promise<S>;
138
+ /** Whether a refresh failure is permanent (re-login required). */
139
+ isPermanent(error: unknown): boolean;
140
+ /** Called after a permanent refresh failure deleted the stored session. */
141
+ onRemoved?(): void;
142
+ }
143
+ /**
144
+ * Per-provider session freshness: loads the stored session, refreshes
145
+ * proactively inside the preempt window or on demand after a 401, and
146
+ * coalesces concurrent refreshes behind one in-flight promise. Permanent
147
+ * refresh failures delete the stored session and surface INVALID_CREDENTIAL
148
+ * with a re-login hint; transient failures fall back to a still-valid token.
149
+ */
150
+ export declare class TokenManager<S extends TimedSession> {
151
+ private readonly options;
152
+ private inflight;
153
+ /** The session whose refresh token the in-flight refresh is spending. */
154
+ private attempted;
155
+ constructor(options: TokenManagerOptions<S>);
156
+ /**
157
+ * Read the stored session without any refresh side effect. Catalog queries
158
+ * (`listModels`) use this to decide whether the provider is logged in.
159
+ * @returns the stored session, or `undefined` when logged out.
160
+ */
161
+ peek(): Promise<S | undefined>;
162
+ /**
163
+ * Whether a session is currently stored (cheap; never refreshes).
164
+ * @returns true when logged in.
165
+ */
166
+ hasSession(): Promise<boolean>;
167
+ /**
168
+ * Resolve a usable session, refreshing proactively or on demand.
169
+ * @param forceRefresh - refresh regardless of expiry (used after a 401).
170
+ * @returns the persisted session to send.
171
+ * @throws LlmError MISSING_CREDENTIAL when logged out, INVALID_CREDENTIAL
172
+ * when the refresh grant is permanently rejected.
173
+ */
174
+ session(forceRefresh?: boolean): Promise<S>;
175
+ private doRefresh;
176
+ }
177
+ /** Fetch signature adapters accept for discovery calls (injectable for tests). */
178
+ export type FetchFn = typeof fetch;
179
+ /** Bound on one account catalog fetch or usage poll — a hang must not block the picker. */
180
+ export declare const DISCOVERY_TIMEOUT_MS = 10000;
181
+ /**
182
+ * Run `work` with an aborting signal. Resolves undefined when the timeout
183
+ * fires (the fetch is aborted); other failures propagate.
184
+ */
185
+ export declare function withTimeout<T>(work: (signal: AbortSignal) => Promise<T>, timeoutMs: number): Promise<T | undefined>;
186
+ /** One rate-limit window reported by a provider's usage endpoint. */
187
+ export interface UsageWindow {
188
+ /** Window kind: `session` for the short rolling window, `weekly` for the 7-day one. */
189
+ kind: 'session' | 'weekly' | 'other';
190
+ /** Model scope for model-specific windows (e.g. `Opus`), when the provider names one. */
191
+ scope?: string;
192
+ /** Percent of the window already consumed (0–100). */
193
+ usedPercent: number;
194
+ /** Epoch milliseconds at which the window resets, when the provider discloses it. */
195
+ resetsAt?: number;
196
+ }
197
+ /** Subscription usage of one provider, as served by the `usage` RPC endpoint. */
198
+ export interface ProviderUsage {
199
+ /** False when the provider has no usage endpoint (grok); windows are absent then. */
200
+ supported: boolean;
201
+ /** Usage windows in display order. */
202
+ windows?: UsageWindow[];
203
+ /** Plan name the usage endpoint reported, when present. */
204
+ plan?: string;
205
+ }
206
+ /** One model discovered from a provider's live model-list endpoint. */
207
+ export interface DiscoveredModel {
208
+ /** Account-specific server-advertised ceiling for local context overrides. */
209
+ maxContextWindow?: number;
210
+ /** Wire model id. */
211
+ id: string;
212
+ /** Human-readable display name. */
213
+ name: string;
214
+ description?: string;
215
+ /** Advertised combined context capacity in tokens. */
216
+ contextWindow?: number;
217
+ /** Server-advertised per-request output token ceiling, when disclosed. */
218
+ maxOutputTokens?: number;
219
+ /** Provider sort hint; lower sorts earlier. */
220
+ priority?: number;
221
+ /** Advertised reasoning efforts, when the provider discloses them. */
222
+ reasoning?: {
223
+ efforts: {
224
+ id: ReasoningEffortId;
225
+ name: string;
226
+ description?: string;
227
+ }[];
228
+ defaultEffort?: ReasoningEffortId;
229
+ };
230
+ /** Accepted request modalities the endpoint advertised (e.g. Copilot's vision support flag). */
231
+ inputModalities?: ('text' | 'image')[];
232
+ /** Claude-specific: which extended-thinking wire shape this model accepts. */
233
+ thinkingType?: 'enabled' | 'adaptive';
234
+ /** Codex-specific: the catalog advertises a fast (priority) service tier. */
235
+ fastTier?: boolean;
236
+ /** Copilot-specific: which upstream protocol the model's endpoints speak. */
237
+ copilotWire?: 'chat-completions' | 'responses';
238
+ /**
239
+ * Copilot-specific: the catalog also lists `/responses` for this model
240
+ * (dual-protocol entries, e.g. gpt-5.4), so a chat-wire request may reroute
241
+ * there when it combines function tools with a reasoning effort.
242
+ */
243
+ copilotResponses?: boolean;
244
+ }
245
+ /** Display name for a wire reasoning-effort identifier. */
246
+ export declare function effortDisplayName(effort: string): string;
247
+ /** The reasoning-block shape every caller passes to {@link mergeReasoning}. */
248
+ export interface ReasoningBlock {
249
+ efforts: readonly {
250
+ id: ReasoningEffortId;
251
+ name: string;
252
+ description?: string;
253
+ }[];
254
+ defaultEffort?: ReasoningEffortId;
255
+ }
256
+ /**
257
+ * Fold a configured per-model default effort into a reasoning block, keeping
258
+ * the DSH runtime invariant `defaultEffort ∈ efforts` (the runtime rejects an
259
+ * unknown default with `INVALID_MODEL_REASONING`).
260
+ *
261
+ * A configured level the base set does not advertise is *dropped*, not
262
+ * appended: for claude/grok/copilot the base is the provider's live catalog,
263
+ * i.e. the truth about what the model accepts, so honouring a stale override
264
+ * would put an unsupported effort on every single request instead of letting
265
+ * the harness reject it before provider I/O. The override then simply falls
266
+ * back to the provider's own default until the user picks a level the catalog
267
+ * still lists.
268
+ *
269
+ * `extendable` opts into the opposite rule for a base that is a *built-in
270
+ * fallback* rather than discovered truth (codex, whose static effort list is
271
+ * known to trail the backend): there, appending the configured level is how a
272
+ * newly shipped tier becomes selectable at all.
273
+ * @param configuredDefault - the user-configured default effort id, or undefined.
274
+ * @param base - the discovered/built-in reasoning block, or undefined.
275
+ * @param options - `extendable` marks the base as a fallback that may be extended.
276
+ * @returns the merged block, or undefined when neither side contributes one.
277
+ */
278
+ export declare function mergeReasoning(configuredDefault: string | undefined, base: ReasoningBlock | undefined, options?: {
279
+ extendable?: boolean;
280
+ }): DiscoveredModel['reasoning'] | undefined;
281
+ /**
282
+ * First account catalog that lists `model` (callers pass default-first).
283
+ * One failing lookup sits that account out so a sibling's metadata still
284
+ * resolves — the same isolation as the picker catalog union.
285
+ */
286
+ export declare function discoverAcrossAccounts(accounts: readonly string[], lookup: (account: string) => Promise<DiscoveredModel | undefined>): Promise<DiscoveredModel | undefined>;
287
+ /** How long a discovered catalog is trusted before re-fetching. */
288
+ export declare const DISCOVERY_TTL_MS: number;
289
+ /** A durable snapshot of one provider's discovered catalog. */
290
+ export interface CatalogSnapshot {
291
+ /** Epoch milliseconds of the successful fetch that produced it. */
292
+ at: number;
293
+ models: DiscoveredModel[];
294
+ }
295
+ /** The durable half of a {@link ModelCatalogCache} (the models.json store). */
296
+ export interface CatalogPersistence {
297
+ /** The last persisted snapshot, or undefined when absent or unusable. */
298
+ load(): Promise<CatalogSnapshot | undefined>;
299
+ /** Persist a fresh snapshot (write-through after every successful fetch). */
300
+ save(snapshot: CatalogSnapshot): Promise<void>;
301
+ /** Drop the persisted snapshot (a 401 proved the credential changed). */
302
+ clear(): Promise<void>;
303
+ }
304
+ /**
305
+ * Cache for one provider's discovered model catalog. The TTL only decides
306
+ * when to REFRESH; it never makes the cache forget: capability metadata
307
+ * (reasoning efforts) must stay stable for a session that selected an effort,
308
+ * or mid-conversation calls fail UNSUPPORTED_REASONING_EFFORT the moment the
309
+ * cache goes stale. `listModels` awaits freshness via {@link get};
310
+ * `resolveModel` uses {@link resolve}, which serves the last-known catalog
311
+ * while a stale entry refreshes in the background, and only awaits the fetch
312
+ * when nothing is known yet. An optional {@link CatalogPersistence} seeds the
313
+ * last-known state across restarts and receives every successful fetch. A 401
314
+ * that still fails after a forced token refresh must call {@link invalidate}.
315
+ */
316
+ export declare class ModelCatalogCache {
317
+ private readonly persistence?;
318
+ private readonly ttlMs;
319
+ private entry;
320
+ private inflight;
321
+ /** Settles once the persisted snapshot (when any) has been considered. */
322
+ private seeded;
323
+ /** Set by {@link invalidate} so an in-flight disk read cannot resurrect dropped state. */
324
+ private seedDisabled;
325
+ /** Bumped by {@link invalidate} so a loser in-flight fetch cannot write back. */
326
+ private generation;
327
+ constructor(persistence?: CatalogPersistence | undefined, ttlMs?: number);
328
+ /**
329
+ * The cached catalog when fresh, without fetching.
330
+ * @returns the cached models, or `undefined` when absent or stale.
331
+ */
332
+ cached(): readonly DiscoveredModel[] | undefined;
333
+ /**
334
+ * The last successfully fetched catalog, ignoring TTL. Used to carry
335
+ * capability metadata forward when a later fetch cannot re-enrich.
336
+ * @returns the last-known models, or `undefined` when nothing has been stored.
337
+ */
338
+ lastKnown(): readonly DiscoveredModel[] | undefined;
339
+ /** Load the persisted snapshot once; a fetch or invalidate that landed first wins. */
340
+ private ensureSeeded;
341
+ /** Run (or join) the single in-flight fetch, updating memory and disk on success. */
342
+ private refresh;
343
+ /**
344
+ * Return the cached catalog when fresh, otherwise fetch and cache it.
345
+ * @param fetcher - performs the provider's model-list request.
346
+ * @returns the discovered models.
347
+ * @throws the fetcher's failure (the `listModels` caller warns and falls back).
348
+ */
349
+ get(fetcher: () => Promise<DiscoveredModel[]>): Promise<readonly DiscoveredModel[]>;
350
+ /**
351
+ * The models for capability resolution. A fresh cache answers directly; a
352
+ * stale one answers immediately from the last-known catalog while a
353
+ * background refresh runs (a mid-conversation `resolveModel` must neither
354
+ * block on nor fail with the network); a cold cache awaits one fetch.
355
+ * @param fetcher - performs the provider's model-list request.
356
+ * @returns the models, or `undefined` when nothing is known (the caller
357
+ * falls back to its static metadata). Never throws.
358
+ */
359
+ resolve(fetcher: () => Promise<DiscoveredModel[]>): Promise<readonly DiscoveredModel[] | undefined>;
360
+ /** Drop the cached catalog (e.g. after a 401 proved the credential changed). */
361
+ invalidate(): void;
362
+ }
363
+ /** Whether discovery failed because the stored login is gone. */
364
+ export declare function isMissingOrInvalidCredential(error: unknown): boolean;
365
+ /** Whether discovery stopped because the caller cancelled or the timeout fired. */
366
+ export declare function isDiscoveryAborted(error: unknown, signal?: AbortSignal): boolean;
367
+ /**
368
+ * Whether discovery failed because the access token was rejected. After
369
+ * {@link discoverOrRetryAuth} this means the token was rejected AGAIN right
370
+ * after a forced refresh: the login is dead server-side (revoked) even though
371
+ * the refresh grant still answers, so the store keeps the session.
372
+ */
373
+ export declare function isDiscoveryAuthFailure(error: unknown): boolean;
374
+ /**
375
+ * Run a catalog fetch, retrying once after a forced token refresh when the
376
+ * first attempt is a 401/AUTH. Only {@link ModelCatalogCache.invalidate}s
377
+ * when the retry is also an auth failure, so a refresh race cannot erase
378
+ * last-known capability metadata.
379
+ */
380
+ export declare function discoverOrRetryAuth<T>(session: (forceRefresh?: boolean) => Promise<unknown>, catalog: ModelCatalogCache, run: () => Promise<T>): Promise<T>;
381
+ /**
382
+ * Keep Codex's session header stable for a supplied, non-empty session ID.
383
+ * Existing UUIDs are preserved; other IDs use a SHA-256-derived UUIDv8 (a
384
+ * custom deterministic layout). UUID formatting is a client convention,
385
+ * not a claim about gateway validation or guaranteed prompt-cache hits.
386
+ * Missing and empty IDs have no session identity and receive a fresh UUIDv4.
387
+ */
388
+ export declare function deterministicSessionId(sessionId?: string): string;
389
+ export {};