@altertable/data-app 0.61.0 → 0.62.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 +5 -3
- package/CONTRIBUTING.md +7 -4
- package/README.md +14 -14
- package/dist/chunks/{contract-ehk50k7e.js → contract-3bnrf5pf.js} +25 -3
- package/dist/chunks/contract-3bnrf5pf.js.map +10 -0
- package/dist/chunks/{contract-zr4s2g7m.js → contract-4vrw9zk9.js} +41 -11
- package/dist/chunks/contract-4vrw9zk9.js.map +12 -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-nt819swq.js.map +1 -1
- package/dist/chunks/{contract-7gpsee0v.js → contract-rrm7s5zp.js} +48 -19
- package/dist/chunks/contract-rrm7s5zp.js.map +12 -0
- package/dist/chunks/{contract-d9skd1n7.js → contract-xjv197ck.js} +161 -14
- package/dist/chunks/contract-xjv197ck.js.map +13 -0
- package/dist/client/index.js +6 -4
- package/dist/client/index.js.map +1 -1
- package/dist/core/appearance.js +1 -1
- package/dist/core/contract.js +5 -3
- package/dist/core/contract.js.map +1 -1
- package/dist/embed/index.js +42 -8
- package/dist/embed/index.js.map +5 -4
- package/dist/local.js +191 -79
- package/dist/local.js.map +8 -7
- package/dist/react/embed/index.js +84 -99
- package/dist/react/embed/index.js.map +4 -5
- package/dist/react/index.css +156 -6
- package/dist/react/index.js +313 -152
- package/dist/react/index.js.map +17 -13
- package/dist/server.js +172 -76
- package/dist/server.js.map +7 -6
- package/dist/types/client/iframe.d.ts +14 -0
- package/dist/types/client/index.d.ts +19 -13
- package/dist/types/core/appearance.d.ts +7 -6
- package/dist/types/core/contract.d.ts +3 -3
- package/dist/types/core/messages.d.ts +7 -1
- package/dist/types/core/operation.d.ts +27 -0
- package/dist/types/core/presentation.d.ts +7 -0
- package/dist/types/embed/bridge.d.ts +12 -0
- package/dist/types/embed/host.d.ts +10 -3
- package/dist/types/embed/index.d.ts +7 -4
- package/dist/types/embed/{shell.d.ts → source.d.ts} +5 -4
- package/dist/types/embed/sql.d.ts +4 -0
- package/dist/types/react/embed/bridge.d.ts +19 -10
- package/dist/types/react/embed/index.d.ts +0 -2
- package/dist/types/react/ui/DataAppSkeleton.d.ts +8 -0
- package/dist/types/react/ui/SearchInput.d.ts +1 -1
- package/dist/types/react/ui/index.d.ts +2 -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 +1 -1
- package/dist/{bootstrap.js → worker.js} +144 -12
- package/docs/app-authoring.md +24 -4
- package/docs/appearance.md +21 -8
- package/docs/client.md +39 -2
- package/docs/contract.md +2 -2
- package/docs/embed.md +105 -18
- package/docs/react-embed.md +84 -24
- package/docs/react.md +51 -0
- package/docs/server-bun.md +5 -0
- package/docs/worker.md +57 -0
- package/package.json +3 -3
- 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-zr4s2g7m.js.map +0 -12
- package/dist/types/embed/standalone.d.ts +0 -1
- package/dist/types/react/embed/shell.d.ts +0 -10
- package/docs/bootstrap.md +0 -76
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../src/embed/host.ts", "../src/embed/shell.ts"],
|
|
4
|
-
"sourcesContent": [
|
|
5
|
-
"import {\n BRIDGE,\n MAX_PENDING,\n REQUEST_TIMEOUT_MS,\n isBridgeMessage,\n validId,\n type BridgeMessage,\n} from '@/src/core/bridge';\n\nimport {\n MessageRoutingError,\n type MessageDispatcher,\n} from '@/src/core/messages';\n\nexport type DataAppConnection =\n | { type: 'origin'; origin: string }\n | { type: 'opaque'; token: string };\nexport type DataAppStatus =\n | 'connecting'\n | 'connected'\n | 'ready'\n | 'failed'\n | 'disconnected';\nexport type DataAppDiagnostic = { direction: 'send' | 'receive'; type: string };\n\n/** The bridge owns delivery and cancellation; the routed handler owns validation, authorization and execution. */\nexport function attachDataAppBridge({\n iframe,\n connection,\n javascript,\n onStatusChange,\n onDiagnostic,\n onMessage,\n window: host = window,\n}: {\n iframe: HTMLIFrameElement;\n connection: DataAppConnection;\n javascript?: string;\n onStatusChange?: (status: DataAppStatus) => void;\n onDiagnostic?: (event: DataAppDiagnostic) => void;\n onMessage: MessageDispatcher;\n window?: Window;\n}) {\n const frameOrigin = connection.type === 'origin' ? connection.origin : 'null';\n if (\n connection.type === 'origin' &&\n new URL(frameOrigin).origin !== frameOrigin\n )\n throw new Error('Expected an exact frame origin.');\n if (connection.type === 'opaque' && !validId(connection.token))\n throw new Error('Invalid sandbox token.');\n let token = connection.type === 'opaque' ? connection.token : undefined;\n const targetOrigin = connection.type === 'opaque' ? '*' : frameOrigin;\n let documentId: string | undefined;\n let sessionId: string | undefined;\n const pending = new Map<string, AbortController>();\n\n function cancelAll() {\n for (const controller of pending.values()) controller.abort();\n pending.clear();\n }\n\n function send(message: Partial<BridgeMessage>) {\n onDiagnostic?.({ direction: 'send', type: message.type ?? 'unknown' });\n iframe.contentWindow?.postMessage(\n {\n channel: BRIDGE,\n version: 1,\n documentId,\n sessionId,\n ...(connection.type === 'opaque' ? { token } : {}),\n ...message,\n },\n targetOrigin\n );\n }\n\n function error(\n id: string,\n code: string,\n message: string,\n requestId?: string\n ) {\n send({ type: 'bridge:error', id, code, message, requestId });\n }\n\n async function request(message: BridgeMessage) {\n const id = message.id;\n if (!validId(id) || pending.has(id)) return;\n if (pending.size >= MAX_PENDING)\n return error(id, 'bridge_busy', 'Too many pending data requests.');\n if (\n typeof message.route !== 'string' ||\n !message.route ||\n message.route.length > 256\n )\n return error(id, 'invalid_message', 'Invalid message route.');\n try {\n const body = JSON.stringify(message.payload);\n if (\n message.payload !== undefined &&\n (typeof body !== 'string' || body.length > 16_384)\n )\n throw new Error('Invalid payload');\n } catch {\n return error(\n id,\n 'invalid_payload',\n 'The message payload is invalid or too large.'\n );\n }\n const controller = new AbortController();\n pending.set(id, controller);\n const timer = setTimeout(() => {\n if (pending.get(id) !== controller) return;\n pending.delete(id);\n controller.abort();\n error(id, 'timeout', 'The data request timed out.');\n }, REQUEST_TIMEOUT_MS);\n controller.signal.addEventListener('abort', () => clearTimeout(timer), {\n once: true,\n });\n try {\n const response = await onMessage(\n { route: message.route, payload: message.payload },\n { signal: controller.signal }\n );\n if (pending.get(id) === controller)\n send({ type: 'bridge:result', id, response });\n } catch (failure) {\n if (pending.get(id) === controller) {\n if (failure instanceof MessageRoutingError)\n error(id, failure.code, failure.message, failure.requestId);\n else\n error(\n id,\n 'request_failed',\n 'The message request failed. Retry the request.'\n );\n }\n } finally {\n clearTimeout(timer);\n if (pending.get(id) === controller) pending.delete(id);\n }\n }\n\n function receive(event: MessageEvent) {\n if (\n event.origin !== frameOrigin ||\n event.source !== iframe.contentWindow ||\n !isBridgeMessage(event.data)\n )\n return;\n const message = event.data;\n if (connection.type === 'opaque' && message.token !== token) return;\n onDiagnostic?.({ direction: 'receive', type: message.type });\n if (message.type === 'bridge:ready') {\n if (message.documentId !== documentId) {\n cancelAll();\n documentId = message.documentId;\n sessionId = crypto.randomUUID();\n }\n onStatusChange?.('connected');\n send({\n type: 'bridge:initialize',\n state: { search: host.location.search, hash: host.location.hash },\n });\n if (javascript !== undefined) send({ type: 'script:load', javascript });\n\n return;\n }\n if (\n !sessionId ||\n message.sessionId !== sessionId ||\n message.documentId !== documentId\n )\n return;\n if (message.type === 'runtime:ready') onStatusChange?.('ready');\n else if (message.type === 'runtime:error') onStatusChange?.('failed');\n else if (message.type === 'bridge:request') void request(message);\n else if (message.type === 'bridge:cancel' && validId(message.id)) {\n pending.get(message.id)?.abort();\n pending.delete(message.id);\n } else if (message.type === 'bridge:disconnect') {\n cancelAll();\n documentId = undefined;\n sessionId = undefined;\n onStatusChange?.('disconnected');\n }\n }\n\n function navigate() {\n send({\n type: 'state:update',\n state: { search: host.location.search, hash: host.location.hash },\n });\n }\n\n function load() {\n if (connection.type === 'opaque') token = crypto.randomUUID();\n cancelAll();\n documentId = undefined;\n sessionId = undefined;\n onStatusChange?.('connecting');\n send({ type: 'bridge:connect', documentId: 'host' });\n }\n\n function dispose() {\n cancelAll();\n iframe.removeEventListener('load', load);\n host.removeEventListener('message', receive);\n host.removeEventListener('popstate', navigate);\n host.removeEventListener('pagehide', cancelAll);\n }\n\n iframe.addEventListener('load', load);\n host.addEventListener('message', receive);\n host.addEventListener('popstate', navigate);\n host.addEventListener('pagehide', cancelAll);\n // Reconnect an already-loaded iframe when its host bridge mounts again.\n onStatusChange?.('connecting');\n send({ type: 'bridge:connect', documentId: 'host' });\n\n return dispose;\n}\n",
|
|
6
|
-
"import { PARENT_PARAM } from '@/src/core/bridge';\nimport type { MessageDispatcher } from '@/src/core/messages';\nimport {\n attachDataAppBridge,\n type DataAppStatus,\n type DataAppDiagnostic,\n} from '@/src/embed/host';\n\nexport type DataAppSource =\n | { type: 'url'; url: string }\n | {\n type: 'bundle';\n bootstrapUrl: string;\n javascript: string;\n revision: string;\n };\nexport type DataAppShellOptions = {\n iframe: HTMLIFrameElement;\n source: DataAppSource;\n onMessage: MessageDispatcher;\n onStatusChange?: (status: DataAppStatus) => void;\n onDiagnostic?: (event: DataAppDiagnostic) => void;\n startupTimeoutMs?: number;\n};\n\n/** Owns loading and sandbox policy. Dispose before replacing the source or retrying. */\nexport function attachDataAppShell({\n iframe,\n source,\n onMessage,\n onStatusChange,\n onDiagnostic,\n startupTimeoutMs = 30_000,\n}: DataAppShellOptions) {\n const host = iframe.ownerDocument.defaultView;\n if (!host) throw new Error('The iframe requires a host window.');\n const url = new URL(\n source.type === 'url' ? source.url : source.bootstrapUrl,\n host.location.href\n );\n if (!/^https?:$/.test(url.protocol))\n throw new Error('Data apps require an HTTP(S) URL.');\n const opaque = source.type === 'bundle';\n if (!opaque && url.origin === host.location.origin)\n throw new Error('URL data apps require a separate origin from the shell.');\n iframe.setAttribute(\n 'sandbox',\n opaque\n ? 'allow-scripts'\n : 'allow-scripts allow-same-origin allow-downloads allow-popups allow-popups-to-escape-sandbox'\n );\n iframe.referrerPolicy = 'no-referrer';\n if (!opaque) url.searchParams.set(PARENT_PARAM, host.location.origin);\n let timer: ReturnType<typeof setTimeout> | undefined;\n let failed = false;\n\n function status(value: DataAppStatus) {\n if (value === 'connecting') failed = false;\n if (failed && value !== 'connecting') return;\n clearTimeout(timer);\n if (value === 'connecting' || value === 'connected')\n timer = setTimeout(() => {\n failed = true;\n disposeBridge();\n onStatusChange?.('failed');\n }, startupTimeoutMs);\n if (value === 'failed') {\n failed = true;\n disposeBridge();\n }\n onStatusChange?.(value);\n }\n\n const disposeBridge = attachDataAppBridge({\n iframe,\n connection: opaque\n ? { type: 'opaque', token: crypto.randomUUID() }\n : { type: 'origin', origin: url.origin },\n javascript: opaque ? source.javascript : undefined,\n onMessage,\n onStatusChange: status,\n onDiagnostic,\n window: host,\n });\n\n function error() {\n return status('failed');\n }\n\n iframe.addEventListener('error', error);\n iframe.src = url.href;\n\n return () => {\n clearTimeout(timer);\n iframe.removeEventListener('error', error);\n disposeBridge();\n };\n}\n"
|
|
7
|
-
],
|
|
8
|
-
"mappings": "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",
|
|
9
|
-
"debugId": "2962A017228A422764756E2164756E21",
|
|
10
|
-
"names": []
|
|
11
|
-
}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../src/client/transport.ts", "../src/client/messages.ts", "../src/client/iframe.ts"],
|
|
4
|
-
"sourcesContent": [
|
|
5
|
-
"import type { TransportResponse } from '@/src/core/bridge';\n\nexport type DataTransport = (\n operation: string,\n input: unknown,\n signal?: AbortSignal\n) => Promise<TransportResponse>;\n\n// A bootstrap and its app may bundle independent copies in the same window.\nconst errorBrand = Symbol.for('@altertable/data-app/DataAppError');\n\nexport class DataAppError extends Error {\n readonly [errorBrand] = true;\n\n static [Symbol.hasInstance](value: unknown): boolean {\n return (\n value instanceof Error &&\n (value as { [errorBrand]?: unknown })[errorBrand] === true\n );\n }\n\n constructor(\n message: string,\n public readonly code: string,\n public readonly requestId?: string\n ) {\n super(message);\n this.name = 'DataAppError';\n }\n}\n\nexport function createHttpTransport({\n endpoint = '/api/data',\n fetch: request = globalThis.fetch,\n}: {\n endpoint?: string;\n fetch?: typeof fetch;\n} = {}): DataTransport {\n async function requestData(\n operation: string,\n input: unknown,\n signal?: AbortSignal\n ): Promise<TransportResponse> {\n const response = await request(\n `${endpoint.replace(/\\/$/, '')}/${encodeURIComponent(operation)}`,\n {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(input),\n signal,\n }\n );\n try {\n return { status: response.status, body: await response.json() };\n } catch (error) {\n if (signal?.aborted) throw error;\n throw new DataAppError(\n response.ok ? 'The data response was invalid.' : 'Could not load data.',\n response.ok ? 'invalid_response' : 'request_failed'\n );\n }\n }\n\n return requestData;\n}\n",
|
|
6
|
-
"import {\n MessageRoutingError,\n type MessageInput,\n type MessageOutput,\n type MessageRoutes,\n type MessageTransport,\n} from '@/src/core/messages';\n\n/** Both ends validate using the same contracts; the transport owns delivery and cancellation. */\nexport function createMessageClient<const Routes extends MessageRoutes>(\n routes: Routes,\n transport: MessageTransport\n) {\n return {\n async request<\n Name extends keyof Routes & string,\n const Input extends MessageInput<NoInfer<Routes[Name]>>,\n >(\n route: Name,\n payload: Input,\n { signal }: { signal?: AbortSignal } = {}\n ): Promise<MessageOutput<Routes[Name], Input>> {\n signal?.throwIfAborted();\n if (!Object.hasOwn(routes, route))\n throw new MessageRoutingError(\n 'unknown_route',\n 'Unknown message route.'\n );\n const contract = routes[route]!;\n let input: unknown;\n try {\n input = contract.input(payload);\n } catch {\n throw new MessageRoutingError(\n 'invalid_payload',\n 'Invalid message payload.'\n );\n }\n const response = await transport({ route, payload: input }, signal);\n signal?.throwIfAborted();\n try {\n return contract.output(response, input as never) as MessageOutput<\n Routes[Name],\n Input\n >;\n } catch (error) {\n if (error instanceof MessageRoutingError) throw error;\n throw new MessageRoutingError(\n 'invalid_response',\n 'Invalid message response.'\n );\n }\n },\n };\n}\n",
|
|
7
|
-
"import {\n BRIDGE,\n PARENT_PARAM,\n MAX_PENDING,\n REQUEST_TIMEOUT_MS,\n isBridgeMessage,\n validId,\n type BridgeMessage,\n type TransportResponse,\n} from '@/src/core/bridge';\nimport {\n defineDataQueryRoute,\n MessageRoutingError,\n type RoutedMessage,\n} from '@/src/core/messages';\nimport { createMessageClient } from '@/src/client/messages';\nimport { DataAppError } from '@/src/client/transport';\n\ntype Pending = {\n start: () => void;\n reject: (error: unknown) => void;\n resolve: (value: unknown) => void;\n};\n\n/** One bridge per document, shared by all clients and retained across module hot replacement. */\nexport function createIframeTransport({\n parentOrigin,\n window: frame = window,\n timeoutMs = REQUEST_TIMEOUT_MS,\n mode = 'url',\n loadScript,\n}: {\n parentOrigin: string;\n window?: Window;\n timeoutMs?: number;\n mode?: 'url' | 'bundle';\n loadScript?: (javascript: string) => void;\n}) {\n if (new URL(parentOrigin).origin !== parentOrigin)\n throw new Error('Expected an exact parent origin.');\n const documentId = crypto.randomUUID();\n let token: string | undefined;\n let sessionId: string | undefined;\n let disposed = false;\n const pending = new Map<string, Pending>();\n let hostState: unknown;\n const stateListeners = new Set<(state: unknown) => void>();\n\n function send(message: Partial<BridgeMessage>) {\n frame.parent.postMessage(\n { channel: BRIDGE, version: 1, documentId, sessionId, token, ...message },\n parentOrigin\n );\n }\n\n function receiveState(state: unknown) {\n hostState = state;\n for (const listener of stateListeners) listener(state);\n }\n\n function receive(event: MessageEvent) {\n if (\n event.origin !== parentOrigin ||\n event.source !== frame.parent ||\n !isBridgeMessage(event.data)\n )\n return;\n const message = event.data;\n if (message.type === 'bridge:connect') {\n if (mode === 'bundle') {\n if (!validId(message.token)) return;\n token = message.token;\n }\n send({ type: 'bridge:ready' });\n\n return;\n }\n if (mode === 'bundle' && (!token || message.token !== token)) return;\n if (message.documentId !== documentId) return;\n if (message.type === 'bridge:initialize' && validId(message.sessionId)) {\n if (sessionId && sessionId !== message.sessionId) {\n for (const entry of pending.values())\n entry.reject(\n new DataAppError(\n 'The preview reconnected. Retry the request.',\n 'bridge_reset'\n )\n );\n }\n const first = !sessionId;\n sessionId = message.sessionId;\n if (first) for (const entry of pending.values()) entry.start();\n receiveState(message.state);\n if (mode === 'url') send({ type: 'runtime:ready' });\n\n return;\n }\n if (!sessionId || message.sessionId !== sessionId) return;\n if (message.type === 'state:update') {\n receiveState(message.state);\n\n return;\n }\n if (\n message.type === 'script:load' &&\n mode === 'bundle' &&\n typeof message.javascript === 'string'\n ) {\n loadScript?.(message.javascript);\n\n return;\n }\n if (typeof message.id !== 'string') return;\n const entry = pending.get(message.id);\n if (!entry) return;\n if (message.type === 'bridge:result' && 'response' in message) {\n entry.resolve(message.response);\n } else if (\n message.type === 'bridge:error' &&\n typeof message.code === 'string' &&\n typeof message.message === 'string'\n ) {\n entry.reject(\n new MessageRoutingError(\n message.code,\n message.message,\n typeof message.requestId === 'string' ? message.requestId : undefined\n )\n );\n }\n }\n\n frame.addEventListener('message', receive);\n\n function requestMessage(\n message: RoutedMessage,\n signal?: AbortSignal\n ): Promise<unknown> {\n return new Promise((resolve, reject) => {\n if (disposed)\n return reject(\n new DataAppError('The preview has closed.', 'bridge_closed')\n );\n if (signal?.aborted) return reject(signal.reason);\n if (pending.size >= MAX_PENDING)\n return reject(\n new DataAppError('Too many pending data requests.', 'bridge_busy')\n );\n const id = crypto.randomUUID();\n let sent = false;\n\n function cleanup() {\n clearTimeout(timer);\n signal?.removeEventListener('abort', abort);\n pending.delete(id);\n }\n\n function abort() {\n if (sent) send({ type: 'bridge:cancel', id });\n cleanup();\n reject(signal?.reason);\n }\n\n const timer = setTimeout(() => {\n if (sent) send({ type: 'bridge:cancel', id });\n cleanup();\n reject(\n new DataAppError(\n sessionId\n ? 'The data request timed out.'\n : 'The preview shell is unavailable. Reload the preview.',\n sessionId ? 'timeout' : 'bridge_unavailable'\n )\n );\n }, timeoutMs);\n const entry: Pending = {\n start() {\n if (sent) return;\n try {\n send({\n type: 'bridge:request',\n id,\n route: message.route,\n payload: message.payload,\n });\n sent = true;\n } catch {\n cleanup();\n reject(\n new DataAppError(\n 'The message payload could not be sent.',\n 'invalid_payload'\n )\n );\n }\n },\n resolve(value) {\n cleanup();\n resolve(value);\n },\n reject(error) {\n cleanup();\n reject(error);\n },\n };\n pending.set(id, entry);\n signal?.addEventListener('abort', abort, { once: true });\n if (sessionId) entry.start();\n else send({ type: 'bridge:ready' });\n });\n }\n\n const messages = createMessageClient(\n { 'data:query': defineDataQueryRoute() },\n requestMessage\n );\n\n async function queryData(\n operation: string,\n input: unknown,\n signal?: AbortSignal\n ): Promise<TransportResponse> {\n try {\n return await messages.request(\n 'data:query',\n { operation, input },\n { signal }\n );\n } catch (error) {\n if (error instanceof MessageRoutingError)\n throw new DataAppError(error.message, error.code, error.requestId);\n throw error;\n }\n }\n\n function disconnect() {\n send({ type: 'bridge:disconnect' });\n sessionId = undefined;\n for (const entry of pending.values())\n entry.reject(\n new DataAppError('The preview has closed.', 'bridge_closed')\n );\n }\n\n function resume(event: PageTransitionEvent) {\n if (event.persisted) send({ type: 'bridge:ready' });\n }\n\n function dispose() {\n if (disposed) return;\n disconnect();\n disposed = true;\n frame.removeEventListener('message', receive);\n frame.removeEventListener('pagehide', disconnect);\n frame.removeEventListener('pageshow', resume);\n stateListeners.clear();\n }\n\n frame.addEventListener('pagehide', disconnect);\n frame.addEventListener('pageshow', resume);\n if (mode === 'url') send({ type: 'bridge:ready' });\n\n return {\n request: requestMessage,\n transport: queryData,\n dispose,\n mode,\n snapshot() {\n return hostState;\n },\n subscribe(listener: (state: unknown) => void) {\n stateListeners.add(listener);\n\n return () => {\n stateListeners.delete(listener);\n };\n },\n ready() {\n send({ type: 'runtime:ready' });\n },\n fail() {\n send({ type: 'runtime:error' });\n },\n };\n}\n\nexport type IframeTransport = ReturnType<typeof createIframeTransport>;\n\nconst bridgeKey = Symbol.for('altertable.localFrameBridge');\nconst installedKey = Symbol.for('altertable.installedTransport');\ntype LocalBridge = Pick<\n ReturnType<typeof createIframeTransport>,\n 'transport'\n> & { connect?: () => Promise<ReturnType<typeof createIframeTransport>> };\ntype FrameWindow = Window & {\n [bridgeKey]?: LocalBridge;\n [installedKey]?: ReturnType<typeof createIframeTransport>;\n};\n\n/** The URL opts into local preview; only same-origin server configuration establishes trust. */\nexport function localFrameBridge(window?: Window): LocalBridge | undefined {\n const activeWindow =\n window ??\n (typeof globalThis.window === 'undefined' ? undefined : globalThis.window);\n if (!activeWindow) return undefined;\n const frame = activeWindow as FrameWindow;\n if (frame[bridgeKey]) return frame[bridgeKey];\n const parentOrigin =\n new URL(frame.location.href).searchParams.get(PARENT_PARAM) ?? '';\n if (!parentOrigin) return undefined;\n\n async function connect(parentOrigin: string) {\n try {\n const response = await frame.fetch('/__altertable/parent', {\n signal: AbortSignal.timeout(5000),\n });\n const config = (await response.json()) as { origin?: unknown };\n if (\n !response.ok ||\n config.origin !== parentOrigin ||\n frame.parent === frame\n )\n throw new Error('Invalid local parent configuration.');\n // Another owner can install a trusted bridge while configuration is pending.\n if (frame[installedKey]) return frame[installedKey];\n if (frame[bridgeKey] !== proxy)\n throw new Error('Preview transport owner changed.');\n const bridge = createIframeTransport({ parentOrigin, window: frame });\n frame[bridgeKey] = bridge;\n frame[installedKey] = bridge;\n\n return bridge;\n } catch {\n throw new DataAppError(\n 'The preview shell could not be verified. Open the URL printed by altertable app dev.',\n 'bridge_unavailable'\n );\n }\n }\n\n let connection: Promise<ReturnType<typeof createIframeTransport>> | undefined;\n\n function getConnection() {\n const installed = frame[installedKey];\n if (installed) return Promise.resolve(installed);\n if (!connection) {\n const attempt = connect(parentOrigin);\n connection = attempt;\n // Clear only this failed attempt; retained proxy references can explicitly retry.\n void attempt.catch(() => {\n if (connection === attempt) connection = undefined;\n });\n }\n\n return connection;\n }\n\n const proxy: LocalBridge = {\n async transport(operation, input, signal) {\n signal?.throwIfAborted();\n const attempt = getConnection();\n let abort: (() => void) | undefined;\n try {\n const bridge = signal\n ? await Promise.race([\n attempt,\n new Promise<never>((_, reject) => {\n const requestSignal = signal;\n\n function handleAbort() {\n reject(requestSignal.reason);\n }\n\n abort = handleAbort;\n requestSignal.addEventListener('abort', handleAbort, {\n once: true,\n });\n }),\n ])\n : await attempt;\n signal?.throwIfAborted();\n\n return bridge.transport(operation, input, signal);\n } finally {\n if (abort) signal?.removeEventListener('abort', abort);\n }\n },\n connect: getConnection,\n };\n frame[bridgeKey] = proxy;\n // Static mounting still verifies eagerly, without an unhandled rejection.\n void getConnection().catch(() => {});\n\n return proxy;\n}\n\n/** Install an explicitly trusted transport for hosted apps and their URL-backed controls. */\nexport function installDataAppTransport(\n bridge: ReturnType<typeof createIframeTransport>,\n frame: Window = window\n) {\n const target = frame as FrameWindow;\n if (target[installedKey])\n throw new Error('A data app transport is already installed.');\n target[bridgeKey] = bridge;\n target[installedKey] = bridge;\n\n return () => {\n if (target[bridgeKey] === bridge) delete target[bridgeKey];\n if (target[installedKey] === bridge) delete target[installedKey];\n bridge.dispose();\n };\n}\n\n/** The bootstrap installs this before executing app code. URL apps can install an explicit connection. */\nexport function getDataAppTransport(frame: Window = window) {\n return (frame as FrameWindow)[installedKey];\n}\n"
|
|
8
|
-
],
|
|
9
|
-
"mappings": "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",
|
|
10
|
-
"debugId": "8A923FD5B245BF3C64756E2164756E21",
|
|
11
|
-
"names": []
|
|
12
|
-
}
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../src/core/messages.ts"],
|
|
4
|
-
"sourcesContent": [
|
|
5
|
-
"import type { TransportResponse } from '@/src/core/bridge';\nimport type { DisclosedQuery } from '@/src/core/contract';\n\nexport type MessageContext = { signal: AbortSignal };\nexport type RoutedMessage = { route: string; payload: unknown };\nexport type MessageDispatcher = (\n message: unknown,\n context: MessageContext\n) => Promise<unknown>;\nexport type MessageTransport = (\n message: RoutedMessage,\n signal?: AbortSignal\n) => Promise<unknown>;\nexport type MessageRoute<Input, Output> = {\n input: (value: unknown) => Input;\n output: (value: unknown, input: Input) => Output;\n};\nexport type MessageRoutes = Record<\n string,\n {\n input: (value: unknown) => unknown;\n output: (value: unknown, input: never) => unknown;\n }\n>;\nexport type MessageInput<Route extends MessageRoutes[string]> = ReturnType<\n Route['input']\n>;\nexport type MessageHandlers<Routes extends MessageRoutes> = {\n [Name in keyof Routes]: (\n payload: MessageInput<Routes[Name]>,\n context: MessageContext\n ) =>\n | ReturnType<Routes[Name]['output']>\n | Promise<ReturnType<Routes[Name]['output']>>;\n};\n\n// A bootstrap and its app may bundle independent copies in the same window.\nconst errorBrand = Symbol.for('@altertable/data-app/MessageRoutingError');\n\n/** Only these deliberate, public failures cross the message boundary. Other errors stay private. */\nexport class MessageRoutingError extends Error {\n readonly [errorBrand] = true;\n\n static [Symbol.hasInstance](value: unknown): boolean {\n return (\n value instanceof Error &&\n (value as { [errorBrand]?: unknown })[errorBrand] === true\n );\n }\n\n constructor(\n public readonly code: string,\n message: string,\n public readonly requestId?: string\n ) {\n super(message);\n this.name = 'MessageRoutingError';\n }\n}\n\nexport function defineMessageRoute<Input, Output>(\n route: MessageRoute<Input, Output>\n): MessageRoute<Input, Output> {\n return route;\n}\n\n/** Contracts are shared; handlers are supplied by the host and never belong in the app bundle. */\nexport function createMessageRouter<const Routes extends MessageRoutes>(\n routes: Routes,\n handlers: MessageHandlers<NoInfer<Routes>>\n) {\n const registered = new Map(\n Object.entries(routes).map(([name, contract]) => {\n const handler = handlers[name];\n if (!name || name.length > 256 || typeof handler !== 'function')\n throw new Error(\n 'Each message route requires a handler and a bounded name.'\n );\n\n return [name, { contract, handler }] as const;\n })\n );\n\n async function dispatch(\n value: unknown,\n context: MessageContext\n ): Promise<unknown> {\n if (\n !value ||\n typeof value !== 'object' ||\n typeof (value as RoutedMessage).route !== 'string'\n )\n throw new MessageRoutingError(\n 'invalid_message',\n 'Invalid routed message.'\n );\n const message = value as RoutedMessage;\n const entry = registered.get(message.route);\n if (!entry)\n throw new MessageRoutingError('unknown_route', 'Unknown message route.');\n let payload: unknown;\n try {\n payload = entry.contract.input(message.payload);\n } catch {\n throw new MessageRoutingError(\n 'invalid_payload',\n 'Invalid message payload.'\n );\n }\n context.signal.throwIfAborted();\n let result: unknown;\n try {\n result = await entry.handler(payload as never, context);\n } catch (error) {\n if (context.signal.aborted) throw context.signal.reason;\n if (error instanceof MessageRoutingError) throw error;\n throw new MessageRoutingError(\n 'request_failed',\n 'The message request failed. Retry the request.'\n );\n }\n context.signal.throwIfAborted();\n try {\n return entry.contract.output(result, payload as never);\n } catch (error) {\n if (error instanceof MessageRoutingError) throw error;\n throw new MessageRoutingError(\n 'invalid_response',\n 'Invalid message response.'\n );\n }\n }\n\n return { dispatch };\n}\n\nexport type OperationContracts = Record<\n string,\n {\n input: (value: unknown) => unknown;\n output: (value: unknown) => unknown;\n }\n>;\nexport type DataQueryInput<Operations extends OperationContracts> = {\n [Name in keyof Operations & string]: {\n operation: Name;\n input: ReturnType<Operations[Name]['input']>;\n };\n}[keyof Operations & string];\nexport type DataQueryBody<Output> = {\n data: Output;\n requestId: string;\n queriedAt: string;\n queryIds: string[];\n queries?: DisclosedQuery[];\n};\nexport type DataQueryRoute<Operations extends OperationContracts> =\n MessageRoute<DataQueryInput<Operations>, TransportResponse> & {\n operations: Operations | undefined;\n };\nexport type MessageOutput<Route extends MessageRoutes[string], Input> =\n Route extends DataQueryRoute<infer Operations>\n ? Input extends { operation: infer Name extends keyof Operations }\n ? {\n status: number;\n body: DataQueryBody<ReturnType<Operations[Name]['output']>>;\n }\n : never\n : ReturnType<Route['output']>;\n\n/** Omit contracts only in generic hosts such as the CLI shell, where Bun validates operations. */\nexport function defineDataQueryRoute<\n Operations extends OperationContracts = OperationContracts,\n>(operations?: Operations): DataQueryRoute<Operations> {\n return {\n operations,\n input(value) {\n if (!value || typeof value !== 'object')\n throw new Error('Invalid query.');\n const request = value as { operation?: unknown; input?: unknown };\n if (\n typeof request.operation !== 'string' ||\n !request.operation ||\n request.operation.length > 256 ||\n request.operation.includes('/')\n )\n throw new Error('Invalid operation.');\n const operation =\n operations && Object.hasOwn(operations, request.operation)\n ? operations[request.operation]\n : undefined;\n if (operations && !operation) throw new Error('Unknown operation.');\n\n return {\n operation: request.operation,\n input: operation ? operation.input(request.input) : request.input,\n } as DataQueryInput<Operations>;\n },\n output(value, input) {\n if (!value || typeof value !== 'object')\n throw new Error('Invalid data response.');\n const response = value as TransportResponse;\n if (\n !Number.isInteger(response.status) ||\n response.status < 100 ||\n response.status > 599 ||\n !response.body ||\n typeof response.body !== 'object'\n )\n throw new Error('Invalid data response.');\n const body = response.body as DataQueryBody<unknown> & {\n error?: { code?: unknown; message?: unknown; requestId?: unknown };\n };\n if (response.status < 200 || response.status >= 300) {\n const failure = body.error;\n throw new MessageRoutingError(\n typeof failure?.code === 'string' ? failure.code : 'request_failed',\n typeof failure?.message === 'string'\n ? failure.message\n : 'Could not load data.',\n typeof failure?.requestId === 'string' ? failure.requestId : undefined\n );\n }\n if (\n !('data' in body) ||\n typeof body.requestId !== 'string' ||\n typeof body.queriedAt !== 'string' ||\n !Array.isArray(body.queryIds) ||\n !body.queryIds.every(id => typeof id === 'string')\n )\n throw new Error('Invalid data envelope.');\n if (\n body.queries !== undefined &&\n (!Array.isArray(body.queries) ||\n !body.queries.every(\n query =>\n query &&\n typeof query === 'object' &&\n typeof query.name === 'string' &&\n typeof query.statement === 'string' &&\n (query.queryId === undefined || typeof query.queryId === 'string')\n ))\n )\n throw new Error('Invalid query evidence.');\n const operation = operations?.[input.operation];\n\n return {\n status: response.status,\n body: {\n ...body,\n data: operation ? operation.output(body.data) : body.data,\n },\n };\n },\n };\n}\n\nexport type NavigationUpdate = {\n search: string;\n hash: string;\n mode: 'push' | 'replace';\n title?: string;\n};\nexport const navigationUpdateRoute = /* @__PURE__ */ defineMessageRoute({\n input(value: unknown): NavigationUpdate {\n if (!value || typeof value !== 'object')\n throw new Error('Invalid navigation.');\n const input = value as NavigationUpdate;\n if (\n typeof input.search !== 'string' ||\n input.search.length > 16_384 ||\n (input.search !== '' && !input.search.startsWith('?')) ||\n typeof input.hash !== 'string' ||\n input.hash.length > 4096 ||\n (input.hash !== '' && !input.hash.startsWith('#')) ||\n (input.mode !== 'push' && input.mode !== 'replace') ||\n (input.title !== undefined &&\n (typeof input.title !== 'string' || input.title.length > 512))\n )\n throw new Error('Invalid navigation.');\n\n return {\n search: input.search,\n hash: input.hash,\n mode: input.mode,\n ...(input.title === undefined ? {} : { title: input.title }),\n };\n },\n output(value: unknown): null {\n if (value !== null) throw new Error('Invalid navigation response.');\n\n return null;\n },\n});\nexport const dataAppRoutes = {\n 'data:query': /* @__PURE__ */ defineDataQueryRoute(),\n 'navigation:update': navigationUpdateRoute,\n};\n"
|
|
6
|
-
],
|
|
7
|
-
"mappings": "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",
|
|
8
|
-
"debugId": "294B82BAC69F23DB64756E2164756E21",
|
|
9
|
-
"names": []
|
|
10
|
-
}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../src/client/location.ts", "../src/client/navigation.ts", "../src/client/index.ts"],
|
|
4
|
-
"sourcesContent": [
|
|
5
|
-
"import { PARENT_PARAM, validLocation } from '@/src/core/bridge';\n\nexport type AppLocation = { search: string; hash: string };\nexport type DataAppLocation = {\n snapshot(): AppLocation;\n subscribe(listener: () => void): () => void;\n update(location: AppLocation, mode?: 'push' | 'replace'): void;\n};\n\n/** Opaque sandboxes keep app state in memory; URL frames retain their real URL for HMR. */\nexport function createAppLocation(\n frame: Window,\n virtual: boolean,\n publish: (location: AppLocation, mode: 'push' | 'replace') => void\n) {\n let state: AppLocation = { search: '', hash: '' };\n let disposed = false;\n const listeners = new Set<() => void>();\n\n function notify() {\n for (const listener of listeners) listener();\n }\n\n function snapshot(): AppLocation {\n if (virtual) return state;\n const url = new URL(frame.location.href);\n url.searchParams.delete(PARENT_PARAM);\n if (state.search !== url.search || state.hash !== url.hash)\n state = { search: url.search, hash: url.hash };\n\n return state;\n }\n\n function apply(next: AppLocation) {\n const previous = snapshot();\n if (previous.search === next.search && previous.hash === next.hash) return;\n if (virtual) state = next;\n else {\n const url = new URL(frame.location.href);\n const parent = url.searchParams.get(PARENT_PARAM);\n url.search = next.search;\n if (parent) url.searchParams.set(PARENT_PARAM, parent);\n url.hash = next.hash;\n frame.history.replaceState(null, '', url);\n frame.dispatchEvent(new Event('popstate'));\n }\n if (virtual) notify();\n }\n\n const location: DataAppLocation = {\n snapshot,\n subscribe(listener) {\n listeners.add(listener);\n if (!virtual) frame.addEventListener('popstate', listener);\n\n return () => {\n listeners.delete(listener);\n frame.removeEventListener('popstate', listener);\n };\n },\n update(next, mode = 'replace') {\n if (disposed) return;\n if (!validLocation(next)) throw new Error('Invalid app location.');\n const before = snapshot();\n if (before.search === next.search && before.hash === next.hash) return;\n apply(next);\n publish(next, mode);\n },\n };\n\n function dispose() {\n disposed = true;\n for (const listener of listeners)\n frame.removeEventListener('popstate', listener);\n listeners.clear();\n }\n\n return { location, apply, dispose };\n}\n",
|
|
6
|
-
"import { createAppLocation, type DataAppLocation } from '@/src/client/location';\nimport { validLocation } from '@/src/core/bridge';\nimport {\n navigationUpdateRoute,\n type NavigationUpdate,\n} from '@/src/core/messages';\nimport { createMessageClient } from '@/src/client/messages';\nimport {\n getDataAppTransport,\n localFrameBridge,\n type IframeTransport,\n} from '@/src/client/iframe';\n\nexport type DataAppNavigation = DataAppLocation & {\n /** Publish URL changes made outside the adapter, including the document title. */\n publish(mode?: 'push' | 'replace'): void;\n dispose(): void;\n};\n\n/** Attach app URL behavior to an already authenticated bridge. */\nexport function createDataAppNavigation({\n bridge,\n window: frame = window,\n}: {\n bridge: IframeTransport;\n window?: Window;\n}): DataAppNavigation {\n return attachNavigation(frame, bridge.mode === 'bundle', bridge).navigation;\n}\n\nfunction attachNavigation(\n frame: Window,\n virtual: boolean,\n connection: IframeTransport | Promise<IframeTransport>\n) {\n let disposed = false;\n let unsubscribe: (() => void) | undefined;\n let send: ((update: NavigationUpdate) => void) | undefined;\n let pendingUpdate: NavigationUpdate | undefined;\n const { location, apply, dispose } = createAppLocation(\n frame,\n virtual,\n publish\n );\n\n function publish(\n location: { search: string; hash: string },\n mode: 'push' | 'replace'\n ) {\n const update = { ...location, mode, title: frame.document.title };\n if (send) send(update);\n else pendingUpdate = update;\n }\n\n function attach(bridge: IframeTransport) {\n if (disposed) return;\n unsubscribe?.();\n const messages = createMessageClient(\n { 'navigation:update': navigationUpdateRoute },\n bridge.request\n );\n\n function sendUpdate(update: NavigationUpdate) {\n void messages.request('navigation:update', update).catch(() => {});\n }\n\n function receiveState(state: unknown) {\n if (!state || typeof state !== 'object' || !validLocation(state)) return;\n pendingUpdate = undefined;\n apply(state as { search: string; hash: string });\n }\n\n send = sendUpdate;\n unsubscribe = bridge.subscribe(receiveState);\n receiveState(bridge.snapshot());\n if (pendingUpdate) {\n sendUpdate(pendingUpdate);\n pendingUpdate = undefined;\n }\n }\n\n if ('then' in connection) void connection.then(attach).catch(() => {});\n else attach(connection);\n\n const navigation: DataAppNavigation = {\n ...location,\n publish(mode = 'replace') {\n if (!disposed) publish(location.snapshot(), mode);\n },\n dispose() {\n disposed = true;\n unsubscribe?.();\n dispose();\n send = undefined;\n pendingUpdate = undefined;\n },\n };\n\n return {\n navigation,\n attach,\n isDisposed() {\n return disposed;\n },\n };\n}\n\nconst navigationKey = Symbol.for('altertable.appNavigation');\ntype NavigationWindow = Window & {\n [navigationKey]?: ReturnType<typeof attachNavigation> & {\n bridge?: IframeTransport;\n };\n};\n\n/** URL controls attach navigation on demand; bootstrap and data-only clients do not. */\nexport function getDataAppNavigation(\n frame: Window = window\n): DataAppNavigation | undefined {\n const target = frame as NavigationWindow;\n const bridge = getDataAppTransport(frame);\n const cached = target[navigationKey]?.isDisposed()\n ? undefined\n : target[navigationKey];\n if (cached) {\n if (bridge && cached.bridge !== bridge) {\n cached.attach(bridge);\n cached.bridge = bridge;\n }\n\n return cached.navigation;\n }\n if (bridge) {\n const adapter = attachNavigation(frame, bridge.mode === 'bundle', bridge);\n target[navigationKey] = { bridge, ...adapter };\n\n return adapter.navigation;\n }\n const preview = localFrameBridge(frame);\n if (!preview?.connect) return undefined;\n const connection = preview.connect();\n const adapter = attachNavigation(frame, false, connection);\n const entry = {\n ...adapter,\n bridge: undefined as IframeTransport | undefined,\n };\n target[navigationKey] = entry;\n void connection\n .then(bridge => {\n entry.bridge = bridge;\n })\n .catch(() => {});\n\n return adapter.navigation;\n}\n",
|
|
7
|
-
"/**\n * Typed clients for HTTP and iframe delivery; safe to import in the browser.\n * @module @altertable/data-app/client\n * @see https://github.com/altertable-ai/data-app/blob/main/docs/client.md\n */\nimport {\n createHttpTransport,\n DataAppError,\n type DataTransport,\n} from '@/src/client/transport';\nimport { localFrameBridge } from '@/src/client/iframe';\nexport {\n createHttpTransport,\n DataAppError,\n type DataTransport,\n} from '@/src/client/transport';\nexport {\n createIframeTransport,\n installDataAppTransport,\n getDataAppTransport,\n type IframeTransport,\n} from '@/src/client/iframe';\nexport { createMessageClient } from '@/src/client/messages';\nimport type { DataOperations, DisclosedQuery } from '@/src/core/contract';\n\nexport type InputOf<T> = T extends { input: (value: unknown) => infer Input }\n ? Input\n : never;\nexport type OutputOf<T> = T extends { output: (value: unknown) => infer Output }\n ? Output\n : never;\n\n/**\n * Parsed operation data and query evidence. `queries` is present only when SQL disclosure is\n * allowed.\n */\nexport type DataResponse<Output, Input = unknown> = {\n data: Output;\n /** The exact browser input that produced this response. Never infer it from current controls. */\n input: Input;\n requestId: string;\n queriedAt: string;\n queryIds: string[];\n queries?: DisclosedQuery[];\n};\n\nexport type DataClient<Operations extends DataOperations> = {\n query<Name extends keyof Operations & string>(\n name: Name,\n input: InputOf<Operations[Name]>,\n options?: { signal?: AbortSignal }\n ): Promise<\n DataResponse<OutputOf<Operations[Name]>, InputOf<Operations[Name]>>\n >;\n};\n\n/** Browser client for named operations; it sends inputs, never SQL or lakehouse credentials. */\nexport function createDataClient<Operations extends DataOperations>(\n options: {\n transport?: DataTransport;\n endpoint?: string;\n fetch?: typeof fetch;\n } = {}\n): DataClient<Operations> {\n const http = createHttpTransport(options);\n\n return {\n async query(name, input, { signal } = {}) {\n const transport =\n options.transport ??\n (options.endpoint !== undefined || options.fetch !== undefined\n ? http\n : (localFrameBridge()?.transport ?? http));\n const response = await transport(name, input, signal);\n const ok = response.status >= 200 && response.status < 300;\n let body: Omit<\n DataResponse<OutputOf<Operations[typeof name]>>,\n 'input'\n > & {\n error?: { code: string; message: string; requestId?: string };\n };\n try {\n const parsed: unknown = response.body;\n if (\n parsed === null ||\n typeof parsed !== 'object' ||\n Array.isArray(parsed)\n )\n throw new Error('Invalid response envelope.');\n body = parsed as typeof body;\n } catch (error) {\n if (signal?.aborted) throw error;\n throw new DataAppError(\n ok ? 'The data response was invalid.' : 'Could not load data.',\n ok ? 'invalid_response' : 'request_failed'\n );\n }\n if (!ok)\n throw new DataAppError(\n body.error?.message ?? 'Could not load data.',\n body.error?.code ?? 'request_failed',\n body.error?.requestId\n );\n\n return { ...body, input };\n },\n };\n}\n\nexport type { DataAppLocation, AppLocation } from '@/src/client/location';\n\nexport {\n createDataAppNavigation,\n getDataAppNavigation,\n type DataAppNavigation,\n} from '@/src/client/navigation';\n"
|
|
8
|
-
],
|
|
9
|
-
"mappings": "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",
|
|
10
|
-
"debugId": "604C308B1E4C235964756E2164756E21",
|
|
11
|
-
"names": []
|
|
12
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,10 +0,0 @@
|
|
|
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;
|
package/docs/bootstrap.md
DELETED
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
# Standalone bootstrap
|
|
2
|
-
|
|
3
|
-
`@altertable/data-app/bootstrap` resolves to a self-contained classic browser
|
|
4
|
-
script. It has no imports, React dependencies, or app navigation behavior. The
|
|
5
|
-
package builds it once; a backend can embed the published file without running a
|
|
6
|
-
bundler.
|
|
7
|
-
|
|
8
|
-
This entry is a script asset, not a module API. Resolve and read it on the server;
|
|
9
|
-
do not import it for execution in Node.js or Bun. For a bootstrap you bundle
|
|
10
|
-
yourself, use `startDataAppBootstrap` from [embedding](embed.md).
|
|
11
|
-
|
|
12
|
-
## Generate the backend HTML
|
|
13
|
-
|
|
14
|
-
Install an exact package version in the backend runtime's `package.json`, commit
|
|
15
|
-
the lockfile, and run this generation step before building or deploying the worker:
|
|
16
|
-
|
|
17
|
-
```js
|
|
18
|
-
// scripts/build-runtime.mjs
|
|
19
|
-
import { mkdir, readFile, writeFile } from 'node:fs/promises';
|
|
20
|
-
|
|
21
|
-
const parentOrigin = 'https://app.altertable.ai';
|
|
22
|
-
const path = import.meta.resolve('@altertable/data-app/bootstrap');
|
|
23
|
-
const javascript = await readFile(new URL(path), 'utf8');
|
|
24
|
-
const inline = javascript.replace(/<\/script/gi, '<\\/script');
|
|
25
|
-
const originAttribute = parentOrigin
|
|
26
|
-
.replaceAll('&', '&')
|
|
27
|
-
.replaceAll('"', '"')
|
|
28
|
-
.replaceAll('<', '<')
|
|
29
|
-
.replaceAll('>', '>');
|
|
30
|
-
|
|
31
|
-
const html = `<!doctype html>
|
|
32
|
-
<html>
|
|
33
|
-
<head>
|
|
34
|
-
<meta charset="utf-8">
|
|
35
|
-
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
36
|
-
</head>
|
|
37
|
-
<body>
|
|
38
|
-
<div id="root"></div>
|
|
39
|
-
<script data-parent-origin="${originAttribute}">${inline}</script>
|
|
40
|
-
</body>
|
|
41
|
-
</html>`;
|
|
42
|
-
|
|
43
|
-
await mkdir('generated', { recursive: true });
|
|
44
|
-
await writeFile(
|
|
45
|
-
'generated/runtime-html.js',
|
|
46
|
-
`export const RUNTIME_HTML = ${JSON.stringify(html)};\n`
|
|
47
|
-
);
|
|
48
|
-
```
|
|
49
|
-
|
|
50
|
-
```fish
|
|
51
|
-
node scripts/build-runtime.mjs
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
The worker imports `RUNTIME_HTML` and serves it as `text/html; charset=utf-8`.
|
|
55
|
-
The resulting HTML needs no package imports or network fetches at runtime.
|
|
56
|
-
|
|
57
|
-
## Configuration and security
|
|
58
|
-
|
|
59
|
-
Use a regular inline `<script>` with `data-parent-origin` on that same element,
|
|
60
|
-
after the app's mount element. The script reads `document.currentScript` and
|
|
61
|
-
starts immediately. Do not use `type="module"`.
|
|
62
|
-
|
|
63
|
-
The hosting service must supply an exact trusted origin, such as
|
|
64
|
-
`https://app.altertable.ai`, through deployment configuration. Missing or invalid
|
|
65
|
-
origins fail before installing a transport. Do not derive this value from an
|
|
66
|
-
unverified query parameter, referrer, or incoming message.
|
|
67
|
-
|
|
68
|
-
Serve the HTML with the [bootstrap CSP](embed.md#trusted-bootstrap), including a
|
|
69
|
-
`frame-ancestors` header restricted to the trusted host. The script installs the
|
|
70
|
-
authenticated transport, retains opaque host state, evaluates the app bundle
|
|
71
|
-
sent by the host, and reports readiness or failure. The app attaches its own
|
|
72
|
-
navigation adapter. Backend authorization still applies to every data request.
|
|
73
|
-
|
|
74
|
-
Upgrade the host package and bootstrap artifact together when changing the bridge
|
|
75
|
-
protocol. See [client navigation](client.md#app-navigation) and
|
|
76
|
-
[embedding](embed.md) for the communication boundaries.
|