@molecule/app-http 1.1.6 → 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 CHANGED
@@ -3,7 +3,7 @@ AUTO-GENERATED — DO NOT EDIT THIS FILE.
3
3
  Generated by `mlcl sync-docs` from the package's src/index.ts JSDoc + mlcl/registry.json.
4
4
  Edits here are overwritten on the next commit (molecule's pre-commit hook regenerates).
5
5
  To change this document, edit the module-level JSDoc in src/index.ts.
6
- Generated: 2026-10-18T09:07:54.160Z
6
+ Generated: 2026-10-18T17:46:02.937Z
7
7
  -->
8
8
 
9
9
  # @molecule/app-http
@@ -219,11 +219,15 @@ interface RequestConfig {
219
219
  /**
220
220
  * Send this request WITHOUT waiting for the session restore (the auth gate).
221
221
  *
222
- * A request the gate itself depends on must set this. A gate registered with
223
- * `setAuthGate` that waits for a session restore whose own request goes through this
224
- * client otherwise waits on itself: the gate holds the restore's request, the restore's
225
- * promise never settles, and every request on the page stalls until the gate times out —
226
- * so pass `skipAuthGate: true` on the restore's own request:
222
+ * A request the gate's restore issues from a LATER continuation must set this. The gate
223
+ * recognizes a request the settle function issues while it runs and never holds it — this
224
+ * package's client awaits the gate before anything else, so a `restoreSession()` that calls
225
+ * it directly does not deadlock. But a restore that awaits something else first
226
+ * (`await storage.get()`), then calls the client, reaches `awaitAuthGate` after that window:
227
+ * the gate then waits on itself, and every request on the page stalls until the gate times
228
+ * out (3 s) — so pass `skipAuthGate: true` on that request. A provider that awaits the gate
229
+ * inside a scheduled interceptor (the Axios bond) also reaches it after the window, so its
230
+ * restore's request needs the opt-out.
227
231
  *
228
232
  * ```typescript
229
233
  * // the request the gate's restore makes, through the same client the gate holds back
@@ -232,7 +236,8 @@ interface RequestConfig {
232
236
  *
233
237
  * `@molecule/app-auth`'s own restore does not need it — it sends its request with
234
238
  * `fetch`, not through this client. An app with its own session store that registers a
235
- * gate with `setAuthGate` does.
239
+ * gate with `setAuthGate` does not need it either when its restore calls the client
240
+ * directly.
236
241
  */
237
242
  skipAuthGate?: boolean
238
243
 
@@ -423,10 +428,20 @@ template auth that is `() => authClient.whenRestored()`, which resolves
423
428
  immediately when no restore is in flight, so registering it never makes a
424
429
  request wait longer than the restore it was about to race anyway.
425
430
 
426
- A gate whose restore sends its OWN request through the gated client deadlocks — the
427
- gate holds the request it is waiting for. That request must pass `skipAuthGate: true`
428
- (see `RequestConfig.skipAuthGate`); `@molecule/app-auth`'s own restore does not
429
- need it because it uses `fetch` rather than the bonded client.
431
+ Waiting for the restore does NOT attach its token: a separately created HTTP
432
+ client needs `createDefaultHttpClientWithAuthBearer({ baseURL,
433
+ getToken: () => authClient.getAccessToken(), authScheme })` from
434
+ `@molecule/app-bonds-default-react` (or the auth client built with
435
+ `createDefaultAuthClientWithHttpSync`, which mirrors the token into the
436
+ bonded client) plus `setAuthGate(() => authClient.whenRestored())`.
437
+
438
+ The restore's own requests are never held: a request the settle function issues while it
439
+ runs goes out immediately, so `setAuthGate(() => restoreSession())` cannot deadlock even
440
+ when `restoreSession` calls the gated client. A restore that awaits something else first
441
+ (a storage read, a `Promise.resolve()`) issues its request from a later continuation, which
442
+ the gate cannot recognize — that request needs `skipAuthGate: true` (see
443
+ `RequestConfig.skipAuthGate`). `@molecule/app-auth`'s own restore needs neither because it
444
+ uses `fetch` rather than the bonded client.
430
445
 
431
446
  ```typescript
432
447
  function setAuthGate(next: (() => Promise<void>) | null): void
@@ -525,10 +540,30 @@ function unwrapSingle(res: unknown): T | null
525
540
 
526
541
  **Returns:** The typed resource `T`, or `null` when the response shape indicates "no resource" (including the various empty envelopes above).
527
542
 
543
+ #### `setAuthTokenSource(source)`
544
+
545
+ Registers the token source a newly bonded client is hydrated from, or clears
546
+ it with `null`.
547
+
548
+ The source is read once per bond: the client bonded AFTER this call (and the
549
+ one bonded now, if any) receives `source()` through `setAuthToken`. That is
550
+ what carries a restored session's token into a client the auth setup ran
551
+ before — the setup does not need to hold a client reference at all.
552
+
553
+ ```typescript
554
+ function setAuthTokenSource(source: (() => string | null | undefined) | null): void
555
+ ```
556
+
557
+ - `source` — Returns the current access token (null when signed out), or `null` to clear.
558
+
528
559
  #### `setClient(client)`
529
560
 
530
561
  Registers an HTTP client as the active singleton.
531
562
 
563
+ A registered `setAuthTokenSource` token source is applied to the client
564
+ here, so a client bonded after the auth setup still carries the restored
565
+ session's token.
566
+
532
567
  ```typescript
533
568
  function setClient(client: HttpClient): void
534
569
  ```
@@ -537,8 +572,8 @@ function setClient(client: HttpClient): void
537
572
 
538
573
  #### `getClient()`
539
574
 
540
- Retrieves the bonded HTTP client. If none is bonded, automatically
541
- creates a default fetch-based client.
575
+ Retrieves the bonded HTTP client. If none is bonded, returns a module-level
576
+ fetch-based fallback — it is NOT bonded.
542
577
 
543
578
  The fallback has NO `baseURL` — a core cannot know an app's API prefix. A relative
544
579
  call then resolves against the page origin, where a dev server answers its own HTML
@@ -546,11 +581,15 @@ shell with a 200. It warns once so the misconfiguration is named instead of show
546
581
  as a crash three components later; a scaffold bonds the shared client with its API
547
582
  prefix, so the fallback only runs in an app that never bonded one.
548
583
 
584
+ Returning it WITHOUT bonding is what keeps a later `setClient()` authoritative: a
585
+ caller that captured this fallback early does not make it the app's client, so the
586
+ scaffold's client (and its token source) still takes effect for every later call.
587
+
549
588
  ```typescript
550
589
  function getClient(): HttpClient
551
590
  ```
552
591
 
553
- **Returns:** The active HTTP client instance.
592
+ **Returns:** The active HTTP client, or the unbonded fallback when none is bonded.
554
593
 
555
594
  #### `get(url, config)`
556
595
 
@@ -702,13 +741,15 @@ authScheme })` from `@molecule/app-bonds-default-react` (or an auth client built
702
741
  `createDefaultAuthClientWithHttpSync`, which mirrors the token into the bonded client), because
703
742
  `setAuthGate` alone sends no `Authorization` header.
704
743
 
705
- **A request the gate itself depends on must opt out of it: pass `skipAuthGate: true`.** A gate
706
- that waits for a session restore whose own request goes through this client waits on itself —
707
- that request is held by the gate waiting for it, so the restore never settles and every request
708
- the gate holds stalls until it times out (3 s). The request that restores the session for a gate
709
- you registered yourself is therefore written
710
- `http.get(currentUserEndpoint, { skipAuthGate: true })`; `@molecule/app-auth`'s own restore does
711
- not need it (it calls `fetch`, not this client).
744
+ **The gate never holds its own restore's request.** A request the settle function issues
745
+ while it runs (its call reaches this client before the function awaits anything) is part of
746
+ the restore it is waiting for, so it goes out immediately — `setAuthGate(() =>
747
+ restoreSession())` does not deadlock even when `restoreSession` uses this client. A restore
748
+ that awaits something else first and only then calls the client reaches it after that
749
+ window, and that request must opt out of the gate: `http.get(currentUserEndpoint, {
750
+ skipAuthGate: true })`. Without the opt-out the gate waits on itself, the restore never
751
+ settles, and every request the gate holds stalls until it times out (3 s).
752
+ `@molecule/app-auth`'s own restore does not need it (it calls `fetch`, not this client).
712
753
 
713
754
  ## Translations
714
755
 
@@ -27,24 +27,28 @@
27
27
  * `setupHttpDefault()`), and a gate installed on the throwaway client the auth
28
28
  * bond saw would be silently lost.
29
29
  *
30
- * ## A request the gate is waiting for must opt out
31
- *
32
- * `awaitAuthGate` holds every request while the gate is pending — including one the gate
33
- * itself depends on. A gate that waits for a session restore whose own request goes through
34
- * the SAME client waits on itself: the restore's `GET /users/me` is held by the gate, the
35
- * restore's promise cannot settle, and nothing but the timeout releases anything (X1
36
- * xr-molecule-flash-m97 lost ~4 min to exactly this — an app registering
37
- * `setAuthGate(() => whenSettled())` over a restore that fetched through its own client, with
38
- * every request stalling the full bound and only a console warning to show for it). So a
39
- * request the gate's restore makes must pass `skipAuthGate: true`
40
- * (`RequestConfig.skipAuthGate`).
41
- *
42
- * Which held request is the gate's own is NOT detectable here: the gate is arbitrary code
43
- * returning a promise, so a request cannot be attributed to the async chain that awaits it —
44
- * and browsers have no async-context API (`AsyncContext` is not shipped) to ask. Releasing
45
- * requests merely because the gate is pending and they carry no token would drop exactly the
46
- * first-paint requests the gate exists to hold. The opt-out is therefore the fix, and a
47
- * timeout with requests held is reported as an error naming it.
30
+ * ## The gate's own restore requests are never held
31
+ *
32
+ * `awaitAuthGate` holds every request while the gate is pending — except the ones the gate's
33
+ * settle function issues itself. Those are part of the restore it is waiting for; holding them
34
+ * makes the gate wait on itself, and nothing but the timeout releases anything (X1
35
+ * xr-molecule-flash-m97 and xr-molecule-flash-m173 both lost minutes to this: an app
36
+ * registering `setAuthGate(() => restoreSession())` over a restore that fetched through the
37
+ * same client, every page held for the full bound, and 917 `GET /api/user` requests named by
38
+ * one console line). So `setAuthGate(() => restoreSession())` works as written when
39
+ * `restoreSession` calls the gated client.
40
+ *
41
+ * "Issued by the gate" means issued while the settle function is running: this package's
42
+ * fetch client awaits the gate before anything else, so a restore's call is made in the settle
43
+ * function's own synchronous execution. A restore that awaits something else first (a storage
44
+ * read, a `Promise.resolve()`) and only then calls the client issues its request from a later
45
+ * continuation, which nothing can attribute to the gate — browsers ship no async-context API
46
+ * (`AsyncContext`/`AsyncLocalStorage`) to ask, and releasing requests merely because the gate is
47
+ * pending would drop exactly the first-paint requests the gate exists to hold (m95). A provider
48
+ * whose request pipeline awaits the gate in a scheduled interceptor (the Axios bond) reaches it
49
+ * a microtask after the settle function returns, outside the window, for the same reason. Such a
50
+ * request must pass `skipAuthGate: true` (`RequestConfig.skipAuthGate`), and a timeout with
51
+ * requests held is reported at error level naming it.
48
52
  *
