@objectstack/client-react 7.3.0 → 7.4.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/dist/index.d.mts CHANGED
@@ -13,9 +13,23 @@ import { DataEvent, MetadataEvent } from '@objectstack/spec/api';
13
13
 
14
14
  interface ObjectStackProviderProps {
15
15
  client: ObjectStackClient;
16
+ /**
17
+ * Active UI locale (BCP-47, e.g. `'zh-CN'`). Keep this in sync with your
18
+ * language switcher — the provider pushes it into the client (so requests
19
+ * carry `Accept-Language`) and metadata hooks (`useObject`, `useView`,
20
+ * `useMetadata`) re-fetch when it changes, so switching language relabels
21
+ * the UI without a page refresh (issue #1319).
22
+ */
23
+ locale?: string;
16
24
  children: ReactNode;
17
25
  }
18
26
  declare const ObjectStackContext: React.Context<ObjectStackClient | null>;
27
+ /**
28
+ * Carries the active UI locale separately from the client so existing
29
+ * `useContext(ObjectStackContext)` consumers keep receiving the bare client
30
+ * (no breaking change to that context's shape).
31
+ */
32
+ declare const ObjectStackLocaleContext: React.Context<string | undefined>;
19
33
  /**
20
34
  * Provider component that makes ObjectStackClient available to all child components
21
35
  *
@@ -25,14 +39,20 @@ declare const ObjectStackContext: React.Context<ObjectStackClient | null>;
25
39
  *
26
40
  * function App() {
27
41
  * return (
28
- * <ObjectStackProvider client={client}>
42
+ * <ObjectStackProvider client={client} locale={language}>
29
43
  * <YourComponents />
30
44
  * </ObjectStackProvider>
31
45
  * );
32
46
  * }
33
47
  * ```
34
48
  */
35
- declare function ObjectStackProvider({ client, children }: ObjectStackProviderProps): React.JSX.Element;
49
+ declare function ObjectStackProvider({ client, locale, children }: ObjectStackProviderProps): React.JSX.Element;
50
+ /**
51
+ * Hook to read the active UI locale provided to {@link ObjectStackProvider}.
52
+ * Returns `undefined` when no locale was supplied. Metadata hooks fold this
53
+ * into their fetch dependencies so a locale change triggers a re-fetch.
54
+ */
55
+ declare function useObjectStackLocale(): string | undefined;
36
56
  /**
37
57
  * Hook to access the ObjectStackClient instance from context
38
58
  *
@@ -568,4 +588,4 @@ declare function useAutoRefresh(object: string, refetch: () => void, options?: {
568
588
  recordId?: string;
569
589
  }): void;
570
590
 
571
- export { ObjectStackContext, ObjectStackProvider, type ObjectStackProviderProps, type UseInfiniteQueryOptions, type UseInfiniteQueryResult, type UseMetadataOptions, type UseMetadataResult, type UseMutationOptions, type UseMutationResult, type UsePaginationOptions, type UsePaginationResult, type UseQueryOptions, type UseQueryResult, useAutoRefresh, useClient, useDataSubscription, useDataSubscriptionCallback, useFields, useInfiniteQuery, useMetadata, useMetadataSubscription, useMetadataSubscriptionCallback, useMutation, useObject, usePagination, useQuery, useRealtimeConnection, useView };
591
+ export { ObjectStackContext, ObjectStackLocaleContext, ObjectStackProvider, type ObjectStackProviderProps, type UseInfiniteQueryOptions, type UseInfiniteQueryResult, type UseMetadataOptions, type UseMetadataResult, type UseMutationOptions, type UseMutationResult, type UsePaginationOptions, type UsePaginationResult, type UseQueryOptions, type UseQueryResult, useAutoRefresh, useClient, useDataSubscription, useDataSubscriptionCallback, useFields, useInfiniteQuery, useMetadata, useMetadataSubscription, useMetadataSubscriptionCallback, useMutation, useObject, useObjectStackLocale, usePagination, useQuery, useRealtimeConnection, useView };
package/dist/index.d.ts CHANGED
@@ -13,9 +13,23 @@ import { DataEvent, MetadataEvent } from '@objectstack/spec/api';
13
13
 
14
14
  interface ObjectStackProviderProps {
15
15
  client: ObjectStackClient;
16
+ /**
17
+ * Active UI locale (BCP-47, e.g. `'zh-CN'`). Keep this in sync with your
18
+ * language switcher — the provider pushes it into the client (so requests
19
+ * carry `Accept-Language`) and metadata hooks (`useObject`, `useView`,
20
+ * `useMetadata`) re-fetch when it changes, so switching language relabels
21
+ * the UI without a page refresh (issue #1319).
22
+ */
23
+ locale?: string;
16
24
  children: ReactNode;
17
25
  }
18
26
  declare const ObjectStackContext: React.Context<ObjectStackClient | null>;
27
+ /**
28
+ * Carries the active UI locale separately from the client so existing
29
+ * `useContext(ObjectStackContext)` consumers keep receiving the bare client
30
+ * (no breaking change to that context's shape).
31
+ */
32
+ declare const ObjectStackLocaleContext: React.Context<string | undefined>;
19
33
  /**
20
34
  * Provider component that makes ObjectStackClient available to all child components
21
35
  *
@@ -25,14 +39,20 @@ declare const ObjectStackContext: React.Context<ObjectStackClient | null>;
25
39
  *
26
40
  * function App() {
27
41
  * return (
28
- * <ObjectStackProvider client={client}>
42
+ * <ObjectStackProvider client={client} locale={language}>
29
43
  * <YourComponents />
30
44
  * </ObjectStackProvider>
31
45
  * );
32
46
  * }
33
47
  * ```
34
48
  */
