@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/docs/react.md ADDED
@@ -0,0 +1,248 @@
1
+ # React
2
+
3
+ Import hooks, components, and UI helpers from `@altertable/data-app/react`.
4
+ Import `@altertable/data-app/react/styles.css` once in the browser entry.
5
+ React 19.2 or newer and React DOM 19.2 or newer are peer dependencies.
6
+
7
+ `mountDataApp({ config, component })` mounts into `#root`, sets the document
8
+ title and language, attaches navigation to an available iframe transport, and
9
+ installs `DataAppProvider`. When mounting through another
10
+ framework, wrap the app in `DataAppProvider` yourself.
11
+
12
+ ## Find UI by task
13
+
14
+ All of these APIs are exported from `/react`. Each component's stylesheet lives beside its implementation.
15
+
16
+ | Task | Start here | Related APIs |
17
+ | ------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
18
+ | Primary request and page shell | [DataApp](https://github.com/altertable-ai/data-app/blob/main/src/react/ui/DataApp.tsx) | AppLayout, AppHeader, AppToolbar, AppFooter, AppScope, ThemeToggle |
19
+ | Initial connection check | [GettingStarted](https://github.com/altertable-ai/data-app/blob/main/src/react/ui/GettingStarted.tsx) | Pair with `connectionCheck()` from `/contract` |
20
+ | Arrange content | [Grid](https://github.com/altertable-ai/data-app/blob/main/src/react/ui/Grid.tsx), [Stack](https://github.com/altertable-ai/data-app/blob/main/src/react/ui/Stack.tsx) | DataWidget |
21
+ | Show a key number | [MetricWidget](https://github.com/altertable-ai/data-app/blob/main/src/react/ui/MetricWidget.tsx) | ComparisonVisual |
22
+ | Show charts and collections | [VisualizationWidget](https://github.com/altertable-ai/data-app/blob/main/src/react/ui/VisualizationWidget.tsx), [TableWidget](https://github.com/altertable-ai/data-app/blob/main/src/react/ui/TableWidget.tsx) | DataTable, Ranking, Breakdown, chartColor |
23
+ | Handle a request's loading, error, and stale data | [DataSection](https://github.com/altertable-ai/data-app/blob/main/src/react/ui/DataSection.tsx) | DataBoundary, DataViewToast, EmptyState, StatusPanel, Skeleton |
24
+ | Show freshness and refresh | [UpdatedAt](https://github.com/altertable-ai/data-app/blob/main/src/react/ui/UpdatedAt.tsx), [AppToolbar](https://github.com/altertable-ai/data-app/blob/main/src/react/ui/AppToolbar.tsx) | RefreshRegion, LiveControl |
25
+ | Bind filters to the URL | [variables](https://github.com/altertable-ai/data-app/blob/main/src/react/ui/variables.ts), [DateRangePicker](https://github.com/altertable-ai/data-app/blob/main/src/react/ui/DateRangePicker.tsx) | Combobox, PeriodSummary, Tabs, useViewTab |
26
+ | Search a loaded collection | [searchItems](https://github.com/altertable-ai/data-app/blob/main/src/react/ui/searchItems.ts), [SearchMatch](https://github.com/altertable-ai/data-app/blob/main/src/react/ui/SearchMatch.tsx) | SearchField |
27
+ | Explain context, glossary, and queries | [AboutData](https://github.com/altertable-ai/data-app/blob/main/src/react/ui/AboutData.tsx), [DataContext](https://github.com/altertable-ai/data-app/blob/main/src/react/ui/data-context.ts) | [GlossaryDefinition](https://github.com/altertable-ai/data-app/blob/main/src/react/ui/GlossaryDefinition.tsx), GlossaryExplanation, [defineDataIdentifiers](https://github.com/altertable-ai/data-app/blob/main/src/react/ui/data-identifiers.tsx) |
28
+ | Present loaded findings | [PresentStory](https://github.com/altertable-ai/data-app/blob/main/src/react/ui/PresentStory.tsx) | StoryFinding |
29
+ | Build custom controls and overlays | [Button](https://github.com/altertable-ai/data-app/blob/main/src/react/ui/Button.tsx), [Sheet](https://github.com/altertable-ai/data-app/blob/main/src/react/ui/Sheet.tsx) | IconButton, Tooltip, HelpPopover, Kbd |
30
+
31
+ ## Bound views and widgets
32
+
33
+ | Definition | Runtime owns |
34
+ | ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
35
+ | `defineOperation` | Input/output validation, check inputs, query limits and cancellation; `query(name, sql)` accepts registered names and records executed evidence. |
36
+ | `defineDataView` | URL variables, operation input, emptiness and the primary date binding. `useView` connects the result and controls to `DataApp`. |
37
+ | `DataApp` | Header, variable bar, refresh state, stale-result notice and dimming, default inspection empty states. |
38
+ | `view.content` | One loading/ready layout. `result.select` never evaluates loading data; `result.metric` binds comparisons to the displayed input. |
39
+ | `context.metric` | Label, numeric format, glossary evidence and optional direction of improvement. |
40
+ | `WidgetViewTabs` | Valid, unique selection IDs and a required empty state per tab. |
41
+
42
+ SQL and business definitions belong to the app. Hosted adapters authorize every request; local development can use the CLI proxy. SQL disclosure also requires server permission.
43
+
44
+ A measured zero and unavailable data have different meanings. Metric readings use `null` for an unavailable previous value. The app defines whether a result is empty. `Breakdown` shows parts of a total; `Ranking` scales against its largest value. Percent formats accept ratios.
45
+
46
+ ## Bind a view
47
+
48
+ ```tsx
49
+ import { createDataClient } from '@altertable/data-app/client';
50
+ import {
51
+ createDataHooks,
52
+ dateRangeVariable,
53
+ DataApp,
54
+ Grid,
55
+ MetricWidget,
56
+ VisualizationWidget,
57
+ Ranking,
58
+ } from '@altertable/data-app/react';
59
+ import type { operations } from '#app/operations.ts';
60
+ import { calendar } from '#app/contracts.ts';
61
+ import { dataContext, actions } from '#app/data-context.tsx';
62
+ import config from '#config';
63
+
64
+ const period = dateRangeVariable({
65
+ key: 'period',
66
+ contract: calendar,
67
+ comparison: true,
68
+ defaultValue: { kind: 'preset', id: 'last-30' },
69
+ });
70
+ const { defineDataView, useView } =
71
+ createDataHooks(createDataClient<typeof operations>());
72
+ const activityView = defineDataView({
73
+ operation: 'activity',
74
+ variables: { period },
75
+ input: ({ period }) => period,
76
+ date: { variable: 'period', input: input => input },
77
+ isEmpty: data => data.features.length === 0,
78
+ empty: { title: 'No activity in this range' },
79
+ });
80
+ const featureEvidence = dataContext.evidence({
81
+ id: 'feature-use',
82
+ queryNames: [dataContext.queryNames.activity],
83
+ });
84
+ const content = activityView.content(result => (
85
+ <Grid columns={2}>
86
+ <MetricWidget
87
+ metric={actions}
88
+ reading={result.metric(data => ({
89
+ current: data.count,
90
+ previous: data.previousCount,
91
+ }))}
92
+ />
93
+ <VisualizationWidget
94
+ title="Feature use"
95
+ evidence={featureEvidence}
96
+ reading={result.select(data => data.features)}
97
+ isEmpty={features => features.length === 0}
98
+ empty={{ title: 'No features' }}
99
+ skeleton={{ variant: 'ranking', rows: 6 }}
100
+ >
101
+ {features => <Ranking items={features} />}
102
+ </VisualizationWidget>
103
+ </Grid>
104
+ ));
105
+ function App() {
106
+ const activity = useView(activityView);
107
+ return (
108
+ <DataApp
109
+ config={config}
110
+ dataContext={dataContext}
111
+ request={activity}
112
+ {...content}
113
+ />
114
+ );
115
+ }
116
+ ```
117
+
118
+ The `date` binding identifies the controlling variable and extracts its range from the operation input. Nested inputs use, for example, `input: (input) => input.period`. The runtime rejects mappings that silently change the selected range or comparison. Non-date views supply `describeInput`; date views can override it when other inputs also need describing.
119
+
120
+ The shared calendar lives in a browser-safe module:
121
+
122
+ ```ts
123
+ import { defineDateRangeContract } from '@altertable/data-app/contract';
124
+ export const calendar = defineDateRangeContract({
125
+ minDate: '2026-01-01',
126
+ maxRangeDays: 90,
127
+ timeZone: 'UTC',
128
+ });
129
+ // Server operation: input: calendar.parseRequest
130
+ ```
131
+
132
+ `useView` generates controls for date, text and fixed-option select variables; custom controls use `result.variables.bind(name)`. `input` chooses which variables reach the operation, so local search can stay local. The callback in `view.content` receives the displayed result, including its original input during refreshes and failures. Hooks belong in the enclosing component.
133
+
134
+ `TableWidget` also accepts `reading={result.select((data) => data.rows)}` and optional `skeletonRows`. Columns and empty states are declared once for both loading and ready layouts. Bounded tables default to 10 rows per page with a bottom footer shared with inspection. Set `pagination={{ pageSize: 8 }}` to change the page size or `pagination={false}` to show all rows. Search runs before pagination; the footer counts only the supplied rows. `limit` remains a separate, mutually exclusive display cap. Large catalogs need query-backed pagination with a stable sort and total count.
135
+
136
+ Bound `VisualizationWidget` and `TableWidget` calls require `evidence` from `context.evidence(...)`. A bound `MetricWidget` gets evidence from its metric definition. Evidence must name at least one glossary entry or query. Static widgets may omit it.
137
+
138
+ `MetricWidget` and `ComparisonVisual` both accept the same `metric` and `reading`. The comparison is enabled by the displayed result's range. The definition supplies formatting and evidence; a reading cannot override those or provide a second value. `favorableDirection` is optional; changes are neutral until the author defines whether up or down is favorable.
139
+
140
+ `defineDataContent` remains available for manually managed requests. Its optional `{ date: (input) => rangeRequest }` binds comparison readings. `DataSection` handles independent requests. Low-level widgets, tabs and layout components remain available for custom interfaces.
141
+
142
+ ## Bind evidence
143
+
144
+ ```tsx
145
+ const queries = defineQueryNames({ activity: 'feature-activity' });
146
+ // In the server operation: queryNames: queries
147
+ const identifiers = defineDataIdentifiers({
148
+ tables: {
149
+ events: {
150
+ catalog: 'product_analytics',
151
+ schema: 'analytics',
152
+ name: 'events',
153
+ },
154
+ },
155
+ columns: { identity: { table: 'events', name: 'identity_uuid' } },
156
+ });
157
+ const { DataIdentifier } = identifiers;
158
+ const context = createDataContext(queries)({
159
+ identifiers: identifiers.definitions,
160
+ description: (
161
+ <>
162
+ Explore activity in <DataIdentifier id="tables.events" />.
163
+ </>
164
+ ),
165
+ glossary: {
166
+ identities: {
167
+ term: 'Tracked identities',
168
+ definition: (
169
+ <>
170
+ Distinct <DataIdentifier id="columns.events.identity" /> values.
171
+ </>
172
+ ),
173
+ queryNames: [queries.activity],
174
+ },
175
+ },
176
+ });
177
+ const evidence = context.evidence({
178
+ id: 'identities',
179
+ glossaryIds: ['identities'],
180
+ queryNames: [queries.activity],
181
+ });
182
+ const actions = context.metric({
183
+ id: 'actions',
184
+ glossaryId: 'identities',
185
+ label: 'Tracked identities',
186
+ format: { kind: 'count' },
187
+ });
188
+ const finding = context.finding({
189
+ id: 'activity',
190
+ headline: 'What people do',
191
+ visual: <ActivityChart />,
192
+ evidence: { id: 'activity-evidence', queryNames: [queries.activity] },
193
+ });
194
+ ```
195
+
196
+ Import `defineQueryNames` from `/contract` and the context/identifier factories from `/react`. Use the same registry in `defineOperation({ queryNames: queries, ... })`. Unknown glossary/query references fail type checks and registry validation; the server also validates returned query names. Physical source identity stays in the identifier registry for future linking.
197
+
198
+ ## Authoring constraints
199
+
200
+ - Date views declare `date: { variable: "period", input: (input) => input }`, or supply `describeInput` for a non-date view.
201
+ - Numeric metrics use `value={count} format={{ kind: "count" }}`. Custom formatted JSX or strings use `content={...}` instead of `value`.
202
+ - Supply `empty` to secondary `DataSection` requests or pass a bound `useView` result. A primary `DataApp` accepts it either from `useView` or as an explicit prop.
203
+ - For alternate views of the same bound result, pass `views={[{ id, label, render }]}` and `viewLabel` to `VisualizationWidget`. Its required `isEmpty` and `empty` apply to the whole result; the widget owns selection. Use `WidgetViewTabs` directly only when views have independent empty states.
204
+ - Variable URL keys cannot use `view`, `about`, `tab`, `present`, or `step`.
205
+
206
+ ## Time views and dimension filters
207
+
208
+ `createDataHooks(client).defineTimeView` owns the `period` variable, calendar
209
+ controls, and displayed-period label. Declare `time: { contract, defaultValue }`,
210
+ an operation, `isEmpty`, and `empty`. With no additional variables, its default
211
+ input is the calendar request. With additional variables, it is `{ period, ...variables }`.
212
+ Supply an `input` mapper for a different operation shape and `bindings` to extract
213
+ nested period or dimension inputs. Mappings must preserve the selected values.
214
+
215
+ `dimensionFilter` requires exactly one option source: fixed `options` or a `facet`.
216
+ Use `defineFacetFilter` to bind a facet operation and its typed input. The generated
217
+ `DimensionPicker` preserves cached options during refresh and failure, offers
218
+ missing values separately, and retains selected values absent from a result with
219
+ zero counts. `SelectableBarChart` can share controlled selection with the picker.
220
+
221
+ ## Findings and inspection
222
+
223
+ `DataWidget` composes a body, toolbar feedback, and footer. Widgets and their
224
+ inspection sheets render the same visual and controls. Keep interactive state
225
+ above both mounts when authoring custom children.
226
+
227
+ `DataApp.story` receives the displayed snapshot, including its original input
228
+ during refresh or failure. Return one to four `StoryFinding` values with unique
229
+ IDs and registered evidence. `PresentStory` presents those findings directly;
230
+ `context.finding` validates their evidence against the context registry.
231
+
232
+ ### Migration from the earlier runtime
233
+
234
+ - `DataWidget` replaces the internal `DataPanel` shell and `StorySection` layout.
235
+ - `PresentStory` replaces `PlayStory`; provide `findings` with explicit `evidence`.
236
+ - `context.finding` replaces `context.storyStep`.
237
+ - Table pagination is enabled by default; use `pagination={false}` for complete tables.
238
+
239
+ ## Component gallery
240
+
241
+ Contributors can preview `/gallery` on the browser fixture server with
242
+ `bun browser-tests/server.ts`. The gallery covers control, widget, request,
243
+ inspection, and narrow-layout defaults. `bun run test:browser` verifies desktop
244
+ and phone interactions. Fixtures are excluded from the published package.
245
+
246
+ Previous data and evidence are retained only when the input changes within the
247
+ same operation. Switching to another operation shows its own cached response or
248
+ an initial loading/error state; it never inherits another operation's result.
@@ -0,0 +1,74 @@
1
+ # Releasing
2
+
3
+ This repository releases one npm package, `@altertable/data-app`. All public
4
+ entries share its version. Release Please manages `package.json`, the release
5
+ manifest, `CHANGELOG.md`, GitHub tags, and release notes.
6
+
7
+ ## Repository setup
8
+
9
+ Enable GitHub Actions and allow it to create pull requests. Configure a
10
+ `RELEASE_PLEASE_TOKEN` repository secret with a fine-grained PAT that can write
11
+ repository contents and pull requests. The
12
+ workflow falls back to `GITHUB_TOKEN`, but PRs created or updated with that token
13
+ do not trigger subsequent GitHub Actions workflows. Use the dedicated token
14
+ when requiring CI checks on release PRs.
15
+
16
+ Configure the npm trusted publisher for `@altertable/data-app`:
17
+
18
+ | Setting | Value |
19
+ | ----------------- | --------------------------------------------------- |
20
+ | Provider | GitHub Actions |
21
+ | Organization | `altertable-ai` |
22
+ | Repository | `data-app` |
23
+ | Workflow filename | `release-please.yml` |
24
+ | Environment | Leave empty; the workflow has no GitHub environment |
25
+
26
+ The publish job grants `id-token: write`, uses npm 11.18.0, and publishes with
27
+ provenance. It uses neither `NPM_TOKEN` nor `NODE_AUTH_TOKEN`. Do not add
28
+ `registry-url` to its `setup-node` step: that creates token authentication
29
+ configuration that interferes with OIDC. See
30
+ [npm trusted publishing](https://docs.npmjs.com/trusted-publishers/).
31
+
32
+ If the npm package does not exist yet, establish it and configure its trusted
33
+ publisher before expecting automated publication to succeed. Package and npm
34
+ account setup are maintainer actions outside repository CI.
35
+
36
+ The manifest starts at the imported runtime version `0.59.1`. This records the
37
+ version baseline, not a claim that it is published. Release Please computes the
38
+ next version from release-relevant commits on `main`.
39
+
40
+ ## Release flow
41
+
42
+ 1. Merge Conventional Commits into `main`.
43
+ 2. Release Please opens or updates a release PR with the version and changelog.
44
+ 3. Review and merge that PR. Release Please creates its `v<version>` tag and
45
+ GitHub release.
46
+ 4. The workflow resolves the tag to a commit SHA and runs the same source,
47
+ package, and workflow checks against that revision. The publish job checks out
48
+ that SHA, confirms the tag has not moved, builds, and publishes to npm.
49
+
50
+ GitHub release creation precedes the publication checks. A failed check blocks
51
+ npm publication and leaves the GitHub release available for a retry.
52
+
53
+ The publish job checks that the tag matches `package.json`, that the GitHub
54
+ release exists and is not a draft, and that GitHub OIDC is available. An existing
55
+ npm version is skipped. Registry errors other than a missing version stop the
56
+ job rather than being treated as permission to publish.
57
+
58
+ CodeQL and dependency review are separate workflows. Branch protection can
59
+ require `Source and packed package`, `Validate workflows`, and `Validate PR
60
+ title`, plus the security checks your repository policy requires.
61
+
62
+ ## Retry a failed publication
63
+
64
+ Run the **Release Please** workflow manually from `main` and enter the existing
65
+ GitHub release tag in its `tag` input. The workflow verifies and publishes that
66
+ tag, rather than the current contents of `main`. Already-published versions are
67
+ skipped, so a retry after a successful publication is safe.
68
+
69
+ Workflow shell logic lives in `scripts/release/`; Node and Bun versions come
70
+ from `.node-version` and `.bun-version`. The npm version is pinned in
71
+ `scripts/release/setup-npm.sh`.
72
+
73
+ To validate repository configuration locally, run `bun run check:workflows` and
74
+ `bun run check`. Local checks do not invoke Release Please or publish to npm.
@@ -0,0 +1,26 @@
1
+ # Local Bun server
2
+
3
+ Import `serveLocalApp` and `localLakehouse` from
4
+ `@altertable/data-app/server/bun`. This entry requires Bun; install `@types/bun`
5
+ when typechecking a Bun app.
6
+
7
+ ```ts
8
+ import { serveLocalApp } from '@altertable/data-app/server/bun';
9
+ import page from './index.html';
10
+ import { operations } from './operations';
11
+
12
+ serveLocalApp({ page, operations, title: 'Activity' });
13
+ ```
14
+
15
+ The server binds to `127.0.0.1`. Its default port is `25837`, overridable through
16
+ `PORT` or the `port` option. It serves the Bun HTML bundle and operation requests.
17
+
18
+ `localLakehouse()` reads the CLI proxy URL and token from
19
+ `ALTERTABLE_DATA_PROXY_URL` and `ALTERTABLE_DATA_PROXY_TOKEN`. It also supports
20
+ server-only `ALTERTABLE_LAKEHOUSE_USERNAME` and
21
+ `ALTERTABLE_LAKEHOUSE_PASSWORD`, with an optional `ALTERTABLE_API_BASE`.
22
+ Missing credentials fail the query. Keep these variables out of browser code.
23
+
24
+ Local serving permits SQL disclosure and does not authenticate hosted viewers.
25
+ Use [the portable server handler](server.md) with per-request authorization when
26
+ hosting an app for other people.
package/docs/server.md ADDED
@@ -0,0 +1,47 @@
1
+ # Server
2
+
3
+ Import `createDataHandler` and the `RequestAccess` type from
4
+ `@altertable/data-app/server`. The handler accepts a Web `Request` and returns a
5
+ `Promise<Response>`. This entry can be imported in Node and Bun without loading
6
+ React or the Bun local-development adapter.
7
+
8
+ ```ts
9
+ import { createDataHandler } from '@altertable/data-app/server';
10
+ import { operations } from './operations';
11
+
12
+ export const handleDataRequest = createDataHandler(
13
+ operations,
14
+ async (request, operation) => {
15
+ const viewer = await authenticate(request);
16
+ return {
17
+ lakehouse: await lakehouseFor(viewer, operation),
18
+ canDiscloseSql: false,
19
+ };
20
+ }
21
+ );
22
+ ```
23
+
24
+ The app supplies `authenticate` and `lakehouseFor`, then routes `/api/data/*`
25
+ requests to the handler. Authorize every viewer and operation, and scope the
26
+ returned lakehouse to the viewer's permitted data. Origin and Fetch Metadata
27
+ checks reject cross-site browser requests; they do not authenticate viewers.
28
+
29
+ The handler validates operation input and output, enforces query row and duration
30
+ bounds, propagates cancellation, and returns request IDs with errors. SQL is
31
+ disclosed only when both the operation policy and `canDiscloseSql` allow it.
32
+ Keep credentials and operation implementations on the server.
33
+
34
+ See [operation contracts](contract.md), the [client](client.md), and the
35
+ [local Bun adapter](server-bun.md).
36
+
37
+ ## Request input limits
38
+
39
+ JSON request bodies are limited to **16,384 encoded bytes**, including multibyte
40
+ UTF-8 content. The handler counts bytes as it reads and cancels remaining
41
+ consumption on overflow; it does not rely on `Content-Length`. Authorization
42
+ runs before reading. Request cancellation interrupts waiting reads. Invalid or
43
+ interrupted bodies return `400/invalid_input`; oversized bodies return
44
+ `413/input_too_large`.
45
+
46
+ `maxDurationMs` bounds execution after input parsing. It does not add a separate
47
+ body-read deadline. The hosting runtime controls the size of individual chunks.
@@ -0,0 +1,51 @@
1
+ # Starter agent instructions
2
+
3
+ The package ships `AGENTS.md`, public documentation in `docs/`, and declarations
4
+ referenced by its export map. Its agent guide describes package usage and includes
5
+ a separate section for contributors working in the package source repository.
6
+
7
+ A starter application's `AGENTS.md` owns its file paths, commands, and analysis
8
+ context. Keep it in the consuming app and explicitly direct agents to the
9
+ installed package guide. Dependency instructions are not guaranteed to be loaded
10
+ automatically: for example, [Codex discovers project instructions along the path
11
+ from the project root to its working directory](https://learn.chatgpt.com/docs/agent-configuration/agents-md),
12
+ not by scanning every dependency.
13
+
14
+ These installed docs replace references to the old vendored `.altertable/runtime`
15
+ layout for apps using this package.
16
+
17
+ Adapt this template to the starter's actual files and scripts:
18
+
19
+ ```markdown
20
+ # Build this data app
21
+
22
+ Inspect source data, time coverage, and existing definitions before choosing an
23
+ exploration. Build conclusions from observed results; do not present association
24
+ as cause. Keep copy concise and relevant to the reader.
25
+
26
+ Read `node_modules/@altertable/data-app/AGENTS.md` first, then
27
+ `node_modules/@altertable/data-app/docs/app-authoring.md`.
28
+
29
+ | Task | App-owned files | Package documentation |
30
+ | ---------------------------------------- | ------------------------------------------- | -------------------------------------- |
31
+ | Define queries and inputs | `src/operations.ts`, shared input contracts | `docs/contract.md`, `docs/server.md` |
32
+ | Build views, filters, and request states | `src/App.tsx` | `docs/react.md` |
33
+ | Explain terms and query evidence | `src/data-context.ts` or `.tsx` | `docs/react.md#bind-evidence` |
34
+ | Change identity and brand | App configuration | `docs/config.md`, `docs/appearance.md` |
35
+ | Configure local serving or hosting | `src/server.ts` | `docs/server-bun.md`, `docs/server.md` |
36
+
37
+ Package documentation paths above are relative to
38
+ `node_modules/@altertable/data-app/`.
39
+
40
+ Edit app-owned source and import public package entries. Keep SQL and credentials
41
+ on the server, and import operation types with `import type` in browser code.
42
+ Do not edit installed package files. The connectivity screen is scaffolding,
43
+ not an example analysis.
44
+
45
+ Run the app's typecheck, lint, and build scripts. Inspect its findings and
46
+ interactions at phone and desktop widths, including loading, empty, error, and
47
+ stale states. Verify that the exploration answers the user's question.
48
+ ```
49
+
50
+ The CLI's existing starter remains owned by its repository. Updating its template
51
+ and checks to consume the published package is a separate migration.
package/package.json ADDED
@@ -0,0 +1,124 @@
1
+ {
2
+ "name": "@altertable/data-app",
3
+ "version": "0.59.1",
4
+ "description": "Contracts, transport, and React UI for Altertable data apps",
5
+ "keywords": [
6
+ "altertable",
7
+ "analytics",
8
+ "data-app",
9
+ "react",
10
+ "typescript"
11
+ ],
12
+ "homepage": "https://github.com/altertable-ai/data-app",
13
+ "bugs": {
14
+ "url": "https://github.com/altertable-ai/data-app/issues"
15
+ },
16
+ "license": "MIT",
17
+ "author": {
18
+ "name": "Altertable",
19
+ "url": "https://altertable.ai"
20
+ },
21
+ "repository": {
22
+ "type": "git",
23
+ "url": "git+https://github.com/altertable-ai/data-app.git"
24
+ },
25
+ "files": [
26
+ "dist",
27
+ "docs",
28
+ "README.md",
29
+ "CONTRIBUTING.md",
30
+ "AGENTS.md"
31
+ ],
32
+ "type": "module",
33
+ "exports": {
34
+ "./contract": {
35
+ "types": "./dist/types/core/contract.d.ts",
36
+ "import": "./dist/core/contract.js"
37
+ },
38
+ "./config": {
39
+ "types": "./dist/types/core/config.d.ts",
40
+ "import": "./dist/core/config.js"
41
+ },
42
+ "./format": {
43
+ "types": "./dist/types/core/format.d.ts",
44
+ "import": "./dist/core/format.js"
45
+ },
46
+ "./appearance": {
47
+ "types": "./dist/types/core/appearance.d.ts",
48
+ "import": "./dist/core/appearance.js"
49
+ },
50
+ "./client": {
51
+ "types": "./dist/types/client/index.d.ts",
52
+ "import": "./dist/client/index.js"
53
+ },
54
+ "./server": {
55
+ "types": "./dist/types/server/index.d.ts",
56
+ "import": "./dist/server.js"
57
+ },
58
+ "./server/bun": {
59
+ "types": "./dist/types/server/local.d.ts",
60
+ "import": "./dist/local.js"
61
+ },
62
+ "./react": {
63
+ "types": "./dist/types/react/index.d.ts",
64
+ "import": "./dist/react/index.js"
65
+ },
66
+ "./react/styles.css": {
67
+ "types": "./dist/react.css.d.ts",
68
+ "default": "./dist/react/index.css"
69
+ },
70
+ "./embed": {
71
+ "types": "./dist/types/embed/index.d.ts",
72
+ "import": "./dist/embed/index.js"
73
+ },
74
+ "./bootstrap": {
75
+ "default": "./dist/bootstrap.js"
76
+ },
77
+ "./react/embed": {
78
+ "types": "./dist/types/react/embed/index.d.ts",
79
+ "import": "./dist/react/embed/index.js"
80
+ }
81
+ },
82
+ "publishConfig": {
83
+ "access": "public",
84
+ "registry": "https://registry.npmjs.org"
85
+ },
86
+ "scripts": {
87
+ "build": "bun run scripts/build.ts && tsc -p tsconfig.build.json && bun run scripts/build-declarations.ts",
88
+ "typecheck": "tsc --noEmit",
89
+ "lint": "oxlint --type-aware src tests scripts browser-tests",
90
+ "format": "oxfmt .",
91
+ "format:check": "oxfmt --check .",
92
+ "test": "bun test ./tests",
93
+ "check": "bun run typecheck && bun run lint && bun run format:check && bun run test && bun run build && bun run test:package",
94
+ "test:package": "bun run scripts/check-package.ts",
95
+ "check:workflows": "bash scripts/check-workflows.sh",
96
+ "test:browser": "playwright test --config browser-tests/playwright.config.ts",
97
+ "lint:fix": "oxlint --type-aware --fix src tests scripts browser-tests"
98
+ },
99
+ "dependencies": {
100
+ "@floating-ui/react": "0.27.20",
101
+ "@internationalized/date": "3.12.4",
102
+ "@tanstack/react-query": "5.104.0",
103
+ "fuzzysort": "4.0.2",
104
+ "lucide-react": "1.48.0",
105
+ "react-aria-components": "1.21.1"
106
+ },
107
+ "devDependencies": {
108
+ "@playwright/test": "1.63.0",
109
+ "@types/bun": "1.4.2",
110
+ "@types/react": "19.3.0",
111
+ "@types/react-dom": "19.3.0",
112
+ "oxfmt": "0.70.0",
113
+ "oxlint": "1.85.0",
114
+ "oxlint-tsgolint": "7.0.2003",
115
+ "react": "19.3.0",
116
+ "react-dom": "19.3.0",
117
+ "typescript": "7.0.2"
118
+ },
119
+ "peerDependencies": {
120
+ "react": ">=19.2.0",
121
+ "react-dom": ">=19.2.0"
122
+ },
123
+ "packageManager": "bun@1.4.2"
124
+ }