@altertable/data-app 0.66.0 → 0.67.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.
Files changed (131) hide show
  1. package/CONTRIBUTING.md +22 -16
  2. package/dist/chunks/{contract-19ckn3n7.js → index-23dktynd.js} +8 -6
  3. package/dist/chunks/index-23dktynd.js.map +10 -0
  4. package/dist/chunks/{contract-havnjmdr.js → index-8qfxv0h5.js} +2272 -1123
  5. package/dist/chunks/index-8qfxv0h5.js.map +108 -0
  6. package/dist/chunks/{contract-rfbakka4.js → index-ag0cgnvq.js} +169 -35
  7. package/dist/chunks/index-ag0cgnvq.js.map +13 -0
  8. package/dist/chunks/index-dq7b35fn.js +307 -0
  9. package/dist/chunks/index-dq7b35fn.js.map +13 -0
  10. package/dist/chunks/{contract-e11m4y7f.js → index-ev2b5aaf.js} +11 -6
  11. package/dist/chunks/{contract-e11m4y7f.js.map → index-ev2b5aaf.js.map} +3 -3
  12. package/dist/chunks/{contract-awa2d5b1.js → index-f5cnbrjz.js} +19 -2
  13. package/dist/chunks/{contract-awa2d5b1.js.map → index-f5cnbrjz.js.map} +4 -3
  14. package/dist/chunks/{contract-13j5zb3c.js → index-ktmvs916.js} +8 -7
  15. package/dist/chunks/index-ktmvs916.js.map +13 -0
  16. package/dist/chunks/index-mt93ff2b.js +28 -0
  17. package/dist/chunks/index-mt93ff2b.js.map +10 -0
  18. package/dist/chunks/{contract-tf8c3qpv.js → index-qd5xgx6y.js} +46 -5
  19. package/dist/chunks/index-qd5xgx6y.js.map +13 -0
  20. package/dist/chunks/{contract-pk603qj7.js → index-x69p7cv7.js} +12 -9
  21. package/dist/chunks/index-x69p7cv7.js.map +10 -0
  22. package/dist/client/index.js +6 -6
  23. package/dist/core/appearance.js +1 -1
  24. package/dist/core/config.js +7 -3
  25. package/dist/core/config.js.map +1 -1
  26. package/dist/core/contract.js +14 -6
  27. package/dist/core/contract.js.map +1 -1
  28. package/dist/core/format.js +1 -1
  29. package/dist/embed/index.js +12 -10
  30. package/dist/embed/index.js.map +4 -4
  31. package/dist/index.js +12 -0
  32. package/dist/index.js.map +9 -0
  33. package/dist/local.js +20 -30
  34. package/dist/local.js.map +7 -8
  35. package/dist/react/embed/index.js +1 -1
  36. package/dist/react/embed/index.js.map +2 -2
  37. package/dist/react/index.js +57 -19
  38. package/dist/react/index.js.map +4 -4
  39. package/dist/react/ui/index.js +836 -178
  40. package/dist/react/ui/index.js.map +15 -9
  41. package/dist/server.js +13 -26
  42. package/dist/server.js.map +6 -7
  43. package/dist/types/client/annotations.d.ts +4 -0
  44. package/dist/types/client/data-client.d.ts +1 -2
  45. package/dist/types/client/iframe.d.ts +4 -2
  46. package/dist/types/core/annotations.d.ts +2 -0
  47. package/dist/types/core/config.d.ts +48 -4
  48. package/dist/types/core/contract.d.ts +20 -12
  49. package/dist/types/core/dimension.d.ts +6 -4
  50. package/dist/types/core/filters.d.ts +44 -0
  51. package/dist/types/core/messages.d.ts +2 -0
  52. package/dist/types/core/operation-types.d.ts +5 -2
  53. package/dist/types/core/operation.d.ts +3 -4
  54. package/dist/types/core/queries.d.ts +16 -0
  55. package/dist/types/core/uuid.d.ts +2 -0
  56. package/dist/types/core/variables.d.ts +32 -13
  57. package/dist/types/embed/runtime-html.d.ts +2 -0
  58. package/dist/types/embed/source.d.ts +2 -1
  59. package/dist/types/index.d.ts +3 -0
  60. package/dist/types/react/annotations/AnnotationBar.d.ts +7 -1
  61. package/dist/types/react/annotations/AnnotationEditor.d.ts +2 -1
  62. package/dist/types/react/annotations/useDataAppAnnotations.d.ts +3 -0
  63. package/dist/types/react/app-context.d.ts +3 -0
  64. package/dist/types/react/index.d.ts +3 -3
  65. package/dist/types/react/mount.d.ts +6 -4
  66. package/dist/types/react/style-contract.d.ts +22 -2
  67. package/dist/types/react/ui/Button.d.ts +3 -3
  68. package/dist/types/react/ui/ChartLegend.d.ts +31 -0
  69. package/dist/types/react/ui/Checkbox.d.ts +15 -4
  70. package/dist/types/react/ui/CheckboxGroup.d.ts +7 -0
  71. package/dist/types/react/ui/{Combobox.d.ts → ChoicePicker.d.ts} +10 -15
  72. package/dist/types/react/ui/ComposedChart.d.ts +41 -0
  73. package/dist/types/react/ui/ComposedChartLegend.d.ts +8 -0
  74. package/dist/types/react/ui/DataAppFrame.d.ts +1 -2
  75. package/dist/types/react/ui/DimensionPicker.d.ts +1 -1
  76. package/dist/types/react/ui/FilterActions.d.ts +10 -0
  77. package/dist/types/react/ui/FilterBar.d.ts +3 -0
  78. package/dist/types/react/ui/GettingStarted.d.ts +2 -4
  79. package/dist/types/react/ui/Menu.d.ts +12 -0
  80. package/dist/types/react/ui/NumberField.d.ts +27 -0
  81. package/dist/types/react/ui/NumberFilterPicker.d.ts +9 -0
  82. package/dist/types/react/ui/PieChart.d.ts +5 -2
  83. package/dist/types/react/ui/RadioGroup.d.ts +18 -0
  84. package/dist/types/react/ui/SearchInput.d.ts +2 -2
  85. package/dist/types/react/ui/Select.d.ts +14 -0
  86. package/dist/types/react/ui/SelectionMark.d.ts +2 -1
  87. package/dist/types/react/ui/TooltipSurface.d.ts +3 -0
  88. package/dist/types/react/ui/chart-data.d.ts +1 -1
  89. package/dist/types/react/ui/chart-primitives.d.ts +20 -0
  90. package/dist/types/react/ui/icons.d.ts +1 -0
  91. package/dist/types/react/ui/index.d.ts +26 -2
  92. package/dist/types/react/ui/keyboard.d.ts +6 -0
  93. package/dist/types/react/ui/shortcuts.d.ts +7 -0
  94. package/dist/types/react/ui/useAppAppearance.d.ts +1 -1
  95. package/dist/types/react/ui/variables.d.ts +4 -2
  96. package/dist/types/react/view-controls.d.ts +3 -1
  97. package/dist/types/server/handler.d.ts +4 -4
  98. package/dist/worker.js +20 -737
  99. package/docs/app-authoring.md +15 -1
  100. package/docs/client.md +8 -8
  101. package/docs/contract.md +42 -20
  102. package/docs/data-context.md +8 -6
  103. package/docs/embed.md +10 -2
  104. package/docs/formatting-and-appearance.md +23 -7
  105. package/docs/hosted-apps.md +9 -2
  106. package/docs/layout.md +1 -1
  107. package/docs/react-embed.md +3 -2
  108. package/docs/react.md +4 -3
  109. package/docs/server-bun.md +1 -1
  110. package/docs/server.md +4 -4
  111. package/docs/styling.md +10 -3
  112. package/docs/ui.md +158 -3
  113. package/docs/variables.md +80 -7
  114. package/docs/views.md +4 -8
  115. package/docs/widgets.md +16 -13
  116. package/examples/starter-data-app/index.tsx +34 -32
  117. package/package.json +16 -11
  118. package/dist/chunks/contract-13j5zb3c.js.map +0 -13
  119. package/dist/chunks/contract-19ckn3n7.js.map +0 -10
  120. package/dist/chunks/contract-h8a6f559.js +0 -286
  121. package/dist/chunks/contract-h8a6f559.js.map +0 -12
  122. package/dist/chunks/contract-havnjmdr.js.map +0 -99
  123. package/dist/chunks/contract-pk603qj7.js.map +0 -10
  124. package/dist/chunks/contract-rfbakka4.js.map +0 -13
  125. package/dist/chunks/contract-tf8c3qpv.js.map +0 -11
  126. package/dist/chunks/contract-wz59z8pq.js +0 -8
  127. package/dist/chunks/contract-wz59z8pq.js.map +0 -10
  128. /package/dist/chunks/{contract-m6n8ctfc.js → index-m6n8ctfc.js} +0 -0
  129. /package/dist/chunks/{contract-m6n8ctfc.js.map → index-m6n8ctfc.js.map} +0 -0
  130. /package/dist/chunks/{contract-mev09s5v.js → index-mev09s5v.js} +0 -0
  131. /package/dist/chunks/{contract-mev09s5v.js.map → index-mev09s5v.js.map} +0 -0
