@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.
- package/README.md +433 -6
- package/dist/auth/index.cjs +188 -1
- package/dist/auth/index.cjs.map +1 -1
- package/dist/auth/index.d.cts +154 -138
- package/dist/auth/index.d.ts +154 -138
- package/dist/auth/index.js +188 -2
- package/dist/auth/index.js.map +1 -1
- package/dist/backends/claude.cjs +341 -22
- package/dist/backends/claude.cjs.map +1 -1
- package/dist/backends/claude.d.cts +2 -1
- package/dist/backends/claude.d.ts +2 -1
- package/dist/backends/claude.js +341 -22
- package/dist/backends/claude.js.map +1 -1
- package/dist/backends/copilot.cjs +133 -25
- package/dist/backends/copilot.cjs.map +1 -1
- package/dist/backends/copilot.d.cts +2 -1
- package/dist/backends/copilot.d.ts +2 -1
- package/dist/backends/copilot.js +133 -25
- package/dist/backends/copilot.js.map +1 -1
- package/dist/backends/vercel-ai.cjs +66 -19
- package/dist/backends/vercel-ai.cjs.map +1 -1
- package/dist/backends/vercel-ai.d.cts +1 -1
- package/dist/backends/vercel-ai.d.ts +1 -1
- package/dist/backends/vercel-ai.js +66 -19
- package/dist/backends/vercel-ai.js.map +1 -1
- package/dist/chat/accumulator.cjs +147 -0
- package/dist/chat/accumulator.cjs.map +1 -0
- package/dist/chat/accumulator.d.cts +61 -0
- package/dist/chat/accumulator.d.ts +61 -0
- package/dist/chat/accumulator.js +145 -0
- package/dist/chat/accumulator.js.map +1 -0
- package/dist/chat/backends.cjs +3534 -0
- package/dist/chat/backends.cjs.map +1 -0
- package/dist/chat/backends.d.cts +62 -0
- package/dist/chat/backends.d.ts +62 -0
- package/dist/chat/backends.js +3501 -0
- package/dist/chat/backends.js.map +1 -0
- package/dist/chat/context.cjs +230 -0
- package/dist/chat/context.cjs.map +1 -0
- package/dist/chat/context.d.cts +167 -0
- package/dist/chat/context.d.ts +167 -0
- package/dist/chat/context.js +227 -0
- package/dist/chat/context.js.map +1 -0
- package/dist/chat/core.cjs +282 -0
- package/dist/chat/core.cjs.map +1 -0
- package/dist/chat/core.d.cts +435 -0
- package/dist/chat/core.d.ts +435 -0
- package/dist/chat/core.js +261 -0
- package/dist/chat/core.js.map +1 -0
- package/dist/chat/errors.cjs +251 -0
- package/dist/chat/errors.cjs.map +1 -0
- package/dist/chat/errors.d.cts +122 -0
- package/dist/chat/errors.d.ts +122 -0
- package/dist/chat/errors.js +243 -0
- package/dist/chat/errors.js.map +1 -0
- package/dist/chat/events.cjs +203 -0
- package/dist/chat/events.cjs.map +1 -0
- package/dist/chat/events.d.cts +241 -0
- package/dist/chat/events.d.ts +241 -0
- package/dist/chat/events.js +196 -0
- package/dist/chat/events.js.map +1 -0
- package/dist/chat/index.cjs +5359 -0
- package/dist/chat/index.cjs.map +1 -0
- package/dist/chat/index.d.cts +52 -0
- package/dist/chat/index.d.ts +52 -0
- package/dist/chat/index.js +5296 -0
- package/dist/chat/index.js.map +1 -0
- package/dist/chat/react.cjs +2739 -0
- package/dist/chat/react.cjs.map +1 -0
- package/dist/chat/react.d.cts +619 -0
- package/dist/chat/react.d.ts +619 -0
- package/dist/chat/react.js +2714 -0
- package/dist/chat/react.js.map +1 -0
- package/dist/chat/runtime.cjs +1030 -0
- package/dist/chat/runtime.cjs.map +1 -0
- package/dist/chat/runtime.d.cts +118 -0
- package/dist/chat/runtime.d.ts +118 -0
- package/dist/chat/runtime.js +1028 -0
- package/dist/chat/runtime.js.map +1 -0
- package/dist/chat/server.cjs +643 -0
- package/dist/chat/server.cjs.map +1 -0
- package/dist/chat/server.d.cts +287 -0
- package/dist/chat/server.d.ts +287 -0
- package/dist/chat/server.js +617 -0
- package/dist/chat/server.js.map +1 -0
- package/dist/chat/sessions.cjs +398 -0
- package/dist/chat/sessions.cjs.map +1 -0
- package/dist/chat/sessions.d.cts +239 -0
- package/dist/chat/sessions.d.ts +239 -0
- package/dist/chat/sessions.js +394 -0
- package/dist/chat/sessions.js.map +1 -0
- package/dist/chat/state.cjs +177 -0
- package/dist/chat/state.cjs.map +1 -0
- package/dist/chat/state.d.cts +92 -0
- package/dist/chat/state.d.ts +92 -0
- package/dist/chat/state.js +167 -0
- package/dist/chat/state.js.map +1 -0
- package/dist/chat/storage.cjs +240 -0
- package/dist/chat/storage.cjs.map +1 -0
- package/dist/chat/storage.d.cts +191 -0
- package/dist/chat/storage.d.ts +191 -0
- package/dist/chat/storage.js +236 -0
- package/dist/chat/storage.js.map +1 -0
- package/dist/errors-BDLbNu9w.d.cts +13 -0
- package/dist/errors-BDLbNu9w.d.ts +13 -0
- package/dist/in-process-transport-C2oPTYs6.d.ts +223 -0
- package/dist/in-process-transport-DG-w5G6k.d.cts +223 -0
- package/dist/index.cjs +25 -13
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +32 -4
- package/dist/index.d.ts +32 -4
- package/dist/index.js +25 -13
- package/dist/index.js.map +1 -1
- package/dist/transport-D1OaUgRk.d.ts +67 -0
- package/dist/transport-DX1Nhm4N.d.cts +67 -0
- package/dist/types-Bh5AhqD-.d.ts +141 -0
- package/dist/types-CGF7AEX1.d.cts +141 -0
- package/dist/{types-BvwNzZCj.d.cts → types-CqvUAYxt.d.cts} +21 -3
- package/dist/{types-BvwNzZCj.d.ts → types-CqvUAYxt.d.ts} +21 -3
- package/dist/types-DLZzlJxt.d.ts +39 -0
- package/dist/types-tE0CXwBl.d.cts +39 -0
- package/package.json +149 -2
package/dist/auth/index.d.ts
CHANGED
|
@@ -1,140 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
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
|
-
|
|
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 };
|
package/dist/auth/index.js
CHANGED
|
@@ -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
|
|
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
|
-
|
|
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
|