49
53
  * @module
50
54
  */
@@ -58,10 +62,20 @@ import type { AuthGateRequest } from './types.js';
58
62
  * immediately when no restore is in flight, so registering it never makes a
59
63
  * request wait longer than the restore it was about to race anyway.
60
64
  *
61
- * A gate whose restore sends its OWN request through the gated client deadlocks — the
62
- * gate holds the request it is waiting for. That request must pass `skipAuthGate: true`
63
- * (see `RequestConfig.skipAuthGate`); `@molecule/app-auth`'s own restore does not
64
- * need it because it uses `fetch` rather than the bonded client.
65
+ * Waiting for the restore does NOT attach its token: a separately created HTTP
66
+ * client needs `createDefaultHttpClientWithAuthBearer({ baseURL,
67
+ * getToken: () => authClient.getAccessToken(), authScheme })` from
68
+ * `@molecule/app-bonds-default-react` (or the auth client built with
69
+ * `createDefaultAuthClientWithHttpSync`, which mirrors the token into the
70
+ * bonded client) plus `setAuthGate(() => authClient.whenRestored())`.
71
+ *
72
+ * The restore's own requests are never held: a request the settle function issues while it
73
+ * runs goes out immediately, so `setAuthGate(() => restoreSession())` cannot deadlock even
74
+ * when `restoreSession` calls the gated client. A restore that awaits something else first
75
+ * (a storage read, a `Promise.resolve()`) issues its request from a later continuation, which
76
+ * the gate cannot recognize — that request needs `skipAuthGate: true` (see
77
+ * `RequestConfig.skipAuthGate`). `@molecule/app-auth`'s own restore needs neither because it
78
+ * uses `fetch` rather than the bonded client.
65
79
  *
66
80
  * @param next - The gate, or `null` to clear a previously registered one.
67
81
  *
