@cortexkit/anthropic-auth-core 1.5.0 → 1.6.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.
@@ -31,6 +31,14 @@ export type AccountQuotaWindow = {
31
31
  checkedAt: number;
32
32
  };
33
33
  export type RoutingMode = 'main-first' | 'fallback-first';
34
+ export type KillswitchThresholds = Partial<Record<QuotaWindowName | '5h' | '1w', number>>;
35
+ export type KillswitchConfig = {
36
+ enabled?: boolean;
37
+ /** Thresholds for the main OAuth account (remaining % below which the account is killed). */
38
+ main?: KillswitchThresholds;
39
+ /** Per-account overrides keyed by account ID. Accounts without an entry use the `main` thresholds. */
40
+ accounts?: Record<string, KillswitchThresholds>;
41
+ };
34
42
  export type AccountStorage = {
35
43
  version: 1;
36
44
  main?: {
@@ -56,6 +64,8 @@ export type AccountStorage = {
56
64
  refreshEveryNRequests?: number;
57
65
  minimumRemaining?: Partial<Record<QuotaWindowName | '5h' | '1w', number>>;
58
66
  failClosedOnUnknownQuota?: boolean;
67
+ /** Opt-in OpenCode TUI toast after quota refresh. Default: false. */
68
+ showToasts?: boolean;
59
69
  mainQuota?: OAuthQuotaSnapshot;
60
70
  mainQuotaCheckedAt?: number;
61
71
  mainQuotaToken?: string;
@@ -83,6 +93,7 @@ export type AccountStorage = {
83
93
  fallbackToDirect?: boolean;
84
94
  transport?: 'http' | 'websocket';
85
95
  };
96
+ killswitch?: KillswitchConfig;
86
97
  accounts: OAuthAccount[];
87
98
  };
88
99
  export type OAuthQuotaSnapshot = Partial<Record<QuotaWindowName, AccountQuotaWindow>>;
@@ -91,6 +102,7 @@ export type AccountManagerOptions = {
91
102
  fetchImpl?: typeof fetch;
92
103
  configPath?: string;
93
104
  quotaManager?: import('./quota-manager.ts').QuotaManager;
105
+ onFallbackStorageChanged?: () => void;
94
106
  };
95
107
  export type AccountRefreshError = {
96
108
  accountId: string;
@@ -149,6 +161,22 @@ export declare function getPersistedMainQuota(storage: AccountStorage | null): {
149
161
  */
150
162
  export declare function getQuotaRefreshEveryNRequests(storage: AccountStorage | null): number;
151
163
  export declare function quotaSnapshotPassesPolicy(quota: OAuthQuotaSnapshot | undefined, storage: AccountStorage | null): boolean;
164
+ export declare const DEFAULT_KILLSWITCH_THRESHOLDS: Record<QuotaWindowName, number>;
165
+ export declare function isKillswitchEnabled(storage: AccountStorage | null): boolean;
166
+ /**
167
+ * Returns true if the account's quota is above its killswitch threshold.
168
+ * When killswitch is disabled, always returns true.
169
+ */
170
+ export declare function killswitchPassesPolicy(quota: OAuthQuotaSnapshot | undefined, storage: AccountStorage | null, accountId?: string): boolean;
171
+ /**
172
+ * Find the earliest reset time across all accounts' quota windows.
173
+ * Returns seconds from `now` until that reset, or 300 as a fallback.
174
+ */
175
+ export declare function killswitchRetryAfterSeconds(mainQuota: OAuthQuotaSnapshot | undefined, fallbackAccounts: Array<{
176
+ quota?: OAuthQuotaSnapshot;
177
+ }>, now: number): number;
178
+ export declare function getKillswitchConfig(storage: AccountStorage | null): KillswitchConfig;
179
+ export declare function setKillswitchPersistent(config: KillswitchConfig, path?: string): Promise<AccountStorage>;
152
180
  export declare function getQuotaNextRefreshAt(quota: OAuthQuotaSnapshot | undefined, storage: AccountStorage | null, now: number): number;
153
181
  export declare function fetchOAuthQuotaSnapshot(input: {
154
182
  accessToken: string;
@@ -166,6 +194,7 @@ export declare class FallbackAccountManager {
166
194
  private refreshTimer;
167
195
  private quotaTimer;
168
196
  readonly quotaManager: import('./quota-manager.ts').QuotaManager | null;
197
+ private readonly onFallbackStorageChanged;
169
198
  constructor(options?: AccountManagerOptions);
170
199
  /**
171
200
  * Seed QuotaManager from persisted account.quota if no cache entry exists
package/dist/accounts.js CHANGED
@@ -130,6 +130,7 @@ function normalizeStorage(value) {
130
130
  claudeFast: isRecord(value.claudeFast) ? value.claudeFast : undefined,
131
131
  cacheKeep: isRecord(value.cacheKeep) ? value.cacheKeep : undefined,
132
132
  relay: isRecord(value.relay) ? value.relay : undefined,
133
+ killswitch: isRecord(value.killswitch) ? value.killswitch : undefined,
133
134
  accounts: value.accounts
134
135
  .map(normalizeAccount)
135
136
  .filter((account) => account != null),
@@ -517,6 +518,95 @@ export function quotaSnapshotPassesPolicy(quota, storage) {
517
518
  }
518
519
  return true;
519
520
  }
521
+ // ---------------------------------------------------------------------------
522
+ // Killswitch — hard-block requests when remaining quota drops below per-account
523
+ // thresholds, even if the API would still accept them.
524
+ // ---------------------------------------------------------------------------
525
+ export const DEFAULT_KILLSWITCH_THRESHOLDS = {
526
+ five_hour: 5,
527
+ seven_day: 10,
528
+ };
529
+ function normalizeKillswitchThresholds(thresholds) {
530
+ return {
531
+ five_hour: thresholds?.five_hour ??
532
+ thresholds?.['5h'] ??
533
+ DEFAULT_KILLSWITCH_THRESHOLDS.five_hour,
534
+ seven_day: thresholds?.seven_day ??
535
+ thresholds?.['1w'] ??
536
+ DEFAULT_KILLSWITCH_THRESHOLDS.seven_day,
537
+ };
538
+ }
539
+ export function isKillswitchEnabled(storage) {
540
+ return storage?.killswitch?.enabled === true;
541
+ }
542
+ function getKillswitchThresholdsForAccount(storage, accountId) {
543
+ if (!storage?.killswitch)
544
+ return DEFAULT_KILLSWITCH_THRESHOLDS;
545
+ if (accountId && storage.killswitch.accounts?.[accountId]) {
546
+ return normalizeKillswitchThresholds(storage.killswitch.accounts[accountId]);
547
+ }
548
+ return normalizeKillswitchThresholds(storage.killswitch.main);
549
+ }
550
+ /**
551
+ * Returns true if the account's quota is above its killswitch threshold.
552
+ * When killswitch is disabled, always returns true.
553
+ */
554
+ export function killswitchPassesPolicy(quota, storage, accountId) {
555
+ if (!isKillswitchEnabled(storage))
556
+ return true;
557
+ const thresholds = getKillswitchThresholdsForAccount(storage, accountId);
558
+ let sawUnknownWindow = false;
559
+ for (const key of ['five_hour', 'seven_day']) {
560
+ const window = quota?.[key];
561
+ // Defer the unknown-window decision: a quota snapshot can legally carry
562
+ // only one window, and a present window below its threshold must still
563
+ // block even if the other window is missing.
564
+ if (!window) {
565
+ sawUnknownWindow = true;
566
+ continue;
567
+ }
568
+ if (window.remainingPercent < thresholds[key])
569
+ return false;
570
+ }
571
+ if (sawUnknownWindow)
572
+ return !failClosedOnUnknownQuota(storage);
573
+ return true;
574
+ }
575
+ /**
576
+ * Find the earliest reset time across all accounts' quota windows.
577
+ * Returns seconds from `now` until that reset, or 300 as a fallback.
578
+ */
579
+ export function killswitchRetryAfterSeconds(mainQuota, fallbackAccounts, now) {
580
+ const resetTimes = [];
581
+ const allQuotas = [mainQuota, ...fallbackAccounts.map((a) => a.quota)];
582
+ for (const quota of allQuotas) {
583
+ for (const key of ['five_hour', 'seven_day']) {
584
+ const resetStr = quota?.[key]?.resetsAt;
585
+ if (!resetStr)
586
+ continue;
587
+ const resetTime = Date.parse(resetStr);
588
+ if (Number.isFinite(resetTime) && resetTime > now) {
589
+ resetTimes.push(resetTime);
590
+ }
591
+ }
592
+ }
593
+ if (!resetTimes.length)
594
+ return 300;
595
+ return Math.max(1, Math.ceil((Math.min(...resetTimes) - now) / 1000)) + 60;
596
+ }
597
+ export function getKillswitchConfig(storage) {
598
+ return storage?.killswitch ?? { enabled: false };
599
+ }
600
+ export async function setKillswitchPersistent(config, path = getAccountStoragePath()) {
601
+ const storage = (await loadAccounts(path)) ?? {
602
+ version: 1,
603
+ main: { type: 'opencode', provider: 'anthropic' },
604
+ accounts: [],
605
+ };
606
+ storage.killswitch = config;
607
+ await saveAccounts(storage, path);
608
+ return storage;
609
+ }
520
610
  export function getQuotaNextRefreshAt(quota, storage, now) {
521
611
  if (!quotaEnabled(storage))
522
612
  return now + getQuotaCheckIntervalMs(storage);
@@ -664,11 +754,13 @@ export class FallbackAccountManager {
664
754
  refreshTimer = null;
665
755
  quotaTimer = null;
666
756
  quotaManager;
757
+ onFallbackStorageChanged;
667
758
  constructor(options = {}) {
668
759
  this.now = options.now ?? Date.now;
669
760
  this.fetchImpl = options.fetchImpl ?? fetch;
670
761
  this.configPath = options.configPath ?? getAccountStoragePath();
671
762
  this.quotaManager = options.quotaManager ?? null;
763
+ this.onFallbackStorageChanged = options.onFallbackStorageChanged;
672
764
  }
673
765
  /**
674
766
  * Seed QuotaManager from persisted account.quota if no cache entry exists
@@ -880,8 +972,10 @@ export class FallbackAccountManager {
880
972
  // Quota probes are advisory; failed probes fail closed at selection time.
881
973
  }
882
974
  }
883
- if (changed)
975
+ if (changed) {
884
976
  await this.save(storage);
977
+ this.onFallbackStorageChanged?.();
978
+ }
885
979
  }
886
980
  async refreshQuotaForAllAccounts(options = {}) {
887
981
  const storage = await this.load();
package/dist/index.d.ts CHANGED
@@ -7,6 +7,7 @@ export * from './claude-code.ts';
7
7
  export * from './constants.ts';
8
8
  export * from './dump.ts';
9
9
  export * from './fast.ts';
10
+ export * from './killswitch.ts';
10
11
  export * from './logger.ts';
11
12
  export * from './pkce.ts';
12
13
  export * from './quota-manager.ts';
package/dist/index.js CHANGED
@@ -7,6 +7,7 @@ export * from "./claude-code.js";
7
7
  export * from "./constants.js";
8
8
  export * from "./dump.js";
9
9
  export * from "./fast.js";
10
+ export * from "./killswitch.js";
10
11
  export * from "./logger.js";
11
12
  export * from "./pkce.js";
12
13
  export * from "./quota-manager.js";
@@ -0,0 +1,27 @@
1
+ import type { KillswitchConfig } from './accounts.ts';
2
+ export declare const KILLSWITCH_COMMAND_NAME = "claude-killswitch";
3
+ export type KillswitchCommandAction = {
4
+ type: 'status';
5
+ } | {
6
+ type: 'on';
7
+ } | {
8
+ type: 'off';
9
+ } | {
10
+ type: 'set';
11
+ entries: Array<{
12
+ account: string;
13
+ fh: number;
14
+ sd: number;
15
+ }>;
16
+ } | {
17
+ type: 'usage';
18
+ };
19
+ export declare function parseKillswitchCommandAction(argumentsText: string): KillswitchCommandAction;
20
+ export declare function executeKillswitchCommand(input: {
21
+ argumentsText: string;
22
+ config: KillswitchConfig;
23
+ accountIds: string[];
24
+ }): {
25
+ text: string;
26
+ updatedConfig?: KillswitchConfig;
27
+ };
@@ -0,0 +1,127 @@
1
+ import { DEFAULT_KILLSWITCH_THRESHOLDS as DEFAULT_THRESHOLDS } from "./accounts.js";
2
+ export const KILLSWITCH_COMMAND_NAME = 'claude-killswitch';
3
+ export function parseKillswitchCommandAction(argumentsText) {
4
+ const parts = argumentsText.trim().split(/\s+/).filter(Boolean);
5
+ if (parts.length === 0)
6
+ return { type: 'status' };
7
+ if (parts.length === 1 && parts[0] === 'on')
8
+ return { type: 'on' };
9
+ if (parts.length === 1 && parts[0] === 'off')
10
+ return { type: 'off' };
11
+ if (parts[0] === 'set') {
12
+ const entries = [];
13
+ for (let i = 1; i < parts.length; i++) {
14
+ const match = parts[i]?.match(/^([^:]+):(\d+),(\d+)$/);
15
+ if (!match)
16
+ return { type: 'usage' };
17
+ const [, account, fhStr, sdStr] = match;
18
+ entries.push({
19
+ account,
20
+ fh: Number.parseInt(fhStr, 10),
21
+ sd: Number.parseInt(sdStr, 10),
22
+ });
23
+ }
24
+ if (entries.length === 0)
25
+ return { type: 'usage' };
26
+ return { type: 'set', entries };
27
+ }
28
+ return { type: 'usage' };
29
+ }
30
+ function buildStatusTable(config, accountIds) {
31
+ const enabled = config.enabled === true;
32
+ const lines = [
33
+ '## Killswitch',
34
+ '',
35
+ `Status: **${enabled ? 'ON' : 'OFF'}**`,
36
+ ];
37
+ if (enabled) {
38
+ lines.push('');
39
+ lines.push('| Account | 5h threshold | 1w threshold |');
40
+ lines.push('| ------- | ------------ | ------------ |');
41
+ const mainT = config.main ?? {};
42
+ const fh = mainT.five_hour ?? mainT['5h'] ?? DEFAULT_THRESHOLDS.five_hour;
43
+ const sd = mainT.seven_day ?? mainT['1w'] ?? DEFAULT_THRESHOLDS.seven_day;
44
+ lines.push(`| main | \u2265 ${fh}% | \u2265 ${sd}% |`);
45
+ for (const id of accountIds) {
46
+ const t = config.accounts?.[id] ?? config.main ?? {};
47
+ const afh = t.five_hour ?? t['5h'] ?? DEFAULT_THRESHOLDS.five_hour;
48
+ const asd = t.seven_day ?? t['1w'] ?? DEFAULT_THRESHOLDS.seven_day;
49
+ lines.push(`| ${id} | \u2265 ${afh}% | \u2265 ${asd}% |`);
50
+ }
51
+ }
52
+ return lines.join('\n');
53
+ }
54
+ const USAGE_TEXT = [
55
+ '## Killswitch Commands',
56
+ '',
57
+ '```',
58
+ `/${KILLSWITCH_COMMAND_NAME} — show status`,
59
+ `/${KILLSWITCH_COMMAND_NAME} on — enable with current or default thresholds`,
60
+ `/${KILLSWITCH_COMMAND_NAME} off — disable`,
61
+ `/${KILLSWITCH_COMMAND_NAME} set all:5,10 — set all accounts to 5h≥5%, 1w≥10%`,
62
+ `/${KILLSWITCH_COMMAND_NAME} set main:3,8 work-alt:5,10 — per-account`,
63
+ '```',
64
+ ].join('\n');
65
+ export function executeKillswitchCommand(input) {
66
+ const action = parseKillswitchCommandAction(input.argumentsText);
67
+ if (action.type === 'status') {
68
+ const status = buildStatusTable(input.config, input.accountIds);
69
+ return { text: `${status}\n\n${USAGE_TEXT}` };
70
+ }
71
+ if (action.type === 'on') {
72
+ const updated = {
73
+ ...input.config,
74
+ enabled: true,
75
+ main: input.config.main ?? {
76
+ five_hour: DEFAULT_THRESHOLDS.five_hour,
77
+ seven_day: DEFAULT_THRESHOLDS.seven_day,
78
+ },
79
+ };
80
+ const status = buildStatusTable(updated, input.accountIds);
81
+ return {
82
+ text: `## Killswitch Enabled\n\n${status}`,
83
+ updatedConfig: updated,
84
+ };
85
+ }
86
+ if (action.type === 'off') {
87
+ const updated = { ...input.config, enabled: false };
88
+ return {
89
+ text: '## Killswitch Disabled',
90
+ updatedConfig: updated,
91
+ };
92
+ }
93
+ if (action.type === 'set') {
94
+ const accounts = { ...(input.config.accounts ?? {}) };
95
+ const updated = {
96
+ ...input.config,
97
+ enabled: true,
98
+ accounts,
99
+ };
100
+ for (const entry of action.entries) {
101
+ const thresholds = {
102
+ five_hour: entry.fh,
103
+ seven_day: entry.sd,
104
+ };
105
+ if (entry.account === 'main') {
106
+ updated.main = thresholds;
107
+ }
108
+ else if (entry.account === 'all') {
109
+ updated.main = thresholds;
110
+ for (const id of input.accountIds) {
111
+ accounts[id] = thresholds;
112
+ }
113
+ }
114
+ else {
115
+ accounts[entry.account] = thresholds;
116
+ }
117
+ }
118
+ const status = buildStatusTable(updated, input.accountIds);
119
+ return {
120
+ text: `## Killswitch Updated\n\n${status}`,
121
+ updatedConfig: updated,
122
+ };
123
+ }
124
+ // usage
125
+ const status = buildStatusTable(input.config, input.accountIds);
126
+ return { text: `${status}\n\n${USAGE_TEXT}` };
127
+ }
package/dist/relay.js CHANGED
@@ -241,6 +241,16 @@ function toBinaryChunk(data) {
241
241
  function parseRelayControlMessage(data) {
242
242
  return JSON.parse(data);
243
243
  }
244
+ function formatCloseEvent(event) {
245
+ const close = event;
246
+ const parts = [
247
+ `code=${close.code ?? 'unknown'}`,
248
+ `wasClean=${close.wasClean ?? 'unknown'}`,
249
+ ];
250
+ if (close.reason)
251
+ parts.push(`reason=${JSON.stringify(close.reason)}`);
252
+ return parts.join(' ');
253
+ }
244
254
  function relayControlErrorMessage(message) {
245
255
  const detail = message.message || 'relay websocket error';
246
256
  return message.status
@@ -364,7 +374,7 @@ class PersistentRelaySession {
364
374
  reject(error);
365
375
  this.failPending(error);
366
376
  });
367
- socket.addEventListener('close', () => {
377
+ socket.addEventListener('close', (event) => {
368
378
  clearTimeout(timeout);
369
379
  if (this.socket === socket) {
370
380
  this.socket = undefined;
@@ -374,9 +384,16 @@ class PersistentRelaySession {
374
384
  if (this.pending) {
375
385
  if (this.pending.retryingBeforeResponse)
376
386
  return;
377
- if (this.retryPendingBeforeResponse(this.pending, 'closed before response'))
387
+ const closedAfterResponseStart = this.pending.responseStartedAt != null;
388
+ const reason = closedAfterResponseStart
389
+ ? 'closed after response_start before stream bytes'
390
+ : 'closed before response';
391
+ if (this.retryPendingBeforeResponse(this.pending, reason, event))
378
392
  return;
379
- const error = new Error('relay websocket closed before response');
393
+ const error = new Error(closedAfterResponseStart
394
+ ? 'relay websocket closed during response stream'
395
+ : 'relay websocket closed before response');
396
+ relayLog(`websocket ${closedAfterResponseStart ? 'closed during response stream' : 'closed before response without retry'} session=${shortAffinity(this.affinity)} request=${this.pending.payload.id} chunks=${this.pending.streamChunkCount} bytes=${this.pending.streamByteCount} ${formatCloseEvent(event)}`);
380
397
  this.failPending(error);
381
398
  }
382
399
  });
@@ -410,6 +427,8 @@ class PersistentRelaySession {
410
427
  rejectDone,
411
428
  sentAt,
412
429
  optimisticResponse,
430
+ streamChunkCount: 0,
431
+ streamByteCount: 0,
413
432
  retryAttempts: 0,
414
433
  retryingBeforeResponse: false,
415
434
  };
@@ -436,8 +455,8 @@ class PersistentRelaySession {
436
455
  this.socket?.close();
437
456
  }, 45_000);
438
457
  }
439
- retryPendingBeforeResponse(pending, reason) {
440
- if (pending.responseStartedAt != null)
458
+ retryPendingBeforeResponse(pending, reason, closeEvent) {
459
+ if (pending.responseStartedAt != null && pending.streamByteCount > 0)
441
460
  return false;
442
461
  if (pending.streamDone)
443
462
  return false;
@@ -448,7 +467,7 @@ class PersistentRelaySession {
448
467
  clearTimeout(pending.timeout);
449
468
  const attempt = pending.retryAttempts;
450
469
  const originalId = pending.payload.id;
451
- relayLog(`websocket ${reason}; reconnecting and retrying full_sync session=${shortAffinity(this.affinity)} request=${originalId} retry=${attempt}`);
470
+ relayLog(`websocket ${reason}; reconnecting and retrying full_sync session=${shortAffinity(this.affinity)} request=${originalId} retry=${attempt} chunks=${pending.streamChunkCount} bytes=${pending.streamByteCount}${closeEvent ? ` ${formatCloseEvent(closeEvent)}` : ''}`);
452
471
  this.socket?.close();
453
472
  this.socket = undefined;
454
473
  this.serverState = undefined;
@@ -484,11 +503,16 @@ class PersistentRelaySession {
484
503
  })();
485
504
  return true;
486
505
  }
506
+ enqueueStreamChunk(pending, chunk) {
507
+ pending.streamChunkCount += 1;
508
+ pending.streamByteCount += chunk.byteLength;
509
+ pending.streamController?.enqueue(chunk);
510
+ }
487
511
  handleBinaryChunk(data) {
488
512
  const pending = this.pending;
489
513
  if (!pending?.responseStarted)
490
514
  return;
491
- pending.streamController?.enqueue(toBinaryChunk(data));
515
+ this.enqueueStreamChunk(pending, toBinaryChunk(data));
492
516
  }
493
517
  resolvePendingResponse(pending, status, statusText, headers) {
494
518
  if (pending.responseStarted)
@@ -542,7 +566,7 @@ class PersistentRelaySession {
542
566
  return;
543
567
  }
544
568
  if (message.type === 'chunk') {
545
- pending.streamController?.enqueue(decodeRelayChunk(message.base64));
569
+ this.enqueueStreamChunk(pending, decodeRelayChunk(message.base64));
546
570
  return;
547
571
  }
548
572
  if (message.type === 'done') {
@@ -555,7 +579,7 @@ class PersistentRelaySession {
555
579
  // would reject a settled promise and leave the stream hanging. Instead,
556
580
  // inject an SSE error event and close cleanly.
557
581
  if (pending.optimisticResponse && pending.responseStartedAt != null) {
558
- relayLog(`websocket relay error during optimistic response session=${shortAffinity(this.affinity)} request=${pending.payload.id} status=${message.status} message=${message.message || 'unknown'}`);
582
+ relayLog(`websocket relay error during optimistic response session=${shortAffinity(this.affinity)} request=${pending.payload.id} status=${message.status} message=${message.message || 'unknown'} chunks=${pending.streamChunkCount} bytes=${pending.streamByteCount}`);
559
583
  pending.streamController?.enqueue(new TextEncoder().encode(`event: error\ndata: ${JSON.stringify({ type: 'error', error: { type: 'relay_error', message: message.message || 'relay error' } })}\n\n`));
560
584
  this.finishPending();
561
585
  this.socket?.close();
@@ -576,7 +600,7 @@ class PersistentRelaySession {
576
600
  if (!pending)
577
601
  return;
578
602
  const finishedAt = perfNowMs();
579
- relayLog(`perf websocket done session=${shortAffinity(this.affinity)} request=${pending.payload.id} sentMs=${formatMs(finishedAt - pending.sentAt)} streamMs=${pending.responseStartedAt == null ? 'unknown' : formatMs(finishedAt - pending.responseStartedAt)}`);
603
+ relayLog(`perf websocket done session=${shortAffinity(this.affinity)} request=${pending.payload.id} sentMs=${formatMs(finishedAt - pending.sentAt)} streamMs=${pending.responseStartedAt == null ? 'unknown' : formatMs(finishedAt - pending.responseStartedAt)} chunks=${pending.streamChunkCount} bytes=${pending.streamByteCount}`);
580
604
  clearTimeout(pending.timeout);
581
605
  if (!pending.streamDone) {
582
606
  pending.streamDone = true;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cortexkit/anthropic-auth-core",
3
- "version": "1.5.0",
3
+ "version": "1.6.0",
4
4
  "type": "module",
5
5
  "repository": {
6
6
  "type": "git",