@altertable/data-app 0.59.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (174) hide show
  1. package/AGENTS.md +35 -0
  2. package/CONTRIBUTING.md +83 -0
  3. package/LICENSE +21 -0
  4. package/README.md +63 -0
  5. package/dist/bootstrap.js +388 -0
  6. package/dist/chunks/contract-14vxdcrs.js +192 -0
  7. package/dist/chunks/contract-14vxdcrs.js.map +10 -0
  8. package/dist/chunks/contract-8q35dcyh.js +9 -0
  9. package/dist/chunks/contract-8q35dcyh.js.map +10 -0
  10. package/dist/chunks/contract-jksbmt5q.js +133 -0
  11. package/dist/chunks/contract-jksbmt5q.js.map +10 -0
  12. package/dist/chunks/contract-mb5nfzwg.js +375 -0
  13. package/dist/chunks/contract-mb5nfzwg.js.map +12 -0
  14. package/dist/chunks/contract-mev09s5v.js +77 -0
  15. package/dist/chunks/contract-mev09s5v.js.map +10 -0
  16. package/dist/chunks/contract-nt819swq.js +321 -0
  17. package/dist/chunks/contract-nt819swq.js.map +11 -0
  18. package/dist/chunks/contract-ryyf6dme.js +21 -0
  19. package/dist/chunks/contract-ryyf6dme.js.map +10 -0
  20. package/dist/chunks/contract-tkkc28tg.js +213 -0
  21. package/dist/chunks/contract-tkkc28tg.js.map +12 -0
  22. package/dist/chunks/contract-tqrf3ykr.js +232 -0
  23. package/dist/chunks/contract-tqrf3ykr.js.map +11 -0
  24. package/dist/chunks/contract-wz59z8pq.js +8 -0
  25. package/dist/chunks/contract-wz59z8pq.js.map +10 -0
  26. package/dist/client/index.js +27 -0
  27. package/dist/client/index.js.map +9 -0
  28. package/dist/core/appearance.js +12 -0
  29. package/dist/core/appearance.js.map +9 -0
  30. package/dist/core/config.js +8 -0
  31. package/dist/core/config.js.map +9 -0
  32. package/dist/core/contract.js +55 -0
  33. package/dist/core/contract.js.map +9 -0
  34. package/dist/core/format.js +18 -0
  35. package/dist/core/format.js.map +9 -0
  36. package/dist/embed/index.js +91 -0
  37. package/dist/embed/index.js.map +11 -0
  38. package/dist/local.js +332 -0
  39. package/dist/local.js.map +15 -0
  40. package/dist/react/embed/index.js +130 -0
  41. package/dist/react/embed/index.js.map +11 -0
  42. package/dist/react/index.css +4478 -0
  43. package/dist/react/index.js +6105 -0
  44. package/dist/react/index.js.map +90 -0
  45. package/dist/react.css.d.ts +1 -0
  46. package/dist/server.js +231 -0
  47. package/dist/server.js.map +14 -0
  48. package/dist/types/client/iframe.d.ts +39 -0
  49. package/dist/types/client/index.d.ts +42 -0
  50. package/dist/types/client/location.d.ts +15 -0
  51. package/dist/types/client/messages.d.ts +7 -0
  52. package/dist/types/client/navigation.d.ts +14 -0
  53. package/dist/types/client/transport.d.ts +15 -0
  54. package/dist/types/core/appearance.d.ts +28 -0
  55. package/dist/types/core/bridge.d.ts +35 -0
  56. package/dist/types/core/config.d.ts +14 -0
  57. package/dist/types/core/contract.d.ts +139 -0
  58. package/dist/types/core/data-view.d.ts +46 -0
  59. package/dist/types/core/date-range.d.ts +20 -0
  60. package/dist/types/core/dimension.d.ts +60 -0
  61. package/dist/types/core/format.d.ts +40 -0
  62. package/dist/types/core/invariant.d.ts +2 -0
  63. package/dist/types/core/messages.d.ts +77 -0
  64. package/dist/types/core/reading.d.ts +17 -0
  65. package/dist/types/core/variables.d.ts +82 -0
  66. package/dist/types/embed/bootstrap.d.ts +5 -0
  67. package/dist/types/embed/host.d.ts +23 -0
  68. package/dist/types/embed/index.d.ts +11 -0
  69. package/dist/types/embed/navigation.d.ts +6 -0
  70. package/dist/types/embed/shell.d.ts +21 -0
  71. package/dist/types/embed/standalone.d.ts +1 -0
  72. package/dist/types/react/content.d.ts +23 -0
  73. package/dist/types/react/embed/bridge.d.ts +12 -0
  74. package/dist/types/react/embed/index.d.ts +9 -0
  75. package/dist/types/react/embed/shell.d.ts +10 -0
  76. package/dist/types/react/hooks.d.ts +831 -0
  77. package/dist/types/react/index.d.ts +11 -0
  78. package/dist/types/react/mount.d.ts +11 -0
  79. package/dist/types/react/ui/AboutData.d.ts +61 -0
  80. package/dist/types/react/ui/AltertableLogo.d.ts +3 -0
  81. package/dist/types/react/ui/AppFooter.d.ts +7 -0
  82. package/dist/types/react/ui/AppHeader.d.ts +12 -0
  83. package/dist/types/react/ui/AppLayout.d.ts +17 -0
  84. package/dist/types/react/ui/AppScope.d.ts +8 -0
  85. package/dist/types/react/ui/AppToolbar.d.ts +32 -0
  86. package/dist/types/react/ui/Breakdown.d.ts +14 -0
  87. package/dist/types/react/ui/Button.d.ts +12 -0
  88. package/dist/types/react/ui/Checkbox.d.ts +11 -0
  89. package/dist/types/react/ui/Combobox.d.ts +43 -0
  90. package/dist/types/react/ui/ComparisonVisual.d.ts +15 -0
  91. package/dist/types/react/ui/ContentSkeleton.d.ts +8 -0
  92. package/dist/types/react/ui/DataApp.d.ts +56 -0
  93. package/dist/types/react/ui/DataBoundary.d.ts +16 -0
  94. package/dist/types/react/ui/DataSection.d.ts +28 -0
  95. package/dist/types/react/ui/DataTable.d.ts +28 -0
  96. package/dist/types/react/ui/DataViewToast.d.ts +12 -0
  97. package/dist/types/react/ui/DataWidget.d.ts +39 -0
  98. package/dist/types/react/ui/DateRangePicker.d.ts +29 -0
  99. package/dist/types/react/ui/DateTimeTooltip.d.ts +10 -0
  100. package/dist/types/react/ui/DimensionPicker.d.ts +11 -0
  101. package/dist/types/react/ui/EmptyState.d.ts +9 -0
  102. package/dist/types/react/ui/GettingStarted.d.ts +9 -0
  103. package/dist/types/react/ui/GlossaryDefinition.d.ts +8 -0
  104. package/dist/types/react/ui/GlossaryExplanation.d.ts +17 -0
  105. package/dist/types/react/ui/GradientScroll.d.ts +16 -0
  106. package/dist/types/react/ui/Grid.d.ts +13 -0
  107. package/dist/types/react/ui/GridItem.d.ts +7 -0
  108. package/dist/types/react/ui/HelpPopover.d.ts +24 -0
  109. package/dist/types/react/ui/IconButton.d.ts +19 -0
  110. package/dist/types/react/ui/InspectionContext.d.ts +10 -0
  111. package/dist/types/react/ui/Kbd.d.ts +8 -0
  112. package/dist/types/react/ui/LiveControl.d.ts +11 -0
  113. package/dist/types/react/ui/MetricWidget.d.ts +48 -0
  114. package/dist/types/react/ui/PeriodSummary.d.ts +17 -0
  115. package/dist/types/react/ui/PresentStory.d.ts +34 -0
  116. package/dist/types/react/ui/QueryList.d.ts +15 -0
  117. package/dist/types/react/ui/Ranking.d.ts +14 -0
  118. package/dist/types/react/ui/RefreshControl.d.ts +11 -0
  119. package/dist/types/react/ui/RefreshRegion.d.ts +10 -0
  120. package/dist/types/react/ui/RequestHint.d.ts +21 -0
  121. package/dist/types/react/ui/SearchField.d.ts +23 -0
  122. package/dist/types/react/ui/SearchInput.d.ts +9 -0
  123. package/dist/types/react/ui/SearchMatch.d.ts +7 -0
  124. package/dist/types/react/ui/SelectableBarChart.d.ts +16 -0
  125. package/dist/types/react/ui/SelectionMark.d.ts +5 -0
  126. package/dist/types/react/ui/Sheet.d.ts +19 -0
  127. package/dist/types/react/ui/Skeleton.d.ts +6 -0
  128. package/dist/types/react/ui/Stack.d.ts +8 -0
  129. package/dist/types/react/ui/StatusPanel.d.ts +11 -0
  130. package/dist/types/react/ui/TableWidget.d.ts +57 -0
  131. package/dist/types/react/ui/Tabs.d.ts +6 -0
  132. package/dist/types/react/ui/ThemeSelector.d.ts +13 -0
  133. package/dist/types/react/ui/Tooltip.d.ts +23 -0
  134. package/dist/types/react/ui/UpdatedAt.d.ts +10 -0
  135. package/dist/types/react/ui/VariableBar.d.ts +7 -0
  136. package/dist/types/react/ui/VisualizationWidget.d.ts +52 -0
  137. package/dist/types/react/ui/WidgetDisclosure.d.ts +7 -0
  138. package/dist/types/react/ui/WidgetEvidence.d.ts +12 -0
  139. package/dist/types/react/ui/WidgetViewTabs.d.ts +17 -0
  140. package/dist/types/react/ui/chartColor.d.ts +1 -0
  141. package/dist/types/react/ui/classNames.d.ts +1 -0
  142. package/dist/types/react/ui/comparison.d.ts +30 -0
  143. package/dist/types/react/ui/data-context.d.ts +65 -0
  144. package/dist/types/react/ui/data-identifiers.d.ts +33 -0
  145. package/dist/types/react/ui/icons.d.ts +42 -0
  146. package/dist/types/react/ui/index.d.ts +129 -0
  147. package/dist/types/react/ui/metric.d.ts +11 -0
  148. package/dist/types/react/ui/search.d.ts +6 -0
  149. package/dist/types/react/ui/searchItems.d.ts +34 -0
  150. package/dist/types/react/ui/shortcuts.d.ts +32 -0
  151. package/dist/types/react/ui/story.d.ts +20 -0
  152. package/dist/types/react/ui/variables.d.ts +36 -0
  153. package/dist/types/react/ui/widget-views.d.ts +3 -0
  154. package/dist/types/react/view-controls.d.ts +17 -0
  155. package/dist/types/react/view.d.ts +49 -0
  156. package/dist/types/server/handler.d.ts +13 -0
  157. package/dist/types/server/index.d.ts +7 -0
  158. package/dist/types/server/local.d.ts +17 -0
  159. package/docs/app-authoring.md +26 -0
  160. package/docs/appearance.md +30 -0
  161. package/docs/bootstrap.md +76 -0
  162. package/docs/client.md +127 -0
  163. package/docs/config.md +21 -0
  164. package/docs/contract.md +95 -0
  165. package/docs/embed.md +98 -0
  166. package/docs/format.md +29 -0
  167. package/docs/react-embed.md +57 -0
  168. package/docs/react-styles.md +17 -0
  169. package/docs/react.md +248 -0
  170. package/docs/releasing.md +74 -0
  171. package/docs/server-bun.md +26 -0
  172. package/docs/server.md +47 -0
  173. package/docs/starter-agent-instructions.md +51 -0
  174. package/package.json +124 -0
