@molecule/app-react-native 1.0.2 → 1.0.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.
Files changed (3) hide show
  1. package/LICENSE +111 -24
  2. package/README.md +1708 -1367
  3. package/package.json +5 -5
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-09-15T13:40:29.572Z
6
+ Generated: 2026-10-23T14:59:33.332Z
7
7
  -->
8
8
 
9
9
  # @molecule/app-react-native
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
  React Native framework bindings for molecule.dev.
16
12
 
17
13
  Re-exports every hook and provider from `@molecule/app-react` (they are pure
@@ -19,6 +15,10 @@ React — no DOM dependency) and adds RN-specific hooks: `useAppState`
19
15
  (foreground/background), `useBackHandler` (Android back button),
20
16
  `useKeyboardHeight`, and `useSafeArea`.
21
17
 
18
+ > **Auto-generated, AI-first package reference** for the [molecule.dev](https://molecule.dev) ecosystem.
19
+ > It is written to be read by coding agents as much as by people, and is generated from this
20
+ > package's source — edit `src/index.ts` JSDoc, not this file.
21
+
22
22
  ## Quick Start
23
23
 
24
24
  ```tsx
@@ -64,140 +64,17 @@ npm install @molecule/app-react-native @molecule/app-keyboard @molecule/app-life
64
64
 
65
65
  ### Interfaces
66
66
 
67
- #### `AgentIdentity`
68
-
69
- Display identity for the AI coding agent and the host product, used to
70
- interpolate the `{{agentName}}` / `{{productName}}` tokens in shared chat/IDE
71
- copy. A consuming app sets these to its own agent + product brand names; the
72
- shared packages fall back to {@link DEFAULT_AGENT_IDENTITY} when it does not.
73
-
74
- ```typescript
75
- interface AgentIdentity {
76
- /** Display name of the AI coding agent. Defaults to {@link DEFAULT_AGENT_NAME}. */
77
- agentName: string
78
- /** Display name of the host product / IDE. Defaults to {@link DEFAULT_PRODUCT_NAME}. */
79
- productName: string
80
- }
81
- ```
82
-
83
- #### `AuthClient`
84
-
85
- Auth client interface that all auth bond packages must implement.
86
- Provides login/logout/register flows, token management, profile
87
- updates, and auth state subscription.
88
-
89
- ```typescript
90
- interface AuthClient<T = UserProfile> {
91
- /**
92
- * Returns the current authentication state snapshot.
93
- */
94
- getState(): AuthState<T>
95
- /**
96
- * Returns whether the user is currently authenticated.
97
- */
98
- isAuthenticated(): boolean
99
- /**
100
- * Gets the current user.
101
- */
102
- getUser(): T | null
103
- /**
104
- * Updates the cached user object (state + persistent storage) without
105
- * hitting the network. Intended for local refreshes after a per-app
106
- * mutation (e.g., the user just PATCHed their own profile and the
107
- * server returned the canonical row). Does NOT change tokens.
108
- */
109
- setUser(user: T | null): void
110
- /**
111
- * Gets the current access token.
112
- */
113
- getAccessToken(): string | null
114
- /**
115
- * Stores the access token in the configured token storage adapter (in-memory
116
- * by default). Use this to seed the token after an out-of-band exchange (e.g.
117
- * the OAuth code→token redirect) instead of writing to `localStorage` directly,
118
- * which would violate the in-memory-default storage contract and make the bearer
119
- * token JS-readable (XSS-exfiltratable). Pass `null` to clear it.
120
- */
121
- setAccessToken(token: string | null): void
122
- /**
123
- * Gets the refresh token.
124
- */
125
- getRefreshToken(): string | null
126
- /**
127
- * Logs in with credentials.
128
- */
129
- login(credentials: LoginCredentials): Promise<AuthResult<T>>
130
- /**
131
- * Logs out the current user.
132
- */
133
- logout(): Promise<void>
134
- /**
135
- * Registers a new user.
136
- */
137
- register(data: RegisterData): Promise<AuthResult<T>>
138
- /**
139
- * Refreshes the access token.
140
- */
141
- refresh(): Promise<AuthResult<T>>
142
- /**
143
- * Requests a password reset.
144
- */
145
- requestPasswordReset(data: PasswordResetRequest): Promise<void>
146
- /**
147
- * Confirms a password reset.
148
- */
149
- confirmPasswordReset(data: PasswordResetConfirm): Promise<void>
150
- /**
151
- * Updates the current user's profile.
152
- */
153
- updateProfile(data: Partial<T>): Promise<T>
154
- /**
155
- * Changes the current user's password.
156
- */
157
- changePassword(oldPassword: string, newPassword: string): Promise<void>
158
- /**
159
- * Initializes auth state (e.g., from stored tokens).
160
- */
161
- initialize(): Promise<void>
162
- /**
163
- * Subscribes to auth state changes.
164
- */
165
- subscribe(callback: (state: AuthState<T>) => void): () => void
166
- /**
167
- * Subscribes to auth state changes (alias for subscribe).
168
- */
169
- onAuthChange(callback: (state: AuthState<T>) => void): () => void
170
- /**
171
- * Gets the current access token (alias for getAccessToken).
172
- */
173
- getToken?(): string | null
174
- /**
175
- * Adds an auth event listener.
176
- */
177
- addEventListener(listener: AuthEventListener): () => void
178
- /**
179
- * Destroys the auth client.
180
- */
181
- destroy(): void
182
- }
183
- ```
184
-
185
- #### `AuthProviderProps`
186
-
187
- Props for auth provider component.
188
-
189
- ```typescript
190
- interface AuthProviderProps<T = unknown> extends ProviderProps {
191
- client: AuthClient<T>
192
- }
193
- ```
194
-
195
67
  #### `AuthState`
196
68
 
197
69
  Reactive authentication state snapshot (initialized, authenticated, user, loading, and error).
198
70
 
199
71
  ```typescript
200
72
  interface AuthState<T = UserProfile> {
73
+ /**
74
+ * The session's state as one value — render from this instead of combining
75
+ * `initialized`/`authenticated`/`loading`. See {@link AuthStatus}.
76
+ */
77
+ status: AuthStatus
201
78
  /**
202
79
  * Whether auth state has been initialized.
203
80
  */
@@ -221,24 +98,178 @@ interface AuthState<T = UserProfile> {
221
98
  }
222
99
  ```
223
100
 
224
- #### `ChatProviderProps`
225
-
226
- Props for the ChatProvider React component.
227
-
228
- ```typescript
229
- interface ChatProviderProps extends ProviderProps {
230
- provider: ChatProvider
231
- }
232
- ```
233
-
234
- #### `EditorProviderProps`
101
+ #### `AuthClient`
235
102
 
236
- Props for editor provider component.
103
+ Auth client interface that all auth bond packages must implement.
104
+ Provides login/logout/register flows, token management, profile
105
+ updates, and auth state subscription.
237
106
 
238
107
  ```typescript
239
- interface EditorProviderProps extends ProviderProps {
240
- provider: EditorProvider
241
- }
108
+ interface AuthClient<T = UserProfile, TRegister extends RegisterExtraShape<TRegister> = Record<never, never>> {
109
+ /**
110
+ * Returns the current authentication state snapshot.
111
+ *
112
+ * READING the state starts the client's one session restore when nobody has called
113
+ * {@link initialize} yet — lazily and exactly once, sharing the promise an explicit
114
+ * `initialize()` returns. A hook (`useAuth()`), a subscriber, `isAuthenticated()` and
115
+ * `getUser()` are reads too, so a client whose entry file dropped the template's
116
+ * `authClient.initialize()` line still restores instead of reporting `'loading'`
117
+ * forever.
118
+ */
119
+ getState(): AuthState<T>;
120
+ /**
121
+ * Returns whether the user is currently authenticated.
122
+ */
123
+ isAuthenticated(): boolean;
124
+ /**
125
+ * Gets the current user.
126
+ */
127
+ getUser(): T | null;
128
+ /**
129
+ * Optional ownership marker for the current session. Compare values only within
130
+ * this client: replacing or ending a session changes it, including re-adopting
131
+ * the same token and user. Profile updates and same-session refreshes keep it.
132
+ * Consumers can use it to discard stale async work without treating editable
133
+ * user fields as an immutable account identifier. Providers without this
134
+ * capability require the consumer's own stable identity check.
135
+ */
136
+ getSessionRevision?(): number;
137
+ /**
138
+ * Updates the cached user object (state + persistent storage) without
139
+ * hitting the network. Intended for local refreshes after a per-app
140
+ * mutation (e.g., the user just PATCHed their own profile and the
141
+ * server returned the canonical row). Does NOT change tokens.
142
+ *
143
+ * This does not sign the client in: `authenticated` and `status` are
144
+ * unchanged, so an anonymous client stays anonymous. Use
145
+ * {@link login} / {@link register} for a credential exchange, or
146
+ * {@link setSession} when the token was issued outside the client.
147
+ */
148
+ setUser(user: T | null): void;
149
+ /**
150
+ * Gets the current access token.
151
+ */
152
+ getAccessToken(): string | null;
153
+ /**
154
+ * Stores the access token in the configured token storage adapter (in a
155
+ * browser, Web Storage; `'memory'` where no browser store exists). Use this
156
+ * to seed the token after an out-of-band exchange (e.g. the OAuth
157
+ * code→token redirect) instead of writing to `localStorage` directly,
158
+ * which would violate the storage contract and make a stored bearer token
159
+ * JS-readable (XSS-exfiltratable). Pass `null` to clear it.
160
+ *
161
+ * This changes token storage only; it does not sign the client in
162
+ * (`authenticated` and `status` are unchanged). Use {@link login} /
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 response. If the session is explicitly replaced or ended
212
+ * while the request is pending, that response does not replace the current
213
+ * session's user or persisted cache.
214
+ */
215
+ updateProfile(data: Partial<T>): Promise<T>;
216
+ /**
217
+ * Changes the current user's password.
218
+ */
219
+ changePassword(oldPassword: string, newPassword: string): Promise<void>;
220
+ /**
221
+ * Initializes auth state (e.g., from stored tokens).
222
+ *
223
+ * LAZY and IDEMPOTENT: the first read of the state ({@link getState},
224
+ * {@link subscribe}, `useAuth()`) starts this same restore when nobody has called
225
+ * `initialize()`, and every later call shares the one promise instead of sending a
226
+ * second request. An app that keeps the template's explicit call behaves exactly as
227
+ * before; an app that loses that line still restores its session.
228
+ *
229
+ * With a stored token AND a stored user it marks the session `'authenticated'`
230
+ * SYNCHRONOUSLY — before its first `await` — so the first render is the
231
+ * signed-in UI and no page waits on a verification round trip. Any check
232
+ * (a refresh, the cookie-restore probe) settles behind that render, and only an
233
+ * explicit 401/403 ends the session; a network/5xx/404 failure keeps it and
234
+ * reports `'unavailable'`. With no stored user the client stays `'loading'`
235
+ * until the cookie restore decides.
236
+ *
237
+ * Do not put this call (or a `/me` request of your own) in front of the first
238
+ * render, and do not render a loading screen over a session it just restored:
239
+ * `whenRestored()` already resolves as soon as the restore has settled, and the
240
+ * HTTP gate built on it holds requests for exactly that window.
241
+ */
242
+ initialize(): Promise<void>;
243
+ /**
244
+ * Re-checks a restored session against the server, in the background — the
245
+ * boot-time validation an app with a stored token needs when a revoked or
246
+ * expired token must sign the user out. Call it AFTER the first render
247
+ * (`initialize()` restores synchronously from storage; this costs one request).
248
+ *
249
+ * - The server confirms the user: the session is refreshed and {@link AuthState.status}
250
+ * stays `'authenticated'`.
251
+ * - The server answers 401 or 403: the token is dead — the stored session is
252
+ * cleared and the status becomes `'unauthenticated'`.
253
+ * - The server cannot confirm the session — a network failure, a 5xx, or a 404
254
+ * from a misconfigured {@link AuthClientConfig.currentUserEndpoint}: the
255
+ * session (token AND user) is KEPT and the status becomes `'unavailable'`, so
256
+ * the app can retry instead of signing the user out over a bad connection or a
257
+ * route that does not exist. The 404 error names `currentUserEndpoint`.
258
+ *
259
+ * Do not hand-write this beside the client: a parallel token/user store for a
260
+ * "validating"/"unavailable" flag is the race this method removes.
261
+ *
262
+ * Optional: a provider with no restorable session has nothing to validate.
263
+ */
264
+ validateSession?(): Promise<void>;
265
+ /**
266
+ * Resolves when the session restore started by `initialize()` has settled — the point
267
+ * after which the client knows whether this visitor is signed in.
268
+ *
269
+ * Resolves IMMEDIATELY when no restore is in flight: before `initialize()` is ever
270
+ * called, and after it has finished. A restore that failed resolves too (it settled the
271
+ * question), so an HTTP client can await this before every request without risking one
272
+ // … truncated — the full declaration is in node_modules/@molecule/app-react-native/dist
242
273
  ```
243
274
 
244
275
  #### `FormController`
@@ -320,7 +351,13 @@ interface FormController<T extends Record<string, unknown> = Record<string, unkn
320
351
  */
321
352
  validate(): Promise<boolean>
322
353
  /**
323
- * Resets the form to initial values.
354
+ * Resets the form and clears errors, touched fields and submission state.
355
+ *
356
+ * With no argument it restores the current baseline — the initial
357
+ * `defaultValues`, or the values a previous `reset(values)` established.
358
+ * Passing `values` merges them over the current baseline and makes the
359
+ * result the new baseline, so a form reset to freshly loaded or saved data
360
+ * reads clean (`isDirty === false`).
324
361
  */
325
362
  reset(values?: Partial<T>): void
326
363
  /**
@@ -352,7 +389,8 @@ Form creation options.
352
389
  ```typescript
353
390
  interface FormOptions<T extends Record<string, unknown>> {
354
391
  /**
355
- * Default values.
392
+ * Default values, captured as the form's clean baseline when the controller
393
+ * is created. Mutating this object afterwards does not change the baseline.
356
394
  */
357
395
  defaultValues?: Partial<T>
358
396
  /**
@@ -393,7 +431,8 @@ interface HttpClient {
393
431
  */
394
432
  defaultHeaders: Record<string, string>
395
433
  /**
396
- * Makes a generic HTTP request.
434
+ * Makes a generic HTTP request. `data` is a field of THIS config object — the same body
435
+ * `post(url, data, config)` takes as its second argument.
397
436
  */
398
437
  request<T = unknown>(config: FullRequestConfig): Promise<HttpResponse<T>>
399
438
  /**
@@ -401,15 +440,19 @@ interface HttpClient {
401
440
  */
402
441
  get<T = unknown>(url: string, config?: RequestConfig): Promise<HttpResponse<T>>
403
442
  /**
404
- * Makes a POST request.
443
+ * Makes a POST request. `data` is the request BODY, not a config object: the wire body is
444
+ * `data` itself, so `post(url, { data: body })` sends `{"data":body}` — pass `body` directly.
445
+ * A config (headers, params) is the THIRD argument.
405
446
  */
406
447
  post<T = unknown>(url: string, data?: unknown, config?: RequestConfig): Promise<HttpResponse<T>>
407
448
  /**
408
- * Makes a PUT request.
449
+ * Makes a PUT request. `data` is the request BODY (second argument) — never `{ data: body }`,
450
+ * which sends `{"data":body}`; a config is the THIRD argument.
409
451
  */
410
452
  put<T = unknown>(url: string, data?: unknown, config?: RequestConfig): Promise<HttpResponse<T>>
411
453
  /**
412
- * Makes a PATCH request.
454
+ * Makes a PATCH request. `data` is the request BODY (second argument) — never `{ data: body }`,
455
+ * which sends `{"data":body}`; a config is the THIRD argument.
413
456
  */
414
457
  patch<T = unknown>(url: string, data?: unknown, config?: RequestConfig): Promise<HttpResponse<T>>
415
458
  /**
@@ -448,77 +491,6 @@ interface HttpClient {
448
491
  }
449
492
  ```
450
493
 
451
- #### `HttpProviderProps`
452
-
453
- Props for http provider component.
454
-
455
- ```typescript
456
- interface HttpProviderProps extends ProviderProps {
457
- client: HttpClient
458
- }
459
- ```
460
-
461
- #### `I18nProviderProps`
462
-
463
- Props for i18n provider component.
464
-
465
- ```typescript
466
- interface I18nProviderProps extends ProviderProps {
467
- provider: I18nProvider
468
- }
469
- ```
470
-
471
- #### `LoggerProviderProps`
472
-
473
- Props for logger provider component.
474
-
475
- ```typescript
476
- interface LoggerProviderProps extends ProviderProps {
477
- provider: LoggerProvider
478
- }
479
- ```
480
-
481
- #### `MoleculeProviderProps`
482
-
483
- Properties for molecule provider.
484
-
485
- ```typescript
486
- interface MoleculeProviderProps extends ProviderProps {
487
- state?: StateProvider
488
- auth?: AuthClient<unknown>
489
- theme?: ThemeProvider
490
- router?: Router
491
- i18n?: I18nProvider
492
- http?: HttpClient
493
- storage?: StorageProvider
494
- logger?: LoggerProvider
495
- chat?: ChatProvider
496
- workspace?: WorkspaceProvider
497
- editor?: EditorProvider
498
- preview?: PreviewProvider
499
- }
500
- ```
501
-
502
- #### `PreviewProviderProps`
503
-
504
- Props for preview provider component.
505
-
506
- ```typescript
507
- interface PreviewProviderProps extends ProviderProps {
508
- provider: PreviewProvider
509
- }
510
- ```
511
-
512
- #### `ProviderProps`
513
-
514
- Props for provider components.
515
-
516
- ```typescript
517
- interface ProviderProps {
518
- children: ReactNode
519
- }
520
- ```
521
-
522
494
  #### `Router`
523
495
 
524
496
  Client-side router providing navigation, guards, route matching, and history control.
@@ -645,163 +617,124 @@ interface RouterConfig {
645
617
  }
646
618
  ```
647
619
 
648
- #### `RouterProviderProps`
620
+ #### `StoreConfig`
649
621
 
650
- Props for router provider component.
622
+ Configuration for creating a store (initial state, optional name, and middleware chain).
651
623
 
652
624
  ```typescript
653
- interface RouterProviderProps extends ProviderProps {
654
- router: Router
625
+ interface StoreConfig<T> {
626
+ /**
627
+ * Initial state value.
628
+ */
629
+ initialState: T
630
+ /**
631
+ * Optional name for debugging.
632
+ */
633
+ name?: string
634
+ /**
635
+ * Optional middleware functions.
636
+ */
637
+ middleware?: StoreMiddleware<T>[]
655
638
  }
656
639
  ```
657
640
 
658
- #### `SendMessageOptions`
641
+ #### `Store`
659
642
 
660
- Options for {@link UseChatResult.sendMessage}.
643
+ Reactive state container with getState, setState, subscribe, and destroy.
644
+
645
+ All state management providers must implement this interface.
661
646
 
662
647
  ```typescript
663
- interface SendMessageOptions {
664
- /**
665
- * Skip the optimistic local user-message bubble. The text is still sent to
666
- * the server. Used for ask_user responses: the answer is folded into the
667
- * ask_user tool card (a checkmark on the chosen option, or the custom text
668
- * shown in-card) rather than echoed as a separate message below it.
669
- */
670
- suppressUserMessage?: boolean
648
+ interface Store<T> {
671
649
  /**
672
- * Mark this send as issued automatically on the user's behalf (e.g. an
673
- * auto-fix prompt). The optimistic local bubble and the persisted message are
674
- * flagged `automatic` so the chat renders it in the distinct auto-sent style
675
- * (agent avatar + accent border) instead of looking like the user typed it.
650
+ * Gets the current state.
676
651
  */
677
- automatic?: boolean
652
+ getState(): T
678
653
  /**
679
- * Mark this send as the answer to the pending `ask_user` question. The most
680
- * recent unanswered `ask_user` tool call in the store is resolved in place —
681
- * its `output` is set to this answer — so the chosen option stays checked
682
- * across remounts (e.g. the discovery→IDE transition) instead of relying on
683
- * ephemeral component state that the answer's selection would otherwise lose.
684
- * Distinct from {@link suppressUserMessage} (which the post-boot kickoff also
685
- * sets) so resolving never misfires on a non-ask_user suppressed send.
654
+ * Sets the state (partial or via updater function).
686
655
  */
687
- askUserAnswer?: boolean
656
+ setState(partial: Partial<T> | ((state: T) => Partial<T>)): void
688
657
  /**
689
- * Mark an {@link automatic} send as directly requested by the user (e.g. the
690
- * editor's "Fix with AI" action, the broken-preview overlay's "Fix with AI"
691
- * button) rather than dispatched autonomously by the platform. A user Stop
692
- * suppresses autonomous automatic sends until the user re-engages; a
693
- * user-initiated one IS that re-engagement — it clears the stop and sends.
658
+ * Subscribes to state changes.
659
+ * Returns an unsubscribe function.
694
660
  */
695
- userInitiated?: boolean
661
+ subscribe(listener: StateListener<T>): () => void
696
662
  /**
697
- * Send on the SIDE CHANNEL: a human-to-human message (e.g. a team note) the
698
- * server intercepts before running any agent turn. When the provider supports
699
- * `sendSideMessage`, the send goes out IMMEDIATELY on an independent request —
700
- * it never queues behind an active turn, never takes over the streaming
701
- * state, and never tears down remote-turn tracking (a viewer's note while
702
- * watching a teammate's turn must not stop the watching). Falls back to the
703
- * normal send path on providers without side-channel support.
663
+ * Destroys the store and cleans up subscriptions.
704
664
  */
705
- sideChannel?: boolean
665
+ destroy(): void
706
666
  }
707
667
  ```
708
668
 
709
- #### `StateProviderProps`
669
+ #### `Theme`
710
670
 
711
- Props for state provider component.
671
+ Complete theme definition.
712
672
 
713
673
  ```typescript
714
- interface StateProviderProps extends ProviderProps {
715
- provider: StateProvider
716
- }
717
- ```
718
-
719
- #### `StorageProviderProps`
720
-
721
- Props for storage provider component.
722
-
723
- ```typescript
724
- interface StorageProviderProps extends ProviderProps {
725
- provider: StorageProvider
674
+ interface Theme {
675
+ name: string
676
+ mode: 'light' | 'dark'
677
+ colors: ThemeColors
678
+ breakpoints: ThemeBreakpoints
679
+ spacing: ThemeSpacing
680
+ typography: ThemeTypography
681
+ borderRadius: ThemeBorderRadius
682
+ shadows: ThemeShadows
683
+ transitions: ThemeTransitions
684
+ zIndex: ThemeZIndex
726
685
  }
727
686
  ```
728
687
 
729
- #### `Store`
730
-
731
- Reactive state container with getState, setState, subscribe, and destroy.
688
+ #### `UseBackHandlerOptions`
732
689
 
733
- All state management providers must implement this interface.
690
+ Options for the useBackHandler hook.
734
691
 
735
692
  ```typescript
736
- interface Store<T> {
737
- /**
738
- * Gets the current state.
739
- */
740
- getState(): T
741
- /**
742
- * Sets the state (partial or via updater function).
743
- */
744
- setState(partial: Partial<T> | ((state: T) => Partial<T>)): void
745
- /**
746
- * Subscribes to state changes.
747
- * Returns an unsubscribe function.
748
- */
749
- subscribe(listener: StateListener<T>): () => void
750
- /**
751
- * Destroys the store and cleans up subscriptions.
752
- */
753
- destroy(): void
693
+ interface UseBackHandlerOptions {
694
+ /** Whether the handler is enabled. Defaults to true. */
695
+ enabled?: boolean
754
696
  }
755
697
  ```
756
698
 
757
- #### `StoreConfig`
699
+ #### `UseAppStateResult`
758
700
 
759
- Configuration for creating a store (initial state, optional name, and middleware chain).
701
+ Result from the useAppState hook.
760
702
 
761
703
  ```typescript
762
- interface StoreConfig<T> {
763
- /**
764
- * Initial state value.
765
- */
766
- initialState: T
767
- /**
768
- * Optional name for debugging.
769
- */
770
- name?: string
771
- /**
772
- * Optional middleware functions.
773
- */
774
- middleware?: StoreMiddleware<T>[]
704
+ interface UseAppStateResult {
705
+ /** Current app state: 'active' | 'background' | 'inactive' */
706
+ appState: string
707
+ /** Whether the app is in the foreground */
708
+ isActive: boolean
775
709
  }
776
710
  ```
777
711
 
778
- #### `Theme`
712
+ #### `UseKeyboardHeightResult`
779
713
 
780
- Complete theme definition.
714
+ Result from the useKeyboardHeight hook.
781
715
 
782
716
  ```typescript
783
- interface Theme {
784
- name: string
785
- mode: 'light' | 'dark'
786
- colors: ThemeColors
787
- breakpoints: ThemeBreakpoints
788
- spacing: ThemeSpacing
789
- typography: ThemeTypography
790
- borderRadius: ThemeBorderRadius
791
- shadows: ThemeShadows
792
- transitions: ThemeTransitions
793
- zIndex: ThemeZIndex
717
+ interface UseKeyboardHeightResult {
718
+ /** Current keyboard height in points (0 when hidden) */
719
+ keyboardHeight: number
720
+ /** Whether the keyboard is currently visible */
721
+ isKeyboardVisible: boolean
794
722
  }
795
723
  ```
796
724
 
797
- #### `ThemeProviderProps`
725
+ #### `AgentIdentity`
798
726
 
799
- Props for theme provider component.
727
+ Display identity for the AI coding agent and the host product, used to
728
+ interpolate the `{{agentName}}` / `{{productName}}` tokens in shared chat/IDE
729
+ copy. A consuming app sets these to its own agent + product brand names; the
730
+ shared packages fall back to {@link DEFAULT_AGENT_IDENTITY} when it does not.
800
731
 
801
732
  ```typescript
802
- interface ThemeProviderProps extends ProviderProps {
803
- provider: ThemeProvider
804
- initialTheme?: string
733
+ interface AgentIdentity {
734
+ /** Display name of the AI coding agent. Defaults to {@link DEFAULT_AGENT_NAME}. */
735
+ agentName: string
736
+ /** Display name of the host product / IDE. Defaults to {@link DEFAULT_PRODUCT_NAME}. */
737
+ productName: string
805
738
  }
806
739
  ```
807
740
 
@@ -827,338 +760,132 @@ interface UseAIModelsResult {
827
760
  }
828
761
  ```
829
762
 
830
- #### `UseAppStateResult`
763
+ #### `UseChangePasswordReturn`
831
764
 
832
- Result from the useAppState hook.
765
+ Return type for useChangePassword hook.
833
766
 
834
767
  ```typescript
835
- interface UseAppStateResult {
836
- /** Current app state: 'active' | 'background' | 'inactive' */
837
- appState: string
838
- /** Whether the app is in the foreground */
839
- isActive: boolean
768
+ interface UseChangePasswordReturn {
769
+ status: UsePromiseState<void>['status']
770
+ error: UsePromiseState<void>['error']
771
+ changePassword: (oldPassword: string, newPassword: string) => Promise<void>
772
+ reset: () => void
840
773
  }
841
774
  ```
842
775
 
843
- #### `UseAuthOptions`
776
+ #### `UseDeviceResult`
844
777
 
845
- Hook options for useAuth.
778
+ Hook return type.
846
779
 
847
780
  ```typescript
848
- interface UseAuthOptions {
849
- /**
850
- * Whether to automatically refresh the token on mount.
851
- */
852
- autoRefresh?: boolean
781
+ interface UseDeviceResult {
782
+ deviceInfo: DeviceInfo
783
+ screenInfo: ScreenInfo
784
+ hardwareInfo: HardwareInfo
785
+ featureSupport: FeatureSupport
786
+ supports: (feature: keyof FeatureSupport) => boolean
787
+ isOnline: () => boolean
788
+ isStandalone: () => boolean
789
+ language: string
790
+ languages: string[]
853
791
  }
854
792
  ```
855
793
 
856
- #### `UseAuthResult`
794
+ #### `UseFormOptions`
857
795
 
858
- Hook result for useAuth.
796
+ Options for useForm hook.
797
+
798
+ Every `FormOptions` field is supported. `createForm` is only an override —
799
+ omit it and the hook creates the controller through the bonded forms
800
+ provider (`createForm` from `@molecule/app-forms`), which uses the built-in
801
+ native provider until the app bonds its own.
859
802
 
860
803
  ```typescript
861
- interface UseAuthResult<T = unknown> {
862
- state: AuthState<T>
863
- login: AuthClient<T>['login']
864
- logout: AuthClient<T>['logout']
865
- register: AuthClient<T>['register']
866
- refresh: AuthClient<T>['refresh']
867
- setUser: AuthClient<T>['setUser']
868
- isAuthenticated: boolean
869
- isLoading: boolean
870
- user: T | null
804
+ interface UseFormOptions<T extends Record<string, unknown>> extends FormOptions<T> {
805
+ /**
806
+ * Explicit form factory for this one form. Defaults to the bonded forms
807
+ * provider; pass it only to pin a specific provider instance.
808
+ */
809
+ createForm?: (options: FormOptions<T>) => FormController<T>
871
810
  }
872
811
  ```
873
812
 
874
- #### `UseBackHandlerOptions`
813
+ #### `UseFormResult`
875
814
 
876
- Options for the useBackHandler hook.
815
+ Result of useForm hook.
877
816
 
878
817
  ```typescript
879
- interface UseBackHandlerOptions {
880
- /** Whether the handler is enabled. Defaults to true. */
881
- enabled?: boolean
818
+ interface UseFormResult<T extends Record<string, unknown>> {
819
+ formState: FormState<T>
820
+ isValid: boolean
821
+ isDirty: boolean
822
+ isSubmitting: boolean
823
+ register: (
824
+ name: keyof T,
825
+ options?: Omit<RegisterOptions, 'name'> & {
826
+ name?: string
827
+ },
828
+ ) => FieldRegistration
829
+ getValue: <K extends keyof T>(name: K) => T[K]
830
+ setValue: <K extends keyof T>(name: K, value: T[K]) => void
831
+ getError: (name: keyof T) => string | undefined
832
+ setError: (name: keyof T, error: string | undefined) => void
833
+ clearErrors: () => void
834
+ handleSubmit: (onSubmit: (values: T) => void | Promise<void>) => (event?: React.FormEvent) => void
835
+ reset: (values?: Partial<T>) => void
836
+ validate: () => Promise<boolean>
882
837
  }
883
838
  ```
884
839
 
885
- #### `UseChangePasswordReturn`
840
+ #### `UseHttpState`
886
841
 
887
- Return type for useChangePassword hook.
842
+ State for async HTTP operations.
888
843
 
889
844
  ```typescript
890
- interface UseChangePasswordReturn {
891
- status: UsePromiseState<void>['status']
892
- error: UsePromiseState<void>['error']
893
- changePassword: (oldPassword: string, newPassword: string) => Promise<void>
894
- reset: () => void
845
+ interface UseHttpState<T> {
846
+ data: T | null
847
+ loading: boolean
848
+ error: Error | null
895
849
  }
896
850
  ```
897
851
 
898
- #### `UseChatOptions`
852
+ #### `UseHttpResult`
899
853
 
900
- Hook options for useChat.
854
+ Result of useHttp hook.
901
855
 
902
856
  ```typescript
903
- interface UseChatOptions {
904
- /** Chat endpoint (e.g., '/projects/123/chat'). */
905
- endpoint: string
906
- /** Project ID for context. */
907
- projectId?: string
908
- /**
909
- * Display name of the AI coding agent, interpolated into user-facing chat
910
- * copy (e.g. the stalled-stream notice). The host passes its own agent brand
911
- * name; defaults to the neutral `DEFAULT_AGENT_NAME` so the shared hook never
912
- * names a specific product.
913
- */
914
- agentName?: string
915
- /** Load history on mount. */
916
- loadOnMount?: boolean
857
+ interface UseHttpResult<T> extends UseHttpState<T> {
917
858
  /**
918
- * This client may only WATCH the conversation (e.g. a read-only project
919
- * viewer): the hook never issues chat POSTs on its behalf — no resume
920
- * request after a reload, no auto-retries. A live turn is followed through
921
- * the remote-watch path instead: pushed broadcast frames (applyRemoteEvent)
922
- * render it in real time and the history reconcile poll backstops gaps, with
923
- * `isRemoteStreaming` driving the activity indicator.
859
+ * Runs the request and resolves with its data, or `null` on failure.
860
+ *
861
+ * This function is IDENTITY-STABLE for as long as `method`, `url` and the HTTP
862
+ * client do not change, so it is safe in a `useEffect` dependency array. Its
863
+ * request options are read when it is CALLED, from the latest committed render.
924
864
  */
925
- readOnly?: boolean
926
- /** Called when a file is created or modified by a tool call (path + new content). */
927
- onFileChange?: (path: string, content: string) => void
928
- /** Called when the AI switches between plan and execute modes. */
929
- onModeChange?: (mode: 'plan' | 'execute') => void
930
- /** Called when the backend assigns or confirms a conversation ID. */
931
- onConversationId?: (id: string) => void
932
- /** Called for every streaming event — useful for notifications, sounds, etc. */
933
- onStreamEvent?: (event: ChatStreamEvent) => void
865
+ execute: () => Promise<T | null>
866
+ reset: () => void
934
867
  }
935
868
  ```
936
869
 
937
- #### `UseChatResult`
870
+ #### `UseHttpOptions`
938
871
 
939
- Hook result for useChat.
872
+ Options for useHttp hook.
873
+
874
+ Every request option — headers, params, body `data`, `signal`, `onSuccess`,
875
+ `onError` — is read at the moment `execute` runs, not when the hook rendered,
876
+ so an inline object or callback needs no memoizing. Only `immediate` is read
877
+ on mount.
940
878
 
941
879
  ```typescript
942
- interface UseChatResult {
943
- messages: ChatMessage[]
944
- isLoading: boolean
880
+ interface UseHttpOptions<T> extends RequestConfig {
945
881
  /**
946
- * True while a backend turn for this conversation streams WITHOUT this client
947
- * owning the request — a turn started in another tab, by a teammate, or any
948
- * server-side continuation. Detected from pushed (broadcast) chat events and
949
- * confirmed/cleared against the server's `streaming` history flag, so the Stop
950
- * control can stay visible and functional whenever ANY backend turn is live —
951
- * not only for sends this hook instance made.
882
+ * Whether to execute the request immediately on mount.
952
883
  */
953
- isRemoteStreaming: boolean
884
+ immediate?: boolean
954
885
  /**
955
- * Tell the hook a pushed (broadcast) chat event arrived for this conversation.
956
- * The host (ChatPanel) calls this from its push-channel handler; the hook then
957
- * confirms against the server's `streaming` flag and, while a remote turn is
958
- * live, keeps `isRemoteStreaming` true until the server reports it finished.
886
+ * Callback when request succeeds.
959
887
  */
960
- noteRemoteStreamEvent: () => void
961
- error: string | null
962
- /**
963
- * Metadata about a limit-related error, for a contextual call-to-action.
964
- * `limitType` names the RULE the backend enforced; `billingAction` names the
965
- * REMEDY it resolved (e.g. `add_funds`, `add_payment_method`,
966
- * `raise_spend_cap`, `upgrade`, `none`) and is what the button should be
967
- * built from — the same limit needs a different button per account.
968
- * `upgradeTier` is the plan an upgrade would move to, explicitly `null` when
969
- * there is no higher tier. The backend owns these vocabularies, so the
970
- * action/tier are plain strings here.
971
- */
972
- errorMeta: {
973
- limitType?: string
974
- requiresSignup?: boolean
975
- billingAction?: string
976
- upgradeTier?: string | null
977
- } | null
978
- /** Current agent mode — plan (read-only research) or execute (full access). */
979
- mode: 'plan' | 'execute'
980
- /**
981
- * Whether the conversation runs at the provider's fast/priority speed tier
982
- * (server-persisted per conversation; hydrated from the history load's
983
- * `fastMode` meta field, when the server provides one). Only meaningful for
984
- * models that support a fast tier — the server ignores it otherwise.
985
- */
986
- fastMode: boolean
987
- /**
988
- * Transient label for a background phase (e.g. the post-response verification
989
- * pass — "Type-checking the API", "Linting"), set by `status` stream events.
990
- * The UI shows it in place of the spinner's generic rotating messages; `null`
991
- * when no such phase is active.
992
- */
993
- streamingStatus: string | null
994
- /**
995
- * Active 5XX backoff-retry countdown, or `null` when none is pending. After a
996
- * backend server error (HTTP 5XX) the hook does NOT surface a terminal error —
997
- * it shows this cancelable countdown and, when it elapses, auto-resumes the
998
- * turn where the user left off (`resume:true`). `secondsRemaining` ticks down
999
- * once per second; `attempt` is the 1-based retry number (capped at 3). 4XX,
1000
- * limit/quota, and signup-required errors never auto-retry.
1001
- */
1002
- retryCountdown: {
1003
- secondsRemaining: number
1004
- attempt: number
1005
- } | null
1006
- /** Update the local mode state (for instant mode toggle without an AI turn). */
1007
- setMode: (mode: 'plan' | 'execute') => void
1008
- /** Update the local fast-mode state (for instant toggle without an AI turn). */
1009
- setFastMode: (fastMode: boolean) => void
1010
- sendMessage: (
1011
- message: string,
1012
- attachments?: ChatAttachment[],
1013
- options?: SendMessageOptions,
1014
- ) => Promise<void>
1015
- abort: () => void
1016
- /**
1017
- * Cancel a pending 5XX auto-retry. Clears the countdown and surfaces the
1018
- * original error (via `error`) so the user sees why the turn failed.
1019
- */
1020
- cancelRetry: () => void
1021
- clearHistory: () => Promise<void>
1022
- /** Edit the content of a queued (not yet sent) message. */
1023
- editQueuedMessage: (msgId: string, newContent: string) => void
1024
- /** Remove a queued (not yet sent) message from the queue. */
1025
- deleteQueuedMessage: (msgId: string) => void
1026
- /** Remove queued auto-fix messages whose content references the given file path. */
1027
- clearQueuedForFile: (filePath: string) => void
1028
- /**
1029
- * Append an inline transcript card (model / mode / skills / custom notice) as a
1030
- * `role:'system'` card-message in the ONE message store. Used by the host (ChatPanel)
1031
- * to render a TEAMMATE's broadcast `card` event live — this client's OWN cards arrive
1032
- * through the stream and are appended internally. De-duped by the server-assigned id.
1033
- */
1034
- appendCardMessage: (
1035
- id: string,
1036
- timestamp: number,
1037
- card: NonNullable<ChatMessage['cardEvent']>,
1038
- ) => void
1039
- /**
1040
- * Append a COMPLETE, non-streaming chat message (a `message` stream event — e.g.
1041
- * a teammate's human-only team note) to the ONE message store. Used by the host
1042
- * (ChatPanel) to render a TEAMMATE's broadcast `message` event live — this
1043
- * client's OWN `message` events arrive through the stream and are appended
1044
- * internally. De-duped by the server-assigned message id.
1045
- */
1046
- appendCompleteMessage: (message: ChatMessage) => void
1047
- /**
1048
- * Ingest ONE pushed (broadcast) stream frame from a turn running elsewhere —
1049
- * a teammate's send, another tab, a server-side continuation — into the ONE
1050
- * message store, through the same content applier as an own SSE stream: text/
1051
- * thinking deltas, tool events, verification, cards, complete messages, done.
1052
- * The host (ChatPanel) calls this from its push-channel handler for every
1053
- * broadcast frame of the OPEN conversation. Own echoes are dropped while a
1054
- * local send is in flight (the SSE stream is authoritative for the sender);
1055
- * complete id-carrying items (cards, team notes) always apply, de-duped.
1056
- */
1057
- applyRemoteEvent: (event: ChatStreamEvent) => void
1058
- /**
1059
- * Reload history and converge the local view on the server transcript (and
1060
- * re-enter a still-streaming turn). The page-lifecycle events run this
1061
- * automatically; the host should ALSO call it whenever its chat push channel
1062
- * (re)connects — a broadcast sent while that socket was down (a teammate's
1063
- * team note against a backgrounded tab or a slept laptop) is otherwise lost
1064
- * until the next lifecycle event happens to fire. Cheap when nothing changed:
1065
- * an identical transcript is never re-applied.
1066
- */
1067
- reconcileHistory: () => Promise<void>
1068
- }
1069
- ```
1070
-
1071
- #### `UseDeviceResult`
1072
-
1073
- Hook return type.
1074
-
1075
- ```typescript
1076
- interface UseDeviceResult {
1077
- deviceInfo: DeviceInfo
1078
- screenInfo: ScreenInfo
1079
- hardwareInfo: HardwareInfo
1080
- featureSupport: FeatureSupport
1081
- supports: (feature: keyof FeatureSupport) => boolean
1082
- isOnline: () => boolean
1083
- isStandalone: () => boolean
1084
- language: string
1085
- languages: string[]
1086
- }
1087
- ```
1088
-
1089
- #### `UseEditorResult`
1090
-
1091
- Hook result for useEditor.
1092
-
1093
- ```typescript
1094
- interface UseEditorResult {
1095
- tabs: EditorTab[]
1096
- activeFile: string | null
1097
- openFile: (file: EditorFile) => void
1098
- closeFile: (path: string) => void
1099
- getContent: () => string | null
1100
- setContent: (path: string, content: string) => void
1101
- setActiveTab: (path: string) => void
1102
- mount: EditorProvider['mount']
1103
- dispose: () => void
1104
- focus: () => void
1105
- openDiff: (file: DiffFile) => void
1106
- closeDiff: () => void
1107
- pinTab: (path: string) => void
1108
- addExtraLib: (content: string, filePath: string) => void
1109
- onFixWithAI: (callback: (request: FixWithAIRequest) => void) => () => void
1110
- }
1111
- ```
1112
-
1113
- #### `UseFormOptions`
1114
-
1115
- Options for useForm hook.
1116
-
1117
- ```typescript
1118
- interface UseFormOptions<T extends Record<string, unknown>> extends FormOptions<T> {
1119
- /**
1120
- * Form provider's createForm function.
1121
- */
1122
- createForm: (options: FormOptions<T>) => FormController<T>
1123
- }
1124
- ```
1125
-
1126
- #### `UseFormResult`
1127
-
1128
- Result of useForm hook.
1129
-
1130
- ```typescript
1131
- interface UseFormResult<T extends Record<string, unknown>> {
1132
- formState: FormState<T>
1133
- isValid: boolean
1134
- isDirty: boolean
1135
- isSubmitting: boolean
1136
- register: (name: keyof T, options?: RegisterOptions) => FieldRegistration
1137
- getValue: <K extends keyof T>(name: K) => T[K]
1138
- setValue: <K extends keyof T>(name: K, value: T[K]) => void
1139
- getError: (name: keyof T) => string | undefined
1140
- setError: (name: keyof T, error: string | undefined) => void
1141
- clearErrors: () => void
1142
- handleSubmit: (onSubmit: (values: T) => void | Promise<void>) => (event?: React.FormEvent) => void
1143
- reset: (values?: Partial<T>) => void
1144
- validate: () => Promise<boolean>
1145
- }
1146
- ```
1147
-
1148
- #### `UseHttpOptions`
1149
-
1150
- Options for useHttp hook.
1151
-
1152
- ```typescript
1153
- interface UseHttpOptions<T> extends RequestConfig {
1154
- /**
1155
- * Whether to execute the request immediately on mount.
1156
- */
1157
- immediate?: boolean
1158
- /**
1159
- * Callback when request succeeds.
1160
- */
1161
- onSuccess?: (data: T) => void
888
+ onSuccess?: (data: T) => void
1162
889
  /**
1163
890
  * Callback when request fails.
1164
891
  */
@@ -1166,42 +893,6 @@ interface UseHttpOptions<T> extends RequestConfig {
1166
893
  }
1167
894
  ```
1168
895
 
1169
- #### `UseHttpResult`
1170
-
1171
- Result of useHttp hook.
1172
-
1173
- ```typescript
1174
- interface UseHttpResult<T> extends UseHttpState<T> {
1175
- execute: () => Promise<T | null>
1176
- reset: () => void
1177
- }
1178
- ```
1179
-
1180
- #### `UseHttpState`
1181
-
1182
- State for async HTTP operations.
1183
-
1184
- ```typescript
1185
- interface UseHttpState<T> {
1186
- data: T | null
1187
- loading: boolean
1188
- error: Error | null
1189
- }
1190
- ```
1191
-
1192
- #### `UseKeyboardHeightResult`
1193
-
1194
- Result from the useKeyboardHeight hook.
1195
-
1196
- ```typescript
1197
- interface UseKeyboardHeightResult {
1198
- /** Current keyboard height in points (0 when hidden) */
1199
- keyboardHeight: number
1200
- /** Whether the keyboard is currently visible */
1201
- isKeyboardVisible: boolean
1202
- }
1203
- ```
1204
-
1205
896
  #### `UseLoginReturn`
1206
897
 
1207
898
  Return type for useLogin hook.
@@ -1269,56 +960,91 @@ interface UsePlatformResult {
1269
960
  }
1270
961
  ```
1271
962
 
1272
- #### `UsePreviewResult`
963
+ #### `UseProfileFormOptions`
1273
964
 
1274
- Hook result for usePreview.
965
+ Configuration for a profile form; transport stays in the auth bond.
1275
966
 
1276
967
  ```typescript
1277
- interface UsePreviewResult {
1278
- state: PreviewState
1279
- setUrl: (url: string) => void
1280
- refresh: () => void
1281
- setDevice: (device: DeviceFrame) => void
1282
- openExternal: () => void
968
+ interface UseProfileFormOptions<TUser, TValues extends Record<string, unknown>> extends Omit<
969
+ UseFormOptions<TValues>,
970
+ 'defaultValues'
971
+ > {
972
+ /** Complete controlled-field defaults, including blank write-only fields. */
973
+ defaultValues: TValues
1283
974
  /**
1284
- * Records a navigation the running preview reported via its `molecule:navigate`
1285
- * message — updates the displayed current location without reloading the iframe.
1286
- * Pass `isReplace` when the preview REPLACED its current history entry (a
1287
- * `replaceState` redirect/canonicalization) so the forward stack is preserved
1288
- * instead of truncated (a `pushState`, the default, truncates forward).
975
+ * Optional additional account identity check; changing it discards prior edits.
976
+ * By default ownership follows the auth client's session revision, so editable
977
+ * fields can change during a save. Providers without getSessionRevision must
978
+ * supply this callback with an identity that remains stable across profile edits.
1289
979
  */
1290
- recordNavigation: (url: string, isReplace?: boolean) => void
1291
- /** Navigates the preview to the previous navigation-history entry (Back). */
1292
- back: () => void
1293
- /** Navigates the preview to the next navigation-history entry (Forward). */
1294
- forward: () => void
980
+ getIdentity?: (user: TUser) => string
981
+ /** Maps the current/saved user into controlled values, e.g. nullable text to ''. */
982
+ toValues: (user: TUser) => TValues
983
+ /**
984
+ * Maps ONLY changed fields into an API patch. Omit blank optional credentials
985
+ * here; preserve undefined/absent fields rather than turning them into null.
986
+ * The second argument is the complete value snapshot taken at submit time.
987
+ */
988
+ toPatch: (changes: Partial<TValues>, values: Readonly<TValues>) => Partial<TUser>
989
+ /**
990
+ * Propagates the server's saved user to other caches, then navigates if needed.
991
+ * Awaited before submission finishes. The auth client already persists and
992
+ * publishes the saved user; never seed caches from the submitted patch.
993
+ */
994
+ onSaved?: (user: TUser) => void | Promise<void>
1295
995
  }
1296
996
  ```
1297
997
 
1298
- #### `UsePromiseState`
998
+ #### `UseProfileFormResult`
1299
999
 
1300
- Extended promise state with actions.
1000
+ Controlled profile form state and native form bindings.
1301
1001
 
1302
1002
  ```typescript
1303
- interface UsePromiseState<T> {
1304
- status: PromiseStatus
1305
- value: T | null
1306
- error: Error | null
1307
- cancel: (message?: string) => void
1003
+ interface UseProfileFormResult<TUser, TValues extends Record<string, unknown>> extends Omit<
1004
+ UseFormResult<TValues>,
1005
+ 'register' | 'handleSubmit' | 'reset'
1006
+ > {
1007
+ /** The shared auth user's current profile. */
1008
+ user: TUser | null
1009
+ /** A user has been loaded; disable submission until this is true. */
1010
+ ready: boolean
1011
+ /**
1012
+ * The latest save/propagation failure. Rejected saves retain edits; a failed
1013
+ * onSaved callback can be retried by submit without repeating the mutation.
1014
+ */
1015
+ error: unknown
1016
+ /** Native input/textarea bindings with the field's concrete value type. */
1017
+ register: <K extends keyof TValues>(
1018
+ name: K,
1019
+ options?: Parameters<UseFormResult<TValues>['register']>[1],
1020
+ ) => Omit<FieldRegistration, 'value'> & {
1021
+ value: TValues[K]
1022
+ }
1023
+ /** Bind to the native form, with a type="submit" button inside it. */
1024
+ formProps: {
1025
+ onSubmit: (event: React.FormEvent<HTMLFormElement>) => void
1026
+ }
1027
+ /**
1028
+ * Validates and saves one submit-time snapshot. Concurrent submits share the
1029
+ * same promise. Resolves undefined on validation, save or propagation failure.
1030
+ */
1031
+ submit: () => Promise<TUser | undefined>
1032
+ /** Discards edits and restores the newest loaded/saved profile baseline. */
1308
1033
  reset: () => void
1309
1034
  }
1310
1035
  ```
1311
1036
 
1312
- #### `UsePushOptions`
1037
+ #### `UsePromiseState`
1313
1038
 
1314
- Options for the usePush hook (e.g. check permission on mount).
1039
+ Extended promise state with actions.
1315
1040
 
1316
1041
  ```typescript
1317
- interface UsePushOptions {
1318
- /**
1319
- * Whether to check permission status on mount.
1320
- */
1321
- checkOnMount?: boolean
1042
+ interface UsePromiseState<T> {
1043
+ status: PromiseStatus
1044
+ value: T | null
1045
+ error: Error | null
1046
+ cancel: (message?: string) => void
1047
+ reset: () => void
1322
1048
  }
1323
1049
  ```
1324
1050
 
@@ -1342,20 +1068,16 @@ interface UsePushResult {
1342
1068
  }
1343
1069
  ```
1344
1070
 
1345
- #### `UseRouterResult`
1071
+ #### `UsePushOptions`
1346
1072
 
1347
- Hook result for useRouter.
1073
+ Options for the usePush hook (e.g. check permission on mount).
1348
1074
 
1349
1075
  ```typescript
1350
- interface UseRouterResult {
1351
- location: Router['getLocation'] extends () => infer R ? R : never
1352
- params: Record<string, string>
1353
- query: QueryParams
1354
- navigate: Router['navigate']
1355
- navigateTo: Router['navigateTo']
1356
- back: Router['back']
1357
- forward: Router['forward']
1358
- isActive: Router['isActive']
1076
+ interface UsePushOptions {
1077
+ /**
1078
+ * Whether to check permission status on mount.
1079
+ */
1080
+ checkOnMount?: boolean
1359
1081
  }
1360
1082
  ```
1361
1083
 
@@ -1364,11 +1086,14 @@ interface UseRouterResult {
1364
1086
  Return type for useSignup hook.
1365
1087
 
1366
1088
  ```typescript
1367
- interface UseSignupReturn<T = unknown> {
1089
+ interface UseSignupReturn<
1090
+ T = unknown,
1091
+ TRegister extends RegisterExtraShape<TRegister> = Record<never, never>,
1092
+ > {
1368
1093
  status: UsePromiseState<AuthResult<T>>['status']
1369
1094
  value: UsePromiseState<AuthResult<T>>['value']
1370
1095
  error: UsePromiseState<AuthResult<T>>['error']
1371
- signup: (data: RegisterData) => Promise<AuthResult<T>>
1096
+ signup: (data: RegisterData<TRegister>) => Promise<AuthResult<T>>
1372
1097
  reset: () => void
1373
1098
  }
1374
1099
  ```
@@ -1404,47 +1129,6 @@ interface UseStorageValueResult<T> {
1404
1129
  }
1405
1130
  ```
1406
1131
 
1407
- #### `UseStoreOptions`
1408
-
1409
- Hook options for useStore.
1410
-
1411
- ```typescript
1412
- interface UseStoreOptions<T, S> {
1413
- selector?: (state: T) => S
1414
- equalityFn?: (a: S, b: S) => boolean
1415
- }
1416
- ```
1417
-
1418
- #### `UseThemeResult`
1419
-
1420
- Hook result for useTheme.
1421
-
1422
- ```typescript
1423
- interface UseThemeResult {
1424
- theme: Theme
1425
- themeName: string
1426
- setTheme: (name: string) => void
1427
- toggleTheme: () => void
1428
- mode: 'light' | 'dark'
1429
- }
1430
- ```
1431
-
1432
- #### `UseTranslationResult`
1433
-
1434
- Hook result for useTranslation.
1435
-
1436
- ```typescript
1437
- interface UseTranslationResult {
1438
- t: I18nProvider['t']
1439
- locale: string
1440
- setLocale: I18nProvider['setLocale']
1441
- locales: ReturnType<I18nProvider['getLocales']>
1442
- formatNumber: I18nProvider['formatNumber']
1443
- formatDate: I18nProvider['formatDate']
1444
- direction: 'ltr' | 'rtl'
1445
- }
1446
- ```
1447
-
1448
1132
  #### `UseVerifyPaymentReturnOptions`
1449
1133
 
1450
1134
  Options for {@link useVerifyPaymentReturn}.
@@ -1482,36 +1166,537 @@ interface UseVerifyPaymentReturnResult {
1482
1166
  * the URL) or auth is still hydrating; `verifying` while the API call is in
1483
1167
  * flight; then `verified` or `failed`.
1484
1168
  */
1485
- status: VerifyPaymentReturnStatus
1486
- /** `true` when the URL identifies a purchase to verify. */
1487
- isReturn: boolean
1488
- /** The provider named by the URL (or the `provider` option). */
1489
- provider: string | null
1490
- /** The provider transaction/session id read from the URL. */
1491
- transactionId: string | null
1492
- /** Why verification failed, when it did. */
1493
- error: Error | null
1494
- /** Re-run the verification — wire this to a retry button. */
1495
- retry: () => void
1496
- }
1497
- ```
1498
-
1499
- #### `UseVersionResult`
1500
-
1501
- Hook return type.
1502
-
1503
- ```typescript
1504
- interface UseVersionResult {
1505
- state: VersionState
1506
- isUpdateAvailable: boolean
1507
- isChecking: boolean
1508
- isServiceWorkerWaiting: boolean
1509
- newVersion: string | undefined
1510
- checkForUpdates: () => Promise<boolean>
1511
- applyUpdate: (options?: { force?: boolean }) => void
1512
- dismissUpdate: () => void
1513
- startPeriodicChecks: (options?: UpdateCheckOptions) => void
1514
- stopPeriodicChecks: () => void
1169
+ status: VerifyPaymentReturnStatus
1170
+ /** `true` when the URL identifies a purchase to verify. */
1171
+ isReturn: boolean
1172
+ /** The provider named by the URL (or the `provider` option). */
1173
+ provider: string | null
1174
+ /** The provider transaction/session id read from the URL. */
1175
+ transactionId: string | null
1176
+ /** Why verification failed, when it did. */
1177
+ error: Error | null
1178
+ /** Re-run the verification — wire this to a retry button. */
1179
+ retry: () => void
1180
+ }
1181
+ ```
1182
+
1183
+ #### `UseVersionResult`
1184
+
1185
+ Hook return type.
1186
+
1187
+ ```typescript
1188
+ interface UseVersionResult {
1189
+ state: VersionState
1190
+ isUpdateAvailable: boolean
1191
+ isChecking: boolean
1192
+ isServiceWorkerWaiting: boolean
1193
+ newVersion: string | undefined
1194
+ checkForUpdates: () => Promise<boolean>
1195
+ applyUpdate: (options?: { force?: boolean }) => void
1196
+ dismissUpdate: () => void
1197
+ startPeriodicChecks: (options?: UpdateCheckOptions) => void
1198
+ stopPeriodicChecks: () => void
1199
+ }
1200
+ ```
1201
+
1202
+ #### `ProviderProps`
1203
+
1204
+ Props for provider components.
1205
+
1206
+ ```typescript
1207
+ interface ProviderProps {
1208
+ children: ReactNode
1209
+ }
1210
+ ```
1211
+
1212
+ #### `StateProviderProps`
1213
+
1214
+ Props for state provider component.
1215
+
1216
+ ```typescript
1217
+ interface StateProviderProps extends ProviderProps {
1218
+ provider: StateProvider
1219
+ }
1220
+ ```
1221
+
1222
+ #### `AuthProviderProps`
1223
+
1224
+ Props for auth provider component.
1225
+
1226
+ ```typescript
1227
+ interface AuthProviderProps<T = unknown> extends ProviderProps {
1228
+ client: AuthClient<T>
1229
+ }
1230
+ ```
1231
+
1232
+ #### `ThemeProviderProps`
1233
+
1234
+ Props for theme provider component.
1235
+
1236
+ ```typescript
1237
+ interface ThemeProviderProps extends ProviderProps {
1238
+ provider: ThemeProvider
1239
+ initialTheme?: string
1240
+ }
1241
+ ```
1242
+
1243
+ #### `RouterProviderProps`
1244
+
1245
+ Props for router provider component.
1246
+
1247
+ ```typescript
1248
+ interface RouterProviderProps extends ProviderProps {
1249
+ router: Router
1250
+ }
1251
+ ```
1252
+
1253
+ #### `I18nProviderProps`
1254
+
1255
+ Props for i18n provider component.
1256
+
1257
+ ```typescript
1258
+ interface I18nProviderProps extends ProviderProps {
1259
+ provider: I18nProvider
1260
+ }
1261
+ ```
1262
+
1263
+ #### `HttpProviderProps`
1264
+
1265
+ Props for http provider component.
1266
+
1267
+ ```typescript
1268
+ interface HttpProviderProps extends ProviderProps {
1269
+ client: HttpClient
1270
+ }
1271
+ ```
1272
+
1273
+ #### `StorageProviderProps`
1274
+
1275
+ Props for storage provider component.
1276
+
1277
+ ```typescript
1278
+ interface StorageProviderProps extends ProviderProps {
1279
+ provider: StorageProvider
1280
+ }
1281
+ ```
1282
+
1283
+ #### `LoggerProviderProps`
1284
+
1285
+ Props for logger provider component.
1286
+
1287
+ ```typescript
1288
+ interface LoggerProviderProps extends ProviderProps {
1289
+ provider: LoggerProvider
1290
+ }
1291
+ ```
1292
+
1293
+ #### `ChatProviderProps`
1294
+
1295
+ Props for the ChatProvider React component.
1296
+
1297
+ ```typescript
1298
+ interface ChatProviderProps extends ProviderProps {
1299
+ provider: ChatProvider
1300
+ }
1301
+ ```
1302
+
1303
+ #### `WorkspaceProviderProps`
1304
+
1305
+ Props for workspace provider component.
1306
+
1307
+ ```typescript
1308
+ interface WorkspaceProviderProps extends ProviderProps {
1309
+ provider: WorkspaceProvider
1310
+ }
1311
+ ```
1312
+
1313
+ #### `EditorProviderProps`
1314
+
1315
+ Props for editor provider component.
1316
+
1317
+ ```typescript
1318
+ interface EditorProviderProps extends ProviderProps {
1319
+ provider: EditorProvider
1320
+ }
1321
+ ```
1322
+
1323
+ #### `PreviewProviderProps`
1324
+
1325
+ Props for preview provider component.
1326
+
1327
+ ```typescript
1328
+ interface PreviewProviderProps extends ProviderProps {
1329
+ provider: PreviewProvider
1330
+ }
1331
+ ```
1332
+
1333
+ #### `MoleculeProviderProps`
1334
+
1335
+ Properties for molecule provider.
1336
+
1337
+ ```typescript
1338
+ interface MoleculeProviderProps extends ProviderProps {
1339
+ state?: StateProvider
1340
+ auth?: AuthClient<unknown>
1341
+ theme?: ThemeProvider
1342
+ router?: Router
1343
+ i18n?: I18nProvider
1344
+ http?: HttpClient
1345
+ storage?: StorageProvider
1346
+ logger?: LoggerProvider
1347
+ chat?: ChatProvider
1348
+ workspace?: WorkspaceProvider
1349
+ editor?: EditorProvider
1350
+ preview?: PreviewProvider
1351
+ }
1352
+ ```
1353
+
1354
+ #### `UseStoreOptions`
1355
+
1356
+ Hook options for useStore.
1357
+
1358
+ ```typescript
1359
+ interface UseStoreOptions<T, S> {
1360
+ selector?: (state: T) => S
1361
+ equalityFn?: (a: S, b: S) => boolean
1362
+ }
1363
+ ```
1364
+
1365
+ #### `UseAuthOptions`
1366
+
1367
+ Hook options for useAuth.
1368
+
1369
+ ```typescript
1370
+ interface UseAuthOptions {
1371
+ /**
1372
+ * Whether to automatically refresh the token on mount.
1373
+ */
1374
+ autoRefresh?: boolean
1375
+ }
1376
+ ```
1377
+
1378
+ #### `UseAuthResult`
1379
+
1380
+ Hook result for useAuth.
1381
+
1382
+ ```typescript
1383
+ interface UseAuthResult<
1384
+ T = unknown,
1385
+ TRegister extends RegisterExtraShape<TRegister> = Record<never, never>,
1386
+ > {
1387
+ /**
1388
+ * The session state as one value — render from this instead of combining
1389
+ * `initialized`/`authenticated`/`loading`. A stored token AND user make it
1390
+ * `'authenticated'` on the first render; only `'loading'` means "no decision
1391
+ * yet", so a route guard waits on that and nothing else.
1392
+ */
1393
+ status: AuthState<T>['status']
1394
+ state: AuthState<T>
1395
+ login: AuthClient<T>['login']
1396
+ logout: AuthClient<T>['logout']
1397
+ register: AuthClient<T, TRegister>['register']
1398
+ refresh: AuthClient<T>['refresh']
1399
+ setUser: AuthClient<T>['setUser']
1400
+ /**
1401
+ * Adopt a session an exchange outside the client already established (an
1402
+ * OAuth code→token redirect, the app's own sign-in endpoint) in ONE update:
1403
+ * the token and user are stored and the hook's consumers see the client as
1404
+ * `authenticated` immediately.
1405
+ *
1406
+ * `setUser` alone does NOT sign the client in, and `setAccessToken` changes
1407
+ * storage only — using those two for a caller-issued session leaves every
1408
+ * `authenticated` read signed out (xr-molecule-flash-m178).
1409
+ */
1410
+ setSession: AuthClient<T>['setSession']
1411
+ isAuthenticated: boolean
1412
+ isLoading: boolean
1413
+ user: T | null
1414
+ }
1415
+ ```
1416
+
1417
+ #### `UseThemeResult`
1418
+
1419
+ Hook result for useTheme.
1420
+
1421
+ ```typescript
1422
+ interface UseThemeResult {
1423
+ theme: Theme
1424
+ themeName: string
1425
+ setTheme: (name: string) => void
1426
+ toggleTheme: () => void
1427
+ mode: 'light' | 'dark'
1428
+ }
1429
+ ```
1430
+
1431
+ #### `UseRouterResult`
1432
+
1433
+ Hook result for useRouter.
1434
+
1435
+ ```typescript
1436
+ interface UseRouterResult {
1437
+ location: Router['getLocation'] extends () => infer R ? R : never
1438
+ params: Record<string, string>
1439
+ query: QueryParams
1440
+ navigate: Router['navigate']
1441
+ navigateTo: Router['navigateTo']
1442
+ back: Router['back']
1443
+ forward: Router['forward']
1444
+ isActive: Router['isActive']
1445
+ }
1446
+ ```
1447
+
1448
+ #### `UseTranslationResult`
1449
+
1450
+ Hook result for useTranslation.
1451
+
1452
+ ```typescript
1453
+ interface UseTranslationResult {
1454
+ t: I18nProvider['t']
1455
+ locale: string
1456
+ setLocale: I18nProvider['setLocale']
1457
+ locales: ReturnType<I18nProvider['getLocales']>
1458
+ formatNumber: I18nProvider['formatNumber']
1459
+ formatDate: I18nProvider['formatDate']
1460
+ direction: 'ltr' | 'rtl'
1461
+ }
1462
+ ```
1463
+
1464
+ #### `UseChatOptions`
1465
+
1466
+ Hook options for useChat.
1467
+
1468
+ ```typescript
1469
+ interface UseChatOptions {
1470
+ /** Chat endpoint (e.g., '/projects/123/chat'). */
1471
+ endpoint: string
1472
+ /** Project ID for context. */
1473
+ projectId?: string
1474
+ /**
1475
+ * Display name of the AI coding agent, interpolated into user-facing chat
1476
+ * copy (e.g. the stalled-stream notice). The host passes its own agent brand
1477
+ * name; defaults to the neutral `DEFAULT_AGENT_NAME` so the shared hook never
1478
+ * names a specific product.
1479
+ */
1480
+ agentName?: string
1481
+ /** Load history on mount. */
1482
+ loadOnMount?: boolean
1483
+ /**
1484
+ * This client may only WATCH the conversation (e.g. a read-only project
1485
+ * viewer): the hook never issues chat POSTs on its behalf — no resume
1486
+ * request after a reload, no auto-retries. A live turn is followed through
1487
+ * the remote-watch path instead: pushed broadcast frames (applyRemoteEvent)
1488
+ * render it in real time and the history reconcile poll backstops gaps, with
1489
+ * `isRemoteStreaming` driving the activity indicator.
1490
+ */
1491
+ readOnly?: boolean
1492
+ /** Called when a file is created or modified by a tool call (path + new content). */
1493
+ onFileChange?: (path: string, content: string) => void
1494
+ /** Called when the AI switches between plan and execute modes. */
1495
+ onModeChange?: (mode: 'plan' | 'execute') => void
1496
+ /** Called when the backend assigns or confirms a conversation ID. */
1497
+ onConversationId?: (id: string) => void
1498
+ /** Called for every streaming event — useful for notifications, sounds, etc. */
1499
+ onStreamEvent?: (event: ChatStreamEvent) => void
1500
+ }
1501
+ ```
1502
+
1503
+ #### `SendMessageOptions`
1504
+
1505
+ Options for {@link UseChatResult.sendMessage}.
1506
+
1507
+ ```typescript
1508
+ interface SendMessageOptions {
1509
+ /** Reuse a queued message's UUID when delivering it after reconnecting. */
1510
+ messageId?: string
1511
+ /**
1512
+ * Skip the optimistic local user-message bubble. The text is still sent to
1513
+ * the server. Used for ask_user responses: the answer is folded into the
1514
+ * ask_user tool card (a checkmark on the chosen option, or the custom text
1515
+ * shown in-card) rather than echoed as a separate message below it.
1516
+ */
1517
+ suppressUserMessage?: boolean
1518
+ /**
1519
+ * Mark this send as issued automatically on the user's behalf (e.g. an
1520
+ * auto-fix prompt). The optimistic local bubble and the persisted message are
1521
+ * flagged `automatic` so the chat renders it in the distinct auto-sent style
1522
+ * (agent avatar + accent border) instead of looking like the user typed it.
1523
+ */
1524
+ automatic?: boolean
1525
+ /**
1526
+ * Mark this send as the answer to the pending `ask_user` question. The most
1527
+ * recent unanswered `ask_user` tool call in the store is resolved in place —
1528
+ * its `output` is set to this answer — so the chosen option stays checked
1529
+ * across remounts (e.g. the discovery→IDE transition) instead of relying on
1530
+ * ephemeral component state that the answer's selection would otherwise lose.
1531
+ * Distinct from {@link suppressUserMessage} (which the post-boot kickoff also
1532
+ * sets) so resolving never misfires on a non-ask_user suppressed send.
1533
+ */
1534
+ askUserAnswer?: boolean
1535
+ /**
1536
+ * Mark an {@link automatic} send as directly requested by the user (e.g. the
1537
+ * editor's "Fix with AI" action, the broken-preview overlay's "Fix with AI"
1538
+ * button) rather than dispatched autonomously by the platform. A user Stop
1539
+ * suppresses autonomous automatic sends until the user re-engages; a
1540
+ * user-initiated one IS that re-engagement — it clears the stop and sends.
1541
+ */
1542
+ userInitiated?: boolean
1543
+ /**
1544
+ * Send on the SIDE CHANNEL: a human-to-human message (e.g. a team note) the
1545
+ * server intercepts before running any agent turn. When the provider supports
1546
+ * `sendSideMessage`, the send goes out IMMEDIATELY on an independent request —
1547
+ * it never queues behind an active turn, never takes over the streaming
1548
+ * state, and never tears down remote-turn tracking (a viewer's note while
1549
+ * watching a teammate's turn must not stop the watching). Falls back to the
1550
+ * normal send path on providers without side-channel support.
1551
+ */
1552
+ sideChannel?: boolean
1553
+ /**
1554
+ * Mark this send as composed through voice dictation — the mic button's
1555
+ * transcript was still present in the composer at submit. The optimistic
1556
+ * bubble and the persisted message are flagged `viaDictation` so the chat
1557
+ * renders a mic badge on the message, live and after a reload.
1558
+ */
1559
+ viaDictation?: boolean
1560
+ }
1561
+ ```
1562
+
1563
+ #### `UseChatResult`
1564
+
1565
+ Hook result for useChat.
1566
+
1567
+ ```typescript
1568
+ interface UseChatResult {
1569
+ messages: ChatMessage[]
1570
+ isLoading: boolean
1571
+ /**
1572
+ * True while a backend turn for this conversation streams WITHOUT this client
1573
+ * owning the request — a turn started in another tab, by a teammate, or any
1574
+ * server-side continuation. Detected from pushed (broadcast) chat events and
1575
+ * confirmed/cleared against the server's `streaming` history flag, so the Stop
1576
+ * control can stay visible and functional whenever ANY backend turn is live —
1577
+ * not only for sends this hook instance made.
1578
+ */
1579
+ isRemoteStreaming: boolean
1580
+ /**
1581
+ * Tell the hook a pushed (broadcast) chat event arrived for this conversation.
1582
+ * The host (ChatPanel) calls this from its push-channel handler; the hook then
1583
+ * confirms against the server's `streaming` flag and, while a remote turn is
1584
+ * live, keeps `isRemoteStreaming` true until the server reports it finished.
1585
+ */
1586
+ noteRemoteStreamEvent: () => void
1587
+ error: string | null
1588
+ /**
1589
+ * Metadata about a limit-related error, for a contextual call-to-action.
1590
+ * `limitType` names the RULE the backend enforced; `billingAction` names the
1591
+ * REMEDY it resolved (e.g. `add_funds`, `add_payment_method`,
1592
+ * `raise_spend_cap`, `upgrade`, `none`) and is what the button should be
1593
+ * built from — the same limit needs a different button per account.
1594
+ * `upgradeTier` is the plan an upgrade would move to, explicitly `null` when
1595
+ * there is no higher tier. The backend owns these vocabularies, so the
1596
+ * action/tier are plain strings here.
1597
+ */
1598
+ errorMeta: {
1599
+ limitType?: string
1600
+ requiresSignup?: boolean
1601
+ billingAction?: string
1602
+ upgradeTier?: string | null
1603
+ } | null
1604
+ /** Current agent mode — plan (read-only research) or execute (full access). */
1605
+ mode: 'plan' | 'execute'
1606
+ /**
1607
+ * Whether the conversation runs at the provider's fast/priority speed tier
1608
+ * (server-persisted per conversation; hydrated from the history load's
1609
+ * `fastMode` meta field, when the server provides one). Only meaningful for
1610
+ * models that support a fast tier — the server ignores it otherwise.
1611
+ */
1612
+ fastMode: boolean
1613
+ /**
1614
+ * Transient label for a background phase (e.g. the post-response verification
1615
+ * pass — "Type-checking the API", "Linting"), set by `status` stream events.
1616
+ * The UI shows it in place of the spinner's generic rotating messages; `null`
1617
+ * when no such phase is active.
1618
+ */
1619
+ streamingStatus: string | null
1620
+ /**
1621
+ * Commands the executor detached with `run_in_background`, newest last. Each
1622
+ * appears here the moment it starts and is replaced in place when it finishes,
1623
+ * so the UI can show work that outlives the tool call that started it.
1624
+ */
1625
+ backgroundTasks: BackgroundTaskState[]
1626
+ /**
1627
+ * Active 5XX backoff-retry countdown, or `null` when none is pending. After a
1628
+ * backend server error (HTTP 5XX) the hook does NOT surface a terminal error —
1629
+ * it shows this cancelable countdown and, when it elapses, auto-resumes the
1630
+ * turn where the user left off (`resume:true`). `secondsRemaining` ticks down
1631
+ * once per second; `attempt` is the 1-based retry number (capped at 3). 4XX,
1632
+ * limit/quota, and signup-required errors never auto-retry.
1633
+ */
1634
+ retryCountdown: {
1635
+ secondsRemaining: number
1636
+ attempt: number
1637
+ } | null
1638
+ /** Update the local mode state (for instant mode toggle without an AI turn). */
1639
+ setMode: (mode: 'plan' | 'execute') => void
1640
+ /** Update the local fast-mode state (for instant toggle without an AI turn). */
1641
+ setFastMode: (fastMode: boolean) => void
1642
+ sendMessage: (
1643
+ message: string,
1644
+ attachments?: ChatAttachment[],
1645
+ options?: SendMessageOptions,
1646
+ ) => Promise<void>
1647
+ abort: () => void
1648
+ /**
1649
+ * Cancel a pending 5XX auto-retry. Clears the countdown and surfaces the
1650
+ * original error (via `error`) so the user sees why the turn failed.
1651
+ */
1652
+ cancelRetry: () => void
1653
+ clearHistory: () => Promise<void>
1654
+ /** Edit the content of a queued (not yet sent) message. */
1655
+ editQueuedMessage: (msgId: string, newContent: string) => void
1656
+ /** Remove a queued (not yet sent) message from the queue. */
1657
+ deleteQueuedMessage: (msgId: string) => void
1658
+ /** Remove queued auto-fix messages whose content references the given file path. */
1659
+ clearQueuedForFile: (filePath: string) => void
1660
+ /**
1661
+ * Append an inline transcript card (model / mode / skills / custom notice) as a
1662
+ * `role:'system'` card-message in the ONE message store. Used by the host (ChatPanel)
1663
+ * to render a TEAMMATE's broadcast `card` event live — this client's OWN cards arrive
1664
+ * through the stream and are appended internally. De-duped by the server-assigned id.
1665
+ */
1666
+ appendCardMessage: (
1667
+ id: string,
1668
+ timestamp: number,
1669
+ card: NonNullable<ChatMessage['cardEvent']>,
1670
+ ) => void
1671
+ /**
1672
+ * Append a COMPLETE, non-streaming chat message (a `message` stream event — e.g.
1673
+ * a teammate's human-only team note) to the ONE message store. Used by the host
1674
+ * (ChatPanel) to render a TEAMMATE's broadcast `message` event live — this
1675
+ * client's OWN `message` events arrive through the stream and are appended
1676
+ * internally. De-duped by the server-assigned message id.
1677
+ */
1678
+ appendCompleteMessage: (message: ChatMessage) => void
1679
+ /**
1680
+ * Ingest ONE pushed (broadcast) stream frame from a turn running elsewhere —
1681
+ * a teammate's send, another tab, a server-side continuation — into the ONE
1682
+ * message store, through the same content applier as an own SSE stream: text/
1683
+ * thinking deltas, tool events, verification, cards, complete messages, done.
1684
+ * The host (ChatPanel) calls this from its push-channel handler for every
1685
+ * broadcast frame of the OPEN conversation. Own echoes are dropped while a
1686
+ * local send is in flight (the SSE stream is authoritative for the sender);
1687
+ * complete id-carrying items (cards, team notes) always apply, de-duped.
1688
+ */
1689
+ applyRemoteEvent: (event: ChatStreamEvent) => void
1690
+ /**
1691
+ * Reload history and converge the local view on the server transcript (and
1692
+ * re-enter a still-streaming turn). The page-lifecycle events run this
1693
+ * automatically; the host should ALSO call it whenever its chat push channel
1694
+ * (re)connects — a broadcast sent while that socket was down (a teammate's
1695
+ * team note against a backgrounded tab or a slept laptop) is otherwise lost
1696
+ * until the next lifecycle event happens to fire. Cheap when nothing changed:
1697
+ * an identical transcript is never re-applied.
1698
+ */
1699
+ reconcileHistory: () => Promise<void>
1515
1700
  }
1516
1701
  ```
1517
1702
 
@@ -1531,28 +1716,58 @@ interface UseWorkspaceResult {
1531
1716
  }
1532
1717
  ```
1533
1718
 
1534
- #### `WorkspaceProviderProps`
1719
+ #### `UseEditorResult`
1535
1720
 
1536
- Props for workspace provider component.
1721
+ Hook result for useEditor.
1537
1722
 
1538
1723
  ```typescript
1539
- interface WorkspaceProviderProps extends ProviderProps {
1540
- provider: WorkspaceProvider
1724
+ interface UseEditorResult {
1725
+ tabs: EditorTab[]
1726
+ activeFile: string | null
1727
+ openFile: (file: EditorFile) => void
1728
+ closeFile: (path: string) => void
1729
+ getContent: () => string | null
1730
+ setContent: (path: string, content: string) => void
1731
+ setActiveTab: (path: string) => void
1732
+ mount: EditorProvider['mount']
1733
+ dispose: () => void
1734
+ focus: () => void
1735
+ openDiff: (file: DiffFile) => void
1736
+ closeDiff: () => void
1737
+ pinTab: (path: string) => void
1738
+ addExtraLib: (content: string, filePath: string) => void
1739
+ onFixWithAI: (callback: (request: FixWithAIRequest) => void) => () => void
1541
1740
  }
1542
1741
  ```
1543
1742
 
1544
- ### Types
1545
-
1546
- #### `AsyncExtendState`
1743
+ #### `UsePreviewResult`
1547
1744
 
1548
- Async-capable extendState function for partial updates.
1745
+ Hook result for usePreview.
1549
1746
 
1550
1747
  ```typescript
1551
- type AsyncExtendState<T> = (
1552
- partial: Partial<T> | ((prev: T) => Partial<T>) | Promise<Partial<T> | ((prev: T) => Partial<T>)>,
1553
- ) => void
1748
+ interface UsePreviewResult {
1749
+ state: PreviewState
1750
+ setUrl: (url: string) => void
1751
+ refresh: () => void
1752
+ setDevice: (device: DeviceFrame) => void
1753
+ openExternal: () => void
1754
+ /**
1755
+ * Records a navigation the running preview reported via its `molecule:navigate`
1756
+ * message — updates the displayed current location without reloading the iframe.
1757
+ * Pass `isReplace` when the preview REPLACED its current history entry (a
1758
+ * `replaceState` redirect/canonicalization) so the forward stack is preserved
1759
+ * instead of truncated (a `pushState`, the default, truncates forward).
1760
+ */
1761
+ recordNavigation: (url: string, isReplace?: boolean) => void
1762
+ /** Navigates the preview to the previous navigation-history entry (Back). */
1763
+ back: () => void
1764
+ /** Navigates the preview to the next navigation-history entry (Forward). */
1765
+ forward: () => void
1766
+ }
1554
1767
  ```
1555
1768
 
1769
+ ### Types
1770
+
1556
1771
  #### `AsyncSetState`
1557
1772
 
1558
1773
  Async-capable setState function.
@@ -1561,6 +1776,18 @@ Async-capable setState function.
1561
1776
  type AsyncSetState<T> = (value: T | ((prev: T) => T) | Promise<T | ((prev: T) => T)>) => void
1562
1777
  ```
1563
1778
 
1779
+ - `value` — The new state value, an updater function receiving previous state, or a Promise resolving to either.
1780
+
1781
+ #### `AsyncExtendState`
1782
+
1783
+ Async-capable extendState function for partial updates.
1784
+
1785
+ ```typescript
1786
+ type AsyncExtendState<T> = (
1787
+ partial: Partial<T> | ((prev: T) => Partial<T>) | Promise<Partial<T> | ((prev: T) => Partial<T>)>,
1788
+ ) => void
1789
+ ```
1790
+
1564
1791
  #### `UseCapacitorAppResult`
1565
1792
 
1566
1793
  Hook return type.
@@ -1581,168 +1808,218 @@ type VerifyPaymentReturnStatus = 'idle' | 'verifying' | 'verified' | 'failed'
1581
1808
 
1582
1809
  ### Functions
1583
1810
 
1584
- #### `AuthProvider(props)`
1811
+ #### `useAppState()`
1585
1812
 
1586
- Provider for authentication.
1813
+ Tracks whether the app is in the foreground, background, or inactive.
1814
+
1815
+ Uses React Native's `AppState` API under the hood. Falls back to
1816
+ 'active' on platforms where AppState is unavailable.
1587
1817
 
1588
1818
  ```typescript
1589
- function AuthProvider({
1590
- client,
1591
- children,
1592
- }: AuthProviderProps<T>): React.ReactElement<unknown, string | React.JSXElementConstructor<any>>
1819
+ function useAppState(): UseAppStateResult
1593
1820
  ```
1594
1821
 
1595
- - `props` — Component props (see {@link AuthProviderProps}).
1822
+ **Returns:** Current app state and whether the app is active.
1596
1823
 
1597
- **Returns:** The rendered auth provider element.
1824
+ #### `useBackHandler(handler, options)`
1598
1825
 
1599
- #### `ChatProvider(props)`
1826
+ Registers a handler for the Android hardware back button.
1600
1827
 
1601
- Provider for AI chat.
1828
+ Return `true` from the handler to prevent the default back behavior,
1829
+ or `false` to allow it.
1602
1830
 
1603
1831
  ```typescript
1604
- function ChatProvider({
1605
- provider,
1606
- children,
1607
- }: ChatProviderProps): React.ReactElement<unknown, string | React.JSXElementConstructor<any>>
1832
+ function useBackHandler(handler: () => boolean, options?: UseBackHandlerOptions): void
1608
1833
  ```
1609
1834
 
1610
- - `props` — Component props (see {@link ChatProviderProps}).
1835
+ - `handler` — Callback invoked when the hardware back button is pressed.
1836
+ - `options` — Optional configuration.
1611
1837
 
1612
- **Returns:** The rendered chat provider element.
1838
+ #### `useKeyboardHeight()`
1613
1839
 
1614
- #### `EditorProvider(props)`
1840
+ Tracks soft keyboard visibility and height.
1615
1841
 
1616
- Provider for code editor.
1842
+ Uses React Native's `Keyboard` API. Falls back to hidden state
1843
+ on platforms where Keyboard is unavailable.
1617
1844
 
1618
1845
  ```typescript
1619
- function EditorProvider({
1620
- provider,
1621
- children,
1622
- }: EditorProviderProps): React.ReactElement<unknown, string | React.JSXElementConstructor<any>>
1846
+ function useKeyboardHeight(): UseKeyboardHeightResult
1623
1847
  ```
1624
1848
 
1625
- - `props` — Component props (see {@link EditorProviderProps}).
1849
+ **Returns:** Current keyboard height and visibility state.
1626
1850
 
1627
- **Returns:** The rendered editor provider element.
1851
+ #### `useSafeArea()`
1628
1852
 
1629
- #### `HttpProvider(props)`
1853
+ Returns the current safe area insets from `react-native-safe-area-context`.
1630
1854
 
1631
- Provider for HTTP client.
1855
+ Must be used within a `SafeAreaProvider`. Falls back to zero insets
1856
+ if the context is unavailable.
1632
1857
 
1633
1858
  ```typescript
1634
- function HttpProvider({
1635
- client,
1636
- children,
1637
- }: HttpProviderProps): React.ReactElement<unknown, string | React.JSXElementConstructor<any>>
1859
+ function useSafeArea(): SafeAreaInsets
1638
1860
  ```
1639
1861
 
1640
- - `props` — Component props (see {@link HttpProviderProps}).
1862
+ **Returns:** Safe area insets for the current device.
1641
1863
 
1642
- **Returns:** The rendered HTTP provider element.
1864
+ #### `resetAIModelsCache()`
1643
1865
 
1644
- #### `I18nProvider(props)`
1866
+ Test-only: drops every cached model list so the next `useAIModels` call
1867
+ refetches. Exposed for unit tests; do not call from production code.
1645
1868
 
1646
- Provider for internationalization.
1869
+ ```typescript
1870
+ function resetAIModelsCache(): void
1871
+ ```
1872
+
1873
+ #### `useAIModels(projectId)`
1874
+
1875
+ Subscribes to the cached AI model catalog. The first mount of a scope
1876
+ triggers a single `GET /ai/models` fetch; subsequent mounts return the
1877
+ cached result.
1647
1878
 
1648
1879
  ```typescript
1649
- function I18nProvider({
1650
- provider,
1651
- children,
1652
- }: I18nProviderProps): React.ReactElement<unknown, string | React.JSXElementConstructor<any>>
1880
+ function useAIModels(projectId?: string): UseAIModelsResult
1653
1881
  ```
1654
1882
 
1655
- - `props` — Component props (see {@link I18nProviderProps}).
1883
+ - `projectId` — Optional project scope: includes that project's custom ("bring your own AI") models on servers that support them.
1656
1884
 
1657
- **Returns:** The rendered i18n provider element.
1885
+ **Returns:** Models, free-tier model, loading flag, and error.
1658
1886
 
1659
- #### `localOnlyMessages(prev, history)`
1887
+ #### `useAuthClient()`
1660
1888
 
1661
- The messages only the local store holds, given a server history: optimistic
1662
- bubbles and session-local cards, minus the optimistic ECHO of a send the
1663
- server already persisted. A local user message carries a local id
1664
- (`user-N`), the server's copy a server id, so ids never match — content does.
1665
- Without this, the dashboard's first prompt (auto-sent by the workspace,
1666
- then merged back in from history by the remote-stream poll) rendered as two
1667
- identical user bubbles in every new project (2026-09-08).
1889
+ Hook to access the auth client from context.
1890
+
1891
+ Pass the same generics the client was created with —
1892
+ `useAuthClient<MyUser, { username: string }>()` — so `register()` accepts
1893
+ the app's own fields.
1668
1894
 
1669
1895
  ```typescript
1670
- function localOnlyMessages(prev: ChatMessage[], history: ChatMessage[]): ChatMessage[]
1896
+ function useAuthClient(): AuthClient<T, TRegister>
1671
1897
  ```
1672
1898
 
1673
- - `prev` — The store's current messages.
1674
- - `history` — The server's history.
1899
+ **Returns:** The auth client from context
1675
1900
 
1676
- **Returns:** The local-only messages to keep after the merged history.
1901
+ #### `useAuth(options)`
1677
1902
 
1678
- #### `LoggerProvider(props)`
1903
+ Hook for authentication state and actions.
1679
1904
 
1680
- Provider for logging.
1905
+ Pass the app's user type — the SAME type used for the auth client and its
1906
+ config (`createJWTAuthClient<MyUser>`, `AuthClientConfig<MyUser>`) — so
1907
+ `user` and `setSession`/`setUser` are typed for the pages:
1908
+ `useAuth<MyUser>()`.
1909
+
1910
+ For a sign-in the app runs itself (an OAuth redirect, a custom endpoint that
1911
+ already issued the token), call `setSession({ accessToken, user })`: it
1912
+ adopts the token and profile atomically and every consumer of this hook sees
1913
+ `status: 'authenticated'` at once. `setUser` alone does not sign in.
1914
+
1915
+ To create an account, use `const { register } = useAuth<MyUser>()` and
1916
+ `await register({ email, password, name })`. Registration returns the auth
1917
+ client's `AuthResult<MyUser>`; there is no separate `useRegister` hook.
1918
+
1919
+ An app whose API takes its OWN registration fields passes the client's
1920
+ second generic here too — `useAuth<MyUser, { username: string }>()` — so
1921
+ `register({ email, password, username })` is typed exactly like the client
1922
+ call (and `requestBody` receives the same payload). Without it, `register`
1923
+ accepts only the base fields.
1681
1924
 
1682
1925
  ```typescript
1683
- function LoggerProvider({
1684
- provider,
1685
- children,
1686
- }: LoggerProviderProps): React.ReactElement<unknown, string | React.JSXElementConstructor<any>>
1926
+ function useAuth(options?: UseAuthOptions): UseAuthResult<T, TRegister>
1687
1927
  ```
1688
1928
 
1689
- - `props` — Component props (see {@link LoggerProviderProps}).
1929
+ - `options` — Hook options
1690
1930
 
1691
- **Returns:** The rendered logger provider element.
1931
+ **Returns:** Auth state and action methods
1692
1932
 
1693
- #### `MoleculeProvider(props)`
1933
+ #### `useUser()`
1694
1934
 
1695
- Combined provider for all molecule services.
1935
+ Hook to get just the authenticated user.
1696
1936
 
1697
- Provides a convenient way to wrap your app with all molecule providers at once.
1698
- Only providers that are passed will be included.
1937
+ ```typescript
1938
+ function useUser(): T | null
1939
+ ```
1940
+
1941
+ **Returns:** The authenticated user or null
1942
+
1943
+ #### `useIsAuthenticated()`
1944
+
1945
+ Hook to check if user is authenticated.
1699
1946
 
1700
1947
  ```typescript
1701
- function MoleculeProvider({
1702
- children,
1703
- state,
1704
- auth,
1705
- theme,
1706
- router,
1707
- i18n,
1708
- http,
1709
- storage,
1710
- logger,
1711
- chat,
1712
- workspace,
1713
- editor,
1714
- preview,
1715
- }: MoleculeProviderProps): React.ReactElement<unknown, string | React.JSXElementConstructor<any>>
1948
+ function useIsAuthenticated(): boolean
1949
+ ```
1950
+
1951
+ **Returns:** Whether the user is authenticated
1952
+
1953
+ #### `useCapacitorApp(options)`
1954
+
1955
+ Hook for Capacitor app initialization and state management.
1956
+
1957
+ Creates a `CapacitorApp` coordinator on mount, subscribes to state changes,
1958
+ and auto-initializes. Cleans up listeners on unmount via `destroy()`.
1959
+
1960
+ ```typescript
1961
+ function useCapacitorApp(options?: CapacitorAppOptions): UseCapacitorAppResult
1716
1962
  ```
1717
1963
 
1718
- - `props` — Component props (see {@link MoleculeProviderProps}) — each service is optional, and ONLY the services passed are provided to the tree.
1964
+ - `options` — Capacitor app configuration options
1719
1965
 
1720
- **Returns:** The rendered combined provider element.
1966
+ **Returns:** Current app state and an `initialize` function for manual re-initialization
1721
1967
 
1722
- #### `PreviewProvider(props)`
1968
+ #### `useChangePassword()`
1723
1969
 
1724
- Provider for live preview.
1970
+ Hook for changing password with async state tracking.
1725
1971
 
1726
1972
  ```typescript
1727
- function PreviewProvider({
1728
- provider,
1729
- children,
1730
- }: PreviewProviderProps): React.ReactElement<unknown, string | React.JSXElementConstructor<any>>
1973
+ function useChangePassword(): UseChangePasswordReturn
1731
1974
  ```
1732
1975
 
1733
- - `props` — Component props (see {@link PreviewProviderProps}).
1976
+ **Returns:** Change password state and action
1734
1977
 
1735
- **Returns:** The rendered preview provider element.
1978
+ #### `convergeHistory(prev, history)`
1736
1979
 
1737
- #### `resetAIModelsCache()`
1980
+ Converge a live store on a fresh server history WITHOUT rewinding anything
1981
+ already on screen. This is the ONE place a server transcript is applied to a
1982
+ local view — the page-lifecycle/push reconcile, the remote-turn poll, the
1983
+ dropped-stream reconcile and the resume poll all go through it, because two
1984
+ paths that almost agree is how a message came to vanish and come back
1985
+ (reported 2026-09-21).
1738
1986
 
1739
- Test-only: drops every cached model list so the next `useAIModels` call
1740
- refetches. Exposed for unit tests; do not call from production code.
1987
+ Per message id the further-along copy wins ({@link messageProgress}); a TIE
1988
+ keeps the local copy, so an unchanged transcript returns the same object
1989
+ references and a poll neither churns React nor rewinds. Messages only the
1990
+ server has are added in the server's order (filling gaps a watcher missed);
1991
+ messages only the store has ({@link localOnlyMessages} — an answer still
1992
+ carrying its local id, a session-local card, a turn the server has not
1993
+ persisted yet) are kept after them.
1741
1994
 
1742
1995
  ```typescript
1743
- function resetAIModelsCache(): void
1996
+ function convergeHistory(prev: ChatMessage[], history: ChatMessage[]): ChatMessage[]
1997
+ ```
1998
+
1999
+ - `prev` — The store's current messages.
2000
+ - `history` — The messages from the server's history endpoint.
2001
+
2002
+ **Returns:** The converged message list.
2003
+
2004
+ #### `localOnlyMessages(prev, history)`
2005
+
2006
+ The messages only the local store holds, given a server history: optimistic
2007
+ bubbles and session-local cards, minus the optimistic ECHO of a send the
2008
+ server already persisted. A local user message carries a local id
2009
+ (`user-N`), the server's copy a server id, so ids never match — content does.
2010
+ Without this, the dashboard's first prompt (auto-sent by the workspace,
2011
+ then merged back in from history by the remote-stream poll) rendered as two
2012
+ identical user bubbles in every new project (2026-09-08).
2013
+
2014
+ ```typescript
2015
+ function localOnlyMessages(prev: ChatMessage[], history: ChatMessage[]): ChatMessage[]
1744
2016
  ```
1745
2017
 
2018
+ - `prev` — The store's current messages.
2019
+ - `history` — The server's history.
2020
+
2021
+ **Returns:** The local-only messages to keep after the merged history.
2022
+
1746
2023
  #### `resetChatStoresForTests()`
1747
2024
 
1748
2025
  Test-only: clear all conversation stores. The store is module-level (it must
@@ -1753,201 +2030,194 @@ outlive component mounts), so it persists across test cases — reset it in a
1753
2030
  function resetChatStoresForTests(): void
1754
2031
  ```
1755
2032
 
1756
- #### `RouterProvider(props)`
2033
+ #### `useChatProvider()`
1757
2034
 
1758
- Provider for routing.
2035
+ Access the chat provider from context.
1759
2036
 
1760
2037
  ```typescript
1761
- function RouterProvider({
1762
- router,
1763
- children,
1764
- }: RouterProviderProps): React.ReactElement<unknown, string | React.JSXElementConstructor<any>>
2038
+ function useChatProvider(): ChatProvider
1765
2039
  ```
1766
2040
 
1767
- - `props` — Component props (see {@link RouterProviderProps}).
2041
+ **Returns:** The ChatProvider instance from the nearest ChatContext.
1768
2042
 
1769
- **Returns:** The rendered router provider element.
2043
+ #### `useChat(options)`
1770
2044
 
1771
- #### `StateProvider(props)`
2045
+ Hook for AI chat with streaming support.
1772
2046
 
1773
- Provider for state management.
2047
+ Manages message state, sends messages to the backend, and handles
2048
+ SSE streaming responses.
1774
2049
 
1775
2050
  ```typescript
1776
- function StateProvider({
1777
- provider,
1778
- children,
1779
- }: StateProviderProps): React.ReactElement<unknown, string | React.JSXElementConstructor<any>>
2051
+ function useChat(options: UseChatOptions): UseChatResult
1780
2052
  ```
1781
2053
 
1782
- - `props` — Component props (see {@link StateProviderProps}).
1783
-
1784
- **Returns:** The rendered state provider element.
1785
-
1786
- #### `StorageProvider(props)`
1787
-
1788
- Provider for storage.
1789
-
1790
- ```typescript
1791
- function StorageProvider({
1792
- provider,
1793
- children,
1794
- }: StorageProviderProps): React.ReactElement<unknown, string | React.JSXElementConstructor<any>>
1795
- ```
2054
+ - `options` — Chat configuration including endpoint URL, project ID, and whether to load history on mount.
1796
2055
 
1797
- - `props` — Component props (see {@link StorageProviderProps}).
2056
+ **Returns:** Chat state and controls: messages, isLoading, error, sendMessage, abort, and clearHistory.
1798
2057
 
1799
- **Returns:** The rendered storage provider element.
2058
+ #### `useDevice()`
1800
2059
 
1801
- #### `ThemeProvider(props)`
2060
+ Hook for device information.
1802
2061
 
1803
- Provider for theming.
2062
+ Uses module-level `getProvider()` — device info is a singleton, not context-provided.
2063
+ Device info is static and doesn't change at runtime, so this uses `useMemo`.
1804
2064
 
1805
2065
  ```typescript
1806
- function ThemeProvider({
1807
- provider,
1808
- children,
1809
- }: ThemeProviderProps): React.ReactElement<unknown, string | React.JSXElementConstructor<any>>
2066
+ function useDevice(): UseDeviceResult
1810
2067
  ```
1811
2068
 
1812
- - `props` — Component props (see {@link ThemeProviderProps}).
1813
-
1814
- **Returns:** The rendered theme provider element.
2069
+ **Returns:** Device information and utility methods
1815
2070
 
1816
- #### `useAIModels(projectId)`
2071
+ #### `useEditorProvider()`
1817
2072
 
1818
- Subscribes to the cached AI model catalog. The first mount of a scope
1819
- triggers a single `GET /ai/models` fetch; subsequent mounts return the
1820
- cached result.
2073
+ Access the editor provider from context.
1821
2074
 
1822
2075
  ```typescript
1823
- function useAIModels(projectId?: string): UseAIModelsResult
2076
+ function useEditorProvider(): EditorProvider
1824
2077
  ```
1825
2078
 
1826
- - `projectId` — Optional project scope: includes that project's custom ("bring your own AI") models on servers that support them.
1827
-
1828
- **Returns:** Models, free-tier model, loading flag, and error.
1829
-
1830
- #### `useAppState()`
2079
+ **Returns:** The EditorProvider instance from the nearest EditorContext.
1831
2080
 
1832
- Tracks whether the app is in the foreground, background, or inactive.
2081
+ #### `useEditor()`
1833
2082
 
1834
- Uses React Native's `AppState` API under the hood. Falls back to
1835
- 'active' on platforms where AppState is unavailable.
2083
+ Hook for code editor management.
1836
2084
 
1837
2085
  ```typescript
1838
- function useAppState(): UseAppStateResult
2086
+ function useEditor(): UseEditorResult
1839
2087
  ```
1840
2088
 
1841
- **Returns:** Current app state and whether the app is active.
2089
+ **Returns:** Editor state and controls: tabs, activeFile, openFile, closeFile, getContent, setContent, setActiveTab, mount, dispose, and focus.
1842
2090
 
1843
- #### `useAuth(options)`
2091
+ #### `useForm(options)`
1844
2092
 
1845
- Hook for authentication state and actions.
2093
+ Hook for form state management.
2094
+
2095
+ Creates its controller through the bonded forms provider, so a React app
2096
+ wires a form library once (`setProvider` from `@molecule/app-forms`) and
2097
+ every form picks it up. Passing `createForm` overrides that for one form.
1846
2098
 
1847
2099
  ```typescript
1848
- function useAuth(options?: UseAuthOptions): UseAuthResult<T>
2100
+ function useForm(options?: UseFormOptions<T>): UseFormResult<T>
1849
2101
  ```
1850
2102
 
1851
- - `options` — Hook options
2103
+ - `options` — Form options. `defaultValues`, `mode` and the form-level `validate` are forwarded to the provider; omit the options entirely for a form whose fields are registered with their own defaults.
1852
2104
 
1853
- **Returns:** Auth state and action methods
2105
+ **Returns:** Form state and methods
1854
2106
 
1855
- #### `useAuthClient()`
2107
+ #### `useWatch(form, name)`
1856
2108
 
1857
- Hook to access the auth client from context.
2109
+ Hook to watch a specific field value.
1858
2110
 
1859
2111
  ```typescript
1860
- function useAuthClient(): AuthClient<T>
2112
+ function useWatch(form: FormController<T>, name: K): T[K]
1861
2113
  ```
1862
2114
 
1863
- **Returns:** The auth client from context
2115
+ - `form` — Form controller
2116
+ - `name` — Field name to watch
1864
2117
 
1865
- #### `useBackHandler(handler, options)`
2118
+ **Returns:** Current field value
1866
2119
 
1867
- Registers a handler for the Android hardware back button.
2120
+ #### `useFieldState(form, name)`
1868
2121
 
1869
- Return `true` from the handler to prevent the default back behavior,
1870
- or `false` to allow it.
2122
+ Hook to get field-level state.
1871
2123
 
1872
2124
  ```typescript
1873
- function useBackHandler(handler: () => boolean, options?: UseBackHandlerOptions): void
2125
+ function useFieldState(form: FormController<T>, name: keyof T): FieldState<T[keyof T]>
1874
2126
  ```
1875
2127
 
1876
- - `handler` — Callback invoked when the hardware back button is pressed.
1877
- - `options` — Optional configuration.
2128
+ - `form` — Form controller
2129
+ - `name` — Field name
1878
2130
 
1879
- #### `useCapacitorApp(options)`
2131
+ **Returns:** Field state (value, error, touched, dirty, valid)
1880
2132
 
1881
- Hook for Capacitor app initialization and state management.
2133
+ #### `useHttpClient()`
1882
2134
 
1883
- Creates a `CapacitorApp` coordinator on mount, subscribes to state changes,
1884
- and auto-initializes. Cleans up listeners on unmount via `destroy()`.
2135
+ Hook to access the HTTP client from context.
1885
2136
 
1886
2137
  ```typescript
1887
- function useCapacitorApp(options?: CapacitorAppOptions): UseCapacitorAppResult
2138
+ function useHttpClient(): HttpClient
1888
2139
  ```
1889
2140
 
1890
- - `options` — Capacitor app configuration options
2141
+ **Returns:** The HTTP client from context
1891
2142
 
1892
- **Returns:** Current app state and an `initialize` function for manual re-initialization
2143
+ #### `useHttp(method, url, options)`
1893
2144
 
1894
- #### `useChangePassword()`
2145
+ Hook for making HTTP requests with state management.
1895
2146
 
1896
- Hook for changing password with async state tracking.
2147
+ `execute` keeps one identity while `method`, `url` and the HTTP client stay the
2148
+ same — across the hook's own loading/data updates, parent rerenders, and inline
2149
+ options or callbacks — so `useEffect(() => { void execute() }, [execute])`
2150
+ runs once per request target instead of looping. The current headers, body,
2151
+ `signal` and callbacks are read when `execute` is called, so a later manual
2152
+ call always sends what the latest committed render passed. Changing `method`, `url` or
2153
+ the client does replace `execute` (it selects a different request) and
2154
+ re-runs such an effect.
1897
2155
 
1898
2156
  ```typescript
1899
- function useChangePassword(): UseChangePasswordReturn
2157
+ function useHttp(
2158
+ method: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE',
2159
+ url: string,
2160
+ options?: UseHttpOptions<T>,
2161
+ ): UseHttpResult<T>
1900
2162
  ```
1901
2163
 
1902
- **Returns:** Change password state and action
2164
+ - `method` — HTTP method
2165
+ - `url` — Request URL
2166
+ - `options` — Request options, read at call time
1903
2167
 
1904
- #### `useChat(options)`
2168
+ **Returns:** Request state and execute function
1905
2169
 
1906
- Hook for AI chat with streaming support.
2170
+ #### `useGet(url, options)`
1907
2171
 
1908
- Manages message state, sends messages to the backend, and handles
1909
- SSE streaming responses.
2172
+ Hook for GET requests.
1910
2173
 
1911
2174
  ```typescript
1912
- function useChat(options: UseChatOptions): UseChatResult
2175
+ function useGet(url: string, options?: UseHttpOptions<T>): UseHttpResult<T>
1913
2176
  ```
1914
2177
 
1915
- - `options` — Chat configuration including endpoint URL, project ID, and whether to load history on mount.
2178
+ - `url` — Request URL to fetch from.
2179
+ - `options` — HTTP request options including callbacks and request config.
1916
2180
 
1917
- **Returns:** Chat state and controls: messages, isLoading, error, sendMessage, abort, and clearHistory.
2181
+ **Returns:** Request state (data, loading, error) and controls (execute, reset).
1918
2182
 
1919
- #### `useChatProvider()`
2183
+ #### `usePost(url, options)`
1920
2184
 
1921
- Access the chat provider from context.
2185
+ Hook for POST requests.
1922
2186
 
1923
2187
  ```typescript
1924
- function useChatProvider(): ChatProvider
2188
+ function usePost(url: string, options?: UseHttpOptions<T>): UseHttpResult<T>
1925
2189
  ```
1926
2190
 
1927
- **Returns:** The ChatProvider instance from the nearest ChatContext.
2191
+ - `url` — Request URL to post to.
2192
+ - `options` — HTTP request options including body data and callbacks.
1928
2193
 
1929
- #### `useChildLogger(parentName, context)`
2194
+ **Returns:** Request state (data, loading, error) and controls (execute, reset).
1930
2195
 
1931
- Hook to create a child logger with additional context.
2196
+ #### `usePut(url, options)`
2197
+
2198
+ Hook for PUT requests.
1932
2199
 
1933
2200
  ```typescript
1934
- function useChildLogger(parentName: string, context: Record<string, unknown>): Logger
2201
+ function usePut(url: string, options?: UseHttpOptions<T>): UseHttpResult<T>
1935
2202
  ```
1936
2203
 
1937
- - `parentName` — Parent logger name
1938
- - `context` — Additional context to include in logs
2204
+ - `url` — Request URL to send the PUT request to.
2205
+ - `options` — HTTP request options including body data and callbacks.
1939
2206
 
1940
- **Returns:** Child logger instance
2207
+ **Returns:** Request state (data, loading, error) and controls (execute, reset).
1941
2208
 
1942
- #### `useCurrentTheme()`
2209
+ #### `usePatch(url, options)`
1943
2210
 
1944
- Hook to get just the current theme object.
2211
+ Hook for PATCH requests.
1945
2212
 
1946
2213
  ```typescript
1947
- function useCurrentTheme(): Theme
2214
+ function usePatch(url: string, options?: UseHttpOptions<T>): UseHttpResult<T>
1948
2215
  ```
1949
2216
 
1950
- **Returns:** The current theme
2217
+ - `url` — Request URL to send the PATCH request to.
2218
+ - `options` — HTTP request options including partial body data and callbacks.
2219
+
2220
+ **Returns:** Request state (data, loading, error) and controls (execute, reset).
1951
2221
 
1952
2222
  #### `useDelete(url, options)`
1953
2223
 
@@ -1962,189 +2232,198 @@ function useDelete(url: string, options?: UseHttpOptions<T>): UseHttpResult<T>
1962
2232
 
1963
2233
  **Returns:** Request state (data, loading, error) and controls (execute, reset).
1964
2234
 
1965
- #### `useDevice()`
1966
-
1967
- Hook for device information.
2235
+ #### `useLoggerProvider()`
1968
2236
 
1969
- Uses module-level `getProvider()` — device info is a singleton, not context-provided.
1970
- Device info is static and doesn't change at runtime, so this uses `useMemo`.
2237
+ Hook to access the logger provider from context.
1971
2238
 
1972
2239
  ```typescript
1973
- function useDevice(): UseDeviceResult
2240
+ function useLoggerProvider(): LoggerProvider
1974
2241
  ```
1975
2242
 
1976
- **Returns:** Device information and utility methods
2243
+ **Returns:** The logger provider from context
1977
2244
 
1978
- #### `useDirection()`
2245
+ #### `useLogger(name, config)`
1979
2246
 
1980
- Hook to get the text direction.
2247
+ Hook to get a logger instance.
1981
2248
 
1982
2249
  ```typescript
1983
- function useDirection(): 'ltr' | 'rtl'
2250
+ function useLogger(name: string, config?: Partial<LoggerConfig>): Logger
1984
2251
  ```
1985
2252
 
1986
- **Returns:** The text direction ('ltr' or 'rtl')
1987
-
1988
- #### `useEditor()`
1989
-
1990
- Hook for code editor management.
1991
-
1992
- ```typescript
1993
- function useEditor(): UseEditorResult
1994
- ```
2253
+ - `name` — Logger name (usually component or module name)
2254
+ - `config` — Optional logger configuration
1995
2255
 
1996
- **Returns:** Editor state and controls: tabs, activeFile, openFile, closeFile, getContent, setContent, setActiveTab, mount, dispose, and focus.
2256
+ **Returns:** Logger instance
1997
2257
 
1998
- #### `useEditorProvider()`
2258
+ #### `useRootLogger()`
1999
2259
 
2000
- Access the editor provider from context.
2260
+ Hook to get the root logger.
2001
2261
 
2002
2262
  ```typescript
2003
- function useEditorProvider(): EditorProvider
2263
+ function useRootLogger(): Logger
2004
2264
  ```
2005
2265
 
2006
- **Returns:** The EditorProvider instance from the nearest EditorContext.
2266
+ **Returns:** Root logger instance
2007
2267
 
2008
- #### `useFieldState(form, name)`
2268
+ #### `useChildLogger(parentName, context)`
2009
2269
 
2010
- Hook to get field-level state.
2270
+ Hook to create a child logger with additional context.
2011
2271
 
2012
2272
  ```typescript
2013
- function useFieldState(form: FormController<T>, name: keyof T): FieldState<T[keyof T]>
2273
+ function useChildLogger(parentName: string, context: Record<string, unknown>): Logger
2014
2274
  ```
2015
2275
 
2016
- - `form` — Form controller
2017
- - `name` — Field name
2276
+ - `parentName` — Parent logger name
2277
+ - `context` — Additional context to include in logs
2018
2278
 
2019
- **Returns:** Field state (value, error, touched, dirty, valid)
2279
+ **Returns:** Child logger instance
2020
2280
 
2021
- #### `useForm(options)`
2281
+ #### `useLogin()`
2022
2282
 
2023
- Hook for form state management.
2283
+ Hook for login with async state tracking.
2284
+ Registration is available through `const { register } = useAuth()`;
2285
+ call `register({ email, password, name })` to create an account. There is
2286
+ no separate `useRegister` hook. Use `usePromise(register)` when the form
2287
+ needs the same pending/error tracking as this login hook.
2024
2288
 
2025
2289
  ```typescript
2026
- function useForm(options: UseFormOptions<T>): UseFormResult<T>
2290
+ function useLogin(): UseLoginReturn<T>
2027
2291
  ```
2028
2292
 
2029
- - `options` — Form options including createForm from a forms provider
2293
+ **Returns:** Login state and action
2030
2294
 
2031
- **Returns:** Form state and methods
2295
+ #### `useOAuth(config)`
2032
2296
 
2033
- #### `useGet(url, options)`
2297
+ Hook for OAuth authentication.
2034
2298
 
2035
- Hook for GET requests.
2299
+ Reads OAuth configuration from the provided config and provides
2300
+ helpers to build OAuth URLs and start a login (full-page or popup).
2301
+ Automatically handles OAuth callbacks by detecting `code` and `state`
2302
+ URL parameters and exchanging them for a session — and, when the callback is
2303
+ running inside a popup we opened, relaying the result to the opener instead.
2036
2304
 
2037
2305
  ```typescript
2038
- function useGet(url: string, options?: UseHttpOptions<T>): UseHttpResult<T>
2306
+ function useOAuth(config?: {
2307
+ baseURL?: string
2308
+ oauthProviders?: string[]
2309
+ oauthEndpoint?: string
2310
+ loginEndpoint?: string
2311
+ onSuccess?: () => void
2312
+ onError?: (error: string) => void
2313
+ }): UseOAuthReturn
2039
2314
  ```
2040
2315
 
2041
- - `url` — Request URL to fetch from.
2042
- - `options` — HTTP request options including callbacks and request config.
2316
+ - `config` — Optional OAuth configuration override.
2317
+ - `config.baseURL` — Base URL for the API server (e.g. "https://api.example.com").
2318
+ - `config.oauthProviders` — List of supported OAuth provider names (e.g. ["google", "github"]).
2319
+ - `config.oauthEndpoint` — Path prefix for OAuth routes (defaults to "/oauth").
2320
+ - `config.loginEndpoint` — Path for the OAuth login POST endpoint (defaults to "/users/log-in/oauth").
2321
+ - `config.onSuccess` — Callback after successful OAuth login.
2322
+ - `config.onError` — Callback on OAuth login failure.
2043
2323
 
2044
- **Returns:** Request state (data, loading, error) and controls (execute, reset).
2324
+ **Returns:** OAuth helpers: providers, getOAuthUrl, redirect, and loginViaPopup.
2045
2325
 
2046
- #### `useHttp(method, url, options)`
2326
+ #### `usePasswordReset()`
2047
2327
 
2048
- Hook for making HTTP requests with state management.
2328
+ Hook for password reset flow with async state tracking.
2329
+
2330
+ Provides separate tracking for the request and confirm steps.
2049
2331
 
2050
2332
  ```typescript
2051
- function useHttp(
2052
- method: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE',
2053
- url: string,
2054
- options?: UseHttpOptions<T>,
2055
- ): UseHttpResult<T>
2333
+ function usePasswordReset(): UsePasswordResetReturn
2056
2334
  ```
2057
2335
 
2058
- - `method` — HTTP method
2059
- - `url` — Request URL
2060
- - `options` — Request options
2336
+ **Returns:** Password reset state and actions
2061
2337
 
2062
- **Returns:** Request state and execute function
2338
+ #### `usePlatform()`
2063
2339
 
2064
- #### `useHttpClient()`
2340
+ Hook for platform detection.
2065
2341
 
2066
- Hook to access the HTTP client from context.
2342
+ Uses module-level functions — platform is a singleton, not context-provided.
2343
+ Platform info is static and doesn't change at runtime, so this uses `useMemo`.
2067
2344
 
2068
2345
  ```typescript
2069
- function useHttpClient(): HttpClient
2346
+ function usePlatform(): UsePlatformResult
2070
2347
  ```
2071
2348
 
2072
- **Returns:** The HTTP client from context
2073
-
2074
- #### `useI18nError(error)`
2349
+ **Returns:** Platform information and utility methods
2075
2350
 
2076
- Translates an error at render time so the displayed message updates automatically
2077
- when the locale changes.
2351
+ #### `usePreviewProvider()`
2078
2352
 
2079
- **Always use this hook to display errors in React components** — accessing
2080
- `error.message` directly bypasses re-translation and leaves stale text after a
2081
- locale switch. If `error` is an `I18nError` (thrown via `throw new I18nError(key)`),
2082
- its key is translated using the current locale. For plain `Error` instances,
2083
- `error.message` is returned unchanged.
2353
+ Access the preview provider from context.
2084
2354
 
2085
2355
  ```typescript
2086
- function useI18nError(error: Error | null | undefined): string | null
2356
+ function usePreviewProvider(): PreviewProvider
2087
2357
  ```
2088
2358
 
2089
- - `error` — The error to translate, or `null`/`undefined`.
2090
-
2091
- **Returns:** The translated error string, or `null` if no error.
2359
+ **Returns:** The PreviewProvider instance from the nearest PreviewContext.
2092
2360
 
2093
- #### `useI18nProvider()`
2361
+ #### `usePreview()`
2094
2362
 
2095
- Hook to access the i18n provider from context.
2363
+ Hook for live preview management.
2096
2364
 
2097
2365
  ```typescript
2098
- function useI18nProvider(): I18nProvider
2366
+ function usePreview(): UsePreviewResult
2099
2367
  ```
2100
2368
 
2101
- **Returns:** The i18n provider from context
2369
+ **Returns:** Preview state and controls: state (url, isLoading, device, error, isConnected), setUrl, refresh, setDevice, and openExternal.
2102
2370
 
2103
- #### `useIsActive(path, exact)`
2371
+ #### `useProfileForm(options)`
2104
2372
 
2105
- Hook to check if a path is active.
2373
+ Owns load → edit → submit → publish for the signed-in user's profile.
2374
+
2375
+ Same-account background updates refresh untouched fields but preserve dirty
2376
+ controls. Session ownership comes from the auth client, independently of mutable
2377
+ profile fields; an explicit getIdentity adds the caller's identity check.
2378
+ Submission snapshots the registered values before asynchronous
2379
+ validation, sends only changed fields through `toPatch`, and uses the auth
2380
+ client's configured updateProfile transport. The saved server response becomes
2381
+ the clean baseline; edits made while saving remain dirty. No request is made
2382
+ for a patch with no fields. A failed request retains the edits and shared user.
2106
2383
 
2107
2384
  ```typescript
2108
- function useIsActive(path: string, exact?: boolean): boolean
2385
+ function useProfileForm(
2386
+ options: UseProfileFormOptions<TUser, TValues>,
2387
+ ): UseProfileFormResult<TUser, TValues>
2109
2388
  ```
2110
2389
 
2111
- - `path` — The path to check
2112
- - `exact` — Whether to match exactly (default: false)
2390
+ - `options` — Controlled defaults, identity and wire adapters, optional cache/navigation callback.
2113
2391
 
2114
- **Returns:** Whether the path is active
2392
+ **Returns:** Form state, typed control bindings, native submit binding and save error.
2115
2393
 
2116
- #### `useIsAuthenticated()`
2394
+ #### `usePush(options)`
2117
2395
 
2118
- Hook to check if user is authenticated.
2396
+ Hook for push notification state and actions.
2397
+
2398
+ Uses module-level `getProvider()` — push is a singleton, not context-provided.
2119
2399
 
2120
2400
  ```typescript
2121
- function useIsAuthenticated(): boolean
2401
+ function usePush(options?: UsePushOptions): UsePushResult
2122
2402
  ```
2123
2403
 
2124
- **Returns:** Whether the user is authenticated
2404
+ - `options` — Hook options
2125
2405
 
2126
- #### `useKeyboardHeight()`
2406
+ **Returns:** Push notification state and action methods
2127
2407
 
2128
- Tracks soft keyboard visibility and height.
2408
+ #### `useRouterInstance()`
2129
2409
 
2130
- Uses React Native's `Keyboard` API. Falls back to hidden state
2131
- on platforms where Keyboard is unavailable.
2410
+ Hook to access the router from context.
2132
2411
 
2133
2412
  ```typescript
2134
- function useKeyboardHeight(): UseKeyboardHeightResult
2413
+ function useRouterInstance(): Router
2135
2414
  ```
2136
2415
 
2137
- **Returns:** Current keyboard height and visibility state.
2416
+ **Returns:** The router from context
2138
2417
 
2139
- #### `useLocale()`
2418
+ #### `useRouter()`
2140
2419
 
2141
- Hook to get the current locale.
2420
+ Hook for routing state and actions.
2142
2421
 
2143
2422
  ```typescript
2144
- function useLocale(): string
2423
+ function useRouter(): UseRouterResult
2145
2424
  ```
2146
2425
 
2147
- **Returns:** The current locale code
2426
+ **Returns:** Router state and navigation methods
2148
2427
 
2149
2428
  #### `useLocation()`
2150
2429
 
@@ -2156,520 +2435,574 @@ function useLocation(): RouteLocation
2156
2435
 
2157
2436
  **Returns:** The current route location
2158
2437
 
2159
- #### `useLogger(name, config)`
2438
+ #### `useParams()`
2160
2439
 
2161
- Hook to get a logger instance.
2440
+ Hook to get route parameters.
2162
2441
 
2163
2442
  ```typescript
2164
- function useLogger(name: string, config?: Partial<LoggerConfig>): Logger
2443
+ function useParams(): T
2165
2444
  ```
2166
2445
 
2167
- - `name` — Logger name (usually component or module name)
2168
- - `config` — Optional logger configuration
2169
-
2170
- **Returns:** Logger instance
2446
+ **Returns:** The current route parameters
2171
2447
 
2172
- #### `useLoggerProvider()`
2448
+ #### `useQuery()`
2173
2449
 
2174
- Hook to access the logger provider from context.
2450
+ Hook to get query parameters.
2175
2451
 
2176
2452
  ```typescript
2177
- function useLoggerProvider(): LoggerProvider
2453
+ function useQuery(): T
2178
2454
  ```
2179
2455
 
2180
- **Returns:** The logger provider from context
2456
+ **Returns:** The current query parameters
2181
2457
 
2182
- #### `useLogin()`
2458
+ #### `useNavigate()`
2183
2459
 
2184
- Hook for login with async state tracking.
2460
+ Hook to get the navigate function.
2185
2461
 
2186
2462
  ```typescript
2187
- function useLogin(): UseLoginReturn<T>
2463
+ function useNavigate(): (path: string, options?: NavigateOptions) => void
2188
2464
  ```
2189
2465
 
2190
- **Returns:** Login state and action
2466
+ **Returns:** The navigate function
2191
2467
 
2192
- #### `useNavigate()`
2468
+ #### `useIsActive(path, exact)`
2193
2469
 
2194
- Hook to get the navigate function.
2470
+ Hook to check if a path is active.
2195
2471
 
2196
2472
  ```typescript
2197
- function useNavigate(): (path: string, options?: NavigateOptions) => void
2473
+ function useIsActive(path: string, exact?: boolean): boolean
2198
2474
  ```
2199
2475
 
2200
- **Returns:** The navigate function
2476
+ - `path` — The path to check
2477
+ - `exact` — Whether to match exactly (default: false)
2201
2478
 
2202
- #### `useOAuth(config)`
2479
+ **Returns:** Whether the path is active
2203
2480
 
2204
- Hook for OAuth authentication.
2481
+ #### `useSignup()`
2205
2482
 
2206
- Reads OAuth configuration from the provided config and provides
2207
- helpers to build OAuth URLs and start a login (full-page or popup).
2208
- Automatically handles OAuth callbacks by detecting `code` and `state`
2209
- URL parameters and exchanging them for a session — and, when the callback is
2210
- running inside a popup we opened, relaying the result to the opener instead.
2483
+ Hook for user registration with async state tracking.
2211
2484
 
2212
2485
  ```typescript
2213
- function useOAuth(config?: {
2214
- baseURL?: string
2215
- oauthProviders?: string[]
2216
- oauthEndpoint?: string
2217
- loginEndpoint?: string
2218
- onSuccess?: () => void
2219
- onError?: (error: string) => void
2220
- }): UseOAuthReturn
2486
+ function useSignup(): UseSignupReturn<T, TRegister>
2221
2487
  ```
2222
2488
 
2223
- - `config` — Optional OAuth configuration override.
2224
- - `config.baseURL` — Base URL for the API server (e.g. "https://api.example.com").
2225
- - `config.oauthProviders` — List of supported OAuth provider names (e.g. ["google", "github"]).
2226
- - `config.oauthEndpoint` — Path prefix for OAuth routes (defaults to "/oauth").
2227
- - `config.loginEndpoint` — Path for the OAuth login POST endpoint (defaults to "/users/log-in/oauth").
2228
- - `config.onSuccess` — Callback after successful OAuth login.
2229
- - `config.onError` — Callback on OAuth login failure.
2489
+ **Returns:** Signup state and action
2230
2490
 
2231
- **Returns:** OAuth helpers: providers, getOAuthUrl, redirect, and loginViaPopup.
2491
+ #### `useStorageProvider()`
2232
2492
 
2233
- #### `useParams()`
2493
+ Hook to access the storage provider from context.
2234
2494
 
2235
- Hook to get route parameters.
2495
+ ```typescript
2496
+ function useStorageProvider(): StorageProvider
2497
+ ```
2498
+
2499
+ **Returns:** The storage provider from context
2500
+
2501
+ #### `useStorageValue(key, options)`
2502
+
2503
+ Hook to manage a single storage value with React state sync.
2236
2504
 
2237
2505
  ```typescript
2238
- function useParams(): T
2506
+ function useStorageValue(key: string, options?: UseStorageValueOptions<T>): UseStorageValueResult<T>
2239
2507
  ```
2240
2508
 
2241
- **Returns:** The current route parameters
2509
+ - `key` — Storage key
2510
+ - `options` — Hook options
2242
2511
 
2243
- #### `usePasswordReset()`
2512
+ **Returns:** Storage value state (value, loading, error) and mutators (setValue, removeValue).
2244
2513
 
2245
- Hook for password reset flow with async state tracking.
2514
+ #### `useStorage()`
2246
2515
 
2247
- Provides separate tracking for the request and confirm steps.
2516
+ Hook for simple storage operations without React state sync.
2248
2517
 
2249
2518
  ```typescript
2250
- function usePasswordReset(): UsePasswordResetReturn
2519
+ function useStorage(): {
2520
+ get: <T>(key: string) => Promise<T | null>
2521
+ set: <T>(key: string, value: T) => Promise<void>
2522
+ remove: (key: string) => Promise<void>
2523
+ clear: () => Promise<void>
2524
+ keys: () => Promise<string[]>
2525
+ }
2251
2526
  ```
2252
2527
 
2253
- **Returns:** Password reset state and actions
2528
+ **Returns:** Storage operation methods
2254
2529
 
2255
- #### `usePatch(url, options)`
2530
+ #### `useStateProvider()`
2256
2531
 
2257
- Hook for PATCH requests.
2532
+ Hook to access the state provider from context.
2533
+
2534
+ The context comes from `<StateProvider provider={…}>` or from
2535
+ `<MoleculeProvider>` — which supplies the provider bonded under
2536
+ `@molecule/app-state` by default, so a scaffolded app needs no `state` prop.
2537
+
2538
+ Only hooks that read the context call this; `useStore(store)` takes its store
2539
+ as an argument and works with no provider at all.
2258
2540
 
2259
2541
  ```typescript
2260
- function usePatch(url: string, options?: UseHttpOptions<T>): UseHttpResult<T>
2542
+ function useStateProvider(): StateProvider
2261
2543
  ```
2262
2544
 
2263
- - `url` — Request URL to send the PATCH request to.
2264
- - `options` — HTTP request options including partial body data and callbacks.
2545
+ **Returns:** The state provider from context
2546
+
2547
+ #### `useStore(store, options)`
2548
+
2549
+ Hook to subscribe to a store with optional selector and equality function.
2550
+
2551
+ The store is the argument, so this hook needs NO `StateProvider`: it reads
2552
+ `store.getState()` and subscribes with `store.subscribe()`, and never touches
2553
+ the state context. A store minted outside the `state` bond — the direct
2554
+ `createStoreWithActions()` / `createStore()` a provider package exports — is
2555
+ therefore as valid here as one `@molecule/app-state`'s `createStore()` made.
2556
+
2557
+ ```typescript
2558
+ function useStore(store: Store<T>, options?: UseStoreOptions<T, S>): S
2559
+ ```
2265
2560
 
2266
- **Returns:** Request state (data, loading, error) and controls (execute, reset).
2561
+ - `store` — The store to subscribe to
2562
+ - `options` — Hook options (selector, equalityFn)
2267
2563
 
2268
- #### `usePlatform()`
2564
+ **Returns:** The selected state
2269
2565
 
2270
- Hook for platform detection.
2566
+ #### `useSetStore(store)`
2271
2567
 
2272
- Uses module-level functions — platform is a singleton, not context-provided.
2273
- Platform info is static and doesn't change at runtime, so this uses `useMemo`.
2568
+ Hook to get the store's setState function.
2274
2569
 
2275
2570
  ```typescript
2276
- function usePlatform(): UsePlatformResult
2571
+ function useSetStore(store: Store<T>): (partial: Partial<T> | ((state: T) => Partial<T>)) => void
2277
2572
  ```
2278
2573
 
2279
- **Returns:** Platform information and utility methods
2574
+ - `store` — The store to get setState from
2280
2575
 
2281
- #### `usePost(url, options)`
2576
+ **Returns:** The setState function
2282
2577
 
2283
- Hook for POST requests.
2578
+ #### `useStoreAction(store, action)`
2579
+
2580
+ Hook to create a bound action for a store.
2284
2581
 
2285
2582
  ```typescript
2286
- function usePost(url: string, options?: UseHttpOptions<T>): UseHttpResult<T>
2583
+ function useStoreAction(
2584
+ store: Store<T>,
2585
+ action: (setState: Store<T>['setState'], getState: Store<T>['getState']) => (...args: Args) => R,
2586
+ ): (...args: Args) => R
2287
2587
  ```
2288
2588
 
2289
- - `url` — Request URL to post to.
2290
- - `options` — HTTP request options including body data and callbacks.
2589
+ - `store` — The store to bind to
2590
+ - `action` — The action function that receives setState and getState
2291
2591
 
2292
- **Returns:** Request state (data, loading, error) and controls (execute, reset).
2592
+ **Returns:** A bound action function
2293
2593
 
2294
- #### `usePreview()`
2594
+ #### `useThemeProvider()`
2295
2595
 
2296
- Hook for live preview management.
2596
+ Hook to access the theme provider from context.
2297
2597
 
2298
2598
  ```typescript
2299
- function usePreview(): UsePreviewResult
2599
+ function useThemeProvider(): ThemeProvider
2300
2600
  ```
2301
2601
 
2302
- **Returns:** Preview state and controls: state (url, isLoading, device, error, isConnected), setUrl, refresh, setDevice, and openExternal.
2602
+ **Returns:** The theme provider from context
2303
2603
 
2304
- #### `usePreviewProvider()`
2604
+ #### `useTheme()`
2305
2605
 
2306
- Access the preview provider from context.
2606
+ Hook for theme state and actions.
2307
2607
 
2308
2608
  ```typescript
2309
- function usePreviewProvider(): PreviewProvider
2609
+ function useTheme(): UseThemeResult
2310
2610
  ```
2311
2611
 
2312
- **Returns:** The PreviewProvider instance from the nearest PreviewContext.
2313
-
2314
- #### `usePush(options)`
2612
+ **Returns:** Theme state and actions
2315
2613
 
2316
- Hook for push notification state and actions.
2614
+ #### `useCurrentTheme()`
2317
2615
 
2318
- Uses module-level `getProvider()` — push is a singleton, not context-provided.
2616
+ Hook to get just the current theme object.
2319
2617
 
2320
2618
  ```typescript
2321
- function usePush(options?: UsePushOptions): UsePushResult
2619
+ function useCurrentTheme(): Theme
2322
2620
  ```
2323
2621
 
2324
- - `options` — Hook options
2325
-
2326
- **Returns:** Push notification state and action methods
2622
+ **Returns:** The current theme
2327
2623
 
2328
- #### `usePut(url, options)`
2624
+ #### `useThemeMode()`
2329
2625
 
2330
- Hook for PUT requests.
2626
+ Hook to get just the theme mode (light/dark).
2331
2627
 
2332
2628
  ```typescript
2333
- function usePut(url: string, options?: UseHttpOptions<T>): UseHttpResult<T>
2629
+ function useThemeMode(): 'light' | 'dark'
2334
2630
  ```
2335
2631
 
2336
- - `url` — Request URL to send the PUT request to.
2337
- - `options` — HTTP request options including body data and callbacks.
2338
-
2339
- **Returns:** Request state (data, loading, error) and controls (execute, reset).
2632
+ **Returns:** The current theme mode
2340
2633
 
2341
- #### `useQuery()`
2634
+ #### `useThemeColors()`
2342
2635
 
2343
- Hook to get query parameters.
2636
+ Hook to get theme colors.
2344
2637
 
2345
2638
  ```typescript
2346
- function useQuery(): T
2639
+ function useThemeColors(): ThemeColors
2347
2640
  ```
2348
2641
 
2349
- **Returns:** The current query parameters
2642
+ **Returns:** The current theme colors
2350
2643
 
2351
- #### `useRootLogger()`
2644
+ #### `useI18nProvider()`
2352
2645
 
2353
- Hook to get the root logger.
2646
+ Hook to access the i18n provider from context.
2354
2647
 
2355
2648
  ```typescript
2356
- function useRootLogger(): Logger
2649
+ function useI18nProvider(): I18nProvider
2357
2650
  ```
2358
2651
 
2359
- **Returns:** Root logger instance
2652
+ **Returns:** The i18n provider from context
2360
2653
 
2361
- #### `useRouter()`
2654
+ #### `useTranslation()`
2362
2655
 
2363
- Hook for routing state and actions.
2656
+ Hook for internationalization.
2364
2657
 
2365
2658
  ```typescript
2366
- function useRouter(): UseRouterResult
2659
+ function useTranslation(): UseTranslationResult
2367
2660
  ```
2368
2661
 
2369
- **Returns:** Router state and navigation methods
2662
+ **Returns:** Translation function and locale management
2370
2663
 
2371
- #### `useRouterInstance()`
2664
+ #### `useT()`
2372
2665
 
2373
- Hook to access the router from context.
2666
+ Hook to get just the translation function.
2374
2667
 
2375
2668
  ```typescript
2376
- function useRouterInstance(): Router
2669
+ function useT(): (
2670
+ key: string,
2671
+ values?: InterpolationValues,
2672
+ options?: { defaultValue?: string; count?: number },
2673
+ ) => string
2377
2674
  ```
2378
2675
 
2379
- **Returns:** The router from context
2380
-
2381
- #### `useSafeArea()`
2676
+ **Returns:** The translation function
2382
2677
 
2383
- Returns the current safe area insets from `react-native-safe-area-context`.
2678
+ #### `useLocale()`
2384
2679
 
2385
- Must be used within a `SafeAreaProvider`. Falls back to zero insets
2386
- if the context is unavailable.
2680
+ Hook to get the current locale.
2387
2681
 
2388
2682
  ```typescript
2389
- function useSafeArea(): SafeAreaInsets
2683
+ function useLocale(): string
2390
2684
  ```
2391
2685
 
2392
- **Returns:** Safe area insets for the current device.
2686
+ **Returns:** The current locale code
2393
2687
 
2394
- #### `useSetStore(store)`
2688
+ #### `useDirection()`
2395
2689
 
2396
- Hook to get the store's setState function.
2690
+ Hook to get the text direction.
2397
2691
 
2398
2692
  ```typescript
2399
- function useSetStore(store: Store<T>): (partial: Partial<T> | ((state: T) => Partial<T>)) => void
2693
+ function useDirection(): 'ltr' | 'rtl'
2400
2694
  ```
2401
2695
 
2402
- - `store` — The store to get setState from
2696
+ **Returns:** The text direction ('ltr' or 'rtl')
2403
2697
 
2404
- **Returns:** The setState function
2698
+ #### `useI18nError(error)`
2405
2699
 
2406
- #### `useSignup()`
2700
+ Translates an error at render time so the displayed message updates automatically
2701
+ when the locale changes.
2407
2702
 
2408
- Hook for user registration with async state tracking.
2703
+ **Always use this hook to display errors in React components** — accessing
2704
+ `error.message` directly bypasses re-translation and leaves stale text after a
2705
+ locale switch. If `error` is an `I18nError` (thrown via `throw new I18nError(key)`),
2706
+ its key is translated using the current locale. For plain `Error` instances,
2707
+ `error.message` is returned unchanged.
2409
2708
 
2410
2709
  ```typescript
2411
- function useSignup(): UseSignupReturn<T>
2710
+ function useI18nError(error: Error | null | undefined): string | null
2412
2711
  ```
2413
2712
 
2414
- **Returns:** Signup state and action
2415
-
2416
- #### `useStateProvider()`
2713
+ - `error` — The error to translate, or `null`/`undefined`.
2417
2714
 
2418
- Hook to access the state provider from context.
2715
+ **Returns:** The translated error string, or `null` if no error.
2419
2716
 
2420
- ```typescript
2421
- function useStateProvider(): StateProvider
2422
- ```
2717
+ #### `useVerifyPaymentReturn(options)`
2423
2718
 
2424
- **Returns:** The state provider from context
2719
+ Reads the payment id a provider put in the return URL and confirms the
2720
+ purchase server-side with `POST /users/:id/verify-payment/:provider`.
2425
2721
 
2426
- #### `useStorage()`
2722
+ **This is why a hosted checkout returns the buyer to the APP and not the
2723
+ API.** Session cookies are host-only on the app's origin, so a top-level
2724
+ redirect from the provider straight to an authenticated API callback on a
2725
+ different host arrives with NO credentials — it answers 401 and the paid plan
2726
+ is never granted. The request this hook makes is a same-origin call from a
2727
+ loaded app page, so the credentials apply. It waits for auth to hydrate
2728
+ first: after the redirect the page is a cold load, and the session is
2729
+ restored from the httpOnly cookie via `GET /users/me`.
2427
2730
 
2428
- Hook for simple storage operations without React state sync.
2731
+ Verification is idempotent server-side (first-claim-wins on the transaction),
2732
+ and this hook additionally runs at most once per transaction id per page.
2733
+ Safe on pages that are also reached normally: with no id in the URL it stays
2734
+ `idle` and issues no request.
2429
2735
 
2430
2736
  ```typescript
2431
- function useStorage(): {
2432
- get: <T>(key: string) => Promise<T | null>
2433
- set: <T>(key: string, value: T) => Promise<void>
2434
- remove: (key: string) => Promise<void>
2435
- clear: () => Promise<void>
2436
- keys: () => Promise<string[]>
2437
- }
2737
+ function useVerifyPaymentReturn(
2738
+ options?: UseVerifyPaymentReturnOptions,
2739
+ ): UseVerifyPaymentReturnResult
2438
2740
  ```
2439
2741
 
2440
- **Returns:** Storage operation methods
2742
+ - `options` — Provider fallback + lifecycle callbacks (see {@link UseVerifyPaymentReturnOptions}).
2441
2743
 
2442
- #### `useStorageProvider()`
2744
+ **Returns:** The verification state (see {@link UseVerifyPaymentReturnResult}).
2443
2745
 
2444
- Hook to access the storage provider from context.
2746
+ #### `useVersion()`
2747
+
2748
+ Hook for version state and update actions.
2749
+
2750
+ Uses module-level `getProvider()` — version is a singleton, not context-provided.
2445
2751
 
2446
2752
  ```typescript
2447
- function useStorageProvider(): StorageProvider
2753
+ function useVersion(): UseVersionResult
2448
2754
  ```
2449
2755
 
2450
- **Returns:** The storage provider from context
2756
+ **Returns:** Version state and action methods
2451
2757
 
2452
- #### `useStorageValue(key, options)`
2758
+ #### `useWorkspaceProvider()`
2453
2759
 
2454
- Hook to manage a single storage value with React state sync.
2760
+ Access the workspace provider from context.
2455
2761
 
2456
2762
  ```typescript
2457
- function useStorageValue(key: string, options?: UseStorageValueOptions<T>): UseStorageValueResult<T>
2763
+ function useWorkspaceProvider(): WorkspaceProvider
2458
2764
  ```
2459
2765
 
2460
- - `key` — Storage key
2461
- - `options` — Hook options
2462
-
2463
- **Returns:** Storage value state (value, loading, error) and mutators (setValue, removeValue).
2766
+ **Returns:** The result.
2464
2767
 
2465
- #### `useStore(store, options)`
2768
+ #### `useWorkspace()`
2466
2769
 
2467
- Hook to subscribe to a store with optional selector and equality function.
2770
+ Hook for IDE workspace layout management.
2468
2771
 
2469
2772
  ```typescript
2470
- function useStore(store: Store<T>, options?: UseStoreOptions<T, S>): S
2773
+ function useWorkspace(): UseWorkspaceResult
2471
2774
  ```
2472
2775
 
2473
- - `store` — The store to subscribe to
2474
- - `options` — Hook options (selector, equalityFn)
2475
-
2476
- **Returns:** The selected state
2776
+ **Returns:** The workspace state and management methods.
2477
2777
 
2478
- #### `useStoreAction(store, action)`
2778
+ #### `StateProvider(props)`
2479
2779
 
2480
- Hook to create a bound action for a store.
2780
+ Provider for state management.
2481
2781
 
2482
2782
  ```typescript
2483
- function useStoreAction(
2484
- store: Store<T>,
2485
- action: (setState: Store<T>['setState'], getState: Store<T>['getState']) => (...args: Args) => R,
2486
- ): (...args: Args) => R
2783
+ function StateProvider({
2784
+ provider,
2785
+ children,
2786
+ }: StateProviderProps): React.ReactElement<unknown, string | React.JSXElementConstructor<any>>
2487
2787
  ```
2488
2788
 
2489
- - `store` — The store to bind to
2490
- - `action` — The action function that receives setState and getState
2789
+ - `props` — Component props (see {@link StateProviderProps}).
2491
2790
 
2492
- **Returns:** A bound action function
2791
+ **Returns:** The rendered state provider element.
2493
2792
 
2494
- #### `useT()`
2793
+ #### `AuthProvider(props)`
2495
2794
 
2496
- Hook to get just the translation function.
2795
+ Provider for authentication.
2497
2796
 
2498
2797
  ```typescript
2499
- function useT(): (
2500
- key: string,
2501
- values?: InterpolationValues,
2502
- options?: { defaultValue?: string; count?: number },
2503
- ) => string
2798
+ function AuthProvider({
2799
+ client,
2800
+ children,
2801
+ }: AuthProviderProps<T>): React.ReactElement<unknown, string | React.JSXElementConstructor<any>>
2504
2802
  ```
2505
2803
 
2506
- **Returns:** The translation function
2804
+ - `props` — Component props (see {@link AuthProviderProps}).
2507
2805
 
2508
- #### `useTheme()`
2806
+ **Returns:** The rendered auth provider element.
2509
2807
 
2510
- Hook for theme state and actions.
2808
+ #### `ThemeProvider(props)`
2809
+
2810
+ Provider for theming.
2511
2811
 
2512
2812
  ```typescript
2513
- function useTheme(): UseThemeResult
2813
+ function ThemeProvider({
2814
+ provider,
2815
+ children,
2816
+ }: ThemeProviderProps): React.ReactElement<unknown, string | React.JSXElementConstructor<any>>
2514
2817
  ```
2515
2818
 
2516
- **Returns:** Theme state and actions
2819
+ - `props` — Component props (see {@link ThemeProviderProps}).
2820
+
2821
+ **Returns:** The rendered theme provider element.
2517
2822
 
2518
- #### `useThemeColors()`
2823
+ #### `RouterProvider(props)`
2519
2824
 
2520
- Hook to get theme colors.
2825
+ Provider for routing.
2521
2826
 
2522
2827
  ```typescript
2523
- function useThemeColors(): ThemeColors
2828
+ function RouterProvider({
2829
+ router,
2830
+ children,
2831
+ }: RouterProviderProps): React.ReactElement<unknown, string | React.JSXElementConstructor<any>>
2524
2832
  ```
2525
2833
 
2526
- **Returns:** The current theme colors
2834
+ - `props` — Component props (see {@link RouterProviderProps}).
2527
2835
 
2528
- #### `useThemeMode()`
2836
+ **Returns:** The rendered router provider element.
2529
2837
 
2530
- Hook to get just the theme mode (light/dark).
2838
+ #### `I18nProvider(props)`
2839
+
2840
+ Provider for internationalization.
2531
2841
 
2532
2842
  ```typescript
2533
- function useThemeMode(): 'light' | 'dark'
2843
+ function I18nProvider({
2844
+ provider,
2845
+ children,
2846
+ }: I18nProviderProps): React.ReactElement<unknown, string | React.JSXElementConstructor<any>>
2534
2847
  ```
2535
2848
 
2536
- **Returns:** The current theme mode
2849
+ - `props` — Component props (see {@link I18nProviderProps}).
2537
2850
 
2538
- #### `useThemeProvider()`
2851
+ **Returns:** The rendered i18n provider element.
2539
2852
 
2540
- Hook to access the theme provider from context.
2853
+ #### `HttpProvider(props)`
2854
+
2855
+ Provider for HTTP client.
2541
2856
 
2542
2857
  ```typescript
2543
- function useThemeProvider(): ThemeProvider
2858
+ function HttpProvider({
2859
+ client,
2860
+ children,
2861
+ }: HttpProviderProps): React.ReactElement<unknown, string | React.JSXElementConstructor<any>>
2544
2862
  ```
2545
2863
 
2546
- **Returns:** The theme provider from context
2864
+ - `props` — Component props (see {@link HttpProviderProps}).
2547
2865
 
2548
- #### `useTranslation()`
2866
+ **Returns:** The rendered HTTP provider element.
2549
2867
 
2550
- Hook for internationalization.
2868
+ #### `StorageProvider(props)`
2869
+
2870
+ Provider for storage.
2551
2871
 
2552
2872
  ```typescript
2553
- function useTranslation(): UseTranslationResult
2873
+ function StorageProvider({
2874
+ provider,
2875
+ children,
2876
+ }: StorageProviderProps): React.ReactElement<unknown, string | React.JSXElementConstructor<any>>
2554
2877
  ```
2555
2878
 
2556
- **Returns:** Translation function and locale management
2879
+ - `props` — Component props (see {@link StorageProviderProps}).
2557
2880
 
2558
- #### `useUser()`
2881
+ **Returns:** The rendered storage provider element.
2559
2882
 
2560
- Hook to get just the authenticated user.
2883
+ #### `LoggerProvider(props)`
2884
+
2885
+ Provider for logging.
2561
2886
 
2562
2887
  ```typescript
2563
- function useUser(): T | null
2888
+ function LoggerProvider({
2889
+ provider,
2890
+ children,
2891
+ }: LoggerProviderProps): React.ReactElement<unknown, string | React.JSXElementConstructor<any>>
2564
2892
  ```
2565
2893
 
2566
- **Returns:** The authenticated user or null
2567
-
2568
- #### `useVerifyPaymentReturn(options)`
2894
+ - `props` — Component props (see {@link LoggerProviderProps}).
2569
2895
 
2570
- Reads the payment id a provider put in the return URL and confirms the
2571
- purchase server-side with `POST /users/:id/verify-payment/:provider`.
2896
+ **Returns:** The rendered logger provider element.
2572
2897
 
2573
- **This is why a hosted checkout returns the buyer to the APP and not the
2574
- API.** Session cookies are host-only on the app's origin, so a top-level
2575
- redirect from the provider straight to an authenticated API callback on a
2576
- different host arrives with NO credentials — it answers 401 and the paid plan
2577
- is never granted. The request this hook makes is a same-origin call from a
2578
- loaded app page, so the credentials apply. It waits for auth to hydrate
2579
- first: after the redirect the page is a cold load, and the session is
2580
- restored from the httpOnly cookie via `GET /users/me`.
2898
+ #### `ChatProvider(props)`
2581
2899
 
2582
- Verification is idempotent server-side (first-claim-wins on the transaction),
2583
- and this hook additionally runs at most once per transaction id per page.
2584
- Safe on pages that are also reached normally: with no id in the URL it stays
2585
- `idle` and issues no request.
2900
+ Provider for AI chat.
2586
2901
 
2587
2902
  ```typescript
2588
- function useVerifyPaymentReturn(
2589
- options?: UseVerifyPaymentReturnOptions,
2590
- ): UseVerifyPaymentReturnResult
2903
+ function ChatProvider({
2904
+ provider,
2905
+ children,
2906
+ }: ChatProviderProps): React.ReactElement<unknown, string | React.JSXElementConstructor<any>>
2591
2907
  ```
2592
2908
 
2593
- - `options` — Provider fallback + lifecycle callbacks (see {@link UseVerifyPaymentReturnOptions}).
2594
-
2595
- **Returns:** The verification state (see {@link UseVerifyPaymentReturnResult}).
2909
+ - `props` — Component props (see {@link ChatProviderProps}).
2596
2910
 
2597
- #### `useVersion()`
2911
+ **Returns:** The rendered chat provider element.
2598
2912
 
2599
- Hook for version state and update actions.
2913
+ #### `WorkspaceProvider(props)`
2600
2914
 
2601
- Uses module-level `getProvider()` — version is a singleton, not context-provided.
2915
+ Provider for IDE workspace.
2602
2916
 
2603
2917
  ```typescript
2604
- function useVersion(): UseVersionResult
2918
+ function WorkspaceProvider({
2919
+ provider,
2920
+ children,
2921
+ }: WorkspaceProviderProps): React.ReactElement<unknown, string | React.JSXElementConstructor<any>>
2605
2922
  ```
2606
2923
 
2607
- **Returns:** Version state and action methods
2924
+ - `props` — Component props (see {@link WorkspaceProviderProps}).
2608
2925
 
2609
- #### `useWatch(form, name)`
2926
+ **Returns:** The rendered workspace provider element.
2610
2927
 
2611
- Hook to watch a specific field value.
2928
+ #### `EditorProvider(props)`
2929
+
2930
+ Provider for code editor.
2612
2931
 
2613
2932
  ```typescript
2614
- function useWatch(form: FormController<T>, name: K): T[K]
2933
+ function EditorProvider({
2934
+ provider,
2935
+ children,
2936
+ }: EditorProviderProps): React.ReactElement<unknown, string | React.JSXElementConstructor<any>>
2615
2937
  ```
2616
2938
 
2617
- - `form` — Form controller
2618
- - `name` — Field name to watch
2939
+ - `props` — Component props (see {@link EditorProviderProps}).
2619
2940
 
2620
- **Returns:** Current field value
2941
+ **Returns:** The rendered editor provider element.
2621
2942
 
2622
- #### `useWorkspace()`
2943
+ #### `PreviewProvider(props)`
2623
2944
 
2624
- Hook for IDE workspace layout management.
2945
+ Provider for live preview.
2625
2946
 
2626
2947
  ```typescript
2627
- function useWorkspace(): UseWorkspaceResult
2948
+ function PreviewProvider({
2949
+ provider,
2950
+ children,
2951
+ }: PreviewProviderProps): React.ReactElement<unknown, string | React.JSXElementConstructor<any>>
2628
2952
  ```
2629
2953
 
2630
- **Returns:** The workspace state and management methods.
2631
-
2632
- #### `useWorkspaceProvider()`
2633
-
2634
- Access the workspace provider from context.
2954
+ - `props` — Component props (see {@link PreviewProviderProps}).
2635
2955
 
2636
- ```typescript
2637
- function useWorkspaceProvider(): WorkspaceProvider
2638
- ```
2956
+ **Returns:** The rendered preview provider element.
2639
2957
 
2640
- **Returns:** The result.
2958
+ #### `MoleculeProvider(props)`
2641
2959
 
2642
- #### `WorkspaceProvider(props)`
2960
+ Combined provider for all molecule services.
2643
2961
 
2644
- Provider for IDE workspace.
2962
+ Provides a convenient way to wrap your app with all molecule providers at once.
2963
+ Only providers that are passed will be included — except `state`, which falls
2964
+ back to the state provider bonded under `@molecule/app-state` (set by
2965
+ `setupAllDefaultBonds()` or a state bond) so `useStore()` works without a
2966
+ `state` prop.
2645
2967
 
2646
2968
  ```typescript
2647
- function WorkspaceProvider({
2648
- provider,
2969
+ function MoleculeProvider({
2649
2970
  children,
2650
- }: WorkspaceProviderProps): React.ReactElement<unknown, string | React.JSXElementConstructor<any>>
2971
+ state,
2972
+ auth,
2973
+ theme,
2974
+ router,
2975
+ i18n,
2976
+ http,
2977
+ storage,
2978
+ logger,
2979
+ chat,
2980
+ workspace,
2981
+ editor,
2982
+ preview,
2983
+ }: MoleculeProviderProps): React.ReactElement<unknown, string | React.JSXElementConstructor<any>>
2651
2984
  ```
2652
2985
 
2653
- - `props` — Component props (see {@link WorkspaceProviderProps}).
2986
+ - `props` — Component props (see {@link MoleculeProviderProps}) — each service is optional, and ONLY the services passed are provided to the tree.
2654
2987
 
2655
- **Returns:** The rendered workspace provider element.
2988
+ **Returns:** The rendered combined provider element.
2656
2989
 
2657
2990
  ### Constants
2658
2991
 
2659
- #### `AuthContext`
2992
+ #### `DEFAULT_AGENT_NAME`
2660
2993
 
2661
- Context for authentication client.
2994
+ Neutral, product-agnostic agent name used when the host supplies none.
2662
2995
 
2663
2996
  ```typescript
2664
- const AuthContext: Context<AuthClient<unknown> | null>
2997
+ const DEFAULT_AGENT_NAME: 'the assistant'
2665
2998
  ```
2666
2999
 
2667
- #### `ChatContext`
3000
+ #### `DEFAULT_PRODUCT_NAME`
2668
3001
 
2669
- Context for AI chat provider.
3002
+ Neutral, product-agnostic product/IDE name used when the host supplies none.
2670
3003
 
2671
3004
  ```typescript
2672
- const ChatContext: Context<ChatProvider | null>
3005
+ const DEFAULT_PRODUCT_NAME: 'the IDE'
2673
3006
  ```
2674
3007
 
2675
3008
  #### `DEFAULT_AGENT_IDENTITY`
@@ -2682,36 +3015,36 @@ passes its own.
2682
3015
  const DEFAULT_AGENT_IDENTITY: AgentIdentity
2683
3016
  ```
2684
3017
 
2685
- #### `DEFAULT_AGENT_NAME`
3018
+ #### `StateContext`
2686
3019
 
2687
- Neutral, product-agnostic agent name used when the host supplies none.
3020
+ Context for state management provider.
2688
3021
 
2689
3022
  ```typescript
2690
- const DEFAULT_AGENT_NAME: 'the assistant'
3023
+ const StateContext: Context<StateProvider | null>
2691
3024
  ```
2692
3025
 
2693
- #### `DEFAULT_PRODUCT_NAME`
3026
+ #### `AuthContext`
2694
3027
 
2695
- Neutral, product-agnostic product/IDE name used when the host supplies none.
3028
+ Context for authentication client.
2696
3029
 
2697
3030
  ```typescript
2698
- const DEFAULT_PRODUCT_NAME: 'the IDE'
3031
+ const AuthContext: Context<AuthClient<unknown, Record<never, never>> | null>
2699
3032
  ```
2700
3033
 
2701
- #### `EditorContext`
3034
+ #### `ThemeContext`
2702
3035
 
2703
- Context for code editor provider.
3036
+ Context for theme provider.
2704
3037
 
2705
3038
  ```typescript
2706
- const EditorContext: Context<EditorProvider | null>
3039
+ const ThemeContext: Context<ThemeProvider | null>
2707
3040
  ```
2708
3041
 
2709
- #### `HttpContext`
3042
+ #### `RouterContext`
2710
3043
 
2711
- Context for HTTP client.
3044
+ Context for router.
2712
3045
 
2713
3046
  ```typescript
2714
- const HttpContext: Context<HttpClient | null>
3047
+ const RouterContext: Context<Router | null>
2715
3048
  ```
2716
3049
 
2717
3050
  #### `I18nContext`
@@ -2722,52 +3055,60 @@ Context for internationalization provider.
2722
3055
  const I18nContext: Context<I18nProvider | null>
2723
3056
  ```
2724
3057
 
2725
- #### `LoggerContext`
3058
+ #### `HttpContext`
2726
3059
 
2727
- Context for logger provider.
3060
+ Context for HTTP client.
2728
3061
 
2729
3062
  ```typescript
2730
- const LoggerContext: Context<LoggerProvider | null>
3063
+ const HttpContext: Context<HttpClient | null>
2731
3064
  ```
2732
3065
 
2733
- #### `PreviewContext`
3066
+ #### `StorageContext`
2734
3067
 
2735
- Context for live preview provider.
3068
+ Context for storage provider.
2736
3069
 
2737
3070
  ```typescript
2738
- const PreviewContext: Context<PreviewProvider | null>
3071
+ const StorageContext: Context<StorageProvider | null>
2739
3072
  ```
2740
3073
 
2741
- #### `RouterContext`
3074
+ #### `LoggerContext`
2742
3075
 
2743
- Context for router.
3076
+ Context for logger provider.
2744
3077
 
2745
3078
  ```typescript
2746
- const RouterContext: Context<Router | null>
3079
+ const LoggerContext: Context<LoggerProvider | null>
2747
3080
  ```
2748
3081
 
2749
- #### `StateContext`
3082
+ #### `ChatContext`
2750
3083
 
2751
- Context for state management provider.
3084
+ Context for AI chat provider.
2752
3085
 
2753
3086
  ```typescript
2754
- const StateContext: Context<StateProvider | null>
3087
+ const ChatContext: Context<ChatProvider | null>
2755
3088
  ```
2756
3089
 
2757
- #### `StorageContext`
3090
+ #### `WorkspaceContext`
2758
3091
 
2759
- Context for storage provider.
3092
+ Context for IDE workspace provider.
2760
3093
 
2761
3094
  ```typescript
2762
- const StorageContext: Context<StorageProvider | null>
3095
+ const WorkspaceContext: Context<WorkspaceProvider | null>
2763
3096
  ```
2764
3097
 
2765
- #### `ThemeContext`
3098
+ #### `EditorContext`
2766
3099
 
2767
- Context for theme provider.
3100
+ Context for code editor provider.
2768
3101
 
2769
3102
  ```typescript
2770
- const ThemeContext: Context<ThemeProvider | null>
3103
+ const EditorContext: Context<EditorProvider | null>
3104
+ ```
3105
+
3106
+ #### `PreviewContext`
3107
+
3108
+ Context for live preview provider.
3109
+
3110
+ ```typescript
3111
+ const PreviewContext: Context<PreviewProvider | null>
2771
3112
  ```
2772
3113
 
2773
3114
  #### `useAsyncState`
@@ -2778,6 +3119,10 @@ Hook like useState but accepts Promises and supports partial state extension.
2778
3119
  const useAsyncState: <T>(initialState: T) => [T, AsyncSetState<T>, AsyncExtendState<T>]
2779
3120
  ```
2780
3121
 
3122
+ - `initialState` — Initial state value
3123
+
3124
+ **Returns:** Tuple of [state, asyncSetState, asyncExtendState]
3125
+
2781
3126
  #### `usePromise`
2782
3127
 
2783
3128
  Hook that wraps an async function with state tracking.
@@ -2791,13 +3136,9 @@ const usePromise: <T extends (...args: any[]) => Promise<any>>(
2791
3136
  ]
2792
3137
  ```
2793
3138
 
2794
- #### `WorkspaceContext`
2795
-
2796
- Context for IDE workspace provider.
3139
+ - `asyncFn` — The async function to wrap
2797
3140
 
2798
- ```typescript
2799
- const WorkspaceContext: Context<WorkspaceProvider | null>
2800
- ```
3141
+ **Returns:** Tuple of [state, wrappedFunction]
2801
3142
 
2802
3143
  ## Injection Notes
2803
3144