@holistics/anfra-sdk 0.7.1 → 0.8.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/README.md +29 -4
- package/dist/api.d.ts +7 -4
- package/dist/api.js +30 -4
- package/dist/app.d.ts +36 -5
- package/dist/app.js +216 -12
- package/dist/{bridge-BKx7u5mX.d.ts → bridge-BmbS9J4V.d.ts} +50 -3
- package/dist/{chunk-KCTLO3CO.js → chunk-KBXITYQK.js} +4 -3
- package/dist/common.d.ts +2 -2
- package/dist/common.js +1 -2
- package/dist/host.d.ts +24 -5
- package/dist/host.js +108 -5
- package/dist/{types-BlzJVcUl.d.ts → types-IR4TNw-M.d.ts} +101 -1
- package/package.json +2 -1
- package/dist/chunk-PKBMQBKP.js +0 -7
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
3
|
+
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
4
4
|
|
|
5
5
|
// src/common/errors.ts
|
|
6
6
|
var DataAppError = class extends Error {
|
|
@@ -33,6 +33,7 @@ var TransportError = class extends DataAppError {
|
|
|
33
33
|
};
|
|
34
34
|
|
|
35
35
|
export {
|
|
36
|
+
__publicField,
|
|
36
37
|
DataAppError,
|
|
37
38
|
ValidationError,
|
|
38
39
|
QueryError,
|
package/dist/common.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
export { D as DataAppError, P as PermissionError, Q as QueryError, T as TransportError, V as ValidationError } from './errors-CKvqVaqU.js';
|
|
2
|
-
export { A as Aggregation, a as AppDeclaration, b as AppJson, c as ArrowType, B as Backend, d as BackendCondition, e as BackendDateDrill, f as
|
|
3
|
-
export { B as BridgeError, a as BridgeMethod, F as FrameMessage, H as HostMessage, P as PROVISION_ELEMENT_ID, b as Provision } from './bridge-
|
|
2
|
+
export { A as Aggregation, a as AppDeclaration, b as AppJson, c as ArrowType, B as Backend, d as BackendCondition, e as BackendDateDrill, f as BackendExportRequest, g as BackendFilter, h as BackendQueryRequest, i as BackendQueryResult, j as BackendSort, C as ColumnMeta, k as Condition, l as ConditionValue, m as ControlMappingJson, n as CrossFilterJson, D as DatasetDescriptor, o as DateDrillDeclaration, p as DateGrain, q as DateTransformation, E as EntityKind, r as EntityRef, s as EntityUsage, t as ExecuteOptions, u as ExecuteSummary, v as ExportFormat, w as ExportFormatOptions, x as ExportOptions, y as ExportResult, F as FILTER_AGGREGATIONS, z as FieldSuggestionsRequest, G as FilterAggregation, H as FilterDeclaration, I as FilterValueType, J as InspectedApp, K as InspectedControl, L as InspectedError, M as InspectedQuery, N as InspectedSelection, O as InspectedStructure, P as Listener, Q as LocateKind, R as LocateTarget, S as MappingJson, T as Operator, U as QueryDebug, V as QueryDeclaration, W as QueryInput, X as QueryResult, Y as QuerySort, Z as QueryState, _ as RenderFormat, $ as RenderRequest, a0 as Rendering, a1 as Row, a2 as SdkEnvironment, a3 as SdkFeatures, a4 as Selection, a5 as SelectionCondition, a6 as SemanticType, a7 as StructureKind, a8 as StructureNode, a9 as Unsubscribe, aa as User } from './types-IR4TNw-M.js';
|
|
3
|
+
export { B as BridgeError, a as BridgeMethod, F as FrameMessage, H as HostMessage, P as PROVISION_ELEMENT_ID, b as Provision } from './bridge-BmbS9J4V.js';
|
package/dist/common.js
CHANGED
package/dist/host.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { b as Provision } from './bridge-
|
|
1
|
+
import { J as InspectedApp, O as InspectedStructure, R as LocateTarget, $ as RenderRequest, a0 as Rendering, B as Backend, D as DatasetDescriptor, aa as User } from './types-IR4TNw-M.js';
|
|
2
|
+
import { b as Provision } from './bridge-BmbS9J4V.js';
|
|
3
3
|
|
|
4
4
|
interface BridgeHandle {
|
|
5
5
|
/** Ask the frame to post (or stop posting) inspection snapshots; survives the frame reloading. */
|
|
@@ -13,8 +13,19 @@ interface BridgeHandle {
|
|
|
13
13
|
locate: (target: LocateTarget) => void;
|
|
14
14
|
/** Start or stop pick mode in the frame: pointing outlines marked elements, a click reports one. */
|
|
15
15
|
setPicking: (on: boolean) => void;
|
|
16
|
+
/**
|
|
17
|
+
* Render the app, or one block or container, once its running queries settle, and save the file
|
|
18
|
+
* for the reader. Rejects with a `ValidationError` when the frame can't, or rendering is off.
|
|
19
|
+
*/
|
|
20
|
+
render: (request: RenderRequest) => Promise<Rendering>;
|
|
16
21
|
stop: () => void;
|
|
17
22
|
}
|
|
23
|
+
interface BridgeOptions {
|
|
24
|
+
/** Whether the frame may render: off unless true, and off, its asks are refused and `render` rejects. */
|
|
25
|
+
render?: boolean;
|
|
26
|
+
/** The renderer's code (`anfra-sdk:renderer`), sent to the frame on its first rendering. */
|
|
27
|
+
renderer?: string;
|
|
28
|
+
}
|
|
18
29
|
interface BridgeCallbacks {
|
|
19
30
|
/** The frame's inspection snapshot: its apps and its structure. */
|
|
20
31
|
onInspect?: (apps: InspectedApp[], structure: InspectedStructure) => void;
|
|
@@ -27,7 +38,7 @@ interface BridgeCallbacks {
|
|
|
27
38
|
* frame are served (a sandboxed frame has an opaque origin, so its window is what identifies it),
|
|
28
39
|
* and only the Backend's own methods: nothing else of the API is reachable from a frame.
|
|
29
40
|
*/
|
|
30
|
-
declare function serveBridge(frame: HTMLIFrameElement, backend: Backend, callbacks?: BridgeCallbacks): BridgeHandle;
|
|
41
|
+
declare function serveBridge(frame: HTMLIFrameElement, backend: Backend, callbacks?: BridgeCallbacks, options?: BridgeOptions): BridgeHandle;
|
|
31
42
|
|
|
32
43
|
interface MountOptions extends BridgeCallbacks {
|
|
33
44
|
/** Where the frame goes: it is appended to this element. */
|
|
@@ -42,9 +53,17 @@ interface MountOptions extends BridgeCallbacks {
|
|
|
42
53
|
backend: Backend;
|
|
43
54
|
/** The frame script; the one built into this package unless given (tests). */
|
|
44
55
|
frameScript?: string;
|
|
56
|
+
/**
|
|
57
|
+
* Whether the frame may render itself as a PNG or PDF (`Anfra.render()`, `render()` here). Off
|
|
58
|
+
* unless turned on: rendering has the host save a file the frame made, so a host opts in to it
|
|
59
|
+
* (docs/designs/data-apps.md, Renderings).
|
|
60
|
+
*/
|
|
61
|
+
render?: boolean;
|
|
62
|
+
/** The renderer's script; the one built into this package unless given (tests). */
|
|
63
|
+
renderer?: string;
|
|
45
64
|
title?: string;
|
|
46
65
|
}
|
|
47
|
-
interface MountedDataApp extends Pick<BridgeHandle, 'setInspecting' | 'highlight' | 'locate' | 'setPicking'> {
|
|
66
|
+
interface MountedDataApp extends Pick<BridgeHandle, 'setInspecting' | 'highlight' | 'locate' | 'setPicking' | 'render'> {
|
|
48
67
|
frame: HTMLIFrameElement;
|
|
49
68
|
/** Stop answering the frame, and remove it. */
|
|
50
69
|
unmount: () => void;
|
|
@@ -71,4 +90,4 @@ interface ProvisionOptions {
|
|
|
71
90
|
*/
|
|
72
91
|
declare function provisionDocument(definition: string, options: ProvisionOptions): string;
|
|
73
92
|
|
|
74
|
-
export { type BridgeCallbacks, type BridgeHandle, type MountOptions, type MountedDataApp, type ProvisionOptions, mountDataApp, provisionDocument, serveBridge };
|
|
93
|
+
export { type BridgeCallbacks, type BridgeHandle, type BridgeOptions, type MountOptions, type MountedDataApp, type ProvisionOptions, mountDataApp, provisionDocument, serveBridge };
|
package/dist/host.js
CHANGED
|
@@ -1,15 +1,67 @@
|
|
|
1
1
|
import {
|
|
2
2
|
PROVISION_ELEMENT_ID
|
|
3
3
|
} from "./chunk-33B2D4U5.js";
|
|
4
|
-
import
|
|
4
|
+
import {
|
|
5
|
+
TransportError,
|
|
6
|
+
ValidationError
|
|
7
|
+
} from "./chunk-KBXITYQK.js";
|
|
5
8
|
|
|
6
9
|
// src/host/bridge.ts
|
|
10
|
+
var RENDERING_OFF = "This host does not render Data Apps.";
|
|
11
|
+
var PICTURES = [
|
|
12
|
+
{ ext: "png", type: "image/png", signature: [137, 80, 78, 71, 13, 10, 26, 10] },
|
|
13
|
+
{ ext: "pdf", type: "application/pdf", signature: [37, 80, 68, 70, 45] }
|
|
14
|
+
];
|
|
15
|
+
var SAVES_PER_WINDOW = 5;
|
|
16
|
+
var SAVE_WINDOW_MS = 1e4;
|
|
17
|
+
function pictureFilename(filename, ext) {
|
|
18
|
+
const name = (typeof filename === "string" ? filename : "").replace(/[\u0000-\u001f\u007f-\u009f\u200e\u200f\u202a-\u202e\u2066-\u2069]/g, "").replace(/[\\/:*?"<>|]/g, "-").trim().replace(/^[.\s]+|[.\s]+$/g, "").slice(0, 200) || "Rendering";
|
|
19
|
+
return name.toLowerCase().endsWith(`.${ext}`) ? name : `${name}.${ext}`;
|
|
20
|
+
}
|
|
21
|
+
async function saveBlob(doc, request) {
|
|
22
|
+
const blob = request?.blob;
|
|
23
|
+
if (!(blob instanceof Blob)) throw new ValidationError("A rendering must be saved as a file.");
|
|
24
|
+
const head = new Uint8Array(await blob.slice(0, 8).arrayBuffer());
|
|
25
|
+
const picture = PICTURES.find(({ signature }) => signature.every((byte, i) => head[i] === byte));
|
|
26
|
+
if (!picture) throw new ValidationError("Only a PNG or a PDF rendering can be saved.");
|
|
27
|
+
const url = URL.createObjectURL(new Blob([blob], { type: picture.type }));
|
|
28
|
+
const a = doc.createElement("a");
|
|
29
|
+
a.href = url;
|
|
30
|
+
a.download = pictureFilename(request.filename, picture.ext);
|
|
31
|
+
a.rel = "noopener";
|
|
32
|
+
a.style.display = "none";
|
|
33
|
+
doc.body.appendChild(a);
|
|
34
|
+
a.click();
|
|
35
|
+
a.remove();
|
|
36
|
+
setTimeout(() => URL.revokeObjectURL(url), 6e4);
|
|
37
|
+
}
|
|
7
38
|
function toBridgeError(err) {
|
|
8
39
|
const e = err;
|
|
9
40
|
return { name: e?.name ?? "QueryError", message: e?.message ?? "The query failed." };
|
|
10
41
|
}
|
|
11
|
-
function
|
|
42
|
+
function saveFile(doc, link) {
|
|
43
|
+
const a = doc.createElement("a");
|
|
44
|
+
a.href = link.url;
|
|
45
|
+
a.download = link.filename;
|
|
46
|
+
a.rel = "noopener";
|
|
47
|
+
a.style.display = "none";
|
|
48
|
+
doc.body.appendChild(a);
|
|
49
|
+
a.click();
|
|
50
|
+
a.remove();
|
|
51
|
+
}
|
|
52
|
+
async function exportAndSave(backend, doc, request, signal) {
|
|
53
|
+
if (!backend.exportQuery) throw new TransportError("This host cannot make exports.");
|
|
54
|
+
const link = await backend.exportQuery(request, signal);
|
|
55
|
+
saveFile(doc, link);
|
|
56
|
+
return link;
|
|
57
|
+
}
|
|
58
|
+
function serveBridge(frame, backend, callbacks = {}, options = {}) {
|
|
12
59
|
const inFlight = /* @__PURE__ */ new Map();
|
|
60
|
+
const renderings = /* @__PURE__ */ new Map();
|
|
61
|
+
let nextRender = 1;
|
|
62
|
+
let saving = false;
|
|
63
|
+
const saves = [];
|
|
64
|
+
const rendering = options.render === true && !!options.renderer;
|
|
13
65
|
let inspecting = false;
|
|
14
66
|
const win = frame.ownerDocument.defaultView ?? window;
|
|
15
67
|
const reply = (message) => frame.contentWindow?.postMessage(message, "*");
|
|
@@ -29,6 +81,14 @@ function serveBridge(frame, backend, callbacks = {}) {
|
|
|
29
81
|
case "anfra:picked":
|
|
30
82
|
if (inspecting) callbacks.onPick?.(message.node);
|
|
31
83
|
return;
|
|
84
|
+
case "anfra:rendered": {
|
|
85
|
+
const pending = renderings.get(message.id);
|
|
86
|
+
if (!pending) return;
|
|
87
|
+
renderings.delete(message.id);
|
|
88
|
+
if (message.ok) pending.resolve(message.result);
|
|
89
|
+
else pending.reject(new ValidationError(message.error.message));
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
32
92
|
case "anfra:cancel":
|
|
33
93
|
inFlight.get(message.id)?.abort();
|
|
34
94
|
inFlight.delete(message.id);
|
|
@@ -37,7 +97,23 @@ function serveBridge(frame, backend, callbacks = {}) {
|
|
|
37
97
|
const { id } = message;
|
|
38
98
|
const controller = new AbortController();
|
|
39
99
|
inFlight.set(id, controller);
|
|
40
|
-
const result = message.method === "submitQuery" ? backend.submitQuery(message.request, controller.signal) : message.method === "fieldSuggestions" ? backend.fieldSuggestions(message.request, controller.signal) :
|
|
100
|
+
const result = message.method === "submitQuery" ? backend.submitQuery(message.request, controller.signal) : message.method === "fieldSuggestions" ? backend.fieldSuggestions(message.request, controller.signal) : message.method === "exportQuery" ? exportAndSave(backend, frame.ownerDocument, message.request, controller.signal) : message.method === "renderer" || message.method === "saveFile" ? (async () => {
|
|
101
|
+
if (!rendering) throw new ValidationError(RENDERING_OFF);
|
|
102
|
+
if (message.method === "renderer") return options.renderer;
|
|
103
|
+
const now = Date.now();
|
|
104
|
+
while (saves.length && now - saves[0] >= SAVE_WINDOW_MS) saves.shift();
|
|
105
|
+
if (saving || saves.length >= SAVES_PER_WINDOW) {
|
|
106
|
+
throw new ValidationError("Too many files saved at once: try again in a few seconds.");
|
|
107
|
+
}
|
|
108
|
+
saving = true;
|
|
109
|
+
saves.push(now);
|
|
110
|
+
try {
|
|
111
|
+
await saveBlob(frame.ownerDocument, message.request);
|
|
112
|
+
} finally {
|
|
113
|
+
saving = false;
|
|
114
|
+
}
|
|
115
|
+
return null;
|
|
116
|
+
})() : Promise.reject(new Error(`No such Backend method: ${String(message.method)}`));
|
|
41
117
|
result.then((value) => reply({ type: "anfra:response", id, ok: true, result: value })).catch((err) => {
|
|
42
118
|
if (err?.name === "AbortError") return;
|
|
43
119
|
reply({ type: "anfra:response", id, ok: false, error: toBridgeError(err) });
|
|
@@ -62,22 +138,40 @@ function serveBridge(frame, backend, callbacks = {}) {
|
|
|
62
138
|
setPicking(on) {
|
|
63
139
|
reply({ type: "anfra:pick-watch", on });
|
|
64
140
|
},
|
|
141
|
+
render(request) {
|
|
142
|
+
if (!rendering) return Promise.reject(new ValidationError(RENDERING_OFF));
|
|
143
|
+
const id = nextRender++;
|
|
144
|
+
return new Promise((resolve, reject) => {
|
|
145
|
+
renderings.set(id, { resolve, reject });
|
|
146
|
+
reply({ type: "anfra:render", id, request });
|
|
147
|
+
});
|
|
148
|
+
},
|
|
65
149
|
stop() {
|
|
66
150
|
win.removeEventListener("message", onMessage);
|
|
67
151
|
inFlight.forEach((controller) => controller.abort());
|
|
68
152
|
inFlight.clear();
|
|
153
|
+
renderings.forEach(({ reject }) => reject(new ValidationError("The Data App was unmounted before its rendering finished.")));
|
|
154
|
+
renderings.clear();
|
|
69
155
|
}
|
|
70
156
|
};
|
|
71
157
|
}
|
|
72
158
|
|
|
73
159
|
// frame-script:anfra-sdk:frame-script
|
|
74
|
-
var anfra_sdk_frame_script_default = '"use strict";(()=>{var ze=Object.defineProperty;var Pe=(t,n,e)=>n in t?ze(t,n,{enumerable:!0,configurable:!0,writable:!0,value:e}):t[n]=e;var d=(t,n,e)=>Pe(t,typeof n!="symbol"?n+"":n,e);var $=class extends Error{constructor(e,r){super(e);d(this,"entity");this.name=new.target.name,this.entity=r,Object.setPrototypeOf(this,new.target.prototype)}},p=class extends ${},T=class extends ${constructor(e,r,i){super(e,r);d(this,"cause");this.cause=i}},P=class extends ${},V=class extends ${constructor(e,r,i){super(e,i);d(this,"status");this.status=r}};var ae="anfra-provision";var O=class{constructor(n){d(this,"listeners",new Set);d(this,"parent");this.parent=n}subscribe(n){return this.listeners.add(n),()=>{this.listeners.delete(n)}}notifyChange(){this.listeners.forEach(n=>n()),this.parent?.notifyChange()}notify(){this.notifyChange()}};var F=class extends O{constructor(e,r,i){super(r);d(this,"kind","query");d(this,"name");d(this,"declaration");d(this,"dataset");d(this,"app");d(this,"_state","idle");d(this,"_result");d(this,"_error");d(this,"_page",1);d(this,"_sort",[]);d(this,"lastRunSignature");d(this,"lastPageRows",0);d(this,"controller");if(!i.aql?.trim())throw new p(`Query \'${e}\' declares no AQL.`,e);let{pageSize:s}=i;if(s!==void 0&&!(Number.isInteger(s)&&s>=1))throw new p(`Query \'${e}\' declares pageSize ${s}; it must be a whole number of at least 1.`,e);this.name=e,this.app=r,this.declaration=i,this.dataset=r.datasetIndex(i.dataset,e)}locate(){return this.app.locate("query",this.name)}get state(){return this._state}get result(){return this._result}get error(){return this._error}get pageSize(){return this.declaration.pageSize}get page(){return this._page}get sort(){return this._sort}setSort(e){this._sort=[...e],this.notify()}get hasMore(){return!this._result||this.pageSize===void 0?!1:this.lastPageRows>=this.pageSize}signature(){let e=this.app.mappingsTo(this.name).map(r=>({field:r.field,aggregation:r.aggregation,condition:r.from.condition})).sort((r,i)=>r.field.localeCompare(i.field)||JSON.stringify(r).localeCompare(JSON.stringify(i)));return JSON.stringify({declaration:this.declaration,conditions:e,selection:this.app.selectionConditionsFor(this.name,"pending"),selectionExpression:this.app.selectionExpressionFor(this.name,"pending"),sort:this._sort,timezone:this.app.timezone,page:this._page})}get isDirty(){return this.lastRunSignature!==void 0&&this.signature()!==this.lastRunSignature}shouldRun(e=!1){return e||this.lastRunSignature===void 0||this.isDirty}abort(){this.controller?.abort()}async fetchMore(){if(this.pageSize===void 0)throw new p(`Query \'${this.name}\' declares no pageSize, so it has no more pages.`,this.name);this.hasMore&&(this._page+=1,await this.app.fetchPage(this))}select(e,r={}){this.app.select(this,Array.isArray(e)?e:[e],r.fields)}get selectedRows(){let{selection:e}=this.app;if(e?.source!==this.name)return[];let r=this._result?.rows;if(!r)return e.rows;let i=l=>JSON.stringify(e.fields.map(o=>l[o]??null)),s=new Set(e.rows.map(i));return r.filter(l=>s.has(i(l)))}markExecuting(){this._state="executing",this._error=void 0,this.notify()}markSuccess(e,r,i){if(this._state="success",this._error=void 0,this.lastRunSignature=r,this.lastPageRows=e.rows.length,i&&this._result){let s=[...this._result.rows,...e.rows];this._result={...e,rows:s,meta:{...e.meta,numRows:s.length}}}else this._result=e;this.notify()}markError(e){this._state="error",this._error=e,this.notify()}rewindPage(){this._page>1&&(this._page-=1)}resetPage(){this._page=1,this.lastPageRows=0}toJSON(){return this.declaration}};var le=["year","quarter","month","week","day","hour","minute"];function Ve(t,n){if(!le.includes(n))throw new p(`Invalid grain \'${n}\'. Expected one of: ${le.join(", ")}.`,t)}function de(t,n){return n?(Ve(t,n),{operator:"transform_date_drill",values:[`datetrunc ${n}`]}):{operator:"none"}}function Je(t){let n=t.toLowerCase();return n.includes("date")||n.includes("time")?"date":n.includes("int")||n.includes("number")||n.includes("float")||n.includes("decimal")?"number":n.includes("bool")?"boolean":"string"}function je(t,n){return JSON.stringify(t??null)===JSON.stringify(n??null)}var I=class extends O{constructor(e,r,i){super(r);d(this,"name");d(this,"app");d(this,"pending");d(this,"applied");d(this,"initial");this.name=e,this.app=r,this.initial=i,this.pending=i}locate(){return this.app.locate("control",this.name)}get condition(){return this.pending}get appliedCondition(){return this.applied}get isDirty(){return this.applied!==void 0&&!je(this.pending,this.applied)}setCondition(e){this.pending=e,this.notify()}reset(){this.setCondition(this.initial)}commit(){this.applied=this.pending}},J=class extends I{constructor(e,r,i,s,l){super(e,r,i.default??{operator:"is",values:[]});d(this,"kind","filter");d(this,"declaration");d(this,"type");d(this,"resolved");d(this,"datasetName");d(this,"backend");d(this,"loadedOptions");if(this.declaration=i,this.backend=l,i.field){if(!s)throw new p(`Filter \'${e}\' names a field but no dataset. Pass \\`dataset\\` alongside \\`field\\`.`,e);this.resolved=s.resolve(i.field,e),this.datasetName=s.descriptor.name,this.type=i.type??Je(this.resolved.type)}else{if(!i.type)throw new p(`Filter \'${e}\' is a manual filter, so it needs a \\`type\\`.`,e);this.type=i.type}this.assertValues(this.condition.values??[]),this.assertValues(i.options??[])}setCondition(e){this.assertValues(e.values??[]),super.setCondition(e)}assertValues(e){if(this.type!=="number")return;let r=e.find(i=>typeof i=="number");if(r!==void 0)throw new p(`Filter \'${this.name}\' filters numbers: give its values as strings, as query results give them (${JSON.stringify(String(r))}, not ${String(r)}), so none has lost a digit.`,this.name)}get isFieldBacked(){return this.resolved!==void 0}get options(){return this.loadedOptions??this.declaration.options??[]}async loadOptions(e,r=new AbortController().signal){let i=this.resolved?.modelName;if(!this.resolved||!i||!this.backend||!this.datasetName)return this.options;let s=await this.backend.fieldSuggestions({dataset:this.datasetName,model:i,field:this.resolved.fieldName,q:e??""},r);return this.loadedOptions=[...s??[]],this.notify(),this.loadedOptions}toJSON(){return this.declaration}},j=class extends I{constructor(e,r,i={}){super(e,r,de(e,i.default));d(this,"kind","dateDrill");d(this,"declaration");this.declaration=i}setGrain(e){this.setCondition(de(this.name,e))}toJSON(){return this.declaration}};var G=class{constructor(n,e,r,i){d(this,"kind","control");d(this,"from");d(this,"to");d(this,"field");d(this,"aggregation");this.from=n,this.to=e,this.field=r,this.aggregation=i}get id(){return`${this.from.name}.${this.to.name}.${this.field}`}toJSON(){return{kind:this.kind,id:this.id,from:{kind:this.from.kind,name:this.from.name},to:{kind:"query",name:this.to.name},field:this.field,...this.aggregation?{aggregation:this.aggregation}:{}}}},q=class{constructor(n,e){d(this,"kind","crossFilter");d(this,"from");d(this,"to");this.from=n,this.to=e}get id(){return`${this.from.name}.${this.to.name}`}toJSON(){return{kind:this.kind,id:this.id,from:{kind:"query",name:this.from.name},to:{kind:"query",name:this.to.name}}}};var Z=["sum","avg","max","min","count","count distinct","median","stdev","stdevp","var","varp"];function Ge(t,n){let e=t.length+1,r=n.length+1,i=Array.from({length:r},(s,l)=>l);for(let s=1;s<e;s++){let l=[s];for(let o=1;o<r;o++)l[o]=Math.min(i[o]+1,l[o-1]+1,i[o-1]+(t[s-1]===n[o-1]?0:1));i=l}return i[r-1]}function qe(t,n){let e,r=1/0;n.forEach(s=>{let l=Ge(t.toLowerCase(),s.toLowerCase());l<r&&(r=l,e=s)});let i=Math.max(2,Math.floor(t.length/3));return r<=i?e:void 0}function M(t,n,e){let r=qe(n,e);return r?`${t} Did you mean \'${r}\'?`:t}var U=class{constructor(n){d(this,"descriptor");d(this,"fields",new Map);d(this,"references");this.descriptor=n,n.data_models.forEach(e=>{e.fields.forEach(r=>{let i=String(e.name);this.fields.set(`${i}.${r.name}`,{modelName:i,fieldName:r.name,isMetric:!1,type:r.type,label:r.label??r.name})})}),n.metrics.forEach(e=>{this.fields.set(e.name,{fieldName:e.name,isMetric:!0,type:e.type,label:e.label??e.name})}),this.references=[...this.fields.keys()]}resolve(n,e){let r=this.fields.get(n);if(r)return r;throw new p(M(`Unknown field \'${n}\' on dataset \'${this.descriptor.name}\'.`,n,this.references),e)}};function ce(t,n,e){let r=t[n];if(r)return r;throw new p(M(`Unknown dataset \'${n}\'.`,n,Object.keys(t)),e)}function ue(t,n){if(!Z.includes(t))throw new p(M(`Invalid filter aggregation \'${t}\'.`,t,[...Z]),n)}function pe(t,n,e){if(!n)throw new p(`A ${e} needs a name.`);for(let r of t)if(r===n)throw new p(`\'${n}\' is already declared in this app.`,n)}function Ue(t,n){if(!(!n||n.operator==="none"||n.operator==="transform_date_drill"||!["is_null","not_null","is_true","is_false","transform_pop_none"].includes(n.operator)&&!n.values?.length))return{field:t.field,operator:n.operator,values:n.values??[],...n.modifier?{modifier:n.modifier}:{},...t.aggregation?{aggregation:t.aggregation}:{}}}function Ke(t,n){if(n?.operator!=="transform_date_drill")return;let e=n.values?.[0];if(typeof e!="string")return;let r=e.replace(/^datetrunc\\s+/,"");return{field:t.field,grain:r}}function He(t,n){let e=n.columns??[],r=(n.values??[]).map(s=>{let l={};return e.forEach((o,a)=>{l[o.name]=s[a]}),l}),{pageSize:i}=t;return{columns:e,rows:r,meta:{...i!==void 0?{page:n.meta?.page??t.page,pageSize:n.meta?.pageSize??i}:{},numRows:n.meta?.numRows??r.length},...n.debug?{debug:n.debug}:{}}}function We(t,n,e,r){let i=n.map(a=>Ue(a,a.from.appliedCondition)).filter(a=>a!==void 0),s=n.map(a=>Ke(a,a.from.appliedCondition)).filter(a=>a!==void 0),l=e.conditions.map(a=>({field:a.field,operator:a.operator,values:a.values})),o=e.expression?[{expr:e.expression}]:[];return{dataset:t.dataset.descriptor.name,aql:t.declaration.aql,input:{filters:[...i,...l],conditions:o,sorts:t.sort.map(a=>({field:a.field,direction:a.direction??"asc"})),dateDrills:s},...t.pageSize!==void 0?{page:t.page,pageSize:t.pageSize}:{},...r.timezone?{timezone:r.timezone}:{},...r.bustCache?{bustCache:!0}:{}}}async function ee(t,n,e,r,i){let s=We(t,n,e,r),l=await r.backend.submitQuery(s,i);return He(t,l)}function Ye(t,n){if(t===null)return"null";if(typeof t=="boolean")return t?"true":"false";if(n==="number"&&typeof t=="string")return et(t);if(typeof t=="number"){if(!Number.isFinite(t))throw new RangeError(`Cannot express ${t} in AQL.`);return Math.abs(t)>=1e21?BigInt(t).toString():String(t)}return JSON.stringify(t).split("\\u2028").join("\\\\u2028").split("\\u2029").join("\\\\u2029")}function fe(t,n,e){return n===null?`is(${t}, null)`:`${t} is ${Ye(n,e)}`}var Xe=new Set(["NaN","Infinity","-Infinity"]),Ze=/^(-?)(0|[1-9]\\d*)(?:\\.(\\d+))?(?:[eE]([+-]?\\d+))?$/;function et(t){let n=Ze.exec(t);if(!n)throw Xe.has(t)?new RangeError(`Cannot express ${t} in AQL.`):new TypeError(`${JSON.stringify(t)} is not a number: a number is a string in JSON\'s number syntax.`);let[,e,r,i="",s]=n;if(s===void 0)return t;let l=r+i,o=r.length+Number(s),a;return o<=0?a=`0.${"0".repeat(-o)}${l}`:o>=l.length?a=l+"0".repeat(o-l.length):a=`${l.slice(0,o)}.${l.slice(o)}`,e+a.replace(/^0+(?=\\d)/,"")}function me(t,n,e){return`${t} matches @(${n} until ${e})`}function he(t,n){if(n.length===0)throw new RangeError(`\\`${t}\\` needs at least one operand.`);return n.length===1?n[0]:`${t}(${n.join(", ")})`}var ge=t=>he("and",t),ye=t=>he("or",t);var tt=/^(\\d{4})-(\\d{2})-(\\d{2})(?:[T ](\\d{2}):(\\d{2})(?::(\\d{2}))?)?/,nt={week:7*864e5,day:864e5,hour:36e5,minute:6e4};function be(t){if(typeof t!="string")return;let n=tt.exec(t);if(n)return{year:Number(n[1]),month:Number(n[2])-1,day:Number(n[3]),hour:Number(n[4]??0),minute:Number(n[5]??0),second:Number(n[6]??0),hasTime:n[4]!==void 0}}function L(t,n){let e=new Date(t),r=s=>String(s).padStart(2,"0"),i=`${e.getUTCFullYear()}-${r(e.getUTCMonth()+1)}-${r(e.getUTCDate())}`;return n?`${i} ${r(e.getUTCHours())}:${r(e.getUTCMinutes())}:${r(e.getUTCSeconds())}`:i}function we(t){return Date.UTC(t.year,t.month,t.day,t.hour,t.minute,t.second)}function te(t){let n=be(t);if(n)return L(we(n),n.hasTime)}function ne(t,n){let e=be(t);if(!e)return;let{year:r,month:i,day:s,hour:l,minute:o,second:a,hasTime:c}=e;return L(n==="year"?Date.UTC(r+1,i,s,l,o,a):n==="quarter"?Date.UTC(r,i+3,s,l,o,a):n==="month"?Date.UTC(r,i+1,s,l,o,a):we(e)+nt[n],c)}function ke(t){if(t?.startsWith("datetrunc "))return t.slice(10)}function rt(t){let n=new Set;return t.filter(e=>{let r=`${typeof e}:${String(e)}`;return n.has(r)?!1:(n.add(r),!0)})}function it(t,n){let e=t.map(te);if(e.some(i=>i===void 0))return!1;let r=e.slice().sort();for(let i=1;i<r.length;i+=1)if(ne(r[i-1],n)!==r[i])return!1;return!0}function st(t,n,e){let r=n.map(te);if(r.some(a=>a===void 0))return;let i=r.slice().sort(),s=i[0],l=ne(i[i.length-1],e);if(!l)return;let o=it(n,e);return{condition:{field:t,operator:"matches",values:[`${s} until ${l}`]},admits:o?n.length:Number.POSITIVE_INFINITY,lossy:!o}}function ot(t,n,e){let r=e.filter(o=>o!=null),i=rt(r);if(!i.length)return{condition:{field:t,operator:"is_null",values:[]},admits:1,lossy:!1};let s=r.length!==e.length,l=ke(n);if(l){let o=st(t,i,l);if(o)return{...o,lossy:o.lossy||s}}return{condition:{field:t,operator:"is",values:i},admits:i.length,lossy:s}}function ve(t){return t.modelId?`${t.modelId}.${t.fieldName}`:t.fieldName}function at(t,n,e,r){try{let i=e.map(s=>ge(n.map(l=>{let o=t.get(l),a=ve(o),c=s[l]??null,b=ke(r[a]);if(b&&typeof c=="string"){let S=te(c),u=ne(c,b);if(S&&u)return me(a,S,u)}if(c!==null&&typeof c!="string"&&typeof c!="number"&&typeof c!="boolean")throw new TypeError("no AQL spelling");return fe(a,c,o.semantic_type)})));return ye(i)}catch{return}}function Se(t,n,e,r={}){let i=t.result?.columns??[],s=new Map(i.map(h=>[h.name,h]));e?.forEach(h=>{let y=s.get(h);if(y){if(y.adhoc)throw new p(`Query \'${t.name}\' cannot cross-filter on \'${h}\': it is a query-local AQL expression, which only this query\'s result carries. The target query would receive a condition naming a field it has never heard of.`,t.name);if(y.isMeasure)throw new p(`Query \'${t.name}\' cannot cross-filter on \'${h}\': it is a measure, and a selection conditions dimensions only.`,t.name);return}throw new p(M(`Query \'${t.name}\' has no column \'${h}\' in its last result.`,h,[...s.keys()]),t.name)});let l=i.filter(h=>!h.isMeasure),o=l.filter(h=>!h.adhoc).map(h=>h.name),a=e?[...e]:o;if(!n.length||!a.length)return;let c=[],b=1,S=!e&&o.length!==l.length,u=!1;a.forEach(h=>{let y=s.get(h),A=ve(y),N=ot(A,r[A],n.map(w=>w[h]));c.push(N.condition),b*=N.admits,u=u||N.lossy});let v=new Set(n.map(h=>JSON.stringify(a.map(y=>h[y]??null))));b>v.size&&(u=!0);let x=c.sort((h,y)=>h.field.localeCompare(y.field)),E={source:t.name,rows:[...n],fields:a};if(u){let h=at(s,a,n,r);if(h)return{...E,conditions:[],expression:h,lossy:S}}return{...E,conditions:x,lossy:S||u}}var C={container:"data-anfra-container",block:"data-anfra-block",query:"data-anfra-query",control:"data-anfra-control",label:"data-anfra-label"},K=`[${C.container}],[${C.block}],[${C.query}],[${C.control}]`;function xe(t){let n=/^(?:(\\d+)\\/)?([^/\\s]+)$/.exec(t);if(n)return{app:n[1]===void 0?0:Number(n[1]),name:n[2]}}var Ee=t=>(t??"").split(/\\s+/).filter(Boolean);function Ce(t,n,e,r){let i=n==="query"?C.query:C.control;return[...t.querySelectorAll(`[${i}]`)].filter(s=>Ee(s.getAttribute(i)).some(l=>{let o=xe(l);return o?.app===e&&o.name===r}))}var lt=(t,n,e)=>{let r=t[e.app];return r?Object.prototype.hasOwnProperty.call(n==="query"?r.queries:r.controls,e.name):!1};function re(t,n){var S;let e=[],r=new Map,i=new Map,s=new Map,l=new Map,o={container:new Set,block:new Set},a={},c=(u,v,x)=>{let E=u?s.get(u).children:e,h=u?`${s.get(u).key}.`:"",y={...v,key:`${h}${E.length}`,children:[]};return E.push(y),r.set(y.key,x),i.set(x,[...i.get(x)??[],y.key]),y};for(let u of t.querySelectorAll(K)){let v=u.parentElement?.closest(K)??null,x=u.getAttribute(C.container),E=u.getAttribute(C.block),h=u.getAttribute(C.label)??void 0,y=v&&(l.get(v)==="block"?v:v.closest(`[${C.block}]`)),A;if(x!==null||E!==null){let w=x!==null?"container":"block",D=(x??E??"").trim(),k=[];x!==null&&E!==null&&k.push("This element is marked as a container and as a block. It counts as a container."),D?o[w].has(D)?k.push(`Another ${w} already has the id "${D}".`):o[w].add(D):k.push(`This ${w} has no id.`),y&&k.push(`A block can\'t hold a ${w}. This one is inside the block "${y.getAttribute(C.block)}".`),A=c(v,{kind:w,id:D,...h!==void 0?{label:h}:{},problems:k},u),s.set(u,A),l.set(u,w)}let N=A?u:v;for(let w of["query","control"])for(let D of Ee(u.getAttribute(w==="query"?C.query:C.control))){let k=xe(D),R=[];if(k?lt(n,w,k)||R.push(n[k.app]?`No ${w} is called "${k.name}" in app ${k.app}.`:`The page has no app ${k.app}.`):R.push(`Can\'t read "${D}". Write the ${w}\'s name, or app/name when the page has several apps.`),c(N,{kind:w,name:k?.name??D,app:k?.app??0,problems:R},u),k&&!R.length){let Y=`${k.app}/${k.name}`,f=a[S=`${w}:${Y}`]??(a[S]={elements:new Set,blocks:new Set});f.elements.add(u);let m=A?.kind==="block"?A.id:y?.getAttribute(C.block);m&&f.blocks.add(m)}}}let b=Object.fromEntries(Object.entries(a).map(([u,v])=>[u,{markers:v.elements.size,blocks:[...v.blocks]}]));return{nodes:e,usage:b,elements:r,keysOf:i}}var dt=(t,n,e)=>`${t}:${n}/${e}`;function ct(t){let n=t.getBoundingClientRect();return`${Math.round(n.width)} \\xD7 ${Math.round(n.height)}`}function De(t,n,e){let r=ct(n);if(t.kind==="container"||t.kind==="block")return{kind:t.kind,name:t.id??"",...t.label?{label:t.label}:{},size:r};let i=e.usage[dt(t.kind,t.app??0,t.name??"")];return{kind:t.kind,name:t.name??"",...i&&i.markers>1?{note:`1 of ${i.markers}`}:{},size:r}}var _e="anfra-overlay";var ut="position:fixed;box-sizing:border-box;background:rgba(37,99,235,0.22);outline:1px solid #2563eb;outline-offset:-1px;",pt="position:fixed;max-width:60vw;display:flex;gap:6px;align-items:baseline;padding:3px 8px;border-radius:4px;background:#0f172a;color:#f8fafc;font:12px/1.4 system-ui,sans-serif;white-space:nowrap;box-shadow:0 2px 8px rgba(0,0,0,0.35);",ft={kind:"color:#94a3b8;",name:"color:#93c5fd;font-weight:700;",label:"color:#f8fafc;",note:"color:#94a3b8;",size:"color:#94a3b8;margin-left:10px;"},ie=class{constructor(n){d(this,"doc",n);d(this,"root");d(this,"shown",[]);d(this,"text",{kind:"",name:""});d(this,"timer");d(this,"reposition",()=>this.draw());let e=n.getElementById(_e);e?this.root=e:(this.root=n.createElement("div"),this.root.id=_e,this.root.setAttribute("aria-hidden","true"),this.root.setAttribute("style","position:fixed;inset:0;z-index:2147483647;pointer-events:none;display:none;"),(n.body??n.documentElement).appendChild(this.root))}show(n,e){if(this.clearTimer(),this.shown=[...n],this.text=e,!this.shown.length){this.hide();return}this.root.style.display="block",this.draw(),this.doc.addEventListener("scroll",this.reposition,{capture:!0,passive:!0}),this.doc.defaultView?.addEventListener("resize",this.reposition)}flash(n,e,r=1500){this.show(n,e),this.timer=setTimeout(()=>this.hide(),r)}hide(){this.clearTimer(),this.shown=[],this.root.style.display="none",this.root.replaceChildren(),this.doc.removeEventListener("scroll",this.reposition,{capture:!0}),this.doc.defaultView?.removeEventListener("resize",this.reposition)}get visible(){return this.shown.length>0}clearTimer(){this.timer!==void 0&&clearTimeout(this.timer),this.timer=void 0}draw(){let n=this.shown.map(o=>{let a=o.getBoundingClientRect(),c=this.doc.createElement("div");return c.setAttribute("style",`${ut}left:${a.left}px;top:${a.top}px;width:${a.width}px;height:${a.height}px;`),c}),e=this.shown[0].getBoundingClientRect(),r=this.doc.createElement("div");r.setAttribute("data-testid","anfra-overlay-label");let i=this.doc.defaultView?.innerHeight??0,s=e.top>=26?e.top-24:Math.max(4,e.top+4),l=Math.max(4,Math.min(e.left,(this.doc.defaultView?.innerWidth??0)-24));r.setAttribute("style",`${pt}left:${l}px;top:${Math.min(s,i-24)}px;`);for(let o of["kind","name","label","note","size"]){let a=this.text[o];if(!a)continue;let c=this.doc.createElement("span");c.setAttribute("style",ft[o]),c.setAttribute("data-part",o),c.textContent=a,r.appendChild(c)}this.root.replaceChildren(...n,r)}},Ae=new WeakMap;function Q(t){let n=Ae.get(t);return n||(n=new ie(t),Ae.set(t,n)),n}function H(t){typeof t.scrollIntoView=="function"&&t.scrollIntoView({block:"center",inline:"nearest",behavior:"smooth"})}var se=Object.freeze([]);function Re(t){return t instanceof Error&&t.name==="AbortError"}function $e(t,n){return t.controller!==n}function mt(t){return{name:t.name,message:t.message,...t.entity?{entity:t.entity}:{},...typeof t.status=="number"?{status:t.status}:{},...t.stack?{stack:t.stack}:{}}}function ht(t){let{result:n}=t;return{state:t.state,isDirty:t.isDirty,page:t.page,hasMore:t.hasMore,columns:n?n.columns.map(e=>({...e})):[],rowCount:n?.meta.numRows??0,selectedRowCount:t.selectedRows.length,signature:t.signature(),...t.error?{error:mt(t.error)}:{},...n?.debug?{debug:{...n.debug}}:{}}}function gt(t){let{options:n}=t;return{kind:t.kind,condition:{...t.condition},...t.appliedCondition?{appliedCondition:{...t.appliedCondition}}:{},isDirty:t.isDirty,...n?{options:[...n]}:{}}}function Oe(t){return{source:t.source,fields:[...t.fields],rowCount:t.rows.length,conditions:t.conditions.map(n=>({...n})),...t.expression?{expression:t.expression}:{},lossy:t.lossy}}function Ne(t){return t?JSON.stringify({source:t.source,conditions:t.conditions,expression:t.expression}):"none"}function Te(t,n){return t instanceof $?t:new T(t?.message??"The query failed.",n,t)}var W=class extends O{constructor(e,r,i,s){super();d(this,"title");d(this,"_timezone");d(this,"datasets");d(this,"backend");d(this,"features");d(this,"_queries",new Map);d(this,"_controls",new Map);d(this,"_mappings",[]);d(this,"_crossFilters",[]);d(this,"_selection");d(this,"_appliedSelection");d(this,"selectionCommitted",!1);d(this,"index",0);this.title=e.title,this._timezone=e.timezone,this.datasets=r,this.backend=i,this.features=s}get queries(){return Object.fromEntries(this._queries)}get controls(){return Object.fromEntries(this._controls)}get mappings(){return[...this._mappings,...this._crossFilters]}get crossFilters(){return this._crossFilters}createQuery(e,r){this.assertNameFree(e,"query");let i=new F(e,this,r);return this._queries.set(e,i),this.notify(),i}createFilter(e,r){this.assertNameFree(e,"filter");let i=r.dataset?this.datasetIndex(r.dataset,e):this.soleDataset(e,r.field),s=new J(e,this,r,i,this.backend);return this._controls.set(e,s),this.notify(),s}createDateDrill(e,r={}){if(this.features?.dateDrill===!1)throw new p(`Date drill \'${e}\' needs a capability this workspace has not enabled. Ask an admin to turn on \\`interactive_control:date_drill\\`.`,e);this.assertNameFree(e,"date drill control");let i=new j(e,this,r);return this._controls.set(e,i),this.notify(),i}mapControl(e,r,i){if(!(e instanceof I))throw new p("mapControl expects a control as its source. To let one query cross-filter another, use app.mapCrossFilter(from, to) \\u2014 a cross-filter edge names no field.");if(this._controls.get(e.name)!==e)throw new p(`Control \'${e.name}\' belongs to a different app.`,e.name);if(this._queries.get(r.name)!==r)throw new p(`Query \'${r.name}\' belongs to a different app.`,r.name);i.aggregation&&ue(i.aggregation,e.name);let s=new G(e,r,i.field,i.aggregation);if(this._mappings.some(l=>l.id===s.id))throw new p(`Mapping \'${s.id}\' is already declared.`,e.name);return this.assertAcyclic(s),this._mappings.push(s),this.notify(),s}mapCrossFilter(e,r){if(!(e instanceof F)||!(r instanceof F))throw new p("mapCrossFilter expects two queries. To let a control condition a query, use app.mapControl(from, to, { field }).");if(this._queries.get(e.name)!==e)throw new p(`Query \'${e.name}\' belongs to a different app.`,e.name);if(this._queries.get(r.name)!==r)throw new p(`Query \'${r.name}\' belongs to a different app.`,r.name);if(e===r)throw new p(`Query \'${e.name}\' cannot cross-filter itself. A source keeps its own rows so it can show what is selected; filtering it would erase the very rows the reader clicked.`,e.name);if(e.declaration.dataset!==r.declaration.dataset)throw new p(`Cross-filter \'${e.name}\' -> \'${r.name}\' spans two datasets (\'${e.declaration.dataset}\' and \'${r.declaration.dataset}\'). A selection carries field references, which mean nothing outside the dataset that resolved them.`,e.name);let i=new q(e,r);if(this._crossFilters.some(s=>s.id===i.id))throw new p(`Cross-filter \'${i.id}\' is already declared.`,e.name);return this._crossFilters.push(i),this.notify(),i}get selection(){return this._selection}get appliedSelection(){return this._appliedSelection}clearSelection(){this._selection&&(this._selection=void 0,this.notify())}setTimezone(e){this._timezone=e,this.notify()}get timezone(){return this._timezone}datasetIndex(e,r){return ce(this.datasets,e,r)}mappingsTo(e){return this._mappings.filter(r=>r.to.name===e)}selectionExpressionFor(e,r){return this.selectionFor(e,r)?.expression}selectionFor(e,r){let i=r==="pending"?this._selection:this._appliedSelection;return!i||i.source===e?void 0:this._crossFilters.some(l=>l.from.name===i.source&&l.to.name===e)?i:void 0}selectionConditionsFor(e,r){let i=r==="pending"?this._selection:this._appliedSelection;return!i||i.source===e?se:this._crossFilters.some(l=>l.from.name===i.source&&l.to.name===e)?i.conditions:se}drillTransformations(e){let r={};return this._mappings.forEach(i=>{if(i.to!==e)return;let s=i.from.appliedCondition;if(s?.operator!=="transform_date_drill")return;let[l]=s.values??[];typeof l=="string"&&(r[i.field]=l)}),r}select(e,r,i){if(this._queries.get(e.name)!==e)throw new p(`Query \'${e.name}\' belongs to a different app.`,e.name);let s=Se(e,r,i,this.drillTransformations(e));s?.lossy&&console.warn(`[anfra-sdk] The selection in \'${e.name}\' filters more broadly than it was made. Its conditions are combined field by field and ANDed, which cannot express "(A and B) or (C and D)", so the targets will also show combinations that were not selected. Select within one dimension, or narrow with \\`fields\\`, to avoid this.`),this._selection=s,this.notify()}get hasChanges(){return[...this._controls.values()].some(e=>e.isDirty)||this.isSelectionDirty}get isSelectionDirty(){return this.selectionCommitted?Ne(this._selection)!==Ne(this._appliedSelection):!1}async execute(e={}){let r=[...this._queries.values()].filter(o=>o.shouldRun(e.force));this._controls.forEach(o=>o.commit()),this._appliedSelection=this._selection,this.selectionCommitted=!0,r.forEach(o=>{o.controller?.abort(),o.resetPage()});let i={backend:this.backend,timezone:this._timezone,bustCache:e.bustCache},s=[],l=[];return await Promise.all(r.map(async o=>{let a=new AbortController;o.controller=a;let c=o.signature();o.markExecuting();try{let b=await ee(o,this.mappingsTo(o.name),{conditions:this.selectionConditionsFor(o.name,"applied"),expression:this.selectionExpressionFor(o.name,"applied")},i,a.signal);if($e(o,a))return;o.markSuccess(b,c,!1),s.push(o.name)}catch(b){if($e(o,a)||Re(b))return;o.markError(Te(b,o.name)),l.push(o.name)}finally{o.controller===a&&(o.controller=void 0)}})),{succeeded:s,failed:l}}async refresh(){return this.execute({force:!0,bustCache:!0})}abort(){this._queries.forEach(e=>e.abort())}async fetchPage(e){let r=new AbortController;e.controller=r;let i=e.signature();e.markExecuting();try{let s=await ee(e,this.mappingsTo(e.name),{conditions:this.selectionConditionsFor(e.name,"applied"),expression:this.selectionExpressionFor(e.name,"applied")},{backend:this.backend,timezone:this._timezone},r.signal);e.markSuccess(s,i,!0)}catch(s){if(e.rewindPage(),Re(s))return;let l=Te(s,e.name);throw e.markError(l),l}finally{e.controller===r&&(e.controller=void 0)}}toJSON(){let e=r=>Object.fromEntries([...this._controls.entries()].filter(([,i])=>i.kind===r).map(([i,s])=>[i,s.toJSON()]));return{...this.title?{title:this.title}:{},...this._timezone?{timezone:this._timezone}:{},queries:Object.fromEntries([...this._queries.entries()].map(([r,i])=>[r,i.toJSON()])),filters:e("filter"),dateDrills:e("dateDrill"),mappings:[...this._mappings.map(r=>r.toJSON()),...this._crossFilters.map(r=>r.toJSON())]}}toInspectJSON(){return{...this.title?{title:this.title}:{},...this._timezone?{timezone:this._timezone}:{},hasChanges:this.hasChanges,declaration:this.toJSON(),queries:Object.fromEntries([...this._queries.entries()].map(([e,r])=>[e,ht(r)])),controls:Object.fromEntries([...this._controls.entries()].map(([e,r])=>[e,gt(r)])),...this._selection?{selection:Oe(this._selection)}:{},...this._appliedSelection?{appliedSelection:Oe(this._appliedSelection)}:{}}}locate(e,r){let i=globalThis.document;if(!i)return!1;let s=Ce(i,e,this.index,r);return s.length?(H(s[0]),Q(i).flash(s,{kind:e,name:r,...s.length>1?{note:`in ${s.length} places`}:{}}),!0):!1}assertNameFree(e,r){pe([...this._queries.keys(),...this._controls.keys()],e,r)}soleDataset(e,r){if(!r)return;let i=Object.keys(this.datasets);if(i.length===1)return this.datasets[i[0]];throw new p(i.length?`Filter \'${e}\' names a field but the environment has ${i.length} datasets. Say which one: ${i.join(", ")}.`:`Filter \'${e}\' names a field but the environment has no datasets.`,e)}assertAcyclic(e){let r=[...this._mappings,e],i=new Map;r.forEach(a=>{let c=a.from.name;i.set(c,[...i.get(c)??[],a.to.name])});let s=new Set,l=new Set,o=a=>{if(s.has(a))return!0;if(l.has(a))return!1;s.add(a);let c=(i.get(a)??[]).some(o);return s.delete(a),l.add(a),c};if([...i.keys()].some(o))throw new p(`Mapping \'${e.id}\' would make the app\'s mappings cyclic.`,e.from.name)}};var Fe="0.7.1";var bt=Fe,oe=class{constructor(n){d(this,"version",bt);d(this,"_apps",[]);d(this,"datasets");d(this,"user");d(this,"indices");d(this,"backend");d(this,"features");if(!n?.datasets)throw new p("No datasets provided. The host must call createSdk({ datasets }) before an app can be declared.");if(!n.user)throw new p("No user provided. The host must call createSdk({ user }) before an app can be declared.");if(!n.backend)throw new p("No backend provided. The host must call createSdk({ backend }) before an app can run a query.");this.datasets=Object.freeze({...n.datasets}),this.user=Object.freeze({...n.user,permissions:Object.freeze({...n.user.permissions})}),this.indices=Object.fromEntries(Object.entries(n.datasets).map(([e,r])=>[e,new U(r)])),this.backend=n.backend,this.features=Object.freeze({...n.features})}createApp(n={}){let e=new W(n,this.indices,this.backend,this.features);return e.index=this._apps.length,this._apps.push(e),e}get apps(){return this._apps}};function Ie(t){return new oe(t)}var B="Anfra";function Me(t,n=globalThis){let e=n[B],r=B in n;return n[B]=t,()=>{r?n[B]=e:delete n[B]}}function Qe(t,n){let e=null,r=a=>a.target instanceof Element?a.target.closest(K):null,i=a=>{let c=r(a);c!==e&&(e=c,n.onHover(c))},s=a=>{a.preventDefault(),a.stopPropagation();let c=r(a);c&&n.onPick(c)},l=a=>{a.key==="Escape"&&n.onCancel()},o={capture:!0};return t.addEventListener("mousemove",i,o),t.addEventListener("click",s,o),t.addEventListener("keydown",l,o),()=>{t.removeEventListener("mousemove",i,o),t.removeEventListener("click",s,o),t.removeEventListener("keydown",l,o)}}function Le(){let t=new Error("Aborted");return t.name="AbortError",t}function wt(t){switch(t?.name){case"PermissionError":return new P(t.message);case"TransportError":return new V(t.message);default:return new T(t?.message||"The query failed.")}}function Be(t){let n=t.document.getElementById(ae);if(!n?.textContent)throw new Error("anfra: this frame was not provisioned by a host.");let e=JSON.parse(n.textContent),r=f=>t.parent.postMessage(f,e.hostOrigin),i=new Map,s=1,l=!1,o;t.addEventListener("message",f=>{if(f.source!==t.parent)return;let m=f.data;switch(m?.type){case"anfra:response":{let g=i.get(m.id);if(!g)return;i.delete(m.id),m.ok?g.resolve(m.result):g.reject(wt(m.error));return}case"anfra:inspect-watch":N(m.open);return;case"anfra:highlight":D(m.node);return;case"anfra:locate":k(m.target);return;case"anfra:pick-watch":R(m.on);return;default:}});function a(f,m,g){return new Promise((_,X)=>{if(g.aborted){X(Le());return}let z=s++;i.set(z,{resolve:_,reject:X}),g.addEventListener("abort",()=>{i.delete(z)&&(r({type:"anfra:cancel",id:z}),X(Le()))},{once:!0}),r({type:"anfra:request",id:z,method:f,request:m})})}let c={submitQuery:(f,m)=>a("submitQuery",f,m).then(g=>(g.debug?.executedAt&&(g.debug.executedAt=new Date(g.debug.executedAt)),g)),fieldSuggestions:(f,m)=>a("fieldSuggestions",f,m)},b=Ie({datasets:e.datasets,user:e.user,backend:c}),S=t.document,u,v="",x,E;function h(){if(o=void 0,!!l)try{u=re(S,b.apps),v=JSON.stringify(u.nodes),r({type:"anfra:inspect",apps:b.apps.map(f=>f.toInspectJSON()),structure:{nodes:u.nodes,usage:u.usage}})}catch{}}function y(){l&&o===void 0&&(o=setTimeout(h,50))}function A(){let f=t.MutationObserver;if(x||typeof f!="function")return;let m=new f(()=>{if(!(!l||o!==void 0))try{JSON.stringify(re(S,b.apps).nodes)!==v&&y()}catch{}});x=m,m.observe(S.documentElement,{childList:!0,subtree:!0,attributes:!0,attributeFilter:["data-anfra-container","data-anfra-block","data-anfra-query","data-anfra-control","data-anfra-label"]})}function N(f){l=f,f?(A(),h()):(x?.disconnect(),x=void 0,R(!1),Q(S).hide(),u=void 0,v="")}function w(f,m){for(let g of f){if(g.key===m)return g;let _=w(g.children,m);if(_)return _}}function D(f){let m=Q(S),g=f!==null&&u?w(u.nodes,f):void 0,_=f!==null?u?.elements.get(f):void 0;if(!g||!_||!u){m.hide();return}m.show([_],De(g,_,u))}function k(f){if("node"in f){let m=u?.elements.get(f.node);m&&H(m),D(f.node)}else b.apps[f.app]?.locate(f.kind,f.name);y()}function R(f){if(!f){E?.(),E=void 0;return}if(E)return;let m=g=>u?.keysOf.get(g)?.[0];E=Qe(S,{onHover:g=>D(g?m(g)??null:null),onPick:g=>{let _=m(g);_!==void 0&&r({type:"anfra:picked",node:_})},onCancel:()=>{R(!1),Q(S).hide(),r({type:"anfra:picked",node:null})}})}let Y=b.createApp.bind(b);b.createApp=f=>{let m=Y(f);return m.subscribe(y),y(),m},Me(b,t),r({type:"anfra:ready"})}Be(window);})();\n';
|
|
160
|
+
var anfra_sdk_frame_script_default = '"use strict";(()=>{var De=Object.defineProperty;var ct=(t,n,e)=>n in t?De(t,n,{enumerable:!0,configurable:!0,writable:!0,value:e}):t[n]=e;var o=(t,n)=>De(t,"name",{value:n,configurable:!0});var c=(t,n,e)=>ct(t,typeof n!="symbol"?n+"":n,e);var ne=class ne extends Error{constructor(e,r){super(e);c(this,"entity");this.name=new.target.name,this.entity=r,Object.setPrototypeOf(this,new.target.prototype)}};o(ne,"DataAppError");var $=ne,re=class re extends ${};o(re,"ValidationError");var u=re,ie=class ie extends ${constructor(e,r,i){super(e,r);c(this,"cause");this.cause=i}};o(ie,"QueryError");var N=ie,oe=class oe extends ${};o(oe,"PermissionError");var I=oe,se=class se extends ${constructor(e,r,i){super(e,i);c(this,"status");this.status=r}};o(se,"TransportError");var O=se;var _e="anfra-provision";var ae=class ae{constructor(n){c(this,"listeners",new Set);c(this,"parent");this.parent=n}subscribe(n){return this.listeners.add(n),()=>{this.listeners.delete(n)}}notifyChange(){this.listeners.forEach(n=>n()),this.parent?.notifyChange()}notify(){this.notifyChange()}};o(ae,"Observable");var F=ae;var le=class le extends F{constructor(e,r,i){super(r);c(this,"kind","query");c(this,"name");c(this,"declaration");c(this,"dataset");c(this,"app");c(this,"_state","idle");c(this,"_result");c(this,"_error");c(this,"_page",1);c(this,"_sort",[]);c(this,"lastRunSignature");c(this,"lastPageRows",0);c(this,"controller");if(!i.aql?.trim())throw new u(`Query \'${e}\' declares no AQL.`,e);let{pageSize:s}=i;if(s!==void 0&&!(Number.isInteger(s)&&s>=1))throw new u(`Query \'${e}\' declares pageSize ${s}; it must be a whole number of at least 1.`,e);this.name=e,this.app=r,this.declaration=i,this.dataset=r.datasetIndex(i.dataset,e)}locate(){return this.app.locate("query",this.name)}get state(){return this._state}get result(){return this._result}get error(){return this._error}get pageSize(){return this.declaration.pageSize}get page(){return this._page}get sort(){return this._sort}setSort(e){this._sort=[...e],this.notify()}get hasMore(){return!this._result||this.pageSize===void 0?!1:this.lastPageRows>=this.pageSize}signature(){let e=this.app.mappingsTo(this.name).map(r=>({field:r.field,aggregation:r.aggregation,condition:r.from.condition})).sort((r,i)=>r.field.localeCompare(i.field)||JSON.stringify(r).localeCompare(JSON.stringify(i)));return JSON.stringify({declaration:this.declaration,conditions:e,selection:this.app.selectionConditionsFor(this.name,"pending"),selectionExpression:this.app.selectionExpressionFor(this.name,"pending"),sort:this._sort,timezone:this.app.timezone,page:this._page})}get isDirty(){return this.lastRunSignature!==void 0&&this.signature()!==this.lastRunSignature}shouldRun(e=!1){return e||this.lastRunSignature===void 0||this.isDirty}abort(){this.controller?.abort()}async fetchMore(){if(this.pageSize===void 0)throw new u(`Query \'${this.name}\' declares no pageSize, so it has no more pages.`,this.name);this.hasMore&&(this._page+=1,await this.app.fetchPage(this))}export(e={}){return this.app.exportQuery(this,e)}select(e,r={}){this.app.select(this,Array.isArray(e)?e:[e],r.fields)}get selectedRows(){let{selection:e}=this.app;if(e?.source!==this.name)return[];let r=this._result?.rows;if(!r)return e.rows;let i=o(a=>JSON.stringify(e.fields.map(l=>a[l]??null)),"key"),s=new Set(e.rows.map(i));return r.filter(a=>s.has(i(a)))}markExecuting(){this._state="executing",this._error=void 0,this.notify()}markSuccess(e,r,i){if(this._state="success",this._error=void 0,this.lastRunSignature=r,this.lastPageRows=e.rows.length,i&&this._result){let s=[...this._result.rows,...e.rows];this._result={...e,rows:s,meta:{...e.meta,numRows:s.length}}}else this._result=e;this.notify()}markError(e){this._state="error",this._error=e,this.notify()}rewindPage(){this._page>1&&(this._page-=1)}resetPage(){this._page=1,this.lastPageRows=0}toJSON(){return this.declaration}};o(le,"Query");var M=le;var $e=["year","quarter","month","week","day","hour","minute"];function ut(t,n){if(!$e.includes(n))throw new u(`Invalid grain \'${n}\'. Expected one of: ${$e.join(", ")}.`,t)}o(ut,"assertGrain");function Oe(t,n){return n?(ut(t,n),{operator:"transform_date_drill",values:[`datetrunc ${n}`]}):{operator:"none"}}o(Oe,"drillCondition");function pt(t){let n=t.toLowerCase();return n.includes("date")||n.includes("time")?"date":n.includes("int")||n.includes("number")||n.includes("float")||n.includes("decimal")?"number":n.includes("bool")?"boolean":"string"}o(pt,"inferType");function ft(t,n){return JSON.stringify(t??null)===JSON.stringify(n??null)}o(ft,"sameCondition");var de=class de extends F{constructor(e,r,i){super(r);c(this,"name");c(this,"app");c(this,"pending");c(this,"applied");c(this,"initial");this.name=e,this.app=r,this.initial=i,this.pending=i}locate(){return this.app.locate("control",this.name)}get condition(){return this.pending}get appliedCondition(){return this.applied}get isDirty(){return this.applied!==void 0&&!ft(this.pending,this.applied)}setCondition(e){this.pending=e,this.notify()}reset(){this.setCondition(this.initial)}commit(){this.applied=this.pending}};o(de,"Control");var L=de,ce=class ce extends L{constructor(e,r,i,s,a){super(e,r,i.default??{operator:"is",values:[]});c(this,"kind","filter");c(this,"declaration");c(this,"type");c(this,"resolved");c(this,"datasetName");c(this,"backend");c(this,"loadedOptions");if(this.declaration=i,this.backend=a,i.field){if(!s)throw new u(`Filter \'${e}\' names a field but no dataset. Pass \\`dataset\\` alongside \\`field\\`.`,e);this.resolved=s.resolve(i.field,e),this.datasetName=s.descriptor.name,this.type=i.type??pt(this.resolved.type)}else{if(!i.type)throw new u(`Filter \'${e}\' is a manual filter, so it needs a \\`type\\`.`,e);this.type=i.type}this.assertValues(this.condition.values??[]),this.assertValues(i.options??[])}setCondition(e){this.assertValues(e.values??[]),super.setCondition(e)}assertValues(e){if(this.type!=="number")return;let r=e.find(i=>typeof i=="number");if(r!==void 0)throw new u(`Filter \'${this.name}\' filters numbers: give its values as strings, as query results give them (${JSON.stringify(String(r))}, not ${String(r)}), so none has lost a digit.`,this.name)}get isFieldBacked(){return this.resolved!==void 0}get options(){return this.loadedOptions??this.declaration.options??[]}async loadOptions(e,r=new AbortController().signal){let i=this.resolved?.modelName;if(!this.resolved||!i||!this.backend||!this.datasetName)return this.options;let s=await this.backend.fieldSuggestions({dataset:this.datasetName,model:i,field:this.resolved.fieldName,q:e??""},r);return this.loadedOptions=[...s??[]],this.notify(),this.loadedOptions}toJSON(){return this.declaration}};o(ce,"Filter");var G=ce,ue=class ue extends L{constructor(e,r,i={}){super(e,r,Oe(e,i.default));c(this,"kind","dateDrill");c(this,"declaration");this.declaration=i}setGrain(e){this.setCondition(Oe(this.name,e))}toJSON(){return this.declaration}};o(ue,"DateDrillControl");var U=ue;var pe=class pe{constructor(n,e,r,i){c(this,"kind","control");c(this,"from");c(this,"to");c(this,"field");c(this,"aggregation");this.from=n,this.to=e,this.field=r,this.aggregation=i}get id(){return`${this.from.name}.${this.to.name}.${this.field}`}toJSON(){return{kind:this.kind,id:this.id,from:{kind:this.from.kind,name:this.from.name},to:{kind:"query",name:this.to.name},field:this.field,...this.aggregation?{aggregation:this.aggregation}:{}}}};o(pe,"Mapping");var H=pe,fe=class fe{constructor(n,e){c(this,"kind","crossFilter");c(this,"from");c(this,"to");this.from=n,this.to=e}get id(){return`${this.from.name}.${this.to.name}`}toJSON(){return{kind:this.kind,id:this.id,from:{kind:"query",name:this.from.name},to:{kind:"query",name:this.to.name}}}};o(fe,"CrossFilter");var K=fe;var me=["sum","avg","max","min","count","count distinct","median","stdev","stdevp","var","varp"];function mt(t,n){let e=t.length+1,r=n.length+1,i=Array.from({length:r},(s,a)=>a);for(let s=1;s<e;s++){let a=[s];for(let l=1;l<r;l++)a[l]=Math.min(i[l]+1,a[l-1]+1,i[l-1]+(t[s-1]===n[l-1]?0:1));i=a}return i[r-1]}o(mt,"editDistance");function ht(t,n){let e,r=1/0;n.forEach(s=>{let a=mt(t.toLowerCase(),s.toLowerCase());a<r&&(r=a,e=s)});let i=Math.max(2,Math.floor(t.length/3));return r<=i?e:void 0}o(ht,"suggest");function P(t,n,e){let r=ht(n,e);return r?`${t} Did you mean \'${r}\'?`:t}o(P,"withSuggestion");var he=class he{constructor(n){c(this,"descriptor");c(this,"fields",new Map);c(this,"references");this.descriptor=n,n.data_models.forEach(e=>{e.fields.forEach(r=>{let i=String(e.name);this.fields.set(`${i}.${r.name}`,{modelName:i,fieldName:r.name,isMetric:!1,type:r.type,label:r.label??r.name})})}),n.metrics.forEach(e=>{this.fields.set(e.name,{fieldName:e.name,isMetric:!0,type:e.type,label:e.label??e.name})}),this.references=[...this.fields.keys()]}resolve(n,e){let r=this.fields.get(n);if(r)return r;throw new u(P(`Unknown field \'${n}\' on dataset \'${this.descriptor.name}\'.`,n,this.references),e)}};o(he,"DatasetIndex");var W=he;function Fe(t,n,e){let r=t[n];if(r)return r;throw new u(P(`Unknown dataset \'${n}\'.`,n,Object.keys(t)),e)}o(Fe,"resolveDataset");function Te(t,n){if(!me.includes(t))throw new u(P(`Invalid filter aggregation \'${t}\'.`,t,[...me]),n)}o(Te,"assertValidFilterAggregation");function Ne(t,n,e){if(!n)throw new u(`A ${e} needs a name.`);for(let r of t)if(r===n)throw new u(`\'${n}\' is already declared in this app.`,n)}o(Ne,"assertUniqueName");function gt(t,n){if(!(!n||n.operator==="none"||n.operator==="transform_date_drill"||!["is_null","not_null","is_true","is_false","transform_pop_none"].includes(n.operator)&&!n.values?.length))return{field:t.field,operator:n.operator,values:n.values??[],...n.modifier?{modifier:n.modifier}:{},...t.aggregation?{aggregation:t.aggregation}:{}}}o(gt,"toFilter");function yt(t,n){if(n?.operator!=="transform_date_drill")return;let e=n.values?.[0];if(typeof e!="string")return;let r=e.replace(/^datetrunc\\s+/,"");return{field:t.field,grain:r}}o(yt,"toDateDrill");function bt(t,n){let e=n.columns??[],r=(n.values??[]).map(s=>{let a={};return e.forEach((l,d)=>{a[l.name]=s[d]}),a}),{pageSize:i}=t;return{columns:e,rows:r,meta:{...i!==void 0?{page:n.meta?.page??t.page,pageSize:n.meta?.pageSize??i}:{},numRows:n.meta?.numRows??r.length},...n.debug?{debug:n.debug}:{}}}o(bt,"toResult");function Ie(t,n,e,r){let i=n.map(d=>gt(d,d.from.appliedCondition)).filter(d=>d!==void 0),s=n.map(d=>yt(d,d.from.appliedCondition)).filter(d=>d!==void 0),a=e.conditions.map(d=>({field:d.field,operator:d.operator,values:d.values})),l=e.expression?[{expr:e.expression}]:[];return{dataset:t.dataset.descriptor.name,aql:t.declaration.aql,input:{filters:[...i,...a],conditions:l,sorts:t.sort.map(d=>({field:d.field,direction:d.direction??"asc"})),dateDrills:s},...r.timezone?{timezone:r.timezone}:{}}}o(Ie,"buildQuery");function wt(t,n,e,r){return{...Ie(t,n,e,r),...t.pageSize!==void 0?{page:t.page,pageSize:t.pageSize}:{},...r.bustCache?{bustCache:!0}:{}}}o(wt,"buildRequest");function kt(t,n){let e=n?.replace(/[/\\\\]/g,"-").replace(/\\p{Cc}/gu,"").trim();return e?`${e} - ${t.name}`:t.name}o(kt,"defaultExportFilename");function Qe(t,n,e,r,i){let s=i.format??"csv",a=s==="csv"?{bom:!0,...i.formatOptions}:i.formatOptions;return{...Ie(t,n,e,r),format:s,...a?{formatOptions:a}:{},filename:i.filename?.trim()||kt(t,r.title)}}o(Qe,"buildExportRequest");async function ge(t,n,e,r,i){let s=wt(t,n,e,r),a=await r.backend.submitQuery(s,i);return bt(t,a)}o(ge,"runQuery");function xt(t,n){if(t===null)return"null";if(typeof t=="boolean")return t?"true":"false";if(n==="number"&&typeof t=="string")return Et(t);if(typeof t=="number"){if(!Number.isFinite(t))throw new RangeError(`Cannot express ${t} in AQL.`);return Math.abs(t)>=1e21?BigInt(t).toString():String(t)}return JSON.stringify(t).split("\\u2028").join("\\\\u2028").split("\\u2029").join("\\\\u2029")}o(xt,"literal");function Me(t,n,e){return n===null?`is(${t}, null)`:`${t} is ${xt(n,e)}`}o(Me,"equals");var St=new Set(["NaN","Infinity","-Infinity"]),vt=/^(-?)(0|[1-9]\\d*)(?:\\.(\\d+))?(?:[eE]([+-]?\\d+))?$/;function Et(t){let n=vt.exec(t);if(!n)throw St.has(t)?new RangeError(`Cannot express ${t} in AQL.`):new TypeError(`${JSON.stringify(t)} is not a number: a number is a string in JSON\'s number syntax.`);let[,e,r,i="",s]=n;if(s===void 0)return t;let a=r+i,l=r.length+Number(s),d;return l<=0?d=`0.${"0".repeat(-l)}${a}`:l>=a.length?d=a+"0".repeat(l-a.length):d=`${a.slice(0,l)}.${a.slice(l)}`,e+d.replace(/^0+(?=\\d)/,"")}o(Et,"numberLiteral");function Le(t,n,e){return`${t} matches @(${n} until ${e})`}o(Le,"dateRange");function Pe(t,n){if(n.length===0)throw new RangeError(`\\`${t}\\` needs at least one operand.`);return n.length===1?n[0]:`${t}(${n.join(", ")})`}o(Pe,"combine");var Be=o(t=>Pe("and",t),"and"),ze=o(t=>Pe("or",t),"or");var Rt=/^(\\d{4})-(\\d{2})-(\\d{2})(?:[T ](\\d{2}):(\\d{2})(?::(\\d{2}))?)?/,Ct={week:7*864e5,day:864e5,hour:36e5,minute:6e4};function Ve(t){if(typeof t!="string")return;let n=Rt.exec(t);if(n)return{year:Number(n[1]),month:Number(n[2])-1,day:Number(n[3]),hour:Number(n[4]??0),minute:Number(n[5]??0),second:Number(n[6]??0),hasTime:n[4]!==void 0}}o(Ve,"parseStamp");function V(t,n){let e=new Date(t),r=o(s=>String(s).padStart(2,"0"),"pad"),i=`${e.getUTCFullYear()}-${r(e.getUTCMonth()+1)}-${r(e.getUTCDate())}`;return n?`${i} ${r(e.getUTCHours())}:${r(e.getUTCMinutes())}:${r(e.getUTCSeconds())}`:i}o(V,"format");function qe(t){return Date.UTC(t.year,t.month,t.day,t.hour,t.minute,t.second)}o(qe,"toMs");function ye(t){let n=Ve(t);if(n)return V(qe(n),n.hasTime)}o(ye,"normalise");function be(t,n){let e=Ve(t);if(!e)return;let{year:r,month:i,day:s,hour:a,minute:l,second:d,hasTime:p}=e;return V(n==="year"?Date.UTC(r+1,i,s,a,l,d):n==="quarter"?Date.UTC(r,i+3,s,a,l,d):n==="month"?Date.UTC(r,i+1,s,a,l,d):qe(e)+Ct[n],p)}o(be,"addGrain");function Je(t){if(t?.startsWith("datetrunc "))return t.slice(10)}o(Je,"grainOf");function At(t){let n=new Set;return t.filter(e=>{let r=`${typeof e}:${String(e)}`;return n.has(r)?!1:(n.add(r),!0)})}o(At,"distinct");function Dt(t,n){let e=t.map(ye);if(e.some(i=>i===void 0))return!1;let r=e.slice().sort();for(let i=1;i<r.length;i+=1)if(be(r[i-1],n)!==r[i])return!1;return!0}o(Dt,"isContiguous");function _t(t,n,e){let r=n.map(ye);if(r.some(d=>d===void 0))return;let i=r.slice().sort(),s=i[0],a=be(i[i.length-1],e);if(!a)return;let l=Dt(n,e);return{condition:{field:t,operator:"matches",values:[`${s} until ${a}`]},admits:l?n.length:Number.POSITIVE_INFINITY,lossy:!l}}o(_t,"dateRange");function $t(t,n,e){let r=e.filter(l=>l!=null),i=At(r);if(!i.length)return{condition:{field:t,operator:"is_null",values:[]},admits:1,lossy:!1};let s=r.length!==e.length,a=Je(n);if(a){let l=_t(t,i,a);if(l)return{...l,lossy:l.lossy||s}}return{condition:{field:t,operator:"is",values:i},admits:i.length,lossy:s}}o($t,"deriveOne");function je(t){return t.modelId?`${t.modelId}.${t.fieldName}`:t.fieldName}o(je,"fieldReferenceOf");function Ot(t,n,e,r){try{let i=e.map(s=>Be(n.map(a=>{let l=t.get(a),d=je(l),p=s[a]??null,E=Je(r[d]);if(E&&typeof p=="string"){let x=ye(p),h=be(p,E);if(x&&h)return Le(d,x,h)}if(p!==null&&typeof p!="string"&&typeof p!="number"&&typeof p!="boolean")throw new TypeError("no AQL spelling");return Me(d,p,l.semantic_type)})));return ze(i)}catch{return}}o(Ot,"selectionExpression");function Ge(t,n,e,r={}){let i=t.result?.columns??[],s=new Map(i.map(g=>[g.name,g]));e?.forEach(g=>{let w=s.get(g);if(w){if(w.adhoc)throw new u(`Query \'${t.name}\' cannot cross-filter on \'${g}\': it is a query-local AQL expression, which only this query\'s result carries. The target query would receive a condition naming a field it has never heard of.`,t.name);if(w.isMeasure)throw new u(`Query \'${t.name}\' cannot cross-filter on \'${g}\': it is a measure, and a selection conditions dimensions only.`,t.name);return}throw new u(P(`Query \'${t.name}\' has no column \'${g}\' in its last result.`,g,[...s.keys()]),t.name)});let a=i.filter(g=>!g.isMeasure),l=a.filter(g=>!g.adhoc).map(g=>g.name),d=e?[...e]:l;if(!n.length||!d.length)return;let p=[],E=1,x=!e&&l.length!==a.length,h=!1;d.forEach(g=>{let w=s.get(g),D=je(w),T=$t(D,r[D],n.map(v=>v[g]));p.push(T.condition),E*=T.admits,h=h||T.lossy});let b=new Set(n.map(g=>JSON.stringify(d.map(w=>g[w]??null))));E>b.size&&(h=!0);let C=p.sort((g,w)=>g.field.localeCompare(w.field)),A={source:t.name,rows:[...n],fields:d};if(h){let g=Ot(s,d,n,r);if(g)return{...A,conditions:[],expression:g,lossy:x}}return{...A,conditions:C,lossy:x||h}}o(Ge,"deriveSelection");var S={container:"data-anfra-container",block:"data-anfra-block",query:"data-anfra-query",control:"data-anfra-control",label:"data-anfra-label"},Y=`[${S.container}],[${S.block}],[${S.query}],[${S.control}]`;function Ue(t){let n=/^(?:(\\d+)\\/)?([^/\\s]+)$/.exec(t);if(n)return{app:n[1]===void 0?0:Number(n[1]),name:n[2]}}o(Ue,"parseRef");var He=o(t=>(t??"").split(/\\s+/).filter(Boolean),"tokens");function Ke(t,n,e,r){let i=n==="query"?S.query:S.control;return[...t.querySelectorAll(`[${i}]`)].filter(s=>He(s.getAttribute(i)).some(a=>{let l=Ue(a);return l?.app===e&&l.name===r}))}o(Ke,"markersFor");var Ft=o((t,n,e)=>{let r=t[e.app];return r?Object.prototype.hasOwnProperty.call(n==="query"?r.queries:r.controls,e.name):!1},"hasEntity");function we(t,n){var x;let e=[],r=new Map,i=new Map,s=new Map,a=new Map,l={container:new Set,block:new Set},d={},p=o((h,b,C)=>{let A=h?s.get(h).children:e,g=h?`${s.get(h).key}.`:"",w={...b,key:`${g}${A.length}`,children:[]};return A.push(w),r.set(w.key,C),i.set(C,[...i.get(C)??[],w.key]),w},"place");for(let h of t.querySelectorAll(Y)){let b=h.parentElement?.closest(Y)??null,C=h.getAttribute(S.container),A=h.getAttribute(S.block),g=h.getAttribute(S.label)??void 0,w=b&&(a.get(b)==="block"?b:b.closest(`[${S.block}]`)),D;if(C!==null||A!==null){let v=C!==null?"container":"block",_=(C??A??"").trim(),k=[];C!==null&&A!==null&&k.push("This element is marked as a container and as a block. It counts as a container."),_?l[v].has(_)?k.push(`Another ${v} already has the id "${_}".`):l[v].add(_):k.push(`This ${v} has no id.`),w&&k.push(`A block can\'t hold a ${v}. This one is inside the block "${w.getAttribute(S.block)}".`),D=p(b,{kind:v,id:_,...g!==void 0?{label:g}:{},problems:k},h),s.set(h,D),a.set(h,v)}let T=D?h:b;for(let v of["query","control"])for(let _ of He(h.getAttribute(v==="query"?S.query:S.control))){let k=Ue(_),Q=[];if(k?Ft(n,v,k)||Q.push(n[k.app]?`No ${v} is called "${k.name}" in app ${k.app}.`:`The page has no app ${k.app}.`):Q.push(`Can\'t read "${_}". Write the ${v}\'s name, or app/name when the page has several apps.`),p(T,{kind:v,name:k?.name??_,app:k?.app??0,problems:Q},h),k&&!Q.length){let z=`${k.app}/${k.name}`,J=d[x=`${v}:${z}`]??(d[x]={elements:new Set,blocks:new Set});J.elements.add(h);let f=D?.kind==="block"?D.id:w?.getAttribute(S.block);f&&J.blocks.add(f)}}}let E=Object.fromEntries(Object.entries(d).map(([h,b])=>[h,{markers:b.elements.size,blocks:[...b.blocks]}]));return{nodes:e,usage:E,elements:r,keysOf:i}}o(we,"buildStructure");var Tt=o((t,n,e)=>`${t}:${n}/${e}`,"usageKey");function Nt(t){let n=t.getBoundingClientRect();return`${Math.round(n.width)} \\xD7 ${Math.round(n.height)}`}o(Nt,"sizeOf");function We(t,n,e){let r=Nt(n);if(t.kind==="container"||t.kind==="block")return{kind:t.kind,name:t.id??"",...t.label?{label:t.label}:{},size:r};let i=e.usage[Tt(t.kind,t.app??0,t.name??"")];return{kind:t.kind,name:t.name??"",...i&&i.markers>1?{note:`1 of ${i.markers}`}:{},size:r}}o(We,"describeNode");var X="anfra-overlay";var It="position:fixed;box-sizing:border-box;background:rgba(37,99,235,0.22);outline:1px solid #2563eb;outline-offset:-1px;",Qt="position:fixed;max-width:60vw;display:flex;gap:6px;align-items:baseline;padding:3px 8px;border-radius:4px;background:#0f172a;color:#f8fafc;font:12px/1.4 system-ui,sans-serif;white-space:nowrap;box-shadow:0 2px 8px rgba(0,0,0,0.35);",Mt={kind:"color:#94a3b8;",name:"color:#93c5fd;font-weight:700;",label:"color:#f8fafc;",note:"color:#94a3b8;",size:"color:#94a3b8;margin-left:10px;"},xe=class xe{constructor(n){c(this,"doc",n);c(this,"root");c(this,"shown",[]);c(this,"text",{kind:"",name:""});c(this,"timer");c(this,"reposition",o(()=>this.draw(),"reposition"));let e=n.getElementById(X);e?this.root=e:(this.root=n.createElement("div"),this.root.id=X,this.root.setAttribute("aria-hidden","true"),this.root.setAttribute("style","position:fixed;inset:0;z-index:2147483647;pointer-events:none;display:none;"),(n.body??n.documentElement).appendChild(this.root))}show(n,e){if(this.clearTimer(),this.shown=[...n],this.text=e,!this.shown.length){this.hide();return}this.root.style.display="block",this.draw(),this.doc.addEventListener("scroll",this.reposition,{capture:!0,passive:!0}),this.doc.defaultView?.addEventListener("resize",this.reposition)}flash(n,e,r=1500){this.show(n,e),this.timer=setTimeout(()=>this.hide(),r)}hide(){this.clearTimer(),this.shown=[],this.root.style.display="none",this.root.replaceChildren(),this.doc.removeEventListener("scroll",this.reposition,{capture:!0}),this.doc.defaultView?.removeEventListener("resize",this.reposition)}get visible(){return this.shown.length>0}clearTimer(){this.timer!==void 0&&clearTimeout(this.timer),this.timer=void 0}draw(){let n=this.shown.map(l=>{let d=l.getBoundingClientRect(),p=this.doc.createElement("div");return p.setAttribute("style",`${It}left:${d.left}px;top:${d.top}px;width:${d.width}px;height:${d.height}px;`),p}),e=this.shown[0].getBoundingClientRect(),r=this.doc.createElement("div");r.setAttribute("data-testid","anfra-overlay-label");let i=this.doc.defaultView?.innerHeight??0,s=e.top>=26?e.top-24:Math.max(4,e.top+4),a=Math.max(4,Math.min(e.left,(this.doc.defaultView?.innerWidth??0)-24));r.setAttribute("style",`${Qt}left:${a}px;top:${Math.min(s,i-24)}px;`);for(let l of["kind","name","label","note","size"]){let d=this.text[l];if(!d)continue;let p=this.doc.createElement("span");p.setAttribute("style",Mt[l]),p.setAttribute("data-part",l),p.textContent=d,r.appendChild(p)}this.root.replaceChildren(...n,r)}};o(xe,"Overlay");var ke=xe,Ye=new WeakMap;function B(t){let n=Ye.get(t);return n||(n=new ke(t),Ye.set(t,n)),n}o(B,"overlayFor");function Z(t){typeof t.scrollIntoView=="function"&&t.scrollIntoView({block:"center",inline:"nearest",behavior:"smooth"})}o(Z,"scrollTo");var Se=Object.freeze([]);function ve(t){return t instanceof Error&&t.name==="AbortError"}o(ve,"isAbort");function Xe(t,n){return t.controller!==n}o(Xe,"superseded");function Lt(t){return{name:t.name,message:t.message,...t.entity?{entity:t.entity}:{},...typeof t.status=="number"?{status:t.status}:{},...t.stack?{stack:t.stack}:{}}}o(Lt,"inspectError");function Pt(t){let{result:n}=t;return{state:t.state,isDirty:t.isDirty,page:t.page,hasMore:t.hasMore,columns:n?n.columns.map(e=>({...e})):[],rowCount:n?.meta.numRows??0,selectedRowCount:t.selectedRows.length,signature:t.signature(),...t.error?{error:Lt(t.error)}:{},...n?.debug?{debug:{...n.debug}}:{}}}o(Pt,"inspectQuery");function Bt(t){let{options:n}=t;return{kind:t.kind,condition:{...t.condition},...t.appliedCondition?{appliedCondition:{...t.appliedCondition}}:{},isDirty:t.isDirty,...n?{options:[...n]}:{}}}o(Bt,"inspectControl");function Ze(t){return{source:t.source,fields:[...t.fields],rowCount:t.rows.length,conditions:t.conditions.map(n=>({...n})),...t.expression?{expression:t.expression}:{},lossy:t.lossy}}o(Ze,"inspectSelection");function et(t){return t?JSON.stringify({source:t.source,conditions:t.conditions,expression:t.expression}):"none"}o(et,"selectionKey");function tt(t,n){return t instanceof $?t:new N(t?.message??"The query failed.",n,t)}o(tt,"toDataAppError");function zt(t,n){if(t instanceof $&&t.entity)return t;let e=t?.message||"The export failed.";return t instanceof I?new I(e,n):t instanceof O?new O(e,t.status,n):t instanceof u?new u(e,n):new N(e,n,t)}o(zt,"toExportError");var Ee=class Ee extends F{constructor(e,r,i,s){super();c(this,"title");c(this,"_timezone");c(this,"datasets");c(this,"backend");c(this,"features");c(this,"_queries",new Map);c(this,"_controls",new Map);c(this,"_mappings",[]);c(this,"_crossFilters",[]);c(this,"_selection");c(this,"_appliedSelection");c(this,"selectionCommitted",!1);c(this,"index",0);this.title=e.title,this._timezone=e.timezone,this.datasets=r,this.backend=i,this.features=s}get queries(){return Object.fromEntries(this._queries)}get controls(){return Object.fromEntries(this._controls)}get mappings(){return[...this._mappings,...this._crossFilters]}get crossFilters(){return this._crossFilters}createQuery(e,r){this.assertNameFree(e,"query");let i=new M(e,this,r);return this._queries.set(e,i),this.notify(),i}createFilter(e,r){this.assertNameFree(e,"filter");let i=r.dataset?this.datasetIndex(r.dataset,e):this.soleDataset(e,r.field),s=new G(e,this,r,i,this.backend);return this._controls.set(e,s),this.notify(),s}createDateDrill(e,r={}){if(this.features?.dateDrill===!1)throw new u(`Date drill \'${e}\' needs a capability this workspace has not enabled. Ask an admin to turn on \\`interactive_control:date_drill\\`.`,e);this.assertNameFree(e,"date drill control");let i=new U(e,this,r);return this._controls.set(e,i),this.notify(),i}mapControl(e,r,i){if(!(e instanceof L))throw new u("mapControl expects a control as its source. To let one query cross-filter another, use app.mapCrossFilter(from, to) \\u2014 a cross-filter edge names no field.");if(this._controls.get(e.name)!==e)throw new u(`Control \'${e.name}\' belongs to a different app.`,e.name);if(this._queries.get(r.name)!==r)throw new u(`Query \'${r.name}\' belongs to a different app.`,r.name);i.aggregation&&Te(i.aggregation,e.name);let s=new H(e,r,i.field,i.aggregation);if(this._mappings.some(a=>a.id===s.id))throw new u(`Mapping \'${s.id}\' is already declared.`,e.name);return this.assertAcyclic(s),this._mappings.push(s),this.notify(),s}mapCrossFilter(e,r){if(!(e instanceof M)||!(r instanceof M))throw new u("mapCrossFilter expects two queries. To let a control condition a query, use app.mapControl(from, to, { field }).");if(this._queries.get(e.name)!==e)throw new u(`Query \'${e.name}\' belongs to a different app.`,e.name);if(this._queries.get(r.name)!==r)throw new u(`Query \'${r.name}\' belongs to a different app.`,r.name);if(e===r)throw new u(`Query \'${e.name}\' cannot cross-filter itself. A source keeps its own rows so it can show what is selected; filtering it would erase the very rows the reader clicked.`,e.name);if(e.declaration.dataset!==r.declaration.dataset)throw new u(`Cross-filter \'${e.name}\' -> \'${r.name}\' spans two datasets (\'${e.declaration.dataset}\' and \'${r.declaration.dataset}\'). A selection carries field references, which mean nothing outside the dataset that resolved them.`,e.name);let i=new K(e,r);if(this._crossFilters.some(s=>s.id===i.id))throw new u(`Cross-filter \'${i.id}\' is already declared.`,e.name);return this._crossFilters.push(i),this.notify(),i}get selection(){return this._selection}get appliedSelection(){return this._appliedSelection}clearSelection(){this._selection&&(this._selection=void 0,this.notify())}setTimezone(e){this._timezone=e,this.notify()}get timezone(){return this._timezone}datasetIndex(e,r){return Fe(this.datasets,e,r)}mappingsTo(e){return this._mappings.filter(r=>r.to.name===e)}selectionExpressionFor(e,r){return this.selectionFor(e,r)?.expression}selectionFor(e,r){let i=r==="pending"?this._selection:this._appliedSelection;return!i||i.source===e?void 0:this._crossFilters.some(a=>a.from.name===i.source&&a.to.name===e)?i:void 0}selectionConditionsFor(e,r){let i=r==="pending"?this._selection:this._appliedSelection;return!i||i.source===e?Se:this._crossFilters.some(a=>a.from.name===i.source&&a.to.name===e)?i.conditions:Se}drillTransformations(e){let r={};return this._mappings.forEach(i=>{if(i.to!==e)return;let s=i.from.appliedCondition;if(s?.operator!=="transform_date_drill")return;let[a]=s.values??[];typeof a=="string"&&(r[i.field]=a)}),r}select(e,r,i){if(this._queries.get(e.name)!==e)throw new u(`Query \'${e.name}\' belongs to a different app.`,e.name);let s=Ge(e,r,i,this.drillTransformations(e));s?.lossy&&console.warn(`[anfra-sdk] The selection in \'${e.name}\' filters more broadly than it was made. Its conditions are combined field by field and ANDed, which cannot express "(A and B) or (C and D)", so the targets will also show combinations that were not selected. Select within one dimension, or narrow with \\`fields\\`, to avoid this.`),this._selection=s,this.notify()}get hasChanges(){return[...this._controls.values()].some(e=>e.isDirty)||this.isSelectionDirty}get isSelectionDirty(){return this.selectionCommitted?et(this._selection)!==et(this._appliedSelection):!1}async execute(e={}){let r=[...this._queries.values()].filter(l=>l.shouldRun(e.force));this._controls.forEach(l=>l.commit()),this._appliedSelection=this._selection,this.selectionCommitted=!0,r.forEach(l=>{l.controller?.abort(),l.resetPage()});let i={backend:this.backend,timezone:this._timezone,bustCache:e.bustCache},s=[],a=[];return await Promise.all(r.map(async l=>{let d=new AbortController;l.controller=d;let p=l.signature();l.markExecuting();try{let E=await ge(l,this.mappingsTo(l.name),{conditions:this.selectionConditionsFor(l.name,"applied"),expression:this.selectionExpressionFor(l.name,"applied")},i,d.signal);if(Xe(l,d))return;l.markSuccess(E,p,!1),s.push(l.name)}catch(E){if(Xe(l,d)||ve(E))return;l.markError(tt(E,l.name)),a.push(l.name)}finally{l.controller===d&&(l.controller=void 0)}})),{succeeded:s,failed:a}}async refresh(){return this.execute({force:!0,bustCache:!0})}abort(){this._queries.forEach(e=>e.abort())}async fetchPage(e){let r=new AbortController;e.controller=r;let i=e.signature();e.markExecuting();try{let s=await ge(e,this.mappingsTo(e.name),{conditions:this.selectionConditionsFor(e.name,"applied"),expression:this.selectionExpressionFor(e.name,"applied")},{backend:this.backend,timezone:this._timezone},r.signal);e.markSuccess(s,i,!0)}catch(s){if(e.rewindPage(),ve(s))return;let a=tt(s,e.name);throw e.markError(a),a}finally{e.controller===r&&(e.controller=void 0)}}async exportQuery(e,r={}){let{backend:i}=this;if(this.features?.export===!1||!i.exportQuery)throw new O("This host cannot make exports.",void 0,e.name);let s=Qe(e,this.mappingsTo(e.name),{conditions:this.selectionConditionsFor(e.name,"applied"),expression:this.selectionExpressionFor(e.name,"applied")},{backend:i,timezone:this._timezone,title:this.title},r);try{return await i.exportQuery(s,r.signal??new AbortController().signal)}catch(a){throw ve(a)?a:zt(a,e.name)}}toJSON(){let e=o(r=>Object.fromEntries([...this._controls.entries()].filter(([,i])=>i.kind===r).map(([i,s])=>[i,s.toJSON()])),"byKind");return{...this.title?{title:this.title}:{},...this._timezone?{timezone:this._timezone}:{},queries:Object.fromEntries([...this._queries.entries()].map(([r,i])=>[r,i.toJSON()])),filters:e("filter"),dateDrills:e("dateDrill"),mappings:[...this._mappings.map(r=>r.toJSON()),...this._crossFilters.map(r=>r.toJSON())]}}toInspectJSON(){return{...this.title?{title:this.title}:{},...this._timezone?{timezone:this._timezone}:{},hasChanges:this.hasChanges,declaration:this.toJSON(),queries:Object.fromEntries([...this._queries.entries()].map(([e,r])=>[e,Pt(r)])),controls:Object.fromEntries([...this._controls.entries()].map(([e,r])=>[e,Bt(r)])),...this._selection?{selection:Ze(this._selection)}:{},...this._appliedSelection?{appliedSelection:Ze(this._appliedSelection)}:{}}}locate(e,r){let i=globalThis.document;if(!i)return!1;let s=Ke(i,e,this.index,r);return s.length?(Z(s[0]),B(i).flash(s,{kind:e,name:r,...s.length>1?{note:`in ${s.length} places`}:{}}),!0):!1}assertNameFree(e,r){Ne([...this._queries.keys(),...this._controls.keys()],e,r)}soleDataset(e,r){if(!r)return;let i=Object.keys(this.datasets);if(i.length===1)return this.datasets[i[0]];throw new u(i.length?`Filter \'${e}\' names a field but the environment has ${i.length} datasets. Say which one: ${i.join(", ")}.`:`Filter \'${e}\' names a field but the environment has no datasets.`,e)}assertAcyclic(e){let r=[...this._mappings,e],i=new Map;r.forEach(d=>{let p=d.from.name;i.set(p,[...i.get(p)??[],d.to.name])});let s=new Set,a=new Set,l=o(d=>{if(s.has(d))return!0;if(a.has(d))return!1;s.add(d);let p=(i.get(d)??[]).some(l);return s.delete(d),a.add(d),p},"walk");if([...i.keys()].some(l))throw new u(`Mapping \'${e.id}\' would make the app\'s mappings cyclic.`,e.from.name)}};o(Ee,"App");var ee=Ee;var nt="0.8.0";var qt=nt,Ce=class Ce{constructor(n){c(this,"version",qt);c(this,"_apps",[]);c(this,"datasets");c(this,"user");c(this,"indices");c(this,"backend");c(this,"features");c(this,"renderHook");if(!n?.datasets)throw new u("No datasets provided. The host must call createSdk({ datasets }) before an app can be declared.");if(!n.user)throw new u("No user provided. The host must call createSdk({ user }) before an app can be declared.");if(!n.backend)throw new u("No backend provided. The host must call createSdk({ backend }) before an app can run a query.");this.datasets=Object.freeze({...n.datasets}),this.user=Object.freeze({...n.user,permissions:Object.freeze({...n.user.permissions})}),this.indices=Object.fromEntries(Object.entries(n.datasets).map(([e,r])=>[e,new W(r)])),this.backend=n.backend,this.renderHook=n.render,this.features=Object.freeze({...n.features,export:n.features?.export??typeof n.backend.exportQuery=="function",render:n.features?.render??typeof n.render=="function"})}createApp(n={}){let e=new ee(n,this.indices,this.backend,this.features);return e.index=this._apps.length,this._apps.push(e),e}render(n){return!this.renderHook||this.features.render===!1?Promise.reject(new u("This host does not render Data Apps: check Anfra.features.render first.")):this.renderHook(n)}get apps(){return this._apps}};o(Ce,"Sdk");var Re=Ce;function rt(t){return new Re(t)}o(rt,"createSdk");var q="Anfra";function it(t,n=globalThis){let e=n[q],r=q in n;return n[q]=t,()=>{r?n[q]=e:delete n[q]}}o(it,"installSandbox");function ot(t,n){let e=null,r=o(d=>d.target instanceof Element?d.target.closest(Y):null,"under"),i=o(d=>{let p=r(d);p!==e&&(e=p,n.onHover(p))},"onMove"),s=o(d=>{d.preventDefault(),d.stopPropagation();let p=r(d);p&&n.onPick(p)},"onClick"),a=o(d=>{d.key==="Escape"&&n.onCancel()},"onKey"),l={capture:!0};return t.addEventListener("mousemove",i,l),t.addEventListener("click",s,l),t.addEventListener("keydown",a,l),()=>{t.removeEventListener("mousemove",i,l),t.removeEventListener("click",s,l),t.removeEventListener("keydown",a,l)}}o(ot,"startPick");var Ae="__anfraRenderer";var Jt="data-anfra-render",jt={png:"png",pdf:"pdf"},Gt=1e4;function Ut(t,n,e,r){let i=jt[t.format],s=t.filename?.trim();if(!s){let a=e.find(d=>d.title)?.title||n.title.trim()||"Data App",l=r&&(r.getAttribute(S.label)||t.block||t.container);s=l?`${a} - ${l}`:a}return s=s.replace(/[/\\\\]/g,"-").replace(/\\p{Cc}/gu,"").trim()||"Data App",s.toLowerCase().endsWith(`.${i}`)?s:`${s}.${i}`}o(Ut,"filenameFor");function Ht(t,n){if(t.block!==void 0&&t.container!==void 0)throw new u("Render a block or a container, not both.",t.block);if(t.format!=="png"&&t.format!=="pdf")throw new u(`Can\'t render as \'${String(t.format)}\': the formats are \'png\' and \'pdf\'.`);let{pixelRatio:e}=t;if(e!==void 0&&!(Number.isFinite(e)&&e>0))throw new u(`pixelRatio ${String(e)} is not a positive number.`);let r=t.block!==void 0?"block":t.container!==void 0?"container":void 0;if(!r)return{element:null};let i=t.block??t.container,s=[...n.querySelectorAll(`[${S[r]}]`)].find(a=>a.getAttribute(S[r])===i);if(!s)throw new u(`No element is marked ${S[r]}="${i}" on the page.`,i);return{element:s,entity:i}}o(Ht,"targetOf");function Kt(t){return t.id===X||t.getAttribute(Jt)==="skip"}o(Kt,"skip");function st(t,n){let e,r=o(()=>{let i=t[Ae];return i?Promise.resolve(i):(e??(e=n.ask.renderer().then(s=>{let a=t.document.createElement("script");a.textContent=s,(t.document.head??t.document.documentElement).appendChild(a),a.remove();let l=t[Ae];if(!l)throw new u("The host sent a renderer that did not install.");return l}).catch(s=>{throw e=void 0,s})),e)},"load");return async i=>{let s=t.document,{element:a,entity:l}=Ht(i??{},s),d=Ut(i,s,n.apps(),a);try{let E=await(await r()).draw(a,{format:i.format,pixelRatio:i.pixelRatio,skip:Kt});return await n.ask.saveFile({blob:E.blob,filename:d}),{filename:d,format:i.format,...E}}catch(p){throw p instanceof u&&p.entity?p:new u(p?.message||"The rendering failed.",l)}}}o(st,"createRender");async function at(t,n,e=Gt){let r=o(()=>n().some(s=>Object.values(s.queries).some(a=>a.state==="executing")),"busy"),i=Date.now()+e;for(;r()&&Date.now()<i;)await new Promise(s=>{t.setTimeout(s,100)});await new Promise(s=>{t.requestAnimationFrame(()=>s(void 0))})}o(at,"settle");function lt(){let t=new Error("Aborted");return t.name="AbortError",t}o(lt,"abortError");function Wt(t){switch(t?.name){case"PermissionError":return new I(t.message);case"TransportError":return new O(t.message);case"ValidationError":return new u(t.message);default:return new N(t?.message||"The query failed.")}}o(Wt,"toError");function dt(t){let n=t.document.getElementById(_e);if(!n?.textContent)throw new Error("anfra: this frame was not provisioned by a host.");let e=JSON.parse(n.textContent),r=o(f=>t.parent.postMessage(f,e.hostOrigin),"post"),i=new Map,s=1,a=!1,l;t.addEventListener("message",f=>{if(f.source!==t.parent)return;let m=f.data;switch(m?.type){case"anfra:response":{let y=i.get(m.id);if(!y)return;i.delete(m.id),m.ok?y.resolve(m.result):y.reject(Wt(m.error));return}case"anfra:inspect-watch":v(m.open);return;case"anfra:highlight":k(m.node);return;case"anfra:locate":Q(m.target);return;case"anfra:pick-watch":z(m.on);return;case"anfra:render":{let{id:y}=m;at(t,()=>x.apps).then(()=>x.render(m.request)).then(R=>r({type:"anfra:rendered",id:y,ok:!0,result:R}),R=>r({type:"anfra:rendered",id:y,ok:!1,error:{name:R?.name??"ValidationError",message:R?.message??"The rendering failed."}}));return}default:}});function d(f,m,y){return new Promise((R,te)=>{if(y.aborted){te(lt());return}let j=s++;i.set(j,{resolve:R,reject:te}),y.addEventListener("abort",()=>{i.delete(j)&&(r({type:"anfra:cancel",id:j}),te(lt()))},{once:!0}),r({type:"anfra:request",id:j,method:f,request:m})})}o(d,"call");let p={submitQuery:o((f,m)=>d("submitQuery",f,m).then(y=>(y.debug?.executedAt&&(y.debug.executedAt=new Date(y.debug.executedAt)),y)),"submitQuery"),fieldSuggestions:o((f,m)=>d("fieldSuggestions",f,m),"fieldSuggestions"),exportQuery:o((f,m)=>d("exportQuery",f,m).then(y=>(y.expiresAt=new Date(y.expiresAt),y)),"exportQuery")},E=st(t,{ask:{renderer:o(()=>d("renderer",null,new AbortController().signal),"renderer"),saveFile:o(f=>d("saveFile",f,new AbortController().signal),"saveFile")},apps:o(()=>x.apps,"apps")}),x=rt({datasets:e.datasets,user:e.user,backend:p,render:E,features:{export:!1,render:!1,...e.features}}),h=t.document,b,C="",A,g;function w(){if(l=void 0,!!a)try{b=we(h,x.apps),C=JSON.stringify(b.nodes),r({type:"anfra:inspect",apps:x.apps.map(f=>f.toInspectJSON()),structure:{nodes:b.nodes,usage:b.usage}})}catch{}}o(w,"postSnapshot");function D(){a&&l===void 0&&(l=setTimeout(w,50))}o(D,"scheduleSnapshot");function T(){let f=t.MutationObserver;if(A||typeof f!="function")return;let m=new f(()=>{if(!(!a||l!==void 0))try{JSON.stringify(we(h,x.apps).nodes)!==C&&D()}catch{}});A=m,m.observe(h.documentElement,{childList:!0,subtree:!0,attributes:!0,attributeFilter:["data-anfra-container","data-anfra-block","data-anfra-query","data-anfra-control","data-anfra-label"]})}o(T,"observeStructure");function v(f){a=f,f?(T(),w()):(A?.disconnect(),A=void 0,z(!1),B(h).hide(),b=void 0,C="")}o(v,"setInspecting");function _(f,m){for(let y of f){if(y.key===m)return y;let R=_(y.children,m);if(R)return R}}o(_,"findNode");function k(f){let m=B(h),y=f!==null&&b?_(b.nodes,f):void 0,R=f!==null?b?.elements.get(f):void 0;if(!y||!R||!b){m.hide();return}m.show([R],We(y,R,b))}o(k,"highlight");function Q(f){if("node"in f){let m=b?.elements.get(f.node);m&&Z(m),k(f.node)}else x.apps[f.app]?.locate(f.kind,f.name);D()}o(Q,"locate");function z(f){if(!f){g?.(),g=void 0;return}if(g)return;let m=o(y=>b?.keysOf.get(y)?.[0],"keyOf");g=ot(h,{onHover:o(y=>k(y?m(y)??null:null),"onHover"),onPick:o(y=>{let R=m(y);R!==void 0&&r({type:"anfra:picked",node:R})},"onPick"),onCancel:o(()=>{z(!1),B(h).hide(),r({type:"anfra:picked",node:null})},"onCancel")})}o(z,"setPicking");let J=x.createApp.bind(x);x.createApp=f=>{let m=J(f);return m.subscribe(D),D(),m},it(x,t),r({type:"anfra:ready"})}o(dt,"bootstrap");dt(window);})();\n';
|
|
75
161
|
|
|
76
162
|
// src/host/frameScript.ts
|
|
77
163
|
function builtFrameScript() {
|
|
78
164
|
return anfra_sdk_frame_script_default || void 0;
|
|
79
165
|
}
|
|
80
166
|
|
|
167
|
+
// renderer:anfra-sdk:renderer
|
|
168
|
+
var anfra_sdk_renderer_default = '"use strict";(()=>{var le=Object.defineProperty;var i=(e,t)=>le(e,"name",{value:t,configurable:!0});function M(e,t){if(e.match(/^[a-z]+:\\/\\//i))return e;if(e.match(/^\\/\\//))return window.location.protocol+e;if(e.match(/^[a-z]+:/i))return e;let n=document.implementation.createHTMLDocument(),r=n.createElement("base"),a=n.createElement("a");return n.head.appendChild(r),n.body.appendChild(a),t&&(r.href=t),a.href=e,a.href}i(M,"resolveUrl");var H=(()=>{let e=0,t=i(()=>`0000${(Math.random()*36**4<<0).toString(36)}`.slice(-4),"random");return()=>(e+=1,`u${t()}${e}`)})();function p(e){let t=[];for(let n=0,r=e.length;n<r;n++)t.push(e[n]);return t}i(p,"toArray");var b=null;function L(e={}){return b||(e.includeStyleProperties?(b=e.includeStyleProperties,b):(b=p(window.getComputedStyle(document.documentElement)),b))}i(L,"getStyleProperties");function $(e,t){let r=(e.ownerDocument.defaultView||window).getComputedStyle(e).getPropertyValue(t);return r?parseFloat(r.replace("px","")):0}i($,"px");function ue(e){let t=$(e,"border-left-width"),n=$(e,"border-right-width");return e.clientWidth+t+n}i(ue,"getNodeWidth");function fe(e){let t=$(e,"border-top-width"),n=$(e,"border-bottom-width");return e.clientHeight+t+n}i(fe,"getNodeHeight");function F(e,t={}){let n=t.width||ue(e),r=t.height||fe(e);return{width:n,height:r}}i(F,"getImageSize");function _(){let e,t;try{t=process}catch{}let n=t&&t.env?t.env.devicePixelRatio:null;return n&&(e=parseInt(n,10),Number.isNaN(e)&&(e=1)),e||window.devicePixelRatio||1}i(_,"getPixelRatio");var g=16384;function V(e){(e.width>g||e.height>g)&&(e.width>g&&e.height>g?e.width>e.height?(e.height*=g/e.width,e.width=g):(e.width*=g/e.height,e.height=g):e.width>g?(e.height*=g/e.width,e.width=g):(e.width*=g/e.height,e.height=g))}i(V,"checkCanvasDimensions");function x(e){return new Promise((t,n)=>{let r=new Image;r.onload=()=>{r.decode().then(()=>{requestAnimationFrame(()=>t(r))})},r.onerror=n,r.crossOrigin="anonymous",r.decoding="async",r.src=e})}i(x,"createImage");async function me(e){return Promise.resolve().then(()=>new XMLSerializer().serializeToString(e)).then(encodeURIComponent).then(t=>`data:image/svg+xml;charset=utf-8,${t}`)}i(me,"svgToDataURL");async function W(e,t,n){let r="http://www.w3.org/2000/svg",a=document.createElementNS(r,"svg"),o=document.createElementNS(r,"foreignObject");return a.setAttribute("width",`${t}`),a.setAttribute("height",`${n}`),a.setAttribute("viewBox",`0 0 ${t} ${n}`),o.setAttribute("width","100%"),o.setAttribute("height","100%"),o.setAttribute("x","0"),o.setAttribute("y","0"),o.setAttribute("externalResourcesRequired","true"),a.appendChild(o),o.appendChild(e),me(a)}i(W,"nodeToDataURL");var m=i((e,t)=>{if(e instanceof t)return!0;let n=Object.getPrototypeOf(e);return n===null?!1:n.constructor.name===t.name||m(n,t)},"isInstanceOfElement");function he(e){let t=e.getPropertyValue("content");return`${e.cssText} content: \'${t.replace(/\'|"/g,"")}\';`}i(he,"formatCSSText");function ge(e,t){return L(t).map(n=>{let r=e.getPropertyValue(n),a=e.getPropertyPriority(n);return`${n}: ${r}${a?" !important":""};`}).join(" ")}i(ge,"formatCSSProperties");function de(e,t,n,r){let a=`.${e}:${t}`,o=n.cssText?he(n):ge(n,r);return document.createTextNode(`${a}{${o}}`)}i(de,"getPseudoElementStyle");function j(e,t,n,r){let a=window.getComputedStyle(e,n),o=a.getPropertyValue("content");if(o===""||o==="none")return;let s=H();try{t.className=`${t.className} ${s}`}catch{return}let c=document.createElement("style");c.appendChild(de(s,n,a,r)),t.appendChild(c)}i(j,"clonePseudoElement");function q(e,t,n){j(e,t,":before",n),j(e,t,":after",n)}i(q,"clonePseudoElements");var z="application/font-woff",G="image/jpeg",pe={woff:z,woff2:z,ttf:"application/font-truetype",eot:"application/vnd.ms-fontobject",png:"image/png",jpg:G,jpeg:G,gif:"image/gif",tiff:"image/tiff",svg:"image/svg+xml",webp:"image/webp"};function ye(e){let t=/\\.([^./]*?)$/g.exec(e);return t?t[1]:""}i(ye,"getExtension");function S(e){let t=ye(e).toLowerCase();return pe[t]||""}i(S,"getMimeType");function we(e){return e.split(/,/)[1]}i(we,"getContentFromDataUrl");function C(e){return e.search(/^(data:)/)!==-1}i(C,"isDataUrl");function U(e,t){return`data:${t};base64,${e}`}i(U,"makeDataUrl");async function v(e,t,n){let r=await fetch(e,t);if(r.status===404)throw new Error(`Resource "${r.url}" not found`);let a=await r.blob();return new Promise((o,s)=>{let c=new FileReader;c.onerror=s,c.onloadend=()=>{try{o(n({res:r,result:c.result}))}catch(l){s(l)}},c.readAsDataURL(a)})}i(v,"fetchAsDataURL");var I={};function be(e,t,n){let r=e.replace(/\\?.*/,"");return n&&(r=e),/ttf|otf|eot|woff2?/i.test(r)&&(r=r.replace(/.*\\//,"")),t?`[${t}]${r}`:r}i(be,"getCacheKey");async function E(e,t,n){let r=be(e,t,n.includeQueryParams);if(I[r]!=null)return I[r];n.cacheBust&&(e+=(/\\?/.test(e)?"&":"?")+new Date().getTime());let a;try{let o=await v(e,n.fetchRequestInit,({res:s,result:c})=>(t||(t=s.headers.get("Content-Type")||""),we(c)));a=U(o,t)}catch(o){a=n.imagePlaceholder||"";let s=`Failed to fetch resource: ${e}`;o&&(s=typeof o=="string"?o:o.message),s&&console.warn(s)}return I[r]=a,a}i(E,"resourceToDataURL");async function xe(e){let t=e.toDataURL();return t==="data:,"?e.cloneNode(!1):x(t)}i(xe,"cloneCanvasElement");async function Se(e,t){if(e.currentSrc){let o=document.createElement("canvas"),s=o.getContext("2d");o.width=e.clientWidth,o.height=e.clientHeight,s?.drawImage(e,0,0,o.width,o.height);let c=o.toDataURL();return x(c)}let n=e.poster,r=S(n),a=await E(n,r,t);return x(a)}i(Se,"cloneVideoElement");async function Ee(e,t){var n;try{if(!((n=e?.contentDocument)===null||n===void 0)&&n.body)return await P(e.contentDocument.body,t,!0)}catch{}return e.cloneNode(!1)}i(Ee,"cloneIFrameElement");async function Re(e,t){return m(e,HTMLCanvasElement)?xe(e):m(e,HTMLVideoElement)?Se(e,t):m(e,HTMLIFrameElement)?Ee(e,t):e.cloneNode(X(e))}i(Re,"cloneSingleNode");var Ae=i(e=>e.tagName!=null&&e.tagName.toUpperCase()==="SLOT","isSlotElement"),X=i(e=>e.tagName!=null&&e.tagName.toUpperCase()==="SVG","isSVGElement");async function Ce(e,t,n){var r,a;if(X(t))return t;let o=[];return Ae(e)&&e.assignedNodes?o=p(e.assignedNodes()):m(e,HTMLIFrameElement)&&(!((r=e.contentDocument)===null||r===void 0)&&r.body)?o=p(e.contentDocument.body.childNodes):o=p(((a=e.shadowRoot)!==null&&a!==void 0?a:e).childNodes),o.length===0||m(e,HTMLVideoElement)||await o.reduce((s,c)=>s.then(()=>P(c,n)).then(l=>{l&&t.appendChild(l)}),Promise.resolve()),t}i(Ce,"cloneChildren");function Pe(e,t,n){let r=t.style;if(!r)return;let a=window.getComputedStyle(e);a.cssText?(r.cssText=a.cssText,r.transformOrigin=a.transformOrigin):L(n).forEach(o=>{let s=a.getPropertyValue(o);o==="font-size"&&s.endsWith("px")&&(s=`${Math.floor(parseFloat(s.substring(0,s.length-2)))-.1}px`),m(e,HTMLIFrameElement)&&o==="display"&&s==="inline"&&(s="block"),o==="d"&&t.getAttribute("d")&&(s=`path(${t.getAttribute("d")})`),r.setProperty(o,s,a.getPropertyPriority(o))})}i(Pe,"cloneCSSStyle");function Te(e,t){m(e,HTMLTextAreaElement)&&(t.innerHTML=e.value),m(e,HTMLInputElement)&&t.setAttribute("value",e.value)}i(Te,"cloneInputValue");function $e(e,t){if(m(e,HTMLSelectElement)){let r=Array.from(t.children).find(a=>e.value===a.getAttribute("value"));r&&r.setAttribute("selected","")}}i($e,"cloneSelectValue");function Le(e,t,n){return m(t,Element)&&(Pe(e,t,n),q(e,t,n),Te(e,t),$e(e,t)),t}i(Le,"decorate");async function De(e,t){let n=e.querySelectorAll?e.querySelectorAll("use"):[];if(n.length===0)return e;let r={};for(let o=0;o<n.length;o++){let c=n[o].getAttribute("xlink:href");if(c){let l=e.querySelector(c),f=document.querySelector(c);!l&&f&&!r[c]&&(r[c]=await P(f,t,!0))}}let a=Object.values(r);if(a.length){let o="http://www.w3.org/1999/xhtml",s=document.createElementNS(o,"svg");s.setAttribute("xmlns",o),s.style.position="absolute",s.style.width="0",s.style.height="0",s.style.overflow="hidden",s.style.display="none";let c=document.createElementNS(o,"defs");s.appendChild(c);for(let l=0;l<a.length;l++)c.appendChild(a[l]);e.appendChild(s)}return e}i(De,"ensureSVGSymbols");async function P(e,t,n){return!n&&t.filter&&!t.filter(e)?null:Promise.resolve(e).then(r=>Re(r,t)).then(r=>Ce(e,r,t)).then(r=>Le(e,r,t)).then(r=>De(r,t))}i(P,"cloneNode");var J=/url\\(([\'"]?)([^\'"]+?)\\1\\)/g,Fe=/url\\([^)]+\\)\\s*format\\((["\']?)([^"\']+)\\1\\)/g,Ie=/src:\\s*(?:url\\([^)]+\\)\\s*format\\([^)]+\\)[,;]\\s*)+/g;function Ue(e){let t=e.replace(/([.*+?^${}()|\\[\\]\\/\\\\])/g,"\\\\$1");return new RegExp(`(url\\\\([\'"]?)(${t})([\'"]?\\\\))`,"g")}i(Ue,"toRegex");function ve(e){let t=[];return e.replace(J,(n,r,a)=>(t.push(a),n)),t.filter(n=>!C(n))}i(ve,"parseURLs");async function ke(e,t,n,r,a){try{let o=n?M(t,n):t,s=S(t),c;if(a){let l=await a(o);c=U(l,s)}else c=await E(o,s,r);return e.replace(Ue(t),`$1${c}$3`)}catch{}return e}i(ke,"embed");function Oe(e,{preferredFontFormat:t}){return t?e.replace(Ie,n=>{for(;;){let[r,,a]=Fe.exec(n)||[];if(!a)return"";if(a===t)return`src: ${r};`}}):e}i(Oe,"filterPreferredFontFormat");function k(e){return e.search(J)!==-1}i(k,"shouldEmbed");async function D(e,t,n){if(!k(e))return e;let r=Oe(e,n);return ve(r).reduce((o,s)=>o.then(c=>ke(c,s,t,n)),Promise.resolve(r))}i(D,"embedResources");async function R(e,t,n){var r;let a=(r=t.style)===null||r===void 0?void 0:r.getPropertyValue(e);if(a){let o=await D(a,null,n);return t.style.setProperty(e,o,t.style.getPropertyPriority(e)),!0}return!1}i(R,"embedProp");async function Be(e,t){await R("background",e,t)||await R("background-image",e,t),await R("mask",e,t)||await R("-webkit-mask",e,t)||await R("mask-image",e,t)||await R("-webkit-mask-image",e,t)}i(Be,"embedBackground");async function Me(e,t){let n=m(e,HTMLImageElement);if(!(n&&!C(e.src))&&!(m(e,SVGImageElement)&&!C(e.href.baseVal)))return;let r=n?e.src:e.href.baseVal,a=await E(r,S(r),t);await new Promise((o,s)=>{e.onload=o,e.onerror=t.onImageErrorHandler?(...l)=>{try{o(t.onImageErrorHandler(...l))}catch(f){s(f)}}:s;let c=e;c.decode&&(c.decode=o),c.loading==="lazy"&&(c.loading="eager"),n?(e.srcset="",e.src=a):e.href.baseVal=a})}i(Me,"embedImageNode");async function He(e,t){let r=p(e.childNodes).map(a=>O(a,t));await Promise.all(r).then(()=>e)}i(He,"embedChildren");async function O(e,t){m(e,Element)&&(await Be(e,t),await Me(e,t),await He(e,t))}i(O,"embedImages");function K(e,t){let{style:n}=e;t.backgroundColor&&(n.backgroundColor=t.backgroundColor),t.width&&(n.width=`${t.width}px`),t.height&&(n.height=`${t.height}px`);let r=t.style;return r!=null&&Object.keys(r).forEach(a=>{n[a]=r[a]}),e}i(K,"applyStyle");var Q={};async function Y(e){let t=Q[e];if(t!=null)return t;let r=await(await fetch(e)).text();return t={url:e,cssText:r},Q[e]=t,t}i(Y,"fetchCSS");async function Z(e,t){let n=e.cssText,r=/url\\(["\']?([^"\')]+)["\']?\\)/g,o=(n.match(/url\\([^)]+\\)/g)||[]).map(async s=>{let c=s.replace(r,"$1");return c.startsWith("https://")||(c=new URL(c,e.url).href),v(c,t.fetchRequestInit,({result:l})=>(n=n.replace(s,`url(${l})`),[s,l]))});return Promise.all(o).then(()=>n)}i(Z,"embedFonts");function N(e){if(e==null)return[];let t=[],n=/(\\/\\*[\\s\\S]*?\\*\\/)/gi,r=e.replace(n,""),a=new RegExp("((@.*?keyframes [\\\\s\\\\S]*?){([\\\\s\\\\S]*?}\\\\s*?)})","gi");for(;;){let l=a.exec(r);if(l===null)break;t.push(l[0])}r=r.replace(a,"");let o=/@import[\\s\\S]*?url\\([^)]*\\)[\\s\\S]*?;/gi,s="((\\\\s*?(?:\\\\/\\\\*[\\\\s\\\\S]*?\\\\*\\\\/)?\\\\s*?@media[\\\\s\\\\S]*?){([\\\\s\\\\S]*?)}\\\\s*?})|(([\\\\s\\\\S]*?){([\\\\s\\\\S]*?)})",c=new RegExp(s,"gi");for(;;){let l=o.exec(r);if(l===null){if(l=c.exec(r),l===null)break;o.lastIndex=c.lastIndex}else c.lastIndex=o.lastIndex;t.push(l[0])}return t}i(N,"parseCSS");async function _e(e,t){let n=[],r=[];return e.forEach(a=>{if("cssRules"in a)try{p(a.cssRules||[]).forEach((o,s)=>{if(o.type===CSSRule.IMPORT_RULE){let c=s+1,l=o.href,f=Y(l).then(u=>Z(u,t)).then(u=>N(u).forEach(h=>{try{a.insertRule(h,h.startsWith("@import")?c+=1:a.cssRules.length)}catch(A){console.error("Error inserting rule from remote css",{rule:h,error:A})}})).catch(u=>{console.error("Error loading remote css",u.toString())});r.push(f)}})}catch(o){let s=e.find(c=>c.href==null)||document.styleSheets[0];a.href!=null&&r.push(Y(a.href).then(c=>Z(c,t)).then(c=>N(c).forEach(l=>{s.insertRule(l,s.cssRules.length)})).catch(c=>{console.error("Error loading remote stylesheet",c)})),console.error("Error inlining remote css file",o)}}),Promise.all(r).then(()=>(e.forEach(a=>{if("cssRules"in a)try{p(a.cssRules||[]).forEach(o=>{n.push(o)})}catch(o){console.error(`Error while reading CSS rules from ${a.href}`,o)}}),n))}i(_e,"getCSSRules");function Ve(e){return e.filter(t=>t.type===CSSRule.FONT_FACE_RULE).filter(t=>k(t.style.getPropertyValue("src")))}i(Ve,"getWebFontRules");async function We(e,t){if(e.ownerDocument==null)throw new Error("Provided element is not within a Document");let n=p(e.ownerDocument.styleSheets),r=await _e(n,t);return Ve(r)}i(We,"parseWebFontRules");function ee(e){return e.trim().replace(/["\']/g,"")}i(ee,"normalizeFontFamily");function je(e){let t=new Set;function n(r){(r.style.fontFamily||getComputedStyle(r).fontFamily).split(",").forEach(o=>{t.add(ee(o))}),Array.from(r.children).forEach(o=>{o instanceof HTMLElement&&n(o)})}return i(n,"traverse"),n(e),t}i(je,"getUsedFonts");async function te(e,t){let n=await We(e,t),r=je(e);return(await Promise.all(n.filter(o=>r.has(ee(o.style.fontFamily))).map(o=>{let s=o.parentStyleSheet?o.parentStyleSheet.href:null;return D(o.cssText,s,t)}))).join(`\n`)}i(te,"getWebFontCSS");async function re(e,t){let n=t.fontEmbedCSS!=null?t.fontEmbedCSS:t.skipFonts?null:await te(e,t);if(n){let r=document.createElement("style"),a=document.createTextNode(n);r.appendChild(a),e.firstChild?e.insertBefore(r,e.firstChild):e.appendChild(r)}}i(re,"embedWebFonts");async function qe(e,t={}){let{width:n,height:r}=F(e,t),a=await P(e,t,!0);return await re(a,t),await O(a,t),K(a,t),await W(a,n,r)}i(qe,"toSvg");async function ne(e,t={}){let{width:n,height:r}=F(e,t),a=await qe(e,t),o=await x(a),s=document.createElement("canvas"),c=s.getContext("2d"),l=t.pixelRatio||_(),f=t.canvasWidth||n,u=t.canvasHeight||r;return s.width=f*l,s.height=u*l,t.skipAutoScale||V(s),s.style.width=`${f}`,s.style.height=`${u}`,t.backgroundColor&&(c.fillStyle=t.backgroundColor,c.fillRect(0,0,s.width,s.height)),c.drawImage(o,0,0,s.width,s.height),s}i(ne,"toCanvas");function oe(e,t,n){let r=(n.width*.75).toFixed(2),a=(n.height*.75).toFixed(2),o=`q ${r} 0 0 ${a} 0 0 cm /Im0 Do Q`,s=new TextEncoder,c=[],l=[],f=0,u=i(d=>{let w=typeof d=="string"?s.encode(d):d;c.push(w),f+=w.length},"push"),h=i((d,w)=>{l[d]=f,u(`${d} 0 obj\n`),(Array.isArray(w)?w:[w]).forEach(u),u(`\nendobj\n`)},"object");u(`%PDF-1.4\n`),u(new Uint8Array([37,226,227,207,211,10])),h(1,"<< /Type /Catalog /Pages 2 0 R >>"),h(2,"<< /Type /Pages /Kids [3 0 R] /Count 1 >>"),h(3,`<< /Type /Page /Parent 2 0 R /MediaBox [0 0 ${r} ${a}] /Resources << /XObject << /Im0 4 0 R >> >> /Contents 5 0 R >>`),h(4,[`<< /Type /XObject /Subtype /Image /Width ${t.width} /Height ${t.height} /ColorSpace /DeviceRGB /BitsPerComponent 8 /Filter /DCTDecode /Length ${e.length} >>\nstream\n`,e,`\nendstream`]),h(5,`<< /Length ${o.length} >>\nstream\n${o}\nendstream`);let A=f;return u(`xref\n0 6\n0000000000 65535 f \n${l.slice(1).map(d=>`${String(d).padStart(10,"0")} 00000 n \n`).join("")}`),u(`trailer\n<< /Size 6 /Root 1 0 R >>\nstartxref\n${A}\n%%EOF\n`),new Blob(c,{type:"application/pdf"})}i(oe,"pdfOfJpeg");var ae="__anfraRenderer",B=class B extends Error{constructor(t){super(t),this.name="RenderFailure"}};i(B,"RenderFailure");var y=B;var T=16384,ie=12e7;function ze(e,t,n){let r=i(c=>e*c<=T&&t*c<=T&&e*t*c*c<=ie,"fits"),a=i(c=>new y(`${e}\\xD7${t} px at pixelRatio ${c} is over a canvas\'s limit (${T} px a side): render a smaller node, or a lower pixelRatio.`),"tooBig");if(n!==void 0){if(!r(n))throw a(n);return n}let o=Math.max(globalThis.devicePixelRatio||1,2);if(r(o))return o;let s=Math.floor(Math.min(T/e,T/t,Math.sqrt(ie/(e*t)))*100)/100;if(s<1)throw a(1);return s}i(ze,"ratioFor");function Ge(e){return!!e&&e!=="transparent"&&!/rgba\\(.*,\\s*0\\)$/.test(e)}i(Ge,"opaque");function Xe(e,t){let n=[];if(e){for(let r=e;r;r=r.parentElement)n.push(r);n.push(t.body)}else n.push(t.documentElement,t.body);return n.map(r=>getComputedStyle(r).backgroundColor).find(Ge)??"#ffffff"}i(Xe,"backgroundOf");function Je(e,t){let n=[],r=i(a=>{if(!t(a)){n.push(a);for(let o of a.children)r(o)}},"walk");return r(e),n}i(Je,"drawnElements");async function Ke(e){let t=new Set;for(let r of e)if(r instanceof HTMLImageElement){let a=r.currentSrc||r.src;a&&!/^(data|blob):/.test(a)&&t.add(a)}let n=await Promise.all([...t].map(async r=>{try{return(await fetch(r,{mode:"cors",cache:"force-cache"})).ok}catch{return!1}}));return[...t].filter((r,a)=>!n[a])}i(Ke,"unreadableImages");var Qe="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7";function Ye(e){return new Promise((t,n)=>{let r=new FileReader;r.onload=()=>t(r.result),r.onerror=()=>n(r.error),r.readAsDataURL(e)})}i(Ye,"dataUrlOf");function Ze(e){let t=new Set;for(let n of e)for(let r of getComputedStyle(n).fontFamily.split(","))t.add(r.trim().replace(/^["\']|["\']$/g,"").toLowerCase());return t}i(Ze,"familiesOf");async function Ne(e,t){let n=Ze(t),r=[];return await Promise.all([...e.styleSheets].map(async o=>{let s=o.href??e.baseURI;try{for(let c of o.cssRules)c instanceof CSSFontFaceRule&&r.push({css:c.cssText,base:s})}catch{if(!o.href)return;try{let c=await(await fetch(o.href,{mode:"cors",cache:"force-cache"})).text();for(let l of c.match(/@font-face\\s*{[^}]*}/g)??[])r.push({css:l,base:s})}catch{}}})),(await Promise.all(r.map(async({css:o,base:s})=>{let c=/font-family:\\s*["\']?([^;"\']+)/.exec(o)?.[1]?.trim().toLowerCase();if(!c||!n.has(c))return"";let l=o;for(let[f,,u]of o.matchAll(/url\\((["\']?)([^"\')]+)\\1\\)/g))if(!u.startsWith("data:"))try{let h=await fetch(new URL(u,s).href,{mode:"cors",cache:"force-cache"});l=l.replace(f,`url(${await Ye(await h.blob())})`)}catch{return""}return l}))).filter(Boolean).join(`\n`)}i(Ne,"embedFonts");function se(e,t,n){return new Promise((r,a)=>{try{e.toBlob(o=>o?r(o):a(new y("The browser made no image of the canvas.")),t,n)}catch{a(new y(\'The page holds something read from another server without CORS (a canvas or a font), so the browser refuses to make an image of it. Load it with CORS, or mark it data-anfra-render="skip".\'))}})}i(se,"toBlob");async function et(e,t){let n=document,r=e??n.body,a=r.getBoundingClientRect(),o=Math.ceil(e?a.width:n.documentElement.scrollWidth),s=Math.ceil(e?a.height:n.documentElement.scrollHeight);if(!o||!s)throw new y("There is nothing to draw: it has no size (hidden, or empty).");let c=ze(o,s,t.pixelRatio),l=Je(r,t.skip),f=await Ke(l),u=await Ne(n,l),h=await ne(r,{width:o,height:s,pixelRatio:c,skipAutoScale:!0,backgroundColor:Xe(e,n),fontEmbedCSS:u,imagePlaceholder:Qe,filter:i(d=>!(d instanceof Element&&t.skip(d)),"filter"),style:e?{boxSizing:"border-box",margin:"0"}:{boxSizing:"border-box",width:`${a.width}px`,height:"auto"}});if(t.format==="png")return{blob:await se(h,"image/png"),width:o,height:s,omitted:f};let A=new Uint8Array(await(await se(h,"image/jpeg",.92)).arrayBuffer());return{blob:oe(A,h,{width:o,height:s}),width:o,height:s,omitted:f}}i(et,"draw");var ce={draw:et};globalThis[ae]=ce;})();\n';
|
|
169
|
+
|
|
170
|
+
// src/host/rendererScript.ts
|
|
171
|
+
function builtRenderer() {
|
|
172
|
+
return anfra_sdk_renderer_default || void 0;
|
|
173
|
+
}
|
|
174
|
+
|
|
81
175
|
// src/host/provision.ts
|
|
82
176
|
function scriptJSON(value) {
|
|
83
177
|
return JSON.stringify(value).replace(/</g, "\\u003c").replace(/>/g, "\\u003e").replace(/&/g, "\\u0026").replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029");
|
|
@@ -118,10 +212,18 @@ function mountDataApp(options) {
|
|
|
118
212
|
frame.setAttribute("sandbox", "allow-scripts");
|
|
119
213
|
frame.title = options.title ?? "Data App";
|
|
120
214
|
options.container.appendChild(frame);
|
|
121
|
-
const
|
|
215
|
+
const renderer = options.renderer ?? builtRenderer();
|
|
216
|
+
const render = options.render === true && !!renderer;
|
|
217
|
+
const bridge = serveBridge(
|
|
218
|
+
frame,
|
|
219
|
+
options.backend,
|
|
220
|
+
{ onInspect: options.onInspect, onPick: options.onPick },
|
|
221
|
+
{ render, renderer }
|
|
222
|
+
);
|
|
122
223
|
const provision = {
|
|
123
224
|
datasets: options.datasets,
|
|
124
225
|
user: options.user,
|
|
226
|
+
features: { export: typeof options.backend.exportQuery === "function", render },
|
|
125
227
|
hostOrigin: doc.defaultView?.location.origin ?? "*"
|
|
126
228
|
};
|
|
127
229
|
frame.srcdoc = provisionDocument(options.definition, { baseHref: options.baseHref, provision, frameScript });
|
|
@@ -131,6 +233,7 @@ function mountDataApp(options) {
|
|
|
131
233
|
highlight: bridge.highlight,
|
|
132
234
|
locate: bridge.locate,
|
|
133
235
|
setPicking: bridge.setPicking,
|
|
236
|
+
render: bridge.render,
|
|
134
237
|
unmount() {
|
|
135
238
|
bridge.stop();
|
|
136
239
|
frame.remove();
|