grist-widget-sdk 0.2.15 → 0.3.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +23 -0
- package/README.md +2 -2
- package/dist/advanced.js +3 -2
- package/dist/advanced.js.map +1 -1
- package/dist/{chunk-ER6UWHZA.js → chunk-7GXVEZ2J.js} +2 -2
- package/dist/{chunk-KOVYBNPJ.js → chunk-D5GBS2NT.js} +8 -31
- package/dist/chunk-D5GBS2NT.js.map +1 -0
- package/dist/chunk-N3X46JW2.js +37 -0
- package/dist/chunk-N3X46JW2.js.map +1 -0
- package/dist/emulator/devtools.cjs +37 -0
- package/dist/emulator/devtools.cjs.map +1 -1
- package/dist/emulator/devtools.js +28 -0
- package/dist/emulator/devtools.js.map +1 -1
- package/dist/emulator/testing.cjs.map +1 -1
- package/dist/emulator/testing.js +2 -1
- package/dist/emulator/testing.js.map +1 -1
- package/dist/index.js +5 -3
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/dist/chunk-KOVYBNPJ.js.map +0 -1
- /package/dist/{chunk-ER6UWHZA.js.map → chunk-7GXVEZ2J.js.map} +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/emulator/testing/index.ts","../../src/emulator/testing/render-with-grist.tsx","../../src/sdk/helpers/grist-widget-interaction.ts","../../src/sdk/internal/subscriptions.ts","../../src/sdk/internal/embedded-handshake-manager.ts","../../src/sdk/internal/ready-singleton.ts","../../src/emulator/api/command-api.ts","../../src/emulator/core/mappings.ts","../../src/emulator/api/custom-section-api.ts","../../src/emulator/api/grist-api.ts","../../src/sdk/helpers/grist-value-codec.ts","../../src/sdk/helpers/grist-safe-parse.ts","../../src/sdk/helpers/replica-normalize.ts","../../src/emulator/core/document.ts","../../src/emulator/core/action-engine.ts","../../src/emulator/core/columnar.ts","../../src/emulator/api/grist-doc-api.ts","../../src/emulator/api/grist-view.ts","../../src/emulator/api/widget-api.ts","../../src/emulator/api/index.ts","../../src/emulator/core/event-bus.ts","../../src/emulator/theme-message.ts","../../src/emulator/transports/iframe.ts","../../src/sdk/helpers/grist-user-actions.ts","../../src/emulator/transports/inline.ts","../../src/emulator/validators.ts","../../src/emulator/create-grist-emulator.ts","../../src/emulator/templates.ts","../../src/emulator/testing/matchers.ts"],"sourcesContent":["/**\n * Test entry point — `grist-widget-sdk/emulator/testing`.\n *\n * Bundles `renderWithGrist`, matchers, document presets, and the most-used\n * @testing-library/react primitives so a typical test file only needs one\n * import line:\n *\n * import {\n * renderWithGrist, presets, screen, fireEvent, waitFor, actionsOf,\n * } from \"grist-widget-sdk/emulator/testing\"\n */\n\nexport { renderWithGrist } from \"./render-with-grist\"\nexport type {\n RenderWithGristOptions,\n RenderWithGristResult,\n} from \"./render-with-grist\"\n\nexport {\n actionsOf,\n eventsOf,\n waitForEvent,\n type WaitForEventKind,\n type WaitForEventOptions,\n} from \"./matchers\"\n\n// Document fixtures (re-export from the emulator entry for convenience).\nexport { presets } from \"../templates\"\n\n// @testing-library/react convenience re-exports — see apps/docs/work.md\nexport {\n act,\n cleanup,\n fireEvent,\n render,\n screen,\n waitFor,\n within,\n} from \"@testing-library/react\"\nexport type { RenderOptions, RenderResult } from \"@testing-library/react\"\n","/**\n * `renderWithGrist(ui, options)` — drop-in replacement for\n * `@testing-library/react`'s `render(ui)` that boots a Grist emulator\n * (inline transport) and exposes it to the test.\n *\n * The emulator is mounted as `window.grist`. The SDK hooks (`useGrist`,\n * `useGristReady`, etc.) detect it via the same path they use in production.\n *\n * Cleanup is automatic when the test's container unmounts.\n */\n\nimport type { ReactElement } from \"react\"\n\nimport { render, type RenderOptions, type RenderResult } from \"@testing-library/react\"\n\nimport { resetEmbeddedHandshakeManagerForTests } from \"../../sdk/internal/embedded-handshake-manager\"\nimport { resetGristReadyCacheForTests } from \"../../sdk/internal/ready-singleton\"\nimport { resetGristEventsForTests } from \"../../sdk/internal/subscriptions\"\nimport { createGristEmulator } from \"../create-grist-emulator\"\nimport type { CreateGristEmulatorOptions, GristEmulator } from \"../create-grist-emulator\"\nimport { presets } from \"../templates\"\n\nexport type RenderWithGristOptions = RenderOptions & {\n emulator?: CreateGristEmulatorOptions\n /** Skip mounting the emulator; you bring your own. Useful for shared fixtures. */\n existing?: GristEmulator\n}\n\nexport type RenderWithGristResult = RenderResult & {\n emulator: GristEmulator\n}\n\nexport function renderWithGrist(\n ui: ReactElement,\n options: RenderWithGristOptions = {}\n): RenderWithGristResult {\n // Make `window.self !== window.top` evaluate to `true` so\n // `useGristAvailability` reports the widget as embedded. We only do this in\n // jsdom; real browsers already enforce this distinction for iframes.\n fakeIframeContext()\n\n resetGristEventsForTests()\n resetGristReadyCacheForTests()\n resetEmbeddedHandshakeManagerForTests()\n\n const emulator =\n options.existing ??\n createGristEmulator(options.emulator ?? { document: presets.blank() })\n\n const result = render(ui, options)\n const originalUnmount = result.unmount\n result.unmount = () => {\n originalUnmount()\n if (!options.existing) emulator.dispose()\n resetGristReadyCacheForTests()\n resetGristEventsForTests()\n resetEmbeddedHandshakeManagerForTests()\n }\n return Object.assign(result, { emulator })\n}\n\nfunction fakeIframeContext() {\n if (typeof window === \"undefined\") return\n if (window.self !== window.top) return // already iframe-like\n try {\n Object.defineProperty(window, \"top\", {\n configurable: true,\n get: () => ({}),\n })\n } catch {\n // Some jsdom versions block redefinition; fail silently — tests using\n // `useGristAvailability` will need to bypass it explicitly in that case.\n }\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 * Module-level subscription manager for Grist's `on*` events.\n *\n * Why this exists: `grist.onRecord`, `onRecords`, `onOptions`, and `onNewRecord`\n * are add-only — there is no `off`. Subscribing in every hook instance leaks\n * handlers for the page lifetime. This module subscribes to each Grist event\n * **at most once** and fans out to React listeners with proper teardown.\n *\n * Last-known values are cached so late subscribers immediately receive the\n * current state (analogous to a BehaviorSubject).\n *\n * Fixed-defaults contract\n * -----------------------\n * The underlying `grist.onRecord` / `onRecords` calls accept a\n * `FetchSelectedOptions` parameter (e.g. `keepEncoded`, `format`), but\n * because we bind **once** at the first subscribe, those options would be\n * \"first-hook-wins\" across the page — a subtle footgun for agents.\n *\n * This module therefore binds with Grist's **public defaults** and does not\n * accept per-subscriber options:\n * - `onRecord` → decoded rows (`keepEncoded: false`)\n * - `onRecords` → decoded rows (`format: \"rows\"`, `keepEncoded: false`)\n *\n * If you need encoded values, use the one-shot readers\n * (`useGrist().fetchSelectedTable({ keepEncoded: true })`) instead of\n * a subscription — that call-site controls its own options.\n */\n\nimport { normalizeWidgetInteraction } from \"../helpers/grist-widget-interaction\"\nimport type { GristWidgetColumnMap, GristWidgetInteraction } from \"../types\"\n\ntype Listener<T> = (value: T) => void\n\nclass GristEvent<T> {\n private listeners = new Set<Listener<T>>()\n private hasValue = false\n private last: T | undefined\n private bind: (() => void) | null = null\n\n constructor(private readonly bindOnce: (emit: (value: T) => void) => void) {}\n\n subscribe(listener: Listener<T>): () => void {\n this.listeners.add(listener)\n if (!this.bind) {\n this.bind = () => {\n // Mark as bound regardless of throw, so we don't retry every render.\n this.bind = () => {}\n try {\n this.bindOnce((value) => {\n this.hasValue = true\n this.last = value\n for (const l of this.listeners) l(value)\n })\n } catch (err) {\n if (typeof console !== \"undefined\") {\n console.error(\"[lib/grist] failed to subscribe to Grist event:\", err)\n }\n }\n }\n this.bind()\n }\n if (this.hasValue && this.last !== undefined) {\n listener(this.last)\n }\n return () => {\n this.listeners.delete(listener)\n }\n }\n\n /** Last cached value (or `undefined` if no event has fired yet). */\n peek(): T | undefined {\n return this.last\n }\n\n /** True once at least one event has fired. */\n get ready(): boolean {\n return this.hasValue\n }\n\n /**\n * Test helper: fan out a payload without calling `grist.on*`.\n * Used to simulate hosts that reuse one record object and mutate it in place.\n */\n deliverForTests(value: T): void {\n this.hasValue = true\n this.last = value\n for (const l of this.listeners) l(value)\n }\n\n /**\n * Test helper: forget the bound state and cached value. Lets a test swap\n * `window.grist` (e.g. via the emulator's `dispose()` + `createGristEmulator()`)\n * and re-bind cleanly on the next subscribe.\n */\n _resetForTests(): void {\n this.listeners.clear()\n this.hasValue = false\n this.last = undefined\n this.bind = null\n }\n}\n\nexport type GristRecordPayload = {\n record: Record<string, unknown> | null\n mappings: GristWidgetColumnMap | null\n}\n\nexport type GristRecordsPayload = {\n records: Record<string, unknown>[]\n mappings: GristWidgetColumnMap | null\n}\n\nexport type GristOptionsPayload = {\n options: Record<string, unknown> | null\n interaction: GristWidgetInteraction | null\n}\n\nexport type GristNewRecordPayload = {\n mappings: GristWidgetColumnMap | null\n}\n\n/**\n * The singletons. These are lazy: nothing is registered with `grist` until\n * the first `subscribe()` call.\n */\ntype GristHostMessage = {\n tableId?: string\n rowId?: number | \"new\"\n dataChange?: boolean\n mappingsChange?: boolean\n}\n\nexport const recordEvent = new GristEvent<GristRecordPayload>((emit) => {\n const deliver = (record: Record<string, unknown> | null, mappings: GristWidgetColumnMap | null) => {\n emit({ record, mappings })\n }\n\n // Pin `keepEncoded: false` so mapped records contain JS-native values for\n // widget code instead of raw cell tuples.\n grist.onRecord(\n (record, mappings) => {\n deliver(record, (mappings as GristWidgetColumnMap | null) ?? null)\n },\n { keepEncoded: false }\n )\n\n // Mirror grist-plugin-api's `onRecord` message handler: Grist's RecordNotifier\n // posts `{ rowId, dataChange: false }` on cursor moves. `onRecord` should\n // handle that, but refetch here when `rowId` changes so widgets never stick on\n // the first row if the callback path is skipped or reordered.\n const fetchSelectedRecord = grist.fetchSelectedRecord ?? grist.docApi?.fetchSelectedRecord\n if (typeof grist.on !== \"function\" || typeof fetchSelectedRecord !== \"function\") {\n return\n }\n let lastRowId: number | undefined\n grist.on(\"message\", async (msg: unknown) => {\n if (!msg || typeof msg !== \"object\") return\n const host = msg as GristHostMessage\n if (!host.tableId || typeof host.rowId !== \"number\") return\n if (host.rowId === lastRowId) return\n lastRowId = host.rowId\n try {\n const record = await fetchSelectedRecord(host.rowId, { keepEncoded: false })\n deliver(record, recordEvent.peek()?.mappings ?? null)\n } catch (err) {\n if (typeof console !== \"undefined\") {\n console.error(\"[grist-widget-sdk] fetchSelectedRecord on cursor message failed:\", err)\n }\n }\n })\n})\n\nexport const recordsEvent = new GristEvent<GristRecordsPayload>((emit) => {\n // Pin `format: \"rows\"` + `keepEncoded: false` so callers always receive\n // row-shaped decoded objects. (GristView would otherwise default to\n // `format: \"columns\"` + `keepEncoded: true`.)\n grist.onRecords(\n (records, mappings) => {\n emit({ records, mappings: (mappings as GristWidgetColumnMap | null) ?? null })\n },\n { keepEncoded: false, format: \"rows\" }\n )\n})\n\nexport const optionsEvent = new GristEvent<GristOptionsPayload>((emit) => {\n grist.onOptions((options, interaction) => {\n const normalized = normalizeWidgetInteraction(\n (interaction as GristWidgetInteraction | null) ?? null\n )\n emit({\n options: options ? { ...options } : null,\n interaction: normalized,\n })\n })\n})\n\nexport const newRecordEvent = new GristEvent<GristNewRecordPayload>((emit) => {\n if (typeof grist.onNewRecord !== \"function\") return\n grist.onNewRecord((mappings) => {\n emit({ mappings: (mappings as GristWidgetColumnMap | null) ?? null })\n })\n})\n\n/**\n * Test-only: reset every event singleton. Call between tests when swapping\n * `window.grist`. Production code never imports this.\n */\nexport function resetGristEventsForTests(): void {\n recordEvent._resetForTests()\n recordsEvent._resetForTests()\n optionsEvent._resetForTests()\n newRecordEvent._resetForTests()\n}\n\n/** Vitest-only: push a record payload through {@link recordEvent} subscribers. */\nexport function deliverRecordForTests(payload: GristRecordPayload): void {\n recordEvent.deliverForTests(payload)\n}\n","/**\n * Page-level embedded handshake manager for widgets that call `useGrist()` /\n * `useGristCore()` without mounting `<GristWidgetProvider>`.\n *\n * A single manager is shared across all hook instances on the page (ref-counted)\n * so mid-level hooks (`useGristActions`, `useGristRowsFromTable`, …) do not\n * spawn competing `grist.ready` handshakes.\n */\n\nimport {\n createGristHandshakeManager,\n type ManagerControls,\n type ManagerOptions,\n} from \"./handshake/manager\"\n\ntype EmbeddedSlot = {\n manager: ManagerControls\n refCount: number\n}\n\nlet embedded: EmbeddedSlot | null = null\n\nexport function acquireEmbeddedHandshakeManager(options: ManagerOptions): ManagerControls {\n if (!embedded) {\n embedded = {\n manager: createGristHandshakeManager(options),\n refCount: 0,\n }\n embedded.manager.start()\n }\n embedded.refCount += 1\n return embedded.manager\n}\n\nexport function releaseEmbeddedHandshakeManager(): void {\n if (!embedded) return\n embedded.refCount -= 1\n if (embedded.refCount <= 0) {\n embedded.manager.stop()\n embedded = null\n }\n}\n\n/** Test isolation — tear down the page-level embedded manager between cases. */\nexport function resetEmbeddedHandshakeManagerForTests(): void {\n if (embedded) {\n embedded.manager.stop()\n embedded = null\n }\n}\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 resetGristReadySingleton(): void {\n inFlight = null\n lastAccess = null\n lastColumnNames = null\n}\n\n/** @deprecated Use {@link resetGristReadySingleton}. Kept for test back-compat. */\nexport const resetGristReadyCacheForTests = resetGristReadySingleton\n","import type { EventBus } from \"../core/event-bus\"\nimport type { CommandApiImpl } from \"./types\"\n\n/**\n * `CommandAPI` host implementation. The widget's \"Edit Options\" gear and a\n * few keyboard shortcuts call into this. We forward the call name on the bus\n * so the inspector and tests can observe it; useful to assert\n * `onEditOptions` flows.\n */\nexport function createCommandApiImpl(bus: EventBus): CommandApiImpl {\n return {\n async run(name) {\n bus.emit({ type: \"user-action\", action: [\"RunCommand\", name] })\n },\n }\n}\n","/**\n * Resolves the `mappings` payload that `CustomSectionAPI.mappings()` returns.\n *\n * The playground emulator does **not** infer logical → real columns from\n * names. Mappings come only from `state.selection.mappings` (playground\n * document inspector or tests). When unset, returns `null`.\n */\n\nimport type { GristWidgetColumnMap } from \"../../sdk/types\"\nimport type { EmulatorDocumentState } from \"./types\"\n\nexport function resolveMappings(state: EmulatorDocumentState): GristWidgetColumnMap | null {\n if (state.selection.mappings !== undefined && state.selection.mappings !== null) {\n return state.selection.mappings\n }\n return null\n}\n","import { resolveMappings } from \"../core/mappings\"\nimport type { EventBus } from \"../core/event-bus\"\nimport type { GristWidgetConfiguration } from \"../../sdk/types\"\nimport type { EmulatorDocumentState } from \"../core/types\"\nimport type { CustomSectionApiImpl } from \"./types\"\n\n/**\n * `CustomSectionAPI` host implementation, called by `grist-plugin-api.js`\n * after `grist.ready()` to hand the host the widget's preferences:\n * required access, declared columns, allowSelectBy, hasCustomOptions, etc.\n *\n * Implementation:\n * - persists the configuration onto `state.configuration`,\n * - emits a `ready` event so the iframe transport knows it's safe to push\n * initial cursor / data / options messages,\n * - re-emits a `mappings-change` so the inspector and tests can react.\n */\nexport function createCustomSectionApiImpl(\n state: EmulatorDocumentState,\n bus: EventBus\n): CustomSectionApiImpl {\n return {\n async configure(settings) {\n const config: GristWidgetConfiguration = {\n requiredAccess: settings.requiredAccess as GristWidgetConfiguration[\"requiredAccess\"],\n columns: settings.columns as GristWidgetConfiguration[\"columns\"],\n allowSelectBy: settings.allowSelectBy as boolean | undefined,\n hasCustomOptions: settings.hasCustomOptions as boolean | undefined,\n }\n state.configuration = config\n bus.emit({ type: \"ready\", configuration: config })\n bus.emit({ type: \"mappings-change\", mappings: resolveMappings(state) })\n },\n\n async mappings() {\n return resolveMappings(state)\n },\n }\n}\n","import type { GristApiImpl } from \"./types\"\n\n/** `_grist_api` host implementation. Minimal v1 — extend as needed. */\nexport function createGristApiImpl(): GristApiImpl {\n return {\n async ping() {\n return \"pong\"\n },\n }\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 { z, type ZodType } from \"zod\"\n\nimport type { GristReplicaColumn, GristRowRecord } from \"../types\"\nimport type { GristColumnarTable } from \"./grist-table-data\"\nimport { normalizeGristChoiceListEntries, type GristChoiceListEntry } from \"./grist-widget-options\"\nimport { decodeGristValue, type GristDecodedValue } from \"./grist-value-codec\"\n\nexport type GristSafeParseIssueCode =\n | \"grist_error\"\n | \"invalid_format\"\n | \"type_mismatch\"\n | \"helper_mismatch\"\n | \"zod_error\"\n\nexport type GristSafeParseIssue = {\n code: GristSafeParseIssueCode\n message: string\n}\n\nexport type GristSafeRefValue = {\n rowId: number\n display?: string | null\n}\n\nexport type GristSafeRefListValue = {\n rowIds: number[]\n displays?: string[]\n}\n\nexport const gristSafeRefValueSchema = z.object({\n rowId: z.number(),\n display: z.string().nullable().optional(),\n})\n\nexport const gristSafeRefListValueSchema = z.object({\n rowIds: z.array(z.number()),\n displays: z.array(z.string()).optional(),\n})\n\nexport const gristCellValueSchema = z.union([\n z.null(),\n z.string(),\n z.number(),\n z.boolean(),\n z.date(),\n z.array(z.unknown()),\n gristSafeRefValueSchema,\n gristSafeRefListValueSchema,\n])\n\nexport type GristCellValue = z.infer<typeof gristCellValueSchema>\n\nexport type GristSafeParseCellResult<TValue = unknown> = {\n ok: boolean\n typedValue: TValue | null\n displayValue: unknown\n raw: unknown\n issues: GristSafeParseIssue[]\n}\n\ntype RefMode = \"id\" | \"detailed\"\n\nexport type SafeParseGristValuesOptions<TValue = unknown> = {\n values: readonly unknown[]\n column?: GristReplicaColumn\n helperValues?: readonly unknown[]\n schema?: ZodType<TValue>\n fallbackUntypedToString?: boolean\n refMode?: RefMode\n}\n\nexport type SafeParseGristTableDataOptions = {\n columns?: Record<string, GristReplicaColumn>\n displayHelpersByRef?: Record<string, string>\n order?: \"none\" | \"id\" | \"grist\"\n fallbackUntypedToString?: boolean\n refMode?: RefMode\n}\n\nexport type GristSafeTableCellIssue = GristSafeParseIssue & {\n rowIndex: number\n colId: string\n}\n\nexport type GristSafeChoiceTokenMeta = {\n value: string\n label: string\n fillColor?: string\n textColor?: string\n valid: boolean\n}\n\nexport type GristSafeTableCellMeta = {\n rowIndex: number\n colId: string\n ok: boolean\n issues: GristSafeParseIssue[]\n choiceTokens?: GristSafeChoiceTokenMeta[]\n}\n\nexport type SafeParseGristTableDataResult<TRow extends Record<string, unknown> = Record<string, unknown>> = {\n rows: GristRowRecord<TRow>[]\n cellIssues: GristSafeTableCellIssue[]\n cellMeta: GristSafeTableCellMeta[]\n cellMetaByKey: Record<string, GristSafeTableCellMeta>\n cellResultsByColumn: Record<string, GristSafeParseCellResult[]>\n}\n\n/** Maps `Ref:*` / `RefList:*` column ids to their paired `gristHelper_*` column id (same rules as safe-parse). */\nexport function inferDisplayHelpersByRef(\n columns: Record<string, GristReplicaColumn>\n): Record<string, string> {\n const out: Record<string, string> = {}\n const helperColumns = Object.entries(columns).filter(([colId]) =>\n colId.startsWith(\"gristHelper_\")\n )\n const usedHelpers = new Set<string>()\n const colRefToColId = new Map<number, string>()\n for (const [colId, col] of Object.entries(columns)) {\n if (typeof col?.colRef === \"number\" && Number.isFinite(col.colRef)) {\n colRefToColId.set(col.colRef, colId)\n }\n }\n for (const [colId, col] of Object.entries(columns)) {\n const type = col?.type\n if (typeof type !== \"string\" || (!type.startsWith(\"Ref:\") && !type.startsWith(\"RefList:\"))) {\n continue\n }\n if (typeof col.displayColRef === \"number\" && Number.isFinite(col.displayColRef)) {\n const helperColId = colRefToColId.get(col.displayColRef)\n if (helperColId) {\n out[colId] = helperColId\n usedHelpers.add(helperColId)\n continue\n }\n }\n const match = helperColumns.find(([, helper]) => {\n const formula = helper?.formula\n return typeof formula === \"string\" && (formula.includes(`$${colId}.`) || formula.includes(`$${colId}`))\n })\n if (match) {\n out[colId] = match[0]\n usedHelpers.add(match[0])\n }\n }\n\n // Secondary fallback for schemas where helper formulas are unavailable:\n // pair unresolved Ref/RefList columns with nearest following gristHelper_*.\n const unresolvedRefs = Object.entries(columns)\n .filter(([colId, col]) => {\n const type = col?.type\n return (\n !out[colId] &&\n typeof type === \"string\" &&\n (type.startsWith(\"Ref:\") || type.startsWith(\"RefList:\"))\n )\n })\n .sort((a, b) => (a[1]?.parentPos ?? Number.MAX_SAFE_INTEGER) - (b[1]?.parentPos ?? Number.MAX_SAFE_INTEGER))\n const helperByPos = helperColumns\n .filter(([helperId]) => !usedHelpers.has(helperId))\n .sort((a, b) => (a[1]?.parentPos ?? Number.MAX_SAFE_INTEGER) - (b[1]?.parentPos ?? Number.MAX_SAFE_INTEGER))\n for (const [refId, refCol] of unresolvedRefs) {\n const refPos = refCol?.parentPos ?? Number.MAX_SAFE_INTEGER\n const candidate = helperByPos.find(([, helperCol]) => {\n const helperPos = helperCol?.parentPos ?? Number.MAX_SAFE_INTEGER\n return helperPos > refPos\n })\n if (!candidate) continue\n out[refId] = candidate[0]\n usedHelpers.add(candidate[0])\n }\n // If multiple unresolved refs remain, greedily map by order.\n for (const [refId] of unresolvedRefs) {\n if (out[refId]) continue\n const candidate = helperByPos.find(([helperId]) => !usedHelpers.has(helperId))\n if (!candidate) continue\n out[refId] = candidate[0]\n usedHelpers.add(candidate[0])\n }\n return out\n}\n\nfunction 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\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\nfunction 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\nfunction columnKind(column?: GristReplicaColumn):\n | \"text\"\n | \"numeric\"\n | \"int\"\n | \"bool\"\n | \"date\"\n | \"datetime\"\n | \"choice\"\n | \"choiceList\"\n | \"ref\"\n | \"refList\"\n | \"attachments\"\n | \"any\"\n | \"unknown\" {\n const type = column?.type\n if (!type) return \"unknown\"\n if (type === \"Text\") return \"text\"\n if (type === \"Numeric\") return \"numeric\"\n if (type === \"Int\") return \"int\"\n if (type === \"Bool\") return \"bool\"\n if (type === \"Date\") return \"date\"\n if (type === \"DateTime\" || type.startsWith(\"DateTime:\")) return \"datetime\"\n if (type === \"Choice\") return \"choice\"\n if (type === \"ChoiceList\") return \"choiceList\"\n if (type.startsWith(\"Ref:\")) return \"ref\"\n if (type.startsWith(\"RefList:\")) return \"refList\"\n if (type === \"Attachments\") return \"attachments\"\n if (type === \"Any\") return \"any\"\n return \"unknown\"\n}\n\nfunction primitiveToString(value: unknown): string | null {\n if (value === null || value === undefined) return null\n if (typeof value === \"string\") return value\n if (typeof value === \"number\" || typeof value === \"boolean\" || typeof value === \"bigint\") {\n return String(value)\n }\n return null\n}\n\nfunction normalizeRefDisplay(value: unknown): { value?: string | null; issue?: GristSafeParseIssue } {\n if (value === null || value === undefined) return { value: null }\n if (typeof value === \"string\") return { value }\n if (typeof value === \"number\" || typeof value === \"boolean\") return { value: String(value) }\n return {\n issue: {\n code: \"helper_mismatch\",\n message: \"Ref display helper value should be a scalar value.\",\n },\n }\n}\n\nfunction normalizeRefListDisplays(value: unknown): { values?: string[]; issue?: GristSafeParseIssue } {\n if (value === null || value === undefined) return { values: [] }\n if (typeof value === \"string\") {\n const s = value.trim()\n if (s === \"\") return { values: [] }\n if (s.startsWith(\"[\")) {\n try {\n const parsed = JSON.parse(s)\n if (Array.isArray(parsed)) {\n return normalizeRefListDisplays(parsed)\n }\n } catch {\n // Keep existing error below for non-array/non-JSON helper strings.\n }\n }\n }\n if (!Array.isArray(value)) {\n return {\n issue: {\n code: \"helper_mismatch\",\n message: \"RefList display helper value should be an array.\",\n },\n }\n }\n // Grist list wire format may leak through as [\"L\", ...items].\n // Treat a leading \"L\" marker as metadata, not a display label.\n const items =\n value.length > 0 && value[0] === \"L\"\n ? value.slice(1)\n : value\n const out: string[] = []\n for (const item of items) {\n const s = primitiveToString(item)\n if (s === null) {\n return {\n issue: {\n code: \"helper_mismatch\",\n message: \"RefList helper items should be scalar values.\",\n },\n }\n }\n out.push(s)\n }\n return { values: out }\n}\n\nfunction normalizeRefValue(\n decoded: GristDecodedValue,\n helperValue: unknown,\n refMode: RefMode\n): { value: number | GristSafeRefValue | null; issues: GristSafeParseIssue[] } {\n const issues: GristSafeParseIssue[] = []\n if (decoded === null) return { value: null, issues }\n\n const rowId =\n typeof decoded === \"number\" && Number.isFinite(decoded)\n ? decoded\n : decoded && typeof decoded === \"object\" && \"__ref\" in decoded\n ? (decoded as { rowId: number }).rowId\n : null\n\n // Grist empty refs can surface as 0; treat as empty cell.\n if (rowId === 0) return { value: null, issues }\n if (rowId === null || !Number.isFinite(rowId)) {\n issues.push({\n code: \"type_mismatch\",\n message: \"Expected a Ref row id.\",\n })\n return { value: null, issues }\n }\n\n if (refMode === \"id\") return { value: rowId, issues }\n\n const helper = normalizeRefDisplay(helperValue)\n if (helper.issue) issues.push(helper.issue)\n return {\n value: { rowId, display: helper.value },\n issues,\n }\n}\n\nfunction normalizeRefListValue(\n decoded: GristDecodedValue,\n helperValue: unknown,\n refMode: RefMode\n): { value: number[] | GristSafeRefListValue | null; issues: GristSafeParseIssue[] } {\n const issues: GristSafeParseIssue[] = []\n if (decoded === null) return { value: null, issues }\n if (!Array.isArray(decoded)) {\n issues.push({\n code: \"type_mismatch\",\n message: \"Expected an array for RefList.\",\n })\n return { value: null, issues }\n }\n\n const rowIds: number[] = []\n for (const item of decoded) {\n if (typeof item === \"number\" && Number.isFinite(item) && item !== 0) {\n rowIds.push(item)\n continue\n }\n if (item && typeof item === \"object\" && \"__ref\" in item) {\n const rowId = (item as { rowId: number }).rowId\n if (typeof rowId === \"number\" && Number.isFinite(rowId) && rowId !== 0) {\n rowIds.push(rowId)\n continue\n }\n }\n issues.push({\n code: \"type_mismatch\",\n message: \"RefList items should be row ids.\",\n })\n return { value: null, issues }\n }\n\n if (refMode === \"id\") return { value: rowIds, issues }\n\n const helper = normalizeRefListDisplays(helperValue)\n if (helper.issue) {\n issues.push(helper.issue)\n } else if (helper.values && helper.values.length > 0 && helper.values.length !== rowIds.length) {\n issues.push({\n code: \"helper_mismatch\",\n message: \"RefList helper labels count does not match row ids count.\",\n })\n }\n return {\n value: { rowIds, displays: helper.values },\n issues,\n }\n}\n\nfunction normalizeByColumnKind(\n decoded: GristDecodedValue,\n kind: ReturnType<typeof columnKind>,\n helperValue: unknown,\n fallbackUntypedToString: boolean,\n refMode: RefMode\n): { value: unknown; issues: GristSafeParseIssue[] } {\n const issues: GristSafeParseIssue[] = []\n if (decoded && typeof decoded === \"object\" && \"__error\" in decoded) {\n issues.push({\n code: \"grist_error\",\n message: (decoded as { message?: string }).message ?? \"Grist returned a cell error.\",\n })\n return { value: null, issues }\n }\n\n switch (kind) {\n case \"ref\":\n return normalizeRefValue(decoded, helperValue, refMode)\n case \"refList\":\n return normalizeRefListValue(decoded, helperValue, refMode)\n case \"date\":\n case \"datetime\":\n if (decoded === null || decoded instanceof Date) return { value: decoded, issues }\n issues.push({ code: \"type_mismatch\", message: \"Expected a Date value.\" })\n return { value: null, issues }\n case \"bool\":\n if (decoded === null || typeof decoded === \"boolean\") return { value: decoded, issues }\n issues.push({ code: \"type_mismatch\", message: \"Expected a boolean value.\" })\n return { value: null, issues }\n case \"numeric\":\n if (decoded === null || (typeof decoded === \"number\" && Number.isFinite(decoded))) {\n return { value: decoded, issues }\n }\n issues.push({ code: \"type_mismatch\", message: \"Expected a numeric value.\" })\n return {\n value:\n typeof decoded === \"string\" ||\n typeof decoded === \"number\" ||\n typeof decoded === \"boolean\"\n ? decoded\n : null,\n issues,\n }\n case \"int\":\n if (decoded === null || (typeof decoded === \"number\" && Number.isInteger(decoded))) {\n return { value: decoded, issues }\n }\n issues.push({ code: \"type_mismatch\", message: \"Expected an integer value.\" })\n return {\n value:\n typeof decoded === \"string\" ||\n typeof decoded === \"number\" ||\n typeof decoded === \"boolean\"\n ? decoded\n : null,\n issues,\n }\n case \"choice\":\n case \"text\":\n if (decoded === null || typeof decoded === \"string\") return { value: decoded, issues }\n issues.push({ code: \"type_mismatch\", message: \"Expected a string value.\" })\n return { value: null, issues }\n case \"choiceList\":\n case \"attachments\":\n if (decoded === null || Array.isArray(decoded)) return { value: decoded, issues }\n issues.push({ code: \"type_mismatch\", message: \"Expected a list value.\" })\n return { value: null, issues }\n case \"any\":\n case \"unknown\":\n // Heuristic fallback: when schema typing is missing but a helper column is\n // attached, infer Ref/RefList from the decoded shape.\n if (helperValue !== undefined) {\n if (typeof decoded === \"number\" || (decoded && typeof decoded === \"object\" && \"__ref\" in decoded)) {\n return normalizeRefValue(decoded, helperValue, refMode)\n }\n if (Array.isArray(decoded)) {\n return normalizeRefListValue(decoded, helperValue, refMode)\n }\n }\n if (!fallbackUntypedToString) return { value: decoded, issues }\n if (decoded === null) return { value: null, issues }\n if (typeof decoded === \"string\") return { value: decoded, issues }\n if (\n typeof decoded === \"number\" ||\n typeof decoded === \"boolean\" ||\n decoded instanceof Date\n ) {\n return {\n value: decoded instanceof Date ? decoded.toISOString() : String(decoded),\n issues,\n }\n }\n if (Array.isArray(decoded)) {\n try {\n return { value: JSON.stringify(decoded), issues }\n } catch {\n issues.push({\n code: \"invalid_format\",\n message: \"Unable to stringify list value.\",\n })\n return { value: null, issues }\n }\n }\n issues.push({\n code: \"type_mismatch\",\n message: \"Untyped value could not be represented as a string.\",\n })\n return { value: null, issues }\n }\n}\n\nfunction buildChoiceTokens(\n col: GristReplicaColumn | undefined,\n value: unknown\n): GristSafeChoiceTokenMeta[] | undefined {\n const type = col?.type\n if (type !== \"Choice\" && type !== \"ChoiceList\") return undefined\n const entries = normalizeGristChoiceListEntries(col?.widgetOptions)\n const byValue = new Map<string, GristChoiceListEntry>(entries.map((entry) => [entry.value, entry]))\n\n if (type === \"Choice\") {\n if (value == null || typeof value !== \"string\" || value.trim() === \"\") return []\n const meta = byValue.get(value)\n if (!meta) return [{ value, label: value, valid: false }]\n return [\n {\n value,\n label: meta.label,\n fillColor: meta.fillColor,\n textColor: meta.textColor,\n valid: true,\n },\n ]\n }\n\n if (!Array.isArray(value)) return []\n const out: GristSafeChoiceTokenMeta[] = []\n for (const item of value) {\n const v = typeof item === \"string\" ? item : String(item)\n const meta = byValue.get(v)\n if (!meta) {\n out.push({ value: v, label: v, valid: false })\n continue\n }\n out.push({\n value: v,\n label: meta.label,\n fillColor: meta.fillColor,\n textColor: meta.textColor,\n valid: true,\n })\n }\n return out\n}\n\nexport function safeParseGristValues<TValue = unknown>(\n options: SafeParseGristValuesOptions<TValue>\n): GristSafeParseCellResult<TValue>[] {\n const fallbackUntypedToString = options.fallbackUntypedToString ?? true\n const refMode = options.refMode ?? \"id\"\n const kind = columnKind(options.column)\n return options.values.map((raw, index) => {\n const decoded = decodeGristValue(raw, options.column)\n const helperValue = options.helperValues?.[index]\n const normalized = normalizeByColumnKind(\n decoded,\n kind,\n helperValue,\n fallbackUntypedToString,\n refMode\n )\n const issues = [...normalized.issues]\n\n if (options.schema) {\n const result = options.schema.safeParse(normalized.value)\n if (!result.success) {\n issues.push({\n code: \"zod_error\",\n message: result.error.issues.map((issue) => issue.message).join(\"; \"),\n })\n }\n }\n\n return {\n ok: issues.length === 0,\n typedValue: normalized.value as TValue | null,\n displayValue: normalized.value,\n raw,\n issues,\n }\n })\n}\n\nexport function safeParseGristTableData<TRow extends Record<string, unknown> = Record<string, unknown>>(\n data: GristColumnarTable,\n options?: SafeParseGristTableDataOptions\n): SafeParseGristTableDataResult<TRow> {\n const columns = options?.columns ?? {}\n const inferredDisplayHelpersByRef = inferDisplayHelpersByRef(columns)\n const displayHelpersByRef: Record<string, string> = {\n ...inferredDisplayHelpersByRef,\n ...(options?.displayHelpersByRef ?? {}),\n }\n // Fallback convention: if `owner` exists and `gristHelper_owner` is fetched,\n // use it as display helper even when formula metadata is unavailable.\n for (const [colId, col] of Object.entries(columns)) {\n const type = col?.type\n if (typeof type !== \"string\" || (!type.startsWith(\"Ref:\") && !type.startsWith(\"RefList:\"))) {\n continue\n }\n if (displayHelpersByRef[colId]) continue\n const byName = `gristHelper_${colId}`\n if (Array.isArray(data[byName])) {\n displayHelpersByRef[colId] = byName\n }\n }\n const fallbackUntypedToString = options?.fallbackUntypedToString ?? true\n const refMode = options?.refMode ?? \"id\"\n const colIds = Object.keys(data)\n const parsedByColumn: Record<string, GristSafeParseCellResult[]> = {}\n\n for (const colId of colIds) {\n const rawValues = Array.isArray(data[colId]) ? data[colId] : []\n const helperColId = displayHelpersByRef[colId]\n const helperValues = helperColId && Array.isArray(data[helperColId]) ? data[helperColId] : undefined\n parsedByColumn[colId] =\n colId === \"id\"\n ? rawValues.map((raw) => ({\n ok: typeof raw === \"number\" && Number.isFinite(raw),\n typedValue: typeof raw === \"number\" && Number.isFinite(raw) ? raw : null,\n displayValue: raw,\n raw,\n issues:\n typeof raw === \"number\" && Number.isFinite(raw)\n ? []\n : [{ code: \"type_mismatch\", message: \"Row id should be numeric.\" }],\n }))\n : safeParseGristValues({\n values: rawValues,\n column: columns[colId],\n helperValues,\n fallbackUntypedToString,\n refMode,\n })\n }\n\n const rowCount = computeRowCount(data)\n const rows: GristRowRecord<TRow>[] = []\n const cellIssues: GristSafeTableCellIssue[] = []\n const cellMeta: GristSafeTableCellMeta[] = []\n for (let rowIndex = 0; rowIndex < rowCount; rowIndex++) {\n const row: Record<string, unknown> = {}\n for (const colId of colIds) {\n const parsed = parsedByColumn[colId]?.[rowIndex]\n row[colId] = parsed?.typedValue ?? null\n const choiceTokens = buildChoiceTokens(columns[colId], parsed?.displayValue)\n if (parsed) {\n if (parsed.issues.length > 0 || (choiceTokens && choiceTokens.length > 0)) {\n cellMeta.push({\n rowIndex,\n colId,\n ok: parsed.ok,\n issues: parsed.issues,\n choiceTokens,\n })\n }\n }\n if (!parsed || parsed.issues.length === 0) continue\n for (const issue of parsed.issues) {\n cellIssues.push({ ...issue, rowIndex, colId })\n }\n }\n rows.push(row as GristRowRecord<TRow>)\n }\n\n const cellMetaByKey: Record<string, GristSafeTableCellMeta> = {}\n for (const meta of cellMeta) {\n const rowId = rows[meta.rowIndex]?.id\n if (typeof rowId !== \"number\") continue\n cellMetaByKey[`${rowId}:${meta.colId}`] = meta\n }\n\n const order = options?.order ?? \"grist\"\n if (order === \"none\") {\n return { rows, cellIssues, cellMeta, cellMetaByKey, cellResultsByColumn: parsedByColumn }\n }\n if (order === \"id\") {\n return {\n rows: [...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 cellIssues,\n cellMeta,\n cellMetaByKey,\n cellResultsByColumn: parsedByColumn,\n }\n }\n return {\n rows: sortRowsByGristOrder(rows),\n cellIssues,\n cellMeta,\n cellMetaByKey,\n cellResultsByColumn: parsedByColumn,\n }\n}\n","import type { GristReplicaDocument, GristReplicaRow, GristReplicaTable } from \"../replica-document\"\n\n/**\n * Ensure `rows` is a concrete array for emulator / merge logic.\n * Call at host boundaries (`createDocument`, tests); JSON may still omit `rows` for schema-only.\n */\nexport function normalizeReplicaTableInput<T extends GristReplicaTable>(table: T): T & { rows: GristReplicaRow[] } {\n return { ...table, rows: table.rows ?? [] }\n}\n\n/** Apply {@link normalizeReplicaTableInput} to every table; shallow-copies the document shell. */\nexport function normalizeReplicaDocumentInput<T extends GristReplicaDocument>(doc: T): T {\n return {\n ...doc,\n tables: Object.fromEntries(\n Object.entries(doc.tables).map(([tableId, t]) => [tableId, normalizeReplicaTableInput(t)])\n ),\n } as T\n}\n\n/** How row arrays appear in serialized replica JSON from {@link buildReplicaJsonPayload}. */\nexport type ReplicaJsonIncludeRows = \"none\" | \"samples\" | \"full\"\n\n/**\n * Clone a replica document for JSON output: strip rows, cap to first N, or pass through.\n * Does not mutate the source document.\n */\nexport function buildReplicaJsonPayload(\n doc: GristReplicaDocument,\n options: { includeRows: ReplicaJsonIncludeRows; sampleRowLimit?: number }\n): GristReplicaDocument {\n const limit = options.sampleRowLimit ?? 10\n const tables = Object.fromEntries(\n Object.entries(doc.tables).map(([tid, t]) => {\n if (options.includeRows === \"none\") {\n const { rows: _r, ...rest } = t\n return [tid, rest]\n }\n if (options.includeRows === \"samples\") {\n const r = t.rows ?? []\n return [tid, { ...t, rows: r.slice(0, limit) }]\n }\n return [tid, { ...t, rows: t.rows }]\n })\n ) as GristReplicaDocument[\"tables\"]\n return { ...doc, tables }\n}\n","import { inferDisplayHelpersByRef } from \"../../sdk/helpers/grist-safe-parse\"\nimport { normalizeReplicaDocumentInput } from \"../../sdk/helpers/replica-normalize\"\nimport { coerceGristDocApiRefRowId } from \"../../sdk/helpers/grist-value-codec\"\nimport type { GristReplicaDocument, GristReplicaTable } from \"../../sdk/replica-document\"\nimport type { GristRowRecord } from \"../../sdk/types\"\nimport type { EmulatorColumn, EmulatorDocumentState, EmulatorTable } from \"./types\"\n\nconst SYSTEM_COLUMN = \"id\"\n\nconst EMULATOR_JS_FORMULA_PLACEHOLDER = \"(emulator JavaScript formula)\"\n\n/** Replica table for {@link createDocument}; columns may include `formulaFn` / `inferredFormula` (emulator-only). */\nexport type CreateDocumentTableInput = Omit<GristReplicaTable, \"columns\"> & {\n columns?: Record<string, EmulatorColumn>\n}\n\n/** Replica document for {@link createDocument}; widens table columns to {@link EmulatorColumn}. */\nexport type CreateDocumentInput = Omit<GristReplicaDocument, \"tables\"> & {\n tables: Record<string, CreateDocumentTableInput>\n}\n\n/**\n * Ensure `formula` (original) and `inferredFormula` strings exist alongside optional `formulaFn`.\n */\nexport function enrichEmulatorColumnMetadata(col: EmulatorColumn): EmulatorColumn {\n const originalTrimmed = col.formula?.trim() ?? \"\"\n const explicitInferred = col.inferredFormula?.trim() ?? \"\"\n\n if (col.formulaFn) {\n const inferredFormula =\n explicitInferred || originalTrimmed || EMULATOR_JS_FORMULA_PLACEHOLDER\n return {\n ...col,\n ...(originalTrimmed ? { formula: col.formula } : {}),\n inferredFormula,\n }\n }\n\n if (explicitInferred || originalTrimmed) {\n return {\n ...col,\n inferredFormula: explicitInferred || originalTrimmed || undefined,\n }\n }\n\n return col\n}\n\n/** Order merged column metadata for stable `fetchTable` / RDG column order. */\nexport function sortEmulatorColumnsByParentPos(columns: Record<string, EmulatorColumn>): Record<string, EmulatorColumn> {\n const entries = Object.entries(columns)\n entries.sort(([ka, a], [kb, b]) => {\n const pa = a.parentPos\n const pb = 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 ka.localeCompare(kb)\n })\n return Object.fromEntries(entries)\n}\n\nfunction inferColumnsFromRows(rows: GristRowRecord[]): Record<string, EmulatorColumn> {\n const columns: Record<string, EmulatorColumn> = {}\n for (const row of rows) {\n for (const key of Object.keys(row)) {\n if (key === SYSTEM_COLUMN) continue\n if (!columns[key]) columns[key] = inferColumnType(row[key])\n }\n }\n return columns\n}\n\nfunction inferColumnType(sample: unknown): EmulatorColumn {\n switch (typeof sample) {\n case \"number\":\n return { type: \"Numeric\" }\n case \"boolean\":\n return { type: \"Bool\" }\n case \"string\":\n return { type: \"Text\" }\n default:\n return { type: \"Any\" }\n }\n}\n\nfunction buildTable(tableId: string, input: CreateDocumentTableInput): EmulatorTable {\n const rows = input.rows ?? []\n const inferred = inferColumnsFromRows(rows)\n const merged: Record<string, EmulatorColumn> = {}\n for (const [colId, col] of Object.entries({ ...inferred, ...(input.columns ?? {}) })) {\n merged[colId] = enrichEmulatorColumnMetadata(col)\n }\n const columns = sortEmulatorColumnsByParentPos(merged)\n return {\n tableId,\n label: input.label,\n columns,\n rows: rows.map((row) => ({ ...row })),\n }\n}\n\n/**\n * Build an immutable initial document state from a user-provided\n * {@link GristReplicaDocument}. The state is **not** frozen — the action\n * engine mutates it in place under deterministic event diffusion.\n */\nexport function createDocument(input: CreateDocumentInput): EmulatorDocumentState {\n if (!input.tables || Object.keys(input.tables).length === 0) {\n throw new Error(\"createDocument: at least one table is required\")\n }\n\n const normalized = normalizeReplicaDocumentInput(input)\n\n const tables = new Map<string, EmulatorTable>()\n for (const [tableId, tableInput] of Object.entries(normalized.tables)) {\n tables.set(tableId, buildTable(tableId, tableInput))\n }\n\n const firstTableId = tables.keys().next().value as string\n const requestedTableId = normalized.selection?.tableId\n const selectedTableId =\n requestedTableId && tables.has(requestedTableId) ? requestedTableId : firstTableId\n const selectedTable = tables.get(selectedTableId)!\n const fallbackRowId =\n typeof selectedTable.rows[0]?.id === \"number\" ? selectedTable.rows[0].id : null\n const selection = {\n tableId: selectedTableId,\n rowId: normalized.selection?.rowId ?? fallbackRowId,\n mappings: normalized.selection?.mappings,\n cursor: normalized.selection?.cursor,\n } as EmulatorDocumentState[\"selection\"]\n\n return {\n docName: normalized.docName ?? \"Untitled emulator document\",\n tables,\n selection,\n widgetOptions: { ...(normalized.widgetOptions ?? {}) },\n widgetInteraction: { ...(normalized.widgetInteraction ?? {}) },\n configuration: normalized.configuration ?? null,\n accessToken: normalized.accessToken ?? null,\n }\n}\n\nexport function getTable(state: EmulatorDocumentState, tableId: string): EmulatorTable {\n const table = state.tables.get(tableId)\n if (!table) throw new Error(`Unknown table: ${tableId}`)\n return table\n}\n\nexport function getSelectedTable(state: EmulatorDocumentState): EmulatorTable {\n return getTable(state, state.selection.tableId)\n}\n\nexport function nextRowId(table: EmulatorTable): number {\n let max = 0\n for (const row of table.rows) {\n if (typeof row.id === \"number\" && row.id > max) max = row.id\n }\n return max + 1\n}\n\nexport function findRow(table: EmulatorTable, rowId: number): GristRowRecord | undefined {\n return table.rows.find((r) => r.id === rowId)\n}\n\nexport function findRowIndex(table: EmulatorTable, rowId: number): number {\n return table.rows.findIndex((r) => r.id === rowId)\n}\n\n/**\n * Re-evaluate every formula column for a given row in-place. Called by the\n * action engine after Add/Update operations.\n */\nexport function evaluateRowFormulas(\n state: EmulatorDocumentState,\n table: EmulatorTable,\n row: GristRowRecord\n): void {\n for (const [colId, col] of Object.entries(table.columns)) {\n if (col.formulaFn) {\n try {\n row[colId] = col.formulaFn(row, { table, document: state })\n } catch (err) {\n row[colId] = formulaError(err)\n }\n }\n }\n}\n\nfunction escapeRegExp(s: string): string {\n return s.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\")\n}\n\n/** Pull stored row ids from a `RefList` cell (`[\"L\", ...]` or legacy shapes). */\nfunction extractRefListIdsFromWire(raw: unknown): number[] {\n if (raw == null) return []\n if (!Array.isArray(raw)) return []\n const items = raw[0] === \"L\" ? raw.slice(1) : raw\n const out: number[] = []\n for (const item of items) {\n if (typeof item === \"number\" && Number.isFinite(item) && item > 0) {\n out.push(Math.trunc(item))\n continue\n }\n if (item && typeof item === \"object\" && \"rowId\" in item) {\n const r = (item as { rowId: unknown }).rowId\n if (typeof r === \"number\" && Number.isFinite(r) && r > 0) {\n out.push(Math.trunc(r))\n continue\n }\n }\n const t = coerceGristDocApiRefRowId(item)\n if (t !== undefined && t > 0) out.push(Math.trunc(t))\n }\n return Array.from(new Set(out))\n}\n\nfunction fieldFromRefListHelperFormula(formula: string | undefined, refColId: string): string | null {\n if (!formula) return null\n const re = new RegExp(`\\\\$${escapeRegExp(refColId)}\\\\.([A-Za-z_]\\\\w*)`)\n const m = formula.match(re)\n return m?.[1] ?? null\n}\n\nfunction firstTextLikeColumnId(columns: Record<string, EmulatorColumn>): string | null {\n let best: { id: string; pos: number } | null = null\n for (const [colId, col] of Object.entries(columns)) {\n if (colId === \"id\" || colId.startsWith(\"gristHelper_\")) continue\n const t = col.type\n if (t !== \"Text\" && t !== \"Choice\") continue\n const pos = col.parentPos ?? 99999\n if (!best || pos < best.pos) best = { id: colId, pos }\n }\n return best?.id ?? null\n}\n\nfunction formatLabelFromCell(value: unknown): string {\n if (value == null) return \"\"\n if (typeof value === \"string\") return value.trim()\n if (typeof value === \"number\" || typeof value === \"boolean\") return String(value)\n if (value instanceof Date) return value.toISOString()\n if (Array.isArray(value) && value[0] === \"E\") return \"\"\n if (typeof value === \"object\" && value && \"__ref\" in value) {\n const r = (value as { rowId?: unknown }).rowId\n return typeof r === \"number\" && Number.isFinite(r) ? String(r) : \"\"\n }\n return \"\"\n}\n\n/**\n * Keep `gristHelper_*` display columns aligned with `RefList:*` ids after writes.\n *\n * Real Grist evaluates helper formulas (`$multiref.Nom`); replica JSON only\n * carries the formula string (no `formulaFn`), so helpers would stay stale and\n * safe-parse would flag `helper_mismatch` with empty labels.\n *\n * Skips helpers that define `formulaFn` so custom JS formulas keep ownership.\n */\nexport function syncRefListDisplayHelpers(\n state: EmulatorDocumentState,\n table: EmulatorTable,\n row: GristRowRecord\n): void {\n const displayHelpersByRef = inferDisplayHelpersByRef(table.columns)\n for (const [colId, col] of Object.entries(table.columns)) {\n const type = col.type\n if (typeof type !== \"string\" || !type.startsWith(\"RefList:\")) continue\n const helperColId = displayHelpersByRef[colId]\n if (!helperColId) continue\n const helperMeta = table.columns[helperColId]\n if (!helperMeta || helperMeta.formulaFn) continue\n\n const targetTableId = type.slice(\"RefList:\".length)\n const targetTable = state.tables.get(targetTableId)\n if (!targetTable) continue\n\n const ids = extractRefListIdsFromWire(row[colId])\n if (ids.length === 0) {\n row[helperColId] = []\n continue\n }\n\n const fieldId =\n fieldFromRefListHelperFormula(helperMeta.formula, colId) ??\n firstTextLikeColumnId(targetTable.columns)\n\n const labels = ids.map((rid) => {\n if (!fieldId) return String(rid)\n const trow = findRow(targetTable, rid)\n if (!trow) return String(rid)\n const lbl = formatLabelFromCell(trow[fieldId])\n return lbl !== \"\" ? lbl : String(rid)\n })\n row[helperColId] = labels\n }\n}\n\nfunction formulaError(err: unknown): unknown {\n // Match Grist's encoded error format: [\"E\", code, message]\n const message = err instanceof Error ? err.message : String(err)\n return [\"E\", \"Error\", message]\n}\n\n/**\n * Synthesise `_grist_Tables` metadata from the emulator's in-memory tables.\n * Returns Grist's columnar wire shape.\n */\nexport function synthesizeTablesMeta(state: EmulatorDocumentState): Record<string, unknown[]> {\n const ids: number[] = []\n const tableIds: string[] = []\n const labels: (string | null)[] = []\n\n let nextId = 1\n for (const [tableId, table] of state.tables.entries()) {\n ids.push(nextId)\n tableIds.push(tableId)\n labels.push(table.label ?? null)\n nextId += 1\n }\n\n return {\n id: ids,\n tableId: tableIds,\n // Optional human-readable label; real Grist keeps more fields, but these\n // are sufficient for `buildReplicaDocumentFromDocApi` to resolve table ids.\n label: labels,\n }\n}\n\n/**\n * Synthesise `_grist_Tables_column` metadata from emulator tables/columns.\n * Mirrors the subset of fields consumed by `buildReplicaDocumentFromDocApi`.\n */\nexport function synthesizeTablesColumnMeta(state: EmulatorDocumentState): Record<string, unknown[]> {\n const parentIds: number[] = []\n const colIds: string[] = []\n const columnIds: number[] = []\n const types: (string | null)[] = []\n const labels: (string | null)[] = []\n const parentPos: (number | null)[] = []\n const isFormula: boolean[] = []\n const formulas: (string | null)[] = []\n const descriptions: (string | null)[] = []\n const widgetOptions: unknown[] = []\n const displayCol: (number | null)[] = []\n const visibleCol: (number | null)[] = []\n\n // Mirror the synthetic table ids from `synthesizeTablesMeta`.\n const tableIdToInternalId = new Map<string, number>()\n {\n let nextId = 1\n for (const [tableId] of state.tables.entries()) {\n tableIdToInternalId.set(tableId, nextId)\n nextId += 1\n }\n }\n\n for (const [tableId, table] of state.tables.entries()) {\n const parentInternalId = tableIdToInternalId.get(tableId)\n if (parentInternalId === undefined) continue\n\n for (const [colId, col] of Object.entries(table.columns)) {\n parentIds.push(parentInternalId)\n colIds.push(colId)\n // Prefer explicit `colRef` when present; fall back to 1-based index of insertion.\n const ref = typeof col.colRef === \"number\" ? col.colRef : columnIds.length + 1\n columnIds.push(ref)\n types.push(col.type ?? null)\n labels.push(col.label ?? null)\n parentPos.push(col.parentPos ?? null)\n isFormula.push(Boolean(col.isFormula))\n const formula = typeof col.formula === \"string\" ? col.formula : null\n formulas.push(formula)\n descriptions.push(col.description ?? null)\n widgetOptions.push(col.widgetOptions ?? null)\n displayCol.push(typeof col.displayColRef === \"number\" ? col.displayColRef : null)\n visibleCol.push(typeof col.visibleColRef === \"number\" ? col.visibleColRef : null)\n }\n }\n\n return {\n parentId: parentIds,\n colId: colIds,\n id: columnIds,\n type: types,\n label: labels,\n parentPos,\n isFormula,\n formula: formulas,\n description: descriptions,\n // Also expose legacy `descr` for robustness.\n descr: descriptions,\n widgetOptions,\n displayCol,\n visibleCol,\n }\n}\n","/**\n * Pure action engine: applies Grist user actions to an\n * {@link EmulatorDocumentState} and emits the resulting events on the bus.\n *\n * This is the single place where state mutates. Every API impl ultimately\n * routes through `applyUserActions` so behaviour is consistent regardless of\n * the surface (`grist.docApi.applyUserActions`, `selectedTable.create`,\n * `setCursorPos`, etc.).\n *\n * Supported user actions:\n * - AddRecord, BulkAddRecord\n * - UpdateRecord, BulkUpdateRecord\n * - RemoveRecord, BulkRemoveRecord\n * - AddColumn, RemoveColumn, RenameColumn, ModifyColumn\n * - AddTable, RemoveTable, RenameTable\n *\n * Unknown actions throw a structured error instead of silently succeeding,\n * which surfaces protocol gaps loudly during widget development.\n */\n\nimport { coerceGristDocApiRefRowId } from \"../../sdk/helpers/grist-value-codec\"\nimport {\n evaluateRowFormulas,\n findRow,\n findRowIndex,\n getTable,\n nextRowId,\n syncRefListDisplayHelpers,\n} from \"./document\"\nimport type { EventBus } from \"./event-bus\"\nimport type { EmulatorColumn, EmulatorDocumentState, EmulatorTable } from \"./types\"\n\nexport class EmulatorActionError extends Error {\n constructor(\n public readonly action: unknown,\n message: string\n ) {\n super(message)\n this.name = \"EmulatorActionError\"\n }\n}\n\nexport type ApplyUserActionResult = {\n /** Result mirroring Grist's `applyUserActions`: per-action retValues. */\n retValues: unknown[]\n /** Tables that received row-level changes (de-duped). */\n changedTableIds: string[]\n}\n\nexport function applyUserActions(\n state: EmulatorDocumentState,\n bus: EventBus,\n actions: unknown[][]\n): ApplyUserActionResult {\n const retValues: unknown[] = []\n const changed = new Set<string>()\n\n for (const action of actions) {\n bus.emit({ type: \"user-action\", action })\n const ret = applySingle(state, action, changed)\n retValues.push(ret)\n }\n\n for (const tableId of changed) {\n bus.emit({ type: \"data-change\", tableId })\n }\n\n return { retValues, changedTableIds: [...changed] }\n}\n\nfunction applySingle(\n state: EmulatorDocumentState,\n action: unknown[],\n changed: Set<string>\n): unknown {\n const [name, ...args] = action\n switch (name) {\n case \"AddRecord\":\n return addRecord(state, args, changed)\n case \"BulkAddRecord\":\n return bulkAddRecord(state, args, changed)\n case \"UpdateRecord\":\n return updateRecord(state, args, changed)\n case \"BulkUpdateRecord\":\n return bulkUpdateRecord(state, args, changed)\n case \"RemoveRecord\":\n return removeRecord(state, args, changed)\n case \"BulkRemoveRecord\":\n return bulkRemoveRecord(state, args, changed)\n case \"AddColumn\":\n return addColumn(state, args)\n case \"AddVisibleColumn\":\n // The emulator has no concept of section view fields, so the \"visible\"\n // part of `AddVisibleColumn` is a no-op here. We still create the\n // column so widgets that issue this user action (the higher-level form\n // recommended by Grist for \"add a column to the active view\") work\n // identically against the emulator.\n return addColumn(state, args)\n case \"RemoveColumn\":\n return removeColumn(state, args, changed)\n case \"RenameColumn\":\n return renameColumn(state, args, changed)\n case \"ModifyColumn\":\n return modifyColumn(state, args, changed)\n case \"AddTable\":\n return addTable(state, args)\n case \"RemoveTable\":\n return removeTable(state, args)\n case \"RenameTable\":\n return renameTable(state, args)\n default:\n throw new EmulatorActionError(action, `Unsupported user action: ${String(name)}`)\n }\n}\n\n// ---------- row ops ----------\n\nfunction addRecord(\n state: EmulatorDocumentState,\n [tableId, rowId, values]: unknown[],\n changed: Set<string>\n): number {\n const table = getTable(state, requireString(tableId, \"AddRecord.tableId\"))\n const id = typeof rowId === \"number\" ? rowId : nextRowId(table)\n const normalizedValues = normalizeValuesForTable(\n table,\n (values as Record<string, unknown>) ?? {}\n )\n const row = { id, ...normalizedValues }\n ensureColumns(table, normalizedValues)\n evaluateRowFormulas(state, table, row)\n syncRefListDisplayHelpers(state, table, row)\n table.rows.push(row)\n changed.add(table.tableId)\n return id\n}\n\nfunction bulkAddRecord(\n state: EmulatorDocumentState,\n [tableId, rowIds, columnar]: unknown[],\n changed: Set<string>\n): number[] {\n const table = getTable(state, requireString(tableId, \"BulkAddRecord.tableId\"))\n const cols = normalizeColumnarForTable(\n table,\n (columnar as Record<string, unknown[]>) ?? {}\n )\n const ids = Array.isArray(rowIds) ? rowIds : []\n const length = ids.length || lengthOf(cols)\n const out: number[] = []\n ensureColumns(table, cols, true)\n for (let i = 0; i < length; i++) {\n const id = typeof ids[i] === \"number\" ? (ids[i] as number) : nextRowId(table)\n const row: Record<string, unknown> & { id: number } = { id }\n for (const colId of Object.keys(cols)) row[colId] = cols[colId][i]\n evaluateRowFormulas(state, table, row)\n syncRefListDisplayHelpers(state, table, row)\n table.rows.push(row)\n out.push(id)\n }\n changed.add(table.tableId)\n return out\n}\n\nfunction updateRecord(\n state: EmulatorDocumentState,\n [tableId, rowId, values]: unknown[],\n changed: Set<string>\n): null {\n const table = getTable(state, requireString(tableId, \"UpdateRecord.tableId\"))\n const id = requireNumber(rowId, \"UpdateRecord.rowId\")\n const row = findRow(table, id)\n if (!row) throw new EmulatorActionError([\"UpdateRecord\", tableId, rowId, values], `Row ${id} not found in ${table.tableId}`)\n const normalizedValues = normalizeValuesForTable(\n table,\n (values as Record<string, unknown>) ?? {}\n )\n ensureColumns(table, normalizedValues)\n Object.assign(row, normalizedValues)\n evaluateRowFormulas(state, table, row)\n syncRefListDisplayHelpers(state, table, row)\n changed.add(table.tableId)\n return null\n}\n\nfunction bulkUpdateRecord(\n state: EmulatorDocumentState,\n [tableId, rowIds, columnar]: unknown[],\n changed: Set<string>\n): null {\n const table = getTable(state, requireString(tableId, \"BulkUpdateRecord.tableId\"))\n const ids = rowIds as number[]\n const cols = normalizeColumnarForTable(\n table,\n (columnar as Record<string, unknown[]>) ?? {}\n )\n ensureColumns(table, cols, true)\n ids.forEach((id, idx) => {\n const row = findRow(table, id)\n if (!row) throw new EmulatorActionError([\"BulkUpdateRecord\", tableId, ids, cols], `Row ${id} not found in ${table.tableId}`)\n for (const colId of Object.keys(cols)) row[colId] = cols[colId][idx]\n evaluateRowFormulas(state, table, row)\n syncRefListDisplayHelpers(state, table, row)\n })\n changed.add(table.tableId)\n return null\n}\n\nfunction removeRecord(\n state: EmulatorDocumentState,\n [tableId, rowId]: unknown[],\n changed: Set<string>\n): null {\n const table = getTable(state, requireString(tableId, \"RemoveRecord.tableId\"))\n const id = requireNumber(rowId, \"RemoveRecord.rowId\")\n const idx = findRowIndex(table, id)\n if (idx >= 0) table.rows.splice(idx, 1)\n if (state.selection.tableId === table.tableId && state.selection.rowId === id) {\n state.selection.rowId = table.rows[0]?.id ?? null\n }\n changed.add(table.tableId)\n return null\n}\n\nfunction bulkRemoveRecord(\n state: EmulatorDocumentState,\n [tableId, rowIds]: unknown[],\n changed: Set<string>\n): null {\n const table = getTable(state, requireString(tableId, \"BulkRemoveRecord.tableId\"))\n const ids = new Set(rowIds as number[])\n table.rows = table.rows.filter((r) => !ids.has(r.id))\n if (state.selection.tableId === table.tableId && typeof state.selection.rowId === \"number\" && ids.has(state.selection.rowId)) {\n state.selection.rowId = table.rows[0]?.id ?? null\n }\n changed.add(table.tableId)\n return null\n}\n\n// ---------- column ops ----------\n\nfunction addColumn(\n state: EmulatorDocumentState,\n [tableId, colId, info]: unknown[]\n): null {\n const table = getTable(state, requireString(tableId, \"AddColumn.tableId\"))\n const col = requireString(colId, \"AddColumn.colId\")\n if (table.columns[col]) throw new EmulatorActionError([\"AddColumn\", tableId, colId], `Column ${col} already exists`)\n table.columns[col] = (info as EmulatorColumn) ?? {}\n for (const row of table.rows) {\n if (!(col in row)) row[col] = null\n }\n return null\n}\n\nfunction removeColumn(\n state: EmulatorDocumentState,\n [tableId, colId]: unknown[],\n changed: Set<string>\n): null {\n const table = getTable(state, requireString(tableId, \"RemoveColumn.tableId\"))\n const col = requireString(colId, \"RemoveColumn.colId\")\n delete table.columns[col]\n for (const row of table.rows) delete row[col]\n changed.add(table.tableId)\n return null\n}\n\nfunction renameColumn(\n state: EmulatorDocumentState,\n [tableId, colId, newColId]: unknown[],\n changed: Set<string>\n): null {\n const table = getTable(state, requireString(tableId, \"RenameColumn.tableId\"))\n const from = requireString(colId, \"RenameColumn.colId\")\n const to = requireString(newColId, \"RenameColumn.newColId\")\n if (!table.columns[from]) throw new EmulatorActionError([\"RenameColumn\", tableId, from, to], `Column ${from} not found`)\n if (from === to) return null\n table.columns[to] = table.columns[from]\n delete table.columns[from]\n for (const row of table.rows) {\n if (from in row) {\n row[to] = row[from]\n delete row[from]\n }\n }\n changed.add(table.tableId)\n return null\n}\n\nfunction modifyColumn(\n state: EmulatorDocumentState,\n [tableId, colId, info]: unknown[],\n changed: Set<string>\n): null {\n const table = getTable(state, requireString(tableId, \"ModifyColumn.tableId\"))\n const col = requireString(colId, \"ModifyColumn.colId\")\n if (!table.columns[col]) throw new EmulatorActionError([\"ModifyColumn\", tableId, colId], `Column ${col} not found`)\n table.columns[col] = { ...table.columns[col], ...(info as EmulatorColumn) }\n changed.add(table.tableId)\n return null\n}\n\n// ---------- table ops ----------\n\nfunction addTable(state: EmulatorDocumentState, [tableId, columns]: unknown[]): string {\n const id = requireString(tableId, \"AddTable.tableId\")\n if (state.tables.has(id)) throw new EmulatorActionError([\"AddTable\", tableId], `Table ${id} already exists`)\n const cols: Record<string, EmulatorColumn> = {}\n for (const c of (columns as Array<{ id: string } & EmulatorColumn>) ?? []) {\n cols[c.id] = { ...c }\n }\n state.tables.set(id, { tableId: id, columns: cols, rows: [] })\n return id\n}\n\nfunction removeTable(state: EmulatorDocumentState, [tableId]: unknown[]): null {\n const id = requireString(tableId, \"RemoveTable.tableId\")\n state.tables.delete(id)\n if (state.selection.tableId === id) {\n const fallback = state.tables.keys().next().value as string | undefined\n if (fallback) {\n state.selection.tableId = fallback\n state.selection.rowId = null\n }\n }\n return null\n}\n\nfunction renameTable(state: EmulatorDocumentState, [from, to]: unknown[]): null {\n const fromId = requireString(from, \"RenameTable.from\")\n const toId = requireString(to, \"RenameTable.to\")\n const table = state.tables.get(fromId)\n if (!table) throw new EmulatorActionError([\"RenameTable\", fromId], `Table ${fromId} not found`)\n state.tables.delete(fromId)\n table.tableId = toId\n state.tables.set(toId, table)\n if (state.selection.tableId === fromId) state.selection.tableId = toId\n return null\n}\n\n// ---------- helpers ----------\n\nfunction ensureColumns(\n table: EmulatorTable,\n values: Record<string, unknown> | Record<string, unknown[]>,\n bulk = false\n): void {\n for (const col of Object.keys(values)) {\n if (!table.columns[col]) {\n const sample = bulk ? (values as Record<string, unknown[]>)[col]?.[0] : (values as Record<string, unknown>)[col]\n table.columns[col] = inferType(sample)\n }\n }\n}\n\nfunction inferType(sample: unknown): EmulatorColumn {\n switch (typeof sample) {\n case \"number\":\n return { type: \"Numeric\" }\n case \"boolean\":\n return { type: \"Bool\" }\n case \"string\":\n return { type: \"Text\" }\n default:\n return { type: \"Any\" }\n }\n}\n\nfunction lengthOf(cols: Record<string, unknown[]>): number {\n for (const arr of Object.values(cols)) if (Array.isArray(arr)) return arr.length\n return 0\n}\n\nfunction requireString(value: unknown, name: string): string {\n if (typeof value !== \"string\" || !value) throw new Error(`Expected non-empty string for ${name}`)\n return value\n}\n\nfunction requireNumber(value: unknown, name: string): number {\n if (typeof value !== \"number\" || Number.isNaN(value)) throw new Error(`Expected number for ${name}`)\n return value\n}\n\nfunction normalizeValuesForTable(\n table: EmulatorTable,\n values: Record<string, unknown>\n): Record<string, unknown> {\n const out: Record<string, unknown> = {}\n for (const [colId, value] of Object.entries(values)) {\n out[colId] = normalizeCellValueForType(value, table.columns[colId]?.type)\n }\n return out\n}\n\nfunction normalizeColumnarForTable(\n table: EmulatorTable,\n columns: Record<string, unknown[]>\n): Record<string, unknown[]> {\n const out: Record<string, unknown[]> = {}\n for (const [colId, values] of Object.entries(columns)) {\n const type = table.columns[colId]?.type\n out[colId] = Array.isArray(values)\n ? values.map((value) => normalizeCellValueForType(value, type))\n : []\n }\n return out\n}\n\nfunction normalizeCellValueForType(value: unknown, type: string | undefined): unknown {\n if (value === null || value === undefined || typeof type !== \"string\") return value\n\n if (type.startsWith(\"Ref:\")) return normalizeRefValue(value)\n if (type.startsWith(\"RefList:\")) return normalizeRefListValue(value)\n return value\n}\n\n/**\n * Canonical ref row id for emulator storage (`Ref:*` columns).\n * Accepts bare ids, `\"12\"`, Grist tuples `[\"r\", id]` / `[\"R\", tableId, id]`,\n * and detailed-ref shapes `{ rowId }` used after safe-parse / RDG edits.\n */\nfunction extractRefRowId(value: unknown): number | null {\n if (value === null || value === undefined) return null\n if (value && typeof value === \"object\" && \"__ref\" in value) {\n const inner = (value as { rowId?: unknown }).rowId\n return extractRefRowId(inner)\n }\n if (value && typeof value === \"object\" && \"rowId\" in value) {\n return extractRefRowId((value as { rowId: unknown }).rowId)\n }\n const fromTuple = coerceGristDocApiRefRowId(value)\n if (fromTuple !== undefined && fromTuple > 0) return Math.trunc(fromTuple)\n return toPositiveInt(value)\n}\n\nfunction normalizeRefValue(value: unknown): number | null {\n return extractRefRowId(value)\n}\n\nfunction normalizeRefListValue(value: unknown): unknown[] {\n const toIdList = (items: unknown[]): number[] =>\n Array.from(\n new Set(items.map((item) => extractRefRowId(item)).filter((item): item is number => item !== null))\n )\n\n // Grist tuple form: [\"L\", ...ids]\n if (Array.isArray(value) && value[0] === \"L\") {\n return [\"L\", ...toIdList(value.slice(1))]\n }\n if (Array.isArray(value)) {\n return [\"L\", ...toIdList(value)]\n }\n if (typeof value === \"string\") {\n const tokens = value.split(\",\").map((t) => t.trim()).filter(Boolean)\n return [\"L\", ...toIdList(tokens)]\n }\n if (value && typeof value === \"object\" && Array.isArray((value as { rowIds?: unknown }).rowIds)) {\n return [\"L\", ...toIdList((value as { rowIds: unknown[] }).rowIds)]\n }\n return [\"L\"]\n}\n\nfunction toPositiveInt(value: unknown): number | null {\n if (typeof value === \"number\" && Number.isFinite(value) && value > 0) return Math.trunc(value)\n if (typeof value === \"string\") {\n const n = Number.parseInt(value.trim(), 10)\n if (Number.isFinite(n) && n > 0) return n\n }\n return null\n}\n","/**\n * Helpers to project an {@link EmulatorTable}'s row-array storage into Grist's\n * columnar wire format expected by `fetchTable` / `fetchSelectedTable`:\n *\n * { id: number[], colA: unknown[], colB: unknown[], ... }\n *\n * When `keepEncoded` is `false` (Grist's default for these APIs), values are\n * passed through as-is — JS-native primitives (string / number / boolean /\n * Date / arrays) are valid Grist plugin values. When `keepEncoded` is `true`,\n * Date columns are emitted in tuple form (`[\"d\", epoch]`) so callers can\n * round-trip them.\n */\n\nimport type { GristRowRecord } from \"../../sdk/types\"\nimport type { EmulatorTable } from \"./types\"\n\nexport type ColumnarTable = Record<string, unknown[]>\n\nexport type ToColumnarOptions = {\n keepEncoded?: boolean\n}\n\nexport function rowsToColumnar(\n table: EmulatorTable,\n rows: readonly GristRowRecord[],\n options: ToColumnarOptions = {}\n): ColumnarTable {\n const cols = Object.keys(table.columns)\n const out: ColumnarTable = { id: rows.map((r) => r.id) }\n for (const col of cols) {\n out[col] = rows.map((r) => encodeForWire(r[col], table.columns[col]?.type, options.keepEncoded))\n }\n return out\n}\n\nexport function rowToRecord(\n table: EmulatorTable,\n row: GristRowRecord,\n options: ToColumnarOptions = {}\n): Record<string, unknown> {\n const out: Record<string, unknown> = { id: row.id }\n for (const col of Object.keys(table.columns)) {\n out[col] = encodeForWire(row[col], table.columns[col]?.type, options.keepEncoded)\n }\n return out\n}\n\nfunction encodeForWire(value: unknown, type: string | undefined, keepEncoded: boolean | undefined): unknown {\n if (value instanceof Date) {\n const epoch = Math.floor(value.getTime() / 1000)\n if (keepEncoded) {\n return type && type.startsWith(\"DateTime\") ? [\"D\", epoch, \"UTC\"] : [\"d\", epoch]\n }\n return epoch\n }\n return value\n}\n","import { applyUserActions } from \"../core/action-engine\"\nimport { rowsToColumnar } from \"../core/columnar\"\nimport { getTable, synthesizeTablesColumnMeta, synthesizeTablesMeta } from \"../core/document\"\nimport type { EventBus } from \"../core/event-bus\"\nimport type { EmulatorDocumentState } from \"../core/types\"\nimport type { GristDocApiImpl } from \"./types\"\n\n/**\n * `GristDocAPI` host implementation. Backs `grist.docApi.*` methods such as\n * `getDocName`, `listTables`, `fetchTable`, `applyUserActions` and\n * `getAccessToken`.\n *\n * `applyUserActions` is the only mutation entry point — every widget write\n * lands here, so tests can listen on the bus for `user-action` events to\n * assert exactly which actions a UI flow generated.\n */\nexport function createGristDocApiImpl(state: EmulatorDocumentState, bus: EventBus): GristDocApiImpl {\n return {\n async getDocName() {\n return state.docName\n },\n\n async listTables() {\n return [...state.tables.keys()]\n },\n\n async fetchTable(tableId) {\n if (tableId === \"_grist_Tables\") {\n return synthesizeTablesMeta(state)\n }\n if (tableId === \"_grist_Tables_column\") {\n return synthesizeTablesColumnMeta(state)\n }\n const table = getTable(state, tableId)\n return rowsToColumnar(table, table.rows)\n },\n\n async applyUserActions(actions) {\n const result = applyUserActions(state, bus, actions)\n return { retValues: result.retValues }\n },\n\n async getAccessToken() {\n if (!state.accessToken) {\n const err = new Error(\"getAccessToken not available (no token configured on emulator)\")\n // Mirror Grist's protocol: rejected stub call.\n throw err\n }\n return { ...state.accessToken }\n },\n }\n}\n","import { rowToRecord, rowsToColumnar } from \"../core/columnar\"\nimport { findRow, getSelectedTable } from \"../core/document\"\nimport type { EventBus } from \"../core/event-bus\"\nimport type { EmulatorDocumentState } from \"../core/types\"\nimport type { GristViewImpl } from \"./types\"\n\n/**\n * `GristView` host implementation.\n *\n * Exposes the section-scoped data API the widget uses through\n * `grist.docApi.fetchSelectedTable()`, `fetchSelectedRecord()` and\n * `setCursorPos()`. Reads from the emulator state, writes to the same state\n * via the action engine where applicable, and emits events on the bus so\n * subscribers (transports, inspector, tests) stay in sync.\n *\n * IMPORTANT: `fetchSelectedTable` always returns Grist's **columnar** wire\n * shape. The production `grist-plugin-api.js` wrapper (which the iframe\n * transport talks to) expects the raw RPC stub to return columnar and does\n * the `format: \"rows\"` transposition + `keepEncoded: false` decoding itself.\n * Returning rows here used to crash the wrapper's `mapValues(data, col =>\n * col.map(decodeObject))` pass — `data` was an array, `col` was a row object\n * with no `.map` method — so widgets observed `records === null` forever.\n * The inline transport mirrors the same wrapper semantics in\n * `transports/inline.ts` so widget code sees identical results in both modes.\n */\nexport function createGristViewImpl(state: EmulatorDocumentState, bus: EventBus): GristViewImpl {\n return {\n async fetchSelectedTable(options) {\n const table = getSelectedTable(state)\n return rowsToColumnar(table, table.rows, { keepEncoded: options?.keepEncoded })\n },\n\n async fetchSelectedRecord(rowId, options) {\n const table = getSelectedTable(state)\n const row = findRow(table, rowId)\n if (!row) throw new Error(`No row ${rowId} in ${table.tableId}`)\n return rowToRecord(table, row, { keepEncoded: options?.keepEncoded })\n },\n\n async allowSelectBy() {\n return state.configuration?.allowSelectBy ?? false\n },\n\n async setSelectedRows(rowIds) {\n if (!rowIds || rowIds.length === 0) {\n state.selection.rowId = null\n } else {\n state.selection.rowId = rowIds[0]\n }\n bus.emit({\n type: \"cursor-change\",\n tableId: state.selection.tableId,\n rowId: state.selection.rowId,\n })\n },\n\n async setCursorPos(cursor) {\n const tableId = state.selection.tableId\n if (typeof cursor.rowId === \"number\") state.selection.rowId = cursor.rowId\n state.selection.cursor = { ...state.selection.cursor, ...cursor }\n bus.emit({\n type: \"cursor-change\",\n tableId,\n rowId: state.selection.rowId,\n cursor: state.selection.cursor,\n })\n },\n }\n}\n","import type { EventBus } from \"../core/event-bus\"\nimport type { EmulatorDocumentState } from \"../core/types\"\nimport type { WidgetApiImpl } from \"./types\"\n\n/**\n * `WidgetAPI` host implementation, backing `grist.widgetApi.*`. Reads and\n * writes the per-widget options bag persisted on the emulator state. Each\n * mutation triggers an `options-change` event so subscribers (the transport\n * pushes an `onOptions` message; tests/inspector update accordingly) stay in\n * lock-step with the document.\n */\nexport function createWidgetApiImpl(state: EmulatorDocumentState, bus: EventBus): WidgetApiImpl {\n function emit() {\n bus.emit({\n type: \"options-change\",\n options: { ...state.widgetOptions },\n interaction: { ...state.widgetInteraction },\n })\n }\n\n return {\n async getOption(key) {\n return state.widgetOptions[key]\n },\n\n async setOption(key, value) {\n state.widgetOptions[key] = value\n emit()\n },\n\n async getOptions() {\n return Object.keys(state.widgetOptions).length > 0 ? { ...state.widgetOptions } : null\n },\n\n async setOptions(options) {\n state.widgetOptions = { ...state.widgetOptions, ...options }\n emit()\n },\n\n async clearOptions() {\n state.widgetOptions = {}\n emit()\n },\n }\n}\n","/**\n * Bundles the six host-side Grist API implementations into one record so\n * transports (iframe, inline) can wire them up uniformly.\n */\n\nimport type { EventBus } from \"../core/event-bus\"\nimport type { EmulatorDocumentState } from \"../core/types\"\nimport { createCommandApiImpl } from \"./command-api\"\nimport { createCustomSectionApiImpl } from \"./custom-section-api\"\nimport { createGristApiImpl } from \"./grist-api\"\nimport { createGristDocApiImpl } from \"./grist-doc-api\"\nimport { createGristViewImpl } from \"./grist-view\"\nimport type {\n CommandApiImpl,\n CustomSectionApiImpl,\n GristApiImpl,\n GristDocApiImpl,\n GristViewImpl,\n WidgetApiImpl,\n} from \"./types\"\nimport { createWidgetApiImpl } from \"./widget-api\"\n\nexport type EmulatorApiBundle = {\n GristView: GristViewImpl\n GristDocAPI: GristDocApiImpl\n WidgetAPI: WidgetApiImpl\n CustomSectionAPI: CustomSectionApiImpl\n GristAPI: GristApiImpl\n CommandAPI: CommandApiImpl\n}\n\n/**\n * Build the implementations bound to a given document state and event bus.\n * Cheap to call — every method delegates to the (mutable) `state`.\n */\nexport function createApiBundle(state: EmulatorDocumentState, bus: EventBus): EmulatorApiBundle {\n return {\n GristView: createGristViewImpl(state, bus),\n GristDocAPI: createGristDocApiImpl(state, bus),\n WidgetAPI: createWidgetApiImpl(state, bus),\n CustomSectionAPI: createCustomSectionApiImpl(state, bus),\n GristAPI: createGristApiImpl(),\n CommandAPI: createCommandApiImpl(bus),\n }\n}\n\nexport type {\n CommandApiImpl,\n CustomSectionApiImpl,\n GristApiImpl,\n GristDocApiImpl,\n GristViewImpl,\n WidgetApiImpl,\n} from \"./types\"\n","/**\n * Tiny pub-sub used to broadcast every emulator state change to:\n * - the transports (which translate events into protocol messages),\n * - the React DevTools inspector (timeline view),\n * - the testing harness (assertions on emitted events).\n */\n\nimport type { GristCursorPos, GristWidgetColumnMap, GristWidgetInteraction } from \"../../sdk/types\"\n\nexport type EmulatorEvent =\n | { type: \"data-change\"; tableId: string }\n | { type: \"cursor-change\"; tableId: string; rowId: number | \"new\" | null; cursor?: GristCursorPos }\n | { type: \"options-change\"; options: Record<string, unknown>; interaction: GristWidgetInteraction }\n | { type: \"theme-change\"; message: Record<string, unknown> }\n | { type: \"ready\"; configuration: unknown }\n | { type: \"user-action\"; action: unknown[] }\n | { type: \"mappings-change\"; mappings: GristWidgetColumnMap | null }\n\nexport type EmulatorEventListener = (event: EmulatorEvent) => void\n\nexport type EventBus = {\n emit: (event: EmulatorEvent) => void\n on: (listener: EmulatorEventListener) => () => void\n history: () => readonly EmulatorEvent[]\n clear: () => void\n}\n\nexport type EventBusOptions = {\n /** Cap on history length (DevTools / tests). Defaults to 200. */\n historyLimit?: number\n}\n\nexport function createEventBus(options: EventBusOptions = {}): EventBus {\n const limit = options.historyLimit ?? 200\n const listeners = new Set<EmulatorEventListener>()\n const history: EmulatorEvent[] = []\n\n return {\n emit(event) {\n history.push(event)\n if (history.length > limit) history.shift()\n for (const fn of [...listeners]) {\n try {\n fn(event)\n } catch (err) {\n // eslint-disable-next-line no-console\n console.error(\"[grist-emulator] event listener threw:\", err)\n }\n }\n },\n on(listener) {\n listeners.add(listener)\n return () => {\n listeners.delete(listener)\n }\n },\n history() {\n return history\n },\n clear() {\n history.length = 0\n },\n }\n}\n","export type GristThemeAppearance = \"light\" | \"dark\"\n\n/** Host → widget postMessage shape used by `grist-plugin-api.js` (`onThemeChange`). */\nexport type GristThemeHostMessage = {\n theme: {\n appearance: GristThemeAppearance\n name: string\n colors: Record<string, string>\n }\n fromReady?: boolean\n}\n\nexport function buildGristThemeHostMessage(\n appearance: GristThemeAppearance,\n options?: { fromReady?: boolean }\n): GristThemeHostMessage {\n return {\n theme: {\n appearance,\n name: appearance,\n colors: {},\n },\n ...(options?.fromReady ? { fromReady: true } : {}),\n }\n}\n","/**\n * Iframe transport — the production-fidelity path.\n *\n * - The iframe loads the real `https://docs.getgrist.com/grist-plugin-api.js`\n * so widget code talks to `window.grist` exactly like in production.\n * - The host (this file) instantiates a `grain-rpc` `Rpc` and wires:\n * * outgoing → `iframe.contentWindow.postMessage(msg, targetOrigin)`\n * * incoming → `window.addEventListener(\"message\", ...)` filtered by\n * `event.source === iframe.contentWindow`.\n * - The Rpc registers the six host impls under their canonical names so\n * `grist-plugin-api.js`'s stubs find them.\n * - Custom messages (cursor / data / options / theme) are pushed via\n * `rpc.postMessage(...)` which `grist-plugin-api.js` dispatches to its\n * internal \"message\" event listeners (the ones used by `onRecord` etc.).\n *\n * Sequence:\n * 1. Host calls `rpc.queueOutgoingUntilReadyMessage()` so messages are\n * buffered until the widget signals it is ready.\n * 2. Widget loads, runs `grist-plugin-api.js`, calls `grist.ready(...)`.\n * 3. Widget's `grist-plugin-api.js` posts a \"ready\" message → host's Rpc\n * flushes the buffered outgoing messages.\n * 4. Widget's `grist.ready(...)` triggers `CustomSectionAPI.configure(...)`\n * on us; we react by emitting initial state (options + cursor + data).\n */\n\nimport { MsgType, Rpc } from \"grain-rpc\"\n\nimport type { GristWidgetInteraction } from \"../../sdk/types\"\nimport type { EmulatorEvent } from \"../core/event-bus\"\nimport { buildGristThemeHostMessage } from \"../theme-message\"\nimport type { EmulatorTransport, TransportContext } from \"./types\"\n\nexport type IframeTransportOptions = TransportContext & {\n iframe: HTMLIFrameElement\n /** `postMessage` target origin. Defaults to \"*\" — fine for emulator usage. */\n targetOrigin?: string\n}\n\nexport function createIframeTransport(options: IframeTransportOptions): EmulatorTransport {\n const { iframe, state, bus, api, targetOrigin = \"*\" } = options\n const timers = new Set<ReturnType<typeof setTimeout>>()\n\n const rpc = new Rpc({\n sendMessage: (msg) => {\n const target = iframe.contentWindow\n if (!target) return\n target.postMessage(msg, targetOrigin)\n },\n logger: { info: () => {}, warn: () => {} },\n })\n\n rpc.queueOutgoingUntilReadyMessage()\n\n /**\n * `grist-plugin-api.js` obtains `docApi` via `getStub(\"GristDocAPI@grist\", …)`, which sends\n * `RpcCall` messages with `mdest: \"grist\"`. In full Grist that forwarder reaches a doc-worker\n * `Rpc`; here all host impls live on this same `Rpc`, so forwarding to `this` would re-emit\n * the call to the iframe and the widget would reject it as `Unknown interface`. Strip `mdest`\n * so `GristDocAPI` resolves to our local `registerImpl` surface (same effective path as tests\n * that use `getStub(\"GristDocAPI\")` without `@grist`).\n */\n const receiveFromWidget = rpc.receiveMessage.bind(rpc)\n rpc.receiveMessage = (msg: unknown) => {\n if (\n msg &&\n typeof msg === \"object\" &&\n (msg as { mtype?: unknown }).mtype === MsgType.RpcCall &&\n (msg as { mdest?: unknown }).mdest === \"grist\"\n ) {\n const copy = { ...(msg as Record<string, unknown>) }\n delete copy.mdest\n receiveFromWidget(copy as never)\n return\n }\n receiveFromWidget(msg as never)\n }\n\n const onMessage = (event: MessageEvent) => {\n if (event.source !== iframe.contentWindow) return\n // Dev runtimes may post unrelated messages (HMR, devtools). Forwarding\n // them to grain-rpc can throw and disturb the ready handshake.\n if (!isRpcEnvelope(event.data)) return\n rpc.receiveMessage(event.data)\n }\n window.addEventListener(\"message\", onMessage)\n\n rpc.registerImpl(\"GristView\", api.GristView)\n rpc.registerImpl(\"GristDocAPI\", api.GristDocAPI)\n rpc.registerImpl(\"WidgetAPI\", api.WidgetAPI)\n rpc.registerImpl(\"CustomSectionAPI\", api.CustomSectionAPI)\n rpc.registerImpl(\"_grist_api\", api.GristAPI)\n rpc.registerImpl(\"CommandAPI\", api.CommandAPI)\n\n const buildInteraction = options.buildInteraction ?? defaultInteraction(state)\n const cursorOf = options.cursor ?? (() => state.selection.cursor)\n const initialCursorOf = options.initialCursor ?? (() => state.selection.rowId)\n\n type HostPushOptions = { mappingsChange?: boolean }\n\n function fireDataChange(tableId?: string, opts?: HostPushOptions) {\n safePostMessage({\n tableId: tableId ?? state.selection.tableId,\n dataChange: true,\n ...(opts?.mappingsChange ? { mappingsChange: true } : {}),\n })\n }\n function fireCursor(rowId?: number | \"new\" | null, opts?: HostPushOptions) {\n const id = rowId === undefined ? initialCursorOf() : rowId\n if (id === null) return\n safePostMessage({\n tableId: state.selection.tableId,\n rowId: id,\n cursor: cursorOf(),\n ...(opts?.mappingsChange ? { mappingsChange: true } : {}),\n })\n }\n function fireOptions() {\n safePostMessage({\n options: hasOptions(state.widgetOptions) ? { ...state.widgetOptions } : null,\n settings: { ...buildInteraction() },\n })\n }\n function fireTheme(message: Record<string, unknown>) {\n safePostMessage(message)\n }\n function emitInitialState(opts?: HostPushOptions) {\n fireOptions()\n if (options.initialTheme) {\n fireTheme(buildGristThemeHostMessage(options.initialTheme, { fromReady: true }))\n }\n fireDataChange(undefined, opts)\n fireCursor(undefined, opts)\n }\n\n function emitInitialStateWithReplay(opts?: HostPushOptions) {\n // Keep initial state delivery resilient when widget subscriptions are\n // attached slightly after ready (common in dev/HMR): send now, then replay\n // on the next microtask and next macrotask.\n emitInitialState(opts)\n queueMicrotask(() => emitInitialState(opts))\n const timer = setTimeout(() => {\n timers.delete(timer)\n emitInitialState(opts)\n }, 0)\n timers.add(timer)\n }\n\n // Bus → transport push. Listens on every emulator state mutation and pushes\n // the matching protocol message to the iframe.\n const offBus = bus.on((event: EmulatorEvent) => {\n switch (event.type) {\n case \"ready\":\n emitInitialStateWithReplay()\n break\n case \"data-change\":\n fireDataChange(event.tableId)\n break\n case \"cursor-change\": {\n const rowId = event.rowId === null ? state.selection.rowId : event.rowId\n if (rowId !== null) {\n safePostMessage({\n tableId: event.tableId,\n rowId,\n cursor: cursorOf(),\n })\n }\n // Match inline transport: cursor moves must also signal `dataChange` so\n // `grist-plugin-api.js` refetches the row and calls `onRecord` again.\n // Cursor-only postMessages left widgets stuck on the first row (#playground).\n fireDataChange(event.tableId)\n break\n }\n case \"options-change\":\n fireOptions()\n break\n case \"mappings-change\":\n // grist-plugin-api only refetches `sectionApi.mappings()` when `mappingsChange`\n // is set on the host message (see getMappingsIfChanged in grist-core).\n emitInitialStateWithReplay({ mappingsChange: true })\n break\n case \"theme-change\":\n fireTheme(event.message)\n break\n }\n })\n\n rpc.processIncoming()\n\n function safePostMessage(payload: Record<string, unknown>): void {\n try {\n rpc.postMessage(payload)\n } catch (err) {\n // Transport failures (broken iframe, crashed widget script, etc.) should\n // never break host-side emulator mutations. We keep the emulator state\n // authoritative and treat iframe delivery as best-effort.\n // eslint-disable-next-line no-console\n console.warn(\"[grist-emulator/iframe] failed to deliver postMessage\", err)\n }\n }\n\n return {\n dispose() {\n window.removeEventListener(\"message\", onMessage)\n offBus()\n for (const timer of timers) clearTimeout(timer)\n timers.clear()\n // grain-rpc 0.1.7 doesn't expose `close()`. We rely on listener removal\n // + GC to dispose the rpc instance.\n },\n fireDataChange,\n fireCursor,\n fireOptions,\n fireTheme,\n emitInitialState,\n }\n}\n\nfunction hasOptions(options: Record<string, unknown>): boolean {\n return Object.keys(options).length > 0\n}\n\nfunction isRpcEnvelope(data: unknown): data is { mtype: number } {\n if (!data || typeof data !== \"object\") return false\n return typeof (data as { mtype?: unknown }).mtype === \"number\"\n}\n\nfunction defaultInteraction(state: { widgetInteraction: GristWidgetInteraction; configuration: { requiredAccess?: string } | null }) {\n return (): GristWidgetInteraction => ({\n access_level: state.configuration?.requiredAccess ?? \"read table\",\n ...state.widgetInteraction,\n })\n}\n","/**\n * Grist `docApi.applyUserActions` payloads are arrays of user-action tuples.\n * @see https://support.getgrist.com/code/interfaces/grist_plugin_api.GristDocAPI/#applyuseractions\n */\n\nexport type GristUserActionTuple = unknown[]\n\n/** `[\"UpdateRecord\", tableId, rowId, { col: value, ... }]` */\nexport function gristUpdateRecordAction(\n tableId: string,\n rowId: number,\n patch: Record<string, unknown>\n): GristUserActionTuple {\n return [\"UpdateRecord\", tableId, rowId, patch]\n}\n\n/** `[\"AddRecord\", tableId, null, { col: value, ... }]` */\nexport function gristAddRecordAction(tableId: string, values: Record<string, unknown>): GristUserActionTuple {\n return [\"AddRecord\", tableId, null, values]\n}\n\n/** `[\"RemoveRecord\", tableId, rowId]` */\nexport function gristRemoveRecordAction(tableId: string, rowId: number): GristUserActionTuple {\n return [\"RemoveRecord\", tableId, rowId]\n}\n\n/** `[\"BulkUpdateRecord\", tableId, rowIds, { col: value[], ... }]` — column arrays must align with `rowIds`. */\nexport function gristBulkUpdateRecordAction(\n tableId: string,\n rowIds: number[],\n columnarPatch: Record<string, unknown[]>\n): GristUserActionTuple {\n return [\"BulkUpdateRecord\", tableId, rowIds, columnarPatch]\n}\n\n/**\n * `[\"BulkAddRecord\", tableId, rowIds | nullArray, { col: value[], ... }]`.\n * Pass `null` (or omit) for `rowIds` to let Grist allocate ids; in user-action\n * format Grist expects an array of nulls of the same length as the value arrays.\n */\nexport function gristBulkAddRecordAction(\n tableId: string,\n values: Record<string, unknown[]>,\n rowIds?: Array<number | null>\n): GristUserActionTuple {\n const length = inferBulkLength(values)\n const ids = rowIds ?? new Array<number | null>(length).fill(null)\n return [\"BulkAddRecord\", tableId, ids, values]\n}\n\n/** `[\"BulkRemoveRecord\", tableId, rowIds]` */\nexport function gristBulkRemoveRecordAction(tableId: string, rowIds: number[]): GristUserActionTuple {\n return [\"BulkRemoveRecord\", tableId, rowIds]\n}\n\n/** `[\"AddColumn\", tableId, colId, colInfo]` — `colInfo` shape depends on Grist version / column type. */\nexport function gristAddColumnAction(tableId: string, colId: string, colInfo: Record<string, unknown>): GristUserActionTuple {\n return [\"AddColumn\", tableId, colId, colInfo]\n}\n\n/** `[\"AddVisibleColumn\", tableId, colId, colInfo]` — like `AddColumn` but also adds the column to the current view section. */\nexport function gristAddVisibleColumnAction(tableId: string, colId: string, colInfo: Record<string, unknown>): GristUserActionTuple {\n return [\"AddVisibleColumn\", tableId, colId, colInfo]\n}\n\n/** `[\"RenameColumn\", tableId, colId, newColId]` */\nexport function gristRenameColumnAction(tableId: string, colId: string, newColId: string): GristUserActionTuple {\n return [\"RenameColumn\", tableId, colId, newColId]\n}\n\n/** `[\"ModifyColumn\", tableId, colId, colInfo]` */\nexport function gristModifyColumnAction(tableId: string, colId: string, colInfo: Record<string, unknown>): GristUserActionTuple {\n return [\"ModifyColumn\", tableId, colId, colInfo]\n}\n\n/** `[\"RemoveColumn\", tableId, colId]` */\nexport function gristRemoveColumnAction(tableId: string, colId: string): GristUserActionTuple {\n return [\"RemoveColumn\", tableId, colId]\n}\n\n/** `[\"AddTable\", tableId, tableInfo]` */\nexport function gristAddTableAction(tableId: string, tableInfo: Record<string, unknown>): GristUserActionTuple {\n return [\"AddTable\", tableId, tableInfo]\n}\n\n/** `[\"RenameTable\", tableId, newTableId]` */\nexport function gristRenameTableAction(tableId: string, newTableId: string): GristUserActionTuple {\n return [\"RenameTable\", tableId, newTableId]\n}\n\n/** `[\"RemoveTable\", tableId]` */\nexport function gristRemoveTableAction(tableId: string): GristUserActionTuple {\n return [\"RemoveTable\", tableId]\n}\n\n/** `[\"DuplicateTable\", tableId, newTableId, options?]` */\nexport function gristDuplicateTableAction(\n tableId: string,\n newTableId: string,\n options?: Record<string, unknown>\n): GristUserActionTuple {\n return options ? [\"DuplicateTable\", tableId, newTableId, options] : [\"DuplicateTable\", tableId, newTableId]\n}\n\n/** `[\"ReplaceTableData\", tableId, rowIds, columnarData]` */\nexport function gristReplaceTableDataAction(\n tableId: string,\n rowIds: Array<number | null>,\n columnarData: Record<string, unknown[]>\n): GristUserActionTuple {\n return [\"ReplaceTableData\", tableId, rowIds, columnarData]\n}\n\n/** `[\"SetDocumentInfo\", info]` */\nexport function gristSetDocumentInfoAction(info: Record<string, unknown>): GristUserActionTuple {\n return [\"SetDocumentInfo\", info]\n}\n\nfunction inferBulkLength(values: Record<string, unknown[]>): number {\n for (const arr of Object.values(values)) if (Array.isArray(arr)) return arr.length\n return 0\n}\n","/**\n * Inline transport — synthesises a `window.grist` global wired directly to\n * the emulator state. No iframe, no postMessage, no serialization.\n *\n * Used for:\n * - SDK unit tests in jsdom (`renderWithGrist(...)`),\n * - IDE-style live previews where widget code lives in the same window\n * as the emulator host.\n *\n * The synthesised `grist` object exposes the **same** typed surface as the\n * production `grist-plugin-api.js` (see `hooks/grist-global.d.ts`). Hooks\n * call `grist.docApi.fetchTable(...)` etc. and get the answer directly from\n * the action engine.\n */\n\nimport type {\n GristCursorPos,\n GristFetchSelectedOptions,\n GristMinimalRecord,\n GristReadyOptions,\n GristTableNewRecord,\n GristTableOpOptions,\n GristTableOperations,\n GristTableUpdateRecord,\n GristTableUpsertOptions,\n GristTableUpsertRecord,\n GristWidgetColumnMap,\n GristWidgetInteraction,\n} from \"../../sdk/types\"\nimport {\n gristAddRecordAction,\n gristBulkAddRecordAction,\n gristBulkRemoveRecordAction,\n gristBulkUpdateRecordAction,\n gristRemoveRecordAction,\n gristUpdateRecordAction,\n} from \"../../sdk/helpers/grist-user-actions\"\nimport { applyUserActions } from \"../core/action-engine\"\nimport type { EmulatorEvent } from \"../core/event-bus\"\nimport { findRow, getTable } from \"../core/document\"\nimport { resolveMappings } from \"../core/mappings\"\nimport type { EmulatorDocumentState } from \"../core/types\"\nimport { buildGristThemeHostMessage } from \"../theme-message\"\nimport type { EmulatorTransport, TransportContext } from \"./types\"\n\n/**\n * Shape of the synthesised global. Matches `globalThis.grist` from\n * `grist-global.d.ts`.\n */\nexport type InlineGristGlobal = {\n ready: (options?: GristReadyOptions) => Promise<void>\n onRecord: (\n cb: (record: Record<string, unknown> | null, mappings?: GristWidgetColumnMap | null) => void,\n options?: GristFetchSelectedOptions\n ) => void\n onRecords: (\n cb: (records: Record<string, unknown>[], mappings?: GristWidgetColumnMap | null) => void,\n options?: GristFetchSelectedOptions\n ) => void\n onOptions: (cb: (options: Record<string, unknown> | null, interaction: GristWidgetInteraction) => void) => void\n onNewRecord: (cb: (mappings: GristWidgetColumnMap | null) => void) => void\n mapColumnNames: (data: Record<string, unknown>) => Record<string, unknown> | null\n mapColumnNamesBack: (data: Record<string, unknown>) => Record<string, unknown>\n getOptions: () => Promise<Record<string, unknown> | null>\n getOption: (key: string) => Promise<unknown>\n setOption: (key: string, value: unknown) => Promise<void>\n setOptions: (options: Record<string, unknown>) => Promise<void>\n clearOptions: () => Promise<void>\n setCursorPos: (pos: GristCursorPos) => Promise<void>\n setSelectedRows: (rowIds: number[] | null) => Promise<void>\n fetchSelectedTable: (options?: GristFetchSelectedOptions) => Promise<Record<string, unknown[]>>\n fetchSelectedRecord: (rowId: number, options?: GristFetchSelectedOptions) => Promise<Record<string, unknown>>\n docApi: {\n getDocName: () => Promise<string>\n listTables: () => Promise<string[]>\n fetchTable: (tableId: string) => Promise<Record<string, unknown[]>>\n applyUserActions: (actions: unknown[][], options?: { desc?: string }) => Promise<{ retValues: unknown[] }>\n getAccessToken?: (options?: { readOnly?: boolean }) => Promise<{ token: string; baseUrl: string }>\n fetchSelectedTable: (options?: GristFetchSelectedOptions) => Promise<Record<string, unknown[]>>\n fetchSelectedRecord: (rowId: number, options?: GristFetchSelectedOptions) => Promise<Record<string, unknown>>\n }\n selectedTable: GristTableOperations\n getTable: (tableId?: string) => GristTableOperations\n sectionApi: {\n configure: (settings: GristReadyOptions) => Promise<void>\n mappings: () => Promise<GristWidgetColumnMap | null>\n }\n on: (eventName: string, listener: (...args: unknown[]) => void) => () => void\n}\n\nexport type InlineTransportOptions = TransportContext & {\n /**\n * Where to mount the synthesised `grist` global.\n * Defaults to the current window. Pass a different target (e.g. an iframe's\n * `contentWindow`) to install it in another realm.\n */\n target?: Window & typeof globalThis\n}\n\n/**\n * Returns an {@link EmulatorTransport} **and** the synthesised `grist`\n * object. `target.grist = global` is set as a side-effect for parity with\n * the production runtime.\n */\nexport function createInlineTransport(\n options: InlineTransportOptions\n): EmulatorTransport & { grist: InlineGristGlobal } {\n const { state, bus, api } = options\n const target = options.target ?? (globalThis as unknown as Window & typeof globalThis)\n\n // The SDK's `useGristAvailability` checks `window.self !== window.top`.\n // The inline transport runs in a top-level window where that's false. We\n // shim `top` so widget code thinks it's embedded — production doesn't use\n // this transport so there's no risk of leaking the shim.\n installFakeIframeContext(target)\n\n type RecordCb = (record: Record<string, unknown> | null, mappings?: GristWidgetColumnMap | null) => void\n type RecordsCb = (records: Record<string, unknown>[], mappings?: GristWidgetColumnMap | null) => void\n type OptionsCb = (options: Record<string, unknown> | null, interaction: GristWidgetInteraction) => void\n type NewRecordCb = (mappings: GristWidgetColumnMap | null) => void\n\n const recordCbs = new Map<RecordCb, GristFetchSelectedOptions | undefined>()\n const recordsCbs = new Map<RecordsCb, GristFetchSelectedOptions | undefined>()\n const optionsCbs = new Set<OptionsCb>()\n const newRecordCbs = new Set<NewRecordCb>()\n const generic = new Map<string, Set<(...args: unknown[]) => void>>()\n\n // Replay caches — production `grist-plugin-api.js` immediately delivers the\n // latest record / records / options to a freshly-subscribed listener, so\n // hooks that subscribe **after** `grist.ready()` still get the initial\n // payload. We mirror that behaviour here.\n type LastRecord = { record: Record<string, unknown> | null; mappings: GristWidgetColumnMap | null }\n type LastRecords = { records: Record<string, unknown>[]; mappings: GristWidgetColumnMap | null }\n type LastOptions = { options: Record<string, unknown> | null; interaction: GristWidgetInteraction }\n let lastRecord: LastRecord | null = null\n let lastRecords: LastRecords | null = null\n let lastOptions: LastOptions | null = null\n let lastNewRecord: GristWidgetColumnMap | null | undefined = undefined\n\n const buildInteraction = options.buildInteraction ?? (() => ({\n access_level: state.configuration?.requiredAccess ?? \"read table\",\n ...state.widgetInteraction,\n }))\n\n async function pushRecord(rowId: number | \"new\" | null) {\n const mappings = resolveMappings(state)\n if (rowId === \"new\") {\n lastNewRecord = mappings\n for (const cb of newRecordCbs) {\n try { cb(mappings) } catch (err) { logErr(err) }\n }\n lastRecord = { record: null, mappings }\n for (const [cb] of recordCbs) {\n try { cb(null, mappings) } catch (err) { logErr(err) }\n }\n return\n }\n if (rowId === null) {\n lastRecord = { record: null, mappings }\n for (const [cb] of recordCbs) {\n try { cb(null, mappings) } catch (err) { logErr(err) }\n }\n return\n }\n let record: Record<string, unknown> | null = null\n try {\n record = await api.GristView.fetchSelectedRecord(rowId)\n } catch (err) {\n logErr(err)\n }\n lastRecord = { record, mappings }\n for (const [cb, opts] of recordCbs) {\n try {\n const r = opts?.keepEncoded\n ? await api.GristView.fetchSelectedRecord(rowId, { keepEncoded: true })\n : record\n cb(r, mappings)\n } catch (err) {\n logErr(err)\n }\n }\n }\n\n async function pushRecords() {\n const mappings = resolveMappings(state)\n let baseRows: Record<string, unknown>[] = []\n try {\n const columnar = await api.GristView.fetchSelectedTable({})\n baseRows = columnsToRows(columnar)\n } catch (err) {\n logErr(err)\n }\n lastRecords = { records: baseRows, mappings }\n for (const [cb, opts] of recordsCbs) {\n try {\n const fetchOptions = coerceFetchOptions(opts)\n // Re-fetch only when the subscriber asked for a different shape\n // (e.g. `keepEncoded: true`). Otherwise reuse the decoded rows we\n // already have to avoid extra work and to match production where\n // the same fetch is broadcast to every listener.\n const rows = fetchOptions?.keepEncoded\n ? columnsToRows(await api.GristView.fetchSelectedTable({ keepEncoded: true }))\n : baseRows\n cb(rows, mappings)\n } catch (err) {\n logErr(err)\n }\n }\n }\n\n /**\n * Mirror what `viewApi.fetchSelectedTable` does inside `grist-plugin-api.js`:\n * the host RPC stub always returns columnar; the wrapper applies the\n * `format: \"rows\"` transpose (and would decode encoded values when\n * `keepEncoded: false` — a no-op here because our `rowsToColumnar` already\n * emits JS-native primitives in that case).\n *\n * Keeping this logic on the inline side guarantees that widgets see the\n * same result whether they go through the iframe transport (real plugin\n * wrapper) or the inline transport (this wrapper).\n */\n async function fetchSelectedTableShaped(\n opts: GristFetchSelectedOptions | undefined\n ): Promise<Record<string, unknown[]> | Record<string, unknown>[]> {\n const fetchOptions = coerceFetchOptions(opts)\n const columnar = (await api.GristView.fetchSelectedTable(\n fetchOptions ? { keepEncoded: fetchOptions.keepEncoded } : {}\n )) as Record<string, unknown[]>\n if (fetchOptions?.format === \"rows\") return columnsToRows(columnar)\n return columnar\n }\n\n function pushOptions() {\n const opts = Object.keys(state.widgetOptions).length > 0 ? { ...state.widgetOptions } : null\n const interaction = buildInteraction()\n lastOptions = { options: opts, interaction }\n for (const cb of optionsCbs) {\n try { cb(opts, interaction) } catch (err) { logErr(err) }\n }\n }\n\n const offBus = bus.on(async (event: EmulatorEvent) => {\n switch (event.type) {\n case \"data-change\":\n await pushRecords()\n await pushRecord(state.selection.rowId)\n break\n case \"cursor-change\":\n await pushRecord(event.rowId)\n break\n case \"options-change\":\n pushOptions()\n break\n case \"ready\":\n pushOptions()\n if (options.initialTheme) {\n notify(\"message\", buildGristThemeHostMessage(options.initialTheme, { fromReady: true }))\n }\n await pushRecords()\n await pushRecord(state.selection.rowId)\n break\n case \"mappings-change\":\n await pushRecords()\n await pushRecord(state.selection.rowId)\n break\n case \"theme-change\":\n notify(\"message\", event.message)\n break\n }\n })\n\n function makeTableOps(tableId: string): GristTableOperations {\n return {\n async getTableId() { return tableId },\n async create(records, options) {\n const list = Array.isArray(records) ? records : [records]\n const ids: GristMinimalRecord[] = []\n for (const r of list) {\n const result = applyUserActions(state, bus, [\n gristAddRecordAction(tableId, parseFields(r.fields, options)),\n ])\n ids.push({ id: result.retValues[0] as number })\n }\n return Array.isArray(records) ? ids : ids[0]\n },\n async update(records: GristTableUpdateRecord | GristTableUpdateRecord[], options?: GristTableOpOptions) {\n const list = Array.isArray(records) ? records : [records]\n const actions = list.map((r) => gristUpdateRecordAction(tableId, r.id, parseFields(r.fields, options)))\n applyUserActions(state, bus, actions)\n },\n async upsert(records: GristTableUpsertRecord | GristTableUpsertRecord[], options?: GristTableUpsertOptions) {\n const list = Array.isArray(records) ? records : [records]\n const allowAdd = options?.add !== false\n const allowUpdate = options?.update !== false\n const table = getTable(state, tableId)\n const actions: unknown[][] = []\n for (const r of list) {\n const matches = table.rows.filter((row) =>\n Object.entries(r.require).every(([k, v]) => row[k] === v)\n )\n if (matches.length > 0) {\n if (!allowUpdate) continue\n const fields = parseFields(r.fields ?? {}, options)\n for (const m of matches) actions.push(gristUpdateRecordAction(tableId, m.id, fields))\n } else if (allowAdd) {\n actions.push(gristAddRecordAction(tableId, { ...r.require, ...parseFields(r.fields ?? {}, options) }))\n }\n }\n if (actions.length > 0) applyUserActions(state, bus, actions)\n },\n async destroy(recordIds: number | number[]) {\n if (Array.isArray(recordIds)) {\n applyUserActions(state, bus, [gristBulkRemoveRecordAction(tableId, recordIds)])\n } else {\n applyUserActions(state, bus, [gristRemoveRecordAction(tableId, recordIds)])\n }\n // touch the unused bulk-add reference for tree-shaking parity, no-op\n void gristBulkAddRecordAction\n void gristBulkUpdateRecordAction\n },\n }\n }\n\n function notify(event: string, ...args: unknown[]) {\n const set = generic.get(event)\n if (!set) return\n for (const fn of set) {\n try { fn(...args) } catch (err) { logErr(err) }\n }\n }\n\n const grist: InlineGristGlobal = {\n async ready(opts) {\n await api.CustomSectionAPI.configure(opts ? { ...opts, onEditOptions: undefined } as unknown as Record<string, unknown> : {})\n },\n\n onRecord(cb, opts) {\n recordCbs.set(cb, opts)\n // Replay last value so late subscribers don't miss the initial event.\n if (lastRecord) {\n try { cb(lastRecord.record, lastRecord.mappings) } catch (err) { logErr(err) }\n }\n },\n onRecords(cb, opts) {\n recordsCbs.set(cb, opts)\n if (lastRecords) {\n try { cb(lastRecords.records, lastRecords.mappings) } catch (err) { logErr(err) }\n }\n },\n onOptions(cb) {\n optionsCbs.add(cb)\n if (lastOptions) {\n try { cb(lastOptions.options, lastOptions.interaction) } catch (err) { logErr(err) }\n }\n },\n onNewRecord(cb) {\n newRecordCbs.add(cb)\n if (lastNewRecord !== undefined) {\n try { cb(lastNewRecord) } catch (err) { logErr(err) }\n }\n },\n\n mapColumnNames(data) {\n const mappings = resolveMappings(state)\n if (!mappings) return null\n const out: Record<string, unknown> = {}\n let allMapped = true\n for (const [logical, real] of Object.entries(mappings)) {\n if (Array.isArray(real)) {\n out[logical] = real.map((r) => data[r])\n } else if (typeof real === \"string\") {\n out[logical] = data[real]\n } else {\n allMapped = false\n }\n }\n return allMapped ? out : null\n },\n mapColumnNamesBack(data) {\n const mappings = resolveMappings(state)\n if (!mappings) return data\n const out: Record<string, unknown> = {}\n for (const [logical, real] of Object.entries(mappings)) {\n if (typeof real === \"string\" && logical in data) {\n out[real] = data[logical]\n }\n }\n return out\n },\n\n getOption: (k) => api.WidgetAPI.getOption(k),\n setOption: (k, v) => api.WidgetAPI.setOption(k, v),\n getOptions: () => api.WidgetAPI.getOptions(),\n setOptions: (o) => api.WidgetAPI.setOptions(o),\n clearOptions: () => api.WidgetAPI.clearOptions(),\n\n setCursorPos: (pos) => api.GristView.setCursorPos(pos),\n setSelectedRows: (rowIds) => api.GristView.setSelectedRows(rowIds),\n fetchSelectedTable: (opts) =>\n fetchSelectedTableShaped(opts) as Promise<Record<string, unknown[]>>,\n fetchSelectedRecord: (rowId, opts) => api.GristView.fetchSelectedRecord(rowId, coerceFetchOptions(opts)),\n\n docApi: {\n getDocName: () => api.GristDocAPI.getDocName(),\n listTables: () => api.GristDocAPI.listTables(),\n fetchTable: (id) => api.GristDocAPI.fetchTable(id),\n applyUserActions: (actions, options) => api.GristDocAPI.applyUserActions(actions, options),\n getAccessToken: (opts) => api.GristDocAPI.getAccessToken(opts),\n fetchSelectedTable: (opts) =>\n fetchSelectedTableShaped(opts) as Promise<Record<string, unknown[]>>,\n fetchSelectedRecord: (rowId, opts) =>\n api.GristView.fetchSelectedRecord(rowId, coerceFetchOptions(opts)),\n },\n\n get selectedTable() {\n return makeTableOps(state.selection.tableId)\n },\n\n getTable(tableId) {\n return makeTableOps(tableId ?? state.selection.tableId)\n },\n\n sectionApi: {\n configure: (settings) => api.CustomSectionAPI.configure(settings as unknown as Record<string, unknown>),\n mappings: () => api.CustomSectionAPI.mappings(),\n },\n\n on(eventName, listener) {\n let set = generic.get(eventName)\n if (!set) generic.set(eventName, (set = new Set()))\n set.add(listener)\n return () => set!.delete(listener)\n },\n }\n\n ;(target as unknown as { grist: InlineGristGlobal }).grist = grist\n\n return {\n grist,\n dispose() {\n offBus()\n // Restore the global (only if we still own it).\n const t = target as unknown as { grist?: unknown }\n if (t.grist === grist) delete t.grist\n recordCbs.clear()\n recordsCbs.clear()\n optionsCbs.clear()\n newRecordCbs.clear()\n generic.clear()\n lastRecord = null\n lastRecords = null\n lastOptions = null\n lastNewRecord = undefined\n },\n fireDataChange(tableId) {\n bus.emit({ type: \"data-change\", tableId: tableId ?? state.selection.tableId })\n },\n fireCursor(rowId) {\n const id = rowId === undefined ? state.selection.rowId : rowId\n bus.emit({ type: \"cursor-change\", tableId: state.selection.tableId, rowId: id })\n },\n fireOptions() {\n pushOptions()\n },\n fireTheme(message) {\n bus.emit({ type: \"theme-change\", message })\n },\n emitInitialState() {\n pushOptions()\n void pushRecords().then(() => pushRecord(state.selection.rowId))\n },\n }\n}\n\nfunction columnsToRows(columnar: Record<string, unknown[]>): Record<string, unknown>[] {\n const cols = Object.keys(columnar)\n if (cols.length === 0) return []\n const length = (columnar[cols[0]] ?? []).length\n const rows: Record<string, unknown>[] = []\n for (let i = 0; i < length; i++) {\n const row: Record<string, unknown> = {}\n for (const c of cols) row[c] = columnar[c][i]\n rows.push(row)\n }\n return rows\n}\n\nfunction parseFields(fields: Record<string, unknown>, _options?: GristTableOpOptions): Record<string, unknown> {\n // The emulator currently doesn't implement string-parsing; pass-through.\n // Hook into here to add date/number parsing when we surface that toggle.\n return { ...fields }\n}\n\nfunction coerceFetchOptions(\n opts: GristFetchSelectedOptions | undefined\n): { keepEncoded?: boolean; format?: \"rows\" | \"columns\" } | undefined {\n if (!opts) return undefined\n const format = opts.format === \"rows\" || opts.format === \"columns\" ? opts.format : undefined\n return { keepEncoded: opts.keepEncoded, format }\n}\n\nfunction logErr(err: unknown) {\n // eslint-disable-next-line no-console\n console.error(\"[grist-emulator/inline]\", err)\n}\n\n// Touch helpers to keep them tree-shake-friendly even if unused in current scope.\nvoid findRow\n\n/**\n * Make `window.self !== window.top` evaluate to `true`. The SDK uses this\n * exact comparison in `useGristAvailability` to detect an iframe environment.\n *\n * Inline transports run inside the host window (tests, IDE preview) and would\n * otherwise be flagged as \"not embedded\" — this shim is the same trick we use\n * in the testing harness and is safe because the inline transport is never\n * shipped to production.\n */\nfunction installFakeIframeContext(target: Window & typeof globalThis) {\n try {\n if (target.self !== target.top) return\n Object.defineProperty(target, \"top\", {\n configurable: true,\n get: () => ({}),\n })\n } catch {\n // Some environments lock these globals; ignore silently.\n }\n}\n","import { z } from \"zod\"\n\nimport type { GristReplicaDocument } from \"../sdk/replica-document\"\n\nconst emulatorRowSchema = z\n .object({ id: z.number() })\n .catchall(z.unknown())\n\nconst formulaKindSchema = z.enum([\"computed\", \"trigger\", \"none\", \"empty_slot\"])\n\nconst replicaColumnSchema = z\n .object({\n colRef: z.number().optional(),\n type: z.string().optional(),\n label: z.string().optional(),\n parentPos: z.number().optional(),\n isFormula: z.boolean().optional(),\n formulaKind: formulaKindSchema.optional(),\n formula: z.string().optional(),\n description: z.string().optional(),\n widgetOptions: z.record(z.string(), z.unknown()).optional(),\n displayColRef: z.number().optional(),\n visibleColRef: z.number().optional(),\n })\n .strict()\n\nconst replicaTableSchema = z\n .object({\n label: z.string().optional(),\n columns: z.record(z.string(), replicaColumnSchema).optional(),\n rows: z.array(emulatorRowSchema).optional(),\n rowCount: z.number().optional(),\n dataOmitted: z.boolean().optional(),\n dataOmittedReason: z.string().optional(),\n error: z.string().optional(),\n })\n .strict()\n\nconst replicaSelectionSchema = z\n .object({\n tableId: z.string().optional(),\n rowId: z.union([z.number(), z.literal(\"new\"), z.null()]).optional(),\n mappings: z.unknown().nullable().optional(),\n cursor: z.unknown().optional(),\n })\n .strict()\n\nconst replicaWidgetConfigurationSchema = z\n .object({\n requiredAccess: z.string().optional(),\n columns: z.unknown().optional(),\n allowSelectBy: z.boolean().optional(),\n hasCustomOptions: z.boolean().optional(),\n })\n .strict()\n\nconst replicaAccessTokenSchema = z\n .object({\n token: z.string(),\n baseUrl: z.string(),\n ttlMsecs: z.number(),\n })\n .strict()\n\nconst replicaDocumentSchema = z\n .object({\n generatedAt: z.string(),\n source: z.string().optional(),\n docName: z.string().optional(),\n mode: z.enum([\"schema-only\", \"schema+samples\", \"schema+data\"]).optional(),\n tables: z.record(z.string(), replicaTableSchema),\n selection: replicaSelectionSchema.optional(),\n widgetOptions: z.record(z.string(), z.unknown()).optional(),\n widgetInteraction: z.unknown().optional(),\n configuration: replicaWidgetConfigurationSchema.optional(),\n accessToken: replicaAccessTokenSchema.nullable().optional(),\n })\n .strict()\n .refine((value) => Object.keys(value.tables).length > 0, {\n message: \"at least one table is required\",\n path: [\"tables\"],\n })\n\nfunction formatZodError(prefix: string, error: z.ZodError): Error {\n const details = error.issues\n .map((issue) => {\n const where = issue.path.length > 0 ? issue.path.join(\".\") : \"<root>\"\n return `${where}: ${issue.message}`\n })\n .join(\"; \")\n return new Error(`${prefix}: ${details}`)\n}\n\nexport function safeParseDocument(input: unknown) {\n return replicaDocumentSchema.safeParse(input)\n}\n\nexport function parseDocument(input: unknown): GristReplicaDocument {\n const result = safeParseDocument(input)\n if (!result.success) {\n throw formatZodError(\"parseDocument\", result.error)\n }\n return result.data as GristReplicaDocument\n}\n","/**\n * Top-level emulator factory. Produces a fully-wired emulator instance:\n *\n * - typed in-memory document state,\n * - shared event bus,\n * - the six host API impls,\n * - one transport (inline by default, iframe when an iframe is provided),\n * - imperative helpers (`mutate`, `apply`, `selectRow`, `selectTable`)\n * that drive the document via the action engine and emit corresponding\n * events.\n *\n * The instance is multi-instance friendly: nothing is stored on `window`.\n */\n\nimport { createApiBundle } from \"./api\"\nimport type { EmulatorApiBundle } from \"./api\"\nimport { applyUserActions } from \"./core/action-engine\"\nimport { createDocument } from \"./core/document\"\nimport { createEventBus } from \"./core/event-bus\"\nimport type { EventBus } from \"./core/event-bus\"\nimport { resolveMappings } from \"./core/mappings\"\nimport type { EmulatorDocumentState } from \"./core/types\"\nimport type { GristReplicaDocument } from \"../sdk/replica-document\"\nimport type { GristWidgetColumnMap } from \"../sdk/types\"\nimport { buildGristThemeHostMessage } from \"./theme-message\"\nimport { createIframeTransport, createInlineTransport } from \"./transports\"\nimport type { EmulatorTransport, InlineGristGlobal } from \"./transports\"\nimport { parseDocument } from \"./validators\"\n\nexport type CreateGristEmulatorOptions = {\n /** The starting document (must satisfy {@link parseDocument}). */\n document: GristReplicaDocument\n /**\n * Pick a transport:\n * - omit / \"inline\" → synthesises `window.grist` directly (or onto `target`),\n * - \"iframe\" → wires a real iframe loading `grist-plugin-api.js`.\n */\n transport?:\n | { kind: \"inline\"; target?: Window & typeof globalThis }\n | { kind: \"iframe\"; iframe: HTMLIFrameElement; targetOrigin?: string }\n /** Initial widget options exposed via `WidgetAPI`. */\n widgetOptions?: Record<string, unknown>\n /**\n * Initial widget interaction info (`access_level` and friends) sent\n * alongside `onOptions`. Defaults to `{ access_level: \"read table\" }`.\n */\n widgetInteraction?: Record<string, unknown>\n /** Initial document theme replayed on widget ready (host `message` channel). */\n initialTheme?: \"light\" | \"dark\"\n}\n\nexport type GristEmulator = {\n /** Underlying mutable document. Treat as read-only outside of `mutate(...)`. */\n state: EmulatorDocumentState\n bus: EventBus\n api: EmulatorApiBundle\n transport: EmulatorTransport\n /** Synthesised `grist` global (only for the inline transport). */\n grist?: InlineGristGlobal\n\n /** Apply a list of Grist user actions; emits the matching events. */\n apply: (actions: unknown[][]) => { retValues: unknown[] }\n /** Convenience helpers for tests and demos. */\n mutate: {\n addRow: (tableId: string, fields: Record<string, unknown>) => number\n updateRow: (tableId: string, rowId: number, fields: Record<string, unknown>) => void\n removeRow: (tableId: string, rowId: number) => void\n }\n selectRow: (rowId: number | \"new\" | null) => void\n selectTable: (tableId: string) => void\n /**\n * Set logical→real column mappings for the playground inspector (and tests).\n * Pass `undefined` to clear — `mappings()` becomes `null` until set again.\n */\n setColumnMappings: (mappings: GristWidgetColumnMap | undefined) => void\n setOptions: (options: Record<string, unknown>) => Promise<void>\n setInteraction: (interaction: Record<string, unknown>) => void\n /** Host theme controls (`grist.on(\"message\")` / `msg.theme`). */\n theme: {\n set: (theme: \"light\" | \"dark\") => void\n }\n /** Tear down the emulator. Idempotent. */\n dispose: () => void\n}\n\nexport function createGristEmulator(options: CreateGristEmulatorOptions): GristEmulator {\n const validatedDocument = parseDocument(options.document)\n const state = createDocument({\n ...validatedDocument,\n widgetOptions: options.widgetOptions ?? validatedDocument.widgetOptions,\n widgetInteraction:\n options.widgetInteraction ?? validatedDocument.widgetInteraction ?? { access_level: \"read table\" },\n })\n const bus = createEventBus()\n const api = createApiBundle(state, bus)\n\n const transportKind = options.transport?.kind ?? \"inline\"\n let transport: EmulatorTransport\n let grist: InlineGristGlobal | undefined\n\n if (transportKind === \"iframe\") {\n if (options.transport?.kind !== \"iframe\") throw new Error(\"transport mismatch\")\n transport = createIframeTransport({\n iframe: options.transport.iframe,\n targetOrigin: options.transport.targetOrigin,\n state,\n bus,\n api,\n initialTheme: options.initialTheme,\n })\n } else {\n const inline = createInlineTransport({\n state,\n bus,\n api,\n initialTheme: options.initialTheme,\n target: options.transport?.kind === \"inline\" ? options.transport.target : undefined,\n })\n transport = inline\n grist = inline.grist\n }\n\n function apply(actions: unknown[][]) {\n return applyUserActions(state, bus, actions)\n }\n\n return {\n state,\n bus,\n api,\n transport,\n grist,\n apply,\n mutate: {\n addRow: (tableId, fields) => apply([[\"AddRecord\", tableId, null, fields]]).retValues[0] as number,\n updateRow: (tableId, rowId, fields) => {\n apply([[\"UpdateRecord\", tableId, rowId, fields]])\n },\n removeRow: (tableId, rowId) => {\n apply([[\"RemoveRecord\", tableId, rowId]])\n },\n },\n selectRow(rowId) {\n state.selection.rowId = rowId\n bus.emit({ type: \"cursor-change\", tableId: state.selection.tableId, rowId })\n },\n selectTable(tableId) {\n if (!state.tables.has(tableId)) throw new Error(`Unknown table: ${tableId}`)\n state.selection.tableId = tableId\n const first = state.tables.get(tableId)!.rows[0]?.id ?? null\n state.selection.rowId = first\n bus.emit({ type: \"data-change\", tableId })\n bus.emit({ type: \"cursor-change\", tableId, rowId: first })\n },\n setColumnMappings(mappings) {\n if (mappings === undefined) {\n delete state.selection.mappings\n } else {\n state.selection.mappings = mappings\n }\n bus.emit({ type: \"mappings-change\", mappings: resolveMappings(state) })\n },\n async setOptions(opts) {\n await api.WidgetAPI.setOptions(opts)\n },\n setInteraction(interaction) {\n state.widgetInteraction = { ...interaction }\n bus.emit({ type: \"options-change\", options: { ...state.widgetOptions }, interaction: { ...interaction } })\n },\n theme: {\n set(next) {\n bus.emit({ type: \"theme-change\", message: buildGristThemeHostMessage(next) })\n },\n },\n dispose() {\n transport.dispose()\n bus.clear()\n },\n }\n}\n","/**\n * Document templates exposed at the top of the emulator API.\n *\n * Templates return plain data — they don't allocate state, the caller passes\n * the returned value into `createGristEmulator(...)` which performs the allocation.\n */\n\nimport type { GristReplicaDocument } from \"../sdk/replica-document\"\n\nconst PRESET_GENERATED_AT = \"1970-01-01T00:00:00.000Z\"\n\nfunction replicaBase(overrides: Omit<GristReplicaDocument, \"generatedAt\">): GristReplicaDocument {\n return {\n generatedAt: PRESET_GENERATED_AT,\n ...overrides,\n }\n}\n\n/**\n * Useful templates for quick demos and tests.\n */\nexport const presets = {\n /**\n * Default starter fixture for demos / sandboxes that need a neutral document\n * without choosing a domain-specific preset.\n */\n defaultTemplate(): GristReplicaDocument {\n return replicaBase({\n docName: \"Default\",\n tables: {\n Table1: {\n label: \"Table1\",\n rows: [\n { id: 1, Name: \"Alice\" },\n { id: 2, Name: \"Bob\" },\n ],\n },\n },\n })\n },\n blank(): GristReplicaDocument {\n return replicaBase({\n docName: \"Blank\",\n tables: {\n Table1: { rows: [{ id: 1 }] },\n },\n })\n },\n todoList(): GristReplicaDocument {\n return replicaBase({\n docName: \"Todo list\",\n mode: \"schema+data\",\n tables: {\n Tasks: {\n label: \"Tasks\",\n columns: {\n title: { type: \"Text\", label: \"Title\" },\n done: { type: \"Bool\", label: \"Done\" },\n priority: { type: \"Choice\", label: \"Priority\" },\n },\n rows: [\n { id: 1, title: \"Buy milk\", done: false, priority: \"high\" },\n { id: 2, title: \"Write the SOTA emulator\", done: true, priority: \"high\" },\n { id: 3, title: \"Ship it\", done: false, priority: \"medium\" },\n ],\n },\n },\n })\n },\n contacts(): GristReplicaDocument {\n return replicaBase({\n docName: \"Contacts\",\n mode: \"schema+data\",\n tables: {\n Contacts: {\n label: \"Contacts\",\n columns: {\n firstName: { type: \"Text\" },\n lastName: { type: \"Text\" },\n email: { type: \"Text\" },\n company: { type: \"Text\" },\n },\n rows: [\n { id: 1, firstName: \"Ada\", lastName: \"Lovelace\", email: \"ada@analytical.engine\", company: \"British Crown\" },\n { id: 2, firstName: \"Linus\", lastName: \"Torvalds\", email: \"linus@kernel.org\", company: \"Linux Foundation\" },\n { id: 3, firstName: \"Margaret\", lastName: \"Hamilton\", email: \"margaret@apollo.nasa\", company: \"NASA\" },\n ],\n },\n },\n })\n },\n}\n","/**\n * Vitest helpers to assert what the widget did to the document.\n *\n * Usage:\n *\n * const { emulator } = renderWithGrist(<MyWidget />)\n * await userEvent.click(screen.getByText(\"Add\"))\n * expect(actionsOf(emulator)).toContainEqual([\"AddRecord\", \"Tasks\", null, { title: \"X\" }])\n */\n\nimport type { GristEmulator } from \"../create-grist-emulator\"\nimport type { EmulatorEvent } from \"../core/event-bus\"\n\nexport function actionsOf(emulator: GristEmulator): unknown[][] {\n return emulator.bus\n .history()\n .filter((e: EmulatorEvent): e is Extract<EmulatorEvent, { type: \"user-action\" }> => e.type === \"user-action\")\n .map((e) => e.action as unknown[])\n}\n\nexport function eventsOf(emulator: GristEmulator): readonly EmulatorEvent[] {\n return emulator.bus.history()\n}\n\n/** Bus event kinds aligned with grist host callbacks (see inline transport). */\nexport type WaitForEventKind = \"ready\" | \"record\" | \"records\" | \"options\" | \"theme\" | \"cursor\"\n\nexport type WaitForEventOptions = {\n timeoutMs?: number\n}\n\nfunction predicateForKind(kind: WaitForEventKind): (event: EmulatorEvent) => boolean {\n switch (kind) {\n case \"ready\":\n return (e) => e.type === \"ready\"\n case \"record\":\n case \"cursor\":\n return (e) => e.type === \"cursor-change\"\n case \"records\":\n return (e) => e.type === \"data-change\"\n case \"options\":\n return (e) => e.type === \"options-change\"\n case \"theme\":\n return (e) => e.type === \"theme-change\"\n }\n}\n\nfunction waitForNextEvent(\n emulator: GristEmulator,\n predicate: (event: EmulatorEvent) => boolean,\n timeoutMs: number,\n label?: string\n): Promise<EmulatorEvent> {\n return new Promise((resolve, reject) => {\n const timer = setTimeout(() => {\n off()\n const hint = label ? ` (kind: ${label})` : \"\"\n const recent = emulator.bus\n .history()\n .slice(-5)\n .map((e) => e.type)\n .join(\", \")\n reject(\n new Error(\n `waitForEvent timed out after ${timeoutMs}ms${hint}.` +\n (recent ? ` Recent bus events: ${recent}.` : \" No bus events yet.\")\n )\n )\n }, timeoutMs)\n const off = emulator.bus.on((event) => {\n if (predicate(event)) {\n clearTimeout(timer)\n off()\n resolve(event)\n }\n })\n })\n}\n\nexport function waitForEvent(\n emulator: GristEmulator,\n kind: WaitForEventKind,\n options?: WaitForEventOptions\n): Promise<EmulatorEvent>\nexport function waitForEvent(\n emulator: GristEmulator,\n predicate: (event: EmulatorEvent) => boolean,\n timeoutMs?: number\n): Promise<EmulatorEvent>\nexport function waitForEvent(\n emulator: GristEmulator,\n kindOrPredicate: WaitForEventKind | ((event: EmulatorEvent) => boolean),\n timeoutOrOptions: number | WaitForEventOptions = 1000\n): Promise<EmulatorEvent> {\n if (typeof kindOrPredicate === \"string\") {\n const opts = typeof timeoutOrOptions === \"object\" ? timeoutOrOptions : {}\n const timeoutMs = opts.timeoutMs ?? 1000\n return waitForNextEvent(emulator, predicateForKind(kindOrPredicate), timeoutMs, kindOrPredicate)\n }\n const timeoutMs = typeof timeoutOrOptions === \"number\" ? timeoutOrOptions : 1000\n return waitForNextEvent(emulator, kindOrPredicate, timeoutMs)\n}\n"],"mappings":"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","names":["options","grist","import_zod","grist","timeoutMs","import_react"]}
|
|
1
|
+
{"version":3,"sources":["../../src/emulator/testing/index.ts","../../src/emulator/testing/render-with-grist.tsx","../../src/sdk/helpers/grist-widget-interaction.ts","../../src/sdk/internal/subscriptions.ts","../../src/sdk/internal/embedded-handshake-manager.ts","../../src/sdk/internal/ready-singleton.ts","../../src/emulator/api/command-api.ts","../../src/emulator/core/mappings.ts","../../src/emulator/api/custom-section-api.ts","../../src/emulator/api/grist-api.ts","../../src/sdk/helpers/grist-value-codec.ts","../../src/sdk/helpers/grist-safe-parse.ts","../../src/sdk/helpers/replica-normalize.ts","../../src/emulator/core/document.ts","../../src/emulator/core/action-engine.ts","../../src/emulator/core/columnar.ts","../../src/emulator/api/grist-doc-api.ts","../../src/emulator/api/grist-view.ts","../../src/emulator/api/widget-api.ts","../../src/emulator/api/index.ts","../../src/emulator/core/event-bus.ts","../../src/emulator/theme-message.ts","../../src/emulator/transports/iframe.ts","../../src/sdk/helpers/grist-user-actions.ts","../../src/emulator/transports/inline.ts","../../src/emulator/validators.ts","../../src/emulator/create-grist-emulator.ts","../../src/emulator/templates.ts","../../src/emulator/testing/matchers.ts"],"sourcesContent":["/**\n * Test entry point — `grist-widget-sdk/emulator/testing`.\n *\n * Bundles `renderWithGrist`, matchers, document presets, and the most-used\n * @testing-library/react primitives so a typical test file only needs one\n * import line:\n *\n * import {\n * renderWithGrist, presets, screen, fireEvent, waitFor, actionsOf,\n * } from \"grist-widget-sdk/emulator/testing\"\n */\n\nexport { renderWithGrist } from \"./render-with-grist\"\nexport type {\n RenderWithGristOptions,\n RenderWithGristResult,\n} from \"./render-with-grist\"\n\nexport {\n actionsOf,\n eventsOf,\n waitForEvent,\n type WaitForEventKind,\n type WaitForEventOptions,\n} from \"./matchers\"\n\n// Document fixtures (re-export from the emulator entry for convenience).\nexport { presets } from \"../templates\"\n\n// @testing-library/react convenience re-exports — see AGENTS.md\nexport {\n act,\n cleanup,\n fireEvent,\n render,\n screen,\n waitFor,\n within,\n} from \"@testing-library/react\"\nexport type { RenderOptions, RenderResult } from \"@testing-library/react\"\n","/**\n * `renderWithGrist(ui, options)` — drop-in replacement for\n * `@testing-library/react`'s `render(ui)` that boots a Grist emulator\n * (inline transport) and exposes it to the test.\n *\n * The emulator is mounted as `window.grist`. The SDK hooks (`useGrist`,\n * `useGristReady`, etc.) detect it via the same path they use in production.\n *\n * Cleanup is automatic when the test's container unmounts.\n */\n\nimport type { ReactElement } from \"react\"\n\nimport { render, type RenderOptions, type RenderResult } from \"@testing-library/react\"\n\nimport { resetEmbeddedHandshakeManagerForTests } from \"../../sdk/internal/embedded-handshake-manager\"\nimport { resetGristReadyCacheForTests } from \"../../sdk/internal/ready-singleton\"\nimport { resetGristEventsForTests } from \"../../sdk/internal/subscriptions\"\nimport { createGristEmulator } from \"../create-grist-emulator\"\nimport type { CreateGristEmulatorOptions, GristEmulator } from \"../create-grist-emulator\"\nimport { presets } from \"../templates\"\n\nexport type RenderWithGristOptions = RenderOptions & {\n emulator?: CreateGristEmulatorOptions\n /** Skip mounting the emulator; you bring your own. Useful for shared fixtures. */\n existing?: GristEmulator\n}\n\nexport type RenderWithGristResult = RenderResult & {\n emulator: GristEmulator\n}\n\nexport function renderWithGrist(\n ui: ReactElement,\n options: RenderWithGristOptions = {}\n): RenderWithGristResult {\n // Make `window.self !== window.top` evaluate to `true` so\n // `useGristAvailability` reports the widget as embedded. We only do this in\n // jsdom; real browsers already enforce this distinction for iframes.\n fakeIframeContext()\n\n resetGristEventsForTests()\n resetGristReadyCacheForTests()\n resetEmbeddedHandshakeManagerForTests()\n\n const emulator =\n options.existing ??\n createGristEmulator(options.emulator ?? { document: presets.blank() })\n\n const result = render(ui, options)\n const originalUnmount = result.unmount\n result.unmount = () => {\n originalUnmount()\n if (!options.existing) emulator.dispose()\n resetGristReadyCacheForTests()\n resetGristEventsForTests()\n resetEmbeddedHandshakeManagerForTests()\n }\n return Object.assign(result, { emulator })\n}\n\nfunction fakeIframeContext() {\n if (typeof window === \"undefined\") return\n if (window.self !== window.top) return // already iframe-like\n try {\n Object.defineProperty(window, \"top\", {\n configurable: true,\n get: () => ({}),\n })\n } catch {\n // Some jsdom versions block redefinition; fail silently — tests using\n // `useGristAvailability` will need to bypass it explicitly in that case.\n }\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 * Module-level subscription manager for Grist's `on*` events.\n *\n * Why this exists: `grist.onRecord`, `onRecords`, `onOptions`, and `onNewRecord`\n * are add-only — there is no `off`. Subscribing in every hook instance leaks\n * handlers for the page lifetime. This module subscribes to each Grist event\n * **at most once** and fans out to React listeners with proper teardown.\n *\n * Last-known values are cached so late subscribers immediately receive the\n * current state (analogous to a BehaviorSubject).\n *\n * Fixed-defaults contract\n * -----------------------\n * The underlying `grist.onRecord` / `onRecords` calls accept a\n * `FetchSelectedOptions` parameter (e.g. `keepEncoded`, `format`), but\n * because we bind **once** at the first subscribe, those options would be\n * \"first-hook-wins\" across the page — a subtle footgun for agents.\n *\n * This module therefore binds with Grist's **public defaults** and does not\n * accept per-subscriber options:\n * - `onRecord` → decoded rows (`keepEncoded: false`)\n * - `onRecords` → decoded rows (`format: \"rows\"`, `keepEncoded: false`)\n *\n * If you need encoded values, use the one-shot readers\n * (`useGrist().fetchSelectedTable({ keepEncoded: true })`) instead of\n * a subscription — that call-site controls its own options.\n */\n\nimport { normalizeWidgetInteraction } from \"../helpers/grist-widget-interaction\"\nimport type { GristWidgetColumnMap, GristWidgetInteraction } from \"../types\"\n\ntype Listener<T> = (value: T) => void\n\nclass GristEvent<T> {\n private listeners = new Set<Listener<T>>()\n private hasValue = false\n private last: T | undefined\n private bind: (() => void) | null = null\n\n constructor(private readonly bindOnce: (emit: (value: T) => void) => void) {}\n\n subscribe(listener: Listener<T>): () => void {\n this.listeners.add(listener)\n if (!this.bind) {\n this.bind = () => {\n // Mark as bound regardless of throw, so we don't retry every render.\n this.bind = () => {}\n try {\n this.bindOnce((value) => {\n this.hasValue = true\n this.last = value\n for (const l of this.listeners) l(value)\n })\n } catch (err) {\n if (typeof console !== \"undefined\") {\n console.error(\"[lib/grist] failed to subscribe to Grist event:\", err)\n }\n }\n }\n this.bind()\n }\n if (this.hasValue && this.last !== undefined) {\n listener(this.last)\n }\n return () => {\n this.listeners.delete(listener)\n }\n }\n\n /** Last cached value (or `undefined` if no event has fired yet). */\n peek(): T | undefined {\n return this.last\n }\n\n /** True once at least one event has fired. */\n get ready(): boolean {\n return this.hasValue\n }\n\n /**\n * Test helper: fan out a payload without calling `grist.on*`.\n * Used to simulate hosts that reuse one record object and mutate it in place.\n */\n deliverForTests(value: T): void {\n this.hasValue = true\n this.last = value\n for (const l of this.listeners) l(value)\n }\n\n /**\n * Test helper: forget the bound state and cached value. Lets a test swap\n * `window.grist` (e.g. via the emulator's `dispose()` + `createGristEmulator()`)\n * and re-bind cleanly on the next subscribe.\n */\n _resetForTests(): void {\n this.listeners.clear()\n this.hasValue = false\n this.last = undefined\n this.bind = null\n }\n}\n\nexport type GristRecordPayload = {\n record: Record<string, unknown> | null\n mappings: GristWidgetColumnMap | null\n}\n\nexport type GristRecordsPayload = {\n records: Record<string, unknown>[]\n mappings: GristWidgetColumnMap | null\n}\n\nexport type GristOptionsPayload = {\n options: Record<string, unknown> | null\n interaction: GristWidgetInteraction | null\n}\n\nexport type GristNewRecordPayload = {\n mappings: GristWidgetColumnMap | null\n}\n\n/**\n * The singletons. These are lazy: nothing is registered with `grist` until\n * the first `subscribe()` call.\n */\ntype GristHostMessage = {\n tableId?: string\n rowId?: number | \"new\"\n dataChange?: boolean\n mappingsChange?: boolean\n}\n\nexport const recordEvent = new GristEvent<GristRecordPayload>((emit) => {\n const deliver = (record: Record<string, unknown> | null, mappings: GristWidgetColumnMap | null) => {\n emit({ record, mappings })\n }\n\n // Pin `keepEncoded: false` so mapped records contain JS-native values for\n // widget code instead of raw cell tuples.\n grist.onRecord(\n (record, mappings) => {\n deliver(record, (mappings as GristWidgetColumnMap | null) ?? null)\n },\n { keepEncoded: false }\n )\n\n // Mirror grist-plugin-api's `onRecord` message handler: Grist's RecordNotifier\n // posts `{ rowId, dataChange: false }` on cursor moves. `onRecord` should\n // handle that, but refetch here when `rowId` changes so widgets never stick on\n // the first row if the callback path is skipped or reordered.\n const fetchSelectedRecord = grist.fetchSelectedRecord ?? grist.docApi?.fetchSelectedRecord\n if (typeof grist.on !== \"function\" || typeof fetchSelectedRecord !== \"function\") {\n return\n }\n let lastRowId: number | undefined\n grist.on(\"message\", async (msg: unknown) => {\n if (!msg || typeof msg !== \"object\") return\n const host = msg as GristHostMessage\n if (!host.tableId || typeof host.rowId !== \"number\") return\n if (host.rowId === lastRowId) return\n lastRowId = host.rowId\n try {\n const record = await fetchSelectedRecord(host.rowId, { keepEncoded: false })\n deliver(record, recordEvent.peek()?.mappings ?? null)\n } catch (err) {\n if (typeof console !== \"undefined\") {\n console.error(\"[grist-widget-sdk] fetchSelectedRecord on cursor message failed:\", err)\n }\n }\n })\n})\n\nexport const recordsEvent = new GristEvent<GristRecordsPayload>((emit) => {\n // Pin `format: \"rows\"` + `keepEncoded: false` so callers always receive\n // row-shaped decoded objects. (GristView would otherwise default to\n // `format: \"columns\"` + `keepEncoded: true`.)\n grist.onRecords(\n (records, mappings) => {\n emit({ records, mappings: (mappings as GristWidgetColumnMap | null) ?? null })\n },\n { keepEncoded: false, format: \"rows\" }\n )\n})\n\nexport const optionsEvent = new GristEvent<GristOptionsPayload>((emit) => {\n grist.onOptions((options, interaction) => {\n const normalized = normalizeWidgetInteraction(\n (interaction as GristWidgetInteraction | null) ?? null\n )\n emit({\n options: options ? { ...options } : null,\n interaction: normalized,\n })\n })\n})\n\nexport const newRecordEvent = new GristEvent<GristNewRecordPayload>((emit) => {\n if (typeof grist.onNewRecord !== \"function\") return\n grist.onNewRecord((mappings) => {\n emit({ mappings: (mappings as GristWidgetColumnMap | null) ?? null })\n })\n})\n\n/**\n * Test-only: reset every event singleton. Call between tests when swapping\n * `window.grist`. Production code never imports this.\n */\nexport function resetGristEventsForTests(): void {\n recordEvent._resetForTests()\n recordsEvent._resetForTests()\n optionsEvent._resetForTests()\n newRecordEvent._resetForTests()\n}\n\n/** Vitest-only: push a record payload through {@link recordEvent} subscribers. */\nexport function deliverRecordForTests(payload: GristRecordPayload): void {\n recordEvent.deliverForTests(payload)\n}\n","/**\n * Page-level embedded handshake manager for widgets that call `useGrist()` /\n * `useGristCore()` without mounting `<GristWidgetProvider>`.\n *\n * A single manager is shared across all hook instances on the page (ref-counted)\n * so mid-level hooks (`useGristActions`, `useGristRowsFromTable`, …) do not\n * spawn competing `grist.ready` handshakes.\n */\n\nimport {\n createGristHandshakeManager,\n type ManagerControls,\n type ManagerOptions,\n} from \"./handshake/manager\"\n\ntype EmbeddedSlot = {\n manager: ManagerControls\n refCount: number\n}\n\nlet embedded: EmbeddedSlot | null = null\n\nexport function acquireEmbeddedHandshakeManager(options: ManagerOptions): ManagerControls {\n if (!embedded) {\n embedded = {\n manager: createGristHandshakeManager(options),\n refCount: 0,\n }\n embedded.manager.start()\n }\n embedded.refCount += 1\n return embedded.manager\n}\n\nexport function releaseEmbeddedHandshakeManager(): void {\n if (!embedded) return\n embedded.refCount -= 1\n if (embedded.refCount <= 0) {\n embedded.manager.stop()\n embedded = null\n }\n}\n\n/** Test isolation — tear down the page-level embedded manager between cases. */\nexport function resetEmbeddedHandshakeManagerForTests(): void {\n if (embedded) {\n embedded.manager.stop()\n embedded = null\n }\n}\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 resetGristReadySingleton(): void {\n inFlight = null\n lastAccess = null\n lastColumnNames = null\n}\n\n/** @deprecated Use {@link resetGristReadySingleton}. Kept for test back-compat. */\nexport const resetGristReadyCacheForTests = resetGristReadySingleton\n","import type { EventBus } from \"../core/event-bus\"\nimport type { CommandApiImpl } from \"./types\"\n\n/**\n * `CommandAPI` host implementation. The widget's \"Edit Options\" gear and a\n * few keyboard shortcuts call into this. We forward the call name on the bus\n * so the inspector and tests can observe it; useful to assert\n * `onEditOptions` flows.\n */\nexport function createCommandApiImpl(bus: EventBus): CommandApiImpl {\n return {\n async run(name) {\n bus.emit({ type: \"user-action\", action: [\"RunCommand\", name] })\n },\n }\n}\n","/**\n * Resolves the `mappings` payload that `CustomSectionAPI.mappings()` returns.\n *\n * The playground emulator does **not** infer logical → real columns from\n * names. Mappings come only from `state.selection.mappings` (playground\n * document inspector or tests). When unset, returns `null`.\n */\n\nimport type { GristWidgetColumnMap } from \"../../sdk/types\"\nimport type { EmulatorDocumentState } from \"./types\"\n\nexport function resolveMappings(state: EmulatorDocumentState): GristWidgetColumnMap | null {\n if (state.selection.mappings !== undefined && state.selection.mappings !== null) {\n return state.selection.mappings\n }\n return null\n}\n","import { resolveMappings } from \"../core/mappings\"\nimport type { EventBus } from \"../core/event-bus\"\nimport type { GristWidgetConfiguration } from \"../../sdk/types\"\nimport type { EmulatorDocumentState } from \"../core/types\"\nimport type { CustomSectionApiImpl } from \"./types\"\n\n/**\n * `CustomSectionAPI` host implementation, called by `grist-plugin-api.js`\n * after `grist.ready()` to hand the host the widget's preferences:\n * required access, declared columns, allowSelectBy, hasCustomOptions, etc.\n *\n * Implementation:\n * - persists the configuration onto `state.configuration`,\n * - emits a `ready` event so the iframe transport knows it's safe to push\n * initial cursor / data / options messages,\n * - re-emits a `mappings-change` so the inspector and tests can react.\n */\nexport function createCustomSectionApiImpl(\n state: EmulatorDocumentState,\n bus: EventBus\n): CustomSectionApiImpl {\n return {\n async configure(settings) {\n const config: GristWidgetConfiguration = {\n requiredAccess: settings.requiredAccess as GristWidgetConfiguration[\"requiredAccess\"],\n columns: settings.columns as GristWidgetConfiguration[\"columns\"],\n allowSelectBy: settings.allowSelectBy as boolean | undefined,\n hasCustomOptions: settings.hasCustomOptions as boolean | undefined,\n }\n state.configuration = config\n bus.emit({ type: \"ready\", configuration: config })\n bus.emit({ type: \"mappings-change\", mappings: resolveMappings(state) })\n },\n\n async mappings() {\n return resolveMappings(state)\n },\n }\n}\n","import type { GristApiImpl } from \"./types\"\n\n/** `_grist_api` host implementation. Minimal v1 — extend as needed. */\nexport function createGristApiImpl(): GristApiImpl {\n return {\n async ping() {\n return \"pong\"\n },\n }\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 { z, type ZodType } from \"zod\"\n\nimport type { GristReplicaColumn, GristRowRecord } from \"../types\"\nimport type { GristColumnarTable } from \"./grist-table-data\"\nimport { normalizeGristChoiceListEntries, type GristChoiceListEntry } from \"./grist-widget-options\"\nimport { decodeGristValue, type GristDecodedValue } from \"./grist-value-codec\"\n\nexport type GristSafeParseIssueCode =\n | \"grist_error\"\n | \"invalid_format\"\n | \"type_mismatch\"\n | \"helper_mismatch\"\n | \"zod_error\"\n\nexport type GristSafeParseIssue = {\n code: GristSafeParseIssueCode\n message: string\n}\n\nexport type GristSafeRefValue = {\n rowId: number\n display?: string | null\n}\n\nexport type GristSafeRefListValue = {\n rowIds: number[]\n displays?: string[]\n}\n\nexport const gristSafeRefValueSchema = z.object({\n rowId: z.number(),\n display: z.string().nullable().optional(),\n})\n\nexport const gristSafeRefListValueSchema = z.object({\n rowIds: z.array(z.number()),\n displays: z.array(z.string()).optional(),\n})\n\nexport const gristCellValueSchema = z.union([\n z.null(),\n z.string(),\n z.number(),\n z.boolean(),\n z.date(),\n z.array(z.unknown()),\n gristSafeRefValueSchema,\n gristSafeRefListValueSchema,\n])\n\nexport type GristCellValue = z.infer<typeof gristCellValueSchema>\n\nexport type GristSafeParseCellResult<TValue = unknown> = {\n ok: boolean\n typedValue: TValue | null\n displayValue: unknown\n raw: unknown\n issues: GristSafeParseIssue[]\n}\n\ntype RefMode = \"id\" | \"detailed\"\n\nexport type SafeParseGristValuesOptions<TValue = unknown> = {\n values: readonly unknown[]\n column?: GristReplicaColumn\n helperValues?: readonly unknown[]\n schema?: ZodType<TValue>\n fallbackUntypedToString?: boolean\n refMode?: RefMode\n}\n\nexport type SafeParseGristTableDataOptions = {\n columns?: Record<string, GristReplicaColumn>\n displayHelpersByRef?: Record<string, string>\n order?: \"none\" | \"id\" | \"grist\"\n fallbackUntypedToString?: boolean\n refMode?: RefMode\n}\n\nexport type GristSafeTableCellIssue = GristSafeParseIssue & {\n rowIndex: number\n colId: string\n}\n\nexport type GristSafeChoiceTokenMeta = {\n value: string\n label: string\n fillColor?: string\n textColor?: string\n valid: boolean\n}\n\nexport type GristSafeTableCellMeta = {\n rowIndex: number\n colId: string\n ok: boolean\n issues: GristSafeParseIssue[]\n choiceTokens?: GristSafeChoiceTokenMeta[]\n}\n\nexport type SafeParseGristTableDataResult<TRow extends Record<string, unknown> = Record<string, unknown>> = {\n rows: GristRowRecord<TRow>[]\n cellIssues: GristSafeTableCellIssue[]\n cellMeta: GristSafeTableCellMeta[]\n cellMetaByKey: Record<string, GristSafeTableCellMeta>\n cellResultsByColumn: Record<string, GristSafeParseCellResult[]>\n}\n\n/** Maps `Ref:*` / `RefList:*` column ids to their paired `gristHelper_*` column id (same rules as safe-parse). */\nexport function inferDisplayHelpersByRef(\n columns: Record<string, GristReplicaColumn>\n): Record<string, string> {\n const out: Record<string, string> = {}\n const helperColumns = Object.entries(columns).filter(([colId]) =>\n colId.startsWith(\"gristHelper_\")\n )\n const usedHelpers = new Set<string>()\n const colRefToColId = new Map<number, string>()\n for (const [colId, col] of Object.entries(columns)) {\n if (typeof col?.colRef === \"number\" && Number.isFinite(col.colRef)) {\n colRefToColId.set(col.colRef, colId)\n }\n }\n for (const [colId, col] of Object.entries(columns)) {\n const type = col?.type\n if (typeof type !== \"string\" || (!type.startsWith(\"Ref:\") && !type.startsWith(\"RefList:\"))) {\n continue\n }\n if (typeof col.displayColRef === \"number\" && Number.isFinite(col.displayColRef)) {\n const helperColId = colRefToColId.get(col.displayColRef)\n if (helperColId) {\n out[colId] = helperColId\n usedHelpers.add(helperColId)\n continue\n }\n }\n const match = helperColumns.find(([, helper]) => {\n const formula = helper?.formula\n return typeof formula === \"string\" && (formula.includes(`$${colId}.`) || formula.includes(`$${colId}`))\n })\n if (match) {\n out[colId] = match[0]\n usedHelpers.add(match[0])\n }\n }\n\n // Secondary fallback for schemas where helper formulas are unavailable:\n // pair unresolved Ref/RefList columns with nearest following gristHelper_*.\n const unresolvedRefs = Object.entries(columns)\n .filter(([colId, col]) => {\n const type = col?.type\n return (\n !out[colId] &&\n typeof type === \"string\" &&\n (type.startsWith(\"Ref:\") || type.startsWith(\"RefList:\"))\n )\n })\n .sort((a, b) => (a[1]?.parentPos ?? Number.MAX_SAFE_INTEGER) - (b[1]?.parentPos ?? Number.MAX_SAFE_INTEGER))\n const helperByPos = helperColumns\n .filter(([helperId]) => !usedHelpers.has(helperId))\n .sort((a, b) => (a[1]?.parentPos ?? Number.MAX_SAFE_INTEGER) - (b[1]?.parentPos ?? Number.MAX_SAFE_INTEGER))\n for (const [refId, refCol] of unresolvedRefs) {\n const refPos = refCol?.parentPos ?? Number.MAX_SAFE_INTEGER\n const candidate = helperByPos.find(([, helperCol]) => {\n const helperPos = helperCol?.parentPos ?? Number.MAX_SAFE_INTEGER\n return helperPos > refPos\n })\n if (!candidate) continue\n out[refId] = candidate[0]\n usedHelpers.add(candidate[0])\n }\n // If multiple unresolved refs remain, greedily map by order.\n for (const [refId] of unresolvedRefs) {\n if (out[refId]) continue\n const candidate = helperByPos.find(([helperId]) => !usedHelpers.has(helperId))\n if (!candidate) continue\n out[refId] = candidate[0]\n usedHelpers.add(candidate[0])\n }\n return out\n}\n\nfunction 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\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\nfunction 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\nfunction columnKind(column?: GristReplicaColumn):\n | \"text\"\n | \"numeric\"\n | \"int\"\n | \"bool\"\n | \"date\"\n | \"datetime\"\n | \"choice\"\n | \"choiceList\"\n | \"ref\"\n | \"refList\"\n | \"attachments\"\n | \"any\"\n | \"unknown\" {\n const type = column?.type\n if (!type) return \"unknown\"\n if (type === \"Text\") return \"text\"\n if (type === \"Numeric\") return \"numeric\"\n if (type === \"Int\") return \"int\"\n if (type === \"Bool\") return \"bool\"\n if (type === \"Date\") return \"date\"\n if (type === \"DateTime\" || type.startsWith(\"DateTime:\")) return \"datetime\"\n if (type === \"Choice\") return \"choice\"\n if (type === \"ChoiceList\") return \"choiceList\"\n if (type.startsWith(\"Ref:\")) return \"ref\"\n if (type.startsWith(\"RefList:\")) return \"refList\"\n if (type === \"Attachments\") return \"attachments\"\n if (type === \"Any\") return \"any\"\n return \"unknown\"\n}\n\nfunction primitiveToString(value: unknown): string | null {\n if (value === null || value === undefined) return null\n if (typeof value === \"string\") return value\n if (typeof value === \"number\" || typeof value === \"boolean\" || typeof value === \"bigint\") {\n return String(value)\n }\n return null\n}\n\nfunction normalizeRefDisplay(value: unknown): { value?: string | null; issue?: GristSafeParseIssue } {\n if (value === null || value === undefined) return { value: null }\n if (typeof value === \"string\") return { value }\n if (typeof value === \"number\" || typeof value === \"boolean\") return { value: String(value) }\n return {\n issue: {\n code: \"helper_mismatch\",\n message: \"Ref display helper value should be a scalar value.\",\n },\n }\n}\n\nfunction normalizeRefListDisplays(value: unknown): { values?: string[]; issue?: GristSafeParseIssue } {\n if (value === null || value === undefined) return { values: [] }\n if (typeof value === \"string\") {\n const s = value.trim()\n if (s === \"\") return { values: [] }\n if (s.startsWith(\"[\")) {\n try {\n const parsed = JSON.parse(s)\n if (Array.isArray(parsed)) {\n return normalizeRefListDisplays(parsed)\n }\n } catch {\n // Keep existing error below for non-array/non-JSON helper strings.\n }\n }\n }\n if (!Array.isArray(value)) {\n return {\n issue: {\n code: \"helper_mismatch\",\n message: \"RefList display helper value should be an array.\",\n },\n }\n }\n // Grist list wire format may leak through as [\"L\", ...items].\n // Treat a leading \"L\" marker as metadata, not a display label.\n const items =\n value.length > 0 && value[0] === \"L\"\n ? value.slice(1)\n : value\n const out: string[] = []\n for (const item of items) {\n const s = primitiveToString(item)\n if (s === null) {\n return {\n issue: {\n code: \"helper_mismatch\",\n message: \"RefList helper items should be scalar values.\",\n },\n }\n }\n out.push(s)\n }\n return { values: out }\n}\n\nfunction normalizeRefValue(\n decoded: GristDecodedValue,\n helperValue: unknown,\n refMode: RefMode\n): { value: number | GristSafeRefValue | null; issues: GristSafeParseIssue[] } {\n const issues: GristSafeParseIssue[] = []\n if (decoded === null) return { value: null, issues }\n\n const rowId =\n typeof decoded === \"number\" && Number.isFinite(decoded)\n ? decoded\n : decoded && typeof decoded === \"object\" && \"__ref\" in decoded\n ? (decoded as { rowId: number }).rowId\n : null\n\n // Grist empty refs can surface as 0; treat as empty cell.\n if (rowId === 0) return { value: null, issues }\n if (rowId === null || !Number.isFinite(rowId)) {\n issues.push({\n code: \"type_mismatch\",\n message: \"Expected a Ref row id.\",\n })\n return { value: null, issues }\n }\n\n if (refMode === \"id\") return { value: rowId, issues }\n\n const helper = normalizeRefDisplay(helperValue)\n if (helper.issue) issues.push(helper.issue)\n return {\n value: { rowId, display: helper.value },\n issues,\n }\n}\n\nfunction normalizeRefListValue(\n decoded: GristDecodedValue,\n helperValue: unknown,\n refMode: RefMode\n): { value: number[] | GristSafeRefListValue | null; issues: GristSafeParseIssue[] } {\n const issues: GristSafeParseIssue[] = []\n if (decoded === null) return { value: null, issues }\n if (!Array.isArray(decoded)) {\n issues.push({\n code: \"type_mismatch\",\n message: \"Expected an array for RefList.\",\n })\n return { value: null, issues }\n }\n\n const rowIds: number[] = []\n for (const item of decoded) {\n if (typeof item === \"number\" && Number.isFinite(item) && item !== 0) {\n rowIds.push(item)\n continue\n }\n if (item && typeof item === \"object\" && \"__ref\" in item) {\n const rowId = (item as { rowId: number }).rowId\n if (typeof rowId === \"number\" && Number.isFinite(rowId) && rowId !== 0) {\n rowIds.push(rowId)\n continue\n }\n }\n issues.push({\n code: \"type_mismatch\",\n message: \"RefList items should be row ids.\",\n })\n return { value: null, issues }\n }\n\n if (refMode === \"id\") return { value: rowIds, issues }\n\n const helper = normalizeRefListDisplays(helperValue)\n if (helper.issue) {\n issues.push(helper.issue)\n } else if (helper.values && helper.values.length > 0 && helper.values.length !== rowIds.length) {\n issues.push({\n code: \"helper_mismatch\",\n message: \"RefList helper labels count does not match row ids count.\",\n })\n }\n return {\n value: { rowIds, displays: helper.values },\n issues,\n }\n}\n\nfunction normalizeByColumnKind(\n decoded: GristDecodedValue,\n kind: ReturnType<typeof columnKind>,\n helperValue: unknown,\n fallbackUntypedToString: boolean,\n refMode: RefMode\n): { value: unknown; issues: GristSafeParseIssue[] } {\n const issues: GristSafeParseIssue[] = []\n if (decoded && typeof decoded === \"object\" && \"__error\" in decoded) {\n issues.push({\n code: \"grist_error\",\n message: (decoded as { message?: string }).message ?? \"Grist returned a cell error.\",\n })\n return { value: null, issues }\n }\n\n switch (kind) {\n case \"ref\":\n return normalizeRefValue(decoded, helperValue, refMode)\n case \"refList\":\n return normalizeRefListValue(decoded, helperValue, refMode)\n case \"date\":\n case \"datetime\":\n if (decoded === null || decoded instanceof Date) return { value: decoded, issues }\n issues.push({ code: \"type_mismatch\", message: \"Expected a Date value.\" })\n return { value: null, issues }\n case \"bool\":\n if (decoded === null || typeof decoded === \"boolean\") return { value: decoded, issues }\n issues.push({ code: \"type_mismatch\", message: \"Expected a boolean value.\" })\n return { value: null, issues }\n case \"numeric\":\n if (decoded === null || (typeof decoded === \"number\" && Number.isFinite(decoded))) {\n return { value: decoded, issues }\n }\n issues.push({ code: \"type_mismatch\", message: \"Expected a numeric value.\" })\n return {\n value:\n typeof decoded === \"string\" ||\n typeof decoded === \"number\" ||\n typeof decoded === \"boolean\"\n ? decoded\n : null,\n issues,\n }\n case \"int\":\n if (decoded === null || (typeof decoded === \"number\" && Number.isInteger(decoded))) {\n return { value: decoded, issues }\n }\n issues.push({ code: \"type_mismatch\", message: \"Expected an integer value.\" })\n return {\n value:\n typeof decoded === \"string\" ||\n typeof decoded === \"number\" ||\n typeof decoded === \"boolean\"\n ? decoded\n : null,\n issues,\n }\n case \"choice\":\n case \"text\":\n if (decoded === null || typeof decoded === \"string\") return { value: decoded, issues }\n issues.push({ code: \"type_mismatch\", message: \"Expected a string value.\" })\n return { value: null, issues }\n case \"choiceList\":\n case \"attachments\":\n if (decoded === null || Array.isArray(decoded)) return { value: decoded, issues }\n issues.push({ code: \"type_mismatch\", message: \"Expected a list value.\" })\n return { value: null, issues }\n case \"any\":\n case \"unknown\":\n // Heuristic fallback: when schema typing is missing but a helper column is\n // attached, infer Ref/RefList from the decoded shape.\n if (helperValue !== undefined) {\n if (typeof decoded === \"number\" || (decoded && typeof decoded === \"object\" && \"__ref\" in decoded)) {\n return normalizeRefValue(decoded, helperValue, refMode)\n }\n if (Array.isArray(decoded)) {\n return normalizeRefListValue(decoded, helperValue, refMode)\n }\n }\n if (!fallbackUntypedToString) return { value: decoded, issues }\n if (decoded === null) return { value: null, issues }\n if (typeof decoded === \"string\") return { value: decoded, issues }\n if (\n typeof decoded === \"number\" ||\n typeof decoded === \"boolean\" ||\n decoded instanceof Date\n ) {\n return {\n value: decoded instanceof Date ? decoded.toISOString() : String(decoded),\n issues,\n }\n }\n if (Array.isArray(decoded)) {\n try {\n return { value: JSON.stringify(decoded), issues }\n } catch {\n issues.push({\n code: \"invalid_format\",\n message: \"Unable to stringify list value.\",\n })\n return { value: null, issues }\n }\n }\n issues.push({\n code: \"type_mismatch\",\n message: \"Untyped value could not be represented as a string.\",\n })\n return { value: null, issues }\n }\n}\n\nfunction buildChoiceTokens(\n col: GristReplicaColumn | undefined,\n value: unknown\n): GristSafeChoiceTokenMeta[] | undefined {\n const type = col?.type\n if (type !== \"Choice\" && type !== \"ChoiceList\") return undefined\n const entries = normalizeGristChoiceListEntries(col?.widgetOptions)\n const byValue = new Map<string, GristChoiceListEntry>(entries.map((entry) => [entry.value, entry]))\n\n if (type === \"Choice\") {\n if (value == null || typeof value !== \"string\" || value.trim() === \"\") return []\n const meta = byValue.get(value)\n if (!meta) return [{ value, label: value, valid: false }]\n return [\n {\n value,\n label: meta.label,\n fillColor: meta.fillColor,\n textColor: meta.textColor,\n valid: true,\n },\n ]\n }\n\n if (!Array.isArray(value)) return []\n const out: GristSafeChoiceTokenMeta[] = []\n for (const item of value) {\n const v = typeof item === \"string\" ? item : String(item)\n const meta = byValue.get(v)\n if (!meta) {\n out.push({ value: v, label: v, valid: false })\n continue\n }\n out.push({\n value: v,\n label: meta.label,\n fillColor: meta.fillColor,\n textColor: meta.textColor,\n valid: true,\n })\n }\n return out\n}\n\nexport function safeParseGristValues<TValue = unknown>(\n options: SafeParseGristValuesOptions<TValue>\n): GristSafeParseCellResult<TValue>[] {\n const fallbackUntypedToString = options.fallbackUntypedToString ?? true\n const refMode = options.refMode ?? \"id\"\n const kind = columnKind(options.column)\n return options.values.map((raw, index) => {\n const decoded = decodeGristValue(raw, options.column)\n const helperValue = options.helperValues?.[index]\n const normalized = normalizeByColumnKind(\n decoded,\n kind,\n helperValue,\n fallbackUntypedToString,\n refMode\n )\n const issues = [...normalized.issues]\n\n if (options.schema) {\n const result = options.schema.safeParse(normalized.value)\n if (!result.success) {\n issues.push({\n code: \"zod_error\",\n message: result.error.issues.map((issue) => issue.message).join(\"; \"),\n })\n }\n }\n\n return {\n ok: issues.length === 0,\n typedValue: normalized.value as TValue | null,\n displayValue: normalized.value,\n raw,\n issues,\n }\n })\n}\n\nexport function safeParseGristTableData<TRow extends Record<string, unknown> = Record<string, unknown>>(\n data: GristColumnarTable,\n options?: SafeParseGristTableDataOptions\n): SafeParseGristTableDataResult<TRow> {\n const columns = options?.columns ?? {}\n const inferredDisplayHelpersByRef = inferDisplayHelpersByRef(columns)\n const displayHelpersByRef: Record<string, string> = {\n ...inferredDisplayHelpersByRef,\n ...(options?.displayHelpersByRef ?? {}),\n }\n // Fallback convention: if `owner` exists and `gristHelper_owner` is fetched,\n // use it as display helper even when formula metadata is unavailable.\n for (const [colId, col] of Object.entries(columns)) {\n const type = col?.type\n if (typeof type !== \"string\" || (!type.startsWith(\"Ref:\") && !type.startsWith(\"RefList:\"))) {\n continue\n }\n if (displayHelpersByRef[colId]) continue\n const byName = `gristHelper_${colId}`\n if (Array.isArray(data[byName])) {\n displayHelpersByRef[colId] = byName\n }\n }\n const fallbackUntypedToString = options?.fallbackUntypedToString ?? true\n const refMode = options?.refMode ?? \"id\"\n const colIds = Object.keys(data)\n const parsedByColumn: Record<string, GristSafeParseCellResult[]> = {}\n\n for (const colId of colIds) {\n const rawValues = Array.isArray(data[colId]) ? data[colId] : []\n const helperColId = displayHelpersByRef[colId]\n const helperValues = helperColId && Array.isArray(data[helperColId]) ? data[helperColId] : undefined\n parsedByColumn[colId] =\n colId === \"id\"\n ? rawValues.map((raw) => ({\n ok: typeof raw === \"number\" && Number.isFinite(raw),\n typedValue: typeof raw === \"number\" && Number.isFinite(raw) ? raw : null,\n displayValue: raw,\n raw,\n issues:\n typeof raw === \"number\" && Number.isFinite(raw)\n ? []\n : [{ code: \"type_mismatch\", message: \"Row id should be numeric.\" }],\n }))\n : safeParseGristValues({\n values: rawValues,\n column: columns[colId],\n helperValues,\n fallbackUntypedToString,\n refMode,\n })\n }\n\n const rowCount = computeRowCount(data)\n const rows: GristRowRecord<TRow>[] = []\n const cellIssues: GristSafeTableCellIssue[] = []\n const cellMeta: GristSafeTableCellMeta[] = []\n for (let rowIndex = 0; rowIndex < rowCount; rowIndex++) {\n const row: Record<string, unknown> = {}\n for (const colId of colIds) {\n const parsed = parsedByColumn[colId]?.[rowIndex]\n row[colId] = parsed?.typedValue ?? null\n const choiceTokens = buildChoiceTokens(columns[colId], parsed?.displayValue)\n if (parsed) {\n if (parsed.issues.length > 0 || (choiceTokens && choiceTokens.length > 0)) {\n cellMeta.push({\n rowIndex,\n colId,\n ok: parsed.ok,\n issues: parsed.issues,\n choiceTokens,\n })\n }\n }\n if (!parsed || parsed.issues.length === 0) continue\n for (const issue of parsed.issues) {\n cellIssues.push({ ...issue, rowIndex, colId })\n }\n }\n rows.push(row as GristRowRecord<TRow>)\n }\n\n const cellMetaByKey: Record<string, GristSafeTableCellMeta> = {}\n for (const meta of cellMeta) {\n const rowId = rows[meta.rowIndex]?.id\n if (typeof rowId !== \"number\") continue\n cellMetaByKey[`${rowId}:${meta.colId}`] = meta\n }\n\n const order = options?.order ?? \"grist\"\n if (order === \"none\") {\n return { rows, cellIssues, cellMeta, cellMetaByKey, cellResultsByColumn: parsedByColumn }\n }\n if (order === \"id\") {\n return {\n rows: [...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 cellIssues,\n cellMeta,\n cellMetaByKey,\n cellResultsByColumn: parsedByColumn,\n }\n }\n return {\n rows: sortRowsByGristOrder(rows),\n cellIssues,\n cellMeta,\n cellMetaByKey,\n cellResultsByColumn: parsedByColumn,\n }\n}\n","import type { GristReplicaDocument, GristReplicaRow, GristReplicaTable } from \"../replica-document\"\n\n/**\n * Ensure `rows` is a concrete array for emulator / merge logic.\n * Call at host boundaries (`createDocument`, tests); JSON may still omit `rows` for schema-only.\n */\nexport function normalizeReplicaTableInput<T extends GristReplicaTable>(table: T): T & { rows: GristReplicaRow[] } {\n return { ...table, rows: table.rows ?? [] }\n}\n\n/** Apply {@link normalizeReplicaTableInput} to every table; shallow-copies the document shell. */\nexport function normalizeReplicaDocumentInput<T extends GristReplicaDocument>(doc: T): T {\n return {\n ...doc,\n tables: Object.fromEntries(\n Object.entries(doc.tables).map(([tableId, t]) => [tableId, normalizeReplicaTableInput(t)])\n ),\n } as T\n}\n\n/** How row arrays appear in serialized replica JSON from {@link buildReplicaJsonPayload}. */\nexport type ReplicaJsonIncludeRows = \"none\" | \"samples\" | \"full\"\n\n/**\n * Clone a replica document for JSON output: strip rows, cap to first N, or pass through.\n * Does not mutate the source document.\n */\nexport function buildReplicaJsonPayload(\n doc: GristReplicaDocument,\n options: { includeRows: ReplicaJsonIncludeRows; sampleRowLimit?: number }\n): GristReplicaDocument {\n const limit = options.sampleRowLimit ?? 10\n const tables = Object.fromEntries(\n Object.entries(doc.tables).map(([tid, t]) => {\n if (options.includeRows === \"none\") {\n const { rows: _r, ...rest } = t\n return [tid, rest]\n }\n if (options.includeRows === \"samples\") {\n const r = t.rows ?? []\n return [tid, { ...t, rows: r.slice(0, limit) }]\n }\n return [tid, { ...t, rows: t.rows }]\n })\n ) as GristReplicaDocument[\"tables\"]\n return { ...doc, tables }\n}\n","import { inferDisplayHelpersByRef } from \"../../sdk/helpers/grist-safe-parse\"\nimport { normalizeReplicaDocumentInput } from \"../../sdk/helpers/replica-normalize\"\nimport { coerceGristDocApiRefRowId } from \"../../sdk/helpers/grist-value-codec\"\nimport type { GristReplicaDocument, GristReplicaTable } from \"../../sdk/replica-document\"\nimport type { GristRowRecord } from \"../../sdk/types\"\nimport type { EmulatorColumn, EmulatorDocumentState, EmulatorTable } from \"./types\"\n\nconst SYSTEM_COLUMN = \"id\"\n\nconst EMULATOR_JS_FORMULA_PLACEHOLDER = \"(emulator JavaScript formula)\"\n\n/** Replica table for {@link createDocument}; columns may include `formulaFn` / `inferredFormula` (emulator-only). */\nexport type CreateDocumentTableInput = Omit<GristReplicaTable, \"columns\"> & {\n columns?: Record<string, EmulatorColumn>\n}\n\n/** Replica document for {@link createDocument}; widens table columns to {@link EmulatorColumn}. */\nexport type CreateDocumentInput = Omit<GristReplicaDocument, \"tables\"> & {\n tables: Record<string, CreateDocumentTableInput>\n}\n\n/**\n * Ensure `formula` (original) and `inferredFormula` strings exist alongside optional `formulaFn`.\n */\nexport function enrichEmulatorColumnMetadata(col: EmulatorColumn): EmulatorColumn {\n const originalTrimmed = col.formula?.trim() ?? \"\"\n const explicitInferred = col.inferredFormula?.trim() ?? \"\"\n\n if (col.formulaFn) {\n const inferredFormula =\n explicitInferred || originalTrimmed || EMULATOR_JS_FORMULA_PLACEHOLDER\n return {\n ...col,\n ...(originalTrimmed ? { formula: col.formula } : {}),\n inferredFormula,\n }\n }\n\n if (explicitInferred || originalTrimmed) {\n return {\n ...col,\n inferredFormula: explicitInferred || originalTrimmed || undefined,\n }\n }\n\n return col\n}\n\n/** Order merged column metadata for stable `fetchTable` / RDG column order. */\nexport function sortEmulatorColumnsByParentPos(columns: Record<string, EmulatorColumn>): Record<string, EmulatorColumn> {\n const entries = Object.entries(columns)\n entries.sort(([ka, a], [kb, b]) => {\n const pa = a.parentPos\n const pb = 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 ka.localeCompare(kb)\n })\n return Object.fromEntries(entries)\n}\n\nfunction inferColumnsFromRows(rows: GristRowRecord[]): Record<string, EmulatorColumn> {\n const columns: Record<string, EmulatorColumn> = {}\n for (const row of rows) {\n for (const key of Object.keys(row)) {\n if (key === SYSTEM_COLUMN) continue\n if (!columns[key]) columns[key] = inferColumnType(row[key])\n }\n }\n return columns\n}\n\nfunction inferColumnType(sample: unknown): EmulatorColumn {\n switch (typeof sample) {\n case \"number\":\n return { type: \"Numeric\" }\n case \"boolean\":\n return { type: \"Bool\" }\n case \"string\":\n return { type: \"Text\" }\n default:\n return { type: \"Any\" }\n }\n}\n\nfunction buildTable(tableId: string, input: CreateDocumentTableInput): EmulatorTable {\n const rows = input.rows ?? []\n const inferred = inferColumnsFromRows(rows)\n const merged: Record<string, EmulatorColumn> = {}\n for (const [colId, col] of Object.entries({ ...inferred, ...(input.columns ?? {}) })) {\n merged[colId] = enrichEmulatorColumnMetadata(col)\n }\n const columns = sortEmulatorColumnsByParentPos(merged)\n return {\n tableId,\n label: input.label,\n columns,\n rows: rows.map((row) => ({ ...row })),\n }\n}\n\n/**\n * Build an immutable initial document state from a user-provided\n * {@link GristReplicaDocument}. The state is **not** frozen — the action\n * engine mutates it in place under deterministic event diffusion.\n */\nexport function createDocument(input: CreateDocumentInput): EmulatorDocumentState {\n if (!input.tables || Object.keys(input.tables).length === 0) {\n throw new Error(\"createDocument: at least one table is required\")\n }\n\n const normalized = normalizeReplicaDocumentInput(input)\n\n const tables = new Map<string, EmulatorTable>()\n for (const [tableId, tableInput] of Object.entries(normalized.tables)) {\n tables.set(tableId, buildTable(tableId, tableInput))\n }\n\n const firstTableId = tables.keys().next().value as string\n const requestedTableId = normalized.selection?.tableId\n const selectedTableId =\n requestedTableId && tables.has(requestedTableId) ? requestedTableId : firstTableId\n const selectedTable = tables.get(selectedTableId)!\n const fallbackRowId =\n typeof selectedTable.rows[0]?.id === \"number\" ? selectedTable.rows[0].id : null\n const selection = {\n tableId: selectedTableId,\n rowId: normalized.selection?.rowId ?? fallbackRowId,\n mappings: normalized.selection?.mappings,\n cursor: normalized.selection?.cursor,\n } as EmulatorDocumentState[\"selection\"]\n\n return {\n docName: normalized.docName ?? \"Untitled emulator document\",\n tables,\n selection,\n widgetOptions: { ...(normalized.widgetOptions ?? {}) },\n widgetInteraction: { ...(normalized.widgetInteraction ?? {}) },\n configuration: normalized.configuration ?? null,\n accessToken: normalized.accessToken ?? null,\n }\n}\n\nexport function getTable(state: EmulatorDocumentState, tableId: string): EmulatorTable {\n const table = state.tables.get(tableId)\n if (!table) throw new Error(`Unknown table: ${tableId}`)\n return table\n}\n\nexport function getSelectedTable(state: EmulatorDocumentState): EmulatorTable {\n return getTable(state, state.selection.tableId)\n}\n\nexport function nextRowId(table: EmulatorTable): number {\n let max = 0\n for (const row of table.rows) {\n if (typeof row.id === \"number\" && row.id > max) max = row.id\n }\n return max + 1\n}\n\nexport function findRow(table: EmulatorTable, rowId: number): GristRowRecord | undefined {\n return table.rows.find((r) => r.id === rowId)\n}\n\nexport function findRowIndex(table: EmulatorTable, rowId: number): number {\n return table.rows.findIndex((r) => r.id === rowId)\n}\n\n/**\n * Re-evaluate every formula column for a given row in-place. Called by the\n * action engine after Add/Update operations.\n */\nexport function evaluateRowFormulas(\n state: EmulatorDocumentState,\n table: EmulatorTable,\n row: GristRowRecord\n): void {\n for (const [colId, col] of Object.entries(table.columns)) {\n if (col.formulaFn) {\n try {\n row[colId] = col.formulaFn(row, { table, document: state })\n } catch (err) {\n row[colId] = formulaError(err)\n }\n }\n }\n}\n\nfunction escapeRegExp(s: string): string {\n return s.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\")\n}\n\n/** Pull stored row ids from a `RefList` cell (`[\"L\", ...]` or legacy shapes). */\nfunction extractRefListIdsFromWire(raw: unknown): number[] {\n if (raw == null) return []\n if (!Array.isArray(raw)) return []\n const items = raw[0] === \"L\" ? raw.slice(1) : raw\n const out: number[] = []\n for (const item of items) {\n if (typeof item === \"number\" && Number.isFinite(item) && item > 0) {\n out.push(Math.trunc(item))\n continue\n }\n if (item && typeof item === \"object\" && \"rowId\" in item) {\n const r = (item as { rowId: unknown }).rowId\n if (typeof r === \"number\" && Number.isFinite(r) && r > 0) {\n out.push(Math.trunc(r))\n continue\n }\n }\n const t = coerceGristDocApiRefRowId(item)\n if (t !== undefined && t > 0) out.push(Math.trunc(t))\n }\n return Array.from(new Set(out))\n}\n\nfunction fieldFromRefListHelperFormula(formula: string | undefined, refColId: string): string | null {\n if (!formula) return null\n const re = new RegExp(`\\\\$${escapeRegExp(refColId)}\\\\.([A-Za-z_]\\\\w*)`)\n const m = formula.match(re)\n return m?.[1] ?? null\n}\n\nfunction firstTextLikeColumnId(columns: Record<string, EmulatorColumn>): string | null {\n let best: { id: string; pos: number } | null = null\n for (const [colId, col] of Object.entries(columns)) {\n if (colId === \"id\" || colId.startsWith(\"gristHelper_\")) continue\n const t = col.type\n if (t !== \"Text\" && t !== \"Choice\") continue\n const pos = col.parentPos ?? 99999\n if (!best || pos < best.pos) best = { id: colId, pos }\n }\n return best?.id ?? null\n}\n\nfunction formatLabelFromCell(value: unknown): string {\n if (value == null) return \"\"\n if (typeof value === \"string\") return value.trim()\n if (typeof value === \"number\" || typeof value === \"boolean\") return String(value)\n if (value instanceof Date) return value.toISOString()\n if (Array.isArray(value) && value[0] === \"E\") return \"\"\n if (typeof value === \"object\" && value && \"__ref\" in value) {\n const r = (value as { rowId?: unknown }).rowId\n return typeof r === \"number\" && Number.isFinite(r) ? String(r) : \"\"\n }\n return \"\"\n}\n\n/**\n * Keep `gristHelper_*` display columns aligned with `RefList:*` ids after writes.\n *\n * Real Grist evaluates helper formulas (`$multiref.Nom`); replica JSON only\n * carries the formula string (no `formulaFn`), so helpers would stay stale and\n * safe-parse would flag `helper_mismatch` with empty labels.\n *\n * Skips helpers that define `formulaFn` so custom JS formulas keep ownership.\n */\nexport function syncRefListDisplayHelpers(\n state: EmulatorDocumentState,\n table: EmulatorTable,\n row: GristRowRecord\n): void {\n const displayHelpersByRef = inferDisplayHelpersByRef(table.columns)\n for (const [colId, col] of Object.entries(table.columns)) {\n const type = col.type\n if (typeof type !== \"string\" || !type.startsWith(\"RefList:\")) continue\n const helperColId = displayHelpersByRef[colId]\n if (!helperColId) continue\n const helperMeta = table.columns[helperColId]\n if (!helperMeta || helperMeta.formulaFn) continue\n\n const targetTableId = type.slice(\"RefList:\".length)\n const targetTable = state.tables.get(targetTableId)\n if (!targetTable) continue\n\n const ids = extractRefListIdsFromWire(row[colId])\n if (ids.length === 0) {\n row[helperColId] = []\n continue\n }\n\n const fieldId =\n fieldFromRefListHelperFormula(helperMeta.formula, colId) ??\n firstTextLikeColumnId(targetTable.columns)\n\n const labels = ids.map((rid) => {\n if (!fieldId) return String(rid)\n const trow = findRow(targetTable, rid)\n if (!trow) return String(rid)\n const lbl = formatLabelFromCell(trow[fieldId])\n return lbl !== \"\" ? lbl : String(rid)\n })\n row[helperColId] = labels\n }\n}\n\nfunction formulaError(err: unknown): unknown {\n // Match Grist's encoded error format: [\"E\", code, message]\n const message = err instanceof Error ? err.message : String(err)\n return [\"E\", \"Error\", message]\n}\n\n/**\n * Synthesise `_grist_Tables` metadata from the emulator's in-memory tables.\n * Returns Grist's columnar wire shape.\n */\nexport function synthesizeTablesMeta(state: EmulatorDocumentState): Record<string, unknown[]> {\n const ids: number[] = []\n const tableIds: string[] = []\n const labels: (string | null)[] = []\n\n let nextId = 1\n for (const [tableId, table] of state.tables.entries()) {\n ids.push(nextId)\n tableIds.push(tableId)\n labels.push(table.label ?? null)\n nextId += 1\n }\n\n return {\n id: ids,\n tableId: tableIds,\n // Optional human-readable label; real Grist keeps more fields, but these\n // are sufficient for `buildReplicaDocumentFromDocApi` to resolve table ids.\n label: labels,\n }\n}\n\n/**\n * Synthesise `_grist_Tables_column` metadata from emulator tables/columns.\n * Mirrors the subset of fields consumed by `buildReplicaDocumentFromDocApi`.\n */\nexport function synthesizeTablesColumnMeta(state: EmulatorDocumentState): Record<string, unknown[]> {\n const parentIds: number[] = []\n const colIds: string[] = []\n const columnIds: number[] = []\n const types: (string | null)[] = []\n const labels: (string | null)[] = []\n const parentPos: (number | null)[] = []\n const isFormula: boolean[] = []\n const formulas: (string | null)[] = []\n const descriptions: (string | null)[] = []\n const widgetOptions: unknown[] = []\n const displayCol: (number | null)[] = []\n const visibleCol: (number | null)[] = []\n\n // Mirror the synthetic table ids from `synthesizeTablesMeta`.\n const tableIdToInternalId = new Map<string, number>()\n {\n let nextId = 1\n for (const [tableId] of state.tables.entries()) {\n tableIdToInternalId.set(tableId, nextId)\n nextId += 1\n }\n }\n\n for (const [tableId, table] of state.tables.entries()) {\n const parentInternalId = tableIdToInternalId.get(tableId)\n if (parentInternalId === undefined) continue\n\n for (const [colId, col] of Object.entries(table.columns)) {\n parentIds.push(parentInternalId)\n colIds.push(colId)\n // Prefer explicit `colRef` when present; fall back to 1-based index of insertion.\n const ref = typeof col.colRef === \"number\" ? col.colRef : columnIds.length + 1\n columnIds.push(ref)\n types.push(col.type ?? null)\n labels.push(col.label ?? null)\n parentPos.push(col.parentPos ?? null)\n isFormula.push(Boolean(col.isFormula))\n const formula = typeof col.formula === \"string\" ? col.formula : null\n formulas.push(formula)\n descriptions.push(col.description ?? null)\n widgetOptions.push(col.widgetOptions ?? null)\n displayCol.push(typeof col.displayColRef === \"number\" ? col.displayColRef : null)\n visibleCol.push(typeof col.visibleColRef === \"number\" ? col.visibleColRef : null)\n }\n }\n\n return {\n parentId: parentIds,\n colId: colIds,\n id: columnIds,\n type: types,\n label: labels,\n parentPos,\n isFormula,\n formula: formulas,\n description: descriptions,\n // Also expose legacy `descr` for robustness.\n descr: descriptions,\n widgetOptions,\n displayCol,\n visibleCol,\n }\n}\n","/**\n * Pure action engine: applies Grist user actions to an\n * {@link EmulatorDocumentState} and emits the resulting events on the bus.\n *\n * This is the single place where state mutates. Every API impl ultimately\n * routes through `applyUserActions` so behaviour is consistent regardless of\n * the surface (`grist.docApi.applyUserActions`, `selectedTable.create`,\n * `setCursorPos`, etc.).\n *\n * Supported user actions:\n * - AddRecord, BulkAddRecord\n * - UpdateRecord, BulkUpdateRecord\n * - RemoveRecord, BulkRemoveRecord\n * - AddColumn, RemoveColumn, RenameColumn, ModifyColumn\n * - AddTable, RemoveTable, RenameTable\n *\n * Unknown actions throw a structured error instead of silently succeeding,\n * which surfaces protocol gaps loudly during widget development.\n */\n\nimport { coerceGristDocApiRefRowId } from \"../../sdk/helpers/grist-value-codec\"\nimport {\n evaluateRowFormulas,\n findRow,\n findRowIndex,\n getTable,\n nextRowId,\n syncRefListDisplayHelpers,\n} from \"./document\"\nimport type { EventBus } from \"./event-bus\"\nimport type { EmulatorColumn, EmulatorDocumentState, EmulatorTable } from \"./types\"\n\nexport class EmulatorActionError extends Error {\n constructor(\n public readonly action: unknown,\n message: string\n ) {\n super(message)\n this.name = \"EmulatorActionError\"\n }\n}\n\nexport type ApplyUserActionResult = {\n /** Result mirroring Grist's `applyUserActions`: per-action retValues. */\n retValues: unknown[]\n /** Tables that received row-level changes (de-duped). */\n changedTableIds: string[]\n}\n\nexport function applyUserActions(\n state: EmulatorDocumentState,\n bus: EventBus,\n actions: unknown[][]\n): ApplyUserActionResult {\n const retValues: unknown[] = []\n const changed = new Set<string>()\n\n for (const action of actions) {\n bus.emit({ type: \"user-action\", action })\n const ret = applySingle(state, action, changed)\n retValues.push(ret)\n }\n\n for (const tableId of changed) {\n bus.emit({ type: \"data-change\", tableId })\n }\n\n return { retValues, changedTableIds: [...changed] }\n}\n\nfunction applySingle(\n state: EmulatorDocumentState,\n action: unknown[],\n changed: Set<string>\n): unknown {\n const [name, ...args] = action\n switch (name) {\n case \"AddRecord\":\n return addRecord(state, args, changed)\n case \"BulkAddRecord\":\n return bulkAddRecord(state, args, changed)\n case \"UpdateRecord\":\n return updateRecord(state, args, changed)\n case \"BulkUpdateRecord\":\n return bulkUpdateRecord(state, args, changed)\n case \"RemoveRecord\":\n return removeRecord(state, args, changed)\n case \"BulkRemoveRecord\":\n return bulkRemoveRecord(state, args, changed)\n case \"AddColumn\":\n return addColumn(state, args)\n case \"AddVisibleColumn\":\n // The emulator has no concept of section view fields, so the \"visible\"\n // part of `AddVisibleColumn` is a no-op here. We still create the\n // column so widgets that issue this user action (the higher-level form\n // recommended by Grist for \"add a column to the active view\") work\n // identically against the emulator.\n return addColumn(state, args)\n case \"RemoveColumn\":\n return removeColumn(state, args, changed)\n case \"RenameColumn\":\n return renameColumn(state, args, changed)\n case \"ModifyColumn\":\n return modifyColumn(state, args, changed)\n case \"AddTable\":\n return addTable(state, args)\n case \"RemoveTable\":\n return removeTable(state, args)\n case \"RenameTable\":\n return renameTable(state, args)\n default:\n throw new EmulatorActionError(action, `Unsupported user action: ${String(name)}`)\n }\n}\n\n// ---------- row ops ----------\n\nfunction addRecord(\n state: EmulatorDocumentState,\n [tableId, rowId, values]: unknown[],\n changed: Set<string>\n): number {\n const table = getTable(state, requireString(tableId, \"AddRecord.tableId\"))\n const id = typeof rowId === \"number\" ? rowId : nextRowId(table)\n const normalizedValues = normalizeValuesForTable(\n table,\n (values as Record<string, unknown>) ?? {}\n )\n const row = { id, ...normalizedValues }\n ensureColumns(table, normalizedValues)\n evaluateRowFormulas(state, table, row)\n syncRefListDisplayHelpers(state, table, row)\n table.rows.push(row)\n changed.add(table.tableId)\n return id\n}\n\nfunction bulkAddRecord(\n state: EmulatorDocumentState,\n [tableId, rowIds, columnar]: unknown[],\n changed: Set<string>\n): number[] {\n const table = getTable(state, requireString(tableId, \"BulkAddRecord.tableId\"))\n const cols = normalizeColumnarForTable(\n table,\n (columnar as Record<string, unknown[]>) ?? {}\n )\n const ids = Array.isArray(rowIds) ? rowIds : []\n const length = ids.length || lengthOf(cols)\n const out: number[] = []\n ensureColumns(table, cols, true)\n for (let i = 0; i < length; i++) {\n const id = typeof ids[i] === \"number\" ? (ids[i] as number) : nextRowId(table)\n const row: Record<string, unknown> & { id: number } = { id }\n for (const colId of Object.keys(cols)) row[colId] = cols[colId][i]\n evaluateRowFormulas(state, table, row)\n syncRefListDisplayHelpers(state, table, row)\n table.rows.push(row)\n out.push(id)\n }\n changed.add(table.tableId)\n return out\n}\n\nfunction updateRecord(\n state: EmulatorDocumentState,\n [tableId, rowId, values]: unknown[],\n changed: Set<string>\n): null {\n const table = getTable(state, requireString(tableId, \"UpdateRecord.tableId\"))\n const id = requireNumber(rowId, \"UpdateRecord.rowId\")\n const row = findRow(table, id)\n if (!row) throw new EmulatorActionError([\"UpdateRecord\", tableId, rowId, values], `Row ${id} not found in ${table.tableId}`)\n const normalizedValues = normalizeValuesForTable(\n table,\n (values as Record<string, unknown>) ?? {}\n )\n ensureColumns(table, normalizedValues)\n Object.assign(row, normalizedValues)\n evaluateRowFormulas(state, table, row)\n syncRefListDisplayHelpers(state, table, row)\n changed.add(table.tableId)\n return null\n}\n\nfunction bulkUpdateRecord(\n state: EmulatorDocumentState,\n [tableId, rowIds, columnar]: unknown[],\n changed: Set<string>\n): null {\n const table = getTable(state, requireString(tableId, \"BulkUpdateRecord.tableId\"))\n const ids = rowIds as number[]\n const cols = normalizeColumnarForTable(\n table,\n (columnar as Record<string, unknown[]>) ?? {}\n )\n ensureColumns(table, cols, true)\n ids.forEach((id, idx) => {\n const row = findRow(table, id)\n if (!row) throw new EmulatorActionError([\"BulkUpdateRecord\", tableId, ids, cols], `Row ${id} not found in ${table.tableId}`)\n for (const colId of Object.keys(cols)) row[colId] = cols[colId][idx]\n evaluateRowFormulas(state, table, row)\n syncRefListDisplayHelpers(state, table, row)\n })\n changed.add(table.tableId)\n return null\n}\n\nfunction removeRecord(\n state: EmulatorDocumentState,\n [tableId, rowId]: unknown[],\n changed: Set<string>\n): null {\n const table = getTable(state, requireString(tableId, \"RemoveRecord.tableId\"))\n const id = requireNumber(rowId, \"RemoveRecord.rowId\")\n const idx = findRowIndex(table, id)\n if (idx >= 0) table.rows.splice(idx, 1)\n if (state.selection.tableId === table.tableId && state.selection.rowId === id) {\n state.selection.rowId = table.rows[0]?.id ?? null\n }\n changed.add(table.tableId)\n return null\n}\n\nfunction bulkRemoveRecord(\n state: EmulatorDocumentState,\n [tableId, rowIds]: unknown[],\n changed: Set<string>\n): null {\n const table = getTable(state, requireString(tableId, \"BulkRemoveRecord.tableId\"))\n const ids = new Set(rowIds as number[])\n table.rows = table.rows.filter((r) => !ids.has(r.id))\n if (state.selection.tableId === table.tableId && typeof state.selection.rowId === \"number\" && ids.has(state.selection.rowId)) {\n state.selection.rowId = table.rows[0]?.id ?? null\n }\n changed.add(table.tableId)\n return null\n}\n\n// ---------- column ops ----------\n\nfunction addColumn(\n state: EmulatorDocumentState,\n [tableId, colId, info]: unknown[]\n): null {\n const table = getTable(state, requireString(tableId, \"AddColumn.tableId\"))\n const col = requireString(colId, \"AddColumn.colId\")\n if (table.columns[col]) throw new EmulatorActionError([\"AddColumn\", tableId, colId], `Column ${col} already exists`)\n table.columns[col] = (info as EmulatorColumn) ?? {}\n for (const row of table.rows) {\n if (!(col in row)) row[col] = null\n }\n return null\n}\n\nfunction removeColumn(\n state: EmulatorDocumentState,\n [tableId, colId]: unknown[],\n changed: Set<string>\n): null {\n const table = getTable(state, requireString(tableId, \"RemoveColumn.tableId\"))\n const col = requireString(colId, \"RemoveColumn.colId\")\n delete table.columns[col]\n for (const row of table.rows) delete row[col]\n changed.add(table.tableId)\n return null\n}\n\nfunction renameColumn(\n state: EmulatorDocumentState,\n [tableId, colId, newColId]: unknown[],\n changed: Set<string>\n): null {\n const table = getTable(state, requireString(tableId, \"RenameColumn.tableId\"))\n const from = requireString(colId, \"RenameColumn.colId\")\n const to = requireString(newColId, \"RenameColumn.newColId\")\n if (!table.columns[from]) throw new EmulatorActionError([\"RenameColumn\", tableId, from, to], `Column ${from} not found`)\n if (from === to) return null\n table.columns[to] = table.columns[from]\n delete table.columns[from]\n for (const row of table.rows) {\n if (from in row) {\n row[to] = row[from]\n delete row[from]\n }\n }\n changed.add(table.tableId)\n return null\n}\n\nfunction modifyColumn(\n state: EmulatorDocumentState,\n [tableId, colId, info]: unknown[],\n changed: Set<string>\n): null {\n const table = getTable(state, requireString(tableId, \"ModifyColumn.tableId\"))\n const col = requireString(colId, \"ModifyColumn.colId\")\n if (!table.columns[col]) throw new EmulatorActionError([\"ModifyColumn\", tableId, colId], `Column ${col} not found`)\n table.columns[col] = { ...table.columns[col], ...(info as EmulatorColumn) }\n changed.add(table.tableId)\n return null\n}\n\n// ---------- table ops ----------\n\nfunction addTable(state: EmulatorDocumentState, [tableId, columns]: unknown[]): string {\n const id = requireString(tableId, \"AddTable.tableId\")\n if (state.tables.has(id)) throw new EmulatorActionError([\"AddTable\", tableId], `Table ${id} already exists`)\n const cols: Record<string, EmulatorColumn> = {}\n for (const c of (columns as Array<{ id: string } & EmulatorColumn>) ?? []) {\n cols[c.id] = { ...c }\n }\n state.tables.set(id, { tableId: id, columns: cols, rows: [] })\n return id\n}\n\nfunction removeTable(state: EmulatorDocumentState, [tableId]: unknown[]): null {\n const id = requireString(tableId, \"RemoveTable.tableId\")\n state.tables.delete(id)\n if (state.selection.tableId === id) {\n const fallback = state.tables.keys().next().value as string | undefined\n if (fallback) {\n state.selection.tableId = fallback\n state.selection.rowId = null\n }\n }\n return null\n}\n\nfunction renameTable(state: EmulatorDocumentState, [from, to]: unknown[]): null {\n const fromId = requireString(from, \"RenameTable.from\")\n const toId = requireString(to, \"RenameTable.to\")\n const table = state.tables.get(fromId)\n if (!table) throw new EmulatorActionError([\"RenameTable\", fromId], `Table ${fromId} not found`)\n state.tables.delete(fromId)\n table.tableId = toId\n state.tables.set(toId, table)\n if (state.selection.tableId === fromId) state.selection.tableId = toId\n return null\n}\n\n// ---------- helpers ----------\n\nfunction ensureColumns(\n table: EmulatorTable,\n values: Record<string, unknown> | Record<string, unknown[]>,\n bulk = false\n): void {\n for (const col of Object.keys(values)) {\n if (!table.columns[col]) {\n const sample = bulk ? (values as Record<string, unknown[]>)[col]?.[0] : (values as Record<string, unknown>)[col]\n table.columns[col] = inferType(sample)\n }\n }\n}\n\nfunction inferType(sample: unknown): EmulatorColumn {\n switch (typeof sample) {\n case \"number\":\n return { type: \"Numeric\" }\n case \"boolean\":\n return { type: \"Bool\" }\n case \"string\":\n return { type: \"Text\" }\n default:\n return { type: \"Any\" }\n }\n}\n\nfunction lengthOf(cols: Record<string, unknown[]>): number {\n for (const arr of Object.values(cols)) if (Array.isArray(arr)) return arr.length\n return 0\n}\n\nfunction requireString(value: unknown, name: string): string {\n if (typeof value !== \"string\" || !value) throw new Error(`Expected non-empty string for ${name}`)\n return value\n}\n\nfunction requireNumber(value: unknown, name: string): number {\n if (typeof value !== \"number\" || Number.isNaN(value)) throw new Error(`Expected number for ${name}`)\n return value\n}\n\nfunction normalizeValuesForTable(\n table: EmulatorTable,\n values: Record<string, unknown>\n): Record<string, unknown> {\n const out: Record<string, unknown> = {}\n for (const [colId, value] of Object.entries(values)) {\n out[colId] = normalizeCellValueForType(value, table.columns[colId]?.type)\n }\n return out\n}\n\nfunction normalizeColumnarForTable(\n table: EmulatorTable,\n columns: Record<string, unknown[]>\n): Record<string, unknown[]> {\n const out: Record<string, unknown[]> = {}\n for (const [colId, values] of Object.entries(columns)) {\n const type = table.columns[colId]?.type\n out[colId] = Array.isArray(values)\n ? values.map((value) => normalizeCellValueForType(value, type))\n : []\n }\n return out\n}\n\nfunction normalizeCellValueForType(value: unknown, type: string | undefined): unknown {\n if (value === null || value === undefined || typeof type !== \"string\") return value\n\n if (type.startsWith(\"Ref:\")) return normalizeRefValue(value)\n if (type.startsWith(\"RefList:\")) return normalizeRefListValue(value)\n return value\n}\n\n/**\n * Canonical ref row id for emulator storage (`Ref:*` columns).\n * Accepts bare ids, `\"12\"`, Grist tuples `[\"r\", id]` / `[\"R\", tableId, id]`,\n * and detailed-ref shapes `{ rowId }` used after safe-parse / RDG edits.\n */\nfunction extractRefRowId(value: unknown): number | null {\n if (value === null || value === undefined) return null\n if (value && typeof value === \"object\" && \"__ref\" in value) {\n const inner = (value as { rowId?: unknown }).rowId\n return extractRefRowId(inner)\n }\n if (value && typeof value === \"object\" && \"rowId\" in value) {\n return extractRefRowId((value as { rowId: unknown }).rowId)\n }\n const fromTuple = coerceGristDocApiRefRowId(value)\n if (fromTuple !== undefined && fromTuple > 0) return Math.trunc(fromTuple)\n return toPositiveInt(value)\n}\n\nfunction normalizeRefValue(value: unknown): number | null {\n return extractRefRowId(value)\n}\n\nfunction normalizeRefListValue(value: unknown): unknown[] {\n const toIdList = (items: unknown[]): number[] =>\n Array.from(\n new Set(items.map((item) => extractRefRowId(item)).filter((item): item is number => item !== null))\n )\n\n // Grist tuple form: [\"L\", ...ids]\n if (Array.isArray(value) && value[0] === \"L\") {\n return [\"L\", ...toIdList(value.slice(1))]\n }\n if (Array.isArray(value)) {\n return [\"L\", ...toIdList(value)]\n }\n if (typeof value === \"string\") {\n const tokens = value.split(\",\").map((t) => t.trim()).filter(Boolean)\n return [\"L\", ...toIdList(tokens)]\n }\n if (value && typeof value === \"object\" && Array.isArray((value as { rowIds?: unknown }).rowIds)) {\n return [\"L\", ...toIdList((value as { rowIds: unknown[] }).rowIds)]\n }\n return [\"L\"]\n}\n\nfunction toPositiveInt(value: unknown): number | null {\n if (typeof value === \"number\" && Number.isFinite(value) && value > 0) return Math.trunc(value)\n if (typeof value === \"string\") {\n const n = Number.parseInt(value.trim(), 10)\n if (Number.isFinite(n) && n > 0) return n\n }\n return null\n}\n","/**\n * Helpers to project an {@link EmulatorTable}'s row-array storage into Grist's\n * columnar wire format expected by `fetchTable` / `fetchSelectedTable`:\n *\n * { id: number[], colA: unknown[], colB: unknown[], ... }\n *\n * When `keepEncoded` is `false` (Grist's default for these APIs), values are\n * passed through as-is — JS-native primitives (string / number / boolean /\n * Date / arrays) are valid Grist plugin values. When `keepEncoded` is `true`,\n * Date columns are emitted in tuple form (`[\"d\", epoch]`) so callers can\n * round-trip them.\n */\n\nimport type { GristRowRecord } from \"../../sdk/types\"\nimport type { EmulatorTable } from \"./types\"\n\nexport type ColumnarTable = Record<string, unknown[]>\n\nexport type ToColumnarOptions = {\n keepEncoded?: boolean\n}\n\nexport function rowsToColumnar(\n table: EmulatorTable,\n rows: readonly GristRowRecord[],\n options: ToColumnarOptions = {}\n): ColumnarTable {\n const cols = Object.keys(table.columns)\n const out: ColumnarTable = { id: rows.map((r) => r.id) }\n for (const col of cols) {\n out[col] = rows.map((r) => encodeForWire(r[col], table.columns[col]?.type, options.keepEncoded))\n }\n return out\n}\n\nexport function rowToRecord(\n table: EmulatorTable,\n row: GristRowRecord,\n options: ToColumnarOptions = {}\n): Record<string, unknown> {\n const out: Record<string, unknown> = { id: row.id }\n for (const col of Object.keys(table.columns)) {\n out[col] = encodeForWire(row[col], table.columns[col]?.type, options.keepEncoded)\n }\n return out\n}\n\nfunction encodeForWire(value: unknown, type: string | undefined, keepEncoded: boolean | undefined): unknown {\n if (value instanceof Date) {\n const epoch = Math.floor(value.getTime() / 1000)\n if (keepEncoded) {\n return type && type.startsWith(\"DateTime\") ? [\"D\", epoch, \"UTC\"] : [\"d\", epoch]\n }\n return epoch\n }\n return value\n}\n","import { applyUserActions } from \"../core/action-engine\"\nimport { rowsToColumnar } from \"../core/columnar\"\nimport { getTable, synthesizeTablesColumnMeta, synthesizeTablesMeta } from \"../core/document\"\nimport type { EventBus } from \"../core/event-bus\"\nimport type { EmulatorDocumentState } from \"../core/types\"\nimport type { GristDocApiImpl } from \"./types\"\n\n/**\n * `GristDocAPI` host implementation. Backs `grist.docApi.*` methods such as\n * `getDocName`, `listTables`, `fetchTable`, `applyUserActions` and\n * `getAccessToken`.\n *\n * `applyUserActions` is the only mutation entry point — every widget write\n * lands here, so tests can listen on the bus for `user-action` events to\n * assert exactly which actions a UI flow generated.\n */\nexport function createGristDocApiImpl(state: EmulatorDocumentState, bus: EventBus): GristDocApiImpl {\n return {\n async getDocName() {\n return state.docName\n },\n\n async listTables() {\n return [...state.tables.keys()]\n },\n\n async fetchTable(tableId) {\n if (tableId === \"_grist_Tables\") {\n return synthesizeTablesMeta(state)\n }\n if (tableId === \"_grist_Tables_column\") {\n return synthesizeTablesColumnMeta(state)\n }\n const table = getTable(state, tableId)\n return rowsToColumnar(table, table.rows)\n },\n\n async applyUserActions(actions) {\n const result = applyUserActions(state, bus, actions)\n return { retValues: result.retValues }\n },\n\n async getAccessToken() {\n if (!state.accessToken) {\n const err = new Error(\"getAccessToken not available (no token configured on emulator)\")\n // Mirror Grist's protocol: rejected stub call.\n throw err\n }\n return { ...state.accessToken }\n },\n }\n}\n","import { rowToRecord, rowsToColumnar } from \"../core/columnar\"\nimport { findRow, getSelectedTable } from \"../core/document\"\nimport type { EventBus } from \"../core/event-bus\"\nimport type { EmulatorDocumentState } from \"../core/types\"\nimport type { GristViewImpl } from \"./types\"\n\n/**\n * `GristView` host implementation.\n *\n * Exposes the section-scoped data API the widget uses through\n * `grist.docApi.fetchSelectedTable()`, `fetchSelectedRecord()` and\n * `setCursorPos()`. Reads from the emulator state, writes to the same state\n * via the action engine where applicable, and emits events on the bus so\n * subscribers (transports, inspector, tests) stay in sync.\n *\n * IMPORTANT: `fetchSelectedTable` always returns Grist's **columnar** wire\n * shape. The production `grist-plugin-api.js` wrapper (which the iframe\n * transport talks to) expects the raw RPC stub to return columnar and does\n * the `format: \"rows\"` transposition + `keepEncoded: false` decoding itself.\n * Returning rows here used to crash the wrapper's `mapValues(data, col =>\n * col.map(decodeObject))` pass — `data` was an array, `col` was a row object\n * with no `.map` method — so widgets observed `records === null` forever.\n * The inline transport mirrors the same wrapper semantics in\n * `transports/inline.ts` so widget code sees identical results in both modes.\n */\nexport function createGristViewImpl(state: EmulatorDocumentState, bus: EventBus): GristViewImpl {\n return {\n async fetchSelectedTable(options) {\n const table = getSelectedTable(state)\n return rowsToColumnar(table, table.rows, { keepEncoded: options?.keepEncoded })\n },\n\n async fetchSelectedRecord(rowId, options) {\n const table = getSelectedTable(state)\n const row = findRow(table, rowId)\n if (!row) throw new Error(`No row ${rowId} in ${table.tableId}`)\n return rowToRecord(table, row, { keepEncoded: options?.keepEncoded })\n },\n\n async allowSelectBy() {\n return state.configuration?.allowSelectBy ?? false\n },\n\n async setSelectedRows(rowIds) {\n if (!rowIds || rowIds.length === 0) {\n state.selection.rowId = null\n } else {\n state.selection.rowId = rowIds[0]\n }\n bus.emit({\n type: \"cursor-change\",\n tableId: state.selection.tableId,\n rowId: state.selection.rowId,\n })\n },\n\n async setCursorPos(cursor) {\n const tableId = state.selection.tableId\n if (typeof cursor.rowId === \"number\") state.selection.rowId = cursor.rowId\n state.selection.cursor = { ...state.selection.cursor, ...cursor }\n bus.emit({\n type: \"cursor-change\",\n tableId,\n rowId: state.selection.rowId,\n cursor: state.selection.cursor,\n })\n },\n }\n}\n","import type { EventBus } from \"../core/event-bus\"\nimport type { EmulatorDocumentState } from \"../core/types\"\nimport type { WidgetApiImpl } from \"./types\"\n\n/**\n * `WidgetAPI` host implementation, backing `grist.widgetApi.*`. Reads and\n * writes the per-widget options bag persisted on the emulator state. Each\n * mutation triggers an `options-change` event so subscribers (the transport\n * pushes an `onOptions` message; tests/inspector update accordingly) stay in\n * lock-step with the document.\n */\nexport function createWidgetApiImpl(state: EmulatorDocumentState, bus: EventBus): WidgetApiImpl {\n function emit() {\n bus.emit({\n type: \"options-change\",\n options: { ...state.widgetOptions },\n interaction: { ...state.widgetInteraction },\n })\n }\n\n return {\n async getOption(key) {\n return state.widgetOptions[key]\n },\n\n async setOption(key, value) {\n state.widgetOptions[key] = value\n emit()\n },\n\n async getOptions() {\n return Object.keys(state.widgetOptions).length > 0 ? { ...state.widgetOptions } : null\n },\n\n async setOptions(options) {\n state.widgetOptions = { ...state.widgetOptions, ...options }\n emit()\n },\n\n async clearOptions() {\n state.widgetOptions = {}\n emit()\n },\n }\n}\n","/**\n * Bundles the six host-side Grist API implementations into one record so\n * transports (iframe, inline) can wire them up uniformly.\n */\n\nimport type { EventBus } from \"../core/event-bus\"\nimport type { EmulatorDocumentState } from \"../core/types\"\nimport { createCommandApiImpl } from \"./command-api\"\nimport { createCustomSectionApiImpl } from \"./custom-section-api\"\nimport { createGristApiImpl } from \"./grist-api\"\nimport { createGristDocApiImpl } from \"./grist-doc-api\"\nimport { createGristViewImpl } from \"./grist-view\"\nimport type {\n CommandApiImpl,\n CustomSectionApiImpl,\n GristApiImpl,\n GristDocApiImpl,\n GristViewImpl,\n WidgetApiImpl,\n} from \"./types\"\nimport { createWidgetApiImpl } from \"./widget-api\"\n\nexport type EmulatorApiBundle = {\n GristView: GristViewImpl\n GristDocAPI: GristDocApiImpl\n WidgetAPI: WidgetApiImpl\n CustomSectionAPI: CustomSectionApiImpl\n GristAPI: GristApiImpl\n CommandAPI: CommandApiImpl\n}\n\n/**\n * Build the implementations bound to a given document state and event bus.\n * Cheap to call — every method delegates to the (mutable) `state`.\n */\nexport function createApiBundle(state: EmulatorDocumentState, bus: EventBus): EmulatorApiBundle {\n return {\n GristView: createGristViewImpl(state, bus),\n GristDocAPI: createGristDocApiImpl(state, bus),\n WidgetAPI: createWidgetApiImpl(state, bus),\n CustomSectionAPI: createCustomSectionApiImpl(state, bus),\n GristAPI: createGristApiImpl(),\n CommandAPI: createCommandApiImpl(bus),\n }\n}\n\nexport type {\n CommandApiImpl,\n CustomSectionApiImpl,\n GristApiImpl,\n GristDocApiImpl,\n GristViewImpl,\n WidgetApiImpl,\n} from \"./types\"\n","/**\n * Tiny pub-sub used to broadcast every emulator state change to:\n * - the transports (which translate events into protocol messages),\n * - the React DevTools inspector (timeline view),\n * - the testing harness (assertions on emitted events).\n */\n\nimport type { GristCursorPos, GristWidgetColumnMap, GristWidgetInteraction } from \"../../sdk/types\"\n\nexport type EmulatorEvent =\n | { type: \"data-change\"; tableId: string }\n | { type: \"cursor-change\"; tableId: string; rowId: number | \"new\" | null; cursor?: GristCursorPos }\n | { type: \"options-change\"; options: Record<string, unknown>; interaction: GristWidgetInteraction }\n | { type: \"theme-change\"; message: Record<string, unknown> }\n | { type: \"ready\"; configuration: unknown }\n | { type: \"user-action\"; action: unknown[] }\n | { type: \"mappings-change\"; mappings: GristWidgetColumnMap | null }\n\nexport type EmulatorEventListener = (event: EmulatorEvent) => void\n\nexport type EventBus = {\n emit: (event: EmulatorEvent) => void\n on: (listener: EmulatorEventListener) => () => void\n history: () => readonly EmulatorEvent[]\n clear: () => void\n}\n\nexport type EventBusOptions = {\n /** Cap on history length (DevTools / tests). Defaults to 200. */\n historyLimit?: number\n}\n\nexport function createEventBus(options: EventBusOptions = {}): EventBus {\n const limit = options.historyLimit ?? 200\n const listeners = new Set<EmulatorEventListener>()\n const history: EmulatorEvent[] = []\n\n return {\n emit(event) {\n history.push(event)\n if (history.length > limit) history.shift()\n for (const fn of [...listeners]) {\n try {\n fn(event)\n } catch (err) {\n // eslint-disable-next-line no-console\n console.error(\"[grist-emulator] event listener threw:\", err)\n }\n }\n },\n on(listener) {\n listeners.add(listener)\n return () => {\n listeners.delete(listener)\n }\n },\n history() {\n return history\n },\n clear() {\n history.length = 0\n },\n }\n}\n","export type GristThemeAppearance = \"light\" | \"dark\"\n\n/** Host → widget postMessage shape used by `grist-plugin-api.js` (`onThemeChange`). */\nexport type GristThemeHostMessage = {\n theme: {\n appearance: GristThemeAppearance\n name: string\n colors: Record<string, string>\n }\n fromReady?: boolean\n}\n\nexport function buildGristThemeHostMessage(\n appearance: GristThemeAppearance,\n options?: { fromReady?: boolean }\n): GristThemeHostMessage {\n return {\n theme: {\n appearance,\n name: appearance,\n colors: {},\n },\n ...(options?.fromReady ? { fromReady: true } : {}),\n }\n}\n","/**\n * Iframe transport — the production-fidelity path.\n *\n * - The iframe loads the real `https://docs.getgrist.com/grist-plugin-api.js`\n * so widget code talks to `window.grist` exactly like in production.\n * - The host (this file) instantiates a `grain-rpc` `Rpc` and wires:\n * * outgoing → `iframe.contentWindow.postMessage(msg, targetOrigin)`\n * * incoming → `window.addEventListener(\"message\", ...)` filtered by\n * `event.source === iframe.contentWindow`.\n * - The Rpc registers the six host impls under their canonical names so\n * `grist-plugin-api.js`'s stubs find them.\n * - Custom messages (cursor / data / options / theme) are pushed via\n * `rpc.postMessage(...)` which `grist-plugin-api.js` dispatches to its\n * internal \"message\" event listeners (the ones used by `onRecord` etc.).\n *\n * Sequence:\n * 1. Host calls `rpc.queueOutgoingUntilReadyMessage()` so messages are\n * buffered until the widget signals it is ready.\n * 2. Widget loads, runs `grist-plugin-api.js`, calls `grist.ready(...)`.\n * 3. Widget's `grist-plugin-api.js` posts a \"ready\" message → host's Rpc\n * flushes the buffered outgoing messages.\n * 4. Widget's `grist.ready(...)` triggers `CustomSectionAPI.configure(...)`\n * on us; we react by emitting initial state (options + cursor + data).\n */\n\nimport { MsgType, Rpc } from \"grain-rpc\"\n\nimport type { GristWidgetInteraction } from \"../../sdk/types\"\nimport type { EmulatorEvent } from \"../core/event-bus\"\nimport { buildGristThemeHostMessage } from \"../theme-message\"\nimport type { EmulatorTransport, TransportContext } from \"./types\"\n\nexport type IframeTransportOptions = TransportContext & {\n iframe: HTMLIFrameElement\n /** `postMessage` target origin. Defaults to \"*\" — fine for emulator usage. */\n targetOrigin?: string\n}\n\nexport function createIframeTransport(options: IframeTransportOptions): EmulatorTransport {\n const { iframe, state, bus, api, targetOrigin = \"*\" } = options\n const timers = new Set<ReturnType<typeof setTimeout>>()\n\n const rpc = new Rpc({\n sendMessage: (msg) => {\n const target = iframe.contentWindow\n if (!target) return\n target.postMessage(msg, targetOrigin)\n },\n logger: { info: () => {}, warn: () => {} },\n })\n\n rpc.queueOutgoingUntilReadyMessage()\n\n /**\n * `grist-plugin-api.js` obtains `docApi` via `getStub(\"GristDocAPI@grist\", …)`, which sends\n * `RpcCall` messages with `mdest: \"grist\"`. In full Grist that forwarder reaches a doc-worker\n * `Rpc`; here all host impls live on this same `Rpc`, so forwarding to `this` would re-emit\n * the call to the iframe and the widget would reject it as `Unknown interface`. Strip `mdest`\n * so `GristDocAPI` resolves to our local `registerImpl` surface (same effective path as tests\n * that use `getStub(\"GristDocAPI\")` without `@grist`).\n */\n const receiveFromWidget = rpc.receiveMessage.bind(rpc)\n rpc.receiveMessage = (msg: unknown) => {\n if (\n msg &&\n typeof msg === \"object\" &&\n (msg as { mtype?: unknown }).mtype === MsgType.RpcCall &&\n (msg as { mdest?: unknown }).mdest === \"grist\"\n ) {\n const copy = { ...(msg as Record<string, unknown>) }\n delete copy.mdest\n receiveFromWidget(copy as never)\n return\n }\n receiveFromWidget(msg as never)\n }\n\n const onMessage = (event: MessageEvent) => {\n if (event.source !== iframe.contentWindow) return\n // Dev runtimes may post unrelated messages (HMR, devtools). Forwarding\n // them to grain-rpc can throw and disturb the ready handshake.\n if (!isRpcEnvelope(event.data)) return\n rpc.receiveMessage(event.data)\n }\n window.addEventListener(\"message\", onMessage)\n\n rpc.registerImpl(\"GristView\", api.GristView)\n rpc.registerImpl(\"GristDocAPI\", api.GristDocAPI)\n rpc.registerImpl(\"WidgetAPI\", api.WidgetAPI)\n rpc.registerImpl(\"CustomSectionAPI\", api.CustomSectionAPI)\n rpc.registerImpl(\"_grist_api\", api.GristAPI)\n rpc.registerImpl(\"CommandAPI\", api.CommandAPI)\n\n const buildInteraction = options.buildInteraction ?? defaultInteraction(state)\n const cursorOf = options.cursor ?? (() => state.selection.cursor)\n const initialCursorOf = options.initialCursor ?? (() => state.selection.rowId)\n\n type HostPushOptions = { mappingsChange?: boolean }\n\n function fireDataChange(tableId?: string, opts?: HostPushOptions) {\n safePostMessage({\n tableId: tableId ?? state.selection.tableId,\n dataChange: true,\n ...(opts?.mappingsChange ? { mappingsChange: true } : {}),\n })\n }\n function fireCursor(rowId?: number | \"new\" | null, opts?: HostPushOptions) {\n const id = rowId === undefined ? initialCursorOf() : rowId\n if (id === null) return\n safePostMessage({\n tableId: state.selection.tableId,\n rowId: id,\n cursor: cursorOf(),\n ...(opts?.mappingsChange ? { mappingsChange: true } : {}),\n })\n }\n function fireOptions() {\n safePostMessage({\n options: hasOptions(state.widgetOptions) ? { ...state.widgetOptions } : null,\n settings: { ...buildInteraction() },\n })\n }\n function fireTheme(message: Record<string, unknown>) {\n safePostMessage(message)\n }\n function emitInitialState(opts?: HostPushOptions) {\n fireOptions()\n if (options.initialTheme) {\n fireTheme(buildGristThemeHostMessage(options.initialTheme, { fromReady: true }))\n }\n fireDataChange(undefined, opts)\n fireCursor(undefined, opts)\n }\n\n function emitInitialStateWithReplay(opts?: HostPushOptions) {\n // Keep initial state delivery resilient when widget subscriptions are\n // attached slightly after ready (common in dev/HMR): send now, then replay\n // on the next microtask and next macrotask.\n emitInitialState(opts)\n queueMicrotask(() => emitInitialState(opts))\n const timer = setTimeout(() => {\n timers.delete(timer)\n emitInitialState(opts)\n }, 0)\n timers.add(timer)\n }\n\n // Bus → transport push. Listens on every emulator state mutation and pushes\n // the matching protocol message to the iframe.\n const offBus = bus.on((event: EmulatorEvent) => {\n switch (event.type) {\n case \"ready\":\n emitInitialStateWithReplay()\n break\n case \"data-change\":\n fireDataChange(event.tableId)\n break\n case \"cursor-change\": {\n const rowId = event.rowId === null ? state.selection.rowId : event.rowId\n if (rowId !== null) {\n safePostMessage({\n tableId: event.tableId,\n rowId,\n cursor: cursorOf(),\n })\n }\n // Match inline transport: cursor moves must also signal `dataChange` so\n // `grist-plugin-api.js` refetches the row and calls `onRecord` again.\n // Cursor-only postMessages left widgets stuck on the first row (#playground).\n fireDataChange(event.tableId)\n break\n }\n case \"options-change\":\n fireOptions()\n break\n case \"mappings-change\":\n // grist-plugin-api only refetches `sectionApi.mappings()` when `mappingsChange`\n // is set on the host message (see getMappingsIfChanged in grist-core).\n emitInitialStateWithReplay({ mappingsChange: true })\n break\n case \"theme-change\":\n fireTheme(event.message)\n break\n }\n })\n\n rpc.processIncoming()\n\n function safePostMessage(payload: Record<string, unknown>): void {\n try {\n rpc.postMessage(payload)\n } catch (err) {\n // Transport failures (broken iframe, crashed widget script, etc.) should\n // never break host-side emulator mutations. We keep the emulator state\n // authoritative and treat iframe delivery as best-effort.\n // eslint-disable-next-line no-console\n console.warn(\"[grist-emulator/iframe] failed to deliver postMessage\", err)\n }\n }\n\n return {\n dispose() {\n window.removeEventListener(\"message\", onMessage)\n offBus()\n for (const timer of timers) clearTimeout(timer)\n timers.clear()\n // grain-rpc 0.1.7 doesn't expose `close()`. We rely on listener removal\n // + GC to dispose the rpc instance.\n },\n fireDataChange,\n fireCursor,\n fireOptions,\n fireTheme,\n emitInitialState,\n }\n}\n\nfunction hasOptions(options: Record<string, unknown>): boolean {\n return Object.keys(options).length > 0\n}\n\nfunction isRpcEnvelope(data: unknown): data is { mtype: number } {\n if (!data || typeof data !== \"object\") return false\n return typeof (data as { mtype?: unknown }).mtype === \"number\"\n}\n\nfunction defaultInteraction(state: { widgetInteraction: GristWidgetInteraction; configuration: { requiredAccess?: string } | null }) {\n return (): GristWidgetInteraction => ({\n access_level: state.configuration?.requiredAccess ?? \"read table\",\n ...state.widgetInteraction,\n })\n}\n","/**\n * Grist `docApi.applyUserActions` payloads are arrays of user-action tuples.\n * @see https://support.getgrist.com/code/interfaces/grist_plugin_api.GristDocAPI/#applyuseractions\n */\n\nexport type GristUserActionTuple = unknown[]\n\n/** `[\"UpdateRecord\", tableId, rowId, { col: value, ... }]` */\nexport function gristUpdateRecordAction(\n tableId: string,\n rowId: number,\n patch: Record<string, unknown>\n): GristUserActionTuple {\n return [\"UpdateRecord\", tableId, rowId, patch]\n}\n\n/** `[\"AddRecord\", tableId, null, { col: value, ... }]` */\nexport function gristAddRecordAction(tableId: string, values: Record<string, unknown>): GristUserActionTuple {\n return [\"AddRecord\", tableId, null, values]\n}\n\n/** `[\"RemoveRecord\", tableId, rowId]` */\nexport function gristRemoveRecordAction(tableId: string, rowId: number): GristUserActionTuple {\n return [\"RemoveRecord\", tableId, rowId]\n}\n\n/** `[\"BulkUpdateRecord\", tableId, rowIds, { col: value[], ... }]` — column arrays must align with `rowIds`. */\nexport function gristBulkUpdateRecordAction(\n tableId: string,\n rowIds: number[],\n columnarPatch: Record<string, unknown[]>\n): GristUserActionTuple {\n return [\"BulkUpdateRecord\", tableId, rowIds, columnarPatch]\n}\n\n/**\n * `[\"BulkAddRecord\", tableId, rowIds | nullArray, { col: value[], ... }]`.\n * Pass `null` (or omit) for `rowIds` to let Grist allocate ids; in user-action\n * format Grist expects an array of nulls of the same length as the value arrays.\n */\nexport function gristBulkAddRecordAction(\n tableId: string,\n values: Record<string, unknown[]>,\n rowIds?: Array<number | null>\n): GristUserActionTuple {\n const length = inferBulkLength(values)\n const ids = rowIds ?? new Array<number | null>(length).fill(null)\n return [\"BulkAddRecord\", tableId, ids, values]\n}\n\n/** `[\"BulkRemoveRecord\", tableId, rowIds]` */\nexport function gristBulkRemoveRecordAction(tableId: string, rowIds: number[]): GristUserActionTuple {\n return [\"BulkRemoveRecord\", tableId, rowIds]\n}\n\n/** `[\"AddColumn\", tableId, colId, colInfo]` — `colInfo` shape depends on Grist version / column type. */\nexport function gristAddColumnAction(tableId: string, colId: string, colInfo: Record<string, unknown>): GristUserActionTuple {\n return [\"AddColumn\", tableId, colId, colInfo]\n}\n\n/** `[\"AddVisibleColumn\", tableId, colId, colInfo]` — like `AddColumn` but also adds the column to the current view section. */\nexport function gristAddVisibleColumnAction(tableId: string, colId: string, colInfo: Record<string, unknown>): GristUserActionTuple {\n return [\"AddVisibleColumn\", tableId, colId, colInfo]\n}\n\n/** `[\"RenameColumn\", tableId, colId, newColId]` */\nexport function gristRenameColumnAction(tableId: string, colId: string, newColId: string): GristUserActionTuple {\n return [\"RenameColumn\", tableId, colId, newColId]\n}\n\n/** `[\"ModifyColumn\", tableId, colId, colInfo]` */\nexport function gristModifyColumnAction(tableId: string, colId: string, colInfo: Record<string, unknown>): GristUserActionTuple {\n return [\"ModifyColumn\", tableId, colId, colInfo]\n}\n\n/** `[\"RemoveColumn\", tableId, colId]` */\nexport function gristRemoveColumnAction(tableId: string, colId: string): GristUserActionTuple {\n return [\"RemoveColumn\", tableId, colId]\n}\n\n/** `[\"AddTable\", tableId, tableInfo]` */\nexport function gristAddTableAction(tableId: string, tableInfo: Record<string, unknown>): GristUserActionTuple {\n return [\"AddTable\", tableId, tableInfo]\n}\n\n/** `[\"RenameTable\", tableId, newTableId]` */\nexport function gristRenameTableAction(tableId: string, newTableId: string): GristUserActionTuple {\n return [\"RenameTable\", tableId, newTableId]\n}\n\n/** `[\"RemoveTable\", tableId]` */\nexport function gristRemoveTableAction(tableId: string): GristUserActionTuple {\n return [\"RemoveTable\", tableId]\n}\n\n/** `[\"DuplicateTable\", tableId, newTableId, options?]` */\nexport function gristDuplicateTableAction(\n tableId: string,\n newTableId: string,\n options?: Record<string, unknown>\n): GristUserActionTuple {\n return options ? [\"DuplicateTable\", tableId, newTableId, options] : [\"DuplicateTable\", tableId, newTableId]\n}\n\n/** `[\"ReplaceTableData\", tableId, rowIds, columnarData]` */\nexport function gristReplaceTableDataAction(\n tableId: string,\n rowIds: Array<number | null>,\n columnarData: Record<string, unknown[]>\n): GristUserActionTuple {\n return [\"ReplaceTableData\", tableId, rowIds, columnarData]\n}\n\n/** `[\"SetDocumentInfo\", info]` */\nexport function gristSetDocumentInfoAction(info: Record<string, unknown>): GristUserActionTuple {\n return [\"SetDocumentInfo\", info]\n}\n\nfunction inferBulkLength(values: Record<string, unknown[]>): number {\n for (const arr of Object.values(values)) if (Array.isArray(arr)) return arr.length\n return 0\n}\n","/**\n * Inline transport — synthesises a `window.grist` global wired directly to\n * the emulator state. No iframe, no postMessage, no serialization.\n *\n * Used for:\n * - SDK unit tests in jsdom (`renderWithGrist(...)`),\n * - IDE-style live previews where widget code lives in the same window\n * as the emulator host.\n *\n * The synthesised `grist` object exposes the **same** typed surface as the\n * production `grist-plugin-api.js` (see `hooks/grist-global.d.ts`). Hooks\n * call `grist.docApi.fetchTable(...)` etc. and get the answer directly from\n * the action engine.\n */\n\nimport type {\n GristCursorPos,\n GristFetchSelectedOptions,\n GristMinimalRecord,\n GristReadyOptions,\n GristTableNewRecord,\n GristTableOpOptions,\n GristTableOperations,\n GristTableUpdateRecord,\n GristTableUpsertOptions,\n GristTableUpsertRecord,\n GristWidgetColumnMap,\n GristWidgetInteraction,\n} from \"../../sdk/types\"\nimport {\n gristAddRecordAction,\n gristBulkAddRecordAction,\n gristBulkRemoveRecordAction,\n gristBulkUpdateRecordAction,\n gristRemoveRecordAction,\n gristUpdateRecordAction,\n} from \"../../sdk/helpers/grist-user-actions\"\nimport { applyUserActions } from \"../core/action-engine\"\nimport type { EmulatorEvent } from \"../core/event-bus\"\nimport { findRow, getTable } from \"../core/document\"\nimport { resolveMappings } from \"../core/mappings\"\nimport type { EmulatorDocumentState } from \"../core/types\"\nimport { buildGristThemeHostMessage } from \"../theme-message\"\nimport type { EmulatorTransport, TransportContext } from \"./types\"\n\n/**\n * Shape of the synthesised global. Matches `globalThis.grist` from\n * `grist-global.d.ts`.\n */\nexport type InlineGristGlobal = {\n ready: (options?: GristReadyOptions) => Promise<void>\n onRecord: (\n cb: (record: Record<string, unknown> | null, mappings?: GristWidgetColumnMap | null) => void,\n options?: GristFetchSelectedOptions\n ) => void\n onRecords: (\n cb: (records: Record<string, unknown>[], mappings?: GristWidgetColumnMap | null) => void,\n options?: GristFetchSelectedOptions\n ) => void\n onOptions: (cb: (options: Record<string, unknown> | null, interaction: GristWidgetInteraction) => void) => void\n onNewRecord: (cb: (mappings: GristWidgetColumnMap | null) => void) => void\n mapColumnNames: (data: Record<string, unknown>) => Record<string, unknown> | null\n mapColumnNamesBack: (data: Record<string, unknown>) => Record<string, unknown>\n getOptions: () => Promise<Record<string, unknown> | null>\n getOption: (key: string) => Promise<unknown>\n setOption: (key: string, value: unknown) => Promise<void>\n setOptions: (options: Record<string, unknown>) => Promise<void>\n clearOptions: () => Promise<void>\n setCursorPos: (pos: GristCursorPos) => Promise<void>\n setSelectedRows: (rowIds: number[] | null) => Promise<void>\n fetchSelectedTable: (options?: GristFetchSelectedOptions) => Promise<Record<string, unknown[]>>\n fetchSelectedRecord: (rowId: number, options?: GristFetchSelectedOptions) => Promise<Record<string, unknown>>\n docApi: {\n getDocName: () => Promise<string>\n listTables: () => Promise<string[]>\n fetchTable: (tableId: string) => Promise<Record<string, unknown[]>>\n applyUserActions: (actions: unknown[][], options?: { desc?: string }) => Promise<{ retValues: unknown[] }>\n getAccessToken?: (options?: { readOnly?: boolean }) => Promise<{ token: string; baseUrl: string }>\n fetchSelectedTable: (options?: GristFetchSelectedOptions) => Promise<Record<string, unknown[]>>\n fetchSelectedRecord: (rowId: number, options?: GristFetchSelectedOptions) => Promise<Record<string, unknown>>\n }\n selectedTable: GristTableOperations\n getTable: (tableId?: string) => GristTableOperations\n sectionApi: {\n configure: (settings: GristReadyOptions) => Promise<void>\n mappings: () => Promise<GristWidgetColumnMap | null>\n }\n on: (eventName: string, listener: (...args: unknown[]) => void) => () => void\n}\n\nexport type InlineTransportOptions = TransportContext & {\n /**\n * Where to mount the synthesised `grist` global.\n * Defaults to the current window. Pass a different target (e.g. an iframe's\n * `contentWindow`) to install it in another realm.\n */\n target?: Window & typeof globalThis\n}\n\n/**\n * Returns an {@link EmulatorTransport} **and** the synthesised `grist`\n * object. `target.grist = global` is set as a side-effect for parity with\n * the production runtime.\n */\nexport function createInlineTransport(\n options: InlineTransportOptions\n): EmulatorTransport & { grist: InlineGristGlobal } {\n const { state, bus, api } = options\n const target = options.target ?? (globalThis as unknown as Window & typeof globalThis)\n\n // The SDK's `useGristAvailability` checks `window.self !== window.top`.\n // The inline transport runs in a top-level window where that's false. We\n // shim `top` so widget code thinks it's embedded — production doesn't use\n // this transport so there's no risk of leaking the shim.\n installFakeIframeContext(target)\n\n type RecordCb = (record: Record<string, unknown> | null, mappings?: GristWidgetColumnMap | null) => void\n type RecordsCb = (records: Record<string, unknown>[], mappings?: GristWidgetColumnMap | null) => void\n type OptionsCb = (options: Record<string, unknown> | null, interaction: GristWidgetInteraction) => void\n type NewRecordCb = (mappings: GristWidgetColumnMap | null) => void\n\n const recordCbs = new Map<RecordCb, GristFetchSelectedOptions | undefined>()\n const recordsCbs = new Map<RecordsCb, GristFetchSelectedOptions | undefined>()\n const optionsCbs = new Set<OptionsCb>()\n const newRecordCbs = new Set<NewRecordCb>()\n const generic = new Map<string, Set<(...args: unknown[]) => void>>()\n\n // Replay caches — production `grist-plugin-api.js` immediately delivers the\n // latest record / records / options to a freshly-subscribed listener, so\n // hooks that subscribe **after** `grist.ready()` still get the initial\n // payload. We mirror that behaviour here.\n type LastRecord = { record: Record<string, unknown> | null; mappings: GristWidgetColumnMap | null }\n type LastRecords = { records: Record<string, unknown>[]; mappings: GristWidgetColumnMap | null }\n type LastOptions = { options: Record<string, unknown> | null; interaction: GristWidgetInteraction }\n let lastRecord: LastRecord | null = null\n let lastRecords: LastRecords | null = null\n let lastOptions: LastOptions | null = null\n let lastNewRecord: GristWidgetColumnMap | null | undefined = undefined\n\n const buildInteraction = options.buildInteraction ?? (() => ({\n access_level: state.configuration?.requiredAccess ?? \"read table\",\n ...state.widgetInteraction,\n }))\n\n async function pushRecord(rowId: number | \"new\" | null) {\n const mappings = resolveMappings(state)\n if (rowId === \"new\") {\n lastNewRecord = mappings\n for (const cb of newRecordCbs) {\n try { cb(mappings) } catch (err) { logErr(err) }\n }\n lastRecord = { record: null, mappings }\n for (const [cb] of recordCbs) {\n try { cb(null, mappings) } catch (err) { logErr(err) }\n }\n return\n }\n if (rowId === null) {\n lastRecord = { record: null, mappings }\n for (const [cb] of recordCbs) {\n try { cb(null, mappings) } catch (err) { logErr(err) }\n }\n return\n }\n let record: Record<string, unknown> | null = null\n try {\n record = await api.GristView.fetchSelectedRecord(rowId)\n } catch (err) {\n logErr(err)\n }\n lastRecord = { record, mappings }\n for (const [cb, opts] of recordCbs) {\n try {\n const r = opts?.keepEncoded\n ? await api.GristView.fetchSelectedRecord(rowId, { keepEncoded: true })\n : record\n cb(r, mappings)\n } catch (err) {\n logErr(err)\n }\n }\n }\n\n async function pushRecords() {\n const mappings = resolveMappings(state)\n let baseRows: Record<string, unknown>[] = []\n try {\n const columnar = await api.GristView.fetchSelectedTable({})\n baseRows = columnsToRows(columnar)\n } catch (err) {\n logErr(err)\n }\n lastRecords = { records: baseRows, mappings }\n for (const [cb, opts] of recordsCbs) {\n try {\n const fetchOptions = coerceFetchOptions(opts)\n // Re-fetch only when the subscriber asked for a different shape\n // (e.g. `keepEncoded: true`). Otherwise reuse the decoded rows we\n // already have to avoid extra work and to match production where\n // the same fetch is broadcast to every listener.\n const rows = fetchOptions?.keepEncoded\n ? columnsToRows(await api.GristView.fetchSelectedTable({ keepEncoded: true }))\n : baseRows\n cb(rows, mappings)\n } catch (err) {\n logErr(err)\n }\n }\n }\n\n /**\n * Mirror what `viewApi.fetchSelectedTable` does inside `grist-plugin-api.js`:\n * the host RPC stub always returns columnar; the wrapper applies the\n * `format: \"rows\"` transpose (and would decode encoded values when\n * `keepEncoded: false` — a no-op here because our `rowsToColumnar` already\n * emits JS-native primitives in that case).\n *\n * Keeping this logic on the inline side guarantees that widgets see the\n * same result whether they go through the iframe transport (real plugin\n * wrapper) or the inline transport (this wrapper).\n */\n async function fetchSelectedTableShaped(\n opts: GristFetchSelectedOptions | undefined\n ): Promise<Record<string, unknown[]> | Record<string, unknown>[]> {\n const fetchOptions = coerceFetchOptions(opts)\n const columnar = (await api.GristView.fetchSelectedTable(\n fetchOptions ? { keepEncoded: fetchOptions.keepEncoded } : {}\n )) as Record<string, unknown[]>\n if (fetchOptions?.format === \"rows\") return columnsToRows(columnar)\n return columnar\n }\n\n function pushOptions() {\n const opts = Object.keys(state.widgetOptions).length > 0 ? { ...state.widgetOptions } : null\n const interaction = buildInteraction()\n lastOptions = { options: opts, interaction }\n for (const cb of optionsCbs) {\n try { cb(opts, interaction) } catch (err) { logErr(err) }\n }\n }\n\n const offBus = bus.on(async (event: EmulatorEvent) => {\n switch (event.type) {\n case \"data-change\":\n await pushRecords()\n await pushRecord(state.selection.rowId)\n break\n case \"cursor-change\":\n await pushRecord(event.rowId)\n break\n case \"options-change\":\n pushOptions()\n break\n case \"ready\":\n pushOptions()\n if (options.initialTheme) {\n notify(\"message\", buildGristThemeHostMessage(options.initialTheme, { fromReady: true }))\n }\n await pushRecords()\n await pushRecord(state.selection.rowId)\n break\n case \"mappings-change\":\n await pushRecords()\n await pushRecord(state.selection.rowId)\n break\n case \"theme-change\":\n notify(\"message\", event.message)\n break\n }\n })\n\n function makeTableOps(tableId: string): GristTableOperations {\n return {\n async getTableId() { return tableId },\n async create(records, options) {\n const list = Array.isArray(records) ? records : [records]\n const ids: GristMinimalRecord[] = []\n for (const r of list) {\n const result = applyUserActions(state, bus, [\n gristAddRecordAction(tableId, parseFields(r.fields, options)),\n ])\n ids.push({ id: result.retValues[0] as number })\n }\n return Array.isArray(records) ? ids : ids[0]\n },\n async update(records: GristTableUpdateRecord | GristTableUpdateRecord[], options?: GristTableOpOptions) {\n const list = Array.isArray(records) ? records : [records]\n const actions = list.map((r) => gristUpdateRecordAction(tableId, r.id, parseFields(r.fields, options)))\n applyUserActions(state, bus, actions)\n },\n async upsert(records: GristTableUpsertRecord | GristTableUpsertRecord[], options?: GristTableUpsertOptions) {\n const list = Array.isArray(records) ? records : [records]\n const allowAdd = options?.add !== false\n const allowUpdate = options?.update !== false\n const table = getTable(state, tableId)\n const actions: unknown[][] = []\n for (const r of list) {\n const matches = table.rows.filter((row) =>\n Object.entries(r.require).every(([k, v]) => row[k] === v)\n )\n if (matches.length > 0) {\n if (!allowUpdate) continue\n const fields = parseFields(r.fields ?? {}, options)\n for (const m of matches) actions.push(gristUpdateRecordAction(tableId, m.id, fields))\n } else if (allowAdd) {\n actions.push(gristAddRecordAction(tableId, { ...r.require, ...parseFields(r.fields ?? {}, options) }))\n }\n }\n if (actions.length > 0) applyUserActions(state, bus, actions)\n },\n async destroy(recordIds: number | number[]) {\n if (Array.isArray(recordIds)) {\n applyUserActions(state, bus, [gristBulkRemoveRecordAction(tableId, recordIds)])\n } else {\n applyUserActions(state, bus, [gristRemoveRecordAction(tableId, recordIds)])\n }\n // touch the unused bulk-add reference for tree-shaking parity, no-op\n void gristBulkAddRecordAction\n void gristBulkUpdateRecordAction\n },\n }\n }\n\n function notify(event: string, ...args: unknown[]) {\n const set = generic.get(event)\n if (!set) return\n for (const fn of set) {\n try { fn(...args) } catch (err) { logErr(err) }\n }\n }\n\n const grist: InlineGristGlobal = {\n async ready(opts) {\n await api.CustomSectionAPI.configure(opts ? { ...opts, onEditOptions: undefined } as unknown as Record<string, unknown> : {})\n },\n\n onRecord(cb, opts) {\n recordCbs.set(cb, opts)\n // Replay last value so late subscribers don't miss the initial event.\n if (lastRecord) {\n try { cb(lastRecord.record, lastRecord.mappings) } catch (err) { logErr(err) }\n }\n },\n onRecords(cb, opts) {\n recordsCbs.set(cb, opts)\n if (lastRecords) {\n try { cb(lastRecords.records, lastRecords.mappings) } catch (err) { logErr(err) }\n }\n },\n onOptions(cb) {\n optionsCbs.add(cb)\n if (lastOptions) {\n try { cb(lastOptions.options, lastOptions.interaction) } catch (err) { logErr(err) }\n }\n },\n onNewRecord(cb) {\n newRecordCbs.add(cb)\n if (lastNewRecord !== undefined) {\n try { cb(lastNewRecord) } catch (err) { logErr(err) }\n }\n },\n\n mapColumnNames(data) {\n const mappings = resolveMappings(state)\n if (!mappings) return null\n const out: Record<string, unknown> = {}\n let allMapped = true\n for (const [logical, real] of Object.entries(mappings)) {\n if (Array.isArray(real)) {\n out[logical] = real.map((r) => data[r])\n } else if (typeof real === \"string\") {\n out[logical] = data[real]\n } else {\n allMapped = false\n }\n }\n return allMapped ? out : null\n },\n mapColumnNamesBack(data) {\n const mappings = resolveMappings(state)\n if (!mappings) return data\n const out: Record<string, unknown> = {}\n for (const [logical, real] of Object.entries(mappings)) {\n if (typeof real === \"string\" && logical in data) {\n out[real] = data[logical]\n }\n }\n return out\n },\n\n getOption: (k) => api.WidgetAPI.getOption(k),\n setOption: (k, v) => api.WidgetAPI.setOption(k, v),\n getOptions: () => api.WidgetAPI.getOptions(),\n setOptions: (o) => api.WidgetAPI.setOptions(o),\n clearOptions: () => api.WidgetAPI.clearOptions(),\n\n setCursorPos: (pos) => api.GristView.setCursorPos(pos),\n setSelectedRows: (rowIds) => api.GristView.setSelectedRows(rowIds),\n fetchSelectedTable: (opts) =>\n fetchSelectedTableShaped(opts) as Promise<Record<string, unknown[]>>,\n fetchSelectedRecord: (rowId, opts) => api.GristView.fetchSelectedRecord(rowId, coerceFetchOptions(opts)),\n\n docApi: {\n getDocName: () => api.GristDocAPI.getDocName(),\n listTables: () => api.GristDocAPI.listTables(),\n fetchTable: (id) => api.GristDocAPI.fetchTable(id),\n applyUserActions: (actions, options) => api.GristDocAPI.applyUserActions(actions, options),\n getAccessToken: (opts) => api.GristDocAPI.getAccessToken(opts),\n fetchSelectedTable: (opts) =>\n fetchSelectedTableShaped(opts) as Promise<Record<string, unknown[]>>,\n fetchSelectedRecord: (rowId, opts) =>\n api.GristView.fetchSelectedRecord(rowId, coerceFetchOptions(opts)),\n },\n\n get selectedTable() {\n return makeTableOps(state.selection.tableId)\n },\n\n getTable(tableId) {\n return makeTableOps(tableId ?? state.selection.tableId)\n },\n\n sectionApi: {\n configure: (settings) => api.CustomSectionAPI.configure(settings as unknown as Record<string, unknown>),\n mappings: () => api.CustomSectionAPI.mappings(),\n },\n\n on(eventName, listener) {\n let set = generic.get(eventName)\n if (!set) generic.set(eventName, (set = new Set()))\n set.add(listener)\n return () => set!.delete(listener)\n },\n }\n\n ;(target as unknown as { grist: InlineGristGlobal }).grist = grist\n\n return {\n grist,\n dispose() {\n offBus()\n // Restore the global (only if we still own it).\n const t = target as unknown as { grist?: unknown }\n if (t.grist === grist) delete t.grist\n recordCbs.clear()\n recordsCbs.clear()\n optionsCbs.clear()\n newRecordCbs.clear()\n generic.clear()\n lastRecord = null\n lastRecords = null\n lastOptions = null\n lastNewRecord = undefined\n },\n fireDataChange(tableId) {\n bus.emit({ type: \"data-change\", tableId: tableId ?? state.selection.tableId })\n },\n fireCursor(rowId) {\n const id = rowId === undefined ? state.selection.rowId : rowId\n bus.emit({ type: \"cursor-change\", tableId: state.selection.tableId, rowId: id })\n },\n fireOptions() {\n pushOptions()\n },\n fireTheme(message) {\n bus.emit({ type: \"theme-change\", message })\n },\n emitInitialState() {\n pushOptions()\n void pushRecords().then(() => pushRecord(state.selection.rowId))\n },\n }\n}\n\nfunction columnsToRows(columnar: Record<string, unknown[]>): Record<string, unknown>[] {\n const cols = Object.keys(columnar)\n if (cols.length === 0) return []\n const length = (columnar[cols[0]] ?? []).length\n const rows: Record<string, unknown>[] = []\n for (let i = 0; i < length; i++) {\n const row: Record<string, unknown> = {}\n for (const c of cols) row[c] = columnar[c][i]\n rows.push(row)\n }\n return rows\n}\n\nfunction parseFields(fields: Record<string, unknown>, _options?: GristTableOpOptions): Record<string, unknown> {\n // The emulator currently doesn't implement string-parsing; pass-through.\n // Hook into here to add date/number parsing when we surface that toggle.\n return { ...fields }\n}\n\nfunction coerceFetchOptions(\n opts: GristFetchSelectedOptions | undefined\n): { keepEncoded?: boolean; format?: \"rows\" | \"columns\" } | undefined {\n if (!opts) return undefined\n const format = opts.format === \"rows\" || opts.format === \"columns\" ? opts.format : undefined\n return { keepEncoded: opts.keepEncoded, format }\n}\n\nfunction logErr(err: unknown) {\n // eslint-disable-next-line no-console\n console.error(\"[grist-emulator/inline]\", err)\n}\n\n// Touch helpers to keep them tree-shake-friendly even if unused in current scope.\nvoid findRow\n\n/**\n * Make `window.self !== window.top` evaluate to `true`. The SDK uses this\n * exact comparison in `useGristAvailability` to detect an iframe environment.\n *\n * Inline transports run inside the host window (tests, IDE preview) and would\n * otherwise be flagged as \"not embedded\" — this shim is the same trick we use\n * in the testing harness and is safe because the inline transport is never\n * shipped to production.\n */\nfunction installFakeIframeContext(target: Window & typeof globalThis) {\n try {\n if (target.self !== target.top) return\n Object.defineProperty(target, \"top\", {\n configurable: true,\n get: () => ({}),\n })\n } catch {\n // Some environments lock these globals; ignore silently.\n }\n}\n","import { z } from \"zod\"\n\nimport type { GristReplicaDocument } from \"../sdk/replica-document\"\n\nconst emulatorRowSchema = z\n .object({ id: z.number() })\n .catchall(z.unknown())\n\nconst formulaKindSchema = z.enum([\"computed\", \"trigger\", \"none\", \"empty_slot\"])\n\nconst replicaColumnSchema = z\n .object({\n colRef: z.number().optional(),\n type: z.string().optional(),\n label: z.string().optional(),\n parentPos: z.number().optional(),\n isFormula: z.boolean().optional(),\n formulaKind: formulaKindSchema.optional(),\n formula: z.string().optional(),\n description: z.string().optional(),\n widgetOptions: z.record(z.string(), z.unknown()).optional(),\n displayColRef: z.number().optional(),\n visibleColRef: z.number().optional(),\n })\n .strict()\n\nconst replicaTableSchema = z\n .object({\n label: z.string().optional(),\n columns: z.record(z.string(), replicaColumnSchema).optional(),\n rows: z.array(emulatorRowSchema).optional(),\n rowCount: z.number().optional(),\n dataOmitted: z.boolean().optional(),\n dataOmittedReason: z.string().optional(),\n error: z.string().optional(),\n })\n .strict()\n\nconst replicaSelectionSchema = z\n .object({\n tableId: z.string().optional(),\n rowId: z.union([z.number(), z.literal(\"new\"), z.null()]).optional(),\n mappings: z.unknown().nullable().optional(),\n cursor: z.unknown().optional(),\n })\n .strict()\n\nconst replicaWidgetConfigurationSchema = z\n .object({\n requiredAccess: z.string().optional(),\n columns: z.unknown().optional(),\n allowSelectBy: z.boolean().optional(),\n hasCustomOptions: z.boolean().optional(),\n })\n .strict()\n\nconst replicaAccessTokenSchema = z\n .object({\n token: z.string(),\n baseUrl: z.string(),\n ttlMsecs: z.number(),\n })\n .strict()\n\nconst replicaDocumentSchema = z\n .object({\n generatedAt: z.string(),\n source: z.string().optional(),\n docName: z.string().optional(),\n mode: z.enum([\"schema-only\", \"schema+samples\", \"schema+data\"]).optional(),\n tables: z.record(z.string(), replicaTableSchema),\n selection: replicaSelectionSchema.optional(),\n widgetOptions: z.record(z.string(), z.unknown()).optional(),\n widgetInteraction: z.unknown().optional(),\n configuration: replicaWidgetConfigurationSchema.optional(),\n accessToken: replicaAccessTokenSchema.nullable().optional(),\n })\n .strict()\n .refine((value) => Object.keys(value.tables).length > 0, {\n message: \"at least one table is required\",\n path: [\"tables\"],\n })\n\nfunction formatZodError(prefix: string, error: z.ZodError): Error {\n const details = error.issues\n .map((issue) => {\n const where = issue.path.length > 0 ? issue.path.join(\".\") : \"<root>\"\n return `${where}: ${issue.message}`\n })\n .join(\"; \")\n return new Error(`${prefix}: ${details}`)\n}\n\nexport function safeParseDocument(input: unknown) {\n return replicaDocumentSchema.safeParse(input)\n}\n\nexport function parseDocument(input: unknown): GristReplicaDocument {\n const result = safeParseDocument(input)\n if (!result.success) {\n throw formatZodError(\"parseDocument\", result.error)\n }\n return result.data as GristReplicaDocument\n}\n","/**\n * Top-level emulator factory. Produces a fully-wired emulator instance:\n *\n * - typed in-memory document state,\n * - shared event bus,\n * - the six host API impls,\n * - one transport (inline by default, iframe when an iframe is provided),\n * - imperative helpers (`mutate`, `apply`, `selectRow`, `selectTable`)\n * that drive the document via the action engine and emit corresponding\n * events.\n *\n * The instance is multi-instance friendly: nothing is stored on `window`.\n */\n\nimport { createApiBundle } from \"./api\"\nimport type { EmulatorApiBundle } from \"./api\"\nimport { applyUserActions } from \"./core/action-engine\"\nimport { createDocument } from \"./core/document\"\nimport { createEventBus } from \"./core/event-bus\"\nimport type { EventBus } from \"./core/event-bus\"\nimport { resolveMappings } from \"./core/mappings\"\nimport type { EmulatorDocumentState } from \"./core/types\"\nimport type { GristReplicaDocument } from \"../sdk/replica-document\"\nimport type { GristWidgetColumnMap } from \"../sdk/types\"\nimport { buildGristThemeHostMessage } from \"./theme-message\"\nimport { createIframeTransport, createInlineTransport } from \"./transports\"\nimport type { EmulatorTransport, InlineGristGlobal } from \"./transports\"\nimport { parseDocument } from \"./validators\"\n\nexport type CreateGristEmulatorOptions = {\n /** The starting document (must satisfy {@link parseDocument}). */\n document: GristReplicaDocument\n /**\n * Pick a transport:\n * - omit / \"inline\" → synthesises `window.grist` directly (or onto `target`),\n * - \"iframe\" → wires a real iframe loading `grist-plugin-api.js`.\n */\n transport?:\n | { kind: \"inline\"; target?: Window & typeof globalThis }\n | { kind: \"iframe\"; iframe: HTMLIFrameElement; targetOrigin?: string }\n /** Initial widget options exposed via `WidgetAPI`. */\n widgetOptions?: Record<string, unknown>\n /**\n * Initial widget interaction info (`access_level` and friends) sent\n * alongside `onOptions`. Defaults to `{ access_level: \"read table\" }`.\n */\n widgetInteraction?: Record<string, unknown>\n /** Initial document theme replayed on widget ready (host `message` channel). */\n initialTheme?: \"light\" | \"dark\"\n}\n\nexport type GristEmulator = {\n /** Underlying mutable document. Treat as read-only outside of `mutate(...)`. */\n state: EmulatorDocumentState\n bus: EventBus\n api: EmulatorApiBundle\n transport: EmulatorTransport\n /** Synthesised `grist` global (only for the inline transport). */\n grist?: InlineGristGlobal\n\n /** Apply a list of Grist user actions; emits the matching events. */\n apply: (actions: unknown[][]) => { retValues: unknown[] }\n /** Convenience helpers for tests and demos. */\n mutate: {\n addRow: (tableId: string, fields: Record<string, unknown>) => number\n updateRow: (tableId: string, rowId: number, fields: Record<string, unknown>) => void\n removeRow: (tableId: string, rowId: number) => void\n }\n selectRow: (rowId: number | \"new\" | null) => void\n selectTable: (tableId: string) => void\n /**\n * Set logical→real column mappings for the playground inspector (and tests).\n * Pass `undefined` to clear — `mappings()` becomes `null` until set again.\n */\n setColumnMappings: (mappings: GristWidgetColumnMap | undefined) => void\n setOptions: (options: Record<string, unknown>) => Promise<void>\n setInteraction: (interaction: Record<string, unknown>) => void\n /** Host theme controls (`grist.on(\"message\")` / `msg.theme`). */\n theme: {\n set: (theme: \"light\" | \"dark\") => void\n }\n /** Tear down the emulator. Idempotent. */\n dispose: () => void\n}\n\nexport function createGristEmulator(options: CreateGristEmulatorOptions): GristEmulator {\n const validatedDocument = parseDocument(options.document)\n const state = createDocument({\n ...validatedDocument,\n widgetOptions: options.widgetOptions ?? validatedDocument.widgetOptions,\n widgetInteraction:\n options.widgetInteraction ?? validatedDocument.widgetInteraction ?? { access_level: \"read table\" },\n })\n const bus = createEventBus()\n const api = createApiBundle(state, bus)\n\n const transportKind = options.transport?.kind ?? \"inline\"\n let transport: EmulatorTransport\n let grist: InlineGristGlobal | undefined\n\n if (transportKind === \"iframe\") {\n if (options.transport?.kind !== \"iframe\") throw new Error(\"transport mismatch\")\n transport = createIframeTransport({\n iframe: options.transport.iframe,\n targetOrigin: options.transport.targetOrigin,\n state,\n bus,\n api,\n initialTheme: options.initialTheme,\n })\n } else {\n const inline = createInlineTransport({\n state,\n bus,\n api,\n initialTheme: options.initialTheme,\n target: options.transport?.kind === \"inline\" ? options.transport.target : undefined,\n })\n transport = inline\n grist = inline.grist\n }\n\n function apply(actions: unknown[][]) {\n return applyUserActions(state, bus, actions)\n }\n\n return {\n state,\n bus,\n api,\n transport,\n grist,\n apply,\n mutate: {\n addRow: (tableId, fields) => apply([[\"AddRecord\", tableId, null, fields]]).retValues[0] as number,\n updateRow: (tableId, rowId, fields) => {\n apply([[\"UpdateRecord\", tableId, rowId, fields]])\n },\n removeRow: (tableId, rowId) => {\n apply([[\"RemoveRecord\", tableId, rowId]])\n },\n },\n selectRow(rowId) {\n state.selection.rowId = rowId\n bus.emit({ type: \"cursor-change\", tableId: state.selection.tableId, rowId })\n },\n selectTable(tableId) {\n if (!state.tables.has(tableId)) throw new Error(`Unknown table: ${tableId}`)\n state.selection.tableId = tableId\n const first = state.tables.get(tableId)!.rows[0]?.id ?? null\n state.selection.rowId = first\n bus.emit({ type: \"data-change\", tableId })\n bus.emit({ type: \"cursor-change\", tableId, rowId: first })\n },\n setColumnMappings(mappings) {\n if (mappings === undefined) {\n delete state.selection.mappings\n } else {\n state.selection.mappings = mappings\n }\n bus.emit({ type: \"mappings-change\", mappings: resolveMappings(state) })\n },\n async setOptions(opts) {\n await api.WidgetAPI.setOptions(opts)\n },\n setInteraction(interaction) {\n state.widgetInteraction = { ...interaction }\n bus.emit({ type: \"options-change\", options: { ...state.widgetOptions }, interaction: { ...interaction } })\n },\n theme: {\n set(next) {\n bus.emit({ type: \"theme-change\", message: buildGristThemeHostMessage(next) })\n },\n },\n dispose() {\n transport.dispose()\n bus.clear()\n },\n }\n}\n","/**\n * Document templates exposed at the top of the emulator API.\n *\n * Templates return plain data — they don't allocate state, the caller passes\n * the returned value into `createGristEmulator(...)` which performs the allocation.\n */\n\nimport type { GristReplicaDocument } from \"../sdk/replica-document\"\n\nconst PRESET_GENERATED_AT = \"1970-01-01T00:00:00.000Z\"\n\nfunction replicaBase(overrides: Omit<GristReplicaDocument, \"generatedAt\">): GristReplicaDocument {\n return {\n generatedAt: PRESET_GENERATED_AT,\n ...overrides,\n }\n}\n\n/**\n * Useful templates for quick demos and tests.\n */\nexport const presets = {\n /**\n * Default starter fixture for demos / sandboxes that need a neutral document\n * without choosing a domain-specific preset.\n */\n defaultTemplate(): GristReplicaDocument {\n return replicaBase({\n docName: \"Default\",\n tables: {\n Table1: {\n label: \"Table1\",\n rows: [\n { id: 1, Name: \"Alice\" },\n { id: 2, Name: \"Bob\" },\n ],\n },\n },\n })\n },\n blank(): GristReplicaDocument {\n return replicaBase({\n docName: \"Blank\",\n tables: {\n Table1: { rows: [{ id: 1 }] },\n },\n })\n },\n todoList(): GristReplicaDocument {\n return replicaBase({\n docName: \"Todo list\",\n mode: \"schema+data\",\n tables: {\n Tasks: {\n label: \"Tasks\",\n columns: {\n title: { type: \"Text\", label: \"Title\" },\n done: { type: \"Bool\", label: \"Done\" },\n priority: { type: \"Choice\", label: \"Priority\" },\n },\n rows: [\n { id: 1, title: \"Buy milk\", done: false, priority: \"high\" },\n { id: 2, title: \"Write the SOTA emulator\", done: true, priority: \"high\" },\n { id: 3, title: \"Ship it\", done: false, priority: \"medium\" },\n ],\n },\n },\n })\n },\n contacts(): GristReplicaDocument {\n return replicaBase({\n docName: \"Contacts\",\n mode: \"schema+data\",\n tables: {\n Contacts: {\n label: \"Contacts\",\n columns: {\n firstName: { type: \"Text\" },\n lastName: { type: \"Text\" },\n email: { type: \"Text\" },\n company: { type: \"Text\" },\n },\n rows: [\n { id: 1, firstName: \"Ada\", lastName: \"Lovelace\", email: \"ada@analytical.engine\", company: \"British Crown\" },\n { id: 2, firstName: \"Linus\", lastName: \"Torvalds\", email: \"linus@kernel.org\", company: \"Linux Foundation\" },\n { id: 3, firstName: \"Margaret\", lastName: \"Hamilton\", email: \"margaret@apollo.nasa\", company: \"NASA\" },\n ],\n },\n },\n })\n },\n}\n","/**\n * Vitest helpers to assert what the widget did to the document.\n *\n * Usage:\n *\n * const { emulator } = renderWithGrist(<MyWidget />)\n * await userEvent.click(screen.getByText(\"Add\"))\n * expect(actionsOf(emulator)).toContainEqual([\"AddRecord\", \"Tasks\", null, { title: \"X\" }])\n */\n\nimport type { GristEmulator } from \"../create-grist-emulator\"\nimport type { EmulatorEvent } from \"../core/event-bus\"\n\nexport function actionsOf(emulator: GristEmulator): unknown[][] {\n return emulator.bus\n .history()\n .filter((e: EmulatorEvent): e is Extract<EmulatorEvent, { type: \"user-action\" }> => e.type === \"user-action\")\n .map((e) => e.action as unknown[])\n}\n\nexport function eventsOf(emulator: GristEmulator): readonly EmulatorEvent[] {\n return emulator.bus.history()\n}\n\n/** Bus event kinds aligned with grist host callbacks (see inline transport). */\nexport type WaitForEventKind = \"ready\" | \"record\" | \"records\" | \"options\" | \"theme\" | \"cursor\"\n\nexport type WaitForEventOptions = {\n timeoutMs?: number\n}\n\nfunction predicateForKind(kind: WaitForEventKind): (event: EmulatorEvent) => boolean {\n switch (kind) {\n case \"ready\":\n return (e) => e.type === \"ready\"\n case \"record\":\n case \"cursor\":\n return (e) => e.type === \"cursor-change\"\n case \"records\":\n return (e) => e.type === \"data-change\"\n case \"options\":\n return (e) => e.type === \"options-change\"\n case \"theme\":\n return (e) => e.type === \"theme-change\"\n }\n}\n\nfunction waitForNextEvent(\n emulator: GristEmulator,\n predicate: (event: EmulatorEvent) => boolean,\n timeoutMs: number,\n label?: string\n): Promise<EmulatorEvent> {\n return new Promise((resolve, reject) => {\n const timer = setTimeout(() => {\n off()\n const hint = label ? ` (kind: ${label})` : \"\"\n const recent = emulator.bus\n .history()\n .slice(-5)\n .map((e) => e.type)\n .join(\", \")\n reject(\n new Error(\n `waitForEvent timed out after ${timeoutMs}ms${hint}.` +\n (recent ? ` Recent bus events: ${recent}.` : \" No bus events yet.\")\n )\n )\n }, timeoutMs)\n const off = emulator.bus.on((event) => {\n if (predicate(event)) {\n clearTimeout(timer)\n off()\n resolve(event)\n }\n })\n })\n}\n\nexport function waitForEvent(\n emulator: GristEmulator,\n kind: WaitForEventKind,\n options?: WaitForEventOptions\n): Promise<EmulatorEvent>\nexport function waitForEvent(\n emulator: GristEmulator,\n predicate: (event: EmulatorEvent) => boolean,\n timeoutMs?: number\n): Promise<EmulatorEvent>\nexport function waitForEvent(\n emulator: GristEmulator,\n kindOrPredicate: WaitForEventKind | ((event: EmulatorEvent) => boolean),\n timeoutOrOptions: number | WaitForEventOptions = 1000\n): Promise<EmulatorEvent> {\n if (typeof kindOrPredicate === \"string\") {\n const opts = typeof timeoutOrOptions === \"object\" ? timeoutOrOptions : {}\n const timeoutMs = opts.timeoutMs ?? 1000\n return waitForNextEvent(emulator, predicateForKind(kindOrPredicate), timeoutMs, kindOrPredicate)\n }\n const timeoutMs = typeof timeoutOrOptions === \"number\" ? timeoutOrOptions : 1000\n return waitForNextEvent(emulator, kindOrPredicate, timeoutMs)\n}\n"],"mappings":"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","names":["options","grist","import_zod","grist","timeoutMs","import_react"]}
|