package/AGENTS.md ADDED
@@ -0,0 +1,35 @@
1
+ # @altertable/data-app
2
+
3
+ ## Build an app with this package
4
+
5
+ Start with [app authoring](docs/app-authoring.md) for the data flow and ownership
6
+ boundaries. Read the documentation for the entry you use:
7
+
8
+ | Task | Documentation |
9
+ | -------------------------------- | ------------------------------------------------------------------ |
10
+ | Define operations and inputs | [Contract](docs/contract.md) |
11
+ | Call operations from the browser | [Client](docs/client.md) |
12
+ | Authorize and execute requests | [Server](docs/server.md) |
13
+ | Serve locally with Bun | [Bun server](docs/server-bun.md) |
14
+ | Compose views and request states | [React](docs/react.md), [stylesheet](docs/react-styles.md) |
15
+ | Embed apps in a host | [Embedding](docs/embed.md), [React embedding](docs/react-embed.md) |
16
+ | Serve a trusted bootstrap | [Standalone bootstrap](docs/bootstrap.md) |
17
+ | Configure identity and theme | [Config](docs/config.md), [appearance](docs/appearance.md) |
18
+ | Format values | [Format](docs/format.md) |
19
+
20
+ Import public package entries. Keep SQL, credentials, and execution on the server;
21
+ use `import type` for operation types in browser code. Import the React stylesheet
22
+ once in the browser entry. Edit app-owned files, not installed package files.
23
+
24
+ Inspect source data and time coverage before choosing an exploration. Build
25
+ findings from observed results and preserve loading, empty, error, and stale
26
+ states. The consuming app's instructions define its paths, commands, and analysis
27
+ context; the [starter template](docs/starter-agent-instructions.md) shows how to
28
+ connect them to this guide.
29
+
30
+ ## Contribute to the package source
31
+
32
+ When working in this package's source repository, read
33
+ [Contributing](CONTRIBUTING.md) for setup, architecture, and checks. Update docs
34
+ when changing public APIs and run `bun run check` before committing. Do not edit
35
+ generated `dist` files.
@@ -0,0 +1,83 @@
1
+ # Contributing
2
+
3
+ Install the versions of Bun and Node.js in `.bun-version` and `.node-version`.
4
+ Node supplies npm for the packed-package check; Bun runs the build, tools, and tests.
5
+ `bunfig.toml` sets `install.exact = true` so newly added dependencies use exact
6
+ versions. Keep `packageManager` aligned with `.bun-version`.
7
+
8
+ ```fish
9
+ bun install --frozen-lockfile
10
+ bun run check
11
+ ```
12
+
13
+ ## Repository layout
14
+
15
+ `src/core` holds shared contracts and data logic. `src/client` owns Fetch transport,
16
+ `src/embed` owns iframe hosting and trusted bootstrap initialization.
17
+ `src/server` owns request handling and the local Bun adapter, and `src/react` owns
18
+ React bindings; `src/react/embed` provides hosts without app UI dependencies.
19
+ Components and their styles live together in `src/react/ui`.
20
+ `docs` describes each public entry. `scripts` builds and checks the published
21
+ artifact. Workflow validation lives in `scripts/check-workflows.sh`, and release
22
+ helpers live in `scripts/release`. Generated `dist` files are ignored; edit source
23
+ instead.
24
+
25
+ `src/embed/standalone.ts` emits `dist/bootstrap.js` as a self-contained classic
26
+ script for backend HTML. It reads its trusted parent origin from the script
27
+ element; keep app navigation and UI dependencies out of this artifact.
28
+
29
+ Keep core, client, server, and embed free of React and UI imports. Client and
30
+ server may depend on core; neither may import the other. Embed may depend on core
31
+ and client. Browser code must not import server
32
+ implementations or credentials. React implementations import focused modules,
33
+ not their own public barrel. Preserve the explicit stylesheet export. Public
34
+ exports and their docs are the consumer interface; internal modules may change.
35
+
36
+ Use repository-root imports (`@/src/...`, `@/package.json`) in source, tests, and
37
+ scripts. Oxlint rejects relative imports and requires declarations for named
38
+ functions (`func-style`). Use method shorthand for object behavior; retain arrows for inline
39
+ callbacks such as collection transforms and hooks. Leave blank lines around
40
+ function declarations, effect hooks, and before returns. Use `useReducer(value =>
41
+ value + 1, 0)` with a `bump…` dispatcher for increment-only counters rather than
42
+ state setters. Run `bun run lint:fix` and `bun run format` for automated fixes.
43
+ The declaration build rewrites aliases to portable relative imports for npm
44
+ consumers.
45
+
46
+ ## Checks
47
+
48
+ | Command | Purpose |
49
+ | ------------------------- | ------------------------------------------------ |
50
+ | `bun run typecheck` | Validate source, tests, and scripts |
51
+ | `bun run lint` | Run type-aware Oxlint checks |
52
+ | `bun run format` | Format source and documentation with Oxfmt |
53
+ | `bun run test` | Run contract, transport, and component tests |
54
+ | `bun run build` | Emit ESM, declarations, and the React stylesheet |
55
+ | `bun run test:package` | Check the built npm archive as a consumer |
56
+ | `bun run test:browser` | Test embedding against built exports in Chromium |
57
+ | `bun run check:workflows` | Validate workflows and shell scripts |
58
+ | `bun run check` | Run all required checks |
59
+
60
+ Add focused tests for changed behavior and update the corresponding entry docs
61
+ when changing public APIs. JSDoc should explain constraints, ownership, units,
62
+ or runtime boundaries without duplicating the full API guide. The packed-package
63
+ check verifies documentation, exports, declarations, browser CSS, and server
64
+ imports. The package retains the
65
+ runtime's Bun test suite; tests use observable output and contract behavior.
66
+
67
+ Use Conventional Commits (`fix:`, `feat:`, `docs:`) and describe behavior changes
68
+ and verification in pull requests. PR titles are checked against these types.
69
+ Flag breaking API changes explicitly.
70
+
71
+ Build the package, then run `bash scripts/install-test-browser.sh` once and
72
+ `bun run test:browser` for iframe work. Browser fixtures import public built
73
+ exports; the bootstrap uses the published standalone asset and app scripts are
74
+ bundled independently.
75
+
76
+ CI runs source and packed-package checks, validates workflow syntax, reviews
77
+ dependency changes, and analyzes JavaScript and TypeScript with CodeQL.
78
+ Dependabot updates Bun dependencies and GitHub Actions weekly. Release Please
79
+ creates version and changelog PRs; merging a release PR publishes the verified
80
+ release tag to npm. See [Releasing](docs/releasing.md) for setup and recovery.
81
+
82
+ App-authoring instructions belong to a consuming app's `AGENTS.md`; see the
83
+ [starter template](docs/starter-agent-instructions.md).
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) Altertable
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,63 @@
1
+ # Altertable Data App
2
+
3
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](./LICENSE)
4
+
5
+ TypeScript contracts, a data client, server handlers, and React UI for building
6
+ interactive apps with Altertable data.
7
+
8
+ ## Installation
9
+
10
+ ```fish
11
+ # npm
12
+ npm install @altertable/data-app
13
+
14
+ # pnpm
15
+ pnpm add @altertable/data-app
16
+
17
+ # Bun
18
+ bun add @altertable/data-app
19
+ ```
20
+
21
+ For React apps, also install React 19.2 or newer and React DOM 19.2 or newer, then import the stylesheet
22
+ once in your browser entry:
23
+
24
+ ```tsx
25
+ import '@altertable/data-app/react/styles.css';
26
+ import { mountDataApp } from '@altertable/data-app/react';
27
+ ```
28
+
29
+ ## Documentation
30
+
31
+ | Entry | Use |
32
+ | ----------------------------------------- | ----------------------------------------------------- |
33
+ | [/contract](docs/contract.md) | Define typed operations, parsers, and date ranges |
34
+ | [/client](docs/client.md) | Call server operations with `fetch` |
35
+ | [/server](docs/server.md) | Authorize and execute requests on a hosted server |
36
+ | [/server/bun](docs/server-bun.md) | Serve an app locally with Bun |
37
+ | [/embed](docs/embed.md) | Host URL apps or sandboxed JavaScript bundles |
38
+ | [/bootstrap](docs/bootstrap.md) | Embed the standalone bootstrap script in backend HTML |
39
+ | [/react/embed](docs/react-embed.md) | Embed apps with React shells and bridges |
40
+ | [/react](docs/react.md) | Compose views, filters, widgets, and request states |
41
+ | [/react/styles.css](docs/react-styles.md) | Load the React UI stylesheet |
42
+ | [/config](docs/config.md) | Define app identity and scope |
43
+ | [/appearance](docs/appearance.md) | Configure brand tokens and viewer theme |
44
+ | [/format](docs/format.md) | Format dates, counts, ratios, and currencies |
45
+
46
+ Start with [app authoring](docs/app-authoring.md) for the complete data flow.
47
+ The package ships these docs alongside its built JavaScript and declarations.
48
+ For agent-assisted work, direct your agent to
49
+ `node_modules/@altertable/data-app/AGENTS.md`.
50
+
51
+ ## Development
52
+
53
+ ```fish
54
+ bun install --frozen-lockfile
55
+ bun run check
56
+ ```
57
+
58
+ See [Contributing](CONTRIBUTING.md) for repository structure and focused checks.
59
+ Releases use [Release Please and npm trusted publishing](docs/releasing.md).
60
+
61
+ ## License
62
+
63
+ [MIT](LICENSE)
@@ -0,0 +1,388 @@
1
+ (() => {
2
+ // src/core/bridge.ts
3
+ var BRIDGE = "altertable:data-app";
4
+ var MAX_PENDING = 128;
5
+ var REQUEST_TIMEOUT_MS = 60000;
6
+ function isBridgeMessage(value) {
7
+ if (!value || typeof value !== "object")
8
+ return false;
9
+ const message = value;
10
+ return message.channel === BRIDGE && message.version === 1 && typeof message.type === "string" && typeof message.documentId === "string" && message.documentId.length > 0 && message.documentId.length <= 128;
11
+ }
12
+ function validId(value) {
13
+ return typeof value === "string" && /^[a-zA-Z0-9_-]{1,128}$/.test(value);
14
+ }
15
+
16
+ // src/core/messages.ts
17
+ var errorBrand = Symbol.for("@altertable/data-app/MessageRoutingError");
18
+
19
+ class MessageRoutingError extends Error {
20
+ code;
21
+ requestId;
22
+ [errorBrand] = true;
23
+ static [Symbol.hasInstance](value) {
24
+ return value instanceof Error && value[errorBrand] === true;
25
+ }
26
+ constructor(code, message, requestId) {
27
+ super(message);
28
+ this.code = code;
29
+ this.requestId = requestId;
30
+ this.name = "MessageRoutingError";
31
+ }
32
+ }
33
+ function defineDataQueryRoute(operations) {
34
+ return {
35
+ operations,
36
+ input(value) {
37
+ if (!value || typeof value !== "object")
38
+ throw new Error("Invalid query.");
39
+ const request = value;
40
+ if (typeof request.operation !== "string" || !request.operation || request.operation.length > 256 || request.operation.includes("/"))
41
+ throw new Error("Invalid operation.");
42
+ const operation = operations && Object.hasOwn(operations, request.operation) ? operations[request.operation] : undefined;
43
+ if (operations && !operation)
44
+ throw new Error("Unknown operation.");
45
+ return {
46
+ operation: request.operation,
47
+ input: operation ? operation.input(request.input) : request.input
48
+ };
49
+ },
50
+ output(value, input) {
51
+ if (!value || typeof value !== "object")
52
+ throw new Error("Invalid data response.");
53
+ const response = value;
54
+ if (!Number.isInteger(response.status) || response.status < 100 || response.status > 599 || !response.body || typeof response.body !== "object")
55
+ throw new Error("Invalid data response.");
56
+ const body = response.body;
57
+ if (response.status < 200 || response.status >= 300) {
58
+ const failure = body.error;
59
+ throw new MessageRoutingError(typeof failure?.code === "string" ? failure.code : "request_failed", typeof failure?.message === "string" ? failure.message : "Could not load data.", typeof failure?.requestId === "string" ? failure.requestId : undefined);
60
+ }
61
+ if (!("data" in body) || typeof body.requestId !== "string" || typeof body.queriedAt !== "string" || !Array.isArray(body.queryIds) || !body.queryIds.every((id) => typeof id === "string"))
62
+ throw new Error("Invalid data envelope.");
63
+ if (body.queries !== undefined && (!Array.isArray(body.queries) || !body.queries.every((query) => query && typeof query === "object" && typeof query.name === "string" && typeof query.statement === "string" && (query.queryId === undefined || typeof query.queryId === "string"))))
64
+ throw new Error("Invalid query evidence.");
65
+ const operation = operations?.[input.operation];
66
+ return {
67
+ status: response.status,
68
+ body: {
69
+ ...body,
70
+ data: operation ? operation.output(body.data) : body.data
71
+ }
72
+ };
73
+ }
74
+ };
75
+ }
76
+
77
+ // src/client/messages.ts
78
+ function createMessageClient(routes, transport) {
79
+ return {
80
+ async request(route, payload, { signal } = {}) {
81
+ signal?.throwIfAborted();
82
+ if (!Object.hasOwn(routes, route))
83
+ throw new MessageRoutingError("unknown_route", "Unknown message route.");
84
+ const contract = routes[route];
85
+ let input;
86
+ try {
87
+ input = contract.input(payload);
88
+ } catch {
89
+ throw new MessageRoutingError("invalid_payload", "Invalid message payload.");
90
+ }
91
+ const response = await transport({ route, payload: input }, signal);
92
+ signal?.throwIfAborted();
93
+ try {
94
+ return contract.output(response, input);
95
+ } catch (error) {
96
+ if (error instanceof MessageRoutingError)
97
+ throw error;
98
+ throw new MessageRoutingError("invalid_response", "Invalid message response.");
99
+ }
100
+ }
101
+ };
102
+ }
103
+
104
+ // src/client/transport.ts
105
+ var errorBrand2 = Symbol.for("@altertable/data-app/DataAppError");
106
+
107
+ class DataAppError extends Error {
108
+ code;
109
+ requestId;
110
+ [errorBrand2] = true;
111
+ static [Symbol.hasInstance](value) {
112
+ return value instanceof Error && value[errorBrand2] === true;
113
+ }
114
+ constructor(message, code, requestId) {
115
+ super(message);
116
+ this.code = code;
117
+ this.requestId = requestId;
118
+ this.name = "DataAppError";
119
+ }
120
+ }
121
+
122
+ // src/client/iframe.ts
123
+ function createIframeTransport({
124
+ parentOrigin,
125
+ window: frame = window,
126
+ timeoutMs = REQUEST_TIMEOUT_MS,
127
+ mode = "url",
128
+ loadScript
129
+ }) {
130
+ if (new URL(parentOrigin).origin !== parentOrigin)
131
+ throw new Error("Expected an exact parent origin.");
132
+ const documentId = crypto.randomUUID();
133
+ let token;
134
+ let sessionId;
135
+ let disposed = false;
136
+ const pending = new Map;
137
+ let hostState;
138
+ const stateListeners = new Set;
139
+ function send(message) {
140
+ frame.parent.postMessage({ channel: BRIDGE, version: 1, documentId, sessionId, token, ...message }, parentOrigin);
141
+ }
142
+ function receiveState(state) {
143
+ hostState = state;
144
+ for (const listener of stateListeners)
145
+ listener(state);
146
+ }
147
+ function receive(event) {
148
+ if (event.origin !== parentOrigin || event.source !== frame.parent || !isBridgeMessage(event.data))
149
+ return;
150
+ const message = event.data;
151
+ if (message.type === "connect") {
152
+ if (mode === "bundle") {
153
+ if (!validId(message.token))
154
+ return;
155
+ token = message.token;
156
+ }
157
+ send({ type: "ready" });
158
+ return;
159
+ }
160
+ if (mode === "bundle" && (!token || message.token !== token))
161
+ return;
162
+ if (message.documentId !== documentId)
163
+ return;
164
+ if (message.type === "initialize" && validId(message.sessionId)) {
165
+ if (sessionId && sessionId !== message.sessionId) {
166
+ for (const entry of pending.values())
167
+ entry.reject(new DataAppError("The preview reconnected. Retry the request.", "bridge_reset"));
168
+ }
169
+ const first = !sessionId;
170
+ sessionId = message.sessionId;
171
+ if (first)
172
+ for (const entry of pending.values())
173
+ entry.start();
174
+ receiveState(message.state);
175
+ if (mode === "url")
176
+ send({ type: "runtime.ready" });
177
+ return;
178
+ }
179
+ if (!sessionId || message.sessionId !== sessionId)
180
+ return;
181
+ if (message.type === "state") {
182
+ receiveState(message.state);
183
+ return;
184
+ }
185
+ if (message.type === "script.load" && mode === "bundle" && typeof message.javascript === "string") {
186
+ loadScript?.(message.javascript);
187
+ return;
188
+ }
189
+ if (typeof message.id !== "string")
190
+ return;
191
+ const entry = pending.get(message.id);
192
+ if (!entry)
193
+ return;
194
+ if (message.type === "result" && "response" in message) {
195
+ entry.resolve(message.response);
196
+ } else if (message.type === "error" && typeof message.code === "string" && typeof message.message === "string") {
197
+ entry.reject(new MessageRoutingError(message.code, message.message, typeof message.requestId === "string" ? message.requestId : undefined));
198
+ }
199
+ }
200
+ frame.addEventListener("message", receive);
201
+ function requestMessage(message, signal) {
202
+ return new Promise((resolve, reject) => {
203
+ if (disposed)
204
+ return reject(new DataAppError("The preview has closed.", "bridge_closed"));
205
+ if (signal?.aborted)
206
+ return reject(signal.reason);
207
+ if (pending.size >= MAX_PENDING)
208
+ return reject(new DataAppError("Too many pending data requests.", "bridge_busy"));
209
+ const id = crypto.randomUUID();
210
+ let sent = false;
211
+ function cleanup() {
212
+ clearTimeout(timer);
213
+ signal?.removeEventListener("abort", abort);
214
+ pending.delete(id);
215
+ }
216
+ function abort() {
217
+ if (sent)
218
+ send({ type: "cancel", id });
219
+ cleanup();
220
+ reject(signal?.reason);
221
+ }
222
+ const timer = setTimeout(() => {
223
+ if (sent)
224
+ send({ type: "cancel", id });
225
+ cleanup();
226
+ reject(new DataAppError(sessionId ? "The data request timed out." : "The preview shell is unavailable. Reload the preview.", sessionId ? "timeout" : "bridge_unavailable"));
227
+ }, timeoutMs);
228
+ const entry = {
229
+ start() {
230
+ if (sent)
231
+ return;
232
+ try {
233
+ send({
234
+ type: "request",
235
+ id,
236
+ route: message.route,
237
+ payload: message.payload
238
+ });
239
+ sent = true;
240
+ } catch {
241
+ cleanup();
242
+ reject(new DataAppError("The message payload could not be sent.", "invalid_payload"));
243
+ }
244
+ },
245
+ resolve(value) {
246
+ cleanup();
247
+ resolve(value);
248
+ },
249
+ reject(error) {
250
+ cleanup();
251
+ reject(error);
252
+ }
253
+ };
254
+ pending.set(id, entry);
255
+ signal?.addEventListener("abort", abort, { once: true });
256
+ if (sessionId)
257
+ entry.start();
258
+ else
259
+ send({ type: "ready" });
260
+ });
261
+ }
262
+ const messages = createMessageClient({ "data.query": defineDataQueryRoute() }, requestMessage);
263
+ async function queryData(operation, input, signal) {
264
+ try {
265
+ return await messages.request("data.query", { operation, input }, { signal });
266
+ } catch (error) {
267
+ if (error instanceof MessageRoutingError)
268
+ throw new DataAppError(error.message, error.code, error.requestId);
269
+ throw error;
270
+ }
271
+ }
272
+ function disconnect() {
273
+ send({ type: "disconnect" });
274
+ sessionId = undefined;
275
+ for (const entry of pending.values())
276
+ entry.reject(new DataAppError("The preview has closed.", "bridge_closed"));
277
+ }
278
+ function resume(event) {
279
+ if (event.persisted)
280
+ send({ type: "ready" });
281
+ }
282
+ function dispose() {
283
+ if (disposed)
284
+ return;
285
+ disconnect();
286
+ disposed = true;
287
+ frame.removeEventListener("message", receive);
288
+ frame.removeEventListener("pagehide", disconnect);
289
+ frame.removeEventListener("pageshow", resume);
290
+ stateListeners.clear();
291
+ }
292
+ frame.addEventListener("pagehide", disconnect);
293
+ frame.addEventListener("pageshow", resume);
294
+ if (mode === "url")
295
+ send({ type: "ready" });
296
+ return {
297
+ request: requestMessage,
298
+ transport: queryData,
299
+ dispose,
300
+ mode,
301
+ snapshot() {
302
+ return hostState;
303
+ },
304
+ subscribe(listener) {
305
+ stateListeners.add(listener);
306
+ return () => {
307
+ stateListeners.delete(listener);
308
+ };
309
+ },
310
+ ready() {
311
+ send({ type: "runtime.ready" });
312
+ },
313
+ fail() {
314
+ send({ type: "runtime.error" });
315
+ }
316
+ };
317
+ }
318
+ var bridgeKey = Symbol.for("altertable.localFrameBridge");
319
+ var installedKey = Symbol.for("altertable.installedTransport");
320
+ function installDataAppTransport(bridge, frame = window) {
321
+ const target = frame;
322
+ if (target[installedKey])
323
+ throw new Error("A data app transport is already installed.");
324
+ target[bridgeKey] = bridge;
325
+ target[installedKey] = bridge;
326
+ return () => {
327
+ if (target[bridgeKey] === bridge)
328
+ delete target[bridgeKey];
329
+ if (target[installedKey] === bridge)
330
+ delete target[installedKey];
331
+ bridge.dispose();
332
+ };
333
+ }
334
+
335
+ // src/embed/bootstrap.ts
336
+ function startDataAppBootstrap({
337
+ parentOrigin,
338
+ window: frame = window
339
+ }) {
340
+ let loaded;
341
+ let failed = false;
342
+ const bridge = createIframeTransport({
343
+ parentOrigin,
344
+ window: frame,
345
+ mode: "bundle",
346
+ loadScript(javascript) {
347
+ if (loaded !== undefined) {
348
+ if (javascript === loaded) {
349
+ if (failed)
350
+ bridge.fail();
351
+ else
352
+ bridge.ready();
353
+ } else
354
+ bridge.fail();
355
+ return;
356
+ }
357
+ loaded = javascript;
358
+ try {
359
+ const script = frame.document.createElement("script");
360
+ script.textContent = javascript;
361
+ frame.document.body.append(script);
362
+ if (!failed)
363
+ bridge.ready();
364
+ } catch {
365
+ reportError();
366
+ }
367
+ }
368
+ });
369
+ function reportError() {
370
+ failed = true;
371
+ bridge.fail();
372
+ }
373
+ frame.addEventListener("error", reportError);
374
+ frame.addEventListener("unhandledrejection", reportError);
375
+ const uninstall = installDataAppTransport(bridge, frame);
376
+ return () => {
377
+ frame.removeEventListener("error", reportError);
378
+ frame.removeEventListener("unhandledrejection", reportError);
379
+ uninstall();
380
+ };
381
+ }
382
+
383
+ // src/embed/standalone.ts
384
+ var parentOrigin = document.currentScript?.dataset.parentOrigin;
385
+ if (!parentOrigin)
386
+ throw new Error("Missing trusted parent origin.");
387
+ startDataAppBootstrap({ parentOrigin });
388
+ })();