35
- declare function ObjectStackProvider({ client, children }: ObjectStackProviderProps): React.JSX.Element;
49
+ declare function ObjectStackProvider({ client, locale, children }: ObjectStackProviderProps): React.JSX.Element;
50
+ /**
51
+ * Hook to read the active UI locale provided to {@link ObjectStackProvider}.
52
+ * Returns `undefined` when no locale was supplied. Metadata hooks fold this
53
+ * into their fetch dependencies so a locale change triggers a re-fetch.
54
+ */
55
+ declare function useObjectStackLocale(): string | undefined;
36
56
  /**
37
57
  * Hook to access the ObjectStackClient instance from context
38
58
  *
@@ -568,4 +588,4 @@ declare function useAutoRefresh(object: string, refetch: () => void, options?: {
568
588
  recordId?: string;
569
589
  }): void;
570
590
 
571
- export { ObjectStackContext, ObjectStackProvider, type ObjectStackProviderProps, type UseInfiniteQueryOptions, type UseInfiniteQueryResult, type UseMetadataOptions, type UseMetadataResult, type UseMutationOptions, type UseMutationResult, type UsePaginationOptions, type UsePaginationResult, type UseQueryOptions, type UseQueryResult, useAutoRefresh, useClient, useDataSubscription, useDataSubscriptionCallback, useFields, useInfiniteQuery, useMetadata, useMetadataSubscription, useMetadataSubscriptionCallback, useMutation, useObject, usePagination, useQuery, useRealtimeConnection, useView };
591
+ export { ObjectStackContext, ObjectStackLocaleContext, ObjectStackProvider, type ObjectStackProviderProps, type UseInfiniteQueryOptions, type UseInfiniteQueryResult, type UseMetadataOptions, type UseMetadataResult, type UseMutationOptions, type UseMutationResult, type UsePaginationOptions, type UsePaginationResult, type UseQueryOptions, type UseQueryResult, useAutoRefresh, useClient, useDataSubscription, useDataSubscriptionCallback, useFields, useInfiniteQuery, useMetadata, useMetadataSubscription, useMetadataSubscriptionCallback, useMutation, useObject, useObjectStackLocale, usePagination, useQuery, useRealtimeConnection, useView };
package/dist/index.js CHANGED
@@ -32,6 +32,7 @@ var index_exports = {};
32
32
  __export(index_exports, {
33
33
  ObjectStackClient: () => import_client.ObjectStackClient,
34
34
  ObjectStackContext: () => ObjectStackContext,
35
+ ObjectStackLocaleContext: () => ObjectStackLocaleContext,
35
36
  ObjectStackProvider: () => ObjectStackProvider,
36
37
  useAutoRefresh: () => useAutoRefresh,
37
38
  useClient: () => useClient,
@@ -44,6 +45,7 @@ __export(index_exports, {
44
45
  useMetadataSubscriptionCallback: () => useMetadataSubscriptionCallback,
45
46
  useMutation: () => useMutation,
46
47
  useObject: () => useObject,
48
+ useObjectStackLocale: () => useObjectStackLocale,
47
49
  usePagination: () => usePagination,
48
50
  useQuery: () => useQuery,
49
51
  useRealtimeConnection: () => useRealtimeConnection,
@@ -55,8 +57,17 @@ module.exports = __toCommonJS(index_exports);
55
57
  var React = __toESM(require("react"));
56
58
  var import_react = require("react");
57
59
  var ObjectStackContext = (0, import_react.createContext)(null);
58
- function ObjectStackProvider({ client, children }) {
59
- return /* @__PURE__ */ React.createElement(ObjectStackContext.Provider, { value: client }, children);
60
+ var ObjectStackLocaleContext = (0, import_react.createContext)(void 0);
61
+ function ObjectStackProvider({ client, locale, children }) {
62
+ const synced = (0, import_react.useRef)(null);
63
+ if (synced.current?.client !== client || synced.current?.locale !== locale) {
64
+ synced.current = { client, locale };
65
+ client.setLocale?.(locale);
66
+ }
67
+ return /* @__PURE__ */ React.createElement(ObjectStackContext.Provider, { value: client }, /* @__PURE__ */ React.createElement(ObjectStackLocaleContext.Provider, { value: locale }, children));
68
+ }
69
+ function useObjectStackLocale() {
70
+ return (0, import_react.useContext)(ObjectStackLocaleContext);
60
71
  }
61
72
  function useClient() {
62
73
  const client = (0, import_react.useContext)(ObjectStackContext);
@@ -367,6 +378,7 @@ function useInfiniteQuery(object, options = {}) {
367
378
  var import_react3 = require("react");
368
379
  function useObject(objectName, options = {}) {
369
380
  const client = useClient();
381
+ const locale = useObjectStackLocale();
370
382
  const [data, setData] = (0, import_react3.useState)(null);
371
383
  const [isLoading, setIsLoading] = (0, import_react3.useState)(true);
372
384
  const [error, setError] = (0, import_react3.useState)(null);
@@ -412,7 +424,7 @@ function useObject(objectName, options = {}) {
412
424
  } finally {
413
425
  setIsLoading(false);
414
426
  }
415
- }, [client, objectName, enabled, useCache, ifNoneMatch, ifModifiedSince, etag, data, onSuccess, onError]);
427
+ }, [client, objectName, locale, enabled, useCache, ifNoneMatch, ifModifiedSince, etag, data, onSuccess, onError]);
416
428
  (0, import_react3.useEffect)(() => {
417
429
  fetchMetadata();
418
430
  }, [fetchMetadata]);
@@ -430,6 +442,7 @@ function useObject(objectName, options = {}) {
430
442
  }