@@ -1 +1 @@
1
- {"version":3,"file":"auth-gate.d.ts","sourceRoot":"","sources":["../src/auth-gate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiDG;AAIH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AA6CjD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,eAAO,MAAM,WAAW,GAAI,MAAM,CAAC,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC,GAAG,IAAI,KAAG,IAGhE,CAAA;AA6BD;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,aAAa,GAAU,UAAU,eAAe,KAAG,OAAO,CAAC,IAAI,CAuC3E,CAAA"}
1
+ {"version":3,"file":"auth-gate.d.ts","sourceRoot":"","sources":["../src/auth-gate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqDG;AAIH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AAkEjD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,eAAO,MAAM,WAAW,GAAI,MAAM,CAAC,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC,GAAG,IAAI,KAAG,IAIhE,CAAA;AA8ED;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,aAAa,GAAU,UAAU,eAAe,KAAG,OAAO,CAAC,IAAI,CAwC3E,CAAA"}
package/dist/auth-gate.js CHANGED
@@ -27,24 +27,28 @@
27
27
  * `setupHttpDefault()`), and a gate installed on the throwaway client the auth
28
28
  * bond saw would be silently lost.
29
29
  *
30
- * ## A request the gate is waiting for must opt out
31
- *
32
- * `awaitAuthGate` holds every request while the gate is pending — including one the gate
33
- * itself depends on. A gate that waits for a session restore whose own request goes through
34
- * the SAME client waits on itself: the restore's `GET /users/me` is held by the gate, the
35
- * restore's promise cannot settle, and nothing but the timeout releases anything (X1
36
- * xr-molecule-flash-m97 lost ~4 min to exactly this — an app registering
37
- * `setAuthGate(() => whenSettled())` over a restore that fetched through its own client, with
38
- * every request stalling the full bound and only a console warning to show for it). So a
39
- * request the gate's restore makes must pass `skipAuthGate: true`
40
- * (`RequestConfig.skipAuthGate`).
41
- *
42
- * Which held request is the gate's own is NOT detectable here: the gate is arbitrary code
43
- * returning a promise, so a request cannot be attributed to the async chain that awaits it —
44
- * and browsers have no async-context API (`AsyncContext` is not shipped) to ask. Releasing
45
- * requests merely because the gate is pending and they carry no token would drop exactly the
46
- * first-paint requests the gate exists to hold. The opt-out is therefore the fix, and a
47
- * timeout with requests held is reported as an error naming it.
30
+ * ## The gate's own restore requests are never held
31
+ *
32
+ * `awaitAuthGate` holds every request while the gate is pending — except the ones the gate's
33
+ * settle function issues itself. Those are part of the restore it is waiting for; holding them
34
+ * makes the gate wait on itself, and nothing but the timeout releases anything (X1
35
+ * xr-molecule-flash-m97 and xr-molecule-flash-m173 both lost minutes to this: an app
36
+ * registering `setAuthGate(() => restoreSession())` over a restore that fetched through the
37
+ * same client, every page held for the full bound, and 917 `GET /api/user` requests named by
38
+ * one console line). So `setAuthGate(() => restoreSession())` works as written when
39
+ * `restoreSession` calls the gated client.
40
+ *
41
+ * "Issued by the gate" means issued while the settle function is running: this package's
42
+ * fetch client awaits the gate before anything else, so a restore's call is made in the settle
43
+ * function's own synchronous execution. A restore that awaits something else first (a storage
44
+ * read, a `Promise.resolve()`) and only then calls the client issues its request from a later
45
+ * continuation, which nothing can attribute to the gate — browsers ship no async-context API
46
+ * (`AsyncContext`/`AsyncLocalStorage`) to ask, and releasing requests merely because the gate is
47
+ * pending would drop exactly the first-paint requests the gate exists to hold (m95). A provider
48
+ * whose request pipeline awaits the gate in a scheduled interceptor (the Axios bond) reaches it
49
+ * a microtask after the settle function returns, outside the window, for the same reason. Such a
50
+ * request must pass `skipAuthGate: true` (`RequestConfig.skipAuthGate`), and a timeout with
51
+ * requests held is reported at error level naming it.
48
52
  *
49
53
  * @module
50
54
  */
@@ -66,6 +70,25 @@ const heldRequests = new Map();
66
70
  * gates. Cleared when the same gate later releases a request normally.
67
71
  */
68
72
  let reportedStall = null;
73
+ /**
74
+ * The settle-function invocation requests are currently waiting on, shared by every request
75
+ * that arrives while the gate is pending.
76
+ *
77
+ * Without it each held request re-invokes the gate, and a gate that issues a request on every
78
+ * call floods the network: the m97 shape measured 855 `fetch` calls for one page (`task-auth-
79
+ * gate-deadlock.report.md`). `null` when no invocation is in flight; `setAuthGate` clears it
80
+ * so a re-registered gate is never shared with the old one's waiters.
81
+ */
82
+ let inFlightGate = null;
83
+ /**
84
+ * True only while the gate's settle function is executing synchronously.
85
+ *
86
+ * A request that reaches `awaitAuthGate` in this window was issued BY the restore — the fetch
87
+ * client's `request()` awaits the gate before anything else, so the call is made in the settle
88
+ * function's own execution. Holding it would make the gate wait on itself (see the module
89
+ * doc); requests issued after the function awaits something else are held as usual.
90
+ */
91
+ let gateSettling = false;
69
92
  /**
70
93
  * How long a request may be held by the gate before it is sent anyway.
71
94
  *
@@ -96,10 +119,20 @@ const GATE_TIMEOUT_MS = 3_000;
96
119
  * immediately when no restore is in flight, so registering it never makes a
97
120
  * request wait longer than the restore it was about to race anyway.
98
121
  *
99
- * A gate whose restore sends its OWN request through the gated client deadlocks — the
100
- * gate holds the request it is waiting for. That request must pass `skipAuthGate: true`
101
- * (see `RequestConfig.skipAuthGate`); `@molecule/app-auth`'s own restore does not
102
- * need it because it uses `fetch` rather than the bonded client.
122
+ * Waiting for the restore does NOT attach its token: a separately created HTTP
123
+ * client needs `createDefaultHttpClientWithAuthBearer({ baseURL,
124
+ * getToken: () => authClient.getAccessToken(), authScheme })` from
125
+ * `@molecule/app-bonds-default-react` (or the auth client built with
126
+ * `createDefaultAuthClientWithHttpSync`, which mirrors the token into the
127
+ * bonded client) plus `setAuthGate(() => authClient.whenRestored())`.
128
+ *
129
+ * The restore's own requests are never held: a request the settle function issues while it
130
+ * runs goes out immediately, so `setAuthGate(() => restoreSession())` cannot deadlock even
131
+ * when `restoreSession` calls the gated client. A restore that awaits something else first
132
+ * (a storage read, a `Promise.resolve()`) issues its request from a later continuation, which
133
+ * the gate cannot recognize — that request needs `skipAuthGate: true` (see
134
+ * `RequestConfig.skipAuthGate`). `@molecule/app-auth`'s own restore needs neither because it
135
+ * uses `fetch` rather than the bonded client.
103
136
  *
104
137
  * @param next - The gate, or `null` to clear a previously registered one.
105
138
  *
@@ -112,6 +145,7 @@ const GATE_TIMEOUT_MS = 3_000;
112
145
  */
113
146
  export const setAuthGate = (next) => {
114
147
  gate = next;
148
+ inFlightGate = null;
115
149
  reportedStall = null;
116
150
  };
117
151
  /**
@@ -121,21 +155,69 @@ export const setAuthGate = (next) => {
121
155
  const describeRequest = (request) => request?.method || request?.url
122
156
  ? `${request?.method ?? 'GET'} ${request?.url ?? ''}`.trim()
123
157
  : 'a request';
158
+ /**
159
+ * How many held request names the stalled-gate report prints before summarizing the rest.
160
+ *
161
+ * The report is console output, and every reader of it truncates: molecule-dev's route walk
162
+ * keeps the first 200 characters of a console error, so the sentence naming the fix has to
163
+ * come first — and the request list is capped so the message stays readable when a deadlocked
164
+ * gate has held hundreds of requests (xr-molecule-flash-m173: 917 `GET /api/user`).
165
+ */
166
+ const MAX_NAMED_HELD_REQUESTS = 5;
124
167
  /**
125
168
  * Reports a gate that timed out while holding requests: once per stuck gate, at error level
126
169
  * so it reaches the page's error console and any error transport — a console warning on a
127
170
  * deployed URL reads as "the site is slow", which is what the gate itself was added for.
171
+ *
172
+ * Leads with the cause and the fix, then names at most `MAX_NAMED_HELD_REQUESTS` distinct
173
+ * requests and counts the rest: an unbounded join buried the fix clause behind 900 names in
174
+ * xr-molecule-flash-m173, and no reader of the line ever reached it.
128
175
  */
