@molecule/app-bonds-default-react 1.1.0 → 1.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +18 -7
- package/dist/auth.d.ts +20 -2
- package/dist/auth.d.ts.map +1 -1
- package/dist/auth.js +48 -4
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -3,15 +3,11 @@ 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-
|
|
6
|
+
Generated: 2026-10-16T23:54:35.164Z
|
|
7
7
|
-->
|
|
8
8
|
|
|
9
9
|
# @molecule/app-bonds-default-react
|
|
10
10
|
|
|
11
|
-
> **Auto-generated, AI-first package reference** for the [molecule.dev](https://molecule.dev) ecosystem.
|
|
12
|
-
> It is written to be read by coding agents as much as by people, and is generated from this
|
|
13
|
-
> package's source — edit `src/index.ts` JSDoc, not this file.
|
|
14
|
-
|
|
15
11
|
`@molecule/app-bonds-default-react` — default app-side bond wirings for the
|
|
16
12
|
React fleet stack, replacing the byte-identical per-app files:
|
|
17
13
|
|
|
@@ -39,6 +35,10 @@ React fleet stack, replacing the byte-identical per-app files:
|
|
|
39
35
|
`...WithFetchClient` variants also keep the bonded http client's bearer
|
|
40
36
|
token in sync with auth events.
|
|
41
37
|
|
|
38
|
+
> **Auto-generated, AI-first package reference** for the [molecule.dev](https://molecule.dev) ecosystem.
|
|
39
|
+
> It is written to be read by coding agents as much as by people, and is generated from this
|
|
40
|
+
> package's source — edit `src/index.ts` JSDoc, not this file.
|
|
41
|
+
|
|
42
42
|
## Quick Start
|
|
43
43
|
|
|
44
44
|
```tsx
|
|
@@ -105,7 +105,11 @@ stripping a leading `/api/` from request URLs.
|
|
|
105
105
|
Replaces ~20 per-app `bonds/http-default.ts` files that hand-roll
|
|
106
106
|
this same wiring. Pass `stripApiPrefix: true` when the app uses
|
|
107
107
|
`baseURL: '/api'` to handle pages that pass `/api/`-prefixed paths
|
|
108
|
-
(would otherwise resolve to `/api/api/...` and 404).
|
|
108
|
+
(would otherwise resolve to `/api/api/...` and 404). Pass `authScheme`
|
|
109
|
+
when the API reads another scheme than `Bearer`: it is an option of THIS
|
|
110
|
+
constructor (`createDefaultHttpClientWithAuthBearer({ authScheme: 'Token', … })`,
|
|
111
|
+
or `createFetchClient({ baseURL, authScheme: 'Token' })` directly), never a
|
|
112
|
+
property of the client it returns.
|
|
109
113
|
|
|
110
114
|
```typescript
|
|
111
115
|
function createDefaultHttpClientWithAuthBearer(opts: {
|
|
@@ -113,6 +117,7 @@ function createDefaultHttpClientWithAuthBearer(opts: {
|
|
|
113
117
|
withCredentials?: boolean
|
|
114
118
|
stripApiPrefix?: boolean
|
|
115
119
|
getToken: () => string | null | undefined
|
|
120
|
+
authScheme?: string
|
|
116
121
|
}): { httpClient: HttpClient; setupHttpDefault: () => void }
|
|
117
122
|
```
|
|
118
123
|
|
|
@@ -140,7 +145,9 @@ client must carry the JWT on every request — without this wiring,
|
|
|
140
145
|
authed endpoints return 401 after page reloads or token refresh.
|
|
141
146
|
|
|
142
147
|
Hydrates the HTTP client's token from the persisted auth state
|
|
143
|
-
on setup, then listens for auth events to keep them aligned
|
|
148
|
+
on setup, then listens for auth events to keep them aligned, and holds
|
|
149
|
+
requests until the session restore settles so a page effect that fetches
|
|
150
|
+
viewer-dependent data on mount cannot race it (see {@link registerAuthGate}).
|
|
144
151
|
|
|
145
152
|
```typescript
|
|
146
153
|
function createDefaultAuthClientWithHttpSync(authConfig: AuthClientConfig): {
|
|
@@ -159,6 +166,10 @@ its bearer token in sync with auth events.
|
|
|
159
166
|
Used by apps where molecule packages render pricing / billing /
|
|
160
167
|
other authed JSON-fetching screens that need both behaviors.
|
|
161
168
|
|
|
169
|
+
Requests are also held until the session restore settles (see
|
|
170
|
+
{@link registerAuthGate}), so a page that fetches viewer-dependent data on
|
|
171
|
+
mount cannot race it and answer for an anonymous viewer.
|
|
172
|
+
|
|
162
173
|
```typescript
|
|
163
174
|
function createDefaultAuthClientWithFetchClient(
|
|
164
175
|
authConfig: AuthClientConfig,
|
package/dist/auth.d.ts
CHANGED
|
@@ -26,13 +26,25 @@ export declare function createDefaultHttpClient(baseURL: string): {
|
|
|
26
26
|
* Replaces ~20 per-app `bonds/http-default.ts` files that hand-roll
|
|
27
27
|
* this same wiring. Pass `stripApiPrefix: true` when the app uses
|
|
28
28
|
* `baseURL: '/api'` to handle pages that pass `/api/`-prefixed paths
|
|
29
|
-
* (would otherwise resolve to `/api/api/...` and 404).
|
|
29
|
+
* (would otherwise resolve to `/api/api/...` and 404). Pass `authScheme`
|
|
30
|
+
* when the API reads another scheme than `Bearer`: it is an option of THIS
|
|
31
|
+
* constructor (`createDefaultHttpClientWithAuthBearer({ authScheme: 'Token', … })`,
|
|
32
|
+
* or `createFetchClient({ baseURL, authScheme: 'Token' })` directly), never a
|
|
33
|
+
* property of the client it returns.
|
|
30
34
|
*/
|
|
31
35
|
export declare function createDefaultHttpClientWithAuthBearer(opts: {
|
|
32
36
|
baseURL: string;
|
|
33
37
|
withCredentials?: boolean;
|
|
34
38
|
stripApiPrefix?: boolean;
|
|
35
39
|
getToken: () => string | null | undefined;
|
|
40
|
+
/**
|
|
41
|
+
* The scheme of the `Authorization` header the token from `getToken()` is sent
|
|
42
|
+
* with: `Bearer` (default), or what the API expects, e.g. `Token` for an API
|
|
43
|
+
* that reads `Authorization: Token <jwt>`. Pass it to this constructor — the
|
|
44
|
+
* same option `@molecule/app-http`'s client config calls `authScheme`, and not
|
|
45
|
+
* a property of the client that comes back.
|
|
46
|
+
*/
|
|
47
|
+
authScheme?: string;
|
|
36
48
|
}): {
|
|
37
49
|
httpClient: HttpClient;
|
|
38
50
|
setupHttpDefault: () => void;
|
|
@@ -66,7 +78,9 @@ export declare function createDefaultAuthClient<TUser extends UserProfile = User
|
|
|
66
78
|
* authed endpoints return 401 after page reloads or token refresh.
|
|
67
79
|
*
|
|
68
80
|
* Hydrates the HTTP client's token from the persisted auth state
|
|
69
|
-
* on setup, then listens for auth events to keep them aligned
|
|
81
|
+
* on setup, then listens for auth events to keep them aligned, and holds
|
|
82
|
+
* requests until the session restore settles so a page effect that fetches
|
|
83
|
+
* viewer-dependent data on mount cannot race it (see {@link registerAuthGate}).
|
|
70
84
|
*/
|
|
71
85
|
export declare function createDefaultAuthClientWithHttpSync<TUser extends UserProfile = UserProfile>(authConfig: AuthClientConfig): {
|
|
72
86
|
authClient: AuthClient<TUser>;
|
|
@@ -80,6 +94,10 @@ export declare function createDefaultAuthClientWithHttpSync<TUser extends UserPr
|
|
|
80
94
|
*
|
|
81
95
|
* Used by apps where molecule packages render pricing / billing /
|
|
82
96
|
* other authed JSON-fetching screens that need both behaviors.
|
|
97
|
+
*
|
|
98
|
+
* Requests are also held until the session restore settles (see
|
|
99
|
+
* {@link registerAuthGate}), so a page that fetches viewer-dependent data on
|
|
100
|
+
* mount cannot race it and answer for an anonymous viewer.
|
|
83
101
|
*/
|
|
84
102
|
export declare function createDefaultAuthClientWithFetchClient<TUser extends UserProfile = UserProfile>(authConfig: AuthClientConfig, fetchClientOptions: {
|
|
85
103
|
baseURL: string;
|
package/dist/auth.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAEnF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAA;
|
|
1
|
+
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAEnF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAA;AAsCpD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,MAAM,GAAG;IACxD,UAAU,EAAE,UAAU,CAAA;IACtB,gBAAgB,EAAE,MAAM,IAAI,CAAA;CAC7B,CAMA;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,qCAAqC,CAAC,IAAI,EAAE;IAC1D,OAAO,EAAE,MAAM,CAAA;IACf,eAAe,CAAC,EAAE,OAAO,CAAA;IACzB,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB,QAAQ,EAAE,MAAM,MAAM,GAAG,IAAI,GAAG,SAAS,CAAA;IACzC;;;;;;OAMG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB,GAAG;IACF,UAAU,EAAE,UAAU,CAAA;IACtB,gBAAgB,EAAE,MAAM,IAAI,CAAA;CAC7B,CAoBA;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,SAAS,WAAW,GAAG,WAAW,EAC7E,UAAU,EAAE,gBAAgB,GAC3B;IACD,UAAU,EAAE,UAAU,CAAC,KAAK,CAAC,CAAA;IAC7B,gBAAgB,EAAE,MAAM,IAAI,CAAA;CAC7B,CAMA;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,mCAAmC,CAAC,KAAK,SAAS,WAAW,GAAG,WAAW,EACzF,UAAU,EAAE,gBAAgB,GAC3B;IACD,UAAU,EAAE,UAAU,CAAC,KAAK,CAAC,CAAA;IAC7B,gBAAgB,EAAE,MAAM,IAAI,CAAA;CAC7B,CA2BA;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,sCAAsC,CAAC,KAAK,SAAS,WAAW,GAAG,WAAW,EAC5F,UAAU,EAAE,gBAAgB,EAC5B,kBAAkB,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,eAAe,CAAC,EAAE,OAAO,CAAA;CAAE,GACjE;IACD,UAAU,EAAE,UAAU,CAAC,KAAK,CAAC,CAAA;IAC7B,gBAAgB,EAAE,MAAM,IAAI,CAAA;CAC7B,CA2BA"}
|
package/dist/auth.js
CHANGED
|
@@ -1,5 +1,34 @@
|
|
|
1
1
|
import { createJWTAuthClient, setClient } from '@molecule/app-auth';
|
|
2
|
-
import { createFetchClient, getClient as getHttpClient, setClient as setHttpClient, } from '@molecule/app-http';
|
|
2
|
+
import { createFetchClient, getClient as getHttpClient, setAuthGate, setClient as setHttpClient, } from '@molecule/app-http';
|
|
3
|
+
/**
|
|
4
|
+
* Holds every HTTP request until this auth client's session restore has settled.
|
|
5
|
+
*
|
|
6
|
+
* Without it a page effect that fires on mount (fetching a profile's `following`
|
|
7
|
+
* flag, a feed, a `favorited` state) sends its request before `initialize()` has
|
|
8
|
+
* restored the session, so it leaves with no `Authorization` header and the server
|
|
9
|
+
* answers for an anonymous viewer. Localhost usually hides it — the restore wins
|
|
10
|
+
* the race against the first effect there — and the deployed URL exposes it, which
|
|
11
|
+
* is how X1 xr-molecule-flash-m95 spent ~25 min treating a "Follow" button on a
|
|
12
|
+
* followed user as database leftovers.
|
|
13
|
+
*
|
|
14
|
+
* `whenRestored()` resolves immediately when no restore is in flight, so a request
|
|
15
|
+
* made after boot never waits at all; it holds only while the restore is actually
|
|
16
|
+
* running. A provider without `whenRestored` (a bond that restores nothing) leaves
|
|
17
|
+
* requests ungated.
|
|
18
|
+
*
|
|
19
|
+
* The restore this gate waits for does NOT go through the gated client — both default auth
|
|
20
|
+
* bonds' `createJWTAuthClient` restores with `fetch` — so the scaffold's own wiring cannot
|
|
21
|
+
* deadlock. An app that registers its own gate over a restore made through the bonded client
|
|
22
|
+
* must exempt that request with `skipAuthGate: true`
|
|
23
|
+
* (`setAuthGate(() => store.whenSettled())` + `http.get(currentUserEndpoint, { skipAuthGate: true })`
|
|
24
|
+
* in the store); otherwise the gate holds the request it is waiting for and every request it
|
|
25
|
+
* holds stalls until the gate times out. See `RequestConfig.skipAuthGate` in `@molecule/app-http`.
|
|
26
|
+
*
|
|
27
|
+
* @param authClient - The bonded auth client.
|
|
28
|
+
*/
|
|
29
|
+
function registerAuthGate(authClient) {
|
|
30
|
+
setAuthGate(() => authClient.whenRestored?.() ?? Promise.resolve());
|
|
31
|
+
}
|
|
3
32
|
/**
|
|
4
33
|
* Builds the default fetch-based HTTP client + wires it into
|
|
5
34
|
* `@molecule/app-http`. Replaces the per-app `bonds/http-default.ts`
|
|
@@ -29,9 +58,14 @@ export function createDefaultHttpClient(baseURL) {
|
|
|
29
58
|
* Replaces ~20 per-app `bonds/http-default.ts` files that hand-roll
|
|
30
59
|
* this same wiring. Pass `stripApiPrefix: true` when the app uses
|
|
31
60
|
* `baseURL: '/api'` to handle pages that pass `/api/`-prefixed paths
|
|
32
|
-
* (would otherwise resolve to `/api/api/...` and 404).
|
|
61
|
+
* (would otherwise resolve to `/api/api/...` and 404). Pass `authScheme`
|
|
62
|
+
* when the API reads another scheme than `Bearer`: it is an option of THIS
|
|
63
|
+
* constructor (`createDefaultHttpClientWithAuthBearer({ authScheme: 'Token', … })`,
|
|
64
|
+
* or `createFetchClient({ baseURL, authScheme: 'Token' })` directly), never a
|
|
65
|
+
* property of the client it returns.
|
|
33
66
|
*/
|
|
34
67
|
export function createDefaultHttpClientWithAuthBearer(opts) {
|
|
68
|
+
const authScheme = opts.authScheme ?? 'Bearer';
|
|
35
69
|
const httpClient = createFetchClient({
|
|
36
70
|
baseURL: opts.baseURL,
|
|
37
71
|
withCredentials: opts.withCredentials,
|
|
@@ -42,7 +76,7 @@ export function createDefaultHttpClientWithAuthBearer(opts) {
|
|
|
42
76
|
}
|
|
43
77
|
const token = opts.getToken();
|
|
44
78
|
if (token) {
|
|
45
|
-
config.headers = { ...config.headers, Authorization:
|
|
79
|
+
config.headers = { ...config.headers, Authorization: `${authScheme} ${token}` };
|
|
46
80
|
}
|
|
47
81
|
return config;
|
|
48
82
|
});
|
|
@@ -83,7 +117,9 @@ export function createDefaultAuthClient(authConfig) {
|
|
|
83
117
|
* authed endpoints return 401 after page reloads or token refresh.
|
|
84
118
|
*
|
|
85
119
|
* Hydrates the HTTP client's token from the persisted auth state
|
|
86
|
-
* on setup, then listens for auth events to keep them aligned
|
|
120
|
+
* on setup, then listens for auth events to keep them aligned, and holds
|
|
121
|
+
* requests until the session restore settles so a page effect that fetches
|
|
122
|
+
* viewer-dependent data on mount cannot race it (see {@link registerAuthGate}).
|
|
87
123
|
*/
|
|
88
124
|
export function createDefaultAuthClientWithHttpSync(authConfig) {
|
|
89
125
|
const authClient = createJWTAuthClient(authConfig);
|
|
@@ -91,6 +127,9 @@ export function createDefaultAuthClientWithHttpSync(authConfig) {
|
|
|
91
127
|
authClient,
|
|
92
128
|
setupAuthDefault: () => {
|
|
93
129
|
setClient(authClient);
|
|
130
|
+
// Requests made while the session is still restoring wait for it, so a page
|
|
131
|
+
// effect that fetches viewer-dependent data on mount cannot race the restore.
|
|
132
|
+
registerAuthGate(authClient);
|
|
94
133
|
const initialToken = authClient.getAccessToken();
|
|
95
134
|
if (initialToken) {
|
|
96
135
|
getHttpClient().setAuthToken(initialToken);
|
|
@@ -119,6 +158,10 @@ export function createDefaultAuthClientWithHttpSync(authConfig) {
|
|
|
119
158
|
*
|
|
120
159
|
* Used by apps where molecule packages render pricing / billing /
|
|
121
160
|
* other authed JSON-fetching screens that need both behaviors.
|
|
161
|
+
*
|
|
162
|
+
* Requests are also held until the session restore settles (see
|
|
163
|
+
* {@link registerAuthGate}), so a page that fetches viewer-dependent data on
|
|
164
|
+
* mount cannot race it and answer for an anonymous viewer.
|
|
122
165
|
*/
|
|
123
166
|
export function createDefaultAuthClientWithFetchClient(authConfig, fetchClientOptions) {
|
|
124
167
|
const authClient = createJWTAuthClient(authConfig);
|
|
@@ -131,6 +174,7 @@ export function createDefaultAuthClientWithFetchClient(authConfig, fetchClientOp
|
|
|
131
174
|
});
|
|
132
175
|
setHttpClient(httpClient);
|
|
133
176
|
setClient(authClient);
|
|
177
|
+
registerAuthGate(authClient);
|
|
134
178
|
const initialToken = authClient.getAccessToken();
|
|
135
179
|
if (initialToken) {
|
|
136
180
|
httpClient.setAuthToken(initialToken);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@molecule/app-bonds-default-react",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.2",
|
|
4
4
|
"description": "Default app-side bond wirings for React+Tailwind+react-router+localStorage+Arimo font+molecule icons. 5 setup functions consolidating 665 byte-identical per-app bond wiring files across the fleet.",
|
|
5
5
|
"homepage": "https://www.molecule.dev/packages/app-bonds-default-react",
|
|
6
6
|
"type": "module",
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
"directory": "packages/app/infrastructure/bonds-default-react"
|
|
39
39
|
},
|
|
40
40
|
"devDependencies": {
|
|
41
|
-
"@molecule/app-auth": "1.
|
|
41
|
+
"@molecule/app-auth": "1.3.0",
|
|
42
42
|
"@molecule/app-charts-chartjs": "1.0.2",
|
|
43
43
|
"@molecule/app-client-search": "1.0.2",
|
|
44
44
|
"@molecule/app-client-search-minisearch": "1.0.3",
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
"@molecule/app-drag-drop-dndkit": "1.0.2",
|
|
51
51
|
"@molecule/app-fonts": "1.1.0",
|
|
52
52
|
"@molecule/app-fonts-arimo": "1.0.2",
|
|
53
|
-
"@molecule/app-http": "1.1.
|
|
53
|
+
"@molecule/app-http": "1.1.3",
|
|
54
54
|
"@molecule/app-icons": "1.0.2",
|
|
55
55
|
"@molecule/app-icons-molecule": "1.0.2",
|
|
56
56
|
"@molecule/app-keyboard-shortcuts": "1.0.2",
|