grist-widget-sdk 0.4.0 → 0.5.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.
Files changed (37) hide show
  1. package/CHANGELOG.md +39 -0
  2. package/README.md +79 -208
  3. package/dist/app.cjs +183 -65
  4. package/dist/app.cjs.map +1 -1
  5. package/dist/app.d.cts +5 -100
  6. package/dist/app.d.ts +5 -100
  7. package/dist/app.js +4 -2
  8. package/dist/{chunk-P6VTEKWO.js → chunk-LSALXIGM.js} +82 -10
  9. package/dist/chunk-LSALXIGM.js.map +1 -0
  10. package/dist/{chunk-O7NY46QY.js → chunk-MAPAWVQC.js} +88 -20
  11. package/dist/chunk-MAPAWVQC.js.map +1 -0
  12. package/dist/{chunk-B5ZZNLVS.js → chunk-OXA2VITC.js} +5 -1
  13. package/dist/chunk-OXA2VITC.js.map +1 -0
  14. package/dist/{use-grist-BK0eke9K.d.cts → define-widget-B1FIvI-h.d.cts} +179 -104
  15. package/dist/{use-grist-C5DMZ3wU.d.ts → define-widget-B9gEtJP0.d.ts} +179 -104
  16. package/dist/emulator/testing.cjs +2390 -2243
  17. package/dist/emulator/testing.cjs.map +1 -1
  18. package/dist/emulator/testing.d.cts +27 -9
  19. package/dist/emulator/testing.d.ts +27 -9
  20. package/dist/emulator/testing.js +74 -55
  21. package/dist/emulator/testing.js.map +1 -1
  22. package/dist/emulator.cjs +4 -0
  23. package/dist/emulator.cjs.map +1 -1
  24. package/dist/emulator.d.cts +3 -3
  25. package/dist/emulator.d.ts +3 -3
  26. package/dist/emulator.js +1 -1
  27. package/dist/index.cjs +133 -67
  28. package/dist/index.cjs.map +1 -1
  29. package/dist/index.d.cts +2 -2
  30. package/dist/index.d.ts +2 -2
  31. package/dist/index.js +5 -1
  32. package/dist/mount-grist-widget-CkB-3iG_.d.ts +137 -0
  33. package/dist/mount-grist-widget-Dtelqao_.d.cts +137 -0
  34. package/package.json +1 -1
  35. package/dist/chunk-B5ZZNLVS.js.map +0 -1
  36. package/dist/chunk-O7NY46QY.js.map +0 -1
  37. package/dist/chunk-P6VTEKWO.js.map +0 -1
