@cortexkit/anthropic-auth-core 1.20.0 → 1.22.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.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @cortexkit/anthropic-auth-core
2
2
 
3
- Shared Anthropic OAuth, quota, routing, cache, cache-keepalive, fast mode, relay, dump, and request-signing helpers used by CortexKit's OpenCode and Pi integrations.
3
+ Shared Anthropic OAuth, stable account identity, optional Claustrum fallback-custody primitives, model metadata, quota, host-local quota feed, routing, cache, cache-keepalive, fast mode, relay, dump, request-signing, thinking-binding, and Fable 5.1 mid-conversation effort helpers used by CortexKit's OpenCode and Pi integrations.
4
4
 
5
5
  User-facing packages:
6
6
 
@@ -4,6 +4,10 @@ export declare const ACCOUNT_FILE_NAME = "anthropic-auth.json";
4
4
  export declare const ACCOUNT_STATE_FILE_NAME = "anthropic-auth-state.json";
5
5
  export declare const QUOTA_URL = "https://api.anthropic.com/api/oauth/usage";
6
6
  export type QuotaWindowName = 'five_hour' | 'seven_day';
7
+ export declare const QUOTA_FIELD_NAMES: readonly ['five_hour', 'seven_day', 'scoped', 'extraUsage', 'bindingWindow', 'fallbackAdvised'];
8
+ export type QuotaFieldName = (typeof QUOTA_FIELD_NAMES)[number];
9
+ export type QuotaFieldSource = 'poll' | 'headers';
10
+ export type QuotaFieldSources = Partial<Record<QuotaFieldName, QuotaFieldSource>>;
7
11
  export type AccountBase = {
8
12
  id: string;
9
13
  label?: string;
@@ -14,6 +18,7 @@ export type AccountBase = {
14
18
  export type OAuthAccount = AccountBase & {
15
19
  type: 'oauth';
16
20
  authLineageId?: string;
21
+ claustrumHandle?: string;
17
22
  access?: string;
18
23
  refresh: string;
19
24
  expires?: number;
@@ -35,6 +40,12 @@ export type ApiKeyAccount = AccountBase & {
35
40
  authHeader?: 'authorization-bearer' | 'x-api-key';
36
41
  };
37
42
  export type FallbackAccount = OAuthAccount | ApiKeyAccount;
43
+ export type ClaustrumAccountGate = {
44
+ enabled?: boolean;
45
+ };
46
+ export type ClaustrumConfig = {
47
+ accounts?: Record<string, ClaustrumAccountGate>;
48
+ };
38
49
  export declare function isOAuthAccount(account: FallbackAccount): account is OAuthAccount;
39
50
  export declare function isApiKeyAccount(account: FallbackAccount): account is ApiKeyAccount;
40
51
  export declare function isValidApiBaseURL(value: string | undefined): boolean;
@@ -43,7 +54,10 @@ export type AccountOperationError = {
43
54
  checkedAt: number;
44
55
  nextRetryAt?: number;
45
56
  retryCount?: number;
57
+ accountIdentity?: string;
46
58
  tokenHash?: string;
59
+ /** Fingerprint of the refresh token that produced this error. */
60
+ refreshTokenFingerprint?: string;
47
61
  /**
48
62
  * HTTP status of the underlying refresh/quota failure, when known. Lets
49
63
  * consumers distinguish a permanently-dead token (400 invalid_grant →
@@ -89,13 +103,18 @@ export type OAuthAccountProfile = {
89
103
  tier: string;
90
104
  orgType: string;
91
105
  checkedAt: number;
106
+ /** Stable account identity; tokenFingerprint remains loadable for legacy state. */
107
+ accountIdentity?: string;
92
108
  tokenFingerprint?: string;
93
109
  };
94
110
  export type OAuthQuotaSnapshot = Partial<Record<QuotaWindowName, AccountQuotaWindow>> & {
111
+ /** Stable main/fallback account identity; access tokens are fetch credentials only. */
112
+ accountIdentity?: string;
95
113
  scoped?: AccountScopedQuotaWindow[];
96
114
  extraUsage?: OAuthExtraUsageSnapshot;
97
115
  bindingWindow?: string;
98
116
  bindingWindowSource?: 'poll' | 'headers';
117
+ fieldSources?: QuotaFieldSources;
99
118
  fallbackAdvised?: boolean;
100
119
  source?: 'poll' | 'headers';
101
120
  checkedAt?: number;
@@ -132,6 +151,7 @@ export type KillswitchConfig = {
132
151
  };
133
152
  export type AccountStorage = {
134
153
  version: 1;
154
+ mainAccountId?: string;
135
155
  main?: {
136
156
  type: 'opencode';
137
157
  provider: 'anthropic';
@@ -146,6 +166,7 @@ export type AccountStorage = {
146
166
  intervalMinutes?: number;
147
167
  refreshBeforeExpiryMinutes?: number;
148
168
  mainLastRefreshError?: AccountOperationError;
169
+ mainRefreshErrorClearedAt?: number;
149
170
  mainRefreshLeaseId?: string;
150
171
  mainRefreshLeaseUntil?: number;
151
172
  mainRefreshLeaseTokenHash?: string;
@@ -162,6 +183,11 @@ export type AccountStorage = {
162
183
  mainQuotaCheckedAt?: number;
163
184
  mainQuotaToken?: string;
164
185
  mainLastQuotaApiError?: AccountOperationError;
186
+ mainQuotaErrorGeneration?: number;
187
+ mainQuotaErrorClearedAt?: number;
188
+ };
189
+ quotaHeaderFeed?: {
190
+ enabled?: boolean;
165
191
  };
166
192
  claudeCache?: {
167
193
  enabled?: boolean;
@@ -176,6 +202,9 @@ export type AccountStorage = {
176
202
  claudeFast?: {
177
203
  enabled?: boolean;
178
204
  };
205
+ thinkingBinding?: {
206
+ prefixMismatchBehavior?: 'account-default' | 'error' | 'drop_block';
207
+ };
179
208
  /**
180
209
  * Zero out Anthropic OAuth model costs in the provider hook. Default: enabled
181
210
  * (OAuth usage is quota-based, not per-token billed, so costs show as $0).
@@ -205,6 +234,7 @@ export type AccountStorage = {
205
234
  fallbackToDirect?: boolean;
206
235
  transport?: 'http' | 'websocket';
207
236
  };
237
+ claustrum?: ClaustrumConfig;
208
238
  killswitch?: KillswitchConfig;
209
239
  accounts: FallbackAccount[];
210
240
  };
@@ -214,7 +244,7 @@ export type AccountStorage = {
214
244
  * (to display the provider's real model costs).
215
245
  */
216
246
  export declare function isCostZeroingEnabled(storage: Pick<AccountStorage, 'costZeroing'>): boolean;
217
- export type AccountRuntimeEntry = Partial<Pick<OAuthAccount, 'access' | 'authLineageId' | 'refresh' | 'expires' | 'lastUsed' | 'lastRefreshedAt' | 'lastRefreshError' | 'lastQuotaRefreshError' | 'quota' | 'profile' | 'prime'> & Pick<ApiKeyAccount, 'apiKey' | 'lastUsed'>>;
247
+ export type AccountRuntimeEntry = Partial<Pick<OAuthAccount, 'access' | 'authLineageId' | 'claustrumHandle' | 'refresh' | 'expires' | 'lastUsed' | 'lastRefreshedAt' | 'lastRefreshError' | 'lastQuotaRefreshError' | 'quota' | 'profile' | 'prime'> & Pick<ApiKeyAccount, 'apiKey' | 'lastUsed'>>;
218
248
  export type AccountRuntimeState = {
219
249
  version: 1;
220
250
  main?: {
@@ -224,7 +254,10 @@ export type AccountRuntimeState = {
224
254
  quotaCheckedAt?: number;
225
255
  quotaToken?: string;
226
256
  lastQuotaApiError?: AccountOperationError;
257
+ quotaErrorGeneration?: number;
258
+ quotaErrorClearedAt?: number;
227
259
  lastRefreshError?: AccountOperationError;
260
+ refreshErrorClearedAt?: number;
228
261
  refreshLeaseId?: string;
229
262
  refreshLeaseUntil?: number;
230
263
  refreshLeaseTokenHash?: string;
@@ -246,6 +279,13 @@ export type AccountManagerOptions = {
246
279
  fetchImpl?: typeof fetch;
247
280
  configPath?: string;
248
281
  quotaManager?: import('./quota-manager.ts').QuotaManager;
282
+ isFallbackAccountVaultServed?: (accountId: string, storage: AccountStorage) => boolean;
283
+ isFallbackAccountVaultEnabled?: (accountId: string, storage: AccountStorage) => boolean;
284
+ resolveFallbackAccessToken?: (account: OAuthAccount, storage: AccountStorage) => {
285
+ token: string;
286
+ source: 'vault' | 'sidecar';
287
+ } | undefined;
288
+ onBackgroundRefresh?: (initial?: boolean) => Promise<void> | void;
249
289
  onFallbackStorageChanged?: () => void;
250
290
  setIntervalImpl?: typeof globalThis.setInterval;
251
291
  clearIntervalImpl?: typeof globalThis.clearInterval;
@@ -254,12 +294,18 @@ export type AccountRefreshError = {
254
294
  accountId: string;
255
295
  message: string;
256
296
  };
297
+ export declare const FALLBACK_BACKGROUND_TICK_MS = 60000;
257
298
  export declare function getAccountStoragePath(): string;
258
299
  export declare function getAccountStatePath(configPath?: string): string;
259
300
  export declare function createEmptyStorage(): AccountStorage;
301
+ export declare function mergeMainQuotaErrorClearedAt(existing: number | undefined, incoming: number | undefined): number | undefined;
302
+ export declare function mergeMainRefreshErrorClearedAt(existing: number | undefined, incoming: number | undefined): number | undefined;
260
303
  export declare function loadAccounts(path?: string): Promise<AccountStorage | null>;
261
304
  /** Returns the latest timestamp carried by any quota snapshot window. */
262
305
  export declare function quotaSnapshotCheckedAt(quota: OAuthQuotaSnapshot | undefined): number;
306
+ export declare function quotaFieldSource(snapshot: OAuthQuotaSnapshot | undefined, field: QuotaFieldName): QuotaFieldSource | undefined;
307
+ export declare function mergeHeaderQuotaForPersistence(existing: OAuthQuotaSnapshot | undefined, incoming: OAuthQuotaSnapshot): OAuthQuotaSnapshot;
308
+ export declare function isClaustrumEnabledForAccount(storage: AccountStorage, accountId: string): boolean;
263
309
  export interface SaveAccountsOptions {
264
310
  /** Account ids intentionally removed by this mutation. */
265
311
  removedAccountIds?: readonly string[];
@@ -267,12 +313,14 @@ export interface SaveAccountsOptions {
267
313
  preserveExistingAccountOrder?: boolean;
268
314
  }
269
315
  export declare function saveAccounts(storage: AccountStorage, path?: string, options?: SaveAccountsOptions): Promise<void>;
316
+ export declare function getOrCreateMainAccountId(path?: string, createId?: () => string): Promise<string>;
270
317
  export declare function saveAccountState(storage: AccountStorage, path?: string, scope?: AccountStateSaveScope): Promise<void>;
271
318
  export declare function saveOAuthProfileState(input: {
272
319
  accountId: 'main' | string;
273
320
  profile: OAuthAccountProfile | undefined;
274
- expectedTokenFingerprint: string;
321
+ accountIdentity?: string;
275
322
  }, path?: string): Promise<boolean>;
323
+ export declare function clearClaustrumRefreshErrorPersistent(accountId: string, handle: string, path?: string): Promise<boolean>;
276
324
  export declare function acquireRefreshFileLock(options: {
277
325
  name: string;
278
326
  ttlMs: number;
@@ -299,17 +347,8 @@ export declare function isCacheKeepSubagentsEnabled(storage: AccountStorage | nu
299
347
  export declare function setCacheKeepSubagentsEnabled(enabled: boolean, path?: string): Promise<AccountStorage>;
300
348
  export declare function isPrimePersistentlyEnabled(storage: AccountStorage | null): boolean;
301
349
  export declare function setPrimePersistentEnabled(enabled: boolean, path?: string): Promise<AccountStorage>;
302
- /**
303
- * Return the stable prime marker identity for an OAuth account, seeding it in
304
- * runtime state when older storage has no lineage yet. Main lookups return
305
- * undefined when the live refresh token is unavailable and no lineage exists.
306
- */
307
- export declare function getOrCreatePrimeAuthLineageId(accountId: 'main' | string, path?: string, mainRefreshToken?: string): Promise<string | undefined>;
308
- /** Advance a main lineage across a refresh performed by this plugin. */
309
- export declare function continueMainPrimeAuthLineageAfterRefresh(input: {
310
- previousRefreshToken: string;
311
- currentRefreshToken: string;
312
- }, path?: string): Promise<void>;
350
+ /** Return the stable prime marker identity for an OAuth account. */
351
+ export declare function getOrCreatePrimeAuthLineageId(accountId: 'main' | string, path?: string): Promise<string | undefined>;
313
352
  /**
314
353
  * Atomically increment an account's cumulative prime counters and persist via
315
354
  * the scoped runtime-state path. The `main` account lives at state.main.prime;
@@ -324,12 +363,14 @@ export declare function getQuotaMinimumRemainingThresholds(storage: AccountStora
324
363
  five_hour: number;
325
364
  seven_day: number;
326
365
  };
366
+ export declare function getRefreshBeforeExpiryMs(storage: AccountStorage | null): number;
327
367
  export declare function getRefreshIntervalMs(storage: AccountStorage | null): number;
328
368
  export declare function hashRefreshToken(refreshToken: string): string;
329
369
  export declare function buildRefreshOperationError(input: {
330
370
  error: unknown;
331
371
  now: number;
332
- refreshToken: string;
372
+ accountIdentity: string | undefined;
373
+ refreshTokenFingerprint?: string;
333
374
  previous?: AccountOperationError;
334
375
  }): AccountOperationError;
335
376
  /**
@@ -348,13 +389,14 @@ export declare function buildRefreshOperationError(input: {
348
389
  * the error with the explicit field.
349
390
  */
350
391
  export declare function isPermanentRefreshError(error: AccountOperationError | undefined): boolean;
351
- export declare function refreshBackoffActive(error: AccountOperationError | undefined, refreshToken: string | undefined, now: number): boolean;
392
+ export declare function refreshBackoffActive(error: AccountOperationError | undefined, accountIdentity: string | undefined, now: number, currentRefreshTokenFingerprint: string | undefined): boolean;
352
393
  export declare function formatRefreshBackoffMessage(error: AccountOperationError, now: number): string;
353
394
  export declare function getFallbackReauthLabels(storage: AccountStorage | null | undefined): string[];
354
395
  export declare function isQuotaPolicyAuthError(error: unknown): boolean;
355
396
  export declare function buildQuotaOperationError(input: {
356
397
  error: unknown;
357
398
  now: number;
399
+ accountIdentity?: string;
358
400
  previous?: AccountOperationError;
359
401
  }): AccountOperationError;
360
402
  export declare function quotaBackoffActive(error: AccountOperationError | undefined, now: number): boolean;
@@ -366,6 +408,7 @@ export declare function getPersistedMainQuota(storage: AccountStorage | null): {
366
408
  quota: OAuthQuotaSnapshot;
367
409
  checkedAt: number;
368
410
  tokenFingerprint?: string;
411
+ accountIdentity?: string;
369
412
  } | null;
370
413
  /**
371
414
  * How often (in requests) to force a quota refresh, independent of the timer.
@@ -376,6 +419,7 @@ export declare function getScopedQuotaWindowForModel(quota: OAuthQuotaSnapshot |
376
419
  export declare function quotaSnapshotModelScopeIsExhausted(quota: OAuthQuotaSnapshot | undefined, model: unknown): boolean;
377
420
  export declare function quotaSnapshotPassesModelScope(quota: OAuthQuotaSnapshot | undefined, model: unknown): boolean;
378
421
  export declare function quotaSnapshotPassesPolicy(quota: OAuthQuotaSnapshot | undefined, storage: AccountStorage | null): boolean;
422
+ export declare function quotaSnapshotHasStandardWindows(quota: OAuthQuotaSnapshot | undefined): quota is OAuthQuotaSnapshot;
379
423
  export declare const DEFAULT_KILLSWITCH_THRESHOLDS: Record<QuotaWindowName | 'scoped', number>;
380
424
  export declare function normalizeKillswitchThresholds(thresholds: KillswitchThresholds | undefined): Record<QuotaWindowName | 'scoped', number>;
381
425
  export declare function isKillswitchEnabled(storage: AccountStorage | null): boolean;
@@ -426,6 +470,10 @@ export declare class FallbackAccountManager {
426
470
  private refreshTimer;
427
471
  private quotaTimer;
428
472
  readonly quotaManager: import('./quota-manager.ts').QuotaManager | null;
473
+ private readonly isFallbackAccountVaultServed;
474
+ private readonly isFallbackAccountVaultEnabled;
475
+ private readonly resolveFallbackAccessToken;
476
+ private readonly onBackgroundRefresh;
429
477
  private readonly onFallbackStorageChanged;
430
478
  private readonly setIntervalImpl;
431
479
  private readonly clearIntervalImpl;
@@ -437,7 +485,7 @@ export declare class FallbackAccountManager {
437
485
  private seedFallbackQuota;
438
486
  load(): Promise<AccountStorage | null>;
439
487
  save(storage: AccountStorage, accountIds?: string[]): Promise<void>;
440
- startBackgroundRefresh(): void;
488
+ startBackgroundRefresh(): Promise<void>;
441
489
  stopBackgroundRefresh(): void;
442
490
  getUsableFallbackAccounts(existingStorage?: AccountStorage | null, options?: {
443
491
  modelId?: string;
@@ -463,11 +511,13 @@ export declare class FallbackAccountManager {
463
511
  }>;
464
512
  refreshAccount(account: OAuthAccount, storage: AccountStorage, options?: {
465
513
  force?: boolean;
514
+ persistError?: boolean;
466
515
  }): Promise<OAuthAccount>;
467
516
  private waitForConcurrentFallbackRefresh;
468
517
  private refreshAccountNow;
469
518
  refreshAccountQuota(account: OAuthAccount, storage: AccountStorage): Promise<{
470
519
  account: OAuthAccount;
471
520
  fetched: boolean;
521
+ changed: boolean;
472
522
  }>;
473
523
  }