@auth-craft/client 0.2.1 → 0.3.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.
Files changed (32) hide show
  1. package/README.md +46 -0
  2. package/dist/core/core.d.ts +13 -0
  3. package/dist/core/core.d.ts.map +1 -1
  4. package/dist/core/core.js +4 -0
  5. package/dist/core/core.js.map +1 -1
  6. package/dist/transport/client.d.ts +22 -1
  7. package/dist/transport/client.d.ts.map +1 -1
  8. package/dist/transport/client.js +130 -99
  9. package/dist/transport/client.js.map +1 -1
  10. package/dist/transport/index.d.ts +5 -1
  11. package/dist/transport/index.d.ts.map +1 -1
  12. package/dist/transport/index.js +3 -0
  13. package/dist/transport/index.js.map +1 -1
  14. package/dist/transport/inline-worker.d.ts +6 -0
  15. package/dist/transport/inline-worker.d.ts.map +1 -1
  16. package/dist/transport/inline-worker.js +8 -1
  17. package/dist/transport/inline-worker.js.map +1 -1
  18. package/dist/transport/provider/storage/session-hint-channel.d.ts +34 -0
  19. package/dist/transport/provider/storage/session-hint-channel.d.ts.map +1 -0
  20. package/dist/transport/provider/storage/session-hint-channel.js +81 -0
  21. package/dist/transport/provider/storage/session-hint-channel.js.map +1 -0
  22. package/dist/transport/provider/storage/session-hint.d.ts +65 -0
  23. package/dist/transport/provider/storage/session-hint.d.ts.map +1 -0
  24. package/dist/transport/provider/storage/session-hint.js +117 -0
  25. package/dist/transport/provider/storage/session-hint.js.map +1 -0
  26. package/dist/transport/types.d.ts +52 -4
  27. package/dist/transport/types.d.ts.map +1 -1
  28. package/dist/transport/worker.d.ts +7 -1
  29. package/dist/transport/worker.d.ts.map +1 -1
  30. package/dist/transport/worker.js +123 -0
  31. package/dist/transport/worker.js.map +1 -1
  32. package/package.json +3 -3
package/README.md CHANGED
@@ -126,6 +126,11 @@ interface AuthCraftClientConfig {
126
126
  * 'system' = admin, 'tenant' = tenant-scoped, omit/'customer' = default.
127
127
  */
128
128
  context?: 'customer' | 'tenant' | 'system'
129
+ /**
130
+ * Skip the boot-time refresh for visitors who never logged in (default false).
131
+ * See "Skipping the pointless boot refresh" below.
132
+ */
133
+ sessionHint?: boolean
129
134
  /**
130
135
  * Subscribe to session state changes (login, logout, refresh, expiry).
131
136
  * Fires after `init()`. Bridge it into app state or trigger auto-logout
@@ -135,6 +140,47 @@ interface AuthCraftClientConfig {
135
140
  }
136
141
  ```
137
142
 
143
+ ### Skipping the pointless boot refresh
144
+
145
+ The refresh token is an httpOnly cookie the worker cannot read, so after every
146
+ reload the worker has no idea whether a session exists — the only way to find out
147
+ is to try `POST /auth/refresh`. For someone who never logged in, that attempt can
148
+ never succeed, yet it is paid on **every** page load, and the app has to wait for
149
+ it to fail before it can render "logged out".
150
+
151
+ `sessionHint: true` makes the worker remember the answer:
152
+
153
+ ```ts
154
+ const client = createAuthCraftClient({
155
+ baseUrl: 'https://auth.example.com',
156
+ strategy: 'cookie-auth',
157
+ allowedDomains: ['auth.example.com'],
158
+ sessionHint: true, // don't try refresh if nobody ever logged in here
159
+ })
160
+ ```
161
+
162
+ - **login succeeds** → the hint is written (IndexedDB; the worker has no
163
+ `localStorage`).
164
+ - **logout**, or a refresh the server rejects → the hint is cleared.
165
+ - **next reload with no hint** → auth-requiring calls resolve immediately as
166
+ `NOT_AUTHENTICATED` with **zero HTTP requests**. Public calls (login, register,
167
+ password reset, …) are unaffected.
168
+
169
+ The hint is one non-secret bit and is never trusted for authorization — it can
170
+ only skip a request that was going to fail anyway. It self-corrects in both
171
+ directions: a rejected refresh clears it, and a login or logout in another tab is
172
+ broadcast to every open tab (via `BroadcastChannel`), so a tab that booted
173
+ "anonymous" starts attempting refresh again without a reload. If IndexedDB is
174
+ unavailable or faulting, the hint **fails open** — the client simply behaves as it
175
+ does today.
176
+
177
+ The storage key is derived from `context`, so a customer login on the same origin
178
+ never implies a `tenant` or `system` session.
179
+
180
+ > Handle `NOT_AUTHENTICATED` as "show the login screen". If your app currently
181
+ > distinguishes "refresh failed" from "never logged in", both now arrive as the
182
+ > same error code — the difference is only that the second costs no request.
183
+
138
184
  ### Transport: worker vs inline
139
185
 
140
186
  By default the client runs its token/refresh loop in a **Web Worker**, so the
@@ -49,6 +49,19 @@ export interface ClientCoreConfig {
49
49
  transport?: 'worker' | 'inline';
50
50
  /** Auth scope → `X-Auth-Context` header. */
51
51
  context?: 'customer' | 'tenant' | 'system';
52
+ /**
53
+ * Skip the boot-time `POST /auth/refresh` for visitors who never logged in.
54
+ *
55
+ * Off by default. When `true`, the worker remembers (in IndexedDB) that a
56
+ * session was established here and, on a later reload, fails auth-requiring
57
+ * calls fast with NOT_AUTHENTICATED instead of spending a refresh that cannot
58
+ * succeed. The hint is cleared whenever the server reports no session and is
59
+ * synced across tabs, so it only ever skips a request that would have failed.
60
+ *
61
+ * The storage key is derived from `context`, so a customer login on the same
62
+ * origin never implies a tenant or system session.
63
+ */
64
+ sessionHint?: boolean;
52
65
  /** Session state changes (login/logout/refresh/expiry). Fires after init(). */
53
66
  onAuthStateChanged?: (state: TransportAuthResult) => void;
54
67
  }
