@molecule/app-bonds-default-react 1.1.2 → 1.1.4

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-16T23:54:35.164Z
6
+ Generated: 2026-10-19T21:59:14.074Z
7
7
  -->
8
8
 
9
9
  # @molecule/app-bonds-default-react
@@ -130,8 +130,8 @@ apps shipped byte-identically. Apps pass their own `authConfig`
130
130
  (which lives in `src/config.ts`).
131
131
 
132
132
  ```typescript
133
- function createDefaultAuthClient(authConfig: AuthClientConfig): {
134
- authClient: AuthClient<TUser>
133
+ function createDefaultAuthClient(authConfig: AuthClientConfig<TUser>): {
134
+ authClient: AuthClient<TUser, TRegister>
135
135
  setupAuthDefault: () => void
136
136
  }
137
137
  ```
@@ -149,9 +149,16 @@ on setup, then listens for auth events to keep them aligned, and holds
149
149
  requests until the session restore settles so a page effect that fetches
150
150
  viewer-dependent data on mount cannot race it (see {@link registerAuthGate}).
151
151
 
152
+ The hydrated token is delivered through `@molecule/app-http`'s token source, not
153
+ through a client read at setup: the scaffold wires auth BEFORE http, so a client
154
+ read here is the unbonded fallback and the restored session's token would land on a
155
+ client nothing sends through (xr-molecule-flash-m156 — a reload sent every request
156
+ with no `Authorization` header). The source is applied to the client WHENEVER it is
157
+ bonded, so setup order no longer decides whether the first request is authorized.
158
+
152
159
  ```typescript
153
- function createDefaultAuthClientWithHttpSync(authConfig: AuthClientConfig): {
154
- authClient: AuthClient<TUser>
160
+ function createDefaultAuthClientWithHttpSync(authConfig: AuthClientConfig<TUser>): {
161
+ authClient: AuthClient<TUser, TRegister>
155
162
  setupAuthDefault: () => void
156
163
  }
157
164
  ```
