@molecule/app-auth 1.3.1 → 1.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md 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-17T07:07:31.667Z
6
+ Generated: 2026-10-17T20:34:11.708Z
7
7
  -->
8
8
 
9
9
  # @molecule/app-auth
@@ -17,6 +17,43 @@ client; `setClient`/`getClient` bond it; `login`/`logout`/`register`/
17
17
  bindings (e.g. `AuthProvider`/`useAuth` in `@molecule/app-react`) wrap the
18
18
  same client.
19
19
 
20
+ **In a scaffolded app, wire it by hand — the sandbox cannot run `mlcl add`.**
21
+ The package is already installed; create the client once at startup with
22
+ `setClient(createJWTAuthClient({ baseURL, authScheme: 'Token', storage:
23
+ createBrowserStorageAdapter() }))`, or `createDefaultAuthClient(authConfig)`
24
+ from `@molecule/app-bonds-default-react` (which also registers
25
+ `whenRestored()` as the HTTP gate), call `initialize()`, and read the session
26
+ through `MoleculeProvider`/`useAuth()` in a React app.
27
+
28
+ **`initialize()` restores the session BEFORE the first render, and no
29
+ hand-rolled token store may replace it.** With the token AND user in the
30
+ store the restore is synchronous and costs no request; with an httpOnly
31
+ session cookie the API sets at login it restores through
32
+ `currentUserEndpoint` (default `/users/me`). `AuthClientConfig.storage` is
33
+ the config field that decides which route a reload takes. A store written
34
+ beside the client answers requests before its own restore settles: the first
35
+ authenticated page renders signed-out, and its 401 signs the user out for
36
+ good.
37
+
38
+ **Never fetch viewer-dependent data before the restore settles.** A
39
+ component effect that runs on mount fires while `initialize()` is still
40
+ restoring, so its request leaves without the `Authorization` header and the
41
+ server answers for an anonymous viewer — a followed user renders "Follow", a
42
+ saved item renders unsaved. On localhost the restore usually wins this race;
43
+ over the network it does not, so the bug appears only on the deployed URL.
44
+ Gate the fetch on the auth state being settled (`state.initialized`), or let
45
+ the HTTP client do it: `@molecule/app-bonds-default-react` registers
46
+ `whenRestored()` as the gate so every request waits for the restore.
47
+
48
+ **A store that registers its own gate must exempt the restore's own request.**
49
+ This client restores with `fetch`, so the gate registered over it never holds
50
+ the restore. A store that restores THROUGH the bonded HTTP client and
51
+ registers that restore as the gate (`setAuthGate(() => store.whenSettled())`)
52
+ waits on itself unless the restore's request passes `skipAuthGate: true` —
53
+ otherwise the gate holds the very request it is waiting for, and every
54
+ request it holds stalls until the gate times out. See
55
+ `RequestConfig.skipAuthGate` in `@molecule/app-http`.
56
+
20
57
  > **Auto-generated, AI-first package reference** for the [molecule.dev](https://molecule.dev) ecosystem.
21
58
  > It is written to be read by coding agents as much as by people, and is generated from this
22
59
  > package's source — edit `src/index.ts` JSDoc, not this file.
@@ -648,6 +685,13 @@ type AuthEventListener = (event: AuthEvent) => void
648
685
 
649
686
  The auth client's `StorageAdapter` over the browser's Web Storage.
650
687
 
688
+ **The restore it enables costs NO request — never block the first paint on one.** With the
689
+ token AND the user in the store, `initialize()` restores the authenticated state synchronously
690
+ (`whenRestored()` is already resolved on the first render); render from it, and validate the
691
+ token as a background request — never in front of the first render. A page that waits on its
692
+ own `/me` call pays a round trip on EVERY navigation (xr-molecule-flash-m122: a 1–5 s restore
693
+ window, eight `waitForURL` timeouts).
694
+
651
695
  Pass it as `AuthClientConfig.storage` to keep the session across a page reload:
652
696
  the client's default (`'memory'`) is lost on reload, and re-establishing the
653
697
  session then needs a credential that survived — this adapter, or an httpOnly
@@ -665,15 +709,15 @@ const authClient = createJWTAuthClient({
665
709
  The scaffold's `authConfig` already passes it, so a scaffolded app survives a
666
710
  reload out of the box; each of these replaces that default:
667
711
 
668
- ```ts
712
+ ````ts
669
713
  storage: 'memory' // memory only: pair it with an httpOnly cookie session
670
714
  storage: createBrowserStorageAdapter({ kind: 'session' }) // survives a reload, dies with the tab
671
- storage: { getItem: (k) => …, setItem: (k, v) => …, removeItem: (k) => … } // your own
672
- ```
715
+
716
+ *(description truncated — read the full text in `node_modules/@molecule/app-auth/dist/browser-storage.d.ts`.)*
673
717
 
674
718
  ```typescript
675
719
  function createBrowserStorageAdapter(options?: BrowserStorageAdapterOptions): StorageAdapter
676
- ```
720
+ ````
677
721
 
678
722
  - `options` — Which Web Storage area to use, or a store to use directly.
679
723
 
@@ -855,38 +899,10 @@ Peer dependencies:
855
899
  (`setClient(createJWTAuthClient({ authScheme: 'Token', … }))` in the auth bond), not
856
900
  properties of a client that already exists. Do not hand-write an auth client for a spec
857
901
  like RealWorld.
858
- - **Whether a reload keeps the user signed in is `AuthClientConfig.storage`,
859
- and one of the two routes must be wired.** The client's own default is
860
- `'memory'`, which is lost on reload, so a session survives one only by
861
- having a credential that survived: (1) `storage: createBrowserStorageAdapter()`
862
- — the browser's `localStorage`, what a scaffolded app's `authConfig` passes
863
- (see `@molecule/app-auth`'s `createBrowserStorageAdapter` for the trade: Web
864
- Storage is script-readable, so an XSS can steal the token), or (2) an
865
- httpOnly session cookie the API sets at login, which `initialize()` restores
866
- through `currentUserEndpoint` (default `/users/me`) — the stronger option
867
- wherever the API supports it, and what `@molecule/api-resource-user` issues.
868
- Wire `initialize()` once at startup either way. Do NOT hand-roll a token
869
- store beside the client for this: it is a config field.
870
902
  - **Endpoint defaults must match your API's real routes** (`/auth/login`,
871
903
  `/auth/register`, `/auth/refresh`, `/users/logout`, `/users/me`, …).
872
904
  Align them via `createJWTAuthClient({ baseURL, ...endpoints })` — never by
873
905
  hand-editing fetch calls in components.
874
- - **Do not fetch viewer-dependent data before the restore settles.** A component
875
- effect that runs on mount fires while `initialize()` is still restoring, so its
876
- request leaves without the `Authorization` header and the server answers for an
877
- anonymous viewer — a followed user renders "Follow", a saved item renders unsaved.
878
- On localhost the restore usually wins this race; over the network it does not, so
879
- the bug appears only on the deployed URL. Two ways out: gate the fetch on the auth
880
- state being settled (`state.initialized`), or let the HTTP client do it — bond the
881
- auth client through `@molecule/app-bonds-default-react`, which registers
882
- `whenRestored()` as the http gate so every request waits for the restore.
883
- - **Your own session store's gate must exempt its restore's own request.** This client
884
- restores with `fetch`, so the gate registered over it never holds the restore. A store
885
- that restores THROUGH the bonded HTTP client and registers that restore as the gate
886
- (`setAuthGate(() => store.whenSettled())`) waits on itself unless the restore's request
887
- passes `skipAuthGate: true` — otherwise the gate holds the very request it is waiting
888
- for, and every request it holds stalls until the gate times out. See
889
- `RequestConfig.skipAuthGate` in `@molecule/app-http`.
890
906
  - Client-side auth state is UX only — the server enforces authorization on
891
907
  every request; hiding a screen is not protection.
892
908
 
@@ -31,6 +31,13 @@ export interface BrowserStorageAdapterOptions {
31
31
  /**
32
32
  * The auth client's `StorageAdapter` over the browser's Web Storage.
33
33
  *
34
+ * **The restore it enables costs NO request — never block the first paint on one.** With the
35
+ * token AND the user in the store, `initialize()` restores the authenticated state synchronously
36
+ * (`whenRestored()` is already resolved on the first render); render from it, and validate the
37
+ * token as a background request — never in front of the first render. A page that waits on its
38
+ * own `/me` call pays a round trip on EVERY navigation (xr-molecule-flash-m122: a 1–5 s restore
39
+ * window, eight `waitForURL` timeouts).
40
+ *
34
41
  * Pass it as `AuthClientConfig.storage` to keep the session across a page reload:
35
42
  * the client's default (`'memory'`) is lost on reload, and re-establishing the
36
43
  * session then needs a credential that survived — this adapter, or an httpOnly
@@ -1 +1 @@
1
- {"version":3,"file":"browser-storage.d.ts","sourceRoot":"","sources":["../src/browser-storage.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAEhD;;;;GAIG;AACH,MAAM,MAAM,kBAAkB,GAAG,OAAO,GAAG,SAAS,CAAA;AAEpD,4EAA4E;AAC5E,MAAM,WAAW,4BAA4B;IAC3C;;;;;;OAMG;IACH,IAAI,CAAC,EAAE,kBAAkB,CAAA;IACzB;;;;;OAKG;IACH,OAAO,CAAC,EAAE,cAAc,CAAA;CACzB;AAeD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwDG;AACH,eAAO,MAAM,2BAA2B,GACtC,UAAS,4BAAiC,KACzC,cA6EF,CAAA"}
1
+ {"version":3,"file":"browser-storage.d.ts","sourceRoot":"","sources":["../src/browser-storage.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAEhD;;;;GAIG;AACH,MAAM,MAAM,kBAAkB,GAAG,OAAO,GAAG,SAAS,CAAA;AAEpD,4EAA4E;AAC5E,MAAM,WAAW,4BAA4B;IAC3C;;;;;;OAMG;IACH,IAAI,CAAC,EAAE,kBAAkB,CAAA;IACzB;;;;;OAKG;IACH,OAAO,CAAC,EAAE,cAAc,CAAA;CACzB;AAeD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+DG;AACH,eAAO,MAAM,2BAA2B,GACtC,UAAS,4BAAiC,KACzC,cA6EF,CAAA"}
@@ -22,6 +22,13 @@ const warn = (message, error) => {
22
22
  /**
23
23
  * The auth client's `StorageAdapter` over the browser's Web Storage.
24
24
  *
25
+ * **The restore it enables costs NO request — never block the first paint on one.** With the
26
+ * token AND the user in the store, `initialize()` restores the authenticated state synchronously
27
+ * (`whenRestored()` is already resolved on the first render); render from it, and validate the
28
+ * token as a background request — never in front of the first render. A page that waits on its
29
+ * own `/me` call pays a round trip on EVERY navigation (xr-molecule-flash-m122: a 1–5 s restore
30
+ * window, eight `waitForURL` timeouts).
31
+ *
25
32
  * Pass it as `AuthClientConfig.storage` to keep the session across a page reload:
26
33
  * the client's default (`'memory'`) is lost on reload, and re-establishing the
27
34
  * session then needs a credential that survived — this adapter, or an httpOnly
@@ -1 +1 @@
1
- {"version":3,"file":"browser-storage.js","sourceRoot":"","sources":["../src/browser-storage.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"browser-storage.js","sourceRoot":"","sources":["../src/browser-storage.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -8,6 +8,43 @@
8
8
  * bindings (e.g. `AuthProvider`/`useAuth` in `@molecule/app-react`) wrap the
9
9
  * same client.
10
10
  *
11
+ * **In a scaffolded app, wire it by hand — the sandbox cannot run `mlcl add`.**
12
+ * The package is already installed; create the client once at startup with
13
+ * `setClient(createJWTAuthClient({ baseURL, authScheme: 'Token', storage:
14
+ * createBrowserStorageAdapter() }))`, or `createDefaultAuthClient(authConfig)`
15
+ * from `@molecule/app-bonds-default-react` (which also registers
16
+ * `whenRestored()` as the HTTP gate), call `initialize()`, and read the session
17
+ * through `MoleculeProvider`/`useAuth()` in a React app.
18
+ *
19
+ * **`initialize()` restores the session BEFORE the first render, and no
20
+ * hand-rolled token store may replace it.** With the token AND user in the
21
+ * store the restore is synchronous and costs no request; with an httpOnly
22
+ * session cookie the API sets at login it restores through
23
+ * `currentUserEndpoint` (default `/users/me`). `AuthClientConfig.storage` is
24
+ * the config field that decides which route a reload takes. A store written
25
+ * beside the client answers requests before its own restore settles: the first
26
+ * authenticated page renders signed-out, and its 401 signs the user out for
27
+ * good.
28
+ *
29
+ * **Never fetch viewer-dependent data before the restore settles.** A
30
+ * component effect that runs on mount fires while `initialize()` is still
31
+ * restoring, so its request leaves without the `Authorization` header and the
32
+ * server answers for an anonymous viewer — a followed user renders "Follow", a
33
+ * saved item renders unsaved. On localhost the restore usually wins this race;
34
+ * over the network it does not, so the bug appears only on the deployed URL.
35
+ * Gate the fetch on the auth state being settled (`state.initialized`), or let
36
+ * the HTTP client do it: `@molecule/app-bonds-default-react` registers
37
+ * `whenRestored()` as the gate so every request waits for the restore.
38
+ *
39
+ * **A store that registers its own gate must exempt the restore's own request.**
40
+ * This client restores with `fetch`, so the gate registered over it never holds
41
+ * the restore. A store that restores THROUGH the bonded HTTP client and
42
+ * registers that restore as the gate (`setAuthGate(() => store.whenSettled())`)
43
+ * waits on itself unless the restore's request passes `skipAuthGate: true` —
44
+ * otherwise the gate holds the very request it is waiting for, and every
45
+ * request it holds stalls until the gate times out. See
46
+ * `RequestConfig.skipAuthGate` in `@molecule/app-http`.
47
+ *
11
48
  * @remarks
12
49
  * - **An API with its own auth envelope keeps this client.** `requestBody` wraps the
13
50
  * login/register payload (`(kind, p) => ({ user: p })`), `mapAuthResponse` reads the
@@ -17,38 +54,10 @@
17
54
  * (`setClient(createJWTAuthClient({ authScheme: 'Token', … }))` in the auth bond), not
18
55
  * properties of a client that already exists. Do not hand-write an auth client for a spec
19
56
  * like RealWorld.
20
- * - **Whether a reload keeps the user signed in is `AuthClientConfig.storage`,
21
- * and one of the two routes must be wired.** The client's own default is
22
- * `'memory'`, which is lost on reload, so a session survives one only by
23
- * having a credential that survived: (1) `storage: createBrowserStorageAdapter()`
24
- * — the browser's `localStorage`, what a scaffolded app's `authConfig` passes
25
- * (see `@molecule/app-auth`'s `createBrowserStorageAdapter` for the trade: Web
26
- * Storage is script-readable, so an XSS can steal the token), or (2) an
27
- * httpOnly session cookie the API sets at login, which `initialize()` restores
28
- * through `currentUserEndpoint` (default `/users/me`) — the stronger option
29
- * wherever the API supports it, and what `@molecule/api-resource-user` issues.
30
- * Wire `initialize()` once at startup either way. Do NOT hand-roll a token
31
- * store beside the client for this: it is a config field.
32
57
  * - **Endpoint defaults must match your API's real routes** (`/auth/login`,
33
58
  * `/auth/register`, `/auth/refresh`, `/users/logout`, `/users/me`, …).
34
59
  * Align them via `createJWTAuthClient({ baseURL, ...endpoints })` — never by
35
60
  * hand-editing fetch calls in components.
36
- * - **Do not fetch viewer-dependent data before the restore settles.** A component
37
- * effect that runs on mount fires while `initialize()` is still restoring, so its
38
- * request leaves without the `Authorization` header and the server answers for an
39
- * anonymous viewer — a followed user renders "Follow", a saved item renders unsaved.
40
- * On localhost the restore usually wins this race; over the network it does not, so
41
- * the bug appears only on the deployed URL. Two ways out: gate the fetch on the auth
42
- * state being settled (`state.initialized`), or let the HTTP client do it — bond the
43
- * auth client through `@molecule/app-bonds-default-react`, which registers
44
- * `whenRestored()` as the http gate so every request waits for the restore.
45
- * - **Your own session store's gate must exempt its restore's own request.** This client
46
- * restores with `fetch`, so the gate registered over it never holds the restore. A store
47
- * that restores THROUGH the bonded HTTP client and registers that restore as the gate
48
- * (`setAuthGate(() => store.whenSettled())`) waits on itself unless the restore's request
49
- * passes `skipAuthGate: true` — otherwise the gate holds the very request it is waiting
50
- * for, and every request it holds stalls until the gate times out. See
51
- * `RequestConfig.skipAuthGate` in `@molecule/app-http`.
52
61
  * - Client-side auth state is UX only — the server enforces authorization on
53
62
  * every request; hiding a screen is not protection.
54
63
  *
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmHG;AAEH,cAAc,sBAAsB,CAAA;AACpC,cAAc,aAAa,CAAA;AAC3B,cAAc,eAAe,CAAA;AAC7B,cAAc,YAAY,CAAA;AAC1B,cAAc,YAAY,CAAA;AAC1B,cAAc,gBAAgB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4HG;AAEH,cAAc,sBAAsB,CAAA;AACpC,cAAc,aAAa,CAAA;AAC3B,cAAc,eAAe,CAAA;AAC7B,cAAc,YAAY,CAAA;AAC1B,cAAc,YAAY,CAAA;AAC1B,cAAc,gBAAgB,CAAA"}
package/dist/index.js CHANGED
@@ -8,6 +8,43 @@
8
8
  * bindings (e.g. `AuthProvider`/`useAuth` in `@molecule/app-react`) wrap the
9
9
  * same client.
10
10
  *
11
+ * **In a scaffolded app, wire it by hand — the sandbox cannot run `mlcl add`.**
12
+ * The package is already installed; create the client once at startup with
13
+ * `setClient(createJWTAuthClient({ baseURL, authScheme: 'Token', storage:
14
+ * createBrowserStorageAdapter() }))`, or `createDefaultAuthClient(authConfig)`
15
+ * from `@molecule/app-bonds-default-react` (which also registers
16
+ * `whenRestored()` as the HTTP gate), call `initialize()`, and read the session
17
+ * through `MoleculeProvider`/`useAuth()` in a React app.
18
+ *
19
+ * **`initialize()` restores the session BEFORE the first render, and no
20
+ * hand-rolled token store may replace it.** With the token AND user in the
21
+ * store the restore is synchronous and costs no request; with an httpOnly
22
+ * session cookie the API sets at login it restores through
23
+ * `currentUserEndpoint` (default `/users/me`). `AuthClientConfig.storage` is
24
+ * the config field that decides which route a reload takes. A store written
25
+ * beside the client answers requests before its own restore settles: the first
26
+ * authenticated page renders signed-out, and its 401 signs the user out for
27
+ * good.
28
+ *
29
+ * **Never fetch viewer-dependent data before the restore settles.** A
30
+ * component effect that runs on mount fires while `initialize()` is still
31
+ * restoring, so its request leaves without the `Authorization` header and the
32
+ * server answers for an anonymous viewer — a followed user renders "Follow", a
33
+ * saved item renders unsaved. On localhost the restore usually wins this race;
34
+ * over the network it does not, so the bug appears only on the deployed URL.
35
+ * Gate the fetch on the auth state being settled (`state.initialized`), or let
36
+ * the HTTP client do it: `@molecule/app-bonds-default-react` registers
37
+ * `whenRestored()` as the gate so every request waits for the restore.
38
+ *
39
+ * **A store that registers its own gate must exempt the restore's own request.**
40
+ * This client restores with `fetch`, so the gate registered over it never holds
41
+ * the restore. A store that restores THROUGH the bonded HTTP client and
42
+ * registers that restore as the gate (`setAuthGate(() => store.whenSettled())`)
43
+ * waits on itself unless the restore's request passes `skipAuthGate: true` —
44
+ * otherwise the gate holds the very request it is waiting for, and every
45
+ * request it holds stalls until the gate times out. See
46
+ * `RequestConfig.skipAuthGate` in `@molecule/app-http`.
47
+ *
11
48
  * @remarks
12
49
  * - **An API with its own auth envelope keeps this client.** `requestBody` wraps the
13
50
  * login/register payload (`(kind, p) => ({ user: p })`), `mapAuthResponse` reads the
@@ -17,38 +54,10 @@
17
54
  * (`setClient(createJWTAuthClient({ authScheme: 'Token', … }))` in the auth bond), not
18
55
  * properties of a client that already exists. Do not hand-write an auth client for a spec
19
56
  * like RealWorld.
20
- * - **Whether a reload keeps the user signed in is `AuthClientConfig.storage`,
21
- * and one of the two routes must be wired.** The client's own default is
22
- * `'memory'`, which is lost on reload, so a session survives one only by
23
- * having a credential that survived: (1) `storage: createBrowserStorageAdapter()`
24
- * — the browser's `localStorage`, what a scaffolded app's `authConfig` passes
25
- * (see `@molecule/app-auth`'s `createBrowserStorageAdapter` for the trade: Web
26
- * Storage is script-readable, so an XSS can steal the token), or (2) an
27
- * httpOnly session cookie the API sets at login, which `initialize()` restores
28
- * through `currentUserEndpoint` (default `/users/me`) — the stronger option
29
- * wherever the API supports it, and what `@molecule/api-resource-user` issues.
30
- * Wire `initialize()` once at startup either way. Do NOT hand-roll a token
31
- * store beside the client for this: it is a config field.
32
57
  * - **Endpoint defaults must match your API's real routes** (`/auth/login`,
33
58
  * `/auth/register`, `/auth/refresh`, `/users/logout`, `/users/me`, …).
34
59
  * Align them via `createJWTAuthClient({ baseURL, ...endpoints })` — never by
35
60
  * hand-editing fetch calls in components.
36
- * - **Do not fetch viewer-dependent data before the restore settles.** A component
37
- * effect that runs on mount fires while `initialize()` is still restoring, so its
38
- * request leaves without the `Authorization` header and the server answers for an
39
- * anonymous viewer — a followed user renders "Follow", a saved item renders unsaved.
40
- * On localhost the restore usually wins this race; over the network it does not, so
41
- * the bug appears only on the deployed URL. Two ways out: gate the fetch on the auth
42
- * state being settled (`state.initialized`), or let the HTTP client do it — bond the
43
- * auth client through `@molecule/app-bonds-default-react`, which registers
44
- * `whenRestored()` as the http gate so every request waits for the restore.
45
- * - **Your own session store's gate must exempt its restore's own request.** This client
46
- * restores with `fetch`, so the gate registered over it never holds the restore. A store
47
- * that restores THROUGH the bonded HTTP client and registers that restore as the gate
48
- * (`setAuthGate(() => store.whenSettled())`) waits on itself unless the restore's request
49
- * passes `skipAuthGate: true` — otherwise the gate holds the very request it is waiting
50
- * for, and every request it holds stalls until the gate times out. See
51
- * `RequestConfig.skipAuthGate` in `@molecule/app-http`.
52
61
  * - Client-side auth state is UX only — the server enforces authorization on
53
62
  * every request; hiding a screen is not protection.
54
63
  *
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmHG;AAEH,cAAc,sBAAsB,CAAA;AACpC,cAAc,aAAa,CAAA;AAC3B,cAAc,eAAe,CAAA;AAC7B,cAAc,YAAY,CAAA;AAC1B,cAAc,YAAY,CAAA;AAC1B,cAAc,gBAAgB,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4HG;AAEH,cAAc,sBAAsB,CAAA;AACpC,cAAc,aAAa,CAAA;AAC3B,cAAc,eAAe,CAAA;AAC7B,cAAc,YAAY,CAAA;AAC1B,cAAc,YAAY,CAAA;AAC1B,cAAc,gBAAgB,CAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@molecule/app-auth",
3
- "version": "1.3.1",
3
+ "version": "1.3.2",
4
4
  "description": "Client-side authentication interface for molecule.dev",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",