431
443
  function useView(objectName, viewType = "list", options = {}) {
432
444
  const client = useClient();
445
+ const locale = useObjectStackLocale();
433
446
  const [data, setData] = (0, import_react3.useState)(null);
434
447
  const [isLoading, setIsLoading] = (0, import_react3.useState)(true);
435
448
  const [error, setError] = (0, import_react3.useState)(null);
@@ -449,7 +462,7 @@ function useView(objectName, viewType = "list", options = {}) {
449
462
  } finally {
450
463
  setIsLoading(false);
451
464
  }
452
- }, [client, objectName, viewType, enabled, onSuccess, onError]);
465
+ }, [client, objectName, viewType, locale, enabled, onSuccess, onError]);
453
466
  (0, import_react3.useEffect)(() => {
454
467
  fetchView();
455
468
  }, [fetchView]);
@@ -477,6 +490,7 @@ function useFields(objectName, options = {}) {
477
490
  }
478
491
  function useMetadata(fetcher, options = {}) {
479
492
  const client = useClient();
493
+ const locale = useObjectStackLocale();
480
494
  const [data, setData] = (0, import_react3.useState)(null);
481
495
  const [isLoading, setIsLoading] = (0, import_react3.useState)(true);
482
496
  const [error, setError] = (0, import_react3.useState)(null);
@@ -496,7 +510,7 @@ function useMetadata(fetcher, options = {}) {
496
510
  } finally {
497
511
  setIsLoading(false);
498
512
  }
499
- }, [client, fetcher, enabled, onSuccess, onError]);
513
+ }, [client, fetcher, locale, enabled, onSuccess, onError]);
500
514
  (0, import_react3.useEffect)(() => {
501
515
  fetchMetadata();
502
516
  }, [fetchMetadata]);
