@cortexkit/anthropic-auth-core 1.19.1 → 1.21.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, 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.
4
4
 
5
5
  User-facing packages:
6
6
 
@@ -13,6 +13,7 @@ export type AccountBase = {
13
13
  };
14
14
  export type OAuthAccount = AccountBase & {
15
15
  type: 'oauth';
16
+ authLineageId?: string;
16
17
  access?: string;
17
18
  refresh: string;
18
19
  expires?: number;
@@ -21,6 +22,11 @@ export type OAuthAccount = AccountBase & {
21
22
  lastQuotaRefreshError?: AccountOperationError;
22
23
  quota?: OAuthQuotaSnapshot;
23
24
  profile?: OAuthAccountProfile;
25
+ /**
26
+ * Per-fallback cumulative prime counters. Lives in the runtime-state file
27
+ * (scoped under `accounts[id].prime`) and never in `anthropic-auth.json`.
28
+ */
29
+ prime?: PrimeUsageCounters;
24
30
  };
25
31
  export type ApiKeyAccount = AccountBase & {
26
32
  type: 'api';
@@ -37,6 +43,7 @@ export type AccountOperationError = {
37
43
  checkedAt: number;
38
44
  nextRetryAt?: number;
39
45
  retryCount?: number;
46
+ accountIdentity?: string;
40
47
  tokenHash?: string;
41
48
  /**
42
49
  * HTTP status of the underlying refresh/quota failure, when known. Lets
@@ -83,9 +90,13 @@ export type OAuthAccountProfile = {
83
90
  tier: string;
84
91
  orgType: string;
85
92
  checkedAt: number;
93
+ /** Stable account identity; tokenFingerprint remains loadable for legacy state. */
94
+ accountIdentity?: string;
86
95
  tokenFingerprint?: string;
87
96
  };
88
97
  export type OAuthQuotaSnapshot = Partial<Record<QuotaWindowName, AccountQuotaWindow>> & {
98
+ /** Stable main/fallback account identity; access tokens are fetch credentials only. */
99
+ accountIdentity?: string;
89
100
  scoped?: AccountScopedQuotaWindow[];
90
101
  extraUsage?: OAuthExtraUsageSnapshot;
91
102
  bindingWindow?: string;
@@ -94,6 +105,27 @@ export type OAuthQuotaSnapshot = Partial<Record<QuotaWindowName, AccountQuotaWin
94
105
  source?: 'poll' | 'headers';
95
106
  checkedAt?: number;
96
107
  };
108
+ export type PrimeUsageCounters = {
109
+ count: number;
110
+ inputTokens: number;
111
+ outputTokens: number;
112
+ since: number;
113
+ };
114
+ export type PrimeUsageDelta = {
115
+ inputTokens?: number;
116
+ outputTokens?: number;
117
+ };
118
+ export type PrimeRuntimeState = {
119
+ enabled?: boolean;
120
+ mainAuthLineageId?: string;
121
+ mainAuthLineageRefreshTokenFingerprint?: string;
122
+ /**
123
+ * Main account prime counters. Persisted only on the main side of the
124
+ * runtime-state file — `configFromStorage()` never writes them to the config
125
+ * file so they cannot leak into `anthropic-auth.json`.
126
+ */
127
+ main?: PrimeUsageCounters;
128
+ };
97
129
  export type RoutingMode = 'main-first' | 'fallback-first' | 'sticky-balanced';
98
130
  export type KillswitchThresholds = Partial<Record<QuotaWindowName | '5h' | '1w' | 'scoped', number>>;
99
131
  export type KillswitchConfig = {
@@ -105,6 +137,7 @@ export type KillswitchConfig = {
105
137
  };
106
138
  export type AccountStorage = {
107
139
  version: 1;
140
+ mainAccountId?: string;
108
141
  main?: {
109
142
  type: 'opencode';
110
143
  provider: 'anthropic';
@@ -135,6 +168,11 @@ export type AccountStorage = {
135
168
  mainQuotaCheckedAt?: number;
136
169
  mainQuotaToken?: string;
137
170
  mainLastQuotaApiError?: AccountOperationError;
171
+ mainQuotaErrorGeneration?: number;
172
+ mainQuotaErrorClearedAt?: number;
173
+ };
174
+ quotaHeaderFeed?: {
175
+ enabled?: boolean;
138
176
  };
139
177
  claudeCache?: {
140
178
  enabled?: boolean;
@@ -164,6 +202,13 @@ export type AccountStorage = {
164
202
  endHour?: number;
165
203
  subagents?: boolean;
166
204
  };
205
+ /**
206
+ * Opt-in flag and runtime metadata for `/claude-prime`. The `enabled` flag
207
+ * belongs on the config side; counters and main lineage bindings live in the
208
+ * state file and must never appear in `anthropic-auth.json`. See
209
+ * `configFromStorage()` for the write-side filter.
210
+ */
211
+ prime?: PrimeRuntimeState;
167
212
  relay?: {
168
213
  enabled?: boolean;
169
214
  url?: string;
@@ -180,7 +225,7 @@ export type AccountStorage = {
180
225
  * (to display the provider's real model costs).
181
226
  */
182
227
  export declare function isCostZeroingEnabled(storage: Pick<AccountStorage, 'costZeroing'>): boolean;
183
- export type AccountRuntimeEntry = Partial<Pick<OAuthAccount, 'access' | 'refresh' | 'expires' | 'lastUsed' | 'lastRefreshedAt' | 'lastRefreshError' | 'lastQuotaRefreshError' | 'quota' | 'profile'> & Pick<ApiKeyAccount, 'apiKey' | 'lastUsed'>>;
228
+ export type AccountRuntimeEntry = Partial<Pick<OAuthAccount, 'access' | 'authLineageId' | 'refresh' | 'expires' | 'lastUsed' | 'lastRefreshedAt' | 'lastRefreshError' | 'lastQuotaRefreshError' | 'quota' | 'profile' | 'prime'> & Pick<ApiKeyAccount, 'apiKey' | 'lastUsed'>>;
184
229
  export type AccountRuntimeState = {
185
230
  version: 1;
186
231
  main?: {
@@ -190,10 +235,15 @@ export type AccountRuntimeState = {
190
235
  quotaCheckedAt?: number;
191
236
  quotaToken?: string;
192
237
  lastQuotaApiError?: AccountOperationError;
238
+ quotaErrorGeneration?: number;
239
+ quotaErrorClearedAt?: number;
193
240
  lastRefreshError?: AccountOperationError;
194
241
  refreshLeaseId?: string;
195
242
  refreshLeaseUntil?: number;
196
243
  refreshLeaseTokenHash?: string;
244
+ prime?: PrimeUsageCounters;
245
+ primeAuthLineageId?: string;
246
+ primeAuthLineageRefreshTokenFingerprint?: string;
197
247
  };
198
248
  accounts?: Record<string, AccountRuntimeEntry>;
199
249
  };
@@ -201,6 +251,7 @@ export type AccountStateSaveScope = {
201
251
  mainProfile?: boolean;
202
252
  mainQuota?: boolean;
203
253
  mainRefresh?: boolean;
254
+ mainPrime?: boolean;
204
255
  accounts?: true | string[];
205
256
  };
206
257
  export type AccountManagerOptions = {
@@ -219,7 +270,11 @@ export type AccountRefreshError = {
219
270
  export declare function getAccountStoragePath(): string;
220
271
  export declare function getAccountStatePath(configPath?: string): string;
221
272
  export declare function createEmptyStorage(): AccountStorage;
273
+ export declare function mergeMainQuotaErrorClearedAt(existing: number | undefined, incoming: number | undefined): number | undefined;
222
274
  export declare function loadAccounts(path?: string): Promise<AccountStorage | null>;
275
+ /** Returns the latest timestamp carried by any quota snapshot window. */
276
+ export declare function quotaSnapshotCheckedAt(quota: OAuthQuotaSnapshot | undefined): number;
277
+ export declare function mergeHeaderQuotaForPersistence(existing: OAuthQuotaSnapshot | undefined, incoming: OAuthQuotaSnapshot): OAuthQuotaSnapshot;
223
278
  export interface SaveAccountsOptions {
224
279
  /** Account ids intentionally removed by this mutation. */
225
280
  removedAccountIds?: readonly string[];
@@ -227,11 +282,12 @@ export interface SaveAccountsOptions {
227
282
  preserveExistingAccountOrder?: boolean;
228
283
  }
229
284
  export declare function saveAccounts(storage: AccountStorage, path?: string, options?: SaveAccountsOptions): Promise<void>;
285
+ export declare function getOrCreateMainAccountId(path?: string, createId?: () => string): Promise<string>;
230
286
  export declare function saveAccountState(storage: AccountStorage, path?: string, scope?: AccountStateSaveScope): Promise<void>;
231
287
  export declare function saveOAuthProfileState(input: {
232
288
  accountId: 'main' | string;
233
289
  profile: OAuthAccountProfile | undefined;
234
- expectedTokenFingerprint: string;
290
+ accountIdentity?: string;
235
291
  }, path?: string): Promise<boolean>;
236
292
  export declare function acquireRefreshFileLock(options: {
237
293
  name: string;
@@ -257,6 +313,19 @@ export declare function setCacheKeepPersistentAlways(path?: string): Promise<Acc
257
313
  export declare function setCacheKeepPersistentEnabled(enabled: boolean, path?: string): Promise<AccountStorage>;
258
314
  export declare function isCacheKeepSubagentsEnabled(storage: AccountStorage | null): boolean;
259
315
  export declare function setCacheKeepSubagentsEnabled(enabled: boolean, path?: string): Promise<AccountStorage>;
316
+ export declare function isPrimePersistentlyEnabled(storage: AccountStorage | null): boolean;
317
+ export declare function setPrimePersistentEnabled(enabled: boolean, path?: string): Promise<AccountStorage>;
318
+ /** Return the stable prime marker identity for an OAuth account. */
319
+ export declare function getOrCreatePrimeAuthLineageId(accountId: 'main' | string, path?: string): Promise<string | undefined>;
320
+ /**
321
+ * Atomically increment an account's cumulative prime counters and persist via
322
+ * the scoped runtime-state path. The `main` account lives at state.main.prime;
323
+ * every other account lives at state.accounts[id].prime. Config-side writes
324
+ * are intentionally NOT triggered so prime counters cannot leak into
325
+ * `anthropic-auth.json`. Callers should not depend on this function to mutate
326
+ * the caller's storage object.
327
+ */
328
+ export declare function incrementPrimeUsagePersistent(accountId: 'main' | string, usage: PrimeUsageDelta, path?: string, now?: number): Promise<PrimeUsageCounters>;
260
329
  export declare function shouldFallbackStatus(status: number, storage: AccountStorage | null): boolean;
261
330
  export declare function getQuotaMinimumRemainingThresholds(storage: AccountStorage | null): {
262
331
  five_hour: number;
@@ -267,7 +336,7 @@ export declare function hashRefreshToken(refreshToken: string): string;
267
336
  export declare function buildRefreshOperationError(input: {
268
337
  error: unknown;
269
338
  now: number;
270
- refreshToken: string;
339
+ accountIdentity: string | undefined;
271
340
  previous?: AccountOperationError;
272
341
  }): AccountOperationError;
273
342
  /**
@@ -286,12 +355,14 @@ export declare function buildRefreshOperationError(input: {
286
355
  * the error with the explicit field.
287
356
  */
288
357
  export declare function isPermanentRefreshError(error: AccountOperationError | undefined): boolean;
289
- export declare function refreshBackoffActive(error: AccountOperationError | undefined, refreshToken: string | undefined, now: number): boolean;
358
+ export declare function refreshBackoffActive(error: AccountOperationError | undefined, accountIdentity: string | undefined, now: number): boolean;
290
359
  export declare function formatRefreshBackoffMessage(error: AccountOperationError, now: number): string;
360
+ export declare function getFallbackReauthLabels(storage: AccountStorage | null | undefined): string[];
291
361
  export declare function isQuotaPolicyAuthError(error: unknown): boolean;
292
362
  export declare function buildQuotaOperationError(input: {
293
363
  error: unknown;
294
364
  now: number;
365
+ accountIdentity?: string;
295
366
  previous?: AccountOperationError;
296
367
  }): AccountOperationError;
297
368
  export declare function quotaBackoffActive(error: AccountOperationError | undefined, now: number): boolean;
@@ -303,6 +374,7 @@ export declare function getPersistedMainQuota(storage: AccountStorage | null): {
303
374
  quota: OAuthQuotaSnapshot;
304
375
  checkedAt: number;
305
376
  tokenFingerprint?: string;
377
+ accountIdentity?: string;
306
378
  } | null;
307
379
  /**
308
380
  * How often (in requests) to force a quota refresh, independent of the timer.
@@ -313,6 +385,7 @@ export declare function getScopedQuotaWindowForModel(quota: OAuthQuotaSnapshot |
313
385
  export declare function quotaSnapshotModelScopeIsExhausted(quota: OAuthQuotaSnapshot | undefined, model: unknown): boolean;
314
386
  export declare function quotaSnapshotPassesModelScope(quota: OAuthQuotaSnapshot | undefined, model: unknown): boolean;
315
387
  export declare function quotaSnapshotPassesPolicy(quota: OAuthQuotaSnapshot | undefined, storage: AccountStorage | null): boolean;
388
+ export declare function quotaSnapshotHasStandardWindows(quota: OAuthQuotaSnapshot | undefined): quota is OAuthQuotaSnapshot;
316
389
  export declare const DEFAULT_KILLSWITCH_THRESHOLDS: Record<QuotaWindowName | 'scoped', number>;
317
390
  export declare function normalizeKillswitchThresholds(thresholds: KillswitchThresholds | undefined): Record<QuotaWindowName | 'scoped', number>;
318
391
  export declare function isKillswitchEnabled(storage: AccountStorage | null): boolean;
@@ -403,5 +476,8 @@ export declare class FallbackAccountManager {
403
476
  }): Promise<OAuthAccount>;
404
477
  private waitForConcurrentFallbackRefresh;
405
478
  private refreshAccountNow;
406
- refreshAccountQuota(account: OAuthAccount, storage: AccountStorage): Promise<OAuthAccount>;
479
+ refreshAccountQuota(account: OAuthAccount, storage: AccountStorage): Promise<{
480
+ account: OAuthAccount;
481
+ fetched: boolean;
482
+ }>;
407
483
  }