129
176
  const reportStalledGate = (stuck) => {
130
177
  if (reportedStall === stuck)
131
178
  return;
132
179
  reportedStall = stuck;
133
- const held = [...heldRequests.values()].join(', ');
134
- logger.error(`The auth gate has not settled after ${GATE_TIMEOUT_MS}ms and ${heldRequests.size} request(s) ` +
135
- `were held by it (${held}); sending them without waiting. If the gate waits for a session ` +
136
- `restore that makes its own request through this HTTP client, that request is being held by ` +
137
- `the gate waiting for it: send it with \`skipAuthGate: true\`, or clear the gate with ` +
138
- `\`setAuthGate(null)\` if nothing restores a session.`);
180
+ const names = [...new Set(heldRequests.values())];
181
+ const shown = names.slice(0, MAX_NAMED_HELD_REQUESTS);
182
+ const more = heldRequests.size - shown.length;
183
+ logger.error(`The auth gate is waiting on itself: its restore's request is held by it. Send that ` +
184
+ `request with \`skipAuthGate: true\`, or clear the gate with \`setAuthGate(null)\` if ` +
185
+ `nothing restores a session. Held ${heldRequests.size} request(s) for ` +
186
+ `${GATE_TIMEOUT_MS}ms${shown.length ? `: ${shown.join(', ')}` : ''}` +
187
+ `${more > 0 ? ` (and ${more} more)` : ''}.`);
188
+ };
189
+ /**
190
+ * Starts the gate's settle function — once, shared by every request that arrives while it is
191
+ * pending — turning a rejection (or a synchronous throw) into a logged warning so a failed
192
+ * restore releases its waiters instead of rejecting them.
193
+ *
194
+ * `gateSettling` is true only for the function's synchronous execution: the IIFE runs
195
+ * `current()` up to its first `await` before this call returns, and any request the restore
196
+ * issues there (the gated client's `request()` awaits the gate before anything else) bypasses
197
+ * the gate instead of waiting on the invocation it belongs to.
198
+ */
199
+ const invokeGate = (current) => {
200
+ if (inFlightGate)
201
+ return inFlightGate;
202
+ let invocation;
203
+ gateSettling = true;
204
+ try {
205
+ invocation = (async () => current())();
206
+ }
207
+ finally {
208
+ gateSettling = false;
209
+ }
210
+ const shared = invocation.catch((error) => {
211
+ logger.warn('The auth gate rejected; sending the request without waiting for it', {
212
+ error,
213
+ });
214
+ });
215
+ inFlightGate = shared;
216
+ void shared.then(() => {
217
+ if (inFlightGate === shared)
218
+ inFlightGate = null;
219
+ });
220
+ return shared;
139
221
  };
140
222
  /**
141
223
  * Awaits the registered gate, if any. Every HTTP provider calls this before it
@@ -160,19 +242,20 @@ export const awaitAuthGate = async (request) => {
160
242
  const current = gate;
161
243
  if (!current)
162
244
  return;
245
+ // Issued while the gate's settle function is running: part of the restore it is settling,
246
+ // never held by it. See `invokeGate` and the module doc.
247
+ if (gateSettling)
248
+ return;
163
249
  const token = Symbol('held-request');
164
250
  heldRequests.set(token, describeRequest(request));
165
251
  let timer;
166
252
  let timedOut = false;
167
253
  try {
168
254
  await Promise.race([
169
- // `(async () => current())()` also turns a gate that throws SYNCHRONOUSLY into a rejection:
170
- // a gate is someone else's code, and no shape of it may reject the request it was holding.
171
- (async () => current())().catch((error) => {
172
- logger.warn('The auth gate rejected; sending the request without waiting for it', {
173
- error,
174
- });
175
- }),
255
+ // One invocation, shared: `invokeGate` also turns a gate that throws SYNCHRONOUSLY into
256
+ // a rejection — a gate is someone else's code, and no shape of it may reject the
257
+ // request it was holding.
258
+ invokeGate(current),
176
259
  new Promise((resolve) => {
177
260
  timer = setTimeout(() => {
178
261
  timedOut = true;
@@ -1 +1 @@
1
- {"version":3,"file":"auth-gate.js","sourceRoot":"","sources":["../src/auth-gate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiDG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAA;AAIhD,MAAM,MAAM,GAAG,SAAS,CAAC,MAAM,CAAC,CAAA;AAEhC,iFAAiF;AACjF,IAAI,IAAI,GAAiC,IAAI,CAAA;AAE7C;;;GAGG;AACH,MAAM,YAAY,GAAG,IAAI,GAAG,EAAkB,CAAA;AAE9C;;;;;;;GAOG;AACH,IAAI,aAAa,GAAiC,IAAI,CAAA;AAEtD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,eAAe,GAAG,KAAK,CAAA;AAE7B;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,IAAkC,EAAQ,EAAE;IACtE,IAAI,GAAG,IAAI,CAAA;IACX,aAAa,GAAG,IAAI,CAAA;AACtB,CAAC,CAAA;AAED;;;GAGG;AACH,MAAM,eAAe,GAAG,CAAC,OAAyB,EAAU,EAAE,CAC5D,OAAO,EAAE,MAAM,IAAI,OAAO,EAAE,GAAG;IAC7B,CAAC,CAAC,GAAG,OAAO,EAAE,MAAM,IAAI,KAAK,IAAI,OAAO,EAAE,GAAG,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE;IAC5D,CAAC,CAAC,WAAW,CAAA;AAEjB;;;;GAIG;AACH,MAAM,iBAAiB,GAAG,CAAC,KAA0B,EAAQ,EAAE;IAC7D,IAAI,aAAa,KAAK,KAAK;QAAE,OAAM;IACnC,aAAa,GAAG,KAAK,CAAA;IACrB,MAAM,IAAI,GAAG,CAAC,GAAG,YAAY,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IAClD,MAAM,CAAC,KAAK,CACV,uCAAuC,eAAe,UAAU,YAAY,CAAC,IAAI,cAAc;QAC7F,oBAAoB,IAAI,mEAAmE;QAC3F,6FAA6F;QAC7F,uFAAuF;QACvF,sDAAsD,CACzD,CAAA;AACH,CAAC,CAAA;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,KAAK,EAAE,OAAyB,EAAiB,EAAE;IAC9E,wFAAwF;IACxF,gDAAgD;IAChD,IAAI,OAAO,EAAE,YAAY;QAAE,OAAM;IAEjC,MAAM,OAAO,GAAG,IAAI,CAAA;IACpB,IAAI,CAAC,OAAO;QAAE,OAAM;IAEpB,MAAM,KAAK,GAAG,MAAM,CAAC,cAAc,CAAC,CAAA;IACpC,YAAY,CAAC,GAAG,CAAC,KAAK,EAAE,eAAe,CAAC,OAAO,CAAC,CAAC,CAAA;IAEjD,IAAI,KAAgD,CAAA;IACpD,IAAI,QAAQ,GAAG,KAAK,CAAA;IACpB,IAAI,CAAC;QACH,MAAM,OAAO,CAAC,IAAI,CAAC;YACjB,4FAA4F;YAC5F,2FAA2F;YAC3F,CAAC,KAAK,IAAI,EAAE,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;gBACxC,MAAM,CAAC,IAAI,CAAC,oEAAoE,EAAE;oBAChF,KAAK;iBACN,CAAC,CAAA;YACJ,CAAC,CAAC;YACF,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE;gBAC5B,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE;oBACtB,QAAQ,GAAG,IAAI,CAAA;oBACf,mFAAmF;oBACnF,iBAAiB,CAAC,OAAO,CAAC,CAAA;oBAC1B,OAAO,EAAE,CAAA;gBACX,CAAC,EAAE,eAAe,CAAC,CAAA;YACrB,CAAC,CAAC;SACH,CAAC,CAAA;IACJ,CAAC;YAAS,CAAC;QACT,IAAI,KAAK;YAAE,YAAY,CAAC,KAAK,CAAC,CAAA;QAC9B,YAAY,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;IAC5B,CAAC;IAED,yFAAyF;IACzF,8EAA8E;IAC9E,IAAI,CAAC,QAAQ,IAAI,aAAa,KAAK,OAAO;QAAE,aAAa,GAAG,IAAI,CAAA;AAClE,CAAC,CAAA"}
1
+ {"version":3,"file":"auth-gate.js","sourceRoot":"","sources":["../src/auth-gate.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -78,13 +78,15 @@
78
78
  * `createDefaultAuthClientWithHttpSync`, which mirrors the token into the bonded client), because
79
79
  * `setAuthGate` alone sends no `Authorization` header.
80
80
  *
81
- * **A request the gate itself depends on must opt out of it: pass `skipAuthGate: true`.** A gate
82
- * that waits for a session restore whose own request goes through this client waits on itself —
83
- * that request is held by the gate waiting for it, so the restore never settles and every request
84
- * the gate holds stalls until it times out (3 s). The request that restores the session for a gate
85
- * you registered yourself is therefore written
86
- * `http.get(currentUserEndpoint, { skipAuthGate: true })`; `@molecule/app-auth`'s own restore does
87
- * not need it (it calls `fetch`, not this client).
81
+ * **The gate never holds its own restore's request.** A request the settle function issues
82
+ * while it runs (its call reaches this client before the function awaits anything) is part of
83
+ * the restore it is waiting for, so it goes out immediately — `setAuthGate(() =>
84
+ * restoreSession())` does not deadlock even when `restoreSession` uses this client. A restore
85
+ * that awaits something else first and only then calls the client reaches it after that
86
+ * window, and that request must opt out of the gate: `http.get(currentUserEndpoint, {
87
+ * skipAuthGate: true })`. Without the opt-out the gate waits on itself, the restore never
88
+ * settles, and every request the gate holds stalls until it times out (3 s).
89
+ * `@molecule/app-auth`'s own restore does not need it (it calls `fetch`, not this client).
88
90
  *
89
91
  * @module
90
92
  */
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyFG;AAEH,cAAc,gBAAgB,CAAA;AAC9B,cAAc,aAAa,CAAA;AAC3B,cAAc,mBAAmB,CAAA;AACjC,cAAc,eAAe,CAAA;AAC7B,cAAc,YAAY,CAAA;AAC1B,cAAc,aAAa,CAAA;AAC3B,cAAc,gBAAgB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2FG;AAEH,cAAc,gBAAgB,CAAA;AAC9B,cAAc,aAAa,CAAA;AAC3B,cAAc,mBAAmB,CAAA;AACjC,cAAc,eAAe,CAAA;AAC7B,cAAc,YAAY,CAAA;AAC1B,cAAc,aAAa,CAAA;AAC3B,cAAc,gBAAgB,CAAA"}
package/dist/index.js CHANGED
@@ -78,13 +78,15 @@
78
78
  * `createDefaultAuthClientWithHttpSync`, which mirrors the token into the bonded client), because
