@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 +1 -1
- package/dist/accounts.d.ts +81 -5
- package/dist/accounts.js +531 -81
- package/dist/auth.d.ts +2 -0
- package/dist/auth.js +3 -2
- package/dist/cache1h.d.ts +1 -1
- package/dist/cache1h.js +1 -1
- package/dist/cachekeep.d.ts +20 -2
- package/dist/cachekeep.js +134 -28
- package/dist/cch.d.ts +1 -0
- package/dist/cch.js +6 -1
- package/dist/claude-code.d.ts +5 -2
- package/dist/claude-code.js +127 -24
- package/dist/commands/account.js +1 -1
- package/dist/constants.d.ts +3 -3
- package/dist/dump.d.ts +13 -1
- package/dist/dump.js +171 -22
- package/dist/index.d.ts +3 -0
- package/dist/index.js +27 -24
- package/dist/killswitch.js +1 -1
- package/dist/models.d.ts +22 -6
- package/dist/models.js +16 -0
- package/dist/oauth-profile.d.ts +2 -1
- package/dist/oauth-profile.js +10 -4
- package/dist/prime.d.ts +219 -0
- package/dist/prime.js +823 -0
- package/dist/quota-header-feed.d.ts +40 -0
- package/dist/quota-header-feed.js +248 -0
- package/dist/quota-headers.js +6 -4
- package/dist/quota-manager.d.ts +41 -25
- package/dist/quota-manager.js +391 -151
- package/dist/quotas.d.ts +4 -4
- package/dist/quotas.js +2 -2
- package/dist/relay.d.ts +2 -0
- package/dist/relay.js +10 -4
- package/dist/routing.d.ts +1 -1
- package/dist/routing.js +1 -1
- package/dist/start.d.ts +13 -0
- package/dist/start.js +29 -0
- package/dist/sticky-routing.d.ts +15 -2
- package/dist/sticky-routing.js +44 -17
- package/package.json +1 -1
package/dist/auth.d.ts
CHANGED
|
@@ -18,9 +18,11 @@ export type ClaudeOAuthRefreshResult = {
|
|
|
18
18
|
refresh: string;
|
|
19
19
|
expires: number;
|
|
20
20
|
expiresIn: number;
|
|
21
|
+
authLineageId?: string;
|
|
21
22
|
};
|
|
22
23
|
export declare function refreshClaudeOAuthToken(input: {
|
|
23
24
|
refreshToken: string;
|
|
25
|
+
authLineageId?: string;
|
|
24
26
|
fetchImpl?: typeof fetch;
|
|
25
27
|
now?: () => number;
|
|
26
28
|
maxRetries?: number;
|
package/dist/auth.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { AUTHORIZE_URLS, AXIOS_USER_AGENT, CLIENT_ID, CODE_CALLBACK_URL, OAUTH_SCOPES, REFRESH_SCOPE, TOKEN_URL, } from
|
|
2
|
-
import { generatePKCE } from
|
|
1
|
+
import { AUTHORIZE_URLS, AXIOS_USER_AGENT, CLIENT_ID, CODE_CALLBACK_URL, OAUTH_SCOPES, REFRESH_SCOPE, TOKEN_URL, } from './constants.js';
|
|
2
|
+
import { generatePKCE } from './pkce.js';
|
|
3
3
|
export function parseRetryAfterHeader(value) {
|
|
4
4
|
if (!value)
|
|
5
5
|
return undefined;
|
|
@@ -83,6 +83,7 @@ export async function refreshClaudeOAuthToken(input) {
|
|
|
83
83
|
refresh: json.refresh_token ?? input.refreshToken,
|
|
84
84
|
expires: refreshedAt + json.expires_in * 1000,
|
|
85
85
|
expiresIn: json.expires_in,
|
|
86
|
+
authLineageId: input.authLineageId,
|
|
86
87
|
};
|
|
87
88
|
}
|
|
88
89
|
catch (error) {
|
package/dist/cache1h.d.ts
CHANGED
|
@@ -13,7 +13,7 @@ export type Cache1hCommandAction = {
|
|
|
13
13
|
type: 'usage';
|
|
14
14
|
};
|
|
15
15
|
export declare function isCache1hEnabled(): boolean;
|
|
16
|
-
export declare function getCache1hMode(): "
|
|
16
|
+
export declare function getCache1hMode(): "automatic" | "explicit" | "hybrid";
|
|
17
17
|
export declare function setCache1hEnabled(enabled: boolean): void;
|
|
18
18
|
export declare function setCache1hMode(mode: Cache1hMode): void;
|
|
19
19
|
export declare function setCache1hState(input: {
|
package/dist/cache1h.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { DEFAULT_CACHE_1H_MODE } from
|
|
1
|
+
import { DEFAULT_CACHE_1H_MODE } from './constants.js';
|
|
2
2
|
export const CACHE_1H_COMMAND_NAME = 'claude-cache';
|
|
3
3
|
const CACHE_1H_STATUS_TITLE = '## Claude Cache Status';
|
|
4
4
|
const CACHE_1H_ENABLED_TITLE = '## Claude Cache Enabled';
|
package/dist/cachekeep.d.ts
CHANGED
|
@@ -7,8 +7,10 @@ export declare const CACHE_KEEP_TICK_MS = 60000;
|
|
|
7
7
|
export declare const CACHE_KEEP_EXTENDED_TTL_BETA = "extended-cache-ttl-2025-04-11";
|
|
8
8
|
export declare const CACHE_KEEP_MAX_TARGETS = 32;
|
|
9
9
|
export declare const CACHE_KEEP_MAX_BODY_BYTES: number;
|
|
10
|
-
export declare const CACHE_KEEP_STALE_TARGET_MS: number;
|
|
11
10
|
export declare const CACHE_KEEP_PREWARM_TIMEOUT_MS = 30000;
|
|
11
|
+
export declare const CACHE_KEEP_RETRY_BASE_MS = 60000;
|
|
12
|
+
export declare const CACHE_KEEP_RETRY_MAX_MS: number;
|
|
13
|
+
export declare const CACHE_KEEP_RETRY_JITTER_MAX_MS = 30000;
|
|
12
14
|
export type CacheKeepWindow = {
|
|
13
15
|
startHour: number;
|
|
14
16
|
endHour: number;
|
|
@@ -70,8 +72,11 @@ export type CacheKeepTarget = {
|
|
|
70
72
|
headers: Record<string, string>;
|
|
71
73
|
bodyText: string;
|
|
72
74
|
cacheExpiresAt: number;
|
|
75
|
+
nextPrewarmAt: number;
|
|
76
|
+
consecutiveFailures: number;
|
|
73
77
|
dayKey: string;
|
|
74
78
|
oauthAccountId?: string;
|
|
79
|
+
isSubagent: boolean;
|
|
75
80
|
};
|
|
76
81
|
export type CacheKeepPrewarmResult = {
|
|
77
82
|
ok: true;
|
|
@@ -84,11 +89,13 @@ export type CacheKeepPrewarmResult = {
|
|
|
84
89
|
ok: false;
|
|
85
90
|
reason: string;
|
|
86
91
|
status?: number;
|
|
92
|
+
transient?: true;
|
|
87
93
|
};
|
|
88
94
|
export declare class CacheKeepManager {
|
|
89
95
|
private readonly options;
|
|
90
96
|
private readonly targets;
|
|
91
97
|
private timer;
|
|
98
|
+
private tickPromise;
|
|
92
99
|
constructor(options: {
|
|
93
100
|
loadStorage: () => Promise<AccountStorage | null>;
|
|
94
101
|
fetchImpl?: typeof fetch;
|
|
@@ -98,6 +105,14 @@ export declare class CacheKeepManager {
|
|
|
98
105
|
clearIntervalImpl?: typeof globalThis.clearInterval;
|
|
99
106
|
prepareHeaders?: (headers: Headers, target: CacheKeepTarget) => Promise<Headers> | Headers;
|
|
100
107
|
onTrackedSessionsChanged?: (sessions: readonly CacheKeepTrackedSession[]) => Promise<void> | void;
|
|
108
|
+
prepareBody?: (bodyText: string, target: CacheKeepTarget) => string | Promise<string>;
|
|
109
|
+
onResponse?: (input: {
|
|
110
|
+
target: CacheKeepTarget;
|
|
111
|
+
bodyText: string;
|
|
112
|
+
status: number;
|
|
113
|
+
data: unknown;
|
|
114
|
+
receivedAt: number;
|
|
115
|
+
}) => void | Promise<void>;
|
|
101
116
|
});
|
|
102
117
|
start(): void;
|
|
103
118
|
stop(): void;
|
|
@@ -122,12 +137,13 @@ export declare class CacheKeepManager {
|
|
|
122
137
|
storage: AccountStorage | null;
|
|
123
138
|
cacheMode: string;
|
|
124
139
|
oauthAccountId?: string;
|
|
140
|
+
isSubagent?: boolean;
|
|
125
141
|
}): {
|
|
126
142
|
tracked: boolean;
|
|
127
143
|
reason: string;
|
|
128
144
|
} | {
|
|
129
|
-
tracked: boolean;
|
|
130
145
|
reason?: undefined;
|
|
146
|
+
tracked: boolean;
|
|
131
147
|
};
|
|
132
148
|
prewarmNow(input: {
|
|
133
149
|
sessionId: string;
|
|
@@ -135,8 +151,10 @@ export declare class CacheKeepManager {
|
|
|
135
151
|
headers: Headers;
|
|
136
152
|
bodyText: string;
|
|
137
153
|
oauthAccountId?: string;
|
|
154
|
+
isSubagent?: boolean;
|
|
138
155
|
}): Promise<CacheKeepPrewarmResult>;
|
|
139
156
|
tick(): Promise<void>;
|
|
157
|
+
private runTick;
|
|
140
158
|
private sendPrewarm;
|
|
141
159
|
private prewarm;
|
|
142
160
|
}
|
package/dist/cachekeep.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { signRequestBody } from
|
|
2
|
-
import { orderClaudeCodeBody } from
|
|
3
|
-
import {
|
|
1
|
+
import { signRequestBody } from './cch.js';
|
|
2
|
+
import { orderClaudeCodeBody } from './claude-code.js';
|
|
3
|
+
import { dumpDirectRequest, dumpResponseArtifact } from './dump.js';
|
|
4
|
+
import { logger } from './logger.js';
|
|
4
5
|
export const CLAUDE_CACHE_KEEP_COMMAND_NAME = 'claude-cachekeep';
|
|
5
6
|
export const CACHE_KEEP_TTL_MS = 60 * 60_000;
|
|
6
7
|
export const CACHE_KEEP_PREWARM_LEAD_MS = 5 * 60_000;
|
|
@@ -8,8 +9,10 @@ export const CACHE_KEEP_TICK_MS = 60_000;
|
|
|
8
9
|
export const CACHE_KEEP_EXTENDED_TTL_BETA = 'extended-cache-ttl-2025-04-11';
|
|
9
10
|
export const CACHE_KEEP_MAX_TARGETS = 32;
|
|
10
11
|
export const CACHE_KEEP_MAX_BODY_BYTES = 16 * 1024 * 1024;
|
|
11
|
-
export const CACHE_KEEP_STALE_TARGET_MS = 2 * CACHE_KEEP_TTL_MS;
|
|
12
12
|
export const CACHE_KEEP_PREWARM_TIMEOUT_MS = 30_000;
|
|
13
|
+
export const CACHE_KEEP_RETRY_BASE_MS = 60_000;
|
|
14
|
+
export const CACHE_KEEP_RETRY_MAX_MS = 15 * 60_000;
|
|
15
|
+
export const CACHE_KEEP_RETRY_JITTER_MAX_MS = 30_000;
|
|
13
16
|
const STATUS_TITLE = '## Claude Cache Keep Status';
|
|
14
17
|
const ENABLED_TITLE = '## Claude Cache Keep Enabled';
|
|
15
18
|
const DISABLED_TITLE = '## Claude Cache Keep Disabled';
|
|
@@ -228,10 +231,22 @@ export async function buildCacheKeepPrewarmBody(bodyText) {
|
|
|
228
231
|
const signedBodyText = await signRequestBody(JSON.stringify(orderClaudeCodeBody(warm)));
|
|
229
232
|
return { ok: true, bodyText: signedBodyText };
|
|
230
233
|
}
|
|
234
|
+
function cacheKeepRetryDelayMs(targetId, failureCount) {
|
|
235
|
+
const exponential = Math.min(CACHE_KEEP_RETRY_MAX_MS, CACHE_KEEP_RETRY_BASE_MS * 2 ** Math.min(Math.max(failureCount - 1, 0), 8));
|
|
236
|
+
let hash = 2_166_136_261;
|
|
237
|
+
for (const character of `${targetId}:${failureCount}`) {
|
|
238
|
+
hash ^= character.charCodeAt(0);
|
|
239
|
+
hash = Math.imul(hash, 16_777_619);
|
|
240
|
+
}
|
|
241
|
+
const jitter = (hash >>> 0) %
|
|
242
|
+
(Math.min(CACHE_KEEP_RETRY_JITTER_MAX_MS, exponential / 4) + 1);
|
|
243
|
+
return exponential + jitter;
|
|
244
|
+
}
|
|
231
245
|
export class CacheKeepManager {
|
|
232
246
|
options;
|
|
233
247
|
targets = new Map();
|
|
234
248
|
timer = null;
|
|
249
|
+
tickPromise = null;
|
|
235
250
|
constructor(options) {
|
|
236
251
|
this.options = options;
|
|
237
252
|
}
|
|
@@ -261,7 +276,7 @@ export class CacheKeepManager {
|
|
|
261
276
|
const today = always ? 'always' : localWindowKey(window, new Date(now));
|
|
262
277
|
const targets = [...this.targets.values()].filter((target) => target.dayKey === today);
|
|
263
278
|
const nextPrewarmAt = targets.length
|
|
264
|
-
? Math.min(...targets.map((target) => target.
|
|
279
|
+
? Math.min(...targets.map((target) => target.nextPrewarmAt))
|
|
265
280
|
: undefined;
|
|
266
281
|
return { trackedSessions: targets.length, nextPrewarmAt };
|
|
267
282
|
}
|
|
@@ -270,7 +285,7 @@ export class CacheKeepManager {
|
|
|
270
285
|
.map((target) => ({
|
|
271
286
|
id: target.id,
|
|
272
287
|
cacheExpiresAt: target.cacheExpiresAt,
|
|
273
|
-
nextPrewarmAt: target.
|
|
288
|
+
nextPrewarmAt: target.nextPrewarmAt,
|
|
274
289
|
}))
|
|
275
290
|
.sort((left, right) => left.id.localeCompare(right.id));
|
|
276
291
|
}
|
|
@@ -312,9 +327,8 @@ export class CacheKeepManager {
|
|
|
312
327
|
this.targets.delete(id);
|
|
313
328
|
continue;
|
|
314
329
|
}
|
|
315
|
-
if (now
|
|
330
|
+
if (now >= target.cacheExpiresAt)
|
|
316
331
|
this.targets.delete(id);
|
|
317
|
-
}
|
|
318
332
|
}
|
|
319
333
|
while (this.targets.size > CACHE_KEEP_MAX_TARGETS)
|
|
320
334
|
this.evictOldestTarget();
|
|
@@ -356,8 +370,11 @@ export class CacheKeepManager {
|
|
|
356
370
|
headers,
|
|
357
371
|
bodyText: input.bodyText,
|
|
358
372
|
cacheExpiresAt: now + CACHE_KEEP_TTL_MS,
|
|
373
|
+
nextPrewarmAt: now + CACHE_KEEP_TTL_MS - CACHE_KEEP_PREWARM_LEAD_MS,
|
|
374
|
+
consecutiveFailures: 0,
|
|
359
375
|
dayKey: today,
|
|
360
376
|
oauthAccountId: input.oauthAccountId,
|
|
377
|
+
isSubagent: input.isSubagent ?? false,
|
|
361
378
|
});
|
|
362
379
|
this.pruneTargets(now, today);
|
|
363
380
|
this.publishTrackedSessions();
|
|
@@ -375,12 +392,26 @@ export class CacheKeepManager {
|
|
|
375
392
|
headers,
|
|
376
393
|
bodyText: input.bodyText,
|
|
377
394
|
cacheExpiresAt: this.options.now?.() ?? Date.now(),
|
|
395
|
+
nextPrewarmAt: this.options.now?.() ?? Date.now(),
|
|
396
|
+
consecutiveFailures: 0,
|
|
378
397
|
dayKey: '',
|
|
379
398
|
oauthAccountId: input.oauthAccountId,
|
|
399
|
+
isSubagent: input.isSubagent ?? false,
|
|
380
400
|
};
|
|
381
401
|
return this.sendPrewarm(target);
|
|
382
402
|
}
|
|
383
|
-
|
|
403
|
+
tick() {
|
|
404
|
+
if (this.tickPromise)
|
|
405
|
+
return this.tickPromise;
|
|
406
|
+
let run;
|
|
407
|
+
run = this.runTick().finally(() => {
|
|
408
|
+
if (this.tickPromise === run)
|
|
409
|
+
this.tickPromise = null;
|
|
410
|
+
});
|
|
411
|
+
this.tickPromise = run;
|
|
412
|
+
return run;
|
|
413
|
+
}
|
|
414
|
+
async runTick() {
|
|
384
415
|
const storage = await this.options.loadStorage();
|
|
385
416
|
const window = getCacheKeepWindow(storage);
|
|
386
417
|
const now = this.options.now?.() ?? Date.now();
|
|
@@ -404,49 +435,120 @@ export class CacheKeepManager {
|
|
|
404
435
|
return;
|
|
405
436
|
}
|
|
406
437
|
logger.debug('cachekeep', 'fired', { targets: this.targets.size });
|
|
407
|
-
const dueAt = now + CACHE_KEEP_PREWARM_LEAD_MS;
|
|
408
438
|
for (const target of this.targets.values()) {
|
|
409
|
-
if (target.
|
|
439
|
+
if (target.nextPrewarmAt > now)
|
|
410
440
|
continue;
|
|
411
|
-
|
|
441
|
+
try {
|
|
442
|
+
await this.prewarm(target, now);
|
|
443
|
+
}
|
|
444
|
+
catch (error) {
|
|
445
|
+
logger.warn('cachekeep', 'prewarm failed', {
|
|
446
|
+
session: target.id,
|
|
447
|
+
reason: error instanceof Error ? error.message : String(error),
|
|
448
|
+
});
|
|
449
|
+
target.consecutiveFailures += 1;
|
|
450
|
+
target.nextPrewarmAt =
|
|
451
|
+
now + cacheKeepRetryDelayMs(target.id, target.consecutiveFailures);
|
|
452
|
+
}
|
|
412
453
|
}
|
|
413
454
|
this.publishTrackedSessions();
|
|
414
455
|
}
|
|
415
456
|
async sendPrewarm(target) {
|
|
416
|
-
|
|
457
|
+
let bodyText = target.bodyText;
|
|
458
|
+
if (this.options.prepareBody) {
|
|
459
|
+
try {
|
|
460
|
+
bodyText = await this.options.prepareBody(bodyText, target);
|
|
461
|
+
}
|
|
462
|
+
catch (error) {
|
|
463
|
+
logger.warn('cachekeep', 'prepare body failed', {
|
|
464
|
+
session: target.id,
|
|
465
|
+
error: error instanceof Error ? error.message : String(error),
|
|
466
|
+
});
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
const preparedTarget = { ...target, bodyText };
|
|
470
|
+
const prewarm = await buildCacheKeepPrewarmBody(bodyText);
|
|
417
471
|
if (!prewarm.ok)
|
|
418
472
|
return prewarm;
|
|
419
473
|
const fetchImpl = this.options.fetchImpl ?? fetch;
|
|
420
|
-
const prewarmTarget = { ...
|
|
474
|
+
const prewarmTarget = { ...preparedTarget, bodyText: prewarm.bodyText };
|
|
421
475
|
const headers = this.options.prepareHeaders
|
|
422
476
|
? await this.options.prepareHeaders(new Headers(target.headers), prewarmTarget)
|
|
423
477
|
: new Headers(target.headers);
|
|
424
478
|
headers.delete('content-length');
|
|
425
479
|
headers.delete('transfer-encoding');
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
480
|
+
let response;
|
|
481
|
+
try {
|
|
482
|
+
response = await fetchImpl(target.url, {
|
|
483
|
+
method: 'POST',
|
|
484
|
+
headers,
|
|
485
|
+
body: prewarm.bodyText,
|
|
486
|
+
signal: AbortSignal.timeout(this.options.prewarmTimeoutMs ?? CACHE_KEEP_PREWARM_TIMEOUT_MS),
|
|
487
|
+
});
|
|
488
|
+
}
|
|
489
|
+
catch (error) {
|
|
490
|
+
return {
|
|
491
|
+
ok: false,
|
|
492
|
+
reason: error instanceof Error ? error.message : String(error),
|
|
493
|
+
transient: true,
|
|
494
|
+
};
|
|
495
|
+
}
|
|
496
|
+
const receivedAt = this.options.now?.() ?? Date.now();
|
|
497
|
+
const raw = await response.text().catch(() => '');
|
|
498
|
+
let data = null;
|
|
499
|
+
try {
|
|
500
|
+
data = raw ? JSON.parse(raw) : null;
|
|
501
|
+
}
|
|
502
|
+
catch { }
|
|
503
|
+
try {
|
|
504
|
+
await this.options.onResponse?.({
|
|
505
|
+
target,
|
|
506
|
+
bodyText: prewarm.bodyText,
|
|
507
|
+
status: response.status,
|
|
508
|
+
data,
|
|
509
|
+
receivedAt,
|
|
510
|
+
});
|
|
511
|
+
}
|
|
512
|
+
catch { }
|
|
513
|
+
try {
|
|
514
|
+
const dumpHandle = await dumpDirectRequest({
|
|
515
|
+
affinity: target.id,
|
|
516
|
+
route: 'cachekeep',
|
|
517
|
+
status: response.status,
|
|
518
|
+
bodyText: prewarm.bodyText,
|
|
519
|
+
url: target.url,
|
|
520
|
+
method: 'POST',
|
|
521
|
+
headers,
|
|
522
|
+
tag: 'cachekeep',
|
|
523
|
+
});
|
|
524
|
+
await dumpResponseArtifact(dumpHandle, {
|
|
525
|
+
status: response.status,
|
|
526
|
+
message: data,
|
|
527
|
+
});
|
|
528
|
+
}
|
|
529
|
+
catch (error) {
|
|
530
|
+
logger.debug('cachekeep', 'dump failed', {
|
|
531
|
+
session: target.id,
|
|
532
|
+
error: error instanceof Error ? error.message : String(error),
|
|
533
|
+
});
|
|
534
|
+
}
|
|
432
535
|
if (!response.ok) {
|
|
433
536
|
return {
|
|
434
537
|
ok: false,
|
|
435
|
-
reason:
|
|
436
|
-
.text()
|
|
437
|
-
.catch(() => '')
|
|
438
|
-
.then((body) => body || `HTTP ${response.status}`),
|
|
538
|
+
reason: raw || `HTTP ${response.status}`,
|
|
439
539
|
status: response.status,
|
|
440
540
|
};
|
|
441
541
|
}
|
|
442
|
-
const
|
|
443
|
-
|
|
542
|
+
const objectData = data && typeof data === 'object' && !Array.isArray(data)
|
|
543
|
+
? data
|
|
544
|
+
: null;
|
|
545
|
+
const usage = objectData?.usage;
|
|
444
546
|
return { ok: true, ...(usage && { usage }) };
|
|
445
547
|
}
|
|
446
548
|
async prewarm(target, now) {
|
|
447
549
|
const result = await this.sendPrewarm(target);
|
|
448
550
|
if (!result.ok) {
|
|
449
|
-
if (result.status == null) {
|
|
551
|
+
if (result.status == null && !result.transient) {
|
|
450
552
|
logger.debug('cachekeep', 'prewarm skipped', {
|
|
451
553
|
session: target.id,
|
|
452
554
|
reason: result.reason,
|
|
@@ -459,11 +561,15 @@ export class CacheKeepManager {
|
|
|
459
561
|
status: result.status,
|
|
460
562
|
reason: result.reason,
|
|
461
563
|
});
|
|
462
|
-
target.
|
|
564
|
+
target.consecutiveFailures += 1;
|
|
565
|
+
target.nextPrewarmAt =
|
|
566
|
+
now + cacheKeepRetryDelayMs(target.id, target.consecutiveFailures);
|
|
463
567
|
}
|
|
464
568
|
return;
|
|
465
569
|
}
|
|
466
570
|
target.cacheExpiresAt = now + CACHE_KEEP_TTL_MS;
|
|
571
|
+
target.nextPrewarmAt = target.cacheExpiresAt - CACHE_KEEP_PREWARM_LEAD_MS;
|
|
572
|
+
target.consecutiveFailures = 0;
|
|
467
573
|
logger.debug('cachekeep', 'prewarm succeeded', {
|
|
468
574
|
session: target.id,
|
|
469
575
|
...(result.usage && { usage: result.usage }),
|
package/dist/cch.d.ts
CHANGED
|
@@ -18,6 +18,7 @@ export declare function extractFirstUserMessageText(messages: Message[]): string
|
|
|
18
18
|
* masks to 20 bits, and writes that value into the billing-header placeholder.
|
|
19
19
|
*/
|
|
20
20
|
export declare function computeCCH(bodyBytes: Uint8Array): Promise<string>;
|
|
21
|
+
export declare function computeXxhash64Hex(value: string): Promise<string>;
|
|
21
22
|
export declare function resetBillingHeaderCCH(bodyString: string): string;
|
|
22
23
|
export declare function extractBillingHeaderCCH(bodyString: string): string | null;
|
|
23
24
|
export declare function signRequestBody(bodyString: string): Promise<string>;
|
package/dist/cch.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createHash } from 'node:crypto';
|
|
2
2
|
import xxhashInit from 'xxhash-wasm';
|
|
3
|
-
import { CLAUDE_CODE_BUILD_HASH, CLAUDE_CODE_VERSION } from
|
|
3
|
+
import { CLAUDE_CODE_BUILD_HASH, CLAUDE_CODE_VERSION } from './constants.js';
|
|
4
4
|
const CCH_SEED = 0x6e52736ac806831en;
|
|
5
5
|
const CCH_PLACEHOLDER = 'cch=00000;';
|
|
6
6
|
export const CCH_PATTERN = /\bcch=([0-9a-f]{5});/;
|
|
@@ -46,6 +46,11 @@ export async function computeCCH(bodyBytes) {
|
|
|
46
46
|
const hash = xxhash64Raw?.(bodyBytes, CCH_SEED) ?? 0n;
|
|
47
47
|
return (hash & 0xfffffn).toString(16).padStart(5, '0');
|
|
48
48
|
}
|
|
49
|
+
export async function computeXxhash64Hex(value) {
|
|
50
|
+
await ensureXxhash();
|
|
51
|
+
const hash = xxhash64Raw?.(new TextEncoder().encode(value), 0n) ?? 0n;
|
|
52
|
+
return hash.toString(16).padStart(16, '0').slice(0, 16);
|
|
53
|
+
}
|
|
49
54
|
export function resetBillingHeaderCCH(bodyString) {
|
|
50
55
|
return bodyString.replace(BILLING_HEADER_CCH_PATTERN, `$1${CCH_PLACEHOLDER}`);
|
|
51
56
|
}
|
package/dist/claude-code.d.ts
CHANGED
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
export type ClaudeCodeIdentity = {
|
|
2
2
|
deviceId: string;
|
|
3
|
+
accountIdentity?: string;
|
|
3
4
|
accountUuid?: string;
|
|
4
5
|
sessionId: string;
|
|
5
6
|
};
|
|
7
|
+
export declare function setBounded<K, V>(map: Map<K, V>, key: K, value: V, limit?: number): void;
|
|
6
8
|
export declare function getClaudeCodeIdentity(seed: string): ClaudeCodeIdentity;
|
|
7
|
-
export declare function
|
|
9
|
+
export declare function resetClaudeCodeIdentityCachesForTest(): void;
|
|
10
|
+
export declare function resolveClaudeCodeIdentity(accessToken: string, model: string | undefined, accountIdentity: string | undefined): Promise<ClaudeCodeIdentity>;
|
|
8
11
|
export declare function buildClaudeCodeMetadataUserId(identity: ClaudeCodeIdentity): string | null;
|
|
9
12
|
export declare function applyClaudeCodeMetadata(body: Record<string, unknown>, identity: ClaudeCodeIdentity): boolean;
|
|
10
|
-
export declare const CLAUDE_CODE_FULL_AGENT_BETAS: readonly [
|
|
13
|
+
export declare const CLAUDE_CODE_FULL_AGENT_BETAS: readonly ['oauth-2025-04-20', 'interleaved-thinking-2025-05-14', 'thinking-token-count-2026-05-13', 'context-management-2025-06-27', 'prompt-caching-scope-2026-01-05', 'claude-code-20250219', 'advisor-tool-2026-03-01', 'advanced-tool-use-2025-11-20', 'extended-cache-ttl-2025-04-11', 'cache-diagnosis-2026-04-07'];
|
|
11
14
|
export declare function selectClaudeCodeBetas(body?: Record<string, unknown> | null, extraBetas?: string[]): string;
|
|
12
15
|
export declare function applyClaudeCodeHeaders(headers: Headers, accessToken: string, options?: {
|
|
13
16
|
body?: Record<string, unknown> | null;
|
package/dist/claude-code.js
CHANGED
|
@@ -1,15 +1,25 @@
|
|
|
1
1
|
import { randomBytes, randomUUID } from 'node:crypto';
|
|
2
|
-
import { CLAUDE_CODE_BUILD_HASH, CLAUDE_CODE_ENTRYPOINT, CLAUDE_CODE_STAINLESS_PACKAGE_VERSION, CLAUDE_CODE_STAINLESS_RUNTIME_VERSION, CLAUDE_CODE_VERSION, FAST_MODE_BETA, USER_AGENT, } from
|
|
2
|
+
import { CLAUDE_CODE_BUILD_HASH, CLAUDE_CODE_ENTRYPOINT, CLAUDE_CODE_STAINLESS_PACKAGE_VERSION, CLAUDE_CODE_STAINLESS_RUNTIME_VERSION, CLAUDE_CODE_VERSION, FAST_MODE_BETA, USER_AGENT, } from './constants.js';
|
|
3
3
|
const IDENTITY_CACHE_LIMIT = 1_000;
|
|
4
4
|
const identityCache = new Map();
|
|
5
|
-
function setBounded(map, key, value) {
|
|
6
|
-
if (!map.has(key) && map.size >=
|
|
5
|
+
export function setBounded(map, key, value, limit = IDENTITY_CACHE_LIMIT) {
|
|
6
|
+
if (!map.has(key) && map.size >= limit) {
|
|
7
7
|
const oldest = map.keys().next().value;
|
|
8
8
|
if (oldest !== undefined)
|
|
9
9
|
map.delete(oldest);
|
|
10
10
|
}
|
|
11
11
|
map.set(key, value);
|
|
12
12
|
}
|
|
13
|
+
function clearCachedAccountUuid(key, identity) {
|
|
14
|
+
if (!identity.accountUuid)
|
|
15
|
+
return identity;
|
|
16
|
+
if (identityCache.get(key) !== identity) {
|
|
17
|
+
return { ...identity, accountUuid: undefined };
|
|
18
|
+
}
|
|
19
|
+
const cleared = { ...identity, accountUuid: undefined };
|
|
20
|
+
setBounded(identityCache, key, cleared);
|
|
21
|
+
return cleared;
|
|
22
|
+
}
|
|
13
23
|
export function getClaudeCodeIdentity(seed) {
|
|
14
24
|
const cacheKey = seed || 'anonymous';
|
|
15
25
|
const cached = identityCache.get(cacheKey);
|
|
@@ -26,6 +36,46 @@ const BOOTSTRAP_IDENTITY_CACHE_TTL_MS = 24 * 60 * 60_000;
|
|
|
26
36
|
const BOOTSTRAP_IDENTITY_NEGATIVE_TTL_MS = 5 * 60_000;
|
|
27
37
|
const bootstrapFetches = new Map();
|
|
28
38
|
const bootstrapResults = new Map();
|
|
39
|
+
export function resetClaudeCodeIdentityCachesForTest() {
|
|
40
|
+
identityCache.clear();
|
|
41
|
+
bootstrapFetches.clear();
|
|
42
|
+
bootstrapResults.clear();
|
|
43
|
+
}
|
|
44
|
+
function compatibilityCacheKey(accessToken) {
|
|
45
|
+
return `compat:${accessToken || 'anonymous'}`;
|
|
46
|
+
}
|
|
47
|
+
function explicitCacheKey(accountIdentity) {
|
|
48
|
+
return `identity:${accountIdentity}`;
|
|
49
|
+
}
|
|
50
|
+
function accountCacheKey(accountUuid, accountIdentity) {
|
|
51
|
+
return `account:${accountUuid}:${accountIdentity}`;
|
|
52
|
+
}
|
|
53
|
+
function adoptCachedIdentity(cached, accountIdentity, accountUuid) {
|
|
54
|
+
if (!cached)
|
|
55
|
+
return undefined;
|
|
56
|
+
if (cached.accountIdentity !== undefined &&
|
|
57
|
+
cached.accountIdentity !== accountIdentity) {
|
|
58
|
+
return undefined;
|
|
59
|
+
}
|
|
60
|
+
if (accountUuid !== undefined &&
|
|
61
|
+
cached.accountUuid !== undefined &&
|
|
62
|
+
cached.accountUuid !== accountUuid) {
|
|
63
|
+
return undefined;
|
|
64
|
+
}
|
|
65
|
+
if (cached.accountIdentity === accountIdentity &&
|
|
66
|
+
(accountUuid === undefined || cached.accountUuid === accountUuid)) {
|
|
67
|
+
return cached;
|
|
68
|
+
}
|
|
69
|
+
return {
|
|
70
|
+
...cached,
|
|
71
|
+
accountIdentity,
|
|
72
|
+
...(accountUuid !== undefined && { accountUuid }),
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
function cacheAccountIdentity(identity, accountIdentity, accountUuid) {
|
|
76
|
+
setBounded(identityCache, explicitCacheKey(accountIdentity), identity);
|
|
77
|
+
setBounded(identityCache, accountCacheKey(accountUuid, accountIdentity), identity);
|
|
78
|
+
}
|
|
29
79
|
async function fetchClaudeCodeAccountUuid(accessToken, model) {
|
|
30
80
|
if (!accessToken.startsWith('sk-ant-oat'))
|
|
31
81
|
return null;
|
|
@@ -60,47 +110,100 @@ async function fetchClaudeCodeAccountUuid(accessToken, model) {
|
|
|
60
110
|
clearTimeout(timeout);
|
|
61
111
|
}
|
|
62
112
|
}
|
|
63
|
-
export async function resolveClaudeCodeIdentity(accessToken, model) {
|
|
64
|
-
const
|
|
113
|
+
export async function resolveClaudeCodeIdentity(accessToken, model, accountIdentity) {
|
|
114
|
+
const stableAccountIdentity = accountIdentity?.trim() || undefined;
|
|
115
|
+
const cacheKey = stableAccountIdentity
|
|
116
|
+
? explicitCacheKey(stableAccountIdentity)
|
|
117
|
+
: compatibilityCacheKey(accessToken);
|
|
118
|
+
let identity;
|
|
119
|
+
if (stableAccountIdentity) {
|
|
120
|
+
const cachedIdentity = adoptCachedIdentity(identityCache.get(cacheKey) ?? identityCache.get(accessToken), stableAccountIdentity);
|
|
121
|
+
identity = cachedIdentity ?? getClaudeCodeIdentity(cacheKey);
|
|
122
|
+
identity = adoptCachedIdentity(identity, stableAccountIdentity) ?? identity;
|
|
123
|
+
setBounded(identityCache, cacheKey, identity);
|
|
124
|
+
}
|
|
125
|
+
else {
|
|
126
|
+
identity =
|
|
127
|
+
identityCache.get(cacheKey) ??
|
|
128
|
+
identityCache.get(accessToken) ??
|
|
129
|
+
getClaudeCodeIdentity(cacheKey);
|
|
130
|
+
setBounded(identityCache, cacheKey, identity);
|
|
131
|
+
setBounded(identityCache, accessToken, identity);
|
|
132
|
+
}
|
|
65
133
|
if (!accessToken.startsWith('sk-ant-oat'))
|
|
66
134
|
return identity;
|
|
67
135
|
const now = Date.now();
|
|
68
|
-
|
|
136
|
+
// A slot-stable identity survives account replacement; bootstrap is the
|
|
137
|
+
// account lookup that must be repeated for each credential presented to it.
|
|
138
|
+
const bootstrapKey = `${cacheKey}:${accessToken}`;
|
|
139
|
+
const cachedResult = bootstrapResults.get(bootstrapKey);
|
|
69
140
|
if (cachedResult && cachedResult.expiresAt > now) {
|
|
70
|
-
if (!cachedResult.accountUuid)
|
|
141
|
+
if (!cachedResult.accountUuid) {
|
|
142
|
+
identity = clearCachedAccountUuid(cacheKey, identity);
|
|
143
|
+
return identity;
|
|
144
|
+
}
|
|
145
|
+
if (!stableAccountIdentity) {
|
|
146
|
+
if (identity.accountUuid === cachedResult.accountUuid)
|
|
147
|
+
return identity;
|
|
148
|
+
identity = { ...identity, accountUuid: cachedResult.accountUuid };
|
|
149
|
+
setBounded(identityCache, bootstrapKey, identity);
|
|
71
150
|
return identity;
|
|
72
|
-
const accountCacheKey = `account:${cachedResult.accountUuid}`;
|
|
73
|
-
const accountIdentity = identityCache.get(accountCacheKey);
|
|
74
|
-
if (accountIdentity) {
|
|
75
|
-
setBounded(identityCache, accessToken, accountIdentity);
|
|
76
|
-
return accountIdentity;
|
|
77
151
|
}
|
|
152
|
+
const cachedAccountIdentity = adoptCachedIdentity(identityCache.get(accountCacheKey(cachedResult.accountUuid, stableAccountIdentity)) ?? identityCache.get(`account:${cachedResult.accountUuid}`), stableAccountIdentity, cachedResult.accountUuid);
|
|
153
|
+
if (cachedAccountIdentity) {
|
|
154
|
+
identity = cachedAccountIdentity;
|
|
155
|
+
cacheAccountIdentity(identity, stableAccountIdentity, cachedResult.accountUuid);
|
|
156
|
+
return identity;
|
|
157
|
+
}
|
|
158
|
+
if (identity.accountUuid === cachedResult.accountUuid)
|
|
159
|
+
return identity;
|
|
160
|
+
identity = {
|
|
161
|
+
...identity,
|
|
162
|
+
accountIdentity: stableAccountIdentity,
|
|
163
|
+
accountUuid: cachedResult.accountUuid,
|
|
164
|
+
};
|
|
165
|
+
cacheAccountIdentity(identity, stableAccountIdentity, cachedResult.accountUuid);
|
|
166
|
+
return identity;
|
|
78
167
|
}
|
|
79
|
-
let fetchPromise = bootstrapFetches.get(
|
|
168
|
+
let fetchPromise = bootstrapFetches.get(bootstrapKey);
|
|
80
169
|
if (!fetchPromise) {
|
|
81
170
|
fetchPromise = fetchClaudeCodeAccountUuid(accessToken, model);
|
|
82
|
-
bootstrapFetches
|
|
171
|
+
setBounded(bootstrapFetches, bootstrapKey, fetchPromise);
|
|
83
172
|
}
|
|
84
173
|
const accountUuid = await fetchPromise.finally(() => {
|
|
85
|
-
bootstrapFetches.
|
|
174
|
+
if (bootstrapFetches.get(bootstrapKey) === fetchPromise) {
|
|
175
|
+
bootstrapFetches.delete(bootstrapKey);
|
|
176
|
+
}
|
|
86
177
|
});
|
|
87
|
-
setBounded(bootstrapResults,
|
|
178
|
+
setBounded(bootstrapResults, bootstrapKey, {
|
|
88
179
|
accountUuid,
|
|
89
180
|
expiresAt: now +
|
|
90
181
|
(accountUuid
|
|
91
182
|
? BOOTSTRAP_IDENTITY_CACHE_TTL_MS
|
|
92
183
|
: BOOTSTRAP_IDENTITY_NEGATIVE_TTL_MS),
|
|
93
184
|
});
|
|
94
|
-
if (!accountUuid)
|
|
185
|
+
if (!accountUuid) {
|
|
186
|
+
identity = clearCachedAccountUuid(cacheKey, identity);
|
|
187
|
+
return identity;
|
|
188
|
+
}
|
|
189
|
+
if (!stableAccountIdentity) {
|
|
190
|
+
identity = { ...identity, accountUuid };
|
|
191
|
+
setBounded(identityCache, bootstrapKey, identity);
|
|
95
192
|
return identity;
|
|
96
|
-
const accountCacheKey = `account:${accountUuid}`;
|
|
97
|
-
const accountIdentity = identityCache.get(accountCacheKey);
|
|
98
|
-
if (accountIdentity) {
|
|
99
|
-
setBounded(identityCache, accessToken, accountIdentity);
|
|
100
|
-
return accountIdentity;
|
|
101
193
|
}
|
|
102
|
-
|
|
103
|
-
|
|
194
|
+
const cachedAccountIdentity = adoptCachedIdentity(identityCache.get(accountCacheKey(accountUuid, stableAccountIdentity)) ??
|
|
195
|
+
identityCache.get(`account:${accountUuid}`), stableAccountIdentity, accountUuid);
|
|
196
|
+
if (cachedAccountIdentity) {
|
|
197
|
+
identity = cachedAccountIdentity;
|
|
198
|
+
cacheAccountIdentity(identity, stableAccountIdentity, accountUuid);
|
|
199
|
+
return identity;
|
|
200
|
+
}
|
|
201
|
+
identity = {
|
|
202
|
+
...identity,
|
|
203
|
+
accountIdentity: stableAccountIdentity,
|
|
204
|
+
accountUuid,
|
|
205
|
+
};
|
|
206
|
+
cacheAccountIdentity(identity, stableAccountIdentity, accountUuid);
|
|
104
207
|
return identity;
|
|
105
208
|
}
|
|
106
209
|
function isRecord(value) {
|
package/dist/commands/account.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { formatOAuthAccountTier } from
|
|
1
|
+
import { formatOAuthAccountTier } from '../oauth-profile.js';
|
|
2
2
|
export const CLAUDE_ACCOUNT_COMMAND_NAME = 'claude-account';
|
|
3
3
|
export function parseAccountCommandAction(argumentsText) {
|
|
4
4
|
const parts = argumentsText.trim().split(/\s+/).filter(Boolean);
|
package/dist/constants.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export declare const CLIENT_ID = "9d1c250a-e61b-44d9-88ed-5944d1962f5e";
|
|
2
2
|
export declare const AUTHORIZE_URLS: {
|
|
3
|
-
readonly console:
|
|
4
|
-
readonly max:
|
|
3
|
+
readonly console: 'https://platform.claude.com/oauth/authorize';
|
|
4
|
+
readonly max: 'https://claude.com/cai/oauth/authorize';
|
|
5
5
|
};
|
|
6
6
|
export declare const CODE_CALLBACK_URL = "https://platform.claude.com/oauth/code/callback";
|
|
7
7
|
export declare const TOKEN_URL = "https://platform.claude.com/v1/oauth/token";
|
|
@@ -24,7 +24,7 @@ export declare const CLAUDE_CODE_ENTRYPOINT = "cli";
|
|
|
24
24
|
export declare const CLAUDE_CODE_STAINLESS_PACKAGE_VERSION = "0.94.0";
|
|
25
25
|
export declare const CLAUDE_CODE_STAINLESS_RUNTIME_VERSION = "v24.3.0";
|
|
26
26
|
export declare const USER_AGENT = "claude-cli/2.1.177 (external, cli)";
|
|
27
|
-
export declare const CACHE_1H_MODES: readonly [
|
|
27
|
+
export declare const CACHE_1H_MODES: readonly ['explicit', 'automatic', 'hybrid'];
|
|
28
28
|
export type Cache1hMode = (typeof CACHE_1H_MODES)[number];
|
|
29
29
|
export declare const DEFAULT_CACHE_1H_MODE: Cache1hMode;
|
|
30
30
|
/**
|