@cortexkit/anthropic-auth-core 1.21.0 → 1.23.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 (59) hide show
  1. package/README.md +1 -1
  2. package/dist/accounts.d.ts +100 -3
  3. package/dist/accounts.js +1099 -169
  4. package/dist/auth.js +6 -10
  5. package/dist/cachekeep.d.ts +18 -1
  6. package/dist/cachekeep.js +108 -82
  7. package/dist/cch.d.ts +23 -9
  8. package/dist/cch.js +104 -21
  9. package/dist/claude-code.d.ts +8 -3
  10. package/dist/claude-code.js +24 -7
  11. package/dist/claustrum-enrollment-registry.d.ts +17 -0
  12. package/dist/claustrum-enrollment-registry.js +194 -0
  13. package/dist/claustrum-enrollment.d.ts +70 -0
  14. package/dist/claustrum-enrollment.js +485 -0
  15. package/dist/claustrum-scoped-roster.d.ts +23 -0
  16. package/dist/claustrum-scoped-roster.js +194 -0
  17. package/dist/claustrum-scoped-runtime.d.ts +28 -0
  18. package/dist/claustrum-scoped-runtime.js +230 -0
  19. package/dist/claustrum-scoped.d.ts +39 -0
  20. package/dist/claustrum-scoped.js +193 -0
  21. package/dist/claustrum.d.ts +252 -0
  22. package/dist/claustrum.js +1471 -0
  23. package/dist/commands/account.d.ts +43 -11
  24. package/dist/commands/account.js +147 -4
  25. package/dist/constants.d.ts +5 -5
  26. package/dist/constants.js +5 -5
  27. package/dist/custom-headers.d.ts +3 -0
  28. package/dist/custom-headers.js +102 -0
  29. package/dist/dump.js +2 -1
  30. package/dist/fast.js +1 -1
  31. package/dist/index.d.ts +11 -0
  32. package/dist/index.js +11 -0
  33. package/dist/json.d.ts +1 -0
  34. package/dist/json.js +10 -0
  35. package/dist/logger.js +3 -1
  36. package/dist/mid-conversation-output-config.d.ts +13 -0
  37. package/dist/mid-conversation-output-config.js +89 -0
  38. package/dist/model-remap.d.ts +27 -0
  39. package/dist/model-remap.js +72 -0
  40. package/dist/models.d.ts +46 -1
  41. package/dist/models.js +87 -8
  42. package/dist/network-errors.d.ts +1 -0
  43. package/dist/network-errors.js +27 -0
  44. package/dist/oauth-profile.d.ts +2 -1
  45. package/dist/oauth-profile.js +6 -0
  46. package/dist/prime.d.ts +11 -3
  47. package/dist/prime.js +25 -7
  48. package/dist/quota-header-feed.d.ts +32 -7
  49. package/dist/quota-header-feed.js +93 -10
  50. package/dist/quota-headers.js +59 -6
  51. package/dist/quota-manager.d.ts +20 -2
  52. package/dist/quota-manager.js +101 -24
  53. package/dist/relay.d.ts +8 -0
  54. package/dist/relay.js +72 -12
  55. package/dist/sticky-routing.d.ts +2 -0
  56. package/dist/sticky-routing.js +19 -1
  57. package/dist/thinking-binding.d.ts +7 -0
  58. package/dist/thinking-binding.js +54 -0
  59. package/package.json +4 -1
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @cortexkit/anthropic-auth-core
2
2
 
3
- Shared Anthropic OAuth, stable account identity, quota, host-local quota feed, 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
 
@@ -1,9 +1,16 @@
1
+ import type { ProviderAccountUuid } from './claude-code.ts';
2
+ import { type CustodyHandleResolution } from './claustrum.ts';
1
3
  import { type Cache1hMode } from './constants.ts';
2
4
  import { type LogLevel } from './logger.ts';
5
+ export type { ProviderAccountUuid } from './claude-code.ts';
3
6
  export declare const ACCOUNT_FILE_NAME = "anthropic-auth.json";
4
7
  export declare const ACCOUNT_STATE_FILE_NAME = "anthropic-auth-state.json";
5
8
  export declare const QUOTA_URL = "https://api.anthropic.com/api/oauth/usage";
6
9
  export type QuotaWindowName = 'five_hour' | 'seven_day';