79
79
  * `setAuthGate` alone sends no `Authorization` header.
80
80
  *
81
- * **A request the gate itself depends on must opt out of it: pass `skipAuthGate: true`.** A gate
82
- * that waits for a session restore whose own request goes through this client waits on itself —
83
- * that request is held by the gate waiting for it, so the restore never settles and every request
84
- * the gate holds stalls until it times out (3 s). The request that restores the session for a gate
85
- * you registered yourself is therefore written
86
- * `http.get(currentUserEndpoint, { skipAuthGate: true })`; `@molecule/app-auth`'s own restore does
87
- * not need it (it calls `fetch`, not this client).
81
+ * **The gate never holds its own restore's request.** A request the settle function issues
82
+ * while it runs (its call reaches this client before the function awaits anything) is part of
83
+ * the restore it is waiting for, so it goes out immediately — `setAuthGate(() =>
84
+ * restoreSession())` does not deadlock even when `restoreSession` uses this client. A restore
85
+ * that awaits something else first and only then calls the client reaches it after that
86
+ * window, and that request must opt out of the gate: `http.get(currentUserEndpoint, {
87
+ * skipAuthGate: true })`. Without the opt-out the gate waits on itself, the restore never
88
+ * settles, and every request the gate holds stalls until it times out (3 s).
89
+ * `@molecule/app-auth`'s own restore does not need it (it calls `fetch`, not this client).
88
90
  *
89
91
  * @module