@@ -1 +1 @@
1
- {"version":3,"file":"core.d.ts","sourceRoot":"","sources":["../../src/core/core.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"core.d.ts","sourceRoot":"","sources":["../../src/core/core.ts"],"names":[],"mappings":"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"}
package/dist/core/core.js CHANGED
@@ -43,6 +43,10 @@ export class ClientCore {
43
43
  ...(headers ? { defaultHeaders: headers } : {}),
44
44
  ...(this.config.workerFactory ? { workerFactory: this.config.workerFactory } : {}),
45
45
  ...(this.config.transport ? { transport: this.config.transport } : {}),
46
+ // Per-scope key: each auth context tracks its own session independently.
47
+ ...(this.config.sessionHint
48
+ ? { sessionHint: { enabled: true, key: `sessionHint:${this.config.context ?? 'customer'}` } }
49
+ : {}),
46
50
  });
47
51
  await this.fg.whenReady();
48
52
  if (this.config.onAuthStateChanged) {
@@ -1 +1 @@
1
- {"version":3,"file":"core.js","sourceRoot":"","sources":["../../src/core/core.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"core.js","sourceRoot":"","sources":["../../src/core/core.ts"],"names":[],"mappings":"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"}
@@ -16,6 +16,10 @@ export declare class FetchGuardClient {
16
16
  private isReady;
17
17
  private requestQueue;
18
18
  private activeRequests;
19
+ /** Ids posted to the worker that still hold a concurrency slot */
20
+ private readonly inFlight;
21
+ /** Round-trip timers (queue wait + worker), keyed by message id */
22
+ private readonly requestTimers;
19
23
  private readonly maxConcurrent;
20
24
  private readonly maxQueueSize;
21
25
  private readonly setupTimeout;
@@ -112,6 +116,20 @@ export declare class FetchGuardClient {
112
116
  * Cancel a pending request by ID
113
117
  */
114
118
  cancel(id: string): void;
119
+ /**
120
+ * Round-trip timeout fired: abort the worker's fetch (if it was sent),
121
+ * free the slot and settle the caller with REQUEST_TIMEOUT.
122
+ */
123
+ private timeoutRequest;
124
+ private armRequestTimer;
125
+ private clearRequestTimer;
126
+ /**
127
+ * End a message's life — the single exit for every path (answer, error,
128
+ * cancel, timeout, send failure). Clears its timer, drops it from the queue
129
+ * if not sent yet, gives back its concurrency slot exactly once, and removes
130
+ * its bookkeeping. Returns the pending entry if the caller still waits.
131
+ */
132
+ private finish;
115
133
  /**
116
134
  * Convenience methods
117
135
  */
@@ -219,7 +237,10 @@ export declare class FetchGuardClient {
219
237
  }>>;
220
238
  /**
221
239
  * Send message through queue system
222
- * All messages go through queue for sequential processing
240
+ * All messages go through queue for sequential processing.
241
+ * Resolves once the message is posted to the worker (or dropped from the
242
+ * queue by finish()); the answer arrives via handleWorkerMessage. Timeouts
243
+ * are the caller's (armRequestTimer), not the queue's.
223
244
  * @param transferables - Optional Transferable objects for zero-copy postMessage
224
245
  */
225
246
  private sendMessageQueued;
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/transport/client.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/transport/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAW,KAAK,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAOvD,OAAO,KAAK,EACV,UAAU,EAGV,aAAa,EACb,iBAAiB,EACjB,qBAAqB,EAMtB,MAAM,YAAY,CAAC;AAwCpB;;GAEG;AACH,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,SAAS,CAAK;IAGtB,OAAO,CAAC,eAAe,CAMnB;IACJ,yCAAyC;IACzC,OAAO,CAAC,WAAW,CAA6B;IAChD,uCAAuC;IACvC,OAAO,CAAC,cAAc,CAAoC;IAC1D,OAAO,CAAC,aAAa,CAA0C;IAC/D,OAAO,CAAC,cAAc,CAAyB;IAC/C,OAAO,CAAC,OAAO,CAAS;IAExB,OAAO,CAAC,YAAY,CAAmB;IACvC,OAAO,CAAC,cAAc,CAAK;IAC3B,kEAAkE;IAClE,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAqB;IAC9C,mEAAmE;IACnE,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAoD;IAClF,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAS;IACvC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAS;IACtC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAS;IACtC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAqB;IACpD,OAAO,CAAC,YAAY,CAAC,CAAa;IAClC,OAAO,CAAC,WAAW,CAAC,CAAyB;IAC7C,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAa;IACpC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAc;IACrC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAe;IACvC,2CAA2C;IAC3C,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAqD;IACtF,8DAA8D;IAC9D,OAAO,CAAC,QAAQ,CAAC,aAAa,CAA2E;IAEzG,YAAY,OAAO,EAAE,iBAAiB,EA2BrC;IAED;;OAEG;YACW,gBAAgB;IAoD9B;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAsG3B;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAiBzB;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAIzB;;;;;;;;;;;;OAYG;IACG,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,GAAE,qBAA0B,GAAG,OAAO,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,CAmD5F;IAED;;OAEG;IACH,OAAO,CAAC,mBAAmB;IA4B3B;;OAEG;YACW,uBAAuB;IA4ErC;;;OAGG;IACH,OAAO,CAAC,YAAY;IAmBpB;;;;;;OAMG;IACH,OAAO,CAAC,WAAW;IAUnB;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAK1B;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAmBxB;;OAEG;IACH,OAAO,CAAC,KAAK;IAIb;;;OAGG;IACH,OAAO,CAAC,cAAc;IAqBtB;;;;OAIG;IACH,WAAW,CACT,GAAG,EAAE,MAAM,EACX,OAAO,GAAE,qBAA0B,GAClC;QACD,EAAE,EAAE,MAAM,CAAC;QACX,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC;QACvC,MAAM,EAAE,MAAM,IAAI,CAAC;KACpB,CAmEA;IAED;;OAEG;IACH,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAiBvB;IAED;;;OAGG;IACH,OAAO,CAAC,cAAc;IAiBtB,OAAO,CAAC,eAAe;IAQvB,OAAO,CAAC,iBAAiB;IAQzB;;;;;OAKG;IACH,OAAO,CAAC,MAAM;IA0Bd;;OAEG;IACG,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,GAAE,IAAI,CAAC,qBAAqB,EAAE,QAAQ,GAAG,MAAM,CAAM,GAAG,OAAO,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,CAEnH;IAEK,IAAI,CACR,GAAG,EAAE,MAAM,EACX,IAAI,CAAC,EAAE,OAAO,EACd,OAAO,GAAE,IAAI,CAAC,qBAAqB,EAAE,QAAQ,GAAG,MAAM,CAAM,GAC3D,OAAO,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,CAwBhC;IAEK,GAAG,CACP,GAAG,EAAE,MAAM,EACX,IAAI,CAAC,EAAE,OAAO,EACd,OAAO,GAAE,IAAI,CAAC,qBAAqB,EAAE,QAAQ,GAAG,MAAM,CAAM,GAC3D,OAAO,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,CAwBhC;IAEK,MAAM,CACV,GAAG,EAAE,MAAM,EACX,OAAO,GAAE,IAAI,CAAC,qBAAqB,EAAE,QAAQ,GAAG,MAAM,CAAM,GAC3D,OAAO,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,CAEhC;IAEK,KAAK,CACT,GAAG,EAAE,MAAM,EACX,IAAI,CAAC,EAAE,OAAO,EACd,OAAO,GAAE,IAAI,CAAC,qBAAqB,EAAE,QAAQ,GAAG,MAAM,CAAM,GAC3D,OAAO,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,CAwBhC;IAED;;;;;;;;;;;;OAYG;IACG,QAAQ,CAAC,CAAC,EACd,MAAM,EAAE,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,OAAO,GAAG,QAAQ,EACnD,GAAG,EAAE,MAAM,EACX,IAAI,CAAC,EAAE,OAAO,EACd,OAAO,GAAE,IAAI,CAAC,qBAAqB,EAAE,QAAQ,GAAG,MAAM,CAAM,GAC3D,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CA0BpB;IAED;;;;;;OAMG;IACG,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,OAAO,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAe/F;IAED;;;;;OAKG;IACG,KAAK,CAAC,OAAO,CAAC,EAAE,OAAO,EAAE,GAAG,CAAC,EAAE,MAAM,EAAE,SAAS,GAAE,OAAc,GAAG,OAAO,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAanG;IAED;;;;OAIG;IACG,MAAM,CAAC,OAAO,CAAC,EAAE,OAAO,EAAE,SAAS,GAAE,OAAc,GAAG,OAAO,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAGtF;IAED;;;OAGG;IACG,YAAY,CAAC,SAAS,GAAE,OAAc,GAAG,OAAO,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAEzE;IAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA6BG;IACG,aAAa,CACjB,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;KAAE,EAC1G,SAAS,GAAE,OAAc,GACxB,OAAO,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAM7B;IAED;;OAEG;IACH,KAAK,IAAI,OAAO,CAEf;IAED;;;OAGG;IACG,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC,CAM/B;IAED;;;OAGG;IACH,OAAO,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI,CAYxC;IAED;;OAEG;IACH,kBAAkB,CAAC,EAAE,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,GAAG,MAAM,IAAI,CAG9D;IAED,+BAA+B;IACzB,IAAI,IAAI,OAAO,CAAC,MAAM,CAAC;QAAE,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC,CAenD;IAED;;;;;;;OAOG;IACH,OAAO,CAAC,iBAAiB;IAsBzB;;;;;;;;OAQG;IACH,OAAO,CAAC,YAAY;IAkCpB;;;OAGG;IACH,OAAO,CAAC,iBAAiB;IAKzB;;OAEG;IACH,OAAO,IAAI,IAAI,CAmBd;CACF;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,iBAAiB,GAAG,gBAAgB,CAEzE"}
@@ -11,8 +11,10 @@ const DEFAULT_MAX_CONCURRENT = 6;
11
11
  const DEFAULT_MAX_QUEUE_SIZE = 1000;
12
12
  /** Default setup timeout (ms) */
13
13
  const DEFAULT_SETUP_TIMEOUT = 10000;
14
- /** Default request timeout (ms) */
15
- const DEFAULT_REQUEST_TIMEOUT = 30000;
14
+ /** Round-trip timeout for AUTH_CALL messages (ms) */
15
+ const AUTH_CALL_TIMEOUT = 15000;
16
+ /** Round-trip timeout for PING messages (ms) */
17
+ const PING_TIMEOUT = 5000;
16
18
  /**
17
19
  * FetchGuard Client - main interface cho việc gọi API thông qua Web Worker
18
20
  */
@@ -31,6 +33,10 @@ export class FetchGuardClient {
31
33
  isReady = false;
32
34
  requestQueue = [];
33
35
  activeRequests = 0;
36
+ /** Ids posted to the worker that still hold a concurrency slot */
37
+ inFlight = new Set();
38
+ /** Round-trip timers (queue wait + worker), keyed by message id */
39
+ requestTimers = new Map();
34
40
  maxConcurrent;
35
41
  maxQueueSize;
36
42
  setupTimeout;
@@ -48,7 +54,7 @@ export class FetchGuardClient {
48
54
  this.maxConcurrent = options.maxConcurrent ?? DEFAULT_MAX_CONCURRENT;
49
55
  this.maxQueueSize = options.maxQueueSize ?? DEFAULT_MAX_QUEUE_SIZE;
50
56
  this.setupTimeout = options.setupTimeout ?? DEFAULT_SETUP_TIMEOUT;
51
- this.requestTimeout = options.requestTimeout ?? DEFAULT_REQUEST_TIMEOUT;
57
+ this.requestTimeout = options.requestTimeout;
52
58
  this.debug = options.debug;
53
59
  this.retry = options.retry;
54
60
  this.dedupe = options.dedupe;
@@ -79,6 +85,7 @@ export class FetchGuardClient {
79
85
  allowedDomains: options.allowedDomains || [],
80
86
  refreshEarlyMs: options.refreshEarlyMs ?? DEFAULT_REFRESH_EARLY_MS,
81
87
  defaultHeaders: options.defaultHeaders || {},
88
+ ...(options.sessionHint ? { sessionHint: options.sessionHint } : {}),
82
89
  };
83
90
  // Serialize provider config based on type
84
91
  let providerConfig = null;
@@ -126,15 +133,11 @@ export class FetchGuardClient {
126
133
  if (type === MSG.FETCH_RESULT) {
127
134
  // FETCH_RESULT contains FetchEnvelope (raw HTTP response)
128
135
  // Worker doesn't judge HTTP status - client receives envelope as-is
129
- const request = this.pendingRequests.get(id);
130
- if (!request)
136
+ // A late answer (after cancel/timeout) only gives back its slot
137
+ const entry = this.finish(id);
138
+ if (!entry)
131
139
  return;
132
- const url = this.requestUrls.get(id);
133
- const timing = this.requestTimings.get(id);
134
- this.pendingRequests.delete(id);
135
- this.requestUrls.delete(id);
136
- this.requestTimings.delete(id);
137
- this.onRequestComplete();
140
+ const { request, url, timing } = entry;
138
141
  // Calculate metrics
139
142
  const metrics = this.calculateMetrics(timing);
140
143
  // Debug hook: onResponse
@@ -146,15 +149,10 @@ export class FetchGuardClient {
146
149
  }
147
150
  if (type === MSG.FETCH_ERROR) {
148
151
  // Network/timeout/cancel errors (no HTTP response)
149
- const request = this.pendingRequests.get(id);
150
- if (!request)
152
+ const entry = this.finish(id);
153
+ if (!entry)
151
154
  return;
152
- const url = this.requestUrls.get(id);
153
- const timing = this.requestTimings.get(id);
154
- this.pendingRequests.delete(id);
155
- this.requestUrls.delete(id);
156
- this.requestTimings.delete(id);
157
- this.onRequestComplete();
155
+ const { request, url, timing } = entry;
158
156
  const errorMessage = String(payload?.error || 'Network error');
159
157
  // Calculate metrics
160
158
  const metrics = this.calculateMetrics(timing);
@@ -166,12 +164,10 @@ export class FetchGuardClient {
166
164
  return;
167
165
  }
168
166
  if (type === MSG.ERROR) {
169
- const request = this.pendingRequests.get(id);
170
- if (!request)
167
+ const entry = this.finish(id);
168
+ if (!entry)
171
169
  return;
172
- this.pendingRequests.delete(id);
173
- this.onRequestComplete();
174
- request.resolve(err(payload.errors, payload.meta));
170
+ entry.request.resolve(err(payload.errors, payload.meta));
175
171
  return;
176
172
  }
177
173
  if (type === MSG.SETUP_ERROR) {
@@ -199,12 +195,7 @@ export class FetchGuardClient {
199
195
  return;
200
196
  }
201
197
  if (type === MSG.PONG) {
202
- const request = this.pendingRequests.get(id);
203
- if (request) {
204
- this.pendingRequests.delete(id);
205
- this.onRequestComplete();
206
- request.resolve(ok({ timestamp: payload?.timestamp }));
207
- }
198
+ this.finish(id)?.request.resolve(ok({ timestamp: payload?.timestamp }));
208
199
  return;
209
200
  }
210
201
  if (type === MSG.AUTH_STATE_CHANGED) {
@@ -213,12 +204,7 @@ export class FetchGuardClient {
213
204
  return;
214
205
  }
215
206
  if (type === MSG.AUTH_CALL_RESULT) {
216
- const request = this.pendingRequests.get(id);
217
- if (request) {
218
- this.pendingRequests.delete(id);
219
- this.onRequestComplete();
220
- request.resolve(ok(payload)); // payload is AuthResult
221
- }
207
+ this.finish(id)?.request.resolve(ok(payload)); // payload is AuthResult
222
208
  return;
223
209
  }
224
210
  if (type === MSG.TOKEN_REFRESHED) {
@@ -234,8 +220,10 @@ export class FetchGuardClient {
234
220
  console.error('Worker error:', error);
235
221
  // Debug hook: onWorkerError
236
222
  this.debug?.onWorkerError?.(error);
237
- // Reject all pending requests
238
- for (const [_id, request] of this.pendingRequests) {
223
+ // Reject all pending requests (in-flight ones keep their slot until the
224
+ // worker answers or never — late answers release it in finish())
225
+ for (const [id, request] of this.pendingRequests) {
226
+ this.clearRequestTimer(id);
239
227
  request.reject(new Error(`Worker error: ${error.message}`));
240
228
  }
241
229
  this.pendingRequests.clear();
@@ -492,6 +480,7 @@ export class FetchGuardClient {
492
480
  */
493
481
  fetchWithId(url, options = {}) {
494
482
  const id = this.generateMessageId();
483
+ const { timeout, ...sendOptions } = options;
495
484
  // The Promise is resolved/rejected via pendingRequests (worker callback).
496
485
  // The executor stays synchronous (no async); the serialize-and-send work
497
486
  // runs separately and routes failures through the same reject path.
@@ -507,16 +496,19 @@ export class FetchGuardClient {
507
496
  // Debug hook: onRequest
508
497
  this.debug?.onRequest?.(url, options);
509
498
  });
499
+ // Round-trip timeout, if any: covers serialization, queue wait and the
500
+ // worker's fetch. Default is none — large uploads are legitimately slow.
501
+ this.armRequestTimer(id, timeout ?? this.requestTimeout);
510
502
  // Serialize (FormData/Headers) then send — async, but kept out of the
511
503
  // Promise executor (noAsyncPromiseExecutor). Failures reject via the
512
504
  // pending request registered above.
513
505
  void (async () => {
514
506
  try {
515
- const serializedOptions = { ...options };
507
+ const serializedOptions = { ...sendOptions };
516
508
  let transferables;
517
509
  // Serialize FormData body before sending to worker
518
- if (options.body && isFormData(options.body)) {
519
- const { data, transferables: formDataTransferables } = await serializeFormData(options.body);
510
+ if (sendOptions.body && isFormData(sendOptions.body)) {
511
+ const { data, transferables: formDataTransferables } = await serializeFormData(sendOptions.body);
520
512
  // SerializedFormData will be deserialized back to FormData in worker
521
513
  serializedOptions.body = data;
522
514
  // ArrayBuffers for zero-copy transfer
@@ -525,24 +517,21 @@ export class FetchGuardClient {
525
517
  }
526
518
  }
527
519
  // Serialize Headers object to plain object (Headers cannot be cloned)
528
- if (options.headers instanceof Headers) {
520
+ if (sendOptions.headers instanceof Headers) {
529
521
  const plainHeaders = {};
530
- options.headers.forEach((value, key) => {
522
+ sendOptions.headers.forEach((value, key) => {
531
523
  plainHeaders[key] = value;
532
524
  });
533
525
  serializedOptions.headers = plainHeaders;
534
526
  }
527
+ // Cancelled or timed out while serializing: don't send it at all
528
+ if (!this.pendingRequests.has(id))
529
+ return;
535
530
  const message = { id, type: MSG.FETCH, payload: { url, options: serializedOptions } };
536
- await this.sendMessageQueued(message, 30000, transferables);
531
+ await this.sendMessageQueued(message, transferables);
537
532
  }
538
533
  catch (error) {
539
- const request = this.pendingRequests.get(id);
540
- if (request) {
541
- this.pendingRequests.delete(id);
542
- this.requestUrls.delete(id);
543
- this.requestTimings.delete(id);
544
- request.reject(error instanceof Error ? error : new Error(String(error)));
545
- }
534
+ this.finish(id)?.request.reject(error instanceof Error ? error : new Error(String(error)));
546
535
  }
547
536
  })();
548
537
  const cancel = () => this.cancel(id);
@@ -552,23 +541,70 @@ export class FetchGuardClient {
552
541
  * Cancel a pending request by ID
553
542
  */
554
543
  cancel(id) {
555
- const request = this.pendingRequests.get(id);
556
- if (request) {
557
- const url = this.requestUrls.get(id);
558
- const timing = this.requestTimings.get(id);
559
- this.pendingRequests.delete(id);
560
- this.requestUrls.delete(id);
561
- this.requestTimings.delete(id);
544
+ const sent = this.inFlight.has(id);
545
+ const entry = this.finish(id);
546
+ if (!entry)
547
+ return;
548
+ // Still queued: finish() dropped it from the queue, nothing to abort
549
+ if (sent)
562
550
  this.worker.postMessage({ id, type: MSG.CANCEL });
563
- // Calculate metrics
564
- const metrics = this.calculateMetrics(timing);
565
- // Debug hook: onError for cancelled request
566
- if (this.debug?.onError && url) {
567
- this.debug.onError(url, { code: 'REQUEST_CANCELLED', message: 'Request cancelled' }, metrics);
568
- }
569
- request.reject(new Error('Request cancelled'));
551
+ // Debug hook: onError for cancelled request
552
+ if (this.debug?.onError && entry.url) {
553
+ this.debug.onError(entry.url, { code: 'REQUEST_CANCELLED', message: 'Request cancelled' }, this.calculateMetrics(entry.timing));
554
+ }
555
+ entry.request.resolve(err(RequestErrors.Cancelled()));
556
+ }
557
+ /**
558
+ * Round-trip timeout fired: abort the worker's fetch (if it was sent),
559
+ * free the slot and settle the caller with REQUEST_TIMEOUT.
560
+ */
561
+ timeoutRequest(id) {
562
+ const sent = this.inFlight.has(id);
563
+ const entry = this.finish(id);
564
+ if (sent)
565
+ this.worker.postMessage({ id, type: MSG.CANCEL });
566
+ if (!entry)
567
+ return;
568
+ if (this.debug?.onError && entry.url) {
569
+ this.debug.onError(entry.url, { code: 'REQUEST_TIMEOUT', message: 'Request timed out' }, this.calculateMetrics(entry.timing));
570
+ }
571
+ entry.request.resolve(err(RequestErrors.Timeout()));
572
+ }
573
+ armRequestTimer(id, timeoutMs) {
574
+ if (timeoutMs === undefined || timeoutMs <= 0)
575
+ return;
576
+ this.requestTimers.set(id, setTimeout(() => this.timeoutRequest(id), timeoutMs));
577
+ }
578
+ clearRequestTimer(id) {
579
+ const timer = this.requestTimers.get(id);
580
+ if (timer !== undefined) {
581
+ clearTimeout(timer);
582
+ this.requestTimers.delete(id);
570
583
  }
571
584
  }
585
+ /**
586
+ * End a message's life — the single exit for every path (answer, error,
587
+ * cancel, timeout, send failure). Clears its timer, drops it from the queue
588
+ * if not sent yet, gives back its concurrency slot exactly once, and removes
589
+ * its bookkeeping. Returns the pending entry if the caller still waits.
590
+ */
591
+ finish(id) {
592
+ this.clearRequestTimer(id);
593
+ const index = this.requestQueue.findIndex((item) => item.id === id);
594
+ if (index !== -1) {
595
+ const [item] = this.requestQueue.splice(index, 1);
596
+ item?.resolve();
597
+ }
598
+ if (this.inFlight.delete(id))
599
+ this.onRequestComplete();
600
+ const request = this.pendingRequests.get(id);
601
+ const url = this.requestUrls.get(id);
602
+ const timing = this.requestTimings.get(id);
603
+ this.pendingRequests.delete(id);
604
+ this.requestUrls.delete(id);
605
+ this.requestTimings.delete(id);
606
+ return request ? { request, url, timing } : undefined;
607
+ }
572
608
  /**
573
609
  * Convenience methods
574
610
  */
@@ -701,12 +737,9 @@ export class FetchGuardClient {
701
737
  resolve: (r) => resolve(r),
702
738
  reject: (e) => reject(e),
703
739
  });
704
- this.sendMessageQueued(message, 15000).catch((error) => {
705
- const request = this.pendingRequests.get(id);
706
- if (request) {
707
- this.pendingRequests.delete(id);
708
- request.reject(error);
709
- }
740
+ this.armRequestTimer(id, AUTH_CALL_TIMEOUT);
741
+ this.sendMessageQueued(message).catch((error) => {
742
+ this.finish(id)?.request.reject(error);
710
743
  });
711
744
  });
712
745
  }
@@ -831,44 +864,33 @@ export class FetchGuardClient {
831
864
  resolve: (r) => resolve(r),
832
865
  reject: (e) => reject(e),
833
866
  });
834
- this.sendMessageQueued(message, 5000).catch((error) => {
835
- const request = this.pendingRequests.get(id);
836
- if (request) {
837
- this.pendingRequests.delete(id);
838
- request.reject(error);
839
- }
867
+ this.armRequestTimer(id, PING_TIMEOUT);
868
+ this.sendMessageQueued(message).catch((error) => {
869
+ this.finish(id)?.request.reject(error);
840
870
  });
841
871
  });
842
872
  }
843
873
  /**
844
874
  * Send message through queue system
845
- * All messages go through queue for sequential processing
875
+ * All messages go through queue for sequential processing.
876
+ * Resolves once the message is posted to the worker (or dropped from the
877
+ * queue by finish()); the answer arrives via handleWorkerMessage. Timeouts
878
+ * are the caller's (armRequestTimer), not the queue's.
846
879
  * @param transferables - Optional Transferable objects for zero-copy postMessage
847
880
  */
848
- sendMessageQueued(message, timeoutMs = this.requestTimeout, transferables) {
881
+ sendMessageQueued(message, transferables) {
849
882
  return new Promise((resolve, reject) => {
850
883
  // Check queue size limit to prevent memory leak
851
884
  if (this.requestQueue.length >= this.maxQueueSize) {
852
885
  reject(err(RequestErrors.QueueFull({ size: this.requestQueue.length, maxSize: this.maxQueueSize })));
853
886
  return;
854
887
  }
855
- const timeout = setTimeout(() => {
856
- const index = this.requestQueue.findIndex((item) => item.id === message.id);
857
- if (index !== -1) {
858
- this.requestQueue.splice(index, 1);
859
- }
860
- this.pendingRequests.delete(message.id);
861
- this.requestUrls.delete(message.id);
862
- this.requestTimings.delete(message.id);
863
- reject(err(RequestErrors.Timeout()));
864
- }, timeoutMs);
865
888
  const queueItem = {
866
889
  id: message.id,
867
890
  message,
868
891
  transferables,
869
- resolve: resolve,
892
+ resolve,
870
893
  reject,
871
- timeout,
872
894
  };
873
895
  this.requestQueue.push(queueItem);
874
896
  this.processQueue();
@@ -890,6 +912,7 @@ export class FetchGuardClient {
890
912
  if (!item)
891
913
  continue;
892
914
  this.activeRequests++;
915
+ this.inFlight.add(item.id);
893
916
  // Update timing: mark when request is actually sent to worker
894
917
  const timing = this.requestTimings.get(item.id);
895
918
  if (timing) {
@@ -903,12 +926,12 @@ export class FetchGuardClient {
903
926
  else {
904
927
  this.worker.postMessage(item.message);
905
928
  }
906
- // Note: activeRequests is decremented when response is received
907
- // in handleWorkerMessage, not here
929
+ // Note: the slot is given back by finish() (answer, cancel, timeout)
930
+ item.resolve();
908
931
  }
909
932
  catch (error) {
933
+ this.inFlight.delete(item.id);
910
934
  this.activeRequests--;
911
- clearTimeout(item.timeout);
912
935
  item.reject(error instanceof Error ? error : new Error(String(error)));
913
936
  // Continue processing queue after error
914
937
  this.processQueue();
@@ -928,14 +951,22 @@ export class FetchGuardClient {
928
951
  */
929
952
  destroy() {
930
953
  this.worker.terminate();
954
+ for (const timer of this.requestTimers.values())
955
+ clearTimeout(timer);
956
+ this.requestTimers.clear();
957
+ const queue = this.requestQueue;
958
+ this.requestQueue = [];
959
+ for (const item of queue)
960
+ item.resolve();
961
+ // Settle every waiting caller — the worker is gone, no answer will come
962
+ for (const request of this.pendingRequests.values()) {
963
+ request.reject(new Error('Client destroyed'));
964
+ }
931
965
  this.pendingRequests.clear();
932
966
  this.requestUrls.clear();
933
967
  this.requestTimings.clear();
934
- for (const item of this.requestQueue) {
935
- clearTimeout(item.timeout);
936
- item.reject(new Error('Client destroyed'));
937
- }
938
- this.requestQueue = [];
968
+ this.inFlight.clear();
969
+ this.activeRequests = 0;
939
970
  }
940
971
  }
941
972
  /**