@@ -599,6 +613,7 @@ var import_client = require("@objectstack/client");
599
613
  0 && (module.exports = {
600
614
  ObjectStackClient,
601
615
  ObjectStackContext,
616
+ ObjectStackLocaleContext,
602
617
  ObjectStackProvider,
603
618
  useAutoRefresh,
604
619
  useClient,
@@ -611,6 +626,7 @@ var import_client = require("@objectstack/client");
611
626
  useMetadataSubscriptionCallback,
612
627
  useMutation,
613
628
  useObject,
629
+ useObjectStackLocale,
614
630
  usePagination,
615
631
  useQuery,
616
632
  useRealtimeConnection,
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.tsx","../src/context.tsx","../src/data-hooks.tsx","../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 useClient,\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 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, ReactNode } from 'react';\nimport { ObjectStackClient } from '@objectstack/client';\n\nexport interface ObjectStackProviderProps {\n client: ObjectStackClient;\n children: ReactNode;\n}\n\nexport const ObjectStackContext = createContext<ObjectStackClient | null>(null);\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}>\n * <YourComponents />\n * </ObjectStackProvider>\n * );\n * }\n * ```\n */\nexport function ObjectStackProvider({ client, children }: ObjectStackProviderProps) {\n return (\n <ObjectStackContext.Provider value={client}>\n {children}\n </ObjectStackContext.Provider>\n );\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';\n\n/**\n * Query options for useQuery hook\n *\n * Supports both **canonical** (Spec protocol) and **legacy** field names.\n * Canonical names are preferred; legacy names are accepted for backward\n * compatibility and will be removed in a future major release.\n *\n * | Canonical | Legacy (deprecated) |\n * |-----------|---------------------|\n * | `where` | `filters` |\n * | `fields` | `select` |\n * | `orderBy` | `sort` |\n * | `limit` | `top` |\n * | `offset` | `skip` |\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 // ── Legacy field names (deprecated) ────────────────────────────────\n /** @deprecated Use `fields` instead. */\n select?: string[];\n /** @deprecated Use `where` instead. */\n filters?: FilterCondition;\n /** @deprecated Use `orderBy` instead. */\n sort?: string | string[];\n /** @deprecated Use `limit` instead. */\n top?: number;\n /** @deprecated Use `offset` instead. */\n skip?: number;\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 // Legacy names (deprecated fallbacks)\n select, filters, sort, top, skip,\n enabled = true,\n refetchInterval,\n onSuccess,\n onError\n } = options;\n\n // Resolve canonical vs legacy: canonical wins when both are provided\n const resolvedFields = fields ?? select;\n const resolvedWhere = where ?? filters;\n const resolvedSort = orderBy ?? sort;\n const resolvedLimit = limit ?? top;\n const resolvedOffset = offset ?? skip;\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 onSuccess?.(result);\n } catch (err) {\n const error = err instanceof Error ? err : new Error('Query failed');\n setError(error);\n onError?.(error);\n } finally {\n setIsLoading(false);\n setIsRefetching(false);\n }\n }, [client, object, query, resolvedFields, resolvedWhere, resolvedSort, resolvedLimit, resolvedOffset, enabled, onSuccess, onError]);\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>, 'top' | 'skip' | '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>, 'skip' | '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 // Legacy names (deprecated fallbacks)\n select, filters, sort,\n enabled = true,\n onSuccess,\n onError\n } = options;\n\n // Resolve canonical vs legacy: canonical wins\n const resolvedFields = fields ?? select;\n const resolvedWhere = where ?? filters;\n const resolvedSort = orderBy ?? sort;\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 onSuccess?.(result);\n } catch (err) {\n const error = err instanceof Error ? err : new Error('Query failed');\n setError(error);\n onError?.(error);\n } finally {\n setIsLoading(false);\n setIsFetchingNextPage(false);\n }\n }, [client, object, query, resolvedFields, resolvedWhere, resolvedSort, pageSize, onSuccess, onError]);\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 * Metadata Hooks\n * \n * React hooks for accessing ObjectStack metadata (schemas, views, fields)\n */\n\nimport { useState, useEffect, useCallback } from 'react';\nimport { useClient } from './context';\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 * @example\n * ```tsx\n * function ObjectSchemaViewer({ objectName }: { objectName: string }) {\n * const { data: schema, isLoading, error } = useObject(objectName);\n * \n * if (isLoading) return <div>Loading schema...</div>;\n * if (error) return <div>Error: {error.message}</div>;\n * \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 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 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 // Use cached metadata endpoint\n const result = await client.meta.getCached(objectName, {\n ifNoneMatch: ifNoneMatch || etag,\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 onSuccess?.(result.data || data);\n } else {\n // Direct fetch without cache\n const result = await client.meta.getItem('object', objectName);\n setData(result);\n onSuccess?.(result);\n }\n } catch (err) {\n const error = err instanceof Error ? err : new Error('Failed to fetch object metadata');\n setError(error);\n onError?.(error);\n } finally {\n setIsLoading(false);\n }\n }, [client, objectName, enabled, useCache, ifNoneMatch, ifModifiedSince, etag, data, onSuccess, onError]);\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 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 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 onSuccess?.(result);\n } catch (err) {\n const error = err instanceof Error ? err : new Error('Failed to fetch view configuration');\n setError(error);\n onError?.(error);\n } finally {\n setIsLoading(false);\n }\n }, [client, objectName, viewType, enabled, onSuccess, onError]);\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 const fields = objectResult.data?.fields\n ? Object.entries(objectResult.data.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 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 const fetchMetadata = useCallback(async () => {\n if (!enabled) return;\n\n try {\n setIsLoading(true);\n setError(null);\n\n const result = await fetcher(client);\n setData(result);\n onSuccess?.(result);\n } catch (err) {\n const error = err instanceof Error ? err : new Error('Failed to fetch metadata');\n setError(error);\n onError?.(error);\n } finally {\n setIsLoading(false);\n }\n }, [client, fetcher, enabled, onSuccess, onError]);\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, useCallback } from 'react';\nimport type { MetadataEvent, DataEvent } from '@objectstack/spec/api';\nimport { useClient } from './context';\n\n/**\n * Hook to subscribe to metadata events\n *\n * @param type - Metadata type to subscribe to (e.g., 'object', 'view', 'agent')\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: string,\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\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: string,\n callback: (event: MetadataEvent) => void,\n options?: { packageId?: string }\n): void {\n const client = useClient();\n\n useEffect(() => {\n if (!client) return;\n\n const unsubscribe = client.events.subscribeMetadata(\n type,\n callback,\n options\n );\n\n return () => {\n unsubscribe();\n };\n }, [client, type, callback, 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\n useEffect(() => {\n if (!client) return;\n\n const unsubscribe = client.events.subscribeData(\n object,\n callback,\n options\n );\n\n return () => {\n unsubscribe();\n };\n }, [client, object, callback, options?.recordId]);\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 * @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 const handleEvent = useCallback((_event: DataEvent) => {\n // Refetch on any data change\n refetch();\n }, [refetch]);\n\n useDataSubscriptionCallback(object, handleEvent, options);\n}\n"],"mappings":"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","names":["import_react","error","import_react","error","import_react"]}
1
+ {"version":3,"sources":["../src/index.tsx","../src/context.tsx","../src/data-hooks.tsx","../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 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';\n\n/**\n * Query options for useQuery hook\n *\n * Supports both **canonical** (Spec protocol) and **legacy** field names.\n * Canonical names are preferred; legacy names are accepted for backward\n * compatibility and will be removed in a future major release.\n *\n * | Canonical | Legacy (deprecated) |\n * |-----------|---------------------|\n * | `where` | `filters` |\n * | `fields` | `select` |\n * | `orderBy` | `sort` |\n * | `limit` | `top` |\n * | `offset` | `skip` |\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 // ── Legacy field names (deprecated) ────────────────────────────────\n /** @deprecated Use `fields` instead. */\n select?: string[];\n /** @deprecated Use `where` instead. */\n filters?: FilterCondition;\n /** @deprecated Use `orderBy` instead. */\n sort?: string | string[];\n /** @deprecated Use `limit` instead. */\n top?: number;\n /** @deprecated Use `offset` instead. */\n skip?: number;\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 // Legacy names (deprecated fallbacks)\n select, filters, sort, top, skip,\n enabled = true,\n refetchInterval,\n onSuccess,\n onError\n } = options;\n\n // Resolve canonical vs legacy: canonical wins when both are provided\n const resolvedFields = fields ?? select;\n const resolvedWhere = where ?? filters;\n const resolvedSort = orderBy ?? sort;\n const resolvedLimit = limit ?? top;\n const resolvedOffset = offset ?? skip;\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 onSuccess?.(result);\n } catch (err) {\n const error = err instanceof Error ? err : new Error('Query failed');\n setError(error);\n onError?.(error);\n } finally {\n setIsLoading(false);\n setIsRefetching(false);\n }\n }, [client, object, query, resolvedFields, resolvedWhere, resolvedSort, resolvedLimit, resolvedOffset, enabled, onSuccess, onError]);\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>, 'top' | 'skip' | '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>, 'skip' | '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 // Legacy names (deprecated fallbacks)\n select, filters, sort,\n enabled = true,\n onSuccess,\n onError\n } = options;\n\n // Resolve canonical vs legacy: canonical wins\n const resolvedFields = fields ?? select;\n const resolvedWhere = where ?? filters;\n const resolvedSort = orderBy ?? sort;\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 onSuccess?.(result);\n } catch (err) {\n const error = err instanceof Error ? err : new Error('Query failed');\n setError(error);\n onError?.(error);\n } finally {\n setIsLoading(false);\n setIsFetchingNextPage(false);\n }\n }, [client, object, query, resolvedFields, resolvedWhere, resolvedSort, pageSize, onSuccess, onError]);\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 * Metadata Hooks\n * \n * React hooks for accessing ObjectStack metadata (schemas, views, fields)\n */\n\nimport { useState, useEffect, useCallback } from 'react';\nimport { useClient, useObjectStackLocale } from './context';\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 * @example\n * ```tsx\n * function ObjectSchemaViewer({ objectName }: { objectName: string }) {\n * const { data: schema, isLoading, error } = useObject(objectName);\n * \n * if (isLoading) return <div>Loading schema...</div>;\n * if (error) return <div>Error: {error.message}</div>;\n * \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 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 // Use cached metadata endpoint\n const result = await client.meta.getCached(objectName, {\n ifNoneMatch: ifNoneMatch || etag,\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 onSuccess?.(result.data || data);\n } else {\n // Direct fetch without cache\n const result = await client.meta.getItem('object', objectName);\n setData(result);\n onSuccess?.(result);\n }\n } catch (err) {\n const error = err instanceof Error ? err : new Error('Failed to fetch object metadata');\n setError(error);\n onError?.(error);\n } finally {\n setIsLoading(false);\n }\n }, [client, objectName, locale, enabled, useCache, ifNoneMatch, ifModifiedSince, etag, data, onSuccess, onError]);\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 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 onSuccess?.(result);\n } catch (err) {\n const error = err instanceof Error ? err : new Error('Failed to fetch view configuration');\n setError(error);\n onError?.(error);\n } finally {\n setIsLoading(false);\n }\n }, [client, objectName, viewType, locale, enabled, onSuccess, onError]);\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 const fields = objectResult.data?.fields\n ? Object.entries(objectResult.data.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 const fetchMetadata = useCallback(async () => {\n if (!enabled) return;\n\n try {\n setIsLoading(true);\n setError(null);\n\n const result = await fetcher(client);\n setData(result);\n onSuccess?.(result);\n } catch (err) {\n const error = err instanceof Error ? err : new Error('Failed to fetch metadata');\n setError(error);\n onError?.(error);\n } finally {\n setIsLoading(false);\n }\n }, [client, fetcher, locale, enabled, onSuccess, onError]);\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, useCallback } from 'react';\nimport type { MetadataEvent, DataEvent } from '@objectstack/spec/api';\nimport { useClient } from './context';\n\n/**\n * Hook to subscribe to metadata events\n *\n * @param type - Metadata type to subscribe to (e.g., 'object', 'view', 'agent')\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: string,\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\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: string,\n callback: (event: MetadataEvent) => void,\n options?: { packageId?: string }\n): void {\n const client = useClient();\n\n useEffect(() => {\n if (!client) return;\n\n const unsubscribe = client.events.subscribeMetadata(\n type,\n callback,\n options\n );\n\n return () => {\n unsubscribe();\n };\n }, [client, type, callback, 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\n useEffect(() => {\n if (!client) return;\n\n const unsubscribe = client.events.subscribeData(\n object,\n callback,\n options\n );\n\n return () => {\n unsubscribe();\n };\n }, [client, object, callback, options?.recordId]);\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 * @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 const handleEvent = useCallback((_event: DataEvent) => {\n // Refetch on any data change\n refetch();\n }, [refetch]);\n\n useDataSubscriptionCallback(object, handleEvent, options);\n}\n"],"mappings":"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","names":["import_react","error","import_react","error","import_react"]}
package/dist/index.mjs CHANGED
@@ -1,9 +1,18 @@
1
1
  // src/context.tsx
2
2
  import * as React from "react";
3
- import { createContext, useContext } from "react";
3
+ import { createContext, useContext, useRef } from "react";
4
4
  var ObjectStackContext = createContext(null);
5
- function ObjectStackProvider({ client, children }) {
6
- return /* @__PURE__ */ React.createElement(ObjectStackContext.Provider, { value: client }, children);
5
+ var ObjectStackLocaleContext = createContext(void 0);
6
+ function ObjectStackProvider({ client, locale, children }) {
7
+ const synced = useRef(null);
8
+ if (synced.current?.client !== client || synced.current?.locale !== locale) {
9
+ synced.current = { client, locale };
10
+ client.setLocale?.(locale);
11
+ }
12
+ return /* @__PURE__ */ React.createElement(ObjectStackContext.Provider, { value: client }, /* @__PURE__ */ React.createElement(ObjectStackLocaleContext.Provider, { value: locale }, children));
13
+ }
14
+ function useObjectStackLocale() {
15
+ return useContext(ObjectStackLocaleContext);
7
16
  }
8
17
  function useClient() {
9
18
  const client = useContext(ObjectStackContext);
@@ -16,14 +25,14 @@ function useClient() {
16
25
  }
17
26
 
18
27
  // src/data-hooks.tsx
19
- import { useState, useEffect, useCallback, useRef } from "react";
28
+ import { useState, useEffect, useCallback, useRef as useRef2 } from "react";
20
29
  function useQuery(object, options = {}) {
21
30
  const client = useClient();
22
31
  const [data, setData] = useState(null);
23
32
  const [isLoading, setIsLoading] = useState(true);
24
33
  const [isRefetching, setIsRefetching] = useState(false);
25
34
  const [error, setError] = useState(null);
26
- const intervalRef = useRef(void 0);
35
+ const intervalRef = useRef2(void 0);
27
36
  const {
28
37
  query,
29
38
  // Canonical names take precedence over legacy names
@@ -314,6 +323,7 @@ function useInfiniteQuery(object, options = {}) {
314
323
  import { useState as useState2, useEffect as useEffect2, useCallback as useCallback2 } from "react";
315
324
  function useObject(objectName, options = {}) {
316
325
  const client = useClient();
326
+ const locale = useObjectStackLocale();
317
327
  const [data, setData] = useState2(null);
318
328
  const [isLoading, setIsLoading] = useState2(true);
319
329
  const [error, setError] = useState2(null);
@@ -359,7 +369,7 @@ function useObject(objectName, options = {}) {
359
369
  } finally {
360
370
  setIsLoading(false);
361
371
  }
362
- }, [client, objectName, enabled, useCache, ifNoneMatch, ifModifiedSince, etag, data, onSuccess, onError]);
372
+ }, [client, objectName, locale, enabled, useCache, ifNoneMatch, ifModifiedSince, etag, data, onSuccess, onError]);
363
373
  useEffect2(() => {
364
374
  fetchMetadata();
365
375
  }, [fetchMetadata]);
@@ -377,6 +387,7 @@ function useObject(objectName, options = {}) {
377
387
  }
378
388
  function useView(objectName, viewType = "list", options = {}) {
379
389
  const client = useClient();
390
+ const locale = useObjectStackLocale();
380
391
  const [data, setData] = useState2(null);
381
392
  const [isLoading, setIsLoading] = useState2(true);
382
393
  const [error, setError] = useState2(null);
@@ -396,7 +407,7 @@ function useView(objectName, viewType = "list", options = {}) {
396
407
  } finally {
397
408
  setIsLoading(false);
398
409
  }
399
- }, [client, objectName, viewType, enabled, onSuccess, onError]);
410
+ }, [client, objectName, viewType, locale, enabled, onSuccess, onError]);
400
411
  useEffect2(() => {
401
412
  fetchView();
402
413
  }, [fetchView]);
