@altertable/data-app 0.64.0 → 0.66.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 +40 -0
- package/CONTRIBUTING.md +37 -3
- package/README.md +2 -2
- package/dist/chunks/{contract-mwe7gnmh.js → contract-13j5zb3c.js} +110 -216
- package/dist/chunks/contract-13j5zb3c.js.map +13 -0
- package/dist/chunks/contract-19ckn3n7.js +78 -0
- package/dist/chunks/contract-19ckn3n7.js.map +10 -0
- package/dist/chunks/contract-awa2d5b1.js +272 -0
- package/dist/chunks/contract-awa2d5b1.js.map +12 -0
- package/dist/chunks/{contract-xtxza1fy.js → contract-e11m4y7f.js} +35 -71
- package/dist/chunks/contract-e11m4y7f.js.map +12 -0
- package/dist/chunks/{contract-zr3jd7mr.js → contract-h8a6f559.js} +100 -75
- package/dist/chunks/contract-h8a6f559.js.map +12 -0
- package/dist/chunks/contract-havnjmdr.js +13011 -0
- package/dist/chunks/contract-havnjmdr.js.map +99 -0
- package/dist/chunks/{contract-txjy0en2.js → contract-m6n8ctfc.js} +64 -72
- package/dist/chunks/contract-m6n8ctfc.js.map +10 -0
- package/dist/chunks/contract-pk603qj7.js +146 -0
- package/dist/chunks/contract-pk603qj7.js.map +10 -0
- package/dist/chunks/{contract-yxbjea23.js → contract-rfbakka4.js} +179 -2
- package/dist/chunks/contract-rfbakka4.js.map +13 -0
- package/dist/client/index.js +11 -6
- package/dist/client/index.js.map +1 -1
- package/dist/core/appearance.js +1 -1
- package/dist/core/contract.js +13 -3
- package/dist/core/contract.js.map +1 -1
- package/dist/embed/index.js +25 -13
- package/dist/embed/index.js.map +3 -3
- package/dist/local.js +1 -1
- package/dist/local.js.map +2 -2
- package/dist/react/embed/index.js +5 -2
- package/dist/react/embed/index.js.map +3 -3
- package/dist/react/index.js +2532 -11273
- package/dist/react/index.js.map +16 -88
- package/dist/react/ui/index.js +1614 -0
- package/dist/react/ui/index.js.map +22 -0
- package/dist/server.js +1 -1
- package/dist/server.js.map +2 -2
- package/dist/types/client/annotations.d.ts +23 -0
- package/dist/types/client/iframe.d.ts +2 -0
- package/dist/types/client/index.d.ts +2 -0
- package/dist/types/client/logger.d.ts +6 -0
- package/dist/types/core/annotations.d.ts +92 -0
- package/dist/types/core/appearance.d.ts +2 -2
- package/dist/types/core/bridge-endpoint.d.ts +21 -0
- package/dist/types/core/bridge.d.ts +137 -16
- package/dist/types/core/contract.d.ts +2 -0
- package/dist/types/core/logger.d.ts +12 -0
- package/dist/types/core/presentation.d.ts +2 -0
- package/dist/types/core/variables.d.ts +2 -5
- package/dist/types/embed/host.d.ts +6 -2
- package/dist/types/embed/index.d.ts +1 -0
- package/dist/types/embed/source.d.ts +1 -1
- package/dist/types/react/annotations/AnnotationBar.d.ts +24 -0
- package/dist/types/react/annotations/AnnotationControls.d.ts +10 -0
- package/dist/types/react/annotations/AnnotationEditor.d.ts +15 -0
- package/dist/types/react/annotations/AnnotationMarkers.d.ts +19 -0
- package/dist/types/react/annotations/AnnotationSelectionLayer.d.ts +12 -0
- package/dist/types/react/annotations/AnnotationTarget.d.ts +9 -0
- package/dist/types/react/annotations/AnnotationTooltip.d.ts +9 -0
- package/dist/types/react/annotations/AnnotationTrigger.d.ts +10 -0
- package/dist/types/react/annotations/annotation-editor-state.d.ts +56 -0
- package/dist/types/react/annotations/annotation-screenshot.d.ts +4 -0
- package/dist/types/react/annotations/annotation-targets.d.ts +33 -0
- package/dist/types/react/annotations/getAnnotationProps.d.ts +15 -0
- package/dist/types/react/annotations/styles.d.ts +3 -0
- package/dist/types/react/annotations/useAnnotationGeometry.d.ts +22 -0
- package/dist/types/react/annotations/useDataAppAnnotations.d.ts +19 -0
- package/dist/types/react/bindings.d.ts +110 -0
- package/dist/types/react/content.d.ts +24 -11
- package/dist/types/react/embed/bridge.d.ts +1 -1
- package/dist/types/react/hooks.d.ts +29 -787
- package/dist/types/react/index.d.ts +30 -104
- package/dist/types/react/source-owner.d.ts +2 -0
- package/dist/types/react/style-contract.d.ts +60 -0
- package/dist/types/react/style-validation.d.ts +2 -0
- package/dist/types/react/ui/AboutData.d.ts +9 -1
- package/dist/types/react/ui/AppHeader.d.ts +1 -2
- package/dist/types/react/ui/AppLayout.d.ts +3 -9
- package/dist/types/react/ui/AppToolbar.d.ts +6 -7
- package/dist/types/react/ui/AreaChart.d.ts +7 -0
- package/dist/types/react/ui/BarChart.d.ts +6 -0
- package/dist/types/react/ui/{ComparisonVisual.d.ts → Comparison.d.ts} +3 -3
- package/dist/types/react/ui/ContentSkeleton.d.ts +2 -0
- package/dist/types/react/ui/DataApp.d.ts +17 -53
- package/dist/types/react/ui/DataAppFrame.d.ts +42 -0
- package/dist/types/react/ui/DataBoundary.d.ts +4 -5
- package/dist/types/react/ui/DataSection.d.ts +6 -18
- package/dist/types/react/ui/DataSectionBoundary.d.ts +30 -0
- package/dist/types/react/ui/DataValue.d.ts +9 -0
- package/dist/types/react/ui/DataWidget.d.ts +2 -1
- package/dist/types/react/ui/DateTimeTooltip.d.ts +1 -1
- package/dist/types/react/ui/ExportControl.d.ts +4 -0
- package/dist/types/react/ui/HelpPopover.d.ts +3 -4
- package/dist/types/react/ui/InspectionContext.d.ts +2 -0
- package/dist/types/react/ui/InspectionProvider.d.ts +29 -0
- package/dist/types/react/ui/LineChart.d.ts +7 -0
- package/dist/types/react/ui/MetricWidget.d.ts +4 -3
- package/dist/types/react/ui/PieChart.d.ts +8 -0
- package/dist/types/react/ui/PresentStory.d.ts +2 -5
- package/dist/types/react/ui/RefreshControl.d.ts +1 -2
- package/dist/types/react/ui/ScatterChart.d.ts +17 -0
- package/dist/types/react/ui/SearchField.d.ts +1 -2
- package/dist/types/react/ui/SearchInput.d.ts +3 -1
- package/dist/types/react/ui/Sheet.d.ts +2 -1
- package/dist/types/react/ui/Skeleton.d.ts +5 -2
- package/dist/types/react/ui/StaticDataApp.d.ts +4 -0
- package/dist/types/react/ui/TableWidget.d.ts +19 -16
- package/dist/types/react/ui/Tabs.d.ts +6 -2
- package/dist/types/react/ui/TextWidget.d.ts +2 -1
- package/dist/types/react/ui/Toast.d.ts +8 -0
- package/dist/types/react/ui/Tooltip.d.ts +4 -3
- package/dist/types/react/ui/TrendChart.d.ts +5 -0
- package/dist/types/react/ui/UpdatedAt.d.ts +1 -1
- package/dist/types/react/ui/VisualizationWidget.d.ts +12 -13
- package/dist/types/react/ui/WidgetViewTabs.d.ts +1 -1
- package/dist/types/react/ui/chart-data.d.ts +25 -0
- package/dist/types/react/ui/csv-export.d.ts +19 -0
- package/dist/types/react/ui/data-context.d.ts +18 -7
- package/dist/types/react/ui/icons.d.ts +2 -0
- package/dist/types/react/ui/index.d.ts +74 -0
- package/dist/types/react/ui/metric.d.ts +1 -1
- package/dist/types/react/ui/presentation.d.ts +5 -1
- package/dist/types/react/ui/shortcuts.d.ts +7 -1
- package/dist/types/react/view-runtime.d.ts +29 -0
- package/dist/types/react/view.d.ts +21 -4
- package/dist/types/react/widgets.d.ts +79 -0
- package/dist/worker.js +381 -79
- package/docs/app-authoring.md +64 -30
- package/docs/data-context.md +89 -0
- package/docs/embed.md +1 -1
- package/docs/formatting-and-appearance.md +52 -0
- package/docs/hosted-apps.md +2 -15
- package/docs/layout.md +33 -0
- package/docs/local-data-apps.md +1 -1
- package/docs/react-embed.md +2 -2
- package/docs/react.md +20 -254
- package/docs/stories-and-export.md +52 -0
- package/docs/styling.md +55 -0
- package/docs/ui-quality.md +20 -0
- package/docs/ui.md +41 -0
- package/docs/variables.md +98 -0
- package/docs/views.md +127 -0
- package/docs/widgets.md +142 -0
- package/examples/starter-data-app/index.tsx +89 -44
- package/package.json +13 -4
- package/dist/chunks/contract-cxr9t12b.js +0 -18
- package/dist/chunks/contract-cxr9t12b.js.map +0 -10
- package/dist/chunks/contract-mwe7gnmh.js.map +0 -13
- package/dist/chunks/contract-txjy0en2.js.map +0 -10
- package/dist/chunks/contract-xtxza1fy.js.map +0 -12
- package/dist/chunks/contract-yxbjea23.js.map +0 -12
- package/dist/chunks/contract-zr3jd7mr.js.map +0 -12
- package/dist/types/react/ui/RefreshRegion.d.ts +0 -9
- package/dist/types/react/ui/SelectableBarChart.d.ts +0 -15
- package/docs/releasing.md +0 -79
- /package/dist/types/react/ui/{comparison.d.ts → metric-comparison.d.ts} +0 -0
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import {
|
|
2
|
+
executeDataOperation,
|
|
3
|
+
toDataOperationFailure
|
|
4
|
+
} from "./contract-pk603qj7.js";
|
|
5
|
+
import {
|
|
6
|
+
DataAppError2,
|
|
7
|
+
createHttpTransport2,
|
|
8
|
+
localFrameBridge,
|
|
9
|
+
getDataAppTransport2
|
|
10
|
+
} from "./contract-13j5zb3c.js";
|
|
11
|
+
import {
|
|
12
|
+
MessageRoutingError2,
|
|
13
|
+
defineDataQueryRoute2
|
|
14
|
+
} from "./contract-tf8c3qpv.js";
|
|
15
|
+
|
|
16
|
+
// src/client/data-client.ts
|
|
17
|
+
var dataQueryRoute = defineDataQueryRoute2();
|
|
18
|
+
function createDataClient2(options = {}) {
|
|
19
|
+
if (options.operations)
|
|
20
|
+
return createOperationClient({
|
|
21
|
+
operations: options.operations,
|
|
22
|
+
lakehouse: options.lakehouse
|
|
23
|
+
});
|
|
24
|
+
const http = createHttpTransport2(options);
|
|
25
|
+
const useHttp = options.endpoint !== undefined || options.fetch !== undefined;
|
|
26
|
+
return {
|
|
27
|
+
async query(name, input, { signal } = {}) {
|
|
28
|
+
const transport = options.transport ?? (useHttp ? http : localFrameBridge()?.transport ?? http);
|
|
29
|
+
const response = await transport(name, input, signal);
|
|
30
|
+
const ok = response.status >= 200 && response.status < 300;
|
|
31
|
+
let body;
|
|
32
|
+
try {
|
|
33
|
+
body = dataQueryRoute.output(response, { operation: name, input }).body;
|
|
34
|
+
} catch (error) {
|
|
35
|
+
if (signal?.aborted)
|
|
36
|
+
throw error;
|
|
37
|
+
if (error instanceof MessageRoutingError2)
|
|
38
|
+
throw new DataAppError2(error.message, error.code, error.requestId);
|
|
39
|
+
throw new DataAppError2(ok ? "The data response was invalid." : "Could not load data.", ok ? "invalid_response" : "request_failed");
|
|
40
|
+
}
|
|
41
|
+
return { ...body, input };
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
function createOperationClient(options) {
|
|
46
|
+
return {
|
|
47
|
+
async query(name, input, { signal } = {}) {
|
|
48
|
+
signal?.throwIfAborted();
|
|
49
|
+
const requestId = crypto.randomUUID();
|
|
50
|
+
if (!Object.hasOwn(options.operations, name))
|
|
51
|
+
throw new DataAppError2("Unknown data operation.", "not_found", requestId);
|
|
52
|
+
const lakehouse = options.lakehouse ?? (typeof window === "undefined" ? undefined : getDataAppTransport2()?.lakehouse);
|
|
53
|
+
if (!lakehouse)
|
|
54
|
+
throw new DataAppError2("An authorized SQL bridge must be installed first.", "bridge_unavailable", requestId);
|
|
55
|
+
try {
|
|
56
|
+
const { body } = await executeDataOperation(options.operations[name], input, {
|
|
57
|
+
lakehouse,
|
|
58
|
+
signal: signal ?? new AbortController().signal,
|
|
59
|
+
includeSql: true,
|
|
60
|
+
requestId,
|
|
61
|
+
operationName: name
|
|
62
|
+
});
|
|
63
|
+
return { ...body, input };
|
|
64
|
+
} catch (error) {
|
|
65
|
+
if (signal?.aborted)
|
|
66
|
+
throw signal.reason;
|
|
67
|
+
if (error instanceof DataAppError2)
|
|
68
|
+
throw error;
|
|
69
|
+
const failure = toDataOperationFailure(error);
|
|
70
|
+
throw new DataAppError2(failure.message, failure.code, requestId);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export { createDataClient2 };
|
|
77
|
+
|
|
78
|
+
//# debugId=64AFD24787CC437264756E2164756E21
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/client/data-client.ts"],
|
|
4
|
+
"sourcesContent": [
|
|
5
|
+
"import { createHttpTransport, DataAppError } from '@/src/client/transport';\nimport { getDataAppTransport, localFrameBridge } from '@/src/client/iframe';\nimport {\n executeDataOperation,\n toDataOperationFailure,\n} from '@/src/core/operation';\nimport type { DataOperations, Lakehouse } from '@/src/core/contract';\nimport { defineDataQueryRoute, MessageRoutingError } from '@/src/core/messages';\nimport type { DataTransport } from '@/src/client/transport';\nimport type {\n DataQueryBody,\n InputOf,\n OutputOf,\n} from '@/src/core/operation-types';\nexport type { InputOf, OutputOf } from '@/src/core/operation-types';\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> = DataQueryBody<Output> & {\n /** The exact browser input that produced this response. */\n input: Input;\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 operations and named-operation delivery are mutually exclusive configurations. */\nexport type DataClientOptions<Operations extends DataOperations> =\n | {\n operations: Operations;\n lakehouse?: Lakehouse;\n transport?: never;\n endpoint?: never;\n fetch?: never;\n }\n | {\n operations?: never;\n lakehouse?: never;\n transport?: DataTransport;\n endpoint?: string;\n fetch?: typeof fetch;\n };\n\nconst dataQueryRoute = defineDataQueryRoute();\n\n/** Named HTTP operations, or browser-owned operations executed through an authorized SQL bridge. */\nexport function createDataClient<Operations extends DataOperations>(\n options: DataClientOptions<Operations> = {}\n): DataClient<Operations> {\n if (options.operations)\n return createOperationClient({\n operations: options.operations,\n lakehouse: options.lakehouse,\n });\n const http = createHttpTransport(options);\n const useHttp = options.endpoint !== undefined || options.fetch !== undefined;\n\n return {\n async query(name, input, { signal } = {}) {\n const transport =\n options.transport ??\n (useHttp ? http : (localFrameBridge()?.transport ?? http));\n const response = await transport(name, input, signal);\n const ok = response.status >= 200 && response.status < 300;\n let body: Omit<DataResponse<OutputOf<Operations[typeof name]>>, 'input'>;\n try {\n body = dataQueryRoute.output(response, { operation: name, input })\n .body as typeof body;\n } catch (error) {\n if (signal?.aborted) throw error;\n if (error instanceof MessageRoutingError)\n throw new DataAppError(error.message, error.code, error.requestId);\n throw new DataAppError(\n ok ? 'The data response was invalid.' : 'Could not load data.',\n ok ? 'invalid_response' : 'request_failed'\n );\n }\n\n return { ...body, input };\n },\n };\n}\n\nfunction createOperationClient<Operations extends DataOperations>(options: {\n operations: Operations;\n lakehouse?: Lakehouse;\n}): DataClient<Operations> {\n return {\n async query(name, input, { signal } = {}) {\n signal?.throwIfAborted();\n const requestId = crypto.randomUUID();\n if (!Object.hasOwn(options.operations, name))\n throw new DataAppError(\n 'Unknown data operation.',\n 'not_found',\n requestId\n );\n const lakehouse =\n options.lakehouse ??\n (typeof window === 'undefined'\n ? undefined\n : getDataAppTransport()?.lakehouse);\n if (!lakehouse)\n throw new DataAppError(\n 'An authorized SQL bridge must be installed first.',\n 'bridge_unavailable',\n requestId\n );\n\n try {\n const { body } = await executeDataOperation(\n options.operations[name]!,\n input,\n {\n lakehouse,\n signal: signal ?? new AbortController().signal,\n includeSql: true,\n requestId,\n operationName: name,\n }\n );\n\n return { ...body, input } as DataResponse<\n OutputOf<Operations[typeof name]>,\n InputOf<Operations[typeof name]>\n >;\n } catch (error) {\n if (signal?.aborted) throw signal.reason;\n if (error instanceof DataAppError) throw error;\n const failure = toDataOperationFailure(error);\n throw new DataAppError(failure.message, failure.code, requestId);\n }\n },\n };\n}\n"
|
|
6
|
+
],
|
|
7
|
+
"mappings": ";;;;;;;;;;;;;;;;AAoDA,IAAM,iBAAiB,sBAAqB;AAGrC,SAAS,iBAAmD,CACjE,UAAyC,CAAC,GAClB;AAAA,EACxB,IAAI,QAAQ;AAAA,IACV,OAAO,sBAAsB;AAAA,MAC3B,YAAY,QAAQ;AAAA,MACpB,WAAW,QAAQ;AAAA,IACrB,CAAC;AAAA,EACH,MAAM,OAAO,qBAAoB,OAAO;AAAA,EACxC,MAAM,UAAU,QAAQ,aAAa,aAAa,QAAQ,UAAU;AAAA,EAEpE,OAAO;AAAA,SACC,MAAK,CAAC,MAAM,SAAS,WAAW,CAAC,GAAG;AAAA,MACxC,MAAM,YACJ,QAAQ,cACP,UAAU,OAAQ,iBAAiB,GAAG,aAAa;AAAA,MACtD,MAAM,WAAW,MAAM,UAAU,MAAM,OAAO,MAAM;AAAA,MACpD,MAAM,KAAK,SAAS,UAAU,OAAO,SAAS,SAAS;AAAA,MACvD,IAAI;AAAA,MACJ,IAAI;AAAA,QACF,OAAO,eAAe,OAAO,UAAU,EAAE,WAAW,MAAM,MAAM,CAAC,EAC9D;AAAA,QACH,OAAO,OAAO;AAAA,QACd,IAAI,QAAQ;AAAA,UAAS,MAAM;AAAA,QAC3B,IAAI,iBAAiB;AAAA,UACnB,MAAM,IAAI,cAAa,MAAM,SAAS,MAAM,MAAM,MAAM,SAAS;AAAA,QACnE,MAAM,IAAI,cACR,KAAK,mCAAmC,wBACxC,KAAK,qBAAqB,gBAC5B;AAAA;AAAA,MAGF,OAAO,KAAK,MAAM,MAAM;AAAA;AAAA,EAE5B;AAAA;AAGF,SAAS,qBAAwD,CAAC,SAGvC;AAAA,EACzB,OAAO;AAAA,SACC,MAAK,CAAC,MAAM,SAAS,WAAW,CAAC,GAAG;AAAA,MACxC,QAAQ,eAAe;AAAA,MACvB,MAAM,YAAY,OAAO,WAAW;AAAA,MACpC,IAAI,CAAC,OAAO,OAAO,QAAQ,YAAY,IAAI;AAAA,QACzC,MAAM,IAAI,cACR,2BACA,aACA,SACF;AAAA,MACF,MAAM,YACJ,QAAQ,cACP,OAAO,WAAW,cACf,YACA,qBAAoB,GAAG;AAAA,MAC7B,IAAI,CAAC;AAAA,QACH,MAAM,IAAI,cACR,qDACA,sBACA,SACF;AAAA,MAEF,IAAI;AAAA,QACF,QAAQ,SAAS,MAAM,qBACrB,QAAQ,WAAW,OACnB,OACA;AAAA,UACE;AAAA,UACA,QAAQ,UAAU,IAAI,gBAAgB,EAAE;AAAA,UACxC,YAAY;AAAA,UACZ;AAAA,UACA,eAAe;AAAA,QACjB,CACF;AAAA,QAEA,OAAO,KAAK,MAAM,MAAM;AAAA,QAIxB,OAAO,OAAO;AAAA,QACd,IAAI,QAAQ;AAAA,UAAS,MAAM,OAAO;AAAA,QAClC,IAAI,iBAAiB;AAAA,UAAc,MAAM;AAAA,QACzC,MAAM,UAAU,uBAAuB,KAAK;AAAA,QAC5C,MAAM,IAAI,cAAa,QAAQ,SAAS,QAAQ,MAAM,SAAS;AAAA;AAAA;AAAA,EAGrE;AAAA;",
|
|
8
|
+
"debugId": "64AFD24787CC437264756E2164756E21",
|
|
9
|
+
"names": []
|
|
10
|
+
}
|
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
// src/core/logger.ts
|
|
2
|
+
function isLogEntry(value) {
|
|
3
|
+
if (!value || typeof value !== "object")
|
|
4
|
+
return false;
|
|
5
|
+
const entry = value;
|
|
6
|
+
return (entry.method === "log" || entry.method === "info" || entry.method === "warn" || entry.method === "error") && Array.isArray(entry.args) && entry.args.length <= 128;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
// src/core/bridge.ts
|
|
10
|
+
var BRIDGE = "altertable:data-app";
|
|
11
|
+
var PARENT_PARAM = "__altertable_parent";
|
|
12
|
+
var MAX_PENDING = 128;
|
|
13
|
+
var REQUEST_TIMEOUT_MS = 60000;
|
|
14
|
+
function validId(value) {
|
|
15
|
+
return typeof value === "string" && /^[a-zA-Z0-9_-]{1,128}$/.test(value);
|
|
16
|
+
}
|
|
17
|
+
function event({
|
|
18
|
+
wire,
|
|
19
|
+
from,
|
|
20
|
+
session,
|
|
21
|
+
parse
|
|
22
|
+
}) {
|
|
23
|
+
return { wire, from, session, parse };
|
|
24
|
+
}
|
|
25
|
+
function id(fields) {
|
|
26
|
+
if (!validId(fields.id))
|
|
27
|
+
throw new Error("Invalid request ID.");
|
|
28
|
+
return fields.id;
|
|
29
|
+
}
|
|
30
|
+
function string(fields, key) {
|
|
31
|
+
const value = fields[key];
|
|
32
|
+
if (typeof value !== "string")
|
|
33
|
+
throw new Error(`Invalid ${key}.`);
|
|
34
|
+
return value;
|
|
35
|
+
}
|
|
36
|
+
function empty() {
|
|
37
|
+
return {};
|
|
38
|
+
}
|
|
39
|
+
var bridgeProtocol = {
|
|
40
|
+
channel: BRIDGE,
|
|
41
|
+
version: 1,
|
|
42
|
+
events: {
|
|
43
|
+
connect: event({
|
|
44
|
+
wire: "bridge:connect",
|
|
45
|
+
from: "host",
|
|
46
|
+
session: "none",
|
|
47
|
+
parse: empty
|
|
48
|
+
}),
|
|
49
|
+
ready: event({
|
|
50
|
+
wire: "bridge:ready",
|
|
51
|
+
from: "app",
|
|
52
|
+
session: "none",
|
|
53
|
+
parse: empty
|
|
54
|
+
}),
|
|
55
|
+
initialize: event({
|
|
56
|
+
wire: "bridge:initialize",
|
|
57
|
+
from: "host",
|
|
58
|
+
session: "establish",
|
|
59
|
+
parse: (fields) => ({ state: fields.state })
|
|
60
|
+
}),
|
|
61
|
+
request: event({
|
|
62
|
+
wire: "bridge:request",
|
|
63
|
+
from: "app",
|
|
64
|
+
session: "current",
|
|
65
|
+
parse: (fields) => {
|
|
66
|
+
const route = string(fields, "route");
|
|
67
|
+
if (!route || route.length > 256)
|
|
68
|
+
throw new Error("Invalid message route.");
|
|
69
|
+
return { id: id(fields), route, payload: fields.payload };
|
|
70
|
+
}
|
|
71
|
+
}),
|
|
72
|
+
result: event({
|
|
73
|
+
wire: "bridge:result",
|
|
74
|
+
from: "host",
|
|
75
|
+
session: "current",
|
|
76
|
+
parse: (fields) => {
|
|
77
|
+
if (!Object.hasOwn(fields, "response"))
|
|
78
|
+
throw new Error("Missing response.");
|
|
79
|
+
return { id: id(fields), response: fields.response };
|
|
80
|
+
}
|
|
81
|
+
}),
|
|
82
|
+
error: event({
|
|
83
|
+
wire: "bridge:error",
|
|
84
|
+
from: "host",
|
|
85
|
+
session: "current",
|
|
86
|
+
parse: (fields) => {
|
|
87
|
+
if (fields.requestId !== undefined && typeof fields.requestId !== "string")
|
|
88
|
+
throw new Error("Invalid requestId.");
|
|
89
|
+
return {
|
|
90
|
+
id: id(fields),
|
|
91
|
+
code: string(fields, "code"),
|
|
92
|
+
message: string(fields, "message"),
|
|
93
|
+
...fields.requestId === undefined ? {} : { requestId: fields.requestId }
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
}),
|
|
97
|
+
cancel: event({
|
|
98
|
+
wire: "bridge:cancel",
|
|
99
|
+
from: "app",
|
|
100
|
+
session: "current",
|
|
101
|
+
parse: (fields) => ({ id: id(fields) })
|
|
102
|
+
}),
|
|
103
|
+
disconnect: event({
|
|
104
|
+
wire: "bridge:disconnect",
|
|
105
|
+
from: "app",
|
|
106
|
+
session: "current",
|
|
107
|
+
parse: empty
|
|
108
|
+
}),
|
|
109
|
+
scriptLoad: event({
|
|
110
|
+
wire: "script:load",
|
|
111
|
+
from: "host",
|
|
112
|
+
session: "current",
|
|
113
|
+
parse: (fields) => ({ javascript: string(fields, "javascript") })
|
|
114
|
+
}),
|
|
115
|
+
stateUpdate: event({
|
|
116
|
+
wire: "state:update",
|
|
117
|
+
from: "host",
|
|
118
|
+
session: "current",
|
|
119
|
+
parse: (fields) => ({ state: fields.state })
|
|
120
|
+
}),
|
|
121
|
+
runtimeLog: event({
|
|
122
|
+
wire: "runtime:log",
|
|
123
|
+
from: "app",
|
|
124
|
+
session: "current",
|
|
125
|
+
parse: (fields) => {
|
|
126
|
+
if (!isLogEntry(fields.payload))
|
|
127
|
+
throw new Error("Invalid log entry.");
|
|
128
|
+
return { payload: fields.payload };
|
|
129
|
+
}
|
|
130
|
+
}),
|
|
131
|
+
runtimeReady: event({
|
|
132
|
+
wire: "runtime:ready",
|
|
133
|
+
from: "app",
|
|
134
|
+
session: "current",
|
|
135
|
+
parse: empty
|
|
136
|
+
}),
|
|
137
|
+
runtimeError: event({
|
|
138
|
+
wire: "runtime:error",
|
|
139
|
+
from: "app",
|
|
140
|
+
session: "current",
|
|
141
|
+
parse: empty
|
|
142
|
+
})
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
var byWire = new Map;
|
|
146
|
+
for (const name of Object.keys(bridgeProtocol.events)) {
|
|
147
|
+
const wire = bridgeProtocol.events[name].wire;
|
|
148
|
+
if (byWire.has(wire))
|
|
149
|
+
throw new Error(`Duplicate bridge event: ${wire}`);
|
|
150
|
+
byWire.set(wire, name);
|
|
151
|
+
}
|
|
152
|
+
function bridgeEventName(wire) {
|
|
153
|
+
return byWire.get(wire);
|
|
154
|
+
}
|
|
155
|
+
function parseBridgeEnvelope(value) {
|
|
156
|
+
if (!value || typeof value !== "object")
|
|
157
|
+
return;
|
|
158
|
+
const fields = value;
|
|
159
|
+
if (fields.channel !== BRIDGE || fields.version !== bridgeProtocol.version || typeof fields.type !== "string" || typeof fields.documentId !== "string" || !fields.documentId || fields.documentId.length > 128 || fields.sessionId !== undefined && !validId(fields.sessionId) || fields.token !== undefined && typeof fields.token !== "string")
|
|
160
|
+
return;
|
|
161
|
+
return fields;
|
|
162
|
+
}
|
|
163
|
+
function parseBridgePayload(envelope, definition) {
|
|
164
|
+
try {
|
|
165
|
+
return {
|
|
166
|
+
channel: BRIDGE,
|
|
167
|
+
version: bridgeProtocol.version,
|
|
168
|
+
documentId: envelope.documentId,
|
|
169
|
+
...envelope.sessionId === undefined ? {} : { sessionId: envelope.sessionId },
|
|
170
|
+
...envelope.token === undefined ? {} : { token: envelope.token },
|
|
171
|
+
type: definition.wire,
|
|
172
|
+
...definition.parse(envelope)
|
|
173
|
+
};
|
|
174
|
+
} catch {
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
function parseBridgeMessage(value) {
|
|
179
|
+
const envelope = parseBridgeEnvelope(value);
|
|
180
|
+
if (!envelope)
|
|
181
|
+
return;
|
|
182
|
+
const name = bridgeEventName(envelope.type);
|
|
183
|
+
if (!name)
|
|
184
|
+
return;
|
|
185
|
+
const definition = bridgeProtocol.events[name];
|
|
186
|
+
if (definition.session !== "none" && envelope.sessionId === undefined)
|
|
187
|
+
return;
|
|
188
|
+
return parseBridgePayload(envelope, definition);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// src/core/bridge-endpoint.ts
|
|
192
|
+
function createBridgeEndpoint({
|
|
193
|
+
role,
|
|
194
|
+
origin,
|
|
195
|
+
source,
|
|
196
|
+
opaque,
|
|
197
|
+
context,
|
|
198
|
+
post,
|
|
199
|
+
diagnostic,
|
|
200
|
+
invalidRequest,
|
|
201
|
+
handlers
|
|
202
|
+
}) {
|
|
203
|
+
let disposed = false;
|
|
204
|
+
function send(name, payload) {
|
|
205
|
+
if (disposed)
|
|
206
|
+
throw new Error("The bridge endpoint has closed.");
|
|
207
|
+
const definition = bridgeProtocol.events[name];
|
|
208
|
+
const current = context();
|
|
209
|
+
const message = parseBridgeMessage({
|
|
210
|
+
...payload,
|
|
211
|
+
channel: bridgeProtocol.channel,
|
|
212
|
+
version: bridgeProtocol.version,
|
|
213
|
+
type: definition.wire,
|
|
214
|
+
documentId: name === "connect" ? "host" : current.documentId,
|
|
215
|
+
sessionId: current.sessionId,
|
|
216
|
+
token: opaque ? current.token : undefined
|
|
217
|
+
});
|
|
218
|
+
if (!message || opaque && !validId(current.token))
|
|
219
|
+
throw new Error("The bridge is not ready to send this event.");
|
|
220
|
+
diagnostic?.("send", definition.wire);
|
|
221
|
+
if (disposed)
|
|
222
|
+
return;
|
|
223
|
+
post(message);
|
|
224
|
+
}
|
|
225
|
+
function receive(event) {
|
|
226
|
+
const peer = source();
|
|
227
|
+
if (disposed || !peer || event.origin !== origin || event.source !== peer)
|
|
228
|
+
return;
|
|
229
|
+
const envelope = parseBridgeEnvelope(event.data);
|
|
230
|
+
if (!envelope)
|
|
231
|
+
return;
|
|
232
|
+
const current = context();
|
|
233
|
+
const connecting = role === "app" && envelope.type === bridgeProtocol.events.connect.wire;
|
|
234
|
+
if (opaque && (connecting ? !validId(envelope.token) : !current.token || envelope.token !== current.token))
|
|
235
|
+
return;
|
|
236
|
+
const name = bridgeEventName(envelope.type);
|
|
237
|
+
if (!name)
|
|
238
|
+
return;
|
|
239
|
+
const definition = bridgeProtocol.events[name];
|
|
240
|
+
if (definition.from === role)
|
|
241
|
+
return;
|
|
242
|
+
if (definition.session === "establish") {
|
|
243
|
+
if (envelope.documentId !== current.documentId || envelope.sessionId === undefined)
|
|
244
|
+
return;
|
|
245
|
+
} else if (definition.session === "current") {
|
|
246
|
+
if (!current.sessionId || envelope.sessionId !== current.sessionId || envelope.documentId !== current.documentId)
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
const message = parseBridgePayload(envelope, definition);
|
|
250
|
+
if (!message) {
|
|
251
|
+
if (role === "host" && name === "request" && validId(envelope.id))
|
|
252
|
+
invalidRequest?.(envelope.id);
|
|
253
|
+
return;
|
|
254
|
+
}
|
|
255
|
+
diagnostic?.("receive", definition.wire);
|
|
256
|
+
if (disposed)
|
|
257
|
+
return;
|
|
258
|
+
const handler = handlers[name];
|
|
259
|
+
handler(message);
|
|
260
|
+
}
|
|
261
|
+
return {
|
|
262
|
+
send,
|
|
263
|
+
receive,
|
|
264
|
+
dispose() {
|
|
265
|
+
disposed = true;
|
|
266
|
+
}
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
export { PARENT_PARAM, MAX_PENDING, REQUEST_TIMEOUT_MS, validId, createBridgeEndpoint };
|
|
271
|
+
|
|
272
|
+
//# debugId=856B2CD0C55C1CE964756E2164756E21
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/core/logger.ts", "../src/core/bridge.ts", "../src/core/bridge-endpoint.ts"],
|
|
4
|
+
"sourcesContent": [
|
|
5
|
+
"/** Host-owned log sink; compatible with console and frontend createLogger(). */\nexport type DataAppLogger = {\n log: (...args: unknown[]) => void;\n info: (...args: unknown[]) => void;\n warn: (...args: unknown[]) => void;\n error: (...args: unknown[]) => void;\n};\n\nexport type LogEntry = {\n method: keyof DataAppLogger;\n args: unknown[];\n};\n\nexport function isLogEntry(value: unknown): value is LogEntry {\n if (!value || typeof value !== 'object') return false;\n const entry = value as Record<string, unknown>;\n return (\n (entry.method === 'log' ||\n entry.method === 'info' ||\n entry.method === 'warn' ||\n entry.method === 'error') &&\n Array.isArray(entry.args) &&\n entry.args.length <= 128\n );\n}\n",
|
|
6
|
+
"import { isLogEntry } from '@/src/core/logger';\n\n/** Data app delivery protocol. IDs identify a document, a shell session, and an individual call. */\nexport const BRIDGE = 'altertable:data-app';\nexport const PARENT_PARAM = '__altertable_parent';\n/** Bound pending requests in the client and host independently.\n * The host enforces its own limit because frames can send messages directly. */\nexport const MAX_PENDING = 128;\nexport const REQUEST_TIMEOUT_MS = 60_000;\nexport type { TransportResponse } from '@/src/core/operation-types';\n\nexport function validId(value: unknown): value is string {\n return typeof value === 'string' && /^[a-zA-Z0-9_-]{1,128}$/.test(value);\n}\n\ntype Fields = Record<string, unknown>;\nexport type BridgeRole = 'host' | 'app';\ntype SessionRule = 'none' | 'establish' | 'current';\n\nfunction event<\n const Wire extends string,\n const Role extends BridgeRole,\n const Session extends SessionRule,\n Payload,\n>({\n wire,\n from,\n session,\n parse,\n}: {\n wire: Wire;\n from: Role;\n session: Session;\n parse: (fields: Fields) => Payload;\n}) {\n return { wire, from, session, parse };\n}\n\nfunction id(fields: Fields) {\n if (!validId(fields.id)) throw new Error('Invalid request ID.');\n return fields.id;\n}\n\nfunction string(fields: Fields, key: string) {\n const value = fields[key];\n if (typeof value !== 'string') throw new Error(`Invalid ${key}.`);\n return value;\n}\n\nfunction empty() {\n return {};\n}\n\n/** Parsers project known fields; opaque values are validated by their owning route or adapter. */\nexport const bridgeProtocol = {\n channel: BRIDGE,\n version: 1,\n events: {\n connect: event({\n wire: 'bridge:connect',\n from: 'host',\n session: 'none',\n parse: empty,\n }),\n ready: event({\n wire: 'bridge:ready',\n from: 'app',\n session: 'none',\n parse: empty,\n }),\n initialize: event({\n wire: 'bridge:initialize',\n from: 'host',\n session: 'establish',\n parse: fields => ({ state: fields.state }),\n }),\n request: event({\n wire: 'bridge:request',\n from: 'app',\n session: 'current',\n parse: fields => {\n const route = string(fields, 'route');\n if (!route || route.length > 256)\n throw new Error('Invalid message route.');\n return { id: id(fields), route, payload: fields.payload };\n },\n }),\n result: event({\n wire: 'bridge:result',\n from: 'host',\n session: 'current',\n parse: fields => {\n if (!Object.hasOwn(fields, 'response'))\n throw new Error('Missing response.');\n return { id: id(fields), response: fields.response };\n },\n }),\n error: event({\n wire: 'bridge:error',\n from: 'host',\n session: 'current',\n parse: fields => {\n if (\n fields.requestId !== undefined &&\n typeof fields.requestId !== 'string'\n )\n throw new Error('Invalid requestId.');\n return {\n id: id(fields),\n code: string(fields, 'code'),\n message: string(fields, 'message'),\n ...(fields.requestId === undefined\n ? {}\n : { requestId: fields.requestId }),\n };\n },\n }),\n cancel: event({\n wire: 'bridge:cancel',\n from: 'app',\n session: 'current',\n parse: fields => ({ id: id(fields) }),\n }),\n disconnect: event({\n wire: 'bridge:disconnect',\n from: 'app',\n session: 'current',\n parse: empty,\n }),\n scriptLoad: event({\n wire: 'script:load',\n from: 'host',\n session: 'current',\n parse: fields => ({ javascript: string(fields, 'javascript') }),\n }),\n stateUpdate: event({\n wire: 'state:update',\n from: 'host',\n session: 'current',\n parse: fields => ({ state: fields.state }),\n }),\n runtimeLog: event({\n wire: 'runtime:log',\n from: 'app',\n session: 'current',\n parse: fields => {\n if (!isLogEntry(fields.payload)) throw new Error('Invalid log entry.');\n return { payload: fields.payload };\n },\n }),\n runtimeReady: event({\n wire: 'runtime:ready',\n from: 'app',\n session: 'current',\n parse: empty,\n }),\n runtimeError: event({\n wire: 'runtime:error',\n from: 'app',\n session: 'current',\n parse: empty,\n }),\n },\n} as const;\n\ntype Events = typeof bridgeProtocol.events;\nexport type BridgeEventName = keyof Events;\nexport type BridgePayload<Name extends BridgeEventName> = ReturnType<\n Events[Name]['parse']\n>;\nexport type BridgeEnvelope = {\n channel: typeof BRIDGE;\n version: typeof bridgeProtocol.version;\n documentId: string;\n sessionId?: string;\n token?: string;\n};\nexport type BridgeEventMessage<Name extends BridgeEventName> =\n Name extends BridgeEventName\n ? BridgeEnvelope & {\n type: Events[Name]['wire'];\n } & (Events[Name]['session'] extends 'none'\n ? {}\n : { sessionId: string }) &\n BridgePayload<Name>\n : never;\nexport type BridgeMessage = {\n [Name in BridgeEventName]: BridgeEventMessage<Name>;\n}[BridgeEventName];\nexport type BridgeEventsFrom<Role extends BridgeRole> = {\n [Name in BridgeEventName]: Events[Name]['from'] extends Role ? Name : never;\n}[BridgeEventName];\nexport type BridgeHandlers<Role extends BridgeRole> = {\n [Name in BridgeEventsFrom<Role extends 'host' ? 'app' : 'host'>]: (\n message: BridgeEventMessage<Name>\n ) => void;\n};\n\nconst byWire = new Map<string, BridgeEventName>();\nfor (const name of Object.keys(bridgeProtocol.events) as BridgeEventName[]) {\n const wire = bridgeProtocol.events[name].wire;\n if (byWire.has(wire)) throw new Error(`Duplicate bridge event: ${wire}`);\n byWire.set(wire, name);\n}\n\nexport function bridgeEventName(wire: string) {\n return byWire.get(wire);\n}\n\n/** Envelope parsing precedes authentication; event-specific fields remain untrusted. */\nexport function parseBridgeEnvelope(\n value: unknown\n): (BridgeEnvelope & Fields & { type: string }) | undefined {\n if (!value || typeof value !== 'object') return;\n const fields = value as Fields;\n if (\n fields.channel !== BRIDGE ||\n fields.version !== bridgeProtocol.version ||\n typeof fields.type !== 'string' ||\n typeof fields.documentId !== 'string' ||\n !fields.documentId ||\n fields.documentId.length > 128 ||\n (fields.sessionId !== undefined && !validId(fields.sessionId)) ||\n (fields.token !== undefined && typeof fields.token !== 'string')\n )\n return;\n return fields as BridgeEnvelope & Fields & { type: string };\n}\n\n/** Project event fields after the caller has checked envelope eligibility. */\nexport function parseBridgePayload(\n envelope: NonNullable<ReturnType<typeof parseBridgeEnvelope>>,\n definition: Events[BridgeEventName]\n): BridgeMessage | undefined {\n try {\n return {\n channel: BRIDGE,\n version: bridgeProtocol.version,\n documentId: envelope.documentId,\n ...(envelope.sessionId === undefined\n ? {}\n : { sessionId: envelope.sessionId }),\n ...(envelope.token === undefined ? {} : { token: envelope.token }),\n type: definition.wire,\n ...definition.parse(envelope),\n } as BridgeMessage;\n } catch {\n return;\n }\n}\n\nexport function parseBridgeMessage(value: unknown): BridgeMessage | undefined {\n const envelope = parseBridgeEnvelope(value);\n if (!envelope) return;\n const name = bridgeEventName(envelope.type);\n if (!name) return;\n const definition = bridgeProtocol.events[name];\n if (definition.session !== 'none' && envelope.sessionId === undefined) return;\n return parseBridgePayload(envelope, definition);\n}\n",
|
|
7
|
+
"import {\n bridgeProtocol,\n bridgeEventName,\n parseBridgeEnvelope,\n parseBridgeMessage,\n parseBridgePayload,\n validId,\n type BridgeMessage,\n type BridgeRole,\n type BridgeEventsFrom,\n type BridgePayload,\n type BridgeEnvelope,\n type BridgeHandlers,\n} from '@/src/core/bridge';\n\ntype ConnectionContext = Pick<BridgeEnvelope, 'sessionId' | 'token'> & {\n documentId?: string;\n};\n\n/** The connection owns IDs and token rotation; callers can only supply event payloads. */\nexport function createBridgeEndpoint<const Role extends BridgeRole>({\n role,\n origin,\n source,\n opaque,\n context,\n post,\n diagnostic,\n invalidRequest,\n handlers,\n}: {\n role: Role;\n handlers: BridgeHandlers<NoInfer<Role>>;\n origin: string;\n source: () => MessageEventSource | null;\n opaque: boolean;\n context: () => ConnectionContext;\n post: (message: BridgeMessage) => void;\n diagnostic?: (\n direction: 'send' | 'receive',\n type: BridgeMessage['type']\n ) => void;\n invalidRequest?: (id: string) => void;\n}) {\n let disposed = false;\n\n function send<\n Name extends BridgeEventsFrom<Role>,\n const Payload extends BridgePayload<NoInfer<Name>>,\n >(\n name: Name,\n payload: Payload &\n Record<Exclude<keyof Payload, keyof BridgePayload<NoInfer<Name>>>, never>\n ) {\n if (disposed) throw new Error('The bridge endpoint has closed.');\n const definition = bridgeProtocol.events[name];\n const current = context();\n const message = parseBridgeMessage({\n ...payload,\n channel: bridgeProtocol.channel,\n version: bridgeProtocol.version,\n type: definition.wire,\n documentId: name === 'connect' ? 'host' : current.documentId,\n sessionId: current.sessionId,\n token: opaque ? current.token : undefined,\n });\n if (!message || (opaque && !validId(current.token)))\n throw new Error('The bridge is not ready to send this event.');\n diagnostic?.('send', definition.wire);\n if (disposed) return;\n post(message);\n }\n\n function receive(event: MessageEvent) {\n const peer = source();\n if (disposed || !peer || event.origin !== origin || event.source !== peer)\n return;\n const envelope = parseBridgeEnvelope(event.data);\n if (!envelope) return;\n const current = context();\n // The app learns its opaque token from a trusted host connect message.\n const connecting =\n role === 'app' && envelope.type === bridgeProtocol.events.connect.wire;\n if (\n opaque &&\n (connecting\n ? !validId(envelope.token)\n : !current.token || envelope.token !== current.token)\n )\n return;\n const name = bridgeEventName(envelope.type);\n if (!name) return;\n const definition = bridgeProtocol.events[name];\n if (definition.from === role) return;\n if (definition.session === 'establish') {\n if (\n envelope.documentId !== current.documentId ||\n envelope.sessionId === undefined\n )\n return;\n } else if (definition.session === 'current') {\n if (\n !current.sessionId ||\n envelope.sessionId !== current.sessionId ||\n envelope.documentId !== current.documentId\n )\n return;\n }\n const message = parseBridgePayload(envelope, definition);\n if (!message) {\n if (role === 'host' && name === 'request' && validId(envelope.id))\n invalidRequest?.(envelope.id);\n return;\n }\n diagnostic?.('receive', definition.wire);\n if (disposed) return;\n // The catalog lookup correlates the key and parsed discriminated message.\n const handler = (handlers as Record<string, (message: unknown) => void>)[\n name\n ]!;\n handler(message);\n }\n\n return {\n send,\n receive,\n dispose() {\n disposed = true;\n },\n };\n}\n"
|
|
8
|
+
],
|
|
9
|
+
"mappings": "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",
|
|
10
|
+
"debugId": "856B2CD0C55C1CE964756E2164756E21",
|
|
11
|
+
"names": []
|
|
12
|
+
}
|
|
@@ -1,82 +1,22 @@
|
|
|
1
1
|
import {
|
|
2
|
-
DataAppError2,
|
|
3
|
-
createHttpTransport2,
|
|
4
2
|
createMessageClient2,
|
|
5
3
|
localFrameBridge,
|
|
6
|
-
getDataAppTransport2
|
|
7
|
-
|
|
8
|
-
toDataOperationFailure
|
|
9
|
-
} from "./contract-mwe7gnmh.js";
|
|
4
|
+
getDataAppTransport2
|
|
5
|
+
} from "./contract-13j5zb3c.js";
|
|
10
6
|
import {
|
|
11
7
|
PARENT_PARAM
|
|
12
|
-
} from "./contract-
|
|
8
|
+
} from "./contract-awa2d5b1.js";
|
|
9
|
+
import {
|
|
10
|
+
annotationDraftRoute2,
|
|
11
|
+
annotationEditorStateRoute2,
|
|
12
|
+
annotationUpdateRoute2,
|
|
13
|
+
annotationModeRoute2
|
|
14
|
+
} from "./contract-rfbakka4.js";
|
|
13
15
|
import {
|
|
14
16
|
validLocation,
|
|
15
|
-
MessageRoutingError2,
|
|
16
|
-
defineDataQueryRoute2,
|
|
17
17
|
navigationUpdateRoute2
|
|
18
18
|
} from "./contract-tf8c3qpv.js";
|
|
19
19
|
|
|
20
|
-
// src/client/data-client.ts
|
|
21
|
-
var dataQueryRoute = defineDataQueryRoute2();
|
|
22
|
-
function createDataClient2(options = {}) {
|
|
23
|
-
if (options.operations)
|
|
24
|
-
return createOperationClient({
|
|
25
|
-
operations: options.operations,
|
|
26
|
-
lakehouse: options.lakehouse
|
|
27
|
-
});
|
|
28
|
-
const http = createHttpTransport2(options);
|
|
29
|
-
const useHttp = options.endpoint !== undefined || options.fetch !== undefined;
|
|
30
|
-
return {
|
|
31
|
-
async query(name, input, { signal } = {}) {
|
|
32
|
-
const transport = options.transport ?? (useHttp ? http : localFrameBridge()?.transport ?? http);
|
|
33
|
-
const response = await transport(name, input, signal);
|
|
34
|
-
const ok = response.status >= 200 && response.status < 300;
|
|
35
|
-
let body;
|
|
36
|
-
try {
|
|
37
|
-
body = dataQueryRoute.output(response, { operation: name, input }).body;
|
|
38
|
-
} catch (error) {
|
|
39
|
-
if (signal?.aborted)
|
|
40
|
-
throw error;
|
|
41
|
-
if (error instanceof MessageRoutingError2)
|
|
42
|
-
throw new DataAppError2(error.message, error.code, error.requestId);
|
|
43
|
-
throw new DataAppError2(ok ? "The data response was invalid." : "Could not load data.", ok ? "invalid_response" : "request_failed");
|
|
44
|
-
}
|
|
45
|
-
return { ...body, input };
|
|
46
|
-
}
|
|
47
|
-
};
|
|
48
|
-
}
|
|
49
|
-
function createOperationClient(options) {
|
|
50
|
-
return {
|
|
51
|
-
async query(name, input, { signal } = {}) {
|
|
52
|
-
signal?.throwIfAborted();
|
|
53
|
-
const requestId = crypto.randomUUID();
|
|
54
|
-
if (!Object.hasOwn(options.operations, name))
|
|
55
|
-
throw new DataAppError2("Unknown data operation.", "not_found", requestId);
|
|
56
|
-
const lakehouse = options.lakehouse ?? (typeof window === "undefined" ? undefined : getDataAppTransport2()?.lakehouse);
|
|
57
|
-
if (!lakehouse)
|
|
58
|
-
throw new DataAppError2("An authorized SQL bridge must be installed first.", "bridge_unavailable", requestId);
|
|
59
|
-
try {
|
|
60
|
-
const { body } = await executeDataOperation(options.operations[name], input, {
|
|
61
|
-
lakehouse,
|
|
62
|
-
signal: signal ?? new AbortController().signal,
|
|
63
|
-
includeSql: true,
|
|
64
|
-
requestId,
|
|
65
|
-
operationName: name
|
|
66
|
-
});
|
|
67
|
-
return { ...body, input };
|
|
68
|
-
} catch (error) {
|
|
69
|
-
if (signal?.aborted)
|
|
70
|
-
throw signal.reason;
|
|
71
|
-
if (error instanceof DataAppError2)
|
|
72
|
-
throw error;
|
|
73
|
-
const failure = toDataOperationFailure(error);
|
|
74
|
-
throw new DataAppError2(failure.message, failure.code, requestId);
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
};
|
|
78
|
-
}
|
|
79
|
-
|
|
80
20
|
// src/client/location.ts
|
|
81
21
|
function createAppLocation(frame, virtual, publish) {
|
|
82
22
|
let state = { search: "", hash: "" };
|
|
@@ -247,6 +187,30 @@ function getDataAppNavigation2(frame = window) {
|
|
|
247
187
|
return adapter.navigation;
|
|
248
188
|
}
|
|
249
189
|
|
|
250
|
-
|
|
190
|
+
// src/client/annotations.ts
|
|
191
|
+
function createAnnotationClient2(transport) {
|
|
192
|
+
const client = createMessageClient2({
|
|
193
|
+
"annotation:draft": annotationDraftRoute2,
|
|
194
|
+
"annotation:update": annotationUpdateRoute2,
|
|
195
|
+
"annotation:mode": annotationModeRoute2,
|
|
196
|
+
"annotation:editor": annotationEditorStateRoute2
|
|
197
|
+
}, transport);
|
|
198
|
+
return {
|
|
199
|
+
reportAnnotationEditorState(state, options) {
|
|
200
|
+
return client.request("annotation:editor", state, options);
|
|
201
|
+
},
|
|
202
|
+
addAnnotation(draft, options) {
|
|
203
|
+
return client.request("annotation:draft", draft, options);
|
|
204
|
+
},
|
|
205
|
+
updateAnnotation(id, comment, options) {
|
|
206
|
+
return client.request("annotation:update", { id, comment }, options);
|
|
207
|
+
},
|
|
208
|
+
requestAnnotationModeChange(request, options) {
|
|
209
|
+
return client.request("annotation:mode", request, options);
|
|
210
|
+
}
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
export { createDataAppNavigation2, getDataAppNavigation2, createAnnotationClient2 };
|
|
251
215
|
|
|
252
|
-
//# debugId=
|
|
216
|
+
//# debugId=19B0E7BB9C5C8F2564756E2164756E21
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/client/location.ts", "../src/client/navigation.ts", "../src/client/annotations.ts"],
|
|
4
|
+
"sourcesContent": [
|
|
5
|
+
"import { PARENT_PARAM } from '@/src/core/bridge';\nimport { validLocation } from '@/src/core/navigation';\n\nimport type { AppLocation, HistoryMode } from '@/src/core/navigation';\nexport type { AppLocation } from '@/src/core/navigation';\nexport type DataAppLocation = {\n snapshot(): AppLocation;\n subscribe(listener: () => void): () => void;\n update(location: AppLocation, mode?: HistoryMode): 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: HistoryMode) => 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 type { AppLocation, HistoryMode } from '@/src/core/navigation';\nimport { createAppLocation, type DataAppLocation } from '@/src/client/location';\nimport { validLocation } from '@/src/core/navigation';\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?: HistoryMode): 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(location: AppLocation, mode: HistoryMode) {\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 (!validLocation(state)) return;\n pendingUpdate = undefined;\n apply(state);\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
|
+
"import {\n annotationDraftRoute,\n annotationUpdateRoute,\n annotationModeRoute,\n annotationEditorStateRoute,\n type DataAppAnnotationDraft,\n} from '@/src/core/annotations';\nimport type { MessageTransport } from '@/src/core/messages';\nimport { createMessageClient } from '@/src/client/messages';\n\n/** Deliver annotations to the authenticated host. Acknowledgement means retained, not sent to an agent. */\nexport function createAnnotationClient(transport: MessageTransport) {\n const client = createMessageClient(\n {\n 'annotation:draft': annotationDraftRoute,\n 'annotation:update': annotationUpdateRoute,\n 'annotation:mode': annotationModeRoute,\n 'annotation:editor': annotationEditorStateRoute,\n },\n transport\n );\n return {\n /** Report the iframe editor's status so the host can guard batch submission. */\n reportAnnotationEditorState(\n state: { hasUnsavedChanges: boolean },\n options?: { signal?: AbortSignal }\n ) {\n return client.request('annotation:editor', state, options);\n },\n addAnnotation(\n draft: DataAppAnnotationDraft,\n options?: { signal?: AbortSignal }\n ) {\n return client.request('annotation:draft', draft, options);\n },\n updateAnnotation(\n id: string,\n comment: string,\n options?: { signal?: AbortSignal }\n ) {\n return client.request('annotation:update', { id, comment }, options);\n },\n /** Ask the host to change its controlled annotation mode. */\n requestAnnotationModeChange(\n request: { active: boolean },\n options?: { signal?: AbortSignal }\n ) {\n return client.request('annotation:mode', request, options);\n },\n };\n}\n"
|
|
8
|
+
],
|
|
9
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;AAYO,SAAS,iBAAiB,CAC/B,OACA,SACA,SACA;AAAA,EACA,IAAI,QAAqB,EAAE,QAAQ,IAAI,MAAM,GAAG;AAAA,EAChD,IAAI,WAAW;AAAA,EACf,MAAM,YAAY,IAAI;AAAA,EAEtB,SAAS,MAAM,GAAG;AAAA,IAChB,WAAW,YAAY;AAAA,MAAW,SAAS;AAAA;AAAA,EAG7C,SAAS,QAAQ,GAAgB;AAAA,IAC/B,IAAI;AAAA,MAAS,OAAO;AAAA,IACpB,MAAM,MAAM,IAAI,IAAI,MAAM,SAAS,IAAI;AAAA,IACvC,IAAI,aAAa,OAAO,YAAY;AAAA,IACpC,IAAI,MAAM,WAAW,IAAI,UAAU,MAAM,SAAS,IAAI;AAAA,MACpD,QAAQ,EAAE,QAAQ,IAAI,QAAQ,MAAM,IAAI,KAAK;AAAA,IAE/C,OAAO;AAAA;AAAA,EAGT,SAAS,KAAK,CAAC,MAAmB;AAAA,IAChC,MAAM,WAAW,SAAS;AAAA,IAC1B,IAAI,SAAS,WAAW,KAAK,UAAU,SAAS,SAAS,KAAK;AAAA,MAAM;AAAA,IACpE,IAAI;AAAA,MAAS,QAAQ;AAAA,IAChB;AAAA,MACH,MAAM,MAAM,IAAI,IAAI,MAAM,SAAS,IAAI;AAAA,MACvC,MAAM,SAAS,IAAI,aAAa,IAAI,YAAY;AAAA,MAChD,IAAI,SAAS,KAAK;AAAA,MAClB,IAAI;AAAA,QAAQ,IAAI,aAAa,IAAI,cAAc,MAAM;AAAA,MACrD,IAAI,OAAO,KAAK;AAAA,MAChB,MAAM,QAAQ,aAAa,MAAM,IAAI,GAAG;AAAA,MACxC,MAAM,cAAc,IAAI,MAAM,UAAU,CAAC;AAAA;AAAA,IAE3C,IAAI;AAAA,MAAS,OAAO;AAAA;AAAA,EAGtB,MAAM,WAA4B;AAAA,IAChC;AAAA,IACA,SAAS,CAAC,UAAU;AAAA,MAClB,UAAU,IAAI,QAAQ;AAAA,MACtB,IAAI,CAAC;AAAA,QAAS,MAAM,iBAAiB,YAAY,QAAQ;AAAA,MAEzD,OAAO,MAAM;AAAA,QACX,UAAU,OAAO,QAAQ;AAAA,QACzB,MAAM,oBAAoB,YAAY,QAAQ;AAAA;AAAA;AAAA,IAGlD,MAAM,CAAC,MAAM,OAAO,WAAW;AAAA,MAC7B,IAAI;AAAA,QAAU;AAAA,MACd,IAAI,CAAC,cAAc,IAAI;AAAA,QAAG,MAAM,IAAI,MAAM,uBAAuB;AAAA,MACjE,MAAM,SAAS,SAAS;AAAA,MACxB,IAAI,OAAO,WAAW,KAAK,UAAU,OAAO,SAAS,KAAK;AAAA,QAAM;AAAA,MAChE,MAAM,IAAI;AAAA,MACV,QAAQ,MAAM,IAAI;AAAA;AAAA,EAEtB;AAAA,EAEA,SAAS,OAAO,GAAG;AAAA,IACjB,WAAW;AAAA,IACX,WAAW,YAAY;AAAA,MACrB,MAAM,oBAAoB,YAAY,QAAQ;AAAA,IAChD,UAAU,MAAM;AAAA;AAAA,EAGlB,OAAO,EAAE,UAAU,OAAO,QAAQ;AAAA;;;AC1D7B,SAAS,wBAAuB;AAAA,EACrC;AAAA,EACA,QAAQ,QAAQ;AAAA,GAII;AAAA,EACpB,OAAO,iBAAiB,OAAO,OAAO,SAAS,UAAU,MAAM,EAAE;AAAA;AAGnE,SAAS,gBAAgB,CACvB,OACA,SACA,YACA;AAAA,EACA,IAAI,WAAW;AAAA,EACf,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,QAAQ,UAAU,OAAO,YAAY,kBACnC,OACA,SACA,OACF;AAAA,EAEA,SAAS,OAAO,CAAC,UAAuB,MAAmB;AAAA,IACzD,MAAM,SAAS,KAAK,UAAU,MAAM,OAAO,MAAM,SAAS,MAAM;AAAA,IAChE,IAAI;AAAA,MAAM,KAAK,MAAM;AAAA,IAChB;AAAA,sBAAgB;AAAA;AAAA,EAGvB,SAAS,MAAM,CAAC,QAAyB;AAAA,IACvC,IAAI;AAAA,MAAU;AAAA,IACd,cAAc;AAAA,IACd,MAAM,WAAW,qBACf,EAAE,qBAAqB,uBAAsB,GAC7C,OAAO,OACT;AAAA,IAEA,SAAS,UAAU,CAAC,QAA0B;AAAA,MACvC,SAAS,QAAQ,qBAAqB,MAAM,EAAE,MAAM,MAAM,EAAE;AAAA;AAAA,IAGnE,SAAS,YAAY,CAAC,OAAgB;AAAA,MACpC,IAAI,CAAC,cAAc,KAAK;AAAA,QAAG;AAAA,MAC3B,gBAAgB;AAAA,MAChB,MAAM,KAAK;AAAA;AAAA,IAGb,OAAO;AAAA,IACP,cAAc,OAAO,UAAU,YAAY;AAAA,IAC3C,aAAa,OAAO,SAAS,CAAC;AAAA,IAC9B,IAAI,eAAe;AAAA,MACjB,WAAW,aAAa;AAAA,MACxB,gBAAgB;AAAA,IAClB;AAAA;AAAA,EAGF,IAAI,UAAU;AAAA,IAAiB,WAAW,KAAK,MAAM,EAAE,MAAM,MAAM,EAAE;AAAA,EAChE;AAAA,WAAO,UAAU;AAAA,EAEtB,MAAM,aAAgC;AAAA,OACjC;AAAA,IACH,OAAO,CAAC,OAAO,WAAW;AAAA,MACxB,IAAI,CAAC;AAAA,QAAU,QAAQ,SAAS,SAAS,GAAG,IAAI;AAAA;AAAA,IAElD,OAAO,GAAG;AAAA,MACR,WAAW;AAAA,MACX,cAAc;AAAA,MACd,QAAQ;AAAA,MACR,OAAO;AAAA,MACP,gBAAgB;AAAA;AAAA,EAEpB;AAAA,EAEA,OAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,UAAU,GAAG;AAAA,MACX,OAAO;AAAA;AAAA,EAEX;AAAA;AAGF,IAAM,gBAAgB,OAAO,IAAI,0BAA0B;AAQpD,SAAS,qBAAoB,CAClC,QAAgB,QACe;AAAA,EAC/B,MAAM,SAAS;AAAA,EACf,MAAM,SAAS,qBAAoB,KAAK;AAAA,EACxC,MAAM,SAAS,OAAO,gBAAgB,WAAW,IAC7C,YACA,OAAO;AAAA,EACX,IAAI,QAAQ;AAAA,IACV,IAAI,UAAU,OAAO,WAAW,QAAQ;AAAA,MACtC,OAAO,OAAO,MAAM;AAAA,MACpB,OAAO,SAAS;AAAA,IAClB;AAAA,IAEA,OAAO,OAAO;AAAA,EAChB;AAAA,EACA,IAAI,QAAQ;AAAA,IACV,MAAM,UAAU,iBAAiB,OAAO,OAAO,SAAS,UAAU,MAAM;AAAA,IACxE,OAAO,iBAAiB,EAAE,WAAW,QAAQ;AAAA,IAE7C,OAAO,QAAQ;AAAA,EACjB;AAAA,EACA,MAAM,UAAU,iBAAiB,KAAK;AAAA,EACtC,IAAI,CAAC,SAAS;AAAA,IAAS;AAAA,EACvB,MAAM,aAAa,QAAQ,QAAQ;AAAA,EACnC,MAAM,UAAU,iBAAiB,OAAO,OAAO,UAAU;AAAA,EACzD,MAAM,QAAQ;AAAA,OACT;AAAA,IACH,QAAQ;AAAA,EACV;AAAA,EACA,OAAO,iBAAiB;AAAA,EACnB,WACF,KAAK,YAAU;AAAA,IACd,MAAM,SAAS;AAAA,GAChB,EACA,MAAM,MAAM,EAAE;AAAA,EAEjB,OAAO,QAAQ;AAAA;;;AC3IV,SAAS,uBAAsB,CAAC,WAA6B;AAAA,EAClE,MAAM,SAAS,qBACb;AAAA,IACE,oBAAoB;AAAA,IACpB,qBAAqB;AAAA,IACrB,mBAAmB;AAAA,IACnB,qBAAqB;AAAA,EACvB,GACA,SACF;AAAA,EACA,OAAO;AAAA,IAEL,2BAA2B,CACzB,OACA,SACA;AAAA,MACA,OAAO,OAAO,QAAQ,qBAAqB,OAAO,OAAO;AAAA;AAAA,IAE3D,aAAa,CACX,OACA,SACA;AAAA,MACA,OAAO,OAAO,QAAQ,oBAAoB,OAAO,OAAO;AAAA;AAAA,IAE1D,gBAAgB,CACd,IACA,SACA,SACA;AAAA,MACA,OAAO,OAAO,QAAQ,qBAAqB,EAAE,IAAI,QAAQ,GAAG,OAAO;AAAA;AAAA,IAGrE,2BAA2B,CACzB,SACA,SACA;AAAA,MACA,OAAO,OAAO,QAAQ,mBAAmB,SAAS,OAAO;AAAA;AAAA,EAE7D;AAAA;",
|
|
10
|
+
"debugId": "19B0E7BB9C5C8F2564756E2164756E21",
|
|
11
|
+
"names": []
|
|
12
|
+
}
|