@altertable/data-app 0.65.0 → 0.67.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (202) hide show
  1. package/AGENTS.md +38 -1
  2. package/CONTRIBUTING.md +54 -14
  3. package/README.md +1 -1
  4. package/dist/chunks/index-23dktynd.js +80 -0
  5. package/dist/chunks/index-23dktynd.js.map +10 -0
  6. package/dist/chunks/index-8qfxv0h5.js +14160 -0
  7. package/dist/chunks/index-8qfxv0h5.js.map +108 -0
  8. package/dist/chunks/index-ag0cgnvq.js +639 -0
  9. package/dist/chunks/index-ag0cgnvq.js.map +13 -0
  10. package/dist/chunks/index-dq7b35fn.js +307 -0
  11. package/dist/chunks/index-dq7b35fn.js.map +13 -0
  12. package/dist/chunks/{contract-a061yj6r.js → index-ev2b5aaf.js} +41 -72
  13. package/dist/chunks/index-ev2b5aaf.js.map +12 -0
  14. package/dist/chunks/{contract-awa2d5b1.js → index-f5cnbrjz.js} +19 -2
  15. package/dist/chunks/{contract-awa2d5b1.js.map → index-f5cnbrjz.js.map} +4 -3
  16. package/dist/chunks/{contract-sm7j7k95.js → index-ktmvs916.js} +9 -150
  17. package/dist/chunks/index-ktmvs916.js.map +13 -0
  18. package/dist/chunks/{contract-txjy0en2.js → index-m6n8ctfc.js} +64 -72
  19. package/dist/chunks/index-m6n8ctfc.js.map +10 -0
  20. package/dist/chunks/index-mt93ff2b.js +28 -0
  21. package/dist/chunks/index-mt93ff2b.js.map +10 -0
  22. package/dist/chunks/{contract-tf8c3qpv.js → index-qd5xgx6y.js} +46 -5
  23. package/dist/chunks/index-qd5xgx6y.js.map +13 -0
  24. package/dist/chunks/index-x69p7cv7.js +149 -0
  25. package/dist/chunks/index-x69p7cv7.js.map +10 -0
  26. package/dist/client/index.js +12 -7
  27. package/dist/client/index.js.map +1 -1
  28. package/dist/core/appearance.js +1 -1
  29. package/dist/core/config.js +7 -3
  30. package/dist/core/config.js.map +1 -1
  31. package/dist/core/contract.js +24 -6
  32. package/dist/core/contract.js.map +1 -1
  33. package/dist/core/format.js +1 -1
  34. package/dist/embed/index.js +16 -12
  35. package/dist/embed/index.js.map +4 -4
  36. package/dist/index.js +12 -0
  37. package/dist/index.js.map +9 -0
  38. package/dist/local.js +20 -30
  39. package/dist/local.js.map +7 -8
  40. package/dist/react/embed/index.js +1 -1
  41. package/dist/react/embed/index.js.map +2 -2
  42. package/dist/react/index.js +2567 -11542
  43. package/dist/react/index.js.map +16 -91
  44. package/dist/react/ui/index.js +2272 -0
  45. package/dist/react/ui/index.js.map +28 -0
  46. package/dist/server.js +13 -26
  47. package/dist/server.js.map +6 -7
  48. package/dist/types/client/annotations.d.ts +27 -0
  49. package/dist/types/client/data-client.d.ts +1 -2
  50. package/dist/types/client/iframe.d.ts +4 -2
  51. package/dist/types/client/index.d.ts +1 -0
  52. package/dist/types/core/annotations.d.ts +94 -0
  53. package/dist/types/core/appearance.d.ts +2 -2
  54. package/dist/types/core/config.d.ts +48 -4
  55. package/dist/types/core/contract.d.ts +21 -11
  56. package/dist/types/core/dimension.d.ts +6 -4
  57. package/dist/types/core/filters.d.ts +44 -0
  58. package/dist/types/core/messages.d.ts +2 -0
  59. package/dist/types/core/operation-types.d.ts +5 -2
  60. package/dist/types/core/operation.d.ts +3 -4
  61. package/dist/types/core/presentation.d.ts +2 -0
  62. package/dist/types/core/queries.d.ts +16 -0
  63. package/dist/types/core/uuid.d.ts +2 -0
  64. package/dist/types/core/variables.d.ts +34 -18
  65. package/dist/types/embed/runtime-html.d.ts +2 -0
  66. package/dist/types/embed/source.d.ts +2 -1
  67. package/dist/types/index.d.ts +3 -0
  68. package/dist/types/react/annotations/AnnotationBar.d.ts +30 -0
  69. package/dist/types/react/annotations/AnnotationControls.d.ts +10 -0
  70. package/dist/types/react/annotations/AnnotationEditor.d.ts +16 -0
  71. package/dist/types/react/annotations/AnnotationMarkers.d.ts +19 -0
  72. package/dist/types/react/annotations/AnnotationSelectionLayer.d.ts +12 -0
  73. package/dist/types/react/annotations/AnnotationTarget.d.ts +9 -0
  74. package/dist/types/react/annotations/AnnotationTooltip.d.ts +9 -0
  75. package/dist/types/react/annotations/AnnotationTrigger.d.ts +10 -0
  76. package/dist/types/react/annotations/annotation-editor-state.d.ts +56 -0
  77. package/dist/types/react/annotations/annotation-screenshot.d.ts +4 -0
  78. package/dist/types/react/annotations/annotation-targets.d.ts +33 -0
  79. package/dist/types/react/annotations/getAnnotationProps.d.ts +15 -0
  80. package/dist/types/react/annotations/styles.d.ts +3 -0
  81. package/dist/types/react/annotations/useAnnotationGeometry.d.ts +22 -0
  82. package/dist/types/react/annotations/useDataAppAnnotations.d.ts +22 -0
  83. package/dist/types/react/app-context.d.ts +3 -0
  84. package/dist/types/react/bindings.d.ts +110 -0
  85. package/dist/types/react/content.d.ts +24 -11
  86. package/dist/types/react/hooks.d.ts +29 -787
  87. package/dist/types/react/index.d.ts +31 -106
  88. package/dist/types/react/mount.d.ts +6 -4
  89. package/dist/types/react/source-owner.d.ts +2 -0
  90. package/dist/types/react/style-contract.d.ts +80 -0
  91. package/dist/types/react/style-validation.d.ts +2 -0
  92. package/dist/types/react/ui/AboutData.d.ts +9 -1
  93. package/dist/types/react/ui/AppHeader.d.ts +1 -2
  94. package/dist/types/react/ui/AppLayout.d.ts +3 -9
  95. package/dist/types/react/ui/AppToolbar.d.ts +5 -8
  96. package/dist/types/react/ui/AreaChart.d.ts +7 -0
  97. package/dist/types/react/ui/BarChart.d.ts +6 -0
  98. package/dist/types/react/ui/Button.d.ts +3 -3
  99. package/dist/types/react/ui/ChartLegend.d.ts +31 -0
  100. package/dist/types/react/ui/Checkbox.d.ts +15 -4
  101. package/dist/types/react/ui/CheckboxGroup.d.ts +7 -0
  102. package/dist/types/react/ui/{Combobox.d.ts → ChoicePicker.d.ts} +10 -15
  103. package/dist/types/react/ui/{ComparisonVisual.d.ts → Comparison.d.ts} +3 -3
  104. package/dist/types/react/ui/ComposedChart.d.ts +41 -0
  105. package/dist/types/react/ui/ComposedChartLegend.d.ts +8 -0
  106. package/dist/types/react/ui/ContentSkeleton.d.ts +2 -0
  107. package/dist/types/react/ui/DataApp.d.ts +17 -58
  108. package/dist/types/react/ui/DataAppFrame.d.ts +41 -0
  109. package/dist/types/react/ui/DataBoundary.d.ts +4 -5
  110. package/dist/types/react/ui/DataSection.d.ts +6 -18
  111. package/dist/types/react/ui/DataSectionBoundary.d.ts +30 -0
  112. package/dist/types/react/ui/DataValue.d.ts +9 -0
  113. package/dist/types/react/ui/DataWidget.d.ts +2 -1
  114. package/dist/types/react/ui/DateTimeTooltip.d.ts +1 -1
  115. package/dist/types/react/ui/DimensionPicker.d.ts +1 -1
  116. package/dist/types/react/ui/ExportControl.d.ts +1 -1
  117. package/dist/types/react/ui/FilterActions.d.ts +10 -0
  118. package/dist/types/react/ui/FilterBar.d.ts +3 -0
  119. package/dist/types/react/ui/GettingStarted.d.ts +2 -4
  120. package/dist/types/react/ui/HelpPopover.d.ts +3 -4
  121. package/dist/types/react/ui/InspectionContext.d.ts +2 -0
  122. package/dist/types/react/ui/InspectionProvider.d.ts +29 -0
  123. package/dist/types/react/ui/LineChart.d.ts +7 -0
  124. package/dist/types/react/ui/Menu.d.ts +12 -0
  125. package/dist/types/react/ui/MetricWidget.d.ts +4 -3
  126. package/dist/types/react/ui/NumberField.d.ts +27 -0
  127. package/dist/types/react/ui/NumberFilterPicker.d.ts +9 -0
  128. package/dist/types/react/ui/PieChart.d.ts +11 -0
  129. package/dist/types/react/ui/PresentStory.d.ts +2 -5
  130. package/dist/types/react/ui/RadioGroup.d.ts +18 -0
  131. package/dist/types/react/ui/RefreshControl.d.ts +1 -2
  132. package/dist/types/react/ui/ScatterChart.d.ts +17 -0
  133. package/dist/types/react/ui/SearchField.d.ts +1 -2
  134. package/dist/types/react/ui/SearchInput.d.ts +3 -1
  135. package/dist/types/react/ui/Select.d.ts +14 -0
  136. package/dist/types/react/ui/SelectionMark.d.ts +2 -1
  137. package/dist/types/react/ui/Sheet.d.ts +2 -1
  138. package/dist/types/react/ui/Skeleton.d.ts +5 -2
  139. package/dist/types/react/ui/StaticDataApp.d.ts +4 -0
  140. package/dist/types/react/ui/TableWidget.d.ts +19 -16
  141. package/dist/types/react/ui/Tabs.d.ts +6 -2
  142. package/dist/types/react/ui/TextWidget.d.ts +2 -1
  143. package/dist/types/react/ui/Tooltip.d.ts +4 -3
  144. package/dist/types/react/ui/TooltipSurface.d.ts +3 -0
  145. package/dist/types/react/ui/TrendChart.d.ts +5 -0
  146. package/dist/types/react/ui/UpdatedAt.d.ts +1 -1
  147. package/dist/types/react/ui/VisualizationWidget.d.ts +12 -13
  148. package/dist/types/react/ui/WidgetViewTabs.d.ts +1 -1
  149. package/dist/types/react/ui/chart-data.d.ts +25 -0
  150. package/dist/types/react/ui/chart-primitives.d.ts +20 -0
  151. package/dist/types/react/ui/data-context.d.ts +18 -7
  152. package/dist/types/react/ui/icons.d.ts +2 -0
  153. package/dist/types/react/ui/index.d.ts +98 -0
  154. package/dist/types/react/ui/keyboard.d.ts +6 -0
  155. package/dist/types/react/ui/metric.d.ts +1 -1
  156. package/dist/types/react/ui/presentation.d.ts +5 -1
  157. package/dist/types/react/ui/shortcuts.d.ts +14 -1
  158. package/dist/types/react/ui/useAppAppearance.d.ts +1 -1
  159. package/dist/types/react/ui/variables.d.ts +4 -2
  160. package/dist/types/react/view-controls.d.ts +3 -1
  161. package/dist/types/react/view-runtime.d.ts +29 -0
  162. package/dist/types/react/view.d.ts +21 -4
  163. package/dist/types/react/widgets.d.ts +79 -0
  164. package/dist/types/server/handler.d.ts +4 -4
  165. package/dist/worker.js +20 -737
  166. package/docs/app-authoring.md +72 -50
  167. package/docs/client.md +8 -8
  168. package/docs/contract.md +42 -20
  169. package/docs/data-context.md +91 -0
  170. package/docs/embed.md +10 -2
  171. package/docs/formatting-and-appearance.md +68 -0
  172. package/docs/hosted-apps.md +9 -15
  173. package/docs/layout.md +5 -3
  174. package/docs/react-embed.md +5 -4
  175. package/docs/react.md +22 -317
  176. package/docs/server-bun.md +1 -1
  177. package/docs/server.md +4 -4
  178. package/docs/stories-and-export.md +52 -0
  179. package/docs/styling.md +62 -0
  180. package/docs/ui-quality.md +20 -0
  181. package/docs/ui.md +196 -0
  182. package/docs/variables.md +171 -0
  183. package/docs/views.md +123 -0
  184. package/docs/widgets.md +145 -0
  185. package/examples/starter-data-app/index.tsx +115 -86
  186. package/package.json +25 -12
  187. package/dist/chunks/contract-a061yj6r.js.map +0 -12
  188. package/dist/chunks/contract-g6hky7x6.js +0 -282
  189. package/dist/chunks/contract-g6hky7x6.js.map +0 -12
  190. package/dist/chunks/contract-sm7j7k95.js.map +0 -14
  191. package/dist/chunks/contract-tf8c3qpv.js.map +0 -11
  192. package/dist/chunks/contract-txjy0en2.js.map +0 -10
  193. package/dist/chunks/contract-wz59z8pq.js +0 -8
  194. package/dist/chunks/contract-wz59z8pq.js.map +0 -10
  195. package/dist/chunks/contract-yxbjea23.js +0 -328
  196. package/dist/chunks/contract-yxbjea23.js.map +0 -12
  197. package/dist/types/react/ui/RefreshRegion.d.ts +0 -9
  198. package/dist/types/react/ui/SelectableBarChart.d.ts +0 -15
  199. package/docs/releasing.md +0 -79
  200. /package/dist/chunks/{contract-mev09s5v.js → index-mev09s5v.js} +0 -0
  201. /package/dist/chunks/{contract-mev09s5v.js.map → index-mev09s5v.js.map} +0 -0
  202. /package/dist/types/react/ui/{comparison.d.ts → metric-comparison.d.ts} +0 -0
