@cortexkit/anthropic-auth-core 1.23.0 → 2.0.1

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 (136) hide show
  1. package/README.md +18 -1
  2. package/dist/accounts.d.ts +4 -163
  3. package/dist/cachekeep.d.ts +9 -0
  4. package/dist/claude-code.d.ts +16 -0
  5. package/dist/claustrum-enrollment.d.ts +2 -0
  6. package/dist/claustrum.d.ts +0 -209
  7. package/dist/commands/account.d.ts +2 -3
  8. package/dist/index.d.ts +45 -4
  9. package/dist/index.js +27569 -38
  10. package/dist/internal-types/LICENSE +21 -0
  11. package/dist/internal-types/commands/builtins.d.ts +71 -0
  12. package/dist/internal-types/commands/index.d.ts +10 -0
  13. package/dist/internal-types/commands/menu.d.ts +61 -0
  14. package/dist/internal-types/commands/model.d.ts +238 -0
  15. package/dist/internal-types/commands/pi.d.ts +23 -0
  16. package/dist/internal-types/commands/seam.d.ts +72 -0
  17. package/dist/internal-types/fs/refresh-file-lock.d.ts +33 -0
  18. package/dist/internal-types/logger/capture-sink.d.ts +14 -0
  19. package/dist/internal-types/logger/engine.d.ts +98 -0
  20. package/dist/internal-types/logger/index.d.ts +6 -0
  21. package/dist/internal-types/logger/redact.d.ts +11 -0
  22. package/dist/internal-types/pi-slot/index.d.ts +3 -0
  23. package/dist/internal-types/pi-slot/slot.d.ts +51 -0
  24. package/dist/internal-types/quota/codec.d.ts +11 -0
  25. package/dist/internal-types/quota/format.d.ts +46 -0
  26. package/dist/internal-types/quota/index.d.ts +10 -0
  27. package/dist/internal-types/quota/map.d.ts +63 -0
  28. package/dist/internal-types/quota/merge.d.ts +48 -0
  29. package/dist/internal-types/quota/projection.d.ts +64 -0
  30. package/dist/internal-types/store/attribution.d.ts +28 -0
  31. package/dist/internal-types/store/errors.d.ts +55 -0
  32. package/dist/internal-types/store/hooks.d.ts +12 -0
  33. package/dist/internal-types/store/identity.d.ts +39 -0
  34. package/dist/internal-types/store/index.d.ts +21 -0
  35. package/dist/internal-types/store/mutate.d.ts +189 -0
  36. package/dist/internal-types/store/pool.d.ts +197 -0
  37. package/dist/internal-types/store/provider-state.d.ts +131 -0
  38. package/dist/internal-types/store/publication.d.ts +47 -0
  39. package/dist/internal-types/store/pull.d.ts +36 -0
  40. package/dist/internal-types/store/refresh-lock.d.ts +67 -0
  41. package/dist/internal-types/store/refresh.d.ts +72 -0
  42. package/dist/internal-types/store/rows.d.ts +313 -0
  43. package/dist/internal-types/store/runtime.d.ts +36 -0
  44. package/dist/internal-types/store/schema.d.ts +443 -0
  45. package/dist/internal-types/store/settings.d.ts +63 -0
  46. package/dist/internal-types/store/torn.d.ts +78 -0
  47. package/dist/migration-source.d.ts +33 -0
  48. package/dist/models.d.ts +41 -0
  49. package/dist/native-account-runtime.d.ts +121 -0
  50. package/dist/native-account-view.d.ts +126 -0
  51. package/dist/native-command-effects.d.ts +59 -0
  52. package/dist/native-credential-validation.d.ts +42 -0
  53. package/dist/native-custody-activation.d.ts +45 -0
  54. package/dist/native-custody.d.ts +114 -0
  55. package/dist/native-enrollment-authority.d.ts +2 -0
  56. package/dist/native-host-auth-read.d.ts +3 -0
  57. package/dist/native-host-auth-write.d.ts +51 -0
  58. package/dist/native-host-auth.d.ts +12 -0
  59. package/dist/native-local-credential-service.d.ts +76 -0
  60. package/dist/native-local-runtime-readers.d.ts +22 -0
  61. package/dist/native-lock-observer.d.ts +12 -0
  62. package/dist/native-menu-executor.d.ts +243 -0
  63. package/dist/native-menu-model.d.ts +142 -0
  64. package/dist/native-migration-proof.d.ts +28 -0
  65. package/dist/native-migration-source.d.ts +47 -0
  66. package/dist/native-migration.d.ts +66 -0
  67. package/dist/native-quota-codec.d.ts +32 -0
  68. package/dist/native-refresh-coordinator.d.ts +240 -0
  69. package/dist/native-roster-seed.d.ts +115 -0
  70. package/dist/native-runtime-registry.d.ts +19 -0
  71. package/dist/native-runtime.d.ts +204 -0
  72. package/dist/native-settings.d.ts +6 -0
  73. package/dist/native-transient-account.d.ts +38 -0
  74. package/dist/native-ui.d.ts +45 -0
  75. package/dist/native-usage-publication.d.ts +12 -0
  76. package/dist/native-vault-admission.d.ts +8 -0
  77. package/dist/native-vault-connection.d.ts +33 -0
  78. package/dist/native-vault-paths.d.ts +13 -0
  79. package/dist/native-vault-runtime.d.ts +102 -0
  80. package/dist/native-vault-seed.d.ts +16 -0
  81. package/dist/pool-authority.d.ts +159 -0
  82. package/dist/pool-binding.d.ts +32 -0
  83. package/dist/pool-paths.d.ts +21 -0
  84. package/dist/pool-store.d.ts +32 -0
  85. package/dist/provider-error.d.ts +139 -0
  86. package/dist/quota-manager.d.ts +18 -7
  87. package/dist/relay.d.ts +14 -1
  88. package/dist/request-history.d.ts +34 -0
  89. package/dist/routing.d.ts +1 -2
  90. package/dist/sse.d.ts +81 -0
  91. package/dist/sticky-routing.d.ts +28 -0
  92. package/package.json +10 -4
  93. package/dist/accounts.js +0 -3881
  94. package/dist/auth.js +0 -185
  95. package/dist/cache1h.js +0 -97
  96. package/dist/cachekeep-registry.js +0 -124
  97. package/dist/cachekeep.js +0 -604
  98. package/dist/cch.js +0 -172
  99. package/dist/claude-code.js +0 -403
  100. package/dist/claustrum-enrollment-registry.d.ts +0 -17
  101. package/dist/claustrum-enrollment-registry.js +0 -194
  102. package/dist/claustrum-enrollment.js +0 -485
  103. package/dist/claustrum-scoped-roster.d.ts +0 -23
  104. package/dist/claustrum-scoped-roster.js +0 -194
  105. package/dist/claustrum-scoped-runtime.d.ts +0 -28
  106. package/dist/claustrum-scoped-runtime.js +0 -230
  107. package/dist/claustrum-scoped.d.ts +0 -39
  108. package/dist/claustrum-scoped.js +0 -193
  109. package/dist/claustrum.js +0 -1471
  110. package/dist/commands/account.js +0 -368
  111. package/dist/constants.js +0 -83
  112. package/dist/custom-headers.js +0 -102
  113. package/dist/dump.js +0 -616
  114. package/dist/fast.js +0 -66
  115. package/dist/json.js +0 -10
  116. package/dist/killswitch.js +0 -132
  117. package/dist/logger.js +0 -288
  118. package/dist/logging.js +0 -59
  119. package/dist/mid-conversation-output-config.js +0 -89
  120. package/dist/model-remap.js +0 -72
  121. package/dist/models.js +0 -177
  122. package/dist/network-errors.js +0 -27
  123. package/dist/oauth-profile.js +0 -60
  124. package/dist/pkce.js +0 -17
  125. package/dist/prime.js +0 -841
  126. package/dist/provider.js +0 -0
  127. package/dist/quota-header-feed.js +0 -331
  128. package/dist/quota-headers.js +0 -121
  129. package/dist/quota-manager.js +0 -856
  130. package/dist/quotas.js +0 -141
  131. package/dist/relay.js +0 -1303
  132. package/dist/routing.js +0 -94
  133. package/dist/start.js +0 -29
  134. package/dist/sticky-routing.js +0 -541
  135. package/dist/thinking-binding.js +0 -54
  136. package/dist/token-fingerprint.js +0 -8
