@objectstack/client-react 17.1.0 → 17.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +398 -0
- package/dist/index.d.mts +72 -9
- package/dist/index.d.ts +72 -9
- package/dist/index.js.map +1 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +5 -5
package/dist/index.d.ts
CHANGED
|
@@ -34,8 +34,17 @@ declare const ObjectStackLocaleContext: React.Context<string | undefined>;
|
|
|
34
34
|
* Provider component that makes ObjectStackClient available to all child components
|
|
35
35
|
*
|
|
36
36
|
* @example
|
|
37
|
+
* <!-- os:check -->
|
|
37
38
|
* ```tsx
|
|
39
|
+
* import { ObjectStackClient } from '@objectstack/client';
|
|
40
|
+
* import { ObjectStackProvider } from '@objectstack/client-react';
|
|
41
|
+
*
|
|
38
42
|
* const client = new ObjectStackClient({ baseUrl: 'http://localhost:3000' });
|
|
43
|
+
* const language = 'en';
|
|
44
|
+
*
|
|
45
|
+
* function YourComponents() {
|
|
46
|
+
* return <div>Your app</div>;
|
|
47
|
+
* }
|
|
39
48
|
*
|
|
40
49
|
* function App() {
|
|
41
50
|
* return (
|
|
@@ -59,7 +68,10 @@ declare function useObjectStackLocale(): string | undefined;
|
|
|
59
68
|
* @throws Error if used outside of ObjectStackProvider
|
|
60
69
|
*
|
|
61
70
|
* @example
|
|
71
|
+
* <!-- os:check -->
|
|
62
72
|
* ```tsx
|
|
73
|
+
* import { useClient } from '@objectstack/client-react';
|
|
74
|
+
*
|
|
63
75
|
* function MyComponent() {
|
|
64
76
|
* const client = useClient();
|
|
65
77
|
* // Use client.data.find(), etc.
|
|
@@ -116,7 +128,10 @@ interface UseQueryResult<T = any> {
|
|
|
116
128
|
* Hook for querying ObjectStack data with automatic caching and refetching
|
|
117
129
|
*
|
|
118
130
|
* @example
|
|
131
|
+
* <!-- os:check -->
|
|
119
132
|
* ```tsx
|
|
133
|
+
* import { useQuery } from '@objectstack/client-react';
|
|
134
|
+
*
|
|
120
135
|
* function TaskList() {
|
|
121
136
|
* const { data, isLoading, error, refetch } = useQuery('todo_task', {
|
|
122
137
|
* fields: ['id', 'subject', 'priority'],
|
|
@@ -129,7 +144,7 @@ interface UseQueryResult<T = any> {
|
|
|
129
144
|
*
|
|
130
145
|
* return (
|
|
131
146
|
* <div>
|
|
132
|
-
* {data?.
|
|
147
|
+
* {data?.records.map(task => (
|
|
133
148
|
* <div key={task.id}>{task.subject}</div>
|
|
134
149
|
* ))}
|
|
135
150
|
* </div>
|
|
@@ -170,7 +185,10 @@ interface UseMutationResult<TData = any, TVariables = any> {
|
|
|
170
185
|
* Hook for creating, updating, or deleting ObjectStack data
|
|
171
186
|
*
|
|
172
187
|
* @example
|
|
188
|
+
* <!-- os:check -->
|
|
173
189
|
* ```tsx
|
|
190
|
+
* import { useMutation } from '@objectstack/client-react';
|
|
191
|
+
*
|
|
174
192
|
* function CreateTaskForm() {
|
|
175
193
|
* const { mutate, isLoading, error } = useMutation('todo_task', 'create', {
|
|
176
194
|
* onSuccess: (data) => {
|
|
@@ -178,11 +196,11 @@ interface UseMutationResult<TData = any, TVariables = any> {
|
|
|
178
196
|
* }
|
|
179
197
|
* });
|
|
180
198
|
*
|
|
181
|
-
* const handleSubmit = (formData) => {
|
|
199
|
+
* const handleSubmit = (formData: Record<string, unknown>) => {
|
|
182
200
|
* mutate(formData);
|
|
183
201
|
* };
|
|
184
202
|
*
|
|
185
|
-
* return <
|
|
203
|
+
* return <button onClick={() => handleSubmit({ subject: 'New task' })}>Create</button>;
|
|
186
204
|
* }
|
|
187
205
|
* ```
|
|
188
206
|
*/
|
|
@@ -221,7 +239,10 @@ interface UsePaginationResult<T = any> extends UseQueryResult<T> {
|
|
|
221
239
|
* Hook for paginated data queries
|
|
222
240
|
*
|
|
223
241
|
* @example
|
|
242
|
+
* <!-- os:check -->
|
|
224
243
|
* ```tsx
|
|
244
|
+
* import { usePagination } from '@objectstack/client-react';
|
|
245
|
+
*
|
|
225
246
|
* function PaginatedTaskList() {
|
|
226
247
|
* const {
|
|
227
248
|
* data,
|
|
@@ -239,7 +260,7 @@ interface UsePaginationResult<T = any> extends UseQueryResult<T> {
|
|
|
239
260
|
*
|
|
240
261
|
* return (
|
|
241
262
|
* <div>
|
|
242
|
-
* {data?.
|
|
263
|
+
* {data?.records.map(task => <div key={task.id}>{task.subject}</div>)}
|
|
243
264
|
* <button onClick={previousPage} disabled={!hasPreviousPage}>Previous</button>
|
|
244
265
|
* <span>Page {page} of {totalPages}</span>
|
|
245
266
|
* <button onClick={nextPage} disabled={!hasNextPage}>Next</button>
|
|
@@ -283,7 +304,10 @@ interface UseInfiniteQueryResult<T = any> {
|
|
|
283
304
|
* Hook for infinite scrolling / load more functionality
|
|
284
305
|
*
|
|
285
306
|
* @example
|
|
307
|
+
* <!-- os:check -->
|
|
286
308
|
* ```tsx
|
|
309
|
+
* import { useInfiniteQuery } from '@objectstack/client-react';
|
|
310
|
+
*
|
|
287
311
|
* function InfiniteTaskList() {
|
|
288
312
|
* const {
|
|
289
313
|
* flatData,
|
|
@@ -362,7 +386,10 @@ interface UseMetadataResult<T = any> {
|
|
|
362
386
|
* now. See {@link useFields} for the pre-flattened field list.
|
|
363
387
|
*
|
|
364
388
|
* @example
|
|
389
|
+
* <!-- os:check -->
|
|
365
390
|
* ```tsx
|
|
391
|
+
* import { useObject } from '@objectstack/client-react';
|
|
392
|
+
*
|
|
366
393
|
* function ObjectSchemaViewer({ objectName }: { objectName: string }) {
|
|
367
394
|
* const { data, isLoading, error } = useObject(objectName);
|
|
368
395
|
*
|
|
@@ -384,7 +411,10 @@ declare function useObject(objectName: string, options?: UseMetadataOptions): Us
|
|
|
384
411
|
* Hook for fetching view configuration
|
|
385
412
|
*
|
|
386
413
|
* @example
|
|
414
|
+
* <!-- os:check -->
|
|
387
415
|
* ```tsx
|
|
416
|
+
* import { useView } from '@objectstack/client-react';
|
|
417
|
+
*
|
|
388
418
|
* function ViewConfiguration({ objectName }: { objectName: string }) {
|
|
389
419
|
* const { data: view, isLoading } = useView(objectName, 'list');
|
|
390
420
|
*
|
|
@@ -404,7 +434,10 @@ declare function useView(objectName: string, viewType?: 'list' | 'form', options
|
|
|
404
434
|
* Hook for extracting fields from object schema
|
|
405
435
|
*
|
|
406
436
|
* @example
|
|
437
|
+
* <!-- os:check -->
|
|
407
438
|
* ```tsx
|
|
439
|
+
* import { useFields } from '@objectstack/client-react';
|
|
440
|
+
*
|
|
408
441
|
* function FieldList({ objectName }: { objectName: string }) {
|
|
409
442
|
* const { data: fields, isLoading } = useFields(objectName);
|
|
410
443
|
*
|
|
@@ -425,11 +458,14 @@ declare function useFields(objectName: string, options?: UseMetadataOptions): Us
|
|
|
425
458
|
* Generic metadata hook for custom metadata queries
|
|
426
459
|
*
|
|
427
460
|
* @example
|
|
461
|
+
* <!-- os:check -->
|
|
428
462
|
* ```tsx
|
|
463
|
+
* import { useMetadata } from '@objectstack/client-react';
|
|
464
|
+
*
|
|
429
465
|
* function CustomMetadata() {
|
|
430
466
|
* const { data, isLoading } = useMetadata(async (client) => {
|
|
431
467
|
* // Custom metadata fetching logic
|
|
432
|
-
* const object = await client.meta.
|
|
468
|
+
* const object = await client.meta.getItem('object', 'custom_object');
|
|
433
469
|
* const view = await client.meta.getView('custom_object', 'list');
|
|
434
470
|
* return { object, view };
|
|
435
471
|
* });
|
|
@@ -453,7 +489,11 @@ declare function useMetadata<T = any>(fetcher: (client: ReturnType<typeof useCli
|
|
|
453
489
|
* @returns Latest metadata event or null
|
|
454
490
|
*
|
|
455
491
|
* @example
|
|
492
|
+
* <!-- os:check -->
|
|
456
493
|
* ```tsx
|
|
494
|
+
* import { useEffect } from 'react';
|
|
495
|
+
* import { useMetadataSubscription } from '@objectstack/client-react';
|
|
496
|
+
*
|
|
457
497
|
* function ObjectList() {
|
|
458
498
|
* const event = useMetadataSubscription('object');
|
|
459
499
|
*
|
|
@@ -479,7 +519,11 @@ declare function useMetadataSubscription(type: MetadataEventSubject, options?: {
|
|
|
479
519
|
* @returns Latest data event or null
|
|
480
520
|
*
|
|
481
521
|
* @example
|
|
522
|
+
* <!-- os:check -->
|
|
482
523
|
* ```tsx
|
|
524
|
+
* import { useEffect } from 'react';
|
|
525
|
+
* import { useDataSubscription } from '@objectstack/client-react';
|
|
526
|
+
*
|
|
483
527
|
* function TaskDetail({ taskId }: { taskId: string }) {
|
|
484
528
|
* const event = useDataSubscription('project_task', { recordId: taskId });
|
|
485
529
|
*
|
|
@@ -509,9 +553,12 @@ declare function useDataSubscription(object: string, options?: {
|
|
|
509
553
|
* @param options - Optional filters
|
|
510
554
|
*
|
|
511
555
|
* @example
|
|
556
|
+
* <!-- os:check -->
|
|
512
557
|
* ```tsx
|
|
558
|
+
* import { useQuery, useMetadataSubscriptionCallback } from '@objectstack/client-react';
|
|
559
|
+
*
|
|
513
560
|
* function ObjectList() {
|
|
514
|
-
* const { refetch } = useQuery(
|
|
561
|
+
* const { refetch } = useQuery('todo_task', {});
|
|
515
562
|
*
|
|
516
563
|
* useMetadataSubscriptionCallback('object', () => {
|
|
517
564
|
* refetch(); // Refetch list when objects change
|
|
@@ -532,9 +579,12 @@ declare function useMetadataSubscriptionCallback(type: MetadataEventSubject, cal
|
|
|
532
579
|
* @param options - Optional filters
|
|
533
580
|
*
|
|
534
581
|
* @example
|
|
582
|
+
* <!-- os:check -->
|
|
535
583
|
* ```tsx
|
|
584
|
+
* import { useQuery, useDataSubscriptionCallback } from '@objectstack/client-react';
|
|
585
|
+
*
|
|
536
586
|
* function TaskList() {
|
|
537
|
-
* const { refetch } = useQuery(
|
|
587
|
+
* const { refetch } = useQuery('project_task', {});
|
|
538
588
|
*
|
|
539
589
|
* useDataSubscriptionCallback('project_task', () => {
|
|
540
590
|
* refetch(); // Refetch list when tasks change
|
|
@@ -567,7 +617,11 @@ declare function useDataSubscriptionCallback(object: string, callback: (event: D
|
|
|
567
617
|
* @returns Latest bulk data event or null
|
|
568
618
|
*
|
|
569
619
|
* @example
|
|
620
|
+
* <!-- os:check -->
|
|
570
621
|
* ```tsx
|
|
622
|
+
* import { useEffect } from 'react';
|
|
623
|
+
* import { useBulkDataSubscription } from '@objectstack/client-react';
|
|
624
|
+
*
|
|
571
625
|
* function TaskList() {
|
|
572
626
|
* const bulk = useBulkDataSubscription('project_task');
|
|
573
627
|
*
|
|
@@ -592,9 +646,12 @@ declare function useBulkDataSubscription(object: string): BulkDataEvent | null;
|
|
|
592
646
|
* @param callback - Callback to invoke on events
|
|
593
647
|
*
|
|
594
648
|
* @example
|
|
649
|
+
* <!-- os:check -->
|
|
595
650
|
* ```tsx
|
|
651
|
+
* import { useQuery, useBulkDataSubscriptionCallback } from '@objectstack/client-react';
|
|
652
|
+
*
|
|
596
653
|
* function TaskList() {
|
|
597
|
-
* const { refetch } = useQuery(
|
|
654
|
+
* const { refetch } = useQuery('project_task', {});
|
|
598
655
|
*
|
|
599
656
|
* useBulkDataSubscriptionCallback('project_task', () => {
|
|
600
657
|
* refetch(); // a predicate write touched an unknown set of rows
|
|
@@ -611,7 +668,10 @@ declare function useBulkDataSubscriptionCallback(object: string, callback: (even
|
|
|
611
668
|
* @returns Whether realtime is connected
|
|
612
669
|
*
|
|
613
670
|
* @example
|
|
671
|
+
* <!-- os:check -->
|
|
614
672
|
* ```tsx
|
|
673
|
+
* import { useRealtimeConnection } from '@objectstack/client-react';
|
|
674
|
+
*
|
|
615
675
|
* function ConnectionIndicator() {
|
|
616
676
|
* const connected = useRealtimeConnection();
|
|
617
677
|
*
|
|
@@ -646,13 +706,16 @@ declare function useRealtimeConnection(): boolean;
|
|
|
646
706
|
* @param options - Optional filters
|
|
647
707
|
*
|
|
648
708
|
* @example
|
|
709
|
+
* <!-- os:check -->
|
|
649
710
|
* ```tsx
|
|
711
|
+
* import { useQuery, useAutoRefresh } from '@objectstack/client-react';
|
|
712
|
+
*
|
|
650
713
|
* function TaskList() {
|
|
651
714
|
* const { data, refetch } = useQuery('project_task', {});
|
|
652
715
|
*
|
|
653
716
|
* useAutoRefresh('project_task', refetch);
|
|
654
717
|
*
|
|
655
|
-
* return <div>{data.map(
|
|
718
|
+
* return <div>{data?.records.map(task => <div key={task.id}>{task.subject}</div>)}</div>;
|
|
656
719
|
* }
|
|
657
720
|
* ```
|
|
658
721
|
*/
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.tsx","../src/context.tsx","../src/data-hooks.tsx","../src/internal-deps.ts","../src/metadata-hooks.tsx","../src/realtime-hooks.tsx"],"sourcesContent":["// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * @objectstack/client-react\n * \n * React hooks for ObjectStack Client SDK\n * \n * Provides type-safe React hooks for:\n * - Data queries (useQuery, useMutation, usePagination, useInfiniteQuery)\n * - Metadata access (useObject, useView, useFields, useMetadata)\n * - Client context (ObjectStackProvider, useClient)\n */\n\n// Context & Provider\nexport {\n ObjectStackProvider,\n ObjectStackContext,\n ObjectStackLocaleContext,\n useClient,\n useObjectStackLocale,\n type ObjectStackProviderProps\n} from './context';\n\n// Data Hooks\nexport {\n useQuery,\n useMutation,\n usePagination,\n useInfiniteQuery,\n type UseQueryOptions,\n type UseQueryResult,\n type UseMutationOptions,\n type UseMutationResult,\n type UsePaginationOptions,\n type UsePaginationResult,\n type UseInfiniteQueryOptions,\n type UseInfiniteQueryResult\n} from './data-hooks';\n\n// Metadata Hooks\nexport {\n useObject,\n useView,\n useFields,\n useMetadata,\n type UseMetadataOptions,\n type UseMetadataResult\n} from './metadata-hooks';\n\n// Realtime Event Hooks\nexport {\n useMetadataSubscription,\n useDataSubscription,\n useMetadataSubscriptionCallback,\n useDataSubscriptionCallback,\n useBulkDataSubscription,\n useBulkDataSubscriptionCallback,\n useRealtimeConnection,\n useAutoRefresh\n} from './realtime-hooks';\n\n// Re-export ObjectStackClient and types from @objectstack/client\nexport { ObjectStackClient, type ClientConfig } from '@objectstack/client';\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * ObjectStack React Context\n * \n * Provides ObjectStackClient instance to React components via Context API\n */\n\nimport * as React from 'react';\nimport { createContext, useContext, useRef, ReactNode } from 'react';\nimport { ObjectStackClient } from '@objectstack/client';\n\nexport interface ObjectStackProviderProps {\n client: ObjectStackClient;\n /**\n * Active UI locale (BCP-47, e.g. `'zh-CN'`). Keep this in sync with your\n * language switcher — the provider pushes it into the client (so requests\n * carry `Accept-Language`) and metadata hooks (`useObject`, `useView`,\n * `useMetadata`) re-fetch when it changes, so switching language relabels\n * the UI without a page refresh (issue #1319).\n */\n locale?: string;\n children: ReactNode;\n}\n\nexport const ObjectStackContext = createContext<ObjectStackClient | null>(null);\n\n/**\n * Carries the active UI locale separately from the client so existing\n * `useContext(ObjectStackContext)` consumers keep receiving the bare client\n * (no breaking change to that context's shape).\n */\nexport const ObjectStackLocaleContext = createContext<string | undefined>(undefined);\n\n/**\n * Provider component that makes ObjectStackClient available to all child components\n * \n * @example\n * ```tsx\n * const client = new ObjectStackClient({ baseUrl: 'http://localhost:3000' });\n * \n * function App() {\n * return (\n * <ObjectStackProvider client={client} locale={language}>\n * <YourComponents />\n * </ObjectStackProvider>\n * );\n * }\n * ```\n */\nexport function ObjectStackProvider({ client, locale, children }: ObjectStackProviderProps) {\n // Mirror the active locale onto the client so every request carries the\n // matching `Accept-Language`.\n //\n // This MUST run during render, not in a `useEffect`. The child metadata\n // hooks read `locale` from context and re-fetch via their own effects, and\n // React flushes child effects *before* parent effects — so syncing the\n // client in an effect here would update it only after the refetch already\n // fired, sending the stale `Accept-Language`. Render runs parent-before-\n // child, so updating the client here guarantees it is current before any\n // child fetches. The ref keeps the write idempotent across re-renders /\n // StrictMode double-invokes.\n const synced = useRef<{ client: ObjectStackClient; locale: string | undefined } | null>(null);\n if (synced.current?.client !== client || synced.current?.locale !== locale) {\n synced.current = { client, locale };\n client.setLocale?.(locale);\n }\n\n return (\n <ObjectStackContext.Provider value={client}>\n <ObjectStackLocaleContext.Provider value={locale}>\n {children}\n </ObjectStackLocaleContext.Provider>\n </ObjectStackContext.Provider>\n );\n}\n\n/**\n * Hook to read the active UI locale provided to {@link ObjectStackProvider}.\n * Returns `undefined` when no locale was supplied. Metadata hooks fold this\n * into their fetch dependencies so a locale change triggers a re-fetch.\n */\nexport function useObjectStackLocale(): string | undefined {\n return useContext(ObjectStackLocaleContext);\n}\n\n/**\n * Hook to access the ObjectStackClient instance from context\n * \n * @throws Error if used outside of ObjectStackProvider\n * \n * @example\n * ```tsx\n * function MyComponent() {\n * const client = useClient();\n * // Use client.data.find(), etc.\n * }\n * ```\n */\nexport function useClient(): ObjectStackClient {\n const client = useContext(ObjectStackContext);\n \n if (!client) {\n throw new Error(\n 'useClient must be used within an ObjectStackProvider. ' +\n 'Make sure your component is wrapped with <ObjectStackProvider client={...}>.'\n );\n }\n \n return client;\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * Data Query Hooks\n * \n * React hooks for querying and mutating ObjectStack data\n */\n\nimport { useState, useEffect, useCallback, useRef } from 'react';\nimport { QueryAST, FilterCondition } from '@objectstack/spec/data';\nimport { PaginatedResult } from '@objectstack/client';\nimport { useClient } from './context';\nimport { stableKey, useEventCallback } from './internal-deps';\n\n/**\n * Query options for useQuery hook.\n *\n * Uses the canonical Spec protocol field names: `where`, `fields`,\n * `orderBy`, `limit`, `offset`. (The legacy aliases `filters` / `select` /\n * `sort` / `top` / `skip` were removed in 11.0.)\n */\nexport interface UseQueryOptions<T = any> {\n /** Query AST or simplified query options */\n query?: Partial<QueryAST>;\n\n // ── Canonical (Spec protocol) field names ──────────────────────────\n /** Filter conditions (WHERE clause). */\n where?: FilterCondition;\n /** Fields to retrieve (SELECT clause). */\n fields?: string[];\n /** Sort definition (ORDER BY clause). */\n orderBy?: string | string[];\n /** Maximum number of records to return (LIMIT). */\n limit?: number;\n /** Number of records to skip (OFFSET). */\n offset?: number;\n\n\n /** Enable/disable automatic query execution */\n enabled?: boolean;\n /** Refetch interval in milliseconds */\n refetchInterval?: number;\n /** Callback on successful query */\n onSuccess?: (data: PaginatedResult<T>) => void;\n /** Callback on error */\n onError?: (error: Error) => void;\n}\n\n/**\n * Query result for useQuery hook\n */\nexport interface UseQueryResult<T = any> {\n /** Query result data */\n data: PaginatedResult<T> | null;\n /** Loading state */\n isLoading: boolean;\n /** Error state */\n error: Error | null;\n /** Refetch the query */\n refetch: () => Promise<void>;\n /** Is currently refetching */\n isRefetching: boolean;\n}\n\n/**\n * Hook for querying ObjectStack data with automatic caching and refetching\n * \n * @example\n * ```tsx\n * function TaskList() {\n * const { data, isLoading, error, refetch } = useQuery('todo_task', {\n * fields: ['id', 'subject', 'priority'],\n * orderBy: ['-created_at'],\n * limit: 20\n * });\n * \n * if (isLoading) return <div>Loading...</div>;\n * if (error) return <div>Error: {error.message}</div>;\n * \n * return (\n * <div>\n * {data?.value.map(task => (\n * <div key={task.id}>{task.subject}</div>\n * ))}\n * </div>\n * );\n * }\n * ```\n */\nexport function useQuery<T = any>(\n object: string,\n options: UseQueryOptions<T> = {}\n): UseQueryResult<T> {\n const client = useClient();\n const [data, setData] = useState<PaginatedResult<T> | null>(null);\n const [isLoading, setIsLoading] = useState(true);\n const [isRefetching, setIsRefetching] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n const intervalRef = useRef<NodeJS.Timeout | undefined>(undefined);\n \n const {\n query,\n // Canonical names take precedence over legacy names\n where, fields, orderBy, limit, offset,\n enabled = true,\n refetchInterval,\n onSuccess,\n onError\n } = options;\n\n const resolvedFields = fields;\n const resolvedWhere = where;\n const resolvedSort = orderBy;\n const resolvedLimit = limit;\n const resolvedOffset = offset;\n\n // The query shape as a VALUE (#4693). `where` / `fields` / `orderBy` are\n // objects and arrays, and the documented usage builds them inline, so keying\n // the fetch on their identities re-ran it every render — and since it calls\n // `setData`, every render caused another render. Measured before this fix:\n // `useQuery('todo_task', { where: { status: 'open' } })` issued 4691 `find`\n // calls in 250ms; the same call with a hoisted options object issued 1.\n const queryKey = stableKey({\n query,\n where: resolvedWhere,\n fields: resolvedFields,\n orderBy: resolvedSort,\n limit: resolvedLimit,\n offset: resolvedOffset,\n });\n\n // Handlers say what to do with a result; they are not part of what is being\n // fetched, so they must not drive refetching.\n const handleSuccess = useEventCallback(onSuccess);\n const handleError = useEventCallback(onError);\n\n const fetchData = useCallback(async (isRefetch = false) => {\n if (!enabled) return;\n \n try {\n if (isRefetch) {\n setIsRefetching(true);\n } else {\n setIsLoading(true);\n }\n setError(null);\n\n let result: PaginatedResult<T>;\n \n if (query) {\n // Use advanced query API\n result = await client.data.query<T>(object, query);\n } else {\n // Use canonical QueryOptionsV2 for the find call\n result = await client.data.find<T>(object, {\n where: resolvedWhere as any,\n fields: resolvedFields,\n orderBy: resolvedSort,\n limit: resolvedLimit,\n offset: resolvedOffset,\n });\n }\n\n setData(result);\n handleSuccess(result);\n } catch (err) {\n const error = err instanceof Error ? err : new Error('Query failed');\n setError(error);\n handleError(error);\n } finally {\n setIsLoading(false);\n setIsRefetching(false);\n }\n }, [client, object, queryKey, enabled, handleSuccess, handleError]);\n\n // Initial fetch and dependency-based refetch\n useEffect(() => {\n fetchData();\n }, [fetchData]);\n\n // Setup refetch interval\n useEffect(() => {\n if (refetchInterval && enabled) {\n intervalRef.current = setInterval(() => {\n fetchData(true);\n }, refetchInterval);\n\n return () => {\n if (intervalRef.current) {\n clearInterval(intervalRef.current);\n }\n };\n }\n return undefined;\n }, [refetchInterval, enabled, fetchData]);\n\n const refetch = useCallback(async () => {\n await fetchData(true);\n }, [fetchData]);\n\n return {\n data,\n isLoading,\n error,\n refetch,\n isRefetching\n };\n}\n\n/**\n * Mutation options for useMutation hook\n */\nexport interface UseMutationOptions<TData = any, TVariables = any> {\n /** Callback on successful mutation */\n onSuccess?: (data: TData, variables: TVariables) => void;\n /** Callback on error */\n onError?: (error: Error, variables: TVariables) => void;\n /** Callback when mutation is settled (success or error) */\n onSettled?: (data: TData | undefined, error: Error | null, variables: TVariables) => void;\n}\n\n/**\n * Mutation result for useMutation hook\n */\nexport interface UseMutationResult<TData = any, TVariables = any> {\n /** Execute the mutation */\n mutate: (variables: TVariables) => Promise<TData>;\n /** Async version of mutate that throws errors */\n mutateAsync: (variables: TVariables) => Promise<TData>;\n /** Mutation result data */\n data: TData | null;\n /** Loading state */\n isLoading: boolean;\n /** Error state */\n error: Error | null;\n /** Reset mutation state */\n reset: () => void;\n}\n\n/**\n * Hook for creating, updating, or deleting ObjectStack data\n * \n * @example\n * ```tsx\n * function CreateTaskForm() {\n * const { mutate, isLoading, error } = useMutation('todo_task', 'create', {\n * onSuccess: (data) => {\n * console.log('Task created:', data);\n * }\n * });\n * \n * const handleSubmit = (formData) => {\n * mutate(formData);\n * };\n * \n * return <form onSubmit={handleSubmit}>...</form>;\n * }\n * ```\n */\nexport function useMutation<TData = any, TVariables = any>(\n object: string,\n operation: 'create' | 'update' | 'delete' | 'createMany' | 'updateMany' | 'deleteMany',\n options: UseMutationOptions<TData, TVariables> = {}\n): UseMutationResult<TData, TVariables> {\n const client = useClient();\n const [data, setData] = useState<TData | null>(null);\n const [isLoading, setIsLoading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n\n const { onSuccess, onError, onSettled } = options;\n\n const mutateAsync = useCallback(async (variables: TVariables): Promise<TData> => {\n setIsLoading(true);\n setError(null);\n\n try {\n let result: TData;\n\n switch (operation) {\n case 'create':\n result = (await client.data.create(object, variables as any)) as TData;\n break;\n case 'update':\n // Expect variables to be { id: string, data: Partial<T> }\n const updateVars = variables as any;\n result = (await client.data.update(object, updateVars.id, updateVars.data)) as TData;\n break;\n case 'delete':\n // Expect variables to be { id: string }\n const deleteVars = variables as any;\n result = await client.data.delete(object, deleteVars.id) as any;\n break;\n case 'createMany':\n // createMany returns an array, which may not match TData type\n result = await client.data.createMany(object, variables as any) as any;\n break;\n case 'updateMany':\n // Expect variables to be { records: Array<{ id: string, data: Partial<T> }> }\n const updateManyVars = variables as any;\n result = await client.data.updateMany(object, updateManyVars.records, updateManyVars.options) as any;\n break;\n case 'deleteMany':\n // Expect variables to be { ids: string[] }\n const deleteManyVars = variables as any;\n result = await client.data.deleteMany(object, deleteManyVars.ids, deleteManyVars.options) as any;\n break;\n default:\n throw new Error(`Unknown operation: ${operation}`);\n }\n\n setData(result);\n onSuccess?.(result, variables);\n onSettled?.(result, null, variables);\n \n return result;\n } catch (err) {\n const error = err instanceof Error ? err : new Error('Mutation failed');\n setError(error);\n onError?.(error, variables);\n onSettled?.(undefined, error, variables);\n throw error;\n } finally {\n setIsLoading(false);\n }\n }, [client, object, operation, onSuccess, onError, onSettled]);\n\n const mutate = useCallback((variables: TVariables): Promise<TData> => {\n return mutateAsync(variables).catch(() => {\n // Swallow error for non-async version\n // Error is still available in the error state\n return null as any;\n });\n }, [mutateAsync]);\n\n const reset = useCallback(() => {\n setData(null);\n setError(null);\n setIsLoading(false);\n }, []);\n\n return {\n mutate,\n mutateAsync,\n data,\n isLoading,\n error,\n reset\n };\n}\n\n/**\n * Pagination options for usePagination hook\n */\nexport interface UsePaginationOptions<T = any> extends Omit<UseQueryOptions<T>, 'limit' | 'offset'> {\n /** Page size */\n pageSize?: number;\n /** Initial page (1-based) */\n initialPage?: number;\n}\n\n/**\n * Pagination result for usePagination hook\n */\nexport interface UsePaginationResult<T = any> extends UseQueryResult<T> {\n /** Current page (1-based) */\n page: number;\n /** Total number of pages */\n totalPages: number;\n /** Total number of records */\n totalCount: number;\n /** Go to next page */\n nextPage: () => void;\n /** Go to previous page */\n previousPage: () => void;\n /** Go to specific page */\n goToPage: (page: number) => void;\n /** Whether there is a next page */\n hasNextPage: boolean;\n /** Whether there is a previous page */\n hasPreviousPage: boolean;\n}\n\n/**\n * Hook for paginated data queries\n * \n * @example\n * ```tsx\n * function PaginatedTaskList() {\n * const {\n * data,\n * isLoading,\n * page,\n * totalPages,\n * nextPage,\n * previousPage,\n * hasNextPage,\n * hasPreviousPage\n * } = usePagination('todo_task', {\n * pageSize: 10,\n * orderBy: ['-created_at']\n * });\n * \n * return (\n * <div>\n * {data?.value.map(task => <div key={task.id}>{task.subject}</div>)}\n * <button onClick={previousPage} disabled={!hasPreviousPage}>Previous</button>\n * <span>Page {page} of {totalPages}</span>\n * <button onClick={nextPage} disabled={!hasNextPage}>Next</button>\n * </div>\n * );\n * }\n * ```\n */\nexport function usePagination<T = any>(\n object: string,\n options: UsePaginationOptions<T> = {}\n): UsePaginationResult<T> {\n const { pageSize = 20, initialPage = 1, ...queryOptions } = options;\n const [page, setPage] = useState(initialPage);\n\n const queryResult = useQuery<T>(object, {\n ...queryOptions,\n limit: pageSize,\n offset: (page - 1) * pageSize\n });\n\n const totalCount = queryResult.data?.total || 0;\n const totalPages = Math.ceil(totalCount / pageSize);\n const hasNextPage = page < totalPages;\n const hasPreviousPage = page > 1;\n\n const nextPage = useCallback(() => {\n if (hasNextPage) {\n setPage(p => p + 1);\n }\n }, [hasNextPage]);\n\n const previousPage = useCallback(() => {\n if (hasPreviousPage) {\n setPage(p => p - 1);\n }\n }, [hasPreviousPage]);\n\n const goToPage = useCallback((newPage: number) => {\n const clampedPage = Math.max(1, Math.min(newPage, totalPages));\n setPage(clampedPage);\n }, [totalPages]);\n\n return {\n ...queryResult,\n page,\n totalPages,\n totalCount,\n nextPage,\n previousPage,\n goToPage,\n hasNextPage,\n hasPreviousPage\n };\n}\n\n/**\n * Infinite query options for useInfiniteQuery hook\n */\nexport interface UseInfiniteQueryOptions<T = any> extends Omit<UseQueryOptions<T>, 'offset'> {\n /** Page size for each fetch */\n pageSize?: number;\n /** Get next page parameter */\n getNextPageParam?: (lastPage: PaginatedResult<T>, allPages: PaginatedResult<T>[]) => number | undefined;\n}\n\n/**\n * Infinite query result for useInfiniteQuery hook\n */\nexport interface UseInfiniteQueryResult<T = any> {\n /** All pages of data */\n data: PaginatedResult<T>[];\n /** Flattened data from all pages */\n flatData: T[];\n /** Loading state */\n isLoading: boolean;\n /** Error state */\n error: Error | null;\n /** Load the next page */\n fetchNextPage: () => Promise<void>;\n /** Whether there are more pages */\n hasNextPage: boolean;\n /** Is currently fetching next page */\n isFetchingNextPage: boolean;\n /** Refetch all pages */\n refetch: () => Promise<void>;\n}\n\n/**\n * Hook for infinite scrolling / load more functionality\n * \n * @example\n * ```tsx\n * function InfiniteTaskList() {\n * const {\n * flatData,\n * isLoading,\n * fetchNextPage,\n * hasNextPage,\n * isFetchingNextPage\n * } = useInfiniteQuery('todo_task', {\n * pageSize: 20,\n * orderBy: ['-created_at']\n * });\n * \n * return (\n * <div>\n * {flatData.map(task => <div key={task.id}>{task.subject}</div>)}\n * {hasNextPage && (\n * <button onClick={fetchNextPage} disabled={isFetchingNextPage}>\n * {isFetchingNextPage ? 'Loading...' : 'Load More'}\n * </button>\n * )}\n * </div>\n * );\n * }\n * ```\n */\nexport function useInfiniteQuery<T = any>(\n object: string,\n options: UseInfiniteQueryOptions<T> = {}\n): UseInfiniteQueryResult<T> {\n const client = useClient();\n const {\n pageSize = 20,\n // getNextPageParam is reserved for future use\n query,\n // Canonical names take precedence over legacy names\n where, fields, orderBy,\n enabled = true,\n onSuccess,\n onError\n } = options;\n\n const resolvedFields = fields;\n const resolvedWhere = where;\n const resolvedSort = orderBy;\n\n // Same value-keyed dependency as useQuery (#4693) — measured at 6611 `find`\n // calls in 250ms before this fix, with inline options.\n const queryKey = stableKey({\n query,\n where: resolvedWhere,\n fields: resolvedFields,\n orderBy: resolvedSort,\n pageSize,\n });\n const handleSuccess = useEventCallback(onSuccess);\n const handleError = useEventCallback(onError);\n\n const [pages, setPages] = useState<PaginatedResult<T>[]>([]);\n const [isLoading, setIsLoading] = useState(true);\n const [isFetchingNextPage, setIsFetchingNextPage] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n const [hasNextPage, setHasNextPage] = useState(true);\n\n const fetchPage = useCallback(async (skip: number, isNextPage = false) => {\n try {\n if (isNextPage) {\n setIsFetchingNextPage(true);\n } else {\n setIsLoading(true);\n }\n setError(null);\n\n let result: PaginatedResult<T>;\n\n if (query) {\n result = await client.data.query<T>(object, {\n ...query,\n limit: pageSize,\n offset: skip\n });\n } else {\n result = await client.data.find<T>(object, {\n where: resolvedWhere as any,\n fields: resolvedFields,\n orderBy: resolvedSort,\n limit: pageSize,\n offset: skip,\n });\n }\n\n if (isNextPage) {\n setPages(prev => [...prev, result]);\n } else {\n setPages([result]);\n }\n\n // Determine if there's a next page\n const fetchedCount = result.records?.length ?? 0;\n const hasMore = fetchedCount === pageSize;\n setHasNextPage(hasMore);\n\n handleSuccess(result);\n } catch (err) {\n const error = err instanceof Error ? err : new Error('Query failed');\n setError(error);\n handleError(error);\n } finally {\n setIsLoading(false);\n setIsFetchingNextPage(false);\n }\n }, [client, object, queryKey, handleSuccess, handleError]);\n\n // Initial fetch\n useEffect(() => {\n if (enabled) {\n fetchPage(0);\n }\n }, [enabled, fetchPage]);\n\n const fetchNextPage = useCallback(async () => {\n if (!hasNextPage || isFetchingNextPage) return;\n\n const nextSkip = pages.length * pageSize;\n await fetchPage(nextSkip, true);\n }, [hasNextPage, isFetchingNextPage, pages.length, pageSize, fetchPage]);\n\n const refetch = useCallback(async () => {\n setPages([]);\n await fetchPage(0);\n }, [fetchPage]);\n\n const flatData = pages.flatMap(page => page.records ?? []);\n\n return {\n data: pages,\n flatData,\n isLoading,\n error,\n fetchNextPage,\n hasNextPage,\n isFetchingNextPage,\n refetch\n };\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * Dependency-array primitives (#4693, #4694) — internal, not exported from the\n * package entry point.\n *\n * Every fetch and subscription hook here keys a `useCallback`/`useEffect` on\n * values the caller supplies inline: `where` / `fields` / `orderBy` objects,\n * `onSuccess` / `onError` handlers, the `fetcher` `useMetadata` takes as a\n * required argument. Inline means a fresh identity on every render, so the\n * effect re-ran on every render — and for the fetch hooks that effect calls\n * `setState`, which renders again. Five hooks were in an unbounded request\n * loop under their own documented usage.\n *\n * The two helpers below fix the two halves of that:\n *\n * - {@link stableKey} turns a structural value into a dependency that changes\n * when the *value* changes rather than when the object is rebuilt;\n * - {@link useEventCallback} gives a caller's handler a fixed identity, so\n * passing it inline no longer re-runs anything.\n *\n * Neither is a substitute for the caller memoizing — they remove the need to.\n * Correctness must not rest on every call site remembering `useMemo`, least of\n * all when the TSDoc examples themselves pass object literals.\n */\n\nimport { useCallback, useEffect, useRef } from 'react';\n\n/**\n * Order-independent stringify, used to derive a dependency from a structural\n * value. Object keys are sorted so `{ a, b }` and `{ b, a }` agree; array order\n * is preserved because it is semantic (`orderBy: ['-created_at', 'name']`).\n *\n * Mirrors the same helper in `service-settings` and `service-automation` — kept\n * local for the same reason they are: it is three lines and a shared util\n * package would be a heavier dependency than the code it carries.\n *\n * Values JSON cannot represent (functions, symbols) collapse to `undefined`\n * here. That is correct for this use: a handler's identity must not drive a\n * refetch, which is exactly what {@link useEventCallback} is for.\n */\nexport function stableKey(input: unknown): string {\n if (input === null || typeof input !== 'object') return JSON.stringify(input) ?? 'undefined';\n if (Array.isArray(input)) return '[' + input.map(stableKey).join(',') + ']';\n const obj = input as Record<string, unknown>;\n const keys = Object.keys(obj).sort();\n return '{' + keys.map((k) => JSON.stringify(k) + ':' + stableKey(obj[k])).join(',') + '}';\n}\n\n/**\n * Wraps a caller-supplied handler in a function whose identity never changes,\n * while always invoking the most recent version.\n *\n * This is what lets the fetch and subscription effects drop `onSuccess` /\n * `onError` / `callback` from their dependency arrays. Those handlers say what\n * to do when something happens; they are not part of *what is subscribed to* or\n * *what is fetched*, so they have no business re-running an effect.\n *\n * The ref is updated in an effect rather than during render: a render may be\n * thrown away under concurrent rendering, and writing through a ref then would\n * publish a handler from a render that never committed.\n *\n * Returns `undefined` from the call when no handler was supplied, so optional\n * handlers need no call-site guard.\n */\nexport function useEventCallback<A extends unknown[], R>(\n fn: ((...args: A) => R) | undefined\n): (...args: A) => R | undefined {\n const ref = useRef(fn);\n\n useEffect(() => {\n ref.current = fn;\n }, [fn]);\n\n return useCallback((...args: A) => ref.current?.(...args), []);\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * Metadata Hooks\n * \n * React hooks for accessing ObjectStack metadata (schemas, views, fields)\n */\n\nimport { useState, useEffect, useCallback, useRef } from 'react';\nimport { useClient, useObjectStackLocale } from './context';\nimport { useEventCallback } from './internal-deps';\n\n/**\n * Metadata query options\n */\nexport interface UseMetadataOptions {\n /** Enable/disable automatic query execution */\n enabled?: boolean;\n /** Use cached metadata if available */\n useCache?: boolean;\n /** ETag for conditional requests */\n ifNoneMatch?: string;\n /** If-Modified-Since header for conditional requests */\n ifModifiedSince?: string;\n /** Callback on successful query */\n onSuccess?: (data: any) => void;\n /** Callback on error */\n onError?: (error: Error) => void;\n}\n\n/**\n * Metadata query result\n */\nexport interface UseMetadataResult<T = any> {\n /** Metadata data */\n data: T | null;\n /** Loading state */\n isLoading: boolean;\n /** Error state */\n error: Error | null;\n /** Refetch the metadata */\n refetch: () => Promise<void>;\n /** ETag from last fetch */\n etag?: string;\n /** Whether data came from cache (304 Not Modified) */\n fromCache: boolean;\n}\n\n/**\n * Hook for fetching object schema/metadata.\n *\n * `data` is the `GET /meta/:type/:name` response envelope\n * (`GetMetaItemResponseSchema`): `{ type, name, item, … }`, with the object\n * schema document under `item`. It is NOT the bare schema.\n *\n * [#5563] It used to be either one, decided by the server's `enableCache`\n * setting: the cached read path (the default) answered the bare document while\n * the uncached path answered the envelope, and this hook fed both into the same\n * state. The route answers one shape now, so the hook can too — and it is the\n * declared one, which keeps the hook isomorphic to the endpoint instead of\n * inventing a second dialect at the SDK boundary. Reading a document field\n * straight off `data` (`data.fields`) was the old spelling; it is `data.item.fields`\n * now. See {@link useFields} for the pre-flattened field list.\n *\n * @example\n * ```tsx\n * function ObjectSchemaViewer({ objectName }: { objectName: string }) {\n * const { data, isLoading, error } = useObject(objectName);\n *\n * if (isLoading) return <div>Loading schema...</div>;\n * if (error) return <div>Error: {error.message}</div>;\n *\n * const schema = data.item;\n * return (\n * <div>\n * <h2>{schema.label}</h2>\n * <p>Fields: {Object.keys(schema.fields).length}</p>\n * </div>\n * );\n * }\n * ```\n */\nexport function useObject(\n objectName: string,\n options: UseMetadataOptions = {}\n): UseMetadataResult {\n const client = useClient();\n // Active UI locale: object/field labels are translated server-side, so a\n // language switch must re-fetch (it is *not* reactive via i18next). Folding\n // `locale` into the fetch deps below triggers that re-fetch (issue #1319).\n const locale = useObjectStackLocale();\n const [data, setData] = useState<any>(null);\n const [isLoading, setIsLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n const [etag, setEtag] = useState<string>();\n const [fromCache, setFromCache] = useState(false);\n\n const {\n enabled = true,\n useCache = true,\n ifNoneMatch,\n ifModifiedSince,\n onSuccess,\n onError\n } = options;\n\n // `data` and `etag` are this hook's OWN state, and the fetch writes both.\n // Depending on them made the fetch its own trigger: `setData` → new `data`\n // identity → new `fetchMetadata` → the effect below re-ran → fetch again.\n // Unlike the data hooks this needed no particular usage to fire — measured at\n // 4306 metadata requests in 250ms for a bare `useObject('todo_task')`\n // (#4693). They are read, never depended on, so they belong in refs.\n const dataRef = useRef(data);\n const etagRef = useRef(etag);\n useEffect(() => {\n dataRef.current = data;\n etagRef.current = etag;\n }, [data, etag]);\n\n const handleSuccess = useEventCallback(onSuccess);\n const handleError = useEventCallback(onError);\n\n const fetchMetadata = useCallback(async () => {\n if (!enabled) return;\n\n try {\n setIsLoading(true);\n setError(null);\n setFromCache(false);\n\n if (useCache) {\n // Both branches address the SAME route (`meta.getCached` is\n // `GET {metadata}/object/:name` with conditional-request headers), so\n // both now put the same `{ type, name, item, … }` envelope into `data`\n // — `result.data` here, the unwrapped response there. [#5563] Before the\n // convergence these two lines disagreed with each other, and which one a\n // deployment hit was decided by its `enableCache` setting.\n const result = await client.meta.getCached(objectName, {\n ifNoneMatch: ifNoneMatch || etagRef.current,\n ifModifiedSince\n });\n\n if (result.notModified) {\n setFromCache(true);\n } else {\n setData(result.data);\n if (result.etag) {\n setEtag(result.etag.value);\n }\n }\n\n handleSuccess(result.data || dataRef.current);\n } else {\n // Direct fetch without cache\n const result = await client.meta.getItem('object', objectName);\n setData(result);\n handleSuccess(result);\n }\n } catch (err) {\n const error = err instanceof Error ? err : new Error('Failed to fetch object metadata');\n setError(error);\n handleError(error);\n } finally {\n setIsLoading(false);\n }\n }, [client, objectName, locale, enabled, useCache, ifNoneMatch, ifModifiedSince, handleSuccess, handleError]);\n\n useEffect(() => {\n fetchMetadata();\n }, [fetchMetadata]);\n\n const refetch = useCallback(async () => {\n await fetchMetadata();\n }, [fetchMetadata]);\n\n return {\n data,\n isLoading,\n error,\n refetch,\n etag,\n fromCache\n };\n}\n\n/**\n * Hook for fetching view configuration\n * \n * @example\n * ```tsx\n * function ViewConfiguration({ objectName }: { objectName: string }) {\n * const { data: view, isLoading } = useView(objectName, 'list');\n * \n * if (isLoading) return <div>Loading view...</div>;\n * \n * return (\n * <div>\n * <h3>List View for {objectName}</h3>\n * <p>Columns: {view?.columns?.length}</p>\n * </div>\n * );\n * }\n * ```\n */\nexport function useView(\n objectName: string,\n viewType: 'list' | 'form' = 'list',\n options: UseMetadataOptions = {}\n): UseMetadataResult {\n const client = useClient();\n // View headers/labels are translated server-side — re-fetch on locale change.\n const locale = useObjectStackLocale();\n const [data, setData] = useState<any>(null);\n const [isLoading, setIsLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n\n const { enabled = true, onSuccess, onError } = options;\n\n const handleSuccess = useEventCallback(onSuccess);\n const handleError = useEventCallback(onError);\n\n const fetchView = useCallback(async () => {\n if (!enabled) return;\n\n try {\n setIsLoading(true);\n setError(null);\n\n const result = await client.meta.getView(objectName, viewType);\n setData(result);\n handleSuccess(result);\n } catch (err) {\n const error = err instanceof Error ? err : new Error('Failed to fetch view configuration');\n setError(error);\n handleError(error);\n } finally {\n setIsLoading(false);\n }\n }, [client, objectName, viewType, locale, enabled, handleSuccess, handleError]);\n\n useEffect(() => {\n fetchView();\n }, [fetchView]);\n\n const refetch = useCallback(async () => {\n await fetchView();\n }, [fetchView]);\n\n return {\n data,\n isLoading,\n error,\n refetch,\n fromCache: false\n };\n}\n\n/**\n * Hook for extracting fields from object schema\n * \n * @example\n * ```tsx\n * function FieldList({ objectName }: { objectName: string }) {\n * const { data: fields, isLoading } = useFields(objectName);\n * \n * if (isLoading) return <div>Loading fields...</div>;\n * \n * return (\n * <ul>\n * {fields?.map(field => (\n * <li key={field.name}>{field.label} ({field.type})</li>\n * ))}\n * </ul>\n * );\n * }\n * ```\n */\nexport function useFields(\n objectName: string,\n options: UseMetadataOptions = {}\n): UseMetadataResult<any[]> {\n const objectResult = useObject(objectName, options);\n\n // [#5563] `useObject().data` is the `{ type, name, item }` envelope; the\n // schema document — and therefore `fields` — is under `item`.\n const schema = objectResult.data?.item;\n const fields = schema?.fields\n ? Object.entries(schema.fields).map(([name, field]: [string, any]) => ({\n name,\n ...field\n }))\n : null;\n\n return {\n ...objectResult,\n data: fields\n };\n}\n\n/**\n * Generic metadata hook for custom metadata queries\n * \n * @example\n * ```tsx\n * function CustomMetadata() {\n * const { data, isLoading } = useMetadata(async (client) => {\n * // Custom metadata fetching logic\n * const object = await client.meta.getObject('custom_object');\n * const view = await client.meta.getView('custom_object', 'list');\n * return { object, view };\n * });\n * \n * return <pre>{JSON.stringify(data, null, 2)}</pre>;\n * }\n * ```\n */\nexport function useMetadata<T = any>(\n fetcher: (client: ReturnType<typeof useClient>) => Promise<T>,\n options: Omit<UseMetadataOptions, 'useCache' | 'ifNoneMatch' | 'ifModifiedSince'> = {}\n): UseMetadataResult<T> {\n const client = useClient();\n // Custom fetchers commonly read server-translated metadata too — refetch on\n // locale change so their labels follow the active language.\n const locale = useObjectStackLocale();\n const [data, setData] = useState<T | null>(null);\n const [isLoading, setIsLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n\n const { enabled = true, onSuccess, onError } = options;\n\n // `fetcher` is a REQUIRED positional argument, so an inline arrow is the only\n // natural way to call this hook — which made the loop unconditional in\n // practice (7654 fetcher invocations in 250ms before this fix, #4693).\n // Stabilizing it here means the fetch re-runs on `client` / `locale` /\n // `enabled` changes, as intended, and not on the caller's render cadence.\n const runFetcher = useEventCallback(fetcher);\n const handleSuccess = useEventCallback(onSuccess);\n const handleError = useEventCallback(onError);\n\n const fetchMetadata = useCallback(async () => {\n if (!enabled) return;\n\n try {\n setIsLoading(true);\n setError(null);\n\n const result = await runFetcher(client);\n setData(result as T);\n handleSuccess(result as T);\n } catch (err) {\n const error = err instanceof Error ? err : new Error('Failed to fetch metadata');\n setError(error);\n handleError(error);\n } finally {\n setIsLoading(false);\n }\n }, [client, runFetcher, locale, enabled, handleSuccess, handleError]);\n\n useEffect(() => {\n fetchMetadata();\n }, [fetchMetadata]);\n\n const refetch = useCallback(async () => {\n await fetchMetadata();\n }, [fetchMetadata]);\n\n return {\n data,\n isLoading,\n error,\n refetch,\n fromCache: false\n };\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * Real-time Event Subscription Hooks\n *\n * Provides React hooks for subscribing to metadata and data events.\n * Events are automatically cleaned up when components unmount.\n */\n\nimport { useEffect, useState } from 'react';\nimport type {\n MetadataEvent,\n MetadataEventSubject,\n DataEvent,\n BulkDataEvent,\n} from '@objectstack/spec/api';\nimport { useClient } from './context';\nimport { useEventCallback } from './internal-deps';\n\n/**\n * Hook to subscribe to metadata events\n *\n * @param type - Metadata type to subscribe to (e.g., 'object', 'view', 'agent').\n * Typed {@link MetadataEventSubject}, the closed set derived from\n * `MetadataEventType` (#4627) — a metadata type with no realtime event\n * contract (`'translation'`, `'datasource'`, …) is a compile error here\n * rather than a subscription that never fires. This hook only forwards the\n * argument to `subscribeMetadata`, so it must not be the looser of the two.\n * @param options - Optional filters (packageId)\n * @returns Latest metadata event or null\n *\n * @example\n * ```tsx\n * function ObjectList() {\n * const event = useMetadataSubscription('object');\n *\n * useEffect(() => {\n * if (event?.type === 'metadata.object.created') {\n * console.log('New object:', event.name);\n * // Refresh list\n * }\n * }, [event]);\n *\n * return <div>...</div>;\n * }\n * ```\n */\nexport function useMetadataSubscription(\n type: MetadataEventSubject,\n options?: { packageId?: string }\n): MetadataEvent | null {\n const client = useClient();\n const [event, setEvent] = useState<MetadataEvent | null>(null);\n\n useEffect(() => {\n if (!client) return;\n\n const unsubscribe = client.events.subscribeMetadata(\n type,\n (e) => setEvent(e),\n options\n );\n\n return () => {\n unsubscribe();\n };\n }, [client, type, options?.packageId]);\n\n return event;\n}\n\n/**\n * Hook to subscribe to data record events\n *\n * @param object - Object name to subscribe to\n * @param options - Optional filters (recordId for specific record)\n * @returns Latest data event or null\n *\n * @example\n * ```tsx\n * function TaskDetail({ taskId }: { taskId: string }) {\n * const event = useDataSubscription('project_task', { recordId: taskId });\n *\n * useEffect(() => {\n * if (event?.type === 'data.record.updated') {\n * console.log('Task updated:', event.changes);\n * // Refresh task data\n * }\n * }, [event]);\n *\n * return <div>...</div>;\n * }\n * ```\n */\nexport function useDataSubscription(\n object: string,\n options?: { recordId?: string }\n): DataEvent | null {\n const client = useClient();\n const [event, setEvent] = useState<DataEvent | null>(null);\n\n useEffect(() => {\n if (!client) return;\n\n const unsubscribe = client.events.subscribeData(\n object,\n (e) => setEvent(e),\n options\n );\n\n return () => {\n unsubscribe();\n };\n }, [client, object, options?.recordId]);\n\n return event;\n}\n\n/**\n * Hook to subscribe to metadata events with a callback\n *\n * This variant doesn't store events in state, it just triggers a callback.\n * Useful for triggering refetches or side effects without re-renders.\n *\n * @param type - Metadata type to subscribe to. Same {@link MetadataEventSubject}\n * narrowing as {@link useMetadataSubscription} (#4627).\n * @param callback - Callback to invoke on events\n * @param options - Optional filters\n *\n * @example\n * ```tsx\n * function ObjectList() {\n * const { refetch } = useQuery(...);\n *\n * useMetadataSubscriptionCallback('object', () => {\n * refetch(); // Refetch list when objects change\n * });\n *\n * return <div>...</div>;\n * }\n * ```\n */\nexport function useMetadataSubscriptionCallback(\n type: MetadataEventSubject,\n callback: (event: MetadataEvent) => void,\n options?: { packageId?: string }\n): void {\n const client = useClient();\n // The callback is what RUNS on an event, not part of what is subscribed to\n // (#4694). Depending on its identity tore down and reopened the subscription\n // on every render whenever the caller passed an inline function — which the\n // examples above do — losing any event that arrived in the gap.\n const handleEvent = useEventCallback(callback);\n\n useEffect(() => {\n if (!client) return;\n\n const unsubscribe = client.events.subscribeMetadata(\n type,\n handleEvent,\n options\n );\n\n return () => {\n unsubscribe();\n };\n }, [client, type, handleEvent, options?.packageId]);\n}\n\n/**\n * Hook to subscribe to data events with a callback\n *\n * @param object - Object name to subscribe to\n * @param callback - Callback to invoke on events\n * @param options - Optional filters\n *\n * @example\n * ```tsx\n * function TaskList() {\n * const { refetch } = useQuery(...);\n *\n * useDataSubscriptionCallback('project_task', () => {\n * refetch(); // Refetch list when tasks change\n * });\n *\n * return <div>...</div>;\n * }\n * ```\n */\nexport function useDataSubscriptionCallback(\n object: string,\n callback: (event: DataEvent) => void,\n options?: { recordId?: string }\n): void {\n const client = useClient();\n // Stable identity so an inline callback does not churn the subscription on\n // every render (#4694) — see useMetadataSubscriptionCallback.\n const handleEvent = useEventCallback(callback);\n\n useEffect(() => {\n if (!client) return;\n\n const unsubscribe = client.events.subscribeData(\n object,\n handleEvent,\n options\n );\n\n return () => {\n unsubscribe();\n };\n }, [client, object, handleEvent, options?.recordId]);\n}\n\n/**\n * Hook to subscribe to bulk (predicate-write) data events\n *\n * A `multi: true` update/delete reaches the driver's `updateMany`/`deleteMany`,\n * which report an affected COUNT and name no rows — so it publishes\n * `data.records.updated` / `data.records.deleted` rather than the per-record\n * events {@link useDataSubscription} delivers (#4639).\n *\n * The event carries `object` and `matched` — there is no `recordId` and no\n * record body, which is why this is a separate hook rather than more types\n * flowing through `useDataSubscription`: a `DataEvent` callback receiving one\n * of these would read `undefined` for every field it expects.\n *\n * Use it to invalidate a list, show \"40 records changed\", or trigger a\n * refetch — not to patch a per-record cache, which a count cannot drive.\n *\n * @param object - Object name to subscribe to\n * @returns Latest bulk data event or null\n *\n * @example\n * ```tsx\n * function TaskList() {\n * const bulk = useBulkDataSubscription('project_task');\n *\n * useEffect(() => {\n * if (bulk) {\n * console.log(`${bulk.matched} tasks changed in one write`);\n * }\n * }, [bulk]);\n *\n * return <div>...</div>;\n * }\n * ```\n */\nexport function useBulkDataSubscription(object: string): BulkDataEvent | null {\n const client = useClient();\n const [event, setEvent] = useState<BulkDataEvent | null>(null);\n\n useEffect(() => {\n if (!client) return;\n\n const unsubscribe = client.events.subscribeBulkData(object, (e) => setEvent(e));\n\n return () => {\n unsubscribe();\n };\n }, [client, object]);\n\n return event;\n}\n\n/**\n * Hook to subscribe to bulk data events with a callback\n *\n * The callback variant of {@link useBulkDataSubscription} — no state, no\n * re-render, for triggering refetches and side effects.\n *\n * @param object - Object name to subscribe to\n * @param callback - Callback to invoke on events\n *\n * @example\n * ```tsx\n * function TaskList() {\n * const { refetch } = useQuery(...);\n *\n * useBulkDataSubscriptionCallback('project_task', () => {\n * refetch(); // a predicate write touched an unknown set of rows\n * });\n *\n * return <div>...</div>;\n * }\n * ```\n */\nexport function useBulkDataSubscriptionCallback(\n object: string,\n callback: (event: BulkDataEvent) => void\n): void {\n const client = useClient();\n // Stable identity so an inline callback does not churn the subscription on\n // every render (#4694) — see useMetadataSubscriptionCallback.\n const handleEvent = useEventCallback(callback);\n\n useEffect(() => {\n if (!client) return;\n\n const unsubscribe = client.events.subscribeBulkData(object, handleEvent);\n\n return () => {\n unsubscribe();\n };\n }, [client, object, handleEvent]);\n}\n\n/**\n * Hook to get connection status of realtime events\n *\n * @returns Whether realtime is connected\n *\n * @example\n * ```tsx\n * function ConnectionIndicator() {\n * const connected = useRealtimeConnection();\n *\n * return (\n * <div>\n * {connected ? '🟢 Connected' : '🔴 Disconnected'}\n * </div>\n * );\n * }\n * ```\n */\nexport function useRealtimeConnection(): boolean {\n const client = useClient();\n const [connected, setConnected] = useState(true);\n\n useEffect(() => {\n if (!client) {\n setConnected(false);\n return;\n }\n\n // For now, assume always connected with in-memory adapter\n // In production, this would listen to WebSocket connection events\n setConnected(true);\n }, [client]);\n\n return connected;\n}\n\n/**\n * Hook for auto-refreshing queries when data changes\n *\n * Combines data subscription with query refetch.\n *\n * Watches BOTH event streams (#4678): per-record `data.record.*` writes and\n * the aggregate `data.records.*` a predicate (`multi: true`) write publishes.\n * A bulk write is the case that dirties a list hardest — one statement can\n * change or delete every row on screen — so a refresh hook that ignored it\n * would sit still exactly when it matters most, while still refreshing for a\n * single-row edit.\n *\n * Mixing the two streams is safe here in a way it is not for\n * {@link useDataSubscription}: this hook's output is a refetch signal, not an\n * event body, so the shape difference that keeps the two contracts apart\n * (no `recordId`, no record) never reaches the caller.\n *\n * @param object - Object name to watch\n * @param refetch - Refetch function from useQuery\n * @param options - Optional filters\n *\n * @example\n * ```tsx\n * function TaskList() {\n * const { data, refetch } = useQuery('project_task', {});\n *\n * useAutoRefresh('project_task', refetch);\n *\n * return <div>{data.map(...)}</div>;\n * }\n * ```\n */\nexport function useAutoRefresh(\n object: string,\n refetch: () => void,\n options?: { recordId?: string }\n): void {\n // No `useCallback` needed: both subscription hooks stabilize the handler\n // themselves (#4694), so a caller passing an unmemoized `refetch` — which\n // `useQuery` returned on every render before #4693 — no longer resubscribes.\n useDataSubscriptionCallback(object, (_event: DataEvent) => refetch(), options);\n\n // A bulk event carries only a count, so when `options.recordId` narrows this\n // hook to one record there is no way to tell whether that record was in the\n // match set. Refetch anyway: a redundant query is cheap, and the alternative\n // is showing a record that a predicate write already changed.\n useBulkDataSubscriptionCallback(object, (_event: BulkDataEvent) => refetch());\n}\n"],"mappings":"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","names":["import_react","import_react","error","import_react","error","import_react"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.tsx","../src/context.tsx","../src/data-hooks.tsx","../src/internal-deps.ts","../src/metadata-hooks.tsx","../src/realtime-hooks.tsx"],"sourcesContent":["// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * @objectstack/client-react\n * \n * React hooks for ObjectStack Client SDK\n * \n * Provides type-safe React hooks for:\n * - Data queries (useQuery, useMutation, usePagination, useInfiniteQuery)\n * - Metadata access (useObject, useView, useFields, useMetadata)\n * - Client context (ObjectStackProvider, useClient)\n */\n\n// Context & Provider\nexport {\n ObjectStackProvider,\n ObjectStackContext,\n ObjectStackLocaleContext,\n useClient,\n useObjectStackLocale,\n type ObjectStackProviderProps\n} from './context';\n\n// Data Hooks\nexport {\n useQuery,\n useMutation,\n usePagination,\n useInfiniteQuery,\n type UseQueryOptions,\n type UseQueryResult,\n type UseMutationOptions,\n type UseMutationResult,\n type UsePaginationOptions,\n type UsePaginationResult,\n type UseInfiniteQueryOptions,\n type UseInfiniteQueryResult\n} from './data-hooks';\n\n// Metadata Hooks\nexport {\n useObject,\n useView,\n useFields,\n useMetadata,\n type UseMetadataOptions,\n type UseMetadataResult\n} from './metadata-hooks';\n\n// Realtime Event Hooks\nexport {\n useMetadataSubscription,\n useDataSubscription,\n useMetadataSubscriptionCallback,\n useDataSubscriptionCallback,\n useBulkDataSubscription,\n useBulkDataSubscriptionCallback,\n useRealtimeConnection,\n useAutoRefresh\n} from './realtime-hooks';\n\n// Re-export ObjectStackClient and types from @objectstack/client\nexport { ObjectStackClient, type ClientConfig } from '@objectstack/client';\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * ObjectStack React Context\n * \n * Provides ObjectStackClient instance to React components via Context API\n */\n\nimport * as React from 'react';\nimport { createContext, useContext, useRef, ReactNode } from 'react';\nimport { ObjectStackClient } from '@objectstack/client';\n\nexport interface ObjectStackProviderProps {\n client: ObjectStackClient;\n /**\n * Active UI locale (BCP-47, e.g. `'zh-CN'`). Keep this in sync with your\n * language switcher — the provider pushes it into the client (so requests\n * carry `Accept-Language`) and metadata hooks (`useObject`, `useView`,\n * `useMetadata`) re-fetch when it changes, so switching language relabels\n * the UI without a page refresh (issue #1319).\n */\n locale?: string;\n children: ReactNode;\n}\n\nexport const ObjectStackContext = createContext<ObjectStackClient | null>(null);\n\n/**\n * Carries the active UI locale separately from the client so existing\n * `useContext(ObjectStackContext)` consumers keep receiving the bare client\n * (no breaking change to that context's shape).\n */\nexport const ObjectStackLocaleContext = createContext<string | undefined>(undefined);\n\n/**\n * Provider component that makes ObjectStackClient available to all child components\n * \n * @example\n * <!-- os:check -->\n * ```tsx\n * import { ObjectStackClient } from '@objectstack/client';\n * import { ObjectStackProvider } from '@objectstack/client-react';\n *\n * const client = new ObjectStackClient({ baseUrl: 'http://localhost:3000' });\n * const language = 'en';\n *\n * function YourComponents() {\n * return <div>Your app</div>;\n * }\n *\n * function App() {\n * return (\n * <ObjectStackProvider client={client} locale={language}>\n * <YourComponents />\n * </ObjectStackProvider>\n * );\n * }\n * ```\n */\nexport function ObjectStackProvider({ client, locale, children }: ObjectStackProviderProps) {\n // Mirror the active locale onto the client so every request carries the\n // matching `Accept-Language`.\n //\n // This MUST run during render, not in a `useEffect`. The child metadata\n // hooks read `locale` from context and re-fetch via their own effects, and\n // React flushes child effects *before* parent effects — so syncing the\n // client in an effect here would update it only after the refetch already\n // fired, sending the stale `Accept-Language`. Render runs parent-before-\n // child, so updating the client here guarantees it is current before any\n // child fetches. The ref keeps the write idempotent across re-renders /\n // StrictMode double-invokes.\n const synced = useRef<{ client: ObjectStackClient; locale: string | undefined } | null>(null);\n if (synced.current?.client !== client || synced.current?.locale !== locale) {\n synced.current = { client, locale };\n client.setLocale?.(locale);\n }\n\n return (\n <ObjectStackContext.Provider value={client}>\n <ObjectStackLocaleContext.Provider value={locale}>\n {children}\n </ObjectStackLocaleContext.Provider>\n </ObjectStackContext.Provider>\n );\n}\n\n/**\n * Hook to read the active UI locale provided to {@link ObjectStackProvider}.\n * Returns `undefined` when no locale was supplied. Metadata hooks fold this\n * into their fetch dependencies so a locale change triggers a re-fetch.\n */\nexport function useObjectStackLocale(): string | undefined {\n return useContext(ObjectStackLocaleContext);\n}\n\n/**\n * Hook to access the ObjectStackClient instance from context\n * \n * @throws Error if used outside of ObjectStackProvider\n * \n * @example\n * <!-- os:check -->\n * ```tsx\n * import { useClient } from '@objectstack/client-react';\n *\n * function MyComponent() {\n * const client = useClient();\n * // Use client.data.find(), etc.\n * }\n * ```\n */\nexport function useClient(): ObjectStackClient {\n const client = useContext(ObjectStackContext);\n \n if (!client) {\n throw new Error(\n 'useClient must be used within an ObjectStackProvider. ' +\n 'Make sure your component is wrapped with <ObjectStackProvider client={...}>.'\n );\n }\n \n return client;\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * Data Query Hooks\n * \n * React hooks for querying and mutating ObjectStack data\n */\n\nimport { useState, useEffect, useCallback, useRef } from 'react';\nimport { QueryAST, FilterCondition } from '@objectstack/spec/data';\nimport { PaginatedResult } from '@objectstack/client';\nimport { useClient } from './context';\nimport { stableKey, useEventCallback } from './internal-deps';\n\n/**\n * Query options for useQuery hook.\n *\n * Uses the canonical Spec protocol field names: `where`, `fields`,\n * `orderBy`, `limit`, `offset`. (The legacy aliases `filters` / `select` /\n * `sort` / `top` / `skip` were removed in 11.0.)\n */\nexport interface UseQueryOptions<T = any> {\n /** Query AST or simplified query options */\n query?: Partial<QueryAST>;\n\n // ── Canonical (Spec protocol) field names ──────────────────────────\n /** Filter conditions (WHERE clause). */\n where?: FilterCondition;\n /** Fields to retrieve (SELECT clause). */\n fields?: string[];\n /** Sort definition (ORDER BY clause). */\n orderBy?: string | string[];\n /** Maximum number of records to return (LIMIT). */\n limit?: number;\n /** Number of records to skip (OFFSET). */\n offset?: number;\n\n\n /** Enable/disable automatic query execution */\n enabled?: boolean;\n /** Refetch interval in milliseconds */\n refetchInterval?: number;\n /** Callback on successful query */\n onSuccess?: (data: PaginatedResult<T>) => void;\n /** Callback on error */\n onError?: (error: Error) => void;\n}\n\n/**\n * Query result for useQuery hook\n */\nexport interface UseQueryResult<T = any> {\n /** Query result data */\n data: PaginatedResult<T> | null;\n /** Loading state */\n isLoading: boolean;\n /** Error state */\n error: Error | null;\n /** Refetch the query */\n refetch: () => Promise<void>;\n /** Is currently refetching */\n isRefetching: boolean;\n}\n\n/**\n * Hook for querying ObjectStack data with automatic caching and refetching\n * \n * @example\n * <!-- os:check -->\n * ```tsx\n * import { useQuery } from '@objectstack/client-react';\n *\n * function TaskList() {\n * const { data, isLoading, error, refetch } = useQuery('todo_task', {\n * fields: ['id', 'subject', 'priority'],\n * orderBy: ['-created_at'],\n * limit: 20\n * });\n *\n * if (isLoading) return <div>Loading...</div>;\n * if (error) return <div>Error: {error.message}</div>;\n *\n * return (\n * <div>\n * {data?.records.map(task => (\n * <div key={task.id}>{task.subject}</div>\n * ))}\n * </div>\n * );\n * }\n * ```\n */\nexport function useQuery<T = any>(\n object: string,\n options: UseQueryOptions<T> = {}\n): UseQueryResult<T> {\n const client = useClient();\n const [data, setData] = useState<PaginatedResult<T> | null>(null);\n const [isLoading, setIsLoading] = useState(true);\n const [isRefetching, setIsRefetching] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n const intervalRef = useRef<NodeJS.Timeout | undefined>(undefined);\n \n const {\n query,\n // Canonical names take precedence over legacy names\n where, fields, orderBy, limit, offset,\n enabled = true,\n refetchInterval,\n onSuccess,\n onError\n } = options;\n\n const resolvedFields = fields;\n const resolvedWhere = where;\n const resolvedSort = orderBy;\n const resolvedLimit = limit;\n const resolvedOffset = offset;\n\n // The query shape as a VALUE (#4693). `where` / `fields` / `orderBy` are\n // objects and arrays, and the documented usage builds them inline, so keying\n // the fetch on their identities re-ran it every render — and since it calls\n // `setData`, every render caused another render. Measured before this fix:\n // `useQuery('todo_task', { where: { status: 'open' } })` issued 4691 `find`\n // calls in 250ms; the same call with a hoisted options object issued 1.\n const queryKey = stableKey({\n query,\n where: resolvedWhere,\n fields: resolvedFields,\n orderBy: resolvedSort,\n limit: resolvedLimit,\n offset: resolvedOffset,\n });\n\n // Handlers say what to do with a result; they are not part of what is being\n // fetched, so they must not drive refetching.\n const handleSuccess = useEventCallback(onSuccess);\n const handleError = useEventCallback(onError);\n\n const fetchData = useCallback(async (isRefetch = false) => {\n if (!enabled) return;\n \n try {\n if (isRefetch) {\n setIsRefetching(true);\n } else {\n setIsLoading(true);\n }\n setError(null);\n\n let result: PaginatedResult<T>;\n \n if (query) {\n // Use advanced query API\n result = await client.data.query<T>(object, query);\n } else {\n // Use canonical QueryOptionsV2 for the find call\n result = await client.data.find<T>(object, {\n where: resolvedWhere as any,\n fields: resolvedFields,\n orderBy: resolvedSort,\n limit: resolvedLimit,\n offset: resolvedOffset,\n });\n }\n\n setData(result);\n handleSuccess(result);\n } catch (err) {\n const error = err instanceof Error ? err : new Error('Query failed');\n setError(error);\n handleError(error);\n } finally {\n setIsLoading(false);\n setIsRefetching(false);\n }\n }, [client, object, queryKey, enabled, handleSuccess, handleError]);\n\n // Initial fetch and dependency-based refetch\n useEffect(() => {\n fetchData();\n }, [fetchData]);\n\n // Setup refetch interval\n useEffect(() => {\n if (refetchInterval && enabled) {\n intervalRef.current = setInterval(() => {\n fetchData(true);\n }, refetchInterval);\n\n return () => {\n if (intervalRef.current) {\n clearInterval(intervalRef.current);\n }\n };\n }\n return undefined;\n }, [refetchInterval, enabled, fetchData]);\n\n const refetch = useCallback(async () => {\n await fetchData(true);\n }, [fetchData]);\n\n return {\n data,\n isLoading,\n error,\n refetch,\n isRefetching\n };\n}\n\n/**\n * Mutation options for useMutation hook\n */\nexport interface UseMutationOptions<TData = any, TVariables = any> {\n /** Callback on successful mutation */\n onSuccess?: (data: TData, variables: TVariables) => void;\n /** Callback on error */\n onError?: (error: Error, variables: TVariables) => void;\n /** Callback when mutation is settled (success or error) */\n onSettled?: (data: TData | undefined, error: Error | null, variables: TVariables) => void;\n}\n\n/**\n * Mutation result for useMutation hook\n */\nexport interface UseMutationResult<TData = any, TVariables = any> {\n /** Execute the mutation */\n mutate: (variables: TVariables) => Promise<TData>;\n /** Async version of mutate that throws errors */\n mutateAsync: (variables: TVariables) => Promise<TData>;\n /** Mutation result data */\n data: TData | null;\n /** Loading state */\n isLoading: boolean;\n /** Error state */\n error: Error | null;\n /** Reset mutation state */\n reset: () => void;\n}\n\n/**\n * Hook for creating, updating, or deleting ObjectStack data\n * \n * @example\n * <!-- os:check -->\n * ```tsx\n * import { useMutation } from '@objectstack/client-react';\n *\n * function CreateTaskForm() {\n * const { mutate, isLoading, error } = useMutation('todo_task', 'create', {\n * onSuccess: (data) => {\n * console.log('Task created:', data);\n * }\n * });\n *\n * const handleSubmit = (formData: Record<string, unknown>) => {\n * mutate(formData);\n * };\n *\n * return <button onClick={() => handleSubmit({ subject: 'New task' })}>Create</button>;\n * }\n * ```\n */\nexport function useMutation<TData = any, TVariables = any>(\n object: string,\n operation: 'create' | 'update' | 'delete' | 'createMany' | 'updateMany' | 'deleteMany',\n options: UseMutationOptions<TData, TVariables> = {}\n): UseMutationResult<TData, TVariables> {\n const client = useClient();\n const [data, setData] = useState<TData | null>(null);\n const [isLoading, setIsLoading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n\n const { onSuccess, onError, onSettled } = options;\n\n const mutateAsync = useCallback(async (variables: TVariables): Promise<TData> => {\n setIsLoading(true);\n setError(null);\n\n try {\n let result: TData;\n\n switch (operation) {\n case 'create':\n result = (await client.data.create(object, variables as any)) as TData;\n break;\n case 'update':\n // Expect variables to be { id: string, data: Partial<T> }\n const updateVars = variables as any;\n result = (await client.data.update(object, updateVars.id, updateVars.data)) as TData;\n break;\n case 'delete':\n // Expect variables to be { id: string }\n const deleteVars = variables as any;\n result = await client.data.delete(object, deleteVars.id) as any;\n break;\n case 'createMany':\n // createMany returns an array, which may not match TData type\n result = await client.data.createMany(object, variables as any) as any;\n break;\n case 'updateMany':\n // Expect variables to be { records: Array<{ id: string, data: Partial<T> }> }\n const updateManyVars = variables as any;\n result = await client.data.updateMany(object, updateManyVars.records, updateManyVars.options) as any;\n break;\n case 'deleteMany':\n // Expect variables to be { ids: string[] }\n const deleteManyVars = variables as any;\n result = await client.data.deleteMany(object, deleteManyVars.ids, deleteManyVars.options) as any;\n break;\n default:\n throw new Error(`Unknown operation: ${operation}`);\n }\n\n setData(result);\n onSuccess?.(result, variables);\n onSettled?.(result, null, variables);\n \n return result;\n } catch (err) {\n const error = err instanceof Error ? err : new Error('Mutation failed');\n setError(error);\n onError?.(error, variables);\n onSettled?.(undefined, error, variables);\n throw error;\n } finally {\n setIsLoading(false);\n }\n }, [client, object, operation, onSuccess, onError, onSettled]);\n\n const mutate = useCallback((variables: TVariables): Promise<TData> => {\n return mutateAsync(variables).catch(() => {\n // Swallow error for non-async version\n // Error is still available in the error state\n return null as any;\n });\n }, [mutateAsync]);\n\n const reset = useCallback(() => {\n setData(null);\n setError(null);\n setIsLoading(false);\n }, []);\n\n return {\n mutate,\n mutateAsync,\n data,\n isLoading,\n error,\n reset\n };\n}\n\n/**\n * Pagination options for usePagination hook\n */\nexport interface UsePaginationOptions<T = any> extends Omit<UseQueryOptions<T>, 'limit' | 'offset'> {\n /** Page size */\n pageSize?: number;\n /** Initial page (1-based) */\n initialPage?: number;\n}\n\n/**\n * Pagination result for usePagination hook\n */\nexport interface UsePaginationResult<T = any> extends UseQueryResult<T> {\n /** Current page (1-based) */\n page: number;\n /** Total number of pages */\n totalPages: number;\n /** Total number of records */\n totalCount: number;\n /** Go to next page */\n nextPage: () => void;\n /** Go to previous page */\n previousPage: () => void;\n /** Go to specific page */\n goToPage: (page: number) => void;\n /** Whether there is a next page */\n hasNextPage: boolean;\n /** Whether there is a previous page */\n hasPreviousPage: boolean;\n}\n\n/**\n * Hook for paginated data queries\n * \n * @example\n * <!-- os:check -->\n * ```tsx\n * import { usePagination } from '@objectstack/client-react';\n *\n * function PaginatedTaskList() {\n * const {\n * data,\n * isLoading,\n * page,\n * totalPages,\n * nextPage,\n * previousPage,\n * hasNextPage,\n * hasPreviousPage\n * } = usePagination('todo_task', {\n * pageSize: 10,\n * orderBy: ['-created_at']\n * });\n *\n * return (\n * <div>\n * {data?.records.map(task => <div key={task.id}>{task.subject}</div>)}\n * <button onClick={previousPage} disabled={!hasPreviousPage}>Previous</button>\n * <span>Page {page} of {totalPages}</span>\n * <button onClick={nextPage} disabled={!hasNextPage}>Next</button>\n * </div>\n * );\n * }\n * ```\n */\nexport function usePagination<T = any>(\n object: string,\n options: UsePaginationOptions<T> = {}\n): UsePaginationResult<T> {\n const { pageSize = 20, initialPage = 1, ...queryOptions } = options;\n const [page, setPage] = useState(initialPage);\n\n const queryResult = useQuery<T>(object, {\n ...queryOptions,\n limit: pageSize,\n offset: (page - 1) * pageSize\n });\n\n const totalCount = queryResult.data?.total || 0;\n const totalPages = Math.ceil(totalCount / pageSize);\n const hasNextPage = page < totalPages;\n const hasPreviousPage = page > 1;\n\n const nextPage = useCallback(() => {\n if (hasNextPage) {\n setPage(p => p + 1);\n }\n }, [hasNextPage]);\n\n const previousPage = useCallback(() => {\n if (hasPreviousPage) {\n setPage(p => p - 1);\n }\n }, [hasPreviousPage]);\n\n const goToPage = useCallback((newPage: number) => {\n const clampedPage = Math.max(1, Math.min(newPage, totalPages));\n setPage(clampedPage);\n }, [totalPages]);\n\n return {\n ...queryResult,\n page,\n totalPages,\n totalCount,\n nextPage,\n previousPage,\n goToPage,\n hasNextPage,\n hasPreviousPage\n };\n}\n\n/**\n * Infinite query options for useInfiniteQuery hook\n */\nexport interface UseInfiniteQueryOptions<T = any> extends Omit<UseQueryOptions<T>, 'offset'> {\n /** Page size for each fetch */\n pageSize?: number;\n /** Get next page parameter */\n getNextPageParam?: (lastPage: PaginatedResult<T>, allPages: PaginatedResult<T>[]) => number | undefined;\n}\n\n/**\n * Infinite query result for useInfiniteQuery hook\n */\nexport interface UseInfiniteQueryResult<T = any> {\n /** All pages of data */\n data: PaginatedResult<T>[];\n /** Flattened data from all pages */\n flatData: T[];\n /** Loading state */\n isLoading: boolean;\n /** Error state */\n error: Error | null;\n /** Load the next page */\n fetchNextPage: () => Promise<void>;\n /** Whether there are more pages */\n hasNextPage: boolean;\n /** Is currently fetching next page */\n isFetchingNextPage: boolean;\n /** Refetch all pages */\n refetch: () => Promise<void>;\n}\n\n/**\n * Hook for infinite scrolling / load more functionality\n * \n * @example\n * <!-- os:check -->\n * ```tsx\n * import { useInfiniteQuery } from '@objectstack/client-react';\n *\n * function InfiniteTaskList() {\n * const {\n * flatData,\n * isLoading,\n * fetchNextPage,\n * hasNextPage,\n * isFetchingNextPage\n * } = useInfiniteQuery('todo_task', {\n * pageSize: 20,\n * orderBy: ['-created_at']\n * });\n *\n * return (\n * <div>\n * {flatData.map(task => <div key={task.id}>{task.subject}</div>)}\n * {hasNextPage && (\n * <button onClick={fetchNextPage} disabled={isFetchingNextPage}>\n * {isFetchingNextPage ? 'Loading...' : 'Load More'}\n * </button>\n * )}\n * </div>\n * );\n * }\n * ```\n */\nexport function useInfiniteQuery<T = any>(\n object: string,\n options: UseInfiniteQueryOptions<T> = {}\n): UseInfiniteQueryResult<T> {\n const client = useClient();\n const {\n pageSize = 20,\n // getNextPageParam is reserved for future use\n query,\n // Canonical names take precedence over legacy names\n where, fields, orderBy,\n enabled = true,\n onSuccess,\n onError\n } = options;\n\n const resolvedFields = fields;\n const resolvedWhere = where;\n const resolvedSort = orderBy;\n\n // Same value-keyed dependency as useQuery (#4693) — measured at 6611 `find`\n // calls in 250ms before this fix, with inline options.\n const queryKey = stableKey({\n query,\n where: resolvedWhere,\n fields: resolvedFields,\n orderBy: resolvedSort,\n pageSize,\n });\n const handleSuccess = useEventCallback(onSuccess);\n const handleError = useEventCallback(onError);\n\n const [pages, setPages] = useState<PaginatedResult<T>[]>([]);\n const [isLoading, setIsLoading] = useState(true);\n const [isFetchingNextPage, setIsFetchingNextPage] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n const [hasNextPage, setHasNextPage] = useState(true);\n\n const fetchPage = useCallback(async (skip: number, isNextPage = false) => {\n try {\n if (isNextPage) {\n setIsFetchingNextPage(true);\n } else {\n setIsLoading(true);\n }\n setError(null);\n\n let result: PaginatedResult<T>;\n\n if (query) {\n result = await client.data.query<T>(object, {\n ...query,\n limit: pageSize,\n offset: skip\n });\n } else {\n result = await client.data.find<T>(object, {\n where: resolvedWhere as any,\n fields: resolvedFields,\n orderBy: resolvedSort,\n limit: pageSize,\n offset: skip,\n });\n }\n\n if (isNextPage) {\n setPages(prev => [...prev, result]);\n } else {\n setPages([result]);\n }\n\n // Determine if there's a next page\n const fetchedCount = result.records?.length ?? 0;\n const hasMore = fetchedCount === pageSize;\n setHasNextPage(hasMore);\n\n handleSuccess(result);\n } catch (err) {\n const error = err instanceof Error ? err : new Error('Query failed');\n setError(error);\n handleError(error);\n } finally {\n setIsLoading(false);\n setIsFetchingNextPage(false);\n }\n }, [client, object, queryKey, handleSuccess, handleError]);\n\n // Initial fetch\n useEffect(() => {\n if (enabled) {\n fetchPage(0);\n }\n }, [enabled, fetchPage]);\n\n const fetchNextPage = useCallback(async () => {\n if (!hasNextPage || isFetchingNextPage) return;\n\n const nextSkip = pages.length * pageSize;\n await fetchPage(nextSkip, true);\n }, [hasNextPage, isFetchingNextPage, pages.length, pageSize, fetchPage]);\n\n const refetch = useCallback(async () => {\n setPages([]);\n await fetchPage(0);\n }, [fetchPage]);\n\n const flatData = pages.flatMap(page => page.records ?? []);\n\n return {\n data: pages,\n flatData,\n isLoading,\n error,\n fetchNextPage,\n hasNextPage,\n isFetchingNextPage,\n refetch\n };\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * Dependency-array primitives (#4693, #4694) — internal, not exported from the\n * package entry point.\n *\n * Every fetch and subscription hook here keys a `useCallback`/`useEffect` on\n * values the caller supplies inline: `where` / `fields` / `orderBy` objects,\n * `onSuccess` / `onError` handlers, the `fetcher` `useMetadata` takes as a\n * required argument. Inline means a fresh identity on every render, so the\n * effect re-ran on every render — and for the fetch hooks that effect calls\n * `setState`, which renders again. Five hooks were in an unbounded request\n * loop under their own documented usage.\n *\n * The two helpers below fix the two halves of that:\n *\n * - {@link stableKey} turns a structural value into a dependency that changes\n * when the *value* changes rather than when the object is rebuilt;\n * - {@link useEventCallback} gives a caller's handler a fixed identity, so\n * passing it inline no longer re-runs anything.\n *\n * Neither is a substitute for the caller memoizing — they remove the need to.\n * Correctness must not rest on every call site remembering `useMemo`, least of\n * all when the TSDoc examples themselves pass object literals.\n */\n\nimport { useCallback, useEffect, useRef } from 'react';\n\n/**\n * Order-independent stringify, used to derive a dependency from a structural\n * value. Object keys are sorted so `{ a, b }` and `{ b, a }` agree; array order\n * is preserved because it is semantic (`orderBy: ['-created_at', 'name']`).\n *\n * Mirrors the same helper in `service-settings` and `service-automation` — kept\n * local for the same reason they are: it is three lines and a shared util\n * package would be a heavier dependency than the code it carries.\n *\n * Values JSON cannot represent (functions, symbols) collapse to `undefined`\n * here. That is correct for this use: a handler's identity must not drive a\n * refetch, which is exactly what {@link useEventCallback} is for.\n */\nexport function stableKey(input: unknown): string {\n if (input === null || typeof input !== 'object') return JSON.stringify(input) ?? 'undefined';\n if (Array.isArray(input)) return '[' + input.map(stableKey).join(',') + ']';\n const obj = input as Record<string, unknown>;\n const keys = Object.keys(obj).sort();\n return '{' + keys.map((k) => JSON.stringify(k) + ':' + stableKey(obj[k])).join(',') + '}';\n}\n\n/**\n * Wraps a caller-supplied handler in a function whose identity never changes,\n * while always invoking the most recent version.\n *\n * This is what lets the fetch and subscription effects drop `onSuccess` /\n * `onError` / `callback` from their dependency arrays. Those handlers say what\n * to do when something happens; they are not part of *what is subscribed to* or\n * *what is fetched*, so they have no business re-running an effect.\n *\n * The ref is updated in an effect rather than during render: a render may be\n * thrown away under concurrent rendering, and writing through a ref then would\n * publish a handler from a render that never committed.\n *\n * Returns `undefined` from the call when no handler was supplied, so optional\n * handlers need no call-site guard.\n */\nexport function useEventCallback<A extends unknown[], R>(\n fn: ((...args: A) => R) | undefined\n): (...args: A) => R | undefined {\n const ref = useRef(fn);\n\n useEffect(() => {\n ref.current = fn;\n }, [fn]);\n\n return useCallback((...args: A) => ref.current?.(...args), []);\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * Metadata Hooks\n * \n * React hooks for accessing ObjectStack metadata (schemas, views, fields)\n */\n\nimport { useState, useEffect, useCallback, useRef } from 'react';\nimport { useClient, useObjectStackLocale } from './context';\nimport { useEventCallback } from './internal-deps';\n\n/**\n * Metadata query options\n */\nexport interface UseMetadataOptions {\n /** Enable/disable automatic query execution */\n enabled?: boolean;\n /** Use cached metadata if available */\n useCache?: boolean;\n /** ETag for conditional requests */\n ifNoneMatch?: string;\n /** If-Modified-Since header for conditional requests */\n ifModifiedSince?: string;\n /** Callback on successful query */\n onSuccess?: (data: any) => void;\n /** Callback on error */\n onError?: (error: Error) => void;\n}\n\n/**\n * Metadata query result\n */\nexport interface UseMetadataResult<T = any> {\n /** Metadata data */\n data: T | null;\n /** Loading state */\n isLoading: boolean;\n /** Error state */\n error: Error | null;\n /** Refetch the metadata */\n refetch: () => Promise<void>;\n /** ETag from last fetch */\n etag?: string;\n /** Whether data came from cache (304 Not Modified) */\n fromCache: boolean;\n}\n\n/**\n * Hook for fetching object schema/metadata.\n *\n * `data` is the `GET /meta/:type/:name` response envelope\n * (`GetMetaItemResponseSchema`): `{ type, name, item, … }`, with the object\n * schema document under `item`. It is NOT the bare schema.\n *\n * [#5563] It used to be either one, decided by the server's `enableCache`\n * setting: the cached read path (the default) answered the bare document while\n * the uncached path answered the envelope, and this hook fed both into the same\n * state. The route answers one shape now, so the hook can too — and it is the\n * declared one, which keeps the hook isomorphic to the endpoint instead of\n * inventing a second dialect at the SDK boundary. Reading a document field\n * straight off `data` (`data.fields`) was the old spelling; it is `data.item.fields`\n * now. See {@link useFields} for the pre-flattened field list.\n *\n * @example\n * <!-- os:check -->\n * ```tsx\n * import { useObject } from '@objectstack/client-react';\n *\n * function ObjectSchemaViewer({ objectName }: { objectName: string }) {\n * const { data, isLoading, error } = useObject(objectName);\n *\n * if (isLoading) return <div>Loading schema...</div>;\n * if (error) return <div>Error: {error.message}</div>;\n *\n * const schema = data.item;\n * return (\n * <div>\n * <h2>{schema.label}</h2>\n * <p>Fields: {Object.keys(schema.fields).length}</p>\n * </div>\n * );\n * }\n * ```\n */\nexport function useObject(\n objectName: string,\n options: UseMetadataOptions = {}\n): UseMetadataResult {\n const client = useClient();\n // Active UI locale: object/field labels are translated server-side, so a\n // language switch must re-fetch (it is *not* reactive via i18next). Folding\n // `locale` into the fetch deps below triggers that re-fetch (issue #1319).\n const locale = useObjectStackLocale();\n const [data, setData] = useState<any>(null);\n const [isLoading, setIsLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n const [etag, setEtag] = useState<string>();\n const [fromCache, setFromCache] = useState(false);\n\n const {\n enabled = true,\n useCache = true,\n ifNoneMatch,\n ifModifiedSince,\n onSuccess,\n onError\n } = options;\n\n // `data` and `etag` are this hook's OWN state, and the fetch writes both.\n // Depending on them made the fetch its own trigger: `setData` → new `data`\n // identity → new `fetchMetadata` → the effect below re-ran → fetch again.\n // Unlike the data hooks this needed no particular usage to fire — measured at\n // 4306 metadata requests in 250ms for a bare `useObject('todo_task')`\n // (#4693). They are read, never depended on, so they belong in refs.\n const dataRef = useRef(data);\n const etagRef = useRef(etag);\n useEffect(() => {\n dataRef.current = data;\n etagRef.current = etag;\n }, [data, etag]);\n\n const handleSuccess = useEventCallback(onSuccess);\n const handleError = useEventCallback(onError);\n\n const fetchMetadata = useCallback(async () => {\n if (!enabled) return;\n\n try {\n setIsLoading(true);\n setError(null);\n setFromCache(false);\n\n if (useCache) {\n // Both branches address the SAME route (`meta.getCached` is\n // `GET {metadata}/object/:name` with conditional-request headers), so\n // both now put the same `{ type, name, item, … }` envelope into `data`\n // — `result.data` here, the unwrapped response there. [#5563] Before the\n // convergence these two lines disagreed with each other, and which one a\n // deployment hit was decided by its `enableCache` setting.\n const result = await client.meta.getCached(objectName, {\n ifNoneMatch: ifNoneMatch || etagRef.current,\n ifModifiedSince\n });\n\n if (result.notModified) {\n setFromCache(true);\n } else {\n setData(result.data);\n if (result.etag) {\n setEtag(result.etag.value);\n }\n }\n\n handleSuccess(result.data || dataRef.current);\n } else {\n // Direct fetch without cache\n const result = await client.meta.getItem('object', objectName);\n setData(result);\n handleSuccess(result);\n }\n } catch (err) {\n const error = err instanceof Error ? err : new Error('Failed to fetch object metadata');\n setError(error);\n handleError(error);\n } finally {\n setIsLoading(false);\n }\n }, [client, objectName, locale, enabled, useCache, ifNoneMatch, ifModifiedSince, handleSuccess, handleError]);\n\n useEffect(() => {\n fetchMetadata();\n }, [fetchMetadata]);\n\n const refetch = useCallback(async () => {\n await fetchMetadata();\n }, [fetchMetadata]);\n\n return {\n data,\n isLoading,\n error,\n refetch,\n etag,\n fromCache\n };\n}\n\n/**\n * Hook for fetching view configuration\n * \n * @example\n * <!-- os:check -->\n * ```tsx\n * import { useView } from '@objectstack/client-react';\n *\n * function ViewConfiguration({ objectName }: { objectName: string }) {\n * const { data: view, isLoading } = useView(objectName, 'list');\n *\n * if (isLoading) return <div>Loading view...</div>;\n *\n * return (\n * <div>\n * <h3>List View for {objectName}</h3>\n * <p>Columns: {view?.columns?.length}</p>\n * </div>\n * );\n * }\n * ```\n */\nexport function useView(\n objectName: string,\n viewType: 'list' | 'form' = 'list',\n options: UseMetadataOptions = {}\n): UseMetadataResult {\n const client = useClient();\n // View headers/labels are translated server-side — re-fetch on locale change.\n const locale = useObjectStackLocale();\n const [data, setData] = useState<any>(null);\n const [isLoading, setIsLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n\n const { enabled = true, onSuccess, onError } = options;\n\n const handleSuccess = useEventCallback(onSuccess);\n const handleError = useEventCallback(onError);\n\n const fetchView = useCallback(async () => {\n if (!enabled) return;\n\n try {\n setIsLoading(true);\n setError(null);\n\n const result = await client.meta.getView(objectName, viewType);\n setData(result);\n handleSuccess(result);\n } catch (err) {\n const error = err instanceof Error ? err : new Error('Failed to fetch view configuration');\n setError(error);\n handleError(error);\n } finally {\n setIsLoading(false);\n }\n }, [client, objectName, viewType, locale, enabled, handleSuccess, handleError]);\n\n useEffect(() => {\n fetchView();\n }, [fetchView]);\n\n const refetch = useCallback(async () => {\n await fetchView();\n }, [fetchView]);\n\n return {\n data,\n isLoading,\n error,\n refetch,\n fromCache: false\n };\n}\n\n/**\n * Hook for extracting fields from object schema\n * \n * @example\n * <!-- os:check -->\n * ```tsx\n * import { useFields } from '@objectstack/client-react';\n *\n * function FieldList({ objectName }: { objectName: string }) {\n * const { data: fields, isLoading } = useFields(objectName);\n *\n * if (isLoading) return <div>Loading fields...</div>;\n *\n * return (\n * <ul>\n * {fields?.map(field => (\n * <li key={field.name}>{field.label} ({field.type})</li>\n * ))}\n * </ul>\n * );\n * }\n * ```\n */\nexport function useFields(\n objectName: string,\n options: UseMetadataOptions = {}\n): UseMetadataResult<any[]> {\n const objectResult = useObject(objectName, options);\n\n // [#5563] `useObject().data` is the `{ type, name, item }` envelope; the\n // schema document — and therefore `fields` — is under `item`.\n const schema = objectResult.data?.item;\n const fields = schema?.fields\n ? Object.entries(schema.fields).map(([name, field]: [string, any]) => ({\n name,\n ...field\n }))\n : null;\n\n return {\n ...objectResult,\n data: fields\n };\n}\n\n/**\n * Generic metadata hook for custom metadata queries\n * \n * @example\n * <!-- os:check -->\n * ```tsx\n * import { useMetadata } from '@objectstack/client-react';\n *\n * function CustomMetadata() {\n * const { data, isLoading } = useMetadata(async (client) => {\n * // Custom metadata fetching logic\n * const object = await client.meta.getItem('object', 'custom_object');\n * const view = await client.meta.getView('custom_object', 'list');\n * return { object, view };\n * });\n *\n * return <pre>{JSON.stringify(data, null, 2)}</pre>;\n * }\n * ```\n */\nexport function useMetadata<T = any>(\n fetcher: (client: ReturnType<typeof useClient>) => Promise<T>,\n options: Omit<UseMetadataOptions, 'useCache' | 'ifNoneMatch' | 'ifModifiedSince'> = {}\n): UseMetadataResult<T> {\n const client = useClient();\n // Custom fetchers commonly read server-translated metadata too — refetch on\n // locale change so their labels follow the active language.\n const locale = useObjectStackLocale();\n const [data, setData] = useState<T | null>(null);\n const [isLoading, setIsLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n\n const { enabled = true, onSuccess, onError } = options;\n\n // `fetcher` is a REQUIRED positional argument, so an inline arrow is the only\n // natural way to call this hook — which made the loop unconditional in\n // practice (7654 fetcher invocations in 250ms before this fix, #4693).\n // Stabilizing it here means the fetch re-runs on `client` / `locale` /\n // `enabled` changes, as intended, and not on the caller's render cadence.\n const runFetcher = useEventCallback(fetcher);\n const handleSuccess = useEventCallback(onSuccess);\n const handleError = useEventCallback(onError);\n\n const fetchMetadata = useCallback(async () => {\n if (!enabled) return;\n\n try {\n setIsLoading(true);\n setError(null);\n\n const result = await runFetcher(client);\n setData(result as T);\n handleSuccess(result as T);\n } catch (err) {\n const error = err instanceof Error ? err : new Error('Failed to fetch metadata');\n setError(error);\n handleError(error);\n } finally {\n setIsLoading(false);\n }\n }, [client, runFetcher, locale, enabled, handleSuccess, handleError]);\n\n useEffect(() => {\n fetchMetadata();\n }, [fetchMetadata]);\n\n const refetch = useCallback(async () => {\n await fetchMetadata();\n }, [fetchMetadata]);\n\n return {\n data,\n isLoading,\n error,\n refetch,\n fromCache: false\n };\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * Real-time Event Subscription Hooks\n *\n * Provides React hooks for subscribing to metadata and data events.\n * Events are automatically cleaned up when components unmount.\n */\n\nimport { useEffect, useState } from 'react';\nimport type {\n MetadataEvent,\n MetadataEventSubject,\n DataEvent,\n BulkDataEvent,\n} from '@objectstack/spec/api';\nimport { useClient } from './context';\nimport { useEventCallback } from './internal-deps';\n\n/**\n * Hook to subscribe to metadata events\n *\n * @param type - Metadata type to subscribe to (e.g., 'object', 'view', 'agent').\n * Typed {@link MetadataEventSubject}, the closed set derived from\n * `MetadataEventType` (#4627) — a metadata type with no realtime event\n * contract (`'translation'`, `'datasource'`, …) is a compile error here\n * rather than a subscription that never fires. This hook only forwards the\n * argument to `subscribeMetadata`, so it must not be the looser of the two.\n * @param options - Optional filters (packageId)\n * @returns Latest metadata event or null\n *\n * @example\n * <!-- os:check -->\n * ```tsx\n * import { useEffect } from 'react';\n * import { useMetadataSubscription } from '@objectstack/client-react';\n *\n * function ObjectList() {\n * const event = useMetadataSubscription('object');\n *\n * useEffect(() => {\n * if (event?.type === 'metadata.object.created') {\n * console.log('New object:', event.name);\n * // Refresh list\n * }\n * }, [event]);\n *\n * return <div>...</div>;\n * }\n * ```\n */\nexport function useMetadataSubscription(\n type: MetadataEventSubject,\n options?: { packageId?: string }\n): MetadataEvent | null {\n const client = useClient();\n const [event, setEvent] = useState<MetadataEvent | null>(null);\n\n useEffect(() => {\n if (!client) return;\n\n const unsubscribe = client.events.subscribeMetadata(\n type,\n (e) => setEvent(e),\n options\n );\n\n return () => {\n unsubscribe();\n };\n }, [client, type, options?.packageId]);\n\n return event;\n}\n\n/**\n * Hook to subscribe to data record events\n *\n * @param object - Object name to subscribe to\n * @param options - Optional filters (recordId for specific record)\n * @returns Latest data event or null\n *\n * @example\n * <!-- os:check -->\n * ```tsx\n * import { useEffect } from 'react';\n * import { useDataSubscription } from '@objectstack/client-react';\n *\n * function TaskDetail({ taskId }: { taskId: string }) {\n * const event = useDataSubscription('project_task', { recordId: taskId });\n *\n * useEffect(() => {\n * if (event?.type === 'data.record.updated') {\n * console.log('Task updated:', event.changes);\n * // Refresh task data\n * }\n * }, [event]);\n *\n * return <div>...</div>;\n * }\n * ```\n */\nexport function useDataSubscription(\n object: string,\n options?: { recordId?: string }\n): DataEvent | null {\n const client = useClient();\n const [event, setEvent] = useState<DataEvent | null>(null);\n\n useEffect(() => {\n if (!client) return;\n\n const unsubscribe = client.events.subscribeData(\n object,\n (e) => setEvent(e),\n options\n );\n\n return () => {\n unsubscribe();\n };\n }, [client, object, options?.recordId]);\n\n return event;\n}\n\n/**\n * Hook to subscribe to metadata events with a callback\n *\n * This variant doesn't store events in state, it just triggers a callback.\n * Useful for triggering refetches or side effects without re-renders.\n *\n * @param type - Metadata type to subscribe to. Same {@link MetadataEventSubject}\n * narrowing as {@link useMetadataSubscription} (#4627).\n * @param callback - Callback to invoke on events\n * @param options - Optional filters\n *\n * @example\n * <!-- os:check -->\n * ```tsx\n * import { useQuery, useMetadataSubscriptionCallback } from '@objectstack/client-react';\n *\n * function ObjectList() {\n * const { refetch } = useQuery('todo_task', {});\n *\n * useMetadataSubscriptionCallback('object', () => {\n * refetch(); // Refetch list when objects change\n * });\n *\n * return <div>...</div>;\n * }\n * ```\n */\nexport function useMetadataSubscriptionCallback(\n type: MetadataEventSubject,\n callback: (event: MetadataEvent) => void,\n options?: { packageId?: string }\n): void {\n const client = useClient();\n // The callback is what RUNS on an event, not part of what is subscribed to\n // (#4694). Depending on its identity tore down and reopened the subscription\n // on every render whenever the caller passed an inline function — which the\n // examples above do — losing any event that arrived in the gap.\n const handleEvent = useEventCallback(callback);\n\n useEffect(() => {\n if (!client) return;\n\n const unsubscribe = client.events.subscribeMetadata(\n type,\n handleEvent,\n options\n );\n\n return () => {\n unsubscribe();\n };\n }, [client, type, handleEvent, options?.packageId]);\n}\n\n/**\n * Hook to subscribe to data events with a callback\n *\n * @param object - Object name to subscribe to\n * @param callback - Callback to invoke on events\n * @param options - Optional filters\n *\n * @example\n * <!-- os:check -->\n * ```tsx\n * import { useQuery, useDataSubscriptionCallback } from '@objectstack/client-react';\n *\n * function TaskList() {\n * const { refetch } = useQuery('project_task', {});\n *\n * useDataSubscriptionCallback('project_task', () => {\n * refetch(); // Refetch list when tasks change\n * });\n *\n * return <div>...</div>;\n * }\n * ```\n */\nexport function useDataSubscriptionCallback(\n object: string,\n callback: (event: DataEvent) => void,\n options?: { recordId?: string }\n): void {\n const client = useClient();\n // Stable identity so an inline callback does not churn the subscription on\n // every render (#4694) — see useMetadataSubscriptionCallback.\n const handleEvent = useEventCallback(callback);\n\n useEffect(() => {\n if (!client) return;\n\n const unsubscribe = client.events.subscribeData(\n object,\n handleEvent,\n options\n );\n\n return () => {\n unsubscribe();\n };\n }, [client, object, handleEvent, options?.recordId]);\n}\n\n/**\n * Hook to subscribe to bulk (predicate-write) data events\n *\n * A `multi: true` update/delete reaches the driver's `updateMany`/`deleteMany`,\n * which report an affected COUNT and name no rows — so it publishes\n * `data.records.updated` / `data.records.deleted` rather than the per-record\n * events {@link useDataSubscription} delivers (#4639).\n *\n * The event carries `object` and `matched` — there is no `recordId` and no\n * record body, which is why this is a separate hook rather than more types\n * flowing through `useDataSubscription`: a `DataEvent` callback receiving one\n * of these would read `undefined` for every field it expects.\n *\n * Use it to invalidate a list, show \"40 records changed\", or trigger a\n * refetch — not to patch a per-record cache, which a count cannot drive.\n *\n * @param object - Object name to subscribe to\n * @returns Latest bulk data event or null\n *\n * @example\n * <!-- os:check -->\n * ```tsx\n * import { useEffect } from 'react';\n * import { useBulkDataSubscription } from '@objectstack/client-react';\n *\n * function TaskList() {\n * const bulk = useBulkDataSubscription('project_task');\n *\n * useEffect(() => {\n * if (bulk) {\n * console.log(`${bulk.matched} tasks changed in one write`);\n * }\n * }, [bulk]);\n *\n * return <div>...</div>;\n * }\n * ```\n */\nexport function useBulkDataSubscription(object: string): BulkDataEvent | null {\n const client = useClient();\n const [event, setEvent] = useState<BulkDataEvent | null>(null);\n\n useEffect(() => {\n if (!client) return;\n\n const unsubscribe = client.events.subscribeBulkData(object, (e) => setEvent(e));\n\n return () => {\n unsubscribe();\n };\n }, [client, object]);\n\n return event;\n}\n\n/**\n * Hook to subscribe to bulk data events with a callback\n *\n * The callback variant of {@link useBulkDataSubscription} — no state, no\n * re-render, for triggering refetches and side effects.\n *\n * @param object - Object name to subscribe to\n * @param callback - Callback to invoke on events\n *\n * @example\n * <!-- os:check -->\n * ```tsx\n * import { useQuery, useBulkDataSubscriptionCallback } from '@objectstack/client-react';\n *\n * function TaskList() {\n * const { refetch } = useQuery('project_task', {});\n *\n * useBulkDataSubscriptionCallback('project_task', () => {\n * refetch(); // a predicate write touched an unknown set of rows\n * });\n *\n * return <div>...</div>;\n * }\n * ```\n */\nexport function useBulkDataSubscriptionCallback(\n object: string,\n callback: (event: BulkDataEvent) => void\n): void {\n const client = useClient();\n // Stable identity so an inline callback does not churn the subscription on\n // every render (#4694) — see useMetadataSubscriptionCallback.\n const handleEvent = useEventCallback(callback);\n\n useEffect(() => {\n if (!client) return;\n\n const unsubscribe = client.events.subscribeBulkData(object, handleEvent);\n\n return () => {\n unsubscribe();\n };\n }, [client, object, handleEvent]);\n}\n\n/**\n * Hook to get connection status of realtime events\n *\n * @returns Whether realtime is connected\n *\n * @example\n * <!-- os:check -->\n * ```tsx\n * import { useRealtimeConnection } from '@objectstack/client-react';\n *\n * function ConnectionIndicator() {\n * const connected = useRealtimeConnection();\n *\n * return (\n * <div>\n * {connected ? '🟢 Connected' : '🔴 Disconnected'}\n * </div>\n * );\n * }\n * ```\n */\nexport function useRealtimeConnection(): boolean {\n const client = useClient();\n const [connected, setConnected] = useState(true);\n\n useEffect(() => {\n if (!client) {\n setConnected(false);\n return;\n }\n\n // For now, assume always connected with in-memory adapter\n // In production, this would listen to WebSocket connection events\n setConnected(true);\n }, [client]);\n\n return connected;\n}\n\n/**\n * Hook for auto-refreshing queries when data changes\n *\n * Combines data subscription with query refetch.\n *\n * Watches BOTH event streams (#4678): per-record `data.record.*` writes and\n * the aggregate `data.records.*` a predicate (`multi: true`) write publishes.\n * A bulk write is the case that dirties a list hardest — one statement can\n * change or delete every row on screen — so a refresh hook that ignored it\n * would sit still exactly when it matters most, while still refreshing for a\n * single-row edit.\n *\n * Mixing the two streams is safe here in a way it is not for\n * {@link useDataSubscription}: this hook's output is a refetch signal, not an\n * event body, so the shape difference that keeps the two contracts apart\n * (no `recordId`, no record) never reaches the caller.\n *\n * @param object - Object name to watch\n * @param refetch - Refetch function from useQuery\n * @param options - Optional filters\n *\n * @example\n * <!-- os:check -->\n * ```tsx\n * import { useQuery, useAutoRefresh } from '@objectstack/client-react';\n *\n * function TaskList() {\n * const { data, refetch } = useQuery('project_task', {});\n *\n * useAutoRefresh('project_task', refetch);\n *\n * return <div>{data?.records.map(task => <div key={task.id}>{task.subject}</div>)}</div>;\n * }\n * ```\n */\nexport function useAutoRefresh(\n object: string,\n refetch: () => void,\n options?: { recordId?: string }\n): void {\n // No `useCallback` needed: both subscription hooks stabilize the handler\n // themselves (#4694), so a caller passing an unmemoized `refetch` — which\n // `useQuery` returned on every render before #4693 — no longer resubscribes.\n useDataSubscriptionCallback(object, (_event: DataEvent) => refetch(), options);\n\n // A bulk event carries only a count, so when `options.recordId` narrows this\n // hook to one record there is no way to tell whether that record was in the\n // match set. Refetch anyway: a redundant query is cheap, and the alternative\n // is showing a record that a predicate write already changed.\n useBulkDataSubscriptionCallback(object, (_event: BulkDataEvent) => refetch());\n}\n"],"mappings":"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","names":["import_react","import_react","error","import_react","error","import_react"]}
|