@molecule/app-http 1.1.5 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md 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-17T19:12:43.116Z
6
+ Generated: 2026-10-18T09:50:54.298Z
7
7
  -->
8
8
 
9
9
  # @molecule/app-http
@@ -525,10 +525,30 @@ function unwrapSingle(res: unknown): T | null
525
525
 
526
526
  **Returns:** The typed resource `T`, or `null` when the response shape indicates "no resource" (including the various empty envelopes above).
527
527
 
528
+ #### `setAuthTokenSource(source)`
529
+
530
+ Registers the token source a newly bonded client is hydrated from, or clears
531
+ it with `null`.
532
+
533
+ The source is read once per bond: the client bonded AFTER this call (and the
534
+ one bonded now, if any) receives `source()` through `setAuthToken`. That is
535
+ what carries a restored session's token into a client the auth setup ran
536
+ before — the setup does not need to hold a client reference at all.
537
+
538
+ ```typescript
539
+ function setAuthTokenSource(source: (() => string | null | undefined) | null): void
540
+ ```
541
+
542
+ - `source` — Returns the current access token (null when signed out), or `null` to clear.
543
+
528
544
  #### `setClient(client)`
529
545
 
530
546
  Registers an HTTP client as the active singleton.
531
547
 
548
+ A registered `setAuthTokenSource` token source is applied to the client
549
+ here, so a client bonded after the auth setup still carries the restored
550
+ session's token.
551
+
532
552
  ```typescript
533
553
  function setClient(client: HttpClient): void
534
554
  ```
@@ -537,8 +557,8 @@ function setClient(client: HttpClient): void
537
557
 
538
558
  #### `getClient()`
539
559
 
540
- Retrieves the bonded HTTP client. If none is bonded, automatically
541
- creates a default fetch-based client.
560
+ Retrieves the bonded HTTP client. If none is bonded, returns a module-level
561
+ fetch-based fallback — it is NOT bonded.
542
562
 
543
563
  The fallback has NO `baseURL` — a core cannot know an app's API prefix. A relative
544
564
  call then resolves against the page origin, where a dev server answers its own HTML
@@ -546,11 +566,15 @@ shell with a 200. It warns once so the misconfiguration is named instead of show
546
566
  as a crash three components later; a scaffold bonds the shared client with its API
547
567
  prefix, so the fallback only runs in an app that never bonded one.
548
568
 
569
+ Returning it WITHOUT bonding is what keeps a later `setClient()` authoritative: a
570
+ caller that captured this fallback early does not make it the app's client, so the
571
+ scaffold's client (and its token source) still takes effect for every later call.
572
+
549
573
  ```typescript
550
574
  function getClient(): HttpClient
551
575
  ```
552
576
 
553
- **Returns:** The active HTTP client instance.
577
+ **Returns:** The active HTTP client, or the unbonded fallback when none is bonded.
554
578
 
555
579
  #### `get(url, config)`
556
580
 
