@witqq/agent-sdk 0.6.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (122) hide show
  1. package/README.md +433 -6
  2. package/dist/auth/index.cjs +188 -1
  3. package/dist/auth/index.cjs.map +1 -1
  4. package/dist/auth/index.d.cts +154 -138
  5. package/dist/auth/index.d.ts +154 -138
  6. package/dist/auth/index.js +188 -2
  7. package/dist/auth/index.js.map +1 -1
  8. package/dist/backends/claude.cjs +341 -22
  9. package/dist/backends/claude.cjs.map +1 -1
  10. package/dist/backends/claude.d.cts +2 -1
  11. package/dist/backends/claude.d.ts +2 -1
  12. package/dist/backends/claude.js +341 -22
  13. package/dist/backends/claude.js.map +1 -1
  14. package/dist/backends/copilot.cjs +133 -25
  15. package/dist/backends/copilot.cjs.map +1 -1
  16. package/dist/backends/copilot.d.cts +2 -1
  17. package/dist/backends/copilot.d.ts +2 -1
  18. package/dist/backends/copilot.js +133 -25
  19. package/dist/backends/copilot.js.map +1 -1
  20. package/dist/backends/vercel-ai.cjs +66 -19
  21. package/dist/backends/vercel-ai.cjs.map +1 -1
  22. package/dist/backends/vercel-ai.d.cts +1 -1
  23. package/dist/backends/vercel-ai.d.ts +1 -1
  24. package/dist/backends/vercel-ai.js +66 -19
  25. package/dist/backends/vercel-ai.js.map +1 -1
  26. package/dist/chat/accumulator.cjs +147 -0
  27. package/dist/chat/accumulator.cjs.map +1 -0
  28. package/dist/chat/accumulator.d.cts +61 -0
  29. package/dist/chat/accumulator.d.ts +61 -0
  30. package/dist/chat/accumulator.js +145 -0
  31. package/dist/chat/accumulator.js.map +1 -0
  32. package/dist/chat/backends.cjs +3534 -0
  33. package/dist/chat/backends.cjs.map +1 -0
  34. package/dist/chat/backends.d.cts +62 -0
  35. package/dist/chat/backends.d.ts +62 -0
  36. package/dist/chat/backends.js +3501 -0
  37. package/dist/chat/backends.js.map +1 -0
  38. package/dist/chat/context.cjs +230 -0
  39. package/dist/chat/context.cjs.map +1 -0
  40. package/dist/chat/context.d.cts +167 -0
  41. package/dist/chat/context.d.ts +167 -0
  42. package/dist/chat/context.js +227 -0
  43. package/dist/chat/context.js.map +1 -0
  44. package/dist/chat/core.cjs +282 -0
  45. package/dist/chat/core.cjs.map +1 -0
  46. package/dist/chat/core.d.cts +435 -0
  47. package/dist/chat/core.d.ts +435 -0
  48. package/dist/chat/core.js +261 -0
  49. package/dist/chat/core.js.map +1 -0
  50. package/dist/chat/errors.cjs +251 -0
  51. package/dist/chat/errors.cjs.map +1 -0
  52. package/dist/chat/errors.d.cts +122 -0
  53. package/dist/chat/errors.d.ts +122 -0
  54. package/dist/chat/errors.js +243 -0
  55. package/dist/chat/errors.js.map +1 -0
  56. package/dist/chat/events.cjs +203 -0
  57. package/dist/chat/events.cjs.map +1 -0
  58. package/dist/chat/events.d.cts +241 -0
  59. package/dist/chat/events.d.ts +241 -0
  60. package/dist/chat/events.js +196 -0
  61. package/dist/chat/events.js.map +1 -0
  62. package/dist/chat/index.cjs +5359 -0
  63. package/dist/chat/index.cjs.map +1 -0
  64. package/dist/chat/index.d.cts +52 -0
  65. package/dist/chat/index.d.ts +52 -0
  66. package/dist/chat/index.js +5296 -0
  67. package/dist/chat/index.js.map +1 -0
  68. package/dist/chat/react.cjs +2739 -0
  69. package/dist/chat/react.cjs.map +1 -0
  70. package/dist/chat/react.d.cts +619 -0
  71. package/dist/chat/react.d.ts +619 -0
  72. package/dist/chat/react.js +2714 -0
  73. package/dist/chat/react.js.map +1 -0
  74. package/dist/chat/runtime.cjs +1030 -0
  75. package/dist/chat/runtime.cjs.map +1 -0
  76. package/dist/chat/runtime.d.cts +118 -0
  77. package/dist/chat/runtime.d.ts +118 -0
  78. package/dist/chat/runtime.js +1028 -0
  79. package/dist/chat/runtime.js.map +1 -0
  80. package/dist/chat/server.cjs +643 -0
  81. package/dist/chat/server.cjs.map +1 -0
  82. package/dist/chat/server.d.cts +287 -0
  83. package/dist/chat/server.d.ts +287 -0
  84. package/dist/chat/server.js +617 -0
  85. package/dist/chat/server.js.map +1 -0
  86. package/dist/chat/sessions.cjs +398 -0
  87. package/dist/chat/sessions.cjs.map +1 -0
  88. package/dist/chat/sessions.d.cts +239 -0
  89. package/dist/chat/sessions.d.ts +239 -0
  90. package/dist/chat/sessions.js +394 -0
  91. package/dist/chat/sessions.js.map +1 -0
  92. package/dist/chat/state.cjs +177 -0
  93. package/dist/chat/state.cjs.map +1 -0
  94. package/dist/chat/state.d.cts +92 -0
  95. package/dist/chat/state.d.ts +92 -0
  96. package/dist/chat/state.js +167 -0
  97. package/dist/chat/state.js.map +1 -0
  98. package/dist/chat/storage.cjs +240 -0
  99. package/dist/chat/storage.cjs.map +1 -0
  100. package/dist/chat/storage.d.cts +191 -0
  101. package/dist/chat/storage.d.ts +191 -0
  102. package/dist/chat/storage.js +236 -0
  103. package/dist/chat/storage.js.map +1 -0
  104. package/dist/errors-BDLbNu9w.d.cts +13 -0
  105. package/dist/errors-BDLbNu9w.d.ts +13 -0
  106. package/dist/in-process-transport-C2oPTYs6.d.ts +223 -0
  107. package/dist/in-process-transport-DG-w5G6k.d.cts +223 -0
  108. package/dist/index.cjs +25 -13
  109. package/dist/index.cjs.map +1 -1
  110. package/dist/index.d.cts +32 -4
  111. package/dist/index.d.ts +32 -4
  112. package/dist/index.js +25 -13
  113. package/dist/index.js.map +1 -1
  114. package/dist/transport-D1OaUgRk.d.ts +67 -0
  115. package/dist/transport-DX1Nhm4N.d.cts +67 -0
  116. package/dist/types-Bh5AhqD-.d.ts +141 -0
  117. package/dist/types-CGF7AEX1.d.cts +141 -0
  118. package/dist/{types-BvwNzZCj.d.cts → types-CqvUAYxt.d.cts} +21 -3
  119. package/dist/{types-BvwNzZCj.d.ts → types-CqvUAYxt.d.ts} +21 -3
  120. package/dist/types-DLZzlJxt.d.ts +39 -0
  121. package/dist/types-tE0CXwBl.d.cts +39 -0
  122. package/package.json +149 -2