10
+ export declare const QUOTA_FIELD_NAMES: readonly ['five_hour', 'seven_day', 'scoped', 'extraUsage', 'bindingWindow', 'fallbackAdvised'];
11
+ export type QuotaFieldName = (typeof QUOTA_FIELD_NAMES)[number];
12
+ export type QuotaFieldSource = 'poll' | 'headers';
13
+ export type QuotaFieldSources = Partial<Record<QuotaFieldName, QuotaFieldSource>>;
7
14
  export type AccountBase = {
8
15
  id: string;
9
16
  label?: string;
@@ -14,6 +21,11 @@ export type AccountBase = {
14
21
  export type OAuthAccount = AccountBase & {
15
22
  type: 'oauth';
16
23
  authLineageId?: string;
24
+ anthropicAccountUuid?: ProviderAccountUuid;
25
+ claustrumHandle?: string;
26
+ /** Non-secret scoped identity; never a capability handle or bearer token. */
27
+ claustrumScopedCredentialId?: string;
28
+ claustrumScopedState?: string;
17
29
  access?: string;
18
30
  refresh: string;
19
31
  expires?: number;
@@ -28,6 +40,10 @@ export type OAuthAccount = AccountBase & {
28
40
  */
29
41
  prime?: PrimeUsageCounters;
30
42
  };
43
+ export declare function hasNoLocalCredential(account: {
44
+ access?: unknown;
45
+ refresh?: unknown;
46
+ }): boolean;
31
47
  export type ApiKeyAccount = AccountBase & {
32
48
  type: 'api';
33
49
  apiKey?: string;
@@ -35,6 +51,25 @@ export type ApiKeyAccount = AccountBase & {
35
51
  authHeader?: 'authorization-bearer' | 'x-api-key';
36
52
  };
37
53
  export type FallbackAccount = OAuthAccount | ApiKeyAccount;
54
+ export type ClaustrumAccountGate = {
55
+ enabled?: boolean;
56
+ };
57
+ export type ClaustrumMode = 'local' | 'claustrum';
58
+ export type ClaustrumConfig = {
59
+ mode?: ClaustrumMode;
60
+ handlesFile?: string;
61
+ /** Set by authoritative scoped discovery, not an authentication toggle. */
62
+ scopedRoster?: true;
63
+ /** Authoritative, non-secret primary identity from scoped discovery. */
64
+ primaryAccount?: {
65
+ credentialId: string;
66
+ accountId: ProviderAccountUuid;
67
+ state: string;
68
+ };
69
+ /** Preserve explicit exclusions when a vaulted account disappears and returns. */
70
+ disabledAccountIdentities?: string[];
71
+ accounts?: Record<string, ClaustrumAccountGate>;
72
+ };
38
73
  export declare function isOAuthAccount(account: FallbackAccount): account is OAuthAccount;
39
74
  export declare function isApiKeyAccount(account: FallbackAccount): account is ApiKeyAccount;
40
75
  export declare function isValidApiBaseURL(value: string | undefined): boolean;
@@ -45,6 +80,8 @@ export type AccountOperationError = {
45
80
  retryCount?: number;
46
81
  accountIdentity?: string;
47
82
  tokenHash?: string;
83
+ /** Fingerprint of the refresh token that produced this error. */
84
+ refreshTokenFingerprint?: string;
48
85
  /**
49
86
  * HTTP status of the underlying refresh/quota failure, when known. Lets
50
87
  * consumers distinguish a permanently-dead token (400 invalid_grant →
@@ -92,6 +129,7 @@ export type OAuthAccountProfile = {
92
129
  checkedAt: number;
93
130
  /** Stable account identity; tokenFingerprint remains loadable for legacy state. */
94
131
  accountIdentity?: string;
132
+ providerAccountUuid?: ProviderAccountUuid;
95
133
  tokenFingerprint?: string;
96
134
  };
97
135
  export type OAuthQuotaSnapshot = Partial<Record<QuotaWindowName, AccountQuotaWindow>> & {
@@ -101,6 +139,7 @@ export type OAuthQuotaSnapshot = Partial<Record<QuotaWindowName, AccountQuotaWin
101
139
  extraUsage?: OAuthExtraUsageSnapshot;
102
140
  bindingWindow?: string;
103
141
  bindingWindowSource?: 'poll' | 'headers';
142
+ fieldSources?: QuotaFieldSources;
104
143
  fallbackAdvised?: boolean;
105
144
  source?: 'poll' | 'headers';
106
145
  checkedAt?: number;
@@ -152,6 +191,7 @@ export type AccountStorage = {
152
191
  intervalMinutes?: number;
153
192
  refreshBeforeExpiryMinutes?: number;
154
193
  mainLastRefreshError?: AccountOperationError;
194
+ mainRefreshErrorClearedAt?: number;
155
195
  mainRefreshLeaseId?: string;
156
196
  mainRefreshLeaseUntil?: number;
157
197
  mainRefreshLeaseTokenHash?: string;
@@ -187,6 +227,9 @@ export type AccountStorage = {
187
227
  claudeFast?: {
188
228
  enabled?: boolean;
189
229
  };
230
+ thinkingBinding?: {
231
+ prefixMismatchBehavior?: 'account-default' | 'error' | 'drop_block';
232
+ };
190
233
  /**
191
234
  * Zero out Anthropic OAuth model costs in the provider hook. Default: enabled
192
235
  * (OAuth usage is quota-based, not per-token billed, so costs show as $0).
@@ -216,6 +259,7 @@ export type AccountStorage = {
216
259
  fallbackToDirect?: boolean;
217
260
  transport?: 'http' | 'websocket';
218
261
  };
262
+ claustrum?: ClaustrumConfig;
219
263
  killswitch?: KillswitchConfig;
220
264
  accounts: FallbackAccount[];
221
265
  };
@@ -225,10 +269,11 @@ export type AccountStorage = {
225
269
  * (to display the provider's real model costs).
226
270
  */
227
271
  export declare function isCostZeroingEnabled(storage: Pick<AccountStorage, 'costZeroing'>): boolean;
228
- export type AccountRuntimeEntry = Partial<Pick<OAuthAccount, 'access' | 'authLineageId' | 'refresh' | 'expires' | 'lastUsed' | 'lastRefreshedAt' | 'lastRefreshError' | 'lastQuotaRefreshError' | 'quota' | 'profile' | 'prime'> & Pick<ApiKeyAccount, 'apiKey' | 'lastUsed'>>;
272
+ export type AccountRuntimeEntry = Partial<Pick<OAuthAccount, 'access' | 'authLineageId' | 'anthropicAccountUuid' | 'claustrumScopedCredentialId' | 'claustrumScopedState' | 'claustrumHandle' | 'refresh' | 'expires' | 'lastUsed' | 'lastRefreshedAt' | 'lastRefreshError' | 'lastQuotaRefreshError' | 'quota' | 'profile' | 'prime'> & Pick<ApiKeyAccount, 'apiKey' | 'lastUsed'>>;
229
273
  export type AccountRuntimeState = {
230
274
  version: 1;
231
275
  main?: {
276
+ scopedAccountIdentity?: string;
232
277
  profile?: OAuthAccountProfile;
233
278
  profileToken?: string;
234
279
  quota?: OAuthQuotaSnapshot;
@@ -238,6 +283,7 @@ export type AccountRuntimeState = {
238
283
  quotaErrorGeneration?: number;
239
284
  quotaErrorClearedAt?: number;
240
285
  lastRefreshError?: AccountOperationError;
286
+ refreshErrorClearedAt?: number;
241
287
  refreshLeaseId?: string;
242
288
  refreshLeaseUntil?: number;
243
289
  refreshLeaseTokenHash?: string;
@@ -253,12 +299,20 @@ export type AccountStateSaveScope = {
253
299
  mainRefresh?: boolean;
254
300
  mainPrime?: boolean;
255
301
  accounts?: true | string[];
302
+ setClaustrumHandleAccountIds?: readonly string[];
256
303
  };
257
304
  export type AccountManagerOptions = {
258
305
  now?: () => number;
259
306
  fetchImpl?: typeof fetch;
260
307
  configPath?: string;
261
308
  quotaManager?: import('./quota-manager.ts').QuotaManager;
309
+ isFallbackAccountVaultServed?: (accountId: string, storage: AccountStorage) => boolean;
310
+ isFallbackAccountVaultEnabled?: (accountId: string, storage: AccountStorage) => boolean;
311
+ resolveFallbackAccessToken?: (account: OAuthAccount, storage: AccountStorage) => {
312
+ token: string;
313
+ source: 'vault' | 'sidecar';
314
+ } | undefined;
315
+ onBackgroundRefresh?: (initial?: boolean) => Promise<void> | void;
262
316
  onFallbackStorageChanged?: () => void;
263
317
  setIntervalImpl?: typeof globalThis.setInterval;
264
318
  clearIntervalImpl?: typeof globalThis.clearInterval;
@@ -267,21 +321,45 @@ export type AccountRefreshError = {
267
321
  accountId: string;
268
322
  message: string;
269
323
  };
324
+ export declare const FALLBACK_BACKGROUND_TICK_MS = 60000;
270
325
  export declare function getAccountStoragePath(): string;
271
326
  export declare function getAccountStatePath(configPath?: string): string;
272
327
  export declare function createEmptyStorage(): AccountStorage;
273
328
  export declare function mergeMainQuotaErrorClearedAt(existing: number | undefined, incoming: number | undefined): number | undefined;
329
+ export declare function mergeMainRefreshErrorClearedAt(existing: number | undefined, incoming: number | undefined): number | undefined;
274
330
  export declare function loadAccounts(path?: string): Promise<AccountStorage | null>;
275
331
  /** Returns the latest timestamp carried by any quota snapshot window. */
276
332
  export declare function quotaSnapshotCheckedAt(quota: OAuthQuotaSnapshot | undefined): number;
333
+ export declare function quotaFieldSource(snapshot: OAuthQuotaSnapshot | undefined, field: QuotaFieldName): QuotaFieldSource | undefined;
277
334
  export declare function mergeHeaderQuotaForPersistence(existing: OAuthQuotaSnapshot | undefined, incoming: OAuthQuotaSnapshot): OAuthQuotaSnapshot;
335
+ export declare function getClaustrumMode(storage: AccountStorage | null): ClaustrumMode;
336
+ export declare function isOAuthAccountVaultOwned(storage: AccountStorage | null, account: FallbackAccount, binding?: CustodyHandleResolution | undefined): boolean;
337
+ export declare function setClaustrumModePersistent(mode: ClaustrumMode, path?: string): Promise<'changed' | 'unchanged'>;
338
+ export declare function clearClaustrumHandlePersistent(input: {
339
+ id: string;
340
+ path?: string;
341
+ }): Promise<'updated' | 'missing' | 'ineligible'>;
278
342
  export interface SaveAccountsOptions {
279
343
  /** Account ids intentionally removed by this mutation. */
280
344
  removedAccountIds?: readonly string[];
281
345
  /** Preserve disk order when a stale snapshot is missing newer accounts. */
282
346
  preserveExistingAccountOrder?: boolean;
347
+ setClaustrumHandleAccountIds?: readonly string[];
283
348
  }
284
349
  export declare function saveAccounts(storage: AccountStorage, path?: string, options?: SaveAccountsOptions): Promise<void>;
350
+ /** Read-modify-write account configuration under the existing config/state lock order.
351
+ * The callback is synchronous: network discovery must happen under its own outer
352
+ * lease, never while holding the config lock. Do not call another persistence API
353
+ * from the callback.
354
+ */
355
+ export declare function mutateAccountsPersistent<T>(path: string, mutate: (storage: AccountStorage) => {
356
+ storage: AccountStorage;
357
+ result: T;
358
+ options?: SaveAccountsOptions;
359
+ save?: boolean;
360
+ }, options?: {
361
+ assertAuthority?: () => Promise<void>;
362
+ }): Promise<T>;
285
363
  export declare function getOrCreateMainAccountId(path?: string, createId?: () => string): Promise<string>;
286
364
  export declare function saveAccountState(storage: AccountStorage, path?: string, scope?: AccountStateSaveScope): Promise<void>;
287
365
  export declare function saveOAuthProfileState(input: {
@@ -289,6 +367,7 @@ export declare function saveOAuthProfileState(input: {
289
367
  profile: OAuthAccountProfile | undefined;
290
368
  accountIdentity?: string;
291
369
  }, path?: string): Promise<boolean>;
370
+ export declare function clearClaustrumRefreshErrorPersistent(accountId: string, handle: string, path?: string): Promise<boolean>;
292
371
  export declare function acquireRefreshFileLock(options: {
293
372
  name: string;
294
373
  ttlMs: number;
@@ -299,6 +378,7 @@ export declare function acquireRefreshFileLock(options: {
299
378
  onStep?: (step: 'stale-marker-stat' | 'stale-marker-claimed' | 'stale-lock-confirmed' | 'eviction-marker-acquired') => void | Promise<void>;
300
379
  }): Promise<{
301
380
  release: () => Promise<void>;
381
+ assertOwned: () => Promise<void>;
302
382
  } | null>;
303
383
  export declare function isCache1hPersistentlyEnabled(storage: AccountStorage | null): boolean;
304
384
  export declare function getCache1hPersistentMode(storage: AccountStorage | null): Cache1hMode;
@@ -331,12 +411,14 @@ export declare function getQuotaMinimumRemainingThresholds(storage: AccountStora
331
411
  five_hour: number;
332
412
  seven_day: number;
333
413
  };
414
+ export declare function getRefreshBeforeExpiryMs(storage: AccountStorage | null): number;
334
415
  export declare function getRefreshIntervalMs(storage: AccountStorage | null): number;
335
416
  export declare function hashRefreshToken(refreshToken: string): string;
336
417
  export declare function buildRefreshOperationError(input: {
337
418
  error: unknown;
338
419
  now: number;
339
420
  accountIdentity: string | undefined;
421
+ refreshTokenFingerprint?: string;
340
422
  previous?: AccountOperationError;
341
423
  }): AccountOperationError;
342
424
  /**
@@ -355,7 +437,7 @@ export declare function buildRefreshOperationError(input: {
355
437
  * the error with the explicit field.
356
438
  */
357
439
  export declare function isPermanentRefreshError(error: AccountOperationError | undefined): boolean;
358
- export declare function refreshBackoffActive(error: AccountOperationError | undefined, accountIdentity: string | undefined, now: number): boolean;
440
+ export declare function refreshBackoffActive(error: AccountOperationError | undefined, accountIdentity: string | undefined, now: number, currentRefreshTokenFingerprint: string | undefined): boolean;
359
441
  export declare function formatRefreshBackoffMessage(error: AccountOperationError, now: number): string;
360
442
  export declare function getFallbackReauthLabels(storage: AccountStorage | null | undefined): string[];
361
443
  export declare function isQuotaPolicyAuthError(error: unknown): boolean;
@@ -425,6 +507,13 @@ export declare function fetchOAuthQuotaSnapshot(input: {
425
507
  now?: () => number;
426
508
  }): Promise<OAuthQuotaSnapshot>;
427
509
  export declare function upsertAccount(storage: AccountStorage, account: FallbackAccount): void;
510
+ export declare function persistFallbackQuotaHeaderPersistent(input: {
511
+ accountId: string;
512
+ authLineageId?: string;
513
+ quota: OAuthQuotaSnapshot;
514
+ anthropicAccountUuid?: ProviderAccountUuid;
515
+ }, path?: string): Promise<boolean>;
516
+ export declare function fallbackAccountUuidForLineage(account: OAuthAccount | undefined, authLineageId?: string): string | null;
428
517
  export declare function removeAccount(storage: AccountStorage, id: string): boolean;
429
518
  export declare function reorderAccounts(storage: AccountStorage, orderedIds: string[]): void;
430
519
  export declare function setAccountEnabled(storage: AccountStorage, id: string, enabled: boolean): boolean;
@@ -433,9 +522,14 @@ export declare class FallbackAccountManager {
433
522
  private readonly fetchImpl;
434
523
  private readonly configPath;
435
524
  private readonly refreshPromises;
525
+ private readonly custodyVerificationAccounts;
436
526
  private refreshTimer;
437
527
  private quotaTimer;
438
528
  readonly quotaManager: import('./quota-manager.ts').QuotaManager | null;
529
+ private readonly isFallbackAccountVaultServed;
530
+ private readonly isFallbackAccountVaultEnabled;
531
+ private readonly resolveFallbackAccessToken;
532
+ private readonly onBackgroundRefresh;
439
533
  private readonly onFallbackStorageChanged;
440
534
  private readonly setIntervalImpl;
441
535
  private readonly clearIntervalImpl;
@@ -447,8 +541,9 @@ export declare class FallbackAccountManager {
447
541
  private seedFallbackQuota;
448
542
  load(): Promise<AccountStorage | null>;
449
543
  save(storage: AccountStorage, accountIds?: string[]): Promise<void>;
450
- startBackgroundRefresh(): void;
544
+ startBackgroundRefresh(): Promise<void>;
451
545
  stopBackgroundRefresh(): void;
546
+ withAccountRefreshLock<T>(accountId: string, fn: () => Promise<T>): Promise<T>;
452
547
  getUsableFallbackAccounts(existingStorage?: AccountStorage | null, options?: {
453
548
  modelId?: string;
454
549
  }): Promise<OAuthAccount[]>;
@@ -473,11 +568,13 @@ export declare class FallbackAccountManager {
473
568
  }>;
474
569
  refreshAccount(account: OAuthAccount, storage: AccountStorage, options?: {
475
570
  force?: boolean;
571
+ persistError?: boolean;
476
572
  }): Promise<OAuthAccount>;
477
573
  private waitForConcurrentFallbackRefresh;
478
574
  private refreshAccountNow;
479
575
  refreshAccountQuota(account: OAuthAccount, storage: AccountStorage): Promise<{
480
576
  account: OAuthAccount;
481
577
  fetched: boolean;
578
+ changed: boolean;
482
579
  }>;
483
580
  }