@molecule/app-react 3.0.2 → 3.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 +180 -55
- package/dist/hooks/useAuth.d.ts +10 -4
- package/dist/hooks/useAuth.d.ts.map +1 -1
- package/dist/hooks/useAuth.js +10 -4
- package/dist/hooks/useAuth.js.map +1 -1
- package/dist/hooks/useChat.d.ts.map +1 -1
- package/dist/hooks/useChat.js +1 -0
- package/dist/hooks/useChat.js.map +1 -1
- package/dist/hooks/useForm.d.ts +6 -3
- package/dist/hooks/useForm.d.ts.map +1 -1
- package/dist/hooks/useForm.js +36 -5
- package/dist/hooks/useForm.js.map +1 -1
- package/dist/hooks/useHttp.d.ts +7 -3
- package/dist/hooks/useHttp.d.ts.map +1 -1
- package/dist/hooks/useHttp.js +14 -2
- package/dist/hooks/useHttp.js.map +1 -1
- package/dist/hooks/useProfileForm.d.ts.map +1 -1
- package/dist/hooks/useProfileForm.js +48 -11
- package/dist/hooks/useProfileForm.js.map +1 -1
- package/dist/index.d.ts +19 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +19 -3
- package/dist/index.js.map +1 -1
- package/dist/providers.d.ts +1 -1
- package/dist/providers.d.ts.map +1 -1
- package/dist/providers.js +5 -3
- package/dist/providers.js.map +1 -1
- package/dist/session-ready.d.ts +41 -0
- package/dist/session-ready.d.ts.map +1 -0
- package/dist/session-ready.js +43 -0
- package/dist/session-ready.js.map +1 -0
- package/dist/types.d.ts +30 -3
- package/dist/types.d.ts.map +1 -1
- package/package.json +4 -4
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-
|
|
6
|
+
Generated: 2026-11-03T18:02:49.265Z
|
|
7
7
|
-->
|
|
8
8
|
|
|
9
9
|
# @molecule/app-react
|
|
@@ -24,6 +24,18 @@ server's saved user. Use its `onSaved` callback to update other query caches
|
|
|
24
24
|
from that response before navigating. Configure the endpoint, method and JSON
|
|
25
25
|
envelope once in `AuthClientConfig`; no page-local session store is needed.
|
|
26
26
|
|
|
27
|
+
**Session restore:** `useAuth().status === 'loading'` is undecided: wait for
|
|
28
|
+
it and redirect only on `status === 'unauthenticated'`. `'unavailable'` keeps
|
|
29
|
+
the session candidate for retry, but `isAuthenticated` can be false and `user`
|
|
30
|
+
can be null. A restore failure other than 401/403 never signs out.
|
|
31
|
+
`MoleculeProvider auth={authClient} awaitSession` (or `SessionReady` inside
|
|
32
|
+
`AuthProvider`) holds public pages until that initial loading status ends,
|
|
33
|
+
so their first render reads the restored user when restoration succeeds.
|
|
34
|
+
`sessionFallback` remains inside the service providers. Unavailable sessions
|
|
35
|
+
also render and can still have a null user. Synchronous SSR renders the
|
|
36
|
+
fallback for a loading client: initialize a request-scoped client first,
|
|
37
|
+
or leave the opt-in hold disabled for SSR.
|
|
38
|
+
|
|
27
39
|
> **Auto-generated, AI-first package reference** for the [molecule.dev](https://molecule.dev) ecosystem.
|
|
28
40
|
> It is written to be read by coding agents as much as by people, and is generated from this
|
|
29
41
|
> package's source — edit `src/index.ts` JSDoc, not this file.
|
|
@@ -57,16 +69,21 @@ import { createJWTAuthClient } from '@molecule/app-auth'
|
|
|
57
69
|
const authClient = createJWTAuthClient({ baseURL: '/api' })
|
|
58
70
|
|
|
59
71
|
function Dashboard() {
|
|
60
|
-
const { user,
|
|
72
|
+
const { user, status, logout } = useAuth<{ name?: string }>()
|
|
61
73
|
const { t } = useTranslation()
|
|
62
74
|
const { theme, toggleTheme } = useTheme()
|
|
63
75
|
|
|
64
|
-
if (
|
|
76
|
+
if (status === 'loading') {
|
|
77
|
+
return <p>{t('auth.restoring', undefined, { defaultValue: 'Restoring session...' })}</p>
|
|
78
|
+
}
|
|
79
|
+
if (status === 'unauthenticated') {
|
|
65
80
|
return <p>{t('auth.required', undefined, { defaultValue: 'Please log in.' })}</p>
|
|
66
81
|
}
|
|
67
82
|
return (
|
|
68
83
|
<div style={{ background: theme.colors.background }}>
|
|
69
|
-
<h1>
|
|
84
|
+
<h1>
|
|
85
|
+
{t('greeting.welcome', { name: user?.name ?? '' }, { defaultValue: 'Welcome, {{name}}!' })}
|
|
86
|
+
</h1>
|
|
70
87
|
<button onClick={toggleTheme}>
|
|
71
88
|
{t('theme.toggle', undefined, { defaultValue: 'Toggle theme' })}
|
|
72
89
|
</button>
|
|
@@ -114,7 +131,10 @@ Reactive authentication state snapshot (initialized, authenticated, user, loadin
|
|
|
114
131
|
interface AuthState<T = UserProfile> {
|
|
115
132
|
/**
|
|
116
133
|
* The session's state as one value — render from this instead of combining
|
|
117
|
-
* `initialized`/`authenticated`/`loading`.
|
|
134
|
+
* `initialized`/`authenticated`/`loading`. `'loading'` is undecided, so wait
|
|
135
|
+
* and redirect only on `'unauthenticated'`; `'unavailable'` keeps the candidate
|
|
136
|
+
* for retry and can have a null profile. A restore failure other than 401/403
|
|
137
|
+
* never signs out. See {@link AuthStatus}.
|
|
118
138
|
*/
|
|
119
139
|
status: AuthStatus
|
|
120
140
|
/**
|
|
@@ -122,11 +142,14 @@ interface AuthState<T = UserProfile> {
|
|
|
122
142
|
*/
|
|
123
143
|
initialized: boolean
|
|
124
144
|
/**
|
|
125
|
-
* Whether the
|
|
145
|
+
* Whether the client has an authenticated session. This is not a server
|
|
146
|
+
* confirmation flag: during `'unavailable'` it can be false for a retained
|
|
147
|
+
* token/cookie-only candidate with no cached profile. Use `status` for redirects.
|
|
126
148
|
*/
|
|
127
149
|
authenticated: boolean
|
|
128
150
|
/**
|
|
129
|
-
* Current user
|
|
151
|
+
* Current user, or null when none is cached. In particular, an `'unavailable'`
|
|
152
|
+
* token/cookie-only restore has a retained candidate but no profile yet.
|
|
130
153
|
*/
|
|
131
154
|
user: T | null
|
|
132
155
|
/**
|
|
@@ -180,12 +203,23 @@ interface AuthClient<T = UserProfile, TRegister extends RegisterExtraShape<TRegi
|
|
|
180
203
|
* Updates the cached user object (state + persistent storage) without
|
|
181
204
|
* hitting the network. Intended for local refreshes after a per-app
|
|
182
205
|
* mutation (e.g., the user just PATCHed their own profile and the
|
|
183
|
-
* server returned the canonical row).
|
|
206
|
+
* server returned the canonical row). A non-null profile does NOT change
|
|
207
|
+
* tokens or sign the client in: `authenticated` and `status` are unchanged,
|
|
208
|
+
* so an anonymous client stays anonymous. Use {@link login} /
|
|
209
|
+
* {@link register} for a credential exchange, or {@link setSession} when
|
|
210
|
+
* the token was issued outside the client.
|
|
184
211
|
*
|
|
185
|
-
*
|
|
186
|
-
*
|
|
187
|
-
*
|
|
188
|
-
*
|
|
212
|
+
* Passing `null` on a signed-in client, or while any session operation is
|
|
213
|
+
* pending, ends the local session: it clears the access token, refresh token
|
|
214
|
+
* and cached user, stops automatic refresh, and settles `authenticated: false`
|
|
215
|
+
* with `status: 'unauthenticated'` in one notification. Every older operation
|
|
216
|
+
* loses session ownership, and a persistent sign-out marker prevents a reload
|
|
217
|
+
* from restoring its credentials or a late cookie. A late credential exchange
|
|
218
|
+
* is revoked best-effort when a logout endpoint is configured, without blocking
|
|
219
|
+
* the caller. This method does not otherwise call the server for a settled
|
|
220
|
+
* session; use {@link logout} for explicit server revocation. On a settled
|
|
221
|
+
* anonymous client, `null` only clears the cached profile and leaves tokens
|
|
222
|
+
* and auth state unchanged.
|
|
189
223
|
*/
|
|
190
224
|
setUser(user: T | null): void;
|
|
191
225
|
/**
|
|
@@ -200,10 +234,13 @@ interface AuthClient<T = UserProfile, TRegister extends RegisterExtraShape<TRegi
|
|
|
200
234
|
* which would violate the storage contract and make a stored bearer token
|
|
201
235
|
* JS-readable (XSS-exfiltratable). Pass `null` to clear it.
|
|
202
236
|
*
|
|
203
|
-
* This changes token storage only
|
|
204
|
-
*
|
|
205
|
-
*
|
|
206
|
-
*
|
|
237
|
+
* This changes token storage only: passing `null` does not by itself sign a
|
|
238
|
+
* signed-in client out, and a non-null token does not sign an anonymous
|
|
239
|
+
* client in (`authenticated` and `status` are unchanged). Use {@link logout}
|
|
240
|
+
* to end a session, or {@link setUser} with `null` for local-only sign-out.
|
|
241
|
+
* Use {@link login} / {@link register} for a credential exchange, or call
|
|
242
|
+
* {@link setSession} with the token and user to establish an already-issued
|
|
243
|
+
* session.
|
|
207
244
|
*/
|
|
208
245
|
setAccessToken(token: string | null): void;
|
|
209
246
|
/**
|
|
@@ -228,7 +265,16 @@ interface AuthClient<T = UserProfile, TRegister extends RegisterExtraShape<TRegi
|
|
|
228
265
|
*/
|
|
229
266
|
login(credentials: LoginCredentials): Promise<AuthResult<T>>;
|
|
230
267
|
/**
|
|
231
|
-
* Logs out the current user.
|
|
268
|
+
* Logs out the current user. The server request is best-effort: a missing
|
|
269
|
+
* logout route (404), any other HTTP failure, or a network error never makes
|
|
270
|
+
* this method reject. It always clears the access token, refresh token and
|
|
271
|
+
* cached user, stops automatic refresh, and publishes one settled
|
|
272
|
+
* `authenticated: false`, `status: 'unauthenticated'` transition. Every pending
|
|
273
|
+
* session operation loses ownership; a persistent marker prevents reload from
|
|
274
|
+
* restoring an older session, and late credentials are revoked best-effort.
|
|
275
|
+
*
|
|
276
|
+
* When the API has no logout route, set {@link AuthClientConfigOptions.logoutEndpoint}
|
|
277
|
+
* to `null` (or `''`) to skip the request. Local sign-out still happens.
|
|
232
278
|
*/
|
|
233
279
|
logout(): Promise<void>;
|
|
234
280
|
/**
|
|
@@ -280,37 +326,6 @@ interface AuthClient<T = UserProfile, TRegister extends RegisterExtraShape<TRegi
|
|
|
280
326
|
* until the cookie restore decides.
|
|
281
327
|
*
|
|
282
328
|
* Do not put this call (or a `/me` request of your own) in front of the first
|
|
283
|
-
* render, and do not render a loading screen over a session it just restored:
|
|
284
|
-
* `whenRestored()` already resolves as soon as the restore has settled, and the
|
|
285
|
-
* HTTP gate built on it holds requests for exactly that window.
|
|
286
|
-
*/
|
|
287
|
-
initialize(): Promise<void>;
|
|
288
|
-
/**
|
|
289
|
-
* Re-checks a restored session against the server, in the background — the
|
|
290
|
-
* boot-time validation an app with a stored token needs when a revoked or
|
|
291
|
-
* expired token must sign the user out. Call it AFTER the first render
|
|
292
|
-
* (`initialize()` restores synchronously from storage; this costs one request).
|
|
293
|
-
*
|
|
294
|
-
* - The server confirms the user: the session is refreshed and {@link AuthState.status}
|
|
295
|
-
* stays `'authenticated'`.
|
|
296
|
-
* - The server answers 401 or 403: the token is dead — the stored session is
|
|
297
|
-
* cleared and the status becomes `'unauthenticated'`.
|
|
298
|
-
* - The server cannot confirm the session — a network failure, a 5xx, or a 404
|
|
299
|
-
* from a misconfigured {@link AuthClientConfig.currentUserEndpoint}: the
|
|
300
|
-
* session (token AND user) is KEPT and the status becomes `'unavailable'`, so
|
|
301
|
-
* the app can retry instead of signing the user out over a bad connection or a
|
|
302
|
-
* route that does not exist. The 404 error names `currentUserEndpoint`.
|
|
303
|
-
*
|
|
304
|
-
* Do not hand-write this beside the client: a parallel token/user store for a
|
|
305
|
-
* "validating"/"unavailable" flag is the race this method removes.
|
|
306
|
-
*
|
|
307
|
-
* Optional: a provider with no restorable session has nothing to validate.
|
|
308
|
-
*/
|
|
309
|
-
validateSession?(): Promise<void>;
|
|
310
|
-
/**
|
|
311
|
-
* Resolves when the session restore started by `initialize()` has settled — the point
|
|
312
|
-
* after which the client knows whether this visitor is signed in.
|
|
313
|
-
*
|
|
314
329
|
// … truncated — the full declaration is in node_modules/@molecule/app-react/dist
|
|
315
330
|
```
|
|
316
331
|
|
|
@@ -399,9 +414,20 @@ interface FormController<T extends FormValuesConstraint<T> = Record<string, unkn
|
|
|
399
414
|
* `defaultValues`, or the values a previous `reset(values)` established.
|
|
400
415
|
* Passing `values` merges them over the current baseline and makes the
|
|
401
416
|
* result the new baseline, so a form reset to freshly loaded or saved data
|
|
402
|
-
* reads clean (`isDirty === false`).
|
|
417
|
+
* reads clean (`isDirty === false`). A changed non-null `id` replaces the
|
|
418
|
+
* record and cancels a pending submit.
|
|
403
419
|
*/
|
|
404
420
|
reset(values?: Partial<T>): void
|
|
421
|
+
/**
|
|
422
|
+
* Applies externally loaded values without clearing submission state.
|
|
423
|
+
*
|
|
424
|
+
* The new clean baseline is the original `defaultValues` plus this latest
|
|
425
|
+
* record, never a merge of earlier records. With `keepDirtyValues`, edited
|
|
426
|
+
* fields retain their values while pristine fields take the loaded values.
|
|
427
|
+
* A changed non-null `id` still replaces the record and cancels a pending
|
|
428
|
+
* submit. Equal-content baselines cause no update.
|
|
429
|
+
*/
|
|
430
|
+
updateValues(values: Partial<T>, resetOptions?: FormResetOptions): void
|
|
405
431
|
/**
|
|
406
432
|
* Handles form submission.
|
|
407
433
|
*/
|
|
@@ -424,6 +450,21 @@ interface FormController<T extends FormValuesConstraint<T> = Record<string, unkn
|
|
|
424
450
|
}
|
|
425
451
|
```
|
|
426
452
|
|
|
453
|
+
#### `FormResetOptions`
|
|
454
|
+
|
|
455
|
+
Options controlling how externally supplied values replace a form's baseline.
|
|
456
|
+
|
|
457
|
+
```typescript
|
|
458
|
+
interface FormResetOptions {
|
|
459
|
+
/**
|
|
460
|
+
* Keep fields whose current value differs from their baseline when `values`
|
|
461
|
+
* changes. Pristine fields still take the new values. False by default, so a
|
|
462
|
+
* new record can replace edits from the previous record.
|
|
463
|
+
*/
|
|
464
|
+
keepDirtyValues?: boolean
|
|
465
|
+
}
|
|
466
|
+
```
|
|
467
|
+
|
|
427
468
|
#### `FormOptions`
|
|
428
469
|
|
|
429
470
|
Form creation options.
|
|
@@ -435,6 +476,14 @@ interface FormOptions<T extends FormValuesConstraint<T>> {
|
|
|
435
476
|
* is created. Mutating this object afterwards does not change the baseline.
|
|
436
477
|
*/
|
|
437
478
|
defaultValues?: Partial<T>
|
|
479
|
+
/**
|
|
480
|
+
* Externally loaded values, merged over `defaultValues` as the clean
|
|
481
|
+
* baseline. Framework bindings also apply later content changes; use
|
|
482
|
+
* `resetOptions.keepDirtyValues` to preserve edits while pristine fields fill.
|
|
483
|
+
*/
|
|
484
|
+
values?: Partial<T>
|
|
485
|
+
/** Controls how framework bindings apply changed `values`. */
|
|
486
|
+
resetOptions?: FormResetOptions
|
|
438
487
|
/**
|
|
439
488
|
* Validation mode.
|
|
440
489
|
*/
|
|
@@ -881,6 +930,7 @@ interface UseFormResult<T extends FormValuesConstraint<T>> {
|
|
|
881
930
|
onSubmit: (values: T) => void | Promise<void>,
|
|
882
931
|
) => (event?: React.FormEvent) => Promise<void>
|
|
883
932
|
reset: (values?: Partial<T>) => void
|
|
933
|
+
updateValues: (values: Partial<T>, resetOptions?: FormResetOptions) => void
|
|
884
934
|
validate: () => Promise<boolean>
|
|
885
935
|
}
|
|
886
936
|
```
|
|
@@ -904,7 +954,8 @@ Result of useHttp hook.
|
|
|
904
954
|
```typescript
|
|
905
955
|
interface UseHttpResult<T> extends UseHttpState<T> {
|
|
906
956
|
/**
|
|
907
|
-
* Runs the request and resolves with its data, or `null` on failure
|
|
957
|
+
* Runs the request and resolves with its own data, or `null` on failure,
|
|
958
|
+
* even when a newer request or `reset` has superseded its displayed state.
|
|
908
959
|
*
|
|
909
960
|
* This function is IDENTITY-STABLE for as long as `method`, `url` and the HTTP
|
|
910
961
|
* client do not change, so it is safe in a `useEffect` dependency array. Its
|
|
@@ -931,11 +982,14 @@ interface UseHttpOptions<T> extends RequestConfig {
|
|
|
931
982
|
*/
|
|
932
983
|
immediate?: boolean
|
|
933
984
|
/**
|
|
934
|
-
* Callback
|
|
985
|
+
* Callback for each request that succeeds while mounted, including a request
|
|
986
|
+
* superseded by another `execute` or `reset`. Read `data` from the hook when
|
|
987
|
+
* only the newest request's result should drive the UI.
|
|
935
988
|
*/
|
|
936
989
|
onSuccess?: (data: T) => void
|
|
937
990
|
/**
|
|
938
|
-
* Callback
|
|
991
|
+
* Callback for each request that fails while mounted, including a request
|
|
992
|
+
* superseded by another `execute` or `reset`.
|
|
939
993
|
*/
|
|
940
994
|
onError?: (error: Error) => void
|
|
941
995
|
}
|
|
@@ -1302,6 +1356,19 @@ interface ProviderProps {
|
|
|
1302
1356
|
}
|
|
1303
1357
|
```
|
|
1304
1358
|
|
|
1359
|
+
#### `SessionReadyProps`
|
|
1360
|
+
|
|
1361
|
+
Props for the `SessionReady` component.
|
|
1362
|
+
|
|
1363
|
+
```typescript
|
|
1364
|
+
interface SessionReadyProps {
|
|
1365
|
+
/** What renders once the initial restore settles — signed in, signed out, or unavailable. */
|
|
1366
|
+
children: ReactNode
|
|
1367
|
+
/** What renders while the session restore is still undecided; default nothing. */
|
|
1368
|
+
fallback?: ReactNode
|
|
1369
|
+
}
|
|
1370
|
+
```
|
|
1371
|
+
|
|
1305
1372
|
#### `StateProviderProps`
|
|
1306
1373
|
|
|
1307
1374
|
Props for state provider component.
|
|
@@ -1431,6 +1498,20 @@ Properties for molecule provider.
|
|
|
1431
1498
|
interface MoleculeProviderProps extends ProviderProps {
|
|
1432
1499
|
state?: StateProvider
|
|
1433
1500
|
auth?: AuthClient<unknown>
|
|
1501
|
+
/**
|
|
1502
|
+
* Render the app only once `auth` leaves its initial loading status ({@link SessionReadyProps}).
|
|
1503
|
+
* After a full page load a returning visitor's session is restored by one request, and until
|
|
1504
|
+
* it answers `useAuth().user` is `null` on every page — a public page's signed-in action
|
|
1505
|
+
* (`if (!user) return`, a redirect to `/login`) then treats a signed-in visitor as signed out.
|
|
1506
|
+
* When restoration succeeds, every page's first render reads the restored user. An
|
|
1507
|
+
* `'unavailable'` session also renders, but remains unconfirmed and may have a null user.
|
|
1508
|
+
* A visitor with no session to restore settles in microtasks without a request.
|
|
1509
|
+
* Ignored without `auth`. Synchronous SSR renders the fallback for a loading client:
|
|
1510
|
+
* initialize a request-scoped client first, or leave this disabled for SSR.
|
|
1511
|
+
*/
|
|
1512
|
+
awaitSession?: boolean
|
|
1513
|
+
/** Rendered instead of the app while {@link MoleculeProviderProps.awaitSession} waits; default nothing. */
|
|
1514
|
+
sessionFallback?: ReactNode
|
|
1434
1515
|
theme?: ThemeProvider
|
|
1435
1516
|
router?: Router
|
|
1436
1517
|
i18n?: I18nProvider
|
|
@@ -1481,7 +1562,9 @@ interface UseAuthResult<
|
|
|
1481
1562
|
* The session state as one value — render from this instead of combining
|
|
1482
1563
|
* `initialized`/`authenticated`/`loading`. A stored token AND user make it
|
|
1483
1564
|
* `'authenticated'` on the first render; only `'loading'` means "no decision
|
|
1484
|
-
* yet", so a route guard waits on that and nothing else.
|
|
1565
|
+
* yet", so a route guard waits on that and nothing else. `'unavailable'` keeps
|
|
1566
|
+
* a session candidate for retry and can have a null profile; redirect only on
|
|
1567
|
+
* `'unauthenticated'`.
|
|
1485
1568
|
*/
|
|
1486
1569
|
status: AuthState<T>['status']
|
|
1487
1570
|
state: AuthState<T>
|
|
@@ -1501,8 +1584,10 @@ interface UseAuthResult<
|
|
|
1501
1584
|
* `authenticated` read signed out.
|
|
1502
1585
|
*/
|
|
1503
1586
|
setSession: AuthClient<T>['setSession']
|
|
1587
|
+
/** Whether a session is authenticated locally; this can be false while unavailable. */
|
|
1504
1588
|
isAuthenticated: boolean
|
|
1505
1589
|
isLoading: boolean
|
|
1590
|
+
/** The cached profile, which can be null while an unavailable candidate is retained. */
|
|
1506
1591
|
user: T | null
|
|
1507
1592
|
}
|
|
1508
1593
|
```
|
|
@@ -1982,6 +2067,12 @@ function useAuthClient<
|
|
|
1982
2067
|
|
|
1983
2068
|
Hook for authentication state and actions.
|
|
1984
2069
|
|
|
2070
|
+
`status === 'loading'` is undecided: wait for it and redirect only on
|
|
2071
|
+
`status === 'unauthenticated'`. `'unavailable'` keeps the session candidate
|
|
2072
|
+
for retry, but `isAuthenticated` can be false and `user` can be null while a
|
|
2073
|
+
token/cookie-only restore has no cached profile. A restore failure other than
|
|
2074
|
+
401/403 never signs out.
|
|
2075
|
+
|
|
1985
2076
|
Pass the app's user type — the SAME type used for the auth client and its
|
|
1986
2077
|
config (`createJWTAuthClient<MyUser>`, `AuthClientConfig<MyUser>`) — so
|
|
1987
2078
|
`user` and `setSession`/`setUser` are typed for the pages:
|
|
@@ -2185,7 +2276,7 @@ function useForm<T extends FormValuesConstraint<T> = Record<string, unknown>>(
|
|
|
2185
2276
|
): UseFormResult<T>
|
|
2186
2277
|
```
|
|
2187
2278
|
|
|
2188
|
-
- `options` — Form options. `defaultValues`, `mode` and the form-level `validate` are forwarded to the provider;
|
|
2279
|
+
- `options` — Form options. `defaultValues`, `mode` and the form-level `validate` are forwarded to the provider. When `values` changes by content, it becomes the new baseline; `resetOptions.keepDirtyValues` retains edited fields while pristine fields take the loaded values. Omit the options entirely for a form whose fields are registered with their own defaults.
|
|
2189
2280
|
|
|
2190
2281
|
**Returns:** Form state and methods
|
|
2191
2282
|
|
|
@@ -3113,6 +3204,8 @@ function MoleculeProvider({
|
|
|
3113
3204
|
workspace,
|
|
3114
3205
|
editor,
|
|
3115
3206
|
preview,
|
|
3207
|
+
awaitSession = false,
|
|
3208
|
+
sessionFallback,
|
|
3116
3209
|
}: MoleculeProviderProps): React.ReactElement
|
|
3117
3210
|
```
|
|
3118
3211
|
|
|
@@ -3120,6 +3213,38 @@ function MoleculeProvider({
|
|
|
3120
3213
|
|
|
3121
3214
|
**Returns:** The rendered combined provider element.
|
|
3122
3215
|
|
|
3216
|
+
#### `SessionReady(props)`
|
|
3217
|
+
|
|
3218
|
+
Renders its children once `useAuth().status` has left `'loading'` (signed in, signed out,
|
|
3219
|
+
or `'unavailable'`), and `fallback` until then. It never redirects. An unavailable session
|
|
3220
|
+
is unconfirmed and may still have `user === null`; handle that status separately from sign-out.
|
|
3221
|
+
|
|
3222
|
+
After a full page load a returning visitor's session is restored by one request. Until it
|
|
3223
|
+
answers, `useAuth().user` is `null` everywhere, so a public page that renders a signed-in action
|
|
3224
|
+
at once lets that action run against "signed out": a Follow button whose handler starts with
|
|
3225
|
+
`if (!user) return` ignores the click, one that redirects to `/login` signs the visitor out of
|
|
3226
|
+
the flow. Wrapping the routes (or passing `awaitSession` to `MoleculeProvider`) makes every
|
|
3227
|
+
page's first render read the restored user when restoration succeeds.
|
|
3228
|
+
|
|
3229
|
+
A visitor with no session to restore settles in microtasks without a request. Must render
|
|
3230
|
+
inside the auth context (`AuthProvider`, or `MoleculeProvider` with `auth`). A client that
|
|
3231
|
+
nobody initialized starts its restore on this first read.
|
|
3232
|
+
The bundled JWT client bounds each auth request (default 10 seconds) and settles a timeout
|
|
3233
|
+
as `'unavailable'`. Custom clients must also settle their initial session status.
|
|
3234
|
+
|
|
3235
|
+
Synchronous SSR renders the fallback while a client is loading. Initialize a request-scoped
|
|
3236
|
+
client before rendering to include its decided content, or leave the hold disabled for SSR.
|
|
3237
|
+
|
|
3238
|
+
_(description truncated — read the full text in `node_modules/@molecule/app-react/dist/session-ready.d.ts`.)_
|
|
3239
|
+
|
|
3240
|
+
```typescript
|
|
3241
|
+
function SessionReady({ children, fallback = null }: SessionReadyProps): ReactNode
|
|
3242
|
+
```
|
|
3243
|
+
|
|
3244
|
+
- `props` — {@link SessionReadyProps}.
|
|
3245
|
+
|
|
3246
|
+
**Returns:** The children once the session is decided, otherwise the fallback.
|
|
3247
|
+
|
|
3123
3248
|
### Constants
|
|
3124
3249
|
|
|
3125
3250
|
#### `DEFAULT_AGENT_NAME`
|
|
@@ -3252,7 +3377,7 @@ Peer dependencies:
|
|
|
3252
3377
|
|
|
3253
3378
|
- `@molecule/app-auth` ^3.0.0
|
|
3254
3379
|
- `@molecule/app-ai-models` ^1.0.1
|
|
3255
|
-
- `@molecule/app-forms` ^2.
|
|
3380
|
+
- `@molecule/app-forms` ^2.2.0
|
|
3256
3381
|
- `@molecule/app-utilities` ^1.0.1
|
|
3257
3382
|
- `@molecule/app-http` ^1.0.1
|
|
3258
3383
|
- `@molecule/app-i18n` ^1.0.1
|
package/dist/hooks/useAuth.d.ts
CHANGED
|
@@ -19,6 +19,12 @@ export declare function useAuthClient<T = unknown, TRegister extends RegisterExt
|
|
|
19
19
|
/**
|
|
20
20
|
* Hook for authentication state and actions.
|
|
21
21
|
*
|
|
22
|
+
* `status === 'loading'` is undecided: wait for it and redirect only on
|
|
23
|
+
* `status === 'unauthenticated'`. `'unavailable'` keeps the session candidate
|
|
24
|
+
* for retry, but `isAuthenticated` can be false and `user` can be null while a
|
|
25
|
+
* token/cookie-only restore has no cached profile. A restore failure other than
|
|
26
|
+
* 401/403 never signs out.
|
|
27
|
+
*
|
|
22
28
|
* Pass the app's user type — the SAME type used for the auth client and its
|
|
23
29
|
* config (`createJWTAuthClient<MyUser>`, `AuthClientConfig<MyUser>`) — so
|
|
24
30
|
* `user` and `setSession`/`setUser` are typed for the pages:
|
|
@@ -44,13 +50,13 @@ export declare function useAuthClient<T = unknown, TRegister extends RegisterExt
|
|
|
44
50
|
*
|
|
45
51
|
* @example
|
|
46
52
|
* ```tsx
|
|
47
|
-
* const { user,
|
|
53
|
+
* const { user, status, login, logout } = useAuth<{ id: string; name?: string }>()
|
|
48
54
|
* const { register } = useAuth<MyUser, { username: string }>()
|
|
49
55
|
* await register({ email, password, username }) // `username` is typed
|
|
50
56
|
*
|
|
51
|
-
* if (
|
|
52
|
-
*
|
|
53
|
-
* }
|
|
57
|
+
* if (status === 'loading') return <p>Restoring session...</p>
|
|
58
|
+
* if (status === 'unauthenticated') return <Navigate to="/login" replace />
|
|
59
|
+
* return <div>Welcome, {user?.name}!</div>
|
|
54
60
|
* ```
|
|
55
61
|
*/
|
|
56
62
|
export declare function useAuth<T = unknown, TRegister extends RegisterExtraShape<TRegister> = Record<never, never>>(options?: UseAuthOptions): UseAuthResult<T, TRegister>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useAuth.d.ts","sourceRoot":"","sources":["../../src/hooks/useAuth.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,KAAK,EACV,UAAU,EAKV,kBAAkB,EACnB,MAAM,oBAAoB,CAAA;AAI3B,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAEhE;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAC3B,CAAC,GAAG,OAAO,EACX,SAAS,SAAS,kBAAkB,CAAC,SAAS,CAAC,GAAG,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,KACnE,UAAU,CAAC,CAAC,EAAE,SAAS,CAAC,CAU5B;AAED
|
|
1
|
+
{"version":3,"file":"useAuth.d.ts","sourceRoot":"","sources":["../../src/hooks/useAuth.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,KAAK,EACV,UAAU,EAKV,kBAAkB,EACnB,MAAM,oBAAoB,CAAA;AAI3B,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAEhE;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAC3B,CAAC,GAAG,OAAO,EACX,SAAS,SAAS,kBAAkB,CAAC,SAAS,CAAC,GAAG,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,KACnE,UAAU,CAAC,CAAC,EAAE,SAAS,CAAC,CAU5B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0CG;AACH,wBAAgB,OAAO,CACrB,CAAC,GAAG,OAAO,EACX,SAAS,SAAS,kBAAkB,CAAC,SAAS,CAAC,GAAG,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,EACtE,OAAO,CAAC,EAAE,cAAc,GAAG,aAAa,CAAC,CAAC,EAAE,SAAS,CAAC,CA2EvD;AAED;;;;GAIG;AACH,wBAAgB,OAAO,CAAC,CAAC,GAAG,OAAO,KAAK,CAAC,GAAG,IAAI,CAG/C;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,IAAI,OAAO,CAG5C"}
|
package/dist/hooks/useAuth.js
CHANGED
|
@@ -28,6 +28,12 @@ export function useAuthClient() {
|
|
|
28
28
|
/**
|
|
29
29
|
* Hook for authentication state and actions.
|
|
30
30
|
*
|
|
31
|
+
* `status === 'loading'` is undecided: wait for it and redirect only on
|
|
32
|
+
* `status === 'unauthenticated'`. `'unavailable'` keeps the session candidate
|
|
33
|
+
* for retry, but `isAuthenticated` can be false and `user` can be null while a
|
|
34
|
+
* token/cookie-only restore has no cached profile. A restore failure other than
|
|
35
|
+
* 401/403 never signs out.
|
|
36
|
+
*
|
|
31
37
|
* Pass the app's user type — the SAME type used for the auth client and its
|
|
32
38
|
* config (`createJWTAuthClient<MyUser>`, `AuthClientConfig<MyUser>`) — so
|
|
33
39
|
* `user` and `setSession`/`setUser` are typed for the pages:
|
|
@@ -53,13 +59,13 @@ export function useAuthClient() {
|
|
|
53
59
|
*
|
|
54
60
|
* @example
|
|
55
61
|
* ```tsx
|
|
56
|
-
* const { user,
|
|
62
|
+
* const { user, status, login, logout } = useAuth<{ id: string; name?: string }>()
|
|
57
63
|
* const { register } = useAuth<MyUser, { username: string }>()
|
|
58
64
|
* await register({ email, password, username }) // `username` is typed
|
|
59
65
|
*
|
|
60
|
-
* if (
|
|
61
|
-
*
|
|
62
|
-
* }
|
|
66
|
+
* if (status === 'loading') return <p>Restoring session...</p>
|
|
67
|
+
* if (status === 'unauthenticated') return <Navigate to="/login" replace />
|
|
68
|
+
* return <div>Welcome, {user?.name}!</div>
|
|
63
69
|
* ```
|
|
64
70
|
*/
|
|
65
71
|
export function useAuth(options) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useAuth.js","sourceRoot":"","sources":["../../src/hooks/useAuth.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,EAAE,oBAAoB,EAAE,MAAM,OAAO,CAAA;AAUxF,OAAO,EAAE,CAAC,EAAE,MAAM,oBAAoB,CAAA;AAEtC,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA;AAG5C;;;;;;;;;GASG;AACH,MAAM,UAAU,aAAa;IAI3B,MAAM,MAAM,GAAG,UAAU,CAAC,WAAW,CAAC,CAAA;IACtC,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CACb,CAAC,CAAC,oCAAoC,EAAE,SAAS,EAAE;YACjD,YAAY,EAAE,mDAAmD;SAClE,CAAC,CACH,CAAA;IACH,CAAC;IACD,OAAO,MAAkC,CAAA;AAC3C,CAAC;AAED
|
|
1
|
+
{"version":3,"file":"useAuth.js","sourceRoot":"","sources":["../../src/hooks/useAuth.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useChat.d.ts","sourceRoot":"","sources":["../../src/hooks/useChat.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAYH,OAAO,KAAK,EAIV,WAAW,EACX,YAAY,EAGb,MAAM,uBAAuB,CAAA;AAK9B,OAAO,KAAK,EAAsB,cAAc,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AA8cpF;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,WAAW,EAAE,EAAE,OAAO,EAAE,WAAW,EAAE,GAAG,WAAW,EAAE,CAc1F;AAiBD;;;;;;;;;;;;GAYG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,WAAW,EAAE,EAAE,OAAO,EAAE,WAAW,EAAE,GAAG,WAAW,EAAE,CAQ5F;AAyDD;;;;GAIG;AACH,wBAAgB,uBAAuB,IAAI,IAAI,CAK9C;AAED;;;;GAIG;AACH,wBAAgB,eAAe,IAAI,YAAY,CAU9C;AAkDD;;;;;;;;GAQG;AACH,wBAAgB,OAAO,CAAC,OAAO,EAAE,cAAc,GAAG,aAAa,
|
|
1
|
+
{"version":3,"file":"useChat.d.ts","sourceRoot":"","sources":["../../src/hooks/useChat.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAYH,OAAO,KAAK,EAIV,WAAW,EACX,YAAY,EAGb,MAAM,uBAAuB,CAAA;AAK9B,OAAO,KAAK,EAAsB,cAAc,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AA8cpF;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,WAAW,EAAE,EAAE,OAAO,EAAE,WAAW,EAAE,GAAG,WAAW,EAAE,CAc1F;AAiBD;;;;;;;;;;;;GAYG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,WAAW,EAAE,EAAE,OAAO,EAAE,WAAW,EAAE,GAAG,WAAW,EAAE,CAQ5F;AAyDD;;;;GAIG;AACH,wBAAgB,uBAAuB,IAAI,IAAI,CAK9C;AAED;;;;GAIG;AACH,wBAAgB,eAAe,IAAI,YAAY,CAU9C;AAkDD;;;;;;;;GAQG;AACH,wBAAgB,OAAO,CAAC,OAAO,EAAE,cAAc,GAAG,aAAa,CAo4E9D"}
|
package/dist/hooks/useChat.js
CHANGED
|
@@ -1519,6 +1519,7 @@ export function useChat(options) {
|
|
|
1519
1519
|
type: 'verification',
|
|
1520
1520
|
status: event.status,
|
|
1521
1521
|
...(event.output ? { output: event.output } : {}),
|
|
1522
|
+
...(event.renderCheckUnavailable ? { renderCheckUnavailable: true } : {}),
|
|
1522
1523
|
workspaces: event.workspaces,
|
|
1523
1524
|
...(event.categories ? { categories: event.categories } : {}),
|
|
1524
1525
|
});
|