@molecule/app-react-native 3.0.1 → 3.0.3
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 +228 -176
- package/package.json +2 -2
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-04T14:20:07.525Z
|
|
7
7
|
-->
|
|
8
8
|
|
|
9
9
|
# @molecule/app-react-native
|
|
@@ -72,7 +72,10 @@ Reactive authentication state snapshot (initialized, authenticated, user, loadin
|
|
|
72
72
|
interface AuthState<T = UserProfile> {
|
|
73
73
|
/**
|
|
74
74
|
* The session's state as one value — render from this instead of combining
|
|
75
|
-
* `initialized`/`authenticated`/`loading`.
|
|
75
|
+
* `initialized`/`authenticated`/`loading`. `'loading'` is undecided, so wait
|
|
76
|
+
* and redirect only on `'unauthenticated'`; `'unavailable'` keeps the candidate
|
|
77
|
+
* for retry and can have a null profile. A restore failure other than 401/403
|
|
78
|
+
* never signs out. See {@link AuthStatus}.
|
|
76
79
|
*/
|
|
77
80
|
status: AuthStatus
|
|
78
81
|
/**
|
|
@@ -80,11 +83,14 @@ interface AuthState<T = UserProfile> {
|
|
|
80
83
|
*/
|
|
81
84
|
initialized: boolean
|
|
82
85
|
/**
|
|
83
|
-
* Whether the
|
|
86
|
+
* Whether the client has an authenticated session. This is not a server
|
|
87
|
+
* confirmation flag: during `'unavailable'` it can be false for a retained
|
|
88
|
+
* token/cookie-only candidate with no cached profile. Use `status` for redirects.
|
|
84
89
|
*/
|
|
85
90
|
authenticated: boolean
|
|
86
91
|
/**
|
|
87
|
-
* Current user
|
|
92
|
+
* Current user, or null when none is cached. In particular, an `'unavailable'`
|
|
93
|
+
* token/cookie-only restore has a retained candidate but no profile yet.
|
|
88
94
|
*/
|
|
89
95
|
user: T | null
|
|
90
96
|
/**
|
|
@@ -105,173 +111,65 @@ Provides login/logout/register flows, token management, profile
|
|
|
105
111
|
updates, and auth state subscription.
|
|
106
112
|
|
|
107
113
|
```typescript
|
|
108
|
-
interface AuthClient<
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
* {@link register} for a credential exchange, or call {@link setSession}
|
|
164
|
-
* with the token and the user to establish an already-issued session.
|
|
165
|
-
*/
|
|
166
|
-
setAccessToken(token: string | null): void;
|
|
167
|
-
/**
|
|
168
|
-
* Adopts a session an out-of-band exchange already established: stores the
|
|
169
|
-
* access token (and the refresh token when given), caches the user, and
|
|
170
|
-
* sets the COMPLETE state — `initialized`, `authenticated`, `status:
|
|
171
|
-
* 'authenticated'`, no error — in one update, with one subscriber
|
|
172
|
-
* notification. Every hook reading the shared client sees the user as
|
|
173
|
-
* signed in immediately.
|
|
174
|
-
*
|
|
175
|
-
* This is the way to seed an OAuth/custom sign-in. Calling
|
|
176
|
-
* {@link setAccessToken} and {@link setUser} instead does NOT sign the
|
|
177
|
-
* client in.
|
|
178
|
-
*/
|
|
179
|
-
setSession(session: AuthSessionSeed<T>): void;
|
|
180
|
-
/**
|
|
181
|
-
* Gets the refresh token.
|
|
182
|
-
*/
|
|
183
|
-
getRefreshToken(): string | null;
|
|
184
|
-
/**
|
|
185
|
-
* Logs in with credentials.
|
|
186
|
-
*/
|
|
187
|
-
login(credentials: LoginCredentials): Promise<AuthResult<T>>;
|
|
188
|
-
/**
|
|
189
|
-
* Logs out the current user.
|
|
190
|
-
*/
|
|
191
|
-
logout(): Promise<void>;
|
|
192
|
-
/**
|
|
193
|
-
* Registers a new user. Accepts the base fields plus the app's own fields
|
|
194
|
-
* (`TRegister`) at the top level — see {@link RegisterData}.
|
|
195
|
-
*/
|
|
196
|
-
register(data: RegisterData<TRegister>): Promise<AuthResult<T>>;
|
|
197
|
-
/**
|
|
198
|
-
* Refreshes the access token.
|
|
199
|
-
*/
|
|
200
|
-
refresh(): Promise<AuthResult<T>>;
|
|
201
|
-
/**
|
|
202
|
-
* Requests a password reset.
|
|
203
|
-
*/
|
|
204
|
-
requestPasswordReset(data: PasswordResetRequest): Promise<void>;
|
|
205
|
-
/**
|
|
206
|
-
* Confirms a password reset.
|
|
207
|
-
*/
|
|
208
|
-
confirmPasswordReset(data: PasswordResetConfirm): Promise<void>;
|
|
209
|
-
/**
|
|
210
|
-
* Updates the current user's profile.
|
|
211
|
-
* Returns the saved profile: the answer applied onto the signed-in user field
|
|
212
|
-
* by field, with or without an `id` — a field it carries replaces the value
|
|
213
|
-
* (`null` clears it), one it omits or leaves `undefined` is kept, so a field
|
|
214
|
-
* cleared by omission must arrive as `null`. A non-object answer is returned
|
|
215
|
-
* as it came. An answer for a replaced or ended session leaves the current one
|
|
216
|
-
* untouched.
|
|
217
|
-
*/
|
|
218
|
-
updateProfile(data: Partial<T>): Promise<T>;
|
|
219
|
-
/**
|
|
220
|
-
* Changes the current user's password.
|
|
221
|
-
*/
|
|
222
|
-
changePassword(oldPassword: string, newPassword: string): Promise<void>;
|
|
223
|
-
/**
|
|
224
|
-
* Initializes auth state (e.g., from stored tokens).
|
|
225
|
-
*
|
|
226
|
-
* LAZY and IDEMPOTENT: the first read of the state ({@link getState},
|
|
227
|
-
* {@link subscribe}, `useAuth()`) starts this same restore when nobody has called
|
|
228
|
-
* `initialize()`, and every later call shares the one promise instead of sending a
|
|
229
|
-
* second request. An app that keeps the template's explicit call behaves exactly as
|
|
230
|
-
* before; an app that loses that line still restores its session.
|
|
231
|
-
*
|
|
232
|
-
* With a stored token AND a stored user it marks the session `'authenticated'`
|
|
233
|
-
* SYNCHRONOUSLY — before its first `await` — so the first render is the
|
|
234
|
-
* signed-in UI and no page waits on a verification round trip. Any check
|
|
235
|
-
* (a refresh, the cookie-restore probe) settles behind that render, and only an
|
|
236
|
-
* explicit 401/403 ends the session; a network/5xx/404 failure keeps it and
|
|
237
|
-
* reports `'unavailable'`. With no stored user the client stays `'loading'`
|
|
238
|
-
* until the cookie restore decides.
|
|
239
|
-
*
|
|
240
|
-
* Do not put this call (or a `/me` request of your own) in front of the first
|
|
241
|
-
* render, and do not render a loading screen over a session it just restored:
|
|
242
|
-
* `whenRestored()` already resolves as soon as the restore has settled, and the
|
|
243
|
-
* HTTP gate built on it holds requests for exactly that window.
|
|
244
|
-
*/
|
|
245
|
-
initialize(): Promise<void>;
|
|
246
|
-
/**
|
|
247
|
-
* Re-checks a restored session against the server, in the background — the
|
|
248
|
-
* boot-time validation an app with a stored token needs when a revoked or
|
|
249
|
-
* expired token must sign the user out. Call it AFTER the first render
|
|
250
|
-
* (`initialize()` restores synchronously from storage; this costs one request).
|
|
251
|
-
*
|
|
252
|
-
* - The server confirms the user: the session is refreshed and {@link AuthState.status}
|
|
253
|
-
* stays `'authenticated'`.
|
|
254
|
-
* - The server answers 401 or 403: the token is dead — the stored session is
|
|
255
|
-
* cleared and the status becomes `'unauthenticated'`.
|
|
256
|
-
* - The server cannot confirm the session — a network failure, a 5xx, or a 404
|
|
257
|
-
* from a misconfigured {@link AuthClientConfig.currentUserEndpoint}: the
|
|
258
|
-
* session (token AND user) is KEPT and the status becomes `'unavailable'`, so
|
|
259
|
-
* the app can retry instead of signing the user out over a bad connection or a
|
|
260
|
-
* route that does not exist. The 404 error names `currentUserEndpoint`.
|
|
261
|
-
*
|
|
262
|
-
* Do not hand-write this beside the client: a parallel token/user store for a
|
|
263
|
-
* "validating"/"unavailable" flag is the race this method removes.
|
|
264
|
-
*
|
|
265
|
-
* Optional: a provider with no restorable session has nothing to validate.
|
|
266
|
-
*/
|
|
267
|
-
validateSession?(): Promise<void>;
|
|
268
|
-
/**
|
|
269
|
-
* Resolves when the session restore started by `initialize()` has settled — the point
|
|
270
|
-
* after which the client knows whether this visitor is signed in.
|
|
271
|
-
*
|
|
272
|
-
// … truncated — the full declaration is in node_modules/@molecule/app-react-native/dist
|
|
114
|
+
interface AuthClient<
|
|
115
|
+
T = UserProfile,
|
|
116
|
+
TRegister extends RegisterExtraShape<TRegister> = Record<never, never>,
|
|
117
|
+
> {
|
|
118
|
+
/** Returns the current authentication state snapshot. */
|
|
119
|
+
getState(): AuthState<T>
|
|
120
|
+
/** Returns whether the user is currently authenticated. */
|
|
121
|
+
isAuthenticated(): boolean
|
|
122
|
+
/** Gets the current user. */
|
|
123
|
+
getUser(): T | null
|
|
124
|
+
/** Optional ownership marker for the current session. */
|
|
125
|
+
getSessionRevision?(): number
|
|
126
|
+
/** Updates the cached user object (state + persistent storage) without hitting the network. */
|
|
127
|
+
setUser(user: T | null): void
|
|
128
|
+
/** Gets the current access token. */
|
|
129
|
+
getAccessToken(): string | null
|
|
130
|
+
/** Stores the access token in the configured token storage adapter (in a browser, Web Storage; `'memory'` where no browser store exists). */
|
|
131
|
+
setAccessToken(token: string | null): void
|
|
132
|
+
/** Adopts a session an out-of-band exchange already established: stores the access token (and the refresh token when given), caches the user, and sets the COMPLET… */
|
|
133
|
+
setSession(session: AuthSessionSeed<T>): void
|
|
134
|
+
/** Gets the refresh token. */
|
|
135
|
+
getRefreshToken(): string | null
|
|
136
|
+
/** Logs in with credentials. */
|
|
137
|
+
login(credentials: LoginCredentials): Promise<AuthResult<T>>
|
|
138
|
+
/** Logs out the current user. */
|
|
139
|
+
logout(): Promise<void>
|
|
140
|
+
/** Registers a new user. */
|
|
141
|
+
register(data: RegisterData<TRegister>): Promise<AuthResult<T>>
|
|
142
|
+
/** Refreshes the access token. */
|
|
143
|
+
refresh(): Promise<AuthResult<T>>
|
|
144
|
+
/** Requests a password reset. */
|
|
145
|
+
requestPasswordReset(data: PasswordResetRequest): Promise<void>
|
|
146
|
+
/** Confirms a password reset. */
|
|
147
|
+
confirmPasswordReset(data: PasswordResetConfirm): Promise<void>
|
|
148
|
+
/** Updates the current user's profile. */
|
|
149
|
+
updateProfile(data: Partial<T>): Promise<T>
|
|
150
|
+
/** Changes the current user's password. */
|
|
151
|
+
changePassword(oldPassword: string, newPassword: string): Promise<void>
|
|
152
|
+
/** Initializes auth state (e.g., from stored tokens). */
|
|
153
|
+
initialize(): Promise<void>
|
|
154
|
+
/** Re-checks a restored session against the server, in the background — the boot-time validation an app with a stored token needs when a revoked or expired token… */
|
|
155
|
+
validateSession?(): Promise<void>
|
|
156
|
+
/** Resolves when the session restore started by `initialize()` has settled — the point after which the client knows whether this visitor is signed in. */
|
|
157
|
+
whenRestored?(): Promise<void>
|
|
158
|
+
/** Subscribes to auth state changes. */
|
|
159
|
+
subscribe(callback: (state: AuthState<T>) => void): () => void
|
|
160
|
+
/** Subscribes to auth state changes (alias for subscribe). */
|
|
161
|
+
onAuthChange(callback: (state: AuthState<T>) => void): () => void
|
|
162
|
+
/** Gets the current access token (alias for getAccessToken). */
|
|
163
|
+
getToken?(): string | null
|
|
164
|
+
/** Adds an auth event listener. */
|
|
165
|
+
addEventListener(listener: AuthEventListener<T>): () => void
|
|
166
|
+
/** Destroys the auth client. */
|
|
167
|
+
destroy(): void
|
|
168
|
+
}
|
|
273
169
|
```
|
|
274
170
|
|
|
171
|
+
_(Member comments are shortened to their first sentence to fit; the full declaration is in `node_modules/@molecule/app-react-native/dist`.)_
|
|
172
|
+
|
|
275
173
|
#### `FormController`
|
|
276
174
|
|
|
277
175
|
Form controller interface.
|
|
@@ -357,9 +255,20 @@ interface FormController<T extends FormValuesConstraint<T> = Record<string, unkn
|
|
|
357
255
|
* `defaultValues`, or the values a previous `reset(values)` established.
|
|
358
256
|
* Passing `values` merges them over the current baseline and makes the
|
|
359
257
|
* result the new baseline, so a form reset to freshly loaded or saved data
|
|
360
|
-
* reads clean (`isDirty === false`).
|
|
258
|
+
* reads clean (`isDirty === false`). A changed non-null `id` replaces the
|
|
259
|
+
* record and cancels a pending submit.
|
|
361
260
|
*/
|
|
362
261
|
reset(values?: Partial<T>): void
|
|
262
|
+
/**
|
|
263
|
+
* Applies externally loaded values without clearing submission state.
|
|
264
|
+
*
|
|
265
|
+
* The new clean baseline is the original `defaultValues` plus this latest
|
|
266
|
+
* record, never a merge of earlier records. With `keepDirtyValues`, edited
|
|
267
|
+
* fields retain their values while pristine fields take the loaded values.
|
|
268
|
+
* A changed non-null `id` still replaces the record and cancels a pending
|
|
269
|
+
* submit. Equal-content baselines cause no update.
|
|
270
|
+
*/
|
|
271
|
+
updateValues(values: Partial<T>, resetOptions?: FormResetOptions): void
|
|
363
272
|
/**
|
|
364
273
|
* Handles form submission.
|
|
365
274
|
*/
|
|
@@ -382,6 +291,21 @@ interface FormController<T extends FormValuesConstraint<T> = Record<string, unkn
|
|
|
382
291
|
}
|
|
383
292
|
```
|
|
384
293
|
|
|
294
|
+
#### `FormResetOptions`
|
|
295
|
+
|
|
296
|
+
Options controlling how externally supplied values replace a form's baseline.
|
|
297
|
+
|
|
298
|
+
```typescript
|
|
299
|
+
interface FormResetOptions {
|
|
300
|
+
/**
|
|
301
|
+
* Keep fields whose current value differs from their baseline when `values`
|
|
302
|
+
* changes. Pristine fields still take the new values. False by default, so a
|
|
303
|
+
* new record can replace edits from the previous record.
|
|
304
|
+
*/
|
|
305
|
+
keepDirtyValues?: boolean
|
|
306
|
+
}
|
|
307
|
+
```
|
|
308
|
+
|
|
385
309
|
#### `FormOptions`
|
|
386
310
|
|
|
387
311
|
Form creation options.
|
|
@@ -393,6 +317,14 @@ interface FormOptions<T extends FormValuesConstraint<T>> {
|
|
|
393
317
|
* is created. Mutating this object afterwards does not change the baseline.
|
|
394
318
|
*/
|
|
395
319
|
defaultValues?: Partial<T>
|
|
320
|
+
/**
|
|
321
|
+
* Externally loaded values, merged over `defaultValues` as the clean
|
|
322
|
+
* baseline. Framework bindings also apply later content changes; use
|
|
323
|
+
* `resetOptions.keepDirtyValues` to preserve edits while pristine fields fill.
|
|
324
|
+
*/
|
|
325
|
+
values?: Partial<T>
|
|
326
|
+
/** Controls how framework bindings apply changed `values`. */
|
|
327
|
+
resetOptions?: FormResetOptions
|
|
396
328
|
/**
|
|
397
329
|
* Validation mode.
|
|
398
330
|
*/
|
|
@@ -869,8 +801,11 @@ interface UseFormResult<T extends FormValuesConstraint<T>> {
|
|
|
869
801
|
getError: (name: keyof T) => string | undefined
|
|
870
802
|
setError: (name: keyof T, error: string | undefined) => void
|
|
871
803
|
clearErrors: () => void
|
|
872
|
-
handleSubmit: (
|
|
804
|
+
handleSubmit: (
|
|
805
|
+
onSubmit: (values: T) => void | Promise<void>,
|
|
806
|
+
) => (event?: React.FormEvent) => Promise<void>
|
|
873
807
|
reset: (values?: Partial<T>) => void
|
|
808
|
+
updateValues: (values: Partial<T>, resetOptions?: FormResetOptions) => void
|
|
874
809
|
validate: () => Promise<boolean>
|
|
875
810
|
}
|
|
876
811
|
```
|
|
@@ -894,7 +829,8 @@ Result of useHttp hook.
|
|
|
894
829
|
```typescript
|
|
895
830
|
interface UseHttpResult<T> extends UseHttpState<T> {
|
|
896
831
|
/**
|
|
897
|
-
* Runs the request and resolves with its data, or `null` on failure
|
|
832
|
+
* Runs the request and resolves with its own data, or `null` on failure,
|
|
833
|
+
* even when a newer request or `reset` has superseded its displayed state.
|
|
898
834
|
*
|
|
899
835
|
* This function is IDENTITY-STABLE for as long as `method`, `url` and the HTTP
|
|
900
836
|
* client do not change, so it is safe in a `useEffect` dependency array. Its
|
|
@@ -921,11 +857,14 @@ interface UseHttpOptions<T> extends RequestConfig {
|
|
|
921
857
|
*/
|
|
922
858
|
immediate?: boolean
|
|
923
859
|
/**
|
|
924
|
-
* Callback
|
|
860
|
+
* Callback for each request that succeeds while mounted, including a request
|
|
861
|
+
* superseded by another `execute` or `reset`. Read `data` from the hook when
|
|
862
|
+
* only the newest request's result should drive the UI.
|
|
925
863
|
*/
|
|
926
864
|
onSuccess?: (data: T) => void
|
|
927
865
|
/**
|
|
928
|
-
* Callback
|
|
866
|
+
* Callback for each request that fails while mounted, including a request
|
|
867
|
+
* superseded by another `execute` or `reset`.
|
|
929
868
|
*/
|
|
930
869
|
onError?: (error: Error) => void
|
|
931
870
|
}
|
|
@@ -965,6 +904,27 @@ interface UseOAuthReturn {
|
|
|
965
904
|
}
|
|
966
905
|
```
|
|
967
906
|
|
|
907
|
+
#### `UseOptimisticValueResult`
|
|
908
|
+
|
|
909
|
+
What {@link useOptimisticValue} returns: the state to render and the two ways to change it.
|
|
910
|
+
|
|
911
|
+
```typescript
|
|
912
|
+
interface UseOptimisticValueResult<T> extends OptimisticValueState<T> {
|
|
913
|
+
/**
|
|
914
|
+
* Shows `next` at once and saves it, after any save already running.
|
|
915
|
+
*
|
|
916
|
+
* @param next - The value the person chose.
|
|
917
|
+
*/
|
|
918
|
+
set: (next: T) => void
|
|
919
|
+
/**
|
|
920
|
+
* Like `set`, computed from the value shown now (`update((on) => !on)`).
|
|
921
|
+
*
|
|
922
|
+
* @param change - Computes the next value from the value shown now.
|
|
923
|
+
*/
|
|
924
|
+
update: (change: (current: T) => T) => void
|
|
925
|
+
}
|
|
926
|
+
```
|
|
927
|
+
|
|
968
928
|
#### `UsePasswordResetReturn`
|
|
969
929
|
|
|
970
930
|
Return type for usePasswordReset hook.
|
|
@@ -1287,6 +1247,19 @@ interface ProviderProps {
|
|
|
1287
1247
|
}
|
|
1288
1248
|
```
|
|
1289
1249
|
|
|
1250
|
+
#### `SessionReadyProps`
|
|
1251
|
+
|
|
1252
|
+
Props for the `SessionReady` component.
|
|
1253
|
+
|
|
1254
|
+
```typescript
|
|
1255
|
+
interface SessionReadyProps {
|
|
1256
|
+
/** What renders once the initial restore settles — signed in, signed out, or unavailable. */
|
|
1257
|
+
children: ReactNode
|
|
1258
|
+
/** What renders while the session restore is still undecided; default nothing. */
|
|
1259
|
+
fallback?: ReactNode
|
|
1260
|
+
}
|
|
1261
|
+
```
|
|
1262
|
+
|
|
1290
1263
|
#### `StateProviderProps`
|
|
1291
1264
|
|
|
1292
1265
|
Props for state provider component.
|
|
@@ -1416,6 +1389,20 @@ Properties for molecule provider.
|
|
|
1416
1389
|
interface MoleculeProviderProps extends ProviderProps {
|
|
1417
1390
|
state?: StateProvider
|
|
1418
1391
|
auth?: AuthClient<unknown>
|
|
1392
|
+
/**
|
|
1393
|
+
* Render the app only once `auth` leaves its initial loading status ({@link SessionReadyProps}).
|
|
1394
|
+
* After a full page load a returning visitor's session is restored by one request, and until
|
|
1395
|
+
* it answers `useAuth().user` is `null` on every page — a public page's signed-in action
|
|
1396
|
+
* (`if (!user) return`, a redirect to `/login`) then treats a signed-in visitor as signed out.
|
|
1397
|
+
* When restoration succeeds, every page's first render reads the restored user. An
|
|
1398
|
+
* `'unavailable'` session also renders, but remains unconfirmed and may have a null user.
|
|
1399
|
+
* A visitor with no session to restore settles in microtasks without a request.
|
|
1400
|
+
* Ignored without `auth`. Synchronous SSR renders the fallback for a loading client:
|
|
1401
|
+
* initialize a request-scoped client first, or leave this disabled for SSR.
|
|
1402
|
+
*/
|
|
1403
|
+
awaitSession?: boolean
|
|
1404
|
+
/** Rendered instead of the app while {@link MoleculeProviderProps.awaitSession} waits; default nothing. */
|
|
1405
|
+
sessionFallback?: ReactNode
|
|
1419
1406
|
theme?: ThemeProvider
|
|
1420
1407
|
router?: Router
|
|
1421
1408
|
i18n?: I18nProvider
|
|
@@ -1466,7 +1453,9 @@ interface UseAuthResult<
|
|
|
1466
1453
|
* The session state as one value — render from this instead of combining
|
|
1467
1454
|
* `initialized`/`authenticated`/`loading`. A stored token AND user make it
|
|
1468
1455
|
* `'authenticated'` on the first render; only `'loading'` means "no decision
|
|
1469
|
-
* yet", so a route guard waits on that and nothing else.
|
|
1456
|
+
* yet", so a route guard waits on that and nothing else. `'unavailable'` keeps
|
|
1457
|
+
* a session candidate for retry and can have a null profile; redirect only on
|
|
1458
|
+
* `'unauthenticated'`.
|
|
1470
1459
|
*/
|
|
1471
1460
|
status: AuthState<T>['status']
|
|
1472
1461
|
state: AuthState<T>
|
|
@@ -1486,8 +1475,10 @@ interface UseAuthResult<
|
|
|
1486
1475
|
* `authenticated` read signed out.
|
|
1487
1476
|
*/
|
|
1488
1477
|
setSession: AuthClient<T>['setSession']
|
|
1478
|
+
/** Whether a session is authenticated locally; this can be false while unavailable. */
|
|
1489
1479
|
isAuthenticated: boolean
|
|
1490
1480
|
isLoading: boolean
|
|
1481
|
+
/** The cached profile, which can be null while an unavailable candidate is retained. */
|
|
1491
1482
|
user: T | null
|
|
1492
1483
|
}
|
|
1493
1484
|
```
|
|
@@ -2011,6 +2002,12 @@ function useAuthClient<
|
|
|
2011
2002
|
|
|
2012
2003
|
Hook for authentication state and actions.
|
|
2013
2004
|
|
|
2005
|
+
`status === 'loading'` is undecided: wait for it and redirect only on
|
|
2006
|
+
`status === 'unauthenticated'`. `'unavailable'` keeps the session candidate
|
|
2007
|
+
for retry, but `isAuthenticated` can be false and `user` can be null while a
|
|
2008
|
+
token/cookie-only restore has no cached profile. A restore failure other than
|
|
2009
|
+
401/403 never signs out.
|
|
2010
|
+
|
|
2014
2011
|
Pass the app's user type — the SAME type used for the auth client and its
|
|
2015
2012
|
config (`createJWTAuthClient<MyUser>`, `AuthClientConfig<MyUser>`) — so
|
|
2016
2013
|
`user` and `setSession`/`setUser` are typed for the pages:
|
|
@@ -2214,7 +2211,7 @@ function useForm<T extends FormValuesConstraint<T> = Record<string, unknown>>(
|
|
|
2214
2211
|
): UseFormResult<T>
|
|
2215
2212
|
```
|
|
2216
2213
|
|
|
2217
|
-
- `options` — Form options. `defaultValues`, `mode` and the form-level `validate` are forwarded to the provider;
|
|
2214
|
+
- `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.
|
|
2218
2215
|
|
|
2219
2216
|
**Returns:** Form state and methods
|
|
2220
2217
|
|
|
@@ -3114,6 +3111,8 @@ function MoleculeProvider({
|
|
|
3114
3111
|
workspace,
|
|
3115
3112
|
editor,
|
|
3116
3113
|
preview,
|
|
3114
|
+
awaitSession,
|
|
3115
|
+
sessionFallback,
|
|
3117
3116
|
}: MoleculeProviderProps): React.ReactElement
|
|
3118
3117
|
```
|
|
3119
3118
|
|
|
@@ -3121,6 +3120,38 @@ function MoleculeProvider({
|
|
|
3121
3120
|
|
|
3122
3121
|
**Returns:** The rendered combined provider element.
|
|
3123
3122
|
|
|
3123
|
+
#### `SessionReady(props)`
|
|
3124
|
+
|
|
3125
|
+
Renders its children once `useAuth().status` has left `'loading'` (signed in, signed out,
|
|
3126
|
+
or `'unavailable'`), and `fallback` until then. It never redirects. An unavailable session
|
|
3127
|
+
is unconfirmed and may still have `user === null`; handle that status separately from sign-out.
|
|
3128
|
+
|
|
3129
|
+
After a full page load a returning visitor's session is restored by one request. Until it
|
|
3130
|
+
answers, `useAuth().user` is `null` everywhere, so a public page that renders a signed-in action
|
|
3131
|
+
at once lets that action run against "signed out": a Follow button whose handler starts with
|
|
3132
|
+
`if (!user) return` ignores the click, one that redirects to `/login` signs the visitor out of
|
|
3133
|
+
the flow. Wrapping the routes (or passing `awaitSession` to `MoleculeProvider`) makes every
|
|
3134
|
+
page's first render read the restored user when restoration succeeds.
|
|
3135
|
+
|
|
3136
|
+
A visitor with no session to restore settles in microtasks without a request. Must render
|
|
3137
|
+
inside the auth context (`AuthProvider`, or `MoleculeProvider` with `auth`). A client that
|
|
3138
|
+
nobody initialized starts its restore on this first read.
|
|
3139
|
+
The bundled JWT client bounds each auth request (default 10 seconds) and settles a timeout
|
|
3140
|
+
as `'unavailable'`. Custom clients must also settle their initial session status.
|
|
3141
|
+
|
|
3142
|
+
Synchronous SSR renders the fallback while a client is loading. Initialize a request-scoped
|
|
3143
|
+
client before rendering to include its decided content, or leave the hold disabled for SSR.
|
|
3144
|
+
|
|
3145
|
+
Route-level redirects for signed-in-only pages stay with `AuthGuard` (`@molecule/app-ui-react`).
|
|
3146
|
+
|
|
3147
|
+
```typescript
|
|
3148
|
+
function SessionReady({ children, fallback }: SessionReadyProps): ReactNode
|
|
3149
|
+
```
|
|
3150
|
+
|
|
3151
|
+
- `props` — {@link SessionReadyProps}.
|
|
3152
|
+
|
|
3153
|
+
**Returns:** The children once the session is decided, otherwise the fallback.
|
|
3154
|
+
|
|
3124
3155
|
### Constants
|
|
3125
3156
|
|
|
3126
3157
|
#### `DEFAULT_AGENT_NAME`
|
|
@@ -3257,6 +3288,27 @@ const useAsyncState: <T>(initialState: T) => [T, AsyncSetState<T>, AsyncExtendSt
|
|
|
3257
3288
|
|
|
3258
3289
|
**Returns:** Tuple of [state, asyncSetState, asyncExtendState]
|
|
3259
3290
|
|
|
3291
|
+
#### `useOptimisticValue`
|
|
3292
|
+
|
|
3293
|
+
A server-backed value — a favorite, follow, like or bookmark button, a rating, a quantity, a
|
|
3294
|
+
setting switch — that changes on the first render after a tap and is saved one change at a
|
|
3295
|
+
time, in order. A tap during a save is saved right after it; only a failure of the newest
|
|
3296
|
+
change puts the server value back. See `createOptimisticValue` in `@molecule/app-state`.
|
|
3297
|
+
|
|
3298
|
+
`value` is the server's value from props or a query. A new `value` is taken only when it
|
|
3299
|
+
differs (by `equals`) from the one the hook last received, and only while nothing is being
|
|
3300
|
+
saved, so a parent re-render or a refetch of older data never flips the button mid-save. The
|
|
3301
|
+
latest `commit` and `onError` are always used. Give the component a `key` per record, so one
|
|
3302
|
+
record's pending change never shows on another.
|
|
3303
|
+
|
|
3304
|
+
```typescript
|
|
3305
|
+
const useOptimisticValue: <T>(options: OptimisticValueOptions<T>) => UseOptimisticValueResult<T>
|
|
3306
|
+
```
|
|
3307
|
+
|
|
3308
|
+
- `options` — The server's current value and how to save a change.
|
|
3309
|
+
|
|
3310
|
+
**Returns:** The value to render, whether a save is pending, the newest failure, and `set`/`update`.
|
|
3311
|
+
|
|
3260
3312
|
#### `usePromise`
|
|
3261
3313
|
|
|
3262
3314
|
Hook that wraps an async function with state tracking.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@molecule/app-react-native",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.3",
|
|
4
4
|
"description": "React Native framework bindings for molecule.dev",
|
|
5
5
|
"homepage": "https://www.molecule.dev/packages/app-react-native",
|
|
6
6
|
"type": "module",
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"directory": "packages/app/frameworks/react-native"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
|
-
"@molecule/app-react": "3.
|
|
36
|
+
"@molecule/app-react": "3.3.1",
|
|
37
37
|
"@types/node": "26.6.5",
|
|
38
38
|
"react": "19.3.1",
|
|
39
39
|
"typescript": "6.0.3",
|