@@ -1,140 +1,6 @@
1
- /**
2
- * Base auth token returned by all auth providers.
3
- *
4
- * @example
5
- * ```ts
6
- * import type { AuthToken } from "@witqq/agent-sdk/auth";
7
- *
8
- * const token: AuthToken = {
9
- * accessToken: "gho_abc123...",
10
- * tokenType: "bearer",
11
- * obtainedAt: Date.now(),
12
- * };
13
- * ```
14
- */
15
- interface AuthToken {
16
- /** The access token string */
17
- accessToken: string;
18
- /** Token type (e.g. "bearer") */
19
- tokenType: string;
20
- /** Seconds until token expires (undefined = long-lived) */
21
- expiresIn?: number;
22
- /** Timestamp when the token was obtained */
23
- obtainedAt: number;
24
- }
25
- /**
26
- * Copilot-specific token (GitHub OAuth, long-lived).
27
- *
28
- * @example
29
- * ```ts
30
- * import type { CopilotAuthToken } from "@witqq/agent-sdk/auth";
31
- *
32
- * const token: CopilotAuthToken = {
33
- * accessToken: "gho_abc123...",
34
- * tokenType: "bearer",
35
- * obtainedAt: Date.now(),
36
- * login: "octocat",
37
- * };
38
- * ```
39
- */
40
- interface CopilotAuthToken extends AuthToken {
41
- /** GitHub user login associated with the token */
42
- login?: string;
43
- }
44
- /**
45
- * Claude-specific token (OAuth+PKCE, expires in 8h).
46
- *
47
- * @example
48
- * ```ts
49
- * import type { ClaudeAuthToken } from "@witqq/agent-sdk/auth";
50
- *
51
- * const token: ClaudeAuthToken = {
52
- * accessToken: "sk-ant-oat01-...",
53
- * tokenType: "bearer",
54
- * expiresIn: 28800,
55
- * obtainedAt: Date.now(),
56
- * refreshToken: "sk-ant-rt01-...",
57
- * scopes: ["user:inference", "user:profile"],
58
- * };
59
- * ```
60
- */
61
- interface ClaudeAuthToken extends AuthToken {
62
- /** Refresh token for obtaining new access tokens */
63
- refreshToken: string;
64
- /** OAuth scopes granted */
65
- scopes: string[];
66
- }
67
- /**
68
- * Result of initiating a GitHub Device Flow.
69
- *
70
- * @example
71
- * ```ts
72
- * import { CopilotAuth } from "@witqq/agent-sdk/auth";
73
- *
74
- * const auth = new CopilotAuth();
75
- * const { userCode, verificationUrl, waitForToken } = await auth.startDeviceFlow();
76
- * console.log(`Open ${verificationUrl} and enter code: ${userCode}`);
77
- * const token = await waitForToken();
78
- * ```
79
- */
80
- interface DeviceFlowResult {
81
- /** The code the user must enter at the verification URL */
82
- userCode: string;
83
- /** URL where the user enters the code */
84
- verificationUrl: string;
85
- /** Polls GitHub until user authorizes; resolves with token */
86
- waitForToken: (signal?: AbortSignal) => Promise<CopilotAuthToken>;
87
- }
88
- /** Options for starting a Claude OAuth flow */
89
- interface OAuthFlowOptions {
90
- /** The redirect URI registered with the OAuth app */
91
- redirectUri?: string;
92
- /** OAuth scopes to request (defaults to user:profile user:inference) */
93
- scopes?: string;
94
- }
95
- /**
96
- * Result of initiating a Claude OAuth flow.
97
- *
98
- * @example
99
- * ```ts
100
- * import type { OAuthFlowResult } from "@witqq/agent-sdk/auth";
101
- *
102
- * const result: OAuthFlowResult = {
103
- * authorizeUrl: "https://claude.ai/oauth/authorize?...",
104
- * completeAuth: async (code) => ({ ... }),
105
- * };
106
- * // Open result.authorizeUrl in browser, get code from redirect
107
- * const token = await result.completeAuth(code);
108
- * ```
109
- */
110
- interface OAuthFlowResult {
111
- /** URL to open in browser for user authorization */
112
- authorizeUrl: string;
113
- /** Exchange the authorization code (or full redirect URL) for tokens */
114
- completeAuth: (codeOrUrl: string) => Promise<ClaudeAuthToken>;
115
- }
116
- /** Base error for auth operations.
117
- * @param message - Error description
118
- * @param options - Standard ErrorOptions (e.g. cause)
119
- */
120
- declare class AuthError extends Error {
121
- constructor(message: string, options?: ErrorOptions);
122
- }
123
- /** Device code expired before user authorized */
124
- declare class DeviceCodeExpiredError extends AuthError {
125
- constructor();
126
- }
127
- /** User denied access during OAuth flow */
128
- declare class AccessDeniedError extends AuthError {
129
- constructor();
130
- }
131
- /** Token exchange or refresh failed.
132
- * @param message - Error description
133
- * @param options - Standard ErrorOptions (e.g. cause)
134
- */
135
- declare class TokenExchangeError extends AuthError {
136
- constructor(message: string, options?: ErrorOptions);
137
- }
1
+ import { D as DeviceFlowResult, O as OAuthFlowOptions, a as OAuthFlowResult, C as ClaudeAuthToken, A as AuthToken } from '../types-Bh5AhqD-.js';
2
+ export { b as AccessDeniedError, c as AuthError, d as CopilotAuthToken, e as DeviceCodeExpiredError, T as TokenExchangeError } from '../types-Bh5AhqD-.js';
3
+ import '../errors-BDLbNu9w.js';
138
4
 