@@ -163,6 +170,14 @@ given `baseURL` (so molecule pkg `useGet('/path')` calls hit
163
170
  `${baseURL}/path` instead of the SPA's catch-all route), AND keeps
164
171
  its bearer token in sync with auth events.
165
172
 
173
+ The auth client restores a stored token AND user SYNCHRONOUSLY, so the first
174
+ render is the signed-in UI — do not gate a protected page (or a provider of
175
+ yours) on a current-user request. This bond registers `whenRestored()` as the
176
+ HTTP gate, so requests still wait for the background restore/verification to
177
+ settle; only `useAuth().status === 'loading'` means "no decision yet"
178
+ (xr-molecule-flash-m177: a page that waited on its own `/me` paid a round trip
179
+ on every navigation).
180
+
166
181
  Used by apps where molecule packages render pricing / billing /
167
182
  other authed JSON-fetching screens that need both behaviors.
168
183
 
@@ -172,9 +187,9 @@ mount cannot race it and answer for an anonymous viewer.
172
187
 
173
188
  ```typescript
174
189
  function createDefaultAuthClientWithFetchClient(
175
- authConfig: AuthClientConfig,
190
+ authConfig: AuthClientConfig<TUser>,
176
191
  fetchClientOptions: { baseURL: string; withCredentials?: boolean },
177
- ): { authClient: AuthClient<TUser>; setupAuthDefault: () => void }
192
+ ): { authClient: AuthClient<TUser, TRegister>; setupAuthDefault: () => void }
178
193
  ```
179
194
 
180
195
  #### `bootstrapApp(opts)`
package/dist/auth.d.ts CHANGED
@@ -65,9 +65,19 @@ export declare function createDefaultHttpClientWithAuthBearer(opts: {
65
65
  * export const { authClient, setupAuthDefault } =
66
66
  * createDefaultAuthClient(authConfig)
67
67
  * ```
68
+ *
69
+ * `TRegister` is the app's own registration fields (`{ username: string }` for a
70
+ * RealWorld-shaped API), passed on to `@molecule/app-auth`'s factory so
71
+ * `authClient.register({ username, email, password })` type-checks with no cast.
72
+ *
73
+ * `TUser` is the profile the app's pages read. Type the config with the SAME
74
+ * type (`const authConfig: AuthClientConfig<MyUser> = { … }`) so its
75
+ * `mapAuthResponse` is checked against `MyUser`: a mapper that omits a required
76
+ * custom field then fails at the `createDefaultAuthClient<MyUser>(authConfig)`
77
+ * call instead of shipping a signed-in page that reads `undefined`.
68
78
  */
69
- export declare function createDefaultAuthClient<TUser extends UserProfile = UserProfile>(authConfig: AuthClientConfig): {
70
- authClient: AuthClient<TUser>;
79
+ export declare function createDefaultAuthClient<TUser extends UserProfile = UserProfile, TRegister extends Record<string, unknown> = Record<never, never>>(authConfig: AuthClientConfig<TUser>): {
80
+ authClient: AuthClient<TUser, TRegister>;
71
81
  setupAuthDefault: () => void;
72
82
  };
73
83
  /**
@@ -81,9 +91,16 @@ export declare function createDefaultAuthClient<TUser extends UserProfile = User
81
91
  * on setup, then listens for auth events to keep them aligned, and holds
82
92
  * requests until the session restore settles so a page effect that fetches
83
93
  * viewer-dependent data on mount cannot race it (see {@link registerAuthGate}).
94
+ *
95
+ * The hydrated token is delivered through `@molecule/app-http`'s token source, not
96
+ * through a client read at setup: the scaffold wires auth BEFORE http, so a client
97
+ * read here is the unbonded fallback and the restored session's token would land on a
98
+ * client nothing sends through (xr-molecule-flash-m156 — a reload sent every request
99
+ * with no `Authorization` header). The source is applied to the client WHENEVER it is
100
+ * bonded, so setup order no longer decides whether the first request is authorized.
84
101
  */
85
- export declare function createDefaultAuthClientWithHttpSync<TUser extends UserProfile = UserProfile>(authConfig: AuthClientConfig): {
86
- authClient: AuthClient<TUser>;
102
+ export declare function createDefaultAuthClientWithHttpSync<TUser extends UserProfile = UserProfile, TRegister extends Record<string, unknown> = Record<never, never>>(authConfig: AuthClientConfig<TUser>): {
103
+ authClient: AuthClient<TUser, TRegister>;
87
104
  setupAuthDefault: () => void;
88
105
  };
89
106
  /**
@@ -92,6 +109,14 @@ export declare function createDefaultAuthClientWithHttpSync<TUser extends UserPr
92
109
  * `${baseURL}/path` instead of the SPA's catch-all route), AND keeps
93
110
  * its bearer token in sync with auth events.
94
111
  *
112
+ * The auth client restores a stored token AND user SYNCHRONOUSLY, so the first
113
+ * render is the signed-in UI — do not gate a protected page (or a provider of
114
+ * yours) on a current-user request. This bond registers `whenRestored()` as the
115
+ * HTTP gate, so requests still wait for the background restore/verification to
116
+ * settle; only `useAuth().status === 'loading'` means "no decision yet"
117
+ * (xr-molecule-flash-m177: a page that waited on its own `/me` paid a round trip
118
+ * on every navigation).
119
+ *
95
120
  * Used by apps where molecule packages render pricing / billing /
96
121
  * other authed JSON-fetching screens that need both behaviors.
97
122
  *
@@ -99,11 +124,11 @@ export declare function createDefaultAuthClientWithHttpSync<TUser extends UserPr
99
124
  * {@link registerAuthGate}), so a page that fetches viewer-dependent data on
100
125
  * mount cannot race it and answer for an anonymous viewer.
101
126
  */
102
- export declare function createDefaultAuthClientWithFetchClient<TUser extends UserProfile = UserProfile>(authConfig: AuthClientConfig, fetchClientOptions: {
127
+ export declare function createDefaultAuthClientWithFetchClient<TUser extends UserProfile = UserProfile, TRegister extends Record<string, unknown> = Record<never, never>>(authConfig: AuthClientConfig<TUser>, fetchClientOptions: {
103
128
  baseURL: string;
104
129
  withCredentials?: boolean;
105
130
  }): {
106
- authClient: AuthClient<TUser>;
131
+ authClient: AuthClient<TUser, TRegister>;
107
132
  setupAuthDefault: () => void;
108
133
  };
109
134
  //# sourceMappingURL=auth.d.ts.map
@@ -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;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"}
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;AAuCpD;;;;;;;;;;;;;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;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,uBAAuB,CACrC,KAAK,SAAS,WAAW,GAAG,WAAW,EACvC,SAAS,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,EAEhE,UAAU,EAAE,gBAAgB,CAAC,KAAK,CAAC,GAClC;IACD,UAAU,EAAE,UAAU,CAAC,KAAK,EAAE,SAAS,CAAC,CAAA;IACxC,gBAAgB,EAAE,MAAM,IAAI,CAAA;CAC7B,CAMA;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,mCAAmC,CACjD,KAAK,SAAS,WAAW,GAAG,WAAW,EACvC,SAAS,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,EAEhE,UAAU,EAAE,gBAAgB,CAAC,KAAK,CAAC,GAClC;IACD,UAAU,EAAE,UAAU,CAAC,KAAK,EAAE,SAAS,CAAC,CAAA;IACxC,gBAAgB,EAAE,MAAM,IAAI,CAAA;CAC7B,CA4BA;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,sCAAsC,CACpD,KAAK,SAAS,WAAW,GAAG,WAAW,EACvC,SAAS,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,EAEhE,UAAU,EAAE,gBAAgB,CAAC,KAAK,CAAC,EACnC,kBAAkB,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,eAAe,CAAC,EAAE,OAAO,CAAA;CAAE,GACjE;IACD,UAAU,EAAE,UAAU,CAAC,KAAK,EAAE,SAAS,CAAC,CAAA;IACxC,gBAAgB,EAAE,MAAM,IAAI,CAAA;CAC7B,CA2BA"}
package/dist/auth.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { createJWTAuthClient, setClient } from '@molecule/app-auth';
2
- import { createFetchClient, getClient as getHttpClient, setAuthGate, setClient as setHttpClient, } from '@molecule/app-http';
2
+ import { createFetchClient, getClient as getHttpClient, setAuthGate, setAuthTokenSource as setHttpAuthTokenSource, setClient as setHttpClient, } from '@molecule/app-http';
3
3
  /**
4
4
  * Holds every HTTP request until this auth client's session restore has settled.
5
5
  *
@@ -101,6 +101,16 @@ export function createDefaultHttpClientWithAuthBearer(opts) {
101
101
  * export const { authClient, setupAuthDefault } =
102
102
  * createDefaultAuthClient(authConfig)
103
103
  * ```
104
+ *
105
+ * `TRegister` is the app's own registration fields (`{ username: string }` for a
106
+ * RealWorld-shaped API), passed on to `@molecule/app-auth`'s factory so
107
+ * `authClient.register({ username, email, password })` type-checks with no cast.
108
+ *
109
+ * `TUser` is the profile the app's pages read. Type the config with the SAME
110
+ * type (`const authConfig: AuthClientConfig<MyUser> = { … }`) so its
111
+ * `mapAuthResponse` is checked against `MyUser`: a mapper that omits a required
112
+ * custom field then fails at the `createDefaultAuthClient<MyUser>(authConfig)`
113
+ * call instead of shipping a signed-in page that reads `undefined`.
104
114
  */
105
115
  export function createDefaultAuthClient(authConfig) {
106
116
  const authClient = createJWTAuthClient(authConfig);
@@ -120,6 +130,13 @@ export function createDefaultAuthClient(authConfig) {
120
130
  * on setup, then listens for auth events to keep them aligned, and holds
121
131
  * requests until the session restore settles so a page effect that fetches
122
132
  * viewer-dependent data on mount cannot race it (see {@link registerAuthGate}).
133
+ *
134
+ * The hydrated token is delivered through `@molecule/app-http`'s token source, not
135
+ * through a client read at setup: the scaffold wires auth BEFORE http, so a client
136
+ * read here is the unbonded fallback and the restored session's token would land on a
137
+ * client nothing sends through (xr-molecule-flash-m156 — a reload sent every request
138
+ * with no `Authorization` header). The source is applied to the client WHENEVER it is
139
+ * bonded, so setup order no longer decides whether the first request is authorized.
123
140
  */
124
141
  export function createDefaultAuthClientWithHttpSync(authConfig) {
125
142
  const authClient = createJWTAuthClient(authConfig);
@@ -130,10 +147,11 @@ export function createDefaultAuthClientWithHttpSync(authConfig) {
130
147
  // Requests made while the session is still restoring wait for it, so a page
131
148
  // effect that fetches viewer-dependent data on mount cannot race the restore.
132
149
  registerAuthGate(authClient);
133
- const initialToken = authClient.getAccessToken();
134
- if (initialToken) {
135
- getHttpClient().setAuthToken(initialToken);
136
- }
150
+ // Resolve the HTTP client per sync, never once here. `setClient` runs this
151
+ // source, so the token reaches the client the scaffold bonds later as well as
152
+ // one already bonded; a client kept from this moment would be the throwaway
153
+ // fallback the later `setHttpDefault()` replaces.
154
+ setHttpAuthTokenSource(() => authClient.getAccessToken());
137
155
  authClient.addEventListener((event) => {
138
156
  if (event.type === 'login' || event.type === 'register' || event.type === 'refresh') {
139
157
  // Mirror the auth client's token EXACTLY — including null. Cookie-session
@@ -156,6 +174,14 @@ export function createDefaultAuthClientWithHttpSync(authConfig) {
156
174
  * `${baseURL}/path` instead of the SPA's catch-all route), AND keeps
157
175
  * its bearer token in sync with auth events.
158
176
  *
177
+ * The auth client restores a stored token AND user SYNCHRONOUSLY, so the first
178
+ * render is the signed-in UI — do not gate a protected page (or a provider of
179
+ * yours) on a current-user request. This bond registers `whenRestored()` as the
180
+ * HTTP gate, so requests still wait for the background restore/verification to
181
+ * settle; only `useAuth().status === 'loading'` means "no decision yet"
182
+ * (xr-molecule-flash-m177: a page that waited on its own `/me` paid a round trip
183
+ * on every navigation).
184
+ *
159
185
  * Used by apps where molecule packages render pricing / billing /
160
186
  * other authed JSON-fetching screens that need both behaviors.
161
187
  *
@@ -172,13 +198,13 @@ export function createDefaultAuthClientWithFetchClient(authConfig, fetchClientOp
172
198
  baseURL: fetchClientOptions.baseURL,
173
199
  withCredentials: fetchClientOptions.withCredentials ?? true,
174
200
  });
201
+ // Registered BEFORE the bond: `setHttpClient` applies the restored session's
202
+ // token, and the same source reaches any client an app bonds later instead of
203
+ // this one (xr-molecule-flash-m156 — a client captured at setup cannot).
204
+ setHttpAuthTokenSource(() => authClient.getAccessToken());
175
205
  setHttpClient(httpClient);
176
206
  setClient(authClient);
177
207
  registerAuthGate(authClient);
178
- const initialToken = authClient.getAccessToken();
179
- if (initialToken) {
180
- httpClient.setAuthToken(initialToken);
181
- }
182
208
  authClient.addEventListener((event) => {
183
209
  if (event.type === 'login' || event.type === 'register' || event.type === 'refresh') {
184
210
  // Mirror the token exactly, including null — see the identical note in
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@molecule/app-bonds-default-react",
3
- "version": "1.1.2",
3
+ "version": "1.1.4",
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.3.0",
41
+ "@molecule/app-auth": "1.5.7",
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",
@@ -48,16 +48,16 @@
48
48
  "@molecule/app-command-palette-cmdk": "1.0.2",
49
49
  "@molecule/app-drag-drop": "1.0.2",
50
50
  "@molecule/app-drag-drop-dndkit": "1.0.2",
51
- "@molecule/app-fonts": "1.1.0",
52
- "@molecule/app-fonts-arimo": "1.0.2",
53
- "@molecule/app-http": "1.1.3",
51
+ "@molecule/app-fonts": "1.2.1",
52
+ "@molecule/app-fonts-arimo": "1.0.3",
53
+ "@molecule/app-http": "1.4.0",
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",
57
57
  "@molecule/app-keyboard-shortcuts-hotkeys": "1.0.2",
58
58
  "@molecule/app-maps-leaflet": "1.0.2",
59
- "@molecule/app-realtime": "1.0.2",
60
- "@molecule/app-realtime-socketio": "1.0.2",
59
+ "@molecule/app-realtime": "1.0.3",
60
+ "@molecule/app-realtime-socketio": "1.1.0",
61
61
  "@molecule/app-routing": "1.0.3",
62
62
  "@molecule/app-routing-react-router": "1.0.2",
63
63
  "@molecule/app-state": "1.0.3",
@@ -65,7 +65,7 @@
65
65
  "@molecule/app-storage-localstorage": "1.0.2",
66
66
  "@molecule/app-theme": "1.0.3",
67
67
  "@molecule/app-theme-css-variables": "1.0.3",
68
- "@molecule/app-ui": "1.3.6",
68
+ "@molecule/app-ui": "1.3.7",
69
69
  "@molecule/app-ui-tailwind": "1.2.6",
70
70
  "@molecule/app-video-hls": "1.0.2",
71
71
  "@molecule/app-virtual-scroll": "1.0.2",