package/dist/app.cjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/app/index.ts","../src/app/mount-grist-widget.tsx","../src/sdk/use-grist.ts","../src/sdk/helpers/grist-value-codec.ts","../src/sdk/helpers/grist-table-data.ts","../src/sdk/helpers/grist-widget-options.ts","../src/sdk/helpers/build-replica-document.ts","../src/sdk/helpers/grist-columns-filters.ts","../src/sdk/helpers/grist-attachment-download.ts","../src/sdk/helpers/grist-fetch-with-auth.ts","../src/sdk/helpers/grist-attachment-upload.ts","../src/sdk/runtime/api.ts","../src/sdk/helpers/grist-mappings.ts","../src/sdk/runtime/derive.ts","../src/sdk/runtime/cells.ts","../src/sdk/helpers/grist-widget-interaction.ts","../src/sdk/runtime/host.ts","../src/sdk/runtime/ready.ts","../src/sdk/helpers/grist-theme-payload.ts","../src/sdk/runtime/runtime.ts","../src/sdk/components/grist-widget-provider.tsx","../src/sdk/components/grist-boundary.tsx","../src/app/chrome/tokens.ts","../src/app/chrome/widget-title.ts","../src/app/chrome/local-dev-page.tsx","../src/app/chrome/release-page.tsx","../src/app/deploy-path.ts","../src/app/released-versions.ts","../src/sdk/helpers/grist-sdk-alerts.ts","../src/app/chrome/widget-alerts.tsx","../src/app/widget-theme.tsx"],"sourcesContent":["/**\n * `grist-widget-sdk/app` — what a widget's `src/main.tsx` used to wire by\n * hand: mounting, inside- vs outside-Grist pages, the deploy channel and\n * version list, and the light/dark theme.\n *\n * ```tsx\n * import { mountGristWidget } from \"grist-widget-sdk/app\"\n * import \"./index.css\"\n * import App, { GRIST_OPTIONS } from \"./App\"\n *\n * mountGristWidget({ App, options: GRIST_OPTIONS, dev: import.meta.env.DEV })\n * ```\n */\n\nexport {\n GristWidgetApp,\n mountGristWidget,\n type GristWidgetAppProps,\n type MountGristWidgetConfig,\n type MountedGristWidget,\n} from \"./mount-grist-widget\"\nexport { useTheme, type ResolvedWidgetTheme, type UseThemeResult, type WidgetTheme } from \"./widget-theme\"\nexport { deployChannelLabel, parseDeployPath, type DeployChannel, type DeployPath } from \"./deploy-path\"\nexport { useReleasedVersions, type ReleasedVersion, type UseReleasedVersionsResult } from \"./released-versions\"\n","import { StrictMode, Suspense, type ComponentType, type ReactNode } from \"react\"\nimport { createRoot } from \"react-dom/client\"\n\nimport { GristBoundary, GristWidgetProvider } from \"../sdk\"\nimport type { UseGristOptions } from \"../sdk\"\nimport { LocalDevPage as DefaultLocalDevPage } from \"./chrome/local-dev-page\"\nimport { ReleasePage as DefaultReleasePage } from \"./chrome/release-page\"\nimport { WidgetAlerts } from \"./chrome/widget-alerts\"\nimport { parseDeployPath, type DeployChannel } from \"./deploy-path\"\nimport { EmbeddedThemeProvider, StandaloneThemeProvider } from \"./widget-theme\"\n\nexport type GristWidgetAppProps = {\n /** The widget. A `React.lazy()` component works too: its code then loads only inside Grist. */\n App: ComponentType\n /** The widget's `GRIST_OPTIONS`: access level, columns, and so on. */\n options: UseGristOptions\n /**\n * Whether this is the local dev server. Pass `import.meta.env.DEV`.\n * Outside Grist it picks the local-dev page over the release page.\n */\n dev?: boolean\n /**\n * Wraps the widget inside Grist, under {@link GristBoundary}. The default\n * lists what needs the user's attention (column mapping, access level,\n * failed writes) above the widget; `null` renders the widget alone.\n */\n Alerts?: ComponentType<{ children: ReactNode }> | null\n /** Shown outside Grist on the local dev server. Defaults to a page pointing at `pnpm test` and the `dev` loop. */\n LocalDevPage?: ComponentType\n /**\n * Shown outside Grist on a deployed URL (`/latest/`, `/dev/`, `/v<version>/`).\n * Defaults to a page linking every channel and version, with the URL to\n * paste into Grist.\n */\n ReleasePage?: ComponentType<{ channel: DeployChannel }>\n}\n\nexport type MountGristWidgetConfig = GristWidgetAppProps & {\n /** The element to render into, or its CSS selector. Defaults to `#root`. */\n root?: Element | string\n}\n\nexport type MountedGristWidget = {\n unmount: () => void\n}\n\n/**\n * Render a widget into the page: everything `src/main.tsx` used to wire by\n * hand.\n *\n * ```tsx\n * import { mountGristWidget } from \"grist-widget-sdk/app\"\n * import \"./index.css\"\n * import App, { GRIST_OPTIONS } from \"./App\"\n *\n * mountGristWidget({ App, options: GRIST_OPTIONS, dev: import.meta.env.DEV })\n * ```\n *\n * Inside Grist, the widget renders in {@link GristWidgetProvider} and\n * {@link GristBoundary}, which gates on its mapped columns when it declares\n * any, and follows Grist's light/dark theme. Outside Grist, where there is\n * nothing to connect to, the page shows `LocalDevPage` on the dev server and\n * `ReleasePage` on a deployed URL.\n */\nexport function mountGristWidget(config: MountGristWidgetConfig): MountedGristWidget {\n const { root = \"#root\", ...props } = config\n const container = typeof root === \"string\" ? document.querySelector(root) : root\n if (!container) {\n throw new Error(`mountGristWidget: no element matches \"${String(root)}\" to render the widget into.`)\n }\n\n const reactRoot = createRoot(container)\n reactRoot.render(\n <StrictMode>\n <GristWidgetApp {...props} />\n </StrictMode>\n )\n return { unmount: () => reactRoot.unmount() }\n}\n\n/**\n * The tree {@link mountGristWidget} renders, as a component: for a test, or\n * for a page that manages its own React root.\n */\nexport function GristWidgetApp({\n App,\n options,\n dev = false,\n Alerts = WidgetAlerts,\n LocalDevPage = DefaultLocalDevPage,\n ReleasePage = DefaultReleasePage,\n}: GristWidgetAppProps) {\n const Wrap = Alerts ?? PassThrough\n if (isEmbedded()) {\n return (\n <GristWidgetProvider options={options}>\n <EmbeddedThemeProvider>\n <GristBoundary>\n <div style={FILL}>\n <Wrap>\n <Suspense fallback={null}>\n <App />\n </Suspense>\n </Wrap>\n </div>\n </GristBoundary>\n </EmbeddedThemeProvider>\n </GristWidgetProvider>\n )\n }\n\n const channel = parseDeployPath(window.location.pathname).channel\n return (\n <StandaloneThemeProvider>\n <div style={FILL}>{dev ? <LocalDevPage /> : <ReleasePage channel={channel} />}</div>\n </StandaloneThemeProvider>\n )\n}\n\nconst FILL = { minHeight: \"100%\", width: \"100%\" } as const\n\n/** A Grist custom widget only ever runs in Grist's iframe. */\nfunction isEmbedded(): boolean {\n return typeof window !== \"undefined\" && window.self !== window.top\n}\n\nfunction PassThrough({ children }: { children: ReactNode }) {\n return <>{children}</>\n}\n","/**\n * `useGrist()`: the widget's one object for Grist — its connection, the\n * selected record and the section's records, column mapping, writes, widget\n * options, linking and the document's REST API.\n *\n * Inside `<GristWidgetProvider>` (what `mountGristWidget()` renders) it reads\n * the provider's connection; outside one, a page-wide connection made with\n * the first caller's options.\n */\n\nimport { createContext, useCallback, useContext, useEffect, useMemo, useSyncExternalStore } from \"react\"\n\nimport type { ValidateColumnMappingsResult } from \"./helpers/grist-mappings\"\nimport { createGristApi, type GristApi } from \"./runtime/api\"\nimport {\n deriveColumnMappingStatus,\n deriveError,\n deriveStatus,\n mapBackPatch,\n type GristWidgetStatus,\n} from \"./runtime/derive\"\nimport { mapAndCheck, type GristCellIssue } from \"./runtime/cells\"\nimport { ALL_STREAMS } from \"./runtime/host\"\nimport { resetGristReady } from \"./runtime/ready\"\nimport {\n createGristRuntime,\n initialRuntimeState,\n type GristRuntime,\n type GristRuntimeOptions,\n type GristRuntimeState,\n type GristTheme,\n type GristWidgetActionStatus,\n} from \"./runtime/runtime\"\nimport type { GristRowRecord, GristWidgetColumnMap } from \"./types\"\n\nexport type { GristTheme, GristWidgetActionStatus, GristWidgetStatus }\nexport type { GristColumnInfo, ListColumnsOptions, ListTablesOptions } from \"./runtime/api\"\n\n/** What the widget asks Grist for: access, columns to map, and the alerts it doesn't want. */\nexport type UseGristOptions = GristRuntimeOptions\n\n/** Derived from the selection: no row, a row, or the add-row placeholder. */\nexport type GristWidgetMode = \"empty\" | \"row\" | \"new-row\"\n\n/**\n * The widget's Grist state and API. Every method is referentially stable for\n * the widget's lifetime: safe in effect dependencies. The object itself is\n * new whenever a value changes; depend on the members you use, not on it.\n */\nexport type UseGristResult<TRow = Record<string, unknown>, TMapped = Record<string, unknown>> = Omit<\n GristApi,\n \"fetchTableRows\"\n> & {\n /** `\"booting\"` until Grist answers, then `\"ready\"`; `\"unavailable\"` outside Grist; `\"error\"` otherwise. */\n status: GristWidgetStatus\n /** Inside Grist with its plugin API (null while connecting). */\n isAvailable: boolean | null\n isReady: boolean\n /** Why the widget can't run (status `\"error\"` or `\"unavailable\"`), else null. */\n error: string | null\n /** Grist's light or dark theme, null until Grist sends it. */\n theme: GristTheme | null\n\n /** The selected row, raw column ids. */\n record: GristRowRecord<TRow> | null\n /** The section's rows (what its filters show), raw column ids. */\n records: GristRowRecord<TRow>[] | null\n /**\n * The selected row under the declared column names, each cell the JS value\n * its declared type promises (a cell that doesn't match is null, and in\n * `cellIssues`); null until every required column is mapped.\n */\n mappedRecord: TMapped | null\n /** Every row of the section, like `mappedRecord`. */\n mappedRecords: TMapped[] | null\n /** The mapped cells that didn't match their declared type (or the widget's `schema`), by row. */\n cellIssues: readonly GristCellIssue[]\n /** Declared column name → the Grist column id(s) mapped to it. */\n mappings: GristWidgetColumnMap\n /** Whether every required declared column is mapped (`pending` until Grist reports mappings). */\n columnMappingStatus: ValidateColumnMappingsResult\n mode: GristWidgetMode\n /** The Grist column id mapped to a declared name, or the name itself. */\n resolveMappedColumnId: (name: string) => string\n /** A patch under declared names, as real column ids for a write (multi-column mappings are skipped). */\n mapBack: (patch: Partial<TMapped>) => Record<string, unknown>\n /** The section's table id. */\n currentTableId: string | null\n\n /** Any table as rows (full access). */\n fetchTableRows: <T extends Record<string, unknown> = Record<string, unknown>>(\n tableId: string,\n options?: Parameters<GristApi[\"fetchTableRows\"]>[1]\n ) => Promise<GristRowRecord<T>[]>\n\n /** The last write's state. */\n actionStatus: GristWidgetActionStatus\n actionError: string | null\n\n /** The options Grist stores for this widget, null until it sends them. */\n widgetOptions: Record<string, unknown> | null\n}\n\ntype GristContextValue = { runtime: GristRuntime; api: GristApi }\n\nconst GristContext = createContext<GristContextValue | null>(null)\nGristContext.displayName = \"GristContext\"\n\n/** @internal The provider's (or the page's) runtime, for the SDK's own components. */\nexport function useGristRuntime(): GristContextValue | null {\n return useContext(GristContext)\n}\n\nfunction newConnection(options: UseGristOptions | undefined): GristContextValue {\n const runtime = createGristRuntime(options)\n return { runtime, api: createGristApi(runtime) }\n}\n\nlet pageConnection: GristContextValue | null = null\n\n/** @internal Tests: forget the page's connection and every Grist binding. */\nexport function resetGristForTests(): void {\n pageConnection = null\n resetGristReady()\n for (const s of ALL_STREAMS) s.reset()\n}\n\nexport const GristContextProvider = GristContext.Provider\nexport { newConnection }\n\nconst serverState = () => initialRuntimeState()\n\n/** The connection's state, re-rendering on every change. */\nexport function useGristState(connection: GristContextValue): GristRuntimeState {\n const { runtime } = connection\n useEffect(() => runtime.start(), [runtime])\n return useSyncExternalStore(runtime.subscribe, runtime.getState, serverState)\n}\n\ntype Mapped<TMapped> = { record: TMapped | null; records: TMapped[] | null; issues: readonly GristCellIssue[] }\n\nconst NO_ISSUES: readonly GristCellIssue[] = Object.freeze([])\n\n/** The mapped, checked record and records; recomputed only when they, the mappings or the options change. */\nfunction useMapped<TMapped>(state: GristRuntimeState, options: GristRuntimeOptions): Mapped<TMapped> {\n const { record, records, mappings } = state\n const { columns, schema } = options\n return useMemo(() => {\n const issues: GristCellIssue[] = []\n const rows =\n records && (columns?.length ? mappings !== null : true)\n ? records.map((r) => {\n const out = mapAndCheck<TMapped>(r, columns, mappings, schema)\n issues.push(...out.issues)\n return out.value\n })\n : null\n const selected = mapAndCheck<TMapped>(record, columns, mappings, schema)\n if (record && !records?.some((r) => r.id === record.id)) issues.push(...selected.issues)\n const mappedRecords = rows && rows.every((r) => r !== null) ? (rows as TMapped[]) : null\n return { record: selected.value, records: mappedRecords, issues: issues.length ? issues : NO_ISSUES }\n }, [record, records, mappings, columns, schema])\n}\n\nfunction buildResult<TRow, TMapped>(\n state: GristRuntimeState,\n mapped: Mapped<TMapped>,\n connection: GristContextValue,\n mapBack: (patch: Partial<TMapped>) => Record<string, unknown>,\n resolveMappedColumnId: (name: string) => string\n): UseGristResult<TRow, TMapped> {\n const { runtime, api } = connection\n const status = deriveStatus(state)\n const columns = runtime.options.columns\n return {\n ...api,\n status,\n isAvailable: state.connection === \"connecting\" ? null : state.connection !== \"not-embedded\" && state.connection !== \"unavailable\",\n isReady: status === \"ready\",\n error: deriveError(state),\n theme: state.theme,\n record: state.record as GristRowRecord<TRow> | null,\n records: state.records as GristRowRecord<TRow>[] | null,\n mappedRecord: mapped.record,\n mappedRecords: mapped.records,\n cellIssues: mapped.issues,\n mappings: state.mappings ?? EMPTY_MAPPINGS,\n columnMappingStatus: deriveColumnMappingStatus(columns, state.mappings),\n mode: state.isNewRecord ? \"new-row\" : state.record ? \"row\" : \"empty\",\n resolveMappedColumnId,\n mapBack,\n currentTableId: state.currentTableId,\n actionStatus: state.actionStatus,\n actionError: state.actionError,\n widgetOptions: state.widgetOptions,\n }\n}\n\nconst EMPTY_MAPPINGS: GristWidgetColumnMap = Object.freeze({}) as GristWidgetColumnMap\n\nfunction useGristResult<TRow, TMapped>(connection: GristContextValue): UseGristResult<TRow, TMapped> {\n const state = useGristState(connection)\n const mappings = state.mappings ?? EMPTY_MAPPINGS\n const { runtime } = connection\n const resolveMappedColumnId = useCallback(\n (name: string) => {\n const real = mappings[name]\n if (typeof real === \"string\" && real) return real\n if (Array.isArray(real) && typeof real[0] === \"string\") return real[0]\n return name\n },\n [mappings]\n )\n const mapBack = useCallback(\n (patch: Partial<TMapped>) => {\n const { fields, skipped } = mapBackPatch(patch as Record<string, unknown>, mappings)\n const previous = runtime.getState().mapBackSkipped\n if (previous.join(\"\\0\") !== skipped.join(\"\\0\")) runtime.update({ mapBackSkipped: skipped })\n return fields\n },\n [mappings, runtime]\n )\n const mapped = useMapped<TMapped>(state, runtime.options)\n return useMemo(\n () => buildResult<TRow, TMapped>(state, mapped, connection, mapBack, resolveMappedColumnId),\n [state, mapped, connection, mapBack, resolveMappedColumnId]\n )\n}\n\n/**\n * The widget's Grist state and API. Inside `<GristWidgetProvider>` it uses the\n * provider's connection and ignores `options`; outside one, the page's, made\n * with the first caller's `options`.\n */\nexport function useGrist<TRow = Record<string, unknown>, TMapped = Record<string, unknown>>(\n options?: UseGristOptions\n): UseGristResult<TRow, TMapped> {\n const fromProvider = useContext(GristContext)\n const connection = fromProvider ?? (pageConnection ??= newConnection(options))\n return useGristResult<TRow, TMapped>(connection)\n}\n\n/** `useGrist()` inside a provider, or null outside one: for components that also work without Grist. */\nexport function useGristOptional<TRow = Record<string, unknown>, TMapped = Record<string, unknown>>(): UseGristResult<\n TRow,\n TMapped\n> | null {\n const fromProvider = useContext(GristContext)\n // The hooks below run in both branches; the provider only decides which connection they read.\n const result = useGristResult<TRow, TMapped>(fromProvider ?? DETACHED)\n return fromProvider ? result : null\n}\n\n/** `useGrist()` inside `<GristWidgetProvider>`; throws outside one. */\nexport function useGristContext<TRow = Record<string, unknown>, TMapped = Record<string, unknown>>(): UseGristResult<\n TRow,\n TMapped\n> {\n if (!useContext(GristContext)) {\n throw new Error(\"useGristContext() must be used inside <GristWidgetProvider> (mountGristWidget renders one).\")\n }\n return useGrist<TRow, TMapped>()\n}\n\n/** A connection that never starts: what useGristOptional reads outside a provider. */\nconst DETACHED: GristContextValue = (() => {\n const state = initialRuntimeState()\n const runtime: GristRuntime = {\n options: {},\n getState: () => state,\n subscribe: () => () => {},\n start: () => () => {},\n reload: async () => {},\n update: () => {},\n }\n return { runtime, api: createGristApi(runtime) }\n})()\n\n/** @internal The nearest provider's connection and its state (idle outside one). */\nexport function useNearestGristState(): {\n connection: GristContextValue | null\n state: GristRuntimeState\n cellIssues: readonly GristCellIssue[]\n} {\n const connection = useContext(GristContext)\n const state = useGristState(connection ?? DETACHED)\n const { issues } = useMapped(state, (connection ?? DETACHED).runtime.options)\n return { connection, state, cellIssues: issues }\n}\n","/**\n * Encoding helpers for Grist cell values.\n *\n * Grist sends some types as marshalled tuples or numeric epochs. This file\n * exposes pure decode/encode functions so widget code never has to spelunk\n * Grist's wire format.\n *\n * References: Grist `grist/RowRecord` and `grist/DocActions` typings.\n */\n\nimport type { GristReplicaColumn } from \"../types\"\n\n/** `[\"E\", \"ErrorClass\", \"message\", traceback?]` — Grist error sentinel. */\nexport type GristEncodedError = [\"E\", string, string?, string?]\n/** `[\"L\", ...items]` — list (used for ChoiceList, RefList, Attachments). */\nexport type GristEncodedList = [\"L\", ...unknown[]]\n/** `[\"D\", epochSeconds, \"tz/Name\"]` — DateTime with timezone. */\nexport type GristEncodedDateTime = [\"D\", number, string]\n/** `[\"d\", epochSeconds]` — Date (no time). */\nexport type GristEncodedDate = [\"d\", number]\n/** `[\"R\", tableId, rowId]` — explicit reference. */\nexport type GristEncodedRef = [\"R\", string, number]\n/** `[\"r\", rowId]` — bare reference (when table is contextual). */\nexport type GristEncodedBareRef = [\"r\", number]\n/** `[\"P\", encoded]` — pending marker. */\nexport type GristEncodedPending = [\"P\"]\n\nexport type GristDecodedValue =\n | null\n | string\n | number\n | boolean\n | Date\n | GristDecodedValue[]\n | { __error: true; type: string; message?: string; traceback?: string }\n | { __ref: true; tableId?: string; rowId: number }\n\nconst MARSHALLED_TAGS = new Set([\"E\", \"L\", \"D\", \"d\", \"R\", \"r\", \"P\"])\n\nfunction isMarshalledTuple(value: unknown): value is unknown[] {\n return (\n Array.isArray(value) &&\n typeof value[0] === \"string\" &&\n value[0].length <= 2 &&\n MARSHALLED_TAGS.has(value[0])\n )\n}\n\n/**\n * Normalises a Grist `fetchTable` cell that points at a row in another table.\n * Most payloads use a bare numeric row id, but `Ref:*` values may appear as\n * `[\"R\", tableId, rowId]` or `[\"r\", rowId]` (same shape as {@link decodeGristValue}).\n */\nexport function coerceGristDocApiRefRowId(value: unknown): number | undefined {\n if (typeof value === \"number\" && Number.isFinite(value)) return value\n if (!Array.isArray(value) || value.length < 2) return undefined\n const tag = value[0]\n if (tag === \"R\" && typeof value[2] === \"number\" && Number.isFinite(value[2])) return value[2]\n if (tag === \"r\" && typeof value[1] === \"number\" && Number.isFinite(value[1])) return value[1]\n return undefined\n}\n\nfunction looksLikeAttachmentColumn(column?: GristReplicaColumn): boolean {\n return column?.type === \"Attachments\"\n}\n\nfunction looksLikeChoiceListColumn(column?: GristReplicaColumn): boolean {\n return column?.type === \"ChoiceList\"\n}\n\nfunction looksLikeRefListColumn(column?: GristReplicaColumn): boolean {\n return typeof column?.type === \"string\" && column.type.startsWith(\"RefList:\")\n}\n\nfunction looksLikeRefColumn(column?: GristReplicaColumn): boolean {\n return typeof column?.type === \"string\" && column.type.startsWith(\"Ref:\")\n}\n\nfunction looksLikeDateColumn(column?: GristReplicaColumn): boolean {\n return column?.type === \"Date\"\n}\n\nfunction looksLikeDateTimeColumn(column?: GristReplicaColumn): boolean {\n return typeof column?.type === \"string\" && column.type.startsWith(\"DateTime\")\n}\n\n/**\n * Decodes a Grist cell value into an idiomatic JS value.\n *\n * Pass the column's metadata (from `useGristSchema` or `_grist_Tables_column`)\n * for type-aware decoding (e.g. `Date` columns return `Date` even when stored as a number).\n */\nexport function decodeGristValue(value: unknown, column?: GristReplicaColumn): GristDecodedValue {\n if (value === null || value === undefined) return null\n\n if (isMarshalledTuple(value)) {\n const tag = value[0] as string\n switch (tag) {\n case \"E\":\n return {\n __error: true,\n type: typeof value[1] === \"string\" ? value[1] : \"Error\",\n message: typeof value[2] === \"string\" ? value[2] : undefined,\n traceback: typeof value[3] === \"string\" ? value[3] : undefined,\n }\n case \"L\":\n return value.slice(1).map((v) => decodeGristValue(v, undefined)) as GristDecodedValue[]\n case \"D\":\n if (typeof value[1] === \"number\") return new Date(value[1] * 1000)\n return null\n case \"d\":\n if (typeof value[1] === \"number\") return new Date(value[1] * 1000)\n return null\n case \"R\":\n return {\n __ref: true,\n tableId: typeof value[1] === \"string\" ? value[1] : undefined,\n rowId: typeof value[2] === \"number\" ? value[2] : 0,\n }\n case \"r\":\n return { __ref: true, rowId: typeof value[1] === \"number\" ? value[1] : 0 }\n case \"P\":\n return null\n default:\n return null\n }\n }\n\n if (looksLikeDateColumn(column) || looksLikeDateTimeColumn(column)) {\n if (typeof value === \"number\" && Number.isFinite(value)) return new Date(value * 1000)\n }\n\n if (looksLikeRefColumn(column) && typeof value === \"number\") {\n return { __ref: true, rowId: value }\n }\n\n if ((looksLikeRefListColumn(column) || looksLikeChoiceListColumn(column) || looksLikeAttachmentColumn(column)) && Array.isArray(value)) {\n return value.map((v) => decodeGristValue(v, undefined)) as GristDecodedValue[]\n }\n\n if (typeof value === \"string\" || typeof value === \"number\" || typeof value === \"boolean\") return value\n if (Array.isArray(value)) return value.map((v) => decodeGristValue(v, undefined)) as GristDecodedValue[]\n return null\n}\n\n/** Convenience: true when the cell is a Grist error sentinel. */\nexport function isGristCellError(value: unknown): value is GristEncodedError {\n return Array.isArray(value) && value[0] === \"E\"\n}\n\n/**\n * Encodes a JS value into Grist's expected wire form for a given column type.\n *\n * Use before passing values to `applyUserActions` or `TableOperations.update`\n * for `Date`, `DateTime`, `Ref`, `RefList`, and `ChoiceList` columns.\n */\nexport function encodeGristValue(value: unknown, column?: GristReplicaColumn): unknown {\n if (value === null || value === undefined) return null\n\n if (looksLikeDateColumn(column) || looksLikeDateTimeColumn(column)) {\n if (value instanceof Date) return Math.floor(value.getTime() / 1000)\n if (typeof value === \"string\") {\n const parsed = Date.parse(value)\n if (!Number.isNaN(parsed)) return Math.floor(parsed / 1000)\n }\n if (typeof value === \"number\") return Math.floor(value)\n }\n\n if (looksLikeRefColumn(column)) {\n if (typeof value === \"number\") return value\n if (value && typeof value === \"object\" && \"rowId\" in value) {\n return (value as { rowId: number }).rowId\n }\n }\n\n if (looksLikeRefListColumn(column) || looksLikeChoiceListColumn(column) || looksLikeAttachmentColumn(column)) {\n if (Array.isArray(value)) {\n const items = value.map((v) => {\n if (v && typeof v === \"object\" && \"rowId\" in v) return (v as { rowId: number }).rowId\n return v\n })\n return [\"L\", ...items]\n }\n }\n\n return value\n}\n","import type { GristDocApi, GristReplicaColumn, GristRowRecord } from \"../types\"\nimport { decodeGristValue } from \"./grist-value-codec\"\n\n/** Column-oriented table payload (`fetchTable`, `fetchSelectedTable`): `{ id: [...], Name: [...] }`. */\nexport type GristColumnarTable = Record<string, unknown[]>\nexport type GristTableRowsOrder = \"none\" | \"id\" | \"grist\"\nexport type FetchGristTableRowsOptions = {\n /** Column metadata, to decode each cell (except `id`) with `decodeGristValue`. */\n columns?: Record<string, GristReplicaColumn>\n /**\n * Row order:\n * - `grist` (default): `manualSort` ascending when present, then `id`.\n * - `id`: numeric `id` ascending.\n * - `none`: as `fetchTable` returned them.\n */\n order?: GristTableRowsOrder\n}\n\n/** Row count from columnar `fetchTable` data (prefers `id` column length). */\nexport function computeRowCount(data: Record<string, unknown[]>): number {\n const idCol = data.id\n if (Array.isArray(idCol)) return idCol.length\n for (const key of Object.keys(data)) {\n const col = data[key]\n if (Array.isArray(col)) return col.length\n }\n return 0\n}\n\n/**\n * Decode columnar `fetchTable` into replica row objects (same convention as the playground grid).\n */\nexport function decodeColumnarToReplicaRows(\n data: GristColumnarTable,\n columnIds: string[],\n columns: Record<string, GristReplicaColumn>,\n maxRows?: number\n): GristRowRecord[] {\n const nFull = computeRowCount(data)\n const n = maxRows !== undefined ? Math.min(nFull, maxRows) : nFull\n const out: GristRowRecord[] = []\n for (let i = 0; i < n; i++) {\n const row: Record<string, unknown> = {}\n for (const k of columnIds) {\n const arr = data[k]\n const raw = Array.isArray(arr) ? arr[i] : undefined\n if (k === \"id\") {\n row[k] = raw\n } else {\n row[k] = decodeGristValue(raw, columns[k]) as unknown\n }\n }\n out.push(row as GristRowRecord)\n }\n return out\n}\n\n/** Turn `fetchTable` output into row objects (order follows the `id` column). */\nexport function tableDataToRows<T = Record<string, unknown>>(\n data: GristColumnarTable\n): GristRowRecord<T>[] {\n const idCol = data.id\n if (!Array.isArray(idCol) || idCol.length === 0) return []\n const keys = Object.keys(data)\n const n = idCol.length\n const rows: GristRowRecord<T>[] = []\n for (let i = 0; i < n; i++) {\n const row: Record<string, unknown> = {}\n for (const k of keys) {\n const col = data[k]\n row[k] = Array.isArray(col) ? col[i] : undefined\n }\n rows.push(row as GristRowRecord<T>)\n }\n return rows\n}\n\nfunction manualSortKey(row: Record<string, unknown>): number | null {\n const v = row.manualSort\n if (typeof v === \"number\" && !Number.isNaN(v)) return v\n if (typeof v === \"string\" && v.trim() !== \"\") {\n const n = Number(v)\n if (!Number.isNaN(n)) return n\n }\n return null\n}\n\n/**\n * Sort rows by Grist's display order: `manualSort` ascending when present on\n * any row, otherwise numeric `id` ascending.\n */\nexport function sortRowsByGristOrder<T = Record<string, unknown>>(\n rows: readonly GristRowRecord<T>[]\n): GristRowRecord<T>[] {\n const hasManual = rows.some((r) => manualSortKey(r as Record<string, unknown>) !== null)\n if (!hasManual) {\n return [...rows].sort((a, b) => {\n const ida = typeof a.id === \"number\" ? a.id : 0\n const idb = typeof b.id === \"number\" ? b.id : 0\n return ida - idb\n })\n }\n return [...rows].sort((a, b) => {\n const ma = manualSortKey(a as Record<string, unknown>)\n const mb = manualSortKey(b as Record<string, unknown>)\n if (ma !== null && mb !== null && ma !== mb) return ma - mb\n if (ma !== null && mb === null) return -1\n if (ma === null && mb !== null) return 1\n const ida = typeof a.id === \"number\" ? a.id : 0\n const idb = typeof b.id === \"number\" ? b.id : 0\n return ida - idb\n })\n}\n\n/**\n * Same row materialization as {@link fetchGristTableRows} after `fetchTable`\n * returns columnar data. Hosts that already have columnar data (e.g. the\n * emulator building from in-memory rows) can use this and skip `docApi.fetchTable`.\n */\nexport function materializeGristRowsFromColumnar<T extends Record<string, unknown> = Record<string, unknown>>(\n data: GristColumnarTable,\n options?: FetchGristTableRowsOptions\n): GristRowRecord<T>[] {\n const order = options?.order ?? \"grist\"\n let rows: GristRowRecord<T>[]\n if (options?.columns) {\n const columnIds = Object.keys(data)\n rows = decodeColumnarToReplicaRows(data, columnIds, options.columns) as GristRowRecord<T>[]\n } else {\n rows = tableDataToRows<T>(data)\n }\n\n if (order === \"none\") return rows\n if (order === \"id\") {\n return [...rows].sort((a, b) => {\n const ida = typeof a.id === \"number\" ? a.id : 0\n const idb = typeof b.id === \"number\" ? b.id : 0\n return ida - idb\n })\n }\n return sortRowsByGristOrder(rows)\n}\n\n/**\n * Fetch a table and return rows as objects, optionally decoded from schema and sorted.\n */\nexport async function fetchGristTableRows<T extends Record<string, unknown> = Record<string, unknown>>(\n docApi: GristDocApi,\n tableId: string,\n options?: FetchGristTableRowsOptions\n): Promise<GristRowRecord<T>[]> {\n const data = (await docApi.fetchTable(tableId)) as GristColumnarTable\n return materializeGristRowsFromColumnar<T>(data, options)\n}\n","/**\n * Grist stores column widget configuration in `_grist_Tables_column.widgetOptions`\n * as a JSON string. Choice fields use `choices: string[]` plus optional\n * `choiceOptions: Record<string, Style>` (e.g. `fillColor`, `textColor`).\n *\n * @see https://github.com/gristlabs/grist-core/blob/main/app/client/widgets/ChoiceEditor.js\n */\n\n/** One selectable choice for UI (value stored in the cell is `value`). */\nexport type GristChoiceListEntry = {\n value: string\n label: string\n fillColor?: string\n textColor?: string\n}\n\n/**\n * Parse a cell value from `_grist_Tables_column.widgetOptions` into a plain object.\n */\nexport function parseGristWidgetOptionsCell(raw: unknown): Record<string, unknown> | undefined {\n if (raw == null || raw === \"\") return undefined\n if (typeof raw === \"string\") {\n try {\n const parsed: unknown = JSON.parse(raw)\n if (parsed && typeof parsed === \"object\" && !Array.isArray(parsed)) {\n return parsed as Record<string, unknown>\n }\n } catch {\n return undefined\n }\n return undefined\n }\n if (typeof raw === \"object\" && !Array.isArray(raw)) {\n return raw as Record<string, unknown>\n }\n return undefined\n}\n\nfunction readStyleColor(style: Record<string, unknown>, key: string): string | undefined {\n const v = style[key]\n return typeof v === \"string\" ? v : undefined\n}\n\n/**\n * Normalizes Grist Choice / ChoiceList widgetOptions into a flat list for dropdowns.\n * `choices` entries are string labels (the stored cell value). Per-choice styling\n * lives in `choiceOptions[label]`.\n */\nexport function normalizeGristChoiceListEntries(\n widgetOptions: Record<string, unknown> | undefined\n): GristChoiceListEntry[] {\n if (!widgetOptions) return []\n const rawChoices = widgetOptions.choices\n if (!Array.isArray(rawChoices)) return []\n\n const choiceOptionsRaw = widgetOptions.choiceOptions\n const choiceOptions: Record<string, Record<string, unknown>> =\n choiceOptionsRaw &&\n typeof choiceOptionsRaw === \"object\" &&\n !Array.isArray(choiceOptionsRaw)\n ? (choiceOptionsRaw as Record<string, Record<string, unknown>>)\n : {}\n\n const out: GristChoiceListEntry[] = []\n for (const c of rawChoices) {\n const value = typeof c === \"string\" ? c : c != null ? String(c) : \"\"\n if (!value) continue\n const style = choiceOptions[value] ?? {}\n out.push({\n value,\n label: value,\n fillColor: readStyleColor(style, \"fillColor\"),\n textColor: readStyleColor(style, \"textColor\"),\n })\n }\n return out\n}\n","import type {\n GristDocApi,\n GristDocumentMode,\n GristReplicaColumn,\n GristReplicaDocument,\n GristReplicaTable,\n} from \"../types\"\nimport { computeRowCount, decodeColumnarToReplicaRows, type GristColumnarTable } from \"./grist-table-data\"\nimport { inferGristFormulaKind } from \"./grist-schema-formula\"\nimport { parseGristWidgetOptionsCell } from \"./grist-widget-options\"\nimport { coerceGristDocApiRefRowId } from \"./grist-value-codec\"\n\nexport type ReplicaTableColumnMetaLite = {\n colRef?: number\n type?: string\n label?: string\n parentPos?: number\n isFormula?: boolean\n formula?: string\n description?: string\n widgetOptions?: Record<string, unknown>\n displayColRef?: number\n visibleColRef?: number\n}\n\nconst FORMULA_PREVIEW_MAX = 500\n\nfunction readCellStr(table: Record<string, unknown[]>, key: string, rowIndex: number): string | undefined {\n const col = table[key]\n if (!Array.isArray(col)) return undefined\n const v = col[rowIndex]\n if (v === null || v === undefined) return undefined\n if (typeof v === \"string\") return v\n if (typeof v === \"number\" || typeof v === \"boolean\") return String(v)\n return undefined\n}\n\nfunction readCellNum(table: Record<string, unknown[]>, key: string, rowIndex: number): number | undefined {\n const col = table[key]\n if (!Array.isArray(col)) return undefined\n const v = col[rowIndex]\n if (typeof v === \"number\" && !Number.isNaN(v)) return v\n if (typeof v === \"string\" && v.trim() !== \"\") {\n const n = Number(v)\n if (!Number.isNaN(n)) return n\n }\n return undefined\n}\n\nfunction pickColumnMeta(meta: ReplicaTableColumnMetaLite | undefined): GristReplicaColumn {\n if (!meta) return {}\n const out: GristReplicaColumn = {}\n if (meta.colRef !== undefined) out.colRef = meta.colRef\n if (meta.type) out.type = meta.type\n if (meta.label) out.label = meta.label\n if (meta.parentPos !== undefined) out.parentPos = meta.parentPos\n if (meta.isFormula) out.isFormula = true\n const formulaRaw = meta.formula?.trim() ?? \"\"\n out.formulaKind = inferGristFormulaKind(Boolean(meta.isFormula), formulaRaw)\n if (formulaRaw) {\n out.formula =\n formulaRaw.length > FORMULA_PREVIEW_MAX ? `${formulaRaw.slice(0, FORMULA_PREVIEW_MAX)}...` : formulaRaw\n }\n if (meta.description) out.description = meta.description\n if (meta.widgetOptions && Object.keys(meta.widgetOptions).length > 0) {\n out.widgetOptions = meta.widgetOptions\n }\n if (meta.displayColRef !== undefined) out.displayColRef = meta.displayColRef\n if (meta.visibleColRef !== undefined) out.visibleColRef = meta.visibleColRef\n return out\n}\n\nexport async function loadColumnMetadataByTable(\n docApi: GristDocApi\n): Promise<Map<string, Map<string, ReplicaTableColumnMetaLite>>> {\n const byTable = new Map<string, Map<string, ReplicaTableColumnMetaLite>>()\n try {\n const tables = await docApi.fetchTable(\"_grist_Tables\")\n const columns = await docApi.fetchTable(\"_grist_Tables_column\")\n const tableIds = tables.tableId\n const tableInternalIds = tables.id\n if (!Array.isArray(tableIds) || !Array.isArray(tableInternalIds)) return byTable\n\n const internalIdToTableId = new Map<number, string>()\n for (let i = 0; i < tableInternalIds.length; i++) {\n const tid = tableIds[i]\n const iid = coerceGristDocApiRefRowId(tableInternalIds[i])\n if (typeof tid === \"string\" && iid !== undefined) internalIdToTableId.set(iid, tid)\n }\n\n const parentIds = columns.parentId\n const colIds = columns.colId\n const columnIds = columns.id\n if (\n !Array.isArray(parentIds) ||\n !Array.isArray(colIds) ||\n !Array.isArray(columnIds) ||\n parentIds.length !== colIds.length ||\n colIds.length !== columnIds.length\n ) {\n return byTable\n }\n\n const n = parentIds.length\n for (let i = 0; i < n; i++) {\n const parentRowId = coerceGristDocApiRefRowId(parentIds[i])\n const colRef = coerceGristDocApiRefRowId(columnIds[i])\n const colId = colIds[i]\n if (parentRowId === undefined || colRef === undefined || typeof colId !== \"string\") continue\n const tableId = internalIdToTableId.get(parentRowId)\n if (!tableId) continue\n\n let colMap = byTable.get(tableId)\n if (!colMap) {\n colMap = new Map()\n byTable.set(tableId, colMap)\n }\n\n const parentPos = readCellNum(columns, \"parentPos\", i)\n const isFormulaCol = columns.isFormula\n const isFormula = Array.isArray(isFormulaCol) ? Boolean(isFormulaCol[i]) : false\n\n const woCol = columns.widgetOptions\n const widgetOptions =\n Array.isArray(woCol) && i < woCol.length ? parseGristWidgetOptionsCell(woCol[i]) : undefined\n const displayColRef = coerceGristDocApiRefRowId(\n Array.isArray(columns.displayCol) ? columns.displayCol[i] : undefined\n )\n const visibleColRef = coerceGristDocApiRefRowId(\n Array.isArray(columns.visibleCol) ? columns.visibleCol[i] : undefined\n )\n\n colMap.set(colId, {\n colRef,\n type: readCellStr(columns, \"type\", i),\n label: readCellStr(columns, \"label\", i),\n parentPos: parentPos !== undefined ? parentPos : undefined,\n isFormula,\n formula: readCellStr(columns, \"formula\", i),\n description: readCellStr(columns, \"description\", i) ?? readCellStr(columns, \"descr\", i),\n widgetOptions,\n displayColRef,\n visibleColRef,\n })\n }\n } catch {\n // Metadata is best-effort; document build still works from cell data alone.\n }\n return byTable\n}\n\nexport function orderedColumnIds(\n data: Record<string, unknown[]>,\n metaByCol: Map<string, ReplicaTableColumnMetaLite>\n): string[] {\n const keys = Object.keys(data).filter((k) => Array.isArray(data[k]))\n keys.sort((a, b) => {\n const pa = metaByCol.get(a)?.parentPos\n const pb = metaByCol.get(b)?.parentPos\n if (pa !== undefined && pb !== undefined && pa !== pb) return pa - pb\n if (pa !== undefined && pb === undefined) return -1\n if (pa === undefined && pb !== undefined) return 1\n return a.localeCompare(b)\n })\n return keys\n}\n\n/** Build replica column metadata from columnar `fetchTable` + `_grist_Tables_column` maps. */\nexport function buildReplicaColumnsFromColumnar(\n data: Record<string, unknown[]>,\n colMeta: Map<string, ReplicaTableColumnMetaLite>\n): Record<string, GristReplicaColumn> {\n const columnIds = orderedColumnIds(data, colMeta)\n const columns: Record<string, GristReplicaColumn> = {}\n for (const colId of columnIds) {\n const arr = data[colId]\n if (!Array.isArray(arr)) continue\n const meta = colMeta.get(colId)\n columns[colId] = pickColumnMeta(meta)\n }\n return columns\n}\n\nfunction rowModeFromIncludeRows(includeRows: false | \"samples\" | \"full\"): GristDocumentMode {\n if (includeRows === false) return \"schema-only\"\n if (includeRows === \"samples\") return \"schema+samples\"\n return \"schema+data\"\n}\n\nexport type BuildReplicaDocumentFromDocApiOptions = {\n /** When false (default), skip fetching row data for `tableId` starting with `_grist`. */\n includeSystemTableData?: boolean\n /**\n * Row bodies: omit (`false`), first N (`samples`), or full decode (`full`).\n * Default `samples`.\n */\n includeRows?: false | \"samples\" | \"full\"\n /** Max rows per table when `includeRows` is `samples`. Default 10. */\n sampleRowLimit?: number\n /** Set on the replica as `source` for host logging / provenance. */\n source?: string\n}\n\n/**\n * Build {@link GristReplicaDocument} from a host `docApi`:\n * metadata from `_grist_Tables` / `_grist_Tables_column` when readable, plus optional decoded `rows`.\n *\n * Prefer {@link useGrist}'s `buildReplicaDocumentFromDocApi()` when you already use the primary hook.\n */\nexport async function buildReplicaDocumentFromDocApi(\n docApi: GristDocApi,\n options?: BuildReplicaDocumentFromDocApiOptions\n): Promise<GristReplicaDocument> {\n const includeSystemTableData = options?.includeSystemTableData ?? false\n const includeRows = options?.includeRows ?? \"samples\"\n const sampleRowLimit = options?.sampleRowLimit ?? 10\n const rowMode = rowModeFromIncludeRows(includeRows)\n\n const metaByTable = await loadColumnMetadataByTable(docApi)\n\n let docName: string | undefined\n try {\n docName = String(await Promise.resolve(docApi.getDocName()))\n } catch {\n docName = undefined\n }\n\n const tableIdsRaw = await Promise.resolve(docApi.listTables())\n const tableIds = Array.isArray(tableIdsRaw) ? [...tableIdsRaw] : []\n\n const tables: Record<string, GristReplicaTable> = {}\n\n for (const tableId of tableIds) {\n const omitData = !includeSystemTableData && tableId.startsWith(\"_grist\")\n if (omitData) {\n tables[tableId] = {\n rowCount: 0,\n dataOmitted: true,\n dataOmittedReason:\n \"Row scan skipped for tables whose id starts with `_grist` unless `includeSystemTableData` is true.\",\n columns: {},\n }\n continue\n }\n\n try {\n const data = (await docApi.fetchTable(tableId)) as GristColumnarTable\n const rowCount = computeRowCount(data)\n const colMeta = metaByTable.get(tableId) ?? new Map<string, ReplicaTableColumnMetaLite>()\n const columnIds = orderedColumnIds(data, colMeta)\n const columns = buildReplicaColumnsFromColumnar(data, colMeta)\n\n const table: GristReplicaTable = { columns, rowCount }\n if (includeRows === \"full\") {\n table.rows = decodeColumnarToReplicaRows(data, columnIds, columns)\n } else if (includeRows === \"samples\") {\n table.rows = decodeColumnarToReplicaRows(data, columnIds, columns, sampleRowLimit)\n }\n tables[tableId] = table\n } catch (err) {\n tables[tableId] = {\n rowCount: 0,\n error: err instanceof Error ? err.message : String(err),\n columns: {},\n }\n }\n }\n\n const out: GristReplicaDocument = {\n generatedAt: new Date().toISOString(),\n docName,\n mode: rowMode,\n tables,\n }\n if (options?.source !== undefined && options.source !== \"\") {\n out.source = options.source\n }\n return out\n}\n","export type GristColumnLike = {\n formula?: string\n}\n\nexport type GristNoiseColumnsOptions = {\n excludeId?: boolean\n excludeGristHelpers?: boolean\n excludeLoggingColumns?: boolean\n /**\n * When `true`, treat Grist's `manualSort` column as noise (omit from filtered replicas).\n * Default `false` — `manualSort` is kept unless you opt in.\n */\n excludeManualSort?: boolean\n}\n\nconst NOISE_COLUMN_FORMULAS = new Set([\"now()\"])\n\nfunction normalizeFormulaForComparison(formula: string): string {\n return formula.trim().toLowerCase().replace(/\\s+/g, \"\")\n}\n\n/**\n * Grist-centric \"technical column\" detection used by document hooks and widgets.\n *\n * - `id` (when {@link GristNoiseColumnsOptions.excludeId} is true — default)\n * - `manualSort` (only when {@link GristNoiseColumnsOptions.excludeManualSort} is true)\n * - `gristHelper_*` (when `excludeGristHelpers` is true — default)\n * - trigger/logging formulas (`NOW()`, `user.*`) (when `excludeLoggingColumns` is true — default)\n */\nexport function isGristNoiseColumn(\n colId: string,\n col?: GristColumnLike,\n options?: GristNoiseColumnsOptions\n): boolean {\n const excludeId = options?.excludeId ?? true\n const excludeGristHelpers = options?.excludeGristHelpers ?? true\n const excludeLoggingColumns = options?.excludeLoggingColumns ?? true\n const excludeManualSort = options?.excludeManualSort ?? false\n\n if (excludeId && colId === \"id\") return true\n if (excludeManualSort && colId === \"manualSort\") return true\n if (excludeGristHelpers && colId.startsWith(\"gristHelper_\")) return true\n\n if (excludeLoggingColumns) {\n const formula = typeof col?.formula === \"string\" ? normalizeFormulaForComparison(col.formula) : \"\"\n if (formula && NOISE_COLUMN_FORMULAS.has(formula)) return true\n if (formula.startsWith(\"user.\")) return true\n }\n\n return false\n}\n","import type { GristDocApi } from \"../types\"\n\nexport type GristFetchedAttachment = {\n base64: string\n contentType: string\n}\n\nexport type GristFetchedAttachmentBlob = {\n blob: Blob\n contentType: string\n}\n\nfunction attachmentIdFromObjectRecord(record: Record<string, unknown>): string | undefined {\n for (const candidate of [record.id, record.attachmentId, record.fileId]) {\n if (candidate === undefined || candidate === null) continue\n return String(candidate)\n }\n return undefined\n}\n\n/**\n * All attachment ids found in a Grist attachment cell value (ordered, deduped).\n * Attachment columns are usually an **array** of file refs; a single id or one JSON object is also supported.\n */\nexport function extractGristAttachmentIdsFromCell(value: unknown): string[] {\n const out: string[] = []\n const seen = new Set<string>()\n const push = (id: string) => {\n if (seen.has(id)) return\n seen.add(id)\n out.push(id)\n }\n\n const walk = (v: unknown): void => {\n if (v === undefined || v === null) return\n if (typeof v === \"number\") {\n push(String(v))\n return\n }\n if (typeof v === \"string\") {\n const trimmed = v.trim()\n if (!trimmed) return\n if (/^\\d+$/.test(trimmed)) {\n push(trimmed)\n return\n }\n try {\n walk(JSON.parse(trimmed) as unknown)\n } catch {\n /* ignore */\n }\n return\n }\n if (Array.isArray(v)) {\n for (const item of v) walk(item)\n return\n }\n if (typeof v === \"object\") {\n const record = v as Record<string, unknown>\n const direct = attachmentIdFromObjectRecord(record)\n if (direct !== undefined) {\n push(direct)\n return\n }\n for (const nested of Object.values(record)) walk(nested)\n }\n }\n\n walk(value)\n return out\n}\n\n/** First attachment id in the cell, if any (see {@link extractGristAttachmentIdsFromCell}). */\nexport function extractGristAttachmentId(value: unknown): string | undefined {\n return extractGristAttachmentIdsFromCell(value)[0]\n}\n\n/**\n * Signed Grist download URL for a single attachment id (`getAccessToken` + query auth).\n */\nexport async function getAttachmentDownloadUrl(\n docApi: GristDocApi,\n attachmentId: string,\n options?: { readOnly?: boolean }\n): Promise<string> {\n const getAccessToken = docApi.getAccessToken\n if (!getAccessToken) {\n throw new Error(\"getAccessToken is not available on docApi\")\n }\n const { token, baseUrl } = await getAccessToken({ readOnly: options?.readOnly ?? false })\n return `${baseUrl}/attachments/${attachmentId}/download?auth=${token}`\n}\n\n/** URL for the `index`’th attachment in a cell value (0-based). */\nexport async function getAttachmentDownloadUrlForCell(\n docApi: GristDocApi,\n cellValue: unknown,\n index: number,\n options?: { readOnly?: boolean }\n): Promise<string | null> {\n const ids = extractGristAttachmentIdsFromCell(cellValue)\n const id = ids[index]\n if (!id) return null\n return getAttachmentDownloadUrl(docApi, id, options)\n}\n\nasync function fetchBytesFromSignedAttachmentUrl(url: string): Promise<{\n buffer: ArrayBuffer\n contentType: string\n}> {\n const response = await fetch(url)\n const contentType = response.headers.get(\"content-type\")?.trim() || \"application/octet-stream\"\n if (!response.ok) {\n throw new Error(`Attachment download failed (${response.status})`)\n }\n const buffer = await response.arrayBuffer()\n return { buffer, contentType }\n}\n\nfunction bufferToBase64(buffer: ArrayBuffer): string {\n const bytes = new Uint8Array(buffer)\n let binary = \"\"\n for (let i = 0; i < bytes.length; i++) binary += String.fromCharCode(bytes[i])\n return btoa(binary)\n}\n\n/** Token + URL + fetch for one attachment id. */\nexport async function fetchAttachmentBase64(\n docApi: GristDocApi,\n attachmentId: string,\n options?: { readOnly?: boolean }\n): Promise<GristFetchedAttachment> {\n const url = await getAttachmentDownloadUrl(docApi, attachmentId, options)\n const { buffer, contentType } = await fetchBytesFromSignedAttachmentUrl(url)\n return { base64: bufferToBase64(buffer), contentType }\n}\n\n/** Download attachment bytes as a `Blob` (preferred for large files). */\nexport async function fetchAttachmentBlob(\n docApi: GristDocApi,\n attachmentId: string,\n options?: { readOnly?: boolean }\n): Promise<GristFetchedAttachmentBlob> {\n const url = await getAttachmentDownloadUrl(docApi, attachmentId, options)\n const { buffer, contentType } = await fetchBytesFromSignedAttachmentUrl(url)\n return { blob: new Blob([buffer], { type: contentType }), contentType }\n}\n\n/** Download the `index`’th attachment in a cell (0-based). */\nexport async function fetchAttachmentBase64ForCell(\n docApi: GristDocApi,\n cellValue: unknown,\n index: number,\n options?: { readOnly?: boolean }\n): Promise<GristFetchedAttachment | null> {\n const url = await getAttachmentDownloadUrlForCell(docApi, cellValue, index, options)\n if (!url) return null\n const { buffer, contentType } = await fetchBytesFromSignedAttachmentUrl(url)\n return { base64: bufferToBase64(buffer), contentType }\n}\n","import type { GristDocApi } from \"../types\"\n\nexport type GristAccessToken = {\n token: string\n baseUrl: string\n}\n\ntype TokenCacheEntry = {\n token: GristAccessToken\n fetchedAt: number\n}\n\nconst TOKEN_TTL_MS = 45_000\nconst cache = new Map<string, TokenCacheEntry>()\nconst inFlight = new Map<string, Promise<GristAccessToken>>()\n\nfunction cacheKey(readOnly: boolean): string {\n return readOnly ? \"ro\" : \"rw\"\n}\n\n/**\n * Returns an access token suitable for calling Grist's REST API directly.\n * Tokens are short-lived; results are cached briefly and coalesced per readOnly flag.\n */\nexport async function getGristAccessToken(\n docApi: GristDocApi,\n options?: { readOnly?: boolean }\n): Promise<GristAccessToken> {\n if (!docApi.getAccessToken) {\n throw new Error(\"getAccessToken is not available on docApi (need higher access level)\")\n }\n\n const readOnly = options?.readOnly ?? false\n const key = cacheKey(readOnly)\n const now = Date.now()\n const hit = cache.get(key)\n if (hit && now - hit.fetchedAt < TOKEN_TTL_MS) {\n return hit.token\n }\n\n const pending = inFlight.get(key)\n if (pending) return pending\n\n const next = docApi.getAccessToken({ readOnly }).then((token) => {\n cache.set(key, { token, fetchedAt: Date.now() })\n inFlight.delete(key)\n return token\n })\n\n inFlight.set(key, next)\n return next\n}\n\n/** Clear cached tokens (tests or after auth errors). */\nexport function clearGristAccessTokenCache(): void {\n cache.clear()\n inFlight.clear()\n}\n\n/**\n * `fetch()` against Grist's REST API with the doc access token attached.\n */\nexport async function fetchWithGristAuth(\n docApi: GristDocApi,\n path: string,\n init?: RequestInit & { readOnly?: boolean }\n): Promise<Response> {\n const readOnly = init?.readOnly ?? false\n let token: GristAccessToken\n try {\n token = await getGristAccessToken(docApi, { readOnly })\n } catch (err) {\n clearGristAccessTokenCache()\n throw err\n }\n\n const isAbsolute = /^https?:\\/\\//i.test(path)\n const cleanPath = isAbsolute ? path : path.startsWith(\"/\") ? path : `/${path}`\n\n const url = isAbsolute\n ? new URL(path)\n : new URL(`${token.baseUrl.replace(/\\/$/, \"\")}${cleanPath}`)\n\n // The token goes into the URL, so it may only go to the Grist instance that\n // issued it. An absolute URL to any other origin (one read from a cell, say)\n // would hand the document's access token to that host.\n const gristOrigin = new URL(token.baseUrl).origin\n if (url.origin !== gristOrigin) {\n throw new Error(\n `fetchWithGristAuth: refusing to send the Grist access token to ${url.origin}; ` +\n `absolute URLs must point at this document's Grist instance (${gristOrigin}). ` +\n `Use plain fetch() for other hosts.`\n )\n }\n\n // Grist signs widget REST calls with a short-lived `auth` query parameter.\n // Do not send `Authorization: Bearer` from the browser: many Grist deployments\n // omit it from Access-Control-Allow-Headers, which breaks POST (e.g. attachment upload).\n if (!url.searchParams.has(\"auth\")) url.searchParams.set(\"auth\", token.token)\n\n const headers = new Headers(init?.headers ?? {})\n headers.delete(\"Authorization\")\n\n const response = await fetch(url.toString(), { ...init, headers })\n if (response.status === 401) {\n clearGristAccessTokenCache()\n const retryToken = await getGristAccessToken(docApi, { readOnly })\n url.searchParams.set(\"auth\", retryToken.token)\n return fetch(url.toString(), { ...init, headers })\n }\n return response\n}\n","import type { GristDocApi } from \"../types\"\nimport { extractGristAttachmentIdsFromCell } from \"./grist-attachment-download\"\nimport { fetchWithGristAuth } from \"./grist-fetch-with-auth\"\nimport { encodeGristValue } from \"./grist-value-codec\"\n\nconst ATTACHMENTS_COLUMN = { type: \"Attachments\" as const }\n\nexport type GristEncodedAttachmentList = [\"L\", ...(number | string)[]]\n\nexport type GristAttachmentUploadResult = {\n /** All attachment ids returned by `POST /attachments`. */\n ids: string[]\n /** First id in `ids` (convenience for single-file uploads). */\n firstId: string\n}\n\n/**\n * Parse the body of `POST /attachments` (widget or REST).\n * Grist returns a JSON array of attachment ids, e.g. `[42]` or `[101, 102]`.\n */\nexport function parseGristAttachmentUploadResponseIds(\n raw: string,\n options?: { strict?: boolean }\n): string[] {\n const trimmed = raw.trim()\n if (!trimmed) {\n throw new Error(\"Attachment upload returned an empty response.\")\n }\n\n let parsed: unknown\n try {\n parsed = JSON.parse(trimmed) as unknown\n } catch {\n if (options?.strict) {\n throw new Error(\"Attachment upload returned non-JSON response.\")\n }\n parsed = trimmed\n }\n\n return extractAttachmentIdsFromUploadPayload(parsed, options)\n}\n\n/**\n * First attachment id from an upload response (see {@link parseGristAttachmentUploadResponseIds}).\n */\nexport function parseGristAttachmentUploadResponse(\n raw: string,\n options?: { strict?: boolean }\n): string {\n const ids = parseGristAttachmentUploadResponseIds(raw, options)\n return ids[0]!\n}\n\nexport function extractAttachmentIdsFromUploadPayload(\n parsed: unknown,\n options?: { strict?: boolean }\n): string[] {\n if (options?.strict) {\n return extractAttachmentIdsFromUploadPayloadStrict(parsed)\n }\n\n const first = extractFirstAttachmentIdFromUploadPayload(parsed)\n if (first !== undefined) {\n if (Array.isArray(parsed)) {\n const ids: string[] = []\n const seen = new Set<string>()\n for (const item of parsed) {\n const id = coerceAttachmentId(item)\n if (id && !seen.has(id)) {\n seen.add(id)\n ids.push(id)\n }\n }\n return ids.length > 0 ? ids : [first]\n }\n return [first]\n }\n\n throw new Error(\"Attachment upload returned an unexpected response shape.\")\n}\n\nfunction extractAttachmentIdsFromUploadPayloadStrict(parsed: unknown): string[] {\n if (typeof parsed === \"number\" && Number.isFinite(parsed)) {\n return [String(parsed)]\n }\n\n if (Array.isArray(parsed)) {\n const ids: string[] = []\n const seen = new Set<string>()\n for (const item of parsed) {\n if (typeof item !== \"number\" || !Number.isFinite(item)) {\n throw new Error(\"Attachment upload returned an unexpected response shape.\")\n }\n const id = String(item)\n if (!seen.has(id)) {\n seen.add(id)\n ids.push(id)\n }\n }\n if (ids.length === 0) {\n throw new Error(\"Attachment upload returned an empty id list.\")\n }\n return ids\n }\n\n throw new Error(\"Attachment upload returned an unexpected response shape.\")\n}\n\n/** @deprecated Prefer {@link extractAttachmentIdsFromUploadPayload}. */\nexport function extractFirstAttachmentIdFromUploadPayload(parsed: unknown): string | undefined {\n if (typeof parsed === \"number\" && Number.isFinite(parsed)) {\n return String(parsed)\n }\n\n if (typeof parsed === \"string\" && parsed.trim()) {\n return parsed.trim()\n }\n\n if (Array.isArray(parsed)) {\n for (const item of parsed) {\n const id = coerceAttachmentId(item)\n if (id) return id\n }\n return undefined\n }\n\n if (parsed && typeof parsed === \"object\") {\n const record = parsed as Record<string, unknown>\n for (const key of [\"id\", \"attachmentId\", \"fileId\"]) {\n const id = coerceAttachmentId(record[key])\n if (id) return id\n }\n }\n\n return undefined\n}\n\nfunction coerceAttachmentId(value: unknown): string | undefined {\n if (typeof value === \"number\" && Number.isFinite(value)) {\n return String(value)\n }\n if (typeof value === \"string\" && value.trim()) {\n return value.trim()\n }\n return undefined\n}\n\nfunction normalizeAttachmentIdForWire(id: string | number): number | string {\n const numeric = typeof id === \"number\" ? id : Number(id)\n if (Number.isFinite(numeric) && String(numeric) === String(id).trim()) {\n return numeric\n }\n return typeof id === \"number\" ? String(id) : id.trim()\n}\n\n/** Wire value for an Attachments cell (Grist list encoding). */\nexport function gristAttachmentCellValues(\n attachmentIds: (string | number)[]\n): GristEncodedAttachmentList {\n const items = attachmentIds.map(normalizeAttachmentIdForWire)\n const encoded = encodeGristValue(items, ATTACHMENTS_COLUMN)\n if (!Array.isArray(encoded) || encoded[0] !== \"L\") {\n return [\"L\", ...items]\n }\n return encoded as GristEncodedAttachmentList\n}\n\n/** Wire value for a single-file Attachments cell. */\nexport function gristAttachmentCellValue(attachmentId: string | number): GristEncodedAttachmentList {\n return gristAttachmentCellValues([attachmentId])\n}\n\n/**\n * Merge new attachment ids into an existing Attachments cell value (deduped, order preserved).\n */\nexport function mergeGristAttachmentCellValue(\n existingCell: unknown,\n newIds: (string | number)[]\n): GristEncodedAttachmentList {\n const existing = extractGristAttachmentIdsFromCell(existingCell)\n const merged: string[] = []\n const seen = new Set<string>()\n const push = (raw: string | number) => {\n const id = String(raw).trim()\n if (!id || seen.has(id)) return\n seen.add(id)\n merged.push(id)\n }\n for (const id of existing) push(id)\n for (const id of newIds) push(id)\n return gristAttachmentCellValues(merged)\n}\n\nconst UPLOAD_HEADERS = {\n \"X-Requested-With\": \"XMLHttpRequest\",\n Accept: \"application/json\",\n} as const\n\n/**\n * Upload a file to the current document via `POST /attachments`.\n *\n * Uses `getAccessToken({ readOnly: false })` and `?auth=` (see Grist widget docs).\n * Requires document **full** access in the widget.\n */\nexport async function uploadGristAttachment(\n docApi: GristDocApi,\n file: Blob | File,\n options?: { fileName?: string }\n): Promise<GristAttachmentUploadResult> {\n const form = new FormData()\n const fileName =\n options?.fileName ?? (file instanceof File && file.name ? file.name : \"upload\")\n form.append(\"upload\", file, fileName)\n\n let response: Response\n try {\n response = await fetchWithGristAuth(docApi, \"/attachments\", {\n method: \"POST\",\n body: form,\n readOnly: false,\n headers: UPLOAD_HEADERS,\n })\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err)\n if (/failed to fetch/i.test(msg)) {\n const widgetOrigin =\n typeof globalThis.location !== \"undefined\"\n ? globalThis.location.origin\n : \"this widget origin\"\n throw new Error(\n `Attachment upload was blocked by the Grist host (CORS). The browser could not POST from ${widgetOrigin} to the document API. If upload worked from a dev URL (e.g. ngrok) but fails after deploy, add the new widget URL to your Grist server CORS allowlist (see grist-core#2040).`,\n { cause: err }\n )\n }\n throw err\n }\n\n const raw = await response.text()\n if (!response.ok) {\n throw new Error(\n raw.trim()\n ? `Attachment upload failed (${response.status}): ${raw.slice(0, 200)}`\n : `Attachment upload failed (${response.status})`\n )\n }\n\n const ids = parseGristAttachmentUploadResponseIds(raw)\n return { ids, firstId: ids[0]! }\n}\n","/**\n * `useGrist()`'s methods, created once per runtime: every one is\n * referentially stable for the widget's lifetime, and reads `grist` when\n * called (the emulator installs and removes it in tests).\n */\n\nimport { loadColumnMetadataByTable } from \"../helpers/build-replica-document\"\nimport { isGristNoiseColumn, type GristNoiseColumnsOptions } from \"../helpers/grist-columns-filters\"\nimport { fetchAttachmentBlob, getAttachmentDownloadUrl, type GristFetchedAttachmentBlob } from \"../helpers/grist-attachment-download\"\nimport { uploadGristAttachment, type GristAttachmentUploadResult } from \"../helpers/grist-attachment-upload\"\nimport { fetchWithGristAuth } from \"../helpers/grist-fetch-with-auth\"\nimport { fetchGristTableRows, type FetchGristTableRowsOptions, type GristColumnarTable } from \"../helpers/grist-table-data\"\nimport type { GristUserActionTuple } from \"../helpers/grist-user-actions\"\nimport type {\n GristApplyUserActionsOptions,\n GristCursorPos,\n GristDocApi,\n GristFetchSelectedOptions,\n GristRowRecord,\n GristTableOperations,\n} from \"../types\"\nimport type { GristRuntime } from \"./runtime\"\n\nexport type ListTablesOptions = {\n /** Include Grist's own tables (`_grist_*`, `GristHidden_*`). */\n includeSystem?: boolean\n}\n\nexport type ListColumnsOptions = GristNoiseColumnsOptions & {\n /** Include every column, Grist's helper and bookkeeping ones too. */\n includeSystem?: boolean\n}\n\nexport type GristColumnInfo = {\n colId: string\n type?: string\n label?: string\n isFormula?: boolean\n formula?: string\n description?: string\n}\n\nexport type GristApi = {\n reload: () => Promise<void>\n fetchSelectedTable: (options?: GristFetchSelectedOptions) => Promise<GristColumnarTable>\n fetchTable: (tableId: string) => Promise<GristColumnarTable>\n fetchTableRows: <T extends Record<string, unknown> = Record<string, unknown>>(\n tableId: string,\n options?: FetchGristTableRowsOptions\n ) => Promise<GristRowRecord<T>[]>\n listTables: (options?: ListTablesOptions) => Promise<string[]>\n listColumns: (tableId: string, options?: ListColumnsOptions) => Promise<GristColumnInfo[]>\n table: GristTableOperations\n getTable: (tableId: string) => GristTableOperations\n applyActions: (actions: GristUserActionTuple[], options?: GristApplyUserActionsOptions) => Promise<unknown>\n setWidgetOptions: (options: Record<string, unknown>) => Promise<void>\n patchWidgetOptions: (patch: Record<string, unknown>) => Promise<void>\n setCursorPosition: (pos: GristCursorPos) => Promise<void>\n setLinkedRowSelection: (rowIds: number[] | null) => Promise<void>\n getAttachmentUrl: (attachmentId: string, options?: { readOnly?: boolean }) => Promise<string>\n fetchAttachmentBlob: (attachmentId: string, options?: { readOnly?: boolean }) => Promise<GristFetchedAttachmentBlob>\n uploadAttachment: (file: Blob | File, options?: { fileName?: string }) => Promise<GristAttachmentUploadResult>\n fetchWithAuth: (path: string, init?: RequestInit & { readOnly?: boolean }) => Promise<Response>\n}\n\nconst ACCESS_ERROR = [/access not granted/i, /need higher access level/i, /requires.*full.*access/i, /RPC_ONCALL_ERROR Access/i]\n\nexport function isAccessInsufficientError(message: string): boolean {\n return ACCESS_ERROR.some((re) => re.test(message))\n}\n\nconst message = (err: unknown) => (err instanceof Error ? err.message : String(err))\n\nexport function createGristApi(runtime: GristRuntime): GristApi {\n const docApi = (): GristDocApi => {\n if (runtime.getState().connection !== \"ready\" || typeof grist === \"undefined\" || !grist.docApi) {\n throw new Error(\"Grist is not ready: wait for useGrist().status === \\\"ready\\\".\")\n }\n return grist.docApi\n }\n\n /** A read: an access refusal is kept for the alerts, cleared by the next read that succeeds. */\n const read = async <T>(fn: () => Promise<T>): Promise<T> => {\n try {\n const out = await fn()\n if (runtime.getState().readError) runtime.update({ readError: null })\n return out\n } catch (err) {\n if (isAccessInsufficientError(message(err))) runtime.update({ readError: message(err) })\n throw err\n }\n }\n\n /** A write: tracked in `actionStatus` / `actionError`. */\n const write = async <T>(fn: () => Promise<T>): Promise<T> => {\n runtime.update({ actionStatus: \"running\", actionError: null })\n try {\n const out = await fn()\n runtime.update({ actionStatus: \"idle\" })\n return out\n } catch (err) {\n runtime.update({ actionStatus: \"error\", actionError: message(err) })\n throw err\n }\n }\n\n const tableOps = (resolve: () => GristTableOperations): GristTableOperations => ({\n getTableId: () => resolve().getTableId(),\n create: ((records: never, opts?: never) => write(() => resolve().create(records, opts))) as GristTableOperations[\"create\"],\n update: (records, opts) => write(() => resolve().update(records, opts)),\n upsert: (records, opts) => write(() => resolve().upsert(records, opts)),\n destroy: (ids) => write(() => resolve().destroy(ids)),\n })\n const tables = new Map<string, GristTableOperations>()\n\n return {\n reload: () => runtime.reload(),\n\n fetchSelectedTable: (options) =>\n read(async () => {\n const impl = docApi().fetchSelectedTable ?? grist.fetchSelectedTable\n if (!impl) throw new Error(\"fetchSelectedTable is not available in this Grist version\")\n return (await impl({ keepEncoded: false, ...options })) as GristColumnarTable\n }),\n fetchTable: (tableId) => read(async () => (await docApi().fetchTable(tableId)) as GristColumnarTable),\n fetchTableRows: (tableId, options) => read(() => fetchGristTableRows(docApi(), tableId, options ?? {})) as never,\n listTables: (options) =>\n read(async () => {\n const all = [...(await docApi().listTables())]\n return options?.includeSystem ? all : all.filter((t) => !t.startsWith(\"_grist\") && !t.startsWith(\"GristHidden_\"))\n }),\n listColumns: (tableId, options) =>\n read(async () => {\n const meta = (await loadColumnMetadataByTable(docApi())).get(tableId)\n if (!meta) return []\n const noise: GristNoiseColumnsOptions = {\n excludeId: options?.excludeId ?? true,\n excludeGristHelpers: options?.excludeGristHelpers ?? true,\n excludeLoggingColumns: options?.excludeLoggingColumns ?? true,\n excludeManualSort: options?.excludeManualSort ?? true,\n }\n return [...meta]\n .filter(([colId, m]) => options?.includeSystem || !isGristNoiseColumn(colId, m, noise))\n .map(([colId, m]) => ({ colId, type: m.type, label: m.label, isFormula: m.isFormula, formula: m.formula, description: m.description }))\n }),\n\n table: tableOps(() => {\n if (!grist.selectedTable) throw new Error(\"grist.selectedTable is not available in this Grist version\")\n return grist.selectedTable\n }),\n getTable: (tableId) => {\n let ops = tables.get(tableId)\n if (!ops) {\n tables.set(\n tableId,\n (ops = tableOps(() => {\n if (typeof grist.getTable !== \"function\") throw new Error(\"grist.getTable is not available in this Grist version\")\n return grist.getTable(tableId)\n }))\n )\n }\n return ops\n },\n applyActions: (actions, options) => write(() => docApi().applyUserActions(actions, options)),\n\n setWidgetOptions: async (options) => {\n await grist.setOptions(options)\n },\n patchWidgetOptions: async (patch) => {\n const current = ((await grist.getOptions()) as Record<string, unknown> | null) ?? {}\n await grist.setOptions({ ...current, ...patch })\n },\n\n setCursorPosition: async (pos) => {\n if (!grist.setCursorPos) throw new Error(\"setCursorPos is not available in this Grist version\")\n await grist.setCursorPos(pos)\n },\n setLinkedRowSelection: async (rowIds) => {\n if (!grist.setSelectedRows) throw new Error(\"setSelectedRows is not available in this Grist version\")\n await grist.setSelectedRows(rowIds)\n },\n\n getAttachmentUrl: (id, options) => read(() => getAttachmentDownloadUrl(docApi(), id, options)),\n fetchAttachmentBlob: (id, options) => read(() => fetchAttachmentBlob(docApi(), id, options)),\n uploadAttachment: (file, options) => write(() => uploadGristAttachment(docApi(), file, options)),\n fetchWithAuth: (path, init) => read(() => fetchWithGristAuth(docApi(), path, init)),\n }\n}\n","import type { GristColumnsToMap, GristColumnToMap, GristWidgetColumnMap } from \"../types\"\n\nexport type ValidateColumnMappingsResult = {\n ok: boolean\n /**\n * `true` while the host has not yet reported column mappings (e.g. between\n * `grist.ready()` resolving and the first `onRecord` / `onRecords` callback,\n * or before `sectionApi.mappings()` returns). Callers should not gate UI or\n * emit mapping alerts while pending.\n */\n pending?: boolean\n /** Logical names of required columns the user has not yet mapped. */\n missing: string[]\n /** Logical names of `allowMultiple` columns mapped to an empty list. */\n emptyMultiples: string[]\n}\n\n/**\n * Merges mapping payloads from `onRecord`, `onRecords`, and `sectionApi.mappings()`.\n * Later sources win; `undefined` sources are skipped; `null` means \"host reported\n * no mappings\" but still counts as a known (empty) payload.\n */\nexport function mergeWidgetColumnMaps(\n ...sources: (GristWidgetColumnMap | null | undefined)[]\n): GristWidgetColumnMap | null | undefined {\n let merged: GristWidgetColumnMap = {}\n let sawDefined = false\n for (const src of sources) {\n if (src === undefined) continue\n sawDefined = true\n if (src === null) continue\n merged = { ...merged, ...src }\n }\n if (!sawDefined) return undefined\n return merged\n}\n\nfunction asColumnSpec(entry: string | GristColumnToMap): GristColumnToMap {\n return typeof entry === \"string\" ? { name: entry } : entry\n}\n\n/**\n * Verifies that the current Grist mappings cover every required column declared\n * in `grist.ready({ columns })`.\n *\n * Use this before reading `mappedRecord` so you can render a \"please configure\n * the widget\" prompt instead of a confusing `null`.\n */\nexport function validateColumnMappings(\n spec: GristColumnsToMap | undefined | null,\n mappings: GristWidgetColumnMap | null | undefined\n): ValidateColumnMappingsResult {\n const missing: string[] = []\n const emptyMultiples: string[] = []\n if (!spec) return { ok: true, pending: false, missing, emptyMultiples }\n\n const m = mappings ?? {}\n for (const raw of spec) {\n const col = asColumnSpec(raw)\n if (col.optional) continue\n const value = m[col.name]\n if (col.allowMultiple) {\n if (value === undefined) {\n missing.push(col.name)\n } else if (!Array.isArray(value) || value.length === 0) {\n emptyMultiples.push(col.name)\n }\n } else {\n if (value === undefined || value === null || value === \"\") missing.push(col.name)\n }\n }\n return {\n ok: missing.length === 0 && emptyMultiples.length === 0,\n pending: false,\n missing,\n emptyMultiples,\n }\n}\n\n/** Status while waiting for the host to report mappings (see `pending`). */\nexport const pendingColumnMappingStatus: ValidateColumnMappingsResult = {\n ok: true,\n pending: true,\n missing: [],\n emptyMultiples: [],\n}\n","/**\n * What `useGrist()` shows, derived from the runtime state: status, error,\n * column-mapping status, the mapped record, and the access check. Pure\n * functions, so they are tested without React or Grist.\n */\n\nimport { validateColumnMappings, type ValidateColumnMappingsResult } from \"../helpers/grist-mappings\"\nimport type { GristColumnsToMap, GristRequiredAccess, GristWidgetColumnMap } from \"../types\"\nimport type { GristRuntimeState } from \"./runtime\"\n\n/** The widget's connection to Grist, as `useGrist().status` reports it. */\nexport type GristWidgetStatus = \"booting\" | \"ready\" | \"unavailable\" | \"error\"\n\nexport const ACCESS_RANK: Record<GristRequiredAccess, number> = { none: 0, \"read table\": 1, full: 2 }\n\nexport function parseAccess(raw: unknown): GristRequiredAccess | null {\n return raw === \"none\" || raw === \"read table\" || raw === \"full\" ? raw : null\n}\n\nexport function accessLabel(level: GristRequiredAccess): string {\n return level === \"full\" ? \"Full document access\" : level === \"read table\" ? \"Read selected table\" : \"No document access\"\n}\n\n/** Grist granted less than the widget declared (Grist reports it with the widget options). */\nexport function accessDenied(state: GristRuntimeState): boolean {\n return state.grantedAccess !== null && ACCESS_RANK[state.grantedAccess] < ACCESS_RANK[state.declaredAccess]\n}\n\nexport function deriveStatus(state: GristRuntimeState): GristWidgetStatus {\n switch (state.connection) {\n case \"connecting\":\n return \"booting\"\n case \"not-embedded\":\n case \"unavailable\":\n return \"unavailable\"\n case \"error\":\n return \"error\"\n case \"ready\":\n return accessDenied(state) ? \"error\" : \"ready\"\n }\n}\n\nexport function deriveError(state: GristRuntimeState): string | null {\n if (state.connection === \"not-embedded\") return \"This page is not embedded in a Grist document.\"\n if (state.connection === \"unavailable\") return \"The Grist plugin API (grist-plugin-api.js) did not load.\"\n if (state.connection === \"error\") return state.connectionError\n if (state.connection === \"ready\" && accessDenied(state)) {\n return `Grist granted \"${accessLabel(state.grantedAccess!)}\"; this widget needs \"${accessLabel(state.declaredAccess)}\". Set the access level in the Custom widget settings.`\n }\n return null\n}\n\nconst MAPPINGS_OK: ValidateColumnMappingsResult = Object.freeze({ ok: true, pending: false, missing: [], emptyMultiples: [] }) as ValidateColumnMappingsResult\nconst MAPPINGS_PENDING: ValidateColumnMappingsResult = Object.freeze({ ok: true, pending: true, missing: [], emptyMultiples: [] }) as ValidateColumnMappingsResult\n\n/** Whether the declared columns are mapped: pending until Grist reports mappings. */\nexport function deriveColumnMappingStatus(\n columns: GristColumnsToMap | undefined,\n mappings: GristWidgetColumnMap | null\n): ValidateColumnMappingsResult {\n if (!columns?.length) return MAPPINGS_OK\n if (mappings === null) return MAPPINGS_PENDING\n return validateColumnMappings(columns, mappings)\n}\n\n/**\n * A logical-name patch as real column ids, for a write. A column mapped to\n * several Grist columns (`allowMultiple`) can't be written back and is\n * reported in `skipped`; a name with no mapping passes through unchanged.\n */\nexport function mapBackPatch(\n patch: Record<string, unknown>,\n mappings: GristWidgetColumnMap\n): { fields: Record<string, unknown>; skipped: string[] } {\n const fields: Record<string, unknown> = {}\n const skipped: string[] = []\n for (const [name, value] of Object.entries(patch)) {\n if (value === undefined) continue\n const real = mappings[name]\n if (Array.isArray(real)) skipped.push(name)\n else fields[typeof real === \"string\" && real ? real : name] = value\n }\n return { fields, skipped }\n}\n","/**\n * Typed reads, with read-only access: each mapped cell checked against the\n * type its column declares in `GRIST_OPTIONS.columns`.\n *\n * Grist's mapping panel only offers the columns of the declared type, so for\n * a mapped column the declaration is the contract; and the plugin API's\n * decoded values already say what they are (a `Date`, a `Reference` with a\n * `rowId`, a list of ids, a `RaisedException` for a formula error, the raw\n * text of an invalid cell). Checked in Grist 1.7.22, every type, both\n * `cellFormat`s. So a cell is turned into the JS value its type promises, or\n * into `null` with an issue: no schema to fetch, no full access, no\n * dependency.\n */\n\nimport type { GristColumnsToMap, GristWidgetColumnMap } from \"../types\"\n\n/** A mapped cell that didn't match its declared type, or a rule of the widget's schema. */\nexport type GristCellIssue = {\n rowId: number\n /** The declared column name, or \"\" for a schema rule on the whole record. */\n column: string\n message: string\n /** The value Grist sent. */\n value: unknown\n}\n\ntype Check = { ok: true; value: unknown } | { ok: false; message: string }\n\nconst ok = (value: unknown): Check => ({ ok: true, value })\nconst bad = (message: string): Check => ({ ok: false, message })\n\n/** A formula error, as the plugin API decodes it (`RaisedException`) or encodes it (`[\"E\", name, …]`). */\nfunction formulaError(value: unknown): string | null {\n if (Array.isArray(value) && value[0] === \"E\") return String(value[1] ?? \"error\")\n if (value && typeof value === \"object\" && (value as { constructor?: { name?: string } }).constructor?.name === \"RaisedException\") {\n return String((value as { name?: unknown }).name ?? \"error\")\n }\n return null\n}\n\nfunction rowIdOf(value: unknown): number | null | undefined {\n if (typeof value === \"number\" && Number.isInteger(value)) return value === 0 ? null : value\n if (value && typeof value === \"object\" && typeof (value as { rowId?: unknown }).rowId === \"number\") {\n const id = (value as { rowId: number }).rowId\n return id === 0 ? null : id\n }\n if (Array.isArray(value) && value[0] === \"R\" && typeof value[2] === \"number\") return value[2] === 0 ? null : value[2]\n return undefined\n}\n\nfunction idsOf(value: unknown): number[] | undefined {\n if (value === null || value === undefined) return []\n const list = Array.isArray(value)\n ? value[0] === \"L\"\n ? value.slice(1)\n : value\n : value && typeof value === \"object\" && Array.isArray((value as { rowIds?: unknown }).rowIds)\n ? (value as { rowIds: unknown[] }).rowIds\n : undefined\n return list?.every((v) => typeof v === \"number\") ? (list as number[]) : undefined\n}\n\nfunction checkOne(base: string, value: unknown): Check {\n switch (base) {\n case \"Any\":\n return ok(value)\n case \"Text\":\n return value === null || typeof value === \"string\" ? ok(value ?? \"\") : bad(\"not text\")\n case \"Numeric\":\n return value === null || (typeof value === \"number\" && Number.isFinite(value)) ? ok(value) : bad(\"not a number\")\n case \"Int\":\n return value === null || (typeof value === \"number\" && Number.isInteger(value)) ? ok(value) : bad(\"not an integer\")\n case \"Bool\":\n return value === null || typeof value === \"boolean\" ? ok(value ?? false) : bad(\"not true or false\")\n case \"Date\":\n case \"DateTime\":\n if (value === null) return ok(null)\n if (value instanceof Date && !Number.isNaN(value.getTime())) return ok(value)\n // Seconds since the epoch: Grist's \"normal\" format, and the emulator's raw rows.\n if (typeof value === \"number\" && Number.isFinite(value)) return ok(new Date(value * 1000))\n return bad(\"not a date\")\n case \"Choice\":\n return value === null || typeof value === \"string\" ? ok(value) : bad(\"not a choice\")\n case \"ChoiceList\": {\n if (value === null || value === undefined) return ok([])\n const list = Array.isArray(value) ? (value[0] === \"L\" ? value.slice(1) : value) : undefined\n return list?.every((v) => typeof v === \"string\") ? ok(list) : bad(\"not a list of choices\")\n }\n case \"Ref\": {\n if (value === null) return ok(null)\n const id = rowIdOf(value)\n return id === undefined ? bad(\"not a reference\") : ok(id)\n }\n case \"RefList\":\n case \"Attachments\": {\n const ids = idsOf(value)\n return ids === undefined ? bad(base === \"RefList\" ? \"not a list of references\" : \"not a list of attachments\") : ok(ids)\n }\n default:\n return ok(value)\n }\n}\n\n/**\n * `value` as its declared `type` promises (\"Numeric\", \"Ref:Tasks\",\n * \"Text,Ref\"…): a match of any listed type, or a failure that says why.\n * Without a type (or \"Any\"), the value as it is.\n */\nexport function checkGristCell(type: string | undefined, value: unknown): Check {\n const error = formulaError(value)\n if (error) return bad(`formula error (${error})`)\n const bases = (type ?? \"Any\")\n .split(\",\")\n .map((t) => t.trim().split(\":\")[0]!)\n .filter(Boolean)\n if (bases.length === 0 || bases.includes(\"Any\")) return ok(value === undefined ? null : value)\n let first: Check | null = null\n for (const base of bases) {\n const check = checkOne(base, value)\n if (check.ok) return check\n first ??= check\n }\n return first!\n}\n\nconst nameOf = (c: GristColumnsToMap[number]) => (typeof c === \"string\" ? c : c.name)\nconst typeOf = (c: GristColumnsToMap[number]) => (typeof c === \"string\" ? undefined : c.type)\nconst isOptional = (c: GristColumnsToMap[number]) => typeof c === \"object\" && c.optional === true\n\n/** Minimal Standard Schema (https://standardschema.dev): zod 4, valibot, arktype implement it. */\nexport type StandardSchema<T = unknown> = {\n readonly \"~standard\": {\n readonly version: 1\n readonly vendor: string\n readonly validate: (\n value: unknown\n ) =>\n | { readonly value: T; readonly issues?: undefined }\n | { readonly issues: ReadonlyArray<{ readonly message: string; readonly path?: ReadonlyArray<PropertyKey | { key: PropertyKey }> }> }\n | Promise<unknown>\n }\n}\n\n/**\n * A record under the widget's declared names, each cell checked against its\n * column's declared type, then the record against `schema` if given. Returns\n * null (no issues) while a required column isn't mapped, like Grist's\n * `mapColumnNames`; the record itself without declared columns.\n */\nexport function mapAndCheck<T>(\n record: Record<string, unknown> | null,\n columns: GristColumnsToMap | undefined,\n mappings: GristWidgetColumnMap | null,\n schema?: StandardSchema\n): { value: T | null; issues: GristCellIssue[] } {\n if (!record) return { value: null, issues: [] }\n if (!columns?.length) return { value: record as T, issues: [] }\n if (mappings === null) return { value: null, issues: [] }\n const rowId = typeof record.id === \"number\" ? record.id : 0\n const out: Record<string, unknown> = { id: record.id }\n const issues: GristCellIssue[] = []\n for (const col of columns) {\n const name = nameOf(col)\n const real = mappings[name]\n const take = (raw: unknown) => {\n const check = checkGristCell(typeOf(col), raw)\n if (check.ok) return check.value\n issues.push({ rowId, column: name, message: check.message, value: raw })\n return null\n }\n if (Array.isArray(real) && real.length > 0) out[name] = real.map((r) => take(record[r]))\n else if (typeof real === \"string\" && real) out[name] = take(record[real])\n else if (!isOptional(col)) return { value: null, issues: [] }\n }\n if (schema) {\n const result = schema[\"~standard\"].validate(out)\n if (result instanceof Promise) {\n issues.push({ rowId, column: \"\", message: \"the schema validates asynchronously; useGrist() needs a synchronous one\", value: out })\n } else if (\"issues\" in result && result.issues) {\n for (const issue of result.issues) {\n const key = issue.path?.[0]\n const column = key === undefined ? \"\" : String(typeof key === \"object\" ? key.key : key)\n issues.push({ rowId, column, message: issue.message, value: column ? out[column] : out })\n }\n } else if (\"value\" in result) {\n return { value: result.value as T, issues }\n }\n }\n return { value: out as T, issues }\n}\n\n// ---------------------------------------------------------------------------\n// Types from a declaration\n// ---------------------------------------------------------------------------\n\ntype BaseOf<T extends string> = T extends `${infer B}:${string}` ? B : T\n\ntype CellOf<T extends string> = T extends `${infer A},${infer Rest}`\n ? CellOf<A> | CellOf<Rest>\n : BaseOf<T> extends \"Text\"\n ? string\n : BaseOf<T> extends \"Numeric\" | \"Int\"\n ? number | null\n : BaseOf<T> extends \"Bool\"\n ? boolean\n : BaseOf<T> extends \"Date\" | \"DateTime\"\n ? Date | null\n : BaseOf<T> extends \"Choice\"\n ? string | null\n : BaseOf<T> extends \"ChoiceList\"\n ? string[]\n : BaseOf<T> extends \"Ref\"\n ? number | null\n : BaseOf<T> extends \"RefList\" | \"Attachments\"\n ? number[]\n : unknown\n\ntype ColumnValue<C> = C extends { type: infer T extends string; allowMultiple: true }\n ? CellOf<T>[]\n : C extends { type: infer T extends string }\n ? CellOf<T>\n : C extends { allowMultiple: true }\n ? unknown[]\n : unknown\n\ntype RequiredName<C> = C extends { optional: true } ? never : C extends string ? C : C extends { name: infer N extends string } ? N : never\ntype OptionalName<C> = C extends { optional: true; name: infer N extends string } ? N : never\ntype ByName<Cs, N> = Extract<Cs, N | { name: N }>\n\n/**\n * The mapped record a `GRIST_OPTIONS` declaration gives, for `useGrist`'s\n * second type argument. Declare the options with `as const satisfies\n * UseGristOptions` so the column names and types stay literal:\n *\n * ```ts\n * export const GRIST_OPTIONS = {\n * requiredAccess: \"read table\",\n * columns: [{ name: \"Title\", type: \"Text\" }, { name: \"Due\", type: \"Date\", optional: true }],\n * } as const satisfies UseGristOptions\n *\n * const w = useGrist<GristRowRecord, GristMappedRow<typeof GRIST_OPTIONS>>()\n * w.mappedRecord?.Due // Date | null | undefined\n * ```\n */\nexport type GristMappedRow<O extends { columns?: readonly unknown[] }> = O[\"columns\"] extends readonly (infer C)[]\n ? { id: number } & { [N in RequiredName<C>]: ColumnValue<ByName<C, N>> } & { [N in OptionalName<C>]?: ColumnValue<ByName<C, N>> }\n : Record<string, unknown>\n","import type { GristWidgetInteraction, GristWidgetLinkingInfo } from \"../types\"\n\n/**\n * Parse `InteractionOptions.linking` from a Grist `onOptions` settings payload.\n */\nexport function parseGristWidgetLinkingInfo(raw: unknown): GristWidgetLinkingInfo | undefined {\n if (!raw || typeof raw !== \"object\" || !(\"asTarget\" in raw)) return undefined\n const linking = raw as { asTarget: unknown; asSource?: unknown }\n return {\n asTarget: linking.asTarget == null ? null : String(linking.asTarget),\n asSource: Boolean(linking.asSource),\n }\n}\n\n/**\n * Normalize the second argument to `grist.onOptions` (Grist `InteractionOptions`).\n * Hosts use `accessLevel` (camelCase); the emulator uses `access_level`.\n */\nexport function normalizeWidgetInteraction(\n interaction: GristWidgetInteraction | null\n): GristWidgetInteraction | null {\n if (!interaction || typeof interaction !== \"object\") return interaction\n const raw = interaction as Record<string, unknown>\n const access_level =\n typeof raw.access_level === \"string\"\n ? raw.access_level\n : typeof raw.accessLevel === \"string\"\n ? raw.accessLevel\n : undefined\n const linking = parseGristWidgetLinkingInfo(raw.linking)\n return {\n ...interaction,\n ...(access_level ? { access_level } : {}),\n ...(linking ? { linking } : {}),\n }\n}\n","/**\n * Grist's event streams, bound once per page.\n *\n * `grist.onRecord`, `onRecords`, `onOptions`, `onNewRecord` and `on(\"message\")`\n * are add-only: there is no `off`. Binding them in every provider (React's\n * StrictMode mounts twice; a widget may remount) would stack handlers for the\n * page's lifetime. Each stream here binds at its first subscriber and fans out\n * to the current ones; a late subscriber gets the last value at once.\n *\n * Records are bound with the plugin API's decoded rows (`keepEncoded: false`,\n * rows for `onRecords`), the shape widget code reads.\n */\n\nimport { normalizeWidgetInteraction } from \"../helpers/grist-widget-interaction\"\nimport type { GristWidgetColumnMap, GristWidgetInteraction } from \"../types\"\n\ntype Listener<T> = (value: T) => void\n\nexport class HostStream<T> {\n private listeners = new Set<Listener<T>>()\n private bound = false\n private has = false\n private last: T | undefined\n\n constructor(private readonly bind: (emit: (value: T) => void) => void) {}\n\n subscribe(listener: Listener<T>): () => void {\n this.listeners.add(listener)\n if (!this.bound) {\n this.bound = true\n try {\n this.bind((value) => this.emit(value))\n } catch (err) {\n console.error(\"[grist-widget-sdk] could not subscribe to a Grist event:\", err)\n }\n }\n if (this.has) listener(this.last as T)\n return () => {\n this.listeners.delete(listener)\n }\n }\n\n peek(): T | undefined {\n return this.last\n }\n\n /** Tests: deliver a value as if Grist had sent it. */\n emit(value: T): void {\n this.has = true\n this.last = value\n for (const l of [...this.listeners]) l(value)\n }\n\n /** Tests: forget the binding, so a new `window.grist` binds afresh. */\n reset(): void {\n this.listeners.clear()\n this.bound = false\n this.has = false\n this.last = undefined\n }\n}\n\nexport type RecordPayload = { record: Record<string, unknown> | null; mappings: GristWidgetColumnMap | null }\nexport type RecordsPayload = { records: Record<string, unknown>[]; mappings: GristWidgetColumnMap | null }\nexport type OptionsPayload = { options: Record<string, unknown> | null; interaction: GristWidgetInteraction | null }\nexport type NewRecordPayload = { mappings: GristWidgetColumnMap | null }\n\nconst asMappings = (m: unknown) => (m && typeof m === \"object\" ? (m as GristWidgetColumnMap) : null)\n\nexport const recordStream = new HostStream<RecordPayload>((emit) => {\n grist.onRecord((record, mappings) => emit({ record, mappings: asMappings(mappings) }), { keepEncoded: false })\n\n // Grist's RecordNotifier posts `{ tableId, rowId }` on a cursor move. The\n // plugin API's onRecord handles it, but refetching here when the row\n // changes keeps a widget from sticking on its first row if that path is\n // skipped (seen in production iframes).\n const fetchSelectedRecord = grist.fetchSelectedRecord ?? grist.docApi?.fetchSelectedRecord\n if (typeof grist.on !== \"function\" || typeof fetchSelectedRecord !== \"function\") return\n let lastRowId: number | undefined\n grist.on(\"message\", async (msg: unknown) => {\n const host = msg as { tableId?: string; rowId?: unknown } | null\n if (!host?.tableId || typeof host.rowId !== \"number\" || host.rowId === lastRowId) return\n lastRowId = host.rowId\n try {\n const record = await fetchSelectedRecord(host.rowId, { keepEncoded: false })\n emit({ record, mappings: recordStream.peek()?.mappings ?? null })\n } catch (err) {\n console.error(\"[grist-widget-sdk] fetchSelectedRecord on a cursor move failed:\", err)\n }\n })\n})\n\nexport const recordsStream = new HostStream<RecordsPayload>((emit) => {\n grist.onRecords((records, mappings) => emit({ records, mappings: asMappings(mappings) }), {\n keepEncoded: false,\n format: \"rows\",\n })\n})\n\nexport const optionsStream = new HostStream<OptionsPayload>((emit) => {\n grist.onOptions((options, interaction) =>\n emit({\n options: options ? { ...options } : null,\n interaction: normalizeWidgetInteraction((interaction as GristWidgetInteraction | null) ?? null),\n })\n )\n})\n\nexport const newRecordStream = new HostStream<NewRecordPayload>((emit) => {\n if (typeof grist.onNewRecord !== \"function\") return\n grist.onNewRecord((mappings) => emit({ mappings: asMappings(mappings) }))\n})\n\n/** Grist's host messages (`grist.on(\"message\")`): the theme travels here. */\nexport const messageStream = new HostStream<unknown>((emit) => {\n if (typeof grist.on !== \"function\") return\n grist.on(\"message\", (msg: unknown) => emit(msg))\n})\n\nexport const ALL_STREAMS = [recordStream, recordsStream, optionsStream, newRecordStream, messageStream] as const\n","/**\n * Single-call wrapper around `grist.ready()`.\n *\n * Grist's contract is \"call ready once\". Multiple `useGristReady` calls (or\n * `useGristWidget` from sibling components) would otherwise race. We:\n *\n * - Coalesce concurrent calls into one in-flight promise.\n * - Re-call `grist.ready` only when `requiredAccess` widens (so an action-capable\n * hook can upgrade a previously read-only handshake).\n */\n\nimport type { GristColumnsToMap, GristReadyOptions, GristRequiredAccess } from \"../types\"\n\nconst ACCESS_RANK: Record<GristRequiredAccess, number> = {\n none: 0,\n \"read table\": 1,\n full: 2,\n}\n\nlet inFlight: Promise<void> | null = null\nlet lastAccess: GristRequiredAccess | null = null\nlet lastColumnNames: ReadonlySet<string> | null = null\n\nfunction columnNamesOf(columns: GristColumnsToMap | undefined): Set<string> {\n return new Set((columns ?? []).map((c) => (typeof c === \"string\" ? c : c.name)))\n}\n\n/**\n * Re-init whenever the new payload asks for strictly more than what's\n * already cached: a higher access level, or a column name the cached\n * payload didn't declare. Prevents a bare fallback caller (e.g. a status\n * chip with no declared columns) from permanently sticking a widget's real,\n * richer requirements to the host once it happens to win the initial race.\n */\nfunction shouldReinit(next: GristRequiredAccess, nextColumns: ReadonlySet<string>): boolean {\n if (!lastAccess) return true\n if (ACCESS_RANK[next] > ACCESS_RANK[lastAccess]) return true\n for (const name of nextColumns) {\n if (!lastColumnNames?.has(name)) return true\n }\n return false\n}\n\n/**\n * Calls `grist.ready` at most once per page (re-called only if access widens\n * or previously-undeclared columns are requested).\n * Returns the same promise for all concurrent callers.\n */\nexport function ensureGristReady(payload: GristReadyOptions): Promise<void> {\n const access = payload.requiredAccess ?? \"read table\"\n const columns = columnNamesOf(payload.columns)\n if (inFlight && !shouldReinit(access, columns)) return inFlight\n\n lastAccess = access\n lastColumnNames = columns\n const next = Promise.resolve().then(() => {\n const result = grist.ready(payload)\n return result instanceof Promise ? result : Promise.resolve()\n })\n\n inFlight = next.catch((err) => {\n inFlight = null\n lastAccess = null\n lastColumnNames = null\n throw err\n })\n return inFlight\n}\n\n/**\n * Forget the cached ready state. Subsequent calls to {@link ensureGristReady}\n * will re-issue `grist.ready` even at the same access level.\n *\n * Production uses: the handshake manager's `reload()` clears the singleton so\n * a soft retry triggers a fresh `grist.ready` (otherwise the cached promise\n * would short-circuit and the user-visible reload would be a no-op).\n *\n * Tests use this between test cases when swapping `window.grist`.\n */\nexport function resetGristReady(): void {\n inFlight = null\n lastAccess = null\n lastColumnNames = null\n}\n\n/** @deprecated Use {@link resetGristReadySingleton}. Kept for test back-compat. */\n","export type GristThemeName = \"light\" | \"dark\"\n\n/**\n * Normalize theme from `grist.on(\"message\")` host payloads (`msg.theme`).\n * Grist sends a theme object with `appearance`; some hosts may send a bare string.\n */\nexport function parseGristThemePayload(payload: unknown): GristThemeName | null {\n if (!payload || typeof payload !== \"object\") return null\n const raw = payload as Record<string, unknown>\n const top = raw.theme\n if (top === \"light\" || top === \"dark\") return top\n if (top && typeof top === \"object\") {\n const appearance = (top as Record<string, unknown>).appearance\n if (appearance === \"light\" || appearance === \"dark\") return appearance\n }\n return null\n}\n","/**\n * The widget's connection to Grist: one store, one `connect()`.\n *\n * The template loads `grist-plugin-api.js` with a classic blocking script, so\n * `window.grist` is there when the widget starts, or it never will be: the\n * check is synchronous (with one more look at `load`, for a page that loads\n * the script asynchronously). Then `grist.ready()` once, and every Grist\n * stream (records, options, mappings, theme) feeds one immutable state that\n * React reads through `useSyncExternalStore`. No polling, no heartbeat: the\n * iframe lives and dies with the Grist page, and a failed call fails where it\n * was made.\n */\n\nimport { parseGristThemePayload } from \"../helpers/grist-theme-payload\"\nimport type { GristSdkAlertKind } from \"../helpers/grist-sdk-alerts\"\nimport type { StandardSchema } from \"./cells\"\nimport type {\n GristReadyOptions,\n GristRequiredAccess,\n GristRowRecord,\n GristWidgetColumnMap,\n GristWidgetInteraction,\n} from \"../types\"\nimport { parseAccess } from \"./derive\"\nimport { messageStream, newRecordStream, optionsStream, recordsStream, recordStream } from \"./host\"\nimport { ensureGristReady, resetGristReady } from \"./ready\"\n\nexport type GristConnection = \"connecting\" | \"ready\" | \"not-embedded\" | \"unavailable\" | \"error\"\nexport type GristTheme = \"light\" | \"dark\"\nexport type GristWidgetActionStatus = \"idle\" | \"running\" | \"error\"\n\nexport type GristRuntimeState = {\n connection: GristConnection\n /** Why the connection failed (`connection === \"error\"`). */\n connectionError: string | null\n declaredAccess: GristRequiredAccess\n /** The access Grist reports with the widget options; null before it does. */\n grantedAccess: GristRequiredAccess | null\n record: GristRowRecord | null\n records: GristRowRecord[] | null\n isNewRecord: boolean\n /** Logical → real column ids; null until Grist reports them. */\n mappings: GristWidgetColumnMap | null\n widgetOptions: Record<string, unknown> | null\n interaction: GristWidgetInteraction | null\n currentTableId: string | null\n theme: GristTheme | null\n actionStatus: GristWidgetActionStatus\n actionError: string | null\n /** The last read that Grist refused for lack of access, for the alerts. */\n readError: string | null\n /** Logical columns the last `mapBack` couldn't write (allowMultiple), for the alerts. */\n mapBackSkipped: readonly string[]\n}\n\n/** What a widget asks Grist for (`UseGristOptions`). */\nexport type GristRuntimeOptions = GristReadyOptions & {\n /** Alert kinds mountGristWidget() never shows for this widget, e.g. [\"section-not-linked\"]. */\n suppressAlerts?: GristSdkAlertKind[]\n /**\n * Extra rules for the mapped records, as a Standard Schema (zod 4,\n * valibot, arktype…), checked after each cell's declared type. A record\n * that fails keeps its typed values; its issues go to `cellIssues`.\n */\n schema?: StandardSchema\n}\n\nexport type GristRuntime = {\n readonly options: GristRuntimeOptions\n getState(): GristRuntimeState\n subscribe(listener: () => void): () => void\n /** Connects (idempotent). Returns a function that stops listening. */\n start(): () => void\n /** Re-runs `grist.ready()` and re-reads mappings and the table. */\n reload(): Promise<void>\n update(patch: Partial<GristRuntimeState>): void\n}\n\nconst READY_TIMEOUT_MS = 30_000\n\nexport function initialRuntimeState(options: GristReadyOptions = {}): GristRuntimeState {\n return {\n connection: \"connecting\",\n connectionError: null,\n declaredAccess: options.requiredAccess ?? \"read table\",\n grantedAccess: null,\n record: null,\n records: null,\n isNewRecord: false,\n mappings: null,\n widgetOptions: null,\n interaction: null,\n currentTableId: null,\n theme: null,\n actionStatus: \"idle\",\n actionError: null,\n readError: null,\n mapBackSkipped: [],\n }\n}\n\nfunction isEmbedded(): boolean {\n try {\n return typeof window !== \"undefined\" && window.self !== window.top\n } catch {\n return true // a cross-origin parent throws: we are in an iframe\n }\n}\n\nconst hasGrist = () => typeof grist !== \"undefined\" && grist !== null\n\nexport function createGristRuntime(options: GristRuntimeOptions = {}): GristRuntime {\n let state = initialRuntimeState(options)\n const listeners = new Set<() => void>()\n let starts = 0\n let stopStreams: (() => void) | null = null\n let attempt = 0\n\n const update = (patch: Partial<GristRuntimeState>) => {\n let changed = false\n for (const key of Object.keys(patch) as (keyof GristRuntimeState)[]) {\n if (!Object.is(state[key], patch[key])) changed = true\n }\n if (!changed) return\n state = { ...state, ...patch }\n for (const l of [...listeners]) l()\n }\n\n const payload: GristReadyOptions = {\n requiredAccess: options.requiredAccess ?? \"read table\",\n columns: options.columns ?? [],\n ...(options.allowSelectBy !== undefined ? { allowSelectBy: options.allowSelectBy } : {}),\n ...(options.hasCustomOptions !== undefined ? { hasCustomOptions: options.hasCustomOptions } : {}),\n ...(options.onEditOptions ? { onEditOptions: options.onEditOptions } : {}),\n }\n\n const refreshTable = async () => {\n try {\n const tableId = await grist.selectedTable?.getTableId()\n if (tableId) update({ currentTableId: tableId })\n } catch {\n // Not every host answers; currentTableId stays as it was.\n }\n }\n\n const refreshMappings = async () => {\n if (typeof grist.sectionApi?.mappings !== \"function\") return\n try {\n const mappings = await grist.sectionApi.mappings()\n // A stream may have reported newer mappings while this was in flight.\n if (state.mappings === null) update({ mappings: (mappings as GristWidgetColumnMap | null) ?? {} })\n } catch {\n // The streams report mappings too.\n }\n }\n\n const connect = async () => {\n const mine = ++attempt\n update({ connection: \"connecting\", connectionError: null })\n let timer: ReturnType<typeof setTimeout> | undefined\n try {\n await Promise.race([\n ensureGristReady(payload),\n new Promise((_, reject) => {\n timer = setTimeout(() => reject(new Error(`Grist did not answer grist.ready() within ${READY_TIMEOUT_MS / 1000} s.`)), READY_TIMEOUT_MS)\n }),\n ])\n } catch (err) {\n if (mine === attempt) update({ connection: \"error\", connectionError: err instanceof Error ? err.message : String(err) })\n return\n } finally {\n clearTimeout(timer)\n }\n if (mine !== attempt) return\n update({ connection: \"ready\" })\n await Promise.all([refreshMappings(), refreshTable()])\n }\n\n const listen = () => {\n const offs = [\n // Copies: a host may reuse one record object and mutate it in place.\n recordStream.subscribe(({ record, mappings }) =>\n update({\n record: record ? ({ ...record } as GristRowRecord) : null,\n isNewRecord: false,\n ...(mappings ? { mappings } : {}),\n })\n ),\n recordsStream.subscribe(({ records, mappings }) => {\n update({ records: records.map((r) => ({ ...r }) as GristRowRecord), ...(mappings ? { mappings } : {}) })\n void refreshTable()\n }),\n optionsStream.subscribe(({ options: widgetOptions, interaction }) =>\n update({\n widgetOptions,\n interaction,\n grantedAccess: parseAccess(interaction?.access_level) ?? state.grantedAccess,\n })\n ),\n newRecordStream.subscribe(({ mappings }) => update({ isNewRecord: true, ...(mappings ? { mappings } : {}) })),\n messageStream.subscribe((msg) => {\n const theme = parseGristThemePayload(msg)\n if (theme) update({ theme })\n }),\n ]\n return () => offs.forEach((off) => off())\n }\n\n const begin = () => {\n if (!isEmbedded()) return update({ connection: \"not-embedded\" })\n if (!hasGrist()) {\n // A page that loads the plugin API asynchronously: one more look once\n // everything has loaded, then it is unavailable.\n if (typeof document !== \"undefined\" && document.readyState !== \"complete\" && typeof window !== \"undefined\") {\n window.addEventListener(\"load\", () => (hasGrist() ? begin() : update({ connection: \"unavailable\" })), { once: true })\n return\n }\n return update({ connection: \"unavailable\" })\n }\n // Bound before ready(): Grist may push the first record during it.\n stopStreams ??= listen()\n void connect()\n }\n\n return {\n options,\n getState: () => state,\n subscribe(listener) {\n listeners.add(listener)\n return () => listeners.delete(listener)\n },\n start() {\n if (starts++ === 0) begin()\n return () => {\n if (--starts > 0) return\n stopStreams?.()\n stopStreams = null\n }\n },\n async reload() {\n if (!hasGrist() || !isEmbedded()) return begin()\n resetGristReady()\n update({ mappings: null })\n stopStreams ??= listen()\n await connect()\n },\n update,\n }\n}\n","import { useState, type ReactNode } from \"react\"\n\nimport { GristContextProvider, newConnection, type UseGristOptions } from \"../use-grist\"\n\nexport type GristWidgetProviderProps = {\n /** Read once, at mount: what the widget asks Grist for. */\n options?: UseGristOptions\n children: ReactNode\n}\n\n/**\n * Connects to Grist for the widgets below it: `useGrist()` under it reads this\n * connection. `mountGristWidget()` renders it; render it yourself only for a\n * page that manages its own React root.\n */\nexport function GristWidgetProvider({ options, children }: GristWidgetProviderProps) {\n const [connection] = useState(() => newConnection(options))\n return <GristContextProvider value={connection}>{children}</GristContextProvider>\n}\n","import { useCallback, useState, type CSSProperties, type ReactNode } from \"react\"\n\nimport { accessDenied, accessLabel, deriveColumnMappingStatus } from \"../runtime/derive\"\nimport type { GristRuntimeState } from \"../runtime/runtime\"\nimport { useGristRuntime, useGristState } from \"../use-grist\"\n\nexport type GristBoundaryProps = {\n children: ReactNode\n}\n\nexport type GristBoundaryActions = {\n reload: () => Promise<void>\n isReloading: boolean\n}\n\nconst shellStyle: CSSProperties = {\n alignItems: \"center\",\n background: \"var(--background)\",\n boxSizing: \"border-box\",\n color: \"var(--foreground)\",\n display: \"flex\",\n flexDirection: \"column\",\n justifyContent: \"center\",\n minHeight: \"100%\",\n padding: \"clamp(16px, 5vh, 32px)\",\n width: \"100%\",\n}\n\nconst cardStyle: CSSProperties = {\n background: \"var(--card)\",\n border: \"1px solid var(--border)\",\n borderRadius: 12,\n boxShadow: \"0 1px 3px rgb(0 0 0 / 0.12)\",\n maxWidth: 420,\n padding: \"20px 22px\",\n textAlign: \"center\",\n width: \"100%\",\n}\n\nconst titleStyle: CSSProperties = {\n color: \"var(--foreground)\",\n fontSize: 15,\n fontWeight: 600,\n lineHeight: 1.35,\n margin: 0,\n}\n\nconst messageStyle: CSSProperties = {\n color: \"var(--muted-foreground)\",\n fontSize: 14,\n lineHeight: 1.5,\n margin: \"10px 0 0\",\n}\n\nconst buttonStyle: CSSProperties = {\n background: \"var(--background)\",\n border: \"1px solid var(--border)\",\n borderRadius: 8,\n color: \"var(--foreground)\",\n cursor: \"pointer\",\n fontSize: 13,\n fontWeight: 500,\n marginTop: 16,\n padding: \"8px 14px\",\n}\n\ntype GristBoundaryScreenProps = {\n title: string\n message: string\n /** Affects WAI-ARIA role only (`alert` vs `status`); copy uses the same neutral styles. */\n tone?: \"default\" | \"error\"\n showRetry?: boolean\n actions?: GristBoundaryActions\n retryLabel?: string\n retryBusyLabel?: string\n}\n\n/** Centered full-viewport chrome for booting / unavailable / error states. */\nexport function GristBoundaryScreen({\n title,\n message,\n tone = \"default\",\n showRetry = false,\n actions,\n retryLabel = \"Try reconnecting\",\n retryBusyLabel = \"Reconnecting…\",\n}: GristBoundaryScreenProps) {\n return (\n <div style={shellStyle} role={tone === \"error\" ? \"alert\" : \"status\"}>\n <div style={cardStyle}>\n <h2 style={titleStyle}>{title}</h2>\n <p style={messageStyle}>{message}</p>\n {showRetry && actions ? (\n <button\n disabled={actions.isReloading}\n onClick={() => void actions.reload()}\n style={{\n ...buttonStyle,\n cursor: actions.isReloading ? \"not-allowed\" : \"pointer\",\n opacity: actions.isReloading ? 0.7 : 1,\n }}\n type=\"button\"\n >\n {actions.isReloading ? retryBusyLabel : retryLabel}\n </button>\n ) : null}\n </div>\n </div>\n )\n}\n\ntype Screen = { title: string; message: string; tone?: \"default\" | \"error\"; retry?: boolean }\n\n/** What the boundary shows instead of the widget, or null to render it. */\nexport function boundaryScreen(state: GristRuntimeState, columns: Parameters<typeof deriveColumnMappingStatus>[0]): Screen | null {\n switch (state.connection) {\n case \"connecting\":\n return { title: \"Connecting to Grist\", message: \"Asking Grist for the access this widget needs…\" }\n case \"not-embedded\":\n return {\n title: \"Open inside Grist\",\n message: \"Open this page as a custom widget inside a Grist document (it runs in an embedded panel, not on its own).\",\n retry: true,\n }\n case \"unavailable\":\n return {\n title: \"Open inside Grist\",\n message: \"The Grist plugin did not load. Reload the page, or open this URL as a custom widget inside a Grist document.\",\n retry: true,\n }\n case \"error\":\n return {\n title: \"Something went wrong\",\n message: state.connectionError ?? \"Something went wrong connecting to Grist. Try again, or reload the page.\",\n tone: \"error\",\n retry: true,\n }\n }\n if (accessDenied(state)) {\n return {\n title: \"More access needed\",\n message: `Set Access level to at least \"${accessLabel(state.declaredAccess)}\" in the Custom widget settings.`,\n tone: \"error\",\n retry: true,\n }\n }\n const mapping = deriveColumnMappingStatus(columns, state.mappings)\n if (mapping.pending) return { title: \"Connecting to Grist\", message: \"Waiting for Grist to report the column mapping…\" }\n if (!mapping.ok) {\n return {\n title: \"Map your columns\",\n message:\n \"Open the widget settings in Grist (Creator Panel → Custom widget) and connect each required column to your table.\",\n }\n }\n return null\n}\n\n/**\n * Renders the widget once Grist is connected, has granted the access it\n * declares, and every required declared column is mapped; until then, a\n * screen that says what is missing (with a retry where one can help).\n * Requires `<GristWidgetProvider>`; `mountGristWidget()` renders both.\n */\nexport function GristBoundary({ children }: GristBoundaryProps) {\n const connection = useGristRuntime()\n if (!connection) throw new Error(\"<GristBoundary> must be used inside <GristWidgetProvider> (mountGristWidget renders both).\")\n const state = useGristState(connection)\n const [isReloading, setIsReloading] = useState(false)\n const reload = useCallback(async () => {\n setIsReloading(true)\n try {\n await connection.runtime.reload()\n } catch (err) {\n console.error(\"[grist-widget-sdk] reload failed:\", err)\n } finally {\n setIsReloading(false)\n }\n }, [connection])\n\n const screen = boundaryScreen(state, connection.runtime.options.columns)\n if (!screen) return <>{children}</>\n return (\n <GristBoundaryScreen\n title={screen.title}\n message={screen.message}\n tone={screen.tone}\n showRetry={screen.retry}\n actions={{ reload, isReloading }}\n retryLabel={screen.tone === \"error\" ? \"Try again\" : \"Try reconnecting\"}\n retryBusyLabel={screen.tone === \"error\" ? \"Retrying…\" : \"Reconnecting…\"}\n />\n )\n}\n","import type { CSSProperties } from \"react\"\n\n/**\n * The chrome's colours and radius: shadcn's CSS variables, so the pages\n * follow a widget's theme (light, dark, its own palette) without depending\n * on its Tailwind config, with neutral fallbacks for a widget without them.\n * Same approach as GristBoundaryScreen.\n */\nconst token = (name: string, fallback: string) => `var(--${name}, ${fallback})`\n\nexport const tokens = {\n background: token(\"background\", \"#ffffff\"),\n foreground: token(\"foreground\", \"#0a0a0a\"),\n card: token(\"card\", \"#ffffff\"),\n mutedForeground: token(\"muted-foreground\", \"#737373\"),\n border: token(\"border\", \"#e5e5e5\"),\n primary: token(\"primary\", \"#171717\"),\n primaryForeground: token(\"primary-foreground\", \"#fafafa\"),\n destructive: token(\"destructive\", \"#dc2626\"),\n radius: token(\"radius\", \"0.625rem\"),\n} as const\n\nexport const pageStyle: CSSProperties = {\n boxSizing: \"border-box\",\n display: \"flex\",\n flexDirection: \"column\",\n justifyContent: \"center\",\n maxWidth: \"28rem\",\n minHeight: \"100%\",\n margin: \"0 auto\",\n padding: \"4rem 1.5rem\",\n color: tokens.foreground,\n font: \"inherit\",\n}\n\nexport const eyebrowStyle: CSSProperties = {\n margin: \"0 0 0.5rem\",\n textAlign: \"center\",\n fontSize: \"0.875rem\",\n fontWeight: 500,\n color: tokens.mutedForeground,\n}\n\nexport const headingStyle: CSSProperties = {\n margin: 0,\n textAlign: \"center\",\n fontSize: \"1.5rem\",\n fontWeight: 600,\n letterSpacing: \"-0.01em\",\n}\n\nexport const leadStyle: CSSProperties = {\n margin: \"0.75rem auto 2rem\",\n maxWidth: \"24rem\",\n textAlign: \"center\",\n fontSize: \"0.875rem\",\n lineHeight: 1.5,\n color: tokens.mutedForeground,\n}\n\nexport const cardStyle: CSSProperties = {\n boxSizing: \"border-box\",\n marginBottom: \"1rem\",\n padding: \"1.25rem\",\n border: `1px solid ${tokens.border}`,\n borderRadius: tokens.radius,\n background: tokens.card,\n}\n\nexport const cardTitleStyle: CSSProperties = {\n margin: \"0 0 0.375rem\",\n fontSize: \"1rem\",\n fontWeight: 600,\n}\n\nexport const cardTextStyle: CSSProperties = {\n margin: 0,\n fontSize: \"0.875rem\",\n lineHeight: 1.5,\n color: tokens.mutedForeground,\n}\n\nexport const codeStyle: CSSProperties = {\n fontFamily: \"ui-monospace, SFMono-Regular, Menlo, monospace\",\n fontSize: \"0.8125rem\",\n color: tokens.foreground,\n}\n","/**\n * The widget's name for the pages shown outside Grist: the page title,\n * which `create-grist-widget` sets to the widget's title in `index.html`.\n */\nexport function widgetTitle(): string {\n const title = typeof document === \"undefined\" ? \"\" : document.title.trim()\n return title || \"Grist widget\"\n}\n","import {\n cardStyle,\n cardTextStyle,\n cardTitleStyle,\n codeStyle,\n eyebrowStyle,\n headingStyle,\n leadStyle,\n pageStyle,\n} from \"./tokens\"\nimport { widgetTitle } from \"./widget-title\"\n\n/**\n * Shown outside Grist on the dev server. Deliberately not a preview of the\n * widget: an emulator can't match real Grist, so it points at the two loops\n * worth trusting, `pnpm test` and the `dev` branch's preview inside Grist.\n */\nexport function LocalDevPage() {\n return (\n <main style={pageStyle}>\n <p style={eyebrowStyle}>{widgetTitle()} · local dev</p>\n <h1 style={headingStyle}>Not embedded in Grist</h1>\n <p style={leadStyle}>This is the local dev server: there's no Grist here to render the widget against.</p>\n\n <section style={cardStyle}>\n <h2 style={cardTitleStyle}>Check it against real Grist</h2>\n <p style={cardTextStyle}>\n Push to <code style={codeStyle}>dev</code>, then open its <code style={codeStyle}>/dev/</code> URL in a\n custom widget of a real Grist document: later pushes reload it there within seconds. Locally,{\" \"}\n <code style={codeStyle}>pnpm test</code> runs the widget against an emulated Grist.\n </p>\n </section>\n\n <section style={cardStyle}>\n <h2 style={cardTitleStyle}>Starting from another example?</h2>\n <p style={cardTextStyle}>\n <code style={codeStyle}>npx create-grist-widget list</code> shows the examples, and{\" \"}\n <code style={codeStyle}>npx create-grist-widget use &lt;example&gt;</code> swaps this widget for one.\n </p>\n </section>\n </main>\n )\n}\n","import { useState, type CSSProperties } from \"react\"\n\nimport { deployChannelLabel, parseDeployPath, type DeployChannel } from \"../deploy-path\"\nimport { useReleasedVersions } from \"../released-versions\"\nimport {\n cardStyle,\n cardTextStyle,\n cardTitleStyle,\n codeStyle,\n eyebrowStyle,\n headingStyle,\n leadStyle,\n pageStyle,\n tokens,\n} from \"./tokens\"\nimport { widgetTitle } from \"./widget-title\"\n\n/**\n * Shown outside Grist on a deployed URL (`/latest/`, `/dev/`, `/v<version>/`\n * or the root): which build this is, links to the others, and the URL to\n * paste into a Grist custom widget.\n */\nexport function ReleasePage({ channel }: { channel: DeployChannel }) {\n const label = deployChannelLabel(channel)\n return (\n <main style={pageStyle}>\n <p style={eyebrowStyle}>\n {widgetTitle()} · {label}\n </p>\n <h1 style={headingStyle}>Grist isn't loaded here</h1>\n <p style={leadStyle}>\n This is the <code style={codeStyle}>{label}</code> build, opened outside Grist. Hover a version to see when it\n was released.\n </p>\n <ChannelLinks current={channel} />\n <InstallUrl />\n </main>\n )\n}\n\nfunction ChannelLinks({ current }: { current: DeployChannel }) {\n const { basePath } = parseDeployPath(window.location.pathname)\n const { versions } = useReleasedVersions()\n const isCurrent = (channel: DeployChannel) =>\n channel.kind === current.kind && (channel.kind !== \"version\" || (current.kind === \"version\" && channel.version === current.version))\n\n return (\n <nav aria-label=\"Versions\" style={{ display: \"flex\", flexWrap: \"wrap\", justifyContent: \"center\", gap: \"0.5rem\", marginBottom: \"2rem\" }}>\n <ChannelLink href={`${basePath}latest/`} active={isCurrent({ kind: \"latest\" })}>\n latest\n </ChannelLink>\n <ChannelLink href={`${basePath}dev/`} active={isCurrent({ kind: \"dev\" })}>\n dev\n </ChannelLink>\n {versions?.map((v) => (\n <ChannelLink\n key={v.version}\n href={`${basePath}v${v.version}/`}\n title={formatDate(v.publishedAt)}\n active={isCurrent({ kind: \"version\", version: v.version })}\n >\n {`v${v.version}`}\n </ChannelLink>\n ))}\n </nav>\n )\n}\n\nfunction ChannelLink({\n href,\n title,\n active,\n children,\n}: {\n href: string\n title?: string\n active: boolean\n children: string\n}) {\n const style: CSSProperties = {\n padding: \"0.25rem 0.75rem\",\n border: `1px solid ${active ? tokens.primary : tokens.border}`,\n borderRadius: \"9999px\",\n background: active ? tokens.primary : \"transparent\",\n color: active ? tokens.primaryForeground : tokens.mutedForeground,\n fontSize: \"0.75rem\",\n fontWeight: 500,\n textDecoration: \"none\",\n }\n return (\n <a href={href} title={title} aria-current={active ? \"page\" : undefined} style={style}>\n {children}\n </a>\n )\n}\n\nfunction InstallUrl() {\n const url = window.location.href\n const [copied, setCopied] = useState(false)\n\n function copy() {\n void navigator.clipboard?.writeText(url).then(() => {\n setCopied(true)\n setTimeout(() => setCopied(false), 1500)\n })\n }\n\n return (\n <section style={cardStyle}>\n <h2 style={cardTitleStyle}>Use it as a Grist custom widget</h2>\n <p style={{ ...cardTextStyle, marginBottom: \"1rem\" }}>Paste this URL into a custom widget's URL field in Grist.</p>\n <div style={{ display: \"flex\", gap: \"0.5rem\" }}>\n <input\n readOnly\n value={url}\n aria-label=\"Widget URL\"\n onFocus={(event) => event.target.select()}\n style={{\n flex: 1,\n minWidth: 0,\n padding: \"0.5rem 0.75rem\",\n border: `1px solid ${tokens.border}`,\n borderRadius: tokens.radius,\n background: \"transparent\",\n color: tokens.foreground,\n font: \"inherit\",\n fontSize: \"0.875rem\",\n }}\n />\n <button\n type=\"button\"\n onClick={copy}\n style={{\n padding: \"0.5rem 1rem\",\n border: \"none\",\n borderRadius: tokens.radius,\n background: tokens.primary,\n color: tokens.primaryForeground,\n font: \"inherit\",\n fontSize: \"0.875rem\",\n fontWeight: 500,\n cursor: \"pointer\",\n }}\n >\n {copied ? \"Copied\" : \"Copy\"}\n </button>\n </div>\n </section>\n )\n}\n\nfunction formatDate(iso: string): string {\n const date = new Date(iso)\n return Number.isNaN(date.getTime())\n ? iso\n : date.toLocaleDateString(undefined, { year: \"numeric\", month: \"short\", day: \"numeric\" })\n}\n","/**\n * Where a deployed build is being served from.\n *\n * A widget's deploy pipeline publishes the same build at its root and at\n * `/latest/`, a preview at `/dev/`, and each release at `/v<version>/`, all\n * under one base path (e.g. `/my-widget/` on GitHub Pages). Opened outside\n * Grist, the page tells them apart from `window.location.pathname` alone.\n */\nexport type DeployChannel =\n | { kind: \"latest\" }\n | { kind: \"dev\" }\n | { kind: \"version\"; version: string }\n\nexport type DeployPath = {\n channel: DeployChannel\n /**\n * The path the channels live under, always ending in `/`: the current\n * path without its channel segment. `\"/my-widget/v1.2.0/\"` gives\n * `\"/my-widget/\"`.\n */\n basePath: string\n}\n\nconst VERSION_SEGMENT = /^v(\\d+\\.\\d+\\.\\d+(?:-[\\w.]+)?)$/\n\n/**\n * Parse a pathname into its deploy channel and base path. A path without a\n * channel segment (the deployed root, or a local dev server) is `latest`:\n * the deploy places the latest release at the root too.\n */\nexport function parseDeployPath(pathname: string): DeployPath {\n const segments = pathname.replace(/\\/+$/, \"\").split(\"/\")\n const last = segments[segments.length - 1] ?? \"\"\n\n let channel: DeployChannel | null = null\n if (last === \"latest\") channel = { kind: \"latest\" }\n else if (last === \"dev\") channel = { kind: \"dev\" }\n else {\n const match = VERSION_SEGMENT.exec(last)\n if (match) channel = { kind: \"version\", version: match[1] }\n }\n\n if (!channel) return { channel: { kind: \"latest\" }, basePath: withTrailingSlash(pathname) }\n return { channel, basePath: withTrailingSlash(segments.slice(0, -1).join(\"/\")) }\n}\n\n/** `\"latest\"`, `\"dev\"` or `\"v1.2.0\"`. */\nexport function deployChannelLabel(channel: DeployChannel): string {\n return channel.kind === \"version\" ? `v${channel.version}` : channel.kind\n}\n\nfunction withTrailingSlash(path: string): string {\n return path.endsWith(\"/\") ? path : `${path}/`\n}\n","import { useEffect, useState } from \"react\"\n\nimport { parseDeployPath } from \"./deploy-path\"\n\n/** One entry of the `versions.json` a widget's deploy pipeline maintains. */\nexport type ReleasedVersion = {\n version: string\n publishedAt: string\n}\n\nexport type UseReleasedVersionsResult = {\n /** Newest first, as the deploy writes them; `null` until loaded. */\n versions: ReleasedVersion[] | null\n /** `true` when `versions.json` couldn't be fetched or read. */\n error: boolean\n}\n\n/**\n * The widget's released versions, read from the `versions.json` next to its\n * channels (see {@link parseDeployPath}). For a page shown outside Grist,\n * such as a release page linking to each version.\n */\nexport function useReleasedVersions(\n pathname: string = typeof window === \"undefined\" ? \"/\" : window.location.pathname\n): UseReleasedVersionsResult {\n const url = `${parseDeployPath(pathname).basePath}versions.json`\n const [result, setResult] = useState<UseReleasedVersionsResult>({ versions: null, error: false })\n\n useEffect(() => {\n let cancelled = false\n fetch(url, { cache: \"no-store\" })\n .then((res) => (res.ok ? res.json() : Promise.reject(new Error(`HTTP ${res.status}`))))\n .then((data: unknown) => {\n if (cancelled) return\n if (!Array.isArray(data)) throw new Error(\"versions.json is not an array\")\n setResult({ versions: data as ReleasedVersion[], error: false })\n })\n .catch(() => {\n if (!cancelled) setResult({ versions: null, error: true })\n })\n return () => {\n cancelled = true\n }\n }, [url])\n\n return result\n}\n","/**\n * The alerts `mountGristWidget()` shows above a running widget: what needs the\n * user's attention in Grist (column mapping, access, a failed write, an\n * unlinked section). The blocking states (not connected, access refused,\n * required columns unmapped) are `<GristBoundary>`'s, not alerts.\n */\n\nimport { useNearestGristState } from \"../use-grist\"\nimport { deriveColumnMappingStatus, deriveStatus } from \"../runtime/derive\"\nimport { isAccessInsufficientError } from \"../runtime/api\"\nimport type { GristCellIssue } from \"../runtime/cells\"\nimport type { GristRuntimeState } from \"../runtime/runtime\"\nimport type { GristColumnsToMap, GristWidgetInteraction } from \"../types\"\nimport { parseGristWidgetLinkingInfo } from \"./grist-widget-interaction\"\n\nexport type GristSdkAlertKind =\n | \"column-mapping\"\n | \"mapping-pending\"\n | \"section-not-linked\"\n | \"source-not-wired\"\n | \"action-error\"\n | \"access-insufficient\"\n | \"map-back-skip\"\n | \"cell-issues\"\n\nexport type GristSdkAlertSeverity = \"info\" | \"warning\" | \"error\"\n\nexport type GristSdkAlertDescriptor = {\n id: string\n kind: GristSdkAlertKind\n severity: GristSdkAlertSeverity\n title: string\n ariaRole: \"status\" | \"alert\"\n message: string\n}\n\nexport type GristSdkAlertsOptions = {\n /** Added to the \"section not linked\" message, e.g. how to link in Grist. */\n sectionNotLinkedHint?: string\n}\n\nconst TITLE: Record<GristSdkAlertKind, string> = {\n \"column-mapping\": \"Column mapping\",\n \"mapping-pending\": \"Column mapping\",\n \"section-not-linked\": \"Widget linking\",\n \"source-not-wired\": \"Widget linking\",\n \"action-error\": \"Action error\",\n \"access-insufficient\": \"Access level\",\n \"map-back-skip\": \"Write skipped\",\n \"cell-issues\": \"Unexpected values\",\n}\n\nconst SEVERITY: Record<GristSdkAlertKind, GristSdkAlertSeverity> = {\n \"column-mapping\": \"warning\",\n \"mapping-pending\": \"info\",\n \"section-not-linked\": \"warning\",\n \"source-not-wired\": \"warning\",\n \"action-error\": \"error\",\n \"access-insufficient\": \"error\",\n \"map-back-skip\": \"warning\",\n \"cell-issues\": \"warning\",\n}\n\nconst alert = (kind: GristSdkAlertKind, message: string, ariaRole: \"status\" | \"alert\" = \"status\"): GristSdkAlertDescriptor => ({\n id: kind,\n kind,\n severity: SEVERITY[kind],\n title: TITLE[kind],\n ariaRole,\n message,\n})\n\n/** A widget section Grist says is linked to nothing. */\nexport function isWidgetSectionNotLinked(interaction: GristWidgetInteraction | null | undefined): boolean {\n const linking = parseGristWidgetLinkingInfo(interaction?.linking)\n return Boolean(linking) && linking!.asTarget == null\n}\n\n/** The alerts for a widget in `state`, pure (tested without React). */\nexport function getGristSdkAlerts(\n state: GristRuntimeState,\n widget: {\n columns?: GristColumnsToMap\n allowSelectBy?: boolean\n suppressAlerts?: readonly GristSdkAlertKind[]\n cellIssues?: readonly GristCellIssue[]\n },\n options: GristSdkAlertsOptions = {}\n): GristSdkAlertDescriptor[] {\n if (deriveStatus(state) !== \"ready\") return []\n const out: GristSdkAlertDescriptor[] = []\n\n const mapping = deriveColumnMappingStatus(widget.columns, state.mappings)\n if (mapping.pending) out.push(alert(\"mapping-pending\", \"Waiting for Grist to report column mappings.\"))\n else if (!mapping.ok) {\n const parts = [\"Column mapping is incomplete.\"]\n if (mapping.missing.length) parts.push(`Required columns: ${mapping.missing.join(\", \")}.`)\n if (mapping.emptyMultiples.length) parts.push(`Assign at least one sheet column for: ${mapping.emptyMultiples.join(\", \")}.`)\n out.push(alert(\"column-mapping\", parts.join(\" \")))\n }\n\n const failure = state.actionError ?? state.readError\n if (failure && isAccessInsufficientError(failure)) {\n out.push(\n alert(\n \"access-insufficient\",\n 'This operation requires \"Full document access\". Set the Access level to \"Full document access\" in the Custom widget configuration panel.',\n \"alert\"\n )\n )\n } else if (state.actionError) {\n out.push(alert(\"action-error\", state.actionError, \"alert\"))\n }\n\n if (state.mapBackSkipped.length) {\n const list = state.mapBackSkipped.join(\", \")\n out.push(alert(\"map-back-skip\", `mapBack skipped multi-mapped column${state.mapBackSkipped.length === 1 ? \"\" : \"s\"}: ${list}.`))\n }\n\n const cellIssues = widget.cellIssues ?? []\n if (cellIssues.length) {\n const first = cellIssues[0]!\n const where = first.column ? `${first.column} in row ${first.rowId}` : `row ${first.rowId}`\n const more = cellIssues.length > 1 ? ` (and ${cellIssues.length - 1} more)` : \"\"\n out.push(alert(\"cell-issues\", `${where}: ${first.message}${more}. Check the column's type, or the cell, in Grist.`))\n }\n\n const linking = parseGristWidgetLinkingInfo(state.interaction?.linking)\n if (widget.allowSelectBy) {\n if (linking && !linking.asSource) {\n out.push(\n alert(\n \"source-not-wired\",\n \"This widget is configured as a selector (allowSelectBy) but no other section is using it as a link source yet. Link another section to read from this widget.\"\n )\n )\n }\n } else if (isWidgetSectionNotLinked(state.interaction)) {\n const hint = options.sectionNotLinkedHint?.trim()\n out.push(\n alert(\n \"section-not-linked\",\n \"This widget section is not linked to a table or selector. Link it from the page settings so the selected row is sent to the widget.\" +\n (hint ? ` ${hint}` : \"\")\n )\n )\n }\n\n const suppressed = widget.suppressAlerts ?? []\n return out.filter((a) => !suppressed.includes(a.kind))\n}\n\n/** @internal The alerts for the widget under the nearest `<GristWidgetProvider>`; [] outside one. */\nexport function useGristSdkAlerts(options?: GristSdkAlertsOptions): GristSdkAlertDescriptor[] {\n const { connection, state, cellIssues } = useNearestGristState()\n if (!connection) return []\n const { columns, allowSelectBy, suppressAlerts } = connection.runtime.options\n return getGristSdkAlerts(state, { columns, allowSelectBy, suppressAlerts, cellIssues }, options)\n}\n","import type { CSSProperties, ReactNode } from \"react\"\n\nimport { useGristSdkAlerts, type GristSdkAlertDescriptor, type GristSdkAlertsOptions } from \"../../sdk/helpers/grist-sdk-alerts\"\nimport { tokens } from \"./tokens\"\n\nconst ALERT_OPTIONS: GristSdkAlertsOptions = {\n sectionNotLinkedHint:\n \"In Grist, select this widget section on the page, then use Link to connect a table, card, or chart view as the selector.\",\n}\n\n/**\n * The default `Alerts` of {@link mountGristWidget}: what needs the user's\n * attention (column mapping, access level, failed writes, an unlinked\n * section), above the widget. Renders nothing extra when all is well.\n */\nexport function WidgetAlerts({ children }: { children: ReactNode }) {\n const alerts = useGristSdkAlerts(ALERT_OPTIONS)\n if (alerts.length === 0) return <>{children}</>\n\n return (\n <div style={{ display: \"flex\", flexDirection: \"column\", gap: \"0.75rem\" }}>\n <div style={{ display: \"flex\", flexDirection: \"column\", gap: \"0.75rem\", padding: \"0.75rem 0.75rem 0\" }}>\n {alerts.map((alert) => (\n <WidgetAlert key={alert.id} alert={alert} />\n ))}\n </div>\n {children}\n </div>\n )\n}\n\nfunction WidgetAlert({ alert }: { alert: GristSdkAlertDescriptor }) {\n const linkIcon = alert.kind === \"section-not-linked\" || alert.kind === \"source-not-wired\"\n return (\n <div role={alert.ariaRole} style={{ ...alertStyle, ...SEVERITY[alert.severity] }}>\n <span aria-hidden style={{ flexShrink: 0, marginTop: \"0.125rem\" }}>\n {linkIcon ? <LinkIcon /> : <WarningIcon />}\n </span>\n <div style={{ minWidth: 0 }}>\n <p style={{ margin: 0, fontWeight: 500 }}>{alert.title}</p>\n <p style={{ margin: \"0.25rem 0 0\", color: tokens.mutedForeground }}>{alert.message}</p>\n </div>\n </div>\n )\n}\n\nconst alertStyle: CSSProperties = {\n boxSizing: \"border-box\",\n display: \"flex\",\n gap: \"0.75rem\",\n padding: \"0.75rem 1rem\",\n border: `1px solid ${tokens.border}`,\n borderRadius: tokens.radius,\n color: tokens.foreground,\n fontSize: \"0.875rem\",\n lineHeight: 1.5,\n}\n\nconst SEVERITY: Record<GristSdkAlertDescriptor[\"severity\"], CSSProperties> = {\n error: { borderColor: tokens.destructive, color: tokens.destructive },\n warning: { borderColor: \"rgb(245 158 11 / 0.4)\", background: \"rgb(245 158 11 / 0.1)\" },\n info: { background: \"transparent\" },\n}\n\nconst ICON = {\n width: 16,\n height: 16,\n viewBox: \"0 0 24 24\",\n fill: \"none\",\n stroke: \"currentColor\",\n strokeWidth: 2,\n strokeLinecap: \"round\",\n strokeLinejoin: \"round\",\n} as const\n\nfunction WarningIcon() {\n return (\n <svg {...ICON}>\n <path d=\"m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3\" />\n <path d=\"M12 9v4\" />\n <path d=\"M12 17h.01\" />\n </svg>\n )\n}\n\nfunction LinkIcon() {\n return (\n <svg {...ICON}>\n <path d=\"M9 17H7A5 5 0 0 1 7 7h2\" />\n <path d=\"M15 7h2a5 5 0 1 1 0 10h-2\" />\n <line x1=\"8\" x2=\"16\" y1=\"12\" y2=\"12\" />\n </svg>\n )\n}\n","import { createContext, useCallback, useContext, useEffect, useMemo, useState, type ReactNode } from \"react\"\n\nimport { useNearestGristState } from \"../sdk/use-grist\"\n\nexport type WidgetTheme = \"light\" | \"dark\" | \"system\"\nexport type ResolvedWidgetTheme = \"light\" | \"dark\"\n\nexport type UseThemeResult = {\n /**\n * Inside Grist: Grist's theme, or `\"system\"` until Grist has sent it.\n * Outside Grist: the saved choice, `\"system\"` by default.\n */\n theme: WidgetTheme\n /** The theme applied to `<html class>`: `\"system\"` resolved to light or dark. */\n resolvedTheme: ResolvedWidgetTheme\n /**\n * Choose a theme outside Grist; it is saved in `localStorage`. Inside Grist\n * this does nothing: the widget follows Grist's theme.\n */\n setTheme: (theme: WidgetTheme) => void\n}\n\nconst STORAGE_KEY = \"theme\"\nconst DARK_QUERY = \"(prefers-color-scheme: dark)\"\nconst THEMES: readonly WidgetTheme[] = [\"light\", \"dark\", \"system\"]\n\nconst ThemeContext = createContext<UseThemeResult | null>(null)\n\n/**\n * The widget's current theme, for components that need it in JavaScript\n * (a toaster, a chart). Same shape as shadcn's `useTheme()`. Styles should\n * rely on the `dark` class that {@link mountGristWidget} keeps on `<html>`.\n * Outside a mounted widget (a unit test, for instance) it reports the\n * system theme and `setTheme` does nothing.\n */\nexport function useTheme(): UseThemeResult {\n const value = useContext(ThemeContext)\n return value ?? { theme: \"system\", resolvedTheme: systemTheme(), setTheme: noop }\n}\n\n/** Inside Grist: follows Grist's theme, and the OS setting until Grist sends one. */\nexport function EmbeddedThemeProvider({ children }: { children: ReactNode }) {\n const gristTheme = useNearestGristState().state.theme\n const system = useSystemTheme(gristTheme === null)\n const resolvedTheme = gristTheme ?? system\n\n useApplyTheme(resolvedTheme)\n\n const value = useMemo<UseThemeResult>(\n () => ({ theme: gristTheme ?? \"system\", resolvedTheme, setTheme: noop }),\n [gristTheme, resolvedTheme]\n )\n return <ThemeContext.Provider value={value}>{children}</ThemeContext.Provider>\n}\n\n/**\n * Outside Grist (`pnpm dev`, the deployed release page): the saved choice,\n * the OS setting by default, and the `d` key to switch between light and\n * dark, as shadcn's theme provider does.\n */\nexport function StandaloneThemeProvider({ children }: { children: ReactNode }) {\n const [theme, setThemeState] = useState<WidgetTheme>(() => readStoredTheme() ?? \"system\")\n const system = useSystemTheme(theme === \"system\")\n const resolvedTheme = theme === \"system\" ? system : theme\n\n useApplyTheme(resolvedTheme)\n\n const setTheme = useCallback((next: WidgetTheme) => {\n writeStoredTheme(next)\n setThemeState(next)\n }, [])\n\n // `d` switches between light and dark, unless typing or using a shortcut.\n useEffect(() => {\n const onKeyDown = (event: KeyboardEvent) => {\n if (event.repeat || event.metaKey || event.ctrlKey || event.altKey) return\n if (event.key.toLowerCase() !== \"d\" || isEditableTarget(event.target)) return\n setThemeState((current) => {\n const currentResolved = current === \"system\" ? systemTheme() : current\n const next: WidgetTheme = currentResolved === \"dark\" ? \"light\" : \"dark\"\n writeStoredTheme(next)\n return next\n })\n }\n window.addEventListener(\"keydown\", onKeyDown)\n return () => window.removeEventListener(\"keydown\", onKeyDown)\n }, [])\n\n // Another tab saving a choice applies here too.\n useEffect(() => {\n const onStorage = (event: StorageEvent) => {\n if (event.key !== STORAGE_KEY) return\n setThemeState(isTheme(event.newValue) ? event.newValue : \"system\")\n }\n window.addEventListener(\"storage\", onStorage)\n return () => window.removeEventListener(\"storage\", onStorage)\n }, [])\n\n const value = useMemo<UseThemeResult>(\n () => ({ theme, resolvedTheme, setTheme }),\n [theme, resolvedTheme, setTheme]\n )\n return <ThemeContext.Provider value={value}>{children}</ThemeContext.Provider>\n}\n\n/** The OS setting, kept current while `active`. */\nfunction useSystemTheme(active: boolean): ResolvedWidgetTheme {\n const [theme, setTheme] = useState<ResolvedWidgetTheme>(systemTheme)\n\n useEffect(() => {\n if (!active || typeof window.matchMedia !== \"function\") return\n const query = window.matchMedia(DARK_QUERY)\n const onChange = () => setTheme(query.matches ? \"dark\" : \"light\")\n onChange()\n query.addEventListener(\"change\", onChange)\n return () => query.removeEventListener(\"change\", onChange)\n }, [active])\n\n return theme\n}\n\n/** Keep `light` or `dark` on `<html class>`, which Tailwind's dark variant reads. */\nfunction useApplyTheme(theme: ResolvedWidgetTheme) {\n useEffect(() => {\n const root = document.documentElement\n if (root.classList.contains(theme) && !root.classList.contains(other(theme))) return\n const restoreTransitions = suspendTransitions()\n root.classList.remove(other(theme))\n root.classList.add(theme)\n restoreTransitions()\n }, [theme])\n}\n\nfunction systemTheme(): ResolvedWidgetTheme {\n if (typeof window === \"undefined\" || typeof window.matchMedia !== \"function\") return \"light\"\n return window.matchMedia(DARK_QUERY).matches ? \"dark\" : \"light\"\n}\n\nfunction other(theme: ResolvedWidgetTheme): ResolvedWidgetTheme {\n return theme === \"dark\" ? \"light\" : \"dark\"\n}\n\n/** Switch themes without every color transition animating at once. */\nfunction suspendTransitions(): () => void {\n const style = document.createElement(\"style\")\n style.appendChild(\n document.createTextNode(\"*,*::before,*::after{-webkit-transition:none!important;transition:none!important}\")\n )\n document.head.appendChild(style)\n return () => {\n window.getComputedStyle(document.body)\n requestAnimationFrame(() => requestAnimationFrame(() => style.remove()))\n }\n}\n\nfunction isEditableTarget(target: EventTarget | null): boolean {\n if (!(target instanceof HTMLElement)) return false\n return target.isContentEditable || target.closest(\"input, textarea, select, [contenteditable='true']\") !== null\n}\n\nfunction isTheme(value: string | null): value is WidgetTheme {\n return value !== null && (THEMES as readonly string[]).includes(value)\n}\n\nfunction readStoredTheme(): WidgetTheme | null {\n try {\n const value = localStorage.getItem(STORAGE_KEY)\n return isTheme(value) ? value : null\n } catch {\n return null\n }\n}\n\nfunction writeStoredTheme(theme: WidgetTheme) {\n try {\n localStorage.setItem(STORAGE_KEY, theme)\n } catch {\n // Storage blocked (private mode, sandboxed iframe): the choice lasts for this page only.\n }\n}\n\nfunction noop() {}\n"],"mappings":"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","names":["import_react","token","token","message","message","ACCESS_RANK","inFlight","import_react","import_react","import_jsx_runtime","message","cardStyle","import_jsx_runtime","cardStyle","import_react","import_react","import_jsx_runtime","cardStyle","message","import_jsx_runtime","alert","SEVERITY","import_react","import_jsx_runtime","import_jsx_runtime","LocalDevPage","ReleasePage","isEmbedded"]}
1
+ {"version":3,"sources":["../src/app/index.ts","../src/app/mount-grist-widget.tsx","../src/sdk/use-grist.ts","../src/sdk/helpers/grist-value-codec.ts","../src/sdk/helpers/grist-table-data.ts","../src/sdk/helpers/grist-widget-options.ts","../src/sdk/helpers/build-replica-document.ts","../src/sdk/helpers/grist-columns-filters.ts","../src/sdk/helpers/grist-attachment-download.ts","../src/sdk/helpers/grist-fetch-with-auth.ts","../src/sdk/helpers/grist-attachment-upload.ts","../src/sdk/runtime/api.ts","../src/sdk/helpers/grist-mappings.ts","../src/sdk/runtime/cells.ts","../src/sdk/runtime/derive.ts","../src/sdk/helpers/grist-widget-interaction.ts","../src/sdk/runtime/host.ts","../src/sdk/runtime/ready.ts","../src/sdk/helpers/grist-theme-payload.ts","../src/sdk/runtime/runtime.ts","../src/sdk/define-widget.ts","../src/sdk/components/grist-widget-provider.tsx","../src/sdk/components/grist-boundary.tsx","../src/sdk/use-widget-metadata.ts","../src/app/chrome/local-dev-page.tsx","../src/app/chrome/tokens.ts","../src/app/chrome/widget-title.ts","../src/app/chrome/release-page.tsx","../src/app/deploy-path.ts","../src/app/released-versions.ts","../src/sdk/helpers/grist-sdk-alerts.ts","../src/app/chrome/widget-alerts.tsx","../src/app/widget-theme.tsx"],"sourcesContent":["/**\n * `grist-widget-sdk/app` — what a widget's `src/main.tsx` used to wire by\n * hand: mounting, inside- vs outside-Grist pages, the deploy channel and\n * version list, and the light/dark theme.\n *\n * ```tsx\n * import { mountGristWidget } from \"grist-widget-sdk/app\"\n * import \"./index.css\"\n * import * as entry from \"./app/App\"\n *\n * mountGristWidget(entry, { dev: import.meta.env.DEV })\n * ```\n */\n\nexport {\n GristWidgetApp,\n entryProps,\n mountGristWidget,\n type GristWidgetAppProps,\n type GristWidgetEntry,\n type MountGristWidgetConfig,\n type MountedGristWidget,\n} from \"./mount-grist-widget\"\nexport { useTheme, type ResolvedWidgetTheme, type UseThemeResult, type WidgetTheme } from \"./widget-theme\"\nexport { deployChannelLabel, parseDeployPath, type DeployChannel, type DeployPath } from \"./deploy-path\"\nexport { useReleasedVersions, type ReleasedVersion, type UseReleasedVersionsResult } from \"./released-versions\"\n","import { StrictMode, Suspense, type ComponentType, type ReactNode } from \"react\"\nimport { createRoot } from \"react-dom/client\"\n\nimport { GristBoundary, GristWidgetProvider, useWidgetMetadata } from \"../sdk\"\nimport type { GristWidget, UseGristOptions } from \"../sdk\"\nimport { isGristWidget } from \"../sdk/define-widget\"\nimport { LocalDevPage as DefaultLocalDevPage } from \"./chrome/local-dev-page\"\nimport { ReleasePage as DefaultReleasePage } from \"./chrome/release-page\"\nimport { WidgetAlerts } from \"./chrome/widget-alerts\"\nimport { parseDeployPath, type DeployChannel } from \"./deploy-path\"\nimport { EmbeddedThemeProvider, StandaloneThemeProvider } from \"./widget-theme\"\n\nexport type GristWidgetAppProps = {\n /** The widget. A `React.lazy()` component works too: its code then loads only inside Grist. */\n App: ComponentType\n /** The widget's `GRIST_OPTIONS`: access level, columns, and so on. */\n options: UseGristOptions\n /** The page's title and description (the widget's `WIDGET_METADATA`, or its declaration's). */\n metadata?: { title?: string; description?: string }\n /**\n * Whether this is the local dev server. Pass `import.meta.env.DEV`.\n * Outside Grist it picks the local-dev page over the release page.\n */\n dev?: boolean\n /**\n * Wraps the widget inside Grist, under {@link GristBoundary}. The default\n * lists what needs the user's attention (column mapping, access level,\n * failed writes) above the widget; `null` renders the widget alone.\n */\n Alerts?: ComponentType<{ children: ReactNode }> | null\n /** Shown outside Grist on the local dev server. Defaults to a page pointing at `pnpm test` and the `dev` loop. */\n LocalDevPage?: ComponentType\n /**\n * Shown outside Grist on a deployed URL (`/latest/`, `/dev/`, `/v<version>/`).\n * Defaults to a page linking every channel and version, with the URL to\n * paste into Grist.\n */\n ReleasePage?: ComponentType<{ channel: DeployChannel }>\n}\n\nexport type MountGristWidgetConfig = GristWidgetAppProps & {\n /** The element to render into, or its CSS selector. Defaults to `#root`. */\n root?: Element | string\n}\n\n/**\n * A widget's entry module, `src/app/App.tsx`, as `import * as entry` gives\n * it: the widget as its default export, its declaration as `widget` (or, in\n * a widget made before `defineGristWidget`, `GRIST_OPTIONS` and\n * `WIDGET_METADATA`), and optionally its own `Alerts`, `LocalDevPage` and\n * `ReleasePage`. Everything a widget customises lives there, in its own\n * file: the template's `src/main.tsx` stays the same in every widget, and\n * `create-grist-widget upgrade` can rewrite it without losing anything.\n */\nexport type GristWidgetEntry = {\n default: ComponentType\n widget?: GristWidget\n GRIST_OPTIONS?: UseGristOptions\n WIDGET_METADATA?: { title?: string; description?: string }\n Alerts?: GristWidgetAppProps[\"Alerts\"]\n LocalDevPage?: GristWidgetAppProps[\"LocalDevPage\"]\n ReleasePage?: GristWidgetAppProps[\"ReleasePage\"]\n}\n\n/** The props {@link GristWidgetApp} takes, from a widget's entry module. */\nexport function entryProps(entry: GristWidgetEntry, dev = false): GristWidgetAppProps {\n const widget = isGristWidget(entry.widget) ? entry.widget : undefined\n const options = widget?.options ?? entry.GRIST_OPTIONS\n if (!options) {\n throw new Error(\n \"mountGristWidget: src/app/App.tsx exports neither `widget` (defineGristWidget) nor `GRIST_OPTIONS`.\"\n )\n }\n const props: GristWidgetAppProps = {\n App: entry.default,\n options,\n metadata: widget?.metadata ?? entry.WIDGET_METADATA,\n dev,\n }\n if (\"Alerts\" in entry) props.Alerts = entry.Alerts\n if (entry.LocalDevPage) props.LocalDevPage = entry.LocalDevPage\n if (entry.ReleasePage) props.ReleasePage = entry.ReleasePage\n return props\n}\n\nexport type MountedGristWidget = {\n unmount: () => void\n}\n\n/**\n * Render a widget into the page: everything `src/main.tsx` used to wire by\n * hand.\n *\n * ```tsx\n * import { mountGristWidget } from \"grist-widget-sdk/app\"\n * import \"./index.css\"\n * import * as entry from \"./app/App\"\n *\n * mountGristWidget(entry, { dev: import.meta.env.DEV })\n * ```\n *\n * It reads the entry module's exports ({@link GristWidgetEntry}): the widget,\n * its declaration and any page it replaces. The older form,\n * `mountGristWidget({ App, options: GRIST_OPTIONS, dev })`, still works.\n *\n * Inside Grist, the widget renders in {@link GristWidgetProvider} and\n * {@link GristBoundary}, which gates on its mapped columns when it declares\n * any, and follows Grist's light/dark theme. Outside Grist, where there is\n * nothing to connect to, the page shows `LocalDevPage` on the dev server and\n * `ReleasePage` on a deployed URL.\n */\nexport function mountGristWidget(entry: GristWidgetEntry, options?: { dev?: boolean; root?: Element | string }): MountedGristWidget\nexport function mountGristWidget(config: MountGristWidgetConfig): MountedGristWidget\nexport function mountGristWidget(\n config: MountGristWidgetConfig | GristWidgetEntry,\n entryOptions: { dev?: boolean; root?: Element | string } = {}\n): MountedGristWidget {\n const { root = \"#root\", ...props } =\n \"App\" in config ? config : { ...entryProps(config, entryOptions.dev), root: entryOptions.root }\n const container = typeof root === \"string\" ? document.querySelector(root) : root\n if (!container) {\n throw new Error(`mountGristWidget: no element matches \"${String(root)}\" to render the widget into.`)\n }\n\n const reactRoot = createRoot(container)\n reactRoot.render(\n <StrictMode>\n <GristWidgetApp {...props} />\n </StrictMode>\n )\n return { unmount: () => reactRoot.unmount() }\n}\n\n/**\n * The tree {@link mountGristWidget} renders, as a component: for a test, or\n * for a page that manages its own React root.\n */\nexport function GristWidgetApp({\n App,\n options,\n metadata,\n dev = false,\n Alerts = WidgetAlerts,\n LocalDevPage = DefaultLocalDevPage,\n ReleasePage = DefaultReleasePage,\n}: GristWidgetAppProps) {\n const Wrap = Alerts ?? PassThrough\n if (isEmbedded()) {\n return (\n <GristWidgetProvider options={options}>\n <PageMetadata metadata={metadata} />\n <EmbeddedThemeProvider>\n <GristBoundary>\n <div style={FILL}>\n <Wrap>\n <Suspense fallback={null}>\n <App />\n </Suspense>\n </Wrap>\n </div>\n </GristBoundary>\n </EmbeddedThemeProvider>\n </GristWidgetProvider>\n )\n }\n\n const channel = parseDeployPath(window.location.pathname).channel\n return (\n <StandaloneThemeProvider>\n <PageMetadata metadata={metadata} />\n <div style={FILL}>{dev ? <LocalDevPage /> : <ReleasePage channel={channel} />}</div>\n </StandaloneThemeProvider>\n )\n}\n\nconst FILL = { minHeight: \"100%\", width: \"100%\" } as const\n\n/** A Grist custom widget only ever runs in Grist's iframe. */\nfunction isEmbedded(): boolean {\n return typeof window !== \"undefined\" && window.self !== window.top\n}\n\n/** The page's title and description, from the widget's declaration. */\nfunction PageMetadata({ metadata }: { metadata: GristWidgetAppProps[\"metadata\"] }) {\n useWidgetMetadata(metadata?.title ? { title: metadata.title, description: metadata.description ?? \"\" } : null)\n return null\n}\n\nfunction PassThrough({ children }: { children: ReactNode }) {\n return <>{children}</>\n}\n","/**\n * `useGrist()`: the widget's one object for Grist — its connection, the\n * selected record and the section's records, column mapping, writes, widget\n * options, linking and the document's REST API.\n *\n * Inside `<GristWidgetProvider>` (what `mountGristWidget()` renders) it reads\n * the provider's connection; outside one, a page-wide connection made with\n * the first caller's options.\n */\n\nimport { createContext, useCallback, useContext, useEffect, useMemo, useSyncExternalStore } from \"react\"\n\nimport type { ValidateColumnMappingsResult } from \"./helpers/grist-mappings\"\nimport { createGristApi, type GristApi } from \"./runtime/api\"\nimport {\n deriveColumnMappingStatus,\n deriveError,\n deriveStatus,\n mapBackPatch,\n type GristWidgetStatus,\n} from \"./runtime/derive\"\nimport { mapAndCheck, type GristCellIssue } from \"./runtime/cells\"\nimport { ALL_STREAMS } from \"./runtime/host\"\nimport { resetGristReady } from \"./runtime/ready\"\nimport {\n createGristRuntime,\n initialRuntimeState,\n type GristRuntime,\n type GristRuntimeOptions,\n type GristRuntimeState,\n type GristTheme,\n type GristWidgetActionStatus,\n} from \"./runtime/runtime\"\nimport type { GristRowRecord, GristWidgetColumnMap } from \"./types\"\n\nexport type { GristTheme, GristWidgetActionStatus, GristWidgetStatus }\nexport type { GristColumnInfo, ListColumnsOptions, ListTablesOptions } from \"./runtime/api\"\n\n/** What the widget asks Grist for: access, columns to map, and the alerts it doesn't want. */\nexport type UseGristOptions = GristRuntimeOptions\n\n/** A write under declared names: any of the mapped record's fields but its `id`. */\nexport type GristRecordPatch<TMapped> = Partial<Omit<TMapped, \"id\">>\n\n/** Derived from the selection: no row, a row, or the add-row placeholder. */\nexport type GristWidgetMode = \"empty\" | \"row\" | \"new-row\"\n\n/**\n * The widget's Grist state and API. Every method is referentially stable for\n * the widget's lifetime: safe in effect dependencies. The object itself is\n * new whenever a value changes; depend on the members you use, not on it.\n */\nexport type UseGristResult<TRow = Record<string, unknown>, TMapped = Record<string, unknown>> = Omit<\n GristApi,\n \"fetchTableRows\"\n> & {\n /** `\"booting\"` until Grist answers, then `\"ready\"`; `\"unavailable\"` outside Grist; `\"error\"` otherwise. */\n status: GristWidgetStatus\n /** Inside Grist with its plugin API (null while connecting). */\n isAvailable: boolean | null\n isReady: boolean\n /** Why the widget can't run (status `\"error\"` or `\"unavailable\"`), else null. */\n error: string | null\n /** Grist's light or dark theme, null until Grist sends it. */\n theme: GristTheme | null\n\n /** The selected row, raw column ids. */\n record: GristRowRecord<TRow> | null\n /** The section's rows (what its filters show), raw column ids. */\n records: GristRowRecord<TRow>[] | null\n /**\n * The selected row under the declared column names, each cell the JS value\n * its declared type promises (a cell that doesn't match is null, and in\n * `cellIssues`); null until every required column is mapped.\n */\n mappedRecord: TMapped | null\n /** Every row of the section, like `mappedRecord`. */\n mappedRecords: TMapped[] | null\n /** The mapped cells that didn't match their declared type (or the widget's `schema`), by row. */\n cellIssues: readonly GristCellIssue[]\n /** Declared column name → the Grist column id(s) mapped to it. */\n mappings: GristWidgetColumnMap\n /** Whether every required declared column is mapped (`pending` until Grist reports mappings). */\n columnMappingStatus: ValidateColumnMappingsResult\n mode: GristWidgetMode\n /** The Grist column id mapped to a declared name, or the name itself. */\n resolveMappedColumnId: (name: string) => string\n /**\n * A patch under declared names, as real column ids for a write, each value\n * encoded for its declared type (multi-column mappings are skipped).\n */\n mapBack: (patch: Partial<TMapped>) => Record<string, unknown>\n /**\n * Writes a patch under declared names to the selected row (or to `rowId`),\n * encoded for each declared type: `mapBack` + `table.update` in one call.\n * Rejects when no row is selected.\n */\n updateRecord: {\n (patch: GristRecordPatch<TMapped>): Promise<void>\n (rowId: number, patch: GristRecordPatch<TMapped>): Promise<void>\n }\n /** Adds a row to the section's table from a patch under declared names; resolves to its row id. */\n addRecord: (patch: GristRecordPatch<TMapped>) => Promise<number>\n /** The section's table id. */\n currentTableId: string | null\n\n /** Any table as rows (full access). */\n fetchTableRows: <T extends Record<string, unknown> = Record<string, unknown>>(\n tableId: string,\n options?: Parameters<GristApi[\"fetchTableRows\"]>[1]\n ) => Promise<GristRowRecord<T>[]>\n\n /** The last write's state. */\n actionStatus: GristWidgetActionStatus\n actionError: string | null\n\n /** The options Grist stores for this widget, null until it sends them. */\n widgetOptions: Record<string, unknown> | null\n}\n\ntype GristContextValue = { runtime: GristRuntime; api: GristApi }\n\nconst GristContext = createContext<GristContextValue | null>(null)\nGristContext.displayName = \"GristContext\"\n\n/** @internal The provider's (or the page's) runtime, for the SDK's own components. */\nexport function useGristRuntime(): GristContextValue | null {\n return useContext(GristContext)\n}\n\nfunction newConnection(options: UseGristOptions | undefined): GristContextValue {\n const runtime = createGristRuntime(options)\n return { runtime, api: createGristApi(runtime) }\n}\n\nlet pageConnection: GristContextValue | null = null\n\n/** @internal Tests: forget the page's connection and every Grist binding. */\nexport function resetGristForTests(): void {\n pageConnection = null\n resetGristReady()\n for (const s of ALL_STREAMS) s.reset()\n}\n\nexport const GristContextProvider = GristContext.Provider\nexport { newConnection }\n\nconst serverState = () => initialRuntimeState()\n\n/** The connection's state, re-rendering on every change. */\nexport function useGristState(connection: GristContextValue): GristRuntimeState {\n const { runtime } = connection\n useEffect(() => runtime.start(), [runtime])\n return useSyncExternalStore(runtime.subscribe, runtime.getState, serverState)\n}\n\ntype Mapped<TMapped> = { record: TMapped | null; records: TMapped[] | null; issues: readonly GristCellIssue[] }\n\nconst NO_ISSUES: readonly GristCellIssue[] = Object.freeze([])\n\n/** The mapped, checked record and records; recomputed only when they, the mappings or the options change. */\nfunction useMapped<TMapped>(state: GristRuntimeState, options: GristRuntimeOptions): Mapped<TMapped> {\n const { record, records, mappings } = state\n const { columns, schema } = options\n return useMemo(() => {\n const issues: GristCellIssue[] = []\n const rows =\n records && (columns?.length ? mappings !== null : true)\n ? records.map((r) => {\n const out = mapAndCheck<TMapped>(r, columns, mappings, schema)\n issues.push(...out.issues)\n return out.value\n })\n : null\n const selected = mapAndCheck<TMapped>(record, columns, mappings, schema)\n if (record && !records?.some((r) => r.id === record.id)) issues.push(...selected.issues)\n const mappedRecords = rows && rows.every((r) => r !== null) ? (rows as TMapped[]) : null\n return { record: selected.value, records: mappedRecords, issues: issues.length ? issues : NO_ISSUES }\n }, [record, records, mappings, columns, schema])\n}\n\ntype RecordWrites = Pick<UseGristResult, \"updateRecord\" | \"addRecord\">\n\n/** `updateRecord` / `addRecord`: stable, reading the mappings and the selection when called. */\nfunction recordWrites(connection: GristContextValue): RecordWrites {\n const { runtime, api } = connection\n const fieldsOf = (patch: Record<string, unknown>) => {\n const { id: _id, ...rest } = patch\n return mapBackPatch(rest, runtime.getState().mappings ?? EMPTY_MAPPINGS, runtime.options.columns).fields\n }\n const updateRecord = ((a: number | Record<string, unknown>, b?: Record<string, unknown>) => {\n const rowId = typeof a === \"number\" ? a : runtime.getState().record?.id\n const patch = typeof a === \"number\" ? (b ?? {}) : a\n if (typeof rowId !== \"number\") {\n return Promise.reject(new Error(\"updateRecord(): no row is selected. Pass the row id: updateRecord(rowId, patch).\"))\n }\n return api.table.update({ id: rowId, fields: fieldsOf(patch) })\n }) as RecordWrites[\"updateRecord\"]\n const addRecord = async (patch: Record<string, unknown>) => {\n const created = await api.table.create({ fields: fieldsOf(patch) })\n return (Array.isArray(created) ? created[0]! : created).id\n }\n return { updateRecord, addRecord }\n}\n\nfunction buildResult<TRow, TMapped>(\n state: GristRuntimeState,\n mapped: Mapped<TMapped>,\n connection: GristContextValue,\n mapBack: (patch: Partial<TMapped>) => Record<string, unknown>,\n resolveMappedColumnId: (name: string) => string,\n writes: RecordWrites\n): UseGristResult<TRow, TMapped> {\n const { runtime, api } = connection\n const status = deriveStatus(state)\n const columns = runtime.options.columns\n return {\n ...api,\n status,\n isAvailable: state.connection === \"connecting\" ? null : state.connection !== \"not-embedded\" && state.connection !== \"unavailable\",\n isReady: status === \"ready\",\n error: deriveError(state),\n theme: state.theme,\n record: state.record as GristRowRecord<TRow> | null,\n records: state.records as GristRowRecord<TRow>[] | null,\n mappedRecord: mapped.record,\n mappedRecords: mapped.records,\n cellIssues: mapped.issues,\n mappings: state.mappings ?? EMPTY_MAPPINGS,\n columnMappingStatus: deriveColumnMappingStatus(columns, state.mappings),\n mode: state.isNewRecord ? \"new-row\" : state.record ? \"row\" : \"empty\",\n resolveMappedColumnId,\n mapBack,\n updateRecord: writes.updateRecord as UseGristResult<TRow, TMapped>[\"updateRecord\"],\n addRecord: writes.addRecord as UseGristResult<TRow, TMapped>[\"addRecord\"],\n currentTableId: state.currentTableId,\n actionStatus: state.actionStatus,\n actionError: state.actionError,\n widgetOptions: state.widgetOptions,\n }\n}\n\nconst EMPTY_MAPPINGS: GristWidgetColumnMap = Object.freeze({}) as GristWidgetColumnMap\n\nfunction useGristResult<TRow, TMapped>(connection: GristContextValue): UseGristResult<TRow, TMapped> {\n const state = useGristState(connection)\n const mappings = state.mappings ?? EMPTY_MAPPINGS\n const { runtime } = connection\n const resolveMappedColumnId = useCallback(\n (name: string) => {\n const real = mappings[name]\n if (typeof real === \"string\" && real) return real\n if (Array.isArray(real) && typeof real[0] === \"string\") return real[0]\n return name\n },\n [mappings]\n )\n const mapBack = useCallback(\n (patch: Partial<TMapped>) => {\n const { fields, skipped } = mapBackPatch(patch as Record<string, unknown>, mappings, runtime.options.columns)\n const previous = runtime.getState().mapBackSkipped\n if (previous.join(\"\\0\") !== skipped.join(\"\\0\")) runtime.update({ mapBackSkipped: skipped })\n return fields\n },\n [mappings, runtime]\n )\n const mapped = useMapped<TMapped>(state, runtime.options)\n const writes = useMemo(() => recordWrites(connection), [connection])\n return useMemo(\n () => buildResult<TRow, TMapped>(state, mapped, connection, mapBack, resolveMappedColumnId, writes),\n [state, mapped, connection, mapBack, resolveMappedColumnId, writes]\n )\n}\n\n/**\n * The widget's Grist state and API. Inside `<GristWidgetProvider>` it uses the\n * provider's connection and ignores `options`; outside one, the page's, made\n * with the first caller's `options`.\n */\nexport function useGrist<TRow = Record<string, unknown>, TMapped = Record<string, unknown>>(\n options?: UseGristOptions\n): UseGristResult<TRow, TMapped> {\n const fromProvider = useContext(GristContext)\n const connection = fromProvider ?? (pageConnection ??= newConnection(options))\n return useGristResult<TRow, TMapped>(connection)\n}\n\n/** `useGrist()` inside a provider, or null outside one: for components that also work without Grist. */\nexport function useGristOptional<TRow = Record<string, unknown>, TMapped = Record<string, unknown>>(): UseGristResult<\n TRow,\n TMapped\n> | null {\n const fromProvider = useContext(GristContext)\n // The hooks below run in both branches; the provider only decides which connection they read.\n const result = useGristResult<TRow, TMapped>(fromProvider ?? DETACHED)\n return fromProvider ? result : null\n}\n\n/** `useGrist()` inside `<GristWidgetProvider>`; throws outside one. */\nexport function useGristContext<TRow = Record<string, unknown>, TMapped = Record<string, unknown>>(): UseGristResult<\n TRow,\n TMapped\n> {\n if (!useContext(GristContext)) {\n throw new Error(\"useGristContext() must be used inside <GristWidgetProvider> (mountGristWidget renders one).\")\n }\n return useGrist<TRow, TMapped>()\n}\n\n/** A connection that never starts: what useGristOptional reads outside a provider. */\nconst DETACHED: GristContextValue = (() => {\n const state = initialRuntimeState()\n const runtime: GristRuntime = {\n options: {},\n getState: () => state,\n subscribe: () => () => {},\n start: () => () => {},\n reload: async () => {},\n update: () => {},\n }\n return { runtime, api: createGristApi(runtime) }\n})()\n\n/** @internal The nearest provider's connection and its state (idle outside one). */\nexport function useNearestGristState(): {\n connection: GristContextValue | null\n state: GristRuntimeState\n cellIssues: readonly GristCellIssue[]\n} {\n const connection = useContext(GristContext)\n const state = useGristState(connection ?? DETACHED)\n const { issues } = useMapped(state, (connection ?? DETACHED).runtime.options)\n return { connection, state, cellIssues: issues }\n}\n","/**\n * Encoding helpers for Grist cell values.\n *\n * Grist sends some types as marshalled tuples or numeric epochs. This file\n * exposes pure decode/encode functions so widget code never has to spelunk\n * Grist's wire format.\n *\n * References: Grist `grist/RowRecord` and `grist/DocActions` typings.\n */\n\nimport type { GristReplicaColumn } from \"../types\"\n\n/** `[\"E\", \"ErrorClass\", \"message\", traceback?]` — Grist error sentinel. */\nexport type GristEncodedError = [\"E\", string, string?, string?]\n/** `[\"L\", ...items]` — list (used for ChoiceList, RefList, Attachments). */\nexport type GristEncodedList = [\"L\", ...unknown[]]\n/** `[\"D\", epochSeconds, \"tz/Name\"]` — DateTime with timezone. */\nexport type GristEncodedDateTime = [\"D\", number, string]\n/** `[\"d\", epochSeconds]` — Date (no time). */\nexport type GristEncodedDate = [\"d\", number]\n/** `[\"R\", tableId, rowId]` — explicit reference. */\nexport type GristEncodedRef = [\"R\", string, number]\n/** `[\"r\", rowId]` — bare reference (when table is contextual). */\nexport type GristEncodedBareRef = [\"r\", number]\n/** `[\"P\", encoded]` — pending marker. */\nexport type GristEncodedPending = [\"P\"]\n\nexport type GristDecodedValue =\n | null\n | string\n | number\n | boolean\n | Date\n | GristDecodedValue[]\n | { __error: true; type: string; message?: string; traceback?: string }\n | { __ref: true; tableId?: string; rowId: number }\n\nconst MARSHALLED_TAGS = new Set([\"E\", \"L\", \"D\", \"d\", \"R\", \"r\", \"P\"])\n\nfunction isMarshalledTuple(value: unknown): value is unknown[] {\n return (\n Array.isArray(value) &&\n typeof value[0] === \"string\" &&\n value[0].length <= 2 &&\n MARSHALLED_TAGS.has(value[0])\n )\n}\n\n/**\n * Normalises a Grist `fetchTable` cell that points at a row in another table.\n * Most payloads use a bare numeric row id, but `Ref:*` values may appear as\n * `[\"R\", tableId, rowId]` or `[\"r\", rowId]` (same shape as {@link decodeGristValue}).\n */\nexport function coerceGristDocApiRefRowId(value: unknown): number | undefined {\n if (typeof value === \"number\" && Number.isFinite(value)) return value\n if (!Array.isArray(value) || value.length < 2) return undefined\n const tag = value[0]\n if (tag === \"R\" && typeof value[2] === \"number\" && Number.isFinite(value[2])) return value[2]\n if (tag === \"r\" && typeof value[1] === \"number\" && Number.isFinite(value[1])) return value[1]\n return undefined\n}\n\nfunction looksLikeAttachmentColumn(column?: GristReplicaColumn): boolean {\n return column?.type === \"Attachments\"\n}\n\nfunction looksLikeChoiceListColumn(column?: GristReplicaColumn): boolean {\n return column?.type === \"ChoiceList\"\n}\n\nfunction looksLikeRefListColumn(column?: GristReplicaColumn): boolean {\n return typeof column?.type === \"string\" && column.type.startsWith(\"RefList:\")\n}\n\nfunction looksLikeRefColumn(column?: GristReplicaColumn): boolean {\n return typeof column?.type === \"string\" && column.type.startsWith(\"Ref:\")\n}\n\nfunction looksLikeDateColumn(column?: GristReplicaColumn): boolean {\n return column?.type === \"Date\"\n}\n\nfunction looksLikeDateTimeColumn(column?: GristReplicaColumn): boolean {\n return typeof column?.type === \"string\" && column.type.startsWith(\"DateTime\")\n}\n\n/**\n * Decodes a Grist cell value into an idiomatic JS value.\n *\n * Pass the column's metadata (from `useGristSchema` or `_grist_Tables_column`)\n * for type-aware decoding (e.g. `Date` columns return `Date` even when stored as a number).\n */\nexport function decodeGristValue(value: unknown, column?: GristReplicaColumn): GristDecodedValue {\n if (value === null || value === undefined) return null\n\n if (isMarshalledTuple(value)) {\n const tag = value[0] as string\n switch (tag) {\n case \"E\":\n return {\n __error: true,\n type: typeof value[1] === \"string\" ? value[1] : \"Error\",\n message: typeof value[2] === \"string\" ? value[2] : undefined,\n traceback: typeof value[3] === \"string\" ? value[3] : undefined,\n }\n case \"L\":\n return value.slice(1).map((v) => decodeGristValue(v, undefined)) as GristDecodedValue[]\n case \"D\":\n if (typeof value[1] === \"number\") return new Date(value[1] * 1000)\n return null\n case \"d\":\n if (typeof value[1] === \"number\") return new Date(value[1] * 1000)\n return null\n case \"R\":\n return {\n __ref: true,\n tableId: typeof value[1] === \"string\" ? value[1] : undefined,\n rowId: typeof value[2] === \"number\" ? value[2] : 0,\n }\n case \"r\":\n return { __ref: true, rowId: typeof value[1] === \"number\" ? value[1] : 0 }\n case \"P\":\n return null\n default:\n return null\n }\n }\n\n if (looksLikeDateColumn(column) || looksLikeDateTimeColumn(column)) {\n if (typeof value === \"number\" && Number.isFinite(value)) return new Date(value * 1000)\n }\n\n if (looksLikeRefColumn(column) && typeof value === \"number\") {\n return { __ref: true, rowId: value }\n }\n\n if ((looksLikeRefListColumn(column) || looksLikeChoiceListColumn(column) || looksLikeAttachmentColumn(column)) && Array.isArray(value)) {\n return value.map((v) => decodeGristValue(v, undefined)) as GristDecodedValue[]\n }\n\n if (typeof value === \"string\" || typeof value === \"number\" || typeof value === \"boolean\") return value\n if (Array.isArray(value)) return value.map((v) => decodeGristValue(v, undefined)) as GristDecodedValue[]\n return null\n}\n\n/** Convenience: true when the cell is a Grist error sentinel. */\nexport function isGristCellError(value: unknown): value is GristEncodedError {\n return Array.isArray(value) && value[0] === \"E\"\n}\n\n/**\n * Encodes a JS value into Grist's expected wire form for a given column type.\n *\n * Use before passing values to `applyUserActions` or `TableOperations.update`\n * for `Date`, `DateTime`, `Ref`, `RefList`, and `ChoiceList` columns.\n */\nexport function encodeGristValue(value: unknown, column?: GristReplicaColumn): unknown {\n if (value === null || value === undefined) return null\n\n if (looksLikeDateColumn(column) || looksLikeDateTimeColumn(column)) {\n if (value instanceof Date) return Math.floor(value.getTime() / 1000)\n if (typeof value === \"string\") {\n const parsed = Date.parse(value)\n if (!Number.isNaN(parsed)) return Math.floor(parsed / 1000)\n }\n if (typeof value === \"number\") return Math.floor(value)\n }\n\n if (looksLikeRefColumn(column)) {\n if (typeof value === \"number\") return value\n if (value && typeof value === \"object\" && \"rowId\" in value) {\n return (value as { rowId: number }).rowId\n }\n }\n\n if (looksLikeRefListColumn(column) || looksLikeChoiceListColumn(column) || looksLikeAttachmentColumn(column)) {\n if (Array.isArray(value)) {\n const items = value.map((v) => {\n if (v && typeof v === \"object\" && \"rowId\" in v) return (v as { rowId: number }).rowId\n return v\n })\n return [\"L\", ...items]\n }\n }\n\n return value\n}\n","import type { GristDocApi, GristReplicaColumn, GristRowRecord } from \"../types\"\nimport { decodeGristValue } from \"./grist-value-codec\"\n\n/** Column-oriented table payload (`fetchTable`, `fetchSelectedTable`): `{ id: [...], Name: [...] }`. */\nexport type GristColumnarTable = Record<string, unknown[]>\nexport type GristTableRowsOrder = \"none\" | \"id\" | \"grist\"\nexport type FetchGristTableRowsOptions = {\n /** Column metadata, to decode each cell (except `id`) with `decodeGristValue`. */\n columns?: Record<string, GristReplicaColumn>\n /**\n * Row order:\n * - `grist` (default): `manualSort` ascending when present, then `id`.\n * - `id`: numeric `id` ascending.\n * - `none`: as `fetchTable` returned them.\n */\n order?: GristTableRowsOrder\n}\n\n/** Row count from columnar `fetchTable` data (prefers `id` column length). */\nexport function computeRowCount(data: Record<string, unknown[]>): number {\n const idCol = data.id\n if (Array.isArray(idCol)) return idCol.length\n for (const key of Object.keys(data)) {\n const col = data[key]\n if (Array.isArray(col)) return col.length\n }\n return 0\n}\n\n/**\n * Decode columnar `fetchTable` into replica row objects (`{ id, ...cells }`, one per row).\n */\nexport function decodeColumnarToReplicaRows(\n data: GristColumnarTable,\n columnIds: string[],\n columns: Record<string, GristReplicaColumn>,\n maxRows?: number\n): GristRowRecord[] {\n const nFull = computeRowCount(data)\n const n = maxRows !== undefined ? Math.min(nFull, maxRows) : nFull\n const out: GristRowRecord[] = []\n for (let i = 0; i < n; i++) {\n const row: Record<string, unknown> = {}\n for (const k of columnIds) {\n const arr = data[k]\n const raw = Array.isArray(arr) ? arr[i] : undefined\n if (k === \"id\") {\n row[k] = raw\n } else {\n row[k] = decodeGristValue(raw, columns[k]) as unknown\n }\n }\n out.push(row as GristRowRecord)\n }\n return out\n}\n\n/** Turn `fetchTable` output into row objects (order follows the `id` column). */\nexport function tableDataToRows<T = Record<string, unknown>>(\n data: GristColumnarTable\n): GristRowRecord<T>[] {\n const idCol = data.id\n if (!Array.isArray(idCol) || idCol.length === 0) return []\n const keys = Object.keys(data)\n const n = idCol.length\n const rows: GristRowRecord<T>[] = []\n for (let i = 0; i < n; i++) {\n const row: Record<string, unknown> = {}\n for (const k of keys) {\n const col = data[k]\n row[k] = Array.isArray(col) ? col[i] : undefined\n }\n rows.push(row as GristRowRecord<T>)\n }\n return rows\n}\n\nfunction manualSortKey(row: Record<string, unknown>): number | null {\n const v = row.manualSort\n if (typeof v === \"number\" && !Number.isNaN(v)) return v\n if (typeof v === \"string\" && v.trim() !== \"\") {\n const n = Number(v)\n if (!Number.isNaN(n)) return n\n }\n return null\n}\n\n/**\n * Sort rows by Grist's display order: `manualSort` ascending when present on\n * any row, otherwise numeric `id` ascending.\n */\nexport function sortRowsByGristOrder<T = Record<string, unknown>>(\n rows: readonly GristRowRecord<T>[]\n): GristRowRecord<T>[] {\n const hasManual = rows.some((r) => manualSortKey(r as Record<string, unknown>) !== null)\n if (!hasManual) {\n return [...rows].sort((a, b) => {\n const ida = typeof a.id === \"number\" ? a.id : 0\n const idb = typeof b.id === \"number\" ? b.id : 0\n return ida - idb\n })\n }\n return [...rows].sort((a, b) => {\n const ma = manualSortKey(a as Record<string, unknown>)\n const mb = manualSortKey(b as Record<string, unknown>)\n if (ma !== null && mb !== null && ma !== mb) return ma - mb\n if (ma !== null && mb === null) return -1\n if (ma === null && mb !== null) return 1\n const ida = typeof a.id === \"number\" ? a.id : 0\n const idb = typeof b.id === \"number\" ? b.id : 0\n return ida - idb\n })\n}\n\n/**\n * Same row materialization as {@link fetchGristTableRows} after `fetchTable`\n * returns columnar data. Hosts that already have columnar data (e.g. the\n * emulator building from in-memory rows) can use this and skip `docApi.fetchTable`.\n */\nexport function materializeGristRowsFromColumnar<T extends Record<string, unknown> = Record<string, unknown>>(\n data: GristColumnarTable,\n options?: FetchGristTableRowsOptions\n): GristRowRecord<T>[] {\n const order = options?.order ?? \"grist\"\n let rows: GristRowRecord<T>[]\n if (options?.columns) {\n const columnIds = Object.keys(data)\n rows = decodeColumnarToReplicaRows(data, columnIds, options.columns) as GristRowRecord<T>[]\n } else {\n rows = tableDataToRows<T>(data)\n }\n\n if (order === \"none\") return rows\n if (order === \"id\") {\n return [...rows].sort((a, b) => {\n const ida = typeof a.id === \"number\" ? a.id : 0\n const idb = typeof b.id === \"number\" ? b.id : 0\n return ida - idb\n })\n }\n return sortRowsByGristOrder(rows)\n}\n\n/**\n * Fetch a table and return rows as objects, optionally decoded from schema and sorted.\n */\nexport async function fetchGristTableRows<T extends Record<string, unknown> = Record<string, unknown>>(\n docApi: GristDocApi,\n tableId: string,\n options?: FetchGristTableRowsOptions\n): Promise<GristRowRecord<T>[]> {\n const data = (await docApi.fetchTable(tableId)) as GristColumnarTable\n return materializeGristRowsFromColumnar<T>(data, options)\n}\n","/**\n * Grist stores column widget configuration in `_grist_Tables_column.widgetOptions`\n * as a JSON string. Choice fields use `choices: string[]` plus optional\n * `choiceOptions: Record<string, Style>` (e.g. `fillColor`, `textColor`).\n *\n * @see https://github.com/gristlabs/grist-core/blob/main/app/client/widgets/ChoiceEditor.js\n */\n\n/** One selectable choice for UI (value stored in the cell is `value`). */\nexport type GristChoiceListEntry = {\n value: string\n label: string\n fillColor?: string\n textColor?: string\n}\n\n/**\n * Parse a cell value from `_grist_Tables_column.widgetOptions` into a plain object.\n */\nexport function parseGristWidgetOptionsCell(raw: unknown): Record<string, unknown> | undefined {\n if (raw == null || raw === \"\") return undefined\n if (typeof raw === \"string\") {\n try {\n const parsed: unknown = JSON.parse(raw)\n if (parsed && typeof parsed === \"object\" && !Array.isArray(parsed)) {\n return parsed as Record<string, unknown>\n }\n } catch {\n return undefined\n }\n return undefined\n }\n if (typeof raw === \"object\" && !Array.isArray(raw)) {\n return raw as Record<string, unknown>\n }\n return undefined\n}\n\nfunction readStyleColor(style: Record<string, unknown>, key: string): string | undefined {\n const v = style[key]\n return typeof v === \"string\" ? v : undefined\n}\n\n/**\n * Normalizes Grist Choice / ChoiceList widgetOptions into a flat list for dropdowns.\n * `choices` entries are string labels (the stored cell value). Per-choice styling\n * lives in `choiceOptions[label]`.\n */\nexport function normalizeGristChoiceListEntries(\n widgetOptions: Record<string, unknown> | undefined\n): GristChoiceListEntry[] {\n if (!widgetOptions) return []\n const rawChoices = widgetOptions.choices\n if (!Array.isArray(rawChoices)) return []\n\n const choiceOptionsRaw = widgetOptions.choiceOptions\n const choiceOptions: Record<string, Record<string, unknown>> =\n choiceOptionsRaw &&\n typeof choiceOptionsRaw === \"object\" &&\n !Array.isArray(choiceOptionsRaw)\n ? (choiceOptionsRaw as Record<string, Record<string, unknown>>)\n : {}\n\n const out: GristChoiceListEntry[] = []\n for (const c of rawChoices) {\n const value = typeof c === \"string\" ? c : c != null ? String(c) : \"\"\n if (!value) continue\n const style = choiceOptions[value] ?? {}\n out.push({\n value,\n label: value,\n fillColor: readStyleColor(style, \"fillColor\"),\n textColor: readStyleColor(style, \"textColor\"),\n })\n }\n return out\n}\n","import type {\n GristDocApi,\n GristDocumentMode,\n GristReplicaColumn,\n GristReplicaDocument,\n GristReplicaTable,\n} from \"../types\"\nimport { computeRowCount, decodeColumnarToReplicaRows, type GristColumnarTable } from \"./grist-table-data\"\nimport { inferGristFormulaKind } from \"./grist-schema-formula\"\nimport { parseGristWidgetOptionsCell } from \"./grist-widget-options\"\nimport { coerceGristDocApiRefRowId } from \"./grist-value-codec\"\n\nexport type ReplicaTableColumnMetaLite = {\n colRef?: number\n type?: string\n label?: string\n parentPos?: number\n isFormula?: boolean\n formula?: string\n description?: string\n widgetOptions?: Record<string, unknown>\n displayColRef?: number\n visibleColRef?: number\n}\n\nconst FORMULA_PREVIEW_MAX = 500\n\nfunction readCellStr(table: Record<string, unknown[]>, key: string, rowIndex: number): string | undefined {\n const col = table[key]\n if (!Array.isArray(col)) return undefined\n const v = col[rowIndex]\n if (v === null || v === undefined) return undefined\n if (typeof v === \"string\") return v\n if (typeof v === \"number\" || typeof v === \"boolean\") return String(v)\n return undefined\n}\n\nfunction readCellNum(table: Record<string, unknown[]>, key: string, rowIndex: number): number | undefined {\n const col = table[key]\n if (!Array.isArray(col)) return undefined\n const v = col[rowIndex]\n if (typeof v === \"number\" && !Number.isNaN(v)) return v\n if (typeof v === \"string\" && v.trim() !== \"\") {\n const n = Number(v)\n if (!Number.isNaN(n)) return n\n }\n return undefined\n}\n\nfunction pickColumnMeta(meta: ReplicaTableColumnMetaLite | undefined): GristReplicaColumn {\n if (!meta) return {}\n const out: GristReplicaColumn = {}\n if (meta.colRef !== undefined) out.colRef = meta.colRef\n if (meta.type) out.type = meta.type\n if (meta.label) out.label = meta.label\n if (meta.parentPos !== undefined) out.parentPos = meta.parentPos\n if (meta.isFormula) out.isFormula = true\n const formulaRaw = meta.formula?.trim() ?? \"\"\n out.formulaKind = inferGristFormulaKind(Boolean(meta.isFormula), formulaRaw)\n if (formulaRaw) {\n out.formula =\n formulaRaw.length > FORMULA_PREVIEW_MAX ? `${formulaRaw.slice(0, FORMULA_PREVIEW_MAX)}...` : formulaRaw\n }\n if (meta.description) out.description = meta.description\n if (meta.widgetOptions && Object.keys(meta.widgetOptions).length > 0) {\n out.widgetOptions = meta.widgetOptions\n }\n if (meta.displayColRef !== undefined) out.displayColRef = meta.displayColRef\n if (meta.visibleColRef !== undefined) out.visibleColRef = meta.visibleColRef\n return out\n}\n\nexport async function loadColumnMetadataByTable(\n docApi: GristDocApi\n): Promise<Map<string, Map<string, ReplicaTableColumnMetaLite>>> {\n const byTable = new Map<string, Map<string, ReplicaTableColumnMetaLite>>()\n try {\n const tables = await docApi.fetchTable(\"_grist_Tables\")\n const columns = await docApi.fetchTable(\"_grist_Tables_column\")\n const tableIds = tables.tableId\n const tableInternalIds = tables.id\n if (!Array.isArray(tableIds) || !Array.isArray(tableInternalIds)) return byTable\n\n const internalIdToTableId = new Map<number, string>()\n for (let i = 0; i < tableInternalIds.length; i++) {\n const tid = tableIds[i]\n const iid = coerceGristDocApiRefRowId(tableInternalIds[i])\n if (typeof tid === \"string\" && iid !== undefined) internalIdToTableId.set(iid, tid)\n }\n\n const parentIds = columns.parentId\n const colIds = columns.colId\n const columnIds = columns.id\n if (\n !Array.isArray(parentIds) ||\n !Array.isArray(colIds) ||\n !Array.isArray(columnIds) ||\n parentIds.length !== colIds.length ||\n colIds.length !== columnIds.length\n ) {\n return byTable\n }\n\n const n = parentIds.length\n for (let i = 0; i < n; i++) {\n const parentRowId = coerceGristDocApiRefRowId(parentIds[i])\n const colRef = coerceGristDocApiRefRowId(columnIds[i])\n const colId = colIds[i]\n if (parentRowId === undefined || colRef === undefined || typeof colId !== \"string\") continue\n const tableId = internalIdToTableId.get(parentRowId)\n if (!tableId) continue\n\n let colMap = byTable.get(tableId)\n if (!colMap) {\n colMap = new Map()\n byTable.set(tableId, colMap)\n }\n\n const parentPos = readCellNum(columns, \"parentPos\", i)\n const isFormulaCol = columns.isFormula\n const isFormula = Array.isArray(isFormulaCol) ? Boolean(isFormulaCol[i]) : false\n\n const woCol = columns.widgetOptions\n const widgetOptions =\n Array.isArray(woCol) && i < woCol.length ? parseGristWidgetOptionsCell(woCol[i]) : undefined\n const displayColRef = coerceGristDocApiRefRowId(\n Array.isArray(columns.displayCol) ? columns.displayCol[i] : undefined\n )\n const visibleColRef = coerceGristDocApiRefRowId(\n Array.isArray(columns.visibleCol) ? columns.visibleCol[i] : undefined\n )\n\n colMap.set(colId, {\n colRef,\n type: readCellStr(columns, \"type\", i),\n label: readCellStr(columns, \"label\", i),\n parentPos: parentPos !== undefined ? parentPos : undefined,\n isFormula,\n formula: readCellStr(columns, \"formula\", i),\n description: readCellStr(columns, \"description\", i) ?? readCellStr(columns, \"descr\", i),\n widgetOptions,\n displayColRef,\n visibleColRef,\n })\n }\n } catch {\n // Metadata is best-effort; document build still works from cell data alone.\n }\n return byTable\n}\n\nexport function orderedColumnIds(\n data: Record<string, unknown[]>,\n metaByCol: Map<string, ReplicaTableColumnMetaLite>\n): string[] {\n const keys = Object.keys(data).filter((k) => Array.isArray(data[k]))\n keys.sort((a, b) => {\n const pa = metaByCol.get(a)?.parentPos\n const pb = metaByCol.get(b)?.parentPos\n if (pa !== undefined && pb !== undefined && pa !== pb) return pa - pb\n if (pa !== undefined && pb === undefined) return -1\n if (pa === undefined && pb !== undefined) return 1\n return a.localeCompare(b)\n })\n return keys\n}\n\n/** Build replica column metadata from columnar `fetchTable` + `_grist_Tables_column` maps. */\nexport function buildReplicaColumnsFromColumnar(\n data: Record<string, unknown[]>,\n colMeta: Map<string, ReplicaTableColumnMetaLite>\n): Record<string, GristReplicaColumn> {\n const columnIds = orderedColumnIds(data, colMeta)\n const columns: Record<string, GristReplicaColumn> = {}\n for (const colId of columnIds) {\n const arr = data[colId]\n if (!Array.isArray(arr)) continue\n const meta = colMeta.get(colId)\n columns[colId] = pickColumnMeta(meta)\n }\n return columns\n}\n\nfunction rowModeFromIncludeRows(includeRows: false | \"samples\" | \"full\"): GristDocumentMode {\n if (includeRows === false) return \"schema-only\"\n if (includeRows === \"samples\") return \"schema+samples\"\n return \"schema+data\"\n}\n\nexport type BuildReplicaDocumentFromDocApiOptions = {\n /** When false (default), skip fetching row data for `tableId` starting with `_grist`. */\n includeSystemTableData?: boolean\n /**\n * Row bodies: omit (`false`), first N (`samples`), or full decode (`full`).\n * Default `samples`.\n */\n includeRows?: false | \"samples\" | \"full\"\n /** Max rows per table when `includeRows` is `samples`. Default 10. */\n sampleRowLimit?: number\n /** Set on the replica as `source` for host logging / provenance. */\n source?: string\n}\n\n/**\n * Build {@link GristReplicaDocument} from a host `docApi`:\n * metadata from `_grist_Tables` / `_grist_Tables_column` when readable, plus optional decoded `rows`.\n *\n * Prefer {@link useGrist}'s `buildReplicaDocumentFromDocApi()` when you already use the primary hook.\n */\nexport async function buildReplicaDocumentFromDocApi(\n docApi: GristDocApi,\n options?: BuildReplicaDocumentFromDocApiOptions\n): Promise<GristReplicaDocument> {\n const includeSystemTableData = options?.includeSystemTableData ?? false\n const includeRows = options?.includeRows ?? \"samples\"\n const sampleRowLimit = options?.sampleRowLimit ?? 10\n const rowMode = rowModeFromIncludeRows(includeRows)\n\n const metaByTable = await loadColumnMetadataByTable(docApi)\n\n let docName: string | undefined\n try {\n docName = String(await Promise.resolve(docApi.getDocName()))\n } catch {\n docName = undefined\n }\n\n const tableIdsRaw = await Promise.resolve(docApi.listTables())\n const tableIds = Array.isArray(tableIdsRaw) ? [...tableIdsRaw] : []\n\n const tables: Record<string, GristReplicaTable> = {}\n\n for (const tableId of tableIds) {\n const omitData = !includeSystemTableData && tableId.startsWith(\"_grist\")\n if (omitData) {\n tables[tableId] = {\n rowCount: 0,\n dataOmitted: true,\n dataOmittedReason:\n \"Row scan skipped for tables whose id starts with `_grist` unless `includeSystemTableData` is true.\",\n columns: {},\n }\n continue\n }\n\n try {\n const data = (await docApi.fetchTable(tableId)) as GristColumnarTable\n const rowCount = computeRowCount(data)\n const colMeta = metaByTable.get(tableId) ?? new Map<string, ReplicaTableColumnMetaLite>()\n const columnIds = orderedColumnIds(data, colMeta)\n const columns = buildReplicaColumnsFromColumnar(data, colMeta)\n\n const table: GristReplicaTable = { columns, rowCount }\n if (includeRows === \"full\") {\n table.rows = decodeColumnarToReplicaRows(data, columnIds, columns)\n } else if (includeRows === \"samples\") {\n table.rows = decodeColumnarToReplicaRows(data, columnIds, columns, sampleRowLimit)\n }\n tables[tableId] = table\n } catch (err) {\n tables[tableId] = {\n rowCount: 0,\n error: err instanceof Error ? err.message : String(err),\n columns: {},\n }\n }\n }\n\n const out: GristReplicaDocument = {\n generatedAt: new Date().toISOString(),\n docName,\n mode: rowMode,\n tables,\n }\n if (options?.source !== undefined && options.source !== \"\") {\n out.source = options.source\n }\n return out\n}\n","export type GristColumnLike = {\n formula?: string\n}\n\nexport type GristNoiseColumnsOptions = {\n excludeId?: boolean\n excludeGristHelpers?: boolean\n excludeLoggingColumns?: boolean\n /**\n * When `true`, treat Grist's `manualSort` column as noise (omit from filtered replicas).\n * Default `false` — `manualSort` is kept unless you opt in.\n */\n excludeManualSort?: boolean\n}\n\nconst NOISE_COLUMN_FORMULAS = new Set([\"now()\"])\n\nfunction normalizeFormulaForComparison(formula: string): string {\n return formula.trim().toLowerCase().replace(/\\s+/g, \"\")\n}\n\n/**\n * Grist-centric \"technical column\" detection used by document hooks and widgets.\n *\n * - `id` (when {@link GristNoiseColumnsOptions.excludeId} is true — default)\n * - `manualSort` (only when {@link GristNoiseColumnsOptions.excludeManualSort} is true)\n * - `gristHelper_*` (when `excludeGristHelpers` is true — default)\n * - trigger/logging formulas (`NOW()`, `user.*`) (when `excludeLoggingColumns` is true — default)\n */\nexport function isGristNoiseColumn(\n colId: string,\n col?: GristColumnLike,\n options?: GristNoiseColumnsOptions\n): boolean {\n const excludeId = options?.excludeId ?? true\n const excludeGristHelpers = options?.excludeGristHelpers ?? true\n const excludeLoggingColumns = options?.excludeLoggingColumns ?? true\n const excludeManualSort = options?.excludeManualSort ?? false\n\n if (excludeId && colId === \"id\") return true\n if (excludeManualSort && colId === \"manualSort\") return true\n if (excludeGristHelpers && colId.startsWith(\"gristHelper_\")) return true\n\n if (excludeLoggingColumns) {\n const formula = typeof col?.formula === \"string\" ? normalizeFormulaForComparison(col.formula) : \"\"\n if (formula && NOISE_COLUMN_FORMULAS.has(formula)) return true\n if (formula.startsWith(\"user.\")) return true\n }\n\n return false\n}\n","import type { GristDocApi } from \"../types\"\n\nexport type GristFetchedAttachment = {\n base64: string\n contentType: string\n}\n\nexport type GristFetchedAttachmentBlob = {\n blob: Blob\n contentType: string\n}\n\nfunction attachmentIdFromObjectRecord(record: Record<string, unknown>): string | undefined {\n for (const candidate of [record.id, record.attachmentId, record.fileId]) {\n if (candidate === undefined || candidate === null) continue\n return String(candidate)\n }\n return undefined\n}\n\n/**\n * All attachment ids found in a Grist attachment cell value (ordered, deduped).\n * Attachment columns are usually an **array** of file refs; a single id or one JSON object is also supported.\n */\nexport function extractGristAttachmentIdsFromCell(value: unknown): string[] {\n const out: string[] = []\n const seen = new Set<string>()\n const push = (id: string) => {\n if (seen.has(id)) return\n seen.add(id)\n out.push(id)\n }\n\n const walk = (v: unknown): void => {\n if (v === undefined || v === null) return\n if (typeof v === \"number\") {\n push(String(v))\n return\n }\n if (typeof v === \"string\") {\n const trimmed = v.trim()\n if (!trimmed) return\n if (/^\\d+$/.test(trimmed)) {\n push(trimmed)\n return\n }\n try {\n walk(JSON.parse(trimmed) as unknown)\n } catch {\n /* ignore */\n }\n return\n }\n if (Array.isArray(v)) {\n for (const item of v) walk(item)\n return\n }\n if (typeof v === \"object\") {\n const record = v as Record<string, unknown>\n const direct = attachmentIdFromObjectRecord(record)\n if (direct !== undefined) {\n push(direct)\n return\n }\n for (const nested of Object.values(record)) walk(nested)\n }\n }\n\n walk(value)\n return out\n}\n\n/** First attachment id in the cell, if any (see {@link extractGristAttachmentIdsFromCell}). */\nexport function extractGristAttachmentId(value: unknown): string | undefined {\n return extractGristAttachmentIdsFromCell(value)[0]\n}\n\n/**\n * Signed Grist download URL for a single attachment id (`getAccessToken` + query auth).\n */\nexport async function getAttachmentDownloadUrl(\n docApi: GristDocApi,\n attachmentId: string,\n options?: { readOnly?: boolean }\n): Promise<string> {\n const getAccessToken = docApi.getAccessToken\n if (!getAccessToken) {\n throw new Error(\"getAccessToken is not available on docApi\")\n }\n const { token, baseUrl } = await getAccessToken({ readOnly: options?.readOnly ?? false })\n return `${baseUrl}/attachments/${attachmentId}/download?auth=${token}`\n}\n\n/** URL for the `index`’th attachment in a cell value (0-based). */\nexport async function getAttachmentDownloadUrlForCell(\n docApi: GristDocApi,\n cellValue: unknown,\n index: number,\n options?: { readOnly?: boolean }\n): Promise<string | null> {\n const ids = extractGristAttachmentIdsFromCell(cellValue)\n const id = ids[index]\n if (!id) return null\n return getAttachmentDownloadUrl(docApi, id, options)\n}\n\nasync function fetchBytesFromSignedAttachmentUrl(url: string): Promise<{\n buffer: ArrayBuffer\n contentType: string\n}> {\n const response = await fetch(url)\n const contentType = response.headers.get(\"content-type\")?.trim() || \"application/octet-stream\"\n if (!response.ok) {\n throw new Error(`Attachment download failed (${response.status})`)\n }\n const buffer = await response.arrayBuffer()\n return { buffer, contentType }\n}\n\nfunction bufferToBase64(buffer: ArrayBuffer): string {\n const bytes = new Uint8Array(buffer)\n let binary = \"\"\n for (let i = 0; i < bytes.length; i++) binary += String.fromCharCode(bytes[i])\n return btoa(binary)\n}\n\n/** Token + URL + fetch for one attachment id. */\nexport async function fetchAttachmentBase64(\n docApi: GristDocApi,\n attachmentId: string,\n options?: { readOnly?: boolean }\n): Promise<GristFetchedAttachment> {\n const url = await getAttachmentDownloadUrl(docApi, attachmentId, options)\n const { buffer, contentType } = await fetchBytesFromSignedAttachmentUrl(url)\n return { base64: bufferToBase64(buffer), contentType }\n}\n\n/** Download attachment bytes as a `Blob` (preferred for large files). */\nexport async function fetchAttachmentBlob(\n docApi: GristDocApi,\n attachmentId: string,\n options?: { readOnly?: boolean }\n): Promise<GristFetchedAttachmentBlob> {\n const url = await getAttachmentDownloadUrl(docApi, attachmentId, options)\n const { buffer, contentType } = await fetchBytesFromSignedAttachmentUrl(url)\n return { blob: new Blob([buffer], { type: contentType }), contentType }\n}\n\n/** Download the `index`’th attachment in a cell (0-based). */\nexport async function fetchAttachmentBase64ForCell(\n docApi: GristDocApi,\n cellValue: unknown,\n index: number,\n options?: { readOnly?: boolean }\n): Promise<GristFetchedAttachment | null> {\n const url = await getAttachmentDownloadUrlForCell(docApi, cellValue, index, options)\n if (!url) return null\n const { buffer, contentType } = await fetchBytesFromSignedAttachmentUrl(url)\n return { base64: bufferToBase64(buffer), contentType }\n}\n","import type { GristDocApi } from \"../types\"\n\nexport type GristAccessToken = {\n token: string\n baseUrl: string\n}\n\ntype TokenCacheEntry = {\n token: GristAccessToken\n fetchedAt: number\n}\n\nconst TOKEN_TTL_MS = 45_000\nconst cache = new Map<string, TokenCacheEntry>()\nconst inFlight = new Map<string, Promise<GristAccessToken>>()\n\nfunction cacheKey(readOnly: boolean): string {\n return readOnly ? \"ro\" : \"rw\"\n}\n\n/**\n * Returns an access token suitable for calling Grist's REST API directly.\n * Tokens are short-lived; results are cached briefly and coalesced per readOnly flag.\n */\nexport async function getGristAccessToken(\n docApi: GristDocApi,\n options?: { readOnly?: boolean }\n): Promise<GristAccessToken> {\n if (!docApi.getAccessToken) {\n throw new Error(\"getAccessToken is not available on docApi (need higher access level)\")\n }\n\n const readOnly = options?.readOnly ?? false\n const key = cacheKey(readOnly)\n const now = Date.now()\n const hit = cache.get(key)\n if (hit && now - hit.fetchedAt < TOKEN_TTL_MS) {\n return hit.token\n }\n\n const pending = inFlight.get(key)\n if (pending) return pending\n\n const next = docApi.getAccessToken({ readOnly }).then((token) => {\n cache.set(key, { token, fetchedAt: Date.now() })\n inFlight.delete(key)\n return token\n })\n\n inFlight.set(key, next)\n return next\n}\n\n/** Clear cached tokens (tests or after auth errors). */\nexport function clearGristAccessTokenCache(): void {\n cache.clear()\n inFlight.clear()\n}\n\n/**\n * `fetch()` against Grist's REST API with the doc access token attached.\n */\nexport async function fetchWithGristAuth(\n docApi: GristDocApi,\n path: string,\n init?: RequestInit & { readOnly?: boolean }\n): Promise<Response> {\n const readOnly = init?.readOnly ?? false\n let token: GristAccessToken\n try {\n token = await getGristAccessToken(docApi, { readOnly })\n } catch (err) {\n clearGristAccessTokenCache()\n throw err\n }\n\n const isAbsolute = /^https?:\\/\\//i.test(path)\n const cleanPath = isAbsolute ? path : path.startsWith(\"/\") ? path : `/${path}`\n\n const url = isAbsolute\n ? new URL(path)\n : new URL(`${token.baseUrl.replace(/\\/$/, \"\")}${cleanPath}`)\n\n // The token goes into the URL, so it may only go to the Grist instance that\n // issued it. An absolute URL to any other origin (one read from a cell, say)\n // would hand the document's access token to that host.\n const gristOrigin = new URL(token.baseUrl).origin\n if (url.origin !== gristOrigin) {\n throw new Error(\n `fetchWithGristAuth: refusing to send the Grist access token to ${url.origin}; ` +\n `absolute URLs must point at this document's Grist instance (${gristOrigin}). ` +\n `Use plain fetch() for other hosts.`\n )\n }\n\n // Grist signs widget REST calls with a short-lived `auth` query parameter.\n // Do not send `Authorization: Bearer` from the browser: many Grist deployments\n // omit it from Access-Control-Allow-Headers, which breaks POST (e.g. attachment upload).\n if (!url.searchParams.has(\"auth\")) url.searchParams.set(\"auth\", token.token)\n\n const headers = new Headers(init?.headers ?? {})\n headers.delete(\"Authorization\")\n\n const response = await fetch(url.toString(), { ...init, headers })\n if (response.status === 401) {\n clearGristAccessTokenCache()\n const retryToken = await getGristAccessToken(docApi, { readOnly })\n url.searchParams.set(\"auth\", retryToken.token)\n return fetch(url.toString(), { ...init, headers })\n }\n return response\n}\n","import type { GristDocApi } from \"../types\"\nimport { extractGristAttachmentIdsFromCell } from \"./grist-attachment-download\"\nimport { fetchWithGristAuth } from \"./grist-fetch-with-auth\"\nimport { encodeGristValue } from \"./grist-value-codec\"\n\nconst ATTACHMENTS_COLUMN = { type: \"Attachments\" as const }\n\nexport type GristEncodedAttachmentList = [\"L\", ...(number | string)[]]\n\nexport type GristAttachmentUploadResult = {\n /** All attachment ids returned by `POST /attachments`. */\n ids: string[]\n /** First id in `ids` (convenience for single-file uploads). */\n firstId: string\n}\n\n/**\n * Parse the body of `POST /attachments` (widget or REST).\n * Grist returns a JSON array of attachment ids, e.g. `[42]` or `[101, 102]`.\n */\nexport function parseGristAttachmentUploadResponseIds(\n raw: string,\n options?: { strict?: boolean }\n): string[] {\n const trimmed = raw.trim()\n if (!trimmed) {\n throw new Error(\"Attachment upload returned an empty response.\")\n }\n\n let parsed: unknown\n try {\n parsed = JSON.parse(trimmed) as unknown\n } catch {\n if (options?.strict) {\n throw new Error(\"Attachment upload returned non-JSON response.\")\n }\n parsed = trimmed\n }\n\n return extractAttachmentIdsFromUploadPayload(parsed, options)\n}\n\n/**\n * First attachment id from an upload response (see {@link parseGristAttachmentUploadResponseIds}).\n */\nexport function parseGristAttachmentUploadResponse(\n raw: string,\n options?: { strict?: boolean }\n): string {\n const ids = parseGristAttachmentUploadResponseIds(raw, options)\n return ids[0]!\n}\n\nexport function extractAttachmentIdsFromUploadPayload(\n parsed: unknown,\n options?: { strict?: boolean }\n): string[] {\n if (options?.strict) {\n return extractAttachmentIdsFromUploadPayloadStrict(parsed)\n }\n\n const first = extractFirstAttachmentIdFromUploadPayload(parsed)\n if (first !== undefined) {\n if (Array.isArray(parsed)) {\n const ids: string[] = []\n const seen = new Set<string>()\n for (const item of parsed) {\n const id = coerceAttachmentId(item)\n if (id && !seen.has(id)) {\n seen.add(id)\n ids.push(id)\n }\n }\n return ids.length > 0 ? ids : [first]\n }\n return [first]\n }\n\n throw new Error(\"Attachment upload returned an unexpected response shape.\")\n}\n\nfunction extractAttachmentIdsFromUploadPayloadStrict(parsed: unknown): string[] {\n if (typeof parsed === \"number\" && Number.isFinite(parsed)) {\n return [String(parsed)]\n }\n\n if (Array.isArray(parsed)) {\n const ids: string[] = []\n const seen = new Set<string>()\n for (const item of parsed) {\n if (typeof item !== \"number\" || !Number.isFinite(item)) {\n throw new Error(\"Attachment upload returned an unexpected response shape.\")\n }\n const id = String(item)\n if (!seen.has(id)) {\n seen.add(id)\n ids.push(id)\n }\n }\n if (ids.length === 0) {\n throw new Error(\"Attachment upload returned an empty id list.\")\n }\n return ids\n }\n\n throw new Error(\"Attachment upload returned an unexpected response shape.\")\n}\n\n/** @deprecated Prefer {@link extractAttachmentIdsFromUploadPayload}. */\nexport function extractFirstAttachmentIdFromUploadPayload(parsed: unknown): string | undefined {\n if (typeof parsed === \"number\" && Number.isFinite(parsed)) {\n return String(parsed)\n }\n\n if (typeof parsed === \"string\" && parsed.trim()) {\n return parsed.trim()\n }\n\n if (Array.isArray(parsed)) {\n for (const item of parsed) {\n const id = coerceAttachmentId(item)\n if (id) return id\n }\n return undefined\n }\n\n if (parsed && typeof parsed === \"object\") {\n const record = parsed as Record<string, unknown>\n for (const key of [\"id\", \"attachmentId\", \"fileId\"]) {\n const id = coerceAttachmentId(record[key])\n if (id) return id\n }\n }\n\n return undefined\n}\n\nfunction coerceAttachmentId(value: unknown): string | undefined {\n if (typeof value === \"number\" && Number.isFinite(value)) {\n return String(value)\n }\n if (typeof value === \"string\" && value.trim()) {\n return value.trim()\n }\n return undefined\n}\n\nfunction normalizeAttachmentIdForWire(id: string | number): number | string {\n const numeric = typeof id === \"number\" ? id : Number(id)\n if (Number.isFinite(numeric) && String(numeric) === String(id).trim()) {\n return numeric\n }\n return typeof id === \"number\" ? String(id) : id.trim()\n}\n\n/** Wire value for an Attachments cell (Grist list encoding). */\nexport function gristAttachmentCellValues(\n attachmentIds: (string | number)[]\n): GristEncodedAttachmentList {\n const items = attachmentIds.map(normalizeAttachmentIdForWire)\n const encoded = encodeGristValue(items, ATTACHMENTS_COLUMN)\n if (!Array.isArray(encoded) || encoded[0] !== \"L\") {\n return [\"L\", ...items]\n }\n return encoded as GristEncodedAttachmentList\n}\n\n/** Wire value for a single-file Attachments cell. */\nexport function gristAttachmentCellValue(attachmentId: string | number): GristEncodedAttachmentList {\n return gristAttachmentCellValues([attachmentId])\n}\n\n/**\n * Merge new attachment ids into an existing Attachments cell value (deduped, order preserved).\n */\nexport function mergeGristAttachmentCellValue(\n existingCell: unknown,\n newIds: (string | number)[]\n): GristEncodedAttachmentList {\n const existing = extractGristAttachmentIdsFromCell(existingCell)\n const merged: string[] = []\n const seen = new Set<string>()\n const push = (raw: string | number) => {\n const id = String(raw).trim()\n if (!id || seen.has(id)) return\n seen.add(id)\n merged.push(id)\n }\n for (const id of existing) push(id)\n for (const id of newIds) push(id)\n return gristAttachmentCellValues(merged)\n}\n\nconst UPLOAD_HEADERS = {\n \"X-Requested-With\": \"XMLHttpRequest\",\n Accept: \"application/json\",\n} as const\n\n/**\n * Upload a file to the current document via `POST /attachments`.\n *\n * Uses `getAccessToken({ readOnly: false })` and `?auth=` (see Grist widget docs).\n * Requires document **full** access in the widget.\n */\nexport async function uploadGristAttachment(\n docApi: GristDocApi,\n file: Blob | File,\n options?: { fileName?: string }\n): Promise<GristAttachmentUploadResult> {\n const form = new FormData()\n const fileName =\n options?.fileName ?? (file instanceof File && file.name ? file.name : \"upload\")\n form.append(\"upload\", file, fileName)\n\n let response: Response\n try {\n response = await fetchWithGristAuth(docApi, \"/attachments\", {\n method: \"POST\",\n body: form,\n readOnly: false,\n headers: UPLOAD_HEADERS,\n })\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err)\n if (/failed to fetch/i.test(msg)) {\n const widgetOrigin =\n typeof globalThis.location !== \"undefined\"\n ? globalThis.location.origin\n : \"this widget origin\"\n throw new Error(\n `Attachment upload was blocked by the Grist host (CORS). The browser could not POST from ${widgetOrigin} to the document API. If upload worked from a dev URL (e.g. ngrok) but fails after deploy, add the new widget URL to your Grist server CORS allowlist (see grist-core#2040).`,\n { cause: err }\n )\n }\n throw err\n }\n\n const raw = await response.text()\n if (!response.ok) {\n throw new Error(\n raw.trim()\n ? `Attachment upload failed (${response.status}): ${raw.slice(0, 200)}`\n : `Attachment upload failed (${response.status})`\n )\n }\n\n const ids = parseGristAttachmentUploadResponseIds(raw)\n return { ids, firstId: ids[0]! }\n}\n","/**\n * `useGrist()`'s methods, created once per runtime: every one is\n * referentially stable for the widget's lifetime, and reads `grist` when\n * called (the emulator installs and removes it in tests).\n */\n\nimport { loadColumnMetadataByTable } from \"../helpers/build-replica-document\"\nimport { isGristNoiseColumn, type GristNoiseColumnsOptions } from \"../helpers/grist-columns-filters\"\nimport { fetchAttachmentBlob, getAttachmentDownloadUrl, type GristFetchedAttachmentBlob } from \"../helpers/grist-attachment-download\"\nimport { uploadGristAttachment, type GristAttachmentUploadResult } from \"../helpers/grist-attachment-upload\"\nimport { fetchWithGristAuth } from \"../helpers/grist-fetch-with-auth\"\nimport { fetchGristTableRows, type FetchGristTableRowsOptions, type GristColumnarTable } from \"../helpers/grist-table-data\"\nimport type { GristUserActionTuple } from \"../helpers/grist-user-actions\"\nimport type {\n GristApplyUserActionsOptions,\n GristCursorPos,\n GristDocApi,\n GristFetchSelectedOptions,\n GristRowRecord,\n GristTableOperations,\n} from \"../types\"\nimport type { GristRuntime } from \"./runtime\"\n\nexport type ListTablesOptions = {\n /** Include Grist's own tables (`_grist_*`, `GristHidden_*`). */\n includeSystem?: boolean\n}\n\nexport type ListColumnsOptions = GristNoiseColumnsOptions & {\n /** Include every column, Grist's helper and bookkeeping ones too. */\n includeSystem?: boolean\n}\n\nexport type GristColumnInfo = {\n colId: string\n type?: string\n label?: string\n isFormula?: boolean\n formula?: string\n description?: string\n}\n\nexport type GristApi = {\n reload: () => Promise<void>\n fetchSelectedTable: (options?: GristFetchSelectedOptions) => Promise<GristColumnarTable>\n fetchTable: (tableId: string) => Promise<GristColumnarTable>\n fetchTableRows: <T extends Record<string, unknown> = Record<string, unknown>>(\n tableId: string,\n options?: FetchGristTableRowsOptions\n ) => Promise<GristRowRecord<T>[]>\n listTables: (options?: ListTablesOptions) => Promise<string[]>\n listColumns: (tableId: string, options?: ListColumnsOptions) => Promise<GristColumnInfo[]>\n table: GristTableOperations\n getTable: (tableId: string) => GristTableOperations\n applyActions: (actions: GristUserActionTuple[], options?: GristApplyUserActionsOptions) => Promise<unknown>\n setWidgetOptions: (options: Record<string, unknown>) => Promise<void>\n patchWidgetOptions: (patch: Record<string, unknown>) => Promise<void>\n setCursorPosition: (pos: GristCursorPos) => Promise<void>\n setLinkedRowSelection: (rowIds: number[] | null) => Promise<void>\n getAttachmentUrl: (attachmentId: string, options?: { readOnly?: boolean }) => Promise<string>\n fetchAttachmentBlob: (attachmentId: string, options?: { readOnly?: boolean }) => Promise<GristFetchedAttachmentBlob>\n uploadAttachment: (file: Blob | File, options?: { fileName?: string }) => Promise<GristAttachmentUploadResult>\n fetchWithAuth: (path: string, init?: RequestInit & { readOnly?: boolean }) => Promise<Response>\n}\n\nconst ACCESS_ERROR = [/access not granted/i, /need higher access level/i, /requires.*full.*access/i, /RPC_ONCALL_ERROR Access/i]\n\nexport function isAccessInsufficientError(message: string): boolean {\n return ACCESS_ERROR.some((re) => re.test(message))\n}\n\nconst message = (err: unknown) => (err instanceof Error ? err.message : String(err))\n\nexport function createGristApi(runtime: GristRuntime): GristApi {\n const docApi = (): GristDocApi => {\n if (runtime.getState().connection !== \"ready\" || typeof grist === \"undefined\" || !grist.docApi) {\n throw new Error(\"Grist is not ready: wait for useGrist().status === \\\"ready\\\".\")\n }\n return grist.docApi\n }\n\n /** A read: an access refusal is kept for the alerts, cleared by the next read that succeeds. */\n const read = async <T>(fn: () => Promise<T>): Promise<T> => {\n try {\n const out = await fn()\n if (runtime.getState().readError) runtime.update({ readError: null })\n return out\n } catch (err) {\n if (isAccessInsufficientError(message(err))) runtime.update({ readError: message(err) })\n throw err\n }\n }\n\n /**\n * A write: tracked in `actionStatus` / `actionError`. Overlapping writes\n * count as one run: `actionStatus` stays `\"running\"` until the last one\n * ends, then is `\"error\"` if any of them failed. A failure is shown in the\n * alerts and rejects the returned promise, which the SDK already handles:\n * a write nobody awaits (`onClick={() => w.table.update(...)}`) doesn't log\n * an unhandled rejection.\n */\n let running = 0\n let failure: string | null = null\n const write = <T>(fn: () => Promise<T>): Promise<T> => {\n if (running++ === 0) failure = null\n runtime.update({ actionStatus: \"running\", actionError: null })\n const done = (async () => {\n try {\n return await fn()\n } catch (err) {\n failure = message(err)\n throw err\n } finally {\n if (--running === 0) runtime.update(failure ? { actionStatus: \"error\", actionError: failure } : { actionStatus: \"idle\" })\n }\n })()\n done.catch(() => {})\n return done\n }\n\n const tableOps = (resolve: () => GristTableOperations): GristTableOperations => ({\n getTableId: () => resolve().getTableId(),\n create: ((records: never, opts?: never) => write(() => resolve().create(records, opts))) as GristTableOperations[\"create\"],\n update: (records, opts) => write(() => resolve().update(records, opts)),\n upsert: (records, opts) => write(() => resolve().upsert(records, opts)),\n destroy: (ids) => write(() => resolve().destroy(ids)),\n })\n const tables = new Map<string, GristTableOperations>()\n\n return {\n reload: () => runtime.reload(),\n\n fetchSelectedTable: (options) =>\n read(async () => {\n const impl = docApi().fetchSelectedTable ?? grist.fetchSelectedTable\n if (!impl) throw new Error(\"fetchSelectedTable is not available in this Grist version\")\n return (await impl({ keepEncoded: false, ...options })) as GristColumnarTable\n }),\n fetchTable: (tableId) => read(async () => (await docApi().fetchTable(tableId)) as GristColumnarTable),\n fetchTableRows: (tableId, options) => read(() => fetchGristTableRows(docApi(), tableId, options ?? {})) as never,\n listTables: (options) =>\n read(async () => {\n const all = [...(await docApi().listTables())]\n return options?.includeSystem ? all : all.filter((t) => !t.startsWith(\"_grist\") && !t.startsWith(\"GristHidden_\"))\n }),\n listColumns: (tableId, options) =>\n read(async () => {\n const meta = (await loadColumnMetadataByTable(docApi())).get(tableId)\n if (!meta) return []\n const noise: GristNoiseColumnsOptions = {\n excludeId: options?.excludeId ?? true,\n excludeGristHelpers: options?.excludeGristHelpers ?? true,\n excludeLoggingColumns: options?.excludeLoggingColumns ?? true,\n excludeManualSort: options?.excludeManualSort ?? true,\n }\n return [...meta]\n .filter(([colId, m]) => options?.includeSystem || !isGristNoiseColumn(colId, m, noise))\n .map(([colId, m]) => ({ colId, type: m.type, label: m.label, isFormula: m.isFormula, formula: m.formula, description: m.description }))\n }),\n\n table: tableOps(() => {\n if (!grist.selectedTable) throw new Error(\"grist.selectedTable is not available in this Grist version\")\n return grist.selectedTable\n }),\n getTable: (tableId) => {\n let ops = tables.get(tableId)\n if (!ops) {\n tables.set(\n tableId,\n (ops = tableOps(() => {\n if (typeof grist.getTable !== \"function\") throw new Error(\"grist.getTable is not available in this Grist version\")\n return grist.getTable(tableId)\n }))\n )\n }\n return ops\n },\n applyActions: (actions, options) => write(() => docApi().applyUserActions(actions, options)),\n\n setWidgetOptions: async (options) => {\n await grist.setOptions(options)\n },\n patchWidgetOptions: async (patch) => {\n const current = ((await grist.getOptions()) as Record<string, unknown> | null) ?? {}\n await grist.setOptions({ ...current, ...patch })\n },\n\n setCursorPosition: async (pos) => {\n if (!grist.setCursorPos) throw new Error(\"setCursorPos is not available in this Grist version\")\n await grist.setCursorPos(pos)\n },\n setLinkedRowSelection: async (rowIds) => {\n if (!grist.setSelectedRows) throw new Error(\"setSelectedRows is not available in this Grist version\")\n await grist.setSelectedRows(rowIds)\n },\n\n getAttachmentUrl: (id, options) => read(() => getAttachmentDownloadUrl(docApi(), id, options)),\n fetchAttachmentBlob: (id, options) => read(() => fetchAttachmentBlob(docApi(), id, options)),\n uploadAttachment: (file, options) => write(() => uploadGristAttachment(docApi(), file, options)),\n fetchWithAuth: (path, init) => read(() => fetchWithGristAuth(docApi(), path, init)),\n }\n}\n","import type { GristColumnsToMap, GristColumnToMap, GristWidgetColumnMap } from \"../types\"\n\nexport type ValidateColumnMappingsResult = {\n ok: boolean\n /**\n * `true` while the host has not yet reported column mappings (e.g. between\n * `grist.ready()` resolving and the first `onRecord` / `onRecords` callback,\n * or before `sectionApi.mappings()` returns). Callers should not gate UI or\n * emit mapping alerts while pending.\n */\n pending?: boolean\n /** Logical names of required columns the user has not yet mapped. */\n missing: string[]\n /** Logical names of `allowMultiple` columns mapped to an empty list. */\n emptyMultiples: string[]\n}\n\n/**\n * Merges mapping payloads from `onRecord`, `onRecords`, and `sectionApi.mappings()`.\n * Later sources win; `undefined` sources are skipped; `null` means \"host reported\n * no mappings\" but still counts as a known (empty) payload.\n */\nexport function mergeWidgetColumnMaps(\n ...sources: (GristWidgetColumnMap | null | undefined)[]\n): GristWidgetColumnMap | null | undefined {\n let merged: GristWidgetColumnMap = {}\n let sawDefined = false\n for (const src of sources) {\n if (src === undefined) continue\n sawDefined = true\n if (src === null) continue\n merged = { ...merged, ...src }\n }\n if (!sawDefined) return undefined\n return merged\n}\n\nfunction asColumnSpec(entry: string | GristColumnToMap): GristColumnToMap {\n return typeof entry === \"string\" ? { name: entry } : entry\n}\n\n/**\n * Verifies that the current Grist mappings cover every required column declared\n * in `grist.ready({ columns })`.\n *\n * Use this before reading `mappedRecord` so you can render a \"please configure\n * the widget\" prompt instead of a confusing `null`.\n */\nexport function validateColumnMappings(\n spec: GristColumnsToMap | undefined | null,\n mappings: GristWidgetColumnMap | null | undefined\n): ValidateColumnMappingsResult {\n const missing: string[] = []\n const emptyMultiples: string[] = []\n if (!spec) return { ok: true, pending: false, missing, emptyMultiples }\n\n const m = mappings ?? {}\n for (const raw of spec) {\n const col = asColumnSpec(raw)\n if (col.optional) continue\n const value = m[col.name]\n if (col.allowMultiple) {\n if (value === undefined) {\n missing.push(col.name)\n } else if (!Array.isArray(value) || value.length === 0) {\n emptyMultiples.push(col.name)\n }\n } else {\n if (value === undefined || value === null || value === \"\") missing.push(col.name)\n }\n }\n return {\n ok: missing.length === 0 && emptyMultiples.length === 0,\n pending: false,\n missing,\n emptyMultiples,\n }\n}\n\n/** Status while waiting for the host to report mappings (see `pending`). */\nexport const pendingColumnMappingStatus: ValidateColumnMappingsResult = {\n ok: true,\n pending: true,\n missing: [],\n emptyMultiples: [],\n}\n","/**\n * Typed reads, with read-only access: each mapped cell checked against the\n * type its column declares in `GRIST_OPTIONS.columns`.\n *\n * Grist's mapping panel only offers the columns of the declared type, so for\n * a mapped column the declaration is the contract; and the plugin API's\n * decoded values already say what they are (a `Date`, a `Reference` with a\n * `rowId`, a list of ids, a `RaisedException` for a formula error, the raw\n * text of an invalid cell). Checked in Grist 1.7.22, every type, both\n * `cellFormat`s. So a cell is turned into the JS value its type promises, or\n * into `null` with an issue: no schema to fetch, no full access, no\n * dependency.\n */\n\nimport type { GristColumnsToMap, GristWidgetColumnMap } from \"../types\"\n\n/** A mapped cell that didn't match its declared type, or a rule of the widget's schema. */\nexport type GristCellIssue = {\n rowId: number\n /** The declared column name, or \"\" for a schema rule on the whole record. */\n column: string\n message: string\n /** The value Grist sent. */\n value: unknown\n}\n\ntype Check = { ok: true; value: unknown } | { ok: false; message: string }\n\nconst ok = (value: unknown): Check => ({ ok: true, value })\nconst bad = (message: string): Check => ({ ok: false, message })\n\n/** A formula error, as the plugin API decodes it (`RaisedException`) or encodes it (`[\"E\", name, …]`). */\nfunction formulaError(value: unknown): string | null {\n if (Array.isArray(value) && value[0] === \"E\") return String(value[1] ?? \"error\")\n if (value && typeof value === \"object\" && (value as { constructor?: { name?: string } }).constructor?.name === \"RaisedException\") {\n return String((value as { name?: unknown }).name ?? \"error\")\n }\n return null\n}\n\nfunction rowIdOf(value: unknown): number | null | undefined {\n if (typeof value === \"number\" && Number.isInteger(value)) return value === 0 ? null : value\n if (value && typeof value === \"object\" && typeof (value as { rowId?: unknown }).rowId === \"number\") {\n const id = (value as { rowId: number }).rowId\n return id === 0 ? null : id\n }\n if (Array.isArray(value) && value[0] === \"R\" && typeof value[2] === \"number\") return value[2] === 0 ? null : value[2]\n return undefined\n}\n\nfunction idsOf(value: unknown): number[] | undefined {\n if (value === null || value === undefined) return []\n const list = Array.isArray(value)\n ? value[0] === \"L\"\n ? value.slice(1)\n : value\n : value && typeof value === \"object\" && Array.isArray((value as { rowIds?: unknown }).rowIds)\n ? (value as { rowIds: unknown[] }).rowIds\n : undefined\n return list?.every((v) => typeof v === \"number\") ? (list as number[]) : undefined\n}\n\nfunction checkOne(base: string, value: unknown): Check {\n switch (base) {\n case \"Any\":\n return ok(value)\n case \"Text\":\n return value === null || typeof value === \"string\" ? ok(value ?? \"\") : bad(\"not text\")\n case \"Numeric\":\n return value === null || (typeof value === \"number\" && Number.isFinite(value)) ? ok(value) : bad(\"not a number\")\n case \"Int\":\n return value === null || (typeof value === \"number\" && Number.isInteger(value)) ? ok(value) : bad(\"not an integer\")\n case \"Bool\":\n return value === null || typeof value === \"boolean\" ? ok(value ?? false) : bad(\"not true or false\")\n case \"Date\":\n case \"DateTime\":\n if (value === null) return ok(null)\n if (value instanceof Date && !Number.isNaN(value.getTime())) return ok(value)\n // Seconds since the epoch: Grist's \"normal\" format, and the emulator's raw rows.\n if (typeof value === \"number\" && Number.isFinite(value)) return ok(new Date(value * 1000))\n return bad(\"not a date\")\n case \"Choice\":\n return value === null || typeof value === \"string\" ? ok(value) : bad(\"not a choice\")\n case \"ChoiceList\": {\n if (value === null || value === undefined) return ok([])\n const list = Array.isArray(value) ? (value[0] === \"L\" ? value.slice(1) : value) : undefined\n return list?.every((v) => typeof v === \"string\") ? ok(list) : bad(\"not a list of choices\")\n }\n case \"Ref\": {\n if (value === null) return ok(null)\n const id = rowIdOf(value)\n return id === undefined ? bad(\"not a reference\") : ok(id)\n }\n case \"RefList\":\n case \"Attachments\": {\n const ids = idsOf(value)\n return ids === undefined ? bad(base === \"RefList\" ? \"not a list of references\" : \"not a list of attachments\") : ok(ids)\n }\n default:\n return ok(value)\n }\n}\n\n/**\n * `value` as its declared `type` promises (\"Numeric\", \"Ref:Tasks\",\n * \"Text,Ref\"…): a match of any listed type, or a failure that says why.\n * Without a type (or \"Any\"), the value as it is.\n */\n/** The base types a declared type accepts: `\"Text,Ref:People\"` → `[\"Text\", \"Ref\"]`. */\nfunction basesOf(type: string | undefined): string[] {\n return (type ?? \"Any\")\n .split(\",\")\n .map((t) => t.trim().split(\":\")[0]!)\n .filter(Boolean)\n}\n\nexport function checkGristCell(type: string | undefined, value: unknown): Check {\n const error = formulaError(value)\n if (error) return bad(`formula error (${error})`)\n const bases = basesOf(type)\n if (bases.length === 0 || bases.includes(\"Any\")) return ok(value === undefined ? null : value)\n let first: Check | null = null\n for (const base of bases) {\n const check = checkOne(base, value)\n if (check.ok) return check\n first ??= check\n }\n return first!\n}\n\nconst LIST_BASES = [\"ChoiceList\", \"RefList\", \"Attachments\"]\n\n/**\n * A value as Grist stores it in a column of the declared `type`: the\n * reverse of what typed reads give. Lists become `[\"L\", ...]` (a RefList's\n * `Reference` items become their row ids), a `Date` for a Date or DateTime\n * column becomes seconds since the epoch, a `Reference` for a Ref column its\n * row id. A list already encoded (`[\"L\", ...]`, as the attachment helpers\n * return it) and every other value pass through, so it is safe to call twice.\n *\n * Grist's plugin API writes values as given: a bare array written to a\n * ChoiceList or RefList column is stored as an error cell. Checked in\n * Grist 1.7.22.\n */\nexport function encodeGristCell(type: string | undefined, value: unknown): unknown {\n if (value === null || value === undefined) return value\n const bases = basesOf(type)\n const accepts = (...names: string[]) => names.some((n) => bases.includes(n))\n if (value instanceof Date) return accepts(\"Date\", \"DateTime\") ? Math.floor(value.getTime() / 1000) : value\n if (Array.isArray(value)) {\n if (!accepts(...LIST_BASES) || value[0] === \"L\") return value\n return [\"L\", ...value.map((item) => rowIdOf(item) ?? item)]\n }\n if (accepts(\"Ref\") && typeof value === \"object\") return rowIdOf(value) ?? value\n return value\n}\n\nexport const nameOf = (c: GristColumnsToMap[number]) => (typeof c === \"string\" ? c : c.name)\nexport const typeOf = (c: GristColumnsToMap[number]) => (typeof c === \"string\" ? undefined : c.type)\nconst isOptional = (c: GristColumnsToMap[number]) => typeof c === \"object\" && c.optional === true\n\n/** Minimal Standard Schema (https://standardschema.dev): zod 4, valibot, arktype implement it. */\nexport type StandardSchema<T = unknown> = {\n readonly \"~standard\": {\n readonly version: 1\n readonly vendor: string\n readonly validate: (\n value: unknown\n ) =>\n | { readonly value: T; readonly issues?: undefined }\n | { readonly issues: ReadonlyArray<{ readonly message: string; readonly path?: ReadonlyArray<PropertyKey | { key: PropertyKey }> }> }\n | Promise<unknown>\n }\n}\n\n/**\n * A record under the widget's declared names, each cell checked against its\n * column's declared type, then the record against `schema` if given. Returns\n * null (no issues) while a required column isn't mapped, like Grist's\n * `mapColumnNames`; the record itself without declared columns.\n */\nexport function mapAndCheck<T>(\n record: Record<string, unknown> | null,\n columns: GristColumnsToMap | undefined,\n mappings: GristWidgetColumnMap | null,\n schema?: StandardSchema\n): { value: T | null; issues: GristCellIssue[] } {\n if (!record) return { value: null, issues: [] }\n if (!columns?.length) return { value: record as T, issues: [] }\n if (mappings === null) return { value: null, issues: [] }\n const rowId = typeof record.id === \"number\" ? record.id : 0\n const out: Record<string, unknown> = { id: record.id }\n const issues: GristCellIssue[] = []\n for (const col of columns) {\n const name = nameOf(col)\n const real = mappings[name]\n const take = (raw: unknown) => {\n const check = checkGristCell(typeOf(col), raw)\n if (check.ok) return check.value\n issues.push({ rowId, column: name, message: check.message, value: raw })\n return null\n }\n if (Array.isArray(real) && real.length > 0) out[name] = real.map((r) => take(record[r]))\n else if (typeof real === \"string\" && real) out[name] = take(record[real])\n else if (!isOptional(col)) return { value: null, issues: [] }\n }\n if (schema) {\n const result = schema[\"~standard\"].validate(out)\n if (result instanceof Promise) {\n issues.push({ rowId, column: \"\", message: \"the schema validates asynchronously; useGrist() needs a synchronous one\", value: out })\n } else if (\"issues\" in result && result.issues) {\n for (const issue of result.issues) {\n const key = issue.path?.[0]\n const column = key === undefined ? \"\" : String(typeof key === \"object\" ? key.key : key)\n issues.push({ rowId, column, message: issue.message, value: column ? out[column] : out })\n }\n } else if (\"value\" in result) {\n return { value: result.value as T, issues }\n }\n }\n return { value: out as T, issues }\n}\n\n// ---------------------------------------------------------------------------\n// Types from a declaration\n// ---------------------------------------------------------------------------\n\ntype BaseOf<T extends string> = T extends `${infer B}:${string}` ? B : T\n\ntype CellOf<T extends string> = T extends `${infer A},${infer Rest}`\n ? CellOf<A> | CellOf<Rest>\n : BaseOf<T> extends \"Text\"\n ? string\n : BaseOf<T> extends \"Numeric\" | \"Int\"\n ? number | null\n : BaseOf<T> extends \"Bool\"\n ? boolean\n : BaseOf<T> extends \"Date\" | \"DateTime\"\n ? Date | null\n : BaseOf<T> extends \"Choice\"\n ? string | null\n : BaseOf<T> extends \"ChoiceList\"\n ? string[]\n : BaseOf<T> extends \"Ref\"\n ? number | null\n : BaseOf<T> extends \"RefList\" | \"Attachments\"\n ? number[]\n : unknown\n\n// Every checked cell is `| null`: a cell that doesn't match its declared type\n// is null in mappedRecord (and listed in cellIssues), whatever the type.\ntype ColumnValue<C> = C extends { type: infer T extends string; allowMultiple: true }\n ? (CellOf<T> | null)[]\n : C extends { type: infer T extends string }\n ? CellOf<T> | null\n : C extends { allowMultiple: true }\n ? unknown[]\n : unknown\n\ntype RequiredName<C> = C extends { optional: true } ? never : C extends string ? C : C extends { name: infer N extends string } ? N : never\ntype OptionalName<C> = C extends { optional: true; name: infer N extends string } ? N : never\ntype ByName<Cs, N> = Extract<Cs, N | { name: N }>\n\n/**\n * The mapped record a `GRIST_OPTIONS` declaration gives, for `useGrist`'s\n * second type argument. Declare the options with `as const satisfies\n * UseGristOptions` so the column names and types stay literal:\n *\n * ```ts\n * export const GRIST_OPTIONS = {\n * requiredAccess: \"read table\",\n * columns: [{ name: \"Title\", type: \"Text\" }, { name: \"Due\", type: \"Date\", optional: true }],\n * } as const satisfies UseGristOptions\n *\n * const w = useGrist<GristRowRecord, GristMappedRow<typeof GRIST_OPTIONS>>()\n * w.mappedRecord?.Due // Date | null | undefined\n * ```\n */\nexport type GristMappedRow<O extends { columns?: readonly unknown[] }> = O[\"columns\"] extends readonly (infer C)[]\n ? { id: number } & { [N in RequiredName<C>]: ColumnValue<ByName<C, N>> } & { [N in OptionalName<C>]?: ColumnValue<ByName<C, N>> }\n : Record<string, unknown>\n","/**\n * What `useGrist()` shows, derived from the runtime state: status, error,\n * column-mapping status, the mapped record, and the access check. Pure\n * functions, so they are tested without React or Grist.\n */\n\nimport { validateColumnMappings, type ValidateColumnMappingsResult } from \"../helpers/grist-mappings\"\nimport type { GristColumnsToMap, GristRequiredAccess, GristWidgetColumnMap } from \"../types\"\nimport { encodeGristCell, nameOf, typeOf } from \"./cells\"\nimport type { GristRuntimeState } from \"./runtime\"\n\n/** The widget's connection to Grist, as `useGrist().status` reports it. */\nexport type GristWidgetStatus = \"booting\" | \"ready\" | \"unavailable\" | \"error\"\n\nexport const ACCESS_RANK: Record<GristRequiredAccess, number> = { none: 0, \"read table\": 1, full: 2 }\n\nexport function parseAccess(raw: unknown): GristRequiredAccess | null {\n return raw === \"none\" || raw === \"read table\" || raw === \"full\" ? raw : null\n}\n\nexport function accessLabel(level: GristRequiredAccess): string {\n return level === \"full\" ? \"Full document access\" : level === \"read table\" ? \"Read selected table\" : \"No document access\"\n}\n\n/** Grist granted less than the widget declared (Grist reports it with the widget options). */\nexport function accessDenied(state: GristRuntimeState): boolean {\n return state.grantedAccess !== null && ACCESS_RANK[state.grantedAccess] < ACCESS_RANK[state.declaredAccess]\n}\n\nexport function deriveStatus(state: GristRuntimeState): GristWidgetStatus {\n switch (state.connection) {\n case \"connecting\":\n return \"booting\"\n case \"not-embedded\":\n case \"unavailable\":\n return \"unavailable\"\n case \"error\":\n return \"error\"\n case \"ready\":\n return accessDenied(state) ? \"error\" : \"ready\"\n }\n}\n\nexport function deriveError(state: GristRuntimeState): string | null {\n if (state.connection === \"not-embedded\") return \"This page is not embedded in a Grist document.\"\n if (state.connection === \"unavailable\") return \"The Grist plugin API (grist-plugin-api.js) did not load.\"\n if (state.connection === \"error\") return state.connectionError\n if (state.connection === \"ready\" && accessDenied(state)) {\n return `Grist granted \"${accessLabel(state.grantedAccess!)}\"; this widget needs \"${accessLabel(state.declaredAccess)}\". Set the access level in the Custom widget settings.`\n }\n return null\n}\n\nconst MAPPINGS_OK: ValidateColumnMappingsResult = Object.freeze({ ok: true, pending: false, missing: [], emptyMultiples: [] }) as ValidateColumnMappingsResult\nconst MAPPINGS_PENDING: ValidateColumnMappingsResult = Object.freeze({ ok: true, pending: true, missing: [], emptyMultiples: [] }) as ValidateColumnMappingsResult\n\n/** Whether the declared columns are mapped: pending until Grist reports mappings. */\nexport function deriveColumnMappingStatus(\n columns: GristColumnsToMap | undefined,\n mappings: GristWidgetColumnMap | null\n): ValidateColumnMappingsResult {\n if (!columns?.length) return MAPPINGS_OK\n if (mappings === null) return MAPPINGS_PENDING\n return validateColumnMappings(columns, mappings)\n}\n\n/**\n * A logical-name patch as real column ids, for a write, each value encoded\n * for its declared type (`encodeGristCell`: lists, dates, references), so\n * what `mappedRecord` gave can be written back as is. A column mapped to\n * several Grist columns (`allowMultiple`) can't be written back and is\n * reported in `skipped`; a name with no mapping passes through unchanged.\n */\nexport function mapBackPatch(\n patch: Record<string, unknown>,\n mappings: GristWidgetColumnMap,\n columns?: GristColumnsToMap\n): { fields: Record<string, unknown>; skipped: string[] } {\n const fields: Record<string, unknown> = {}\n const skipped: string[] = []\n for (const [name, value] of Object.entries(patch)) {\n if (value === undefined) continue\n const real = mappings[name]\n if (Array.isArray(real)) {\n skipped.push(name)\n continue\n }\n const declared = columns?.find((c) => nameOf(c) === name)\n fields[typeof real === \"string\" && real ? real : name] = declared ? encodeGristCell(typeOf(declared), value) : value\n }\n return { fields, skipped }\n}\n","import type { GristWidgetInteraction, GristWidgetLinkingInfo } from \"../types\"\n\n/**\n * Parse `InteractionOptions.linking` from a Grist `onOptions` settings payload.\n */\nexport function parseGristWidgetLinkingInfo(raw: unknown): GristWidgetLinkingInfo | undefined {\n if (!raw || typeof raw !== \"object\" || !(\"asTarget\" in raw)) return undefined\n const linking = raw as { asTarget: unknown; asSource?: unknown }\n return {\n asTarget: linking.asTarget == null ? null : String(linking.asTarget),\n asSource: Boolean(linking.asSource),\n }\n}\n\n/**\n * Normalize the second argument to `grist.onOptions` (Grist `InteractionOptions`).\n * Hosts use `accessLevel` (camelCase); the emulator uses `access_level`.\n */\nexport function normalizeWidgetInteraction(\n interaction: GristWidgetInteraction | null\n): GristWidgetInteraction | null {\n if (!interaction || typeof interaction !== \"object\") return interaction\n const raw = interaction as Record<string, unknown>\n const access_level =\n typeof raw.access_level === \"string\"\n ? raw.access_level\n : typeof raw.accessLevel === \"string\"\n ? raw.accessLevel\n : undefined\n const linking = parseGristWidgetLinkingInfo(raw.linking)\n return {\n ...interaction,\n ...(access_level ? { access_level } : {}),\n ...(linking ? { linking } : {}),\n }\n}\n","/**\n * Grist's event streams, bound once per page.\n *\n * `grist.onRecord`, `onRecords`, `onOptions`, `onNewRecord` and `on(\"message\")`\n * are add-only: there is no `off`. Binding them in every provider (React's\n * StrictMode mounts twice; a widget may remount) would stack handlers for the\n * page's lifetime. Each stream here binds at its first subscriber and fans out\n * to the current ones; a late subscriber gets the last value at once.\n *\n * Records are bound with the plugin API's decoded rows (`keepEncoded: false`,\n * rows for `onRecords`), the shape widget code reads.\n */\n\nimport { normalizeWidgetInteraction } from \"../helpers/grist-widget-interaction\"\nimport type { GristWidgetColumnMap, GristWidgetInteraction } from \"../types\"\n\ntype Listener<T> = (value: T) => void\n\nexport class HostStream<T> {\n private listeners = new Set<Listener<T>>()\n private bound = false\n private has = false\n private last: T | undefined\n\n constructor(private readonly bind: (emit: (value: T) => void) => void) {}\n\n subscribe(listener: Listener<T>): () => void {\n this.listeners.add(listener)\n if (!this.bound) {\n this.bound = true\n try {\n this.bind((value) => this.emit(value))\n } catch (err) {\n console.error(\"[grist-widget-sdk] could not subscribe to a Grist event:\", err)\n }\n }\n if (this.has) listener(this.last as T)\n return () => {\n this.listeners.delete(listener)\n }\n }\n\n peek(): T | undefined {\n return this.last\n }\n\n /** Tests: deliver a value as if Grist had sent it. */\n emit(value: T): void {\n this.has = true\n this.last = value\n for (const l of [...this.listeners]) l(value)\n }\n\n /** Tests: forget the binding, so a new `window.grist` binds afresh. */\n reset(): void {\n this.listeners.clear()\n this.bound = false\n this.has = false\n this.last = undefined\n }\n}\n\nexport type RecordPayload = { record: Record<string, unknown> | null; mappings: GristWidgetColumnMap | null }\nexport type RecordsPayload = { records: Record<string, unknown>[]; mappings: GristWidgetColumnMap | null }\nexport type OptionsPayload = { options: Record<string, unknown> | null; interaction: GristWidgetInteraction | null }\nexport type NewRecordPayload = { mappings: GristWidgetColumnMap | null }\n\nconst asMappings = (m: unknown) => (m && typeof m === \"object\" ? (m as GristWidgetColumnMap) : null)\n\nexport const recordStream = new HostStream<RecordPayload>((emit) => {\n grist.onRecord((record, mappings) => emit({ record, mappings: asMappings(mappings) }), { keepEncoded: false })\n\n // Grist's RecordNotifier posts `{ tableId, rowId }` on a cursor move. The\n // plugin API's onRecord handles it, but refetching here when the row\n // changes keeps a widget from sticking on its first row if that path is\n // skipped (seen in production iframes).\n const fetchSelectedRecord = grist.fetchSelectedRecord ?? grist.docApi?.fetchSelectedRecord\n if (typeof grist.on !== \"function\" || typeof fetchSelectedRecord !== \"function\") return\n let lastRowId: number | undefined\n grist.on(\"message\", async (msg: unknown) => {\n const host = msg as { tableId?: string; rowId?: unknown } | null\n if (!host?.tableId || typeof host.rowId !== \"number\" || host.rowId === lastRowId) return\n lastRowId = host.rowId\n try {\n const record = await fetchSelectedRecord(host.rowId, { keepEncoded: false })\n emit({ record, mappings: recordStream.peek()?.mappings ?? null })\n } catch (err) {\n console.error(\"[grist-widget-sdk] fetchSelectedRecord on a cursor move failed:\", err)\n }\n })\n})\n\nexport const recordsStream = new HostStream<RecordsPayload>((emit) => {\n grist.onRecords((records, mappings) => emit({ records, mappings: asMappings(mappings) }), {\n keepEncoded: false,\n format: \"rows\",\n })\n})\n\nexport const optionsStream = new HostStream<OptionsPayload>((emit) => {\n grist.onOptions((options, interaction) =>\n emit({\n options: options ? { ...options } : null,\n interaction: normalizeWidgetInteraction((interaction as GristWidgetInteraction | null) ?? null),\n })\n )\n})\n\nexport const newRecordStream = new HostStream<NewRecordPayload>((emit) => {\n if (typeof grist.onNewRecord !== \"function\") return\n grist.onNewRecord((mappings) => emit({ mappings: asMappings(mappings) }))\n})\n\n/** Grist's host messages (`grist.on(\"message\")`): the theme travels here. */\nexport const messageStream = new HostStream<unknown>((emit) => {\n if (typeof grist.on !== \"function\") return\n grist.on(\"message\", (msg: unknown) => emit(msg))\n})\n\nexport const ALL_STREAMS = [recordStream, recordsStream, optionsStream, newRecordStream, messageStream] as const\n","/**\n * Single-call wrapper around `grist.ready()`.\n *\n * Grist's contract is \"call ready once\". Multiple `useGristReady` calls (or\n * `useGristWidget` from sibling components) would otherwise race. We:\n *\n * - Coalesce concurrent calls into one in-flight promise.\n * - Re-call `grist.ready` only when `requiredAccess` widens (so an action-capable\n * hook can upgrade a previously read-only handshake).\n */\n\nimport type { GristColumnsToMap, GristReadyOptions, GristRequiredAccess } from \"../types\"\n\nconst ACCESS_RANK: Record<GristRequiredAccess, number> = {\n none: 0,\n \"read table\": 1,\n full: 2,\n}\n\nlet inFlight: Promise<void> | null = null\nlet lastAccess: GristRequiredAccess | null = null\nlet lastColumnNames: ReadonlySet<string> | null = null\n\nfunction columnNamesOf(columns: GristColumnsToMap | undefined): Set<string> {\n return new Set((columns ?? []).map((c) => (typeof c === \"string\" ? c : c.name)))\n}\n\n/**\n * Re-init whenever the new payload asks for strictly more than what's\n * already cached: a higher access level, or a column name the cached\n * payload didn't declare. Prevents a bare fallback caller (e.g. a status\n * chip with no declared columns) from permanently sticking a widget's real,\n * richer requirements to the host once it happens to win the initial race.\n */\nfunction shouldReinit(next: GristRequiredAccess, nextColumns: ReadonlySet<string>): boolean {\n if (!lastAccess) return true\n if (ACCESS_RANK[next] > ACCESS_RANK[lastAccess]) return true\n for (const name of nextColumns) {\n if (!lastColumnNames?.has(name)) return true\n }\n return false\n}\n\n/**\n * Calls `grist.ready` at most once per page (re-called only if access widens\n * or previously-undeclared columns are requested).\n * Returns the same promise for all concurrent callers.\n */\nexport function ensureGristReady(payload: GristReadyOptions): Promise<void> {\n const access = payload.requiredAccess ?? \"read table\"\n const columns = columnNamesOf(payload.columns)\n if (inFlight && !shouldReinit(access, columns)) return inFlight\n\n lastAccess = access\n lastColumnNames = columns\n const next = Promise.resolve().then(() => {\n const result = grist.ready(payload)\n return result instanceof Promise ? result : Promise.resolve()\n })\n\n inFlight = next.catch((err) => {\n inFlight = null\n lastAccess = null\n lastColumnNames = null\n throw err\n })\n return inFlight\n}\n\n/**\n * Forget the cached ready state. Subsequent calls to {@link ensureGristReady}\n * will re-issue `grist.ready` even at the same access level.\n *\n * Production uses: the handshake manager's `reload()` clears the singleton so\n * a soft retry triggers a fresh `grist.ready` (otherwise the cached promise\n * would short-circuit and the user-visible reload would be a no-op).\n *\n * Tests use this between test cases when swapping `window.grist`.\n */\nexport function resetGristReady(): void {\n inFlight = null\n lastAccess = null\n lastColumnNames = null\n}\n\n/** @deprecated Use {@link resetGristReadySingleton}. Kept for test back-compat. */\n","export type GristThemeName = \"light\" | \"dark\"\n\n/**\n * Normalize theme from `grist.on(\"message\")` host payloads (`msg.theme`).\n * Grist sends a theme object with `appearance`; some hosts may send a bare string.\n */\nexport function parseGristThemePayload(payload: unknown): GristThemeName | null {\n if (!payload || typeof payload !== \"object\") return null\n const raw = payload as Record<string, unknown>\n const top = raw.theme\n if (top === \"light\" || top === \"dark\") return top\n if (top && typeof top === \"object\") {\n const appearance = (top as Record<string, unknown>).appearance\n if (appearance === \"light\" || appearance === \"dark\") return appearance\n }\n return null\n}\n","/**\n * The widget's connection to Grist: one store, one `connect()`.\n *\n * The template loads `grist-plugin-api.js` with a classic blocking script, so\n * `window.grist` is there when the widget starts, or it never will be: the\n * check is synchronous (with one more look at `load`, for a page that loads\n * the script asynchronously). Then `grist.ready()` once, and every Grist\n * stream (records, options, mappings, theme) feeds one immutable state that\n * React reads through `useSyncExternalStore`. No polling, no heartbeat: the\n * iframe lives and dies with the Grist page, and a failed call fails where it\n * was made.\n */\n\nimport { parseGristThemePayload } from \"../helpers/grist-theme-payload\"\nimport type { GristSdkAlertKind } from \"../helpers/grist-sdk-alerts\"\nimport type { StandardSchema } from \"./cells\"\nimport type {\n GristReadyOptions,\n GristRequiredAccess,\n GristRowRecord,\n GristWidgetColumnMap,\n GristWidgetInteraction,\n} from \"../types\"\nimport { parseAccess } from \"./derive\"\nimport { messageStream, newRecordStream, optionsStream, recordsStream, recordStream } from \"./host\"\nimport { ensureGristReady, resetGristReady } from \"./ready\"\n\nexport type GristConnection = \"connecting\" | \"ready\" | \"not-embedded\" | \"unavailable\" | \"error\"\nexport type GristTheme = \"light\" | \"dark\"\nexport type GristWidgetActionStatus = \"idle\" | \"running\" | \"error\"\n\nexport type GristRuntimeState = {\n connection: GristConnection\n /** Why the connection failed (`connection === \"error\"`). */\n connectionError: string | null\n declaredAccess: GristRequiredAccess\n /** The access Grist reports with the widget options; null before it does. */\n grantedAccess: GristRequiredAccess | null\n record: GristRowRecord | null\n records: GristRowRecord[] | null\n isNewRecord: boolean\n /** Logical → real column ids; null until Grist reports them. */\n mappings: GristWidgetColumnMap | null\n widgetOptions: Record<string, unknown> | null\n interaction: GristWidgetInteraction | null\n currentTableId: string | null\n theme: GristTheme | null\n actionStatus: GristWidgetActionStatus\n actionError: string | null\n /** The last read that Grist refused for lack of access, for the alerts. */\n readError: string | null\n /** Logical columns the last `mapBack` couldn't write (allowMultiple), for the alerts. */\n mapBackSkipped: readonly string[]\n}\n\n/** What a widget asks Grist for (`UseGristOptions`). */\nexport type GristRuntimeOptions = GristReadyOptions & {\n /** Alert kinds mountGristWidget() never shows for this widget, e.g. [\"section-not-linked\"]. */\n suppressAlerts?: GristSdkAlertKind[]\n /**\n * Extra rules for the mapped records, as a Standard Schema (zod 4,\n * valibot, arktype…), checked after each cell's declared type. A record\n * that fails keeps its typed values; its issues go to `cellIssues`.\n */\n schema?: StandardSchema\n}\n\nexport type GristRuntime = {\n readonly options: GristRuntimeOptions\n getState(): GristRuntimeState\n subscribe(listener: () => void): () => void\n /** Connects (idempotent). Returns a function that stops listening. */\n start(): () => void\n /** Re-runs `grist.ready()` and re-reads mappings and the table. */\n reload(): Promise<void>\n update(patch: Partial<GristRuntimeState>): void\n}\n\nconst READY_TIMEOUT_MS = 30_000\n\nexport function initialRuntimeState(options: GristReadyOptions = {}): GristRuntimeState {\n return {\n connection: \"connecting\",\n connectionError: null,\n declaredAccess: options.requiredAccess ?? \"read table\",\n grantedAccess: null,\n record: null,\n records: null,\n isNewRecord: false,\n mappings: null,\n widgetOptions: null,\n interaction: null,\n currentTableId: null,\n theme: null,\n actionStatus: \"idle\",\n actionError: null,\n readError: null,\n mapBackSkipped: [],\n }\n}\n\nfunction isEmbedded(): boolean {\n try {\n return typeof window !== \"undefined\" && window.self !== window.top\n } catch {\n return true // a cross-origin parent throws: we are in an iframe\n }\n}\n\nconst hasGrist = () => typeof grist !== \"undefined\" && grist !== null\n\nexport function createGristRuntime(options: GristRuntimeOptions = {}): GristRuntime {\n let state = initialRuntimeState(options)\n const listeners = new Set<() => void>()\n let starts = 0\n let stopStreams: (() => void) | null = null\n let attempt = 0\n\n const update = (patch: Partial<GristRuntimeState>) => {\n let changed = false\n for (const key of Object.keys(patch) as (keyof GristRuntimeState)[]) {\n if (!Object.is(state[key], patch[key])) changed = true\n }\n if (!changed) return\n state = { ...state, ...patch }\n for (const l of [...listeners]) l()\n }\n\n const payload: GristReadyOptions = {\n requiredAccess: options.requiredAccess ?? \"read table\",\n columns: options.columns ?? [],\n ...(options.allowSelectBy !== undefined ? { allowSelectBy: options.allowSelectBy } : {}),\n ...(options.hasCustomOptions !== undefined ? { hasCustomOptions: options.hasCustomOptions } : {}),\n ...(options.onEditOptions ? { onEditOptions: options.onEditOptions } : {}),\n }\n\n const refreshTable = async () => {\n try {\n const tableId = await grist.selectedTable?.getTableId()\n if (tableId) update({ currentTableId: tableId })\n } catch {\n // Not every host answers; currentTableId stays as it was.\n }\n }\n\n const refreshMappings = async () => {\n if (typeof grist.sectionApi?.mappings !== \"function\") return\n try {\n const mappings = await grist.sectionApi.mappings()\n // A stream may have reported newer mappings while this was in flight.\n if (state.mappings === null) update({ mappings: (mappings as GristWidgetColumnMap | null) ?? {} })\n } catch {\n // The streams report mappings too.\n }\n }\n\n const connect = async () => {\n const mine = ++attempt\n update({ connection: \"connecting\", connectionError: null })\n let timer: ReturnType<typeof setTimeout> | undefined\n try {\n await Promise.race([\n ensureGristReady(payload),\n new Promise((_, reject) => {\n timer = setTimeout(() => reject(new Error(`Grist did not answer grist.ready() within ${READY_TIMEOUT_MS / 1000} s.`)), READY_TIMEOUT_MS)\n }),\n ])\n } catch (err) {\n if (mine === attempt) update({ connection: \"error\", connectionError: err instanceof Error ? err.message : String(err) })\n return\n } finally {\n clearTimeout(timer)\n }\n if (mine !== attempt) return\n update({ connection: \"ready\" })\n await Promise.all([refreshMappings(), refreshTable()])\n }\n\n const listen = () => {\n const offs = [\n // Copies: a host may reuse one record object and mutate it in place.\n recordStream.subscribe(({ record, mappings }) =>\n update({\n record: record ? ({ ...record } as GristRowRecord) : null,\n isNewRecord: false,\n ...(mappings ? { mappings } : {}),\n })\n ),\n recordsStream.subscribe(({ records, mappings }) => {\n update({ records: records.map((r) => ({ ...r }) as GristRowRecord), ...(mappings ? { mappings } : {}) })\n void refreshTable()\n }),\n optionsStream.subscribe(({ options: widgetOptions, interaction }) =>\n update({\n widgetOptions,\n interaction,\n grantedAccess: parseAccess(interaction?.access_level) ?? state.grantedAccess,\n })\n ),\n newRecordStream.subscribe(({ mappings }) => update({ isNewRecord: true, ...(mappings ? { mappings } : {}) })),\n messageStream.subscribe((msg) => {\n const theme = parseGristThemePayload(msg)\n if (theme) update({ theme })\n }),\n ]\n return () => offs.forEach((off) => off())\n }\n\n const begin = () => {\n if (!isEmbedded()) return update({ connection: \"not-embedded\" })\n if (!hasGrist()) {\n // A page that loads the plugin API asynchronously: one more look once\n // everything has loaded, then it is unavailable.\n if (typeof document !== \"undefined\" && document.readyState !== \"complete\" && typeof window !== \"undefined\") {\n window.addEventListener(\"load\", () => (hasGrist() ? begin() : update({ connection: \"unavailable\" })), { once: true })\n return\n }\n return update({ connection: \"unavailable\" })\n }\n // Bound before ready(): Grist may push the first record during it.\n stopStreams ??= listen()\n void connect()\n }\n\n return {\n options,\n getState: () => state,\n subscribe(listener) {\n listeners.add(listener)\n return () => listeners.delete(listener)\n },\n start() {\n if (starts++ === 0) begin()\n return () => {\n if (--starts > 0) return\n stopStreams?.()\n stopStreams = null\n }\n },\n async reload() {\n if (!hasGrist() || !isEmbedded()) return begin()\n resetGristReady()\n update({ mappings: null })\n stopStreams ??= listen()\n await connect()\n },\n update,\n }\n}\n","/**\n * `defineGristWidget()`: a widget's whole declaration in one typed value.\n * Everything else reads it: `widget.useGrist()` types the mapped records and\n * the writes from it, `mountGristWidget()` takes the access level, the\n * columns and the title from it, and the tests map its columns.\n *\n * ```ts\n * export const widget = defineGristWidget({\n * title: \"Tasks\",\n * requiredAccess: \"full\",\n * columns: [{ name: \"Title\", type: \"Text\" }, { name: \"Done\", type: \"Bool\" }],\n * })\n *\n * const w = widget.useGrist() // w.mappedRecord: { id; Title: string | null; Done: boolean | null } | null\n * await w.updateRecord({ Done: true })\n * ```\n */\n\nimport type { GristMappedRow } from \"./runtime/cells\"\nimport type { GristRowRecord } from \"./types\"\nimport { useGrist, type UseGristOptions, type UseGristResult } from \"./use-grist\"\n\n/** What a widget declares: `UseGristOptions`, plus its title and description. */\nexport type GristWidgetDefinition = UseGristOptions & {\n /** The widget's name: the page's title, and its manifest's. */\n title?: string\n /** One sentence: the page's description, and its manifest's. */\n description?: string\n}\n\n/** The widget's mapped record type, from its declaration. */\nexport type GristWidgetRow<W> = W extends GristWidget<infer D> ? GristMappedRow<D> : never\n\n/** A declared widget. Pass it to `mountGristWidget()` (as `widget`, exported from `src/app/App.tsx`). */\nexport type GristWidget<D extends GristWidgetDefinition = GristWidgetDefinition> = {\n /** The declaration, as written. */\n readonly definition: D\n /** What the widget asks Grist for: the declaration without its title and description. */\n readonly options: UseGristOptions\n readonly metadata: { title?: string; description?: string }\n /**\n * `useGrist()`, typed from the declaration: `mappedRecord`, `mappedRecords`,\n * `mapBack`, `updateRecord` and `addRecord` use the declared names and the\n * value each declared type gives. A hook: call it in a component.\n */\n useGrist: () => UseGristResult<GristRowRecord, GristMappedRow<D>>\n}\n\n/**\n * Declares a widget. The `const` type parameter keeps the column names and\n * types literal, so the mapped record is typed with no annotation, no\n * `as const` and no generics.\n */\nexport function defineGristWidget<const D extends GristWidgetDefinition>(definition: D): GristWidget<D> {\n const { title, description, ...options } = definition\n return {\n definition,\n options,\n metadata: { title, description },\n useGrist: () => useGrist<GristRowRecord, GristMappedRow<D>>(options),\n }\n}\n\n/** True for a declared widget (as opposed to plain `GRIST_OPTIONS`). */\nexport function isGristWidget(value: unknown): value is GristWidget {\n return typeof value === \"object\" && value !== null && \"definition\" in value && \"useGrist\" in value\n}\n","import { useState, type ReactNode } from \"react\"\n\nimport { GristContextProvider, newConnection, type UseGristOptions } from \"../use-grist\"\n\nexport type GristWidgetProviderProps = {\n /** Read once, at mount: what the widget asks Grist for. */\n options?: UseGristOptions\n children: ReactNode\n}\n\n/**\n * Connects to Grist for the widgets below it: `useGrist()` under it reads this\n * connection. `mountGristWidget()` renders it; render it yourself only for a\n * page that manages its own React root.\n */\nexport function GristWidgetProvider({ options, children }: GristWidgetProviderProps) {\n const [connection] = useState(() => newConnection(options))\n return <GristContextProvider value={connection}>{children}</GristContextProvider>\n}\n","import { useCallback, useState, type CSSProperties, type ReactNode } from \"react\"\n\nimport { accessDenied, accessLabel, deriveColumnMappingStatus } from \"../runtime/derive\"\nimport type { GristRuntimeState } from \"../runtime/runtime\"\nimport { useGristRuntime, useGristState } from \"../use-grist\"\n\nexport type GristBoundaryProps = {\n children: ReactNode\n}\n\nexport type GristBoundaryActions = {\n reload: () => Promise<void>\n isReloading: boolean\n}\n\nconst shellStyle: CSSProperties = {\n alignItems: \"center\",\n background: \"var(--background)\",\n boxSizing: \"border-box\",\n color: \"var(--foreground)\",\n display: \"flex\",\n flexDirection: \"column\",\n justifyContent: \"center\",\n minHeight: \"100%\",\n padding: \"clamp(16px, 5vh, 32px)\",\n width: \"100%\",\n}\n\nconst cardStyle: CSSProperties = {\n background: \"var(--card)\",\n border: \"1px solid var(--border)\",\n borderRadius: 12,\n boxShadow: \"0 1px 3px rgb(0 0 0 / 0.12)\",\n maxWidth: 420,\n padding: \"20px 22px\",\n textAlign: \"center\",\n width: \"100%\",\n}\n\nconst titleStyle: CSSProperties = {\n color: \"var(--foreground)\",\n fontSize: 15,\n fontWeight: 600,\n lineHeight: 1.35,\n margin: 0,\n}\n\nconst messageStyle: CSSProperties = {\n color: \"var(--muted-foreground)\",\n fontSize: 14,\n lineHeight: 1.5,\n margin: \"10px 0 0\",\n}\n\nconst buttonStyle: CSSProperties = {\n background: \"var(--background)\",\n border: \"1px solid var(--border)\",\n borderRadius: 8,\n color: \"var(--foreground)\",\n cursor: \"pointer\",\n fontSize: 13,\n fontWeight: 500,\n marginTop: 16,\n padding: \"8px 14px\",\n}\n\ntype GristBoundaryScreenProps = {\n title: string\n message: string\n /** Affects WAI-ARIA role only (`alert` vs `status`); copy uses the same neutral styles. */\n tone?: \"default\" | \"error\"\n showRetry?: boolean\n actions?: GristBoundaryActions\n retryLabel?: string\n retryBusyLabel?: string\n}\n\n/** Centered full-viewport chrome for booting / unavailable / error states. */\nexport function GristBoundaryScreen({\n title,\n message,\n tone = \"default\",\n showRetry = false,\n actions,\n retryLabel = \"Try reconnecting\",\n retryBusyLabel = \"Reconnecting…\",\n}: GristBoundaryScreenProps) {\n return (\n <div style={shellStyle} role={tone === \"error\" ? \"alert\" : \"status\"}>\n <div style={cardStyle}>\n <h2 style={titleStyle}>{title}</h2>\n <p style={messageStyle}>{message}</p>\n {showRetry && actions ? (\n <button\n disabled={actions.isReloading}\n onClick={() => void actions.reload()}\n style={{\n ...buttonStyle,\n cursor: actions.isReloading ? \"not-allowed\" : \"pointer\",\n opacity: actions.isReloading ? 0.7 : 1,\n }}\n type=\"button\"\n >\n {actions.isReloading ? retryBusyLabel : retryLabel}\n </button>\n ) : null}\n </div>\n </div>\n )\n}\n\ntype Screen = { title: string; message: string; tone?: \"default\" | \"error\"; retry?: boolean }\n\n/** What the boundary shows instead of the widget, or null to render it. */\nexport function boundaryScreen(state: GristRuntimeState, columns: Parameters<typeof deriveColumnMappingStatus>[0]): Screen | null {\n switch (state.connection) {\n case \"connecting\":\n return { title: \"Connecting to Grist\", message: \"Asking Grist for the access this widget needs…\" }\n case \"not-embedded\":\n return {\n title: \"Open inside Grist\",\n message: \"Open this page as a custom widget inside a Grist document (it runs in an embedded panel, not on its own).\",\n retry: true,\n }\n case \"unavailable\":\n return {\n title: \"Open inside Grist\",\n message: \"The Grist plugin did not load. Reload the page, or open this URL as a custom widget inside a Grist document.\",\n retry: true,\n }\n case \"error\":\n return {\n title: \"Something went wrong\",\n message: state.connectionError ?? \"Something went wrong connecting to Grist. Try again, or reload the page.\",\n tone: \"error\",\n retry: true,\n }\n }\n if (accessDenied(state)) {\n return {\n title: \"More access needed\",\n message: `Set Access level to at least \"${accessLabel(state.declaredAccess)}\" in the Custom widget settings.`,\n tone: \"error\",\n retry: true,\n }\n }\n const mapping = deriveColumnMappingStatus(columns, state.mappings)\n if (mapping.pending) return { title: \"Connecting to Grist\", message: \"Waiting for Grist to report the column mapping…\" }\n if (!mapping.ok) {\n return {\n title: \"Map your columns\",\n message:\n \"Open the widget settings in Grist (Creator Panel → Custom widget) and connect each required column to your table.\",\n }\n }\n return null\n}\n\n/**\n * Renders the widget once Grist is connected, has granted the access it\n * declares, and every required declared column is mapped; until then, a\n * screen that says what is missing (with a retry where one can help).\n * Requires `<GristWidgetProvider>`; `mountGristWidget()` renders both.\n */\nexport function GristBoundary({ children }: GristBoundaryProps) {\n const connection = useGristRuntime()\n if (!connection) throw new Error(\"<GristBoundary> must be used inside <GristWidgetProvider> (mountGristWidget renders both).\")\n const state = useGristState(connection)\n const [isReloading, setIsReloading] = useState(false)\n const reload = useCallback(async () => {\n setIsReloading(true)\n try {\n await connection.runtime.reload()\n } catch (err) {\n console.error(\"[grist-widget-sdk] reload failed:\", err)\n } finally {\n setIsReloading(false)\n }\n }, [connection])\n\n const screen = boundaryScreen(state, connection.runtime.options.columns)\n if (!screen) return <>{children}</>\n return (\n <GristBoundaryScreen\n title={screen.title}\n message={screen.message}\n tone={screen.tone}\n showRetry={screen.retry}\n actions={{ reload, isReloading }}\n retryLabel={screen.tone === \"error\" ? \"Try again\" : \"Try reconnecting\"}\n retryBusyLabel={screen.tone === \"error\" ? \"Retrying…\" : \"Reconnecting…\"}\n />\n )\n}\n","import { useEffect } from \"react\"\n\nexport type UseWidgetMetadataInput = {\n title: string\n description: string\n}\n\nexport function useWidgetMetadata(input?: UseWidgetMetadataInput | null) {\n useEffect(() => {\n if (!input) return\n\n const { title, description } = input\n const canonicalUrl = window.location.href\n\n document.title = title\n setMetaTag(\"name\", \"title\", title)\n setMetaTag(\"name\", \"description\", description)\n setMetaTag(\"property\", \"og:title\", title)\n setMetaTag(\"property\", \"og:description\", description)\n setMetaTag(\"property\", \"og:type\", \"website\")\n setMetaTag(\"property\", \"og:url\", canonicalUrl)\n setMetaTag(\"name\", \"twitter:card\", \"summary\")\n setMetaTag(\"name\", \"twitter:title\", title)\n setMetaTag(\"name\", \"twitter:description\", description)\n\n }, [input])\n}\n\nfunction setMetaTag(key: \"name\" | \"property\", value: string, content: string) {\n let meta = document.head.querySelector<HTMLMetaElement>(\n `meta[${key}=\"${value}\"]`\n )\n if (!meta) {\n meta = document.createElement(\"meta\")\n meta.setAttribute(key, value)\n document.head.appendChild(meta)\n }\n meta.setAttribute(\"content\", content)\n}\n","import { useEffect, useState } from \"react\"\n\nimport {\n cardStyle,\n cardTextStyle,\n cardTitleStyle,\n codeStyle,\n eyebrowStyle,\n headingStyle,\n leadStyle,\n pageStyle,\n} from \"./tokens\"\nimport { widgetTitle } from \"./widget-title\"\n\n/**\n * Whether the widget has a demo page (`public/demo/`). The dev server serves\n * it at `demo/index.html` (Vite answers a bare `demo/` with the app's own page).\n */\nfunction useHasDemo(): boolean | null {\n const [has, setHas] = useState<boolean | null>(null)\n useEffect(() => {\n if (typeof fetch !== \"function\") return\n let live = true\n fetch(\"demo/demo.grist\", { method: \"HEAD\" })\n .then((res) => live && setHas(res.ok))\n .catch(() => live && setHas(false))\n return () => {\n live = false\n }\n }, [])\n return has\n}\n\n/**\n * Shown outside Grist on the dev server. Deliberately not a preview of the\n * widget: an emulator can't match real Grist. It points at the loops worth\n * trusting: the widget in real Grist running in this browser (the demo page,\n * grist-static, on this dev server's build, so edits reload in place),\n * `pnpm test`, and the `dev` branch's preview inside a Grist document.\n */\nexport function LocalDevPage() {\n const hasDemo = useHasDemo()\n return (\n <main style={pageStyle}>\n <p style={eyebrowStyle}>{widgetTitle()} · local dev</p>\n <h1 style={headingStyle}>Not embedded in Grist</h1>\n <p style={leadStyle}>This is the local dev server: there's no Grist here to render the widget against.</p>\n\n <section style={cardStyle}>\n <h2 style={cardTitleStyle}>Open it in Grist, in this browser</h2>\n {hasDemo === false ? (\n <p style={cardTextStyle}>\n Run <code style={codeStyle}>pnpm demo --save</code> once (it needs Docker): it writes{\" \"}\n <code style={codeStyle}>public/demo/</code>, a document for this widget. Then{\" \"}\n <a href=\"demo/index.html\">demo/index.html</a> opens it in real Grist, running in the browser, on this dev server&apos;s\n widget: edits reload in place.\n </p>\n ) : (\n <p style={cardTextStyle}>\n <a href=\"demo/index.html\">Open demo/index.html</a>: real Grist running in the browser (no server, nothing saved), with\n this dev server&apos;s widget, so edits reload in place. Its document is{\" \"}\n <code style={codeStyle}>public/demo/demo.grist</code>: after changing the declared columns, run{\" \"}\n <code style={codeStyle}>pnpm demo --save</code> (Docker) to regenerate it.\n </p>\n )}\n </section>\n\n <section style={cardStyle}>\n <h2 style={cardTitleStyle}>Check it against real Grist</h2>\n <p style={cardTextStyle}>\n Push to <code style={codeStyle}>dev</code>, then open its <code style={codeStyle}>/dev/</code> URL in a\n custom widget of a real Grist document: later pushes reload it there within seconds. Locally,{\" \"}\n <code style={codeStyle}>pnpm test</code> runs the widget against an emulated Grist.\n </p>\n </section>\n\n <section style={cardStyle}>\n <h2 style={cardTitleStyle}>Starting from another example?</h2>\n <p style={cardTextStyle}>\n <code style={codeStyle}>npx create-grist-widget list</code> shows the examples, and{\" \"}\n <code style={codeStyle}>npx create-grist-widget use &lt;example&gt;</code> swaps this widget for one.\n </p>\n </section>\n </main>\n )\n}\n","import type { CSSProperties } from \"react\"\n\n/**\n * The chrome's colours and radius: shadcn's CSS variables, so the pages\n * follow a widget's theme (light, dark, its own palette) without depending\n * on its Tailwind config, with neutral fallbacks for a widget without them.\n * Same approach as GristBoundaryScreen.\n */\nconst token = (name: string, fallback: string) => `var(--${name}, ${fallback})`\n\nexport const tokens = {\n background: token(\"background\", \"#ffffff\"),\n foreground: token(\"foreground\", \"#0a0a0a\"),\n card: token(\"card\", \"#ffffff\"),\n mutedForeground: token(\"muted-foreground\", \"#737373\"),\n border: token(\"border\", \"#e5e5e5\"),\n primary: token(\"primary\", \"#171717\"),\n primaryForeground: token(\"primary-foreground\", \"#fafafa\"),\n destructive: token(\"destructive\", \"#dc2626\"),\n radius: token(\"radius\", \"0.625rem\"),\n} as const\n\nexport const pageStyle: CSSProperties = {\n boxSizing: \"border-box\",\n display: \"flex\",\n flexDirection: \"column\",\n justifyContent: \"center\",\n maxWidth: \"28rem\",\n minHeight: \"100%\",\n margin: \"0 auto\",\n padding: \"4rem 1.5rem\",\n color: tokens.foreground,\n font: \"inherit\",\n}\n\nexport const eyebrowStyle: CSSProperties = {\n margin: \"0 0 0.5rem\",\n textAlign: \"center\",\n fontSize: \"0.875rem\",\n fontWeight: 500,\n color: tokens.mutedForeground,\n}\n\nexport const headingStyle: CSSProperties = {\n margin: 0,\n textAlign: \"center\",\n fontSize: \"1.5rem\",\n fontWeight: 600,\n letterSpacing: \"-0.01em\",\n}\n\nexport const leadStyle: CSSProperties = {\n margin: \"0.75rem auto 2rem\",\n maxWidth: \"24rem\",\n textAlign: \"center\",\n fontSize: \"0.875rem\",\n lineHeight: 1.5,\n color: tokens.mutedForeground,\n}\n\nexport const cardStyle: CSSProperties = {\n boxSizing: \"border-box\",\n marginBottom: \"1rem\",\n padding: \"1.25rem\",\n border: `1px solid ${tokens.border}`,\n borderRadius: tokens.radius,\n background: tokens.card,\n}\n\nexport const cardTitleStyle: CSSProperties = {\n margin: \"0 0 0.375rem\",\n fontSize: \"1rem\",\n fontWeight: 600,\n}\n\nexport const cardTextStyle: CSSProperties = {\n margin: 0,\n fontSize: \"0.875rem\",\n lineHeight: 1.5,\n color: tokens.mutedForeground,\n}\n\nexport const codeStyle: CSSProperties = {\n fontFamily: \"ui-monospace, SFMono-Regular, Menlo, monospace\",\n fontSize: \"0.8125rem\",\n color: tokens.foreground,\n}\n","/**\n * The widget's name for the pages shown outside Grist: the page title,\n * which `create-grist-widget` sets to the widget's title in `index.html`.\n */\nexport function widgetTitle(): string {\n const title = typeof document === \"undefined\" ? \"\" : document.title.trim()\n return title || \"Grist widget\"\n}\n","import { useState, type CSSProperties } from \"react\"\n\nimport { deployChannelLabel, parseDeployPath, type DeployChannel } from \"../deploy-path\"\nimport { useReleasedVersions } from \"../released-versions\"\nimport {\n cardStyle,\n cardTextStyle,\n cardTitleStyle,\n codeStyle,\n eyebrowStyle,\n headingStyle,\n leadStyle,\n pageStyle,\n tokens,\n} from \"./tokens\"\nimport { widgetTitle } from \"./widget-title\"\n\n/**\n * Shown outside Grist on a deployed URL (`/latest/`, `/dev/`, `/v<version>/`\n * or the root): which build this is, links to the others, and the URL to\n * paste into a Grist custom widget.\n */\nexport function ReleasePage({ channel }: { channel: DeployChannel }) {\n const label = deployChannelLabel(channel)\n return (\n <main style={pageStyle}>\n <p style={eyebrowStyle}>\n {widgetTitle()} · {label}\n </p>\n <h1 style={headingStyle}>Grist isn't loaded here</h1>\n <p style={leadStyle}>\n This is the <code style={codeStyle}>{label}</code> build, opened outside Grist. Hover a version to see when it\n was released.\n </p>\n <ChannelLinks current={channel} />\n <InstallUrl />\n </main>\n )\n}\n\nfunction ChannelLinks({ current }: { current: DeployChannel }) {\n const { basePath } = parseDeployPath(window.location.pathname)\n const { versions } = useReleasedVersions()\n const isCurrent = (channel: DeployChannel) =>\n channel.kind === current.kind && (channel.kind !== \"version\" || (current.kind === \"version\" && channel.version === current.version))\n\n return (\n <nav aria-label=\"Versions\" style={{ display: \"flex\", flexWrap: \"wrap\", justifyContent: \"center\", gap: \"0.5rem\", marginBottom: \"2rem\" }}>\n <ChannelLink href={`${basePath}latest/`} active={isCurrent({ kind: \"latest\" })}>\n latest\n </ChannelLink>\n <ChannelLink href={`${basePath}dev/`} active={isCurrent({ kind: \"dev\" })}>\n dev\n </ChannelLink>\n {versions?.map((v) => (\n <ChannelLink\n key={v.version}\n href={`${basePath}v${v.version}/`}\n title={formatDate(v.publishedAt)}\n active={isCurrent({ kind: \"version\", version: v.version })}\n >\n {`v${v.version}`}\n </ChannelLink>\n ))}\n </nav>\n )\n}\n\nfunction ChannelLink({\n href,\n title,\n active,\n children,\n}: {\n href: string\n title?: string\n active: boolean\n children: string\n}) {\n const style: CSSProperties = {\n padding: \"0.25rem 0.75rem\",\n border: `1px solid ${active ? tokens.primary : tokens.border}`,\n borderRadius: \"9999px\",\n background: active ? tokens.primary : \"transparent\",\n color: active ? tokens.primaryForeground : tokens.mutedForeground,\n fontSize: \"0.75rem\",\n fontWeight: 500,\n textDecoration: \"none\",\n }\n return (\n <a href={href} title={title} aria-current={active ? \"page\" : undefined} style={style}>\n {children}\n </a>\n )\n}\n\nfunction InstallUrl() {\n const url = window.location.href\n const [copied, setCopied] = useState(false)\n\n function copy() {\n void navigator.clipboard?.writeText(url).then(() => {\n setCopied(true)\n setTimeout(() => setCopied(false), 1500)\n })\n }\n\n return (\n <section style={cardStyle}>\n <h2 style={cardTitleStyle}>Use it as a Grist custom widget</h2>\n <p style={{ ...cardTextStyle, marginBottom: \"1rem\" }}>Paste this URL into a custom widget's URL field in Grist.</p>\n <div style={{ display: \"flex\", gap: \"0.5rem\" }}>\n <input\n readOnly\n value={url}\n aria-label=\"Widget URL\"\n onFocus={(event) => event.target.select()}\n style={{\n flex: 1,\n minWidth: 0,\n padding: \"0.5rem 0.75rem\",\n border: `1px solid ${tokens.border}`,\n borderRadius: tokens.radius,\n background: \"transparent\",\n color: tokens.foreground,\n font: \"inherit\",\n fontSize: \"0.875rem\",\n }}\n />\n <button\n type=\"button\"\n onClick={copy}\n style={{\n padding: \"0.5rem 1rem\",\n border: \"none\",\n borderRadius: tokens.radius,\n background: tokens.primary,\n color: tokens.primaryForeground,\n font: \"inherit\",\n fontSize: \"0.875rem\",\n fontWeight: 500,\n cursor: \"pointer\",\n }}\n >\n {copied ? \"Copied\" : \"Copy\"}\n </button>\n </div>\n </section>\n )\n}\n\nfunction formatDate(iso: string): string {\n const date = new Date(iso)\n return Number.isNaN(date.getTime())\n ? iso\n : date.toLocaleDateString(undefined, { year: \"numeric\", month: \"short\", day: \"numeric\" })\n}\n","/**\n * Where a deployed build is being served from.\n *\n * A widget's deploy pipeline publishes the same build at its root and at\n * `/latest/`, a preview at `/dev/`, and each release at `/v<version>/`, all\n * under one base path (e.g. `/my-widget/` on GitHub Pages). Opened outside\n * Grist, the page tells them apart from `window.location.pathname` alone.\n */\nexport type DeployChannel =\n | { kind: \"latest\" }\n | { kind: \"dev\" }\n | { kind: \"version\"; version: string }\n\nexport type DeployPath = {\n channel: DeployChannel\n /**\n * The path the channels live under, always ending in `/`: the current\n * path without its channel segment. `\"/my-widget/v1.2.0/\"` gives\n * `\"/my-widget/\"`.\n */\n basePath: string\n}\n\nconst VERSION_SEGMENT = /^v(\\d+\\.\\d+\\.\\d+(?:-[\\w.]+)?)$/\n\n/**\n * Parse a pathname into its deploy channel and base path. A path without a\n * channel segment (the deployed root, or a local dev server) is `latest`:\n * the deploy places the latest release at the root too.\n */\nexport function parseDeployPath(pathname: string): DeployPath {\n const segments = pathname.replace(/\\/+$/, \"\").split(\"/\")\n const last = segments[segments.length - 1] ?? \"\"\n\n let channel: DeployChannel | null = null\n if (last === \"latest\") channel = { kind: \"latest\" }\n else if (last === \"dev\") channel = { kind: \"dev\" }\n else {\n const match = VERSION_SEGMENT.exec(last)\n if (match) channel = { kind: \"version\", version: match[1] }\n }\n\n if (!channel) return { channel: { kind: \"latest\" }, basePath: withTrailingSlash(pathname) }\n return { channel, basePath: withTrailingSlash(segments.slice(0, -1).join(\"/\")) }\n}\n\n/** `\"latest\"`, `\"dev\"` or `\"v1.2.0\"`. */\nexport function deployChannelLabel(channel: DeployChannel): string {\n return channel.kind === \"version\" ? `v${channel.version}` : channel.kind\n}\n\nfunction withTrailingSlash(path: string): string {\n return path.endsWith(\"/\") ? path : `${path}/`\n}\n","import { useEffect, useState } from \"react\"\n\nimport { parseDeployPath } from \"./deploy-path\"\n\n/** One entry of the `versions.json` a widget's deploy pipeline maintains. */\nexport type ReleasedVersion = {\n version: string\n publishedAt: string\n}\n\nexport type UseReleasedVersionsResult = {\n /** Newest first, as the deploy writes them; `null` until loaded. */\n versions: ReleasedVersion[] | null\n /** `true` when `versions.json` couldn't be fetched or read. */\n error: boolean\n}\n\n/**\n * The widget's released versions, read from the `versions.json` next to its\n * channels (see {@link parseDeployPath}). For a page shown outside Grist,\n * such as a release page linking to each version.\n */\nexport function useReleasedVersions(\n pathname: string = typeof window === \"undefined\" ? \"/\" : window.location.pathname\n): UseReleasedVersionsResult {\n const url = `${parseDeployPath(pathname).basePath}versions.json`\n const [result, setResult] = useState<UseReleasedVersionsResult>({ versions: null, error: false })\n\n useEffect(() => {\n let cancelled = false\n fetch(url, { cache: \"no-store\" })\n .then((res) => (res.ok ? res.json() : Promise.reject(new Error(`HTTP ${res.status}`))))\n .then((data: unknown) => {\n if (cancelled) return\n if (!Array.isArray(data)) throw new Error(\"versions.json is not an array\")\n setResult({ versions: data as ReleasedVersion[], error: false })\n })\n .catch(() => {\n if (!cancelled) setResult({ versions: null, error: true })\n })\n return () => {\n cancelled = true\n }\n }, [url])\n\n return result\n}\n","/**\n * The alerts `mountGristWidget()` shows above a running widget: what needs the\n * user's attention in Grist (column mapping, access, a failed write, an\n * unlinked section). The blocking states (not connected, access refused,\n * required columns unmapped) are `<GristBoundary>`'s, not alerts.\n */\n\nimport { useNearestGristState } from \"../use-grist\"\nimport { deriveColumnMappingStatus, deriveStatus } from \"../runtime/derive\"\nimport { isAccessInsufficientError } from \"../runtime/api\"\nimport type { GristCellIssue } from \"../runtime/cells\"\nimport type { GristRuntimeState } from \"../runtime/runtime\"\nimport type { GristColumnsToMap, GristWidgetInteraction } from \"../types\"\nimport { parseGristWidgetLinkingInfo } from \"./grist-widget-interaction\"\n\nexport type GristSdkAlertKind =\n | \"column-mapping\"\n | \"mapping-pending\"\n | \"section-not-linked\"\n | \"source-not-wired\"\n | \"action-error\"\n | \"access-insufficient\"\n | \"map-back-skip\"\n | \"cell-issues\"\n\nexport type GristSdkAlertSeverity = \"info\" | \"warning\" | \"error\"\n\nexport type GristSdkAlertDescriptor = {\n id: string\n kind: GristSdkAlertKind\n severity: GristSdkAlertSeverity\n title: string\n ariaRole: \"status\" | \"alert\"\n message: string\n}\n\nexport type GristSdkAlertsOptions = {\n /** Added to the \"section not linked\" message, e.g. how to link in Grist. */\n sectionNotLinkedHint?: string\n}\n\nconst TITLE: Record<GristSdkAlertKind, string> = {\n \"column-mapping\": \"Column mapping\",\n \"mapping-pending\": \"Column mapping\",\n \"section-not-linked\": \"Widget linking\",\n \"source-not-wired\": \"Widget linking\",\n \"action-error\": \"Action error\",\n \"access-insufficient\": \"Access level\",\n \"map-back-skip\": \"Write skipped\",\n \"cell-issues\": \"Unexpected values\",\n}\n\nconst SEVERITY: Record<GristSdkAlertKind, GristSdkAlertSeverity> = {\n \"column-mapping\": \"warning\",\n \"mapping-pending\": \"info\",\n \"section-not-linked\": \"warning\",\n \"source-not-wired\": \"warning\",\n \"action-error\": \"error\",\n \"access-insufficient\": \"error\",\n \"map-back-skip\": \"warning\",\n \"cell-issues\": \"warning\",\n}\n\nconst alert = (kind: GristSdkAlertKind, message: string, ariaRole: \"status\" | \"alert\" = \"status\"): GristSdkAlertDescriptor => ({\n id: kind,\n kind,\n severity: SEVERITY[kind],\n title: TITLE[kind],\n ariaRole,\n message,\n})\n\n/** A widget section Grist says is linked to nothing. */\nexport function isWidgetSectionNotLinked(interaction: GristWidgetInteraction | null | undefined): boolean {\n const linking = parseGristWidgetLinkingInfo(interaction?.linking)\n return Boolean(linking) && linking!.asTarget == null\n}\n\n/** The alerts for a widget in `state`, pure (tested without React). */\nexport function getGristSdkAlerts(\n state: GristRuntimeState,\n widget: {\n columns?: GristColumnsToMap\n allowSelectBy?: boolean\n suppressAlerts?: readonly GristSdkAlertKind[]\n cellIssues?: readonly GristCellIssue[]\n },\n options: GristSdkAlertsOptions = {}\n): GristSdkAlertDescriptor[] {\n if (deriveStatus(state) !== \"ready\") return []\n const out: GristSdkAlertDescriptor[] = []\n\n const mapping = deriveColumnMappingStatus(widget.columns, state.mappings)\n if (mapping.pending) out.push(alert(\"mapping-pending\", \"Waiting for Grist to report column mappings.\"))\n else if (!mapping.ok) {\n const parts = [\"Column mapping is incomplete.\"]\n if (mapping.missing.length) parts.push(`Required columns: ${mapping.missing.join(\", \")}.`)\n if (mapping.emptyMultiples.length) parts.push(`Assign at least one sheet column for: ${mapping.emptyMultiples.join(\", \")}.`)\n out.push(alert(\"column-mapping\", parts.join(\" \")))\n }\n\n const failure = state.actionError ?? state.readError\n if (failure && isAccessInsufficientError(failure)) {\n out.push(\n alert(\n \"access-insufficient\",\n 'This operation requires \"Full document access\". Set the Access level to \"Full document access\" in the Custom widget configuration panel.',\n \"alert\"\n )\n )\n } else if (state.actionError) {\n out.push(alert(\"action-error\", state.actionError, \"alert\"))\n }\n\n if (state.mapBackSkipped.length) {\n const list = state.mapBackSkipped.join(\", \")\n out.push(alert(\"map-back-skip\", `mapBack skipped multi-mapped column${state.mapBackSkipped.length === 1 ? \"\" : \"s\"}: ${list}.`))\n }\n\n const cellIssues = widget.cellIssues ?? []\n if (cellIssues.length) {\n const first = cellIssues[0]!\n const where = first.column ? `${first.column} in row ${first.rowId}` : `row ${first.rowId}`\n const more = cellIssues.length > 1 ? ` (and ${cellIssues.length - 1} more)` : \"\"\n out.push(alert(\"cell-issues\", `${where}: ${first.message}${more}. Check the column's type, or the cell, in Grist.`))\n }\n\n const linking = parseGristWidgetLinkingInfo(state.interaction?.linking)\n if (widget.allowSelectBy) {\n if (linking && !linking.asSource) {\n out.push(\n alert(\n \"source-not-wired\",\n \"This widget is configured as a selector (allowSelectBy) but no other section is using it as a link source yet. Link another section to read from this widget.\"\n )\n )\n }\n } else if (isWidgetSectionNotLinked(state.interaction)) {\n const hint = options.sectionNotLinkedHint?.trim()\n out.push(\n alert(\n \"section-not-linked\",\n \"This widget section is not linked to a table or selector. Link it from the page settings so the selected row is sent to the widget.\" +\n (hint ? ` ${hint}` : \"\")\n )\n )\n }\n\n const suppressed = widget.suppressAlerts ?? []\n return out.filter((a) => !suppressed.includes(a.kind))\n}\n\n/** @internal The alerts for the widget under the nearest `<GristWidgetProvider>`; [] outside one. */\nexport function useGristSdkAlerts(options?: GristSdkAlertsOptions): GristSdkAlertDescriptor[] {\n const { connection, state, cellIssues } = useNearestGristState()\n if (!connection) return []\n const { columns, allowSelectBy, suppressAlerts } = connection.runtime.options\n return getGristSdkAlerts(state, { columns, allowSelectBy, suppressAlerts, cellIssues }, options)\n}\n","import type { CSSProperties, ReactNode } from \"react\"\n\nimport { useGristSdkAlerts, type GristSdkAlertDescriptor, type GristSdkAlertsOptions } from \"../../sdk/helpers/grist-sdk-alerts\"\nimport { tokens } from \"./tokens\"\n\nconst ALERT_OPTIONS: GristSdkAlertsOptions = {\n sectionNotLinkedHint:\n \"In Grist, select this widget section on the page, then use Link to connect a table, card, or chart view as the selector.\",\n}\n\n/**\n * The default `Alerts` of {@link mountGristWidget}: what needs the user's\n * attention (column mapping, access level, failed writes, an unlinked\n * section), above the widget. Renders nothing extra when all is well.\n */\nexport function WidgetAlerts({ children }: { children: ReactNode }) {\n const alerts = useGristSdkAlerts(ALERT_OPTIONS)\n if (alerts.length === 0) return <>{children}</>\n\n return (\n <div style={{ display: \"flex\", flexDirection: \"column\", gap: \"0.75rem\" }}>\n <div style={{ display: \"flex\", flexDirection: \"column\", gap: \"0.75rem\", padding: \"0.75rem 0.75rem 0\" }}>\n {alerts.map((alert) => (\n <WidgetAlert key={alert.id} alert={alert} />\n ))}\n </div>\n {children}\n </div>\n )\n}\n\nfunction WidgetAlert({ alert }: { alert: GristSdkAlertDescriptor }) {\n const linkIcon = alert.kind === \"section-not-linked\" || alert.kind === \"source-not-wired\"\n return (\n <div role={alert.ariaRole} style={{ ...alertStyle, ...SEVERITY[alert.severity] }}>\n <span aria-hidden style={{ flexShrink: 0, marginTop: \"0.125rem\" }}>\n {linkIcon ? <LinkIcon /> : <WarningIcon />}\n </span>\n <div style={{ minWidth: 0 }}>\n <p style={{ margin: 0, fontWeight: 500 }}>{alert.title}</p>\n <p style={{ margin: \"0.25rem 0 0\", color: tokens.mutedForeground }}>{alert.message}</p>\n </div>\n </div>\n )\n}\n\nconst alertStyle: CSSProperties = {\n boxSizing: \"border-box\",\n display: \"flex\",\n gap: \"0.75rem\",\n padding: \"0.75rem 1rem\",\n border: `1px solid ${tokens.border}`,\n borderRadius: tokens.radius,\n color: tokens.foreground,\n fontSize: \"0.875rem\",\n lineHeight: 1.5,\n}\n\nconst SEVERITY: Record<GristSdkAlertDescriptor[\"severity\"], CSSProperties> = {\n error: { borderColor: tokens.destructive, color: tokens.destructive },\n warning: { borderColor: \"rgb(245 158 11 / 0.4)\", background: \"rgb(245 158 11 / 0.1)\" },\n info: { background: \"transparent\" },\n}\n\nconst ICON = {\n width: 16,\n height: 16,\n viewBox: \"0 0 24 24\",\n fill: \"none\",\n stroke: \"currentColor\",\n strokeWidth: 2,\n strokeLinecap: \"round\",\n strokeLinejoin: \"round\",\n} as const\n\nfunction WarningIcon() {\n return (\n <svg {...ICON}>\n <path d=\"m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3\" />\n <path d=\"M12 9v4\" />\n <path d=\"M12 17h.01\" />\n </svg>\n )\n}\n\nfunction LinkIcon() {\n return (\n <svg {...ICON}>\n <path d=\"M9 17H7A5 5 0 0 1 7 7h2\" />\n <path d=\"M15 7h2a5 5 0 1 1 0 10h-2\" />\n <line x1=\"8\" x2=\"16\" y1=\"12\" y2=\"12\" />\n </svg>\n )\n}\n","import { createContext, useCallback, useContext, useEffect, useMemo, useState, type ReactNode } from \"react\"\n\nimport { useNearestGristState } from \"../sdk/use-grist\"\n\nexport type WidgetTheme = \"light\" | \"dark\" | \"system\"\nexport type ResolvedWidgetTheme = \"light\" | \"dark\"\n\nexport type UseThemeResult = {\n /**\n * Inside Grist: Grist's theme, or `\"system\"` until Grist has sent it.\n * Outside Grist: the saved choice, `\"system\"` by default.\n */\n theme: WidgetTheme\n /** The theme applied to `<html class>`: `\"system\"` resolved to light or dark. */\n resolvedTheme: ResolvedWidgetTheme\n /**\n * Choose a theme outside Grist; it is saved in `localStorage`. Inside Grist\n * this does nothing: the widget follows Grist's theme.\n */\n setTheme: (theme: WidgetTheme) => void\n}\n\nconst STORAGE_KEY = \"theme\"\nconst DARK_QUERY = \"(prefers-color-scheme: dark)\"\nconst THEMES: readonly WidgetTheme[] = [\"light\", \"dark\", \"system\"]\n\nconst ThemeContext = createContext<UseThemeResult | null>(null)\n\n/**\n * The widget's current theme, for components that need it in JavaScript\n * (a toaster, a chart). Same shape as shadcn's `useTheme()`. Styles should\n * rely on the `dark` class that {@link mountGristWidget} keeps on `<html>`.\n * Outside a mounted widget (a unit test, for instance) it reports the\n * system theme and `setTheme` does nothing.\n */\nexport function useTheme(): UseThemeResult {\n const value = useContext(ThemeContext)\n return value ?? { theme: \"system\", resolvedTheme: systemTheme(), setTheme: noop }\n}\n\n/** Inside Grist: follows Grist's theme, and the OS setting until Grist sends one. */\nexport function EmbeddedThemeProvider({ children }: { children: ReactNode }) {\n const gristTheme = useNearestGristState().state.theme\n const system = useSystemTheme(gristTheme === null)\n const resolvedTheme = gristTheme ?? system\n\n useApplyTheme(resolvedTheme)\n\n const value = useMemo<UseThemeResult>(\n () => ({ theme: gristTheme ?? \"system\", resolvedTheme, setTheme: noop }),\n [gristTheme, resolvedTheme]\n )\n return <ThemeContext.Provider value={value}>{children}</ThemeContext.Provider>\n}\n\n/**\n * Outside Grist (`pnpm dev`, the deployed release page): the saved choice,\n * the OS setting by default, and the `d` key to switch between light and\n * dark, as shadcn's theme provider does.\n */\nexport function StandaloneThemeProvider({ children }: { children: ReactNode }) {\n const [theme, setThemeState] = useState<WidgetTheme>(() => readStoredTheme() ?? \"system\")\n const system = useSystemTheme(theme === \"system\")\n const resolvedTheme = theme === \"system\" ? system : theme\n\n useApplyTheme(resolvedTheme)\n\n const setTheme = useCallback((next: WidgetTheme) => {\n writeStoredTheme(next)\n setThemeState(next)\n }, [])\n\n // `d` switches between light and dark, unless typing or using a shortcut.\n useEffect(() => {\n const onKeyDown = (event: KeyboardEvent) => {\n if (event.repeat || event.metaKey || event.ctrlKey || event.altKey) return\n if (event.key.toLowerCase() !== \"d\" || isEditableTarget(event.target)) return\n setThemeState((current) => {\n const currentResolved = current === \"system\" ? systemTheme() : current\n const next: WidgetTheme = currentResolved === \"dark\" ? \"light\" : \"dark\"\n writeStoredTheme(next)\n return next\n })\n }\n window.addEventListener(\"keydown\", onKeyDown)\n return () => window.removeEventListener(\"keydown\", onKeyDown)\n }, [])\n\n // Another tab saving a choice applies here too.\n useEffect(() => {\n const onStorage = (event: StorageEvent) => {\n if (event.key !== STORAGE_KEY) return\n setThemeState(isTheme(event.newValue) ? event.newValue : \"system\")\n }\n window.addEventListener(\"storage\", onStorage)\n return () => window.removeEventListener(\"storage\", onStorage)\n }, [])\n\n const value = useMemo<UseThemeResult>(\n () => ({ theme, resolvedTheme, setTheme }),\n [theme, resolvedTheme, setTheme]\n )\n return <ThemeContext.Provider value={value}>{children}</ThemeContext.Provider>\n}\n\n/** The OS setting, kept current while `active`. */\nfunction useSystemTheme(active: boolean): ResolvedWidgetTheme {\n const [theme, setTheme] = useState<ResolvedWidgetTheme>(systemTheme)\n\n useEffect(() => {\n if (!active || typeof window.matchMedia !== \"function\") return\n const query = window.matchMedia(DARK_QUERY)\n const onChange = () => setTheme(query.matches ? \"dark\" : \"light\")\n onChange()\n query.addEventListener(\"change\", onChange)\n return () => query.removeEventListener(\"change\", onChange)\n }, [active])\n\n return theme\n}\n\n/** Keep `light` or `dark` on `<html class>`, which Tailwind's dark variant reads. */\nfunction useApplyTheme(theme: ResolvedWidgetTheme) {\n useEffect(() => {\n const root = document.documentElement\n if (root.classList.contains(theme) && !root.classList.contains(other(theme))) return\n const restoreTransitions = suspendTransitions()\n root.classList.remove(other(theme))\n root.classList.add(theme)\n restoreTransitions()\n }, [theme])\n}\n\nfunction systemTheme(): ResolvedWidgetTheme {\n if (typeof window === \"undefined\" || typeof window.matchMedia !== \"function\") return \"light\"\n return window.matchMedia(DARK_QUERY).matches ? \"dark\" : \"light\"\n}\n\nfunction other(theme: ResolvedWidgetTheme): ResolvedWidgetTheme {\n return theme === \"dark\" ? \"light\" : \"dark\"\n}\n\n/** Switch themes without every color transition animating at once. */\nfunction suspendTransitions(): () => void {\n const style = document.createElement(\"style\")\n style.appendChild(\n document.createTextNode(\"*,*::before,*::after{-webkit-transition:none!important;transition:none!important}\")\n )\n document.head.appendChild(style)\n return () => {\n window.getComputedStyle(document.body)\n requestAnimationFrame(() => requestAnimationFrame(() => style.remove()))\n }\n}\n\nfunction isEditableTarget(target: EventTarget | null): boolean {\n if (!(target instanceof HTMLElement)) return false\n return target.isContentEditable || target.closest(\"input, textarea, select, [contenteditable='true']\") !== null\n}\n\nfunction isTheme(value: string | null): value is WidgetTheme {\n return value !== null && (THEMES as readonly string[]).includes(value)\n}\n\nfunction readStoredTheme(): WidgetTheme | null {\n try {\n const value = localStorage.getItem(STORAGE_KEY)\n return isTheme(value) ? value : null\n } catch {\n return null\n }\n}\n\nfunction writeStoredTheme(theme: WidgetTheme) {\n try {\n localStorage.setItem(STORAGE_KEY, theme)\n } catch {\n // Storage blocked (private mode, sandboxed iframe): the choice lasts for this page only.\n }\n}\n\nfunction noop() {}\n"],"mappings":"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","names":["import_react","token","token","message","message","ACCESS_RANK","inFlight","import_react","import_react","import_jsx_runtime","message","import_react","import_react","cardStyle","import_jsx_runtime","cardStyle","import_react","import_react","import_jsx_runtime","cardStyle","message","import_jsx_runtime","alert","SEVERITY","import_react","import_jsx_runtime","import_jsx_runtime","LocalDevPage","ReleasePage","isEmbedded"]}