package/dist/worker.js CHANGED
@@ -1,3 +1,23 @@
1
+ // src/embed/runtime-html.ts
2
+ var PAGE_CSP = "default-src 'none'; script-src 'unsafe-inline'; style-src 'unsafe-inline'; img-src data: blob:; connect-src 'none'; form-action 'none'; base-uri 'none'";
3
+ var inlineBootstrap = '(()=>{function q(){if(typeof crypto.randomUUID==="function")return crypto.randomUUID();let e=crypto.getRandomValues(new Uint8Array(16));e[6]=e[6]&15|64,e[8]=e[8]&63|128;let t=Array.from(e,(r)=>r.toString(16).padStart(2,"0"));return[t.slice(0,4),t.slice(4,6),t.slice(6,8),t.slice(8,10),t.slice(10)].map((r)=>r.join("")).join("-")}function X(e){if(!e||typeof e!=="object")return!1;let t=e;return(t.method==="log"||t.method==="info"||t.method==="warn"||t.method==="error")&&Array.isArray(t.args)&&t.args.length<=128}var U="altertable:data-app";var J=128,Z=60000;function M(e){return typeof e==="string"&&/^[a-zA-Z0-9_-]{1,128}$/.test(e)}function g({wire:e,from:t,session:r,parse:n}){return{wire:e,from:t,session:r,parse:n}}function j(e){if(!M(e.id))throw Error("Invalid request ID.");return e.id}function L(e,t){let r=e[t];if(typeof r!=="string")throw Error(`Invalid ${t}.`);return r}function A(){return{}}var m={channel:U,version:1,events:{connect:g({wire:"bridge:connect",from:"host",session:"none",parse:A}),ready:g({wire:"bridge:ready",from:"app",session:"none",parse:A}),initialize:g({wire:"bridge:initialize",from:"host",session:"establish",parse:(e)=>({state:e.state})}),request:g({wire:"bridge:request",from:"app",session:"current",parse:(e)=>{let t=L(e,"route");if(!t||t.length>256)throw Error("Invalid message route.");return{id:j(e),route:t,payload:e.payload}}}),result:g({wire:"bridge:result",from:"host",session:"current",parse:(e)=>{if(!Object.hasOwn(e,"response"))throw Error("Missing response.");return{id:j(e),response:e.response}}}),error:g({wire:"bridge:error",from:"host",session:"current",parse:(e)=>{if(e.requestId!==void 0&&typeof e.requestId!=="string")throw Error("Invalid requestId.");return{id:j(e),code:L(e,"code"),message:L(e,"message"),...e.requestId===void 0?{}:{requestId:e.requestId}}}}),cancel:g({wire:"bridge:cancel",from:"app",session:"current",parse:(e)=>({id:j(e)})}),disconnect:g({wire:"bridge:disconnect",from:"app",session:"current",parse:A}),scriptLoad:g({wire:"script:load",from:"host",session:"current",parse:(e)=>({javascript:L(e,"javascript")})}),stateUpdate:g({wire:"state:update",from:"host",session:"current",parse:(e)=>({state:e.state})}),runtimeLog:g({wire:"runtime:log",from:"app",session:"current",parse:(e)=>{if(!X(e.payload))throw Error("Invalid log entry.");return{payload:e.payload}}}),runtimeReady:g({wire:"runtime:ready",from:"app",session:"current",parse:A}),runtimeError:g({wire:"runtime:error",from:"app",session:"current",parse:A})}},_=new Map;for(let e of Object.keys(m.events)){let t=m.events[e].wire;if(_.has(t))throw Error(`Duplicate bridge event: ${t}`);_.set(t,e)}function C(e){return _.get(e)}function F(e){if(!e||typeof e!=="object")return;let t=e;if(t.channel!==U||t.version!==m.version||typeof t.type!=="string"||typeof t.documentId!=="string"||!t.documentId||t.documentId.length>128||t.sessionId!==void 0&&!M(t.sessionId)||t.token!==void 0&&typeof t.token!=="string")return;return t}function W(e,t){try{return{channel:U,version:m.version,documentId:e.documentId,...e.sessionId===void 0?{}:{sessionId:e.sessionId},...e.token===void 0?{}:{token:e.token},type:t.wire,...t.parse(e)}}catch{return}}function Y(e){let t=F(e);if(!t)return;let r=C(t.type);if(!r)return;let n=m.events[r];if(n.session!=="none"&&t.sessionId===void 0)return;return W(t,n)}function ee({role:e,origin:t,source:r,opaque:n,context:o,post:d,diagnostic:a,invalidRequest:u,handlers:l}){let c=!1;function p(b,R){if(c)throw Error("The bridge endpoint has closed.");let i=m.events[b],f=o(),k=Y({...R,channel:m.channel,version:m.version,type:i.wire,documentId:b==="connect"?"host":f.documentId,sessionId:f.sessionId,token:n?f.token:void 0});if(!k||n&&!M(f.token))throw Error("The bridge is not ready to send this event.");if(a?.("send",i.wire),c)return;d(k)}function v(b){let R=r();if(c||!R||b.origin!==t||b.source!==R)return;let i=F(b.data);if(!i)return;let f=o(),k=e==="app"&&i.type===m.events.connect.wire;if(n&&(k?!M(i.token):!f.token||i.token!==f.token))return;let B=C(i.type);if(!B)return;let x=m.events[B];if(x.from===e)return;if(x.session==="establish"){if(i.documentId!==f.documentId||i.sessionId===void 0)return}else if(x.session==="current"){if(!f.sessionId||i.sessionId!==f.sessionId||i.documentId!==f.documentId)return}let N=W(i,x);if(!N){if(e==="host"&&B==="request"&&M(i.id))u?.(i.id);return}if(a?.("receive",x.wire),c)return;let T=l[B];T(N)}return{send:p,receive:v,dispose(){c=!0}}}function ge(e){return e===null||typeof e==="string"||typeof e==="boolean"||typeof e==="number"&&Number.isFinite(e)}function V(e){return!!e&&typeof e==="object"&&!Array.isArray(e)&&Object.values(e).every(ge)}var te=Symbol.for("@altertable/data-app/MessageRoutingError");class h extends Error{code;requestId;[te]=!0;static[Symbol.hasInstance](e){return e instanceof Error&&e[te]===!0}constructor(e,t,r){super(t);this.code=e;this.requestId=r;this.name="MessageRoutingError"}}function me(e){return e}function re(e){return{operations:e,input(t){if(!t||typeof t!=="object")throw Error("Invalid query.");let r=t;if(typeof r.operation!=="string"||!r.operation||r.operation.length>256||r.operation.includes("/"))throw Error("Invalid operation.");let n=e&&Object.hasOwn(e,r.operation)?e[r.operation]:void 0;if(e&&!n)throw Error("Unknown operation.");return{operation:r.operation,input:n?n.input(r.input):r.input}},output(t,r){if(!t||typeof t!=="object")throw Error("Invalid data response.");let n=t;if(!Number.isInteger(n.status)||n.status<100||n.status>599||!n.body||typeof n.body!=="object"||Array.isArray(n.body))throw Error("Invalid data response.");let o=n.body;if(n.status<200||n.status>=300){let a=o.error;throw new h(typeof a?.code==="string"?a.code:"request_failed",typeof a?.message==="string"?a.message:"Could not load data.",typeof a?.requestId==="string"?a.requestId:void 0)}if(!("data"in o)||typeof o.requestId!=="string"||typeof o.queriedAt!=="string"||!Array.isArray(o.queryIds)||!o.queryIds.every((a)=>typeof a==="string"))throw Error("Invalid data envelope.");if(o.queries!==void 0&&(!Array.isArray(o.queries)||!o.queries.every((a)=>a&&typeof a==="object"&&typeof a.name==="string"&&typeof a.statement==="string"&&(a.params===void 0||V(a.params))&&(a.queryId===void 0||typeof a.queryId==="string"))))throw Error("Invalid query evidence.");let d=e?.[r.operation];return{status:n.status,body:{...o,data:d?d.output(o.data):o.data}}}}}var ne=me({input(e){if(!e||typeof e!=="object")throw Error("Invalid SQL query.");let t=e;if(typeof t.statement!=="string"||!t.statement.trim()||typeof t.limit!=="number"||!Number.isSafeInteger(t.limit)||t.limit<1||t.params!==void 0&&!V(t.params))throw Error("Invalid SQL query.");return{statement:t.statement,limit:t.limit,...t.params===void 0?{}:{params:t.params}}},output(e,t){if(!e||typeof e!=="object")throw Error("Invalid query result.");let r=e;if(!Array.isArray(r.columns)||!r.columns.every((n)=>n&&typeof n.name==="string"&&(n.type===void 0||typeof n.type==="string"))||!Array.isArray(r.rows)||r.rows.length>t.limit||!r.rows.every((n)=>Array.isArray(n)&&n.length===r.columns.length)||r.queryId!==void 0&&typeof r.queryId!=="string")throw Error("Invalid query result.");return{columns:r.columns,rows:r.rows,...r.queryId===void 0?{}:{queryId:r.queryId}}}});function oe(e,t){return{async request(r,n,{signal:o}={}){if(o?.throwIfAborted(),!Object.hasOwn(e,r))throw new h("unknown_route","Unknown message route.");let d=e[r],a;try{a=d.input(n)}catch{throw new h("invalid_payload","Invalid message payload.")}let u=await t({route:r,payload:a},o);o?.throwIfAborted();try{return d.output(u,a)}catch(l){if(l instanceof h)throw l;throw new h("invalid_response","Invalid message response.")}}}}var se=Symbol.for("@altertable/data-app/DataAppError");class E extends Error{code;requestId;[se]=!0;static[Symbol.hasInstance](e){return e instanceof Error&&e[se]===!0}constructor(e,t,r){super(e);this.code=t;this.requestId=r;this.name="DataAppError"}}function ae(e,t){function r(o){if(o.length===1&&typeof o[0]==="function"){let d=o[0]();return Array.isArray(d)?d:[d]}return o.map((d)=>typeof d==="function"?d():d)}function n(o,d){if(!e())return;try{t({method:o,args:r(d)})}catch{}}return{log:(...o)=>n("log",o),info:(...o)=>n("info",o),warn:(...o)=>n("warn",o),error:(...o)=>n("error",o)}}function ie(e,t){if(t.type==="runtime:log")return;e.log(()=>{let r={type:t.type};if("id"in t)r.id=t.id;if(t.type==="bridge:request"){r.route=t.route;let n=t.payload;if(t.route==="data:query"&&n&&typeof n==="object"&&"operation"in n&&typeof n.operation==="string")r.operation=n.operation}return["Sending message to parent",r]})}function de(e){if(e instanceof h)throw new E(e.message,e.code,e.requestId);throw e}function ue({parentOrigin:e,window:t=window,timeoutMs:r=Z,mode:n="url",loadScript:o}){if(new URL(e).origin!==e)throw Error("Expected an exact parent origin.");let d=q(),a,u,l=!1,c=new Map,p,v=new Set,b=ae(()=>!l&&!!u&&!!p&&typeof p==="object"&&("logging"in p)&&p.logging===!0,(s)=>i("runtimeLog",{payload:s})),R=ee({role:"app",origin:e,source:()=>t.parent,opaque:n==="bundle",context:()=>({documentId:d,sessionId:u,token:a}),post(s){t.parent.postMessage(s,e),ie(b,s)},handlers:{connect(s){if(n==="bundle")a=s.token;i("ready",{})},initialize(s){if(u&&u!==s.sessionId)for(let I of c.values())I.reject(new E("The preview reconnected. Retry the request.","bridge_reset"));let y=!u;if(u=s.sessionId,k(s.state),y)for(let I of c.values())I.start();if(l)return;if(n==="url")i("runtimeReady",{})},stateUpdate(s){k(s.state)},scriptLoad(s){if(n==="bundle")o?.(s.javascript)},result(s){c.get(s.id)?.resolve(s.response)},error(s){c.get(s.id)?.reject(new h(s.code,s.message,s.requestId))}}}),{send:i,receive:f}=R;function k(s){p=s;for(let y of v)y(s)}t.addEventListener("message",f);function B(s,y){return new Promise((I,w)=>{if(l)return w(new E("The preview has closed.","bridge_closed"));if(y?.aborted)return w(y.reason);if(c.size>=J)return w(new E("Too many pending data requests.","bridge_busy"));let O=q(),Q=!1;function P(){clearTimeout(ye),y?.removeEventListener("abort",G),c.delete(O)}function G(){if(Q)i("cancel",{id:O});P(),w(y?.reason)}let ye=setTimeout(()=>{if(Q)i("cancel",{id:O});P(),w(new E(u?"The data request timed out.":"The preview shell is unavailable. Reload the preview.",u?"timeout":"bridge_unavailable"))},r),K={start(){if(Q)return;try{i("request",{id:O,route:s.route,payload:s.payload}),Q=!0}catch{P(),w(new E("The message payload could not be sent.","invalid_payload"))}},resolve(S){P(),I(S)},reject(S){P(),w(S)}};if(c.set(O,K),y?.addEventListener("abort",G,{once:!0}),u)K.start();else if(n==="url"||a)i("ready",{})})}let x=oe({"data:query":re(),"data:sql":ne},B);function N(s,y,I){return x.request("data:query",{operation:s,input:y},{signal:I}).catch(de)}function T(){if(u)i("disconnect",{});u=void 0;for(let s of c.values())s.reject(new E("The preview has closed.","bridge_closed"))}function H(s){if(s.persisted&&(n==="url"||a))i("ready",{})}function fe(){if(l)return;T(),l=!0,R.dispose(),t.removeEventListener("message",f),t.removeEventListener("pagehide",T),t.removeEventListener("pageshow",H),v.clear()}if(t.addEventListener("pagehide",T),t.addEventListener("pageshow",H),n==="url")i("ready",{});return{logger:b,request:B,transport:N,lakehouse:{queryAll(s,{limit:y,signal:I,params:w}){return x.request("data:sql",{statement:s,limit:y,...w===void 0?{}:{params:w}},{signal:I}).catch(de)}},dispose:fe,mode:n,snapshot(){return p},subscribe(s){return v.add(s),()=>{v.delete(s)}},ready(){if(!l&&u)i("runtimeReady",{})},fail(){if(!l&&u)i("runtimeError",{})}}}var z=Symbol.for("altertable.localFrameBridge"),D=Symbol.for("altertable.installedTransport");function pe(e,t=window){let r=t;if(r[D])throw Error("A data app transport is already installed.");return r[z]=e,r[D]=e,()=>{if(r[z]===e)delete r[z];if(r[D]===e)delete r[D];e.dispose()}}function ce({parentOrigin:e,window:t=window}){let r,n=!1,o=`altertable-data-app-${q()}.js`,d=ue({parentOrigin:e,window:t,mode:"bundle",loadScript(p){if(r!==void 0){if(p===r)if(n)d.fail();else d.ready();else d.fail();return}r=p;try{let v=t.document.createElement("script");if(v.textContent=`${p}\n//# sourceURL=${o}`,t.document.body.append(v),!n)d.ready()}catch{a()}}});function a(){n=!0,d.fail()}function u(p){if(p.filename===o)a()}function l(p){if(p.reason instanceof Error&&p.reason.stack?.includes(o))a()}t.addEventListener("error",u),t.addEventListener("unhandledrejection",l);let c=pe(d,t);return()=>{t.removeEventListener("error",u),t.removeEventListener("unhandledrejection",l),c()}}var le=document.currentScript?.dataset.parentOrigin;if(!le)throw Error("Missing trusted parent origin.");ce({parentOrigin:le});})();\n'.replace(/<\/script/gi, (match) => `<\\${match.slice(1)}`);
4
+ function runtimeHtml(parentOrigin) {
5
+ const attribute = parentOrigin.replaceAll("&", "&amp;").replaceAll('"', "&quot;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll("'", "&#39;");
6
+ return `<!doctype html>
7
+ <html>
8
+ <head>
9
+ <meta charset="utf-8">
10
+ <meta name="viewport" content="width=device-width,initial-scale=1">
11
+ <meta http-equiv="Content-Security-Policy" content="${PAGE_CSP}">
12
+ </head>
13
+ <body>
14
+ <div id="root"></div>
15
+ <script data-parent-origin="${attribute}">${inlineBootstrap}</script>
16
+ </body>
17
+ </html>
18
+ `;
19
+ }
20
+
1
21
  // src/worker/trusted-parent.ts
2
22
  function exactOrigin(value) {
3
23
  const url = new URL(value);
@@ -46,743 +66,6 @@ function trustedParent(config, searchParams) {
46
66
 
47
67
  // src/worker/index.ts
48
68
  var TOKEN_RE = /^(?=.{1,63}$)[a-z0-9]+(?:-[a-z0-9]+)+-app-[1-9][0-9]*$/;
49
- var PAGE_CSP = "default-src 'none'; script-src 'unsafe-inline'; style-src 'unsafe-inline'; img-src data: blob:; connect-src 'none'; form-action 'none'; base-uri 'none'";
50
- var inlineBootstrap = `(() => {
51
- // src/core/logger.ts
52
- function isLogEntry(value) {
53
- if (!value || typeof value !== "object")
54
- return false;
55
- const entry = value;
56
- return (entry.method === "log" || entry.method === "info" || entry.method === "warn" || entry.method === "error") && Array.isArray(entry.args) && entry.args.length <= 128;
57
- }
58
-
59
- // src/core/bridge.ts
60
- var BRIDGE = "altertable:data-app";
61
- var MAX_PENDING = 128;
62
- var REQUEST_TIMEOUT_MS = 60000;
63
- function validId(value) {
64
- return typeof value === "string" && /^[a-zA-Z0-9_-]{1,128}$/.test(value);
65
- }
66
- function event({
67
- wire,
68
- from,
69
- session,
70
- parse
71
- }) {
72
- return { wire, from, session, parse };
73
- }
74
- function id(fields) {
75
- if (!validId(fields.id))
76
- throw new Error("Invalid request ID.");
77
- return fields.id;
78
- }
79
- function string(fields, key) {
80
- const value = fields[key];
81
- if (typeof value !== "string")
82
- throw new Error(\`Invalid \${key}.\`);
83
- return value;
84
- }
85
- function empty() {
86
- return {};
87
- }
88
- var bridgeProtocol = {
89
- channel: BRIDGE,
90
- version: 1,
91
- events: {
92
- connect: event({
93
- wire: "bridge:connect",
94
- from: "host",
95
- session: "none",
96
- parse: empty
97
- }),
98
- ready: event({
99
- wire: "bridge:ready",
100
- from: "app",
101
- session: "none",
102
- parse: empty
103
- }),
104
- initialize: event({
105
- wire: "bridge:initialize",
106
- from: "host",
107
- session: "establish",
108
- parse: (fields) => ({ state: fields.state })
109
- }),
110
- request: event({
111
- wire: "bridge:request",
112
- from: "app",
113
- session: "current",
114
- parse: (fields) => {
115
- const route = string(fields, "route");
116
- if (!route || route.length > 256)
117
- throw new Error("Invalid message route.");
118
- return { id: id(fields), route, payload: fields.payload };
119
- }
120
- }),
121
- result: event({
122
- wire: "bridge:result",
123
- from: "host",
124
- session: "current",
125
- parse: (fields) => {
126
- if (!Object.hasOwn(fields, "response"))
127
- throw new Error("Missing response.");
128
- return { id: id(fields), response: fields.response };
129
- }
130
- }),
131
- error: event({
132
- wire: "bridge:error",
133
- from: "host",
134
- session: "current",
135
- parse: (fields) => {
136
- if (fields.requestId !== undefined && typeof fields.requestId !== "string")
137
- throw new Error("Invalid requestId.");
138
- return {
139
- id: id(fields),
140
- code: string(fields, "code"),
141
- message: string(fields, "message"),
142
- ...fields.requestId === undefined ? {} : { requestId: fields.requestId }
143
- };
144
- }
145
- }),
146
- cancel: event({
147
- wire: "bridge:cancel",
148
- from: "app",
149
- session: "current",
150
- parse: (fields) => ({ id: id(fields) })
151
- }),
152
- disconnect: event({
153
- wire: "bridge:disconnect",
154
- from: "app",
155
- session: "current",
156
- parse: empty
157
- }),
158
- scriptLoad: event({
159
- wire: "script:load",
160
- from: "host",
161
- session: "current",
162
- parse: (fields) => ({ javascript: string(fields, "javascript") })
163
- }),
164
- stateUpdate: event({
165
- wire: "state:update",
166
- from: "host",
167
- session: "current",
168
- parse: (fields) => ({ state: fields.state })
169
- }),
170
- runtimeLog: event({
171
- wire: "runtime:log",
172
- from: "app",
173
- session: "current",
174
- parse: (fields) => {
175
- if (!isLogEntry(fields.payload))
176
- throw new Error("Invalid log entry.");
177
- return { payload: fields.payload };
178
- }
179
- }),
180
- runtimeReady: event({
181
- wire: "runtime:ready",
182
- from: "app",
183
- session: "current",
184
- parse: empty
185
- }),
186
- runtimeError: event({
187
- wire: "runtime:error",
188
- from: "app",
189
- session: "current",
190
- parse: empty
191
- })
192
- }
193
- };
194
- var byWire = new Map;
195
- for (const name of Object.keys(bridgeProtocol.events)) {
196
- const wire = bridgeProtocol.events[name].wire;
197
- if (byWire.has(wire))
198
- throw new Error(\`Duplicate bridge event: \${wire}\`);
199
- byWire.set(wire, name);
200
- }
201
- function bridgeEventName(wire) {
202
- return byWire.get(wire);
203
- }
204
- function parseBridgeEnvelope(value) {
205
- if (!value || typeof value !== "object")
206
- return;
207
- const fields = value;
208
- if (fields.channel !== BRIDGE || fields.version !== bridgeProtocol.version || typeof fields.type !== "string" || typeof fields.documentId !== "string" || !fields.documentId || fields.documentId.length > 128 || fields.sessionId !== undefined && !validId(fields.sessionId) || fields.token !== undefined && typeof fields.token !== "string")
209
- return;
210
- return fields;
211
- }
212
- function parseBridgePayload(envelope, definition) {
213
- try {
214
- return {
215
- channel: BRIDGE,
216
- version: bridgeProtocol.version,
217
- documentId: envelope.documentId,
218
- ...envelope.sessionId === undefined ? {} : { sessionId: envelope.sessionId },
219
- ...envelope.token === undefined ? {} : { token: envelope.token },
220
- type: definition.wire,
221
- ...definition.parse(envelope)
222
- };
223
- } catch {
224
- return;
225
- }
226
- }
227
- function parseBridgeMessage(value) {
228
- const envelope = parseBridgeEnvelope(value);
229
- if (!envelope)
230
- return;
231
- const name = bridgeEventName(envelope.type);
232
- if (!name)
233
- return;
234
- const definition = bridgeProtocol.events[name];
235
- if (definition.session !== "none" && envelope.sessionId === undefined)
236
- return;
237
- return parseBridgePayload(envelope, definition);
238
- }
239
-
240
- // src/core/bridge-endpoint.ts
241
- function createBridgeEndpoint({
242
- role,
243
- origin,
244
- source,
245
- opaque,
246
- context,
247
- post,
248
- diagnostic,
249
- invalidRequest,
250
- handlers
251
- }) {
252
- let disposed = false;
253
- function send(name, payload) {
254
- if (disposed)
255
- throw new Error("The bridge endpoint has closed.");
256
- const definition = bridgeProtocol.events[name];
257
- const current = context();
258
- const message = parseBridgeMessage({
259
- ...payload,
260
- channel: bridgeProtocol.channel,
261
- version: bridgeProtocol.version,
262
- type: definition.wire,
263
- documentId: name === "connect" ? "host" : current.documentId,
264
- sessionId: current.sessionId,
265
- token: opaque ? current.token : undefined
266
- });
267
- if (!message || opaque && !validId(current.token))
268
- throw new Error("The bridge is not ready to send this event.");
269
- diagnostic?.("send", definition.wire);
270
- if (disposed)
271
- return;
272
- post(message);
273
- }
274
- function receive(event) {
275
- const peer = source();
276
- if (disposed || !peer || event.origin !== origin || event.source !== peer)
277
- return;
278
- const envelope = parseBridgeEnvelope(event.data);
279
- if (!envelope)
280
- return;
281
- const current = context();
282
- const connecting = role === "app" && envelope.type === bridgeProtocol.events.connect.wire;
283
- if (opaque && (connecting ? !validId(envelope.token) : !current.token || envelope.token !== current.token))
284
- return;
285
- const name = bridgeEventName(envelope.type);
286
- if (!name)
287
- return;
288
- const definition = bridgeProtocol.events[name];
289
- if (definition.from === role)
290
- return;
291
- if (definition.session === "establish") {
292
- if (envelope.documentId !== current.documentId || envelope.sessionId === undefined)
293
- return;
294
- } else if (definition.session === "current") {
295
- if (!current.sessionId || envelope.sessionId !== current.sessionId || envelope.documentId !== current.documentId)
296
- return;
297
- }
298
- const message = parseBridgePayload(envelope, definition);
299
- if (!message) {
300
- if (role === "host" && name === "request" && validId(envelope.id))
301
- invalidRequest?.(envelope.id);
302
- return;
303
- }
304
- diagnostic?.("receive", definition.wire);
305
- if (disposed)
306
- return;
307
- const handler = handlers[name];
308
- handler(message);
309
- }
310
- return {
311
- send,
312
- receive,
313
- dispose() {
314
- disposed = true;
315
- }
316
- };
317
- }
318
-
319
- // src/core/messages.ts
320
- var errorBrand = Symbol.for("@altertable/data-app/MessageRoutingError");
321
-
322
- class MessageRoutingError extends Error {
323
- code;
324
- requestId;
325
- [errorBrand] = true;
326
- static [Symbol.hasInstance](value) {
327
- return value instanceof Error && value[errorBrand] === true;
328
- }
329
- constructor(code, message, requestId) {
330
- super(message);
331
- this.code = code;
332
- this.requestId = requestId;
333
- this.name = "MessageRoutingError";
334
- }
335
- }
336
- function defineMessageRoute(route) {
337
- return route;
338
- }
339
- function defineDataQueryRoute(operations) {
340
- return {
341
- operations,
342
- input(value) {
343
- if (!value || typeof value !== "object")
344
- throw new Error("Invalid query.");
345
- const request = value;
346
- if (typeof request.operation !== "string" || !request.operation || request.operation.length > 256 || request.operation.includes("/"))
347
- throw new Error("Invalid operation.");
348
- const operation = operations && Object.hasOwn(operations, request.operation) ? operations[request.operation] : undefined;
349
- if (operations && !operation)
350
- throw new Error("Unknown operation.");
351
- return {
352
- operation: request.operation,
353
- input: operation ? operation.input(request.input) : request.input
354
- };
355
- },
356
- output(value, input) {
357
- if (!value || typeof value !== "object")
358
- throw new Error("Invalid data response.");
359
- const response = value;
360
- if (!Number.isInteger(response.status) || response.status < 100 || response.status > 599 || !response.body || typeof response.body !== "object" || Array.isArray(response.body))
361
- throw new Error("Invalid data response.");
362
- const body = response.body;
363
- if (response.status < 200 || response.status >= 300) {
364
- const failure = body.error;
365
- throw new MessageRoutingError(typeof failure?.code === "string" ? failure.code : "request_failed", typeof failure?.message === "string" ? failure.message : "Could not load data.", typeof failure?.requestId === "string" ? failure.requestId : undefined);
366
- }
367
- if (!("data" in body) || typeof body.requestId !== "string" || typeof body.queriedAt !== "string" || !Array.isArray(body.queryIds) || !body.queryIds.every((id) => typeof id === "string"))
368
- throw new Error("Invalid data envelope.");
369
- if (body.queries !== undefined && (!Array.isArray(body.queries) || !body.queries.every((query) => query && typeof query === "object" && typeof query.name === "string" && typeof query.statement === "string" && (query.queryId === undefined || typeof query.queryId === "string"))))
370
- throw new Error("Invalid query evidence.");
371
- const operation = operations?.[input.operation];
372
- return {
373
- status: response.status,
374
- body: {
375
- ...body,
376
- data: operation ? operation.output(body.data) : body.data
377
- }
378
- };
379
- }
380
- };
381
- }
382
- var sqlQueryRoute = defineMessageRoute({
383
- input(value) {
384
- if (!value || typeof value !== "object")
385
- throw new Error("Invalid SQL query.");
386
- const query = value;
387
- if (typeof query.statement !== "string" || !query.statement.trim() || typeof query.limit !== "number" || !Number.isSafeInteger(query.limit) || query.limit < 1)
388
- throw new Error("Invalid SQL query.");
389
- return { statement: query.statement, limit: query.limit };
390
- },
391
- output(value, input) {
392
- if (!value || typeof value !== "object")
393
- throw new Error("Invalid query result.");
394
- const result = value;
395
- if (!Array.isArray(result.columns) || !result.columns.every((column) => column && typeof column.name === "string" && (column.type === undefined || typeof column.type === "string")) || !Array.isArray(result.rows) || result.rows.length > input.limit || !result.rows.every((row) => Array.isArray(row) && row.length === result.columns.length) || result.queryId !== undefined && typeof result.queryId !== "string")
396
- throw new Error("Invalid query result.");
397
- return {
398
- columns: result.columns,
399
- rows: result.rows,
400
- ...result.queryId === undefined ? {} : { queryId: result.queryId }
401
- };
402
- }
403
- });
404
-
405
- // src/client/messages.ts
406
- function createMessageClient(routes, transport) {
407
- return {
408
- async request(route, payload, { signal } = {}) {
409
- signal?.throwIfAborted();
410
- if (!Object.hasOwn(routes, route))
411
- throw new MessageRoutingError("unknown_route", "Unknown message route.");
412
- const contract = routes[route];
413
- let input;
414
- try {
415
- input = contract.input(payload);
416
- } catch {
417
- throw new MessageRoutingError("invalid_payload", "Invalid message payload.");
418
- }
419
- const response = await transport({ route, payload: input }, signal);
420
- signal?.throwIfAborted();
421
- try {
422
- return contract.output(response, input);
423
- } catch (error) {
424
- if (error instanceof MessageRoutingError)
425
- throw error;
426
- throw new MessageRoutingError("invalid_response", "Invalid message response.");
427
- }
428
- }
429
- };
430
- }
431
-
432
- // src/client/transport.ts
433
- var errorBrand2 = Symbol.for("@altertable/data-app/DataAppError");
434
-
435
- class DataAppError extends Error {
436
- code;
437
- requestId;
438
- [errorBrand2] = true;
439
- static [Symbol.hasInstance](value) {
440
- return value instanceof Error && value[errorBrand2] === true;
441
- }
442
- constructor(message, code, requestId) {
443
- super(message);
444
- this.code = code;
445
- this.requestId = requestId;
446
- this.name = "DataAppError";
447
- }
448
- }
449
-
450
- // src/client/logger.ts
451
- function createBridgeLogger(enabled, send) {
452
- function resolve(args) {
453
- if (args.length === 1 && typeof args[0] === "function") {
454
- const value = args[0]();
455
- return Array.isArray(value) ? value : [value];
456
- }
457
- return args.map((arg) => typeof arg === "function" ? arg() : arg);
458
- }
459
- function write(method, args) {
460
- if (!enabled())
461
- return;
462
- try {
463
- send({ method, args: resolve(args) });
464
- } catch {}
465
- }
466
- return {
467
- log: (...args) => write("log", args),
468
- info: (...args) => write("info", args),
469
- warn: (...args) => write("warn", args),
470
- error: (...args) => write("error", args)
471
- };
472
- }
473
- function logBridgeMessage(logger, message) {
474
- if (message.type === "runtime:log")
475
- return;
476
- logger.log(() => {
477
- const metadata = { type: message.type };
478
- if ("id" in message)
479
- metadata.id = message.id;
480
- if (message.type === "bridge:request") {
481
- metadata.route = message.route;
482
- const payload = message.payload;
483
- if (message.route === "data:query" && payload && typeof payload === "object" && "operation" in payload && typeof payload.operation === "string")
484
- metadata.operation = payload.operation;
485
- }
486
- return ["Sending message to parent", metadata];
487
- });
488
- }
489
-
490
- // src/client/iframe.ts
491
- function rethrowDataMessageError(error) {
492
- if (error instanceof MessageRoutingError)
493
- throw new DataAppError(error.message, error.code, error.requestId);
494
- throw error;
495
- }
496
- function createIframeTransport({
497
- parentOrigin,
498
- window: frame = window,
499
- timeoutMs = REQUEST_TIMEOUT_MS,
500
- mode = "url",
501
- loadScript
502
- }) {
503
- if (new URL(parentOrigin).origin !== parentOrigin)
504
- throw new Error("Expected an exact parent origin.");
505
- const documentId = crypto.randomUUID();
506
- let token;
507
- let sessionId;
508
- let disposed = false;
509
- const pending = new Map;
510
- let hostState;
511
- const stateListeners = new Set;
512
- const logger = createBridgeLogger(() => !disposed && !!sessionId && !!hostState && typeof hostState === "object" && ("logging" in hostState) && hostState.logging === true, (entry) => send("runtimeLog", { payload: entry }));
513
- const endpoint = createBridgeEndpoint({
514
- role: "app",
515
- origin: parentOrigin,
516
- source: () => frame.parent,
517
- opaque: mode === "bundle",
518
- context: () => ({ documentId, sessionId, token }),
519
- post(message) {
520
- frame.parent.postMessage(message, parentOrigin);
521
- logBridgeMessage(logger, message);
522
- },
523
- handlers: {
524
- connect(message) {
525
- if (mode === "bundle")
526
- token = message.token;
527
- send("ready", {});
528
- },
529
- initialize(message) {
530
- if (sessionId && sessionId !== message.sessionId) {
531
- for (const entry of pending.values())
532
- entry.reject(new DataAppError("The preview reconnected. Retry the request.", "bridge_reset"));
533
- }
534
- const first = !sessionId;
535
- sessionId = message.sessionId;
536
- receiveState(message.state);
537
- if (first)
538
- for (const entry of pending.values())
539
- entry.start();
540
- if (disposed)
541
- return;
542
- if (mode === "url")
543
- send("runtimeReady", {});
544
- },
545
- stateUpdate(message) {
546
- receiveState(message.state);
547
- },
548
- scriptLoad(message) {
549
- if (mode === "bundle")
550
- loadScript?.(message.javascript);
551
- },
552
- result(message) {
553
- pending.get(message.id)?.resolve(message.response);
554
- },
555
- error(message) {
556
- pending.get(message.id)?.reject(new MessageRoutingError(message.code, message.message, message.requestId));
557
- }
558
- }
559
- });
560
- const send = endpoint.send;
561
- const receive = endpoint.receive;
562
- function receiveState(state) {
563
- hostState = state;
564
- for (const listener of stateListeners)
565
- listener(state);
566
- }
567
- frame.addEventListener("message", receive);
568
- function requestMessage(message, signal) {
569
- return new Promise((resolve, reject) => {
570
- if (disposed)
571
- return reject(new DataAppError("The preview has closed.", "bridge_closed"));
572
- if (signal?.aborted)
573
- return reject(signal.reason);
574
- if (pending.size >= MAX_PENDING)
575
- return reject(new DataAppError("Too many pending data requests.", "bridge_busy"));
576
- const id = crypto.randomUUID();
577
- let sent = false;
578
- function cleanup() {
579
- clearTimeout(timer);
580
- signal?.removeEventListener("abort", abort);
581
- pending.delete(id);
582
- }
583
- function abort() {
584
- if (sent)
585
- send("cancel", { id });
586
- cleanup();
587
- reject(signal?.reason);
588
- }
589
- const timer = setTimeout(() => {
590
- if (sent)
591
- send("cancel", { id });
592
- cleanup();
593
- reject(new DataAppError(sessionId ? "The data request timed out." : "The preview shell is unavailable. Reload the preview.", sessionId ? "timeout" : "bridge_unavailable"));
594
- }, timeoutMs);
595
- const entry = {
596
- start() {
597
- if (sent)
598
- return;
599
- try {
600
- send("request", {
601
- id,
602
- route: message.route,
603
- payload: message.payload
604
- });
605
- sent = true;
606
- } catch {
607
- cleanup();
608
- reject(new DataAppError("The message payload could not be sent.", "invalid_payload"));
609
- }
610
- },
611
- resolve(value) {
612
- cleanup();
613
- resolve(value);
614
- },
615
- reject(error) {
616
- cleanup();
617
- reject(error);
618
- }
619
- };
620
- pending.set(id, entry);
621
- signal?.addEventListener("abort", abort, { once: true });
622
- if (sessionId)
623
- entry.start();
624
- else if (mode === "url" || token)
625
- send("ready", {});
626
- });
627
- }
628
- const messages = createMessageClient({ "data:query": defineDataQueryRoute(), "data:sql": sqlQueryRoute }, requestMessage);
629
- function queryOperation(operation, input, signal) {
630
- return messages.request("data:query", { operation, input }, { signal }).catch(rethrowDataMessageError);
631
- }
632
- function disconnect() {
633
- if (sessionId)
634
- send("disconnect", {});
635
- sessionId = undefined;
636
- for (const entry of pending.values())
637
- entry.reject(new DataAppError("The preview has closed.", "bridge_closed"));
638
- }
639
- function resume(event) {
640
- if (event.persisted && (mode === "url" || token))
641
- send("ready", {});
642
- }
643
- function dispose() {
644
- if (disposed)
645
- return;
646
- disconnect();
647
- disposed = true;
648
- endpoint.dispose();
649
- frame.removeEventListener("message", receive);
650
- frame.removeEventListener("pagehide", disconnect);
651
- frame.removeEventListener("pageshow", resume);
652
- stateListeners.clear();
653
- }
654
- frame.addEventListener("pagehide", disconnect);
655
- frame.addEventListener("pageshow", resume);
656
- if (mode === "url")
657
- send("ready", {});
658
- return {
659
- logger,
660
- request: requestMessage,
661
- transport: queryOperation,
662
- lakehouse: {
663
- queryAll(statement, { limit, signal }) {
664
- return messages.request("data:sql", { statement, limit }, { signal }).catch(rethrowDataMessageError);
665
- }
666
- },
667
- dispose,
668
- mode,
669
- snapshot() {
670
- return hostState;
671
- },
672
- subscribe(listener) {
673
- stateListeners.add(listener);
674
- return () => {
675
- stateListeners.delete(listener);
676
- };
677
- },
678
- ready() {
679
- if (!disposed && sessionId)
680
- send("runtimeReady", {});
681
- },
682
- fail() {
683
- if (!disposed && sessionId)
684
- send("runtimeError", {});
685
- }
686
- };
687
- }
688
- var bridgeKey = Symbol.for("altertable.localFrameBridge");
689
- var installedKey = Symbol.for("altertable.installedTransport");
690
- function installDataAppTransport(bridge, frame = window) {
691
- const target = frame;
692
- if (target[installedKey])
693
- throw new Error("A data app transport is already installed.");
694
- target[bridgeKey] = bridge;
695
- target[installedKey] = bridge;
696
- return () => {
697
- if (target[bridgeKey] === bridge)
698
- delete target[bridgeKey];
699
- if (target[installedKey] === bridge)
700
- delete target[installedKey];
701
- bridge.dispose();
702
- };
703
- }
704
-
705
- // src/embed/bootstrap.ts
706
- function startDataAppBootstrap({
707
- parentOrigin,
708
- window: frame = window
709
- }) {
710
- let loaded;
711
- let failed = false;
712
- const bundleSource = \`altertable-data-app-\${crypto.randomUUID()}.js\`;
713
- const bridge = createIframeTransport({
714
- parentOrigin,
715
- window: frame,
716
- mode: "bundle",
717
- loadScript(javascript) {
718
- if (loaded !== undefined) {
719
- if (javascript === loaded) {
720
- if (failed)
721
- bridge.fail();
722
- else
723
- bridge.ready();
724
- } else
725
- bridge.fail();
726
- return;
727
- }
728
- loaded = javascript;
729
- try {
730
- const script = frame.document.createElement("script");
731
- script.textContent = \`\${javascript}
732
- //# sourceURL=\${bundleSource}\`;
733
- frame.document.body.append(script);
734
- if (!failed)
735
- bridge.ready();
736
- } catch {
737
- reportError();
738
- }
739
- }
740
- });
741
- function reportError() {
742
- failed = true;
743
- bridge.fail();
744
- }
745
- function reportBundleError(event) {
746
- if (event.filename === bundleSource)
747
- reportError();
748
- }
749
- function reportBundleRejection(event) {
750
- if (event.reason instanceof Error && event.reason.stack?.includes(bundleSource))
751
- reportError();
752
- }
753
- frame.addEventListener("error", reportBundleError);
754
- frame.addEventListener("unhandledrejection", reportBundleRejection);
755
- const uninstall = installDataAppTransport(bridge, frame);
756
- return () => {
757
- frame.removeEventListener("error", reportBundleError);
758
- frame.removeEventListener("unhandledrejection", reportBundleRejection);
759
- uninstall();
760
- };
761
- }
762
-
763
- // src/embed/standalone.ts
764
- var parentOrigin = document.currentScript?.dataset.parentOrigin;
765
- if (!parentOrigin)
766
- throw new Error("Missing trusted parent origin.");
767
- startDataAppBootstrap({ parentOrigin });
768
- })();
769
- `.replace(/<\/script/gi, (match) => `<\\${match.slice(1)}`);
770
- function runtimeHtml(parentOrigin) {
771
- const attribute = parentOrigin.replaceAll("&", "&amp;").replaceAll('"', "&quot;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll("'", "&#39;");
772
- return `<!doctype html>
773
- <html>
774
- <head>
775
- <meta charset="utf-8">
776
- <meta name="viewport" content="width=device-width,initial-scale=1">
777
- <meta http-equiv="Content-Security-Policy" content="${PAGE_CSP}">
778
- </head>
779
- <body>
780
- <div id="root"></div>
781
- <script data-parent-origin="${attribute}">${inlineBootstrap}</script>
782
- </body>
783
- </html>
784
- `;
785
- }
786
69
  function isPreviewHost(hostname, domainName) {
787
70
  const suffix = `.${domainName}`;
788
71
  return hostname.endsWith(suffix) && TOKEN_RE.test(hostname.slice(0, -suffix.length));