139
5
  /** Fetch function type for dependency injection in tests */
140
6
  type FetchFn$1 = typeof globalThis.fetch;
@@ -268,4 +134,154 @@ declare class ClaudeAuth {
268
134
  private mapTokenResponse;
269
135
  }
270
136
 
271
- export { AccessDeniedError, AuthError, type AuthToken, ClaudeAuth, type ClaudeAuthToken, CopilotAuth, type CopilotAuthToken, DeviceCodeExpiredError, type DeviceFlowResult, type OAuthFlowOptions, type OAuthFlowResult, TokenExchangeError };
137
+ /**
138
+ * Automatic background token refresh manager.
139
+ *
140
+ * Schedules token refresh at a configurable threshold before expiry
141
+ * (default 80% of token lifetime). Emits events on refresh, failure,
142
+ * and token expiry. Handles retry on failure and clean disposal.
143
+ *
144
+ * When all retries are exhausted but the token hasn't expired yet,
145
+ * the manager waits until the token's expiry time and then starts
146
+ * a fresh retry cycle. This continues until refresh succeeds or
147
+ * the token expires.
148
+ *
149
+ * @example Basic usage
150
+ * ```ts
151
+ * import { TokenRefreshManager } from "@witqq/agent-sdk/auth";
152
+ *
153
+ * const manager = new TokenRefreshManager({
154
+ * token: claudeToken,
155
+ * refresh: (rt) => claudeAuth.refreshToken(rt),
156
+ * });
157
+ * manager.on("refreshed", (newToken) => { tokenStore.save("claude", newToken); });
158
+ * manager.on("error", (err) => { console.error("Refresh failed:", err); });
159
+ * manager.start();
160
+ * // ...later
161
+ * manager.dispose();
162
+ * ```
163
+ *
164
+ * @example Integration with createAuthHandler
165
+ * ```ts
166
+ * import { TokenRefreshManager } from "@witqq/agent-sdk/auth";
167
+ * import { createAuthHandler } from "@witqq/agent-sdk/chat/server";
168
+ * import type { ClaudeAuthToken } from "@witqq/agent-sdk/auth";
169
+ *
170
+ * let refreshManager: TokenRefreshManager | undefined;
171
+ *
172
+ * const authHandler = createAuthHandler({
173
+ * tokenStore,
174
+ * onAuth: (provider, token) => {
175
+ * // Clean up previous manager
176
+ * refreshManager?.dispose();
177
+ * refreshManager = undefined;
178
+ *
179
+ * if (provider === "claude" && token.expiresIn) {
180
+ * refreshManager = new TokenRefreshManager({
181
+ * token,
182
+ * refresh: (t) =>
183
+ * claudeAuth.refreshToken((t as ClaudeAuthToken).refreshToken),
184
+ * });
185
+ * refreshManager.on("refreshed", (newToken) => {
186
+ * tokenStore.save("claude", newToken);
187
+ * });
188
+ * refreshManager.on("expired", () => {
189
+ * console.warn("Claude token expired — re-authentication required");
190
+ * });
191
+ * refreshManager.start();
192
+ * }
193
+ * },
194
+ * });
195
+ * ```
196
+ */
197
+
198
+ /** Events emitted by TokenRefreshManager */
199
+ interface TokenRefreshEvents {
200
+ /** Emitted when token was successfully refreshed */
201
+ refreshed: (token: AuthToken) => void;
202
+ /** Emitted when refresh attempt failed (may retry) */
203
+ error: (error: Error, attempt: number) => void;
204
+ /** Emitted when token expired and could not be refreshed */
205
+ expired: () => void;
206
+ /** Emitted when manager is disposed */
207
+ disposed: () => void;
208
+ }
209
+ /** Configuration for TokenRefreshManager */
210
+ interface TokenRefreshOptions {
211
+ /** Current token with expiresIn and obtainedAt */
212
+ token: AuthToken;
213
+ /**
214
+ * Function that performs the actual token refresh.
215
+ * Receives the current token and returns a new one.
216
+ */
217
+ refresh: (token: AuthToken) => Promise<AuthToken>;
218
+ /**
219
+ * Fraction of token lifetime at which to trigger refresh (0-1).
220
+ * Default: 0.8 (refresh at 80% of lifetime, i.e. with 20% remaining)
221
+ */
222
+ refreshThreshold?: number;
223
+ /**
224
+ * Maximum retry attempts on refresh failure. Default: 3
225
+ */
226
+ maxRetries?: number;
227
+ /**
228
+ * Base delay between retries in ms. Exponential backoff applied. Default: 1000
229
+ */
230
+ retryDelayMs?: number;
231
+ /**
232
+ * Minimum schedule delay in ms (prevents scheduling in the past). Default: 1000
233
+ */
234
+ minDelayMs?: number;
235
+ }
236
+ type EventName = keyof TokenRefreshEvents;
237
+ /**
238
+ * Background token refresh manager with event emission and retry logic.
239
+ *
240
+ * Lifecycle: `new` → `start()` → (auto-refreshes) → `stop()` or `dispose()`
241
+ */
242
+ declare class TokenRefreshManager {
243
+ private currentToken;
244
+ private readonly refreshFn;
245
+ private readonly threshold;
246
+ private readonly maxRetries;
247
+ private readonly retryDelayMs;
248
+ private readonly minDelayMs;
249
+ private timerId;
250
+ private running;
251
+ private disposed;
252
+ private readonly listeners;
253
+ constructor(options: TokenRefreshOptions);
254
+ /** Register an event listener */
255
+ on<K extends EventName>(event: K, listener: TokenRefreshEvents[K]): this;
256
+ /** Remove an event listener */
257
+ off<K extends EventName>(event: K, listener: TokenRefreshEvents[K]): this;
258
+ /** Current token managed by this instance */
259
+ get token(): AuthToken;
260
+ /** Whether the manager is currently running */
261
+ get isRunning(): boolean;
262
+ /** Whether the manager has been disposed */
263
+ get isDisposed(): boolean;
264
+ /**
265
+ * Start automatic refresh scheduling.
266
+ * If the token is already expired, emits "expired" immediately.
267
+ * If the token has no expiresIn, does nothing (long-lived token).
268
+ */
269
+ start(): void;
270
+ /** Stop automatic refresh (can be restarted with start()) */
271
+ stop(): void;
272
+ /**
273
+ * Update the managed token (e.g. after manual refresh).
274
+ * Reschedules automatic refresh if running.
275
+ */
276
+ updateToken(token: AuthToken): void;
277
+ /** Stop and clean up all resources */
278
+ dispose(): void;
279
+ private schedule;
280
+ private performRefresh;
281
+ private computeRefreshDelay;
282
+ private isTokenExpired;
283
+ private clearTimer;
284
+ private emit;
285
+ }
286
+
287
+ export { AuthToken, ClaudeAuth, ClaudeAuthToken, CopilotAuth, DeviceFlowResult, OAuthFlowOptions, OAuthFlowResult, type TokenRefreshEvents, TokenRefreshManager, type TokenRefreshOptions };
@@ -1,7 +1,21 @@
1
1
  import { createHash, randomBytes } from 'crypto';
