@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
@@ -0,0 +1,139 @@
1
+ export type QueryResult = {
2
+ columns: {
3
+ name: string;
4
+ type?: string;
5
+ }[];
6
+ rows: unknown[][];
7
+ queryId?: string;
8
+ };
9
+ export declare function parseEmptyInput(value: unknown): Record<string, never>;
10
+ export declare function parseTrue(value: unknown): true;
11
+ export type DateRangeInput = {
12
+ start: string;
13
+ end: string;
14
+ };
15
+ export type DateRangeRequest = {
16
+ range: DateRangeInput;
17
+ comparison: DateRangeInput | null;
18
+ };
19
+ /** The immediately preceding, equally long set of calendar days. */
20
+ export declare function previousDateRange({ start, end, }: DateRangeInput): DateRangeInput;
21
+ export type ReportingPeriod = {
22
+ kind: 'rolling';
23
+ amount: number;
24
+ unit: 'hour' | 'day';
25
+ end: string;
26
+ } | {
27
+ kind: 'calendar';
28
+ start: string;
29
+ end: string;
30
+ timeZone: string;
31
+ };
32
+ export type DateRangeContractOptions = {
33
+ minDate?: string;
34
+ maxDate?: string | (() => string);
35
+ maxRangeDays: number;
36
+ timeZone: string;
37
+ completeDays?: boolean;
38
+ };
39
+ /** One source policy for the server parser, URL variable, and displayed reporting period. */
40
+ export declare function defineDateRangeContract(options: DateRangeContractOptions): {
41
+ request: (value: unknown, compare?: boolean) => DateRangeRequest;
42
+ parseRequest: (value: unknown) => DateRangeRequest;
43
+ bounds: () => {
44
+ minDate: string | undefined;
45
+ maxDate: string;
46
+ maxRangeDays: number;
47
+ timeZone: string;
48
+ };
49
+ parse(value: unknown): DateRangeInput;
50
+ period: ({ start, end }: DateRangeInput) => ReportingPeriod;
51
+ comparison: (input: DateRangeInput) => DateRangeInput | null;
52
+ describeInput: (input: DateRangeInput) => string;
53
+ view: {
54
+ period: ({ start, end }: DateRangeInput) => ReportingPeriod;
55
+ describeInput: (input: DateRangeInput) => string;
56
+ };
57
+ };
58
+ export type DateRangeContract = ReturnType<typeof defineDateRangeContract>;
59
+ /** Validate calendar dates and a bounded inclusive range on the server. */
60
+ export declare function parseDateRangeInput(value: unknown, { minDate, maxDate, maxRangeDays, }: {
61
+ minDate?: string;
62
+ maxDate?: string;
63
+ maxRangeDays: number;
64
+ }): DateRangeInput;
65
+ /** Accepts numeric strings from DuckDB; rejects negative, fractional, and unsafe integers. */
66
+ export declare function parseCount(value: unknown): number;
67
+ export declare function parseLabel(value: unknown, maxLength?: number): string;
68
+ /** Rejects missing or duplicate columns and rows whose width differs from the column list. */
69
+ export declare function rowsAsRecords(result: QueryResult, requiredColumns: readonly string[]): Record<string, unknown>[];
70
+ /** One named statement an operation ran. Returned only when SQL disclosure is allowed. */
71
+ export type DisclosedQuery = {
72
+ name: string;
73
+ statement: string;
74
+ queryId?: string;
75
+ };
76
+ export declare function defineQueryNames<const Names extends Record<string, string>>(names: Names): Names;
77
+ export declare class DataSourceError extends Error {
78
+ readonly reason: 'unauthorized' | 'forbidden' | 'rate_limited' | 'query_rejected' | 'unavailable';
79
+ readonly status?: number | undefined;
80
+ queryName?: string;
81
+ constructor(reason: 'unauthorized' | 'forbidden' | 'rate_limited' | 'query_rejected' | 'unavailable', status?: number | undefined);
82
+ }
83
+ /** Server-only query interface supplied by a local or hosted adapter. */
84
+ export type Lakehouse = {
85
+ queryAll(statement: string, options: {
86
+ limit: number;
87
+ signal: AbortSignal;
88
+ name?: string;
89
+ }): Promise<QueryResult>;
90
+ };
91
+ export type OperationContext = {
92
+ lakehouse: Lakehouse;
93
+ signal: AbortSignal;
94
+ };
95
+ /**
96
+ * Both parsers run on the server before results cross the JSON boundary. Schema libraries can be
97
+ * used inside either parser.
98
+ */
99
+ export type DataOperation<Input, Output> = {
100
+ input: (value: unknown) => Input;
101
+ output: (value: unknown) => Output;
102
+ run: (context: OperationContext, input: Input) => Promise<Output>;
103
+ checks: readonly Input[];
104
+ queryNames?: Readonly<Record<string, string>>;
105
+ policy: {
106
+ maxQueryRows: number;
107
+ maxDurationMs: number;
108
+ maxResponseBytes?: number;
109
+ exposeSql?: boolean;
110
+ };
111
+ };
112
+ export type OperationQuery<Names extends Readonly<Record<string, string>>> = (name: Names[keyof Names], statement: string, options?: {
113
+ limit?: number;
114
+ }) => Promise<QueryResult>;
115
+ export declare function defineOperation<Input, Output, const Names extends Readonly<Record<string, string>> = Record<string, never>>(operation: Omit<DataOperation<Input, Output>, 'run' | 'queryNames'> & {
116
+ queryNames?: Names;
117
+ run: (context: OperationContext & {
118
+ query: OperationQuery<NoInfer<Names>>;
119
+ }, input: Input) => Promise<Output>;
120
+ }): DataOperation<Input, Output> & {
121
+ queryNames?: Names;
122
+ };
123
+ export declare const connectionQueryNames: {
124
+ readonly connection: "connection-check";
125
+ };
126
+ /** Success requires a bounded SQL query; it does not establish access to a particular dataset. */
127
+ export declare function connectionCheck(): DataOperation<Record<string, never>, true>;
128
+ export type DataOperations = Record<string, {
129
+ input: (value: unknown) => unknown;
130
+ output: (value: unknown) => unknown;
131
+ run: (context: OperationContext, input: never) => Promise<unknown>;
132
+ checks: readonly unknown[];
133
+ queryNames?: Readonly<Record<string, string>>;
134
+ policy: DataOperation<never, unknown>['policy'];
135
+ }>;
136
+ export { dimensionFilter, parseDimensionSelection, parseFacetOptions, dimensionPredicate, } from './dimension.js';
137
+ export type { DimensionSelection, DimensionMember, DimensionOption, DimensionVariable, DimensionFilterOptions, } from './dimension.js';
138
+ export * from './messages.js';
139
+ export type { TransportResponse } from './bridge.js';
@@ -0,0 +1,46 @@
1
+ export type DataView<T, Input = unknown> = {
2
+ kind: 'loading';
3
+ } | {
4
+ kind: 'empty';
5
+ input: Input;
6
+ } | {
7
+ kind: 'error';
8
+ error: Error;
9
+ } | {
10
+ kind: 'ready';
11
+ data: T;
12
+ input: Input;
13
+ } | {
14
+ kind: 'updating';
15
+ data: T;
16
+ requestedInput: Input;
17
+ displayedInput: Input;
18
+ message: string;
19
+ } | {
20
+ kind: 'stale-error';
21
+ data: T;
22
+ requestedInput: Input;
23
+ displayedInput: Input;
24
+ error: Error;
25
+ message: string;
26
+ };
27
+ export type DataSnapshot<Data, Input> = {
28
+ data: Data;
29
+ input: Input;
30
+ };
31
+ export type DisplayedSnapshot<Data, Input> = DataSnapshot<Data, Input> & {
32
+ state: 'ready' | 'updating' | 'stale-error';
33
+ };
34
+ /** The result currently shown to the reader, including the input that produced it. */
35
+ export declare function displayedSnapshot<Data, Input>(view: DataView<Data, Input>): DisplayedSnapshot<Data, Input> | undefined;
36
+ /** Keep the requested input separate from the input that produced visible data. */
37
+ export declare function resolveDataView<Data, Input>({ requestedInput, current, previous, pending, error, sameInput, describe, isEmpty, }: {
38
+ requestedInput: Input;
39
+ current?: DataSnapshot<Data, Input>;
40
+ previous?: DataSnapshot<Data, Input>;
41
+ pending: boolean;
42
+ error?: Error;
43
+ sameInput: (a: Input, b: Input) => boolean;
44
+ describe: (input: Input) => string;
45
+ isEmpty: (data: Data) => boolean;
46
+ }): DataView<Data, Input>;
@@ -0,0 +1,20 @@
1
+ /** ISO calendar dates; the app operation defines timezone and inclusive bounds. */
2
+ export type DateRange = {
3
+ start: string;
4
+ end: string;
5
+ };
6
+ export type DatePresetId = 'day' | 'last-3' | 'last-7' | 'last-14' | 'last-30' | 'last-90' | 'this-week' | 'previous-week' | 'this-month' | 'previous-month';
7
+ export type DatePreset = {
8
+ id: DatePresetId;
9
+ label: string;
10
+ range: DateRange;
11
+ };
12
+ export declare function inclusiveDays(range: DateRange): number;
13
+ export declare function withinBounds(range: DateRange, minDate?: string, maxDate?: string, maxRangeDays?: number): boolean;
14
+ /** Only offer ranges the app says it can query. Dates and range lengths are inclusive. */
15
+ export declare function availableDatePresets({ minDate, maxDate, maxRangeDays, timeZone, }: {
16
+ minDate?: string;
17
+ maxDate?: string;
18
+ maxRangeDays?: number;
19
+ timeZone?: string;
20
+ }): DatePreset[];
@@ -0,0 +1,60 @@
1
+ import type { AppVariable, HistoryMode } from './variables.js';
2
+ export type DimensionValue = string | number;
3
+ export type DimensionMember<T extends DimensionValue = DimensionValue> = {
4
+ kind: 'value';
5
+ value: T;
6
+ } | {
7
+ kind: 'missing';
8
+ };
9
+ export type DimensionSelection<T extends DimensionValue = DimensionValue> = {
10
+ kind: 'all';
11
+ } | {
12
+ kind: 'include';
13
+ members: readonly DimensionMember<T>[];
14
+ };
15
+ export type DimensionOption<T extends DimensionValue = DimensionValue> = {
16
+ value: T;
17
+ label: string;
18
+ count?: number;
19
+ };
20
+ export type DimensionVariable<T extends DimensionValue = DimensionValue> = Omit<AppVariable<DimensionSelection<T>, 'dimension'>, 'options'> & {
21
+ label: string;
22
+ selection: 'single' | 'multiple';
23
+ valueType: 'string' | 'number';
24
+ allowMissing: boolean;
25
+ maxSelected: number;
26
+ options: readonly DimensionOption<T>[];
27
+ facet?: {
28
+ operation: string;
29
+ input: (values: Record<string, unknown>) => unknown;
30
+ };
31
+ describe: (selection: DimensionSelection<T>) => string;
32
+ };
33
+ export declare function dimensionMemberKey(member: DimensionMember): string;
34
+ export type DimensionFilterOptions<T extends DimensionValue> = {
35
+ key: string;
36
+ label: string;
37
+ valueType: T extends number ? 'number' : 'string';
38
+ selection: 'single' | 'multiple';
39
+ allowMissing?: boolean;
40
+ maxSelected?: number;
41
+ history?: HistoryMode;
42
+ } & ({
43
+ options: readonly DimensionOption<T>[];
44
+ facet?: never;
45
+ } | {
46
+ /** A bounded operation supplies options and counts; input chooses other filters affecting counts. */
47
+ facet: {
48
+ operation: string;
49
+ input: (values: Record<string, unknown>) => unknown;
50
+ };
51
+ options?: never;
52
+ });
53
+ /** A bounded categorical filter. URL tags distinguish missing from literal "null". */
54
+ export declare function dimensionFilter<const T extends DimensionValue>(config: DimensionFilterOptions<T>): DimensionVariable<T>;
55
+ /** Server-side parser; call from the operation input parser before building SQL. */
56
+ export declare function parseDimensionSelection<T extends DimensionValue>(value: unknown, filter: DimensionVariable<T>): DimensionSelection<T>;
57
+ /** Validate bounded facet results before showing them in a picker. */
58
+ export declare function parseFacetOptions<T extends DimensionValue>(value: unknown, filter: DimensionVariable<T>): DimensionOption<T>[];
59
+ /** Central SQL literal encoding for transports without bound parameters. Column is an allowlisted identifier. */
60
+ export declare function dimensionPredicate<T extends DimensionValue, const Columns extends readonly string[]>(column: Columns[number], selection: DimensionSelection<T>, allowedColumns: Columns): string;
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Date and number formatting with explicit units and missing-value behavior.
3
+ * @module @altertable/data-app/format
4
+ * @see https://github.com/altertable-ai/data-app/blob/main/docs/format.md
5
+ */
6
+ type CommonOptions = {
7
+ locale?: string;
8
+ missing?: string;
9
+ };
10
+ /** Compact, unambiguous calendar dates for labels and request status. */
11
+ export declare function formatDateRange({ start, end, }: {
12
+ start: string;
13
+ end: string;
14
+ }): string;
15
+ export type MetricFormat = {
16
+ kind: 'count';
17
+ compact?: boolean;
18
+ locale?: string;
19
+ } | {
20
+ kind: 'ratio';
21
+ maximumFractionDigits?: number;
22
+ locale?: string;
23
+ } | {
24
+ kind: 'currency';
25
+ currency: string;
26
+ locale?: string;
27
+ };
28
+ export declare function formatMetric(value: number, format: MetricFormat): string;
29
+ /** Missing and non-finite values use the `missing` label; negative zero renders as zero. */
30
+ export declare function formatNumber(value: number | null | undefined, options?: CommonOptions & Intl.NumberFormatOptions): string;
31
+ /** Negative and fractional counts render as missing. Compact notation is opt-in. */
32
+ export declare function formatCount(value: number | null | undefined, options?: CommonOptions & {
33
+ compact?: boolean;
34
+ }): string;
35
+ export declare function pluralize(count: number, singular: string, plural?: string): string;
36
+ /** Accepts a ratio (0.116), not a percentage (11.6). */
37
+ export declare function formatPercent(ratio: number | null | undefined, options?: CommonOptions & {
38
+ maximumFractionDigits?: number;
39
+ }): string;
40
+ export {};
@@ -0,0 +1,2 @@
1
+ /** Assert an author or data contract while preserving a useful failure message. */
2
+ export declare function invariant(condition: unknown, message: string): asserts condition;
@@ -0,0 +1,77 @@
1
+ import type { TransportResponse } from './bridge.js';
2
+ import type { DisclosedQuery } from './contract.js';
3
+ export type MessageContext = {
4
+ signal: AbortSignal;
5
+ };
6
+ export type RoutedMessage = {
7
+ route: string;
8
+ payload: unknown;
9
+ };
10
+ export type MessageDispatcher = (message: unknown, context: MessageContext) => Promise<unknown>;
11
+ export type MessageTransport = (message: RoutedMessage, signal?: AbortSignal) => Promise<unknown>;
12
+ export type MessageRoute<Input, Output> = {
13
+ input: (value: unknown) => Input;
14
+ output: (value: unknown, input: Input) => Output;
15
+ };
16
+ export type MessageRoutes = Record<string, {
17
+ input: (value: unknown) => unknown;
18
+ output: (value: unknown, input: never) => unknown;
19
+ }>;
20
+ export type MessageInput<Route extends MessageRoutes[string]> = ReturnType<Route['input']>;
21
+ export type MessageHandlers<Routes extends MessageRoutes> = {
22
+ [Name in keyof Routes]: (payload: MessageInput<Routes[Name]>, context: MessageContext) => ReturnType<Routes[Name]['output']> | Promise<ReturnType<Routes[Name]['output']>>;
23
+ };
24
+ declare const errorBrand: unique symbol;
25
+ /** Only these deliberate, public failures cross the message boundary. Other errors stay private. */
26
+ export declare class MessageRoutingError extends Error {
27
+ readonly code: string;
28
+ readonly requestId?: string | undefined;
29
+ readonly [errorBrand] = true;
30
+ static [Symbol.hasInstance](value: unknown): boolean;
31
+ constructor(code: string, message: string, requestId?: string | undefined);
32
+ }
33
+ export declare function defineMessageRoute<Input, Output>(route: MessageRoute<Input, Output>): MessageRoute<Input, Output>;
34
+ /** Contracts are shared; handlers are supplied by the host and never belong in the app bundle. */
35
+ export declare function createMessageRouter<const Routes extends MessageRoutes>(routes: Routes, handlers: MessageHandlers<NoInfer<Routes>>): {
36
+ dispatch: (value: unknown, context: MessageContext) => Promise<unknown>;
37
+ };
38
+ export type OperationContracts = Record<string, {
39
+ input: (value: unknown) => unknown;
40
+ output: (value: unknown) => unknown;
41
+ }>;
42
+ export type DataQueryInput<Operations extends OperationContracts> = {
43
+ [Name in keyof Operations & string]: {
44
+ operation: Name;
45
+ input: ReturnType<Operations[Name]['input']>;
46
+ };
47
+ }[keyof Operations & string];
48
+ export type DataQueryBody<Output> = {
49
+ data: Output;
50
+ requestId: string;
51
+ queriedAt: string;
52
+ queryIds: string[];
53
+ queries?: DisclosedQuery[];
54
+ };
55
+ export type DataQueryRoute<Operations extends OperationContracts> = MessageRoute<DataQueryInput<Operations>, TransportResponse> & {
56
+ operations: Operations | undefined;
57
+ };
58
+ export type MessageOutput<Route extends MessageRoutes[string], Input> = Route extends DataQueryRoute<infer Operations> ? Input extends {
59
+ operation: infer Name extends keyof Operations;
60
+ } ? {
61
+ status: number;
62
+ body: DataQueryBody<ReturnType<Operations[Name]['output']>>;
63
+ } : never : ReturnType<Route['output']>;
64
+ /** Omit contracts only in generic hosts such as the CLI shell, where Bun validates operations. */
65
+ export declare function defineDataQueryRoute<Operations extends OperationContracts = OperationContracts>(operations?: Operations): DataQueryRoute<Operations>;
66
+ export type NavigationUpdate = {
67
+ search: string;
68
+ hash: string;
69
+ mode: 'push' | 'replace';
70
+ title?: string;
71
+ };
72
+ export declare const navigationUpdateRoute: MessageRoute<NavigationUpdate, null>;
73
+ export declare const dataAppRoutes: {
74
+ 'data.query': DataQueryRoute<OperationContracts>;
75
+ 'navigation.update': MessageRoute<NavigationUpdate, null>;
76
+ };
77
+ export {};
@@ -0,0 +1,17 @@
1
+ import type { DateRangeRequest } from './contract.js';
2
+ export type DataReading<Value> = {
3
+ loading: true;
4
+ value?: never;
5
+ } | {
6
+ loading: false;
7
+ value: Value;
8
+ };
9
+ /** Zero is measured data. null or omitted means no previous measurement.
10
+ * Comparison activation belongs to the reading's period, not these values. */
11
+ export type MetricValues = {
12
+ current: number;
13
+ previous?: number | null;
14
+ };
15
+ export type MetricReading = DataReading<MetricValues & {
16
+ period?: DateRangeRequest;
17
+ }>;
@@ -0,0 +1,82 @@
1
+ import { type DatePresetId, type DateRange } from './date-range.js';
2
+ import type { DateRangeContract, DateRangeRequest } from './contract.js';
3
+ import type { DimensionSelection, DimensionVariable } from './dimension.js';
4
+ export type HistoryMode = 'push' | 'replace';
5
+ /** An app-owned value with one URL representation. Controls never parse or write routes. */
6
+ export type AppVariable<Value, Kind extends string = Value extends string ? 'text' | 'select' : 'dateRange'> = {
7
+ kind: Kind;
8
+ label?: string;
9
+ options?: readonly {
10
+ id: string;
11
+ label: string;
12
+ }[];
13
+ urlKeys: readonly string[];
14
+ defaultValue: Value;
15
+ history: HistoryMode;
16
+ read: (params: URLSearchParams) => Value;
17
+ write: (value: Value) => Record<string, string | null>;
18
+ valid: (value: Value) => boolean;
19
+ same: (left: Value, right: Value) => boolean;
20
+ };
21
+ export type VariableCollection = Record<string, AppVariable<string> | DateRangeVariable | DimensionVariable<any>>;
22
+ export type AppVariableValues<Variables> = {
23
+ [Key in keyof Variables]: Variables[Key] extends DimensionVariable<infer Value> ? DimensionSelection<Value> : Variables[Key] extends AppVariable<infer Value, string> ? Value : never;
24
+ };
25
+ /** Name variables once in the app. URL keys must be unique across its controls. */
26
+ export declare function defineAppVariables<const Variables extends VariableCollection>(variables: Variables): Variables;
27
+ type ScalarVariableOptions = {
28
+ label?: string;
29
+ key: string;
30
+ defaultValue?: string;
31
+ history?: HistoryMode;
32
+ };
33
+ /** A local text filter. Typing replaces the current history entry by default. */
34
+ export declare function textVariable({ key, label, defaultValue, history, }: ScalarVariableOptions): AppVariable<string>;
35
+ /** A single choice. Supply values when the option set is known before data loads. */
36
+ export declare function selectVariable({ key, label, defaultValue, values, history, }: ScalarVariableOptions & {
37
+ defaultValue: string;
38
+ values?: readonly string[];
39
+ }): AppVariable<string>;
40
+ export type DateRangeSelection = {
41
+ kind: 'preset';
42
+ id: DatePresetId;
43
+ comparison?: 'previous';
44
+ } | {
45
+ kind: 'dates';
46
+ start: string;
47
+ end: string;
48
+ comparison?: 'previous';
49
+ };
50
+ export type DateRangeVariableOptions = {
51
+ label?: string;
52
+ /** URL key for a relative preset; explicit dates use startKey and endKey. */
53
+ key: string;
54
+ startKey?: string;
55
+ endKey?: string;
56
+ defaultValue: DateRangeSelection & {
57
+ comparison?: never;
58
+ };
59
+ contract: DateRangeContract;
60
+ history?: HistoryMode;
61
+ /** Opt into a URL-backed comparison with the preceding equal-length range. */
62
+ comparison?: boolean;
63
+ comparisonKey?: string;
64
+ };
65
+ export type DateRangeVariable = AppVariable<DateRangeSelection> & {
66
+ kind: 'dateRange';
67
+ supportsComparison: boolean;
68
+ input: (selection: DateRangeSelection) => DateRangeRequest;
69
+ describeInput: (input: DateRangeRequest) => string;
70
+ bounds: () => {
71
+ minDate?: string;
72
+ maxDate: string;
73
+ maxRangeDays: number;
74
+ timeZone: string;
75
+ };
76
+ resolve: (selection: DateRangeSelection) => DateRange;
77
+ previous: (selection: DateRangeSelection) => DateRange | null;
78
+ comparisonRange: (selection: DateRangeSelection) => DateRange | null;
79
+ };
80
+ /** A date variable keeps relative presets relative and validates exact dates against source coverage. */
81
+ export declare function dateRangeVariable({ key, label, startKey, endKey, defaultValue, contract, history, comparison, comparisonKey, }: DateRangeVariableOptions): DateRangeVariable;
82
+ export {};
@@ -0,0 +1,5 @@
1
+ /** Run from a trusted bootstrap page in an allow-scripts-only iframe. CSP can prohibit network access. */
2
+ export declare function startDataAppBootstrap({ parentOrigin, window: frame, }: {
3
+ parentOrigin: string;
4
+ window?: Window;
5
+ }): () => void;
@@ -0,0 +1,23 @@
1
+ import { type MessageDispatcher } from '../core/messages.js';
2
+ export type DataAppConnection = {
3
+ type: 'origin';
4
+ origin: string;
5
+ } | {
6
+ type: 'opaque';
7
+ token: string;
8
+ };
9
+ export type DataAppStatus = 'connecting' | 'connected' | 'ready' | 'failed' | 'disconnected';
10
+ export type DataAppDiagnostic = {
11
+ direction: 'send' | 'receive';
12
+ type: string;
13
+ };
14
+ /** The bridge owns delivery and cancellation; the routed handler owns validation, authorization and execution. */
15
+ export declare function attachDataAppBridge({ iframe, connection, javascript, onStatusChange, onDiagnostic, onMessage, window: host, }: {
16
+ iframe: HTMLIFrameElement;
17
+ connection: DataAppConnection;
18
+ javascript?: string;
19
+ onStatusChange?: (status: DataAppStatus) => void;
20
+ onDiagnostic?: (event: DataAppDiagnostic) => void;
21
+ onMessage: MessageDispatcher;
22
+ window?: Window;
23
+ }): () => void;
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Framework-neutral iframe hosting and sandboxed bundle initialization.
3
+ * @module @altertable/data-app/embed
4
+ * @see https://github.com/altertable-ai/data-app/blob/main/docs/embed.md
5
+ */
6
+ export { attachDataAppBridge } from './host.js';
7
+ export type { DataAppConnection, DataAppStatus, DataAppDiagnostic, } from './host.js';
8
+ export { attachDataAppShell } from './shell.js';
9
+ export type { DataAppSource, DataAppShellOptions } from './shell.js';
10
+ export { startDataAppBootstrap } from './bootstrap.js';
11
+ export { createNavigationHandler } from './navigation.js';
@@ -0,0 +1,6 @@
1
+ import type { NavigationUpdate } from '../core/messages.js';
2
+ /** Override this handler for framework routers. Reserved host parameters survive app navigation. */
3
+ export declare function createNavigationHandler({ window: host, reservedSearchParams, }?: {
4
+ window?: Window;
5
+ reservedSearchParams?: readonly string[];
6
+ }): (input: NavigationUpdate) => null;
@@ -0,0 +1,21 @@
1
+ import type { MessageDispatcher } from '../core/messages.js';
2
+ import { type DataAppStatus, type DataAppDiagnostic } from './host.js';
3
+ export type DataAppSource = {
4
+ type: 'url';
5
+ url: string;
6
+ } | {
7
+ type: 'bundle';
8
+ bootstrapUrl: string;
9
+ javascript: string;
10
+ revision: string;
11
+ };
12
+ export type DataAppShellOptions = {
13
+ iframe: HTMLIFrameElement;
14
+ source: DataAppSource;
15
+ onMessage: MessageDispatcher;
16
+ onStatusChange?: (status: DataAppStatus) => void;
17
+ onDiagnostic?: (event: DataAppDiagnostic) => void;
18
+ startupTimeoutMs?: number;
19
+ };
20
+ /** Owns loading and sandbox policy. Dispose before replacing the source or retrying. */
21
+ export declare function attachDataAppShell({ iframe, source, onMessage, onStatusChange, onDiagnostic, startupTimeoutMs, }: DataAppShellOptions): () => void;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,23 @@
1
+ import type { ReactNode } from 'react';
2
+ import type { DataReading, MetricReading, MetricValues } from '../core/reading.js';
3
+ import type { DateRangeRequest } from '../core/contract.js';
4
+ export type DataContentHelpers<Data> = {
5
+ select: <Value>(select: (data: Data) => Value) => DataReading<Value>;
6
+ metric: (select: (data: Data) => MetricValues) => MetricReading;
7
+ };
8
+ export type DataContentState<Data, Input> = DataContentHelpers<Data> & ({
9
+ loading: true;
10
+ data?: never;
11
+ input?: never;
12
+ } | {
13
+ loading: false;
14
+ data: Data;
15
+ input: Input;
16
+ });
17
+ /** Selectors run only for displayed data. Date comparisons inherit that result's input. */
18
+ export declare function defineDataContent<Data, Input>(render: (state: DataContentState<Data, Input>) => ReactNode, options?: {
19
+ date?: (input: Input) => DateRangeRequest;
20
+ }): {
21
+ loading: ReactNode;
22
+ children(data: Data, input: Input): ReactNode;
23
+ };
@@ -0,0 +1,12 @@
1
+ import { type ComponentRef } from 'react';
2
+ import { type DataAppConnection, type DataAppStatus, type DataAppDiagnostic } from '../../embed/host.js';
3
+ import type { MessageDispatcher } from '../../core/messages.js';
4
+ export type DataAppBridgeProps = {
5
+ iframe: ComponentRef<'iframe'> | null;
6
+ connection: DataAppConnection;
7
+ onMessage: MessageDispatcher;
8
+ onStatusChange?: (status: DataAppStatus) => void;
9
+ onDiagnostic?: (event: DataAppDiagnostic) => void;
10
+ };
11
+ /** Delivery only; the host owns the iframe and route handlers, including navigation. */
12
+ export declare function DataAppBridge({ iframe, connection, onMessage, onStatusChange, onDiagnostic, }: DataAppBridgeProps): null;
@@ -0,0 +1,9 @@
1
+ /**
2
+ * React iframe hosts; independent of the app UI and its stylesheet.
3
+ * @module @altertable/data-app/react/embed
4
+ * @see https://github.com/altertable-ai/data-app/blob/main/docs/react-embed.md
5
+ */
6
+ export { DataAppBridge } from './bridge.js';
7
+ export type { DataAppBridgeProps } from './bridge.js';
8
+ export { DataAppShell } from './shell.js';
9
+ export type { DataAppShellProps } from './shell.js';
@@ -0,0 +1,10 @@
1
+ import { type ReactNode } from 'react';
2
+ import { type DataAppSource, type DataAppShellOptions } from '../../embed/shell.js';
3
+ export type DataAppShellProps = Pick<DataAppShellOptions, 'onMessage' | 'onStatusChange' | 'onDiagnostic' | 'startupTimeoutMs'> & {
4
+ source: DataAppSource;
5
+ title: string;
6
+ loading?: ReactNode;
7
+ renderError?: (retry: () => void) => ReactNode;
8
+ };
9
+ /** Source changes and retries replace the entire frame; handler changes retain its session. */
10
+ export declare function DataAppShell({ source, title, onMessage, onStatusChange, onDiagnostic, startupTimeoutMs, loading, renderError, }: DataAppShellProps): import("react").JSX.Element;