90
92
  */
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyFG;AAEH,cAAc,gBAAgB,CAAA;AAC9B,cAAc,aAAa,CAAA;AAC3B,cAAc,mBAAmB,CAAA;AACjC,cAAc,eAAe,CAAA;AAC7B,cAAc,YAAY,CAAA;AAC1B,cAAc,aAAa,CAAA;AAC3B,cAAc,gBAAgB,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2FG;AAEH,cAAc,gBAAgB,CAAA;AAC9B,cAAc,aAAa,CAAA;AAC3B,cAAc,mBAAmB,CAAA;AACjC,cAAc,eAAe,CAAA;AAC7B,cAAc,YAAY,CAAA;AAC1B,cAAc,aAAa,CAAA;AAC3B,cAAc,gBAAgB,CAAA"}
package/dist/types.d.ts CHANGED
@@ -30,11 +30,15 @@ export interface RequestConfig {
30
30
  /**
31
31
  * Send this request WITHOUT waiting for the session restore (the auth gate).
32
32
  *
33
- * A request the gate itself depends on must set this. A gate registered with
34
- * `setAuthGate` that waits for a session restore whose own request goes through this
35
- * client otherwise waits on itself: the gate holds the restore's request, the restore's
36
- * promise never settles, and every request on the page stalls until the gate times out —
37
- * so pass `skipAuthGate: true` on the restore's own request:
33
+ * A request the gate's restore issues from a LATER continuation must set this. The gate
34
+ * recognizes a request the settle function issues while it runs and never holds it — this
35
+ * package's client awaits the gate before anything else, so a `restoreSession()` that calls
36
+ * it directly does not deadlock. But a restore that awaits something else first
37
+ * (`await storage.get()`), then calls the client, reaches `awaitAuthGate` after that window:
38
+ * the gate then waits on itself, and every request on the page stalls until the gate times
39
+ * out (3 s) — so pass `skipAuthGate: true` on that request. A provider that awaits the gate
40
+ * inside a scheduled interceptor (the Axios bond) also reaches it after the window, so its
41
+ * restore's request needs the opt-out.
38
42
  *
39
43
  * ```typescript
40
44
  * // the request the gate's restore makes, through the same client the gate holds back
@@ -43,7 +47,8 @@ export interface RequestConfig {
43
47
  *
44
48
  * `@molecule/app-auth`'s own restore does not need it — it sends its request with
45
49
  * `fetch`, not through this client. An app with its own session store that registers a
46
- * gate with `setAuthGate` does.
50
+ * gate with `setAuthGate` does not need it either when its restore calls the client
51
+ * directly.
47
52
  */
48
53
  skipAuthGate?: boolean;
49
54
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;GAEG;AACH,MAAM,MAAM,UAAU,GAAG,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM,GAAG,SAAS,CAAA;AAEzF;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAEhC;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,CAAC,CAAA;IAE9D;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAA;IAEhB;;OAEG;IACH,eAAe,CAAC,EAAE,OAAO,CAAA;IAEzB;;;;;;;;;;;;;;;;;OAiBG;IACH,YAAY,CAAC,EAAE,OAAO,CAAA;IAEtB;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,aAAa,CAAA;IAEvD;;OAEG;IACH,MAAM,CAAC,EAAE,WAAW,CAAA;IAEpB;;;;;;OAMG;IACH,IAAI,CAAC,EAAE,OAAO,CAAA;IAEd;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAClC;AAED;;;;;;GAMG;AACH,MAAM,WAAW,eAAe;IAC9B;;;OAGG;IACH,YAAY,CAAC,EAAE,OAAO,CAAA;IAEtB;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAA;IAEf;;;OAGG;IACH,GAAG,CAAC,EAAE,MAAM,CAAA;CACb;AAED;;GAEG;AACH,MAAM,WAAW,iBAAkB,SAAQ,aAAa;IACtD;;OAEG;IACH,MAAM,EAAE,UAAU,CAAA;IAElB;;OAEG;IACH,GAAG,EAAE,MAAM,CAAA;IAEX;;OAEG;IACH,IAAI,CAAC,EAAE,OAAO,CAAA;CACf;AAED;;GAEG;AACH,MAAM,WAAW,YAAY,CAAC,CAAC,GAAG,OAAO;IACvC;;OAEG;IACH,IAAI,EAAE,CAAC,CAAA;IAEP;;OAEG;IACH,MAAM,EAAE,MAAM,CAAA;IAEd;;OAEG;IACH,UAAU,EAAE,MAAM,CAAA;IAElB;;OAEG;IACH,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAE/B;;OAEG;IACH,MAAM,EAAE,iBAAiB,CAAA;CAC1B;AAED;;GAEG;AACH,qBAAa,SAAU,SAAQ,KAAK;IAGzB,MAAM,EAAE,MAAM;IACd,QAAQ,CAAC,EAAE,YAAY;IACvB,MAAM,CAAC,EAAE,iBAAiB;IAC1B,QAAQ,CAAC,EAAE,MAAM;gBAJxB,OAAO,EAAE,MAAM,EACR,MAAM,EAAE,MAAM,EACd,QAAQ,CAAC,EAAE,YAAY,YAAA,EACvB,MAAM,CAAC,EAAE,iBAAiB,YAAA,EAC1B,QAAQ,CAAC,EAAE,MAAM,YAAA;CAK3B"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;GAEG;AACH,MAAM,MAAM,UAAU,GAAG,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM,GAAG,SAAS,CAAA;AAEzF;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAEhC;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,CAAC,CAAA;IAE9D;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAA;IAEhB;;OAEG;IACH,eAAe,CAAC,EAAE,OAAO,CAAA;IAEzB;;;;;;;;;;;;;;;;;;;;;;OAsBG;IACH,YAAY,CAAC,EAAE,OAAO,CAAA;IAEtB;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,aAAa,CAAA;IAEvD;;OAEG;IACH,MAAM,CAAC,EAAE,WAAW,CAAA;IAEpB;;;;;;OAMG;IACH,IAAI,CAAC,EAAE,OAAO,CAAA;IAEd;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAClC;AAED;;;;;;GAMG;AACH,MAAM,WAAW,eAAe;IAC9B;;;OAGG;IACH,YAAY,CAAC,EAAE,OAAO,CAAA;IAEtB;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAA;IAEf;;;OAGG;IACH,GAAG,CAAC,EAAE,MAAM,CAAA;CACb;AAED;;GAEG;AACH,MAAM,WAAW,iBAAkB,SAAQ,aAAa;IACtD;;OAEG;IACH,MAAM,EAAE,UAAU,CAAA;IAElB;;OAEG;IACH,GAAG,EAAE,MAAM,CAAA;IAEX;;OAEG;IACH,IAAI,CAAC,EAAE,OAAO,CAAA;CACf;AAED;;GAEG;AACH,MAAM,WAAW,YAAY,CAAC,CAAC,GAAG,OAAO;IACvC;;OAEG;IACH,IAAI,EAAE,CAAC,CAAA;IAEP;;OAEG;IACH,MAAM,EAAE,MAAM,CAAA;IAEd;;OAEG;IACH,UAAU,EAAE,MAAM,CAAA;IAElB;;OAEG;IACH,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAE/B;;OAEG;IACH,MAAM,EAAE,iBAAiB,CAAA;CAC1B;AAED;;GAEG;AACH,qBAAa,SAAU,SAAQ,KAAK;IAGzB,MAAM,EAAE,MAAM;IACd,QAAQ,CAAC,EAAE,YAAY;IACvB,MAAM,CAAC,EAAE,iBAAiB;IAC1B,QAAQ,CAAC,EAAE,MAAM;gBAJxB,OAAO,EAAE,MAAM,EACR,MAAM,EAAE,MAAM,EACd,QAAQ,CAAC,EAAE,YAAY,YAAA,EACvB,MAAM,CAAC,EAAE,iBAAiB,YAAA,EAC1B,QAAQ,CAAC,EAAE,MAAM,YAAA;CAK3B"}
package/dist/types.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAwJH;;GAEG;AACH,MAAM,OAAO,SAAU,SAAQ,KAAK;IAGzB;IACA;IACA;IACA;IALT,YACE,OAAe,EACR,MAAc,EACd,QAAuB,EACvB,MAA0B,EAC1B,QAAiB;QAExB,KAAK,CAAC,OAAO,CAAC,CAAA;QALP,WAAM,GAAN,MAAM,CAAQ;QACd,aAAQ,GAAR,QAAQ,CAAe;QACvB,WAAM,GAAN,MAAM,CAAoB;QAC1B,aAAQ,GAAR,QAAQ,CAAS;QAGxB,IAAI,CAAC,IAAI,GAAG,WAAW,CAAA;IACzB,CAAC;CACF"}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AA6JH;;GAEG;AACH,MAAM,OAAO,SAAU,SAAQ,KAAK;IAGzB;IACA;IACA;IACA;IALT,YACE,OAAe,EACR,MAAc,EACd,QAAuB,EACvB,MAA0B,EAC1B,QAAiB;QAExB,KAAK,CAAC,OAAO,CAAC,CAAA;QALP,WAAM,GAAN,MAAM,CAAQ;QACd,aAAQ,GAAR,QAAQ,CAAe;QACvB,WAAM,GAAN,MAAM,CAAoB;QAC1B,aAAQ,GAAR,QAAQ,CAAS;QAGxB,IAAI,CAAC,IAAI,GAAG,WAAW,CAAA;IACzB,CAAC;CACF"}
@@ -1,17 +1,39 @@
1
1
  /**
2
2
  * HTTP bond accessor and convenience request functions.
3
3
  *
4
- * If no custom client is bonded, a fetch-based client is auto-created
5
- * on first access. Provides `get`, `post`, `put`, `patch`, and `del`
6
- * shorthand functions that delegate to the bonded client.
4
+ * If no custom client is bonded, a fetch-based client is returned — it is NOT
5
+ * bonded, so a client bonded later is what every subsequent call sees.
6
+ * Provides `get`, `post`, `put`, `patch`, and `del` shorthand functions that
7
+ * delegate to the bonded client.
7
8
  *
8
9
  * @module
9
10
  */
10
11
  import type { HttpClient } from './client.js';
11
12
  import type { HttpResponse, RequestConfig } from './types.js';
