@auth-craft/client 0.1.0 → 0.1.2
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 +144 -8
- package/dist/core/core.d.ts +72 -0
- package/dist/core/core.d.ts.map +1 -0
- package/dist/core/core.js +105 -0
- package/dist/core/core.js.map +1 -0
- package/dist/core/proxy.d.ts +79 -0
- package/dist/core/proxy.d.ts.map +1 -0
- package/dist/core/proxy.js +99 -0
- package/dist/core/proxy.js.map +1 -0
- package/dist/index.d.ts +15 -28
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +23 -55
- package/dist/index.js.map +1 -1
- package/dist/transport/client.d.ts +250 -0
- package/dist/transport/client.d.ts.map +1 -0
- package/dist/transport/client.js +940 -0
- package/dist/transport/client.js.map +1 -0
- package/dist/transport/constants.d.ts +9 -0
- package/dist/transport/constants.d.ts.map +1 -0
- package/dist/transport/constants.js +9 -0
- package/dist/transport/constants.js.map +1 -0
- package/dist/transport/error-codes.d.ts +41 -0
- package/dist/transport/error-codes.d.ts.map +1 -0
- package/dist/transport/error-codes.js +38 -0
- package/dist/transport/error-codes.js.map +1 -0
- package/dist/transport/errors.d.ts +55 -0
- package/dist/transport/errors.d.ts.map +1 -0
- package/dist/transport/errors.js +55 -0
- package/dist/transport/errors.js.map +1 -0
- package/dist/transport/helpers.d.ts +135 -0
- package/dist/transport/helpers.d.ts.map +1 -0
- package/dist/transport/helpers.js +185 -0
- package/dist/transport/helpers.js.map +1 -0
- package/dist/transport/index.d.ts +22 -0
- package/dist/transport/index.d.ts.map +1 -0
- package/dist/transport/index.js +32 -0
- package/dist/transport/index.js.map +1 -0
- package/dist/transport/messages.d.ts +104 -0
- package/dist/transport/messages.d.ts.map +1 -0
- package/dist/transport/messages.js +24 -0
- package/dist/transport/messages.js.map +1 -0
- package/dist/transport/provider/create-provider.d.ts +38 -0
- package/dist/transport/provider/create-provider.d.ts.map +1 -0
- package/dist/transport/provider/create-provider.js +127 -0
- package/dist/transport/provider/create-provider.js.map +1 -0
- package/dist/transport/provider/parser/body.d.ts +7 -0
- package/dist/transport/provider/parser/body.d.ts.map +1 -0
- package/dist/transport/provider/parser/body.js +17 -0
- package/dist/transport/provider/parser/body.js.map +1 -0
- package/dist/transport/provider/parser/cookie.d.ts +8 -0
- package/dist/transport/provider/parser/cookie.d.ts.map +1 -0
- package/dist/transport/provider/parser/cookie.js +17 -0
- package/dist/transport/provider/parser/cookie.js.map +1 -0
- package/dist/transport/provider/parser/normalize.d.ts +6 -0
- package/dist/transport/provider/parser/normalize.d.ts.map +1 -0
- package/dist/transport/provider/parser/normalize.js +21 -0
- package/dist/transport/provider/parser/normalize.js.map +1 -0
- package/dist/transport/provider/presets.d.ts +31 -0
- package/dist/transport/provider/presets.d.ts.map +1 -0
- package/dist/transport/provider/presets.js +35 -0
- package/dist/transport/provider/presets.js.map +1 -0
- package/dist/transport/provider/register-presets.d.ts +10 -0
- package/dist/transport/provider/register-presets.d.ts.map +1 -0
- package/dist/transport/provider/register-presets.js +32 -0
- package/dist/transport/provider/register-presets.js.map +1 -0
- package/dist/transport/provider/storage/indexeddb.d.ts +26 -0
- package/dist/transport/provider/storage/indexeddb.d.ts.map +1 -0
- package/dist/transport/provider/storage/indexeddb.js +72 -0
- package/dist/transport/provider/storage/indexeddb.js.map +1 -0
- package/dist/transport/provider/strategy/body.d.ts +28 -0
- package/dist/transport/provider/strategy/body.d.ts.map +1 -0
- package/dist/transport/provider/strategy/body.js +73 -0
- package/dist/transport/provider/strategy/body.js.map +1 -0
- package/dist/transport/provider/strategy/cookie.d.ts +29 -0
- package/dist/transport/provider/strategy/cookie.d.ts.map +1 -0
- package/dist/transport/provider/strategy/cookie.js +70 -0
- package/dist/transport/provider/strategy/cookie.js.map +1 -0
- package/dist/transport/result.d.ts +28 -0
- package/dist/transport/result.d.ts.map +1 -0
- package/dist/transport/result.js +87 -0
- package/dist/transport/result.js.map +1 -0
- package/dist/transport/types.d.ts +488 -0
- package/dist/transport/types.d.ts.map +1 -0
- package/dist/transport/types.js +3 -0
- package/dist/transport/types.js.map +1 -0
- package/dist/transport/utils/binary.d.ts +20 -0
- package/dist/transport/utils/binary.d.ts.map +1 -0
- package/dist/transport/utils/binary.js +51 -0
- package/dist/transport/utils/binary.js.map +1 -0
- package/dist/transport/utils/formdata.d.ts +26 -0
- package/dist/transport/utils/formdata.d.ts.map +1 -0
- package/dist/transport/utils/formdata.js +77 -0
- package/dist/transport/utils/formdata.js.map +1 -0
- package/dist/transport/utils/registry.d.ts +26 -0
- package/dist/transport/utils/registry.d.ts.map +1 -0
- package/dist/transport/utils/registry.js +51 -0
- package/dist/transport/utils/registry.js.map +1 -0
- package/dist/transport/worker-post.d.ts +44 -0
- package/dist/transport/worker-post.d.ts.map +1 -0
- package/dist/transport/worker-post.js +104 -0
- package/dist/transport/worker-post.js.map +1 -0
- package/dist/transport/worker.d.ts +10 -0
- package/dist/transport/worker.d.ts.map +1 -0
- package/dist/transport/worker.js +421 -0
- package/dist/transport/worker.js.map +1 -0
- package/dist/types.test-d.js +3 -9
- package/dist/types.test-d.js.map +1 -1
- package/eslint-isolation.mjs +82 -0
- package/package.json +30 -16
|
@@ -0,0 +1,488 @@
|
|
|
1
|
+
import type { Result } from 'ts-micro-result';
|
|
2
|
+
/**
|
|
3
|
+
* FetchGuard Business Types
|
|
4
|
+
*
|
|
5
|
+
* Contains domain logic types: Provider, Config, API Response, etc.
|
|
6
|
+
* For message protocol types, see messages.ts
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Token info returned from provider
|
|
10
|
+
*
|
|
11
|
+
* All fields are optional to support various custom auth methods:
|
|
12
|
+
* - Standard login/refresh: returns token + optional fields
|
|
13
|
+
* - Update user info: may only return user (no token update)
|
|
14
|
+
* - Verify OTP: may return nothing (just validation)
|
|
15
|
+
* - Custom auth flows: flexible field combinations
|
|
16
|
+
*/
|
|
17
|
+
export interface TokenInfo {
|
|
18
|
+
token?: string | null;
|
|
19
|
+
expiresAt?: number | null;
|
|
20
|
+
refreshToken?: string | null;
|
|
21
|
+
user?: unknown;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Options for token exchange operation
|
|
25
|
+
*
|
|
26
|
+
* Used when switching tenant, changing scope, or any operation
|
|
27
|
+
* that exchanges current token for a new one with different claims
|
|
28
|
+
*/
|
|
29
|
+
export interface ExchangeTokenOptions {
|
|
30
|
+
/** HTTP method to use. Default: 'POST' */
|
|
31
|
+
method?: 'POST' | 'PUT';
|
|
32
|
+
/** Payload to send with the request (e.g., tenantId, scope) */
|
|
33
|
+
payload?: Record<string, unknown>;
|
|
34
|
+
/** Custom headers for this request. Overrides defaultHeaders if same key. */
|
|
35
|
+
headers?: Record<string, string>;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Auth result returned from auth operations and auth state changes
|
|
39
|
+
* Used by: login(), logout(), refreshToken(), onAuthStateChanged()
|
|
40
|
+
*/
|
|
41
|
+
export interface AuthResult {
|
|
42
|
+
/** Whether user is authenticated (has valid non-expired token) */
|
|
43
|
+
authenticated: boolean;
|
|
44
|
+
/** User info from token (if available) */
|
|
45
|
+
user?: unknown;
|
|
46
|
+
/** Token expiry timestamp in milliseconds (if available) */
|
|
47
|
+
expiresAt?: number | null;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Interface for token provider
|
|
51
|
+
*
|
|
52
|
+
* Provider has 3 required methods:
|
|
53
|
+
* - refreshToken: Refresh access token when expired
|
|
54
|
+
* - login: Login with credentials
|
|
55
|
+
* - logout: Logout (clear tokens)
|
|
56
|
+
*
|
|
57
|
+
* User can add custom auth methods (loginWithPhone, loginWithGoogle, etc.)
|
|
58
|
+
* All custom methods must return Result<TokenInfo> for token retrieval
|
|
59
|
+
*/
|
|
60
|
+
export interface TokenProvider {
|
|
61
|
+
/**
|
|
62
|
+
* Refresh tokens (required)
|
|
63
|
+
* @param refreshToken - Current refresh token (from worker memory, null if not available)
|
|
64
|
+
* @returns Result<TokenInfo> with new tokens
|
|
65
|
+
*/
|
|
66
|
+
refreshToken(refreshToken: string | null): Promise<Result<TokenInfo>>;
|
|
67
|
+
/**
|
|
68
|
+
* Login with credentials (required)
|
|
69
|
+
* @param payload - Login credentials (email/password, etc.)
|
|
70
|
+
* @param url - Optional URL override (if not provided, uses configured loginUrl)
|
|
71
|
+
* @returns Result<TokenInfo> with tokens
|
|
72
|
+
*/
|
|
73
|
+
login(payload: unknown, url?: string): Promise<Result<TokenInfo>>;
|
|
74
|
+
/**
|
|
75
|
+
* Logout - clear tokens (required)
|
|
76
|
+
* @param payload - Optional logout payload
|
|
77
|
+
* @returns Result<TokenInfo> with all fields reset (token = '', refreshToken = undefined, user = undefined)
|
|
78
|
+
*/
|
|
79
|
+
logout(payload?: unknown): Promise<Result<TokenInfo>>;
|
|
80
|
+
/**
|
|
81
|
+
* Exchange current token for a new one with different context
|
|
82
|
+
*
|
|
83
|
+
* Useful for switching tenants, changing scopes, or any operation
|
|
84
|
+
* that requires exchanging the current token for a new one.
|
|
85
|
+
*
|
|
86
|
+
* @param accessToken - Current access token (injected by worker)
|
|
87
|
+
* @param url - URL to call for token exchange
|
|
88
|
+
* @param options - Exchange options (method, payload)
|
|
89
|
+
* @returns Result<TokenInfo> with new tokens
|
|
90
|
+
*/
|
|
91
|
+
exchangeToken(accessToken: string, url: string, options?: ExchangeTokenOptions): Promise<Result<TokenInfo>>;
|
|
92
|
+
/**
|
|
93
|
+
* Custom auth methods (optional)
|
|
94
|
+
* Examples: loginWithPhone, loginWithGoogle, loginWithFacebook, etc.
|
|
95
|
+
* All must return Result<TokenInfo> for token retrieval
|
|
96
|
+
*
|
|
97
|
+
* Note: `never[]` args (not `any[]`) keep the index signature compatible with
|
|
98
|
+
* the specific method signatures above (parameter bivariance) without `any`.
|
|
99
|
+
*/
|
|
100
|
+
[key: string]: (...args: never[]) => Promise<Result<TokenInfo>>;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Storage error context for debugging
|
|
104
|
+
*/
|
|
105
|
+
export type StorageErrorContext = 'get' | 'set' | 'delete' | 'open';
|
|
106
|
+
/**
|
|
107
|
+
* Storage error callback type
|
|
108
|
+
* Called when IndexedDB operations fail (quota exceeded, permission denied, etc.)
|
|
109
|
+
* Storage still fails closed (returns null), but this allows logging/debugging.
|
|
110
|
+
*/
|
|
111
|
+
export type StorageErrorCallback = (error: Error, context: StorageErrorContext) => void;
|
|
112
|
+
/**
|
|
113
|
+
* Interface for refresh token storage - only stores refresh token
|
|
114
|
+
*
|
|
115
|
+
* Access token is always stored in worker memory.
|
|
116
|
+
* Refresh token storage is OPTIONAL:
|
|
117
|
+
* - If available (IndexedDB): persist refresh token for reuse after reload
|
|
118
|
+
* - If not (undefined): cookie-based auth (httpOnly cookie)
|
|
119
|
+
*/
|
|
120
|
+
export interface RefreshTokenStorage {
|
|
121
|
+
get(): Promise<string | null>;
|
|
122
|
+
set(token: string | null): Promise<void>;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Interface for token parser - parse token from backend response
|
|
126
|
+
* Parser returns complete TokenInfo (including user data)
|
|
127
|
+
*/
|
|
128
|
+
export interface TokenParser {
|
|
129
|
+
parse(response: Response): Promise<TokenInfo>;
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Interface for auth strategy - defines how to call auth APIs
|
|
133
|
+
*
|
|
134
|
+
* Strategy focuses only on API calls, returns Response
|
|
135
|
+
* Provider handles parsing and storage
|
|
136
|
+
*
|
|
137
|
+
* All methods are required
|
|
138
|
+
*/
|
|
139
|
+
export interface AuthStrategy {
|
|
140
|
+
/** Refresh access token */
|
|
141
|
+
refresh(refreshToken: string | null): Promise<Response>;
|
|
142
|
+
/**
|
|
143
|
+
* Login with credentials
|
|
144
|
+
* @param payload - Login credentials
|
|
145
|
+
* @param url - Optional URL override (if not provided, uses configured loginUrl)
|
|
146
|
+
*/
|
|
147
|
+
login(payload: unknown, url?: string): Promise<Response>;
|
|
148
|
+
/** Logout */
|
|
149
|
+
logout(payload?: unknown): Promise<Response>;
|
|
150
|
+
/**
|
|
151
|
+
* Exchange current token for a new one with different context
|
|
152
|
+
* @param accessToken - Current access token
|
|
153
|
+
* @param url - URL to call for token exchange
|
|
154
|
+
* @param options - Exchange options (method, payload)
|
|
155
|
+
*/
|
|
156
|
+
exchangeToken(accessToken: string, url: string, options?: ExchangeTokenOptions): Promise<Response>;
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Provider preset configuration for built-in auth strategies
|
|
160
|
+
*/
|
|
161
|
+
export interface ProviderPresetConfig {
|
|
162
|
+
type: 'cookie-auth' | 'body-auth';
|
|
163
|
+
refreshUrl: string;
|
|
164
|
+
loginUrl: string;
|
|
165
|
+
logoutUrl: string;
|
|
166
|
+
refreshTokenKey?: string;
|
|
167
|
+
/** Custom headers to include in all auth requests (login, logout, refresh) */
|
|
168
|
+
headers?: Record<string, string>;
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Configuration for FetchGuard client
|
|
172
|
+
*/
|
|
173
|
+
export interface FetchGuardOptions {
|
|
174
|
+
/**
|
|
175
|
+
* Token provider - 3 options:
|
|
176
|
+
* 1. TokenProvider instance (for custom providers)
|
|
177
|
+
* 2. ProviderPresetConfig object (for built-in presets)
|
|
178
|
+
* 3. string (for registry lookup - advanced usage)
|
|
179
|
+
*/
|
|
180
|
+
provider: TokenProvider | ProviderPresetConfig | string;
|
|
181
|
+
/** List of allowed domains (wildcard supported) */
|
|
182
|
+
allowedDomains?: string[];
|
|
183
|
+
/** Early refresh time for tokens (ms) */
|
|
184
|
+
refreshEarlyMs?: number;
|
|
185
|
+
/** Default headers to include in all requests */
|
|
186
|
+
defaultHeaders?: Record<string, string>;
|
|
187
|
+
/**
|
|
188
|
+
* Maximum concurrent requests to worker (default: 6)
|
|
189
|
+
* Controls how many requests can be in-flight simultaneously.
|
|
190
|
+
* Set to 1 for strictly sequential processing.
|
|
191
|
+
* Higher values increase throughput but may cause worker congestion.
|
|
192
|
+
*/
|
|
193
|
+
maxConcurrent?: number;
|
|
194
|
+
/**
|
|
195
|
+
* Maximum queue size for pending requests (default: 1000)
|
|
196
|
+
* When queue is full, new requests will immediately fail with QUEUE_FULL error.
|
|
197
|
+
* Prevents memory leak if worker is unresponsive.
|
|
198
|
+
*/
|
|
199
|
+
maxQueueSize?: number;
|
|
200
|
+
/**
|
|
201
|
+
* Worker setup timeout in milliseconds (default: 10000)
|
|
202
|
+
* How long to wait for worker to be ready before failing.
|
|
203
|
+
*/
|
|
204
|
+
setupTimeout?: number;
|
|
205
|
+
/**
|
|
206
|
+
* Default request timeout in milliseconds (default: 30000)
|
|
207
|
+
* How long to wait for a request to complete before timing out.
|
|
208
|
+
* Can be overridden per-request via fetch options.
|
|
209
|
+
*/
|
|
210
|
+
requestTimeout?: number;
|
|
211
|
+
/**
|
|
212
|
+
* Debug hooks for observing operations (logging, monitoring)
|
|
213
|
+
* All hooks are observe-only - they cannot modify requests/responses.
|
|
214
|
+
*/
|
|
215
|
+
debug?: DebugHooks;
|
|
216
|
+
/**
|
|
217
|
+
* Retry configuration for network errors
|
|
218
|
+
* Only retries on transport failures, NOT on HTTP errors (4xx/5xx)
|
|
219
|
+
*/
|
|
220
|
+
retry?: RetryConfig;
|
|
221
|
+
/**
|
|
222
|
+
* Request deduplication configuration
|
|
223
|
+
* When enabled, duplicate requests to the same URL within a time window
|
|
224
|
+
* will share the same response instead of making multiple requests.
|
|
225
|
+
*/
|
|
226
|
+
dedupe?: DedupeConfig;
|
|
227
|
+
/**
|
|
228
|
+
* Custom worker factory function
|
|
229
|
+
*
|
|
230
|
+
* Use this when you need a custom provider with parser/strategy functions.
|
|
231
|
+
* Create a custom worker file that imports 'fetchguard/worker' and registers
|
|
232
|
+
* your provider, then pass a factory function that creates that worker.
|
|
233
|
+
*
|
|
234
|
+
* @example
|
|
235
|
+
* ```ts
|
|
236
|
+
* // my-worker.ts
|
|
237
|
+
* import 'fetchguard/worker'
|
|
238
|
+
* import { registerProvider, createProvider, ... } from 'fetchguard'
|
|
239
|
+
* const myProvider = createProvider({ parser: myParser, strategy: myStrategy, ... })
|
|
240
|
+
* registerProvider('my-auth', myProvider)
|
|
241
|
+
*
|
|
242
|
+
* // main.ts
|
|
243
|
+
* import MyWorker from './my-worker?worker'
|
|
244
|
+
* const api = createClient({
|
|
245
|
+
* provider: 'my-auth',
|
|
246
|
+
* workerFactory: () => new MyWorker()
|
|
247
|
+
* })
|
|
248
|
+
* ```
|
|
249
|
+
*/
|
|
250
|
+
workerFactory?: () => Worker;
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* Internal worker configuration
|
|
254
|
+
*/
|
|
255
|
+
export interface WorkerConfig {
|
|
256
|
+
allowedDomains: string[];
|
|
257
|
+
refreshEarlyMs: number;
|
|
258
|
+
defaultHeaders: Record<string, string>;
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* Extended RequestInit with FetchGuard-specific options
|
|
262
|
+
*/
|
|
263
|
+
export interface FetchGuardRequestInit extends RequestInit {
|
|
264
|
+
/** Whether this request requires authentication. Default: true */
|
|
265
|
+
requiresAuth?: boolean;
|
|
266
|
+
/** Include response headers in result metadata and FETCH_RESULT payload */
|
|
267
|
+
includeHeaders?: boolean;
|
|
268
|
+
}
|
|
269
|
+
/**
|
|
270
|
+
* Fetch envelope - raw HTTP response from worker
|
|
271
|
+
*
|
|
272
|
+
* Worker only fetches and returns raw data, does NOT judge HTTP status.
|
|
273
|
+
* Client receives envelope and decides ok/err based on business logic.
|
|
274
|
+
*
|
|
275
|
+
* - status: HTTP status code (2xx, 3xx, 4xx, 5xx)
|
|
276
|
+
* - body: string (text/JSON) or base64 (binary)
|
|
277
|
+
* - contentType: always present, indicates how to decode body
|
|
278
|
+
* - headers: empty object if includeHeaders: false
|
|
279
|
+
*/
|
|
280
|
+
export interface FetchEnvelope {
|
|
281
|
+
status: number;
|
|
282
|
+
body: string;
|
|
283
|
+
contentType: string;
|
|
284
|
+
headers: Record<string, string>;
|
|
285
|
+
}
|
|
286
|
+
/**
|
|
287
|
+
* Serialized file data for transfer over postMessage
|
|
288
|
+
* Uses ArrayBuffer for zero-copy transfer via Transferable
|
|
289
|
+
*/
|
|
290
|
+
export interface SerializedFile {
|
|
291
|
+
name: string;
|
|
292
|
+
type: string;
|
|
293
|
+
/** ArrayBuffer - transferred via postMessage Transferable for zero-copy */
|
|
294
|
+
buffer: ArrayBuffer;
|
|
295
|
+
}
|
|
296
|
+
/**
|
|
297
|
+
* Serialized FormData entry - can be string or file
|
|
298
|
+
*/
|
|
299
|
+
export type SerializedFormDataEntry = string | SerializedFile;
|
|
300
|
+
/**
|
|
301
|
+
* Serialized FormData for transfer over postMessage
|
|
302
|
+
*/
|
|
303
|
+
export interface SerializedFormData {
|
|
304
|
+
_type: 'FormData';
|
|
305
|
+
entries: Array<[string, SerializedFormDataEntry]>;
|
|
306
|
+
}
|
|
307
|
+
/**
|
|
308
|
+
* Result of FormData serialization with transferables
|
|
309
|
+
* Used for zero-copy transfer via postMessage
|
|
310
|
+
*/
|
|
311
|
+
export interface SerializedFormDataResult {
|
|
312
|
+
data: SerializedFormData;
|
|
313
|
+
/** ArrayBuffers to transfer - pass to postMessage as second argument */
|
|
314
|
+
transferables: ArrayBuffer[];
|
|
315
|
+
}
|
|
316
|
+
/**
|
|
317
|
+
* Network error detail for transport failures
|
|
318
|
+
* Used when no HTTP response is received (connection failed, timeout, cancelled)
|
|
319
|
+
*/
|
|
320
|
+
export interface NetworkErrorDetail {
|
|
321
|
+
code: 'NETWORK_ERROR' | 'REQUEST_CANCELLED' | 'RESPONSE_PARSE_FAILED';
|
|
322
|
+
message: string;
|
|
323
|
+
}
|
|
324
|
+
/**
|
|
325
|
+
* Reason for token refresh
|
|
326
|
+
*/
|
|
327
|
+
export type RefreshReason = 'expired' | 'proactive' | 'manual';
|
|
328
|
+
/**
|
|
329
|
+
* Request timing metrics for performance monitoring
|
|
330
|
+
*
|
|
331
|
+
* All times are in milliseconds.
|
|
332
|
+
*/
|
|
333
|
+
export interface RequestMetrics {
|
|
334
|
+
/** When request was initiated (Date.now()) */
|
|
335
|
+
startTime: number;
|
|
336
|
+
/** When response was received (Date.now()) */
|
|
337
|
+
endTime: number;
|
|
338
|
+
/** Total duration (endTime - startTime) */
|
|
339
|
+
duration: number;
|
|
340
|
+
/** Time spent waiting in queue before processing */
|
|
341
|
+
queueTime: number;
|
|
342
|
+
/** Time spent in IPC (postMessage round-trip overhead) */
|
|
343
|
+
ipcTime: number;
|
|
344
|
+
}
|
|
345
|
+
/**
|
|
346
|
+
* Debug hooks for observing FetchGuard operations
|
|
347
|
+
*
|
|
348
|
+
* All hooks are observe-only - they cannot modify requests/responses.
|
|
349
|
+
* Useful for logging, debugging, and monitoring.
|
|
350
|
+
*
|
|
351
|
+
* Note: Hooks run synchronously and should not perform heavy operations.
|
|
352
|
+
*/
|
|
353
|
+
export interface DebugHooks {
|
|
354
|
+
/**
|
|
355
|
+
* Called before each request is sent to worker
|
|
356
|
+
* @param url - Request URL
|
|
357
|
+
* @param options - Request options (method, headers, etc.)
|
|
358
|
+
*/
|
|
359
|
+
onRequest?: (url: string, options: FetchGuardRequestInit) => void;
|
|
360
|
+
/**
|
|
361
|
+
* Called when response is received from worker
|
|
362
|
+
* @param url - Request URL
|
|
363
|
+
* @param envelope - Response envelope (status, body, headers)
|
|
364
|
+
* @param metrics - Request timing metrics (optional, for performance monitoring)
|
|
365
|
+
*/
|
|
366
|
+
onResponse?: (url: string, envelope: FetchEnvelope, metrics?: RequestMetrics) => void;
|
|
367
|
+
/**
|
|
368
|
+
* Called when token refresh occurs
|
|
369
|
+
* @param reason - Why refresh happened: 'expired', 'proactive', or 'manual'
|
|
370
|
+
*/
|
|
371
|
+
onRefresh?: (reason: RefreshReason) => void;
|
|
372
|
+
/**
|
|
373
|
+
* Called when transport error occurs (network failure, timeout, cancelled)
|
|
374
|
+
* @param url - Request URL
|
|
375
|
+
* @param error - Error detail with code and message
|
|
376
|
+
* @param metrics - Request timing metrics (optional)
|
|
377
|
+
*/
|
|
378
|
+
onError?: (url: string, error: NetworkErrorDetail, metrics?: RequestMetrics) => void;
|
|
379
|
+
/**
|
|
380
|
+
* Called when worker is ready after initialization
|
|
381
|
+
*/
|
|
382
|
+
onWorkerReady?: () => void;
|
|
383
|
+
/**
|
|
384
|
+
* Called when worker encounters a fatal error
|
|
385
|
+
* @param error - Error event from worker
|
|
386
|
+
*/
|
|
387
|
+
onWorkerError?: (error: ErrorEvent) => void;
|
|
388
|
+
}
|
|
389
|
+
/**
|
|
390
|
+
* Retry configuration for network errors
|
|
391
|
+
*
|
|
392
|
+
* Only retries on transport failures (network error, timeout).
|
|
393
|
+
* Does NOT retry on HTTP errors (4xx/5xx) - those are valid responses.
|
|
394
|
+
* Does NOT retry cancelled requests.
|
|
395
|
+
*/
|
|
396
|
+
export interface RetryConfig {
|
|
397
|
+
/**
|
|
398
|
+
* Maximum number of retry attempts (default: 0 = no retry)
|
|
399
|
+
*/
|
|
400
|
+
maxAttempts?: number;
|
|
401
|
+
/**
|
|
402
|
+
* Delay between retries in milliseconds (default: 1000)
|
|
403
|
+
*/
|
|
404
|
+
delay?: number;
|
|
405
|
+
/**
|
|
406
|
+
* Exponential backoff multiplier (default: 1 = no backoff)
|
|
407
|
+
* Example: delay=1000, backoff=2 => 1s, 2s, 4s, 8s...
|
|
408
|
+
*/
|
|
409
|
+
backoff?: number;
|
|
410
|
+
/**
|
|
411
|
+
* Maximum delay in milliseconds (default: 30000)
|
|
412
|
+
* Caps the delay when using exponential backoff
|
|
413
|
+
*/
|
|
414
|
+
maxDelay?: number;
|
|
415
|
+
/**
|
|
416
|
+
* Jitter factor to add randomness to retry delays (default: 0 = no jitter)
|
|
417
|
+
* Range: 0 to 1 (e.g., 0.5 = ±50% randomness)
|
|
418
|
+
* Helps prevent thundering herd when many clients retry simultaneously.
|
|
419
|
+
*
|
|
420
|
+
* Note: Jitter is only applied when shouldRetry returns true.
|
|
421
|
+
* If request fails permanently, no jitter delay occurs.
|
|
422
|
+
*
|
|
423
|
+
* Example: delay=1000, jitter=0.5 => delay between 500ms and 1500ms
|
|
424
|
+
*/
|
|
425
|
+
jitter?: number;
|
|
426
|
+
/**
|
|
427
|
+
* Custom condition to determine if error should be retried
|
|
428
|
+
* Default: retry on NETWORK_ERROR only
|
|
429
|
+
* @param error - The error that occurred
|
|
430
|
+
* @returns true to retry, false to fail immediately
|
|
431
|
+
*/
|
|
432
|
+
shouldRetry?: (error: NetworkErrorDetail) => boolean;
|
|
433
|
+
}
|
|
434
|
+
/**
|
|
435
|
+
* Request deduplication configuration
|
|
436
|
+
*
|
|
437
|
+
* When enabled, identical GET requests (same URL) within a time window
|
|
438
|
+
* will share the same in-flight request instead of making duplicates.
|
|
439
|
+
*
|
|
440
|
+
* IMPORTANT:
|
|
441
|
+
* - Only applies to GET requests (POST/PUT/DELETE are never deduplicated)
|
|
442
|
+
* - Only deduplicates in-flight requests (not caching)
|
|
443
|
+
* - Safe for most read operations
|
|
444
|
+
*/
|
|
445
|
+
export interface DedupeConfig {
|
|
446
|
+
/**
|
|
447
|
+
* Enable deduplication (default: false)
|
|
448
|
+
*/
|
|
449
|
+
enabled?: boolean;
|
|
450
|
+
/**
|
|
451
|
+
* Time window in milliseconds to consider requests as duplicates (default: 0)
|
|
452
|
+
* 0 = only dedupe concurrent/in-flight requests
|
|
453
|
+
* >0 = also dedupe requests within this time window after completion
|
|
454
|
+
*/
|
|
455
|
+
window?: number;
|
|
456
|
+
/**
|
|
457
|
+
* Custom key generator for deduplication
|
|
458
|
+
* Default: uses URL only for GET requests
|
|
459
|
+
* @param url - Request URL
|
|
460
|
+
* @param options - Request options
|
|
461
|
+
* @returns Key string, or null to skip deduplication for this request
|
|
462
|
+
*/
|
|
463
|
+
keyGenerator?: (url: string, options: FetchGuardRequestInit) => string | null;
|
|
464
|
+
}
|
|
465
|
+
/**
|
|
466
|
+
* Transport result - represents the outcome of a network request
|
|
467
|
+
*
|
|
468
|
+
* IMPORTANT: This is a TRANSPORT result, not a business result.
|
|
469
|
+
* - ok = HTTP response received (check envelope.status for 2xx/4xx/5xx)
|
|
470
|
+
* - err = Network failure (no response received)
|
|
471
|
+
*
|
|
472
|
+
* Example:
|
|
473
|
+
* ```typescript
|
|
474
|
+
* const result = await api.get('/users')
|
|
475
|
+
* if (result.ok) {
|
|
476
|
+
* // Transport succeeded - got HTTP response
|
|
477
|
+
* if (result.data.status >= 200 && result.data.status < 400) {
|
|
478
|
+
* // Business success
|
|
479
|
+
* } else {
|
|
480
|
+
* // Business error (4xx/5xx) - still has response body
|
|
481
|
+
* }
|
|
482
|
+
* } else {
|
|
483
|
+
* // Transport failed - no response (network error, timeout, cancelled)
|
|
484
|
+
* }
|
|
485
|
+
* ```
|
|
486
|
+
*/
|
|
487
|
+
export type TransportResult = Result<FetchEnvelope>;
|
|
488
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/transport/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/transport/types.ts"],"names":[],"mappings":"AAAA,iCAAiC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Binary data utilities for Worker
|
|
3
|
+
* Handles ArrayBuffer <-> Base64 conversion for binary responses
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Convert ArrayBuffer to base64 string
|
|
7
|
+
* Used in worker to encode binary responses for postMessage transfer
|
|
8
|
+
*/
|
|
9
|
+
export declare function arrayBufferToBase64(buffer: ArrayBuffer): string;
|
|
10
|
+
/**
|
|
11
|
+
* Convert base64 string to ArrayBuffer
|
|
12
|
+
* Used in client to decode binary responses
|
|
13
|
+
*/
|
|
14
|
+
export declare function base64ToArrayBuffer(base64: string): ArrayBuffer;
|
|
15
|
+
/**
|
|
16
|
+
* Check if content type is binary (should be base64 encoded)
|
|
17
|
+
* Returns true for images, PDFs, videos, etc.
|
|
18
|
+
*/
|
|
19
|
+
export declare function isBinaryContentType(contentType: string): boolean;
|
|
20
|
+
//# sourceMappingURL=binary.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"binary.d.ts","sourceRoot":"","sources":["../../../src/transport/utils/binary.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,CAO/D;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,WAAW,CAO/D;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAahE"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Binary data utilities for Worker
|
|
3
|
+
* Handles ArrayBuffer <-> Base64 conversion for binary responses
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Convert ArrayBuffer to base64 string
|
|
7
|
+
* Used in worker to encode binary responses for postMessage transfer
|
|
8
|
+
*/
|
|
9
|
+
export function arrayBufferToBase64(buffer) {
|
|
10
|
+
const bytes = new Uint8Array(buffer);
|
|
11
|
+
let binary = '';
|
|
12
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
13
|
+
binary += String.fromCharCode(bytes[i]);
|
|
14
|
+
}
|
|
15
|
+
return btoa(binary);
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Convert base64 string to ArrayBuffer
|
|
19
|
+
* Used in client to decode binary responses
|
|
20
|
+
*/
|
|
21
|
+
export function base64ToArrayBuffer(base64) {
|
|
22
|
+
const binary = atob(base64);
|
|
23
|
+
const bytes = new Uint8Array(binary.length);
|
|
24
|
+
for (let i = 0; i < binary.length; i++) {
|
|
25
|
+
bytes[i] = binary.charCodeAt(i);
|
|
26
|
+
}
|
|
27
|
+
return bytes.buffer;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Check if content type is binary (should be base64 encoded)
|
|
31
|
+
* Returns true for images, PDFs, videos, etc.
|
|
32
|
+
*/
|
|
33
|
+
export function isBinaryContentType(contentType) {
|
|
34
|
+
const normalized = contentType.toLowerCase();
|
|
35
|
+
// Text types - NOT binary
|
|
36
|
+
if (normalized.includes('text/'))
|
|
37
|
+
return false;
|
|
38
|
+
if (normalized.includes('json'))
|
|
39
|
+
return false;
|
|
40
|
+
if (normalized.includes('xml'))
|
|
41
|
+
return false;
|
|
42
|
+
if (normalized.includes('javascript'))
|
|
43
|
+
return false;
|
|
44
|
+
if (normalized.includes('ecmascript'))
|
|
45
|
+
return false;
|
|
46
|
+
if (normalized.includes('html'))
|
|
47
|
+
return false;
|
|
48
|
+
// Everything else is considered binary
|
|
49
|
+
return true;
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=binary.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"binary.js","sourceRoot":"","sources":["../../../src/transport/utils/binary.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;GAGG;AACH,MAAM,UAAU,mBAAmB,CAAC,MAAmB;IACrD,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,MAAM,CAAC,CAAC;IACrC,IAAI,MAAM,GAAG,EAAE,CAAC;IAChB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACtC,MAAM,IAAI,MAAM,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAC1C,CAAC;IACD,OAAO,IAAI,CAAC,MAAM,CAAC,CAAC;AACtB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,mBAAmB,CAAC,MAAc;IAChD,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC;IAC5B,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAC5C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACvC,KAAK,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;IAClC,CAAC;IACD,OAAO,KAAK,CAAC,MAAM,CAAC;AACtB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,mBAAmB,CAAC,WAAmB;IACrD,MAAM,UAAU,GAAG,WAAW,CAAC,WAAW,EAAE,CAAC;IAE7C,0BAA0B;IAC1B,IAAI,UAAU,CAAC,QAAQ,CAAC,OAAO,CAAC;QAAE,OAAO,KAAK,CAAC;IAC/C,IAAI,UAAU,CAAC,QAAQ,CAAC,MAAM,CAAC;QAAE,OAAO,KAAK,CAAC;IAC9C,IAAI,UAAU,CAAC,QAAQ,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IAC7C,IAAI,UAAU,CAAC,QAAQ,CAAC,YAAY,CAAC;QAAE,OAAO,KAAK,CAAC;IACpD,IAAI,UAAU,CAAC,QAAQ,CAAC,YAAY,CAAC;QAAE,OAAO,KAAK,CAAC;IACpD,IAAI,UAAU,CAAC,QAAQ,CAAC,MAAM,CAAC;QAAE,OAAO,KAAK,CAAC;IAE9C,uCAAuC;IACvC,OAAO,IAAI,CAAC;AACd,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { SerializedFormData, SerializedFormDataResult } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* Serialize FormData for transfer over postMessage
|
|
4
|
+
*
|
|
5
|
+
* FormData cannot be cloned via postMessage, so we need to serialize it first.
|
|
6
|
+
* Files are converted to ArrayBuffer and returned as transferables for zero-copy transfer.
|
|
7
|
+
*
|
|
8
|
+
* IMPORTANT: Preserves original field order by using single-pass iteration.
|
|
9
|
+
*
|
|
10
|
+
* @returns SerializedFormDataResult with data and transferables array
|
|
11
|
+
*/
|
|
12
|
+
export declare function serializeFormData(formData: FormData): Promise<SerializedFormDataResult>;
|
|
13
|
+
/**
|
|
14
|
+
* Deserialize SerializedFormData back to FormData in worker
|
|
15
|
+
* Reconstructs File objects from transferred ArrayBuffers
|
|
16
|
+
*/
|
|
17
|
+
export declare function deserializeFormData(serialized: SerializedFormData): FormData;
|
|
18
|
+
/**
|
|
19
|
+
* Check if body is FormData
|
|
20
|
+
*/
|
|
21
|
+
export declare function isFormData(body: unknown): body is FormData;
|
|
22
|
+
/**
|
|
23
|
+
* Check if serialized body is SerializedFormData
|
|
24
|
+
*/
|
|
25
|
+
export declare function isSerializedFormData(body: unknown): body is SerializedFormData;
|
|
26
|
+
//# sourceMappingURL=formdata.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"formdata.d.ts","sourceRoot":"","sources":["../../../src/transport/utils/formdata.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAkB,kBAAkB,EAA2B,wBAAwB,EAAE,MAAM,UAAU,CAAC;AAEtH;;;;;;;;;GASG;AACH,wBAAsB,iBAAiB,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,wBAAwB,CAAC,CAuC7F;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,UAAU,EAAE,kBAAkB,GAAG,QAAQ,CAc5E;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,IAAI,QAAQ,CAE1D;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,IAAI,kBAAkB,CAE9E"}
|