fetchguard 1.1.4 → 1.2.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.
- package/README.md +42 -14
- package/dist/index.d.ts +37 -21
- package/dist/index.js +26 -10
- package/dist/index.js.map +1 -1
- package/dist/worker.js +38 -26
- package/dist/worker.js.map +1 -1
- package/package.json +4 -5
package/README.md
CHANGED
|
@@ -372,10 +372,10 @@ const myProvider = createProvider({
|
|
|
372
372
|
registerProvider('otp-auth', myProvider)
|
|
373
373
|
const api = createClient({ provider: 'otp-auth' })
|
|
374
374
|
|
|
375
|
-
// Call custom method with
|
|
376
|
-
await api.call('loginWithOTP',
|
|
377
|
-
await api.call('loginWithGoogle',
|
|
378
|
-
await api.call('refreshToken',
|
|
375
|
+
// Call custom method with event emission
|
|
376
|
+
await api.call('loginWithOTP', true, { phone: '+1234567890', code: '123456' })
|
|
377
|
+
await api.call('loginWithGoogle', false, { token: 'google_token' }) // Silent
|
|
378
|
+
await api.call('refreshToken', true) // With event
|
|
379
379
|
```
|
|
380
380
|
|
|
381
381
|
## Domain Allow-List
|
|
@@ -428,10 +428,10 @@ The library targets modern browsers with Web Worker and (optionally) IndexedDB s
|
|
|
428
428
|
- `cancel(id)`: Cancel pending request
|
|
429
429
|
|
|
430
430
|
**Authentication:**
|
|
431
|
-
- `login(payload?,
|
|
432
|
-
- `logout(payload?,
|
|
433
|
-
- `refreshToken(
|
|
434
|
-
- `call(method,
|
|
431
|
+
- `login(payload?, emitEvent?)`: `Promise<Result<AuthResult>>` - Login with optional event emission (default: true)
|
|
432
|
+
- `logout(payload?, emitEvent?)`: `Promise<Result<AuthResult>>` - Logout with optional event emission (default: true)
|
|
433
|
+
- `refreshToken(emitEvent?)`: `Promise<Result<AuthResult>>` - Refresh access token with optional event emission (default: true)
|
|
434
|
+
- `call(method, emitEvent?, ...args)`: `Promise<Result<AuthResult>>` - Call custom provider methods with event emission
|
|
435
435
|
|
|
436
436
|
**Events:**
|
|
437
437
|
- `onAuthStateChanged(callback)`: `() => void` - Subscribe to auth state changes
|
|
@@ -443,7 +443,7 @@ The library targets modern browsers with Web Worker and (optionally) IndexedDB s
|
|
|
443
443
|
Types:
|
|
444
444
|
|
|
445
445
|
- ApiResponse<T> = { data: T; status: number; headers: Record<string, string> }
|
|
446
|
-
-
|
|
446
|
+
- AuthResult = { authenticated: boolean; user?: unknown; expiresAt?: number | null }
|
|
447
447
|
- FetchGuardRequestInit extends RequestInit with:
|
|
448
448
|
- requiresAuth?: boolean // default true
|
|
449
449
|
- includeHeaders?: boolean // default false
|
|
@@ -472,13 +472,41 @@ if (res.isOk()) {
|
|
|
472
472
|
|
|
473
473
|
Grouped error helpers are exported: `GeneralErrors`, `InitErrors`, `AuthErrors`, `DomainErrors`, `NetworkErrors`, `RequestErrors`.
|
|
474
474
|
|
|
475
|
-
## Auth
|
|
475
|
+
## Auth Methods and Events
|
|
476
476
|
|
|
477
|
-
|
|
477
|
+
### AuthResult Return Value
|
|
478
478
|
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
479
|
+
All auth methods (`login`, `logout`, `refreshToken`, `call`) now return `Promise<Result<AuthResult>>`:
|
|
480
|
+
|
|
481
|
+
```ts
|
|
482
|
+
interface AuthResult {
|
|
483
|
+
authenticated: boolean // Is user authenticated?
|
|
484
|
+
user?: unknown // User info (if available)
|
|
485
|
+
expiresAt?: number | null // Token expiry timestamp
|
|
486
|
+
}
|
|
487
|
+
```
|
|
488
|
+
|
|
489
|
+
### Event Emission Control
|
|
490
|
+
|
|
491
|
+
The `emitEvent` parameter controls whether `AUTH_STATE_CHANGED` event is emitted:
|
|
492
|
+
|
|
493
|
+
```ts
|
|
494
|
+
// Emit event (default - updates UI)
|
|
495
|
+
await api.login(credentials, true)
|
|
496
|
+
await api.login(credentials) // Same as above
|
|
497
|
+
|
|
498
|
+
// Silent (no event - useful for checks)
|
|
499
|
+
const result = await api.refreshToken(false)
|
|
500
|
+
if (result.isOk()) {
|
|
501
|
+
const { authenticated, expiresAt } = result.data
|
|
502
|
+
// Check state without triggering listeners
|
|
503
|
+
}
|
|
504
|
+
```
|
|
505
|
+
|
|
506
|
+
**Benefits:**
|
|
507
|
+
- ✅ Always get `AuthResult` back (no void)
|
|
508
|
+
- ✅ Simple boolean instead of 3-value enum
|
|
509
|
+
- ✅ Consistent API across all auth methods
|
|
482
510
|
|
|
483
511
|
## Roadmap
|
|
484
512
|
|
package/dist/index.d.ts
CHANGED
|
@@ -10,14 +10,31 @@ import * as ts_micro_result_factories_errors_advanced from 'ts-micro-result/fact
|
|
|
10
10
|
*/
|
|
11
11
|
/**
|
|
12
12
|
* Token info returned from provider
|
|
13
|
+
*
|
|
14
|
+
* All fields are optional to support various custom auth methods:
|
|
15
|
+
* - Standard login/refresh: returns token + optional fields
|
|
16
|
+
* - Update user info: may only return user (no token update)
|
|
17
|
+
* - Verify OTP: may return nothing (just validation)
|
|
18
|
+
* - Custom auth flows: flexible field combinations
|
|
13
19
|
*/
|
|
14
20
|
interface TokenInfo {
|
|
15
|
-
token
|
|
16
|
-
expiresAt?: number;
|
|
17
|
-
refreshToken?: string;
|
|
21
|
+
token?: string | null;
|
|
22
|
+
expiresAt?: number | null;
|
|
23
|
+
refreshToken?: string | null;
|
|
18
24
|
user?: unknown;
|
|
19
25
|
}
|
|
20
|
-
|
|
26
|
+
/**
|
|
27
|
+
* Auth result returned from auth operations and auth state changes
|
|
28
|
+
* Used by: login(), logout(), refreshToken(), onAuthStateChanged()
|
|
29
|
+
*/
|
|
30
|
+
interface AuthResult {
|
|
31
|
+
/** Whether user is authenticated (has valid non-expired token) */
|
|
32
|
+
authenticated: boolean;
|
|
33
|
+
/** User info from token (if available) */
|
|
34
|
+
user?: unknown;
|
|
35
|
+
/** Token expiry timestamp in milliseconds (if available) */
|
|
36
|
+
expiresAt?: number | null;
|
|
37
|
+
}
|
|
21
38
|
/**
|
|
22
39
|
* Interface for token provider
|
|
23
40
|
*
|
|
@@ -214,22 +231,28 @@ declare class FetchGuardClient {
|
|
|
214
231
|
/**
|
|
215
232
|
* Generic method to call any auth method on provider
|
|
216
233
|
* @param method - Method name (login, logout, loginWithPhone, etc.)
|
|
234
|
+
* @param emitEvent - Whether to emit AUTH_STATE_CHANGED event (default: true)
|
|
217
235
|
* @param args - Arguments to pass to the method
|
|
218
|
-
* @returns Result
|
|
236
|
+
* @returns Promise<Result<AuthResult>> - Always returns AuthResult
|
|
219
237
|
*/
|
|
220
|
-
call(method: string,
|
|
238
|
+
call(method: string, emitEvent?: boolean, ...args: unknown[]): Promise<Result<AuthResult>>;
|
|
221
239
|
/**
|
|
222
240
|
* Convenience wrapper for login
|
|
241
|
+
* @param payload - Login credentials
|
|
242
|
+
* @param emitEvent - Whether to emit AUTH_STATE_CHANGED event (default: true)
|
|
223
243
|
*/
|
|
224
|
-
login(payload?: unknown,
|
|
244
|
+
login(payload?: unknown, emitEvent?: boolean): Promise<Result<AuthResult>>;
|
|
225
245
|
/**
|
|
226
246
|
* Convenience wrapper for logout
|
|
247
|
+
* @param payload - Optional logout payload
|
|
248
|
+
* @param emitEvent - Whether to emit AUTH_STATE_CHANGED event (default: true)
|
|
227
249
|
*/
|
|
228
|
-
logout(payload?: unknown,
|
|
250
|
+
logout(payload?: unknown, emitEvent?: boolean): Promise<Result<AuthResult>>;
|
|
229
251
|
/**
|
|
230
252
|
* Convenience wrapper for refreshToken
|
|
253
|
+
* @param emitEvent - Whether to emit AUTH_STATE_CHANGED event (default: true)
|
|
231
254
|
*/
|
|
232
|
-
refreshToken(
|
|
255
|
+
refreshToken(emitEvent?: boolean): Promise<Result<AuthResult>>;
|
|
233
256
|
/**
|
|
234
257
|
* Check if worker is ready
|
|
235
258
|
*/
|
|
@@ -247,11 +270,7 @@ declare class FetchGuardClient {
|
|
|
247
270
|
/**
|
|
248
271
|
* Subscribe to auth state changes
|
|
249
272
|
*/
|
|
250
|
-
onAuthStateChanged(cb: (state:
|
|
251
|
-
authenticated: boolean;
|
|
252
|
-
expiresAt?: number | null;
|
|
253
|
-
user?: unknown;
|
|
254
|
-
}) => void): () => void;
|
|
273
|
+
onAuthStateChanged(cb: (state: AuthResult) => void): () => void;
|
|
255
274
|
/** Send PING and await PONG */
|
|
256
275
|
ping(): Promise<Result<{
|
|
257
276
|
timestamp: number;
|
|
@@ -313,7 +332,7 @@ interface MainPayloads {
|
|
|
313
332
|
AUTH_CALL: {
|
|
314
333
|
method: string;
|
|
315
334
|
args: unknown[];
|
|
316
|
-
|
|
335
|
+
emitEvent?: boolean;
|
|
317
336
|
};
|
|
318
337
|
CANCEL: undefined;
|
|
319
338
|
PING: {
|
|
@@ -335,11 +354,8 @@ interface WorkerPayloads {
|
|
|
335
354
|
level: 'info' | 'warn' | 'error';
|
|
336
355
|
message: string;
|
|
337
356
|
};
|
|
338
|
-
AUTH_STATE_CHANGED:
|
|
339
|
-
|
|
340
|
-
expiresAt?: number | null;
|
|
341
|
-
user?: unknown;
|
|
342
|
-
};
|
|
357
|
+
AUTH_STATE_CHANGED: AuthResult;
|
|
358
|
+
AUTH_CALL_RESULT: AuthResult;
|
|
343
359
|
FETCH_RESULT: {
|
|
344
360
|
status: number;
|
|
345
361
|
headers?: Record<string, string>;
|
|
@@ -571,4 +587,4 @@ declare function createBodyProvider(config: {
|
|
|
571
587
|
refreshTokenKey?: string;
|
|
572
588
|
}): TokenProvider;
|
|
573
589
|
|
|
574
|
-
export { type ApiResponse, AuthErrors, type
|
|
590
|
+
export { type ApiResponse, AuthErrors, type AuthResult, type AuthStrategy, DomainErrors, FetchGuardClient, type FetchGuardOptions, type FetchGuardRequestInit, GeneralErrors, InitErrors, MSG, type MainToWorkerMessage, type MessageType, NetworkErrors, type ProviderConfig, type ProviderPresetConfig, type RefreshTokenStorage, RequestErrors, type TokenInfo, type TokenParser, type TokenProvider, type WorkerConfig, type WorkerToMainMessage, bodyParser, bodyStrategy, clearProviders, cookieParser, cookieStrategy, createBodyProvider, createBodyStrategy, createClient, createCookieProvider, createCookieStrategy, createIndexedDBStorage, createProvider, getProvider, hasProvider, listProviders, registerProvider, unregisterProvider };
|
package/dist/index.js
CHANGED
|
@@ -15,6 +15,7 @@ var MSG = Object.freeze({
|
|
|
15
15
|
PONG: "PONG",
|
|
16
16
|
LOG: "LOG",
|
|
17
17
|
AUTH_STATE_CHANGED: "AUTH_STATE_CHANGED",
|
|
18
|
+
AUTH_CALL_RESULT: "AUTH_CALL_RESULT",
|
|
18
19
|
FETCH_RESULT: "FETCH_RESULT",
|
|
19
20
|
FETCH_ERROR: "FETCH_ERROR"
|
|
20
21
|
});
|
|
@@ -191,6 +192,14 @@ var FetchGuardClient = class {
|
|
|
191
192
|
for (const cb of this.authListeners) cb(payload);
|
|
192
193
|
return;
|
|
193
194
|
}
|
|
195
|
+
if (type === MSG.AUTH_CALL_RESULT) {
|
|
196
|
+
const request = this.pendingRequests.get(id);
|
|
197
|
+
if (request) {
|
|
198
|
+
this.pendingRequests.delete(id);
|
|
199
|
+
request.resolve(ok(payload));
|
|
200
|
+
}
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
194
203
|
}
|
|
195
204
|
/**
|
|
196
205
|
* Handle worker errors
|
|
@@ -298,12 +307,13 @@ var FetchGuardClient = class {
|
|
|
298
307
|
/**
|
|
299
308
|
* Generic method to call any auth method on provider
|
|
300
309
|
* @param method - Method name (login, logout, loginWithPhone, etc.)
|
|
310
|
+
* @param emitEvent - Whether to emit AUTH_STATE_CHANGED event (default: true)
|
|
301
311
|
* @param args - Arguments to pass to the method
|
|
302
|
-
* @returns Result
|
|
312
|
+
* @returns Promise<Result<AuthResult>> - Always returns AuthResult
|
|
303
313
|
*/
|
|
304
|
-
async call(method,
|
|
314
|
+
async call(method, emitEvent, ...args) {
|
|
305
315
|
const id = this.generateMessageId();
|
|
306
|
-
const message = { id, type: MSG.AUTH_CALL, payload: { method, args,
|
|
316
|
+
const message = { id, type: MSG.AUTH_CALL, payload: { method, args, emitEvent } };
|
|
307
317
|
return new Promise((resolve, reject) => {
|
|
308
318
|
this.pendingRequests.set(id, {
|
|
309
319
|
resolve: (r) => resolve(r),
|
|
@@ -320,23 +330,28 @@ var FetchGuardClient = class {
|
|
|
320
330
|
}
|
|
321
331
|
/**
|
|
322
332
|
* Convenience wrapper for login
|
|
333
|
+
* @param payload - Login credentials
|
|
334
|
+
* @param emitEvent - Whether to emit AUTH_STATE_CHANGED event (default: true)
|
|
323
335
|
*/
|
|
324
|
-
async login(payload,
|
|
336
|
+
async login(payload, emitEvent = true) {
|
|
325
337
|
const args = typeof payload === "undefined" ? [] : [payload];
|
|
326
|
-
return this.call("login",
|
|
338
|
+
return this.call("login", emitEvent, ...args);
|
|
327
339
|
}
|
|
328
340
|
/**
|
|
329
341
|
* Convenience wrapper for logout
|
|
342
|
+
* @param payload - Optional logout payload
|
|
343
|
+
* @param emitEvent - Whether to emit AUTH_STATE_CHANGED event (default: true)
|
|
330
344
|
*/
|
|
331
|
-
async logout(payload,
|
|
345
|
+
async logout(payload, emitEvent = true) {
|
|
332
346
|
const args = typeof payload === "undefined" ? [] : [payload];
|
|
333
|
-
return this.call("logout",
|
|
347
|
+
return this.call("logout", emitEvent, ...args);
|
|
334
348
|
}
|
|
335
349
|
/**
|
|
336
350
|
* Convenience wrapper for refreshToken
|
|
351
|
+
* @param emitEvent - Whether to emit AUTH_STATE_CHANGED event (default: true)
|
|
337
352
|
*/
|
|
338
|
-
async refreshToken(
|
|
339
|
-
return this.call("refreshToken",
|
|
353
|
+
async refreshToken(emitEvent = true) {
|
|
354
|
+
return this.call("refreshToken", emitEvent);
|
|
340
355
|
}
|
|
341
356
|
/**
|
|
342
357
|
* Check if worker is ready
|
|
@@ -547,7 +562,8 @@ function createProvider(config) {
|
|
|
547
562
|
token: "",
|
|
548
563
|
refreshToken: void 0,
|
|
549
564
|
expiresAt: void 0,
|
|
550
|
-
user:
|
|
565
|
+
user: null
|
|
566
|
+
// Explicitly clear user on logout
|
|
551
567
|
});
|
|
552
568
|
} catch (error) {
|
|
553
569
|
return err2(NetworkErrors.NetworkError({ message: String(error) }));
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/client.ts","../src/messages.ts","../src/constants.ts","../src/errors.ts","../src/utils/registry.ts","../src/provider/create-provider.ts","../src/provider/storage/indexeddb.ts","../src/provider/parser/body.ts","../src/provider/parser/cookie.ts","../src/provider/strategy/cookie.ts","../src/provider/strategy/body.ts","../src/provider/presets.ts"],"sourcesContent":["import type {\r\n FetchGuardOptions,\r\n FetchGuardRequestInit,\r\n WorkerConfig,\r\n ApiResponse,\r\n ProviderPresetConfig,\r\n AuthResponseMode\r\n} from './types'\r\nimport { fromJSON, ok, err, type Result } from 'ts-micro-result'\r\nimport { MSG } from './messages'\r\nimport {\r\n DEFAULT_REFRESH_EARLY_MS,\r\n DEFAULT_TIMEOUT_MS,\r\n DEFAULT_RETRY_COUNT,\r\n DEFAULT_RETRY_DELAY_MS\r\n} from './constants'\r\nimport { GeneralErrors, NetworkErrors } from './errors'\r\n\r\n/**\r\n * Queue item for sequential message processing\r\n * Inspired by old-workers/ApiWorkerService.ts\r\n */\r\ninterface QueueItem {\r\n id: string\r\n message: any\r\n resolve: (response: any) => void\r\n reject: (error: Error) => void\r\n timeout: ReturnType<typeof setTimeout>\r\n}\r\n\r\n/**\r\n * FetchGuard Client - main interface cho việc gọi API thông qua Web Worker\r\n */\r\nexport class FetchGuardClient {\r\n private worker: Worker\r\n private messageId = 0\r\n private pendingRequests = new Map<string, {\r\n resolve: (value: any) => void\r\n reject: (error: Error) => void\r\n }>()\r\n private authListeners = new Set<(state: { authenticated: boolean; expiresAt?: number | null; user?: unknown }) => void>()\r\n private readyListeners = new Set<() => void>()\r\n private isReady = false\r\n\r\n private requestQueue: QueueItem[] = []\r\n private isProcessingQueue = false\r\n private queueTimeout = 30000 // 30 seconds\r\n private setupResolve?: () => void\r\n private setupReject?: (error: Error) => void\r\n\r\n constructor(options: FetchGuardOptions) {\r\n this.worker = new Worker(new URL('./worker.js', import.meta.url), { \r\n type: 'module' \r\n })\r\n\r\n this.worker.onmessage = this.handleWorkerMessage.bind(this)\r\n this.worker.onerror = this.handleWorkerError.bind(this)\r\n\r\n this.initializeWorker(options)\r\n }\r\n\r\n /**\r\n * Initialize worker with config and provider\r\n */\r\n private async initializeWorker(options: FetchGuardOptions): Promise<void> {\r\n const config: WorkerConfig = {\r\n allowedDomains: options.allowedDomains || [],\r\n debug: options.debug || false,\r\n refreshEarlyMs: options.refreshEarlyMs ?? DEFAULT_REFRESH_EARLY_MS,\r\n defaultTimeoutMs: options.defaultTimeoutMs ?? DEFAULT_TIMEOUT_MS,\r\n retryCount: options.retryCount ?? DEFAULT_RETRY_COUNT,\r\n retryDelayMs: options.retryDelayMs ?? DEFAULT_RETRY_DELAY_MS\r\n }\r\n\r\n // Serialize provider config based on type\r\n let providerConfig: ProviderPresetConfig | string | null = null\r\n\r\n if (typeof options.provider === 'string') {\r\n // String = registry lookup (advanced usage)\r\n providerConfig = options.provider\r\n } else if ('type' in options.provider && options.provider.type) {\r\n // ProviderPresetConfig object (recommended)\r\n providerConfig = options.provider as ProviderPresetConfig\r\n } else {\r\n // TokenProvider instance - NOT SUPPORTED\r\n throw new Error(\r\n 'Direct TokenProvider instance is not supported. Use ProviderPresetConfig instead:\\n' +\r\n ' { type: \"cookie-auth\", refreshUrl: \"...\", loginUrl: \"...\", logoutUrl: \"...\" }\\n' +\r\n 'Or for custom providers, register in worker code and use string name.'\r\n )\r\n }\r\n\r\n const message = {\r\n id: this.generateMessageId(),\r\n type: MSG.SETUP,\r\n payload: {\r\n config,\r\n providerConfig\r\n }\r\n }\r\n\r\n return new Promise((resolve, reject) => {\r\n // Setup will respond with READY (no id, so we track separately)\r\n this.setupResolve = resolve\r\n this.setupReject = reject\r\n\r\n this.worker.postMessage(message)\r\n\r\n setTimeout(() => {\r\n if (this.setupReject) {\r\n this.setupReject(new Error('Worker setup timeout'))\r\n this.setupResolve = undefined\r\n this.setupReject = undefined\r\n }\r\n }, 10000)\r\n })\r\n }\r\n\r\n\r\n /**\r\n * Handle worker messages\r\n */\r\n private handleWorkerMessage(event: MessageEvent): void {\r\n const { id, type, payload } = event.data\r\n\r\n if (type === MSG.FETCH_RESULT || type === MSG.FETCH_ERROR) {\r\n const request = this.pendingRequests.get(id)\r\n if (!request) return\r\n\r\n this.pendingRequests.delete(id)\r\n\r\n if (type === MSG.FETCH_RESULT) {\r\n const status = payload?.status ?? 200\r\n const headers = payload?.headers ?? {}\r\n const body = String(payload?.body ?? '')\r\n let data: any\r\n try { data = JSON.parse(body) } catch { data = body }\r\n request.resolve(ok<ApiResponse>({ data, status, headers }))\r\n return\r\n }\r\n\r\n if (type === MSG.FETCH_ERROR) {\r\n const status = typeof payload?.status === 'number' ? payload.status : undefined\r\n if (typeof status === 'number') {\r\n request.resolve(err(NetworkErrors.HttpError({ message: String(payload?.error || 'HTTP error') }), undefined, status))\r\n } else {\r\n request.resolve(err(NetworkErrors.NetworkError({ message: String(payload?.error || 'Network error') })))\r\n }\r\n return\r\n }\r\n }\r\n\r\n if (type === MSG.RESULT) {\r\n const request = this.pendingRequests.get(id)\r\n if (!request) return\r\n\r\n this.pendingRequests.delete(id)\r\n\r\n if (payload && payload.result) {\r\n try {\r\n const result = fromJSON(JSON.stringify(payload.result))\r\n request.resolve(result)\r\n } catch (e) {\r\n request.resolve(err(GeneralErrors.ResultParse({ message: String(e) })))\r\n }\r\n }\r\n return\r\n }\r\n\r\n if (type === MSG.READY) {\r\n this.isReady = true\r\n\r\n // Notify ready listeners\r\n for (const listener of this.readyListeners) {\r\n listener()\r\n }\r\n\r\n if (this.setupResolve) {\r\n this.setupResolve()\r\n this.setupResolve = undefined\r\n this.setupReject = undefined\r\n }\r\n return\r\n }\r\n\r\n if (type === MSG.PONG) {\r\n const request = this.pendingRequests.get(id)\r\n if (request) {\r\n this.pendingRequests.delete(id)\r\n request.resolve(ok({ timestamp: payload?.timestamp }))\r\n }\r\n return\r\n }\r\n\r\n if (type === MSG.AUTH_STATE_CHANGED) {\r\n for (const cb of this.authListeners) cb(payload)\r\n return\r\n }\r\n }\r\n\r\n /**\r\n * Handle worker errors\r\n */\r\n private handleWorkerError(error: ErrorEvent): void {\r\n console.error('Worker error:', error)\r\n // Reject all pending requests\r\n for (const [id, request] of this.pendingRequests) {\r\n request.reject(new Error(`Worker error: ${error.message}`))\r\n }\r\n this.pendingRequests.clear()\r\n }\r\n\r\n /**\r\n * Generate unique message ID\r\n */\r\n private generateMessageId(): string {\r\n return `msg_${++this.messageId}_${Date.now()}`\r\n }\r\n\r\n /**\r\n * Make API request\r\n */\r\n async fetch(url: string, options: FetchGuardRequestInit = {}): Promise<Result<ApiResponse>> {\r\n const { result } = this.fetchWithId(url, options)\r\n return result\r\n }\r\n\r\n /**\r\n * Fetch with id for external cancellation\r\n * Returns { id, result, cancel } \r\n * Now uses queue system for sequential processing\r\n */\r\n fetchWithId(url: string, options: FetchGuardRequestInit = {}): {\r\n id: string\r\n result: Promise<Result<ApiResponse>>\r\n cancel: () => void\r\n } {\r\n const id = this.generateMessageId()\r\n\r\n const message = { id, type: MSG.FETCH, payload: { url, options } }\r\n\r\n const result = new Promise<Result<ApiResponse>>((resolve, reject) => {\r\n this.pendingRequests.set(id, {\r\n resolve: (response) => resolve(response),\r\n reject: (error) => reject(error)\r\n })\r\n })\r\n\r\n this.sendMessageQueued(message, 30000).catch((error) => {\r\n const request = this.pendingRequests.get(id)\r\n if (request) {\r\n this.pendingRequests.delete(id)\r\n request.reject(error)\r\n }\r\n })\r\n\r\n const cancel = () => this.cancel(id)\r\n\r\n return { id, result, cancel }\r\n }\r\n\r\n /**\r\n * Cancel a pending request by ID\r\n */\r\n cancel(id: string): void {\r\n const request = this.pendingRequests.get(id)\r\n if (request) {\r\n this.pendingRequests.delete(id)\r\n this.worker.postMessage({ id, type: MSG.CANCEL })\r\n request.reject(new Error('Request cancelled'))\r\n }\r\n }\r\n\r\n /**\r\n * Convenience methods\r\n */\r\n async get(url: string, options: Omit<FetchGuardRequestInit, 'method' | 'body'> = {}): Promise<Result<ApiResponse>> {\r\n return this.fetch(url, { ...options, method: 'GET' })\r\n }\r\n\r\n async post(url: string, body?: any, options: Omit<FetchGuardRequestInit, 'method' | 'body'> = {}): Promise<Result<ApiResponse>> {\r\n const headers = new Headers(options.headers)\r\n\r\n // Set Content-Type if not already set and body is being stringified\r\n if (body && !headers.has('Content-Type')) {\r\n headers.set('Content-Type', 'application/json')\r\n }\r\n\r\n return this.fetch(url, {\r\n ...options,\r\n headers,\r\n method: 'POST',\r\n body: body ? JSON.stringify(body) : undefined\r\n })\r\n }\r\n\r\n async put(url: string, body?: any, options: Omit<FetchGuardRequestInit, 'method' | 'body'> = {}): Promise<Result<ApiResponse>> {\r\n const headers = new Headers(options.headers)\r\n\r\n // Set Content-Type if not already set and body is being stringified\r\n if (body && !headers.has('Content-Type')) {\r\n headers.set('Content-Type', 'application/json')\r\n }\r\n\r\n return this.fetch(url, {\r\n ...options,\r\n headers,\r\n method: 'PUT',\r\n body: body ? JSON.stringify(body) : undefined\r\n })\r\n }\r\n\r\n async delete(url: string, options: Omit<FetchGuardRequestInit, 'method' | 'body'> = {}): Promise<Result<ApiResponse>> {\r\n return this.fetch(url, { ...options, method: 'DELETE' })\r\n }\r\n\r\n async patch(url: string, body?: any, options: Omit<FetchGuardRequestInit, 'method' | 'body'> = {}): Promise<Result<ApiResponse>> {\r\n const headers = new Headers(options.headers)\r\n\r\n // Set Content-Type if not already set and body is being stringified\r\n if (body && !headers.has('Content-Type')) {\r\n headers.set('Content-Type', 'application/json')\r\n }\r\n\r\n return this.fetch(url, {\r\n ...options,\r\n headers,\r\n method: 'PATCH',\r\n body: body ? JSON.stringify(body) : undefined\r\n })\r\n }\r\n\r\n /**\r\n * Generic method to call any auth method on provider\r\n * @param method - Method name (login, logout, loginWithPhone, etc.)\r\n * @param args - Arguments to pass to the method\r\n * @returns Result base on responseMode\r\n */\r\n async call(method: string, responseMode?: AuthResponseMode, ...args: unknown[]): Promise<Result<void>> {\r\n const id = this.generateMessageId()\r\n const message = { id, type: MSG.AUTH_CALL, payload: { method, args, responseMode } }\r\n\r\n return new Promise((resolve, reject) => {\r\n this.pendingRequests.set(id, {\r\n resolve: (r: any) => resolve(r),\r\n reject: (e: Error) => reject(e)\r\n })\r\n\r\n this.sendMessageQueued(message, 15000).catch((error) => {\r\n const request = this.pendingRequests.get(id)\r\n if (request) {\r\n this.pendingRequests.delete(id)\r\n request.reject(error)\r\n }\r\n })\r\n })\r\n }\r\n\r\n\r\n /**\r\n * Convenience wrapper for login\r\n */\r\n async login(payload?: unknown, responseMode: AuthResponseMode = 'both'): Promise<Result<void>> {\r\n const args = typeof payload === 'undefined' ? [] : [payload]\r\n return this.call('login', responseMode, args)\r\n }\r\n\r\n /**\r\n * Convenience wrapper for logout\r\n */\r\n async logout(payload?: unknown, responseMode: AuthResponseMode = 'event-only'): Promise<Result<void>> {\r\n const args = typeof payload === 'undefined' ? [] : [payload]\r\n return this.call('logout', responseMode, args)\r\n }\r\n\r\n /**\r\n * Convenience wrapper for refreshToken\r\n */\r\n async refreshToken(responseMode?: AuthResponseMode): Promise<Result<void>> {\r\n return this.call('refreshToken', responseMode, [])\r\n }\r\n\r\n /**\r\n * Check if worker is ready\r\n */\r\n ready(): boolean {\r\n return this.isReady\r\n }\r\n\r\n /**\r\n * Wait for worker to be ready\r\n * Returns immediately if already ready\r\n */\r\n async whenReady(): Promise<void> {\r\n if (this.isReady) return Promise.resolve()\r\n\r\n return new Promise<void>((resolve) => {\r\n this.readyListeners.add(resolve)\r\n })\r\n }\r\n\r\n /**\r\n * Subscribe to ready event\r\n * Callback is called immediately if already ready\r\n */\r\n onReady(callback: () => void): () => void {\r\n if (this.isReady) {\r\n // Already ready - call immediately\r\n callback()\r\n }\r\n\r\n this.readyListeners.add(callback)\r\n\r\n // Return unsubscribe function\r\n return () => {\r\n this.readyListeners.delete(callback)\r\n }\r\n }\r\n\r\n /**\r\n * Subscribe to auth state changes\r\n */\r\n onAuthStateChanged(cb: (state: { authenticated: boolean; expiresAt?: number | null; user?: unknown }) => void): () => void {\r\n this.authListeners.add(cb)\r\n return () => this.authListeners.delete(cb)\r\n }\r\n\r\n /** Send PING and await PONG */\r\n async ping(): Promise<Result<{ timestamp: number }>> {\r\n const id = this.generateMessageId()\r\n const message = { id, type: MSG.PING, payload: { timestamp: Date.now() } }\r\n\r\n return new Promise((resolve, reject) => {\r\n this.pendingRequests.set(id, {\r\n resolve: (r: any) => resolve(r),\r\n reject: (e: Error) => reject(e)\r\n })\r\n\r\n this.sendMessageQueued(message, 5000).catch((error) => {\r\n const request = this.pendingRequests.get(id)\r\n if (request) {\r\n this.pendingRequests.delete(id)\r\n request.reject(error)\r\n }\r\n })\r\n })\r\n }\r\n\r\n\r\n /**\r\n * Send message through queue system\r\n * All messages go through queue for sequential processing\r\n */\r\n private sendMessageQueued<T = any>(message: any, timeoutMs: number = this.queueTimeout): Promise<T> {\r\n return new Promise((resolve, reject) => {\r\n const timeout = setTimeout(() => {\r\n const index = this.requestQueue.findIndex(item => item.id === message.id)\r\n if (index !== -1) {\r\n this.requestQueue.splice(index, 1)\r\n }\r\n this.pendingRequests.delete(message.id)\r\n reject(new Error('Request timeout'))\r\n }, timeoutMs)\r\n\r\n const queueItem: QueueItem = {\r\n id: message.id,\r\n message,\r\n resolve,\r\n reject,\r\n timeout\r\n }\r\n\r\n this.requestQueue.push(queueItem)\r\n\r\n this.processQueue()\r\n })\r\n }\r\n\r\n /**\r\n * Process message queue sequentially\r\n * Benefits:\r\n * - Sequential processing prevents worker overload\r\n * - Better error isolation (one failure doesn't affect others)\r\n * - 50ms delay between requests for backpressure\r\n */\r\n private async processQueue(): Promise<void> {\r\n if (this.isProcessingQueue || this.requestQueue.length === 0) {\r\n return\r\n }\r\n\r\n this.isProcessingQueue = true\r\n\r\n while (this.requestQueue.length > 0) {\r\n const item = this.requestQueue.shift()\r\n if (!item) continue\r\n\r\n try {\r\n this.worker.postMessage(item.message)\r\n\r\n await new Promise(resolve => setTimeout(resolve, 50))\r\n } catch (error) {\r\n clearTimeout(item.timeout)\r\n item.reject(error instanceof Error ? error : new Error(String(error)))\r\n }\r\n }\r\n\r\n this.isProcessingQueue = false\r\n }\r\n\r\n /**\r\n * Cleanup - terminate worker\r\n */\r\n destroy(): void {\r\n this.worker.terminate()\r\n this.pendingRequests.clear()\r\n\r\n for (const item of this.requestQueue) {\r\n clearTimeout(item.timeout)\r\n item.reject(new Error('Client destroyed'))\r\n }\r\n this.requestQueue = []\r\n }\r\n}\r\n\r\n/**\r\n * Factory function to create FetchGuard client\r\n */\r\nexport function createClient(options: FetchGuardOptions): FetchGuardClient {\r\n return new FetchGuardClient(options)\r\n}\r\n","import type { SerializedResult } from 'ts-micro-result'\r\nimport type { WorkerConfig, FetchGuardRequestInit, ProviderPresetConfig, AuthResponseMode } from './types'\n\r\n/**\r\n * MESSAGE PAYLOADS - SINGLE SOURCE OF TRUTH\r\n *\r\n * Define all message payloads here. Type unions and MSG constants are auto-generated.\r\n *\r\n * USAGE:\r\n * - To add a new message: Just add one line to the appropriate interface\r\n * - Payload types are automatically inferred\r\n * - MSG constants are automatically generated\r\n *\r\n * EXAMPLE:\r\n * ```typescript\r\n * interface MainPayloads {\r\n * NEW_MESSAGE: { foo: string } // Add this line\r\n * }\r\n * // => Automatically get MainToWorkerMessage union with NEW_MESSAGE\r\n * // => Automatically get MSG.NEW_MESSAGE = 'NEW_MESSAGE'\r\n * ```\r\n */\r\n\r\n/**\r\n * Payloads for messages sent from Main thread → Worker thread\r\n */\r\nexport interface MainPayloads {\n SETUP: { config: WorkerConfig; providerConfig: ProviderPresetConfig | string | null }\n FETCH: { url: string; options?: FetchGuardRequestInit }\n AUTH_CALL: { method: string; args: unknown[]; responseMode?: AuthResponseMode } // Generic auth method call (login, logout, loginWithPhone, etc.)\n CANCEL: undefined\r\n PING: { timestamp: number }\r\n}\r\n\r\n/**\r\n * Payloads for messages sent from Worker thread → Main thread\r\n */\r\nexport interface WorkerPayloads {\r\n RESULT: { result: SerializedResult | object }\r\n READY: undefined\r\n PONG: { timestamp: number }\r\n LOG: { level: 'info' | 'warn' | 'error'; message: string }\r\n AUTH_STATE_CHANGED: { authenticated: boolean; expiresAt?: number | null; user?: unknown }\r\n FETCH_RESULT: { status: number; headers?: Record<string, string>; body: string }\r\n FETCH_ERROR: { error: string; status?: number }\r\n}\r\n\r\n/**\r\n * Generate message type from payload definition\r\n * Handles optional payloads (undefined) gracefully\r\n */\r\ntype MessageFromPayloads<P> = {\r\n [K in keyof P]: { id: string; type: K } & (\r\n P[K] extends undefined ? {} : { payload: P[K] }\r\n )\r\n}[keyof P]\r\n\r\n/**\r\n * Message type unions - auto-generated from payload interfaces\r\n */\r\nexport type MainToWorkerMessage = MessageFromPayloads<MainPayloads>\r\nexport type WorkerToMainMessage = MessageFromPayloads<WorkerPayloads>\r\n\r\n/**\r\n * Message type unions for compile-time type checking\r\n */\r\nexport type MainType = keyof MainPayloads\r\nexport type WorkerType = keyof WorkerPayloads\r\nexport type MessageType = MainType | WorkerType\r\n\r\n/**\r\n * MSG constants object\r\n * Usage: MSG.SETUP, MSG.FETCH, etc.\r\n */\r\nexport const MSG = Object.freeze({\r\n // Main -> Worker messages\r\n SETUP: 'SETUP',\r\n FETCH: 'FETCH',\r\n AUTH_CALL: 'AUTH_CALL',\r\n CANCEL: 'CANCEL',\r\n PING: 'PING',\r\n\r\n // Worker -> Main messages\r\n RESULT: 'RESULT',\r\n READY: 'READY',\r\n PONG: 'PONG',\r\n LOG: 'LOG',\r\n AUTH_STATE_CHANGED: 'AUTH_STATE_CHANGED',\r\n FETCH_RESULT: 'FETCH_RESULT',\r\n FETCH_ERROR: 'FETCH_ERROR'\r\n}) as { readonly [K in MessageType]: K }\r\n","/**\n * FetchGuard Default Configuration Values\n */\n\n/**\n * Default time (in milliseconds) to refresh token before expiry\n * @default 60000 (60 seconds)\n */\nexport const DEFAULT_REFRESH_EARLY_MS = 60_000\n\n/**\n * Default timeout for API requests (in milliseconds)\n * @default 30000 (30 seconds)\n */\nexport const DEFAULT_TIMEOUT_MS = 30_000\n\n/**\n * Default number of retry attempts for failed requests\n * @default 3\n */\nexport const DEFAULT_RETRY_COUNT = 3\n\n/**\n * Default delay between retry attempts (in milliseconds)\n * @default 1000 (1 second)\n */\nexport const DEFAULT_RETRY_DELAY_MS = 1_000\n","/**\n * Error definitions organized by domain\n * Using ts-micro-result's defineError for consistency\n */\n\nimport { defineError, defineErrorAdvanced } from 'ts-micro-result'\n\n/**\n * General errors\n */\nexport const GeneralErrors = {\n Unexpected: defineError('UNEXPECTED', 'Unexpected error', 500),\n UnknownMessage: defineError('UNKNOWN_MESSAGE', 'Unknown message type', 400),\n ResultParse: defineError('RESULT_PARSE_ERROR', 'Failed to parse result', 500),\n} as const\n\n/**\n * Initialization errors\n */\nexport const InitErrors = {\n NotInitialized: defineError('INIT_ERROR', 'Worker not initialized', 500),\n ProviderInitFailed: defineError('PROVIDER_INIT_FAILED', 'Failed to initialize provider', 500),\n InitFailed: defineError('INIT_FAILED', 'Initialization failed', 500),\n} as const\n\n/**\n * Authentication & Token errors\n */\nexport const AuthErrors = {\n TokenRefreshFailed: defineError('TOKEN_REFRESH_FAILED', 'Token refresh failed', 401),\n LoginFailed: defineError('LOGIN_FAILED', 'Login failed', 401),\n LogoutFailed: defineError('LOGOUT_FAILED', 'Logout failed', 500),\n NotAuthenticated: defineError('NOT_AUTHENTICATED', 'User is not authenticated', 401),\n} as const\n\n/**\n * Domain validation errors\n */\nexport const DomainErrors = {\n NotAllowed: defineErrorAdvanced('DOMAIN_NOT_ALLOWED', 'Domain not allowed: {url}', 403),\n} as const\n\n/**\n * Network & HTTP errors\n */\nexport const NetworkErrors = {\n NetworkError: defineError('NETWORK_ERROR', 'Network error', 500),\n HttpError: defineError('HTTP_ERROR', 'HTTP error', 500),\n FetchError: defineError('FETCH_ERROR', 'Fetch error', 500),\n} as const\n\n/**\n * Request errors\n */\nexport const RequestErrors = {\n Cancelled: defineError('REQUEST_CANCELLED', 'Request was cancelled', 499),\n Timeout: defineError('REQUEST_TIMEOUT', 'Request timeout', 408),\n} as const\n","import type { TokenProvider } from '../types'\r\n\r\n/**\r\n * Registry to manage token providers\r\n */\r\nconst registry = new Map<string, TokenProvider>()\r\n\r\n/**\r\n * Register a token provider with name\r\n */\r\nexport function registerProvider(name: string, provider: TokenProvider): void {\r\n if (typeof name !== 'string' || !name.trim()) {\r\n throw new Error('Provider name must be a non-empty string')\r\n }\r\n \r\n if (!provider || typeof provider.refreshToken !== 'function') {\r\n throw new Error('Provider must implement TokenProvider interface')\r\n }\r\n \r\n registry.set(name, provider)\r\n}\r\n\r\n/**\r\n * Get provider by name\r\n */\r\nexport function getProvider(name: string): TokenProvider {\r\n const provider = registry.get(name)\r\n if (!provider) {\r\n throw new Error(`Provider '${name}' not found. Available providers: ${Array.from(registry.keys()).join(', ')}`)\r\n }\r\n return provider\r\n}\r\n\r\n/**\r\n * Check if provider exists\r\n */\r\nexport function hasProvider(name: string): boolean {\r\n return registry.has(name)\r\n}\r\n\r\n/**\r\n * Get list of all provider names\r\n */\r\nexport function listProviders(): string[] {\r\n return Array.from(registry.keys())\r\n}\r\n\r\n/**\r\n * Remove provider\r\n */\r\nexport function unregisterProvider(name: string): boolean {\r\n return registry.delete(name)\r\n}\r\n\r\n/**\r\n * Remove all providers\r\n */\r\nexport function clearProviders(): void {\r\n registry.clear()\r\n}\r\n","import type {\r\n TokenProvider,\r\n RefreshTokenStorage,\r\n TokenParser,\r\n AuthStrategy,\r\n TokenInfo\r\n} from '../types'\r\nimport { ok, err, type Result } from 'ts-micro-result'\r\nimport { AuthErrors, NetworkErrors } from '../errors'\r\n\r\n/**\r\n * Custom auth method type\r\n */\r\ntype CustomAuthMethod = (...args: any[]) => Promise<Result<TokenInfo>>\r\n\r\n/**\r\n * Configuration for creating provider\r\n *\r\n * refreshStorage: OPTIONAL - to load refresh token initially when worker starts\r\n * - undefined: cookie-based auth (httpOnly cookie, no need to load)\r\n * - RefreshTokenStorage: body-based auth (load from IndexedDB on startup)\r\n *\r\n * strategy: AuthStrategy with refresh (required), login/logout (required)\r\n *\r\n * customMethods: OPTIONAL - custom auth methods (loginWithPhone, loginWithGoogle, etc.)\r\n */\r\nexport interface ProviderConfig {\r\n refreshStorage?: RefreshTokenStorage\r\n parser: TokenParser\r\n strategy: AuthStrategy\r\n customMethods?: Record<string, CustomAuthMethod>\r\n}\r\n\r\n/**\r\n * Factory function to create TokenProvider from modular components\r\n *\r\n * Provider automatically handles refresh token:\r\n * - If refreshToken is null and storage exists → load from storage initially\r\n * - If refreshToken exists → use token from worker memory\r\n * - Cookie-based (no storage) → always null\r\n *\r\n * Custom methods:\r\n * - User can add custom auth methods (loginWithPhone, loginWithGoogle, etc.)\r\n * - Custom methods will be spread into provider object\r\n */\r\nexport function createProvider(config: ProviderConfig): TokenProvider {\r\n const baseProvider: Pick<TokenProvider, 'refreshToken' | 'login' | 'logout'> = {\r\n async refreshToken(refreshToken: string | null) {\r\n let currentRefreshToken = refreshToken\r\n if (currentRefreshToken === null && config.refreshStorage) {\r\n currentRefreshToken = await config.refreshStorage.get()\r\n }\r\n\r\n try {\r\n const response = await config.strategy.refresh(currentRefreshToken)\r\n\r\n if (!response.ok) {\r\n return err(AuthErrors.TokenRefreshFailed({ message: `HTTP ${response.status}` }))\r\n }\r\n\r\n const tokenInfo = await config.parser.parse(response)\r\n if (!tokenInfo.token) {\r\n return err(AuthErrors.TokenRefreshFailed({ message: 'No access token in response' }))\r\n }\r\n\r\n if (config.refreshStorage && tokenInfo.refreshToken) {\r\n await config.refreshStorage.set(tokenInfo.refreshToken)\r\n }\r\n\r\n return ok(tokenInfo)\r\n } catch (error) {\r\n return err(NetworkErrors.NetworkError({ message: String(error) }))\r\n }\r\n },\r\n\r\n async login(payload: unknown) {\r\n try {\r\n const response = await config.strategy.login(payload)\r\n\r\n if (!response.ok) {\r\n return err(AuthErrors.LoginFailed({ message: `HTTP ${response.status}` }))\r\n }\r\n\r\n const tokenInfo = await config.parser.parse(response)\r\n if (!tokenInfo.token) {\r\n return err(AuthErrors.LoginFailed({ message: 'No access token in response' }))\r\n }\r\n\r\n if (config.refreshStorage && tokenInfo.refreshToken) {\r\n await config.refreshStorage.set(tokenInfo.refreshToken)\r\n }\r\n\r\n return ok(tokenInfo)\r\n } catch (error) {\r\n return err(NetworkErrors.NetworkError({ message: String(error) }))\r\n }\r\n },\r\n\r\n async logout(payload?: unknown) {\r\n try {\r\n const response = await config.strategy.logout(payload)\r\n\r\n if (!response.ok) {\r\n return err(AuthErrors.LogoutFailed({ message: `HTTP ${response.status}` }))\r\n }\r\n\r\n if (config.refreshStorage) {\r\n await config.refreshStorage.set(null)\r\n }\r\n\r\n return ok({\r\n token: '',\r\n refreshToken: undefined,\r\n expiresAt: undefined,\r\n user: undefined\r\n })\r\n } catch (error) {\r\n return err(NetworkErrors.NetworkError({ message: String(error) }))\r\n }\r\n }\r\n }\r\n\r\n // Merge custom methods if provided\r\n if (config.customMethods) {\r\n return {\r\n ...baseProvider,\r\n ...config.customMethods\r\n } as TokenProvider\r\n }\r\n\r\n return baseProvider as TokenProvider\r\n}\r\n","import type { RefreshTokenStorage } from '../../types'\r\n\r\n/**\r\n * IndexedDB storage - only stores refresh token in IndexedDB\r\n * Suitable for body-based refresh strategy\r\n * Persists refresh token for reuse after reload\r\n */\r\nexport function createIndexedDBStorage(dbName = 'FetchGuardDB', refreshTokenKey = 'refreshToken'): RefreshTokenStorage {\r\n const storeName = 'tokens'\r\n\r\n const openDB = (): Promise<IDBDatabase> => {\r\n return new Promise((resolve, reject) => {\r\n const request = indexedDB.open(dbName, 1)\r\n \r\n request.onerror = () => reject(request.error)\r\n request.onsuccess = () => resolve(request.result)\r\n \r\n request.onupgradeneeded = (event) => {\r\n const db = (event.target as IDBOpenDBRequest).result\r\n if (!db.objectStoreNames.contains(storeName)) {\r\n const store = db.createObjectStore(storeName, { keyPath: 'key' })\r\n store.createIndex('timestamp', 'timestamp', { unique: false })\r\n }\r\n }\r\n })\r\n }\r\n\r\n const promisifyRequest = <T>(request: IDBRequest<T>): Promise<T> => {\r\n return new Promise((resolve, reject) => {\r\n request.onsuccess = () => resolve(request.result)\r\n request.onerror = () => reject(request.error)\r\n })\r\n }\r\n\r\n return {\r\n async get() {\r\n try {\r\n const db = await openDB()\r\n const transaction = db.transaction([storeName], 'readonly')\r\n const store = transaction.objectStore(storeName)\r\n const result = await promisifyRequest(store.get(refreshTokenKey))\r\n return result?.value || null\r\n } catch (error) {\r\n console.warn('Failed to get refresh token from IndexedDB:', error)\r\n return null\r\n }\r\n },\r\n async set(token) {\r\n try {\r\n const db = await openDB()\r\n const transaction = db.transaction([storeName], 'readwrite')\r\n const store = transaction.objectStore(storeName)\r\n\r\n if (token) {\r\n await promisifyRequest(store.put({ key: refreshTokenKey, value: token, timestamp: Date.now() }))\r\n } else {\r\n await promisifyRequest(store.delete(refreshTokenKey))\r\n }\r\n } catch (error) {\r\n console.warn('Failed to save refresh token to IndexedDB:', error)\r\n }\r\n }\r\n }\r\n}\r\n","import type { TokenParser } from '../../types'\r\n\r\n/**\r\n * Body parser - parse token from response body (JSON)\r\n * Expects response format: { data: { accessToken, refreshToken, expiresAt?, user? } }\r\n */\r\nexport const bodyParser: TokenParser = {\r\n async parse(response) {\r\n const json = await response.clone().json()\r\n return {\r\n token: json.data.accessToken,\r\n refreshToken: json.data.refreshToken,\r\n expiresAt: json.data.expiresAt,\r\n user: json.data.user\r\n }\r\n }\r\n}\r\n","import type { TokenParser } from '../../types'\r\n\r\n/**\r\n * Cookie parser - parse access token from response body\r\n * Expects response format: { data: { accessToken, expiresAt?, user? } }\r\n * Refresh token is automatically set by backend into httpOnly cookie\r\n */\r\nexport const cookieParser: TokenParser = {\r\n async parse(response) {\r\n const json = await response.clone().json()\r\n return {\r\n token: json.data.accessToken,\r\n expiresAt: json.data.expiresAt,\r\n user: json.data.user\r\n }\r\n }\r\n}\r\n","import type { AuthStrategy } from '../../types'\r\n\r\n/**\r\n * Cookie auth strategy - all auth operations via httpOnly cookies\r\n * Suitable for SSR and cross-domain authentication\r\n *\r\n * Refresh token is sent automatically via httpOnly cookie\r\n * Credentials are sent in request body\r\n */\r\nexport function createCookieStrategy(config: {\r\n refreshUrl: string\r\n loginUrl: string\r\n logoutUrl: string\r\n}): AuthStrategy {\r\n return {\r\n async refresh() {\r\n return fetch(config.refreshUrl, {\r\n method: 'POST',\r\n headers: { 'Content-Type': 'application/json' },\r\n credentials: 'include'\r\n })\r\n },\r\n\r\n async login(payload) {\r\n return fetch(config.loginUrl, {\r\n method: 'POST',\r\n headers: { 'Content-Type': 'application/json' },\r\n body: JSON.stringify(payload),\r\n credentials: 'include'\r\n })\r\n },\r\n\r\n async logout(payload) {\r\n return fetch(config.logoutUrl, {\r\n method: 'POST',\r\n headers: { 'Content-Type': 'application/json' },\r\n body: payload ? JSON.stringify(payload) : undefined,\r\n credentials: 'include'\r\n })\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Standard cookie strategy\r\n */\r\nexport const cookieStrategy = createCookieStrategy({\r\n refreshUrl: '/auth/refresh',\r\n loginUrl: '/auth/login',\r\n logoutUrl: '/auth/logout'\r\n})\r\n","import type { AuthStrategy } from '../../types'\r\n\r\n/**\r\n * Body auth strategy - all auth operations via request body\r\n * Suitable for SPA applications\r\n *\r\n * All tokens/credentials are sent in request body\r\n */\r\nexport function createBodyStrategy(config: {\r\n refreshUrl: string\r\n loginUrl: string\r\n logoutUrl: string\r\n}): AuthStrategy {\r\n return {\r\n async refresh(refreshToken) {\r\n if (!refreshToken) {\r\n throw new Error('No refresh token available')\r\n }\r\n\r\n return fetch(config.refreshUrl, {\r\n method: 'POST',\r\n headers: { 'Content-Type': 'application/json' },\r\n body: JSON.stringify({ refreshToken }),\r\n credentials: 'include'\r\n })\r\n },\r\n\r\n async login(payload) {\r\n return fetch(config.loginUrl, {\r\n method: 'POST',\r\n headers: { 'Content-Type': 'application/json' },\r\n body: JSON.stringify(payload),\r\n credentials: 'include'\r\n })\r\n },\r\n\r\n async logout(payload) {\r\n return fetch(config.logoutUrl, {\r\n method: 'POST',\r\n headers: { 'Content-Type': 'application/json' },\r\n body: payload ? JSON.stringify(payload) : undefined,\r\n credentials: 'include'\r\n })\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Standard body strategy\r\n */\r\nexport const bodyStrategy = createBodyStrategy({\r\n refreshUrl: '/auth/refresh',\r\n loginUrl: '/auth/login',\r\n logoutUrl: '/auth/logout'\r\n})\r\n","import { createProvider } from './create-provider'\r\nimport { createIndexedDBStorage } from './storage/indexeddb'\r\nimport { bodyParser } from './parser/body'\r\nimport { cookieParser } from './parser/cookie'\r\nimport { createCookieStrategy } from './strategy/cookie'\r\nimport { createBodyStrategy } from './strategy/body'\r\nimport type { TokenProvider } from '../types'\r\n\r\n/**\r\n * Cookie Provider - uses httpOnly cookies\r\n * Suitable for SSR and cross-domain authentication\r\n *\r\n * Access token: Worker memory\r\n * Refresh token: httpOnly cookie (managed by backend)\r\n */\r\nexport function createCookieProvider(config: {\r\n refreshUrl: string\r\n loginUrl: string\r\n logoutUrl: string\r\n}): TokenProvider {\r\n return createProvider({\r\n refreshStorage: undefined,\r\n parser: cookieParser,\r\n strategy: createCookieStrategy(config)\r\n })\r\n}\r\n\r\n/**\r\n * Body Provider - refresh token in response body, persisted to IndexedDB\r\n * Suitable for SPA applications\r\n *\r\n * Access token: Worker memory\r\n * Refresh token: IndexedDB (persists across reload)\r\n */\r\nexport function createBodyProvider(config: {\r\n refreshUrl: string\r\n loginUrl: string\r\n logoutUrl: string\r\n refreshTokenKey?: string\r\n}): TokenProvider {\r\n return createProvider({\r\n refreshStorage: createIndexedDBStorage('FetchGuardDB', config.refreshTokenKey || 'refreshToken'),\r\n parser: bodyParser,\r\n strategy: createBodyStrategy(config)\r\n })\r\n}\r\n"],"mappings":"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","names":["ok","err","err","ok"]}
|
|
1
|
+
{"version":3,"sources":["../src/client.ts","../src/messages.ts","../src/constants.ts","../src/errors.ts","../src/utils/registry.ts","../src/provider/create-provider.ts","../src/provider/storage/indexeddb.ts","../src/provider/parser/body.ts","../src/provider/parser/cookie.ts","../src/provider/strategy/cookie.ts","../src/provider/strategy/body.ts","../src/provider/presets.ts"],"sourcesContent":["import type {\r\n FetchGuardOptions,\r\n FetchGuardRequestInit,\r\n WorkerConfig,\r\n ApiResponse,\r\n ProviderPresetConfig,\r\n AuthResult\r\n} from './types'\r\nimport { fromJSON, ok, err, type Result } from 'ts-micro-result'\r\nimport { MSG } from './messages'\r\nimport {\r\n DEFAULT_REFRESH_EARLY_MS,\r\n DEFAULT_TIMEOUT_MS,\r\n DEFAULT_RETRY_COUNT,\r\n DEFAULT_RETRY_DELAY_MS\r\n} from './constants'\r\nimport { GeneralErrors, NetworkErrors } from './errors'\r\n\r\n/**\r\n * Queue item for sequential message processing\r\n * Inspired by old-workers/ApiWorkerService.ts\r\n */\r\ninterface QueueItem {\r\n id: string\r\n message: any\r\n resolve: (response: any) => void\r\n reject: (error: Error) => void\r\n timeout: ReturnType<typeof setTimeout>\r\n}\r\n\r\n/**\r\n * FetchGuard Client - main interface cho việc gọi API thông qua Web Worker\r\n */\r\nexport class FetchGuardClient {\r\n private worker: Worker\r\n private messageId = 0\r\n private pendingRequests = new Map<string, {\r\n resolve: (value: any) => void\r\n reject: (error: Error) => void\r\n }>()\r\n private authListeners = new Set<(state: AuthResult) => void>()\r\n private readyListeners = new Set<() => void>()\r\n private isReady = false\r\n\r\n private requestQueue: QueueItem[] = []\r\n private isProcessingQueue = false\r\n private queueTimeout = 30000 // 30 seconds\r\n private setupResolve?: () => void\r\n private setupReject?: (error: Error) => void\r\n\r\n constructor(options: FetchGuardOptions) {\r\n this.worker = new Worker(new URL('./worker.js', import.meta.url), { \r\n type: 'module' \r\n })\r\n\r\n this.worker.onmessage = this.handleWorkerMessage.bind(this)\r\n this.worker.onerror = this.handleWorkerError.bind(this)\r\n\r\n this.initializeWorker(options)\r\n }\r\n\r\n /**\r\n * Initialize worker with config and provider\r\n */\r\n private async initializeWorker(options: FetchGuardOptions): Promise<void> {\r\n const config: WorkerConfig = {\r\n allowedDomains: options.allowedDomains || [],\r\n debug: options.debug || false,\r\n refreshEarlyMs: options.refreshEarlyMs ?? DEFAULT_REFRESH_EARLY_MS,\r\n defaultTimeoutMs: options.defaultTimeoutMs ?? DEFAULT_TIMEOUT_MS,\r\n retryCount: options.retryCount ?? DEFAULT_RETRY_COUNT,\r\n retryDelayMs: options.retryDelayMs ?? DEFAULT_RETRY_DELAY_MS\r\n }\r\n\r\n // Serialize provider config based on type\r\n let providerConfig: ProviderPresetConfig | string | null = null\r\n\r\n if (typeof options.provider === 'string') {\r\n // String = registry lookup (advanced usage)\r\n providerConfig = options.provider\r\n } else if ('type' in options.provider && options.provider.type) {\r\n // ProviderPresetConfig object (recommended)\r\n providerConfig = options.provider as ProviderPresetConfig\r\n } else {\r\n // TokenProvider instance - NOT SUPPORTED\r\n throw new Error(\r\n 'Direct TokenProvider instance is not supported. Use ProviderPresetConfig instead:\\n' +\r\n ' { type: \"cookie-auth\", refreshUrl: \"...\", loginUrl: \"...\", logoutUrl: \"...\" }\\n' +\r\n 'Or for custom providers, register in worker code and use string name.'\r\n )\r\n }\r\n\r\n const message = {\r\n id: this.generateMessageId(),\r\n type: MSG.SETUP,\r\n payload: {\r\n config,\r\n providerConfig\r\n }\r\n }\r\n\r\n return new Promise((resolve, reject) => {\r\n // Setup will respond with READY (no id, so we track separately)\r\n this.setupResolve = resolve\r\n this.setupReject = reject\r\n\r\n this.worker.postMessage(message)\r\n\r\n setTimeout(() => {\r\n if (this.setupReject) {\r\n this.setupReject(new Error('Worker setup timeout'))\r\n this.setupResolve = undefined\r\n this.setupReject = undefined\r\n }\r\n }, 10000)\r\n })\r\n }\r\n\r\n\r\n /**\r\n * Handle worker messages\r\n */\r\n private handleWorkerMessage(event: MessageEvent): void {\r\n const { id, type, payload } = event.data\r\n\r\n if (type === MSG.FETCH_RESULT || type === MSG.FETCH_ERROR) {\r\n const request = this.pendingRequests.get(id)\r\n if (!request) return\r\n\r\n this.pendingRequests.delete(id)\r\n\r\n if (type === MSG.FETCH_RESULT) {\r\n const status = payload?.status ?? 200\r\n const headers = payload?.headers ?? {}\r\n const body = String(payload?.body ?? '')\r\n let data: any\r\n try { data = JSON.parse(body) } catch { data = body }\r\n request.resolve(ok<ApiResponse>({ data, status, headers }))\r\n return\r\n }\r\n\r\n if (type === MSG.FETCH_ERROR) {\r\n const status = typeof payload?.status === 'number' ? payload.status : undefined\r\n if (typeof status === 'number') {\r\n request.resolve(err(NetworkErrors.HttpError({ message: String(payload?.error || 'HTTP error') }), undefined, status))\r\n } else {\r\n request.resolve(err(NetworkErrors.NetworkError({ message: String(payload?.error || 'Network error') })))\r\n }\r\n return\r\n }\r\n }\r\n\r\n if (type === MSG.RESULT) {\r\n const request = this.pendingRequests.get(id)\r\n if (!request) return\r\n\r\n this.pendingRequests.delete(id)\r\n\r\n if (payload && payload.result) {\r\n try {\r\n const result = fromJSON(JSON.stringify(payload.result))\r\n request.resolve(result)\r\n } catch (e) {\r\n request.resolve(err(GeneralErrors.ResultParse({ message: String(e) })))\r\n }\r\n }\r\n return\r\n }\r\n\r\n if (type === MSG.READY) {\r\n this.isReady = true\r\n\r\n // Notify ready listeners\r\n for (const listener of this.readyListeners) {\r\n listener()\r\n }\r\n\r\n if (this.setupResolve) {\r\n this.setupResolve()\r\n this.setupResolve = undefined\r\n this.setupReject = undefined\r\n }\r\n return\r\n }\r\n\r\n if (type === MSG.PONG) {\r\n const request = this.pendingRequests.get(id)\r\n if (request) {\r\n this.pendingRequests.delete(id)\r\n request.resolve(ok({ timestamp: payload?.timestamp }))\r\n }\r\n return\r\n }\r\n\r\n if (type === MSG.AUTH_STATE_CHANGED) {\r\n for (const cb of this.authListeners) cb(payload)\r\n return\r\n }\r\n\r\n if (type === MSG.AUTH_CALL_RESULT) {\r\n const request = this.pendingRequests.get(id)\r\n if (request) {\r\n this.pendingRequests.delete(id)\r\n request.resolve(ok(payload)) // payload is AuthResult\r\n }\r\n return\r\n }\r\n }\r\n\r\n /**\r\n * Handle worker errors\r\n */\r\n private handleWorkerError(error: ErrorEvent): void {\r\n console.error('Worker error:', error)\r\n // Reject all pending requests\r\n for (const [id, request] of this.pendingRequests) {\r\n request.reject(new Error(`Worker error: ${error.message}`))\r\n }\r\n this.pendingRequests.clear()\r\n }\r\n\r\n /**\r\n * Generate unique message ID\r\n */\r\n private generateMessageId(): string {\r\n return `msg_${++this.messageId}_${Date.now()}`\r\n }\r\n\r\n /**\r\n * Make API request\r\n */\r\n async fetch(url: string, options: FetchGuardRequestInit = {}): Promise<Result<ApiResponse>> {\r\n const { result } = this.fetchWithId(url, options)\r\n return result\r\n }\r\n\r\n /**\r\n * Fetch with id for external cancellation\r\n * Returns { id, result, cancel } \r\n * Now uses queue system for sequential processing\r\n */\r\n fetchWithId(url: string, options: FetchGuardRequestInit = {}): {\r\n id: string\r\n result: Promise<Result<ApiResponse>>\r\n cancel: () => void\r\n } {\r\n const id = this.generateMessageId()\r\n\r\n const message = { id, type: MSG.FETCH, payload: { url, options } }\r\n\r\n const result = new Promise<Result<ApiResponse>>((resolve, reject) => {\r\n this.pendingRequests.set(id, {\r\n resolve: (response) => resolve(response),\r\n reject: (error) => reject(error)\r\n })\r\n })\r\n\r\n this.sendMessageQueued(message, 30000).catch((error) => {\r\n const request = this.pendingRequests.get(id)\r\n if (request) {\r\n this.pendingRequests.delete(id)\r\n request.reject(error)\r\n }\r\n })\r\n\r\n const cancel = () => this.cancel(id)\r\n\r\n return { id, result, cancel }\r\n }\r\n\r\n /**\r\n * Cancel a pending request by ID\r\n */\r\n cancel(id: string): void {\r\n const request = this.pendingRequests.get(id)\r\n if (request) {\r\n this.pendingRequests.delete(id)\r\n this.worker.postMessage({ id, type: MSG.CANCEL })\r\n request.reject(new Error('Request cancelled'))\r\n }\r\n }\r\n\r\n /**\r\n * Convenience methods\r\n */\r\n async get(url: string, options: Omit<FetchGuardRequestInit, 'method' | 'body'> = {}): Promise<Result<ApiResponse>> {\r\n return this.fetch(url, { ...options, method: 'GET' })\r\n }\r\n\r\n async post(url: string, body?: any, options: Omit<FetchGuardRequestInit, 'method' | 'body'> = {}): Promise<Result<ApiResponse>> {\r\n const headers = new Headers(options.headers)\r\n\r\n // Set Content-Type if not already set and body is being stringified\r\n if (body && !headers.has('Content-Type')) {\r\n headers.set('Content-Type', 'application/json')\r\n }\r\n\r\n return this.fetch(url, {\r\n ...options,\r\n headers,\r\n method: 'POST',\r\n body: body ? JSON.stringify(body) : undefined\r\n })\r\n }\r\n\r\n async put(url: string, body?: any, options: Omit<FetchGuardRequestInit, 'method' | 'body'> = {}): Promise<Result<ApiResponse>> {\r\n const headers = new Headers(options.headers)\r\n\r\n // Set Content-Type if not already set and body is being stringified\r\n if (body && !headers.has('Content-Type')) {\r\n headers.set('Content-Type', 'application/json')\r\n }\r\n\r\n return this.fetch(url, {\r\n ...options,\r\n headers,\r\n method: 'PUT',\r\n body: body ? JSON.stringify(body) : undefined\r\n })\r\n }\r\n\r\n async delete(url: string, options: Omit<FetchGuardRequestInit, 'method' | 'body'> = {}): Promise<Result<ApiResponse>> {\r\n return this.fetch(url, { ...options, method: 'DELETE' })\r\n }\r\n\r\n async patch(url: string, body?: any, options: Omit<FetchGuardRequestInit, 'method' | 'body'> = {}): Promise<Result<ApiResponse>> {\r\n const headers = new Headers(options.headers)\r\n\r\n // Set Content-Type if not already set and body is being stringified\r\n if (body && !headers.has('Content-Type')) {\r\n headers.set('Content-Type', 'application/json')\r\n }\r\n\r\n return this.fetch(url, {\r\n ...options,\r\n headers,\r\n method: 'PATCH',\r\n body: body ? JSON.stringify(body) : undefined\r\n })\r\n }\r\n\r\n /**\r\n * Generic method to call any auth method on provider\r\n * @param method - Method name (login, logout, loginWithPhone, etc.)\r\n * @param emitEvent - Whether to emit AUTH_STATE_CHANGED event (default: true)\r\n * @param args - Arguments to pass to the method\r\n * @returns Promise<Result<AuthResult>> - Always returns AuthResult\r\n */\r\n async call(method: string, emitEvent?: boolean, ...args: unknown[]): Promise<Result<AuthResult>> {\r\n const id = this.generateMessageId()\r\n const message = { id, type: MSG.AUTH_CALL, payload: { method, args, emitEvent } }\r\n\r\n return new Promise((resolve, reject) => {\r\n this.pendingRequests.set(id, {\r\n resolve: (r: any) => resolve(r),\r\n reject: (e: Error) => reject(e)\r\n })\r\n\r\n this.sendMessageQueued(message, 15000).catch((error) => {\r\n const request = this.pendingRequests.get(id)\r\n if (request) {\r\n this.pendingRequests.delete(id)\r\n request.reject(error)\r\n }\r\n })\r\n })\r\n }\r\n\r\n\r\n /**\r\n * Convenience wrapper for login\r\n * @param payload - Login credentials\r\n * @param emitEvent - Whether to emit AUTH_STATE_CHANGED event (default: true)\r\n */\r\n async login(payload?: unknown, emitEvent: boolean = true): Promise<Result<AuthResult>> {\r\n const args = typeof payload === 'undefined' ? [] : [payload]\r\n return this.call('login', emitEvent, ...args)\r\n }\r\n\r\n /**\r\n * Convenience wrapper for logout\r\n * @param payload - Optional logout payload\r\n * @param emitEvent - Whether to emit AUTH_STATE_CHANGED event (default: true)\r\n */\r\n async logout(payload?: unknown, emitEvent: boolean = true): Promise<Result<AuthResult>> {\r\n const args = typeof payload === 'undefined' ? [] : [payload]\r\n return this.call('logout', emitEvent, ...args)\r\n }\r\n\r\n /**\r\n * Convenience wrapper for refreshToken\r\n * @param emitEvent - Whether to emit AUTH_STATE_CHANGED event (default: true)\r\n */\r\n async refreshToken(emitEvent: boolean = true): Promise<Result<AuthResult>> {\r\n return this.call('refreshToken', emitEvent)\r\n }\r\n\r\n /**\r\n * Check if worker is ready\r\n */\r\n ready(): boolean {\r\n return this.isReady\r\n }\r\n\r\n /**\r\n * Wait for worker to be ready\r\n * Returns immediately if already ready\r\n */\r\n async whenReady(): Promise<void> {\r\n if (this.isReady) return Promise.resolve()\r\n\r\n return new Promise<void>((resolve) => {\r\n this.readyListeners.add(resolve)\r\n })\r\n }\r\n\r\n /**\r\n * Subscribe to ready event\r\n * Callback is called immediately if already ready\r\n */\r\n onReady(callback: () => void): () => void {\r\n if (this.isReady) {\r\n // Already ready - call immediately\r\n callback()\r\n }\r\n\r\n this.readyListeners.add(callback)\r\n\r\n // Return unsubscribe function\r\n return () => {\r\n this.readyListeners.delete(callback)\r\n }\r\n }\r\n\r\n /**\r\n * Subscribe to auth state changes\r\n */\r\n onAuthStateChanged(cb: (state: AuthResult) => void): () => void {\r\n this.authListeners.add(cb)\r\n return () => this.authListeners.delete(cb)\r\n }\r\n\r\n /** Send PING and await PONG */\r\n async ping(): Promise<Result<{ timestamp: number }>> {\r\n const id = this.generateMessageId()\r\n const message = { id, type: MSG.PING, payload: { timestamp: Date.now() } }\r\n\r\n return new Promise((resolve, reject) => {\r\n this.pendingRequests.set(id, {\r\n resolve: (r: any) => resolve(r),\r\n reject: (e: Error) => reject(e)\r\n })\r\n\r\n this.sendMessageQueued(message, 5000).catch((error) => {\r\n const request = this.pendingRequests.get(id)\r\n if (request) {\r\n this.pendingRequests.delete(id)\r\n request.reject(error)\r\n }\r\n })\r\n })\r\n }\r\n\r\n\r\n /**\r\n * Send message through queue system\r\n * All messages go through queue for sequential processing\r\n */\r\n private sendMessageQueued<T = any>(message: any, timeoutMs: number = this.queueTimeout): Promise<T> {\r\n return new Promise((resolve, reject) => {\r\n const timeout = setTimeout(() => {\r\n const index = this.requestQueue.findIndex(item => item.id === message.id)\r\n if (index !== -1) {\r\n this.requestQueue.splice(index, 1)\r\n }\r\n this.pendingRequests.delete(message.id)\r\n reject(new Error('Request timeout'))\r\n }, timeoutMs)\r\n\r\n const queueItem: QueueItem = {\r\n id: message.id,\r\n message,\r\n resolve,\r\n reject,\r\n timeout\r\n }\r\n\r\n this.requestQueue.push(queueItem)\r\n\r\n this.processQueue()\r\n })\r\n }\r\n\r\n /**\r\n * Process message queue sequentially\r\n * Benefits:\r\n * - Sequential processing prevents worker overload\r\n * - Better error isolation (one failure doesn't affect others)\r\n * - 50ms delay between requests for backpressure\r\n */\r\n private async processQueue(): Promise<void> {\r\n if (this.isProcessingQueue || this.requestQueue.length === 0) {\r\n return\r\n }\r\n\r\n this.isProcessingQueue = true\r\n\r\n while (this.requestQueue.length > 0) {\r\n const item = this.requestQueue.shift()\r\n if (!item) continue\r\n\r\n try {\r\n this.worker.postMessage(item.message)\r\n\r\n await new Promise(resolve => setTimeout(resolve, 50))\r\n } catch (error) {\r\n clearTimeout(item.timeout)\r\n item.reject(error instanceof Error ? error : new Error(String(error)))\r\n }\r\n }\r\n\r\n this.isProcessingQueue = false\r\n }\r\n\r\n /**\r\n * Cleanup - terminate worker\r\n */\r\n destroy(): void {\r\n this.worker.terminate()\r\n this.pendingRequests.clear()\r\n\r\n for (const item of this.requestQueue) {\r\n clearTimeout(item.timeout)\r\n item.reject(new Error('Client destroyed'))\r\n }\r\n this.requestQueue = []\r\n }\r\n}\r\n\r\n/**\r\n * Factory function to create FetchGuard client\r\n */\r\nexport function createClient(options: FetchGuardOptions): FetchGuardClient {\r\n return new FetchGuardClient(options)\r\n}\r\n","import type { SerializedResult } from 'ts-micro-result'\r\nimport type { WorkerConfig, FetchGuardRequestInit, ProviderPresetConfig, AuthResult } from './types'\r\n\r\n/**\r\n * MESSAGE PAYLOADS - SINGLE SOURCE OF TRUTH\r\n *\r\n * Define all message payloads here. Type unions and MSG constants are auto-generated.\r\n *\r\n * USAGE:\r\n * - To add a new message: Just add one line to the appropriate interface\r\n * - Payload types are automatically inferred\r\n * - MSG constants are automatically generated\r\n *\r\n * EXAMPLE:\r\n * ```typescript\r\n * interface MainPayloads {\r\n * NEW_MESSAGE: { foo: string } // Add this line\r\n * }\r\n * // => Automatically get MainToWorkerMessage union with NEW_MESSAGE\r\n * // => Automatically get MSG.NEW_MESSAGE = 'NEW_MESSAGE'\r\n * ```\r\n */\r\n\r\n/**\r\n * Payloads for messages sent from Main thread → Worker thread\r\n */\r\nexport interface MainPayloads {\r\n SETUP: { config: WorkerConfig; providerConfig: ProviderPresetConfig | string | null }\r\n FETCH: { url: string; options?: FetchGuardRequestInit }\r\n AUTH_CALL: { method: string; args: unknown[]; emitEvent?: boolean } // Generic auth method call (login, logout, loginWithPhone, etc.)\r\n CANCEL: undefined\r\n PING: { timestamp: number }\r\n}\r\n\r\n/**\r\n * Payloads for messages sent from Worker thread → Main thread\r\n */\r\nexport interface WorkerPayloads {\r\n RESULT: { result: SerializedResult | object }\r\n READY: undefined\r\n PONG: { timestamp: number }\r\n LOG: { level: 'info' | 'warn' | 'error'; message: string }\r\n AUTH_STATE_CHANGED: AuthResult\r\n AUTH_CALL_RESULT: AuthResult\r\n FETCH_RESULT: { status: number; headers?: Record<string, string>; body: string }\r\n FETCH_ERROR: { error: string; status?: number }\r\n}\r\n\r\n/**\r\n * Generate message type from payload definition\r\n * Handles optional payloads (undefined) gracefully\r\n */\r\ntype MessageFromPayloads<P> = {\r\n [K in keyof P]: { id: string; type: K } & (\r\n P[K] extends undefined ? {} : { payload: P[K] }\r\n )\r\n}[keyof P]\r\n\r\n/**\r\n * Message type unions - auto-generated from payload interfaces\r\n */\r\nexport type MainToWorkerMessage = MessageFromPayloads<MainPayloads>\r\nexport type WorkerToMainMessage = MessageFromPayloads<WorkerPayloads>\r\n\r\n/**\r\n * Message type unions for compile-time type checking\r\n */\r\nexport type MainType = keyof MainPayloads\r\nexport type WorkerType = keyof WorkerPayloads\r\nexport type MessageType = MainType | WorkerType\r\n\r\n/**\r\n * MSG constants object\r\n * Usage: MSG.SETUP, MSG.FETCH, etc.\r\n */\r\nexport const MSG = Object.freeze({\r\n // Main -> Worker messages\r\n SETUP: 'SETUP',\r\n FETCH: 'FETCH',\r\n AUTH_CALL: 'AUTH_CALL',\r\n CANCEL: 'CANCEL',\r\n PING: 'PING',\r\n\r\n // Worker -> Main messages\r\n RESULT: 'RESULT',\r\n READY: 'READY',\r\n PONG: 'PONG',\r\n LOG: 'LOG',\r\n AUTH_STATE_CHANGED: 'AUTH_STATE_CHANGED',\r\n AUTH_CALL_RESULT: 'AUTH_CALL_RESULT',\r\n FETCH_RESULT: 'FETCH_RESULT',\r\n FETCH_ERROR: 'FETCH_ERROR'\r\n}) as { readonly [K in MessageType]: K }\r\n","/**\n * FetchGuard Default Configuration Values\n */\n\n/**\n * Default time (in milliseconds) to refresh token before expiry\n * @default 60000 (60 seconds)\n */\nexport const DEFAULT_REFRESH_EARLY_MS = 60_000\n\n/**\n * Default timeout for API requests (in milliseconds)\n * @default 30000 (30 seconds)\n */\nexport const DEFAULT_TIMEOUT_MS = 30_000\n\n/**\n * Default number of retry attempts for failed requests\n * @default 3\n */\nexport const DEFAULT_RETRY_COUNT = 3\n\n/**\n * Default delay between retry attempts (in milliseconds)\n * @default 1000 (1 second)\n */\nexport const DEFAULT_RETRY_DELAY_MS = 1_000\n","/**\n * Error definitions organized by domain\n * Using ts-micro-result's defineError for consistency\n */\n\nimport { defineError, defineErrorAdvanced } from 'ts-micro-result'\n\n/**\n * General errors\n */\nexport const GeneralErrors = {\n Unexpected: defineError('UNEXPECTED', 'Unexpected error', 500),\n UnknownMessage: defineError('UNKNOWN_MESSAGE', 'Unknown message type', 400),\n ResultParse: defineError('RESULT_PARSE_ERROR', 'Failed to parse result', 500),\n} as const\n\n/**\n * Initialization errors\n */\nexport const InitErrors = {\n NotInitialized: defineError('INIT_ERROR', 'Worker not initialized', 500),\n ProviderInitFailed: defineError('PROVIDER_INIT_FAILED', 'Failed to initialize provider', 500),\n InitFailed: defineError('INIT_FAILED', 'Initialization failed', 500),\n} as const\n\n/**\n * Authentication & Token errors\n */\nexport const AuthErrors = {\n TokenRefreshFailed: defineError('TOKEN_REFRESH_FAILED', 'Token refresh failed', 401),\n LoginFailed: defineError('LOGIN_FAILED', 'Login failed', 401),\n LogoutFailed: defineError('LOGOUT_FAILED', 'Logout failed', 500),\n NotAuthenticated: defineError('NOT_AUTHENTICATED', 'User is not authenticated', 401),\n} as const\n\n/**\n * Domain validation errors\n */\nexport const DomainErrors = {\n NotAllowed: defineErrorAdvanced('DOMAIN_NOT_ALLOWED', 'Domain not allowed: {url}', 403),\n} as const\n\n/**\n * Network & HTTP errors\n */\nexport const NetworkErrors = {\n NetworkError: defineError('NETWORK_ERROR', 'Network error', 500),\n HttpError: defineError('HTTP_ERROR', 'HTTP error', 500),\n FetchError: defineError('FETCH_ERROR', 'Fetch error', 500),\n} as const\n\n/**\n * Request errors\n */\nexport const RequestErrors = {\n Cancelled: defineError('REQUEST_CANCELLED', 'Request was cancelled', 499),\n Timeout: defineError('REQUEST_TIMEOUT', 'Request timeout', 408),\n} as const\n","import type { TokenProvider } from '../types'\r\n\r\n/**\r\n * Registry to manage token providers\r\n */\r\nconst registry = new Map<string, TokenProvider>()\r\n\r\n/**\r\n * Register a token provider with name\r\n */\r\nexport function registerProvider(name: string, provider: TokenProvider): void {\r\n if (typeof name !== 'string' || !name.trim()) {\r\n throw new Error('Provider name must be a non-empty string')\r\n }\r\n \r\n if (!provider || typeof provider.refreshToken !== 'function') {\r\n throw new Error('Provider must implement TokenProvider interface')\r\n }\r\n \r\n registry.set(name, provider)\r\n}\r\n\r\n/**\r\n * Get provider by name\r\n */\r\nexport function getProvider(name: string): TokenProvider {\r\n const provider = registry.get(name)\r\n if (!provider) {\r\n throw new Error(`Provider '${name}' not found. Available providers: ${Array.from(registry.keys()).join(', ')}`)\r\n }\r\n return provider\r\n}\r\n\r\n/**\r\n * Check if provider exists\r\n */\r\nexport function hasProvider(name: string): boolean {\r\n return registry.has(name)\r\n}\r\n\r\n/**\r\n * Get list of all provider names\r\n */\r\nexport function listProviders(): string[] {\r\n return Array.from(registry.keys())\r\n}\r\n\r\n/**\r\n * Remove provider\r\n */\r\nexport function unregisterProvider(name: string): boolean {\r\n return registry.delete(name)\r\n}\r\n\r\n/**\r\n * Remove all providers\r\n */\r\nexport function clearProviders(): void {\r\n registry.clear()\r\n}\r\n","import type {\r\n TokenProvider,\r\n RefreshTokenStorage,\r\n TokenParser,\r\n AuthStrategy,\r\n TokenInfo\r\n} from '../types'\r\nimport { ok, err, type Result } from 'ts-micro-result'\r\nimport { AuthErrors, NetworkErrors } from '../errors'\r\n\r\n/**\r\n * Custom auth method type\r\n */\r\ntype CustomAuthMethod = (...args: any[]) => Promise<Result<TokenInfo>>\r\n\r\n/**\r\n * Configuration for creating provider\r\n *\r\n * refreshStorage: OPTIONAL - to load refresh token initially when worker starts\r\n * - undefined: cookie-based auth (httpOnly cookie, no need to load)\r\n * - RefreshTokenStorage: body-based auth (load from IndexedDB on startup)\r\n *\r\n * strategy: AuthStrategy with refresh (required), login/logout (required)\r\n *\r\n * customMethods: OPTIONAL - custom auth methods (loginWithPhone, loginWithGoogle, etc.)\r\n */\r\nexport interface ProviderConfig {\r\n refreshStorage?: RefreshTokenStorage\r\n parser: TokenParser\r\n strategy: AuthStrategy\r\n customMethods?: Record<string, CustomAuthMethod>\r\n}\r\n\r\n/**\r\n * Factory function to create TokenProvider from modular components\r\n *\r\n * Provider automatically handles refresh token:\r\n * - If refreshToken is null and storage exists → load from storage initially\r\n * - If refreshToken exists → use token from worker memory\r\n * - Cookie-based (no storage) → always null\r\n *\r\n * Custom methods:\r\n * - User can add custom auth methods (loginWithPhone, loginWithGoogle, etc.)\r\n * - Custom methods will be spread into provider object\r\n */\r\nexport function createProvider(config: ProviderConfig): TokenProvider {\r\n const baseProvider: Pick<TokenProvider, 'refreshToken' | 'login' | 'logout'> = {\r\n async refreshToken(refreshToken: string | null) {\r\n let currentRefreshToken = refreshToken\r\n if (currentRefreshToken === null && config.refreshStorage) {\r\n currentRefreshToken = await config.refreshStorage.get()\r\n }\r\n\r\n try {\r\n const response = await config.strategy.refresh(currentRefreshToken)\r\n\r\n if (!response.ok) {\r\n return err(AuthErrors.TokenRefreshFailed({ message: `HTTP ${response.status}` }))\r\n }\r\n\r\n const tokenInfo = await config.parser.parse(response)\r\n if (!tokenInfo.token) {\r\n return err(AuthErrors.TokenRefreshFailed({ message: 'No access token in response' }))\r\n }\r\n\r\n if (config.refreshStorage && tokenInfo.refreshToken) {\r\n await config.refreshStorage.set(tokenInfo.refreshToken)\r\n }\r\n\r\n return ok(tokenInfo)\r\n } catch (error) {\r\n return err(NetworkErrors.NetworkError({ message: String(error) }))\r\n }\r\n },\r\n\r\n async login(payload: unknown) {\r\n try {\r\n const response = await config.strategy.login(payload)\r\n\r\n if (!response.ok) {\r\n return err(AuthErrors.LoginFailed({ message: `HTTP ${response.status}` }))\r\n }\r\n\r\n const tokenInfo = await config.parser.parse(response)\r\n if (!tokenInfo.token) {\r\n return err(AuthErrors.LoginFailed({ message: 'No access token in response' }))\r\n }\r\n\r\n if (config.refreshStorage && tokenInfo.refreshToken) {\r\n await config.refreshStorage.set(tokenInfo.refreshToken)\r\n }\r\n\r\n return ok(tokenInfo)\r\n } catch (error) {\r\n return err(NetworkErrors.NetworkError({ message: String(error) }))\r\n }\r\n },\r\n\r\n async logout(payload?: unknown) {\r\n try {\r\n const response = await config.strategy.logout(payload)\r\n\r\n if (!response.ok) {\r\n return err(AuthErrors.LogoutFailed({ message: `HTTP ${response.status}` }))\r\n }\r\n\r\n if (config.refreshStorage) {\r\n await config.refreshStorage.set(null)\r\n }\r\n\r\n return ok({\r\n token: '',\r\n refreshToken: undefined,\r\n expiresAt: undefined,\r\n user: null // Explicitly clear user on logout\r\n })\r\n } catch (error) {\r\n return err(NetworkErrors.NetworkError({ message: String(error) }))\r\n }\r\n }\r\n }\r\n\r\n // Merge custom methods if provided\r\n if (config.customMethods) {\r\n return {\r\n ...baseProvider,\r\n ...config.customMethods\r\n } as TokenProvider\r\n }\r\n\r\n return baseProvider as TokenProvider\r\n}\r\n","import type { RefreshTokenStorage } from '../../types'\r\n\r\n/**\r\n * IndexedDB storage - only stores refresh token in IndexedDB\r\n * Suitable for body-based refresh strategy\r\n * Persists refresh token for reuse after reload\r\n */\r\nexport function createIndexedDBStorage(dbName = 'FetchGuardDB', refreshTokenKey = 'refreshToken'): RefreshTokenStorage {\r\n const storeName = 'tokens'\r\n\r\n const openDB = (): Promise<IDBDatabase> => {\r\n return new Promise((resolve, reject) => {\r\n const request = indexedDB.open(dbName, 1)\r\n \r\n request.onerror = () => reject(request.error)\r\n request.onsuccess = () => resolve(request.result)\r\n \r\n request.onupgradeneeded = (event) => {\r\n const db = (event.target as IDBOpenDBRequest).result\r\n if (!db.objectStoreNames.contains(storeName)) {\r\n const store = db.createObjectStore(storeName, { keyPath: 'key' })\r\n store.createIndex('timestamp', 'timestamp', { unique: false })\r\n }\r\n }\r\n })\r\n }\r\n\r\n const promisifyRequest = <T>(request: IDBRequest<T>): Promise<T> => {\r\n return new Promise((resolve, reject) => {\r\n request.onsuccess = () => resolve(request.result)\r\n request.onerror = () => reject(request.error)\r\n })\r\n }\r\n\r\n return {\r\n async get() {\r\n try {\r\n const db = await openDB()\r\n const transaction = db.transaction([storeName], 'readonly')\r\n const store = transaction.objectStore(storeName)\r\n const result = await promisifyRequest(store.get(refreshTokenKey))\r\n return result?.value || null\r\n } catch (error) {\r\n console.warn('Failed to get refresh token from IndexedDB:', error)\r\n return null\r\n }\r\n },\r\n async set(token) {\r\n try {\r\n const db = await openDB()\r\n const transaction = db.transaction([storeName], 'readwrite')\r\n const store = transaction.objectStore(storeName)\r\n\r\n if (token) {\r\n await promisifyRequest(store.put({ key: refreshTokenKey, value: token, timestamp: Date.now() }))\r\n } else {\r\n await promisifyRequest(store.delete(refreshTokenKey))\r\n }\r\n } catch (error) {\r\n console.warn('Failed to save refresh token to IndexedDB:', error)\r\n }\r\n }\r\n }\r\n}\r\n","import type { TokenParser } from '../../types'\r\n\r\n/**\r\n * Body parser - parse token from response body (JSON)\r\n * Expects response format: { data: { accessToken, refreshToken, expiresAt?, user? } }\r\n */\r\nexport const bodyParser: TokenParser = {\r\n async parse(response) {\r\n const json = await response.clone().json()\r\n return {\r\n token: json.data.accessToken,\r\n refreshToken: json.data.refreshToken,\r\n expiresAt: json.data.expiresAt,\r\n user: json.data.user\r\n }\r\n }\r\n}\r\n","import type { TokenParser } from '../../types'\r\n\r\n/**\r\n * Cookie parser - parse access token from response body\r\n * Expects response format: { data: { accessToken, expiresAt?, user? } }\r\n * Refresh token is automatically set by backend into httpOnly cookie\r\n */\r\nexport const cookieParser: TokenParser = {\r\n async parse(response) {\r\n const json = await response.clone().json()\r\n return {\r\n token: json.data.accessToken,\r\n expiresAt: json.data.expiresAt,\r\n user: json.data.user\r\n }\r\n }\r\n}\r\n","import type { AuthStrategy } from '../../types'\r\n\r\n/**\r\n * Cookie auth strategy - all auth operations via httpOnly cookies\r\n * Suitable for SSR and cross-domain authentication\r\n *\r\n * Refresh token is sent automatically via httpOnly cookie\r\n * Credentials are sent in request body\r\n */\r\nexport function createCookieStrategy(config: {\r\n refreshUrl: string\r\n loginUrl: string\r\n logoutUrl: string\r\n}): AuthStrategy {\r\n return {\r\n async refresh() {\r\n return fetch(config.refreshUrl, {\r\n method: 'POST',\r\n headers: { 'Content-Type': 'application/json' },\r\n credentials: 'include'\r\n })\r\n },\r\n\r\n async login(payload) {\r\n return fetch(config.loginUrl, {\r\n method: 'POST',\r\n headers: { 'Content-Type': 'application/json' },\r\n body: JSON.stringify(payload),\r\n credentials: 'include'\r\n })\r\n },\r\n\r\n async logout(payload) {\r\n return fetch(config.logoutUrl, {\r\n method: 'POST',\r\n headers: { 'Content-Type': 'application/json' },\r\n body: payload ? JSON.stringify(payload) : undefined,\r\n credentials: 'include'\r\n })\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Standard cookie strategy\r\n */\r\nexport const cookieStrategy = createCookieStrategy({\r\n refreshUrl: '/auth/refresh',\r\n loginUrl: '/auth/login',\r\n logoutUrl: '/auth/logout'\r\n})\r\n","import type { AuthStrategy } from '../../types'\r\n\r\n/**\r\n * Body auth strategy - all auth operations via request body\r\n * Suitable for SPA applications\r\n *\r\n * All tokens/credentials are sent in request body\r\n */\r\nexport function createBodyStrategy(config: {\r\n refreshUrl: string\r\n loginUrl: string\r\n logoutUrl: string\r\n}): AuthStrategy {\r\n return {\r\n async refresh(refreshToken) {\r\n if (!refreshToken) {\r\n throw new Error('No refresh token available')\r\n }\r\n\r\n return fetch(config.refreshUrl, {\r\n method: 'POST',\r\n headers: { 'Content-Type': 'application/json' },\r\n body: JSON.stringify({ refreshToken }),\r\n credentials: 'include'\r\n })\r\n },\r\n\r\n async login(payload) {\r\n return fetch(config.loginUrl, {\r\n method: 'POST',\r\n headers: { 'Content-Type': 'application/json' },\r\n body: JSON.stringify(payload),\r\n credentials: 'include'\r\n })\r\n },\r\n\r\n async logout(payload) {\r\n return fetch(config.logoutUrl, {\r\n method: 'POST',\r\n headers: { 'Content-Type': 'application/json' },\r\n body: payload ? JSON.stringify(payload) : undefined,\r\n credentials: 'include'\r\n })\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Standard body strategy\r\n */\r\nexport const bodyStrategy = createBodyStrategy({\r\n refreshUrl: '/auth/refresh',\r\n loginUrl: '/auth/login',\r\n logoutUrl: '/auth/logout'\r\n})\r\n","import { createProvider } from './create-provider'\r\nimport { createIndexedDBStorage } from './storage/indexeddb'\r\nimport { bodyParser } from './parser/body'\r\nimport { cookieParser } from './parser/cookie'\r\nimport { createCookieStrategy } from './strategy/cookie'\r\nimport { createBodyStrategy } from './strategy/body'\r\nimport type { TokenProvider } from '../types'\r\n\r\n/**\r\n * Cookie Provider - uses httpOnly cookies\r\n * Suitable for SSR and cross-domain authentication\r\n *\r\n * Access token: Worker memory\r\n * Refresh token: httpOnly cookie (managed by backend)\r\n */\r\nexport function createCookieProvider(config: {\r\n refreshUrl: string\r\n loginUrl: string\r\n logoutUrl: string\r\n}): TokenProvider {\r\n return createProvider({\r\n refreshStorage: undefined,\r\n parser: cookieParser,\r\n strategy: createCookieStrategy(config)\r\n })\r\n}\r\n\r\n/**\r\n * Body Provider - refresh token in response body, persisted to IndexedDB\r\n * Suitable for SPA applications\r\n *\r\n * Access token: Worker memory\r\n * Refresh token: IndexedDB (persists across reload)\r\n */\r\nexport function createBodyProvider(config: {\r\n refreshUrl: string\r\n loginUrl: string\r\n logoutUrl: string\r\n refreshTokenKey?: string\r\n}): TokenProvider {\r\n return createProvider({\r\n refreshStorage: createIndexedDBStorage('FetchGuardDB', config.refreshTokenKey || 'refreshToken'),\r\n parser: bodyParser,\r\n strategy: createBodyStrategy(config)\r\n })\r\n}\r\n"],"mappings":"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","names":["ok","err","err","ok"]}
|
package/dist/worker.js
CHANGED
|
@@ -15,6 +15,7 @@ var MSG = Object.freeze({
|
|
|
15
15
|
PONG: "PONG",
|
|
16
16
|
LOG: "LOG",
|
|
17
17
|
AUTH_STATE_CHANGED: "AUTH_STATE_CHANGED",
|
|
18
|
+
AUTH_CALL_RESULT: "AUTH_CALL_RESULT",
|
|
18
19
|
FETCH_RESULT: "FETCH_RESULT",
|
|
19
20
|
FETCH_ERROR: "FETCH_ERROR"
|
|
20
21
|
});
|
|
@@ -92,11 +93,18 @@ function sendPong(id, timestamp) {
|
|
|
92
93
|
payload: { timestamp }
|
|
93
94
|
});
|
|
94
95
|
}
|
|
95
|
-
function sendAuthStateChanged(
|
|
96
|
+
function sendAuthStateChanged(authResult) {
|
|
96
97
|
post({
|
|
97
98
|
type: MSG.AUTH_STATE_CHANGED,
|
|
98
99
|
id: `evt_${Date.now()}`,
|
|
99
|
-
payload:
|
|
100
|
+
payload: authResult
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
function sendAuthCallResult(id, authResult) {
|
|
104
|
+
post({
|
|
105
|
+
type: MSG.AUTH_CALL_RESULT,
|
|
106
|
+
id,
|
|
107
|
+
payload: authResult
|
|
100
108
|
});
|
|
101
109
|
}
|
|
102
110
|
|
|
@@ -167,7 +175,8 @@ function createProvider(config) {
|
|
|
167
175
|
token: "",
|
|
168
176
|
refreshToken: void 0,
|
|
169
177
|
expiresAt: void 0,
|
|
170
|
-
user:
|
|
178
|
+
user: null
|
|
179
|
+
// Explicitly clear user on logout
|
|
171
180
|
});
|
|
172
181
|
} catch (error) {
|
|
173
182
|
return err(NetworkErrors.NetworkError({ message: String(error) }));
|
|
@@ -483,10 +492,18 @@ function buildProviderFromPreset(config) {
|
|
|
483
492
|
return response.ok ? ok2({ body, status: response.status, headers: responseHeaders }) : err2(NetworkErrors.HttpError({ message: `HTTP ${response.status}: ${body}` }));
|
|
484
493
|
}
|
|
485
494
|
function setTokenState(tokenInfo, emitEvent = true) {
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
495
|
+
if ("token" in tokenInfo) {
|
|
496
|
+
accessToken = tokenInfo.token ?? null;
|
|
497
|
+
}
|
|
498
|
+
if ("expiresAt" in tokenInfo) {
|
|
499
|
+
expiresAt = tokenInfo.expiresAt ?? null;
|
|
500
|
+
}
|
|
501
|
+
if ("user" in tokenInfo) {
|
|
502
|
+
currentUser = tokenInfo.user;
|
|
503
|
+
}
|
|
504
|
+
if ("refreshToken" in tokenInfo) {
|
|
505
|
+
refreshToken = tokenInfo.refreshToken ?? null;
|
|
506
|
+
}
|
|
490
507
|
if (emitEvent) {
|
|
491
508
|
postAuthChanged();
|
|
492
509
|
}
|
|
@@ -494,7 +511,11 @@ function buildProviderFromPreset(config) {
|
|
|
494
511
|
function postAuthChanged() {
|
|
495
512
|
const now = Date.now();
|
|
496
513
|
const authenticated = accessToken !== null && accessToken !== "" && (expiresAt === null || expiresAt > now);
|
|
497
|
-
sendAuthStateChanged(
|
|
514
|
+
sendAuthStateChanged({
|
|
515
|
+
authenticated,
|
|
516
|
+
expiresAt,
|
|
517
|
+
user: currentUser
|
|
518
|
+
});
|
|
498
519
|
}
|
|
499
520
|
self.onmessage = async (event) => {
|
|
500
521
|
const data = event.data;
|
|
@@ -544,8 +565,8 @@ function buildProviderFromPreset(config) {
|
|
|
544
565
|
case MSG.AUTH_CALL: {
|
|
545
566
|
const { id, payload } = data;
|
|
546
567
|
try {
|
|
547
|
-
const { method, args,
|
|
548
|
-
const
|
|
568
|
+
const { method, args, emitEvent } = payload;
|
|
569
|
+
const shouldEmitEvent = emitEvent ?? true;
|
|
549
570
|
if (typeof provider[method] !== "function") {
|
|
550
571
|
sendResult(id, err2(GeneralErrors.Unexpected({ message: `Method '${method}' not found on provider` })));
|
|
551
572
|
break;
|
|
@@ -556,23 +577,14 @@ function buildProviderFromPreset(config) {
|
|
|
556
577
|
break;
|
|
557
578
|
}
|
|
558
579
|
const tokenInfo = result.data;
|
|
559
|
-
const shouldEmitEvent = mode !== "result-only";
|
|
560
|
-
const shouldSendResult = mode !== "event-only";
|
|
561
580
|
setTokenState(tokenInfo, shouldEmitEvent);
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
expiresAt,
|
|
570
|
-
user: currentUser
|
|
571
|
-
})
|
|
572
|
-
);
|
|
573
|
-
} else {
|
|
574
|
-
sendResult(id, ok2(void 0));
|
|
575
|
-
}
|
|
581
|
+
const now = Date.now();
|
|
582
|
+
const authenticated = accessToken !== null && accessToken !== "" && (expiresAt === null || expiresAt > now);
|
|
583
|
+
sendAuthCallResult(id, {
|
|
584
|
+
authenticated,
|
|
585
|
+
expiresAt,
|
|
586
|
+
user: currentUser
|
|
587
|
+
});
|
|
576
588
|
} catch (error) {
|
|
577
589
|
sendResult(id, err2(GeneralErrors.Unexpected({ message: error instanceof Error ? error.message : String(error) })));
|
|
578
590
|
}
|
package/dist/worker.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/worker.ts","../src/messages.ts","../src/constants.ts","../src/errors.ts","../src/worker-post.ts","../src/utils/registry.ts","../src/provider/create-provider.ts","../src/provider/storage/indexeddb.ts","../src/provider/parser/body.ts","../src/provider/parser/cookie.ts","../src/provider/strategy/cookie.ts","../src/provider/strategy/body.ts","../src/provider/presets.ts","../src/provider/register-presets.ts"],"sourcesContent":["/// <reference lib=\"webworker\" />\n\nimport type { WorkerConfig } from './types'\nimport type { MainToWorkerMessage } from './messages'\nimport { ok, err, type Result } from 'ts-micro-result'\nimport { MSG } from './messages'\nimport { DEFAULT_REFRESH_EARLY_MS } from './constants'\nimport {\n InitErrors,\n DomainErrors,\n NetworkErrors,\n RequestErrors,\n GeneralErrors\n} from './errors'\nimport { sendAuthStateChanged, sendPong, sendReady, sendResult, sendFetchResult, sendFetchError } from './worker-post'\nimport { getProvider } from './utils/registry'\nimport { buildProviderFromPreset } from './provider/register-presets'\n\n/**\n * IIFE Closure to protect sensitive tokens from external access\n * Inspired by api-worker.js security pattern\n */\n;(function () {\n let config: WorkerConfig | null = null\n let provider: any = null\n let accessToken: string | null = null\n let refreshToken: string | null = null\n let expiresAt: number | null = null\n let currentUser: unknown | undefined\n const pendingControllers = new Map<string, AbortController>()\n let refreshPromise: Promise<void> | null = null\n\n/**\n * Ensure we have a valid access token (not expired).\n * If token is missing or expired, refresh it.\n * Prevents concurrent refresh attempts.\n */\nasync function ensureValidToken(): Promise<Result<string | null>> {\n if (accessToken && expiresAt) {\n const refreshEarlyMs = config?.refreshEarlyMs ?? DEFAULT_REFRESH_EARLY_MS\n const timeLeft = expiresAt - Date.now()\n if (timeLeft > refreshEarlyMs) {\n return ok(accessToken)\n }\n }\n\n if (refreshPromise) {\n await refreshPromise\n return ok(accessToken)\n }\n\n refreshPromise = (async () => {\n try {\n const valueRes = await provider.refreshToken(refreshToken)\n\n if (valueRes.isError()) {\n setTokenState({ token: null, expiresAt: null, user: undefined, refreshToken: undefined })\n return\n }\n\n const tokenInfo = valueRes.data\n\n setTokenState(tokenInfo)\n } finally {\n refreshPromise = null\n }\n })()\n\n await refreshPromise\n return ok(accessToken)\n}\n\n/**\n * Validate domain against allowed domains\n */\nfunction validateDomain(url: string): boolean {\n if (!config?.allowedDomains?.length) {\n return true\n }\n\n try {\n const urlObj = new URL(url)\n const hostname = urlObj.hostname\n const port = urlObj.port\n\n for (const entry of config.allowedDomains) {\n const idx = entry.lastIndexOf(':')\n const hasPort = idx > -1 && entry.indexOf(':') === idx\n const pattern = hasPort ? entry.slice(0, idx) : entry\n const entryPort = hasPort ? entry.slice(idx + 1) : ''\n const isWildcard = pattern.startsWith('*.')\n const base = isWildcard ? pattern.slice(2) : pattern\n\n const hostnameMatch = isWildcard\n ? (hostname === base || hostname.endsWith('.' + base))\n : (hostname === base)\n \n if (!hostnameMatch) continue\n\n if (hasPort) {\n if (port === entryPort) return true\n continue\n }\n return true\n }\n return false\n } catch {\n return false\n }\n}\n\n/**\n * Make API request with proactive token management\n */\nasync function makeApiRequest(url: string, options: any = {}) {\n if (!config) {\n return err(InitErrors.NotInitialized())\n }\n\n if (!validateDomain(url)) {\n return err(DomainErrors.NotAllowed({ url }))\n }\n\n const requiresAuth = options.requiresAuth !== false\n const includeHeaders = options.includeHeaders === true\n const fetchOptions: RequestInit = { ...options }\n delete (fetchOptions as any).requiresAuth\n delete (fetchOptions as any).includeHeaders\n\n const headers: Record<string, string> = {\n ...(fetchOptions.headers as Record<string, string> || {})\n }\n\n if (!headers['Content-Type'] && !headers['content-type'] && fetchOptions.body) {\n if (typeof fetchOptions.body === 'object' && !(fetchOptions.body instanceof FormData) && !(fetchOptions.body instanceof URLSearchParams)) {\n headers['Content-Type'] = 'application/json'\n }\n }\n\n if (requiresAuth) {\n const tokenRes = await ensureValidToken()\n if (tokenRes.isError()) return tokenRes\n\n const token = tokenRes.data\n if (token) {\n headers['Authorization'] = `Bearer ${token}`\n }\n }\n\n let response: Response | null = null\n let networkErr: Result<never> | null = null\n response = await fetch(url, { ...fetchOptions, headers, credentials: 'include' }).catch((e) => {\n const aborted = (e && (e as any).name === 'AbortError')\n networkErr = aborted ? err(RequestErrors.Cancelled()) : err(NetworkErrors.NetworkError({ message: String(e) }))\n return null as any\n })\n if (!response) return (networkErr ?? err(NetworkErrors.NetworkError({ message: 'Unknown network error' })))\n\n const body = await response.text()\n let responseHeaders: Record<string, string> | undefined\n if (includeHeaders) {\n responseHeaders = {}\n response.headers.forEach((value, key) => {\n (responseHeaders as Record<string, string>)[key] = value\n })\n }\n\n return response.ok\n ? ok({ body, status: response.status, headers: responseHeaders })\n : err(NetworkErrors.HttpError({ message: `HTTP ${response.status}: ${body}` }))\n}\n\n/**\n * Update token state from TokenInfo and auto emit AUTH_STATE_CHANGED\n */\nfunction setTokenState(tokenInfo: { token: string | null; expiresAt?: number | null; user?: unknown; refreshToken?: string }, emitEvent: boolean = true) {\n accessToken = tokenInfo.token\n expiresAt = tokenInfo.expiresAt ?? null\n currentUser = tokenInfo.user\n refreshToken = tokenInfo.refreshToken ?? null\n\n if (emitEvent) {\n postAuthChanged()\n }\n}\n\n/**\n * Emit AUTH_STATE_CHANGED event based on current state\n * authenticated = true if we have valid non-expired token\n */\nfunction postAuthChanged() {\n const now = Date.now()\n const authenticated = accessToken !== null && accessToken !== '' && (expiresAt === null || expiresAt > now)\n sendAuthStateChanged(authenticated, expiresAt, currentUser)\n}\n\n/**\n * Main message handler\n * Each case has its own try-catch for better error isolation\n * Inspired by old-workers/api-worker.ts:24-123\n */\nself.onmessage = async (event: MessageEvent<MainToWorkerMessage>) => {\n const data = event.data\n switch (data.type) {\n case MSG.SETUP: {\n try {\n const payload = data.payload\n config = payload.config\n\n const providerConfig = payload.providerConfig\n\n // Build provider from config\n if (typeof providerConfig === 'string') {\n // Registry lookup\n provider = getProvider(providerConfig)\n } else if (providerConfig && typeof providerConfig === 'object' && 'type' in providerConfig) {\n // ProviderPresetConfig object\n provider = buildProviderFromPreset(providerConfig as any)\n } else {\n throw new Error('Invalid provider config')\n }\n\n sendReady()\n } catch (error) {\n console.error('[FetchGuard Worker] Setup failed:', error)\n }\n break\n }\n\n case MSG.FETCH: {\n const { id } = data\n try {\n const { url, options } = data.payload\n const controller = new AbortController()\n pendingControllers.set(id, controller)\n const merged: RequestInit = { ...(options || {}), signal: controller.signal }\n const result = await makeApiRequest(url, merged)\n\n if (result.isOk()) {\n const response = result.data as { body: string; status: number; headers?: Record<string, string> }\n sendFetchResult(id, response.status, response.body, response.headers)\n } else {\n const error = result.errors?.[0]\n const message = error?.message || 'Unknown error'\n const status = result.status\n sendFetchError(id, message, status)\n }\n\n pendingControllers.delete(id)\n } catch (error) {\n pendingControllers.delete(id)\n sendFetchError(id, error instanceof Error ? error.message : String(error), undefined)\n }\n break\n }\n\n case MSG.AUTH_CALL: {\n const { id, payload } = data\n try {\n const { method, args, responseMode } = payload\n const mode = responseMode ?? 'result-only'\n\n if (typeof provider[method] !== 'function') {\n sendResult(id, err(GeneralErrors.Unexpected({ message: `Method '${method}' not found on provider` })))\n break\n }\n\n const result = await provider[method](...args)\n if (result.isError()) {\n sendResult(id, result)\n break\n }\n\n const tokenInfo = result.data\n\n const shouldEmitEvent = mode !== 'result-only'\n const shouldSendResult = mode !== 'event-only'\n\n setTokenState(tokenInfo, shouldEmitEvent)\n\n if (shouldSendResult) {\n const now = Date.now()\n const authenticated =\n accessToken !== null && accessToken !== '' && (expiresAt === null || expiresAt > now)\n\n sendResult(\n id,\n ok({\n authenticated,\n expiresAt,\n user: currentUser\n })\n )\n }\n else{\n sendResult(id, ok(undefined))\n }\n } catch (error) {\n sendResult(id, err(GeneralErrors.Unexpected({ message: error instanceof Error ? error.message : String(error) })))\n }\n break\n }\n\n case MSG.CANCEL: {\n try {\n const { id } = data\n const controller = pendingControllers.get(id)\n if (controller) {\n controller.abort()\n pendingControllers.delete(id)\n }\n } catch (error) {\n if (config?.debug) {\n console.error('CANCEL error:', error)\n }\n }\n break\n }\n\n case MSG.PING: {\n const { id } = data\n try {\n const ts = data.payload?.timestamp ?? Date.now()\n sendPong(id, ts)\n } catch (error) {\n sendResult(id, err(GeneralErrors.Unexpected({ message: error instanceof Error ? error.message : String(error) })))\n }\n break\n }\n\n default: {\n const anyData: any = data\n sendResult(anyData.id, err(GeneralErrors.UnknownMessage({ message: `Unknown message type: ${String(anyData.type)}` })))\n }\n }\n}\n\n})() // End IIFE - Immediately Invoked Function Expression\n","import type { SerializedResult } from 'ts-micro-result'\r\nimport type { WorkerConfig, FetchGuardRequestInit, ProviderPresetConfig, AuthResponseMode } from './types'\n\r\n/**\r\n * MESSAGE PAYLOADS - SINGLE SOURCE OF TRUTH\r\n *\r\n * Define all message payloads here. Type unions and MSG constants are auto-generated.\r\n *\r\n * USAGE:\r\n * - To add a new message: Just add one line to the appropriate interface\r\n * - Payload types are automatically inferred\r\n * - MSG constants are automatically generated\r\n *\r\n * EXAMPLE:\r\n * ```typescript\r\n * interface MainPayloads {\r\n * NEW_MESSAGE: { foo: string } // Add this line\r\n * }\r\n * // => Automatically get MainToWorkerMessage union with NEW_MESSAGE\r\n * // => Automatically get MSG.NEW_MESSAGE = 'NEW_MESSAGE'\r\n * ```\r\n */\r\n\r\n/**\r\n * Payloads for messages sent from Main thread → Worker thread\r\n */\r\nexport interface MainPayloads {\n SETUP: { config: WorkerConfig; providerConfig: ProviderPresetConfig | string | null }\n FETCH: { url: string; options?: FetchGuardRequestInit }\n AUTH_CALL: { method: string; args: unknown[]; responseMode?: AuthResponseMode } // Generic auth method call (login, logout, loginWithPhone, etc.)\n CANCEL: undefined\r\n PING: { timestamp: number }\r\n}\r\n\r\n/**\r\n * Payloads for messages sent from Worker thread → Main thread\r\n */\r\nexport interface WorkerPayloads {\r\n RESULT: { result: SerializedResult | object }\r\n READY: undefined\r\n PONG: { timestamp: number }\r\n LOG: { level: 'info' | 'warn' | 'error'; message: string }\r\n AUTH_STATE_CHANGED: { authenticated: boolean; expiresAt?: number | null; user?: unknown }\r\n FETCH_RESULT: { status: number; headers?: Record<string, string>; body: string }\r\n FETCH_ERROR: { error: string; status?: number }\r\n}\r\n\r\n/**\r\n * Generate message type from payload definition\r\n * Handles optional payloads (undefined) gracefully\r\n */\r\ntype MessageFromPayloads<P> = {\r\n [K in keyof P]: { id: string; type: K } & (\r\n P[K] extends undefined ? {} : { payload: P[K] }\r\n )\r\n}[keyof P]\r\n\r\n/**\r\n * Message type unions - auto-generated from payload interfaces\r\n */\r\nexport type MainToWorkerMessage = MessageFromPayloads<MainPayloads>\r\nexport type WorkerToMainMessage = MessageFromPayloads<WorkerPayloads>\r\n\r\n/**\r\n * Message type unions for compile-time type checking\r\n */\r\nexport type MainType = keyof MainPayloads\r\nexport type WorkerType = keyof WorkerPayloads\r\nexport type MessageType = MainType | WorkerType\r\n\r\n/**\r\n * MSG constants object\r\n * Usage: MSG.SETUP, MSG.FETCH, etc.\r\n */\r\nexport const MSG = Object.freeze({\r\n // Main -> Worker messages\r\n SETUP: 'SETUP',\r\n FETCH: 'FETCH',\r\n AUTH_CALL: 'AUTH_CALL',\r\n CANCEL: 'CANCEL',\r\n PING: 'PING',\r\n\r\n // Worker -> Main messages\r\n RESULT: 'RESULT',\r\n READY: 'READY',\r\n PONG: 'PONG',\r\n LOG: 'LOG',\r\n AUTH_STATE_CHANGED: 'AUTH_STATE_CHANGED',\r\n FETCH_RESULT: 'FETCH_RESULT',\r\n FETCH_ERROR: 'FETCH_ERROR'\r\n}) as { readonly [K in MessageType]: K }\r\n","/**\n * FetchGuard Default Configuration Values\n */\n\n/**\n * Default time (in milliseconds) to refresh token before expiry\n * @default 60000 (60 seconds)\n */\nexport const DEFAULT_REFRESH_EARLY_MS = 60_000\n\n/**\n * Default timeout for API requests (in milliseconds)\n * @default 30000 (30 seconds)\n */\nexport const DEFAULT_TIMEOUT_MS = 30_000\n\n/**\n * Default number of retry attempts for failed requests\n * @default 3\n */\nexport const DEFAULT_RETRY_COUNT = 3\n\n/**\n * Default delay between retry attempts (in milliseconds)\n * @default 1000 (1 second)\n */\nexport const DEFAULT_RETRY_DELAY_MS = 1_000\n","/**\n * Error definitions organized by domain\n * Using ts-micro-result's defineError for consistency\n */\n\nimport { defineError, defineErrorAdvanced } from 'ts-micro-result'\n\n/**\n * General errors\n */\nexport const GeneralErrors = {\n Unexpected: defineError('UNEXPECTED', 'Unexpected error', 500),\n UnknownMessage: defineError('UNKNOWN_MESSAGE', 'Unknown message type', 400),\n ResultParse: defineError('RESULT_PARSE_ERROR', 'Failed to parse result', 500),\n} as const\n\n/**\n * Initialization errors\n */\nexport const InitErrors = {\n NotInitialized: defineError('INIT_ERROR', 'Worker not initialized', 500),\n ProviderInitFailed: defineError('PROVIDER_INIT_FAILED', 'Failed to initialize provider', 500),\n InitFailed: defineError('INIT_FAILED', 'Initialization failed', 500),\n} as const\n\n/**\n * Authentication & Token errors\n */\nexport const AuthErrors = {\n TokenRefreshFailed: defineError('TOKEN_REFRESH_FAILED', 'Token refresh failed', 401),\n LoginFailed: defineError('LOGIN_FAILED', 'Login failed', 401),\n LogoutFailed: defineError('LOGOUT_FAILED', 'Logout failed', 500),\n NotAuthenticated: defineError('NOT_AUTHENTICATED', 'User is not authenticated', 401),\n} as const\n\n/**\n * Domain validation errors\n */\nexport const DomainErrors = {\n NotAllowed: defineErrorAdvanced('DOMAIN_NOT_ALLOWED', 'Domain not allowed: {url}', 403),\n} as const\n\n/**\n * Network & HTTP errors\n */\nexport const NetworkErrors = {\n NetworkError: defineError('NETWORK_ERROR', 'Network error', 500),\n HttpError: defineError('HTTP_ERROR', 'HTTP error', 500),\n FetchError: defineError('FETCH_ERROR', 'Fetch error', 500),\n} as const\n\n/**\n * Request errors\n */\nexport const RequestErrors = {\n Cancelled: defineError('REQUEST_CANCELLED', 'Request was cancelled', 499),\n Timeout: defineError('REQUEST_TIMEOUT', 'Request timeout', 408),\n} as const\n","/**\r\n * Worker postMessage helpers\r\n * Utilities to send messages from worker thread to main thread\r\n */\r\n\r\nimport type { WorkerToMainMessage } from './messages'\r\nimport type { Result } from 'ts-micro-result'\r\nimport { MSG } from './messages'\r\n\r\n/**\r\n * Internal helper to post message to main thread\r\n */\r\nfunction post(message: WorkerToMainMessage): void {\r\n ;(self as DedicatedWorkerGlobalScope).postMessage(message)\r\n}\r\n\r\n/**\r\n * Send generic Result for non-fetch operations (INIT, LOGIN, LOGOUT, etc.)\r\n */\r\nexport function sendResult(id: string, result: Result<any>): void {\r\n post({\r\n type: MSG.RESULT,\r\n id,\r\n payload: { result: result.toJSON() }\r\n } as any)\r\n}\r\n\r\n/**\r\n * Send successful fetch response\r\n */\r\nexport function sendFetchResult(id: string, status: number, body: string, headers?: Record<string, string>): void {\r\n post({\r\n type: MSG.FETCH_RESULT,\r\n id,\r\n payload: headers ? ({ status, body, headers }) : ({ status, body })\r\n } as any)\r\n}\r\n\r\n/**\r\n * Send fetch error response\r\n */\r\nexport function sendFetchError(id: string, error: string, status?: number): void {\r\n post({\r\n type: MSG.FETCH_ERROR,\r\n id,\r\n payload: { error, status }\r\n } as any)\r\n}\r\n\r\n/**\r\n * Send READY event (worker initialized)\r\n */\r\nexport function sendReady(): void {\r\n post({\r\n type: MSG.READY,\r\n id: `evt_${Date.now()}`\r\n } as any)\r\n}\r\n\r\n/**\r\n * Send PONG response to PING\r\n */\r\nexport function sendPong(id: string, timestamp: number): void {\r\n post({\r\n type: MSG.PONG,\r\n id,\r\n payload: { timestamp }\r\n } as any)\r\n}\r\n\r\n/**\r\n * Send AUTH_STATE_CHANGED event\r\n */\r\nexport function sendAuthStateChanged(authenticated: boolean, expiresAt?: number | null, user?: unknown): void {\r\n post({\r\n type: MSG.AUTH_STATE_CHANGED,\r\n id: `evt_${Date.now()}`,\r\n payload: { authenticated, expiresAt, user }\r\n } as any)\r\n}\r\n","import type { TokenProvider } from '../types'\r\n\r\n/**\r\n * Registry to manage token providers\r\n */\r\nconst registry = new Map<string, TokenProvider>()\r\n\r\n/**\r\n * Register a token provider with name\r\n */\r\nexport function registerProvider(name: string, provider: TokenProvider): void {\r\n if (typeof name !== 'string' || !name.trim()) {\r\n throw new Error('Provider name must be a non-empty string')\r\n }\r\n \r\n if (!provider || typeof provider.refreshToken !== 'function') {\r\n throw new Error('Provider must implement TokenProvider interface')\r\n }\r\n \r\n registry.set(name, provider)\r\n}\r\n\r\n/**\r\n * Get provider by name\r\n */\r\nexport function getProvider(name: string): TokenProvider {\r\n const provider = registry.get(name)\r\n if (!provider) {\r\n throw new Error(`Provider '${name}' not found. Available providers: ${Array.from(registry.keys()).join(', ')}`)\r\n }\r\n return provider\r\n}\r\n\r\n/**\r\n * Check if provider exists\r\n */\r\nexport function hasProvider(name: string): boolean {\r\n return registry.has(name)\r\n}\r\n\r\n/**\r\n * Get list of all provider names\r\n */\r\nexport function listProviders(): string[] {\r\n return Array.from(registry.keys())\r\n}\r\n\r\n/**\r\n * Remove provider\r\n */\r\nexport function unregisterProvider(name: string): boolean {\r\n return registry.delete(name)\r\n}\r\n\r\n/**\r\n * Remove all providers\r\n */\r\nexport function clearProviders(): void {\r\n registry.clear()\r\n}\r\n","import type {\r\n TokenProvider,\r\n RefreshTokenStorage,\r\n TokenParser,\r\n AuthStrategy,\r\n TokenInfo\r\n} from '../types'\r\nimport { ok, err, type Result } from 'ts-micro-result'\r\nimport { AuthErrors, NetworkErrors } from '../errors'\r\n\r\n/**\r\n * Custom auth method type\r\n */\r\ntype CustomAuthMethod = (...args: any[]) => Promise<Result<TokenInfo>>\r\n\r\n/**\r\n * Configuration for creating provider\r\n *\r\n * refreshStorage: OPTIONAL - to load refresh token initially when worker starts\r\n * - undefined: cookie-based auth (httpOnly cookie, no need to load)\r\n * - RefreshTokenStorage: body-based auth (load from IndexedDB on startup)\r\n *\r\n * strategy: AuthStrategy with refresh (required), login/logout (required)\r\n *\r\n * customMethods: OPTIONAL - custom auth methods (loginWithPhone, loginWithGoogle, etc.)\r\n */\r\nexport interface ProviderConfig {\r\n refreshStorage?: RefreshTokenStorage\r\n parser: TokenParser\r\n strategy: AuthStrategy\r\n customMethods?: Record<string, CustomAuthMethod>\r\n}\r\n\r\n/**\r\n * Factory function to create TokenProvider from modular components\r\n *\r\n * Provider automatically handles refresh token:\r\n * - If refreshToken is null and storage exists → load from storage initially\r\n * - If refreshToken exists → use token from worker memory\r\n * - Cookie-based (no storage) → always null\r\n *\r\n * Custom methods:\r\n * - User can add custom auth methods (loginWithPhone, loginWithGoogle, etc.)\r\n * - Custom methods will be spread into provider object\r\n */\r\nexport function createProvider(config: ProviderConfig): TokenProvider {\r\n const baseProvider: Pick<TokenProvider, 'refreshToken' | 'login' | 'logout'> = {\r\n async refreshToken(refreshToken: string | null) {\r\n let currentRefreshToken = refreshToken\r\n if (currentRefreshToken === null && config.refreshStorage) {\r\n currentRefreshToken = await config.refreshStorage.get()\r\n }\r\n\r\n try {\r\n const response = await config.strategy.refresh(currentRefreshToken)\r\n\r\n if (!response.ok) {\r\n return err(AuthErrors.TokenRefreshFailed({ message: `HTTP ${response.status}` }))\r\n }\r\n\r\n const tokenInfo = await config.parser.parse(response)\r\n if (!tokenInfo.token) {\r\n return err(AuthErrors.TokenRefreshFailed({ message: 'No access token in response' }))\r\n }\r\n\r\n if (config.refreshStorage && tokenInfo.refreshToken) {\r\n await config.refreshStorage.set(tokenInfo.refreshToken)\r\n }\r\n\r\n return ok(tokenInfo)\r\n } catch (error) {\r\n return err(NetworkErrors.NetworkError({ message: String(error) }))\r\n }\r\n },\r\n\r\n async login(payload: unknown) {\r\n try {\r\n const response = await config.strategy.login(payload)\r\n\r\n if (!response.ok) {\r\n return err(AuthErrors.LoginFailed({ message: `HTTP ${response.status}` }))\r\n }\r\n\r\n const tokenInfo = await config.parser.parse(response)\r\n if (!tokenInfo.token) {\r\n return err(AuthErrors.LoginFailed({ message: 'No access token in response' }))\r\n }\r\n\r\n if (config.refreshStorage && tokenInfo.refreshToken) {\r\n await config.refreshStorage.set(tokenInfo.refreshToken)\r\n }\r\n\r\n return ok(tokenInfo)\r\n } catch (error) {\r\n return err(NetworkErrors.NetworkError({ message: String(error) }))\r\n }\r\n },\r\n\r\n async logout(payload?: unknown) {\r\n try {\r\n const response = await config.strategy.logout(payload)\r\n\r\n if (!response.ok) {\r\n return err(AuthErrors.LogoutFailed({ message: `HTTP ${response.status}` }))\r\n }\r\n\r\n if (config.refreshStorage) {\r\n await config.refreshStorage.set(null)\r\n }\r\n\r\n return ok({\r\n token: '',\r\n refreshToken: undefined,\r\n expiresAt: undefined,\r\n user: undefined\r\n })\r\n } catch (error) {\r\n return err(NetworkErrors.NetworkError({ message: String(error) }))\r\n }\r\n }\r\n }\r\n\r\n // Merge custom methods if provided\r\n if (config.customMethods) {\r\n return {\r\n ...baseProvider,\r\n ...config.customMethods\r\n } as TokenProvider\r\n }\r\n\r\n return baseProvider as TokenProvider\r\n}\r\n","import type { RefreshTokenStorage } from '../../types'\r\n\r\n/**\r\n * IndexedDB storage - only stores refresh token in IndexedDB\r\n * Suitable for body-based refresh strategy\r\n * Persists refresh token for reuse after reload\r\n */\r\nexport function createIndexedDBStorage(dbName = 'FetchGuardDB', refreshTokenKey = 'refreshToken'): RefreshTokenStorage {\r\n const storeName = 'tokens'\r\n\r\n const openDB = (): Promise<IDBDatabase> => {\r\n return new Promise((resolve, reject) => {\r\n const request = indexedDB.open(dbName, 1)\r\n \r\n request.onerror = () => reject(request.error)\r\n request.onsuccess = () => resolve(request.result)\r\n \r\n request.onupgradeneeded = (event) => {\r\n const db = (event.target as IDBOpenDBRequest).result\r\n if (!db.objectStoreNames.contains(storeName)) {\r\n const store = db.createObjectStore(storeName, { keyPath: 'key' })\r\n store.createIndex('timestamp', 'timestamp', { unique: false })\r\n }\r\n }\r\n })\r\n }\r\n\r\n const promisifyRequest = <T>(request: IDBRequest<T>): Promise<T> => {\r\n return new Promise((resolve, reject) => {\r\n request.onsuccess = () => resolve(request.result)\r\n request.onerror = () => reject(request.error)\r\n })\r\n }\r\n\r\n return {\r\n async get() {\r\n try {\r\n const db = await openDB()\r\n const transaction = db.transaction([storeName], 'readonly')\r\n const store = transaction.objectStore(storeName)\r\n const result = await promisifyRequest(store.get(refreshTokenKey))\r\n return result?.value || null\r\n } catch (error) {\r\n console.warn('Failed to get refresh token from IndexedDB:', error)\r\n return null\r\n }\r\n },\r\n async set(token) {\r\n try {\r\n const db = await openDB()\r\n const transaction = db.transaction([storeName], 'readwrite')\r\n const store = transaction.objectStore(storeName)\r\n\r\n if (token) {\r\n await promisifyRequest(store.put({ key: refreshTokenKey, value: token, timestamp: Date.now() }))\r\n } else {\r\n await promisifyRequest(store.delete(refreshTokenKey))\r\n }\r\n } catch (error) {\r\n console.warn('Failed to save refresh token to IndexedDB:', error)\r\n }\r\n }\r\n }\r\n}\r\n","import type { TokenParser } from '../../types'\r\n\r\n/**\r\n * Body parser - parse token from response body (JSON)\r\n * Expects response format: { data: { accessToken, refreshToken, expiresAt?, user? } }\r\n */\r\nexport const bodyParser: TokenParser = {\r\n async parse(response) {\r\n const json = await response.clone().json()\r\n return {\r\n token: json.data.accessToken,\r\n refreshToken: json.data.refreshToken,\r\n expiresAt: json.data.expiresAt,\r\n user: json.data.user\r\n }\r\n }\r\n}\r\n","import type { TokenParser } from '../../types'\r\n\r\n/**\r\n * Cookie parser - parse access token from response body\r\n * Expects response format: { data: { accessToken, expiresAt?, user? } }\r\n * Refresh token is automatically set by backend into httpOnly cookie\r\n */\r\nexport const cookieParser: TokenParser = {\r\n async parse(response) {\r\n const json = await response.clone().json()\r\n return {\r\n token: json.data.accessToken,\r\n expiresAt: json.data.expiresAt,\r\n user: json.data.user\r\n }\r\n }\r\n}\r\n","import type { AuthStrategy } from '../../types'\r\n\r\n/**\r\n * Cookie auth strategy - all auth operations via httpOnly cookies\r\n * Suitable for SSR and cross-domain authentication\r\n *\r\n * Refresh token is sent automatically via httpOnly cookie\r\n * Credentials are sent in request body\r\n */\r\nexport function createCookieStrategy(config: {\r\n refreshUrl: string\r\n loginUrl: string\r\n logoutUrl: string\r\n}): AuthStrategy {\r\n return {\r\n async refresh() {\r\n return fetch(config.refreshUrl, {\r\n method: 'POST',\r\n headers: { 'Content-Type': 'application/json' },\r\n credentials: 'include'\r\n })\r\n },\r\n\r\n async login(payload) {\r\n return fetch(config.loginUrl, {\r\n method: 'POST',\r\n headers: { 'Content-Type': 'application/json' },\r\n body: JSON.stringify(payload),\r\n credentials: 'include'\r\n })\r\n },\r\n\r\n async logout(payload) {\r\n return fetch(config.logoutUrl, {\r\n method: 'POST',\r\n headers: { 'Content-Type': 'application/json' },\r\n body: payload ? JSON.stringify(payload) : undefined,\r\n credentials: 'include'\r\n })\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Standard cookie strategy\r\n */\r\nexport const cookieStrategy = createCookieStrategy({\r\n refreshUrl: '/auth/refresh',\r\n loginUrl: '/auth/login',\r\n logoutUrl: '/auth/logout'\r\n})\r\n","import type { AuthStrategy } from '../../types'\r\n\r\n/**\r\n * Body auth strategy - all auth operations via request body\r\n * Suitable for SPA applications\r\n *\r\n * All tokens/credentials are sent in request body\r\n */\r\nexport function createBodyStrategy(config: {\r\n refreshUrl: string\r\n loginUrl: string\r\n logoutUrl: string\r\n}): AuthStrategy {\r\n return {\r\n async refresh(refreshToken) {\r\n if (!refreshToken) {\r\n throw new Error('No refresh token available')\r\n }\r\n\r\n return fetch(config.refreshUrl, {\r\n method: 'POST',\r\n headers: { 'Content-Type': 'application/json' },\r\n body: JSON.stringify({ refreshToken }),\r\n credentials: 'include'\r\n })\r\n },\r\n\r\n async login(payload) {\r\n return fetch(config.loginUrl, {\r\n method: 'POST',\r\n headers: { 'Content-Type': 'application/json' },\r\n body: JSON.stringify(payload),\r\n credentials: 'include'\r\n })\r\n },\r\n\r\n async logout(payload) {\r\n return fetch(config.logoutUrl, {\r\n method: 'POST',\r\n headers: { 'Content-Type': 'application/json' },\r\n body: payload ? JSON.stringify(payload) : undefined,\r\n credentials: 'include'\r\n })\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Standard body strategy\r\n */\r\nexport const bodyStrategy = createBodyStrategy({\r\n refreshUrl: '/auth/refresh',\r\n loginUrl: '/auth/login',\r\n logoutUrl: '/auth/logout'\r\n})\r\n","import { createProvider } from './create-provider'\r\nimport { createIndexedDBStorage } from './storage/indexeddb'\r\nimport { bodyParser } from './parser/body'\r\nimport { cookieParser } from './parser/cookie'\r\nimport { createCookieStrategy } from './strategy/cookie'\r\nimport { createBodyStrategy } from './strategy/body'\r\nimport type { TokenProvider } from '../types'\r\n\r\n/**\r\n * Cookie Provider - uses httpOnly cookies\r\n * Suitable for SSR and cross-domain authentication\r\n *\r\n * Access token: Worker memory\r\n * Refresh token: httpOnly cookie (managed by backend)\r\n */\r\nexport function createCookieProvider(config: {\r\n refreshUrl: string\r\n loginUrl: string\r\n logoutUrl: string\r\n}): TokenProvider {\r\n return createProvider({\r\n refreshStorage: undefined,\r\n parser: cookieParser,\r\n strategy: createCookieStrategy(config)\r\n })\r\n}\r\n\r\n/**\r\n * Body Provider - refresh token in response body, persisted to IndexedDB\r\n * Suitable for SPA applications\r\n *\r\n * Access token: Worker memory\r\n * Refresh token: IndexedDB (persists across reload)\r\n */\r\nexport function createBodyProvider(config: {\r\n refreshUrl: string\r\n loginUrl: string\r\n logoutUrl: string\r\n refreshTokenKey?: string\r\n}): TokenProvider {\r\n return createProvider({\r\n refreshStorage: createIndexedDBStorage('FetchGuardDB', config.refreshTokenKey || 'refreshToken'),\r\n parser: bodyParser,\r\n strategy: createBodyStrategy(config)\r\n })\r\n}\r\n","import { createCookieProvider, createBodyProvider } from './presets'\r\nimport type { TokenProvider, ProviderPresetConfig } from '../types'\r\n\r\n/**\r\n * Build provider from preset config\r\n * This is called in worker when receiving SETUP message\r\n */\r\nexport function buildProviderFromPreset(config: ProviderPresetConfig): TokenProvider {\r\n switch (config.type) {\r\n case 'cookie-auth':\r\n return createCookieProvider({\r\n refreshUrl: config.refreshUrl,\r\n loginUrl: config.loginUrl,\r\n logoutUrl: config.logoutUrl\r\n })\r\n\r\n case 'body-auth':\r\n return createBodyProvider({\r\n refreshUrl: config.refreshUrl,\r\n loginUrl: config.loginUrl,\r\n logoutUrl: config.logoutUrl,\r\n refreshTokenKey: config.refreshTokenKey\r\n })\r\n\r\n default:\r\n throw new Error(`Unknown provider type: ${(config as any).type}`)\r\n }\r\n}\r\n"],"mappings":"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","names":["ok","err","ok","err"]}
|
|
1
|
+
{"version":3,"sources":["../src/worker.ts","../src/messages.ts","../src/constants.ts","../src/errors.ts","../src/worker-post.ts","../src/utils/registry.ts","../src/provider/create-provider.ts","../src/provider/storage/indexeddb.ts","../src/provider/parser/body.ts","../src/provider/parser/cookie.ts","../src/provider/strategy/cookie.ts","../src/provider/strategy/body.ts","../src/provider/presets.ts","../src/provider/register-presets.ts"],"sourcesContent":["/// <reference lib=\"webworker\" />\n\nimport type { WorkerConfig } from './types'\nimport type { MainToWorkerMessage } from './messages'\nimport { ok, err, type Result } from 'ts-micro-result'\nimport { MSG } from './messages'\nimport { DEFAULT_REFRESH_EARLY_MS } from './constants'\nimport {\n InitErrors,\n DomainErrors,\n NetworkErrors,\n RequestErrors,\n GeneralErrors\n} from './errors'\nimport { sendAuthStateChanged, sendAuthCallResult, sendPong, sendReady, sendResult, sendFetchResult, sendFetchError } from './worker-post'\nimport { getProvider } from './utils/registry'\nimport { buildProviderFromPreset } from './provider/register-presets'\n\n/**\n * IIFE Closure to protect sensitive tokens from external access\n * Inspired by api-worker.js security pattern\n */\n;(function () {\n let config: WorkerConfig | null = null\n let provider: any = null\n let accessToken: string | null = null\n let refreshToken: string | null = null\n let expiresAt: number | null = null\n let currentUser: unknown | undefined\n const pendingControllers = new Map<string, AbortController>()\n let refreshPromise: Promise<void> | null = null\n\n/**\n * Ensure we have a valid access token (not expired).\n * If token is missing or expired, refresh it.\n * Prevents concurrent refresh attempts.\n */\nasync function ensureValidToken(): Promise<Result<string | null>> {\n if (accessToken && expiresAt) {\n const refreshEarlyMs = config?.refreshEarlyMs ?? DEFAULT_REFRESH_EARLY_MS\n const timeLeft = expiresAt - Date.now()\n if (timeLeft > refreshEarlyMs) {\n return ok(accessToken)\n }\n }\n\n if (refreshPromise) {\n await refreshPromise\n return ok(accessToken)\n }\n\n refreshPromise = (async () => {\n try {\n const valueRes = await provider.refreshToken(refreshToken)\n\n if (valueRes.isError()) {\n setTokenState({ token: null, expiresAt: null, user: undefined, refreshToken: undefined })\n return\n }\n\n const tokenInfo = valueRes.data\n\n setTokenState(tokenInfo)\n } finally {\n refreshPromise = null\n }\n })()\n\n await refreshPromise\n return ok(accessToken)\n}\n\n/**\n * Validate domain against allowed domains\n */\nfunction validateDomain(url: string): boolean {\n if (!config?.allowedDomains?.length) {\n return true\n }\n\n try {\n const urlObj = new URL(url)\n const hostname = urlObj.hostname\n const port = urlObj.port\n\n for (const entry of config.allowedDomains) {\n const idx = entry.lastIndexOf(':')\n const hasPort = idx > -1 && entry.indexOf(':') === idx\n const pattern = hasPort ? entry.slice(0, idx) : entry\n const entryPort = hasPort ? entry.slice(idx + 1) : ''\n const isWildcard = pattern.startsWith('*.')\n const base = isWildcard ? pattern.slice(2) : pattern\n\n const hostnameMatch = isWildcard\n ? (hostname === base || hostname.endsWith('.' + base))\n : (hostname === base)\n \n if (!hostnameMatch) continue\n\n if (hasPort) {\n if (port === entryPort) return true\n continue\n }\n return true\n }\n return false\n } catch {\n return false\n }\n}\n\n/**\n * Make API request with proactive token management\n */\nasync function makeApiRequest(url: string, options: any = {}) {\n if (!config) {\n return err(InitErrors.NotInitialized())\n }\n\n if (!validateDomain(url)) {\n return err(DomainErrors.NotAllowed({ url }))\n }\n\n const requiresAuth = options.requiresAuth !== false\n const includeHeaders = options.includeHeaders === true\n const fetchOptions: RequestInit = { ...options }\n delete (fetchOptions as any).requiresAuth\n delete (fetchOptions as any).includeHeaders\n\n const headers: Record<string, string> = {\n ...(fetchOptions.headers as Record<string, string> || {})\n }\n\n if (!headers['Content-Type'] && !headers['content-type'] && fetchOptions.body) {\n if (typeof fetchOptions.body === 'object' && !(fetchOptions.body instanceof FormData) && !(fetchOptions.body instanceof URLSearchParams)) {\n headers['Content-Type'] = 'application/json'\n }\n }\n\n if (requiresAuth) {\n const tokenRes = await ensureValidToken()\n if (tokenRes.isError()) return tokenRes\n\n const token = tokenRes.data\n if (token) {\n headers['Authorization'] = `Bearer ${token}`\n }\n }\n\n let response: Response | null = null\n let networkErr: Result<never> | null = null\n response = await fetch(url, { ...fetchOptions, headers, credentials: 'include' }).catch((e) => {\n const aborted = (e && (e as any).name === 'AbortError')\n networkErr = aborted ? err(RequestErrors.Cancelled()) : err(NetworkErrors.NetworkError({ message: String(e) }))\n return null as any\n })\n if (!response) return (networkErr ?? err(NetworkErrors.NetworkError({ message: 'Unknown network error' })))\n\n const body = await response.text()\n let responseHeaders: Record<string, string> | undefined\n if (includeHeaders) {\n responseHeaders = {}\n response.headers.forEach((value, key) => {\n (responseHeaders as Record<string, string>)[key] = value\n })\n }\n\n return response.ok\n ? ok({ body, status: response.status, headers: responseHeaders })\n : err(NetworkErrors.HttpError({ message: `HTTP ${response.status}: ${body}` }))\n}\n\n/**\n * Update token state from TokenInfo and auto emit AUTH_STATE_CHANGED\n *\n * Smart update logic for ALL fields:\n * - Only update field if key exists in tokenInfo\n * - If key exists with value: update to that value (including null)\n * - If key doesn't exist: preserve existing value\n *\n * This allows flexible custom auth methods:\n * - Standard login/refresh: returns { token, user, expiresAt }\n * - Update user info: may only return { user: {...} } (no token change)\n * - Verify OTP: may return {} (just validation, no state change)\n * - Logout: returns { token: null, user: null, ... } to clear all\n */\nfunction setTokenState(tokenInfo: { token?: string | null; expiresAt?: number | null; user?: unknown; refreshToken?: string | null }, emitEvent: boolean = true) {\n // Apply smart preservation to ALL fields\n if ('token' in tokenInfo) {\n accessToken = tokenInfo.token ?? null\n }\n\n if ('expiresAt' in tokenInfo) {\n expiresAt = tokenInfo.expiresAt ?? null\n }\n\n if ('user' in tokenInfo) {\n currentUser = tokenInfo.user\n }\n\n if ('refreshToken' in tokenInfo) {\n refreshToken = tokenInfo.refreshToken ?? null\n }\n\n if (emitEvent) {\n postAuthChanged()\n }\n}\n\n/**\n * Emit AUTH_STATE_CHANGED event based on current state\n * authenticated = true if we have valid non-expired token\n */\nfunction postAuthChanged() {\n const now = Date.now()\n const authenticated = accessToken !== null && accessToken !== '' && (expiresAt === null || expiresAt > now)\n sendAuthStateChanged({\n authenticated,\n expiresAt,\n user: currentUser\n })\n}\n\n/**\n * Main message handler\n * Each case has its own try-catch for better error isolation\n * Inspired by old-workers/api-worker.ts:24-123\n */\nself.onmessage = async (event: MessageEvent<MainToWorkerMessage>) => {\n const data = event.data\n switch (data.type) {\n case MSG.SETUP: {\n try {\n const payload = data.payload\n config = payload.config\n\n const providerConfig = payload.providerConfig\n\n // Build provider from config\n if (typeof providerConfig === 'string') {\n // Registry lookup\n provider = getProvider(providerConfig)\n } else if (providerConfig && typeof providerConfig === 'object' && 'type' in providerConfig) {\n // ProviderPresetConfig object\n provider = buildProviderFromPreset(providerConfig as any)\n } else {\n throw new Error('Invalid provider config')\n }\n\n sendReady()\n } catch (error) {\n console.error('[FetchGuard Worker] Setup failed:', error)\n }\n break\n }\n\n case MSG.FETCH: {\n const { id } = data\n try {\n const { url, options } = data.payload\n const controller = new AbortController()\n pendingControllers.set(id, controller)\n const merged: RequestInit = { ...(options || {}), signal: controller.signal }\n const result = await makeApiRequest(url, merged)\n\n if (result.isOk()) {\n const response = result.data as { body: string; status: number; headers?: Record<string, string> }\n sendFetchResult(id, response.status, response.body, response.headers)\n } else {\n const error = result.errors?.[0]\n const message = error?.message || 'Unknown error'\n const status = result.status\n sendFetchError(id, message, status)\n }\n\n pendingControllers.delete(id)\n } catch (error) {\n pendingControllers.delete(id)\n sendFetchError(id, error instanceof Error ? error.message : String(error), undefined)\n }\n break\n }\n\n case MSG.AUTH_CALL: {\n const { id, payload } = data\n try {\n const { method, args, emitEvent } = payload\n const shouldEmitEvent = emitEvent ?? true // Default: emit event\n\n if (typeof provider[method] !== 'function') {\n sendResult(id, err(GeneralErrors.Unexpected({ message: `Method '${method}' not found on provider` })))\n break\n }\n\n const result = await provider[method](...args)\n if (result.isError()) {\n sendResult(id, result)\n break\n }\n\n const tokenInfo = result.data\n\n // Update token state and optionally emit event\n setTokenState(tokenInfo, shouldEmitEvent)\n\n // Always send AuthResult back\n const now = Date.now()\n const authenticated =\n accessToken !== null && accessToken !== '' && (expiresAt === null || expiresAt > now)\n\n sendAuthCallResult(id, {\n authenticated,\n expiresAt,\n user: currentUser\n })\n } catch (error) {\n sendResult(id, err(GeneralErrors.Unexpected({ message: error instanceof Error ? error.message : String(error) })))\n }\n break\n }\n\n case MSG.CANCEL: {\n try {\n const { id } = data\n const controller = pendingControllers.get(id)\n if (controller) {\n controller.abort()\n pendingControllers.delete(id)\n }\n } catch (error) {\n if (config?.debug) {\n console.error('CANCEL error:', error)\n }\n }\n break\n }\n\n case MSG.PING: {\n const { id } = data\n try {\n const ts = data.payload?.timestamp ?? Date.now()\n sendPong(id, ts)\n } catch (error) {\n sendResult(id, err(GeneralErrors.Unexpected({ message: error instanceof Error ? error.message : String(error) })))\n }\n break\n }\n\n default: {\n const anyData: any = data\n sendResult(anyData.id, err(GeneralErrors.UnknownMessage({ message: `Unknown message type: ${String(anyData.type)}` })))\n }\n }\n}\n\n})() // End IIFE - Immediately Invoked Function Expression\n","import type { SerializedResult } from 'ts-micro-result'\r\nimport type { WorkerConfig, FetchGuardRequestInit, ProviderPresetConfig, AuthResult } from './types'\r\n\r\n/**\r\n * MESSAGE PAYLOADS - SINGLE SOURCE OF TRUTH\r\n *\r\n * Define all message payloads here. Type unions and MSG constants are auto-generated.\r\n *\r\n * USAGE:\r\n * - To add a new message: Just add one line to the appropriate interface\r\n * - Payload types are automatically inferred\r\n * - MSG constants are automatically generated\r\n *\r\n * EXAMPLE:\r\n * ```typescript\r\n * interface MainPayloads {\r\n * NEW_MESSAGE: { foo: string } // Add this line\r\n * }\r\n * // => Automatically get MainToWorkerMessage union with NEW_MESSAGE\r\n * // => Automatically get MSG.NEW_MESSAGE = 'NEW_MESSAGE'\r\n * ```\r\n */\r\n\r\n/**\r\n * Payloads for messages sent from Main thread → Worker thread\r\n */\r\nexport interface MainPayloads {\r\n SETUP: { config: WorkerConfig; providerConfig: ProviderPresetConfig | string | null }\r\n FETCH: { url: string; options?: FetchGuardRequestInit }\r\n AUTH_CALL: { method: string; args: unknown[]; emitEvent?: boolean } // Generic auth method call (login, logout, loginWithPhone, etc.)\r\n CANCEL: undefined\r\n PING: { timestamp: number }\r\n}\r\n\r\n/**\r\n * Payloads for messages sent from Worker thread → Main thread\r\n */\r\nexport interface WorkerPayloads {\r\n RESULT: { result: SerializedResult | object }\r\n READY: undefined\r\n PONG: { timestamp: number }\r\n LOG: { level: 'info' | 'warn' | 'error'; message: string }\r\n AUTH_STATE_CHANGED: AuthResult\r\n AUTH_CALL_RESULT: AuthResult\r\n FETCH_RESULT: { status: number; headers?: Record<string, string>; body: string }\r\n FETCH_ERROR: { error: string; status?: number }\r\n}\r\n\r\n/**\r\n * Generate message type from payload definition\r\n * Handles optional payloads (undefined) gracefully\r\n */\r\ntype MessageFromPayloads<P> = {\r\n [K in keyof P]: { id: string; type: K } & (\r\n P[K] extends undefined ? {} : { payload: P[K] }\r\n )\r\n}[keyof P]\r\n\r\n/**\r\n * Message type unions - auto-generated from payload interfaces\r\n */\r\nexport type MainToWorkerMessage = MessageFromPayloads<MainPayloads>\r\nexport type WorkerToMainMessage = MessageFromPayloads<WorkerPayloads>\r\n\r\n/**\r\n * Message type unions for compile-time type checking\r\n */\r\nexport type MainType = keyof MainPayloads\r\nexport type WorkerType = keyof WorkerPayloads\r\nexport type MessageType = MainType | WorkerType\r\n\r\n/**\r\n * MSG constants object\r\n * Usage: MSG.SETUP, MSG.FETCH, etc.\r\n */\r\nexport const MSG = Object.freeze({\r\n // Main -> Worker messages\r\n SETUP: 'SETUP',\r\n FETCH: 'FETCH',\r\n AUTH_CALL: 'AUTH_CALL',\r\n CANCEL: 'CANCEL',\r\n PING: 'PING',\r\n\r\n // Worker -> Main messages\r\n RESULT: 'RESULT',\r\n READY: 'READY',\r\n PONG: 'PONG',\r\n LOG: 'LOG',\r\n AUTH_STATE_CHANGED: 'AUTH_STATE_CHANGED',\r\n AUTH_CALL_RESULT: 'AUTH_CALL_RESULT',\r\n FETCH_RESULT: 'FETCH_RESULT',\r\n FETCH_ERROR: 'FETCH_ERROR'\r\n}) as { readonly [K in MessageType]: K }\r\n","/**\n * FetchGuard Default Configuration Values\n */\n\n/**\n * Default time (in milliseconds) to refresh token before expiry\n * @default 60000 (60 seconds)\n */\nexport const DEFAULT_REFRESH_EARLY_MS = 60_000\n\n/**\n * Default timeout for API requests (in milliseconds)\n * @default 30000 (30 seconds)\n */\nexport const DEFAULT_TIMEOUT_MS = 30_000\n\n/**\n * Default number of retry attempts for failed requests\n * @default 3\n */\nexport const DEFAULT_RETRY_COUNT = 3\n\n/**\n * Default delay between retry attempts (in milliseconds)\n * @default 1000 (1 second)\n */\nexport const DEFAULT_RETRY_DELAY_MS = 1_000\n","/**\n * Error definitions organized by domain\n * Using ts-micro-result's defineError for consistency\n */\n\nimport { defineError, defineErrorAdvanced } from 'ts-micro-result'\n\n/**\n * General errors\n */\nexport const GeneralErrors = {\n Unexpected: defineError('UNEXPECTED', 'Unexpected error', 500),\n UnknownMessage: defineError('UNKNOWN_MESSAGE', 'Unknown message type', 400),\n ResultParse: defineError('RESULT_PARSE_ERROR', 'Failed to parse result', 500),\n} as const\n\n/**\n * Initialization errors\n */\nexport const InitErrors = {\n NotInitialized: defineError('INIT_ERROR', 'Worker not initialized', 500),\n ProviderInitFailed: defineError('PROVIDER_INIT_FAILED', 'Failed to initialize provider', 500),\n InitFailed: defineError('INIT_FAILED', 'Initialization failed', 500),\n} as const\n\n/**\n * Authentication & Token errors\n */\nexport const AuthErrors = {\n TokenRefreshFailed: defineError('TOKEN_REFRESH_FAILED', 'Token refresh failed', 401),\n LoginFailed: defineError('LOGIN_FAILED', 'Login failed', 401),\n LogoutFailed: defineError('LOGOUT_FAILED', 'Logout failed', 500),\n NotAuthenticated: defineError('NOT_AUTHENTICATED', 'User is not authenticated', 401),\n} as const\n\n/**\n * Domain validation errors\n */\nexport const DomainErrors = {\n NotAllowed: defineErrorAdvanced('DOMAIN_NOT_ALLOWED', 'Domain not allowed: {url}', 403),\n} as const\n\n/**\n * Network & HTTP errors\n */\nexport const NetworkErrors = {\n NetworkError: defineError('NETWORK_ERROR', 'Network error', 500),\n HttpError: defineError('HTTP_ERROR', 'HTTP error', 500),\n FetchError: defineError('FETCH_ERROR', 'Fetch error', 500),\n} as const\n\n/**\n * Request errors\n */\nexport const RequestErrors = {\n Cancelled: defineError('REQUEST_CANCELLED', 'Request was cancelled', 499),\n Timeout: defineError('REQUEST_TIMEOUT', 'Request timeout', 408),\n} as const\n","/**\r\n * Worker postMessage helpers\r\n * Utilities to send messages from worker thread to main thread\r\n */\r\n\r\nimport type { WorkerToMainMessage } from './messages'\r\nimport type { Result } from 'ts-micro-result'\r\nimport type { AuthResult } from './types'\r\nimport { MSG } from './messages'\r\n\r\n/**\r\n * Internal helper to post message to main thread\r\n */\r\nfunction post(message: WorkerToMainMessage): void {\r\n ;(self as DedicatedWorkerGlobalScope).postMessage(message)\r\n}\r\n\r\n/**\r\n * Send generic Result for non-fetch operations (INIT, LOGIN, LOGOUT, etc.)\r\n */\r\nexport function sendResult(id: string, result: Result<any>): void {\r\n post({\r\n type: MSG.RESULT,\r\n id,\r\n payload: { result: result.toJSON() }\r\n } as any)\r\n}\r\n\r\n/**\r\n * Send successful fetch response\r\n */\r\nexport function sendFetchResult(id: string, status: number, body: string, headers?: Record<string, string>): void {\r\n post({\r\n type: MSG.FETCH_RESULT,\r\n id,\r\n payload: headers ? ({ status, body, headers }) : ({ status, body })\r\n } as any)\r\n}\r\n\r\n/**\r\n * Send fetch error response\r\n */\r\nexport function sendFetchError(id: string, error: string, status?: number): void {\r\n post({\r\n type: MSG.FETCH_ERROR,\r\n id,\r\n payload: { error, status }\r\n } as any)\r\n}\r\n\r\n/**\r\n * Send READY event (worker initialized)\r\n */\r\nexport function sendReady(): void {\r\n post({\r\n type: MSG.READY,\r\n id: `evt_${Date.now()}`\r\n } as any)\r\n}\r\n\r\n/**\r\n * Send PONG response to PING\r\n */\r\nexport function sendPong(id: string, timestamp: number): void {\r\n post({\r\n type: MSG.PONG,\r\n id,\r\n payload: { timestamp }\r\n } as any)\r\n}\r\n\r\n/**\r\n * Send AUTH_STATE_CHANGED event\r\n */\r\nexport function sendAuthStateChanged(authResult: AuthResult): void {\r\n post({\r\n type: MSG.AUTH_STATE_CHANGED,\r\n id: `evt_${Date.now()}`,\r\n payload: authResult\r\n } as any)\r\n}\r\n\r\n/**\r\n * Send AUTH_CALL_RESULT (auth method result)\r\n */\r\nexport function sendAuthCallResult(id: string, authResult: AuthResult): void {\r\n post({\r\n type: MSG.AUTH_CALL_RESULT,\r\n id,\r\n payload: authResult\r\n } as any)\r\n}\r\n","import type { TokenProvider } from '../types'\r\n\r\n/**\r\n * Registry to manage token providers\r\n */\r\nconst registry = new Map<string, TokenProvider>()\r\n\r\n/**\r\n * Register a token provider with name\r\n */\r\nexport function registerProvider(name: string, provider: TokenProvider): void {\r\n if (typeof name !== 'string' || !name.trim()) {\r\n throw new Error('Provider name must be a non-empty string')\r\n }\r\n \r\n if (!provider || typeof provider.refreshToken !== 'function') {\r\n throw new Error('Provider must implement TokenProvider interface')\r\n }\r\n \r\n registry.set(name, provider)\r\n}\r\n\r\n/**\r\n * Get provider by name\r\n */\r\nexport function getProvider(name: string): TokenProvider {\r\n const provider = registry.get(name)\r\n if (!provider) {\r\n throw new Error(`Provider '${name}' not found. Available providers: ${Array.from(registry.keys()).join(', ')}`)\r\n }\r\n return provider\r\n}\r\n\r\n/**\r\n * Check if provider exists\r\n */\r\nexport function hasProvider(name: string): boolean {\r\n return registry.has(name)\r\n}\r\n\r\n/**\r\n * Get list of all provider names\r\n */\r\nexport function listProviders(): string[] {\r\n return Array.from(registry.keys())\r\n}\r\n\r\n/**\r\n * Remove provider\r\n */\r\nexport function unregisterProvider(name: string): boolean {\r\n return registry.delete(name)\r\n}\r\n\r\n/**\r\n * Remove all providers\r\n */\r\nexport function clearProviders(): void {\r\n registry.clear()\r\n}\r\n","import type {\r\n TokenProvider,\r\n RefreshTokenStorage,\r\n TokenParser,\r\n AuthStrategy,\r\n TokenInfo\r\n} from '../types'\r\nimport { ok, err, type Result } from 'ts-micro-result'\r\nimport { AuthErrors, NetworkErrors } from '../errors'\r\n\r\n/**\r\n * Custom auth method type\r\n */\r\ntype CustomAuthMethod = (...args: any[]) => Promise<Result<TokenInfo>>\r\n\r\n/**\r\n * Configuration for creating provider\r\n *\r\n * refreshStorage: OPTIONAL - to load refresh token initially when worker starts\r\n * - undefined: cookie-based auth (httpOnly cookie, no need to load)\r\n * - RefreshTokenStorage: body-based auth (load from IndexedDB on startup)\r\n *\r\n * strategy: AuthStrategy with refresh (required), login/logout (required)\r\n *\r\n * customMethods: OPTIONAL - custom auth methods (loginWithPhone, loginWithGoogle, etc.)\r\n */\r\nexport interface ProviderConfig {\r\n refreshStorage?: RefreshTokenStorage\r\n parser: TokenParser\r\n strategy: AuthStrategy\r\n customMethods?: Record<string, CustomAuthMethod>\r\n}\r\n\r\n/**\r\n * Factory function to create TokenProvider from modular components\r\n *\r\n * Provider automatically handles refresh token:\r\n * - If refreshToken is null and storage exists → load from storage initially\r\n * - If refreshToken exists → use token from worker memory\r\n * - Cookie-based (no storage) → always null\r\n *\r\n * Custom methods:\r\n * - User can add custom auth methods (loginWithPhone, loginWithGoogle, etc.)\r\n * - Custom methods will be spread into provider object\r\n */\r\nexport function createProvider(config: ProviderConfig): TokenProvider {\r\n const baseProvider: Pick<TokenProvider, 'refreshToken' | 'login' | 'logout'> = {\r\n async refreshToken(refreshToken: string | null) {\r\n let currentRefreshToken = refreshToken\r\n if (currentRefreshToken === null && config.refreshStorage) {\r\n currentRefreshToken = await config.refreshStorage.get()\r\n }\r\n\r\n try {\r\n const response = await config.strategy.refresh(currentRefreshToken)\r\n\r\n if (!response.ok) {\r\n return err(AuthErrors.TokenRefreshFailed({ message: `HTTP ${response.status}` }))\r\n }\r\n\r\n const tokenInfo = await config.parser.parse(response)\r\n if (!tokenInfo.token) {\r\n return err(AuthErrors.TokenRefreshFailed({ message: 'No access token in response' }))\r\n }\r\n\r\n if (config.refreshStorage && tokenInfo.refreshToken) {\r\n await config.refreshStorage.set(tokenInfo.refreshToken)\r\n }\r\n\r\n return ok(tokenInfo)\r\n } catch (error) {\r\n return err(NetworkErrors.NetworkError({ message: String(error) }))\r\n }\r\n },\r\n\r\n async login(payload: unknown) {\r\n try {\r\n const response = await config.strategy.login(payload)\r\n\r\n if (!response.ok) {\r\n return err(AuthErrors.LoginFailed({ message: `HTTP ${response.status}` }))\r\n }\r\n\r\n const tokenInfo = await config.parser.parse(response)\r\n if (!tokenInfo.token) {\r\n return err(AuthErrors.LoginFailed({ message: 'No access token in response' }))\r\n }\r\n\r\n if (config.refreshStorage && tokenInfo.refreshToken) {\r\n await config.refreshStorage.set(tokenInfo.refreshToken)\r\n }\r\n\r\n return ok(tokenInfo)\r\n } catch (error) {\r\n return err(NetworkErrors.NetworkError({ message: String(error) }))\r\n }\r\n },\r\n\r\n async logout(payload?: unknown) {\r\n try {\r\n const response = await config.strategy.logout(payload)\r\n\r\n if (!response.ok) {\r\n return err(AuthErrors.LogoutFailed({ message: `HTTP ${response.status}` }))\r\n }\r\n\r\n if (config.refreshStorage) {\r\n await config.refreshStorage.set(null)\r\n }\r\n\r\n return ok({\r\n token: '',\r\n refreshToken: undefined,\r\n expiresAt: undefined,\r\n user: null // Explicitly clear user on logout\r\n })\r\n } catch (error) {\r\n return err(NetworkErrors.NetworkError({ message: String(error) }))\r\n }\r\n }\r\n }\r\n\r\n // Merge custom methods if provided\r\n if (config.customMethods) {\r\n return {\r\n ...baseProvider,\r\n ...config.customMethods\r\n } as TokenProvider\r\n }\r\n\r\n return baseProvider as TokenProvider\r\n}\r\n","import type { RefreshTokenStorage } from '../../types'\r\n\r\n/**\r\n * IndexedDB storage - only stores refresh token in IndexedDB\r\n * Suitable for body-based refresh strategy\r\n * Persists refresh token for reuse after reload\r\n */\r\nexport function createIndexedDBStorage(dbName = 'FetchGuardDB', refreshTokenKey = 'refreshToken'): RefreshTokenStorage {\r\n const storeName = 'tokens'\r\n\r\n const openDB = (): Promise<IDBDatabase> => {\r\n return new Promise((resolve, reject) => {\r\n const request = indexedDB.open(dbName, 1)\r\n \r\n request.onerror = () => reject(request.error)\r\n request.onsuccess = () => resolve(request.result)\r\n \r\n request.onupgradeneeded = (event) => {\r\n const db = (event.target as IDBOpenDBRequest).result\r\n if (!db.objectStoreNames.contains(storeName)) {\r\n const store = db.createObjectStore(storeName, { keyPath: 'key' })\r\n store.createIndex('timestamp', 'timestamp', { unique: false })\r\n }\r\n }\r\n })\r\n }\r\n\r\n const promisifyRequest = <T>(request: IDBRequest<T>): Promise<T> => {\r\n return new Promise((resolve, reject) => {\r\n request.onsuccess = () => resolve(request.result)\r\n request.onerror = () => reject(request.error)\r\n })\r\n }\r\n\r\n return {\r\n async get() {\r\n try {\r\n const db = await openDB()\r\n const transaction = db.transaction([storeName], 'readonly')\r\n const store = transaction.objectStore(storeName)\r\n const result = await promisifyRequest(store.get(refreshTokenKey))\r\n return result?.value || null\r\n } catch (error) {\r\n console.warn('Failed to get refresh token from IndexedDB:', error)\r\n return null\r\n }\r\n },\r\n async set(token) {\r\n try {\r\n const db = await openDB()\r\n const transaction = db.transaction([storeName], 'readwrite')\r\n const store = transaction.objectStore(storeName)\r\n\r\n if (token) {\r\n await promisifyRequest(store.put({ key: refreshTokenKey, value: token, timestamp: Date.now() }))\r\n } else {\r\n await promisifyRequest(store.delete(refreshTokenKey))\r\n }\r\n } catch (error) {\r\n console.warn('Failed to save refresh token to IndexedDB:', error)\r\n }\r\n }\r\n }\r\n}\r\n","import type { TokenParser } from '../../types'\r\n\r\n/**\r\n * Body parser - parse token from response body (JSON)\r\n * Expects response format: { data: { accessToken, refreshToken, expiresAt?, user? } }\r\n */\r\nexport const bodyParser: TokenParser = {\r\n async parse(response) {\r\n const json = await response.clone().json()\r\n return {\r\n token: json.data.accessToken,\r\n refreshToken: json.data.refreshToken,\r\n expiresAt: json.data.expiresAt,\r\n user: json.data.user\r\n }\r\n }\r\n}\r\n","import type { TokenParser } from '../../types'\r\n\r\n/**\r\n * Cookie parser - parse access token from response body\r\n * Expects response format: { data: { accessToken, expiresAt?, user? } }\r\n * Refresh token is automatically set by backend into httpOnly cookie\r\n */\r\nexport const cookieParser: TokenParser = {\r\n async parse(response) {\r\n const json = await response.clone().json()\r\n return {\r\n token: json.data.accessToken,\r\n expiresAt: json.data.expiresAt,\r\n user: json.data.user\r\n }\r\n }\r\n}\r\n","import type { AuthStrategy } from '../../types'\r\n\r\n/**\r\n * Cookie auth strategy - all auth operations via httpOnly cookies\r\n * Suitable for SSR and cross-domain authentication\r\n *\r\n * Refresh token is sent automatically via httpOnly cookie\r\n * Credentials are sent in request body\r\n */\r\nexport function createCookieStrategy(config: {\r\n refreshUrl: string\r\n loginUrl: string\r\n logoutUrl: string\r\n}): AuthStrategy {\r\n return {\r\n async refresh() {\r\n return fetch(config.refreshUrl, {\r\n method: 'POST',\r\n headers: { 'Content-Type': 'application/json' },\r\n credentials: 'include'\r\n })\r\n },\r\n\r\n async login(payload) {\r\n return fetch(config.loginUrl, {\r\n method: 'POST',\r\n headers: { 'Content-Type': 'application/json' },\r\n body: JSON.stringify(payload),\r\n credentials: 'include'\r\n })\r\n },\r\n\r\n async logout(payload) {\r\n return fetch(config.logoutUrl, {\r\n method: 'POST',\r\n headers: { 'Content-Type': 'application/json' },\r\n body: payload ? JSON.stringify(payload) : undefined,\r\n credentials: 'include'\r\n })\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Standard cookie strategy\r\n */\r\nexport const cookieStrategy = createCookieStrategy({\r\n refreshUrl: '/auth/refresh',\r\n loginUrl: '/auth/login',\r\n logoutUrl: '/auth/logout'\r\n})\r\n","import type { AuthStrategy } from '../../types'\r\n\r\n/**\r\n * Body auth strategy - all auth operations via request body\r\n * Suitable for SPA applications\r\n *\r\n * All tokens/credentials are sent in request body\r\n */\r\nexport function createBodyStrategy(config: {\r\n refreshUrl: string\r\n loginUrl: string\r\n logoutUrl: string\r\n}): AuthStrategy {\r\n return {\r\n async refresh(refreshToken) {\r\n if (!refreshToken) {\r\n throw new Error('No refresh token available')\r\n }\r\n\r\n return fetch(config.refreshUrl, {\r\n method: 'POST',\r\n headers: { 'Content-Type': 'application/json' },\r\n body: JSON.stringify({ refreshToken }),\r\n credentials: 'include'\r\n })\r\n },\r\n\r\n async login(payload) {\r\n return fetch(config.loginUrl, {\r\n method: 'POST',\r\n headers: { 'Content-Type': 'application/json' },\r\n body: JSON.stringify(payload),\r\n credentials: 'include'\r\n })\r\n },\r\n\r\n async logout(payload) {\r\n return fetch(config.logoutUrl, {\r\n method: 'POST',\r\n headers: { 'Content-Type': 'application/json' },\r\n body: payload ? JSON.stringify(payload) : undefined,\r\n credentials: 'include'\r\n })\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Standard body strategy\r\n */\r\nexport const bodyStrategy = createBodyStrategy({\r\n refreshUrl: '/auth/refresh',\r\n loginUrl: '/auth/login',\r\n logoutUrl: '/auth/logout'\r\n})\r\n","import { createProvider } from './create-provider'\r\nimport { createIndexedDBStorage } from './storage/indexeddb'\r\nimport { bodyParser } from './parser/body'\r\nimport { cookieParser } from './parser/cookie'\r\nimport { createCookieStrategy } from './strategy/cookie'\r\nimport { createBodyStrategy } from './strategy/body'\r\nimport type { TokenProvider } from '../types'\r\n\r\n/**\r\n * Cookie Provider - uses httpOnly cookies\r\n * Suitable for SSR and cross-domain authentication\r\n *\r\n * Access token: Worker memory\r\n * Refresh token: httpOnly cookie (managed by backend)\r\n */\r\nexport function createCookieProvider(config: {\r\n refreshUrl: string\r\n loginUrl: string\r\n logoutUrl: string\r\n}): TokenProvider {\r\n return createProvider({\r\n refreshStorage: undefined,\r\n parser: cookieParser,\r\n strategy: createCookieStrategy(config)\r\n })\r\n}\r\n\r\n/**\r\n * Body Provider - refresh token in response body, persisted to IndexedDB\r\n * Suitable for SPA applications\r\n *\r\n * Access token: Worker memory\r\n * Refresh token: IndexedDB (persists across reload)\r\n */\r\nexport function createBodyProvider(config: {\r\n refreshUrl: string\r\n loginUrl: string\r\n logoutUrl: string\r\n refreshTokenKey?: string\r\n}): TokenProvider {\r\n return createProvider({\r\n refreshStorage: createIndexedDBStorage('FetchGuardDB', config.refreshTokenKey || 'refreshToken'),\r\n parser: bodyParser,\r\n strategy: createBodyStrategy(config)\r\n })\r\n}\r\n","import { createCookieProvider, createBodyProvider } from './presets'\r\nimport type { TokenProvider, ProviderPresetConfig } from '../types'\r\n\r\n/**\r\n * Build provider from preset config\r\n * This is called in worker when receiving SETUP message\r\n */\r\nexport function buildProviderFromPreset(config: ProviderPresetConfig): TokenProvider {\r\n switch (config.type) {\r\n case 'cookie-auth':\r\n return createCookieProvider({\r\n refreshUrl: config.refreshUrl,\r\n loginUrl: config.loginUrl,\r\n logoutUrl: config.logoutUrl\r\n })\r\n\r\n case 'body-auth':\r\n return createBodyProvider({\r\n refreshUrl: config.refreshUrl,\r\n loginUrl: config.loginUrl,\r\n logoutUrl: config.logoutUrl,\r\n refreshTokenKey: config.refreshTokenKey\r\n })\r\n\r\n default:\r\n throw new Error(`Unknown provider type: ${(config as any).type}`)\r\n }\r\n}\r\n"],"mappings":"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","names":["ok","err","ok","err"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fetchguard",
|
|
3
|
-
"version": "1.1
|
|
3
|
+
"version": "1.2.1",
|
|
4
4
|
"description": "A secure fetch API library that runs in Web Workers with automatic token management",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -42,20 +42,19 @@
|
|
|
42
42
|
],
|
|
43
43
|
"author": "",
|
|
44
44
|
"license": "MIT",
|
|
45
|
+
"dependencies": {
|
|
46
|
+
"ts-micro-result": "^2.1.10"
|
|
47
|
+
},
|
|
45
48
|
"devDependencies": {
|
|
46
49
|
"@vitest/browser": "^4.0.2",
|
|
47
50
|
"@vitest/browser-playwright": "^4.0.2",
|
|
48
51
|
"@vitest/ui": "^4.0.2",
|
|
49
52
|
"happy-dom": "^20.0.8",
|
|
50
53
|
"playwright": "^1.45.1",
|
|
51
|
-
"ts-micro-result": "^2.1.10",
|
|
52
54
|
"tsup": "^8.0.0",
|
|
53
55
|
"typescript": "^5.0.0",
|
|
54
56
|
"vitest": "^4.0.2"
|
|
55
57
|
},
|
|
56
|
-
"peerDependencies": {
|
|
57
|
-
"ts-micro-result": "^2.1.10"
|
|
58
|
-
},
|
|
59
58
|
"engines": {
|
|
60
59
|
"node": ">=16.0.0"
|
|
61
60
|
},
|