package/dist/cachekeep.js DELETED
@@ -1,604 +0,0 @@
1
- import { signRequestBody, stripBillingLineageFromBody } from './cch.js';
2
- import { orderClaudeCodeBody } from './claude-code.js';
3
- import { dumpDirectRequest, dumpResponseArtifact } from './dump.js';
4
- import { logger } from './logger.js';
5
- export const CLAUDE_CACHE_KEEP_COMMAND_NAME = 'claude-cachekeep';
6
- export const CACHE_KEEP_TTL_MS = 60 * 60_000;
7
- export const CACHE_KEEP_PREWARM_LEAD_MS = 5 * 60_000;
8
- export const CACHE_KEEP_TICK_MS = 60_000;
9
- export const CACHE_KEEP_EXTENDED_TTL_BETA = 'extended-cache-ttl-2025-04-11';
10
- export const CACHE_KEEP_MAX_TARGETS = 32;
11
- export const CACHE_KEEP_MAX_BODY_BYTES = 16 * 1024 * 1024;
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;
16
- const STATUS_TITLE = '## Claude Cache Keep Status';
17
- const ENABLED_TITLE = '## Claude Cache Keep Enabled';
18
- const DISABLED_TITLE = '## Claude Cache Keep Disabled';
19
- const USAGE_TITLE = '## Claude Cache Keep Usage';
20
- const USAGE = 'Usage: `/claude-cachekeep`, `/claude-cachekeep always`, `/claude-cachekeep off`, or `/claude-cachekeep HH-HH`.';
21
- function padHour(hour) {
22
- return String(hour).padStart(2, '0');
23
- }
24
- export function parseCacheKeepCommandAction(input) {
25
- const trimmed = input.trim();
26
- if (!trimmed)
27
- return { type: 'status' };
28
- if (trimmed === 'off')
29
- return { type: 'disable' };
30
- if (trimmed === 'always')
31
- return { type: 'always' };
32
- if (trimmed === 'subagents on')
33
- return { type: 'subagents', enabled: true };
34
- if (trimmed === 'subagents off')
35
- return { type: 'subagents', enabled: false };
36
- const match = /^(\d{1,2})-(\d{1,2})$/.exec(trimmed);
37
- if (!match)
38
- return { type: 'usage' };
39
- const startHour = Number(match[1]);
40
- const endHour = Number(match[2]);
41
- if (!Number.isInteger(startHour) ||
42
- !Number.isInteger(endHour) ||
43
- startHour < 0 ||
44
- startHour > 23 ||
45
- endHour < 0 ||
46
- endHour > 23 ||
47
- startHour === endHour) {
48
- return { type: 'usage' };
49
- }
50
- return { type: 'window', startHour, endHour };
51
- }
52
- export function getCacheKeepWindow(storage) {
53
- const startHour = Number(storage?.cacheKeep?.startHour);
54
- const endHour = Number(storage?.cacheKeep?.endHour);
55
- if (!Number.isInteger(startHour) ||
56
- !Number.isInteger(endHour) ||
57
- startHour < 0 ||
58
- startHour > 23 ||
59
- endHour < 0 ||
60
- endHour > 23 ||
61
- startHour === endHour) {
62
- return undefined;
63
- }
64
- return { startHour, endHour };
65
- }
66
- export function isCacheKeepAlways(storage) {
67
- return (storage?.cacheKeep?.enabled === true && storage.cacheKeep.always === true);
68
- }
69
- export function isCacheKeepPersistentlyEnabled(storage) {
70
- return (storage?.cacheKeep?.enabled === true &&
71
- (isCacheKeepAlways(storage) || !!getCacheKeepWindow(storage)));
72
- }
73
- export function isCacheKeepHybridActive(storage) {
74
- return (isCacheKeepPersistentlyEnabled(storage) &&
75
- storage?.claudeCache?.enabled === true &&
76
- storage.claudeCache.mode === 'hybrid');
77
- }
78
- export function isWithinCacheKeepWindow(window, now = new Date()) {
79
- if (!window)
80
- return false;
81
- const hour = now.getHours();
82
- if (window.startHour < window.endHour) {
83
- return hour >= window.startHour && hour < window.endHour;
84
- }
85
- return hour >= window.startHour || hour < window.endHour;
86
- }
87
- export function isCacheKeepActiveNow(storage, now = new Date()) {
88
- if (storage?.cacheKeep?.enabled !== true)
89
- return false;
90
- return (isCacheKeepAlways(storage) ||
91
- isWithinCacheKeepWindow(getCacheKeepWindow(storage), now));
92
- }
93
- export function localDayKey(now = new Date()) {
94
- return `${now.getFullYear()}-${padHour(now.getMonth() + 1)}-${padHour(now.getDate())}`;
95
- }
96
- function localWindowKey(window, now = new Date()) {
97
- if (window &&
98
- window.startHour > window.endHour &&
99
- now.getHours() < window.endHour) {
100
- const previous = new Date(now);
101
- previous.setDate(previous.getDate() - 1);
102
- return localDayKey(previous);
103
- }
104
- return localDayKey(now);
105
- }
106
- function cacheKeepPeriodKey(storage, window, now = new Date()) {
107
- return isCacheKeepAlways(storage) ? 'always' : localWindowKey(window, now);
108
- }
109
- export function buildCacheKeepStatusSummary(status) {
110
- const schedule = status.always
111
- ? 'always (while this process is running)'
112
- : status.window
113
- ? `${padHour(status.window.startHour)}-${padHour(status.window.endHour)}`
114
- : 'not configured';
115
- const lines = [
116
- `Cache keep: ${status.enabled ? 'enabled' : 'disabled'}`,
117
- `Schedule: ${schedule}`,
118
- 'Mode requirement: `/claude-cache mode hybrid` must be active.',
119
- ];
120
- if (typeof status.hybridActive === 'boolean') {
121
- lines.push(`Hybrid active: ${status.hybridActive ? 'yes' : 'no'}`);
122
- }
123
- if (typeof status.trackedSessions === 'number') {
124
- lines.push(`Tracked sessions: ${status.trackedSessions}`);
125
- }
126
- if (status.trackedSessionDetails?.length) {
127
- lines.push('Sessions:');
128
- for (const session of status.trackedSessionDetails) {
129
- lines.push(`- ${session.id}`);
130
- }
131
- }
132
- if (status.nextPrewarmAt) {
133
- lines.push(`Next prewarm: ${new Date(status.nextPrewarmAt).toLocaleString()}`);
134
- }
135
- return lines.join('\n');
136
- }
137
- export function executeCacheKeepCommand(input) {
138
- const action = parseCacheKeepCommandAction(input.argumentsText);
139
- const status = {
140
- enabled: input.enabled ?? false,
141
- always: input.always,
142
- window: input.window,
143
- trackedSessions: input.trackedSessions,
144
- trackedSessionDetails: input.trackedSessionDetails,
145
- nextPrewarmAt: input.nextPrewarmAt,
146
- hybridActive: input.hybridActive,
147
- };
148
- if (action.type === 'status') {
149
- return [STATUS_TITLE, '', buildCacheKeepStatusSummary(status)].join('\n');
150
- }
151
- if (action.type === 'disable') {
152
- return [
153
- DISABLED_TITLE,
154
- '',
155
- buildCacheKeepStatusSummary({ ...status, enabled: false }),
156
- ].join('\n');
157
- }
158
- if (action.type === 'always') {
159
- return [
160
- ENABLED_TITLE,
161
- '',
162
- buildCacheKeepStatusSummary({
163
- ...status,
164
- enabled: true,
165
- always: true,
166
- window: undefined,
167
- }),
168
- ].join('\n');
169
- }
170
- if (action.type === 'window') {
171
- return [
172
- ENABLED_TITLE,
173
- '',
174
- buildCacheKeepStatusSummary({
175
- ...status,
176
- enabled: true,
177
- always: false,
178
- window: { startHour: action.startHour, endHour: action.endHour },
179
- }),
180
- ].join('\n');
181
- }
182
- if (action.type === 'subagents') {
183
- return [
184
- STATUS_TITLE,
185
- '',
186
- buildCacheKeepStatusSummary(status),
187
- '',
188
- `Subagent tracking: ${action.enabled ? 'enabled' : 'disabled'}`,
189
- ].join('\n');
190
- }
191
- return [USAGE_TITLE, '', USAGE, '', buildCacheKeepStatusSummary(status)].join('\n');
192
- }
193
- function hasExplicitCacheControl(value) {
194
- if (!value || typeof value !== 'object')
195
- return false;
196
- if (Array.isArray(value))
197
- return value.some(hasExplicitCacheControl);
198
- const record = value;
199
- const cacheControl = record.cache_control;
200
- if (cacheControl &&
201
- typeof cacheControl === 'object' &&
202
- cacheControl.type === 'ephemeral') {
203
- return true;
204
- }
205
- return Object.values(record).some(hasExplicitCacheControl);
206
- }
207
- export async function buildCacheKeepPrewarmBody(bodyText) {
208
- let body;
209
- try {
210
- body = JSON.parse(bodyText);
211
- }
212
- catch {
213
- return { ok: false, reason: 'body is not valid JSON' };
214
- }
215
- if (!hasExplicitCacheControl(body)) {
216
- return { ok: false, reason: 'body has no explicit cache breakpoints' };
217
- }
218
- const warm = structuredClone(body);
219
- stripBillingLineageFromBody(warm);
220
- warm.max_tokens = 0;
221
- delete warm.stream;
222
- const thinking = warm.thinking;
223
- if (thinking?.type === 'enabled')
224
- delete warm.thinking;
225
- const outputConfig = warm.output_config;
226
- if (outputConfig?.format)
227
- delete warm.output_config;
228
- const toolChoice = warm.tool_choice;
229
- if (toolChoice?.type === 'tool' || toolChoice?.type === 'any') {
230
- delete warm.tool_choice;
231
- }
232
- const signedBodyText = await signRequestBody(JSON.stringify(orderClaudeCodeBody(warm)));
233
- return { ok: true, bodyText: signedBodyText };
234
- }
235
- function cacheKeepRetryDelayMs(targetId, failureCount) {
236
- const exponential = Math.min(CACHE_KEEP_RETRY_MAX_MS, CACHE_KEEP_RETRY_BASE_MS * 2 ** Math.min(Math.max(failureCount - 1, 0), 8));
237
- let hash = 2_166_136_261;
238
- for (const character of `${targetId}:${failureCount}`) {
239
- hash ^= character.charCodeAt(0);
240
- hash = Math.imul(hash, 16_777_619);
241
- }
242
- const jitter = (hash >>> 0) %
243
- (Math.min(CACHE_KEEP_RETRY_JITTER_MAX_MS, exponential / 4) + 1);
244
- return exponential + jitter;
245
- }
246
- export class CacheKeepManager {
247
- options;
248
- targets = new Map();
249
- timer = null;
250
- tickPromise = null;
251
- nextPrewarmAttemptId = 0;
252
- constructor(options) {
253
- this.options = options;
254
- }
255
- start() {
256
- if (this.timer)
257
- return;
258
- logger.debug('cachekeep', 'started');
259
- this.timer = (this.options.setIntervalImpl ?? globalThis.setInterval)(() => {
260
- void this.tick().catch((error) => {
261
- logger.warn('cachekeep', 'tick failed', {
262
- error: error instanceof Error ? error.message : String(error),
263
- });
264
- });
265
- }, CACHE_KEEP_TICK_MS);
266
- if ('unref' in this.timer)
267
- this.timer.unref();
268
- }
269
- stop() {
270
- if (!this.timer)
271
- return;
272
- logger.debug('cachekeep', 'stopped');
273
- const clearIntervalImpl = this.options.clearIntervalImpl ?? globalThis.clearInterval;
274
- clearIntervalImpl(this.timer);
275
- this.timer = null;
276
- }
277
- stats(window, now = this.options.now?.() ?? Date.now(), always = false) {
278
- const today = always ? 'always' : localWindowKey(window, new Date(now));
279
- const targets = [...this.targets.values()].filter((target) => target.dayKey === today);
280
- const nextPrewarmAt = targets.length
281
- ? Math.min(...targets.map((target) => target.nextPrewarmAt))
282
- : undefined;
283
- return { trackedSessions: targets.length, nextPrewarmAt };
284
- }
285
- trackedSessions() {
286
- return [...this.targets.values()]
287
- .map((target) => ({
288
- id: target.id,
289
- cacheExpiresAt: target.cacheExpiresAt,
290
- nextPrewarmAt: target.nextPrewarmAt,
291
- }))
292
- .sort((left, right) => left.id.localeCompare(right.id));
293
- }
294
- trackedOAuthRoute(sessionId) {
295
- const target = this.targets.get(sessionId);
296
- return target ? { oauthAccountId: target.oauthAccountId } : undefined;
297
- }
298
- trackedCount() {
299
- return this.targets.size;
300
- }
301
- publishTrackedSessions() {
302
- const callback = this.options.onTrackedSessionsChanged;
303
- if (!callback)
304
- return;
305
- try {
306
- void Promise.resolve(callback(this.trackedSessions())).catch((error) => {
307
- logger.warn('cachekeep', 'failed to publish tracked sessions', {
308
- error: error instanceof Error ? error.message : String(error),
309
- });
310
- });
311
- }
312
- catch (error) {
313
- logger.warn('cachekeep', 'failed to publish tracked sessions', {
314
- error: error instanceof Error ? error.message : String(error),
315
- });
316
- }
317
- }
318
- totalBodyBytes() {
319
- return [...this.targets.values()].reduce((sum, target) => sum + target.bodyText.length, 0);
320
- }
321
- evictOldestTarget() {
322
- const oldest = this.targets.keys().next().value;
323
- if (oldest !== undefined)
324
- this.targets.delete(oldest);
325
- }
326
- pruneTargets(now, today) {
327
- for (const [id, target] of this.targets) {
328
- if (today && target.dayKey !== today) {
329
- this.targets.delete(id);
330
- continue;
331
- }
332
- if (now >= target.cacheExpiresAt)
333
- this.targets.delete(id);
334
- }
335
- while (this.targets.size > CACHE_KEEP_MAX_TARGETS)
336
- this.evictOldestTarget();
337
- while (this.totalBodyBytes() > CACHE_KEEP_MAX_BODY_BYTES) {
338
- const before = this.targets.size;
339
- this.evictOldestTarget();
340
- if (this.targets.size === before)
341
- break;
342
- }
343
- }
344
- track(input) {
345
- if (!input.sessionId)
346
- return { tracked: false, reason: 'missing session id' };
347
- if (!isCacheKeepPersistentlyEnabled(input.storage)) {
348
- return { tracked: false, reason: 'cachekeep disabled' };
349
- }
350
- if (input.cacheMode !== 'hybrid') {
351
- return { tracked: false, reason: 'cache mode is not hybrid' };
352
- }
353
- if (input.bodyText.length > CACHE_KEEP_MAX_BODY_BYTES) {
354
- return { tracked: false, reason: 'body exceeds cachekeep memory budget' };
355
- }
356
- const now = this.options.now?.() ?? Date.now();
357
- const window = getCacheKeepWindow(input.storage);
358
- if (!isCacheKeepActiveNow(input.storage, new Date(now))) {
359
- return { tracked: false, reason: 'outside configured schedule' };
360
- }
361
- const today = cacheKeepPeriodKey(input.storage, window, new Date(now));
362
- this.pruneTargets(now, today);
363
- if (this.targets.has(input.sessionId))
364
- this.targets.delete(input.sessionId);
365
- const headers = {};
366
- input.headers.forEach((value, key) => {
367
- headers[key] = value;
368
- });
369
- this.targets.set(input.sessionId, {
370
- id: input.sessionId,
371
- url: input.url,
372
- headers,
373
- bodyText: input.bodyText,
374
- cacheExpiresAt: now + CACHE_KEEP_TTL_MS,
375
- nextPrewarmAt: now + CACHE_KEEP_TTL_MS - CACHE_KEEP_PREWARM_LEAD_MS,
376
- consecutiveFailures: 0,
377
- dayKey: today,
378
- oauthAccountId: input.oauthAccountId,
379
- oauthAccountIdentity: input.oauthAccountIdentity,
380
- accountStoragePath: input.accountStoragePath,
381
- isSubagent: input.isSubagent ?? false,
382
- });
383
- this.pruneTargets(now, today);
384
- this.publishTrackedSessions();
385
- this.start();
386
- return { tracked: true };
387
- }
388
- async prewarmNow(input) {
389
- const headers = {};
390
- input.headers.forEach((value, key) => {
391
- headers[key] = value;
392
- });
393
- const target = {
394
- id: input.sessionId,
395
- url: input.url,
396
- headers,
397
- bodyText: input.bodyText,
398
- cacheExpiresAt: this.options.now?.() ?? Date.now(),
399
- nextPrewarmAt: this.options.now?.() ?? Date.now(),
400
- consecutiveFailures: 0,
401
- dayKey: '',
402
- oauthAccountId: input.oauthAccountId,
403
- oauthAccountIdentity: input.oauthAccountIdentity,
404
- accountStoragePath: input.accountStoragePath,
405
- isSubagent: input.isSubagent ?? false,
406
- };
407
- return this.sendPrewarm(target);
408
- }
409
- tick() {
410
- if (this.tickPromise)
411
- return this.tickPromise;
412
- let run;
413
- run = this.runTick().finally(() => {
414
- if (this.tickPromise === run)
415
- this.tickPromise = null;
416
- });
417
- this.tickPromise = run;
418
- return run;
419
- }
420
- async runTick() {
421
- const storage = await this.options.loadStorage();
422
- const window = getCacheKeepWindow(storage);
423
- const now = this.options.now?.() ?? Date.now();
424
- const today = cacheKeepPeriodKey(storage, window, new Date(now));
425
- if (isCacheKeepAlways(storage)) {
426
- for (const target of this.targets.values())
427
- target.dayKey = 'always';
428
- }
429
- this.pruneTargets(now, today);
430
- if (!this.targets.size) {
431
- this.publishTrackedSessions();
432
- this.stop();
433
- return;
434
- }
435
- if (!isCacheKeepHybridActive(storage)) {
436
- this.publishTrackedSessions();
437
- return;
438
- }
439
- if (!isCacheKeepActiveNow(storage, new Date(now))) {
440
- this.publishTrackedSessions();
441
- return;
442
- }
443
- logger.debug('cachekeep', 'fired', { targets: this.targets.size });
444
- for (const target of this.targets.values()) {
445
- if (target.nextPrewarmAt > now)
446
- continue;
447
- try {
448
- await this.prewarm(target, now);
449
- }
450
- catch (error) {
451
- logger.warn('cachekeep', 'prewarm failed', {
452
- session: target.id,
453
- reason: error instanceof Error ? error.message : String(error),
454
- });
455
- target.consecutiveFailures += 1;
456
- target.nextPrewarmAt =
457
- now + cacheKeepRetryDelayMs(target.id, target.consecutiveFailures);
458
- }
459
- }
460
- this.publishTrackedSessions();
461
- }
462
- async sendPrewarm(target) {
463
- const attempt = {
464
- id: ++this.nextPrewarmAttemptId,
465
- signal: AbortSignal.timeout(this.options.prewarmTimeoutMs ?? CACHE_KEEP_PREWARM_TIMEOUT_MS),
466
- };
467
- try {
468
- let bodyText = target.bodyText;
469
- if (this.options.prepareBody) {
470
- try {
471
- bodyText = await this.options.prepareBody(bodyText, target);
472
- }
473
- catch (error) {
474
- logger.warn('cachekeep', 'prepare body failed', {
475
- session: target.id,
476
- error: error instanceof Error ? error.message : String(error),
477
- });
478
- }
479
- }
480
- const preparedTarget = { ...target, bodyText };
481
- const prewarm = await buildCacheKeepPrewarmBody(bodyText);
482
- if (!prewarm.ok)
483
- return prewarm;
484
- const fetchImpl = this.options.fetchImpl ?? fetch;
485
- const prewarmTarget = { ...preparedTarget, bodyText: prewarm.bodyText };
486
- const headers = this.options.prepareHeaders
487
- ? await this.options.prepareHeaders(new Headers(target.headers), prewarmTarget, attempt)
488
- : new Headers(target.headers);
489
- if (!headers) {
490
- return {
491
- ok: false,
492
- reason: 'OAuth cache prewarm credential is unavailable',
493
- transient: true,
494
- };
495
- }
496
- headers.delete('content-length');
497
- headers.delete('transfer-encoding');
498
- let response;
499
- try {
500
- response = await fetchImpl(target.url, {
501
- method: 'POST',
502
- headers,
503
- body: prewarm.bodyText,
504
- signal: attempt.signal,
505
- });
506
- }
507
- catch (error) {
508
- return {
509
- ok: false,
510
- reason: error instanceof Error ? error.message : String(error),
511
- transient: true,
512
- };
513
- }
514
- const receivedAt = this.options.now?.() ?? Date.now();
515
- const raw = await response.text().catch(() => '');
516
- let data = null;
517
- try {
518
- data = raw ? JSON.parse(raw) : null;
519
- }
520
- catch { }
521
- try {
522
- await this.options.onResponse?.({
523
- target,
524
- bodyText: prewarm.bodyText,
525
- status: response.status,
526
- data,
527
- receivedAt,
528
- attempt,
529
- });
530
- }
531
- catch { }
532
- try {
533
- const dumpHandle = await dumpDirectRequest({
534
- affinity: target.id,
535
- route: 'cachekeep',
536
- status: response.status,
537
- bodyText: prewarm.bodyText,
538
- url: target.url,
539
- method: 'POST',
540
- headers,
541
- tag: 'cachekeep',
542
- });
543
- await dumpResponseArtifact(dumpHandle, {
544
- status: response.status,
545
- message: data,
546
- });
547
- }
548
- catch (error) {
549
- logger.debug('cachekeep', 'dump failed', {
550
- session: target.id,
551
- error: error instanceof Error ? error.message : String(error),
552
- });
553
- }
554
- if (!response.ok) {
555
- return {
556
- ok: false,
557
- reason: raw || `HTTP ${response.status}`,
558
- status: response.status,
559
- };
560
- }
561
- const objectData = data && typeof data === 'object' && !Array.isArray(data)
562
- ? data
563
- : null;
564
- const usage = objectData?.usage;
565
- return { ok: true, ...(usage && { usage }) };
566
- }
567
- finally {
568
- try {
569
- await this.options.onComplete?.({ target, attempt });
570
- }
571
- catch { }
572
- }
573
- }
574
- async prewarm(target, now) {
575
- const result = await this.sendPrewarm(target);
576
- if (!result.ok) {
577
- if (result.status == null && !result.transient) {
578
- logger.debug('cachekeep', 'prewarm skipped', {
579
- session: target.id,
580
- reason: result.reason,
581
- });
582
- this.targets.delete(target.id);
583
- }
584
- else {
585
- logger.warn('cachekeep', 'prewarm failed', {
586
- session: target.id,
587
- status: result.status,
588
- reason: result.reason,
589
- });
590
- target.consecutiveFailures += 1;
591
- target.nextPrewarmAt =
592
- now + cacheKeepRetryDelayMs(target.id, target.consecutiveFailures);
593
- }
594
- return;
595
- }
596
- target.cacheExpiresAt = now + CACHE_KEEP_TTL_MS;
597
- target.nextPrewarmAt = target.cacheExpiresAt - CACHE_KEEP_PREWARM_LEAD_MS;
598
- target.consecutiveFailures = 0;
599
- logger.debug('cachekeep', 'prewarm succeeded', {
600
- session: target.id,
601
- ...(result.usage && { usage: result.usage }),
602
- });
603
- }
604
- }