@altertable/data-app 0.61.0 → 0.63.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.
- package/AGENTS.md +4 -32
- package/CONTRIBUTING.md +63 -72
- package/README.md +14 -38
- package/dist/chunks/{contract-d9skd1n7.js → contract-8wdybxj7.js} +163 -16
- package/dist/chunks/contract-8wdybxj7.js.map +13 -0
- package/dist/chunks/{contract-ryyf6dme.js → contract-cxr9t12b.js} +2 -5
- package/dist/chunks/contract-cxr9t12b.js.map +10 -0
- package/dist/chunks/{contract-14vxdcrs.js → contract-farfe948.js} +17 -21
- package/dist/chunks/contract-farfe948.js.map +10 -0
- package/dist/chunks/contract-mev09s5v.js.map +2 -2
- package/dist/chunks/{contract-ehk50k7e.js → contract-tf8c3qpv.js} +34 -4
- package/dist/chunks/contract-tf8c3qpv.js.map +11 -0
- package/dist/chunks/{contract-zr4s2g7m.js → contract-tkc552ze.js} +75 -36
- package/dist/chunks/contract-tkc552ze.js.map +12 -0
- package/dist/chunks/{contract-nt819swq.js → contract-wd8qe3mt.js} +6 -1
- package/dist/chunks/{contract-nt819swq.js.map → contract-wd8qe3mt.js.map} +3 -3
- package/dist/chunks/contract-wz59z8pq.js.map +1 -1
- package/dist/chunks/{contract-7gpsee0v.js → contract-zr3jd7mr.js} +51 -22
- package/dist/chunks/contract-zr3jd7mr.js.map +12 -0
- package/dist/client/index.js +7 -6
- package/dist/client/index.js.map +1 -1
- package/dist/core/appearance.js +1 -1
- package/dist/core/contract.js +6 -4
- package/dist/core/contract.js.map +1 -1
- package/dist/embed/index.js +41 -9
- package/dist/embed/index.js.map +5 -4
- package/dist/local.js +172 -84
- package/dist/local.js.map +7 -8
- package/dist/react/embed/index.js +83 -99
- package/dist/react/embed/index.js.map +4 -5
- package/dist/react/index.js +5701 -324
- package/dist/react/index.js.map +74 -65
- package/dist/server.js +153 -81
- package/dist/server.js.map +6 -7
- package/dist/types/client/data-client.d.ts +33 -0
- package/dist/types/client/iframe.d.ts +14 -0
- package/dist/types/client/index.d.ts +4 -34
- package/dist/types/client/location.d.ts +4 -6
- package/dist/types/client/navigation.d.ts +2 -1
- package/dist/types/core/appearance.d.ts +7 -6
- package/dist/types/core/bridge.d.ts +2 -8
- package/dist/types/core/config.d.ts +1 -1
- package/dist/types/core/contract.d.ts +9 -56
- package/dist/types/core/format.d.ts +0 -1
- package/dist/types/core/messages.d.ts +11 -30
- package/dist/types/core/navigation.d.ts +11 -0
- package/dist/types/core/operation-types.d.ts +76 -0
- package/dist/types/core/operation.d.ts +21 -0
- package/dist/types/core/presentation.d.ts +7 -0
- package/dist/types/core/variables.d.ts +2 -2
- package/dist/types/embed/bridge.d.ts +12 -0
- package/dist/types/embed/host.d.ts +14 -5
- package/dist/types/embed/index.d.ts +6 -4
- package/dist/types/embed/source.d.ts +15 -0
- package/dist/types/embed/sql.d.ts +4 -0
- package/dist/types/react/content.d.ts +3 -3
- package/dist/types/react/embed/bridge.d.ts +19 -10
- package/dist/types/react/embed/index.d.ts +0 -2
- package/dist/types/react/hooks.d.ts +65 -64
- package/dist/types/react/index.d.ts +135 -2
- package/dist/types/react/injectStyles.d.ts +7 -0
- package/dist/types/react/shellStyles.d.ts +3 -0
- package/dist/types/react/styles.d.ts +8 -0
- package/dist/types/react/ui/AboutData.d.ts +0 -1
- package/dist/types/react/ui/AppFooter.d.ts +0 -1
- package/dist/types/react/ui/AppHeader.d.ts +0 -1
- package/dist/types/react/ui/AppLayout.d.ts +0 -1
- package/dist/types/react/ui/AppScope.d.ts +0 -1
- package/dist/types/react/ui/AppToolbar.d.ts +0 -1
- package/dist/types/react/ui/Breakdown.d.ts +0 -1
- package/dist/types/react/ui/Button.d.ts +0 -1
- package/dist/types/react/ui/Checkbox.d.ts +0 -1
- package/dist/types/react/ui/Combobox.d.ts +0 -1
- package/dist/types/react/ui/ComparisonVisual.d.ts +0 -1
- package/dist/types/react/ui/ContentSkeleton.d.ts +2 -5
- package/dist/types/react/ui/DataApp.d.ts +2 -2
- package/dist/types/react/ui/DataAppSkeleton.d.ts +7 -0
- package/dist/types/react/ui/DataBoundary.d.ts +0 -1
- package/dist/types/react/ui/DataSection.d.ts +2 -4
- package/dist/types/react/ui/DataTable.d.ts +2 -3
- package/dist/types/react/ui/DataViewToast.d.ts +0 -1
- package/dist/types/react/ui/DataWidget.d.ts +4 -14
- package/dist/types/react/ui/DateRangePicker.d.ts +0 -1
- package/dist/types/react/ui/DateTimeTooltip.d.ts +0 -1
- package/dist/types/react/ui/EmptyState.d.ts +2 -5
- package/dist/types/react/ui/GettingStarted.d.ts +0 -1
- package/dist/types/react/ui/GlossaryDefinition.d.ts +0 -1
- package/dist/types/react/ui/GlossaryExplanation.d.ts +0 -1
- package/dist/types/react/ui/GradientScroll.d.ts +0 -1
- package/dist/types/react/ui/Grid.d.ts +0 -1
- package/dist/types/react/ui/HelpPopover.d.ts +0 -2
- package/dist/types/react/ui/Kbd.d.ts +0 -1
- package/dist/types/react/ui/LiveControl.d.ts +0 -1
- package/dist/types/react/ui/MetricWidget.d.ts +0 -2
- package/dist/types/react/ui/PeriodSummary.d.ts +0 -1
- package/dist/types/react/ui/PresentStory.d.ts +0 -1
- package/dist/types/react/ui/QueryList.d.ts +0 -1
- package/dist/types/react/ui/Ranking.d.ts +0 -1
- package/dist/types/react/ui/RefreshControl.d.ts +0 -1
- package/dist/types/react/ui/RefreshRegion.d.ts +0 -1
- package/dist/types/react/ui/RequestHint.d.ts +0 -1
- package/dist/types/react/ui/SearchField.d.ts +0 -1
- package/dist/types/react/ui/SearchInput.d.ts +1 -2
- package/dist/types/react/ui/SearchMatch.d.ts +0 -1
- package/dist/types/react/ui/SelectableBarChart.d.ts +0 -1
- package/dist/types/react/ui/SelectionMark.d.ts +0 -1
- package/dist/types/react/ui/Sheet.d.ts +0 -1
- package/dist/types/react/ui/Skeleton.d.ts +0 -1
- package/dist/types/react/ui/Stack.d.ts +0 -1
- package/dist/types/react/ui/StatusPanel.d.ts +0 -1
- package/dist/types/react/ui/TableWidget.d.ts +2 -3
- package/dist/types/react/ui/Tabs.d.ts +0 -1
- package/dist/types/react/ui/TextContent.d.ts +4 -0
- package/dist/types/react/ui/TextWidget.d.ts +19 -0
- package/dist/types/react/ui/ThemeSelector.d.ts +0 -1
- package/dist/types/react/ui/Tooltip.d.ts +0 -1
- package/dist/types/react/ui/UpdatedAt.d.ts +0 -1
- package/dist/types/react/ui/VariableBar.d.ts +0 -1
- package/dist/types/react/ui/VisualizationWidget.d.ts +5 -13
- package/dist/types/react/ui/WidgetDisclosure.d.ts +0 -1
- package/dist/types/react/ui/WidgetViewTabs.d.ts +2 -3
- package/dist/types/react/ui/data-identifiers.d.ts +0 -1
- package/dist/types/react/ui/presentation.d.ts +19 -0
- package/dist/types/react/ui/useAppAppearance.d.ts +3 -0
- package/dist/types/react/ui/useDataAppPresentation.d.ts +3 -0
- package/dist/types/react/view-controls.d.ts +2 -2
- package/dist/types/react/view.d.ts +2 -2
- package/dist/{bootstrap.js → worker.js} +144 -12
- package/docs/app-authoring.md +60 -24
- package/docs/client.md +48 -19
- package/docs/contract.md +10 -10
- package/docs/embed.md +94 -26
- package/docs/hosted-apps.md +39 -0
- package/docs/local-data-apps.md +14 -0
- package/docs/react-embed.md +75 -24
- package/docs/react.md +118 -93
- package/docs/server-bun.md +4 -1
- package/docs/server.md +2 -2
- package/docs/worker.md +55 -0
- package/examples/starter-data-app/index.tsx +159 -0
- package/package.json +18 -12
- package/dist/chunks/contract-14vxdcrs.js.map +0 -10
- package/dist/chunks/contract-7gpsee0v.js.map +0 -11
- package/dist/chunks/contract-d9skd1n7.js.map +0 -12
- package/dist/chunks/contract-ehk50k7e.js.map +0 -10
- package/dist/chunks/contract-ryyf6dme.js.map +0 -10
- package/dist/chunks/contract-zr4s2g7m.js.map +0 -12
- package/dist/react/index.css +0 -4478
- package/dist/react.css.d.ts +0 -1
- package/dist/types/embed/shell.d.ts +0 -21
- package/dist/types/embed/standalone.d.ts +0 -1
- package/dist/types/react/embed/shell.d.ts +0 -10
- package/dist/types/react/ui/index.d.ts +0 -129
- package/docs/appearance.md +0 -30
- package/docs/bootstrap.md +0 -76
- package/docs/config.md +0 -21
- package/docs/format.md +0 -29
- package/docs/react-styles.md +0 -17
- package/docs/starter-agent-instructions.md +0 -53
package/docs/embed.md
CHANGED
|
@@ -6,13 +6,13 @@ app UI stylesheet.
|
|
|
6
6
|
|
|
7
7
|
## Sources
|
|
8
8
|
|
|
9
|
-
`
|
|
9
|
+
`attachDataAppBridge()` in source mode owns iframe loading, sandbox policy, startup timeout, and
|
|
10
10
|
message delivery. The host supplies an iframe and a validated message dispatcher:
|
|
11
11
|
|
|
12
12
|
```ts
|
|
13
|
-
import {
|
|
13
|
+
import { attachDataAppBridge } from '@altertable/data-app/embed';
|
|
14
14
|
|
|
15
|
-
const
|
|
15
|
+
const host = attachDataAppBridge({
|
|
16
16
|
iframe,
|
|
17
17
|
source: { type: 'url', url: 'https://apps.example.com/report' },
|
|
18
18
|
onMessage: router.dispatch,
|
|
@@ -20,8 +20,8 @@ const dispose = attachDataAppShell({
|
|
|
20
20
|
```
|
|
21
21
|
|
|
22
22
|
The host defines `iframe` and `router`; see [message contracts](contract.md#message-routes).
|
|
23
|
-
|
|
24
|
-
and a different origin from its host. The
|
|
23
|
+
Call `host.dispose()` before replacing the source or retrying. A URL source requires HTTP(S)
|
|
24
|
+
and a different origin from its host. The source bridge adds `__altertable_parent` to the
|
|
25
25
|
app URL. A hosted app must explicitly install a transport to its configured,
|
|
26
26
|
trusted parent origin using the [client API](client.md#iframe-transport).
|
|
27
27
|
The query parameter alone does not establish trust.
|
|
@@ -31,24 +31,25 @@ A bundle source has this shape:
|
|
|
31
31
|
```ts
|
|
32
32
|
const source = {
|
|
33
33
|
type: 'bundle' as const,
|
|
34
|
-
bootstrapUrl: 'https://
|
|
34
|
+
bootstrapUrl: 'https://my-report-app-1.apps.example.net/',
|
|
35
35
|
javascript: bundle.javascript,
|
|
36
|
-
revision: bundle.revision,
|
|
37
36
|
};
|
|
38
37
|
```
|
|
39
38
|
|
|
40
|
-
The host provides a self-contained JavaScript bundle
|
|
41
|
-
|
|
39
|
+
The host provides a self-contained JavaScript bundle. React bridges replace the
|
|
40
|
+
iframe whenever its JavaScript content changes. Serve the bootstrap page with a CSP compatible with the bundle.
|
|
42
41
|
Bundle mode uses `sandbox="allow-scripts"` and an opaque origin; it cannot read
|
|
43
42
|
the host document or use same-origin privileges. Both modes use
|
|
44
43
|
`referrerPolicy="no-referrer"`.
|
|
45
44
|
|
|
46
45
|
## Trusted bootstrap
|
|
47
46
|
|
|
48
|
-
For
|
|
49
|
-
|
|
47
|
+
For Cloudflare hosting, upload the [Worker asset](worker.md). It includes the
|
|
48
|
+
bootstrap HTML and security policy; deployments supply the runtime domain and
|
|
49
|
+
trusted parent origins through bindings.
|
|
50
50
|
|
|
51
|
-
|
|
51
|
+
For other hosts that own their HTML and security policy, bundle this initializer
|
|
52
|
+
into the bootstrap document before any app code:
|
|
52
53
|
|
|
53
54
|
```ts
|
|
54
55
|
import { startDataAppBootstrap } from '@altertable/data-app/embed';
|
|
@@ -59,22 +60,21 @@ const dispose = startDataAppBootstrap({
|
|
|
59
60
|
```
|
|
60
61
|
|
|
61
62
|
The bootstrap URL is trusted executable code: it receives the app script and
|
|
62
|
-
session token. Its hosting service must enforce its CSP. The
|
|
63
|
+
session token. Its hosting service must enforce its CSP. The bridge cannot impose
|
|
63
64
|
CSP on a remote response. A starting policy for self-contained scripts and styles
|
|
64
65
|
is `default-src 'none'; script-src 'unsafe-inline'; style-src 'unsafe-inline';
|
|
65
66
|
img-src data: blob:; connect-src 'none'; base-uri 'none'; form-action 'none'`.
|
|
66
67
|
The initializer installs a shared transport before evaluating the app script;
|
|
67
68
|
data clients discover it even when independently bundled. The bootstrap contains
|
|
68
69
|
no app navigation adapter. React mounting or URL controls attach navigation in the
|
|
69
|
-
app bundle; non-React apps use `createDataAppNavigation` from `/client`.
|
|
70
|
+
app bundle; non-React apps use `createDataAppNavigation()` from `/client`.
|
|
70
71
|
|
|
71
72
|
## Delivery and navigation
|
|
72
73
|
|
|
73
|
-
`attachDataAppBridge`
|
|
74
|
+
`attachDataAppBridge()` also supports connection mode for a host-owned iframe. Supply
|
|
74
75
|
`connection: { type: 'origin', origin }` or `{ type: 'opaque', token }`, and an
|
|
75
|
-
`onMessage` dispatcher. It returns
|
|
76
|
-
correlation, cancellation, bounded pending requests, and reconnection. Use
|
|
77
|
-
shell for bundle loading and token rotation. The opaque destination requires
|
|
76
|
+
`onMessage` dispatcher. Both modes use the same transport. It returns `dispose()` and `setPresentation()` methods and owns source/origin checks, request
|
|
77
|
+
correlation, cancellation, bounded pending requests, and reconnection. Use source mode for bundle loading and token rotation. The opaque destination requires
|
|
78
78
|
wildcard delivery, but incoming messages still require the exact iframe window,
|
|
79
79
|
null origin, token, document, and session to match.
|
|
80
80
|
|
|
@@ -91,16 +91,84 @@ opaque apps keep that state in memory rather than modifying their document URL.
|
|
|
91
91
|
`disconnected`. `connected` means transport initialization; `ready` means a URL
|
|
92
92
|
client acknowledged initialization or a bundle script finished evaluation. It
|
|
93
93
|
does not mean asynchronous data queries finished. Script errors report `failed`.
|
|
94
|
-
The
|
|
94
|
+
The source bridge's `startupTimeoutMs` defaults to 30 seconds.
|
|
95
95
|
|
|
96
96
|
`onDiagnostic` receives only message `direction` and `type`, never tokens or
|
|
97
97
|
payloads. Routed handlers must authorize every data request. Message validation
|
|
98
98
|
and iframe isolation do not grant access to data or execute SQL.
|
|
99
99
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
100
|
+
## SQL query route
|
|
101
|
+
|
|
102
|
+
Hosts serving browser-owned operations register `sqlQueryRoute` explicitly:
|
|
103
|
+
|
|
104
|
+
```ts
|
|
105
|
+
import {
|
|
106
|
+
createMessageRouter,
|
|
107
|
+
sqlQueryRoute,
|
|
108
|
+
} from '@altertable/data-app/contract';
|
|
109
|
+
import { createSqlQueryHandler } from '@altertable/data-app/embed';
|
|
110
|
+
|
|
111
|
+
const router = createMessageRouter(
|
|
112
|
+
{ 'data:sql': sqlQueryRoute },
|
|
113
|
+
{
|
|
114
|
+
'data:sql': createSqlQueryHandler(async (query, { signal }) => {
|
|
115
|
+
return authorizedLakehouseForCurrentViewer(query, signal);
|
|
116
|
+
}),
|
|
117
|
+
}
|
|
118
|
+
);
|
|
119
|
+
// Supply router.dispatch as the shell's onMessage handler.
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
The host supplies `authorizedLakehouseForCurrentViewer()`. Its backend must enforce
|
|
123
|
+
viewer/dataset permissions, permitted query behavior, maximum rows, execution
|
|
124
|
+
time, concurrency, and response size independently of browser policy. Route
|
|
125
|
+
validation is not SQL authorization. `createSqlQueryHandler()` calls authorization
|
|
126
|
+
for each query, forwards cancellation, and preserves `DataSourceError` reasons
|
|
127
|
+
as public `source_*` errors with request IDs. Authorization failures return
|
|
128
|
+
`forbidden`; unknown query errors are hidden. Custom handlers can return deliberate
|
|
129
|
+
public failures with `MessageRoutingError`.
|
|
130
|
+
|
|
131
|
+
`SqlQueryInput` (exported from `/contract`) carries
|
|
132
|
+
`{ statement: string, limit: number }`; responses are
|
|
133
|
+
`{ columns: { name: string, type?: string }[], rows: unknown[][], queryId?: string }`.
|
|
134
|
+
The route rejects empty statements, unsafe or nonpositive limits, malformed
|
|
135
|
+
results, and results exceeding the requested limit. The bridge's existing payload
|
|
136
|
+
and pending-call limits apply, and cancellation reaches the handler's signal.
|
|
137
|
+
Operation names and inputs stay in the app; query evidence is assembled there.
|
|
138
|
+
|
|
139
|
+
`dataAppRoutes` retains named `data:query` and navigation routes for existing
|
|
140
|
+
server-backed hosts. SQL hosts opt into `data:sql`; they need no named-operation
|
|
141
|
+
handler unless they also serve HTTP-style apps. Update the host before switching
|
|
142
|
+
an app to browser-owned operations. Older hosts reject `data:sql` as unknown.
|
|
143
|
+
|
|
144
|
+
## Parent presentation
|
|
145
|
+
|
|
146
|
+
The parent declares where the iframe is mounted and owns its resolved theme:
|
|
147
|
+
|
|
148
|
+
```ts
|
|
149
|
+
const host = attachDataAppBridge({
|
|
150
|
+
iframe,
|
|
151
|
+
source: { type: 'url', url: 'https://apps.example.com/report' },
|
|
152
|
+
presentation: { surface: 'embedded', theme: 'dark' },
|
|
153
|
+
onMessage: router.dispatch,
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
// Update presentation without replacing the iframe or its bridge session.
|
|
157
|
+
host.setPresentation({ surface: 'embedded', theme: 'light' });
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
Both source and connection modes support the `presentation` option and
|
|
161
|
+
`host.setPresentation(presentation)` method. `DataAppPresentation` is exported from
|
|
162
|
+
`/embed`. Use `surface: 'embedded'` when the parent provides page chrome, as in the
|
|
163
|
+
Altertable frontend, and `'standalone'` when the app provides its own header and
|
|
164
|
+
footer. `theme` must be resolved to `'light'` or
|
|
165
|
+
`'dark'`; the parent decides how its system preference is resolved.
|
|
166
|
+
|
|
167
|
+
Presentation travels over `postMessage()` in the authenticated `bridge:initialize` and
|
|
168
|
+
`state:update` messages, alongside `search` and `hash`. Framework-neutral apps
|
|
169
|
+
can narrow the unknown state returned by `bridge.snapshot()` to read its
|
|
170
|
+
`presentation` field, and subscribe through `bridge.subscribe()`. React `<DataApp>` consumes it automatically.
|
|
171
|
+
An embedded surface renders toolbar actions without the page header or footer.
|
|
172
|
+
Both surfaces follow the parent's theme, including presentation mode, without
|
|
173
|
+
changing saved viewer preferences. Omitting presentation preserves standalone behavior;
|
|
174
|
+
`host.setPresentation(undefined)` restores it.
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# Author a data app
|
|
2
|
+
|
|
3
|
+
Follow the [shared authoring flow](app-authoring.md) using [index.tsx](../examples/starter-data-app/index.tsx) for a hosted / remote / cloud data app. Keep the app in
|
|
4
|
+
one file with public package imports; omit server files, HTML, credentials, and
|
|
5
|
+
relative or app-alias imports.
|
|
6
|
+
|
|
7
|
+
Replace the sample SQL, parsers, filters, data context, story, and configuration with
|
|
8
|
+
an exploration of the source data you inspected. The starter uses two SQL
|
|
9
|
+
`VALUES` rows, so it needs no production table.
|
|
10
|
+
|
|
11
|
+
For execution details, see [browser-owned operations](client.md#browser-owned-operations-for-bundle-apps).
|
|
12
|
+
|
|
13
|
+
## Convert a local data app
|
|
14
|
+
|
|
15
|
+
1. Combine the app's operations and parsers, data context, views, story,
|
|
16
|
+
configuration, and browser entry into one `index.tsx`, following the
|
|
17
|
+
[single-file starter](../examples/starter-data-app/index.tsx).
|
|
18
|
+
2. Replace the HTTP client with `createDataClient({ operations })`, using the
|
|
19
|
+
operation registry as a value. See [browser-owned operations](client.md#browser-owned-operations-for-bundle-apps)
|
|
20
|
+
for execution through the host.
|
|
21
|
+
3. Remove the Bun server, HTML, server adapters, credentials, and relative or
|
|
22
|
+
app-alias imports. Rewrite any operation that depends on server-only code
|
|
23
|
+
to use the operation's `query()` helper.
|
|
24
|
+
4. Confirm the host can query the same catalogs, tables, and fields.
|
|
25
|
+
[Verify the app](app-authoring.md#verify-the-app) in the hosted runtime against
|
|
26
|
+
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).
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# Author a local data app
|
|
2
|
+
|
|
3
|
+
Start from the CLI scaffold or the [local starter](https://github.com/altertable-ai/data-app/tree/main/examples/starter-local-data-app).
|
|
4
|
+
Use the starter's README for setup and its AGENTS.md to find app-owned files.
|
|
5
|
+
Replace the connectivity screen with the exploration and story from the
|
|
6
|
+
[shared authoring flow](app-authoring.md).
|
|
7
|
+
|
|
8
|
+
| Task | Documentation |
|
|
9
|
+
| --------------------------------------- | ---------------------------------------- |
|
|
10
|
+
| Serve locally with Bun | [Bun server](server-bun.md) |
|
|
11
|
+
| Execute and authorize server operations | [Server](server.md) |
|
|
12
|
+
| Call operations from the browser | [HTTP client](client.md#http-operations) |
|
|
13
|
+
|
|
14
|
+
You can also [convert the local app to a hosted data app](hosted-apps.md#convert-a-local-data-app).
|
package/docs/react-embed.md
CHANGED
|
@@ -1,36 +1,70 @@
|
|
|
1
1
|
# React embedding
|
|
2
2
|
|
|
3
|
-
Import
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
Import `<DataAppBridge>` from `@altertable/data-app/react/embed`. This entry depends
|
|
4
|
+
on React and the embedding engine, and does not load the app's widgets, React
|
|
5
|
+
Query, or CSS.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
The bridge owns iframe setup and `postMessage()` communication. The consuming
|
|
8
|
+
frontend or CLI owns its shell: fetching a bundle, subscriptions, layout, loading
|
|
9
|
+
and error UI, and retry controls. Both hosts use the same bridge and transport.
|
|
10
|
+
|
|
11
|
+
## Source-managed iframe
|
|
12
|
+
|
|
13
|
+
Use `source` for local URL apps or hosted bundles. The bridge creates the iframe,
|
|
14
|
+
configures its sandbox, loads its source, and reports connection status. It renders
|
|
15
|
+
only the iframe; it adds no loading, error, or retry UI and does not hide the frame.
|
|
8
16
|
|
|
9
17
|
```tsx
|
|
10
|
-
import {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
18
|
+
import { useReducer, useState } from 'react';
|
|
19
|
+
import { DataAppBridge } from '@altertable/data-app/react/embed';
|
|
20
|
+
import type { DataAppStatus } from '@altertable/data-app/embed';
|
|
21
|
+
|
|
22
|
+
function Shell() {
|
|
23
|
+
const [status, setStatus] = useState<DataAppStatus>('connecting');
|
|
24
|
+
const [attempt, retry] = useReducer(value => value + 1, 0);
|
|
25
|
+
|
|
26
|
+
return (
|
|
27
|
+
<div className="app-shell">
|
|
28
|
+
{status !== 'ready' && status !== 'failed' && <p>Loading report…</p>}
|
|
29
|
+
{status === 'failed' && <button onClick={retry}>Retry report</button>}
|
|
30
|
+
<DataAppBridge
|
|
31
|
+
key={attempt}
|
|
32
|
+
title="Activity report"
|
|
33
|
+
source={{ type: 'url', url: 'http://127.0.0.1:25837/' }}
|
|
34
|
+
onMessage={router.dispatch}
|
|
35
|
+
onStatusChange={setStatus}
|
|
36
|
+
iframeProps={{ className: 'app-frame', hidden: status !== 'ready' }}
|
|
37
|
+
/>
|
|
38
|
+
</div>
|
|
39
|
+
);
|
|
40
|
+
}
|
|
19
41
|
```
|
|
20
42
|
|
|
21
43
|
The host supplies `router` using [message contracts](contract.md#message-routes).
|
|
22
|
-
|
|
23
|
-
`source
|
|
44
|
+
The local URL must have a different origin from its shell. For hosted bundles,
|
|
45
|
+
replace `source` with:
|
|
46
|
+
|
|
47
|
+
```tsx
|
|
48
|
+
source={{ type: 'bundle', bootstrapUrl, javascript }}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
The host supplies those bundle values. See [embedding](embed.md) for trust,
|
|
52
|
+
sandbox, CSP, and bootstrap setup.
|
|
24
53
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
without resetting the session. `startupTimeoutMs`, `onStatusChange`, and
|
|
28
|
-
`onDiagnostic` have the same meaning as in the framework-neutral API.
|
|
29
|
-
|
|
54
|
+
Source URL or JavaScript content changes replace the entire iframe. Change the
|
|
55
|
+
bridge's React `key` to retry with a fresh frame. Handler changes use the latest
|
|
56
|
+
callbacks without resetting the session. `startupTimeoutMs`, `onStatusChange`, and
|
|
57
|
+
`onDiagnostic` have the same meaning as in the framework-neutral API.
|
|
58
|
+
|
|
59
|
+
`iframeProps` forwards presentation and accessibility attributes to the iframe,
|
|
60
|
+
including `className`, `style`, and `hidden`. The bridge controls `src`, `srcDoc`,
|
|
61
|
+
`sandbox`, `referrerPolicy`, `loading`, and the callback ref. Loading is always
|
|
62
|
+
`eager` so an iframe hidden until ready can start. Supply `title` directly.
|
|
30
63
|
|
|
31
64
|
## Host-owned iframe
|
|
32
65
|
|
|
33
|
-
Use
|
|
66
|
+
Use the same `<DataAppBridge>` with `iframe` and `connection` when the host already
|
|
67
|
+
owns a loaded iframe and its security policy:
|
|
34
68
|
|
|
35
69
|
```tsx
|
|
36
70
|
import { useState, type ComponentRef } from 'react';
|
|
@@ -52,6 +86,23 @@ function Host() {
|
|
|
52
86
|
```
|
|
53
87
|
|
|
54
88
|
The app supplies `appUrl` and `router`. A callback ref lets the bridge observe late
|
|
55
|
-
mounting and replacement; listeners attach to the iframe's owner document.
|
|
56
|
-
|
|
57
|
-
sandbox policy,
|
|
89
|
+
mounting and replacement; listeners attach to the iframe's owner document. This
|
|
90
|
+
mode renders nothing and handles delivery only. Use source mode for bundle
|
|
91
|
+
loading, sandbox policy, token rotation, and startup timeout. The two prop modes
|
|
92
|
+
are mutually exclusive.
|
|
93
|
+
|
|
94
|
+
## Loading an embedded app
|
|
95
|
+
|
|
96
|
+
Use `<DataAppSkeleton>` from `/react` while the host builds or starts an app.
|
|
97
|
+
Call `injectDataAppShellStyles()` from `/react` before rendering the placeholder.
|
|
98
|
+
The host owns when to show it and supplies any surrounding header or footer.
|
|
99
|
+
`/react/embed` itself remains independent of UI components and styles.
|
|
100
|
+
|
|
101
|
+
## Parent-owned presentation
|
|
102
|
+
|
|
103
|
+
Pass `presentation={{ surface: 'embedded', theme: resolvedTheme }}`
|
|
104
|
+
to `<DataAppBridge>` in either source or connection mode. Use `'standalone'` when the app should render its own page chrome.
|
|
105
|
+
Prop updates publish trusted state without reloading the iframe or reconnecting
|
|
106
|
+
the session. Resolve system preference in the parent to `'light'` or `'dark'`.
|
|
107
|
+
Inside an embedded surface, `<DataApp>` retains toolbar actions and hides its header
|
|
108
|
+
and footer. See [parent presentation](embed.md#parent-presentation).
|