13
+ /**
14
+ * Registers the token source a newly bonded client is hydrated from, or clears
15
+ * it with `null`.
16
+ *
17
+ * The source is read once per bond: the client bonded AFTER this call (and the
18
+ * one bonded now, if any) receives `source()` through `setAuthToken`. That is
19
+ * what carries a restored session's token into a client the auth setup ran
20
+ * before — the setup does not need to hold a client reference at all.
21
+ *
22
+ * @param source - Returns the current access token (null when signed out), or `null` to clear.
23
+ *
24
+ * @example
25
+ * ```typescript
26
+ * setAuthTokenSource(() => authClient.getAccessToken())
27
+ * ```
28
+ */
29
+ export declare const setAuthTokenSource: (source: (() => string | null | undefined) | null) => void;
12
30
  /**
13
31
  * Registers an HTTP client as the active singleton.
14
32
  *
33
+ * A registered `setAuthTokenSource` token source is applied to the client
34
+ * here, so a client bonded after the auth setup still carries the restored
35
+ * session's token.
36
+ *
15
37
  * @param client - The HTTP client implementation to bond.
16
38
  *
17
39
  * @example
@@ -22,8 +44,8 @@ import type { HttpResponse, RequestConfig } from './types.js';
22
44
  */
23
45
  export declare const setClient: (client: HttpClient) => void;
24
46
  /**
25
- * Retrieves the bonded HTTP client. If none is bonded, automatically
26
- * creates a default fetch-based client.
47
+ * Retrieves the bonded HTTP client. If none is bonded, returns a module-level
48
+ * fetch-based fallback — it is NOT bonded.
27
49
  *
28
50
  * The fallback has NO `baseURL` — a core cannot know an app's API prefix. A relative
29
51
  * call then resolves against the page origin, where a dev server answers its own HTML
@@ -31,7 +53,11 @@ export declare const setClient: (client: HttpClient) => void;
31
53
  * as a crash three components later; a scaffold bonds the shared client with its API
32
54
  * prefix, so the fallback only runs in an app that never bonded one.
33
55
  *
34
- * @returns The active HTTP client instance.
56
+ * Returning it WITHOUT bonding is what keeps a later `setClient()` authoritative: a
57
+ * caller that captured this fallback early does not make it the app's client, so the
58
+ * scaffold's client (and its token source) still takes effect for every later call.
59
+ *
60
+ * @returns The active HTTP client, or the unbonded fallback when none is bonded.
35
61
  */
36
62
  export declare const getClient: () => HttpClient;