@@ -424,6 +435,7 @@ function useFields(objectName, options = {}) {
424
435
  }
425
436
  function useMetadata(fetcher, options = {}) {
426
437
  const client = useClient();
438
+ const locale = useObjectStackLocale();
427
439
  const [data, setData] = useState2(null);
428
440
  const [isLoading, setIsLoading] = useState2(true);
429
441
  const [error, setError] = useState2(null);
@@ -443,7 +455,7 @@ function useMetadata(fetcher, options = {}) {
443
455
  } finally {
444
456
  setIsLoading(false);
445
457
  }
446
- }, [client, fetcher, enabled, onSuccess, onError]);
458
+ }, [client, fetcher, locale, enabled, onSuccess, onError]);
447
459
  useEffect2(() => {
448
460
  fetchMetadata();
449
461
  }, [fetchMetadata]);
@@ -545,6 +557,7 @@ import { ObjectStackClient } from "@objectstack/client";
545
557
  export {
546
558
  ObjectStackClient,
547
559
  ObjectStackContext,
560
+ ObjectStackLocaleContext,
548
561
  ObjectStackProvider,
549
562
  useAutoRefresh,
550
563
  useClient,
@@ -557,6 +570,7 @@ export {
557
570
  useMetadataSubscriptionCallback,
558
571
  useMutation,
559
572
  useObject,
573
+ useObjectStackLocale,
560
574
  usePagination,
561
575
  useQuery,
562
576
  useRealtimeConnection,
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/context.tsx","../src/data-hooks.tsx","../src/metadata-hooks.tsx","../src/realtime-hooks.tsx","../src/index.tsx"],"sourcesContent":["// 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, ReactNode } from 'react';\nimport { ObjectStackClient } from '@objectstack/client';\n\nexport interface ObjectStackProviderProps {\n client: ObjectStackClient;\n children: ReactNode;\n}\n\nexport const ObjectStackContext = createContext<ObjectStackClient | null>(null);\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}>\n * <YourComponents />\n * </ObjectStackProvider>\n * );\n * }\n * ```\n */\nexport function ObjectStackProvider({ client, children }: ObjectStackProviderProps) {\n return (\n <ObjectStackContext.Provider value={client}>\n {children}\n </ObjectStackContext.Provider>\n );\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';\n\n/**\n * Query options for useQuery hook\n *\n * Supports both **canonical** (Spec protocol) and **legacy** field names.\n * Canonical names are preferred; legacy names are accepted for backward\n * compatibility and will be removed in a future major release.\n *\n * | Canonical | Legacy (deprecated) |\n * |-----------|---------------------|\n * | `where` | `filters` |\n * | `fields` | `select` |\n * | `orderBy` | `sort` |\n * | `limit` | `top` |\n * | `offset` | `skip` |\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 // ── Legacy field names (deprecated) ────────────────────────────────\n /** @deprecated Use `fields` instead. */\n select?: string[];\n /** @deprecated Use `where` instead. */\n filters?: FilterCondition;\n /** @deprecated Use `orderBy` instead. */\n sort?: string | string[];\n /** @deprecated Use `limit` instead. */\n top?: number;\n /** @deprecated Use `offset` instead. */\n skip?: number;\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 // Legacy names (deprecated fallbacks)\n select, filters, sort, top, skip,\n enabled = true,\n refetchInterval,\n onSuccess,\n onError\n } = options;\n\n // Resolve canonical vs legacy: canonical wins when both are provided\n const resolvedFields = fields ?? select;\n const resolvedWhere = where ?? filters;\n const resolvedSort = orderBy ?? sort;\n const resolvedLimit = limit ?? top;\n const resolvedOffset = offset ?? skip;\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 onSuccess?.(result);\n } catch (err) {\n const error = err instanceof Error ? err : new Error('Query failed');\n setError(error);\n onError?.(error);\n } finally {\n setIsLoading(false);\n setIsRefetching(false);\n }\n }, [client, object, query, resolvedFields, resolvedWhere, resolvedSort, resolvedLimit, resolvedOffset, enabled, onSuccess, onError]);\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>, 'top' | 'skip' | '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>, 'skip' | '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 // Legacy names (deprecated fallbacks)\n select, filters, sort,\n enabled = true,\n onSuccess,\n onError\n } = options;\n\n // Resolve canonical vs legacy: canonical wins\n const resolvedFields = fields ?? select;\n const resolvedWhere = where ?? filters;\n const resolvedSort = orderBy ?? sort;\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 onSuccess?.(result);\n } catch (err) {\n const error = err instanceof Error ? err : new Error('Query failed');\n setError(error);\n onError?.(error);\n } finally {\n setIsLoading(false);\n setIsFetchingNextPage(false);\n }\n }, [client, object, query, resolvedFields, resolvedWhere, resolvedSort, pageSize, onSuccess, onError]);\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 * Metadata Hooks\n * \n * React hooks for accessing ObjectStack metadata (schemas, views, fields)\n */\n\nimport { useState, useEffect, useCallback } from 'react';\nimport { useClient } from './context';\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 * @example\n * ```tsx\n * function ObjectSchemaViewer({ objectName }: { objectName: string }) {\n * const { data: schema, isLoading, error } = useObject(objectName);\n * \n * if (isLoading) return <div>Loading schema...</div>;\n * if (error) return <div>Error: {error.message}</div>;\n * \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 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 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 // Use cached metadata endpoint\n const result = await client.meta.getCached(objectName, {\n ifNoneMatch: ifNoneMatch || etag,\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 onSuccess?.(result.data || data);\n } else {\n // Direct fetch without cache\n const result = await client.meta.getItem('object', objectName);\n setData(result);\n onSuccess?.(result);\n }\n } catch (err) {\n const error = err instanceof Error ? err : new Error('Failed to fetch object metadata');\n setError(error);\n onError?.(error);\n } finally {\n setIsLoading(false);\n }\n }, [client, objectName, enabled, useCache, ifNoneMatch, ifModifiedSince, etag, data, onSuccess, onError]);\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 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 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 onSuccess?.(result);\n } catch (err) {\n const error = err instanceof Error ? err : new Error('Failed to fetch view configuration');\n setError(error);\n onError?.(error);\n } finally {\n setIsLoading(false);\n }\n }, [client, objectName, viewType, enabled, onSuccess, onError]);\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 const fields = objectResult.data?.fields\n ? Object.entries(objectResult.data.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 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 const fetchMetadata = useCallback(async () => {\n if (!enabled) return;\n\n try {\n setIsLoading(true);\n setError(null);\n\n const result = await fetcher(client);\n setData(result);\n onSuccess?.(result);\n } catch (err) {\n const error = err instanceof Error ? err : new Error('Failed to fetch metadata');\n setError(error);\n onError?.(error);\n } finally {\n setIsLoading(false);\n }\n }, [client, fetcher, enabled, onSuccess, onError]);\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, useCallback } from 'react';\nimport type { MetadataEvent, DataEvent } from '@objectstack/spec/api';\nimport { useClient } from './context';\n\n/**\n * Hook to subscribe to metadata events\n *\n * @param type - Metadata type to subscribe to (e.g., 'object', 'view', 'agent')\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: string,\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\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: string,\n callback: (event: MetadataEvent) => void,\n options?: { packageId?: string }\n): void {\n const client = useClient();\n\n useEffect(() => {\n if (!client) return;\n\n const unsubscribe = client.events.subscribeMetadata(\n type,\n callback,\n options\n );\n\n return () => {\n unsubscribe();\n };\n }, [client, type, callback, 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\n useEffect(() => {\n if (!client) return;\n\n const unsubscribe = client.events.subscribeData(\n object,\n callback,\n options\n );\n\n return () => {\n unsubscribe();\n };\n }, [client, object, callback, options?.recordId]);\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 * @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 const handleEvent = useCallback((_event: DataEvent) => {\n // Refetch on any data change\n refetch();\n }, [refetch]);\n\n useDataSubscriptionCallback(object, handleEvent, options);\n}\n","// 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 useClient,\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 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"],"mappings":"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","names":["error","useState","useEffect","useCallback","useState","useCallback","error","useEffect","useEffect","useState","useCallback","useState","useEffect","useCallback"]}
1
+ {"version":3,"sources":["../src/context.tsx","../src/data-hooks.tsx","../src/metadata-hooks.tsx","../src/realtime-hooks.tsx","../src/index.tsx"],"sourcesContent":["// 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';\n\n/**\n * Query options for useQuery hook\n *\n * Supports both **canonical** (Spec protocol) and **legacy** field names.\n * Canonical names are preferred; legacy names are accepted for backward\n * compatibility and will be removed in a future major release.\n *\n * | Canonical | Legacy (deprecated) |\n * |-----------|---------------------|\n * | `where` | `filters` |\n * | `fields` | `select` |\n * | `orderBy` | `sort` |\n * | `limit` | `top` |\n * | `offset` | `skip` |\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 // ── Legacy field names (deprecated) ────────────────────────────────\n /** @deprecated Use `fields` instead. */\n select?: string[];\n /** @deprecated Use `where` instead. */\n filters?: FilterCondition;\n /** @deprecated Use `orderBy` instead. */\n sort?: string | string[];\n /** @deprecated Use `limit` instead. */\n top?: number;\n /** @deprecated Use `offset` instead. */\n skip?: number;\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 // Legacy names (deprecated fallbacks)\n select, filters, sort, top, skip,\n enabled = true,\n refetchInterval,\n onSuccess,\n onError\n } = options;\n\n // Resolve canonical vs legacy: canonical wins when both are provided\n const resolvedFields = fields ?? select;\n const resolvedWhere = where ?? filters;\n const resolvedSort = orderBy ?? sort;\n const resolvedLimit = limit ?? top;\n const resolvedOffset = offset ?? skip;\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 onSuccess?.(result);\n } catch (err) {\n const error = err instanceof Error ? err : new Error('Query failed');\n setError(error);\n onError?.(error);\n } finally {\n setIsLoading(false);\n setIsRefetching(false);\n }\n }, [client, object, query, resolvedFields, resolvedWhere, resolvedSort, resolvedLimit, resolvedOffset, enabled, onSuccess, onError]);\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>, 'top' | 'skip' | '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>, 'skip' | '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 // Legacy names (deprecated fallbacks)\n select, filters, sort,\n enabled = true,\n onSuccess,\n onError\n } = options;\n\n // Resolve canonical vs legacy: canonical wins\n const resolvedFields = fields ?? select;\n const resolvedWhere = where ?? filters;\n const resolvedSort = orderBy ?? sort;\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 onSuccess?.(result);\n } catch (err) {\n const error = err instanceof Error ? err : new Error('Query failed');\n setError(error);\n onError?.(error);\n } finally {\n setIsLoading(false);\n setIsFetchingNextPage(false);\n }\n }, [client, object, query, resolvedFields, resolvedWhere, resolvedSort, pageSize, onSuccess, onError]);\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 * Metadata Hooks\n * \n * React hooks for accessing ObjectStack metadata (schemas, views, fields)\n */\n\nimport { useState, useEffect, useCallback } from 'react';\nimport { useClient, useObjectStackLocale } from './context';\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 * @example\n * ```tsx\n * function ObjectSchemaViewer({ objectName }: { objectName: string }) {\n * const { data: schema, isLoading, error } = useObject(objectName);\n * \n * if (isLoading) return <div>Loading schema...</div>;\n * if (error) return <div>Error: {error.message}</div>;\n * \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 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 // Use cached metadata endpoint\n const result = await client.meta.getCached(objectName, {\n ifNoneMatch: ifNoneMatch || etag,\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 onSuccess?.(result.data || data);\n } else {\n // Direct fetch without cache\n const result = await client.meta.getItem('object', objectName);\n setData(result);\n onSuccess?.(result);\n }\n } catch (err) {\n const error = err instanceof Error ? err : new Error('Failed to fetch object metadata');\n setError(error);\n onError?.(error);\n } finally {\n setIsLoading(false);\n }\n }, [client, objectName, locale, enabled, useCache, ifNoneMatch, ifModifiedSince, etag, data, onSuccess, onError]);\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 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 onSuccess?.(result);\n } catch (err) {\n const error = err instanceof Error ? err : new Error('Failed to fetch view configuration');\n setError(error);\n onError?.(error);\n } finally {\n setIsLoading(false);\n }\n }, [client, objectName, viewType, locale, enabled, onSuccess, onError]);\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 const fields = objectResult.data?.fields\n ? Object.entries(objectResult.data.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 const fetchMetadata = useCallback(async () => {\n if (!enabled) return;\n\n try {\n setIsLoading(true);\n setError(null);\n\n const result = await fetcher(client);\n setData(result);\n onSuccess?.(result);\n } catch (err) {\n const error = err instanceof Error ? err : new Error('Failed to fetch metadata');\n setError(error);\n onError?.(error);\n } finally {\n setIsLoading(false);\n }\n }, [client, fetcher, locale, enabled, onSuccess, onError]);\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, useCallback } from 'react';\nimport type { MetadataEvent, DataEvent } from '@objectstack/spec/api';\nimport { useClient } from './context';\n\n/**\n * Hook to subscribe to metadata events\n *\n * @param type - Metadata type to subscribe to (e.g., 'object', 'view', 'agent')\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: string,\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\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: string,\n callback: (event: MetadataEvent) => void,\n options?: { packageId?: string }\n): void {\n const client = useClient();\n\n useEffect(() => {\n if (!client) return;\n\n const unsubscribe = client.events.subscribeMetadata(\n type,\n callback,\n options\n );\n\n return () => {\n unsubscribe();\n };\n }, [client, type, callback, 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\n useEffect(() => {\n if (!client) return;\n\n const unsubscribe = client.events.subscribeData(\n object,\n callback,\n options\n );\n\n return () => {\n unsubscribe();\n };\n }, [client, object, callback, options?.recordId]);\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 * @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 const handleEvent = useCallback((_event: DataEvent) => {\n // Refetch on any data change\n refetch();\n }, [refetch]);\n\n useDataSubscriptionCallback(object, handleEvent, options);\n}\n","// 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 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"],"mappings":"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","names":["useRef","useRef","error","useState","useEffect","useCallback","useState","useCallback","error","useEffect","useEffect","useState","useCallback","useState","useEffect","useCallback"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@objectstack/client-react",
3
- "version": "7.3.0",
3
+ "version": "7.4.0",
4
4
  "license": "Apache-2.0",
5
5
  "description": "React hooks for ObjectStack Client SDK",
6
6
  "main": "dist/index.js",
@@ -16,9 +16,9 @@
16
16
  "react": ">=18.0.0"
17
17
  },
18
18
  "dependencies": {
19
- "@objectstack/client": "7.3.0",
20
- "@objectstack/core": "7.3.0",
21
- "@objectstack/spec": "7.3.0"
19
+ "@objectstack/client": "7.4.0",
20
+ "@objectstack/core": "7.4.0",
21
+ "@objectstack/spec": "7.4.0"
22
22
  },
23
23
  "devDependencies": {
24
24
  "@types/react": "^19.2.15",