2
2
 
3
+ // src/errors.ts
4
+ var AgentSDKError = class extends Error {
5
+ /** @internal Marker for cross-bundle identity checks */
6
+ _agentSDKError = true;
7
+ constructor(message, options) {
8
+ super(message, options);
9
+ this.name = "AgentSDKError";
10
+ }
11
+ /** Check if an error is an AgentSDKError (works across bundled copies) */
12
+ static is(error) {
13
+ return error instanceof Error && "_agentSDKError" in error && error._agentSDKError === true;
14
+ }
15
+ };
16
+
3
17
  // src/auth/types.ts
4
- var AuthError = class extends Error {
18
+ var AuthError = class extends AgentSDKError {
5
19
  constructor(message, options) {
6
20
  super(message, options);
7
21
  this.name = "AuthError";
@@ -347,6 +361,178 @@ function hexEncode(bytes) {
347
361
  return Buffer.from(bytes).toString("hex");
348
362
  }
349
363
 
350
- export { AccessDeniedError, AuthError, ClaudeAuth, CopilotAuth, DeviceCodeExpiredError, TokenExchangeError };
364
+ // src/auth/refresh-manager.ts
365
+ var TokenRefreshManager = class {
366
+ currentToken;
367
+ refreshFn;
368
+ threshold;
369
+ maxRetries;
370
+ retryDelayMs;
371
+ minDelayMs;
372
+ timerId = null;
373
+ running = false;
374
+ disposed = false;
375
+ listeners = {
376
+ refreshed: /* @__PURE__ */ new Set(),
377
+ error: /* @__PURE__ */ new Set(),
378
+ expired: /* @__PURE__ */ new Set(),
379
+ disposed: /* @__PURE__ */ new Set()
380
+ };
381
+ constructor(options) {
382
+ this.currentToken = { ...options.token };
383
+ this.refreshFn = options.refresh;
384
+ this.threshold = options.refreshThreshold ?? 0.8;
385
+ this.maxRetries = options.maxRetries ?? 3;
386
+ this.retryDelayMs = options.retryDelayMs ?? 1e3;
387
+ this.minDelayMs = options.minDelayMs ?? 1e3;
388
+ }
389
+ /** Register an event listener */
390
+ on(event, listener) {
391
+ this.listeners[event].add(listener);
392
+ return this;
393
+ }
394
+ /** Remove an event listener */
395
+ off(event, listener) {
396
+ this.listeners[event].delete(listener);
397
+ return this;
398
+ }
399
+ /** Current token managed by this instance */
400
+ get token() {
401
+ return { ...this.currentToken };
402
+ }
403
+ /** Whether the manager is currently running */
404
+ get isRunning() {
405
+ return this.running;
406
+ }
407
+ /** Whether the manager has been disposed */
408
+ get isDisposed() {
409
+ return this.disposed;
410
+ }
411
+ /**
412
+ * Start automatic refresh scheduling.
413
+ * If the token is already expired, emits "expired" immediately.
414
+ * If the token has no expiresIn, does nothing (long-lived token).
415
+ */
416
+ start() {
417
+ if (this.disposed) return;
418
+ if (this.running) return;
419
+ this.running = true;
420
+ this.schedule();
421
+ }
422
+ /** Stop automatic refresh (can be restarted with start()) */
423
+ stop() {
424
+ this.running = false;
425
+ this.clearTimer();
426
+ }
427
+ /**
428
+ * Update the managed token (e.g. after manual refresh).
429
+ * Reschedules automatic refresh if running.
430
+ */
431
+ updateToken(token) {
432
+ if (this.disposed) return;
433
+ this.currentToken = { ...token };
434
+ if (this.running) {
435
+ this.clearTimer();
436
+ this.schedule();
437
+ }
438
+ }
439
+ /** Stop and clean up all resources */
440
+ dispose() {
441
+ if (this.disposed) return;
442
+ this.stop();
443
+ this.disposed = true;
444
+ this.emit("disposed");
445
+ for (const set of Object.values(this.listeners)) {
446
+ set.clear();
447
+ }
448
+ }
449
+ // ─── Private ──────────────────────────────────────────────────
450
+ schedule() {
451
+ if (!this.running || this.disposed) return;
452
+ const delayMs = this.computeRefreshDelay();
453
+ if (delayMs === null) {
454
+ return;
455
+ }
456
+ if (delayMs <= 0) {
457
+ this.timerId = setTimeout(() => {
458
+ this.timerId = null;
459
+ if (!this.running || this.disposed) return;
460
+ void this.performRefresh();
461
+ }, 0);
462
+ return;
463
+ }
464
+ this.timerId = setTimeout(() => {
465
+ this.timerId = null;
466
+ if (!this.running || this.disposed) return;
467
+ void this.performRefresh();
468
+ }, Math.max(delayMs, this.minDelayMs));
469
+ }
470
+ async performRefresh(attempt = 1) {
471
+ if (!this.running || this.disposed) return;
472
+ try {
473
+ const newToken = await this.refreshFn(this.currentToken);
474
+ if (!this.running || this.disposed) return;
475
+ this.currentToken = { ...newToken };
476
+ this.emit("refreshed", newToken);
477
+ this.schedule();
478
+ } catch (err) {
479
+ if (!this.running || this.disposed) return;
480
+ const error = err instanceof Error ? err : new Error(String(err));
481
+ this.emit("error", error, attempt);
482
+ if (attempt < this.maxRetries) {
483
+ const delay = this.retryDelayMs * Math.pow(2, attempt - 1);
484
+ this.timerId = setTimeout(() => {
485
+ this.timerId = null;
486
+ if (!this.running || this.disposed) return;
487
+ void this.performRefresh(attempt + 1);
488
+ }, delay);
489
+ } else {
490
+ if (this.isTokenExpired()) {
491
+ this.running = false;
492
+ this.emit("expired");
493
+ } else {
494
+ const expiresIn = this.currentToken.expiresIn;
495
+ if (expiresIn == null) return;
496
+ const expiresAt = this.currentToken.obtainedAt + expiresIn * 1e3;
497
+ const waitMs = Math.max(expiresAt - Date.now(), this.minDelayMs);
498
+ this.timerId = setTimeout(() => {
499
+ this.timerId = null;
500
+ if (!this.running || this.disposed) return;
501
+ void this.performRefresh();
502
+ }, waitMs);
503
+ }
504
+ }
505
+ }
506
+ }
507
+ computeRefreshDelay() {
508
+ if (this.currentToken.expiresIn == null) return null;
509
+ const lifetimeMs = this.currentToken.expiresIn * 1e3;
510
+ const refreshAtMs = this.currentToken.obtainedAt + lifetimeMs * this.threshold;
511
+ const now = Date.now();
512
+ const delay = refreshAtMs - now;
513
+ return delay;
514
+ }
515
+ isTokenExpired() {
516
+ if (this.currentToken.expiresIn == null) return false;
517
+ const expiresAt = this.currentToken.obtainedAt + this.currentToken.expiresIn * 1e3;
518
+ return Date.now() >= expiresAt;
519
+ }
520
+ clearTimer() {
521
+ if (this.timerId !== null) {
522
+ clearTimeout(this.timerId);
523
+ this.timerId = null;
524
+ }
525
+ }
526
+ emit(event, ...args) {
527
+ for (const listener of this.listeners[event]) {
528
+ try {
529
+ listener(...args);
530
+ } catch {
531
+ }
532
+ }
533
+ }
534
+ };
535
+
536
+ export { AccessDeniedError, AuthError, ClaudeAuth, CopilotAuth, DeviceCodeExpiredError, TokenExchangeError, TokenRefreshManager };
351
537
  //# sourceMappingURL=index.js.map
352
538
  //# sourceMappingURL=index.js.map