37
63
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"utilities.d.ts","sourceRoot":"","sources":["../src/utilities.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAKH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAE7C,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAO7D;;;;;;;;;;GAUG;AACH,eAAO,MAAM,SAAS,GAAI,QAAQ,UAAU,KAAG,IAE9C,CAAA;AAED;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,SAAS,QAAO,UAa5B,CAAA;AAED;;;;;;GAMG;AACH,eAAO,MAAM,GAAG,GAAI,CAAC,GAAG,OAAO,EAAE,KAAK,MAAM,EAAE,SAAS,aAAa,KAAG,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAC7D,CAAA;AAEjC;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,IAAI,GAAI,CAAC,GAAG,OAAO,EAC9B,KAAK,MAAM,EACX,OAAO,OAAO,EACd,SAAS,aAAa,KACrB,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAA2C,CAAA;AAErE;;;;;;;;;GASG;AACH,eAAO,MAAM,GAAG,GAAI,CAAC,GAAG,OAAO,EAC7B,KAAK,MAAM,EACX,OAAO,OAAO,EACd,SAAS,aAAa,KACrB,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAA0C,CAAA;AAEpE;;;;;;;;;GASG;AACH,eAAO,MAAM,KAAK,GAAI,CAAC,GAAG,OAAO,EAC/B,KAAK,MAAM,EACX,OAAO,OAAO,EACd,SAAS,aAAa,KACrB,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAA4C,CAAA;AAEtE;;;;;;GAMG;AACH,eAAO,MAAM,GAAG,GAAI,CAAC,GAAG,OAAO,EAAE,KAAK,MAAM,EAAE,SAAS,aAAa,KAAG,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAC1D,CAAA;AAEpC;;;GAGG;AACH,eAAO,MAAM,WAAW,mBAA4D,CAAA"}
1
+ {"version":3,"file":"utilities.d.ts","sourceRoot":"","sources":["../src/utilities.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAKH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAE7C,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AA6B7D;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,kBAAkB,GAAI,QAAQ,CAAC,MAAM,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,GAAG,IAAI,KAAG,IAIrF,CAAA;AAED;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,SAAS,GAAI,QAAQ,UAAU,KAAG,IAG9C,CAAA;AAED;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,SAAS,QAAO,UAY5B,CAAA;AAED;;;;;;GAMG;AACH,eAAO,MAAM,GAAG,GAAI,CAAC,GAAG,OAAO,EAAE,KAAK,MAAM,EAAE,SAAS,aAAa,KAAG,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAC7D,CAAA;AAEjC;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,IAAI,GAAI,CAAC,GAAG,OAAO,EAC9B,KAAK,MAAM,EACX,OAAO,OAAO,EACd,SAAS,aAAa,KACrB,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAA2C,CAAA;AAErE;;;;;;;;;GASG;AACH,eAAO,MAAM,GAAG,GAAI,CAAC,GAAG,OAAO,EAC7B,KAAK,MAAM,EACX,OAAO,OAAO,EACd,SAAS,aAAa,KACrB,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAA0C,CAAA;AAEpE;;;;;;;;;GASG;AACH,eAAO,MAAM,KAAK,GAAI,CAAC,GAAG,OAAO,EAC/B,KAAK,MAAM,EACX,OAAO,OAAO,EACd,SAAS,aAAa,KACrB,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAA4C,CAAA;AAEtE;;;;;;GAMG;AACH,eAAO,MAAM,GAAG,GAAI,CAAC,GAAG,OAAO,EAAE,KAAK,MAAM,EAAE,SAAS,aAAa,KAAG,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAC1D,CAAA;AAEpC;;;GAGG;AACH,eAAO,MAAM,WAAW,mBAA4D,CAAA"}
package/dist/utilities.js CHANGED
@@ -1,9 +1,10 @@
1
1
  /**
2
2
  * HTTP bond accessor and convenience request functions.
3
3
  *
4
- * If no custom client is bonded, a fetch-based client is auto-created
5
- * on first access. Provides `get`, `post`, `put`, `patch`, and `del`
6
- * shorthand functions that delegate to the bonded client.
4
+ * If no custom client is bonded, a fetch-based client is returned — it is NOT
5
+ * bonded, so a client bonded later is what every subsequent call sees.
6
+ * Provides `get`, `post`, `put`, `patch`, and `del` shorthand functions that
7
+ * delegate to the bonded client.
7
8
  *
8
9
  * @module
9
10
  */
@@ -13,9 +14,55 @@ import { createFetchClient } from './provider.js';
13
14
  const BOND_TYPE = 'http-client';
14
15
  /** One warning per page load is enough to name a missing bond. */
15
16
  let warnedAboutFallback = false;
17
+ /**
18
+ * The client `getClient()` returns while nothing is bonded.
19
+ *
20
+ * Module-level and deliberately NEVER bonded: bonding it made the fallback the
21
+ * page's shared client, so a caller that read `getClient()` before
22
+ * `setClient()` captured a no-baseURL client that every later `setClient()`
23
+ * could not reach — the app's real client was bonded and the caller's token
24
+ * sync kept writing into the orphan, so every request went out bare
25
+ * (xr-molecule-flash-m156, 401 `token is missing` after a reload).
26
+ */
27
+ let unbondedFallback = null;
28
+ /**
29
+ * The auth client whose token every HTTP client starts with, or null.
30
+ *
31
+ * `setClient` applies it at bond time, which is the only moment that can reach a
32
+ * client created AFTER the auth setup ran — the scaffold wires auth before http,
33
+ * so the auth bond's initial token had no client to land on
34
+ * (`createDefaultAuthClientWithHttpSync` in `@molecule/app-bonds-default-react`).
35
+ */
36
+ let authTokenSource = null;
37
+ /**
38
+ * Registers the token source a newly bonded client is hydrated from, or clears
39
+ * it with `null`.
40
+ *
41
+ * The source is read once per bond: the client bonded AFTER this call (and the
42
+ * one bonded now, if any) receives `source()` through `setAuthToken`. That is
43
+ * what carries a restored session's token into a client the auth setup ran
44
+ * before — the setup does not need to hold a client reference at all.
45
+ *
46
+ * @param source - Returns the current access token (null when signed out), or `null` to clear.
47
+ *
48
+ * @example
49
+ * ```typescript
50
+ * setAuthTokenSource(() => authClient.getAccessToken())
51
+ * ```
52
+ */
53
+ export const setAuthTokenSource = (source) => {
54
+ authTokenSource = source;
55
+ const bonded = bondGet(BOND_TYPE);
56
+ if (bonded && source)
57
+ bonded.setAuthToken(source() ?? null);
58
+ };
16
59
  /**
17
60
  * Registers an HTTP client as the active singleton.
18
61
  *
62
+ * A registered `setAuthTokenSource` token source is applied to the client
63
+ * here, so a client bonded after the auth setup still carries the restored
64
+ * session's token.
65
+ *
19
66
  * @param client - The HTTP client implementation to bond.
20
67
  *
21
68
  * @example
@@ -26,10 +73,12 @@ let warnedAboutFallback = false;
26
73
  */
27
74
  export const setClient = (client) => {
28
75
  bond(BOND_TYPE, client);
76
+ if (authTokenSource)
77
+ client.setAuthToken(authTokenSource() ?? null);
29
78
  };
30
79
  /**
31
- * Retrieves the bonded HTTP client. If none is bonded, automatically
32
- * creates a default fetch-based client.
80
+ * Retrieves the bonded HTTP client. If none is bonded, returns a module-level
81
+ * fetch-based fallback — it is NOT bonded.
33
82
  *
34
83
  * The fallback has NO `baseURL` — a core cannot know an app's API prefix. A relative
35
84
  * call then resolves against the page origin, where a dev server answers its own HTML
@@ -37,20 +86,24 @@ export const setClient = (client) => {
37
86
  * as a crash three components later; a scaffold bonds the shared client with its API
38
87
  * prefix, so the fallback only runs in an app that never bonded one.
39
88
  *
40
- * @returns The active HTTP client instance.
89
+ * Returning it WITHOUT bonding is what keeps a later `setClient()` authoritative: a
90
+ * caller that captured this fallback early does not make it the app's client, so the
91
+ * scaffold's client (and its token source) still takes effect for every later call.
92
+ *
93
+ * @returns The active HTTP client, or the unbonded fallback when none is bonded.
41
94
  */
42
95
  export const getClient = () => {
43
96
  const existing = bondGet(BOND_TYPE);
44
97
  if (existing)
45
98
  return existing;
46
- const fallback = createFetchClient();
47
- bond(BOND_TYPE, fallback);
99
+ if (!unbondedFallback)
100
+ unbondedFallback = createFetchClient();
48
101
  if (!warnedAboutFallback) {
49
102
  warnedAboutFallback = true;
50
103
  getLogger('http').warn('@molecule/app-http: no client is bonded — requests go to the page origin with no baseURL. ' +
51
104
  "Bond one: setClient(createFetchClient({ baseURL: '/api' })).");
52
105
  }
53
- return fallback;
106
+ return unbondedFallback;
54
107
  };
55
108
  /**
56
109
  * Makes a GET request using the bonded HTTP client.
@@ -1 +1 @@
1
- {"version":3,"file":"utilities.js","sourceRoot":"","sources":["../src/utilities.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,IAAI,EAAE,GAAG,IAAI,OAAO,EAAE,MAAM,oBAAoB,CAAA;AACzD,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAA;AAGhD,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAA;AAGjD,MAAM,SAAS,GAAG,aAAa,CAAA;AAE/B,kEAAkE;AAClE,IAAI,mBAAmB,GAAG,KAAK,CAAA;AAE/B;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,MAAkB,EAAQ,EAAE;IACpD,IAAI,CAAC,SAAS,EAAE,MAAM,CAAC,CAAA;AACzB,CAAC,CAAA;AAED;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,SAAS,GAAG,GAAe,EAAE;IACxC,MAAM,QAAQ,GAAG,OAAO,CAAa,SAAS,CAAC,CAAA;IAC/C,IAAI,QAAQ;QAAE,OAAO,QAAQ,CAAA;IAC7B,MAAM,QAAQ,GAAG,iBAAiB,EAAE,CAAA;IACpC,IAAI,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAA;IACzB,IAAI,CAAC,mBAAmB,EAAE,CAAC;QACzB,mBAAmB,GAAG,IAAI,CAAA;QAC1B,SAAS,CAAC,MAAM,CAAC,CAAC,IAAI,CACpB,4FAA4F;YAC1F,8DAA8D,CACjE,CAAA;IACH,CAAC;IACD,OAAO,QAAQ,CAAA;AACjB,CAAC,CAAA;AAED;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,GAAG,GAAG,CAAc,GAAW,EAAE,MAAsB,EAA4B,EAAE,CAChG,SAAS,EAAE,CAAC,GAAG,CAAI,GAAG,EAAE,MAAM,CAAC,CAAA;AAEjC;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,IAAI,GAAG,CAClB,GAAW,EACX,IAAc,EACd,MAAsB,EACI,EAAE,CAAC,SAAS,EAAE,CAAC,IAAI,CAAI,GAAG,EAAE,IAAI,EAAE,MAAM,CAAC,CAAA;AAErE;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,GAAG,GAAG,CACjB,GAAW,EACX,IAAc,EACd,MAAsB,EACI,EAAE,CAAC,SAAS,EAAE,CAAC,GAAG,CAAI,GAAG,EAAE,IAAI,EAAE,MAAM,CAAC,CAAA;AAEpE;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,KAAK,GAAG,CACnB,GAAW,EACX,IAAc,EACd,MAAsB,EACI,EAAE,CAAC,SAAS,EAAE,CAAC,KAAK,CAAI,GAAG,EAAE,IAAI,EAAE,MAAM,CAAC,CAAA;AAEtE;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,GAAG,GAAG,CAAc,GAAW,EAAE,MAAsB,EAA4B,EAAE,CAChG,SAAS,EAAE,CAAC,MAAM,CAAI,GAAG,EAAE,MAAM,CAAC,CAAA;AAEpC;;;GAGG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,OAAO,KAAK,KAAK,WAAW,CAAC,CAAC,CAAC,iBAAiB,EAAE,CAAC,CAAC,CAAC,IAAI,CAAA"}
1
+ {"version":3,"file":"utilities.js","sourceRoot":"","sources":["../src/utilities.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@molecule/app-http",
3
- "version": "1.1.6",
3
+ "version": "1.2.1",
4
4
  "description": "Client HTTP interface for molecule.dev",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",