@@ -696,6 +720,11 @@ that fetches viewer-dependent data on mount (a profile's `following` flag, a fee
696
720
  bond registers that wait with `setAuthGate`; apps that bond auth through
697
721
  `@molecule/app-bonds-default-react` get it without doing anything. An app with its own session
698
722
  module registers its own: `setAuthGate(() => session.whenRestored())`.
723
+ Waiting for the restore does NOT attach the token: a client created beside the auth bond needs
724
+ `createDefaultHttpClientWithAuthBearer({ baseURL, getToken: () => authClient.getAccessToken(),
725
+ authScheme })` from `@molecule/app-bonds-default-react` (or an auth client built with
726
+ `createDefaultAuthClientWithHttpSync`, which mirrors the token into the bonded client), because
727
+ `setAuthGate` alone sends no `Authorization` header.
699
728
 
700
729
  **A request the gate itself depends on must opt out of it: pass `skipAuthGate: true`.** A gate
701
730
  that waits for a session restore whose own request goes through this client waits on itself —
@@ -15,6 +15,13 @@
15
15
  * `@molecule/app-bonds-default-react`'s auth helpers register the gate for
16
16
  * apps that bond auth, so an app does not have to get it right itself.
17
17
  *
18
+ * Waiting for the restore does NOT attach its token: a separately created HTTP
19
+ * client needs `createDefaultHttpClientWithAuthBearer({ baseURL,
20
+ * getToken: () => authClient.getAccessToken(), authScheme })` from
21
+ * `@molecule/app-bonds-default-react` (or the auth client built with
22
+ * `createDefaultAuthClientWithHttpSync`, which mirrors the token into the
23
+ * bonded client) plus `setAuthGate(() => authClient.whenRestored())`.
24
+ *
18
25
  * The gate is module-level, not per client, on purpose: the client an app ends
19
26
  * up using is often created AFTER the auth bond ran (`setupAuthDefault()` then
20
27
  * `setupHttpDefault()`), and a gate installed on the throwaway client the auth
@@ -1 +1 @@
1
- {"version":3,"file":"auth-gate.d.ts","sourceRoot":"","sources":["../src/auth-gate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0CG;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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;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"}
package/dist/auth-gate.js CHANGED
@@ -15,6 +15,13 @@
15
15
  * `@molecule/app-bonds-default-react`'s auth helpers register the gate for
16
16
  * apps that bond auth, so an app does not have to get it right itself.
17
17
  *
18
+ * Waiting for the restore does NOT attach its token: a separately created HTTP
19
+ * client needs `createDefaultHttpClientWithAuthBearer({ baseURL,
20
+ * getToken: () => authClient.getAccessToken(), authScheme })` from
21
+ * `@molecule/app-bonds-default-react` (or the auth client built with
22
+ * `createDefaultAuthClientWithHttpSync`, which mirrors the token into the
23
+ * bonded client) plus `setAuthGate(() => authClient.whenRestored())`.
24
+ *
18
25
  * The gate is module-level, not per client, on purpose: the client an app ends
19
26
  * up using is often created AFTER the auth bond ran (`setupAuthDefault()` then
20
27
  * `setupHttpDefault()`), and a gate installed on the throwaway client the auth
@@ -1 +1 @@
1
- {"version":3,"file":"auth-gate.js","sourceRoot":"","sources":["../src/auth-gate.ts"],"names":[],"mappings":"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"}
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
@@ -72,6 +72,11 @@
72
72
  * bond registers that wait with `setAuthGate`; apps that bond auth through
73
73
  * `@molecule/app-bonds-default-react` get it without doing anything. An app with its own session
74
74
  * module registers its own: `setAuthGate(() => session.whenRestored())`.
75
+ * Waiting for the restore does NOT attach the token: a client created beside the auth bond needs
76
+ * `createDefaultHttpClientWithAuthBearer({ baseURL, getToken: () => authClient.getAccessToken(),
77
+ * authScheme })` from `@molecule/app-bonds-default-react` (or an auth client built with
78
+ * `createDefaultAuthClientWithHttpSync`, which mirrors the token into the bonded client), because
79
+ * `setAuthGate` alone sends no `Authorization` header.
75
80
  *
76
81
  * **A request the gate itself depends on must opt out of it: pass `skipAuthGate: true`.** A gate
77
82
  * that waits for a session restore whose own request goes through this client waits on itself —
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoFG;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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;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"}
package/dist/index.js CHANGED
@@ -72,6 +72,11 @@
72
72
  * bond registers that wait with `setAuthGate`; apps that bond auth through
73
73
  * `@molecule/app-bonds-default-react` get it without doing anything. An app with its own session
74
74
  * module registers its own: `setAuthGate(() => session.whenRestored())`.
75
+ * Waiting for the restore does NOT attach the token: a client created beside the auth bond needs
76
+ * `createDefaultHttpClientWithAuthBearer({ baseURL, getToken: () => authClient.getAccessToken(),
77
+ * authScheme })` from `@molecule/app-bonds-default-react` (or an auth client built with
78
+ * `createDefaultAuthClientWithHttpSync`, which mirrors the token into the bonded client), because
79
+ * `setAuthGate` alone sends no `Authorization` header.
75
80
  *
76
81
  * **A request the gate itself depends on must opt out of it: pass `skipAuthGate: true`.** A gate
77
82
  * that waits for a session restore whose own request goes through this client waits on itself —
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoFG;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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;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,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.5",
3
+ "version": "1.2.0",
4
4
  "description": "Client HTTP interface for molecule.dev",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -33,7 +33,7 @@
33
33
  "@molecule/app-logger": "^1.0.1"
34
34
  },
35
35
  "devDependencies": {
36
- "@molecule/app-bond": "1.0.2",
36
+ "@molecule/app-bond": "1.0.3",
37
37
  "@molecule/app-i18n": "1.0.3",
38
38
  "@molecule/app-logger": "1.0.2",
39
39
  "@types/node": "26.1.2",