import * as React from 'react'; import { ReactNode } from 'react'; import { ObjectStackClient, PaginatedResult } from '@objectstack/client'; export { ClientConfig, ObjectStackClient } from '@objectstack/client'; import { QueryAST, FilterCondition } from '@objectstack/spec/data'; import { DataEvent, MetadataEvent } from '@objectstack/spec/api'; /** * ObjectStack React Context * * Provides ObjectStackClient instance to React components via Context API */ interface ObjectStackProviderProps { client: ObjectStackClient; /** * Active UI locale (BCP-47, e.g. `'zh-CN'`). Keep this in sync with your * language switcher — the provider pushes it into the client (so requests * carry `Accept-Language`) and metadata hooks (`useObject`, `useView`, * `useMetadata`) re-fetch when it changes, so switching language relabels * the UI without a page refresh (issue #1319). */ locale?: string; children: ReactNode; } declare const ObjectStackContext: React.Context; /** * Carries the active UI locale separately from the client so existing * `useContext(ObjectStackContext)` consumers keep receiving the bare client * (no breaking change to that context's shape). */ declare const ObjectStackLocaleContext: React.Context; /** * Provider component that makes ObjectStackClient available to all child components * * @example * ```tsx * const client = new ObjectStackClient({ baseUrl: 'http://localhost:3000' }); * * function App() { * return ( * * * * ); * } * ``` */ declare function ObjectStackProvider({ client, locale, children }: ObjectStackProviderProps): React.JSX.Element; /** * Hook to read the active UI locale provided to {@link ObjectStackProvider}. * Returns `undefined` when no locale was supplied. Metadata hooks fold this * into their fetch dependencies so a locale change triggers a re-fetch. */ declare function useObjectStackLocale(): string | undefined; /** * Hook to access the ObjectStackClient instance from context * * @throws Error if used outside of ObjectStackProvider * * @example * ```tsx * function MyComponent() { * const client = useClient(); * // Use client.data.find(), etc. * } * ``` */ declare function useClient(): ObjectStackClient; /** * Query options for useQuery hook * * Supports both **canonical** (Spec protocol) and **legacy** field names. * Canonical names are preferred; legacy names are accepted for backward * compatibility and will be removed in a future major release. * * | Canonical | Legacy (deprecated) | * |-----------|---------------------| * | `where` | `filters` | * | `fields` | `select` | * | `orderBy` | `sort` | * | `limit` | `top` | * | `offset` | `skip` | */ interface UseQueryOptions { /** Query AST or simplified query options */ query?: Partial; /** Filter conditions (WHERE clause). */ where?: FilterCondition; /** Fields to retrieve (SELECT clause). */ fields?: string[]; /** Sort definition (ORDER BY clause). */ orderBy?: string | string[]; /** Maximum number of records to return (LIMIT). */ limit?: number; /** Number of records to skip (OFFSET). */ offset?: number; /** @deprecated Use `fields` instead. */ select?: string[]; /** @deprecated Use `where` instead. */ filters?: FilterCondition; /** @deprecated Use `orderBy` instead. */ sort?: string | string[]; /** @deprecated Use `limit` instead. */ top?: number; /** @deprecated Use `offset` instead. */ skip?: number; /** Enable/disable automatic query execution */ enabled?: boolean; /** Refetch interval in milliseconds */ refetchInterval?: number; /** Callback on successful query */ onSuccess?: (data: PaginatedResult) => void; /** Callback on error */ onError?: (error: Error) => void; } /** * Query result for useQuery hook */ interface UseQueryResult { /** Query result data */ data: PaginatedResult | null; /** Loading state */ isLoading: boolean; /** Error state */ error: Error | null; /** Refetch the query */ refetch: () => Promise; /** Is currently refetching */ isRefetching: boolean; } /** * Hook for querying ObjectStack data with automatic caching and refetching * * @example * ```tsx * function TaskList() { * const { data, isLoading, error, refetch } = useQuery('todo_task', { * fields: ['id', 'subject', 'priority'], * orderBy: ['-created_at'], * limit: 20 * }); * * if (isLoading) return
Loading...
; * if (error) return
Error: {error.message}
; * * return ( *
* {data?.value.map(task => ( *
{task.subject}
* ))} *
* ); * } * ``` */ declare function useQuery(object: string, options?: UseQueryOptions): UseQueryResult; /** * Mutation options for useMutation hook */ interface UseMutationOptions { /** Callback on successful mutation */ onSuccess?: (data: TData, variables: TVariables) => void; /** Callback on error */ onError?: (error: Error, variables: TVariables) => void; /** Callback when mutation is settled (success or error) */ onSettled?: (data: TData | undefined, error: Error | null, variables: TVariables) => void; } /** * Mutation result for useMutation hook */ interface UseMutationResult { /** Execute the mutation */ mutate: (variables: TVariables) => Promise; /** Async version of mutate that throws errors */ mutateAsync: (variables: TVariables) => Promise; /** Mutation result data */ data: TData | null; /** Loading state */ isLoading: boolean; /** Error state */ error: Error | null; /** Reset mutation state */ reset: () => void; } /** * Hook for creating, updating, or deleting ObjectStack data * * @example * ```tsx * function CreateTaskForm() { * const { mutate, isLoading, error } = useMutation('todo_task', 'create', { * onSuccess: (data) => { * console.log('Task created:', data); * } * }); * * const handleSubmit = (formData) => { * mutate(formData); * }; * * return
...
; * } * ``` */ declare function useMutation(object: string, operation: 'create' | 'update' | 'delete' | 'createMany' | 'updateMany' | 'deleteMany', options?: UseMutationOptions): UseMutationResult; /** * Pagination options for usePagination hook */ interface UsePaginationOptions extends Omit, 'top' | 'skip' | 'limit' | 'offset'> { /** Page size */ pageSize?: number; /** Initial page (1-based) */ initialPage?: number; } /** * Pagination result for usePagination hook */ interface UsePaginationResult extends UseQueryResult { /** Current page (1-based) */ page: number; /** Total number of pages */ totalPages: number; /** Total number of records */ totalCount: number; /** Go to next page */ nextPage: () => void; /** Go to previous page */ previousPage: () => void; /** Go to specific page */ goToPage: (page: number) => void; /** Whether there is a next page */ hasNextPage: boolean; /** Whether there is a previous page */ hasPreviousPage: boolean; } /** * Hook for paginated data queries * * @example * ```tsx * function PaginatedTaskList() { * const { * data, * isLoading, * page, * totalPages, * nextPage, * previousPage, * hasNextPage, * hasPreviousPage * } = usePagination('todo_task', { * pageSize: 10, * orderBy: ['-created_at'] * }); * * return ( *
* {data?.value.map(task =>
{task.subject}
)} * * Page {page} of {totalPages} * *
* ); * } * ``` */ declare function usePagination(object: string, options?: UsePaginationOptions): UsePaginationResult; /** * Infinite query options for useInfiniteQuery hook */ interface UseInfiniteQueryOptions extends Omit, 'skip' | 'offset'> { /** Page size for each fetch */ pageSize?: number; /** Get next page parameter */ getNextPageParam?: (lastPage: PaginatedResult, allPages: PaginatedResult[]) => number | undefined; } /** * Infinite query result for useInfiniteQuery hook */ interface UseInfiniteQueryResult { /** All pages of data */ data: PaginatedResult[]; /** Flattened data from all pages */ flatData: T[]; /** Loading state */ isLoading: boolean; /** Error state */ error: Error | null; /** Load the next page */ fetchNextPage: () => Promise; /** Whether there are more pages */ hasNextPage: boolean; /** Is currently fetching next page */ isFetchingNextPage: boolean; /** Refetch all pages */ refetch: () => Promise; } /** * Hook for infinite scrolling / load more functionality * * @example * ```tsx * function InfiniteTaskList() { * const { * flatData, * isLoading, * fetchNextPage, * hasNextPage, * isFetchingNextPage * } = useInfiniteQuery('todo_task', { * pageSize: 20, * orderBy: ['-created_at'] * }); * * return ( *
* {flatData.map(task =>
{task.subject}
)} * {hasNextPage && ( * * )} *
* ); * } * ``` */ declare function useInfiniteQuery(object: string, options?: UseInfiniteQueryOptions): UseInfiniteQueryResult; /** * Metadata query options */ interface UseMetadataOptions { /** Enable/disable automatic query execution */ enabled?: boolean; /** Use cached metadata if available */ useCache?: boolean; /** ETag for conditional requests */ ifNoneMatch?: string; /** If-Modified-Since header for conditional requests */ ifModifiedSince?: string; /** Callback on successful query */ onSuccess?: (data: any) => void; /** Callback on error */ onError?: (error: Error) => void; } /** * Metadata query result */ interface UseMetadataResult { /** Metadata data */ data: T | null; /** Loading state */ isLoading: boolean; /** Error state */ error: Error | null; /** Refetch the metadata */ refetch: () => Promise; /** ETag from last fetch */ etag?: string; /** Whether data came from cache (304 Not Modified) */ fromCache: boolean; } /** * Hook for fetching object schema/metadata * * @example * ```tsx * function ObjectSchemaViewer({ objectName }: { objectName: string }) { * const { data: schema, isLoading, error } = useObject(objectName); * * if (isLoading) return
Loading schema...
; * if (error) return
Error: {error.message}
; * * return ( *
*

{schema.label}

*

Fields: {Object.keys(schema.fields).length}

*
* ); * } * ``` */ declare function useObject(objectName: string, options?: UseMetadataOptions): UseMetadataResult; /** * Hook for fetching view configuration * * @example * ```tsx * function ViewConfiguration({ objectName }: { objectName: string }) { * const { data: view, isLoading } = useView(objectName, 'list'); * * if (isLoading) return
Loading view...
; * * return ( *
*

List View for {objectName}

*

Columns: {view?.columns?.length}

*
* ); * } * ``` */ declare function useView(objectName: string, viewType?: 'list' | 'form', options?: UseMetadataOptions): UseMetadataResult; /** * Hook for extracting fields from object schema * * @example * ```tsx * function FieldList({ objectName }: { objectName: string }) { * const { data: fields, isLoading } = useFields(objectName); * * if (isLoading) return
Loading fields...
; * * return ( *
    * {fields?.map(field => ( *
  • {field.label} ({field.type})
  • * ))} *
* ); * } * ``` */ declare function useFields(objectName: string, options?: UseMetadataOptions): UseMetadataResult; /** * Generic metadata hook for custom metadata queries * * @example * ```tsx * function CustomMetadata() { * const { data, isLoading } = useMetadata(async (client) => { * // Custom metadata fetching logic * const object = await client.meta.getObject('custom_object'); * const view = await client.meta.getView('custom_object', 'list'); * return { object, view }; * }); * * return
{JSON.stringify(data, null, 2)}
; * } * ``` */ declare function useMetadata(fetcher: (client: ReturnType) => Promise, options?: Omit): UseMetadataResult; /** * Hook to subscribe to metadata events * * @param type - Metadata type to subscribe to (e.g., 'object', 'view', 'agent') * @param options - Optional filters (packageId) * @returns Latest metadata event or null * * @example * ```tsx * function ObjectList() { * const event = useMetadataSubscription('object'); * * useEffect(() => { * if (event?.type === 'metadata.object.created') { * console.log('New object:', event.name); * // Refresh list * } * }, [event]); * * return
...
; * } * ``` */ declare function useMetadataSubscription(type: string, options?: { packageId?: string; }): MetadataEvent | null; /** * Hook to subscribe to data record events * * @param object - Object name to subscribe to * @param options - Optional filters (recordId for specific record) * @returns Latest data event or null * * @example * ```tsx * function TaskDetail({ taskId }: { taskId: string }) { * const event = useDataSubscription('project_task', { recordId: taskId }); * * useEffect(() => { * if (event?.type === 'data.record.updated') { * console.log('Task updated:', event.changes); * // Refresh task data * } * }, [event]); * * return
...
; * } * ``` */ declare function useDataSubscription(object: string, options?: { recordId?: string; }): DataEvent | null; /** * Hook to subscribe to metadata events with a callback * * This variant doesn't store events in state, it just triggers a callback. * Useful for triggering refetches or side effects without re-renders. * * @param type - Metadata type to subscribe to * @param callback - Callback to invoke on events * @param options - Optional filters * * @example * ```tsx * function ObjectList() { * const { refetch } = useQuery(...); * * useMetadataSubscriptionCallback('object', () => { * refetch(); // Refetch list when objects change * }); * * return
...
; * } * ``` */ declare function useMetadataSubscriptionCallback(type: string, callback: (event: MetadataEvent) => void, options?: { packageId?: string; }): void; /** * Hook to subscribe to data events with a callback * * @param object - Object name to subscribe to * @param callback - Callback to invoke on events * @param options - Optional filters * * @example * ```tsx * function TaskList() { * const { refetch } = useQuery(...); * * useDataSubscriptionCallback('project_task', () => { * refetch(); // Refetch list when tasks change * }); * * return
...
; * } * ``` */ declare function useDataSubscriptionCallback(object: string, callback: (event: DataEvent) => void, options?: { recordId?: string; }): void; /** * Hook to get connection status of realtime events * * @returns Whether realtime is connected * * @example * ```tsx * function ConnectionIndicator() { * const connected = useRealtimeConnection(); * * return ( *
* {connected ? '🟢 Connected' : '🔴 Disconnected'} *
* ); * } * ``` */ declare function useRealtimeConnection(): boolean; /** * Hook for auto-refreshing queries when data changes * * Combines data subscription with query refetch. * * @param object - Object name to watch * @param refetch - Refetch function from useQuery * @param options - Optional filters * * @example * ```tsx * function TaskList() { * const { data, refetch } = useQuery('project_task', {}); * * useAutoRefresh('project_task', refetch); * * return
{data.map(...)}
; * } * ``` */ declare function useAutoRefresh(object: string, refetch: () => void, options?: { recordId?: string; }): void; 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 };