@molecule/app-react-native 1.0.1 → 1.0.3

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