@@ -7,6 +7,13 @@ queries, definitions, and evidence.
7
7
 
8
8
  ## Inspect the data
9
9
 
10
+ Declare the query source of truth with `defineDataApp()`. Generate
11
+ operations with `dataApp.defineOperation()` and execute queries by
12
+ name with parameter values. When a query registry is supplied, use only its queries
13
+ and preserve its SQL. Otherwise, inspect the data and declare the queries the app needs.
14
+ Derive displays, exports, and findings from their results. See
15
+ [named queries](contract.md#execute-named-queries).
16
+
10
17
  Inspect the relevant catalogs, tables, and fields, their time coverage, and
11
18
  existing definitions. Choose a question the available data can answer.
12
19
 
@@ -21,69 +28,84 @@ Choose the execution path:
21
28
 
22
29
  Lead with a supported finding and expose the relevant fields as filter variables. Use a date filter for questions worth exploring over time,
23
30
  or a fixed period snapshot for a deliberate historical analysis.
31
+
32
+ Use relevant user-controlled query parameters as app filters. Map filter values to
33
+ declared parameters through operation inputs, and reuse query defaults when they
34
+ match the initial selection. One filter may supply several parameters, such as a
35
+ date range supplying `start` and `end`. Keep protected parameters, such as `orgId`,
36
+ and internal execution settings out of filter controls.
37
+
24
38
  Register inspected tables and fields with `defineDataIdentifiers()` and use
25
39
  `<DataIdentifier>` when naming sources. Register terms and query evidence so
26
40
  readers can inspect the source of each claim.
27
41
 
28
42
  Connect visualizations with introductions and explanations. Use `<TextWidget>`
29
43
  for a narrative panel with the standard widget frame, or `<TextContent>` for
30
- borderless prose. Bind claims to `result.select((data, input) => ...)` so their
31
- values and scope follow the displayed results through filter changes, refresh,
32
- and failure.
33
-
34
- | Task | Documentation |
35
- | ------------------------------------------ | ---------------------------------------------------------- |
36
- | Define queries, inputs, and result parsing | [Operations](contract.md) |
37
- | Build views, filters, and request states | [React](react.md) |
38
- | Introduce and explain visualizations | [Narrative text](react.md#narrative-text) |
39
- | Find formatters and presentation helpers | [App helpers](react.md#reuse-app-helpers) |
40
- | Register source names | [Source identifiers](react.md#register-source-identifiers) |
41
- | Choose date and field filters | [Filter variables](react.md#time-views-and-field-filters) |
42
- | Handle refresh and stale results | [Displayed results](react.md#preserve-displayed-results) |
43
- | Export displayed data as CSV | [CSV export](react.md#export-displayed-data-as-csv) |
44
- | Bind definitions and source evidence | [Data context](react.md#bind-evidence) |
45
-
46
- Use the exported types for configuration, appearance, formatting, and component
47
- options. Declare configuration with `satisfies DataAppConfig` so appearance
48
- fields and values are checked before bundling.
49
-
50
- ## Compose the layout
51
-
52
- See the [layout contract](layout.md).
53
-
54
- ## Export the displayed results
55
-
56
- Provide `DataApp.csvExport` in every analytical app. The request-backed API
57
- requires a callback that selects an explicit filename and named datasets with ordered columns and raw
58
- rows from the displayed snapshot. Follow [CSV export](react.md#export-displayed-data-as-csv)
59
- and the [starter](../examples/starter-data-app/index.tsx); use the built-in toolbar
60
- action rather than adding a custom download button.
61
-
62
- Export every distinct analytical dataset at its displayed grain, including relevant
63
- dimensions and measures. Reuse one dataset for charts or metrics derived from the
64
- same rows. One dataset downloads as CSV; multiple datasets offer individual CSVs
65
- and **Export all** as a ZIP archive. Use the displayed input for scope labels and filenames. Export the
66
- bounded result the app already has; do not issue a different query or mix pending
67
- filters into the visible result. Setup and static screens may omit export.
68
-
69
- ## Present the findings
70
-
71
- Compose a [story](react.md#present-data-with-stories) from the exploration's
72
- findings. Lead with the answer, then show the evidence and comparisons that
73
- explain it. Select the findings that matter to the audience; do not turn every
74
- row or chart into a step.
44
+ borderless prose. Render the app title, description, and instructions immediately. Use metric and dataset
45
+ bindings for dynamic values and `<DataValue>` for values within static prose.
46
+ Skeletonize only the content that needs data. Reuse bindings and the displayed
47
+ source in narrative so values, formatting, and evidence follow filter changes,
48
+ refresh, and failure.
49
+
50
+ | Task | Documentation |
51
+ | ------------------------------------------------ | ----------------------------------------------------------------- |
52
+ | Choose components, CSS tokens, and styling hooks | [Styling](styling.md) |
53
+ | Define queries, inputs, and result parsing | [Operations](contract.md) |
54
+ | Build views, filters, and request states | [Views](views.md) |
55
+ | Introduce and explain visualizations | [Narrative text](widgets.md#narrative-text) |
56
+ | Find formatters and presentation helpers | [App helpers](formatting-and-appearance.md) |
57
+ | Register source names | [Source identifiers](data-context.md#register-source-identifiers) |
58
+ | Choose date and field filters | [Filter variables](variables.md) |
59
+ | Handle refresh and stale results | [Displayed results](views.md#preserve-displayed-results) |
60
+ | Export displayed data as CSV | [CSV export](stories-and-export.md#export-displayed-data-as-csv) |
61
+ | Render widgets and custom visuals | [Widgets](widgets.md) |
62
+ | Bind definitions and source evidence | [Data context](data-context.md#bind-evidence) |
63
+
64
+ Declare reusable [datasets and metrics](widgets.md#declare-datasets-and-metrics)
65
+ on the view so tables, exports, and stories share values and evidence.
66
+
67
+ Every data app supplies a [story and CSV export](stories-and-export.md)
68
+ from the displayed result. Export all distinct datasets at their displayed grain;
69
+ reuse a dataset when several visuals derive from the same rows. Present the
70
+ findings that answer the reader's question, rather than every row or chart.
71
+ Use the [standard layout](layout.md) and built-in toolbar actions.
72
+
73
+ ### Organize the exploration
74
+
75
+ Use sections for a focused question and for findings readers should compare
76
+ side by side. Add app-level `<Tabs>` from `/react/ui` when the exploration has
77
+ distinct analytical questions, such as Overview, Retention, and Segments, each
78
+ with its own context and group of widgets. Lead with the most useful overview
79
+ and label tabs by the question or subject they explore.
80
+
81
+ Use `<VisualizationWidget>`'s `views` for alternate representations of the same
82
+ dataset, such as a chart and its rows. Keep these choices within the widget;
83
+ use filter variables when the reader is changing the data scope.
84
+
85
+ Navigation tabs, widget views, and declared data views have different roles.
86
+ A declared view owns inputs, requests, and displayed results; a tab does not
87
+ require a separate data view. Keep related datasets in one view for a coherent
88
+ snapshot. Use independent views and `<DataSection>` boundaries when content
89
+ needs separate requests. Keep filter placement consistent across tabs and make
90
+ each filter's scope clear. Derive findings, story, and export from the displayed
91
+ results and their inputs.
92
+
93
+ Choose each visual for the question it answers; see
94
+ [visualization selection](widgets.md#choose-a-visualization).
75
95
 
76
96
  ## Verify the app
77
97
 
98
+ Follow the [UI quality contract](ui-quality.md) for hierarchy, responsive
99
+ composition, typography, and control states.
100
+
78
101
  Verify findings against the source and the user's question. Distinguish measured
79
102
  zero, unavailable values, and empty results. Check filters, refresh, loading,
80
103
  empty, error, and stale states, then present the story. Download CSV from the
81
104
  standalone and embedded toolbar and verify its filename, columns, raw values,
82
105
  and filter scope against the displayed result. Export and Present story must be
83
- available once analytical results are shown; initial loading, empty, and initial
84
- errors have neither action. Inspect both experiences
106
+ available once results are shown; initial loading, empty, and initial
107
+ errors keep both actions visible and disabled. Inspect both experiences
85
108
  at phone and desktop widths in light and dark themes.
86
109
 
87
- The app owns its queries, result parsing, business definitions, configuration,
88
- and presentation. Credentials, authorization, and enforced access/query limits
89
- stay backend-owned. Edit app-owned files; installed package files are dependencies.
110
+ Keep credentials, authorization, and enforced query limits in the host/backend.
111
+ Edit app-owned files; installed package files are dependencies.
package/docs/client.md CHANGED
@@ -15,8 +15,9 @@ const response = await client.query('activity', input, { signal });
15
15
  ```
16
16
 
17
17
  The app defines `operations`, `input`, and an optional cancellation `signal`.
18
- Operation input and output types are inferred from the server registry. Keep the
19
- registry import type-only so its SQL and implementation stay on the server.
18
+ Operation input and output types are inferred from the server operation map. Keep the
19
+ server operation map import type-only so its implementations stay on the server.
20
+ The shared app declaration contains the query registry and is browser-safe.
20
21
 
21
22
  The default endpoint is `/api/data`. Override it with
22
23
  `createDataClient({ endpoint, fetch })` to change the base URL or supply a Fetch
@@ -24,8 +25,7 @@ implementation. Calls POST JSON to `/api/data/:operation`; the client sends
24
25
  operation inputs rather than SQL or credentials.
25
26
 
26
27
  `DataResponse` contains `data`, the exact request `input`, `requestId`,
27
- `queriedAt`, and `queryIds`. `queries` is present when the operation exposes SQL
28
- and the execution runtime permits disclosure. Use the returned input when labeling stale data during a refresh.
28
+ `queriedAt`, `queryIds`, and executed `queries`. Use the returned input when labeling stale data during a refresh.
29
29
  HTTP and iframe delivery validate the same success envelope: data, request ID,
30
30
  query timestamp, query IDs, and optional query evidence. Malformed responses
31
31
  reject with `invalid_response`.
@@ -46,17 +46,17 @@ Bundle apps pass their operation registry as a value:
46
46
  import { connectionCheck } from '@altertable/data-app/contract';
47
47
  import { createDataClient } from '@altertable/data-app/client';
48
48
 
49
+ // dataApp declares a connection query.
49
50
  const client = createDataClient({
50
- operations: { connection: connectionCheck() },
51
+ operations: { connection: connectionCheck(dataApp.queries) },
51
52
  });
52
53
  const response = await client.query('connection', {});
53
54
  ```
54
55
 
55
56
  The client runs input parsing, operation logic, and output parsing in the browser.
56
- Operation policy bounds rows, duration, and response size and records query evidence. Each query sends `{ statement, limit }`
57
+ Operation policy bounds rows, duration, and response size and records query evidence. Each query sends `{ statement, limit, params? }`
57
58
  to the installed iframe bridge's `data:sql` route; the host needs no operation
58
- registry. SQL is visible in the browser, even when `exposeSql` is false; that flag
59
- only controls evidence in the returned response. Credentials remain backend-owned.
59
+ registry. Results include query evidence. Credentials remain backend-owned.
60
60
 
61
61
  The trusted bootstrap installs the bridge for bundle apps. A custom runtime must
62
62
  install it before querying. An explicit `lakehouse` can supply another authorized
package/docs/contract.md CHANGED
@@ -2,35 +2,58 @@
2
2
 
3
3
  Import operation definitions, parsers, and shared types from
4
4
  `@altertable/data-app/contract`. This entry is safe to import in browser and server
5
- modules. For HTTP apps, keep SQL and operation implementations on the server; browser modules
6
- should import their operation types using `import type`.
5
+ modules. The app declaration is browser-safe and includes its SQL registry. For HTTP apps,
6
+ keep operation implementations, credentials, and authorization on the server; browser modules
7
+ import operation types using `import type`.
7
8
 
8
9
  ## Execute named queries
9
10
 
10
- The app supplies `calendar`, `parseActivity()`, `checkInput`, `buildActivitySql()`,
11
- and `parseActivityRows()` in this example.
11
+ Declare SQL once with `defineDataApp()` to preserve exact query and parameter
12
+ names. Use stable `lowerCamelCase` IDs describing the result, such as `products`,
13
+ `productsByCategory`, or `dailyRevenue`. Use plural names for row lists; keep parameter
14
+ values in `params`.
15
+ The app owns an immutable registry snapshot. Define operations with
16
+ `dataApp.defineOperation()`.
12
17
 
13
18
  ```ts
14
- import {
15
- defineOperation,
16
- defineQueryNames,
17
- } from '@altertable/data-app/contract';
19
+ import { defineDataApp } from '@altertable/data-app';
20
+ import { rowsAsRecords } from '@altertable/data-app/contract';
21
+
22
+ const dataApp = defineDataApp({
23
+ title: 'Products',
24
+ description: 'Explore products for the selected organization.',
25
+ scope: { organization: 'demo', environment: 'production' },
26
+ appearance: { theme: 'system' },
27
+ queries: {
28
+ products: {
29
+ statement: 'SELECT * FROM products WHERE org_id = $orgId LIMIT $limit',
30
+ params: { orgId: {}, limit: { defaultValue: 10 } },
31
+ },
32
+ },
33
+ });
18
34
 
19
- const queries = defineQueryNames({ activity: 'feature-activity' });
20
- const activity = defineOperation({
21
- queryNames: queries,
22
- input: calendar.parseRequest,
23
- output: parseActivity,
24
- checks: [checkInput],
25
- policy: { maxQueryRows: 100, maxDurationMs: 15000, exposeSql: true },
35
+ const products = dataApp.defineOperation({
36
+ input: parseProductInput,
37
+ output: parseProducts,
38
+ checks: [{}],
39
+ policy: { maxQueryRows: 100, maxDurationMs: 15000 },
26
40
  async run({ query }, input) {
27
- const result = await query(queries.activity, buildActivitySql(input));
28
- return parseActivityRows(result);
41
+ const result = await query('products', input);
42
+ return rowsAsRecords(result, ['org_id']);
29
43
  },
30
44
  });
31
45
  ```
32
46
 
33
- `query()` inherits the operation's limit and cancellation signal; `{ limit }` can lower a particular query's bound. Names are checked by TypeScript and at runtime. Responses include executed SQL and query IDs when disclosure is allowed. HTTP browser modules import operation types with `import type`. Bundle apps import their browser-owned operation registry as a value and use [browser execution](client.md#browser-owned-operations-for-bundle-apps). Never bundle credentials or server adapters.
47
+ `parseProductInput()` and `parseProducts()` are app-owned example functions, not
48
+ package exports. Validate
49
+ filter values in the input parser. `{}` declares a required parameter; `{ defaultValue }` supplies
50
+ a fallback. `query(name, params, { limit })` executes only registered queries and
51
+ inherits the operation's row limit and cancellation signal.
52
+
53
+ SQL and resolved parameter values pass unchanged to the backend. Results include
54
+ query evidence; use `products.queryNames` with `createDataContext()` to bind it.
55
+ For HTTP apps, authorization can supply protected `queryParams`, such as `orgId`.
56
+ The host/backend enforces data access and limits.
34
57
 
35
58
  ## Shared date ranges
36
59
 
@@ -50,8 +73,7 @@ export const calendar = defineDateRangeContract({
50
73
  ```
51
74
 
52
75
  `parseEmptyInput()`, `parseTrue()`, `parseCount()`, and `parseDateRangeInput()` validate
53
- common inputs and results. `connectionCheck()` defines a bounded connectivity
54
- operation. A successful connectivity check confirms access; it is not an
76
+ common inputs and results. `connectionCheck(dataApp.queries)` runs the registered `connection` query. A successful connectivity check confirms access; it is not an
55
77
  analysis result.
56
78
 
57
79
  See [server authorization](server.md) and [React views](react.md) for the two
@@ -0,0 +1,91 @@
1
+ # Data context and evidence
2
+
3
+ Set `dataContext: context` in each view for source descriptions, glossary, and
4
+ permitted query evidence. App inspection and the view's sections use that context.
5
+ Render registered identifiers where `<DataIdentifier>` is used.
6
+
7
+ Physical source identifiers name inspected tables and columns. Glossary entries
8
+ explain business meaning. Query names link those definitions and displayed claims
9
+ to their execution evidence. Keep all three explicit.
10
+
11
+ ## Register source identifiers
12
+
13
+ Use `defineDataIdentifiers()` from `/react` to register exact catalog, schema,
14
+ table, and field names. Use `<DataIdentifier>` in descriptions and glossary
15
+ entries to render those source references consistently.
16
+
17
+ ```tsx
18
+ import { defineDataIdentifiers } from '@altertable/data-app/react';
19
+
20
+ const identifiers = defineDataIdentifiers({
21
+ tables: {
22
+ events: {
23
+ catalog: 'product_analytics',
24
+ schema: 'analytics',
25
+ name: 'events',
26
+ },
27
+ },
28
+ columns: { identity: { table: 'events', name: 'identity_uuid' } },
29
+ });
30
+ const { DataIdentifier } = identifiers;
31
+
32
+ <DataIdentifier id="tables.events" />;
33
+ <DataIdentifier id="columns.events.identity" />;
34
+ ```
35
+
36
+ Pass `identifiers.definitions` to `createDataContext()` to reuse the source
37
+ registry.
38
+
39
+ ## Bind evidence
40
+
41
+ ```tsx
42
+ const queries = activity.queryNames;
43
+ const context = createDataContext(queries)({
44
+ identifiers: identifiers.definitions,
45
+ description: (
46
+ <>
47
+ Explore activity in <DataIdentifier id="tables.events" />.
48
+ </>
49
+ ),
50
+ glossary: {
51
+ identities: {
52
+ term: 'Tracked identities',
53
+ definition: (
54
+ <>
55
+ Distinct <DataIdentifier id="columns.events.identity" /> values.
56
+ </>
57
+ ),
58
+ queryNames: [queries.activity],
59
+ },
60
+ },
61
+ });
62
+ const evidence = context.evidence({
63
+ id: 'identities',
64
+ glossaryIds: ['identities'],
65
+ queryNames: [queries.activity],
66
+ });
67
+ // activityView is declared with dataContext: context.
68
+ const trackedIdentities = activityView.metric(
69
+ {
70
+ id: 'identities',
71
+ glossaryId: 'identities',
72
+ format: { kind: 'count', compact: true },
73
+ },
74
+ data => ({ current: data.count })
75
+ );
76
+ const finding = context.finding({
77
+ id: 'activity',
78
+ headline: 'What people do',
79
+ visual: <ActivityChart />,
80
+ evidence: { id: 'activity-evidence', queryNames: [queries.activity] },
81
+ });
82
+ ```
83
+
84
+ Query inspection shows the executed SQL and resolved parameters; copy actions include both.
85
+
86
+ Import context and identifier factories from `/react`. Use the operation’s derived `queryNames` for evidence.
87
+
88
+ Use `view.metric(definition, select)` to register and bind a metric in one call.
89
+ Declare dataset evidence references inside `view.dataset()`; the view registers
90
+ and validates them too.
91
+ Widgets and stories share its values and evidence; see [datasets and metrics](widgets.md#declare-datasets-and-metrics).
package/docs/embed.md CHANGED
@@ -31,11 +31,18 @@ A bundle source has this shape:
31
31
  ```ts
32
32
  const source = {
33
33
  type: 'bundle' as const,
34
- bootstrapUrl: 'https://my-report-app-1.apps.example.net/',
35
34
  javascript: bundle.javascript,
36
35
  };
37
36
  ```
38
37
 
38
+ Omit `bootstrapUrl` to load the SDK's packaged bootstrap as a `data:` document.
39
+ This supports MCP hosts that permit opaque child frames but block remote frame
40
+ URLs. The SDK embeds the exact host origin and applies a CSP that prohibits
41
+ direct network access. Data requests go through the host's dispatcher.
42
+
43
+ Supply an HTTP(S) `bootstrapUrl` to use an externally served trusted bootstrap,
44
+ such as the [Worker asset](worker.md).
45
+
39
46
  The host provides a self-contained JavaScript bundle. React bridges replace the
40
47
  iframe whenever its JavaScript content changes. Serve the bootstrap page with a CSP compatible with the bundle.
41
48
  Bundle mode uses `sandbox="allow-scripts"` and an opaque origin; it cannot read
@@ -129,7 +136,8 @@ as public `source_*` errors with request IDs. Authorization failures return
129
136
  public failures with `MessageRoutingError`.
130
137
 
131
138
  `SqlQueryInput` (exported from `/contract`) carries
132
- `{ statement: string, limit: number }`; responses are
139
+ `{ statement: string, limit: number, params?: QueryParameters }`; the backend
140
+ interprets the unchanged statement and parameter values. Responses are
133
141
  `{ columns: { name: string, type?: string }[], rows: unknown[][], queryId?: string }`.
134
142
  The route rejects empty statements, unsafe or nonpositive limits, malformed
135
143
  results, and results exceeding the requested limit. The bridge's existing payload
@@ -0,0 +1,68 @@
1
+ # Formatting and appearance
2
+
3
+ Use package helpers so a value has the same meaning in prose, tables, charts,
4
+ and stories. TypeScript and JSDoc describe options and supported values.
5
+
6
+ ## Format values
7
+
8
+ Import formatting helpers from `@altertable/data-app/format`.
9
+
10
+ | Helper | Use |
11
+ | ------------------- | ------------------------------------------------------ |
12
+ | `formatNumber()` | General numerical values |
13
+ | `formatCount()` | Nonnegative integer counts, optionally compact |
14
+ | `formatPercent()` | Ratios represented as a fraction, such as 0.12 for 12% |
15
+ | `formatMetric()` | A metric definition's count, ratio, or currency format |
16
+ | `formatDateRange()` | Inclusive calendar ranges |
17
+ | `pluralize()` | Count-dependent labels |
18
+
19
+ Missing values render distinctly from measured zero. Declare formatting once on
20
+ `view.metric()` so widgets, comparisons, and narrative share it; reuse the
21
+ definition with `formatMetric()` in story headlines.
22
+
23
+ Use compact counts for headline metrics and chart labels. Declare count metrics
24
+ with `format: { kind: 'count', compact: true }`. Keep full counts in tables used
25
+ for precise comparisons and raw numeric values in datasets for CSV export.
26
+
27
+ ```ts
28
+ formatCount(2_200_000, { compact: true }); // "2.2M"
29
+ formatCount(2_200_000); // "2,200,000"
30
+ ```
31
+
32
+ For signed or fractional measures, use `formatNumber()` with
33
+ `notation: 'compact'` and preserve the measure's units.
34
+
35
+ Import `chartColor()` from `/react` to select colors from the configured palette.
36
+ `<PeriodSummary>` describes reporting periods; `<UpdatedAt>` and
37
+ `<DateTimeTooltip>` expose readable timestamps with exact-date details.
38
+ `<DataTableTimestamp>` and `<DataTableShare>` format custom table cells.
39
+
40
+ ## Configure identity and appearance
41
+
42
+ ```ts
43
+ import { defineDataApp } from '@altertable/data-app';
44
+
45
+ const dataApp = defineDataApp({
46
+ title: 'Product activity',
47
+ description: 'Explore product usage and trends.',
48
+ scope: { organization: 'Acme', environment: 'Production' },
49
+ appearance: {
50
+ theme: 'system',
51
+ accentColor: '#405d47',
52
+ density: 'comfortable',
53
+ },
54
+ queries: {},
55
+ });
56
+ ```
57
+
58
+ Scope labels describe the configured connection; they do not grant access.
59
+ `dataAppTitle()` produces the scoped document title used by `mountDataApp()`.
60
+
61
+ Title and description explain the app and can be revised when regenerating it.
62
+ Omit appearance to use the standard defaults.
63
+
64
+ Appearance controls the brand palette, typography, density, corner radius, and
65
+ elevation. Those settings apply consistently to the app instead of tuning each
66
+ widget. Theme preference is reader-owned in standalone apps. A trusted parent's
67
+ resolved theme takes precedence and hides local theme controls; see
68
+ [parent presentation](embed.md#parent-presentation).
@@ -4,7 +4,14 @@ Follow the [shared authoring flow](app-authoring.md) using [index.tsx](../exampl
4
4
  one file with public package imports; omit server files, HTML, credentials, and
5
5
  relative or app-alias imports.
6
6
 
7
- Replace the sample SQL, parsers, filters, data context, CSV export, story, and configuration with
7
+ Declare exactly one top-level const initialized with `defineDataApp({ ... })`, imported
8
+ from `@altertable/data-app`. Keep executable composition outside its literal argument.
9
+ For the future backend extractor, use schema-valid literals without spreads, computed keys,
10
+ references, calls, or template interpolation. Extraction will read and validate the argument
11
+ before bundling, without evaluating app code or parsing SQL. Import aliases and any variable
12
+ name are allowed; export only for other modules. Static apps use `queries: {}`.
13
+
14
+ Replace the sample app declaration, operations, filters, data context, CSV export, and story with
8
15
  an exploration of the source data you inspected. The starter uses two SQL
9
16
  `VALUES` rows, so it needs no production table.
10
17
 
@@ -13,7 +20,7 @@ For execution details, see [browser-owned operations](client.md#browser-owned-op
13
20
  ## Convert a local data app
14
21
 
15
22
  1. Combine the app's operations and parsers, data context, views, story,
16
- CSV export, configuration, and browser entry into one `index.tsx`, following the
23
+ CSV export, app declaration, and browser entry into one `index.tsx`, following the
17
24
  [single-file starter](../examples/starter-data-app/index.tsx).
18
25
  2. Replace the HTTP client with `createDataClient({ operations })`, using the
19
26
  operation registry as a value. See [browser-owned operations](client.md#browser-owned-operations-for-bundle-apps)
@@ -24,16 +31,3 @@ For execution details, see [browser-owned operations](client.md#browser-owned-op
24
31
  4. Confirm the host can query the same catalogs, tables, and fields.
25
32
  [Verify the app](app-authoring.md#verify-the-app) in the hosted runtime against
26
33
  the local version's filters and findings.
27
-
28
- ## Preview in this repository
29
-
30
- ```fish
31
- bun install --frozen-lockfile
32
- bun run build
33
- bun browser-tests/server.ts
34
- ```
35
-
36
- Open [the starter preview](http://127.0.0.1:27418/starter-data-app).
37
- Its test host executes the sample SQL through the iframe bridge using SQLite.
38
-
39
- For checks, see [Contributing](../CONTRIBUTING.md).
package/docs/layout.md CHANGED
@@ -6,9 +6,11 @@ for sections, `<Grid>` for peer widgets, and `<GridItem>` for spans. Use
6
6
  external spacing. Keep widget customization inside the widget so its parent can maintain consistent
7
7
  spacing between sections and cards.
8
8
 
9
- By default, section and widget gaps use `--at-layout-gap`, with density configured once
10
- in `DataAppConfig.appearance`. The package owns wrapping and span collapse based
11
- on the available container width.
9
+ By default, section and widget gaps use `--atbl-layout-gap`, with density configured once
10
+ in `app.appearance`. The package owns wrapping and span collapse based
11
+ on the available container width and configured gap. Custom length values for
12
+ `--atbl-layout-gap`, `--atbl-space-sm`, and `--atbl-space-md` also drive span
13
+ collapse; a two-column span activates only when two minimum-width tracks fit.
12
14
 
13
15
  ```tsx
14
16
  <Stack>
@@ -45,10 +45,11 @@ The local URL must have a different origin from its shell. For hosted bundles,
45
45
  replace `source` with:
46
46
 
47
47
  ```tsx
48
- source={{ type: 'bundle', bootstrapUrl, javascript }}
48
+ source={{ type: 'bundle', javascript }}
49
49
  ```
50
50
 
51
- The host supplies those bundle values. See [embedding](embed.md) for trust,
51
+ The host supplies the JavaScript bundle. Omit `bootstrapUrl` for the packaged
52
+ opaque bootstrap, or supply an HTTP(S) URL for an external bootstrap. See [embedding](embed.md) for trust,
52
53
  sandbox, CSP, and bootstrap setup.
53
54
 
54
55
  Source URL or JavaScript content changes replace the entire iframe. Change the
@@ -93,8 +94,8 @@ are mutually exclusive.
93
94
 
94
95
  ## Loading an embedded app
95
96
 
96
- Use `<DataAppSkeleton>` from `/react` while the host builds or starts an app.
97
- Call `injectDataAppShellStyles()` from `/react` before rendering the placeholder.
97
+ Use `<DataAppSkeleton>` from `/react/ui` while the host builds or starts an app.
98
+ Call `injectDataAppShellStyles()` from `/react/ui` before rendering the placeholder.
98
99
  The host owns when to show it and supplies any surrounding header or footer.
99
100
  `/react/embed` itself remains independent of UI components and styles.
100
101