grist-widget-sdk 0.2.15 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +6 -0
- package/dist/advanced.js +3 -2
- package/dist/advanced.js.map +1 -1
- package/dist/{chunk-ER6UWHZA.js → chunk-7GXVEZ2J.js} +2 -2
- package/dist/{chunk-KOVYBNPJ.js → chunk-D5GBS2NT.js} +8 -31
- package/dist/chunk-D5GBS2NT.js.map +1 -0
- package/dist/chunk-N3X46JW2.js +37 -0
- package/dist/chunk-N3X46JW2.js.map +1 -0
- package/dist/emulator/devtools.cjs +37 -0
- package/dist/emulator/devtools.cjs.map +1 -1
- package/dist/emulator/devtools.js +28 -0
- package/dist/emulator/devtools.js.map +1 -1
- package/dist/emulator/testing.js +2 -1
- package/dist/emulator/testing.js.map +1 -1
- package/dist/index.js +5 -3
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-KOVYBNPJ.js.map +0 -1
- /package/dist/{chunk-ER6UWHZA.js.map → chunk-7GXVEZ2J.js.map} +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# grist-widget-sdk
|
|
2
2
|
|
|
3
|
+
## 0.3.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- f2604a3: `EmulatorInspector` (the drop-in devtools component) gains an "Access level" control: three buttons (none / read table / full) that call `emulator.setInteraction({ access_level })` at runtime, so you can test how a widget behaves under each granted level without editing code and reloading. The emulator already supported this (`setInteraction` + transports reading `state.widgetInteraction`), it just had no UI to drive it.
|
|
8
|
+
|
|
3
9
|
## 0.2.15
|
|
4
10
|
|
|
5
11
|
### Patch Changes
|
package/dist/advanced.js
CHANGED
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
useGristReady,
|
|
8
8
|
useGristWidgetOptionsFromContext,
|
|
9
9
|
useRpcHeartbeatCoalesce
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-7GXVEZ2J.js";
|
|
11
11
|
import {
|
|
12
12
|
createGristHandshakeManager,
|
|
13
13
|
deriveCapabilities,
|
|
@@ -20,10 +20,11 @@ import {
|
|
|
20
20
|
recordEvent,
|
|
21
21
|
recordsEvent,
|
|
22
22
|
resetGristReadySingleton
|
|
23
|
-
} from "./chunk-
|
|
23
|
+
} from "./chunk-D5GBS2NT.js";
|
|
24
24
|
import {
|
|
25
25
|
tableDataToRows
|
|
26
26
|
} from "./chunk-JASMM2YC.js";
|
|
27
|
+
import "./chunk-N3X46JW2.js";
|
|
27
28
|
import {
|
|
28
29
|
gristAddRecordAction,
|
|
29
30
|
gristBulkAddRecordAction,
|
package/dist/advanced.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/sdk/low-level-hooks/use-grist-availability.ts","../src/sdk/low-level-hooks/use-grist-handshake.ts","../src/sdk/low-level-hooks/use-ambient-grist-handshake.ts","../src/sdk/components/grist-handshake-provider.tsx","../src/sdk/low-level-hooks/use-grist-record.ts","../src/sdk/low-level-hooks/use-grist-records.ts","../src/sdk/low-level-hooks/use-grist-new-record.ts","../src/sdk/mid-level-hooks/use-grist-actions.ts","../src/sdk/mid-level-hooks/use-grist-mapped-record.ts","../src/sdk/mid-level-hooks/use-grist-table-ops.ts","../src/sdk/mid-level-hooks/use-grist-rows-from-table.ts","../src/sdk/mid-level-hooks/use-grist-access-token.ts","../src/sdk/mid-level-hooks/use-grist-section.ts","../src/sdk/mid-level-hooks/use-grist-widget-options.ts","../src/sdk/use-grist-table.ts"],"sourcesContent":["import { useGristCore, type UseGristCoreOptions } from \"../internal/hooks/use-grist-core\"\n\nexport type UseGristAvailabilityOptions = Pick<\n UseGristCoreOptions,\n \"availabilityMaxAttempts\" | \"availabilityIntervalMs\" | \"logWhenNotEmbedded\"\n>\n\n/**\n * Handshake-backed availability — projects `isAvailable` from the FSM.\n */\nexport function useGristAvailability(options?: UseGristAvailabilityOptions): boolean | null {\n const { isAvailable } = useGristCore(options)\n return isAvailable\n}\n","/**\n * `useGristHandshake()` — React adapter over {@link GristHandshakeManager}.\n *\n * Exposes the full {@link GristWidgetSnapshot} plus derived\n * {@link GristCapabilities}, plus `reload()` / `restart()` controls.\n *\n * Identity stability\n * ------------------\n * The snapshot reference changes whenever the reducer produces a new\n * snapshot. Capabilities are memoized by snapshot identity, so consumers\n * branching on a single capability (e.g. `canWriteRecords`) avoid extra\n * re-renders unless that boolean actually flips.\n *\n * SSR-safe: `getServerSnapshot` returns the initial snapshot deterministically.\n */\n\nimport { useEffect, useMemo, useRef, useSyncExternalStore } from \"react\"\n\nimport {\n deriveCapabilities,\n deriveErrorMessage,\n deriveStatus,\n initialGristSnapshot,\n type GristCapabilities,\n type GristWidgetSnapshot,\n type GristWidgetStatus,\n} from \"../internal/handshake\"\nimport {\n createGristHandshakeManager,\n type ManagerControls,\n type ManagerOptions,\n} from \"../internal/handshake/manager\"\nimport { ensureGristReady, resetGristReadySingleton } from \"../internal/ready-singleton\"\n\nexport type UseGristHandshakeOptions = ManagerOptions\n\nexport type UseGristHandshakeResult = {\n snapshot: GristWidgetSnapshot\n status: GristWidgetStatus\n error: string | null\n capabilities: GristCapabilities\n reload: () => void\n restart: () => void\n}\n\n/**\n * Mount a handshake manager local to the component subtree. Multiple\n * widgets in the same page should NOT call this in parallel — instead,\n * mount a single `<GristWidgetProvider>` at the app root.\n *\n * In tests, pass `options.env` (see `createTestEnvironment`) to drive the\n * machine with a virtual clock.\n */\nexport function useGristHandshake(options: UseGristHandshakeOptions = {}): UseGristHandshakeResult {\n // Memoize the manager so it survives re-renders. Caller is responsible for\n // passing stable options; in practice this is set once at the provider.\n const optionsRef = useRef(options)\n optionsRef.current = options\n const managerRef = useRef<ManagerControls | null>(null)\n if (managerRef.current === null) {\n // Default to the page-level `ensureGristReady()` singleton so a\n // standalone `useGristHandshake()` (mounted alongside a real\n // `<GristWidgetProvider>` for its observable snapshot, per the \"custom\n // retry / observability\" pattern) can't call the real `grist.ready()`\n // independently and race the widget's own declared options. Callers\n // that pass their own `negotiate`/`onBeforeReload` still win.\n managerRef.current = createGristHandshakeManager({\n ...options,\n negotiate: {\n readyImpl: (payload) => ensureGristReady(payload),\n ...options.negotiate,\n },\n onBeforeReload: () => {\n resetGristReadySingleton()\n options.onBeforeReload?.()\n },\n })\n }\n const manager = managerRef.current\n\n useEffect(() => {\n manager.start()\n return () => {\n manager.stop()\n }\n }, [manager])\n\n const snapshot = useSyncExternalStore(\n manager.subscribe,\n manager.getSnapshot,\n initialGristSnapshot\n )\n\n const projected = useMemo(\n () => ({\n status: deriveStatus(snapshot),\n error: deriveErrorMessage(snapshot),\n capabilities: deriveCapabilities(snapshot),\n }),\n [snapshot]\n )\n\n return useMemo(\n () => ({\n snapshot,\n status: projected.status,\n error: projected.error,\n capabilities: projected.capabilities,\n reload: manager.reload,\n restart: manager.restart,\n }),\n [snapshot, projected, manager]\n )\n}\n\n/**\n * Convenience hook — equivalent to `useGristHandshake().capabilities` but\n * skips returning the full snapshot. Intended for leaf components that only\n * need to gate UI on `canRender` / `canWriteRecords` / etc.\n */\nexport function useGristCapabilities(\n options: UseGristHandshakeOptions = {}\n): GristCapabilities {\n return useGristHandshake(options).capabilities\n}\n","/**\n * `useAmbientGristHandshake()` — observe an already-mounted handshake\n * manager without ever creating one.\n *\n * `useGristHandshake()` / `<GristHandshakeProvider>` both mount their OWN\n * manager, which calls the real `grist.ready()` independently of any\n * `<GristWidgetProvider>` elsewhere on the page. That's fine for a widget's\n * single app-root provider, but wrong for read-only UI (a connection-status\n * chip, a debug overlay) that must share the *same* handshake as the real\n * widget rather than run a second, competing one. This hook only reads\n * whatever manager a `<GristWidgetProvider>` ancestor already published;\n * it returns `null` outside one instead of falling back to creating its own.\n */\n\nimport { useMemo, useSyncExternalStore } from \"react\"\n\nimport {\n deriveCapabilities,\n deriveErrorMessage,\n deriveStatus,\n initialGristSnapshot,\n type GristCapabilities,\n type GristWidgetSnapshot,\n type GristWidgetStatus,\n} from \"../internal/handshake\"\nimport { useGristManagerOptional } from \"../internal/handshake-manager-context\"\n\nexport type UseAmbientGristHandshakeResult = {\n snapshot: GristWidgetSnapshot\n status: GristWidgetStatus\n error: string | null\n capabilities: GristCapabilities\n reload: () => void\n restart: () => void\n}\n\nconst noopSubscribe = () => () => {}\nconst getInitialSnapshot = () => initialGristSnapshot()\n\n/**\n * Returns `null` when mounted outside a `<GristWidgetProvider>` — there is\n * no ambient manager to observe, and this hook intentionally never creates\n * one. Mount inside `<GristWidgetProvider>` to get a live value.\n */\nexport function useAmbientGristHandshake(): UseAmbientGristHandshakeResult | null {\n const manager = useGristManagerOptional()\n\n const snapshot = useSyncExternalStore(\n manager?.subscribe ?? noopSubscribe,\n manager?.getSnapshot ?? getInitialSnapshot,\n getInitialSnapshot\n )\n\n return useMemo(() => {\n if (!manager) return null\n return {\n snapshot,\n status: deriveStatus(snapshot),\n error: deriveErrorMessage(snapshot),\n capabilities: deriveCapabilities(snapshot),\n reload: manager.reload,\n restart: manager.restart,\n }\n }, [manager, snapshot])\n}\n","/**\n * `<GristHandshakeProvider>` — opt-in React provider that mounts a single\n * {@link GristHandshakeManager} at the app root and broadcasts its snapshot\n * to all descendants.\n *\n * Use this provider when you want the full SOTA handshake model (snapshot +\n * capabilities + heartbeat + reload/restart) without the slice composition\n * of `<GristWidgetProvider>`. The two providers are independent:\n *\n * - `<GristWidgetProvider>` (legacy) — full SDK surface, hooks slices.\n * - `<GristHandshakeProvider>` (new) — handshake state machine only.\n *\n * Both can coexist if you need both surfaces; `grist.ready` is deduped by\n * the SDK's ready singleton so concurrent calls are safe.\n */\n\nimport {\n createContext,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useSyncExternalStore,\n type ReactNode,\n} from \"react\"\n\nimport {\n createGristHandshakeManager,\n type ManagerControls,\n type ManagerOptions,\n} from \"../internal/handshake/manager\"\nimport {\n deriveCapabilities,\n deriveErrorMessage,\n deriveStatus,\n initialGristSnapshot,\n type GristCapabilities,\n type GristWidgetSnapshot,\n type GristWidgetStatus,\n} from \"../internal/handshake\"\nimport { ensureGristReady, resetGristReadySingleton } from \"../internal/ready-singleton\"\n\nexport type GristHandshakeContextValue = {\n snapshot: GristWidgetSnapshot\n status: GristWidgetStatus\n error: string | null\n capabilities: GristCapabilities\n reload: () => void\n restart: () => void\n recordRpcSuccess: () => void\n recordRpcFailure: () => void\n}\n\nconst GristHandshakeReactContext = createContext<GristHandshakeContextValue | null>(null)\n\nexport type GristHandshakeProviderProps = {\n options?: ManagerOptions\n children: ReactNode\n}\n\n/**\n * Mount a single {@link GristHandshakeManager} for the React subtree and\n * expose its snapshot via context.\n *\n * The manager is created **once** on first mount; the `options` prop is\n * captured at that time. To re-create the manager with new options, unmount\n * and re-mount the provider (e.g. via a `key`).\n */\nexport function GristHandshakeProvider({ options, children }: GristHandshakeProviderProps) {\n // Manager is allocated once. Subsequent option changes are intentionally\n // ignored — handshake configuration should be stable for the lifetime of\n // the widget.\n const managerRef = useRef<ManagerControls | null>(null)\n if (managerRef.current === null) {\n // Default to the page-level `ensureGristReady()` singleton so a bare\n // `<GristHandshakeProvider>` (no options) can't win a race against a\n // sibling `<GristWidgetProvider>` by calling the real `grist.ready()`\n // directly with its own default payload. Callers that pass their own\n // `negotiate`/`onBeforeReload` still win. (Read-only observers of an\n // ancestor `<GristWidgetProvider>`, like the template's `GristStatusChip`,\n // should prefer `useAmbientGristHandshake()` instead of this provider —\n // it observes the existing manager rather than allocating a new one.)\n managerRef.current = createGristHandshakeManager({\n ...options,\n negotiate: {\n readyImpl: (payload) => ensureGristReady(payload),\n ...options?.negotiate,\n },\n onBeforeReload: () => {\n resetGristReadySingleton()\n options?.onBeforeReload?.()\n },\n })\n }\n const manager = managerRef.current\n\n useEffect(() => {\n manager.start()\n return () => {\n manager.stop()\n }\n }, [manager])\n\n const snapshot = useSyncExternalStore(\n manager.subscribe,\n manager.getSnapshot,\n initialGristSnapshot\n )\n\n const value = useMemo<GristHandshakeContextValue>(\n () => ({\n snapshot,\n status: deriveStatus(snapshot),\n error: deriveErrorMessage(snapshot),\n capabilities: deriveCapabilities(snapshot),\n reload: manager.reload,\n restart: manager.restart,\n recordRpcSuccess: manager.recordRpcSuccess,\n recordRpcFailure: manager.recordRpcFailure,\n }),\n [snapshot, manager]\n )\n\n return (\n <GristHandshakeReactContext.Provider value={value}>\n {children}\n </GristHandshakeReactContext.Provider>\n )\n}\n\n/**\n * Read the handshake context. Throws if no `<GristHandshakeProvider>` is\n * mounted in the tree.\n *\n * Use {@link useGristHandshakeContextOptional} when the provider is optional\n * (e.g. when the same component is sometimes used standalone).\n */\nexport function useGristHandshakeContext(): GristHandshakeContextValue {\n const ctx = useContext(GristHandshakeReactContext)\n if (!ctx) {\n throw new Error(\n \"useGristHandshakeContext() must be used inside <GristHandshakeProvider>\"\n )\n }\n return ctx\n}\n\n/** Non-throwing variant. */\nexport function useGristHandshakeContextOptional(): GristHandshakeContextValue | null {\n return useContext(GristHandshakeReactContext)\n}\n","import { useEffect, useRef, useState } from \"react\"\n\nimport { recordEvent } from \"../internal/subscriptions\"\nimport type { GristReadyOptions, GristWidgetColumnMap } from \"../types\"\nimport { useGristReady } from \"./use-grist-ready\"\n\nexport type UseGristRecordSubscriptionResult = {\n loading: boolean\n error: string | null\n /** Latest mappings from `grist.onRecord` (logical name → real column id, or `string[]` for `allowMultiple`). */\n mappings: GristWidgetColumnMap | null\n}\n\n// Subscription errors are logged inside the singleton; nothing surfaces here.\n\n/**\n * Subscribes to the currently-selected row in the widget's section.\n *\n * The Grist event is shared across all hook instances (no leak).\n */\nexport function useGristRecord(\n cb: (record: Record<string, unknown> | null, mappings: GristWidgetColumnMap | null) => void,\n options?: GristReadyOptions\n): UseGristRecordSubscriptionResult {\n const cbRef = useRef(cb)\n useEffect(() => {\n cbRef.current = cb\n }, [cb])\n\n const [mappings, setMappings] = useState<GristWidgetColumnMap | null>(null)\n const { docApi, error: readyError } = useGristReady({\n requiredAccess: options?.requiredAccess ?? \"read table\",\n columns: options?.columns,\n allowSelectBy: options?.allowSelectBy,\n hasCustomOptions: options?.hasCustomOptions,\n onEditOptions: options?.onEditOptions,\n })\n\n useEffect(() => {\n if (!docApi) return\n return recordEvent.subscribe(({ record, mappings: nextMappings }) => {\n setMappings(nextMappings)\n cbRef.current(record, nextMappings)\n })\n }, [docApi])\n\n return {\n loading: docApi === null && !readyError,\n error: readyError,\n mappings,\n }\n}\n","import { useEffect, useRef, useState } from \"react\"\n\nimport { recordsEvent } from \"../internal/subscriptions\"\nimport type { GristReadyOptions, GristWidgetColumnMap } from \"../types\"\nimport { useGristReady } from \"./use-grist-ready\"\nimport type { UseGristRecordSubscriptionResult } from \"./use-grist-record\"\n\n/**\n * Subscribes to the full row set visible in the widget's section\n * (filters, sorts, and linked rows applied).\n */\nexport function useGristRecords(\n cb: (records: Record<string, unknown>[], mappings: GristWidgetColumnMap | null) => void,\n options?: GristReadyOptions\n): UseGristRecordSubscriptionResult {\n const cbRef = useRef(cb)\n useEffect(() => {\n cbRef.current = cb\n }, [cb])\n\n const [mappings, setMappings] = useState<GristWidgetColumnMap | null>(null)\n const { docApi, error: readyError } = useGristReady({\n requiredAccess: options?.requiredAccess ?? \"read table\",\n columns: options?.columns,\n allowSelectBy: options?.allowSelectBy,\n hasCustomOptions: options?.hasCustomOptions,\n onEditOptions: options?.onEditOptions,\n })\n\n useEffect(() => {\n if (!docApi) return\n return recordsEvent.subscribe(({ records, mappings: nextMappings }) => {\n setMappings(nextMappings)\n cbRef.current(records, nextMappings)\n })\n }, [docApi])\n\n return {\n loading: docApi === null && !readyError,\n error: readyError,\n mappings,\n }\n}\n","import { useEffect, useRef, useState } from \"react\"\n\nimport { newRecordEvent } from \"../internal/subscriptions\"\nimport type { GristReadyOptions, GristWidgetColumnMap } from \"../types\"\nimport { useGristReady } from \"./use-grist-ready\"\n\nexport type UseGristNewRecordResult = {\n /** True when the user has selected the blank \"new row\" placeholder. */\n isNewRecord: boolean\n /** Mappings reported by Grist alongside the new-record event. */\n mappings: GristWidgetColumnMap | null\n loading: boolean\n error: string | null\n}\n\n/**\n * Subscribes to `grist.onNewRecord` — fires when the user selects the blank\n * row in the linked section. Useful for form-style widgets that need to\n * switch into \"create\" mode.\n *\n * `isNewRecord` is reset to `false` whenever a real `onRecord` payload arrives,\n * so callers don't need to manage that themselves.\n */\nexport function useGristNewRecord(options?: GristReadyOptions): UseGristNewRecordResult {\n const { docApi, error: readyError } = useGristReady({\n requiredAccess: options?.requiredAccess ?? \"read table\",\n columns: options?.columns,\n allowSelectBy: options?.allowSelectBy,\n hasCustomOptions: options?.hasCustomOptions,\n onEditOptions: options?.onEditOptions,\n })\n\n const [isNewRecord, setIsNewRecord] = useState(false)\n const [mappings, setMappings] = useState<GristWidgetColumnMap | null>(null)\n const subscribedRef = useRef(false)\n\n useEffect(() => {\n if (!docApi || subscribedRef.current) return\n if (typeof grist.onNewRecord !== \"function\") return\n subscribedRef.current = true\n return newRecordEvent.subscribe(({ mappings: nextMappings }) => {\n setIsNewRecord(true)\n setMappings(nextMappings)\n })\n }, [docApi])\n\n return {\n isNewRecord,\n mappings,\n loading: docApi === null && !readyError,\n error: readyError,\n }\n}\n","import { useCallback, useState } from \"react\"\n\nimport {\n gristAddRecordAction,\n gristBulkAddRecordAction,\n gristBulkRemoveRecordAction,\n gristBulkUpdateRecordAction,\n gristRemoveRecordAction,\n gristUpdateRecordAction,\n type GristUserActionTuple,\n} from \"../helpers/grist-user-actions\"\nimport { useRpcHeartbeatCoalesce } from \"../internal/hooks/use-rpc-heartbeat-coalesce\"\nimport { useGristReady } from \"../low-level-hooks/use-grist-ready\"\nimport type { GristApplyUserActionsOptions, GristReadyOptions } from \"../types\"\n\nexport type GristActionsStatus = \"idle\" | \"running\" | \"error\"\n\nexport type UseGristActionsOptions = Pick<\n GristReadyOptions,\n \"requiredAccess\" | \"columns\" | \"allowSelectBy\" | \"hasCustomOptions\" | \"onEditOptions\"\n>\n\nexport type UseGristActionsResult = {\n status: GristActionsStatus\n error: string | null\n /** Apply raw user actions. `applyOptions.desc` is shown in the document undo stack. */\n apply: (actions: GristUserActionTuple[], applyOptions?: GristApplyUserActionsOptions) => Promise<unknown>\n updateRecord: (\n tableId: string,\n recordId: number,\n patch: Record<string, unknown>,\n applyOptions?: GristApplyUserActionsOptions\n ) => Promise<unknown>\n addRecord: (\n tableId: string,\n values: Record<string, unknown>,\n applyOptions?: GristApplyUserActionsOptions\n ) => Promise<unknown>\n removeRecord: (\n tableId: string,\n recordId: number,\n applyOptions?: GristApplyUserActionsOptions\n ) => Promise<unknown>\n bulkAddRecord: (\n tableId: string,\n values: Record<string, unknown[]>,\n applyOptions?: GristApplyUserActionsOptions\n ) => Promise<unknown>\n bulkUpdateRecord: (\n tableId: string,\n rowIds: number[],\n columnarPatch: Record<string, unknown[]>,\n applyOptions?: GristApplyUserActionsOptions\n ) => Promise<unknown>\n bulkRemoveRecord: (\n tableId: string,\n rowIds: number[],\n applyOptions?: GristApplyUserActionsOptions\n ) => Promise<unknown>\n}\n\nexport function useGristActions(options?: UseGristActionsOptions): UseGristActionsResult {\n const requiredAccess = options?.requiredAccess ?? \"full\"\n const { docApi, error: readyError } = useGristReady({\n requiredAccess,\n columns: options?.columns,\n allowSelectBy: options?.allowSelectBy,\n hasCustomOptions: options?.hasCustomOptions,\n onEditOptions: options?.onEditOptions,\n })\n const [status, setStatus] = useState<GristActionsStatus>(\"idle\")\n const [actionError, setActionError] = useState<string | null>(null)\n const coalesceRpc = useRpcHeartbeatCoalesce()\n\n const apply = useCallback(\n async (actions: GristUserActionTuple[], applyOptions?: GristApplyUserActionsOptions): Promise<unknown> => {\n if (!docApi) throw new Error(\"Grist docApi is not ready\")\n setStatus(\"running\")\n setActionError(null)\n try {\n const out = await coalesceRpc(() => docApi.applyUserActions(actions, applyOptions))\n setStatus(\"idle\")\n return out\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n setActionError(message)\n setStatus(\"error\")\n throw err\n }\n },\n [docApi, coalesceRpc]\n )\n\n const updateRecord = useCallback(\n (tableId: string, recordId: number, patch: Record<string, unknown>, applyOptions?: GristApplyUserActionsOptions) =>\n apply([gristUpdateRecordAction(tableId, recordId, patch)], applyOptions),\n [apply]\n )\n\n const addRecord = useCallback(\n (tableId: string, values: Record<string, unknown>, applyOptions?: GristApplyUserActionsOptions) =>\n apply([gristAddRecordAction(tableId, values)], applyOptions),\n [apply]\n )\n\n const removeRecord = useCallback(\n (tableId: string, recordId: number, applyOptions?: GristApplyUserActionsOptions) =>\n apply([gristRemoveRecordAction(tableId, recordId)], applyOptions),\n [apply]\n )\n\n const bulkAddRecord = useCallback(\n (tableId: string, values: Record<string, unknown[]>, applyOptions?: GristApplyUserActionsOptions) =>\n apply([gristBulkAddRecordAction(tableId, values)], applyOptions),\n [apply]\n )\n\n const bulkUpdateRecord = useCallback(\n (tableId: string, rowIds: number[], columnarPatch: Record<string, unknown[]>, applyOptions?: GristApplyUserActionsOptions) =>\n apply([gristBulkUpdateRecordAction(tableId, rowIds, columnarPatch)], applyOptions),\n [apply]\n )\n\n const bulkRemoveRecord = useCallback(\n (tableId: string, rowIds: number[], applyOptions?: GristApplyUserActionsOptions) =>\n apply([gristBulkRemoveRecordAction(tableId, rowIds)], applyOptions),\n [apply]\n )\n\n return {\n status: readyError ? \"error\" : status,\n error: readyError ?? actionError,\n apply,\n updateRecord,\n addRecord,\n removeRecord,\n bulkAddRecord,\n bulkUpdateRecord,\n bulkRemoveRecord,\n }\n}\n","import { useCallback, useEffect, useState } from \"react\"\n\nimport { recordEvent } from \"../internal/subscriptions\"\nimport { useGristReady } from \"../low-level-hooks/use-grist-ready\"\nimport type { GristReadyOptions, GristWidgetColumnMap } from \"../types\"\n\nexport type UseGristMappedRecordResult<T> = {\n rawRecord: Record<string, unknown> | null\n mappedRecord: T | null\n /** Current column mappings reported by Grist. */\n mappings: GristWidgetColumnMap | null\n loading: boolean\n error: string | null\n /**\n * Reverse-map a logical patch (`{ logicalName: value }`) into a real-column\n * patch (`{ realColId: value }`) ready for `applyUserActions` /\n * `useGristTableOps.update`.\n * Falls back to `grist.mapColumnNamesBack` when present, otherwise resolves\n * names manually from `mappings` (single-mapped columns only).\n */\n mapBack: (patch: Partial<T>) => Record<string, unknown>\n /** Resolve a single logical name to its current real column id. */\n resolveColumnId: (logicalName: keyof T & string) => string | undefined\n}\n\nfunction manualMapBack<T>(patch: Partial<T>, mappings: GristWidgetColumnMap | null): Record<string, unknown> {\n if (!mappings) return { ...(patch as Record<string, unknown>) }\n const out: Record<string, unknown> = {}\n for (const [name, value] of Object.entries(patch as Record<string, unknown>)) {\n const target = mappings[name]\n if (Array.isArray(target)) {\n // allowMultiple: cannot decide which underlying column to write — skip and warn.\n if (typeof console !== \"undefined\") {\n console.warn(`[lib/grist] mapBack: cannot reverse-map allowMultiple field \"${name}\" without grist.mapColumnNamesBack`)\n }\n continue\n }\n out[target ?? name] = value\n }\n return out\n}\n\n/**\n * Subscribes to the selected row, applies `grist.mapColumnNames` so widget code\n * sees logical column names, and exposes `mapBack` for safe writes.\n */\nexport function useGristMappedRecord<T = Record<string, unknown>>(\n options?: GristReadyOptions\n): UseGristMappedRecordResult<T> {\n const requiredAccess = options?.requiredAccess ?? \"read table\"\n const { docApi, error: readyError } = useGristReady({\n requiredAccess,\n columns: options?.columns,\n allowSelectBy: options?.allowSelectBy,\n hasCustomOptions: options?.hasCustomOptions,\n onEditOptions: options?.onEditOptions,\n })\n const [rawRecord, setRawRecord] = useState<Record<string, unknown> | null>(null)\n const [mappedRecord, setMappedRecord] = useState<T | null>(null)\n const [mappings, setMappings] = useState<GristWidgetColumnMap | null>(null)\n\n useEffect(() => {\n if (!docApi) return\n return recordEvent.subscribe(({ record, mappings: nextMappings }) => {\n setRawRecord(record)\n setMappings(nextMappings)\n if (!record) {\n setMappedRecord(null)\n return\n }\n if (typeof grist.mapColumnNames === \"function\") {\n const mapped = grist.mapColumnNames(record)\n setMappedRecord(\n mapped !== null && mapped !== undefined ? (mapped as T) : null\n )\n return\n }\n setMappedRecord(record as T)\n })\n }, [docApi])\n\n const mapBack = useCallback(\n (patch: Partial<T>): Record<string, unknown> => {\n if (typeof grist.mapColumnNamesBack === \"function\") {\n return grist.mapColumnNamesBack(patch as Record<string, unknown>)\n }\n return manualMapBack<T>(patch, mappings)\n },\n [mappings]\n )\n\n const resolveColumnId = useCallback(\n (logicalName: keyof T & string): string | undefined => {\n const value = mappings?.[logicalName]\n if (Array.isArray(value)) return undefined\n return value ?? undefined\n },\n [mappings]\n )\n\n return {\n rawRecord,\n mappedRecord,\n mappings,\n loading: docApi === null && !readyError,\n error: readyError,\n mapBack,\n resolveColumnId,\n }\n}\n","import { useCallback, useState } from \"react\"\n\nimport { useRpcHeartbeatCoalesce } from \"../internal/hooks/use-rpc-heartbeat-coalesce\"\nimport { useGristReady } from \"../low-level-hooks/use-grist-ready\"\nimport type {\n GristMinimalRecord,\n GristReadyOptions,\n GristTableNewRecord,\n GristTableOpOptions,\n GristTableOperations,\n GristTableUpdateRecord,\n GristTableUpsertOptions,\n GristTableUpsertRecord,\n} from \"../types\"\n\nexport type GristTableOpsStatus = \"idle\" | \"running\" | \"error\"\n\nexport type UseGristTableOpsOptions = {\n /**\n * Table to operate on:\n * - `\"selected\"` (default): use `grist.selectedTable` (the widget's current table).\n * - any other string: use `grist.getTable(tableId)`.\n */\n tableId?: \"selected\" | string\n /** Defaults to `\"full\"` since these operations write to the document. */\n requiredAccess?: GristReadyOptions[\"requiredAccess\"]\n} & Pick<GristReadyOptions, \"columns\" | \"allowSelectBy\" | \"hasCustomOptions\" | \"onEditOptions\">\n\nexport type UseGristTableOpsResult = {\n status: GristTableOpsStatus\n error: string | null\n /** Resolves the runtime tableId (only meaningful when `tableId` is `\"selected\"`). */\n getTableId: () => Promise<string>\n create: (\n records: GristTableNewRecord | GristTableNewRecord[],\n opOptions?: GristTableOpOptions\n ) => Promise<GristMinimalRecord | GristMinimalRecord[]>\n update: (\n records: GristTableUpdateRecord | GristTableUpdateRecord[],\n opOptions?: GristTableOpOptions\n ) => Promise<void>\n upsert: (\n records: GristTableUpsertRecord | GristTableUpsertRecord[],\n opOptions?: GristTableUpsertOptions\n ) => Promise<void>\n destroy: (recordIds: number | number[]) => Promise<void>\n}\n\nfunction resolveOps(tableId: \"selected\" | string): GristTableOperations {\n if (tableId === \"selected\") {\n if (!grist.selectedTable) throw new Error(\"grist.selectedTable is not available\")\n return grist.selectedTable\n }\n if (typeof grist.getTable !== \"function\") {\n throw new Error(\"grist.getTable is not available in this Grist version\")\n }\n return grist.getTable(tableId)\n}\n\n/**\n * Strongly-typed CRUD wrapper around Grist's `TableOperations` (`grist.selectedTable`\n * or `grist.getTable(tableId)`). Prefer this over hand-rolled `applyUserActions`.\n *\n * @see https://support.getgrist.com/code/interfaces/TableOperations.TableOperations/\n */\nexport function useGristTableOps(options?: UseGristTableOpsOptions): UseGristTableOpsResult {\n const requiredAccess = options?.requiredAccess ?? \"full\"\n const tableIdOption: \"selected\" | string = options?.tableId ?? \"selected\"\n const { docApi, error: readyError } = useGristReady({\n requiredAccess,\n columns: options?.columns,\n allowSelectBy: options?.allowSelectBy,\n hasCustomOptions: options?.hasCustomOptions,\n onEditOptions: options?.onEditOptions,\n })\n\n const [status, setStatus] = useState<GristTableOpsStatus>(\"idle\")\n const [actionError, setActionError] = useState<string | null>(null)\n const coalesceRpc = useRpcHeartbeatCoalesce()\n\n // `resolveOps` is synchronous and idempotent (it only reads `grist.selectedTable`\n // / `grist.getTable`), so derive `ops` during render instead of via effect.\n let ops: GristTableOperations | null = null\n let resolveError: string | null = null\n if (docApi) {\n try {\n ops = resolveOps(tableIdOption)\n } catch (err) {\n resolveError = err instanceof Error ? err.message : String(err)\n }\n }\n\n const wrap = useCallback(\n async <T>(run: (ops: GristTableOperations) => Promise<T>): Promise<T> => {\n if (!ops) throw new Error(\"Grist table operations are not ready\")\n setStatus(\"running\")\n setActionError(null)\n try {\n const out = await coalesceRpc(() => run(ops))\n setStatus(\"idle\")\n return out\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n setActionError(message)\n setStatus(\"error\")\n throw err\n }\n },\n [ops, coalesceRpc]\n )\n\n const getTableId = useCallback(async () => {\n if (!ops) throw new Error(\"Grist table operations are not ready\")\n return ops.getTableId()\n }, [ops])\n\n const create = useCallback(\n (records: GristTableNewRecord | GristTableNewRecord[], opOptions?: GristTableOpOptions) =>\n wrap((o) => o.create(records, opOptions)),\n [wrap]\n )\n\n const update = useCallback(\n (records: GristTableUpdateRecord | GristTableUpdateRecord[], opOptions?: GristTableOpOptions) =>\n wrap((o) => o.update(records, opOptions)),\n [wrap]\n )\n\n const upsert = useCallback(\n (records: GristTableUpsertRecord | GristTableUpsertRecord[], opOptions?: GristTableUpsertOptions) =>\n wrap((o) => o.upsert(records, opOptions)),\n [wrap]\n )\n\n const destroy = useCallback(\n (recordIds: number | number[]) => wrap((o) => o.destroy(recordIds)),\n [wrap]\n )\n\n return {\n status: readyError || resolveError ? \"error\" : status,\n error: readyError ?? resolveError ?? actionError,\n getTableId,\n create,\n update,\n upsert,\n destroy,\n }\n}\n","import { useCallback, useContext, useEffect, useRef, useState } from \"react\"\n\nimport { tableDataToRows, type GristColumnarTable } from \"../helpers/grist-table-data\"\nimport { GristReadsContext } from \"../internal/contexts\"\nimport { useRpcHeartbeatCoalesce } from \"../internal/hooks/use-rpc-heartbeat-coalesce\"\nimport { useGristReady } from \"../low-level-hooks/use-grist-ready\"\nimport type { GristReadyOptions, GristRowRecord } from \"../types\"\n\nexport type UseGristRowsFromTableOptions<T> = {\n tableId: string\n /** Re-fetch on a fixed cadence (ms). Default: disabled. */\n pollIntervalMs?: number\n /** Map raw rows to a domain shape (e.g. `decodeGristValue` your columns). */\n transform?: (row: GristRowRecord) => GristRowRecord<T>\n requiredAccess?: GristReadyOptions[\"requiredAccess\"]\n} & Pick<GristReadyOptions, \"columns\" | \"allowSelectBy\" | \"hasCustomOptions\" | \"onEditOptions\">\n\nexport type UseGristRowsFromTableResult<T> = {\n rows: GristRowRecord<T>[] | null\n loading: boolean\n error: string | null\n /** Force a re-fetch (call after writes that should be reflected immediately). */\n refresh: () => Promise<void>\n}\n\n/**\n * Subscribes to a full table's rows via `docApi.fetchTable`.\n *\n * Unlike `useGristRecords` (which is bound to the widget's selected section),\n * this hook works against any table id and **doesn't auto-update on Grist\n * writes from elsewhere** — call `refresh()` after your own writes, or set\n * `pollIntervalMs` for polling.\n */\nexport function useGristRowsFromTable<T = Record<string, unknown>>(\n options: UseGristRowsFromTableOptions<T>\n): UseGristRowsFromTableResult<T> {\n const requiredAccess = options.requiredAccess ?? \"read table\"\n const { docApi, error: readyError } = useGristReady({\n requiredAccess,\n columns: options.columns,\n allowSelectBy: options.allowSelectBy,\n hasCustomOptions: options.hasCustomOptions,\n onEditOptions: options.onEditOptions,\n })\n\n // When inside a GristWidgetProvider, delegate to the provider's guarded\n // fetchTable so access-insufficient errors flow through readError → alerts.\n const providerFetchTable = useContext(GristReadsContext)?.fetchTable\n\n const [rows, setRows] = useState<GristRowRecord<T>[] | null>(null)\n const [loading, setLoading] = useState(false)\n const [fetchError, setFetchError] = useState<string | null>(null)\n const transformRef = useRef(options.transform)\n transformRef.current = options.transform\n const coalesceRpc = useRpcHeartbeatCoalesce()\n\n const refresh = useCallback(async () => {\n if (!docApi) return\n setLoading(true)\n setFetchError(null)\n try {\n const data = providerFetchTable\n ? await providerFetchTable(options.tableId)\n : ((await coalesceRpc(\n () => docApi.fetchTable(options.tableId) as Promise<GristColumnarTable>\n )) as GristColumnarTable)\n const raw = tableDataToRows(data)\n const t = transformRef.current\n setRows(t ? raw.map((r) => t(r)) : (raw as GristRowRecord<T>[]))\n } catch (err) {\n setFetchError(err instanceof Error ? err.message : String(err))\n setRows(null)\n } finally {\n setLoading(false)\n }\n }, [docApi, providerFetchTable, options.tableId, coalesceRpc])\n\n useEffect(() => {\n if (docApi) void refresh()\n }, [docApi, refresh])\n\n useEffect(() => {\n if (!docApi || !options.pollIntervalMs || options.pollIntervalMs <= 0) return\n const id = window.setInterval(() => void refresh(), options.pollIntervalMs)\n return () => window.clearInterval(id)\n }, [docApi, options.pollIntervalMs, refresh])\n\n return {\n rows,\n loading,\n error: readyError ?? fetchError,\n refresh,\n }\n}\n","import { useCallback, useEffect, useState } from \"react\"\n\nimport {\n fetchWithGristAuth as fetchWithGristAuthCore,\n getGristAccessToken,\n type GristAccessToken,\n} from \"../helpers/grist-fetch-with-auth\"\nimport { useGristReady } from \"../low-level-hooks/use-grist-ready\"\nimport type { GristReadyOptions } from \"../types\"\n\nexport type UseGristAccessTokenOptions = {\n /** Default for all token requests issued by this hook. */\n readOnly?: boolean\n /** Pre-fetch a token on mount so `token` is non-null when widgets render. */\n prefetch?: boolean\n /** Defaults to `\"full\"` since tokens are used for REST calls. */\n requiredAccess?: GristReadyOptions[\"requiredAccess\"]\n} & Pick<GristReadyOptions, \"columns\" | \"allowSelectBy\" | \"hasCustomOptions\" | \"onEditOptions\">\n\nexport type UseGristAccessTokenResult = {\n token: GristAccessToken | null\n loading: boolean\n error: string | null\n /** Request a fresh token (Grist tokens are short-lived; do not cache aggressively). */\n refresh: (overrides?: { readOnly?: boolean }) => Promise<GristAccessToken>\n /** `fetch()` against Grist's REST API with auth attached. */\n fetch: (path: string, init?: RequestInit & { readOnly?: boolean }) => Promise<Response>\n}\n\n/**\n * Exposes `docApi.getAccessToken` plus a ready-to-use `fetch` for calling\n * Grist's REST API (e.g. attachments, records, sql) from a widget.\n */\nexport function useGristAccessToken(options?: UseGristAccessTokenOptions): UseGristAccessTokenResult {\n const requiredAccess = options?.requiredAccess ?? \"full\"\n const readOnlyDefault = options?.readOnly ?? false\n const prefetch = options?.prefetch ?? false\n const { docApi, error: readyError } = useGristReady({\n requiredAccess,\n columns: options?.columns,\n allowSelectBy: options?.allowSelectBy,\n hasCustomOptions: options?.hasCustomOptions,\n onEditOptions: options?.onEditOptions,\n })\n\n const [token, setToken] = useState<GristAccessToken | null>(null)\n const [loading, setLoading] = useState(false)\n const [error, setError] = useState<string | null>(null)\n\n const refresh = useCallback(\n async (overrides?: { readOnly?: boolean }): Promise<GristAccessToken> => {\n if (!docApi) throw new Error(\"Grist is not ready\")\n setLoading(true)\n setError(null)\n try {\n const next = await getGristAccessToken(docApi, { readOnly: overrides?.readOnly ?? readOnlyDefault })\n setToken(next)\n return next\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n setError(message)\n throw err\n } finally {\n setLoading(false)\n }\n },\n [docApi, readOnlyDefault]\n )\n\n const fetchFn = useCallback(\n (path: string, init?: RequestInit & { readOnly?: boolean }) => {\n if (!docApi) throw new Error(\"Grist is not ready\")\n return fetchWithGristAuthCore(docApi, path, { readOnly: readOnlyDefault, ...init })\n },\n [docApi, readOnlyDefault]\n )\n\n useEffect(() => {\n if (docApi && prefetch) void refresh()\n }, [docApi, prefetch, refresh])\n\n return {\n token,\n loading,\n error: readyError ?? error,\n refresh,\n fetch: fetchFn,\n }\n}\n","import { useCallback, useEffect, useState } from \"react\"\n\nimport { useGristReady } from \"../low-level-hooks/use-grist-ready\"\nimport type { GristReadyOptions, GristWidgetColumnMap } from \"../types\"\n\nexport type UseGristSectionResult = {\n /** Current widget ↔ section column mappings, refreshed on demand. */\n mappings: GristWidgetColumnMap | null\n loading: boolean\n error: string | null\n /** Re-read mappings from `sectionApi`. */\n refresh: () => Promise<void>\n /**\n * Update the widget's declared `ColumnsToMap` (and other ready options) after\n * mount. Use this to dynamically request more columns once the user has\n * configured the widget.\n */\n configure: (options: GristReadyOptions) => Promise<void>\n}\n\n/**\n * Wraps Grist's `sectionApi` (`mappings()` + `configure()`) so widgets can\n * inspect/refresh the column mapping and re-declare requirements without\n * touching `grist` directly.\n */\nexport function useGristSection(options?: GristReadyOptions): UseGristSectionResult {\n const { docApi, error: readyError } = useGristReady({\n requiredAccess: options?.requiredAccess ?? \"read table\",\n columns: options?.columns,\n allowSelectBy: options?.allowSelectBy,\n hasCustomOptions: options?.hasCustomOptions,\n onEditOptions: options?.onEditOptions,\n })\n\n const [mappings, setMappings] = useState<GristWidgetColumnMap | null>(null)\n const [loading, setLoading] = useState(false)\n const [error, setError] = useState<string | null>(null)\n\n const refresh = useCallback(async () => {\n if (!docApi) return\n if (!grist.sectionApi?.mappings) {\n setError(\"grist.sectionApi.mappings is not available in this Grist version\")\n return\n }\n setLoading(true)\n setError(null)\n try {\n const next = await grist.sectionApi.mappings()\n setMappings(next)\n } catch (err) {\n setError(err instanceof Error ? err.message : String(err))\n } finally {\n setLoading(false)\n }\n }, [docApi])\n\n const configure = useCallback(async (next: GristReadyOptions) => {\n if (!grist.sectionApi?.configure) {\n throw new Error(\"grist.sectionApi.configure is not available in this Grist version\")\n }\n await grist.sectionApi.configure(next)\n }, [])\n\n useEffect(() => {\n if (docApi) void refresh()\n }, [docApi, refresh])\n\n return {\n mappings,\n loading,\n error: readyError ?? error,\n refresh,\n configure,\n }\n}\n","import { useCallback, useEffect, useMemo, useRef, useState } from \"react\"\n\nimport { optionsEvent } from \"../internal/subscriptions\"\nimport { useGristReady } from \"../low-level-hooks/use-grist-ready\"\nimport type { GristReadyOptions } from \"../types\"\n\nexport type UseGristWidgetOptionsConfig<T> = {\n /** Default values returned before Grist responds and merged with stored options. */\n defaults: T\n /** Debounce window for `setOptions` writes (ms). Default: 250. */\n debounceMs?: number\n /**\n * Optional namespace inside `grist.setOptions`. When set, this hook reads/writes\n * `grist.setOption(namespace, value)` instead of the whole options blob — useful\n * to share the options bag with `hasCustomOptions` / unrelated widget state.\n */\n namespace?: string\n requiredAccess?: GristReadyOptions[\"requiredAccess\"]\n} & Pick<GristReadyOptions, \"columns\" | \"allowSelectBy\" | \"hasCustomOptions\" | \"onEditOptions\">\n\nexport type UseGristWidgetOptionsResult<T> = {\n options: T\n /** True until Grist has responded with the initial `onOptions` payload. */\n loading: boolean\n error: string | null\n /** Replace the options object (debounced write to Grist). */\n setOptions: (next: T) => void\n /** Patch a subset of keys (debounced write to Grist). */\n patchOptions: (patch: Partial<T>) => void\n /** Reset to `defaults` (immediate write to Grist). */\n reset: () => Promise<void>\n}\n\nfunction mergeWithDefaults<T>(defaults: T, stored: unknown, namespace?: string): T {\n if (stored === null || stored === undefined) return { ...defaults }\n const source = (namespace ? (stored as Record<string, unknown>)[namespace] : stored) as Partial<T> | undefined\n if (!source || typeof source !== \"object\") return { ...defaults }\n return { ...defaults, ...source }\n}\n\n/**\n * Persist a typed object of widget settings via `grist.onOptions` / `setOptions`.\n *\n * - Defaults are returned immediately (no flicker before Grist responds).\n * - Writes are debounced and batched.\n * - `hasCustomOptions` defaults to `true` so Grist exposes the gear icon — pass\n * `hasCustomOptions: false` to opt out.\n */\nexport function useGristWidgetOptions<T extends Record<string, unknown>>(\n config: UseGristWidgetOptionsConfig<T>\n): UseGristWidgetOptionsResult<T> {\n const requiredAccess = config.requiredAccess ?? \"read table\"\n const debounceMs = config.debounceMs ?? 250\n const hasCustomOptions = config.hasCustomOptions ?? true\n const { docApi, error: readyError } = useGristReady({\n requiredAccess,\n columns: config.columns,\n allowSelectBy: config.allowSelectBy,\n hasCustomOptions,\n onEditOptions: config.onEditOptions,\n })\n\n const defaultsRef = useRef(config.defaults)\n useEffect(() => {\n defaultsRef.current = config.defaults\n }, [config.defaults])\n\n const [options, setOptionsState] = useState<T>(() => ({ ...config.defaults }))\n const [loading, setLoading] = useState(true)\n const [error, setError] = useState<string | null>(null)\n const lastWrittenRef = useRef<T | null>(null)\n const debounceRef = useRef<number | null>(null)\n\n // Subscribe to remote changes (initial + external edits)\n useEffect(() => {\n if (!docApi) return\n return optionsEvent.subscribe(({ options: stored }) => {\n const merged = mergeWithDefaults(defaultsRef.current, stored, config.namespace)\n lastWrittenRef.current = merged\n setOptionsState(merged)\n setLoading(false)\n })\n }, [docApi, config.namespace])\n\n const flushWrite = useCallback(\n async (value: T) => {\n try {\n if (config.namespace) {\n await grist.setOption(config.namespace, value)\n } else {\n await grist.setOptions({ ...value })\n }\n lastWrittenRef.current = value\n } catch (err) {\n setError(err instanceof Error ? err.message : String(err))\n }\n },\n [config.namespace]\n )\n\n const scheduleWrite = useCallback(\n (value: T) => {\n if (debounceRef.current) window.clearTimeout(debounceRef.current)\n debounceRef.current = window.setTimeout(() => {\n debounceRef.current = null\n void flushWrite(value)\n }, debounceMs)\n },\n [debounceMs, flushWrite]\n )\n\n useEffect(() => {\n return () => {\n if (debounceRef.current) window.clearTimeout(debounceRef.current)\n }\n }, [])\n\n const setOptionsApi = useCallback(\n (next: T) => {\n setOptionsState(next)\n scheduleWrite(next)\n },\n [scheduleWrite]\n )\n\n const patchOptionsApi = useCallback(\n (patch: Partial<T>) => {\n setOptionsState((prev) => {\n const next = { ...prev, ...patch }\n scheduleWrite(next)\n return next\n })\n },\n [scheduleWrite]\n )\n\n const reset = useCallback(async () => {\n if (debounceRef.current) {\n window.clearTimeout(debounceRef.current)\n debounceRef.current = null\n }\n const next = { ...defaultsRef.current }\n setOptionsState(next)\n await flushWrite(next)\n }, [flushWrite])\n\n return useMemo(\n () => ({\n options,\n loading,\n error: readyError ?? error,\n setOptions: setOptionsApi,\n patchOptions: patchOptionsApi,\n reset,\n }),\n [options, loading, readyError, error, setOptionsApi, patchOptionsApi, reset]\n )\n}\n","import { useCallback, useEffect, useState } from \"react\"\n\nimport type { GristColumnarTable } from \"./helpers/grist-table-data\"\nimport { useGristReady } from \"./low-level-hooks/use-grist-ready\"\nimport type { GristFetchSelectedOptions, GristReadyOptions, GristRequiredAccess } from \"./types\"\n\nexport type UseGristTableOptions = {\n requiredAccess?: GristRequiredAccess\n /**\n * `'current'` (default): follow the widget’s selected table.\n * Any other string: fixed table id (no `grist.selectedTable` polling).\n */\n tableId?: \"current\" | string\n} & Pick<GristReadyOptions, \"columns\" | \"allowSelectBy\" | \"hasCustomOptions\" | \"onEditOptions\">\n\nexport type UseGristTableResult = {\n tableId: string | null\n loading: boolean\n error: string | null\n refresh: () => Promise<void>\n fetchTable: (targetTableId: string) => Promise<GristColumnarTable>\n listTables: () => Promise<string[]>\n getDocName: () => Promise<string>\n fetchSelectedTable: (fetchOptions?: GristFetchSelectedOptions) => Promise<GristColumnarTable>\n fetchSelectedRecord: (rowId: number, fetchOptions?: GristFetchSelectedOptions) => Promise<Record<string, unknown>>\n}\n\nfunction isCurrentMode(option: string | undefined): boolean {\n return option === undefined || option === \"current\"\n}\n\n/**\n * Selected or fixed table id plus document reads — no raw `docApi` on the result.\n */\nexport function useGristTable(options?: UseGristTableOptions): UseGristTableResult {\n const requiredAccess = options?.requiredAccess ?? \"read table\"\n const tableIdOption = options?.tableId ?? \"current\"\n const { docApi, error: readyError } = useGristReady({\n requiredAccess,\n columns: options?.columns,\n allowSelectBy: options?.allowSelectBy,\n hasCustomOptions: options?.hasCustomOptions,\n onEditOptions: options?.onEditOptions,\n })\n const [tableId, setTableId] = useState<string | null>(null)\n const [loading, setLoading] = useState(false)\n const [error, setError] = useState<string | null>(null)\n\n const fetchTable = useCallback(\n async (targetTableId: string) => {\n if (!docApi) throw new Error(\"Grist is not ready\")\n return docApi.fetchTable(targetTableId) as Promise<GristColumnarTable>\n },\n [docApi]\n )\n\n const listTables = useCallback(async () => {\n if (!docApi) throw new Error(\"Grist is not ready\")\n const out = await Promise.resolve(docApi.listTables())\n return [...out]\n }, [docApi])\n\n const getDocName = useCallback(async () => {\n if (!docApi) throw new Error(\"Grist is not ready\")\n return String(await Promise.resolve(docApi.getDocName()))\n }, [docApi])\n\n const fetchSelectedTable = useCallback(\n async (fetchOptions?: GristFetchSelectedOptions) => {\n if (!docApi) throw new Error(\"Grist is not ready\")\n const impl = docApi.fetchSelectedTable ?? grist.fetchSelectedTable\n if (!impl) throw new Error(\"fetchSelectedTable is not available in this Grist version\")\n const merged: GristFetchSelectedOptions = { keepEncoded: false, format: \"rows\", ...fetchOptions }\n return (await impl(merged)) as GristColumnarTable\n },\n [docApi]\n )\n\n const fetchSelectedRecord = useCallback(\n async (rowId: number, fetchOptions?: GristFetchSelectedOptions) => {\n if (!docApi) throw new Error(\"Grist is not ready\")\n const impl = docApi.fetchSelectedRecord ?? grist.fetchSelectedRecord\n if (!impl) throw new Error(\"fetchSelectedRecord is not available in this Grist version\")\n const merged: GristFetchSelectedOptions = { keepEncoded: false, format: \"rows\", ...fetchOptions }\n return (await impl(rowId, merged)) as Record<string, unknown>\n },\n [docApi]\n )\n\n const refresh = useCallback(async () => {\n if (!docApi) return\n if (!isCurrentMode(tableIdOption)) {\n setTableId(tableIdOption)\n setError(null)\n return\n }\n setLoading(true)\n setError(null)\n try {\n const next = await grist.selectedTable?.getTableId()\n setTableId(next ?? null)\n } catch (err) {\n setTableId(null)\n setError(err instanceof Error ? err.message : String(err))\n } finally {\n setLoading(false)\n }\n }, [docApi, tableIdOption])\n\n useEffect(() => {\n if (docApi) void refresh()\n }, [docApi, refresh])\n\n return {\n tableId,\n loading,\n error: readyError ?? error,\n refresh,\n fetchTable,\n listTables,\n getDocName,\n fetchSelectedTable,\n fetchSelectedRecord,\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAUO,SAAS,qBAAqB,SAAuD;AAC1F,QAAM,EAAE,YAAY,IAAI,aAAa,OAAO;AAC5C,SAAO;AACT;;;ACGA,SAAS,WAAW,SAAS,QAAQ,4BAA4B;AAqC1D,SAAS,kBAAkB,UAAoC,CAAC,GAA4B;AAGjG,QAAM,aAAa,OAAO,OAAO;AACjC,aAAW,UAAU;AACrB,QAAM,aAAa,OAA+B,IAAI;AACtD,MAAI,WAAW,YAAY,MAAM;AAO/B,eAAW,UAAU,4BAA4B;AAAA,MAC/C,GAAG;AAAA,MACH,WAAW;AAAA,QACT,WAAW,CAAC,YAAY,iBAAiB,OAAO;AAAA,QAChD,GAAG,QAAQ;AAAA,MACb;AAAA,MACA,gBAAgB,MAAM;AACpB,iCAAyB;AACzB,gBAAQ,iBAAiB;AAAA,MAC3B;AAAA,IACF,CAAC;AAAA,EACH;AACA,QAAM,UAAU,WAAW;AAE3B,YAAU,MAAM;AACd,YAAQ,MAAM;AACd,WAAO,MAAM;AACX,cAAQ,KAAK;AAAA,IACf;AAAA,EACF,GAAG,CAAC,OAAO,CAAC;AAEZ,QAAM,WAAW;AAAA,IACf,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR;AAAA,EACF;AAEA,QAAM,YAAY;AAAA,IAChB,OAAO;AAAA,MACL,QAAQ,aAAa,QAAQ;AAAA,MAC7B,OAAO,mBAAmB,QAAQ;AAAA,MAClC,cAAc,mBAAmB,QAAQ;AAAA,IAC3C;AAAA,IACA,CAAC,QAAQ;AAAA,EACX;AAEA,SAAO;AAAA,IACL,OAAO;AAAA,MACL;AAAA,MACA,QAAQ,UAAU;AAAA,MAClB,OAAO,UAAU;AAAA,MACjB,cAAc,UAAU;AAAA,MACxB,QAAQ,QAAQ;AAAA,MAChB,SAAS,QAAQ;AAAA,IACnB;AAAA,IACA,CAAC,UAAU,WAAW,OAAO;AAAA,EAC/B;AACF;AAOO,SAAS,qBACd,UAAoC,CAAC,GAClB;AACnB,SAAO,kBAAkB,OAAO,EAAE;AACpC;;;AC9GA,SAAS,WAAAA,UAAS,wBAAAC,6BAA4B;AAsB9C,IAAM,gBAAgB,MAAM,MAAM;AAAC;AACnC,IAAM,qBAAqB,MAAM,qBAAqB;AAO/C,SAAS,2BAAkE;AAChF,QAAM,UAAU,wBAAwB;AAExC,QAAM,WAAWC;AAAA,IACf,SAAS,aAAa;AAAA,IACtB,SAAS,eAAe;AAAA,IACxB;AAAA,EACF;AAEA,SAAOC,SAAQ,MAAM;AACnB,QAAI,CAAC,QAAS,QAAO;AACrB,WAAO;AAAA,MACL;AAAA,MACA,QAAQ,aAAa,QAAQ;AAAA,MAC7B,OAAO,mBAAmB,QAAQ;AAAA,MAClC,cAAc,mBAAmB,QAAQ;AAAA,MACzC,QAAQ,QAAQ;AAAA,MAChB,SAAS,QAAQ;AAAA,IACnB;AAAA,EACF,GAAG,CAAC,SAAS,QAAQ,CAAC;AACxB;;;AChDA;AAAA,EACE;AAAA,EACA;AAAA,EACA,aAAAC;AAAA,EACA,WAAAC;AAAA,EACA,UAAAC;AAAA,EACA,wBAAAC;AAAA,OAEK;AAoGH;AAvEJ,IAAM,6BAA6B,cAAiD,IAAI;AAejF,SAAS,uBAAuB,EAAE,SAAS,SAAS,GAAgC;AAIzF,QAAM,aAAaC,QAA+B,IAAI;AACtD,MAAI,WAAW,YAAY,MAAM;AAS/B,eAAW,UAAU,4BAA4B;AAAA,MAC/C,GAAG;AAAA,MACH,WAAW;AAAA,QACT,WAAW,CAAC,YAAY,iBAAiB,OAAO;AAAA,QAChD,GAAG,SAAS;AAAA,MACd;AAAA,MACA,gBAAgB,MAAM;AACpB,iCAAyB;AACzB,iBAAS,iBAAiB;AAAA,MAC5B;AAAA,IACF,CAAC;AAAA,EACH;AACA,QAAM,UAAU,WAAW;AAE3B,EAAAC,WAAU,MAAM;AACd,YAAQ,MAAM;AACd,WAAO,MAAM;AACX,cAAQ,KAAK;AAAA,IACf;AAAA,EACF,GAAG,CAAC,OAAO,CAAC;AAEZ,QAAM,WAAWC;AAAA,IACf,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR;AAAA,EACF;AAEA,QAAM,QAAQC;AAAA,IACZ,OAAO;AAAA,MACL;AAAA,MACA,QAAQ,aAAa,QAAQ;AAAA,MAC7B,OAAO,mBAAmB,QAAQ;AAAA,MAClC,cAAc,mBAAmB,QAAQ;AAAA,MACzC,QAAQ,QAAQ;AAAA,MAChB,SAAS,QAAQ;AAAA,MACjB,kBAAkB,QAAQ;AAAA,MAC1B,kBAAkB,QAAQ;AAAA,IAC5B;AAAA,IACA,CAAC,UAAU,OAAO;AAAA,EACpB;AAEA,SACE,oBAAC,2BAA2B,UAA3B,EAAoC,OAClC,UACH;AAEJ;AASO,SAAS,2BAAuD;AACrE,QAAM,MAAM,WAAW,0BAA0B;AACjD,MAAI,CAAC,KAAK;AACR,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AAGO,SAAS,mCAAsE;AACpF,SAAO,WAAW,0BAA0B;AAC9C;;;ACtJA,SAAS,aAAAC,YAAW,UAAAC,SAAQ,gBAAgB;AAoBrC,SAAS,eACd,IACA,SACkC;AAClC,QAAM,QAAQC,QAAO,EAAE;AACvB,EAAAC,WAAU,MAAM;AACd,UAAM,UAAU;AAAA,EAClB,GAAG,CAAC,EAAE,CAAC;AAEP,QAAM,CAAC,UAAU,WAAW,IAAI,SAAsC,IAAI;AAC1E,QAAM,EAAE,QAAQ,OAAO,WAAW,IAAI,cAAc;AAAA,IAClD,gBAAgB,SAAS,kBAAkB;AAAA,IAC3C,SAAS,SAAS;AAAA,IAClB,eAAe,SAAS;AAAA,IACxB,kBAAkB,SAAS;AAAA,IAC3B,eAAe,SAAS;AAAA,EAC1B,CAAC;AAED,EAAAA,WAAU,MAAM;AACd,QAAI,CAAC,OAAQ;AACb,WAAO,YAAY,UAAU,CAAC,EAAE,QAAQ,UAAU,aAAa,MAAM;AACnE,kBAAY,YAAY;AACxB,YAAM,QAAQ,QAAQ,YAAY;AAAA,IACpC,CAAC;AAAA,EACH,GAAG,CAAC,MAAM,CAAC;AAEX,SAAO;AAAA,IACL,SAAS,WAAW,QAAQ,CAAC;AAAA,IAC7B,OAAO;AAAA,IACP;AAAA,EACF;AACF;;;ACnDA,SAAS,aAAAC,YAAW,UAAAC,SAAQ,YAAAC,iBAAgB;AAWrC,SAAS,gBACd,IACA,SACkC;AAClC,QAAM,QAAQC,QAAO,EAAE;AACvB,EAAAC,WAAU,MAAM;AACd,UAAM,UAAU;AAAA,EAClB,GAAG,CAAC,EAAE,CAAC;AAEP,QAAM,CAAC,UAAU,WAAW,IAAIC,UAAsC,IAAI;AAC1E,QAAM,EAAE,QAAQ,OAAO,WAAW,IAAI,cAAc;AAAA,IAClD,gBAAgB,SAAS,kBAAkB;AAAA,IAC3C,SAAS,SAAS;AAAA,IAClB,eAAe,SAAS;AAAA,IACxB,kBAAkB,SAAS;AAAA,IAC3B,eAAe,SAAS;AAAA,EAC1B,CAAC;AAED,EAAAD,WAAU,MAAM;AACd,QAAI,CAAC,OAAQ;AACb,WAAO,aAAa,UAAU,CAAC,EAAE,SAAS,UAAU,aAAa,MAAM;AACrE,kBAAY,YAAY;AACxB,YAAM,QAAQ,SAAS,YAAY;AAAA,IACrC,CAAC;AAAA,EACH,GAAG,CAAC,MAAM,CAAC;AAEX,SAAO;AAAA,IACL,SAAS,WAAW,QAAQ,CAAC;AAAA,IAC7B,OAAO;AAAA,IACP;AAAA,EACF;AACF;;;AC1CA,SAAS,aAAAE,YAAW,UAAAC,SAAQ,YAAAC,iBAAgB;AAuBrC,SAAS,kBAAkB,SAAsD;AACtF,QAAM,EAAE,QAAQ,OAAO,WAAW,IAAI,cAAc;AAAA,IAClD,gBAAgB,SAAS,kBAAkB;AAAA,IAC3C,SAAS,SAAS;AAAA,IAClB,eAAe,SAAS;AAAA,IACxB,kBAAkB,SAAS;AAAA,IAC3B,eAAe,SAAS;AAAA,EAC1B,CAAC;AAED,QAAM,CAAC,aAAa,cAAc,IAAIC,UAAS,KAAK;AACpD,QAAM,CAAC,UAAU,WAAW,IAAIA,UAAsC,IAAI;AAC1E,QAAM,gBAAgBC,QAAO,KAAK;AAElC,EAAAC,WAAU,MAAM;AACd,QAAI,CAAC,UAAU,cAAc,QAAS;AACtC,QAAI,OAAO,MAAM,gBAAgB,WAAY;AAC7C,kBAAc,UAAU;AACxB,WAAO,eAAe,UAAU,CAAC,EAAE,UAAU,aAAa,MAAM;AAC9D,qBAAe,IAAI;AACnB,kBAAY,YAAY;AAAA,IAC1B,CAAC;AAAA,EACH,GAAG,CAAC,MAAM,CAAC;AAEX,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,SAAS,WAAW,QAAQ,CAAC;AAAA,IAC7B,OAAO;AAAA,EACT;AACF;;;ACpDA,SAAS,aAAa,YAAAC,iBAAgB;AA6D/B,SAAS,gBAAgB,SAAyD;AACvF,QAAM,iBAAiB,SAAS,kBAAkB;AAClD,QAAM,EAAE,QAAQ,OAAO,WAAW,IAAI,cAAc;AAAA,IAClD;AAAA,IACA,SAAS,SAAS;AAAA,IAClB,eAAe,SAAS;AAAA,IACxB,kBAAkB,SAAS;AAAA,IAC3B,eAAe,SAAS;AAAA,EAC1B,CAAC;AACD,QAAM,CAAC,QAAQ,SAAS,IAAIC,UAA6B,MAAM;AAC/D,QAAM,CAAC,aAAa,cAAc,IAAIA,UAAwB,IAAI;AAClE,QAAM,cAAc,wBAAwB;AAE5C,QAAM,QAAQ;AAAA,IACZ,OAAO,SAAiC,iBAAkE;AACxG,UAAI,CAAC,OAAQ,OAAM,IAAI,MAAM,2BAA2B;AACxD,gBAAU,SAAS;AACnB,qBAAe,IAAI;AACnB,UAAI;AACF,cAAM,MAAM,MAAM,YAAY,MAAM,OAAO,iBAAiB,SAAS,YAAY,CAAC;AAClF,kBAAU,MAAM;AAChB,eAAO;AAAA,MACT,SAAS,KAAK;AACZ,cAAM,UAAU,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC/D,uBAAe,OAAO;AACtB,kBAAU,OAAO;AACjB,cAAM;AAAA,MACR;AAAA,IACF;AAAA,IACA,CAAC,QAAQ,WAAW;AAAA,EACtB;AAEA,QAAM,eAAe;AAAA,IACnB,CAAC,SAAiB,UAAkB,OAAgC,iBAClE,MAAM,CAAC,wBAAwB,SAAS,UAAU,KAAK,CAAC,GAAG,YAAY;AAAA,IACzE,CAAC,KAAK;AAAA,EACR;AAEA,QAAM,YAAY;AAAA,IAChB,CAAC,SAAiB,QAAiC,iBACjD,MAAM,CAAC,qBAAqB,SAAS,MAAM,CAAC,GAAG,YAAY;AAAA,IAC7D,CAAC,KAAK;AAAA,EACR;AAEA,QAAM,eAAe;AAAA,IACnB,CAAC,SAAiB,UAAkB,iBAClC,MAAM,CAAC,wBAAwB,SAAS,QAAQ,CAAC,GAAG,YAAY;AAAA,IAClE,CAAC,KAAK;AAAA,EACR;AAEA,QAAM,gBAAgB;AAAA,IACpB,CAAC,SAAiB,QAAmC,iBACnD,MAAM,CAAC,yBAAyB,SAAS,MAAM,CAAC,GAAG,YAAY;AAAA,IACjE,CAAC,KAAK;AAAA,EACR;AAEA,QAAM,mBAAmB;AAAA,IACvB,CAAC,SAAiB,QAAkB,eAA0C,iBAC5E,MAAM,CAAC,4BAA4B,SAAS,QAAQ,aAAa,CAAC,GAAG,YAAY;AAAA,IACnF,CAAC,KAAK;AAAA,EACR;AAEA,QAAM,mBAAmB;AAAA,IACvB,CAAC,SAAiB,QAAkB,iBAClC,MAAM,CAAC,4BAA4B,SAAS,MAAM,CAAC,GAAG,YAAY;AAAA,IACpE,CAAC,KAAK;AAAA,EACR;AAEA,SAAO;AAAA,IACL,QAAQ,aAAa,UAAU;AAAA,IAC/B,OAAO,cAAc;AAAA,IACrB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;;;AC5IA,SAAS,eAAAC,cAAa,aAAAC,YAAW,YAAAC,iBAAgB;AAyBjD,SAAS,cAAiB,OAAmB,UAAgE;AAC3G,MAAI,CAAC,SAAU,QAAO,EAAE,GAAI,MAAkC;AAC9D,QAAM,MAA+B,CAAC;AACtC,aAAW,CAAC,MAAM,KAAK,KAAK,OAAO,QAAQ,KAAgC,GAAG;AAC5E,UAAM,SAAS,SAAS,IAAI;AAC5B,QAAI,MAAM,QAAQ,MAAM,GAAG;AAEzB,UAAI,OAAO,YAAY,aAAa;AAClC,gBAAQ,KAAK,gEAAgE,IAAI,oCAAoC;AAAA,MACvH;AACA;AAAA,IACF;AACA,QAAI,UAAU,IAAI,IAAI;AAAA,EACxB;AACA,SAAO;AACT;AAMO,SAAS,qBACd,SAC+B;AAC/B,QAAM,iBAAiB,SAAS,kBAAkB;AAClD,QAAM,EAAE,QAAQ,OAAO,WAAW,IAAI,cAAc;AAAA,IAClD;AAAA,IACA,SAAS,SAAS;AAAA,IAClB,eAAe,SAAS;AAAA,IACxB,kBAAkB,SAAS;AAAA,IAC3B,eAAe,SAAS;AAAA,EAC1B,CAAC;AACD,QAAM,CAAC,WAAW,YAAY,IAAIC,UAAyC,IAAI;AAC/E,QAAM,CAAC,cAAc,eAAe,IAAIA,UAAmB,IAAI;AAC/D,QAAM,CAAC,UAAU,WAAW,IAAIA,UAAsC,IAAI;AAE1E,EAAAC,WAAU,MAAM;AACd,QAAI,CAAC,OAAQ;AACb,WAAO,YAAY,UAAU,CAAC,EAAE,QAAQ,UAAU,aAAa,MAAM;AACnE,mBAAa,MAAM;AACnB,kBAAY,YAAY;AACxB,UAAI,CAAC,QAAQ;AACX,wBAAgB,IAAI;AACpB;AAAA,MACF;AACA,UAAI,OAAO,MAAM,mBAAmB,YAAY;AAC9C,cAAM,SAAS,MAAM,eAAe,MAAM;AAC1C;AAAA,UACE,WAAW,QAAQ,WAAW,SAAa,SAAe;AAAA,QAC5D;AACA;AAAA,MACF;AACA,sBAAgB,MAAW;AAAA,IAC7B,CAAC;AAAA,EACH,GAAG,CAAC,MAAM,CAAC;AAEX,QAAM,UAAUC;AAAA,IACd,CAAC,UAA+C;AAC9C,UAAI,OAAO,MAAM,uBAAuB,YAAY;AAClD,eAAO,MAAM,mBAAmB,KAAgC;AAAA,MAClE;AACA,aAAO,cAAiB,OAAO,QAAQ;AAAA,IACzC;AAAA,IACA,CAAC,QAAQ;AAAA,EACX;AAEA,QAAM,kBAAkBA;AAAA,IACtB,CAAC,gBAAsD;AACrD,YAAM,QAAQ,WAAW,WAAW;AACpC,UAAI,MAAM,QAAQ,KAAK,EAAG,QAAO;AACjC,aAAO,SAAS;AAAA,IAClB;AAAA,IACA,CAAC,QAAQ;AAAA,EACX;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA,SAAS,WAAW,QAAQ,CAAC;AAAA,IAC7B,OAAO;AAAA,IACP;AAAA,IACA;AAAA,EACF;AACF;;;AC7GA,SAAS,eAAAC,cAAa,YAAAC,iBAAgB;AAgDtC,SAAS,WAAW,SAAoD;AACtE,MAAI,YAAY,YAAY;AAC1B,QAAI,CAAC,MAAM,cAAe,OAAM,IAAI,MAAM,sCAAsC;AAChF,WAAO,MAAM;AAAA,EACf;AACA,MAAI,OAAO,MAAM,aAAa,YAAY;AACxC,UAAM,IAAI,MAAM,uDAAuD;AAAA,EACzE;AACA,SAAO,MAAM,SAAS,OAAO;AAC/B;AAQO,SAAS,iBAAiB,SAA2D;AAC1F,QAAM,iBAAiB,SAAS,kBAAkB;AAClD,QAAM,gBAAqC,SAAS,WAAW;AAC/D,QAAM,EAAE,QAAQ,OAAO,WAAW,IAAI,cAAc;AAAA,IAClD;AAAA,IACA,SAAS,SAAS;AAAA,IAClB,eAAe,SAAS;AAAA,IACxB,kBAAkB,SAAS;AAAA,IAC3B,eAAe,SAAS;AAAA,EAC1B,CAAC;AAED,QAAM,CAAC,QAAQ,SAAS,IAAIC,UAA8B,MAAM;AAChE,QAAM,CAAC,aAAa,cAAc,IAAIA,UAAwB,IAAI;AAClE,QAAM,cAAc,wBAAwB;AAI5C,MAAI,MAAmC;AACvC,MAAI,eAA8B;AAClC,MAAI,QAAQ;AACV,QAAI;AACF,YAAM,WAAW,aAAa;AAAA,IAChC,SAAS,KAAK;AACZ,qBAAe,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAAA,IAChE;AAAA,EACF;AAEA,QAAM,OAAOC;AAAA,IACX,OAAU,QAA+D;AACvE,UAAI,CAAC,IAAK,OAAM,IAAI,MAAM,sCAAsC;AAChE,gBAAU,SAAS;AACnB,qBAAe,IAAI;AACnB,UAAI;AACF,cAAM,MAAM,MAAM,YAAY,MAAM,IAAI,GAAG,CAAC;AAC5C,kBAAU,MAAM;AAChB,eAAO;AAAA,MACT,SAAS,KAAK;AACZ,cAAM,UAAU,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC/D,uBAAe,OAAO;AACtB,kBAAU,OAAO;AACjB,cAAM;AAAA,MACR;AAAA,IACF;AAAA,IACA,CAAC,KAAK,WAAW;AAAA,EACnB;AAEA,QAAM,aAAaA,aAAY,YAAY;AACzC,QAAI,CAAC,IAAK,OAAM,IAAI,MAAM,sCAAsC;AAChE,WAAO,IAAI,WAAW;AAAA,EACxB,GAAG,CAAC,GAAG,CAAC;AAER,QAAM,SAASA;AAAA,IACb,CAAC,SAAsD,cACrD,KAAK,CAAC,MAAM,EAAE,OAAO,SAAS,SAAS,CAAC;AAAA,IAC1C,CAAC,IAAI;AAAA,EACP;AAEA,QAAM,SAASA;AAAA,IACb,CAAC,SAA4D,cAC3D,KAAK,CAAC,MAAM,EAAE,OAAO,SAAS,SAAS,CAAC;AAAA,IAC1C,CAAC,IAAI;AAAA,EACP;AAEA,QAAM,SAASA;AAAA,IACb,CAAC,SAA4D,cAC3D,KAAK,CAAC,MAAM,EAAE,OAAO,SAAS,SAAS,CAAC;AAAA,IAC1C,CAAC,IAAI;AAAA,EACP;AAEA,QAAM,UAAUA;AAAA,IACd,CAAC,cAAiC,KAAK,CAAC,MAAM,EAAE,QAAQ,SAAS,CAAC;AAAA,IAClE,CAAC,IAAI;AAAA,EACP;AAEA,SAAO;AAAA,IACL,QAAQ,cAAc,eAAe,UAAU;AAAA,IAC/C,OAAO,cAAc,gBAAgB;AAAA,IACrC;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;;;ACpJA,SAAS,eAAAC,cAAa,cAAAC,aAAY,aAAAC,YAAW,UAAAC,SAAQ,YAAAC,iBAAgB;AAiC9D,SAAS,sBACd,SACgC;AAChC,QAAM,iBAAiB,QAAQ,kBAAkB;AACjD,QAAM,EAAE,QAAQ,OAAO,WAAW,IAAI,cAAc;AAAA,IAClD;AAAA,IACA,SAAS,QAAQ;AAAA,IACjB,eAAe,QAAQ;AAAA,IACvB,kBAAkB,QAAQ;AAAA,IAC1B,eAAe,QAAQ;AAAA,EACzB,CAAC;AAID,QAAM,qBAAqBC,YAAW,iBAAiB,GAAG;AAE1D,QAAM,CAAC,MAAM,OAAO,IAAIC,UAAqC,IAAI;AACjE,QAAM,CAAC,SAAS,UAAU,IAAIA,UAAS,KAAK;AAC5C,QAAM,CAAC,YAAY,aAAa,IAAIA,UAAwB,IAAI;AAChE,QAAM,eAAeC,QAAO,QAAQ,SAAS;AAC7C,eAAa,UAAU,QAAQ;AAC/B,QAAM,cAAc,wBAAwB;AAE5C,QAAM,UAAUC,aAAY,YAAY;AACtC,QAAI,CAAC,OAAQ;AACb,eAAW,IAAI;AACf,kBAAc,IAAI;AAClB,QAAI;AACF,YAAM,OAAO,qBACT,MAAM,mBAAmB,QAAQ,OAAO,IACtC,MAAM;AAAA,QACN,MAAM,OAAO,WAAW,QAAQ,OAAO;AAAA,MACzC;AACJ,YAAM,MAAM,gBAAgB,IAAI;AAChC,YAAM,IAAI,aAAa;AACvB,cAAQ,IAAI,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,IAAK,GAA2B;AAAA,IACjE,SAAS,KAAK;AACZ,oBAAc,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAC9D,cAAQ,IAAI;AAAA,IACd,UAAE;AACA,iBAAW,KAAK;AAAA,IAClB;AAAA,EACF,GAAG,CAAC,QAAQ,oBAAoB,QAAQ,SAAS,WAAW,CAAC;AAE7D,EAAAC,WAAU,MAAM;AACd,QAAI,OAAQ,MAAK,QAAQ;AAAA,EAC3B,GAAG,CAAC,QAAQ,OAAO,CAAC;AAEpB,EAAAA,WAAU,MAAM;AACd,QAAI,CAAC,UAAU,CAAC,QAAQ,kBAAkB,QAAQ,kBAAkB,EAAG;AACvE,UAAM,KAAK,OAAO,YAAY,MAAM,KAAK,QAAQ,GAAG,QAAQ,cAAc;AAC1E,WAAO,MAAM,OAAO,cAAc,EAAE;AAAA,EACtC,GAAG,CAAC,QAAQ,QAAQ,gBAAgB,OAAO,CAAC;AAE5C,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,OAAO,cAAc;AAAA,IACrB;AAAA,EACF;AACF;;;AC7FA,SAAS,eAAAC,cAAa,aAAAC,YAAW,YAAAC,iBAAgB;AAiC1C,SAAS,oBAAoB,SAAiE;AACnG,QAAM,iBAAiB,SAAS,kBAAkB;AAClD,QAAM,kBAAkB,SAAS,YAAY;AAC7C,QAAM,WAAW,SAAS,YAAY;AACtC,QAAM,EAAE,QAAQ,OAAO,WAAW,IAAI,cAAc;AAAA,IAClD;AAAA,IACA,SAAS,SAAS;AAAA,IAClB,eAAe,SAAS;AAAA,IACxB,kBAAkB,SAAS;AAAA,IAC3B,eAAe,SAAS;AAAA,EAC1B,CAAC;AAED,QAAM,CAAC,OAAO,QAAQ,IAAIC,UAAkC,IAAI;AAChE,QAAM,CAAC,SAAS,UAAU,IAAIA,UAAS,KAAK;AAC5C,QAAM,CAAC,OAAO,QAAQ,IAAIA,UAAwB,IAAI;AAEtD,QAAM,UAAUC;AAAA,IACd,OAAO,cAAkE;AACvE,UAAI,CAAC,OAAQ,OAAM,IAAI,MAAM,oBAAoB;AACjD,iBAAW,IAAI;AACf,eAAS,IAAI;AACb,UAAI;AACF,cAAM,OAAO,MAAM,oBAAoB,QAAQ,EAAE,UAAU,WAAW,YAAY,gBAAgB,CAAC;AACnG,iBAAS,IAAI;AACb,eAAO;AAAA,MACT,SAAS,KAAK;AACZ,cAAM,UAAU,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC/D,iBAAS,OAAO;AAChB,cAAM;AAAA,MACR,UAAE;AACA,mBAAW,KAAK;AAAA,MAClB;AAAA,IACF;AAAA,IACA,CAAC,QAAQ,eAAe;AAAA,EAC1B;AAEA,QAAM,UAAUA;AAAA,IACd,CAAC,MAAc,SAAgD;AAC7D,UAAI,CAAC,OAAQ,OAAM,IAAI,MAAM,oBAAoB;AACjD,aAAO,mBAAuB,QAAQ,MAAM,EAAE,UAAU,iBAAiB,GAAG,KAAK,CAAC;AAAA,IACpF;AAAA,IACA,CAAC,QAAQ,eAAe;AAAA,EAC1B;AAEA,EAAAC,WAAU,MAAM;AACd,QAAI,UAAU,SAAU,MAAK,QAAQ;AAAA,EACvC,GAAG,CAAC,QAAQ,UAAU,OAAO,CAAC;AAE9B,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,OAAO,cAAc;AAAA,IACrB;AAAA,IACA,OAAO;AAAA,EACT;AACF;;;ACxFA,SAAS,eAAAC,cAAa,aAAAC,YAAW,YAAAC,iBAAgB;AAyB1C,SAAS,gBAAgB,SAAoD;AAClF,QAAM,EAAE,QAAQ,OAAO,WAAW,IAAI,cAAc;AAAA,IAClD,gBAAgB,SAAS,kBAAkB;AAAA,IAC3C,SAAS,SAAS;AAAA,IAClB,eAAe,SAAS;AAAA,IACxB,kBAAkB,SAAS;AAAA,IAC3B,eAAe,SAAS;AAAA,EAC1B,CAAC;AAED,QAAM,CAAC,UAAU,WAAW,IAAIC,UAAsC,IAAI;AAC1E,QAAM,CAAC,SAAS,UAAU,IAAIA,UAAS,KAAK;AAC5C,QAAM,CAAC,OAAO,QAAQ,IAAIA,UAAwB,IAAI;AAEtD,QAAM,UAAUC,aAAY,YAAY;AACtC,QAAI,CAAC,OAAQ;AACb,QAAI,CAAC,MAAM,YAAY,UAAU;AAC/B,eAAS,kEAAkE;AAC3E;AAAA,IACF;AACA,eAAW,IAAI;AACf,aAAS,IAAI;AACb,QAAI;AACF,YAAM,OAAO,MAAM,MAAM,WAAW,SAAS;AAC7C,kBAAY,IAAI;AAAA,IAClB,SAAS,KAAK;AACZ,eAAS,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,IAC3D,UAAE;AACA,iBAAW,KAAK;AAAA,IAClB;AAAA,EACF,GAAG,CAAC,MAAM,CAAC;AAEX,QAAM,YAAYA,aAAY,OAAO,SAA4B;AAC/D,QAAI,CAAC,MAAM,YAAY,WAAW;AAChC,YAAM,IAAI,MAAM,mEAAmE;AAAA,IACrF;AACA,UAAM,MAAM,WAAW,UAAU,IAAI;AAAA,EACvC,GAAG,CAAC,CAAC;AAEL,EAAAC,WAAU,MAAM;AACd,QAAI,OAAQ,MAAK,QAAQ;AAAA,EAC3B,GAAG,CAAC,QAAQ,OAAO,CAAC;AAEpB,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,OAAO,cAAc;AAAA,IACrB;AAAA,IACA;AAAA,EACF;AACF;;;AC1EA,SAAS,eAAAC,cAAa,aAAAC,aAAW,WAAAC,UAAS,UAAAC,SAAQ,YAAAC,kBAAgB;AAiClE,SAAS,kBAAqB,UAAa,QAAiB,WAAuB;AACjF,MAAI,WAAW,QAAQ,WAAW,OAAW,QAAO,EAAE,GAAG,SAAS;AAClE,QAAM,SAAU,YAAa,OAAmC,SAAS,IAAI;AAC7E,MAAI,CAAC,UAAU,OAAO,WAAW,SAAU,QAAO,EAAE,GAAG,SAAS;AAChE,SAAO,EAAE,GAAG,UAAU,GAAG,OAAO;AAClC;AAUO,SAAS,sBACd,QACgC;AAChC,QAAM,iBAAiB,OAAO,kBAAkB;AAChD,QAAM,aAAa,OAAO,cAAc;AACxC,QAAM,mBAAmB,OAAO,oBAAoB;AACpD,QAAM,EAAE,QAAQ,OAAO,WAAW,IAAI,cAAc;AAAA,IAClD;AAAA,IACA,SAAS,OAAO;AAAA,IAChB,eAAe,OAAO;AAAA,IACtB;AAAA,IACA,eAAe,OAAO;AAAA,EACxB,CAAC;AAED,QAAM,cAAcC,QAAO,OAAO,QAAQ;AAC1C,EAAAC,YAAU,MAAM;AACd,gBAAY,UAAU,OAAO;AAAA,EAC/B,GAAG,CAAC,OAAO,QAAQ,CAAC;AAEpB,QAAM,CAAC,SAAS,eAAe,IAAIC,WAAY,OAAO,EAAE,GAAG,OAAO,SAAS,EAAE;AAC7E,QAAM,CAAC,SAAS,UAAU,IAAIA,WAAS,IAAI;AAC3C,QAAM,CAAC,OAAO,QAAQ,IAAIA,WAAwB,IAAI;AACtD,QAAM,iBAAiBF,QAAiB,IAAI;AAC5C,QAAM,cAAcA,QAAsB,IAAI;AAG9C,EAAAC,YAAU,MAAM;AACd,QAAI,CAAC,OAAQ;AACb,WAAO,aAAa,UAAU,CAAC,EAAE,SAAS,OAAO,MAAM;AACrD,YAAM,SAAS,kBAAkB,YAAY,SAAS,QAAQ,OAAO,SAAS;AAC9E,qBAAe,UAAU;AACzB,sBAAgB,MAAM;AACtB,iBAAW,KAAK;AAAA,IAClB,CAAC;AAAA,EACH,GAAG,CAAC,QAAQ,OAAO,SAAS,CAAC;AAE7B,QAAM,aAAaE;AAAA,IACjB,OAAO,UAAa;AAClB,UAAI;AACF,YAAI,OAAO,WAAW;AACpB,gBAAM,MAAM,UAAU,OAAO,WAAW,KAAK;AAAA,QAC/C,OAAO;AACL,gBAAM,MAAM,WAAW,EAAE,GAAG,MAAM,CAAC;AAAA,QACrC;AACA,uBAAe,UAAU;AAAA,MAC3B,SAAS,KAAK;AACZ,iBAAS,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,MAC3D;AAAA,IACF;AAAA,IACA,CAAC,OAAO,SAAS;AAAA,EACnB;AAEA,QAAM,gBAAgBA;AAAA,IACpB,CAAC,UAAa;AACZ,UAAI,YAAY,QAAS,QAAO,aAAa,YAAY,OAAO;AAChE,kBAAY,UAAU,OAAO,WAAW,MAAM;AAC5C,oBAAY,UAAU;AACtB,aAAK,WAAW,KAAK;AAAA,MACvB,GAAG,UAAU;AAAA,IACf;AAAA,IACA,CAAC,YAAY,UAAU;AAAA,EACzB;AAEA,EAAAF,YAAU,MAAM;AACd,WAAO,MAAM;AACX,UAAI,YAAY,QAAS,QAAO,aAAa,YAAY,OAAO;AAAA,IAClE;AAAA,EACF,GAAG,CAAC,CAAC;AAEL,QAAM,gBAAgBE;AAAA,IACpB,CAAC,SAAY;AACX,sBAAgB,IAAI;AACpB,oBAAc,IAAI;AAAA,IACpB;AAAA,IACA,CAAC,aAAa;AAAA,EAChB;AAEA,QAAM,kBAAkBA;AAAA,IACtB,CAAC,UAAsB;AACrB,sBAAgB,CAAC,SAAS;AACxB,cAAM,OAAO,EAAE,GAAG,MAAM,GAAG,MAAM;AACjC,sBAAc,IAAI;AAClB,eAAO;AAAA,MACT,CAAC;AAAA,IACH;AAAA,IACA,CAAC,aAAa;AAAA,EAChB;AAEA,QAAM,QAAQA,aAAY,YAAY;AACpC,QAAI,YAAY,SAAS;AACvB,aAAO,aAAa,YAAY,OAAO;AACvC,kBAAY,UAAU;AAAA,IACxB;AACA,UAAM,OAAO,EAAE,GAAG,YAAY,QAAQ;AACtC,oBAAgB,IAAI;AACpB,UAAM,WAAW,IAAI;AAAA,EACvB,GAAG,CAAC,UAAU,CAAC;AAEf,SAAOC;AAAA,IACL,OAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA,OAAO,cAAc;AAAA,MACrB,YAAY;AAAA,MACZ,cAAc;AAAA,MACd;AAAA,IACF;AAAA,IACA,CAAC,SAAS,SAAS,YAAY,OAAO,eAAe,iBAAiB,KAAK;AAAA,EAC7E;AACF;;;AC7JA,SAAS,eAAAC,cAAa,aAAAC,aAAW,YAAAC,kBAAgB;AA2BjD,SAAS,cAAc,QAAqC;AAC1D,SAAO,WAAW,UAAa,WAAW;AAC5C;AAKO,SAAS,cAAc,SAAqD;AACjF,QAAM,iBAAiB,SAAS,kBAAkB;AAClD,QAAM,gBAAgB,SAAS,WAAW;AAC1C,QAAM,EAAE,QAAQ,OAAO,WAAW,IAAI,cAAc;AAAA,IAClD;AAAA,IACA,SAAS,SAAS;AAAA,IAClB,eAAe,SAAS;AAAA,IACxB,kBAAkB,SAAS;AAAA,IAC3B,eAAe,SAAS;AAAA,EAC1B,CAAC;AACD,QAAM,CAAC,SAAS,UAAU,IAAIC,WAAwB,IAAI;AAC1D,QAAM,CAAC,SAAS,UAAU,IAAIA,WAAS,KAAK;AAC5C,QAAM,CAAC,OAAO,QAAQ,IAAIA,WAAwB,IAAI;AAEtD,QAAM,aAAaC;AAAA,IACjB,OAAO,kBAA0B;AAC/B,UAAI,CAAC,OAAQ,OAAM,IAAI,MAAM,oBAAoB;AACjD,aAAO,OAAO,WAAW,aAAa;AAAA,IACxC;AAAA,IACA,CAAC,MAAM;AAAA,EACT;AAEA,QAAM,aAAaA,aAAY,YAAY;AACzC,QAAI,CAAC,OAAQ,OAAM,IAAI,MAAM,oBAAoB;AACjD,UAAM,MAAM,MAAM,QAAQ,QAAQ,OAAO,WAAW,CAAC;AACrD,WAAO,CAAC,GAAG,GAAG;AAAA,EAChB,GAAG,CAAC,MAAM,CAAC;AAEX,QAAM,aAAaA,aAAY,YAAY;AACzC,QAAI,CAAC,OAAQ,OAAM,IAAI,MAAM,oBAAoB;AACjD,WAAO,OAAO,MAAM,QAAQ,QAAQ,OAAO,WAAW,CAAC,CAAC;AAAA,EAC1D,GAAG,CAAC,MAAM,CAAC;AAEX,QAAM,qBAAqBA;AAAA,IACzB,OAAO,iBAA6C;AAClD,UAAI,CAAC,OAAQ,OAAM,IAAI,MAAM,oBAAoB;AACjD,YAAM,OAAO,OAAO,sBAAsB,MAAM;AAChD,UAAI,CAAC,KAAM,OAAM,IAAI,MAAM,2DAA2D;AACtF,YAAM,SAAoC,EAAE,aAAa,OAAO,QAAQ,QAAQ,GAAG,aAAa;AAChG,aAAQ,MAAM,KAAK,MAAM;AAAA,IAC3B;AAAA,IACA,CAAC,MAAM;AAAA,EACT;AAEA,QAAM,sBAAsBA;AAAA,IAC1B,OAAO,OAAe,iBAA6C;AACjE,UAAI,CAAC,OAAQ,OAAM,IAAI,MAAM,oBAAoB;AACjD,YAAM,OAAO,OAAO,uBAAuB,MAAM;AACjD,UAAI,CAAC,KAAM,OAAM,IAAI,MAAM,4DAA4D;AACvF,YAAM,SAAoC,EAAE,aAAa,OAAO,QAAQ,QAAQ,GAAG,aAAa;AAChG,aAAQ,MAAM,KAAK,OAAO,MAAM;AAAA,IAClC;AAAA,IACA,CAAC,MAAM;AAAA,EACT;AAEA,QAAM,UAAUA,aAAY,YAAY;AACtC,QAAI,CAAC,OAAQ;AACb,QAAI,CAAC,cAAc,aAAa,GAAG;AACjC,iBAAW,aAAa;AACxB,eAAS,IAAI;AACb;AAAA,IACF;AACA,eAAW,IAAI;AACf,aAAS,IAAI;AACb,QAAI;AACF,YAAM,OAAO,MAAM,MAAM,eAAe,WAAW;AACnD,iBAAW,QAAQ,IAAI;AAAA,IACzB,SAAS,KAAK;AACZ,iBAAW,IAAI;AACf,eAAS,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,IAC3D,UAAE;AACA,iBAAW,KAAK;AAAA,IAClB;AAAA,EACF,GAAG,CAAC,QAAQ,aAAa,CAAC;AAE1B,EAAAC,YAAU,MAAM;AACd,QAAI,OAAQ,MAAK,QAAQ;AAAA,EAC3B,GAAG,CAAC,QAAQ,OAAO,CAAC;AAEpB,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,OAAO,cAAc;AAAA,IACrB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;","names":["useMemo","useSyncExternalStore","useSyncExternalStore","useMemo","useEffect","useMemo","useRef","useSyncExternalStore","useRef","useEffect","useSyncExternalStore","useMemo","useEffect","useRef","useRef","useEffect","useEffect","useRef","useState","useRef","useEffect","useState","useEffect","useRef","useState","useState","useRef","useEffect","useState","useState","useCallback","useEffect","useState","useState","useEffect","useCallback","useCallback","useState","useState","useCallback","useCallback","useContext","useEffect","useRef","useState","useContext","useState","useRef","useCallback","useEffect","useCallback","useEffect","useState","useState","useCallback","useEffect","useCallback","useEffect","useState","useState","useCallback","useEffect","useCallback","useEffect","useMemo","useRef","useState","useRef","useEffect","useState","useCallback","useMemo","useCallback","useEffect","useState","useState","useCallback","useEffect"]}
|
|
1
|
+
{"version":3,"sources":["../src/sdk/low-level-hooks/use-grist-availability.ts","../src/sdk/low-level-hooks/use-grist-handshake.ts","../src/sdk/low-level-hooks/use-ambient-grist-handshake.ts","../src/sdk/components/grist-handshake-provider.tsx","../src/sdk/low-level-hooks/use-grist-record.ts","../src/sdk/low-level-hooks/use-grist-records.ts","../src/sdk/low-level-hooks/use-grist-new-record.ts","../src/sdk/mid-level-hooks/use-grist-actions.ts","../src/sdk/mid-level-hooks/use-grist-mapped-record.ts","../src/sdk/mid-level-hooks/use-grist-table-ops.ts","../src/sdk/mid-level-hooks/use-grist-rows-from-table.ts","../src/sdk/mid-level-hooks/use-grist-access-token.ts","../src/sdk/mid-level-hooks/use-grist-section.ts","../src/sdk/mid-level-hooks/use-grist-widget-options.ts","../src/sdk/use-grist-table.ts"],"sourcesContent":["import { useGristCore, type UseGristCoreOptions } from \"../internal/hooks/use-grist-core\"\n\nexport type UseGristAvailabilityOptions = Pick<\n UseGristCoreOptions,\n \"availabilityMaxAttempts\" | \"availabilityIntervalMs\" | \"logWhenNotEmbedded\"\n>\n\n/**\n * Handshake-backed availability — projects `isAvailable` from the FSM.\n */\nexport function useGristAvailability(options?: UseGristAvailabilityOptions): boolean | null {\n const { isAvailable } = useGristCore(options)\n return isAvailable\n}\n","/**\n * `useGristHandshake()` — React adapter over {@link GristHandshakeManager}.\n *\n * Exposes the full {@link GristWidgetSnapshot} plus derived\n * {@link GristCapabilities}, plus `reload()` / `restart()` controls.\n *\n * Identity stability\n * ------------------\n * The snapshot reference changes whenever the reducer produces a new\n * snapshot. Capabilities are memoized by snapshot identity, so consumers\n * branching on a single capability (e.g. `canWriteRecords`) avoid extra\n * re-renders unless that boolean actually flips.\n *\n * SSR-safe: `getServerSnapshot` returns the initial snapshot deterministically.\n */\n\nimport { useEffect, useMemo, useRef, useSyncExternalStore } from \"react\"\n\nimport {\n deriveCapabilities,\n deriveErrorMessage,\n deriveStatus,\n initialGristSnapshot,\n type GristCapabilities,\n type GristWidgetSnapshot,\n type GristWidgetStatus,\n} from \"../internal/handshake\"\nimport {\n createGristHandshakeManager,\n type ManagerControls,\n type ManagerOptions,\n} from \"../internal/handshake/manager\"\nimport { ensureGristReady, resetGristReadySingleton } from \"../internal/ready-singleton\"\n\nexport type UseGristHandshakeOptions = ManagerOptions\n\nexport type UseGristHandshakeResult = {\n snapshot: GristWidgetSnapshot\n status: GristWidgetStatus\n error: string | null\n capabilities: GristCapabilities\n reload: () => void\n restart: () => void\n}\n\n/**\n * Mount a handshake manager local to the component subtree. Multiple\n * widgets in the same page should NOT call this in parallel — instead,\n * mount a single `<GristWidgetProvider>` at the app root.\n *\n * In tests, pass `options.env` (see `createTestEnvironment`) to drive the\n * machine with a virtual clock.\n */\nexport function useGristHandshake(options: UseGristHandshakeOptions = {}): UseGristHandshakeResult {\n // Memoize the manager so it survives re-renders. Caller is responsible for\n // passing stable options; in practice this is set once at the provider.\n const optionsRef = useRef(options)\n optionsRef.current = options\n const managerRef = useRef<ManagerControls | null>(null)\n if (managerRef.current === null) {\n // Default to the page-level `ensureGristReady()` singleton so a\n // standalone `useGristHandshake()` (mounted alongside a real\n // `<GristWidgetProvider>` for its observable snapshot, per the \"custom\n // retry / observability\" pattern) can't call the real `grist.ready()`\n // independently and race the widget's own declared options. Callers\n // that pass their own `negotiate`/`onBeforeReload` still win.\n managerRef.current = createGristHandshakeManager({\n ...options,\n negotiate: {\n readyImpl: (payload) => ensureGristReady(payload),\n ...options.negotiate,\n },\n onBeforeReload: () => {\n resetGristReadySingleton()\n options.onBeforeReload?.()\n },\n })\n }\n const manager = managerRef.current\n\n useEffect(() => {\n manager.start()\n return () => {\n manager.stop()\n }\n }, [manager])\n\n const snapshot = useSyncExternalStore(\n manager.subscribe,\n manager.getSnapshot,\n initialGristSnapshot\n )\n\n const projected = useMemo(\n () => ({\n status: deriveStatus(snapshot),\n error: deriveErrorMessage(snapshot),\n capabilities: deriveCapabilities(snapshot),\n }),\n [snapshot]\n )\n\n return useMemo(\n () => ({\n snapshot,\n status: projected.status,\n error: projected.error,\n capabilities: projected.capabilities,\n reload: manager.reload,\n restart: manager.restart,\n }),\n [snapshot, projected, manager]\n )\n}\n\n/**\n * Convenience hook — equivalent to `useGristHandshake().capabilities` but\n * skips returning the full snapshot. Intended for leaf components that only\n * need to gate UI on `canRender` / `canWriteRecords` / etc.\n */\nexport function useGristCapabilities(\n options: UseGristHandshakeOptions = {}\n): GristCapabilities {\n return useGristHandshake(options).capabilities\n}\n","/**\n * `useAmbientGristHandshake()` — observe an already-mounted handshake\n * manager without ever creating one.\n *\n * `useGristHandshake()` / `<GristHandshakeProvider>` both mount their OWN\n * manager, which calls the real `grist.ready()` independently of any\n * `<GristWidgetProvider>` elsewhere on the page. That's fine for a widget's\n * single app-root provider, but wrong for read-only UI (a connection-status\n * chip, a debug overlay) that must share the *same* handshake as the real\n * widget rather than run a second, competing one. This hook only reads\n * whatever manager a `<GristWidgetProvider>` ancestor already published;\n * it returns `null` outside one instead of falling back to creating its own.\n */\n\nimport { useMemo, useSyncExternalStore } from \"react\"\n\nimport {\n deriveCapabilities,\n deriveErrorMessage,\n deriveStatus,\n initialGristSnapshot,\n type GristCapabilities,\n type GristWidgetSnapshot,\n type GristWidgetStatus,\n} from \"../internal/handshake\"\nimport { useGristManagerOptional } from \"../internal/handshake-manager-context\"\n\nexport type UseAmbientGristHandshakeResult = {\n snapshot: GristWidgetSnapshot\n status: GristWidgetStatus\n error: string | null\n capabilities: GristCapabilities\n reload: () => void\n restart: () => void\n}\n\nconst noopSubscribe = () => () => {}\nconst getInitialSnapshot = () => initialGristSnapshot()\n\n/**\n * Returns `null` when mounted outside a `<GristWidgetProvider>` — there is\n * no ambient manager to observe, and this hook intentionally never creates\n * one. Mount inside `<GristWidgetProvider>` to get a live value.\n */\nexport function useAmbientGristHandshake(): UseAmbientGristHandshakeResult | null {\n const manager = useGristManagerOptional()\n\n const snapshot = useSyncExternalStore(\n manager?.subscribe ?? noopSubscribe,\n manager?.getSnapshot ?? getInitialSnapshot,\n getInitialSnapshot\n )\n\n return useMemo(() => {\n if (!manager) return null\n return {\n snapshot,\n status: deriveStatus(snapshot),\n error: deriveErrorMessage(snapshot),\n capabilities: deriveCapabilities(snapshot),\n reload: manager.reload,\n restart: manager.restart,\n }\n }, [manager, snapshot])\n}\n","/**\n * `<GristHandshakeProvider>` — opt-in React provider that mounts a single\n * {@link GristHandshakeManager} at the app root and broadcasts its snapshot\n * to all descendants.\n *\n * Use this provider when you want the full SOTA handshake model (snapshot +\n * capabilities + heartbeat + reload/restart) without the slice composition\n * of `<GristWidgetProvider>`. The two providers are independent:\n *\n * - `<GristWidgetProvider>` (legacy) — full SDK surface, hooks slices.\n * - `<GristHandshakeProvider>` (new) — handshake state machine only.\n *\n * Both can coexist if you need both surfaces; `grist.ready` is deduped by\n * the SDK's ready singleton so concurrent calls are safe.\n */\n\nimport {\n createContext,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useSyncExternalStore,\n type ReactNode,\n} from \"react\"\n\nimport {\n createGristHandshakeManager,\n type ManagerControls,\n type ManagerOptions,\n} from \"../internal/handshake/manager\"\nimport {\n deriveCapabilities,\n deriveErrorMessage,\n deriveStatus,\n initialGristSnapshot,\n type GristCapabilities,\n type GristWidgetSnapshot,\n type GristWidgetStatus,\n} from \"../internal/handshake\"\nimport { ensureGristReady, resetGristReadySingleton } from \"../internal/ready-singleton\"\n\nexport type GristHandshakeContextValue = {\n snapshot: GristWidgetSnapshot\n status: GristWidgetStatus\n error: string | null\n capabilities: GristCapabilities\n reload: () => void\n restart: () => void\n recordRpcSuccess: () => void\n recordRpcFailure: () => void\n}\n\nconst GristHandshakeReactContext = createContext<GristHandshakeContextValue | null>(null)\n\nexport type GristHandshakeProviderProps = {\n options?: ManagerOptions\n children: ReactNode\n}\n\n/**\n * Mount a single {@link GristHandshakeManager} for the React subtree and\n * expose its snapshot via context.\n *\n * The manager is created **once** on first mount; the `options` prop is\n * captured at that time. To re-create the manager with new options, unmount\n * and re-mount the provider (e.g. via a `key`).\n */\nexport function GristHandshakeProvider({ options, children }: GristHandshakeProviderProps) {\n // Manager is allocated once. Subsequent option changes are intentionally\n // ignored — handshake configuration should be stable for the lifetime of\n // the widget.\n const managerRef = useRef<ManagerControls | null>(null)\n if (managerRef.current === null) {\n // Default to the page-level `ensureGristReady()` singleton so a bare\n // `<GristHandshakeProvider>` (no options) can't win a race against a\n // sibling `<GristWidgetProvider>` by calling the real `grist.ready()`\n // directly with its own default payload. Callers that pass their own\n // `negotiate`/`onBeforeReload` still win. (Read-only observers of an\n // ancestor `<GristWidgetProvider>`, like the template's `GristStatusChip`,\n // should prefer `useAmbientGristHandshake()` instead of this provider —\n // it observes the existing manager rather than allocating a new one.)\n managerRef.current = createGristHandshakeManager({\n ...options,\n negotiate: {\n readyImpl: (payload) => ensureGristReady(payload),\n ...options?.negotiate,\n },\n onBeforeReload: () => {\n resetGristReadySingleton()\n options?.onBeforeReload?.()\n },\n })\n }\n const manager = managerRef.current\n\n useEffect(() => {\n manager.start()\n return () => {\n manager.stop()\n }\n }, [manager])\n\n const snapshot = useSyncExternalStore(\n manager.subscribe,\n manager.getSnapshot,\n initialGristSnapshot\n )\n\n const value = useMemo<GristHandshakeContextValue>(\n () => ({\n snapshot,\n status: deriveStatus(snapshot),\n error: deriveErrorMessage(snapshot),\n capabilities: deriveCapabilities(snapshot),\n reload: manager.reload,\n restart: manager.restart,\n recordRpcSuccess: manager.recordRpcSuccess,\n recordRpcFailure: manager.recordRpcFailure,\n }),\n [snapshot, manager]\n )\n\n return (\n <GristHandshakeReactContext.Provider value={value}>\n {children}\n </GristHandshakeReactContext.Provider>\n )\n}\n\n/**\n * Read the handshake context. Throws if no `<GristHandshakeProvider>` is\n * mounted in the tree.\n *\n * Use {@link useGristHandshakeContextOptional} when the provider is optional\n * (e.g. when the same component is sometimes used standalone).\n */\nexport function useGristHandshakeContext(): GristHandshakeContextValue {\n const ctx = useContext(GristHandshakeReactContext)\n if (!ctx) {\n throw new Error(\n \"useGristHandshakeContext() must be used inside <GristHandshakeProvider>\"\n )\n }\n return ctx\n}\n\n/** Non-throwing variant. */\nexport function useGristHandshakeContextOptional(): GristHandshakeContextValue | null {\n return useContext(GristHandshakeReactContext)\n}\n","import { useEffect, useRef, useState } from \"react\"\n\nimport { recordEvent } from \"../internal/subscriptions\"\nimport type { GristReadyOptions, GristWidgetColumnMap } from \"../types\"\nimport { useGristReady } from \"./use-grist-ready\"\n\nexport type UseGristRecordSubscriptionResult = {\n loading: boolean\n error: string | null\n /** Latest mappings from `grist.onRecord` (logical name → real column id, or `string[]` for `allowMultiple`). */\n mappings: GristWidgetColumnMap | null\n}\n\n// Subscription errors are logged inside the singleton; nothing surfaces here.\n\n/**\n * Subscribes to the currently-selected row in the widget's section.\n *\n * The Grist event is shared across all hook instances (no leak).\n */\nexport function useGristRecord(\n cb: (record: Record<string, unknown> | null, mappings: GristWidgetColumnMap | null) => void,\n options?: GristReadyOptions\n): UseGristRecordSubscriptionResult {\n const cbRef = useRef(cb)\n useEffect(() => {\n cbRef.current = cb\n }, [cb])\n\n const [mappings, setMappings] = useState<GristWidgetColumnMap | null>(null)\n const { docApi, error: readyError } = useGristReady({\n requiredAccess: options?.requiredAccess ?? \"read table\",\n columns: options?.columns,\n allowSelectBy: options?.allowSelectBy,\n hasCustomOptions: options?.hasCustomOptions,\n onEditOptions: options?.onEditOptions,\n })\n\n useEffect(() => {\n if (!docApi) return\n return recordEvent.subscribe(({ record, mappings: nextMappings }) => {\n setMappings(nextMappings)\n cbRef.current(record, nextMappings)\n })\n }, [docApi])\n\n return {\n loading: docApi === null && !readyError,\n error: readyError,\n mappings,\n }\n}\n","import { useEffect, useRef, useState } from \"react\"\n\nimport { recordsEvent } from \"../internal/subscriptions\"\nimport type { GristReadyOptions, GristWidgetColumnMap } from \"../types\"\nimport { useGristReady } from \"./use-grist-ready\"\nimport type { UseGristRecordSubscriptionResult } from \"./use-grist-record\"\n\n/**\n * Subscribes to the full row set visible in the widget's section\n * (filters, sorts, and linked rows applied).\n */\nexport function useGristRecords(\n cb: (records: Record<string, unknown>[], mappings: GristWidgetColumnMap | null) => void,\n options?: GristReadyOptions\n): UseGristRecordSubscriptionResult {\n const cbRef = useRef(cb)\n useEffect(() => {\n cbRef.current = cb\n }, [cb])\n\n const [mappings, setMappings] = useState<GristWidgetColumnMap | null>(null)\n const { docApi, error: readyError } = useGristReady({\n requiredAccess: options?.requiredAccess ?? \"read table\",\n columns: options?.columns,\n allowSelectBy: options?.allowSelectBy,\n hasCustomOptions: options?.hasCustomOptions,\n onEditOptions: options?.onEditOptions,\n })\n\n useEffect(() => {\n if (!docApi) return\n return recordsEvent.subscribe(({ records, mappings: nextMappings }) => {\n setMappings(nextMappings)\n cbRef.current(records, nextMappings)\n })\n }, [docApi])\n\n return {\n loading: docApi === null && !readyError,\n error: readyError,\n mappings,\n }\n}\n","import { useEffect, useRef, useState } from \"react\"\n\nimport { newRecordEvent } from \"../internal/subscriptions\"\nimport type { GristReadyOptions, GristWidgetColumnMap } from \"../types\"\nimport { useGristReady } from \"./use-grist-ready\"\n\nexport type UseGristNewRecordResult = {\n /** True when the user has selected the blank \"new row\" placeholder. */\n isNewRecord: boolean\n /** Mappings reported by Grist alongside the new-record event. */\n mappings: GristWidgetColumnMap | null\n loading: boolean\n error: string | null\n}\n\n/**\n * Subscribes to `grist.onNewRecord` — fires when the user selects the blank\n * row in the linked section. Useful for form-style widgets that need to\n * switch into \"create\" mode.\n *\n * `isNewRecord` is reset to `false` whenever a real `onRecord` payload arrives,\n * so callers don't need to manage that themselves.\n */\nexport function useGristNewRecord(options?: GristReadyOptions): UseGristNewRecordResult {\n const { docApi, error: readyError } = useGristReady({\n requiredAccess: options?.requiredAccess ?? \"read table\",\n columns: options?.columns,\n allowSelectBy: options?.allowSelectBy,\n hasCustomOptions: options?.hasCustomOptions,\n onEditOptions: options?.onEditOptions,\n })\n\n const [isNewRecord, setIsNewRecord] = useState(false)\n const [mappings, setMappings] = useState<GristWidgetColumnMap | null>(null)\n const subscribedRef = useRef(false)\n\n useEffect(() => {\n if (!docApi || subscribedRef.current) return\n if (typeof grist.onNewRecord !== \"function\") return\n subscribedRef.current = true\n return newRecordEvent.subscribe(({ mappings: nextMappings }) => {\n setIsNewRecord(true)\n setMappings(nextMappings)\n })\n }, [docApi])\n\n return {\n isNewRecord,\n mappings,\n loading: docApi === null && !readyError,\n error: readyError,\n }\n}\n","import { useCallback, useState } from \"react\"\n\nimport {\n gristAddRecordAction,\n gristBulkAddRecordAction,\n gristBulkRemoveRecordAction,\n gristBulkUpdateRecordAction,\n gristRemoveRecordAction,\n gristUpdateRecordAction,\n type GristUserActionTuple,\n} from \"../helpers/grist-user-actions\"\nimport { useRpcHeartbeatCoalesce } from \"../internal/hooks/use-rpc-heartbeat-coalesce\"\nimport { useGristReady } from \"../low-level-hooks/use-grist-ready\"\nimport type { GristApplyUserActionsOptions, GristReadyOptions } from \"../types\"\n\nexport type GristActionsStatus = \"idle\" | \"running\" | \"error\"\n\nexport type UseGristActionsOptions = Pick<\n GristReadyOptions,\n \"requiredAccess\" | \"columns\" | \"allowSelectBy\" | \"hasCustomOptions\" | \"onEditOptions\"\n>\n\nexport type UseGristActionsResult = {\n status: GristActionsStatus\n error: string | null\n /** Apply raw user actions. `applyOptions.desc` is shown in the document undo stack. */\n apply: (actions: GristUserActionTuple[], applyOptions?: GristApplyUserActionsOptions) => Promise<unknown>\n updateRecord: (\n tableId: string,\n recordId: number,\n patch: Record<string, unknown>,\n applyOptions?: GristApplyUserActionsOptions\n ) => Promise<unknown>\n addRecord: (\n tableId: string,\n values: Record<string, unknown>,\n applyOptions?: GristApplyUserActionsOptions\n ) => Promise<unknown>\n removeRecord: (\n tableId: string,\n recordId: number,\n applyOptions?: GristApplyUserActionsOptions\n ) => Promise<unknown>\n bulkAddRecord: (\n tableId: string,\n values: Record<string, unknown[]>,\n applyOptions?: GristApplyUserActionsOptions\n ) => Promise<unknown>\n bulkUpdateRecord: (\n tableId: string,\n rowIds: number[],\n columnarPatch: Record<string, unknown[]>,\n applyOptions?: GristApplyUserActionsOptions\n ) => Promise<unknown>\n bulkRemoveRecord: (\n tableId: string,\n rowIds: number[],\n applyOptions?: GristApplyUserActionsOptions\n ) => Promise<unknown>\n}\n\nexport function useGristActions(options?: UseGristActionsOptions): UseGristActionsResult {\n const requiredAccess = options?.requiredAccess ?? \"full\"\n const { docApi, error: readyError } = useGristReady({\n requiredAccess,\n columns: options?.columns,\n allowSelectBy: options?.allowSelectBy,\n hasCustomOptions: options?.hasCustomOptions,\n onEditOptions: options?.onEditOptions,\n })\n const [status, setStatus] = useState<GristActionsStatus>(\"idle\")\n const [actionError, setActionError] = useState<string | null>(null)\n const coalesceRpc = useRpcHeartbeatCoalesce()\n\n const apply = useCallback(\n async (actions: GristUserActionTuple[], applyOptions?: GristApplyUserActionsOptions): Promise<unknown> => {\n if (!docApi) throw new Error(\"Grist docApi is not ready\")\n setStatus(\"running\")\n setActionError(null)\n try {\n const out = await coalesceRpc(() => docApi.applyUserActions(actions, applyOptions))\n setStatus(\"idle\")\n return out\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n setActionError(message)\n setStatus(\"error\")\n throw err\n }\n },\n [docApi, coalesceRpc]\n )\n\n const updateRecord = useCallback(\n (tableId: string, recordId: number, patch: Record<string, unknown>, applyOptions?: GristApplyUserActionsOptions) =>\n apply([gristUpdateRecordAction(tableId, recordId, patch)], applyOptions),\n [apply]\n )\n\n const addRecord = useCallback(\n (tableId: string, values: Record<string, unknown>, applyOptions?: GristApplyUserActionsOptions) =>\n apply([gristAddRecordAction(tableId, values)], applyOptions),\n [apply]\n )\n\n const removeRecord = useCallback(\n (tableId: string, recordId: number, applyOptions?: GristApplyUserActionsOptions) =>\n apply([gristRemoveRecordAction(tableId, recordId)], applyOptions),\n [apply]\n )\n\n const bulkAddRecord = useCallback(\n (tableId: string, values: Record<string, unknown[]>, applyOptions?: GristApplyUserActionsOptions) =>\n apply([gristBulkAddRecordAction(tableId, values)], applyOptions),\n [apply]\n )\n\n const bulkUpdateRecord = useCallback(\n (tableId: string, rowIds: number[], columnarPatch: Record<string, unknown[]>, applyOptions?: GristApplyUserActionsOptions) =>\n apply([gristBulkUpdateRecordAction(tableId, rowIds, columnarPatch)], applyOptions),\n [apply]\n )\n\n const bulkRemoveRecord = useCallback(\n (tableId: string, rowIds: number[], applyOptions?: GristApplyUserActionsOptions) =>\n apply([gristBulkRemoveRecordAction(tableId, rowIds)], applyOptions),\n [apply]\n )\n\n return {\n status: readyError ? \"error\" : status,\n error: readyError ?? actionError,\n apply,\n updateRecord,\n addRecord,\n removeRecord,\n bulkAddRecord,\n bulkUpdateRecord,\n bulkRemoveRecord,\n }\n}\n","import { useCallback, useEffect, useState } from \"react\"\n\nimport { recordEvent } from \"../internal/subscriptions\"\nimport { useGristReady } from \"../low-level-hooks/use-grist-ready\"\nimport type { GristReadyOptions, GristWidgetColumnMap } from \"../types\"\n\nexport type UseGristMappedRecordResult<T> = {\n rawRecord: Record<string, unknown> | null\n mappedRecord: T | null\n /** Current column mappings reported by Grist. */\n mappings: GristWidgetColumnMap | null\n loading: boolean\n error: string | null\n /**\n * Reverse-map a logical patch (`{ logicalName: value }`) into a real-column\n * patch (`{ realColId: value }`) ready for `applyUserActions` /\n * `useGristTableOps.update`.\n * Falls back to `grist.mapColumnNamesBack` when present, otherwise resolves\n * names manually from `mappings` (single-mapped columns only).\n */\n mapBack: (patch: Partial<T>) => Record<string, unknown>\n /** Resolve a single logical name to its current real column id. */\n resolveColumnId: (logicalName: keyof T & string) => string | undefined\n}\n\nfunction manualMapBack<T>(patch: Partial<T>, mappings: GristWidgetColumnMap | null): Record<string, unknown> {\n if (!mappings) return { ...(patch as Record<string, unknown>) }\n const out: Record<string, unknown> = {}\n for (const [name, value] of Object.entries(patch as Record<string, unknown>)) {\n const target = mappings[name]\n if (Array.isArray(target)) {\n // allowMultiple: cannot decide which underlying column to write — skip and warn.\n if (typeof console !== \"undefined\") {\n console.warn(`[lib/grist] mapBack: cannot reverse-map allowMultiple field \"${name}\" without grist.mapColumnNamesBack`)\n }\n continue\n }\n out[target ?? name] = value\n }\n return out\n}\n\n/**\n * Subscribes to the selected row, applies `grist.mapColumnNames` so widget code\n * sees logical column names, and exposes `mapBack` for safe writes.\n */\nexport function useGristMappedRecord<T = Record<string, unknown>>(\n options?: GristReadyOptions\n): UseGristMappedRecordResult<T> {\n const requiredAccess = options?.requiredAccess ?? \"read table\"\n const { docApi, error: readyError } = useGristReady({\n requiredAccess,\n columns: options?.columns,\n allowSelectBy: options?.allowSelectBy,\n hasCustomOptions: options?.hasCustomOptions,\n onEditOptions: options?.onEditOptions,\n })\n const [rawRecord, setRawRecord] = useState<Record<string, unknown> | null>(null)\n const [mappedRecord, setMappedRecord] = useState<T | null>(null)\n const [mappings, setMappings] = useState<GristWidgetColumnMap | null>(null)\n\n useEffect(() => {\n if (!docApi) return\n return recordEvent.subscribe(({ record, mappings: nextMappings }) => {\n setRawRecord(record)\n setMappings(nextMappings)\n if (!record) {\n setMappedRecord(null)\n return\n }\n if (typeof grist.mapColumnNames === \"function\") {\n const mapped = grist.mapColumnNames(record)\n setMappedRecord(\n mapped !== null && mapped !== undefined ? (mapped as T) : null\n )\n return\n }\n setMappedRecord(record as T)\n })\n }, [docApi])\n\n const mapBack = useCallback(\n (patch: Partial<T>): Record<string, unknown> => {\n if (typeof grist.mapColumnNamesBack === \"function\") {\n return grist.mapColumnNamesBack(patch as Record<string, unknown>)\n }\n return manualMapBack<T>(patch, mappings)\n },\n [mappings]\n )\n\n const resolveColumnId = useCallback(\n (logicalName: keyof T & string): string | undefined => {\n const value = mappings?.[logicalName]\n if (Array.isArray(value)) return undefined\n return value ?? undefined\n },\n [mappings]\n )\n\n return {\n rawRecord,\n mappedRecord,\n mappings,\n loading: docApi === null && !readyError,\n error: readyError,\n mapBack,\n resolveColumnId,\n }\n}\n","import { useCallback, useState } from \"react\"\n\nimport { useRpcHeartbeatCoalesce } from \"../internal/hooks/use-rpc-heartbeat-coalesce\"\nimport { useGristReady } from \"../low-level-hooks/use-grist-ready\"\nimport type {\n GristMinimalRecord,\n GristReadyOptions,\n GristTableNewRecord,\n GristTableOpOptions,\n GristTableOperations,\n GristTableUpdateRecord,\n GristTableUpsertOptions,\n GristTableUpsertRecord,\n} from \"../types\"\n\nexport type GristTableOpsStatus = \"idle\" | \"running\" | \"error\"\n\nexport type UseGristTableOpsOptions = {\n /**\n * Table to operate on:\n * - `\"selected\"` (default): use `grist.selectedTable` (the widget's current table).\n * - any other string: use `grist.getTable(tableId)`.\n */\n tableId?: \"selected\" | string\n /** Defaults to `\"full\"` since these operations write to the document. */\n requiredAccess?: GristReadyOptions[\"requiredAccess\"]\n} & Pick<GristReadyOptions, \"columns\" | \"allowSelectBy\" | \"hasCustomOptions\" | \"onEditOptions\">\n\nexport type UseGristTableOpsResult = {\n status: GristTableOpsStatus\n error: string | null\n /** Resolves the runtime tableId (only meaningful when `tableId` is `\"selected\"`). */\n getTableId: () => Promise<string>\n create: (\n records: GristTableNewRecord | GristTableNewRecord[],\n opOptions?: GristTableOpOptions\n ) => Promise<GristMinimalRecord | GristMinimalRecord[]>\n update: (\n records: GristTableUpdateRecord | GristTableUpdateRecord[],\n opOptions?: GristTableOpOptions\n ) => Promise<void>\n upsert: (\n records: GristTableUpsertRecord | GristTableUpsertRecord[],\n opOptions?: GristTableUpsertOptions\n ) => Promise<void>\n destroy: (recordIds: number | number[]) => Promise<void>\n}\n\nfunction resolveOps(tableId: \"selected\" | string): GristTableOperations {\n if (tableId === \"selected\") {\n if (!grist.selectedTable) throw new Error(\"grist.selectedTable is not available\")\n return grist.selectedTable\n }\n if (typeof grist.getTable !== \"function\") {\n throw new Error(\"grist.getTable is not available in this Grist version\")\n }\n return grist.getTable(tableId)\n}\n\n/**\n * Strongly-typed CRUD wrapper around Grist's `TableOperations` (`grist.selectedTable`\n * or `grist.getTable(tableId)`). Prefer this over hand-rolled `applyUserActions`.\n *\n * @see https://support.getgrist.com/code/interfaces/TableOperations.TableOperations/\n */\nexport function useGristTableOps(options?: UseGristTableOpsOptions): UseGristTableOpsResult {\n const requiredAccess = options?.requiredAccess ?? \"full\"\n const tableIdOption: \"selected\" | string = options?.tableId ?? \"selected\"\n const { docApi, error: readyError } = useGristReady({\n requiredAccess,\n columns: options?.columns,\n allowSelectBy: options?.allowSelectBy,\n hasCustomOptions: options?.hasCustomOptions,\n onEditOptions: options?.onEditOptions,\n })\n\n const [status, setStatus] = useState<GristTableOpsStatus>(\"idle\")\n const [actionError, setActionError] = useState<string | null>(null)\n const coalesceRpc = useRpcHeartbeatCoalesce()\n\n // `resolveOps` is synchronous and idempotent (it only reads `grist.selectedTable`\n // / `grist.getTable`), so derive `ops` during render instead of via effect.\n let ops: GristTableOperations | null = null\n let resolveError: string | null = null\n if (docApi) {\n try {\n ops = resolveOps(tableIdOption)\n } catch (err) {\n resolveError = err instanceof Error ? err.message : String(err)\n }\n }\n\n const wrap = useCallback(\n async <T>(run: (ops: GristTableOperations) => Promise<T>): Promise<T> => {\n if (!ops) throw new Error(\"Grist table operations are not ready\")\n setStatus(\"running\")\n setActionError(null)\n try {\n const out = await coalesceRpc(() => run(ops))\n setStatus(\"idle\")\n return out\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n setActionError(message)\n setStatus(\"error\")\n throw err\n }\n },\n [ops, coalesceRpc]\n )\n\n const getTableId = useCallback(async () => {\n if (!ops) throw new Error(\"Grist table operations are not ready\")\n return ops.getTableId()\n }, [ops])\n\n const create = useCallback(\n (records: GristTableNewRecord | GristTableNewRecord[], opOptions?: GristTableOpOptions) =>\n wrap((o) => o.create(records, opOptions)),\n [wrap]\n )\n\n const update = useCallback(\n (records: GristTableUpdateRecord | GristTableUpdateRecord[], opOptions?: GristTableOpOptions) =>\n wrap((o) => o.update(records, opOptions)),\n [wrap]\n )\n\n const upsert = useCallback(\n (records: GristTableUpsertRecord | GristTableUpsertRecord[], opOptions?: GristTableUpsertOptions) =>\n wrap((o) => o.upsert(records, opOptions)),\n [wrap]\n )\n\n const destroy = useCallback(\n (recordIds: number | number[]) => wrap((o) => o.destroy(recordIds)),\n [wrap]\n )\n\n return {\n status: readyError || resolveError ? \"error\" : status,\n error: readyError ?? resolveError ?? actionError,\n getTableId,\n create,\n update,\n upsert,\n destroy,\n }\n}\n","import { useCallback, useContext, useEffect, useRef, useState } from \"react\"\n\nimport { tableDataToRows, type GristColumnarTable } from \"../helpers/grist-table-data\"\nimport { GristReadsContext } from \"../internal/contexts\"\nimport { useRpcHeartbeatCoalesce } from \"../internal/hooks/use-rpc-heartbeat-coalesce\"\nimport { useGristReady } from \"../low-level-hooks/use-grist-ready\"\nimport type { GristReadyOptions, GristRowRecord } from \"../types\"\n\nexport type UseGristRowsFromTableOptions<T> = {\n tableId: string\n /** Re-fetch on a fixed cadence (ms). Default: disabled. */\n pollIntervalMs?: number\n /** Map raw rows to a domain shape (e.g. `decodeGristValue` your columns). */\n transform?: (row: GristRowRecord) => GristRowRecord<T>\n requiredAccess?: GristReadyOptions[\"requiredAccess\"]\n} & Pick<GristReadyOptions, \"columns\" | \"allowSelectBy\" | \"hasCustomOptions\" | \"onEditOptions\">\n\nexport type UseGristRowsFromTableResult<T> = {\n rows: GristRowRecord<T>[] | null\n loading: boolean\n error: string | null\n /** Force a re-fetch (call after writes that should be reflected immediately). */\n refresh: () => Promise<void>\n}\n\n/**\n * Subscribes to a full table's rows via `docApi.fetchTable`.\n *\n * Unlike `useGristRecords` (which is bound to the widget's selected section),\n * this hook works against any table id and **doesn't auto-update on Grist\n * writes from elsewhere** — call `refresh()` after your own writes, or set\n * `pollIntervalMs` for polling.\n */\nexport function useGristRowsFromTable<T = Record<string, unknown>>(\n options: UseGristRowsFromTableOptions<T>\n): UseGristRowsFromTableResult<T> {\n const requiredAccess = options.requiredAccess ?? \"read table\"\n const { docApi, error: readyError } = useGristReady({\n requiredAccess,\n columns: options.columns,\n allowSelectBy: options.allowSelectBy,\n hasCustomOptions: options.hasCustomOptions,\n onEditOptions: options.onEditOptions,\n })\n\n // When inside a GristWidgetProvider, delegate to the provider's guarded\n // fetchTable so access-insufficient errors flow through readError → alerts.\n const providerFetchTable = useContext(GristReadsContext)?.fetchTable\n\n const [rows, setRows] = useState<GristRowRecord<T>[] | null>(null)\n const [loading, setLoading] = useState(false)\n const [fetchError, setFetchError] = useState<string | null>(null)\n const transformRef = useRef(options.transform)\n transformRef.current = options.transform\n const coalesceRpc = useRpcHeartbeatCoalesce()\n\n const refresh = useCallback(async () => {\n if (!docApi) return\n setLoading(true)\n setFetchError(null)\n try {\n const data = providerFetchTable\n ? await providerFetchTable(options.tableId)\n : ((await coalesceRpc(\n () => docApi.fetchTable(options.tableId) as Promise<GristColumnarTable>\n )) as GristColumnarTable)\n const raw = tableDataToRows(data)\n const t = transformRef.current\n setRows(t ? raw.map((r) => t(r)) : (raw as GristRowRecord<T>[]))\n } catch (err) {\n setFetchError(err instanceof Error ? err.message : String(err))\n setRows(null)\n } finally {\n setLoading(false)\n }\n }, [docApi, providerFetchTable, options.tableId, coalesceRpc])\n\n useEffect(() => {\n if (docApi) void refresh()\n }, [docApi, refresh])\n\n useEffect(() => {\n if (!docApi || !options.pollIntervalMs || options.pollIntervalMs <= 0) return\n const id = window.setInterval(() => void refresh(), options.pollIntervalMs)\n return () => window.clearInterval(id)\n }, [docApi, options.pollIntervalMs, refresh])\n\n return {\n rows,\n loading,\n error: readyError ?? fetchError,\n refresh,\n }\n}\n","import { useCallback, useEffect, useState } from \"react\"\n\nimport {\n fetchWithGristAuth as fetchWithGristAuthCore,\n getGristAccessToken,\n type GristAccessToken,\n} from \"../helpers/grist-fetch-with-auth\"\nimport { useGristReady } from \"../low-level-hooks/use-grist-ready\"\nimport type { GristReadyOptions } from \"../types\"\n\nexport type UseGristAccessTokenOptions = {\n /** Default for all token requests issued by this hook. */\n readOnly?: boolean\n /** Pre-fetch a token on mount so `token` is non-null when widgets render. */\n prefetch?: boolean\n /** Defaults to `\"full\"` since tokens are used for REST calls. */\n requiredAccess?: GristReadyOptions[\"requiredAccess\"]\n} & Pick<GristReadyOptions, \"columns\" | \"allowSelectBy\" | \"hasCustomOptions\" | \"onEditOptions\">\n\nexport type UseGristAccessTokenResult = {\n token: GristAccessToken | null\n loading: boolean\n error: string | null\n /** Request a fresh token (Grist tokens are short-lived; do not cache aggressively). */\n refresh: (overrides?: { readOnly?: boolean }) => Promise<GristAccessToken>\n /** `fetch()` against Grist's REST API with auth attached. */\n fetch: (path: string, init?: RequestInit & { readOnly?: boolean }) => Promise<Response>\n}\n\n/**\n * Exposes `docApi.getAccessToken` plus a ready-to-use `fetch` for calling\n * Grist's REST API (e.g. attachments, records, sql) from a widget.\n */\nexport function useGristAccessToken(options?: UseGristAccessTokenOptions): UseGristAccessTokenResult {\n const requiredAccess = options?.requiredAccess ?? \"full\"\n const readOnlyDefault = options?.readOnly ?? false\n const prefetch = options?.prefetch ?? false\n const { docApi, error: readyError } = useGristReady({\n requiredAccess,\n columns: options?.columns,\n allowSelectBy: options?.allowSelectBy,\n hasCustomOptions: options?.hasCustomOptions,\n onEditOptions: options?.onEditOptions,\n })\n\n const [token, setToken] = useState<GristAccessToken | null>(null)\n const [loading, setLoading] = useState(false)\n const [error, setError] = useState<string | null>(null)\n\n const refresh = useCallback(\n async (overrides?: { readOnly?: boolean }): Promise<GristAccessToken> => {\n if (!docApi) throw new Error(\"Grist is not ready\")\n setLoading(true)\n setError(null)\n try {\n const next = await getGristAccessToken(docApi, { readOnly: overrides?.readOnly ?? readOnlyDefault })\n setToken(next)\n return next\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n setError(message)\n throw err\n } finally {\n setLoading(false)\n }\n },\n [docApi, readOnlyDefault]\n )\n\n const fetchFn = useCallback(\n (path: string, init?: RequestInit & { readOnly?: boolean }) => {\n if (!docApi) throw new Error(\"Grist is not ready\")\n return fetchWithGristAuthCore(docApi, path, { readOnly: readOnlyDefault, ...init })\n },\n [docApi, readOnlyDefault]\n )\n\n useEffect(() => {\n if (docApi && prefetch) void refresh()\n }, [docApi, prefetch, refresh])\n\n return {\n token,\n loading,\n error: readyError ?? error,\n refresh,\n fetch: fetchFn,\n }\n}\n","import { useCallback, useEffect, useState } from \"react\"\n\nimport { useGristReady } from \"../low-level-hooks/use-grist-ready\"\nimport type { GristReadyOptions, GristWidgetColumnMap } from \"../types\"\n\nexport type UseGristSectionResult = {\n /** Current widget ↔ section column mappings, refreshed on demand. */\n mappings: GristWidgetColumnMap | null\n loading: boolean\n error: string | null\n /** Re-read mappings from `sectionApi`. */\n refresh: () => Promise<void>\n /**\n * Update the widget's declared `ColumnsToMap` (and other ready options) after\n * mount. Use this to dynamically request more columns once the user has\n * configured the widget.\n */\n configure: (options: GristReadyOptions) => Promise<void>\n}\n\n/**\n * Wraps Grist's `sectionApi` (`mappings()` + `configure()`) so widgets can\n * inspect/refresh the column mapping and re-declare requirements without\n * touching `grist` directly.\n */\nexport function useGristSection(options?: GristReadyOptions): UseGristSectionResult {\n const { docApi, error: readyError } = useGristReady({\n requiredAccess: options?.requiredAccess ?? \"read table\",\n columns: options?.columns,\n allowSelectBy: options?.allowSelectBy,\n hasCustomOptions: options?.hasCustomOptions,\n onEditOptions: options?.onEditOptions,\n })\n\n const [mappings, setMappings] = useState<GristWidgetColumnMap | null>(null)\n const [loading, setLoading] = useState(false)\n const [error, setError] = useState<string | null>(null)\n\n const refresh = useCallback(async () => {\n if (!docApi) return\n if (!grist.sectionApi?.mappings) {\n setError(\"grist.sectionApi.mappings is not available in this Grist version\")\n return\n }\n setLoading(true)\n setError(null)\n try {\n const next = await grist.sectionApi.mappings()\n setMappings(next)\n } catch (err) {\n setError(err instanceof Error ? err.message : String(err))\n } finally {\n setLoading(false)\n }\n }, [docApi])\n\n const configure = useCallback(async (next: GristReadyOptions) => {\n if (!grist.sectionApi?.configure) {\n throw new Error(\"grist.sectionApi.configure is not available in this Grist version\")\n }\n await grist.sectionApi.configure(next)\n }, [])\n\n useEffect(() => {\n if (docApi) void refresh()\n }, [docApi, refresh])\n\n return {\n mappings,\n loading,\n error: readyError ?? error,\n refresh,\n configure,\n }\n}\n","import { useCallback, useEffect, useMemo, useRef, useState } from \"react\"\n\nimport { optionsEvent } from \"../internal/subscriptions\"\nimport { useGristReady } from \"../low-level-hooks/use-grist-ready\"\nimport type { GristReadyOptions } from \"../types\"\n\nexport type UseGristWidgetOptionsConfig<T> = {\n /** Default values returned before Grist responds and merged with stored options. */\n defaults: T\n /** Debounce window for `setOptions` writes (ms). Default: 250. */\n debounceMs?: number\n /**\n * Optional namespace inside `grist.setOptions`. When set, this hook reads/writes\n * `grist.setOption(namespace, value)` instead of the whole options blob — useful\n * to share the options bag with `hasCustomOptions` / unrelated widget state.\n */\n namespace?: string\n requiredAccess?: GristReadyOptions[\"requiredAccess\"]\n} & Pick<GristReadyOptions, \"columns\" | \"allowSelectBy\" | \"hasCustomOptions\" | \"onEditOptions\">\n\nexport type UseGristWidgetOptionsResult<T> = {\n options: T\n /** True until Grist has responded with the initial `onOptions` payload. */\n loading: boolean\n error: string | null\n /** Replace the options object (debounced write to Grist). */\n setOptions: (next: T) => void\n /** Patch a subset of keys (debounced write to Grist). */\n patchOptions: (patch: Partial<T>) => void\n /** Reset to `defaults` (immediate write to Grist). */\n reset: () => Promise<void>\n}\n\nfunction mergeWithDefaults<T>(defaults: T, stored: unknown, namespace?: string): T {\n if (stored === null || stored === undefined) return { ...defaults }\n const source = (namespace ? (stored as Record<string, unknown>)[namespace] : stored) as Partial<T> | undefined\n if (!source || typeof source !== \"object\") return { ...defaults }\n return { ...defaults, ...source }\n}\n\n/**\n * Persist a typed object of widget settings via `grist.onOptions` / `setOptions`.\n *\n * - Defaults are returned immediately (no flicker before Grist responds).\n * - Writes are debounced and batched.\n * - `hasCustomOptions` defaults to `true` so Grist exposes the gear icon — pass\n * `hasCustomOptions: false` to opt out.\n */\nexport function useGristWidgetOptions<T extends Record<string, unknown>>(\n config: UseGristWidgetOptionsConfig<T>\n): UseGristWidgetOptionsResult<T> {\n const requiredAccess = config.requiredAccess ?? \"read table\"\n const debounceMs = config.debounceMs ?? 250\n const hasCustomOptions = config.hasCustomOptions ?? true\n const { docApi, error: readyError } = useGristReady({\n requiredAccess,\n columns: config.columns,\n allowSelectBy: config.allowSelectBy,\n hasCustomOptions,\n onEditOptions: config.onEditOptions,\n })\n\n const defaultsRef = useRef(config.defaults)\n useEffect(() => {\n defaultsRef.current = config.defaults\n }, [config.defaults])\n\n const [options, setOptionsState] = useState<T>(() => ({ ...config.defaults }))\n const [loading, setLoading] = useState(true)\n const [error, setError] = useState<string | null>(null)\n const lastWrittenRef = useRef<T | null>(null)\n const debounceRef = useRef<number | null>(null)\n\n // Subscribe to remote changes (initial + external edits)\n useEffect(() => {\n if (!docApi) return\n return optionsEvent.subscribe(({ options: stored }) => {\n const merged = mergeWithDefaults(defaultsRef.current, stored, config.namespace)\n lastWrittenRef.current = merged\n setOptionsState(merged)\n setLoading(false)\n })\n }, [docApi, config.namespace])\n\n const flushWrite = useCallback(\n async (value: T) => {\n try {\n if (config.namespace) {\n await grist.setOption(config.namespace, value)\n } else {\n await grist.setOptions({ ...value })\n }\n lastWrittenRef.current = value\n } catch (err) {\n setError(err instanceof Error ? err.message : String(err))\n }\n },\n [config.namespace]\n )\n\n const scheduleWrite = useCallback(\n (value: T) => {\n if (debounceRef.current) window.clearTimeout(debounceRef.current)\n debounceRef.current = window.setTimeout(() => {\n debounceRef.current = null\n void flushWrite(value)\n }, debounceMs)\n },\n [debounceMs, flushWrite]\n )\n\n useEffect(() => {\n return () => {\n if (debounceRef.current) window.clearTimeout(debounceRef.current)\n }\n }, [])\n\n const setOptionsApi = useCallback(\n (next: T) => {\n setOptionsState(next)\n scheduleWrite(next)\n },\n [scheduleWrite]\n )\n\n const patchOptionsApi = useCallback(\n (patch: Partial<T>) => {\n setOptionsState((prev) => {\n const next = { ...prev, ...patch }\n scheduleWrite(next)\n return next\n })\n },\n [scheduleWrite]\n )\n\n const reset = useCallback(async () => {\n if (debounceRef.current) {\n window.clearTimeout(debounceRef.current)\n debounceRef.current = null\n }\n const next = { ...defaultsRef.current }\n setOptionsState(next)\n await flushWrite(next)\n }, [flushWrite])\n\n return useMemo(\n () => ({\n options,\n loading,\n error: readyError ?? error,\n setOptions: setOptionsApi,\n patchOptions: patchOptionsApi,\n reset,\n }),\n [options, loading, readyError, error, setOptionsApi, patchOptionsApi, reset]\n )\n}\n","import { useCallback, useEffect, useState } from \"react\"\n\nimport type { GristColumnarTable } from \"./helpers/grist-table-data\"\nimport { useGristReady } from \"./low-level-hooks/use-grist-ready\"\nimport type { GristFetchSelectedOptions, GristReadyOptions, GristRequiredAccess } from \"./types\"\n\nexport type UseGristTableOptions = {\n requiredAccess?: GristRequiredAccess\n /**\n * `'current'` (default): follow the widget’s selected table.\n * Any other string: fixed table id (no `grist.selectedTable` polling).\n */\n tableId?: \"current\" | string\n} & Pick<GristReadyOptions, \"columns\" | \"allowSelectBy\" | \"hasCustomOptions\" | \"onEditOptions\">\n\nexport type UseGristTableResult = {\n tableId: string | null\n loading: boolean\n error: string | null\n refresh: () => Promise<void>\n fetchTable: (targetTableId: string) => Promise<GristColumnarTable>\n listTables: () => Promise<string[]>\n getDocName: () => Promise<string>\n fetchSelectedTable: (fetchOptions?: GristFetchSelectedOptions) => Promise<GristColumnarTable>\n fetchSelectedRecord: (rowId: number, fetchOptions?: GristFetchSelectedOptions) => Promise<Record<string, unknown>>\n}\n\nfunction isCurrentMode(option: string | undefined): boolean {\n return option === undefined || option === \"current\"\n}\n\n/**\n * Selected or fixed table id plus document reads — no raw `docApi` on the result.\n */\nexport function useGristTable(options?: UseGristTableOptions): UseGristTableResult {\n const requiredAccess = options?.requiredAccess ?? \"read table\"\n const tableIdOption = options?.tableId ?? \"current\"\n const { docApi, error: readyError } = useGristReady({\n requiredAccess,\n columns: options?.columns,\n allowSelectBy: options?.allowSelectBy,\n hasCustomOptions: options?.hasCustomOptions,\n onEditOptions: options?.onEditOptions,\n })\n const [tableId, setTableId] = useState<string | null>(null)\n const [loading, setLoading] = useState(false)\n const [error, setError] = useState<string | null>(null)\n\n const fetchTable = useCallback(\n async (targetTableId: string) => {\n if (!docApi) throw new Error(\"Grist is not ready\")\n return docApi.fetchTable(targetTableId) as Promise<GristColumnarTable>\n },\n [docApi]\n )\n\n const listTables = useCallback(async () => {\n if (!docApi) throw new Error(\"Grist is not ready\")\n const out = await Promise.resolve(docApi.listTables())\n return [...out]\n }, [docApi])\n\n const getDocName = useCallback(async () => {\n if (!docApi) throw new Error(\"Grist is not ready\")\n return String(await Promise.resolve(docApi.getDocName()))\n }, [docApi])\n\n const fetchSelectedTable = useCallback(\n async (fetchOptions?: GristFetchSelectedOptions) => {\n if (!docApi) throw new Error(\"Grist is not ready\")\n const impl = docApi.fetchSelectedTable ?? grist.fetchSelectedTable\n if (!impl) throw new Error(\"fetchSelectedTable is not available in this Grist version\")\n const merged: GristFetchSelectedOptions = { keepEncoded: false, format: \"rows\", ...fetchOptions }\n return (await impl(merged)) as GristColumnarTable\n },\n [docApi]\n )\n\n const fetchSelectedRecord = useCallback(\n async (rowId: number, fetchOptions?: GristFetchSelectedOptions) => {\n if (!docApi) throw new Error(\"Grist is not ready\")\n const impl = docApi.fetchSelectedRecord ?? grist.fetchSelectedRecord\n if (!impl) throw new Error(\"fetchSelectedRecord is not available in this Grist version\")\n const merged: GristFetchSelectedOptions = { keepEncoded: false, format: \"rows\", ...fetchOptions }\n return (await impl(rowId, merged)) as Record<string, unknown>\n },\n [docApi]\n )\n\n const refresh = useCallback(async () => {\n if (!docApi) return\n if (!isCurrentMode(tableIdOption)) {\n setTableId(tableIdOption)\n setError(null)\n return\n }\n setLoading(true)\n setError(null)\n try {\n const next = await grist.selectedTable?.getTableId()\n setTableId(next ?? null)\n } catch (err) {\n setTableId(null)\n setError(err instanceof Error ? err.message : String(err))\n } finally {\n setLoading(false)\n }\n }, [docApi, tableIdOption])\n\n useEffect(() => {\n if (docApi) void refresh()\n }, [docApi, refresh])\n\n return {\n tableId,\n loading,\n error: readyError ?? error,\n refresh,\n fetchTable,\n listTables,\n getDocName,\n fetchSelectedTable,\n fetchSelectedRecord,\n }\n}\n"],"mappings":"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","names":["useMemo","useSyncExternalStore","useSyncExternalStore","useMemo","useEffect","useMemo","useRef","useSyncExternalStore","useRef","useEffect","useSyncExternalStore","useMemo","useEffect","useRef","useRef","useEffect","useEffect","useRef","useState","useRef","useEffect","useState","useEffect","useRef","useState","useState","useRef","useEffect","useState","useState","useCallback","useEffect","useState","useState","useEffect","useCallback","useCallback","useState","useState","useCallback","useCallback","useContext","useEffect","useRef","useState","useContext","useState","useRef","useCallback","useEffect","useCallback","useEffect","useState","useState","useCallback","useEffect","useCallback","useEffect","useState","useState","useCallback","useEffect","useCallback","useEffect","useMemo","useRef","useState","useRef","useEffect","useState","useCallback","useMemo","useCallback","useEffect","useState","useState","useCallback","useEffect"]}
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
initialGristSnapshot,
|
|
8
8
|
releaseEmbeddedHandshakeManager,
|
|
9
9
|
resetGristReadySingleton
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-D5GBS2NT.js";
|
|
11
11
|
|
|
12
12
|
// src/sdk/helpers/grist-fetch-with-auth.ts
|
|
13
13
|
var TOKEN_TTL_MS = 45e3;
|
|
@@ -476,4 +476,4 @@ export {
|
|
|
476
476
|
useGristReady,
|
|
477
477
|
useGristWidgetOptionsFromContext
|
|
478
478
|
};
|
|
479
|
-
//# sourceMappingURL=chunk-
|
|
479
|
+
//# sourceMappingURL=chunk-7GXVEZ2J.js.map
|
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ACCESS_RANK,
|
|
3
|
+
formatInsufficientAccessMessage,
|
|
4
|
+
isAccessSufficient,
|
|
5
|
+
parseGristRequiredAccess
|
|
6
|
+
} from "./chunk-N3X46JW2.js";
|
|
7
|
+
|
|
1
8
|
// src/sdk/helpers/grist-mappings.ts
|
|
2
9
|
function asColumnSpec(entry) {
|
|
3
10
|
return typeof entry === "string" ? { name: entry } : entry;
|
|
@@ -35,35 +42,6 @@ var pendingColumnMappingStatus = {
|
|
|
35
42
|
emptyMultiples: []
|
|
36
43
|
};
|
|
37
44
|
|
|
38
|
-
// src/sdk/internal/handshake/access.ts
|
|
39
|
-
var ACCESS_RANK = {
|
|
40
|
-
none: 0,
|
|
41
|
-
"read table": 1,
|
|
42
|
-
full: 2
|
|
43
|
-
};
|
|
44
|
-
var GRIST_ACCESS_LEVELS = ["none", "read table", "full"];
|
|
45
|
-
function parseGristRequiredAccess(raw) {
|
|
46
|
-
if (!raw) return null;
|
|
47
|
-
return GRIST_ACCESS_LEVELS.includes(raw) ? raw : null;
|
|
48
|
-
}
|
|
49
|
-
function isAccessSufficient(granted, required) {
|
|
50
|
-
return ACCESS_RANK[granted] >= ACCESS_RANK[required];
|
|
51
|
-
}
|
|
52
|
-
function gristAccessLevelLabel(level) {
|
|
53
|
-
switch (level) {
|
|
54
|
-
case "none":
|
|
55
|
-
return "No document access";
|
|
56
|
-
case "read table":
|
|
57
|
-
return "Read selected table";
|
|
58
|
-
case "full":
|
|
59
|
-
return "Full document access";
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
function formatInsufficientAccessMessage(required, _granted) {
|
|
63
|
-
const need = gristAccessLevelLabel(required);
|
|
64
|
-
return `Set Access level to at least "${need}" in the Custom widget settings.`;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
45
|
// src/sdk/internal/handshake/types.ts
|
|
68
46
|
var ZERO_GENERATION = 0;
|
|
69
47
|
function nextGeneration(current) {
|
|
@@ -1629,7 +1607,6 @@ function resetEmbeddedHandshakeManagerForTests() {
|
|
|
1629
1607
|
|
|
1630
1608
|
export {
|
|
1631
1609
|
validateColumnMappings,
|
|
1632
|
-
gristAccessLevelLabel,
|
|
1633
1610
|
initialGristSnapshot,
|
|
1634
1611
|
deriveStatus,
|
|
1635
1612
|
deriveErrorMessage,
|
|
@@ -1650,4 +1627,4 @@ export {
|
|
|
1650
1627
|
releaseEmbeddedHandshakeManager,
|
|
1651
1628
|
resetEmbeddedHandshakeManagerForTests
|
|
1652
1629
|
};
|
|
1653
|
-
//# sourceMappingURL=chunk-
|
|
1630
|
+
//# sourceMappingURL=chunk-D5GBS2NT.js.map
|