@vielzeug/sandbox 2.0.0 → 2.1.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 (46) hide show
  1. package/dist/_document.cjs +3 -3
  2. package/dist/_document.cjs.map +1 -1
  3. package/dist/_document.d.ts +2 -2
  4. package/dist/_document.d.ts.map +1 -1
  5. package/dist/_document.js +9 -12
  6. package/dist/_document.js.map +1 -1
  7. package/dist/_policy.cjs +1 -1
  8. package/dist/_policy.cjs.map +1 -1
  9. package/dist/_policy.d.ts +1 -0
  10. package/dist/_policy.d.ts.map +1 -1
  11. package/dist/_policy.js +4 -1
  12. package/dist/_policy.js.map +1 -1
  13. package/dist/_runtime.cjs +1 -1
  14. package/dist/_runtime.cjs.map +1 -1
  15. package/dist/_runtime.d.ts.map +1 -1
  16. package/dist/_runtime.js +1 -1
  17. package/dist/_runtime.js.map +1 -1
  18. package/dist/errors.cjs +1 -1
  19. package/dist/errors.cjs.map +1 -1
  20. package/dist/errors.d.ts +0 -1
  21. package/dist/errors.d.ts.map +1 -1
  22. package/dist/errors.js +1 -4
  23. package/dist/errors.js.map +1 -1
  24. package/dist/index.cjs +1 -1
  25. package/dist/index.d.ts +3 -1
  26. package/dist/index.d.ts.map +1 -1
  27. package/dist/index.js +4 -4
  28. package/dist/sandbox.cjs +14 -14
  29. package/dist/sandbox.cjs.map +1 -1
  30. package/dist/sandbox.iife.js +13 -13
  31. package/dist/sandbox.iife.js.map +1 -1
  32. package/dist/sandbox.js +14 -14
  33. package/dist/sandbox.js.map +1 -1
  34. package/dist/testing.cjs.map +1 -1
  35. package/dist/testing.d.ts +4 -4
  36. package/dist/testing.d.ts.map +1 -1
  37. package/dist/testing.js.map +1 -1
  38. package/dist/types.d.ts +25 -25
  39. package/dist/types.d.ts.map +1 -1
  40. package/package.json +28 -23
  41. package/dist/_sandbox.cjs +0 -2
  42. package/dist/_sandbox.cjs.map +0 -1
  43. package/dist/_sandbox.d.ts +0 -5
  44. package/dist/_sandbox.d.ts.map +0 -1
  45. package/dist/_sandbox.js +0 -11
  46. package/dist/_sandbox.js.map +0 -1
@@ -1,4 +1,4 @@
1
- const e=require("./_policy.cjs"),t=require("./_bridge.cjs");function n(e){return e.replace(/<\/style/gi,`\\3C /style`)}function r(e){return e.replace(/&/g,`&amp;`).replace(/"/g,`&quot;`).replace(/</g,`&lt;`).replace(/>/g,`&gt;`)}function i(e){return e.replace(/&/g,`&amp;`).replace(/</g,`&lt;`).replace(/>/g,`&gt;`)}function a(a,o,s){let c=r(e.buildCspFromOptions(o)),l=Object.entries(o.namedStyles).map(([e,t])=>`<style id="${r(e)}">${n(t)}</style>`).join(`
1
+ const e=require("./_bridge.cjs"),t=require("./_policy.cjs");function n(e){return e.replace(/<\/style/gi,`\\3C /style`)}function r(e){return e.replace(/&/g,`&amp;`).replace(/"/g,`&quot;`).replace(/</g,`&lt;`).replace(/>/g,`&gt;`)}function i(e){return e.replace(/&/g,`&amp;`).replace(/</g,`&lt;`).replace(/>/g,`&gt;`)}function a(a,o,s){let c=r(t.buildCspFromOptions(o)),l=Object.entries(o.namedStyles).map(([e,t])=>`<style id="${r(e)}">${n(t)}</style>`).join(`
2
2
  `),u=o.scripts.map(e=>`<script crossorigin="anonymous" src="${r(e)}"><\/script>`).join(`
3
3
  `),d=o.nonce?` nonce="${r(o.nonce)}"`:``,f=`<script${d}>window.__sandboxChannel=${JSON.stringify(s.channel)};window.__sandboxGeneration=${s.generation};<\/script>`;return`<!doctype html>
4
4
  <html lang="${r(o.lang)}">
@@ -14,8 +14,8 @@ ${l}
14
14
  ${u}
15
15
  ${a}
16
16
  <script${d}>
17
- ${t.buildBridgeScript(s)}
17
+ ${e.buildBridgeScript(s)}
18
18
  <\/script>
19
19
  </body>
20
- </html>`}function o(t,n={}){return a(t,e.normalizeSandboxOptions(n),{channel:``,generation:0})}function s(e,t,n){return a(e,t,n)}exports.buildDocument=o,exports.buildRuntimeDocument=s;
20
+ </html>`}function o(e,n={}){return a(e,t.normalizeSandboxOptions(n),{channel:``,generation:0})}exports.buildDocument=o,exports.buildDocumentFromOptions=a;
21
21
  //# sourceMappingURL=_document.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"_document.cjs","names":[],"sources":["../src/_document.ts"],"sourcesContent":["import type { BridgeBootstrap } from './_protocol.js';\nimport type { SandboxOptions } from './types.js';\n\nimport { buildBridgeScript } from './_bridge.js';\nimport { buildCspFromOptions, normalizeSandboxOptions, type NormalizedSandboxOptions } from './_policy.js';\n\nfunction escapeCss(css: string): string {\n return css.replace(/<\\/style/gi, '\\\\3C /style');\n}\n\nfunction escapeAttr(value: string): string {\n return value.replace(/&/g, '&amp;').replace(/\"/g, '&quot;').replace(/</g, '&lt;').replace(/>/g, '&gt;');\n}\n\nfunction escapeText(value: string): string {\n return value.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');\n}\n\nfunction buildDocumentFromOptions(html: string, options: NormalizedSandboxOptions, bootstrap: BridgeBootstrap): string {\n const csp = escapeAttr(buildCspFromOptions(options));\n const styles = Object.entries(options.namedStyles)\n .map(([id, css]) => `<style id=\"${escapeAttr(id)}\">${escapeCss(css)}</style>`)\n .join('\\n');\n const scripts = options.scripts\n .map((src) => `<script crossorigin=\"anonymous\" src=\"${escapeAttr(src)}\"></script>`)\n .join('\\n');\n const nonce = options.nonce ? ` nonce=\"${escapeAttr(options.nonce)}\"` : '';\n const bootstrapScript = `<script${nonce}>window.__sandboxChannel=${JSON.stringify(bootstrap.channel)};window.__sandboxGeneration=${bootstrap.generation};</script>`;\n\n return `<!doctype html>\n<html lang=\"${escapeAttr(options.lang)}\">\n<head>\n<meta http-equiv=\"Content-Security-Policy\" content=\"${csp}\">\n${bootstrapScript}\n<meta charset=\"utf-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n<title>${escapeText(options.title)}</title>\n${styles}\n</head>\n<body>\n${scripts}\n${html}\n<script${nonce}>\n${buildBridgeScript(bootstrap)}\n</script>\n</body>\n</html>`;\n}\n\nexport function buildDocument(html: string, options: SandboxOptions = {}): string {\n return buildDocumentFromOptions(html, normalizeSandboxOptions(options), { channel: '', generation: 0 });\n}\n\nexport function buildRuntimeDocument(\n html: string,\n options: NormalizedSandboxOptions,\n bootstrap: BridgeBootstrap,\n): string {\n return buildDocumentFromOptions(html, options, bootstrap);\n}\n"],"mappings":"4DAMA,SAAS,EAAU,EAAqB,CACtC,OAAO,EAAI,QAAQ,aAAc,aAAa,CAChD,CAEA,SAAS,EAAW,EAAuB,CACzC,OAAO,EAAM,QAAQ,KAAM,OAAO,CAAC,CAAC,QAAQ,KAAM,QAAQ,CAAC,CAAC,QAAQ,KAAM,MAAM,CAAC,CAAC,QAAQ,KAAM,MAAM,CACxG,CAEA,SAAS,EAAW,EAAuB,CACzC,OAAO,EAAM,QAAQ,KAAM,OAAO,CAAC,CAAC,QAAQ,KAAM,MAAM,CAAC,CAAC,QAAQ,KAAM,MAAM,CAChF,CAEA,SAAS,EAAyB,EAAc,EAAmC,EAAoC,CACrH,IAAM,EAAM,EAAW,EAAA,oBAAoB,CAAO,CAAC,EAC7C,EAAS,OAAO,QAAQ,EAAQ,WAAW,CAAC,CAC/C,KAAK,CAAC,EAAI,KAAS,cAAc,EAAW,CAAE,EAAE,IAAI,EAAU,CAAG,EAAE,SAAS,CAAC,CAC7E,KAAK;CAAI,EACN,EAAU,EAAQ,QACrB,IAAK,GAAQ,wCAAwC,EAAW,CAAG,EAAE,aAAY,CAAC,CAClF,KAAK;CAAI,EACN,EAAQ,EAAQ,MAAQ,WAAW,EAAW,EAAQ,KAAK,EAAE,GAAK,GAClE,EAAkB,UAAU,EAAM,2BAA2B,KAAK,UAAU,EAAU,OAAO,EAAE,8BAA8B,EAAU,WAAW,aAExJ,MAAO;cACK,EAAW,EAAQ,IAAI,EAAE;;sDAEe,EAAI;EACxD,EAAgB;;;SAGT,EAAW,EAAQ,KAAK,EAAE;EACjC,EAAO;;;EAGP,EAAQ;EACR,EAAK;SACE,EAAM;EACb,EAAA,kBAAkB,CAAS,EAAE;;;QAI/B,CAEA,SAAgB,EAAc,EAAc,EAA0B,CAAC,EAAW,CAChF,OAAO,EAAyB,EAAM,EAAA,wBAAwB,CAAO,EAAG,CAAE,QAAS,GAAI,WAAY,CAAE,CAAC,CACxG,CAEA,SAAgB,EACd,EACA,EACA,EACQ,CACR,OAAO,EAAyB,EAAM,EAAS,CAAS,CAC1D"}
1
+ {"version":3,"file":"_document.cjs","names":[],"sources":["../src/_document.ts"],"sourcesContent":["import { buildBridgeScript } from './_bridge.js';\nimport { buildCspFromOptions, type NormalizedSandboxOptions, normalizeSandboxOptions } from './_policy.js';\nimport type { BridgeBootstrap } from './_protocol.js';\nimport type { SandboxOptions } from './types.js';\n\nfunction escapeCss(css: string): string {\n return css.replace(/<\\/style/gi, '\\\\3C /style');\n}\n\nfunction escapeAttr(value: string): string {\n return value.replace(/&/g, '&amp;').replace(/\"/g, '&quot;').replace(/</g, '&lt;').replace(/>/g, '&gt;');\n}\n\nfunction escapeText(value: string): string {\n return value.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');\n}\n\nexport function buildDocumentFromOptions(\n html: string,\n options: NormalizedSandboxOptions,\n bootstrap: BridgeBootstrap,\n): string {\n const csp = escapeAttr(buildCspFromOptions(options));\n const styles = Object.entries(options.namedStyles)\n .map(([id, css]) => `<style id=\"${escapeAttr(id)}\">${escapeCss(css)}</style>`)\n .join('\\n');\n const scripts = options.scripts\n .map((src) => `<script crossorigin=\"anonymous\" src=\"${escapeAttr(src)}\"></script>`)\n .join('\\n');\n const nonce = options.nonce ? ` nonce=\"${escapeAttr(options.nonce)}\"` : '';\n const bootstrapScript = `<script${nonce}>window.__sandboxChannel=${JSON.stringify(bootstrap.channel)};window.__sandboxGeneration=${bootstrap.generation};</script>`;\n\n return `<!doctype html>\n<html lang=\"${escapeAttr(options.lang)}\">\n<head>\n<meta http-equiv=\"Content-Security-Policy\" content=\"${csp}\">\n${bootstrapScript}\n<meta charset=\"utf-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n<title>${escapeText(options.title)}</title>\n${styles}\n</head>\n<body>\n${scripts}\n${html}\n<script${nonce}>\n${buildBridgeScript(bootstrap)}\n</script>\n</body>\n</html>`;\n}\n\nexport function buildDocument(html: string, options: SandboxOptions = {}): string {\n return buildDocumentFromOptions(html, normalizeSandboxOptions(options), { channel: '', generation: 0 });\n}\n"],"mappings":"4DAKA,SAAS,EAAU,EAAqB,CACtC,OAAO,EAAI,QAAQ,aAAc,aAAa,CAChD,CAEA,SAAS,EAAW,EAAuB,CACzC,OAAO,EAAM,QAAQ,KAAM,OAAO,CAAC,CAAC,QAAQ,KAAM,QAAQ,CAAC,CAAC,QAAQ,KAAM,MAAM,CAAC,CAAC,QAAQ,KAAM,MAAM,CACxG,CAEA,SAAS,EAAW,EAAuB,CACzC,OAAO,EAAM,QAAQ,KAAM,OAAO,CAAC,CAAC,QAAQ,KAAM,MAAM,CAAC,CAAC,QAAQ,KAAM,MAAM,CAChF,CAEA,SAAgB,EACd,EACA,EACA,EACQ,CACR,IAAM,EAAM,EAAW,EAAA,oBAAoB,CAAO,CAAC,EAC7C,EAAS,OAAO,QAAQ,EAAQ,WAAW,CAAC,CAC/C,KAAK,CAAC,EAAI,KAAS,cAAc,EAAW,CAAE,EAAE,IAAI,EAAU,CAAG,EAAE,SAAS,CAAC,CAC7E,KAAK;CAAI,EACN,EAAU,EAAQ,QACrB,IAAK,GAAQ,wCAAwC,EAAW,CAAG,EAAE,aAAY,CAAC,CAClF,KAAK;CAAI,EACN,EAAQ,EAAQ,MAAQ,WAAW,EAAW,EAAQ,KAAK,EAAE,GAAK,GAClE,EAAkB,UAAU,EAAM,2BAA2B,KAAK,UAAU,EAAU,OAAO,EAAE,8BAA8B,EAAU,WAAW,aAExJ,MAAO;cACK,EAAW,EAAQ,IAAI,EAAE;;sDAEe,EAAI;EACxD,EAAgB;;;SAGT,EAAW,EAAQ,KAAK,EAAE;EACjC,EAAO;;;EAGP,EAAQ;EACR,EAAK;SACE,EAAM;EACb,EAAA,kBAAkB,CAAS,EAAE;;;QAI/B,CAEA,SAAgB,EAAc,EAAc,EAA0B,CAAC,EAAW,CAChF,OAAO,EAAyB,EAAM,EAAA,wBAAwB,CAAO,EAAG,CAAE,QAAS,GAAI,WAAY,CAAE,CAAC,CACxG"}
@@ -1,6 +1,6 @@
1
+ import { type NormalizedSandboxOptions } from './_policy.js';
1
2
  import type { BridgeBootstrap } from './_protocol.js';
2
3
  import type { SandboxOptions } from './types.js';
3
- import { type NormalizedSandboxOptions } from './_policy.js';
4
+ export declare function buildDocumentFromOptions(html: string, options: NormalizedSandboxOptions, bootstrap: BridgeBootstrap): string;
4
5
  export declare function buildDocument(html: string, options?: SandboxOptions): string;
5
- export declare function buildRuntimeDocument(html: string, options: NormalizedSandboxOptions, bootstrap: BridgeBootstrap): string;
6
6
  //# sourceMappingURL=_document.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"_document.d.ts","sourceRoot":"","sources":["../src/_document.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACtD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAGjD,OAAO,EAAgD,KAAK,wBAAwB,EAAE,MAAM,cAAc,CAAC;AA6C3G,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,cAAmB,GAAG,MAAM,CAEhF;AAED,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,wBAAwB,EACjC,SAAS,EAAE,eAAe,GACzB,MAAM,CAER"}
1
+ {"version":3,"file":"_document.d.ts","sourceRoot":"","sources":["../src/_document.ts"],"names":[],"mappings":"AACA,OAAO,EAAuB,KAAK,wBAAwB,EAA2B,MAAM,cAAc,CAAC;AAC3G,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACtD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAcjD,wBAAgB,wBAAwB,CACtC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,wBAAwB,EACjC,SAAS,EAAE,eAAe,GACzB,MAAM,CA6BR;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,cAAmB,GAAG,MAAM,CAEhF"}
package/dist/_document.js CHANGED
@@ -1,5 +1,5 @@
1
- import { buildCspFromOptions as e, normalizeSandboxOptions as t } from "./_policy.js";
2
- import { buildBridgeScript as n } from "./_bridge.js";
1
+ import { buildBridgeScript as e } from "./_bridge.js";
2
+ import { buildCspFromOptions as t, normalizeSandboxOptions as n } from "./_policy.js";
3
3
  //#region src/_document.ts
4
4
  function r(e) {
5
5
  return e.replace(/<\/style/gi, "\\3C /style");
@@ -10,8 +10,8 @@ function i(e) {
10
10
  function a(e) {
11
11
  return e.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
12
12
  }
13
- function o(t, o, s) {
14
- let c = i(e(o)), l = Object.entries(o.namedStyles).map(([e, t]) => `<style id="${i(e)}">${r(t)}</style>`).join("\n"), u = o.scripts.map((e) => `<script crossorigin="anonymous" src="${i(e)}"><\/script>`).join("\n"), d = o.nonce ? ` nonce="${i(o.nonce)}"` : "", f = `<script${d}>window.__sandboxChannel=${JSON.stringify(s.channel)};window.__sandboxGeneration=${s.generation};<\/script>`;
13
+ function o(n, o, s) {
14
+ let c = i(t(o)), l = Object.entries(o.namedStyles).map(([e, t]) => `<style id="${i(e)}">${r(t)}</style>`).join("\n"), u = o.scripts.map((e) => `<script crossorigin="anonymous" src="${i(e)}"><\/script>`).join("\n"), d = o.nonce ? ` nonce="${i(o.nonce)}"` : "", f = `<script${d}>window.__sandboxChannel=${JSON.stringify(s.channel)};window.__sandboxGeneration=${s.generation};<\/script>`;
15
15
  return `<!doctype html>
16
16
  <html lang="${i(o.lang)}">
17
17
  <head>
@@ -24,23 +24,20 @@ ${l}
24
24
  </head>
25
25
  <body>
26
26
  ${u}
27
- ${t}
27
+ ${n}
28
28
  <script${d}>
29
- ${n(s)}
29
+ ${e(s)}
30
30
  <\/script>
31
31
  </body>
32
32
  </html>`;
33
33
  }
34
- function s(e, n = {}) {
35
- return o(e, t(n), {
34
+ function s(e, t = {}) {
35
+ return o(e, n(t), {
36
36
  channel: "",
37
37
  generation: 0
38
38
  });
39
39
  }
40
- function c(e, t, n) {
41
- return o(e, t, n);
42
- }
43
40
  //#endregion
44
- export { s as buildDocument, c as buildRuntimeDocument };
41
+ export { s as buildDocument, o as buildDocumentFromOptions };
45
42
 
46
43
  //# sourceMappingURL=_document.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"_document.js","names":[],"sources":["../src/_document.ts"],"sourcesContent":["import type { BridgeBootstrap } from './_protocol.js';\nimport type { SandboxOptions } from './types.js';\n\nimport { buildBridgeScript } from './_bridge.js';\nimport { buildCspFromOptions, normalizeSandboxOptions, type NormalizedSandboxOptions } from './_policy.js';\n\nfunction escapeCss(css: string): string {\n return css.replace(/<\\/style/gi, '\\\\3C /style');\n}\n\nfunction escapeAttr(value: string): string {\n return value.replace(/&/g, '&amp;').replace(/\"/g, '&quot;').replace(/</g, '&lt;').replace(/>/g, '&gt;');\n}\n\nfunction escapeText(value: string): string {\n return value.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');\n}\n\nfunction buildDocumentFromOptions(html: string, options: NormalizedSandboxOptions, bootstrap: BridgeBootstrap): string {\n const csp = escapeAttr(buildCspFromOptions(options));\n const styles = Object.entries(options.namedStyles)\n .map(([id, css]) => `<style id=\"${escapeAttr(id)}\">${escapeCss(css)}</style>`)\n .join('\\n');\n const scripts = options.scripts\n .map((src) => `<script crossorigin=\"anonymous\" src=\"${escapeAttr(src)}\"></script>`)\n .join('\\n');\n const nonce = options.nonce ? ` nonce=\"${escapeAttr(options.nonce)}\"` : '';\n const bootstrapScript = `<script${nonce}>window.__sandboxChannel=${JSON.stringify(bootstrap.channel)};window.__sandboxGeneration=${bootstrap.generation};</script>`;\n\n return `<!doctype html>\n<html lang=\"${escapeAttr(options.lang)}\">\n<head>\n<meta http-equiv=\"Content-Security-Policy\" content=\"${csp}\">\n${bootstrapScript}\n<meta charset=\"utf-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n<title>${escapeText(options.title)}</title>\n${styles}\n</head>\n<body>\n${scripts}\n${html}\n<script${nonce}>\n${buildBridgeScript(bootstrap)}\n</script>\n</body>\n</html>`;\n}\n\nexport function buildDocument(html: string, options: SandboxOptions = {}): string {\n return buildDocumentFromOptions(html, normalizeSandboxOptions(options), { channel: '', generation: 0 });\n}\n\nexport function buildRuntimeDocument(\n html: string,\n options: NormalizedSandboxOptions,\n bootstrap: BridgeBootstrap,\n): string {\n return buildDocumentFromOptions(html, options, bootstrap);\n}\n"],"mappings":";;;AAMA,SAAS,EAAU,GAAqB;CACtC,OAAO,EAAI,QAAQ,cAAc,aAAa;AAChD;AAEA,SAAS,EAAW,GAAuB;CACzC,OAAO,EAAM,QAAQ,MAAM,OAAO,CAAC,CAAC,QAAQ,MAAM,QAAQ,CAAC,CAAC,QAAQ,MAAM,MAAM,CAAC,CAAC,QAAQ,MAAM,MAAM;AACxG;AAEA,SAAS,EAAW,GAAuB;CACzC,OAAO,EAAM,QAAQ,MAAM,OAAO,CAAC,CAAC,QAAQ,MAAM,MAAM,CAAC,CAAC,QAAQ,MAAM,MAAM;AAChF;AAEA,SAAS,EAAyB,GAAc,GAAmC,GAAoC;CACrH,IAAM,IAAM,EAAW,EAAoB,CAAO,CAAC,GAC7C,IAAS,OAAO,QAAQ,EAAQ,WAAW,CAAC,CAC/C,KAAK,CAAC,GAAI,OAAS,cAAc,EAAW,CAAE,EAAE,IAAI,EAAU,CAAG,EAAE,SAAS,CAAC,CAC7E,KAAK,IAAI,GACN,IAAU,EAAQ,QACrB,KAAK,MAAQ,wCAAwC,EAAW,CAAG,EAAE,aAAY,CAAC,CAClF,KAAK,IAAI,GACN,IAAQ,EAAQ,QAAQ,WAAW,EAAW,EAAQ,KAAK,EAAE,KAAK,IAClE,IAAkB,UAAU,EAAM,2BAA2B,KAAK,UAAU,EAAU,OAAO,EAAE,8BAA8B,EAAU,WAAW;CAExJ,OAAO;cACK,EAAW,EAAQ,IAAI,EAAE;;sDAEe,EAAI;EACxD,EAAgB;;;SAGT,EAAW,EAAQ,KAAK,EAAE;EACjC,EAAO;;;EAGP,EAAQ;EACR,EAAK;SACE,EAAM;EACb,EAAkB,CAAS,EAAE;;;;AAI/B;AAEA,SAAgB,EAAc,GAAc,IAA0B,CAAC,GAAW;CAChF,OAAO,EAAyB,GAAM,EAAwB,CAAO,GAAG;EAAE,SAAS;EAAI,YAAY;CAAE,CAAC;AACxG;AAEA,SAAgB,EACd,GACA,GACA,GACQ;CACR,OAAO,EAAyB,GAAM,GAAS,CAAS;AAC1D"}
1
+ {"version":3,"file":"_document.js","names":[],"sources":["../src/_document.ts"],"sourcesContent":["import { buildBridgeScript } from './_bridge.js';\nimport { buildCspFromOptions, type NormalizedSandboxOptions, normalizeSandboxOptions } from './_policy.js';\nimport type { BridgeBootstrap } from './_protocol.js';\nimport type { SandboxOptions } from './types.js';\n\nfunction escapeCss(css: string): string {\n return css.replace(/<\\/style/gi, '\\\\3C /style');\n}\n\nfunction escapeAttr(value: string): string {\n return value.replace(/&/g, '&amp;').replace(/\"/g, '&quot;').replace(/</g, '&lt;').replace(/>/g, '&gt;');\n}\n\nfunction escapeText(value: string): string {\n return value.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');\n}\n\nexport function buildDocumentFromOptions(\n html: string,\n options: NormalizedSandboxOptions,\n bootstrap: BridgeBootstrap,\n): string {\n const csp = escapeAttr(buildCspFromOptions(options));\n const styles = Object.entries(options.namedStyles)\n .map(([id, css]) => `<style id=\"${escapeAttr(id)}\">${escapeCss(css)}</style>`)\n .join('\\n');\n const scripts = options.scripts\n .map((src) => `<script crossorigin=\"anonymous\" src=\"${escapeAttr(src)}\"></script>`)\n .join('\\n');\n const nonce = options.nonce ? ` nonce=\"${escapeAttr(options.nonce)}\"` : '';\n const bootstrapScript = `<script${nonce}>window.__sandboxChannel=${JSON.stringify(bootstrap.channel)};window.__sandboxGeneration=${bootstrap.generation};</script>`;\n\n return `<!doctype html>\n<html lang=\"${escapeAttr(options.lang)}\">\n<head>\n<meta http-equiv=\"Content-Security-Policy\" content=\"${csp}\">\n${bootstrapScript}\n<meta charset=\"utf-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n<title>${escapeText(options.title)}</title>\n${styles}\n</head>\n<body>\n${scripts}\n${html}\n<script${nonce}>\n${buildBridgeScript(bootstrap)}\n</script>\n</body>\n</html>`;\n}\n\nexport function buildDocument(html: string, options: SandboxOptions = {}): string {\n return buildDocumentFromOptions(html, normalizeSandboxOptions(options), { channel: '', generation: 0 });\n}\n"],"mappings":";;;AAKA,SAAS,EAAU,GAAqB;CACtC,OAAO,EAAI,QAAQ,cAAc,aAAa;AAChD;AAEA,SAAS,EAAW,GAAuB;CACzC,OAAO,EAAM,QAAQ,MAAM,OAAO,CAAC,CAAC,QAAQ,MAAM,QAAQ,CAAC,CAAC,QAAQ,MAAM,MAAM,CAAC,CAAC,QAAQ,MAAM,MAAM;AACxG;AAEA,SAAS,EAAW,GAAuB;CACzC,OAAO,EAAM,QAAQ,MAAM,OAAO,CAAC,CAAC,QAAQ,MAAM,MAAM,CAAC,CAAC,QAAQ,MAAM,MAAM;AAChF;AAEA,SAAgB,EACd,GACA,GACA,GACQ;CACR,IAAM,IAAM,EAAW,EAAoB,CAAO,CAAC,GAC7C,IAAS,OAAO,QAAQ,EAAQ,WAAW,CAAC,CAC/C,KAAK,CAAC,GAAI,OAAS,cAAc,EAAW,CAAE,EAAE,IAAI,EAAU,CAAG,EAAE,SAAS,CAAC,CAC7E,KAAK,IAAI,GACN,IAAU,EAAQ,QACrB,KAAK,MAAQ,wCAAwC,EAAW,CAAG,EAAE,aAAY,CAAC,CAClF,KAAK,IAAI,GACN,IAAQ,EAAQ,QAAQ,WAAW,EAAW,EAAQ,KAAK,EAAE,KAAK,IAClE,IAAkB,UAAU,EAAM,2BAA2B,KAAK,UAAU,EAAU,OAAO,EAAE,8BAA8B,EAAU,WAAW;CAExJ,OAAO;cACK,EAAW,EAAQ,IAAI,EAAE;;sDAEe,EAAI;EACxD,EAAgB;;;SAGT,EAAW,EAAQ,KAAK,EAAE;EACjC,EAAO;;;EAGP,EAAQ;EACR,EAAK;SACE,EAAM;EACb,EAAkB,CAAS,EAAE;;;;AAI/B;AAEA,SAAgB,EAAc,GAAc,IAA0B,CAAC,GAAW;CAChF,OAAO,EAAyB,GAAM,EAAwB,CAAO,GAAG;EAAE,SAAS;EAAI,YAAY;CAAE,CAAC;AACxG"}
package/dist/_policy.cjs CHANGED
@@ -1,2 +1,2 @@
1
- const e=require("./errors.cjs");var t=/^[A-Za-z][A-Za-z0-9_-]*$/,n=/^[A-Za-z]{2,3}(?:-[A-Za-z0-9]{2,8})*$/,r=/^[A-Za-z0-9+/_-]+={0,2}$/;function i(t,n){throw new e.SandboxConfigurationError(`${t} is invalid: ${String(n)}`)}function a(e,t){let n;try{n=new URL(e)}catch{return i(t,e)}return n.protocol!==`http:`&&n.protocol!==`https:`||n.username||n.password||n.pathname!==`/`||n.search||n.hash?i(t,e):n.origin}function o(e,t){return(e??[]).map(e=>a(e,t))}function s(e){let t;try{t=new URL(e)}catch{return i(`scripts`,e)}return t.protocol!==`http:`&&t.protocol!==`https:`?i(`scripts`,e):t.href}function c(e){let n={};for(let[r,a]of Object.entries(e??{}))(!t.test(r)||typeof a!=`string`)&&i(`namedStyles`,r),n[r]=a;return n}function l(e={}){let t=e.lang??`en`;n.test(t)||i(`lang`,t),e.nonce!==void 0&&(!r.test(e.nonce)||e.nonce.length===0)&&i(`nonce`,e.nonce),e.title!==void 0&&typeof e.title!=`string`&&i(`title`,e.title);let a=(e.scripts??[]).map(s);return{allowedFontOrigins:o(e.allowedFontOrigins,`allowedFontOrigins`),allowedImageOrigins:o(e.allowedImageOrigins,`allowedImageOrigins`),allowedScriptOrigins:o(e.allowedScriptOrigins,`allowedScriptOrigins`),allowedStyleOrigins:o(e.allowedStyleOrigins,`allowedStyleOrigins`),lang:t,namedStyles:c(e.namedStyles),nonce:e.nonce,scripts:a,title:e.title??``}}function u(e){let t=[`'unsafe-inline'`,...e.nonce?[`'nonce-${e.nonce}'`]:[],...e.allowedScriptOrigins,...e.scripts.map(e=>new URL(e).origin)].join(` `),n=[`'unsafe-inline'`,...e.allowedStyleOrigins].join(` `),r=[`data:`,...e.allowedImageOrigins].join(` `),i=e.allowedFontOrigins.join(` `)||`'none'`;return[`default-src 'none'`,`script-src ${t}`,`style-src ${n}`,`img-src ${r}`,`font-src ${i}`,`connect-src 'none'`,`form-action 'none'`,`base-uri 'none'`].join(`; `)}exports.buildCspFromOptions=u,exports.normalizeSandboxOptions=l;
1
+ const e=require("./errors.cjs");var t=/^[A-Za-z][A-Za-z0-9_-]*$/,n=/^[A-Za-z]{2,3}(?:-[A-Za-z0-9]{2,8})*$/,r=/^[A-Za-z0-9+/_-]+={0,2}$/;function i(t,n){throw new e.SandboxConfigurationError(`${t} is invalid: ${String(n)}`)}function a(e,t){let n;try{n=new URL(e)}catch{return i(t,e)}return n.protocol!==`http:`&&n.protocol!==`https:`||n.username||n.password||n.pathname!==`/`||n.search||n.hash?i(t,e):n.origin}function o(e,t){return(e??[]).map(e=>a(e,t))}function s(e){let t;try{t=new URL(e)}catch{return i(`scripts`,e)}return t.protocol!==`http:`&&t.protocol!==`https:`?i(`scripts`,e):t.href}function c(e){let n={};for(let[r,a]of Object.entries(e??{}))(!t.test(r)||typeof a!=`string`)&&i(`namedStyles`,r),n[r]=a;return n}function l(e={}){let t=e.lang??`en`;n.test(t)||i(`lang`,t),e.nonce!==void 0&&(!r.test(e.nonce)||e.nonce.length===0)&&i(`nonce`,e.nonce),e.title!==void 0&&typeof e.title!=`string`&&i(`title`,e.title);let a=(e.scripts??[]).map(s);return{allowedFontOrigins:o(e.allowedFontOrigins,`allowedFontOrigins`),allowedImageOrigins:o(e.allowedImageOrigins,`allowedImageOrigins`),allowedScriptOrigins:o(e.allowedScriptOrigins,`allowedScriptOrigins`),allowedStyleOrigins:o(e.allowedStyleOrigins,`allowedStyleOrigins`),lang:t,namedStyles:c(e.namedStyles),nonce:e.nonce,scripts:a,title:e.title??``}}function u(e){let t=[`'unsafe-inline'`,...e.nonce?[`'nonce-${e.nonce}'`]:[],...e.allowedScriptOrigins,...e.scripts.map(e=>new URL(e).origin)].join(` `),n=[`'unsafe-inline'`,...e.allowedStyleOrigins].join(` `),r=[`data:`,...e.allowedImageOrigins].join(` `),i=e.allowedFontOrigins.join(` `)||`'none'`;return[`default-src 'none'`,`script-src ${t}`,`style-src ${n}`,`img-src ${r}`,`font-src ${i}`,`connect-src 'none'`,`form-action 'none'`,`base-uri 'none'`].join(`; `)}function d(e={}){return u(l(e))}exports.buildCsp=d,exports.buildCspFromOptions=u,exports.normalizeSandboxOptions=l;
2
2
  //# sourceMappingURL=_policy.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"_policy.cjs","names":[],"sources":["../src/_policy.ts"],"sourcesContent":["import type { SandboxOptions } from './types.js';\n\nimport { SandboxConfigurationError } from './errors.js';\n\nexport interface NormalizedSandboxOptions {\n allowedFontOrigins: string[];\n allowedImageOrigins: string[];\n allowedScriptOrigins: string[];\n allowedStyleOrigins: string[];\n lang: string;\n namedStyles: Record<string, string>;\n nonce: string | undefined;\n scripts: string[];\n title: string;\n}\n\nconst ID = /^[A-Za-z][A-Za-z0-9_-]*$/;\nconst LANG = /^[A-Za-z]{2,3}(?:-[A-Za-z0-9]{2,8})*$/;\nconst NONCE = /^[A-Za-z0-9+/_-]+={0,2}$/;\n\nfunction fail(field: string, value: unknown): never {\n throw new SandboxConfigurationError(`${field} is invalid: ${String(value)}`);\n}\n\nfunction normalizeOrigin(value: string, field: string): string {\n let url: URL;\n\n try {\n url = new URL(value);\n } catch {\n return fail(field, value);\n }\n\n if (\n (url.protocol !== 'http:' && url.protocol !== 'https:') ||\n url.username ||\n url.password ||\n url.pathname !== '/' ||\n url.search ||\n url.hash\n ) {\n return fail(field, value);\n }\n\n return url.origin;\n}\n\nfunction normalizeOrigins(values: string[] | undefined, field: string): string[] {\n return (values ?? []).map((value) => normalizeOrigin(value, field));\n}\n\nfunction normalizeScript(value: string): string {\n let url: URL;\n\n try {\n url = new URL(value);\n } catch {\n return fail('scripts', value);\n }\n\n if (url.protocol !== 'http:' && url.protocol !== 'https:') return fail('scripts', value);\n\n return url.href;\n}\n\nfunction normalizeStyles(styles: Record<string, string> | undefined): Record<string, string> {\n const normalized: Record<string, string> = {};\n\n for (const [id, css] of Object.entries(styles ?? {})) {\n if (!ID.test(id) || typeof css !== 'string') fail('namedStyles', id);\n\n normalized[id] = css;\n }\n\n return normalized;\n}\n\nexport function normalizeSandboxOptions(options: SandboxOptions = {}): NormalizedSandboxOptions {\n const lang = options.lang ?? 'en';\n\n if (!LANG.test(lang)) fail('lang', lang);\n\n if (options.nonce !== undefined && (!NONCE.test(options.nonce) || options.nonce.length === 0)) {\n fail('nonce', options.nonce);\n }\n\n if (options.title !== undefined && typeof options.title !== 'string') fail('title', options.title);\n\n const scripts = (options.scripts ?? []).map(normalizeScript);\n\n return {\n allowedFontOrigins: normalizeOrigins(options.allowedFontOrigins, 'allowedFontOrigins'),\n allowedImageOrigins: normalizeOrigins(options.allowedImageOrigins, 'allowedImageOrigins'),\n allowedScriptOrigins: normalizeOrigins(options.allowedScriptOrigins, 'allowedScriptOrigins'),\n allowedStyleOrigins: normalizeOrigins(options.allowedStyleOrigins, 'allowedStyleOrigins'),\n lang,\n namedStyles: normalizeStyles(options.namedStyles),\n nonce: options.nonce,\n scripts,\n title: options.title ?? '',\n };\n}\n\nexport function buildCspFromOptions(options: NormalizedSandboxOptions): string {\n const scriptOrigins = [\n \"'unsafe-inline'\",\n ...(options.nonce ? [`'nonce-${options.nonce}'`] : []),\n ...options.allowedScriptOrigins,\n ...options.scripts.map((script) => new URL(script).origin),\n ].join(' ');\n const styleOrigins = [\"'unsafe-inline'\", ...options.allowedStyleOrigins].join(' ');\n const imageOrigins = ['data:', ...options.allowedImageOrigins].join(' ');\n const fontOrigins = options.allowedFontOrigins.join(' ') || \"'none'\";\n\n return [\n \"default-src 'none'\",\n `script-src ${scriptOrigins}`,\n `style-src ${styleOrigins}`,\n `img-src ${imageOrigins}`,\n `font-src ${fontOrigins}`,\n \"connect-src 'none'\",\n \"form-action 'none'\",\n \"base-uri 'none'\",\n ].join('; ');\n}\n"],"mappings":"gCAgBA,IAAM,EAAK,2BACL,EAAO,wCACP,EAAQ,2BAEd,SAAS,EAAK,EAAe,EAAuB,CAClD,MAAM,IAAI,EAAA,0BAA0B,GAAG,EAAM,eAAe,OAAO,CAAK,GAAG,CAC7E,CAEA,SAAS,EAAgB,EAAe,EAAuB,CAC7D,IAAI,EAEJ,GAAI,CACF,EAAM,IAAI,IAAI,CAAK,CACrB,MAAQ,CACN,OAAO,EAAK,EAAO,CAAK,CAC1B,CAaA,OAVG,EAAI,WAAa,SAAW,EAAI,WAAa,UAC9C,EAAI,UACJ,EAAI,UACJ,EAAI,WAAa,KACjB,EAAI,QACJ,EAAI,KAEG,EAAK,EAAO,CAAK,EAGnB,EAAI,MACb,CAEA,SAAS,EAAiB,EAA8B,EAAyB,CAC/E,OAAQ,GAAU,CAAC,EAAA,CAAG,IAAK,GAAU,EAAgB,EAAO,CAAK,CAAC,CACpE,CAEA,SAAS,EAAgB,EAAuB,CAC9C,IAAI,EAEJ,GAAI,CACF,EAAM,IAAI,IAAI,CAAK,CACrB,MAAQ,CACN,OAAO,EAAK,UAAW,CAAK,CAC9B,CAIA,OAFI,EAAI,WAAa,SAAW,EAAI,WAAa,SAAiB,EAAK,UAAW,CAAK,EAEhF,EAAI,IACb,CAEA,SAAS,EAAgB,EAAoE,CAC3F,IAAM,EAAqC,CAAC,EAE5C,IAAK,GAAM,CAAC,EAAI,KAAQ,OAAO,QAAQ,GAAU,CAAC,CAAC,GAC7C,CAAC,EAAG,KAAK,CAAE,GAAK,OAAO,GAAQ,WAAU,EAAK,cAAe,CAAE,EAEnE,EAAW,GAAM,EAGnB,OAAO,CACT,CAEA,SAAgB,EAAwB,EAA0B,CAAC,EAA6B,CAC9F,IAAM,EAAO,EAAQ,MAAQ,KAExB,EAAK,KAAK,CAAI,GAAG,EAAK,OAAQ,CAAI,EAEnC,EAAQ,QAAU,IAAA,KAAc,CAAC,EAAM,KAAK,EAAQ,KAAK,GAAK,EAAQ,MAAM,SAAW,IACzF,EAAK,QAAS,EAAQ,KAAK,EAGzB,EAAQ,QAAU,IAAA,IAAa,OAAO,EAAQ,OAAU,UAAU,EAAK,QAAS,EAAQ,KAAK,EAEjG,IAAM,GAAW,EAAQ,SAAW,CAAC,EAAA,CAAG,IAAI,CAAe,EAE3D,MAAO,CACL,mBAAoB,EAAiB,EAAQ,mBAAoB,oBAAoB,EACrF,oBAAqB,EAAiB,EAAQ,oBAAqB,qBAAqB,EACxF,qBAAsB,EAAiB,EAAQ,qBAAsB,sBAAsB,EAC3F,oBAAqB,EAAiB,EAAQ,oBAAqB,qBAAqB,EACxF,OACA,YAAa,EAAgB,EAAQ,WAAW,EAChD,MAAO,EAAQ,MACf,UACA,MAAO,EAAQ,OAAS,EAC1B,CACF,CAEA,SAAgB,EAAoB,EAA2C,CAC7E,IAAM,EAAgB,CACpB,kBACA,GAAI,EAAQ,MAAQ,CAAC,UAAU,EAAQ,MAAM,EAAE,EAAI,CAAC,EACpD,GAAG,EAAQ,qBACX,GAAG,EAAQ,QAAQ,IAAK,GAAW,IAAI,IAAI,CAAM,CAAC,CAAC,MAAM,CAC3D,CAAC,CAAC,KAAK,GAAG,EACJ,EAAe,CAAC,kBAAmB,GAAG,EAAQ,mBAAmB,CAAC,CAAC,KAAK,GAAG,EAC3E,EAAe,CAAC,QAAS,GAAG,EAAQ,mBAAmB,CAAC,CAAC,KAAK,GAAG,EACjE,EAAc,EAAQ,mBAAmB,KAAK,GAAG,GAAK,SAE5D,MAAO,CACL,qBACA,cAAc,IACd,aAAa,IACb,WAAW,IACX,YAAY,IACZ,qBACA,qBACA,iBACF,CAAC,CAAC,KAAK,IAAI,CACb"}
1
+ {"version":3,"file":"_policy.cjs","names":[],"sources":["../src/_policy.ts"],"sourcesContent":["import { SandboxConfigurationError } from './errors.js';\nimport type { SandboxOptions } from './types.js';\n\nexport interface NormalizedSandboxOptions {\n allowedFontOrigins: string[];\n allowedImageOrigins: string[];\n allowedScriptOrigins: string[];\n allowedStyleOrigins: string[];\n lang: string;\n namedStyles: Record<string, string>;\n nonce: string | undefined;\n scripts: string[];\n title: string;\n}\n\nconst ID = /^[A-Za-z][A-Za-z0-9_-]*$/;\nconst LANG = /^[A-Za-z]{2,3}(?:-[A-Za-z0-9]{2,8})*$/;\nconst NONCE = /^[A-Za-z0-9+/_-]+={0,2}$/;\n\nfunction fail(field: string, value: unknown): never {\n throw new SandboxConfigurationError(`${field} is invalid: ${String(value)}`);\n}\n\nfunction normalizeOrigin(value: string, field: string): string {\n let url: URL;\n\n try {\n url = new URL(value);\n } catch {\n return fail(field, value);\n }\n\n if (\n (url.protocol !== 'http:' && url.protocol !== 'https:') ||\n url.username ||\n url.password ||\n url.pathname !== '/' ||\n url.search ||\n url.hash\n ) {\n return fail(field, value);\n }\n\n return url.origin;\n}\n\nfunction normalizeOrigins(values: string[] | undefined, field: string): string[] {\n return (values ?? []).map((value) => normalizeOrigin(value, field));\n}\n\nfunction normalizeScript(value: string): string {\n let url: URL;\n\n try {\n url = new URL(value);\n } catch {\n return fail('scripts', value);\n }\n\n if (url.protocol !== 'http:' && url.protocol !== 'https:') return fail('scripts', value);\n\n return url.href;\n}\n\nfunction normalizeStyles(styles: Record<string, string> | undefined): Record<string, string> {\n const normalized: Record<string, string> = {};\n\n for (const [id, css] of Object.entries(styles ?? {})) {\n if (!ID.test(id) || typeof css !== 'string') fail('namedStyles', id);\n\n normalized[id] = css;\n }\n\n return normalized;\n}\n\nexport function normalizeSandboxOptions(options: SandboxOptions = {}): NormalizedSandboxOptions {\n const lang = options.lang ?? 'en';\n\n if (!LANG.test(lang)) fail('lang', lang);\n\n if (options.nonce !== undefined && (!NONCE.test(options.nonce) || options.nonce.length === 0)) {\n fail('nonce', options.nonce);\n }\n\n if (options.title !== undefined && typeof options.title !== 'string') fail('title', options.title);\n\n const scripts = (options.scripts ?? []).map(normalizeScript);\n\n return {\n allowedFontOrigins: normalizeOrigins(options.allowedFontOrigins, 'allowedFontOrigins'),\n allowedImageOrigins: normalizeOrigins(options.allowedImageOrigins, 'allowedImageOrigins'),\n allowedScriptOrigins: normalizeOrigins(options.allowedScriptOrigins, 'allowedScriptOrigins'),\n allowedStyleOrigins: normalizeOrigins(options.allowedStyleOrigins, 'allowedStyleOrigins'),\n lang,\n namedStyles: normalizeStyles(options.namedStyles),\n nonce: options.nonce,\n scripts,\n title: options.title ?? '',\n };\n}\n\nexport function buildCspFromOptions(options: NormalizedSandboxOptions): string {\n const scriptOrigins = [\n \"'unsafe-inline'\",\n ...(options.nonce ? [`'nonce-${options.nonce}'`] : []),\n ...options.allowedScriptOrigins,\n ...options.scripts.map((script) => new URL(script).origin),\n ].join(' ');\n const styleOrigins = [\"'unsafe-inline'\", ...options.allowedStyleOrigins].join(' ');\n const imageOrigins = ['data:', ...options.allowedImageOrigins].join(' ');\n const fontOrigins = options.allowedFontOrigins.join(' ') || \"'none'\";\n\n return [\n \"default-src 'none'\",\n `script-src ${scriptOrigins}`,\n `style-src ${styleOrigins}`,\n `img-src ${imageOrigins}`,\n `font-src ${fontOrigins}`,\n \"connect-src 'none'\",\n \"form-action 'none'\",\n \"base-uri 'none'\",\n ].join('; ');\n}\n\nexport function buildCsp(options: SandboxOptions = {}): string {\n return buildCspFromOptions(normalizeSandboxOptions(options));\n}\n"],"mappings":"gCAeA,IAAM,EAAK,2BACL,EAAO,wCACP,EAAQ,2BAEd,SAAS,EAAK,EAAe,EAAuB,CAClD,MAAM,IAAI,EAAA,0BAA0B,GAAG,EAAM,eAAe,OAAO,CAAK,GAAG,CAC7E,CAEA,SAAS,EAAgB,EAAe,EAAuB,CAC7D,IAAI,EAEJ,GAAI,CACF,EAAM,IAAI,IAAI,CAAK,CACrB,MAAQ,CACN,OAAO,EAAK,EAAO,CAAK,CAC1B,CAaA,OAVG,EAAI,WAAa,SAAW,EAAI,WAAa,UAC9C,EAAI,UACJ,EAAI,UACJ,EAAI,WAAa,KACjB,EAAI,QACJ,EAAI,KAEG,EAAK,EAAO,CAAK,EAGnB,EAAI,MACb,CAEA,SAAS,EAAiB,EAA8B,EAAyB,CAC/E,OAAQ,GAAU,CAAC,EAAA,CAAG,IAAK,GAAU,EAAgB,EAAO,CAAK,CAAC,CACpE,CAEA,SAAS,EAAgB,EAAuB,CAC9C,IAAI,EAEJ,GAAI,CACF,EAAM,IAAI,IAAI,CAAK,CACrB,MAAQ,CACN,OAAO,EAAK,UAAW,CAAK,CAC9B,CAIA,OAFI,EAAI,WAAa,SAAW,EAAI,WAAa,SAAiB,EAAK,UAAW,CAAK,EAEhF,EAAI,IACb,CAEA,SAAS,EAAgB,EAAoE,CAC3F,IAAM,EAAqC,CAAC,EAE5C,IAAK,GAAM,CAAC,EAAI,KAAQ,OAAO,QAAQ,GAAU,CAAC,CAAC,GAC7C,CAAC,EAAG,KAAK,CAAE,GAAK,OAAO,GAAQ,WAAU,EAAK,cAAe,CAAE,EAEnE,EAAW,GAAM,EAGnB,OAAO,CACT,CAEA,SAAgB,EAAwB,EAA0B,CAAC,EAA6B,CAC9F,IAAM,EAAO,EAAQ,MAAQ,KAExB,EAAK,KAAK,CAAI,GAAG,EAAK,OAAQ,CAAI,EAEnC,EAAQ,QAAU,IAAA,KAAc,CAAC,EAAM,KAAK,EAAQ,KAAK,GAAK,EAAQ,MAAM,SAAW,IACzF,EAAK,QAAS,EAAQ,KAAK,EAGzB,EAAQ,QAAU,IAAA,IAAa,OAAO,EAAQ,OAAU,UAAU,EAAK,QAAS,EAAQ,KAAK,EAEjG,IAAM,GAAW,EAAQ,SAAW,CAAC,EAAA,CAAG,IAAI,CAAe,EAE3D,MAAO,CACL,mBAAoB,EAAiB,EAAQ,mBAAoB,oBAAoB,EACrF,oBAAqB,EAAiB,EAAQ,oBAAqB,qBAAqB,EACxF,qBAAsB,EAAiB,EAAQ,qBAAsB,sBAAsB,EAC3F,oBAAqB,EAAiB,EAAQ,oBAAqB,qBAAqB,EACxF,OACA,YAAa,EAAgB,EAAQ,WAAW,EAChD,MAAO,EAAQ,MACf,UACA,MAAO,EAAQ,OAAS,EAC1B,CACF,CAEA,SAAgB,EAAoB,EAA2C,CAC7E,IAAM,EAAgB,CACpB,kBACA,GAAI,EAAQ,MAAQ,CAAC,UAAU,EAAQ,MAAM,EAAE,EAAI,CAAC,EACpD,GAAG,EAAQ,qBACX,GAAG,EAAQ,QAAQ,IAAK,GAAW,IAAI,IAAI,CAAM,CAAC,CAAC,MAAM,CAC3D,CAAC,CAAC,KAAK,GAAG,EACJ,EAAe,CAAC,kBAAmB,GAAG,EAAQ,mBAAmB,CAAC,CAAC,KAAK,GAAG,EAC3E,EAAe,CAAC,QAAS,GAAG,EAAQ,mBAAmB,CAAC,CAAC,KAAK,GAAG,EACjE,EAAc,EAAQ,mBAAmB,KAAK,GAAG,GAAK,SAE5D,MAAO,CACL,qBACA,cAAc,IACd,aAAa,IACb,WAAW,IACX,YAAY,IACZ,qBACA,qBACA,iBACF,CAAC,CAAC,KAAK,IAAI,CACb,CAEA,SAAgB,EAAS,EAA0B,CAAC,EAAW,CAC7D,OAAO,EAAoB,EAAwB,CAAO,CAAC,CAC7D"}
package/dist/_policy.d.ts CHANGED
@@ -12,4 +12,5 @@ export interface NormalizedSandboxOptions {
12
12
  }
13
13
  export declare function normalizeSandboxOptions(options?: SandboxOptions): NormalizedSandboxOptions;
14
14
  export declare function buildCspFromOptions(options: NormalizedSandboxOptions): string;
15
+ export declare function buildCsp(options?: SandboxOptions): string;
15
16
  //# sourceMappingURL=_policy.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"_policy.d.ts","sourceRoot":"","sources":["../src/_policy.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAIjD,MAAM,WAAW,wBAAwB;IACvC,kBAAkB,EAAE,MAAM,EAAE,CAAC;IAC7B,mBAAmB,EAAE,MAAM,EAAE,CAAC;IAC9B,oBAAoB,EAAE,MAAM,EAAE,CAAC;IAC/B,mBAAmB,EAAE,MAAM,EAAE,CAAC;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;CACf;AA+DD,wBAAgB,uBAAuB,CAAC,OAAO,GAAE,cAAmB,GAAG,wBAAwB,CAwB9F;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,wBAAwB,GAAG,MAAM,CAqB7E"}
1
+ {"version":3,"file":"_policy.d.ts","sourceRoot":"","sources":["../src/_policy.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjD,MAAM,WAAW,wBAAwB;IACvC,kBAAkB,EAAE,MAAM,EAAE,CAAC;IAC7B,mBAAmB,EAAE,MAAM,EAAE,CAAC;IAC9B,oBAAoB,EAAE,MAAM,EAAE,CAAC;IAC/B,mBAAmB,EAAE,MAAM,EAAE,CAAC;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;CACf;AA+DD,wBAAgB,uBAAuB,CAAC,OAAO,GAAE,cAAmB,GAAG,wBAAwB,CAwB9F;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,wBAAwB,GAAG,MAAM,CAqB7E;AAED,wBAAgB,QAAQ,CAAC,OAAO,GAAE,cAAmB,GAAG,MAAM,CAE7D"}
package/dist/_policy.js CHANGED
@@ -64,7 +64,10 @@ function u(e) {
64
64
  "base-uri 'none'"
65
65
  ].join("; ");
66
66
  }
67
+ function d(e = {}) {
68
+ return u(l(e));
69
+ }
67
70
  //#endregion
68
- export { u as buildCspFromOptions, l as normalizeSandboxOptions };
71
+ export { d as buildCsp, u as buildCspFromOptions, l as normalizeSandboxOptions };
69
72
 
70
73
  //# sourceMappingURL=_policy.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"_policy.js","names":[],"sources":["../src/_policy.ts"],"sourcesContent":["import type { SandboxOptions } from './types.js';\n\nimport { SandboxConfigurationError } from './errors.js';\n\nexport interface NormalizedSandboxOptions {\n allowedFontOrigins: string[];\n allowedImageOrigins: string[];\n allowedScriptOrigins: string[];\n allowedStyleOrigins: string[];\n lang: string;\n namedStyles: Record<string, string>;\n nonce: string | undefined;\n scripts: string[];\n title: string;\n}\n\nconst ID = /^[A-Za-z][A-Za-z0-9_-]*$/;\nconst LANG = /^[A-Za-z]{2,3}(?:-[A-Za-z0-9]{2,8})*$/;\nconst NONCE = /^[A-Za-z0-9+/_-]+={0,2}$/;\n\nfunction fail(field: string, value: unknown): never {\n throw new SandboxConfigurationError(`${field} is invalid: ${String(value)}`);\n}\n\nfunction normalizeOrigin(value: string, field: string): string {\n let url: URL;\n\n try {\n url = new URL(value);\n } catch {\n return fail(field, value);\n }\n\n if (\n (url.protocol !== 'http:' && url.protocol !== 'https:') ||\n url.username ||\n url.password ||\n url.pathname !== '/' ||\n url.search ||\n url.hash\n ) {\n return fail(field, value);\n }\n\n return url.origin;\n}\n\nfunction normalizeOrigins(values: string[] | undefined, field: string): string[] {\n return (values ?? []).map((value) => normalizeOrigin(value, field));\n}\n\nfunction normalizeScript(value: string): string {\n let url: URL;\n\n try {\n url = new URL(value);\n } catch {\n return fail('scripts', value);\n }\n\n if (url.protocol !== 'http:' && url.protocol !== 'https:') return fail('scripts', value);\n\n return url.href;\n}\n\nfunction normalizeStyles(styles: Record<string, string> | undefined): Record<string, string> {\n const normalized: Record<string, string> = {};\n\n for (const [id, css] of Object.entries(styles ?? {})) {\n if (!ID.test(id) || typeof css !== 'string') fail('namedStyles', id);\n\n normalized[id] = css;\n }\n\n return normalized;\n}\n\nexport function normalizeSandboxOptions(options: SandboxOptions = {}): NormalizedSandboxOptions {\n const lang = options.lang ?? 'en';\n\n if (!LANG.test(lang)) fail('lang', lang);\n\n if (options.nonce !== undefined && (!NONCE.test(options.nonce) || options.nonce.length === 0)) {\n fail('nonce', options.nonce);\n }\n\n if (options.title !== undefined && typeof options.title !== 'string') fail('title', options.title);\n\n const scripts = (options.scripts ?? []).map(normalizeScript);\n\n return {\n allowedFontOrigins: normalizeOrigins(options.allowedFontOrigins, 'allowedFontOrigins'),\n allowedImageOrigins: normalizeOrigins(options.allowedImageOrigins, 'allowedImageOrigins'),\n allowedScriptOrigins: normalizeOrigins(options.allowedScriptOrigins, 'allowedScriptOrigins'),\n allowedStyleOrigins: normalizeOrigins(options.allowedStyleOrigins, 'allowedStyleOrigins'),\n lang,\n namedStyles: normalizeStyles(options.namedStyles),\n nonce: options.nonce,\n scripts,\n title: options.title ?? '',\n };\n}\n\nexport function buildCspFromOptions(options: NormalizedSandboxOptions): string {\n const scriptOrigins = [\n \"'unsafe-inline'\",\n ...(options.nonce ? [`'nonce-${options.nonce}'`] : []),\n ...options.allowedScriptOrigins,\n ...options.scripts.map((script) => new URL(script).origin),\n ].join(' ');\n const styleOrigins = [\"'unsafe-inline'\", ...options.allowedStyleOrigins].join(' ');\n const imageOrigins = ['data:', ...options.allowedImageOrigins].join(' ');\n const fontOrigins = options.allowedFontOrigins.join(' ') || \"'none'\";\n\n return [\n \"default-src 'none'\",\n `script-src ${scriptOrigins}`,\n `style-src ${styleOrigins}`,\n `img-src ${imageOrigins}`,\n `font-src ${fontOrigins}`,\n \"connect-src 'none'\",\n \"form-action 'none'\",\n \"base-uri 'none'\",\n ].join('; ');\n}\n"],"mappings":";;AAgBA,IAAM,IAAK,4BACL,IAAO,yCACP,IAAQ;AAEd,SAAS,EAAK,GAAe,GAAuB;CAClD,MAAM,IAAI,EAA0B,GAAG,EAAM,eAAe,OAAO,CAAK,GAAG;AAC7E;AAEA,SAAS,EAAgB,GAAe,GAAuB;CAC7D,IAAI;CAEJ,IAAI;EACF,IAAM,IAAI,IAAI,CAAK;CACrB,QAAQ;EACN,OAAO,EAAK,GAAO,CAAK;CAC1B;CAaA,OAVG,EAAI,aAAa,WAAW,EAAI,aAAa,YAC9C,EAAI,YACJ,EAAI,YACJ,EAAI,aAAa,OACjB,EAAI,UACJ,EAAI,OAEG,EAAK,GAAO,CAAK,IAGnB,EAAI;AACb;AAEA,SAAS,EAAiB,GAA8B,GAAyB;CAC/E,QAAQ,KAAU,CAAC,EAAA,CAAG,KAAK,MAAU,EAAgB,GAAO,CAAK,CAAC;AACpE;AAEA,SAAS,EAAgB,GAAuB;CAC9C,IAAI;CAEJ,IAAI;EACF,IAAM,IAAI,IAAI,CAAK;CACrB,QAAQ;EACN,OAAO,EAAK,WAAW,CAAK;CAC9B;CAIA,OAFI,EAAI,aAAa,WAAW,EAAI,aAAa,WAAiB,EAAK,WAAW,CAAK,IAEhF,EAAI;AACb;AAEA,SAAS,EAAgB,GAAoE;CAC3F,IAAM,IAAqC,CAAC;CAE5C,KAAK,IAAM,CAAC,GAAI,MAAQ,OAAO,QAAQ,KAAU,CAAC,CAAC,GAGjD,CAFI,CAAC,EAAG,KAAK,CAAE,KAAK,OAAO,KAAQ,aAAU,EAAK,eAAe,CAAE,GAEnE,EAAW,KAAM;CAGnB,OAAO;AACT;AAEA,SAAgB,EAAwB,IAA0B,CAAC,GAA6B;CAC9F,IAAM,IAAO,EAAQ,QAAQ;CAQ7B,AANK,EAAK,KAAK,CAAI,KAAG,EAAK,QAAQ,CAAI,GAEnC,EAAQ,UAAU,KAAA,MAAc,CAAC,EAAM,KAAK,EAAQ,KAAK,KAAK,EAAQ,MAAM,WAAW,MACzF,EAAK,SAAS,EAAQ,KAAK,GAGzB,EAAQ,UAAU,KAAA,KAAa,OAAO,EAAQ,SAAU,YAAU,EAAK,SAAS,EAAQ,KAAK;CAEjG,IAAM,KAAW,EAAQ,WAAW,CAAC,EAAA,CAAG,IAAI,CAAe;CAE3D,OAAO;EACL,oBAAoB,EAAiB,EAAQ,oBAAoB,oBAAoB;EACrF,qBAAqB,EAAiB,EAAQ,qBAAqB,qBAAqB;EACxF,sBAAsB,EAAiB,EAAQ,sBAAsB,sBAAsB;EAC3F,qBAAqB,EAAiB,EAAQ,qBAAqB,qBAAqB;EACxF;EACA,aAAa,EAAgB,EAAQ,WAAW;EAChD,OAAO,EAAQ;EACf;EACA,OAAO,EAAQ,SAAS;CAC1B;AACF;AAEA,SAAgB,EAAoB,GAA2C;CAC7E,IAAM,IAAgB;EACpB;EACA,GAAI,EAAQ,QAAQ,CAAC,UAAU,EAAQ,MAAM,EAAE,IAAI,CAAC;EACpD,GAAG,EAAQ;EACX,GAAG,EAAQ,QAAQ,KAAK,MAAW,IAAI,IAAI,CAAM,CAAC,CAAC,MAAM;CAC3D,CAAC,CAAC,KAAK,GAAG,GACJ,IAAe,CAAC,mBAAmB,GAAG,EAAQ,mBAAmB,CAAC,CAAC,KAAK,GAAG,GAC3E,IAAe,CAAC,SAAS,GAAG,EAAQ,mBAAmB,CAAC,CAAC,KAAK,GAAG,GACjE,IAAc,EAAQ,mBAAmB,KAAK,GAAG,KAAK;CAE5D,OAAO;EACL;EACA,cAAc;EACd,aAAa;EACb,WAAW;EACX,YAAY;EACZ;EACA;EACA;CACF,CAAC,CAAC,KAAK,IAAI;AACb"}
1
+ {"version":3,"file":"_policy.js","names":[],"sources":["../src/_policy.ts"],"sourcesContent":["import { SandboxConfigurationError } from './errors.js';\nimport type { SandboxOptions } from './types.js';\n\nexport interface NormalizedSandboxOptions {\n allowedFontOrigins: string[];\n allowedImageOrigins: string[];\n allowedScriptOrigins: string[];\n allowedStyleOrigins: string[];\n lang: string;\n namedStyles: Record<string, string>;\n nonce: string | undefined;\n scripts: string[];\n title: string;\n}\n\nconst ID = /^[A-Za-z][A-Za-z0-9_-]*$/;\nconst LANG = /^[A-Za-z]{2,3}(?:-[A-Za-z0-9]{2,8})*$/;\nconst NONCE = /^[A-Za-z0-9+/_-]+={0,2}$/;\n\nfunction fail(field: string, value: unknown): never {\n throw new SandboxConfigurationError(`${field} is invalid: ${String(value)}`);\n}\n\nfunction normalizeOrigin(value: string, field: string): string {\n let url: URL;\n\n try {\n url = new URL(value);\n } catch {\n return fail(field, value);\n }\n\n if (\n (url.protocol !== 'http:' && url.protocol !== 'https:') ||\n url.username ||\n url.password ||\n url.pathname !== '/' ||\n url.search ||\n url.hash\n ) {\n return fail(field, value);\n }\n\n return url.origin;\n}\n\nfunction normalizeOrigins(values: string[] | undefined, field: string): string[] {\n return (values ?? []).map((value) => normalizeOrigin(value, field));\n}\n\nfunction normalizeScript(value: string): string {\n let url: URL;\n\n try {\n url = new URL(value);\n } catch {\n return fail('scripts', value);\n }\n\n if (url.protocol !== 'http:' && url.protocol !== 'https:') return fail('scripts', value);\n\n return url.href;\n}\n\nfunction normalizeStyles(styles: Record<string, string> | undefined): Record<string, string> {\n const normalized: Record<string, string> = {};\n\n for (const [id, css] of Object.entries(styles ?? {})) {\n if (!ID.test(id) || typeof css !== 'string') fail('namedStyles', id);\n\n normalized[id] = css;\n }\n\n return normalized;\n}\n\nexport function normalizeSandboxOptions(options: SandboxOptions = {}): NormalizedSandboxOptions {\n const lang = options.lang ?? 'en';\n\n if (!LANG.test(lang)) fail('lang', lang);\n\n if (options.nonce !== undefined && (!NONCE.test(options.nonce) || options.nonce.length === 0)) {\n fail('nonce', options.nonce);\n }\n\n if (options.title !== undefined && typeof options.title !== 'string') fail('title', options.title);\n\n const scripts = (options.scripts ?? []).map(normalizeScript);\n\n return {\n allowedFontOrigins: normalizeOrigins(options.allowedFontOrigins, 'allowedFontOrigins'),\n allowedImageOrigins: normalizeOrigins(options.allowedImageOrigins, 'allowedImageOrigins'),\n allowedScriptOrigins: normalizeOrigins(options.allowedScriptOrigins, 'allowedScriptOrigins'),\n allowedStyleOrigins: normalizeOrigins(options.allowedStyleOrigins, 'allowedStyleOrigins'),\n lang,\n namedStyles: normalizeStyles(options.namedStyles),\n nonce: options.nonce,\n scripts,\n title: options.title ?? '',\n };\n}\n\nexport function buildCspFromOptions(options: NormalizedSandboxOptions): string {\n const scriptOrigins = [\n \"'unsafe-inline'\",\n ...(options.nonce ? [`'nonce-${options.nonce}'`] : []),\n ...options.allowedScriptOrigins,\n ...options.scripts.map((script) => new URL(script).origin),\n ].join(' ');\n const styleOrigins = [\"'unsafe-inline'\", ...options.allowedStyleOrigins].join(' ');\n const imageOrigins = ['data:', ...options.allowedImageOrigins].join(' ');\n const fontOrigins = options.allowedFontOrigins.join(' ') || \"'none'\";\n\n return [\n \"default-src 'none'\",\n `script-src ${scriptOrigins}`,\n `style-src ${styleOrigins}`,\n `img-src ${imageOrigins}`,\n `font-src ${fontOrigins}`,\n \"connect-src 'none'\",\n \"form-action 'none'\",\n \"base-uri 'none'\",\n ].join('; ');\n}\n\nexport function buildCsp(options: SandboxOptions = {}): string {\n return buildCspFromOptions(normalizeSandboxOptions(options));\n}\n"],"mappings":";;AAeA,IAAM,IAAK,4BACL,IAAO,yCACP,IAAQ;AAEd,SAAS,EAAK,GAAe,GAAuB;CAClD,MAAM,IAAI,EAA0B,GAAG,EAAM,eAAe,OAAO,CAAK,GAAG;AAC7E;AAEA,SAAS,EAAgB,GAAe,GAAuB;CAC7D,IAAI;CAEJ,IAAI;EACF,IAAM,IAAI,IAAI,CAAK;CACrB,QAAQ;EACN,OAAO,EAAK,GAAO,CAAK;CAC1B;CAaA,OAVG,EAAI,aAAa,WAAW,EAAI,aAAa,YAC9C,EAAI,YACJ,EAAI,YACJ,EAAI,aAAa,OACjB,EAAI,UACJ,EAAI,OAEG,EAAK,GAAO,CAAK,IAGnB,EAAI;AACb;AAEA,SAAS,EAAiB,GAA8B,GAAyB;CAC/E,QAAQ,KAAU,CAAC,EAAA,CAAG,KAAK,MAAU,EAAgB,GAAO,CAAK,CAAC;AACpE;AAEA,SAAS,EAAgB,GAAuB;CAC9C,IAAI;CAEJ,IAAI;EACF,IAAM,IAAI,IAAI,CAAK;CACrB,QAAQ;EACN,OAAO,EAAK,WAAW,CAAK;CAC9B;CAIA,OAFI,EAAI,aAAa,WAAW,EAAI,aAAa,WAAiB,EAAK,WAAW,CAAK,IAEhF,EAAI;AACb;AAEA,SAAS,EAAgB,GAAoE;CAC3F,IAAM,IAAqC,CAAC;CAE5C,KAAK,IAAM,CAAC,GAAI,MAAQ,OAAO,QAAQ,KAAU,CAAC,CAAC,GAGjD,CAFI,CAAC,EAAG,KAAK,CAAE,KAAK,OAAO,KAAQ,aAAU,EAAK,eAAe,CAAE,GAEnE,EAAW,KAAM;CAGnB,OAAO;AACT;AAEA,SAAgB,EAAwB,IAA0B,CAAC,GAA6B;CAC9F,IAAM,IAAO,EAAQ,QAAQ;CAQ7B,AANK,EAAK,KAAK,CAAI,KAAG,EAAK,QAAQ,CAAI,GAEnC,EAAQ,UAAU,KAAA,MAAc,CAAC,EAAM,KAAK,EAAQ,KAAK,KAAK,EAAQ,MAAM,WAAW,MACzF,EAAK,SAAS,EAAQ,KAAK,GAGzB,EAAQ,UAAU,KAAA,KAAa,OAAO,EAAQ,SAAU,YAAU,EAAK,SAAS,EAAQ,KAAK;CAEjG,IAAM,KAAW,EAAQ,WAAW,CAAC,EAAA,CAAG,IAAI,CAAe;CAE3D,OAAO;EACL,oBAAoB,EAAiB,EAAQ,oBAAoB,oBAAoB;EACrF,qBAAqB,EAAiB,EAAQ,qBAAqB,qBAAqB;EACxF,sBAAsB,EAAiB,EAAQ,sBAAsB,sBAAsB;EAC3F,qBAAqB,EAAiB,EAAQ,qBAAqB,qBAAqB;EACxF;EACA,aAAa,EAAgB,EAAQ,WAAW;EAChD,OAAO,EAAQ;EACf;EACA,OAAO,EAAQ,SAAS;CAC1B;AACF;AAEA,SAAgB,EAAoB,GAA2C;CAC7E,IAAM,IAAgB;EACpB;EACA,GAAI,EAAQ,QAAQ,CAAC,UAAU,EAAQ,MAAM,EAAE,IAAI,CAAC;EACpD,GAAG,EAAQ;EACX,GAAG,EAAQ,QAAQ,KAAK,MAAW,IAAI,IAAI,CAAM,CAAC,CAAC,MAAM;CAC3D,CAAC,CAAC,KAAK,GAAG,GACJ,IAAe,CAAC,mBAAmB,GAAG,EAAQ,mBAAmB,CAAC,CAAC,KAAK,GAAG,GAC3E,IAAe,CAAC,SAAS,GAAG,EAAQ,mBAAmB,CAAC,CAAC,KAAK,GAAG,GACjE,IAAc,EAAQ,mBAAmB,KAAK,GAAG,KAAK;CAE5D,OAAO;EACL;EACA,cAAc;EACd,aAAa;EACb,WAAW;EACX,YAAY;EACZ;EACA;EACA;CACF,CAAC,CAAC,KAAK,IAAI;AACb;AAEA,SAAgB,EAAS,IAA0B,CAAC,GAAW;CAC7D,OAAO,EAAoB,EAAwB,CAAO,CAAC;AAC7D"}
package/dist/_runtime.cjs CHANGED
@@ -1,2 +1,2 @@
1
- const e=require("./errors.cjs"),t=require("./_policy.cjs"),n=require("./_document.cjs");require("./_dev.cjs");const r=require("./_protocol.cjs");var i=5e3;function a(a,o={}){let s=t.normalizeSandboxOptions(o),c=r.createChannel(),l={...s.namedStyles},u=new Set,d=new AbortController,f=null,p=!1,m=!1,h=0,g=null,_=null,v,y=new Promise(e=>{v=e});function b(){return{channel:c,generation:h}}function x(){g!==null&&(clearTimeout(g),g=null)}function S(){x(),_?.resolve(),_=null,m=!1}function C(e){for(let t of u)t(e)}function w(e){if(!f||e.source!==f.contentWindow)return;let t=b();if(r.isProtocolMessage(e.data,t))switch(e.data.type){case r.MSG_CUSTOM:typeof e.data.event==`string`&&C({detail:e.data.detail,event:e.data.event,type:r.MSG_CUSTOM});break;case r.MSG_ERROR:typeof e.data.message==`string`&&C({message:e.data.message,...typeof e.data.stack==`string`?{stack:e.data.stack}:{},type:r.MSG_ERROR});break;case r.MSG_READY:S(),v(),m=!0;break;case r.MSG_RESIZE:typeof e.data.height==`number`&&Number.isFinite(e.data.height)&&e.data.height>=0&&C({height:e.data.height,type:r.MSG_RESIZE})}}function T(){return f||(f=document.createElement(`iframe`),f.setAttribute(`sandbox`,`allow-scripts`),f.setAttribute(`referrerpolicy`,`no-referrer`),f.dataset.sandboxChannel=c,a.appendChild(f),window.addEventListener(`message`,w),f)}function E(){p||(p=!0,S(),d.abort(),v(),f&&=(window.removeEventListener(`message`,w),f.remove(),null),u.clear())}function D(e){return p?()=>{}:(u.add(e),()=>u.delete(e))}function O(t,r){if(p||r?.signal?.aborted)return Promise.resolve();t.trim(),S(),h+=1;let a=T(),o=b(),c={...s,namedStyles:{...l}};a.dataset.sandboxGeneration=String(h),a.srcdoc=n.buildRuntimeDocument(t,c,o);let u=new Promise((e,t)=>{_={reject:t,resolve:e}});return g=setTimeout(()=>{_&&(_.reject(new e.SandboxTimeoutError(`render() did not receive a 'ready' signal from the sandbox document within ${i}ms. The document is likely missing the bridge script — use buildDocument() to generate documents that include it.`)),_=null,g=null)},i),u}function k(e){f?.contentWindow?.postMessage(r.envelope(b(),e),`*`)}function A(e){p||!m||!f?.contentWindow||k({html:e,type:r.MSG_HTML_REPLACE})}function j(e,t){p||f?.contentWindow&&k({key:e,type:r.MSG_STATE_UPDATE,value:t})}function M(e){p||f?.contentWindow&&k({record:e,type:r.MSG_STATE_UPDATE_ALL})}function N(e,t){p||(l[e]=t,m&&f?.contentWindow&&k({css:t,id:e,type:r.MSG_STYLE_PATCH}))}return{get disposalSignal(){return d.signal},dispose:E,get disposed(){return p},onMessage:D,ready:y,render:O,replaceBody:A,setState:j,setStateAll:M,[Symbol.dispose](){E()},updateStyle:N}}exports.createSandbox=a;
1
+ const e=require("./errors.cjs"),t=require("./_policy.cjs"),n=require("./_document.cjs");require("./_dev.cjs");const r=require("./_protocol.cjs");var i=5e3;function a(a,o={}){let s=t.normalizeSandboxOptions(o),c=r.createChannel(),l={...s.namedStyles},u=new Set,d=new AbortController,f=null,p=!1,m=!1,h=0,g=null,_=null,v,y=new Promise(e=>{v=e});function b(){return{channel:c,generation:h}}function x(){g!==null&&(clearTimeout(g),g=null)}function S(){x(),_?.resolve(),_=null,m=!1}function C(e){for(let t of u)t(e)}function w(e){if(!f||e.source!==f.contentWindow)return;let t=b();if(r.isProtocolMessage(e.data,t))switch(e.data.type){case r.MSG_CUSTOM:typeof e.data.event==`string`&&C({detail:e.data.detail,event:e.data.event,type:r.MSG_CUSTOM});break;case r.MSG_ERROR:typeof e.data.message==`string`&&C({message:e.data.message,...typeof e.data.stack==`string`?{stack:e.data.stack}:{},type:r.MSG_ERROR});break;case r.MSG_READY:S(),v(),m=!0;break;case r.MSG_RESIZE:typeof e.data.height==`number`&&Number.isFinite(e.data.height)&&e.data.height>=0&&C({height:e.data.height,type:r.MSG_RESIZE})}}function T(){return f||(f=document.createElement(`iframe`),f.setAttribute(`sandbox`,`allow-scripts`),f.setAttribute(`referrerpolicy`,`no-referrer`),f.dataset.sandboxChannel=c,a.appendChild(f),window.addEventListener(`message`,w),f)}function E(){p||(p=!0,S(),d.abort(),v(),f&&=(window.removeEventListener(`message`,w),f.remove(),null),u.clear())}function D(e){return p?()=>{}:(u.add(e),()=>u.delete(e))}function O(t,r){if(p||r?.signal?.aborted)return Promise.resolve();t.trim(),S(),h+=1;let a=T(),o=b(),c={...s,namedStyles:{...l}};a.dataset.sandboxGeneration=String(h),a.srcdoc=n.buildDocumentFromOptions(t,c,o);let u=new Promise((e,t)=>{_={reject:t,resolve:e}});return g=setTimeout(()=>{_&&(_.reject(new e.SandboxTimeoutError(`render() did not receive a 'ready' signal from the sandbox document within ${i}ms. The document is likely missing the bridge script — use buildDocument() to generate documents that include it.`)),_=null,g=null)},i),u}function k(e){f?.contentWindow?.postMessage(r.envelope(b(),e),`*`)}function A(e){p||!m||!f?.contentWindow||k({html:e,type:r.MSG_HTML_REPLACE})}function j(e,t){p||f?.contentWindow&&k({key:e,type:r.MSG_STATE_UPDATE,value:t})}function M(e){p||f?.contentWindow&&k({record:e,type:r.MSG_STATE_UPDATE_ALL})}function N(e,t){p||(l[e]=t,m&&f?.contentWindow&&k({css:t,id:e,type:r.MSG_STYLE_PATCH}))}return{get disposalSignal(){return d.signal},dispose:E,get disposed(){return p},onMessage:D,ready:y,render:O,replaceBody:A,setState:j,setStateAll:M,[Symbol.dispose](){E()},updateStyle:N}}exports.createSandbox=a;
2
2
  //# sourceMappingURL=_runtime.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"_runtime.cjs","names":[],"sources":["../src/_runtime.ts"],"sourcesContent":["import type { SandboxHandle, SandboxMessage, SandboxOptions, Unsubscribe } from './types.js';\n\nimport { devOnly, warn } from './_dev.js';\nimport { buildRuntimeDocument } from './_document.js';\nimport { normalizeSandboxOptions } from './_policy.js';\nimport {\n createChannel,\n envelope,\n isProtocolMessage,\n MSG_CUSTOM,\n MSG_ERROR,\n MSG_HTML_REPLACE,\n MSG_READY,\n MSG_RESIZE,\n MSG_STATE_UPDATE,\n MSG_STATE_UPDATE_ALL,\n MSG_STYLE_PATCH,\n type BridgeBootstrap,\n} from './_protocol.js';\nimport { SandboxTimeoutError } from './errors.js';\n\nconst READY_TIMEOUT_MS = 5000;\n\nexport function createSandbox(container: HTMLElement, options: SandboxOptions = {}): SandboxHandle {\n const normalized = normalizeSandboxOptions(options);\n const channel = createChannel();\n const namedStyles: Record<string, string> = { ...normalized.namedStyles };\n const listeners = new Set<(message: SandboxMessage) => void>();\n const controller = new AbortController();\n let iframe: HTMLIFrameElement | null = null;\n let disposed = false;\n let bridgeReady = false;\n let generation = 0;\n let readyTimeout: ReturnType<typeof setTimeout> | null = null;\n let currentRender: { reject: (error: unknown) => void; resolve: () => void } | null = null;\n\n let resolveReady!: () => void;\n const ready = new Promise<void>((resolve) => {\n resolveReady = resolve;\n });\n\n function currentBootstrap(): BridgeBootstrap {\n return { channel, generation };\n }\n\n function clearReadyTimeout(): void {\n if (readyTimeout === null) return;\n\n clearTimeout(readyTimeout);\n readyTimeout = null;\n }\n\n function supersedePendingRender(): void {\n clearReadyTimeout();\n currentRender?.resolve();\n currentRender = null;\n bridgeReady = false;\n }\n\n function broadcast(message: SandboxMessage): void {\n for (const listener of listeners) listener(message);\n }\n\n function handleMessage(event: MessageEvent): void {\n if (!iframe || event.source !== iframe.contentWindow) return;\n\n const bootstrap = currentBootstrap();\n\n if (!isProtocolMessage(event.data, bootstrap)) return;\n\n switch (event.data.type) {\n case MSG_CUSTOM:\n if (typeof event.data.event === 'string') {\n broadcast({ detail: event.data.detail, event: event.data.event, type: MSG_CUSTOM });\n }\n\n break;\n case MSG_ERROR:\n if (typeof event.data.message === 'string') {\n broadcast({\n message: event.data.message,\n ...(typeof event.data.stack === 'string' ? { stack: event.data.stack } : {}),\n type: MSG_ERROR,\n });\n }\n\n break;\n case MSG_READY:\n supersedePendingRender();\n resolveReady();\n bridgeReady = true;\n break;\n case MSG_RESIZE:\n if (typeof event.data.height === 'number' && Number.isFinite(event.data.height) && event.data.height >= 0) {\n broadcast({ height: event.data.height, type: MSG_RESIZE });\n }\n\n break;\n }\n }\n\n function ensureIframe(): HTMLIFrameElement {\n if (iframe) return iframe;\n\n iframe = document.createElement('iframe');\n iframe.setAttribute('sandbox', 'allow-scripts');\n iframe.setAttribute('referrerpolicy', 'no-referrer');\n iframe.dataset.sandboxChannel = channel;\n container.appendChild(iframe);\n window.addEventListener('message', handleMessage);\n\n return iframe;\n }\n\n function dispose(): void {\n if (disposed) return;\n\n disposed = true;\n supersedePendingRender();\n controller.abort();\n resolveReady();\n\n if (iframe) {\n window.removeEventListener('message', handleMessage);\n iframe.remove();\n iframe = null;\n }\n\n listeners.clear();\n }\n\n function onMessage(handler: (message: SandboxMessage) => void): Unsubscribe {\n if (disposed) {\n warn('onMessage() called on a disposed sandbox — handler will never fire.');\n\n return () => {};\n }\n\n listeners.add(handler);\n\n return () => listeners.delete(handler);\n }\n\n function render(html: string, renderOptions?: { signal?: AbortSignal }): Promise<void> {\n if (disposed) {\n warn('render() called on a disposed sandbox.');\n\n return Promise.resolve();\n }\n\n if (renderOptions?.signal?.aborted) return Promise.resolve();\n\n if (!html.trim()) warn('render() called with empty HTML.');\n\n supersedePendingRender();\n generation += 1;\n\n const current = ensureIframe();\n const bootstrap = currentBootstrap();\n const documentOptions = { ...normalized, namedStyles: { ...namedStyles } };\n\n current.dataset.sandboxGeneration = String(generation);\n current.srcdoc = buildRuntimeDocument(html, documentOptions, bootstrap);\n\n const promise = new Promise<void>((resolve, reject) => {\n currentRender = { reject, resolve };\n });\n\n readyTimeout = setTimeout(() => {\n if (!currentRender) return;\n\n currentRender.reject(\n new SandboxTimeoutError(\n `render() did not receive a 'ready' signal from the sandbox document within ${READY_TIMEOUT_MS}ms. ` +\n 'The document is likely missing the bridge script — use buildDocument() to generate documents that include it.',\n ),\n );\n currentRender = null;\n readyTimeout = null;\n }, READY_TIMEOUT_MS);\n\n return promise;\n }\n\n function send(message: Record<string, unknown>): void {\n iframe?.contentWindow?.postMessage(envelope(currentBootstrap(), message), '*');\n }\n\n function replaceBody(html: string): void {\n if (disposed) {\n warn('replaceBody() called on a disposed sandbox.');\n\n return;\n }\n\n if (!bridgeReady || !iframe?.contentWindow) {\n warn('replaceBody() called before render() has resolved — bridge is not ready. Await render() first.');\n\n return;\n }\n\n send({ html, type: MSG_HTML_REPLACE });\n }\n\n function setState(key: string, value: unknown): void {\n if (disposed) {\n warn('setState() called on a disposed sandbox.');\n\n return;\n }\n\n if (!iframe?.contentWindow) {\n warn('setState() called before render() — sandbox has no document yet.');\n\n return;\n }\n\n if (!bridgeReady) {\n warn('setState() called before ready — state update may be lost. Await render() first.');\n }\n\n send({ key, type: MSG_STATE_UPDATE, value });\n }\n\n function setStateAll(record: Record<string, unknown>): void {\n if (disposed) {\n warn('setStateAll() called on a disposed sandbox.');\n\n return;\n }\n\n if (!iframe?.contentWindow) {\n warn('setStateAll() called before render() — sandbox has no document yet.');\n\n return;\n }\n\n if (!bridgeReady) {\n warn('setStateAll() called before ready — state updates may be lost. Await render() first.');\n }\n\n send({ record, type: MSG_STATE_UPDATE_ALL });\n }\n\n function updateStyle(id: string, css: string): void {\n if (disposed) return;\n\n devOnly(() => {\n if (!(id in namedStyles)) {\n warn(`updateStyle('${id}', …) — '${id}' is not a known namedStyles key.`);\n }\n });\n\n namedStyles[id] = css;\n\n if (bridgeReady && iframe?.contentWindow) send({ css, id, type: MSG_STYLE_PATCH });\n }\n\n return {\n get disposalSignal() {\n return controller.signal;\n },\n dispose,\n get disposed() {\n return disposed;\n },\n onMessage,\n ready,\n render,\n replaceBody,\n setState,\n setStateAll,\n [Symbol.dispose]() {\n dispose();\n },\n updateStyle,\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"_runtime.cjs","names":[],"sources":["../src/_runtime.ts"],"sourcesContent":["import { devOnly, warn } from './_dev.js';\nimport { buildDocumentFromOptions } from './_document.js';\nimport { normalizeSandboxOptions } from './_policy.js';\nimport {\n type BridgeBootstrap,\n createChannel,\n envelope,\n isProtocolMessage,\n MSG_CUSTOM,\n MSG_ERROR,\n MSG_HTML_REPLACE,\n MSG_READY,\n MSG_RESIZE,\n MSG_STATE_UPDATE,\n MSG_STATE_UPDATE_ALL,\n MSG_STYLE_PATCH,\n} from './_protocol.js';\nimport { SandboxTimeoutError } from './errors.js';\nimport type { SandboxHandle, SandboxMessage, SandboxOptions, Unsubscribe } from './types.js';\n\nconst READY_TIMEOUT_MS = 5000;\n\nexport function createSandbox(container: HTMLElement, options: SandboxOptions = {}): SandboxHandle {\n const normalized = normalizeSandboxOptions(options);\n const channel = createChannel();\n const namedStyles: Record<string, string> = { ...normalized.namedStyles };\n const listeners = new Set<(message: SandboxMessage) => void>();\n const controller = new AbortController();\n let iframe: HTMLIFrameElement | null = null;\n let disposed = false;\n let bridgeReady = false;\n let generation = 0;\n let readyTimeout: ReturnType<typeof setTimeout> | null = null;\n let currentRender: { reject: (error: unknown) => void; resolve: () => void } | null = null;\n\n let resolveReady!: () => void;\n const ready = new Promise<void>((resolve) => {\n resolveReady = resolve;\n });\n\n function currentBootstrap(): BridgeBootstrap {\n return { channel, generation };\n }\n\n function clearReadyTimeout(): void {\n if (readyTimeout === null) return;\n\n clearTimeout(readyTimeout);\n readyTimeout = null;\n }\n\n function supersedePendingRender(): void {\n clearReadyTimeout();\n currentRender?.resolve();\n currentRender = null;\n bridgeReady = false;\n }\n\n function broadcast(message: SandboxMessage): void {\n for (const listener of listeners) listener(message);\n }\n\n function handleMessage(event: MessageEvent): void {\n if (!iframe || event.source !== iframe.contentWindow) return;\n\n const bootstrap = currentBootstrap();\n\n if (!isProtocolMessage(event.data, bootstrap)) return;\n\n switch (event.data.type) {\n case MSG_CUSTOM:\n if (typeof event.data.event === 'string') {\n broadcast({ detail: event.data.detail, event: event.data.event, type: MSG_CUSTOM });\n }\n\n break;\n case MSG_ERROR:\n if (typeof event.data.message === 'string') {\n broadcast({\n message: event.data.message,\n ...(typeof event.data.stack === 'string' ? { stack: event.data.stack } : {}),\n type: MSG_ERROR,\n });\n }\n\n break;\n case MSG_READY:\n supersedePendingRender();\n resolveReady();\n bridgeReady = true;\n break;\n case MSG_RESIZE:\n if (typeof event.data.height === 'number' && Number.isFinite(event.data.height) && event.data.height >= 0) {\n broadcast({ height: event.data.height, type: MSG_RESIZE });\n }\n\n break;\n }\n }\n\n function ensureIframe(): HTMLIFrameElement {\n if (iframe) return iframe;\n\n iframe = document.createElement('iframe');\n iframe.setAttribute('sandbox', 'allow-scripts');\n iframe.setAttribute('referrerpolicy', 'no-referrer');\n iframe.dataset.sandboxChannel = channel;\n container.appendChild(iframe);\n window.addEventListener('message', handleMessage);\n\n return iframe;\n }\n\n function dispose(): void {\n if (disposed) return;\n\n disposed = true;\n supersedePendingRender();\n controller.abort();\n resolveReady();\n\n if (iframe) {\n window.removeEventListener('message', handleMessage);\n iframe.remove();\n iframe = null;\n }\n\n listeners.clear();\n }\n\n function onMessage(handler: (message: SandboxMessage) => void): Unsubscribe {\n if (disposed) {\n warn('onMessage() called on a disposed sandbox — handler will never fire.');\n\n return () => {};\n }\n\n listeners.add(handler);\n\n return () => listeners.delete(handler);\n }\n\n function render(html: string, renderOptions?: { signal?: AbortSignal }): Promise<void> {\n if (disposed) {\n warn('render() called on a disposed sandbox.');\n\n return Promise.resolve();\n }\n\n if (renderOptions?.signal?.aborted) return Promise.resolve();\n\n if (!html.trim()) warn('render() called with empty HTML.');\n\n supersedePendingRender();\n generation += 1;\n\n const current = ensureIframe();\n const bootstrap = currentBootstrap();\n const documentOptions = { ...normalized, namedStyles: { ...namedStyles } };\n\n current.dataset.sandboxGeneration = String(generation);\n current.srcdoc = buildDocumentFromOptions(html, documentOptions, bootstrap);\n\n const promise = new Promise<void>((resolve, reject) => {\n currentRender = { reject, resolve };\n });\n\n readyTimeout = setTimeout(() => {\n if (!currentRender) return;\n\n currentRender.reject(\n new SandboxTimeoutError(\n `render() did not receive a 'ready' signal from the sandbox document within ${READY_TIMEOUT_MS}ms. ` +\n 'The document is likely missing the bridge script — use buildDocument() to generate documents that include it.',\n ),\n );\n currentRender = null;\n readyTimeout = null;\n }, READY_TIMEOUT_MS);\n\n return promise;\n }\n\n function send(message: Record<string, unknown>): void {\n iframe?.contentWindow?.postMessage(envelope(currentBootstrap(), message), '*');\n }\n\n function replaceBody(html: string): void {\n if (disposed) {\n warn('replaceBody() called on a disposed sandbox.');\n\n return;\n }\n\n if (!bridgeReady || !iframe?.contentWindow) {\n warn('replaceBody() called before render() has resolved — bridge is not ready. Await render() first.');\n\n return;\n }\n\n send({ html, type: MSG_HTML_REPLACE });\n }\n\n function setState(key: string, value: unknown): void {\n if (disposed) {\n warn('setState() called on a disposed sandbox.');\n\n return;\n }\n\n if (!iframe?.contentWindow) {\n warn('setState() called before render() — sandbox has no document yet.');\n\n return;\n }\n\n if (!bridgeReady) {\n warn('setState() called before ready — state update may be lost. Await render() first.');\n }\n\n send({ key, type: MSG_STATE_UPDATE, value });\n }\n\n function setStateAll(record: Record<string, unknown>): void {\n if (disposed) {\n warn('setStateAll() called on a disposed sandbox.');\n\n return;\n }\n\n if (!iframe?.contentWindow) {\n warn('setStateAll() called before render() — sandbox has no document yet.');\n\n return;\n }\n\n if (!bridgeReady) {\n warn('setStateAll() called before ready — state updates may be lost. Await render() first.');\n }\n\n send({ record, type: MSG_STATE_UPDATE_ALL });\n }\n\n function updateStyle(id: string, css: string): void {\n if (disposed) return;\n\n devOnly(() => {\n if (!(id in namedStyles)) {\n warn(`updateStyle('${id}', …) — '${id}' is not a known namedStyles key.`);\n }\n });\n\n namedStyles[id] = css;\n\n if (bridgeReady && iframe?.contentWindow) send({ css, id, type: MSG_STYLE_PATCH });\n }\n\n return {\n get disposalSignal() {\n return controller.signal;\n },\n dispose,\n get disposed() {\n return disposed;\n },\n onMessage,\n ready,\n render,\n replaceBody,\n setState,\n setStateAll,\n [Symbol.dispose]() {\n dispose();\n },\n updateStyle,\n };\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"_runtime.d.ts","sourceRoot":"","sources":["../src/_runtime.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAkB,cAAc,EAAe,MAAM,YAAY,CAAC;AAuB7F,wBAAgB,aAAa,CAAC,SAAS,EAAE,WAAW,EAAE,OAAO,GAAE,cAAmB,GAAG,aAAa,CA8PjG"}
1
+ {"version":3,"file":"_runtime.d.ts","sourceRoot":"","sources":["../src/_runtime.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAE,aAAa,EAAkB,cAAc,EAAe,MAAM,YAAY,CAAC;AAI7F,wBAAgB,aAAa,CAAC,SAAS,EAAE,WAAW,EAAE,OAAO,GAAE,cAAmB,GAAG,aAAa,CA8PjG"}
package/dist/_runtime.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { SandboxTimeoutError as e } from "./errors.js";
2
2
  import { normalizeSandboxOptions as t } from "./_policy.js";
3
- import { buildRuntimeDocument as n } from "./_document.js";
3
+ import { buildDocumentFromOptions as n } from "./_document.js";
4
4
  import "./_dev.js";
5
5
  import { MSG_CUSTOM as r, MSG_ERROR as i, MSG_HTML_REPLACE as a, MSG_READY as o, MSG_RESIZE as s, MSG_STATE_UPDATE as c, MSG_STATE_UPDATE_ALL as l, MSG_STYLE_PATCH as u, createChannel as d, envelope as f, isProtocolMessage as p } from "./_protocol.js";
6
6
  //#region src/_runtime.ts
@@ -1 +1 @@
1
- {"version":3,"file":"_runtime.js","names":[],"sources":["../src/_runtime.ts"],"sourcesContent":["import type { SandboxHandle, SandboxMessage, SandboxOptions, Unsubscribe } from './types.js';\n\nimport { devOnly, warn } from './_dev.js';\nimport { buildRuntimeDocument } from './_document.js';\nimport { normalizeSandboxOptions } from './_policy.js';\nimport {\n createChannel,\n envelope,\n isProtocolMessage,\n MSG_CUSTOM,\n MSG_ERROR,\n MSG_HTML_REPLACE,\n MSG_READY,\n MSG_RESIZE,\n MSG_STATE_UPDATE,\n MSG_STATE_UPDATE_ALL,\n MSG_STYLE_PATCH,\n type BridgeBootstrap,\n} from './_protocol.js';\nimport { SandboxTimeoutError } from './errors.js';\n\nconst READY_TIMEOUT_MS = 5000;\n\nexport function createSandbox(container: HTMLElement, options: SandboxOptions = {}): SandboxHandle {\n const normalized = normalizeSandboxOptions(options);\n const channel = createChannel();\n const namedStyles: Record<string, string> = { ...normalized.namedStyles };\n const listeners = new Set<(message: SandboxMessage) => void>();\n const controller = new AbortController();\n let iframe: HTMLIFrameElement | null = null;\n let disposed = false;\n let bridgeReady = false;\n let generation = 0;\n let readyTimeout: ReturnType<typeof setTimeout> | null = null;\n let currentRender: { reject: (error: unknown) => void; resolve: () => void } | null = null;\n\n let resolveReady!: () => void;\n const ready = new Promise<void>((resolve) => {\n resolveReady = resolve;\n });\n\n function currentBootstrap(): BridgeBootstrap {\n return { channel, generation };\n }\n\n function clearReadyTimeout(): void {\n if (readyTimeout === null) return;\n\n clearTimeout(readyTimeout);\n readyTimeout = null;\n }\n\n function supersedePendingRender(): void {\n clearReadyTimeout();\n currentRender?.resolve();\n currentRender = null;\n bridgeReady = false;\n }\n\n function broadcast(message: SandboxMessage): void {\n for (const listener of listeners) listener(message);\n }\n\n function handleMessage(event: MessageEvent): void {\n if (!iframe || event.source !== iframe.contentWindow) return;\n\n const bootstrap = currentBootstrap();\n\n if (!isProtocolMessage(event.data, bootstrap)) return;\n\n switch (event.data.type) {\n case MSG_CUSTOM:\n if (typeof event.data.event === 'string') {\n broadcast({ detail: event.data.detail, event: event.data.event, type: MSG_CUSTOM });\n }\n\n break;\n case MSG_ERROR:\n if (typeof event.data.message === 'string') {\n broadcast({\n message: event.data.message,\n ...(typeof event.data.stack === 'string' ? { stack: event.data.stack } : {}),\n type: MSG_ERROR,\n });\n }\n\n break;\n case MSG_READY:\n supersedePendingRender();\n resolveReady();\n bridgeReady = true;\n break;\n case MSG_RESIZE:\n if (typeof event.data.height === 'number' && Number.isFinite(event.data.height) && event.data.height >= 0) {\n broadcast({ height: event.data.height, type: MSG_RESIZE });\n }\n\n break;\n }\n }\n\n function ensureIframe(): HTMLIFrameElement {\n if (iframe) return iframe;\n\n iframe = document.createElement('iframe');\n iframe.setAttribute('sandbox', 'allow-scripts');\n iframe.setAttribute('referrerpolicy', 'no-referrer');\n iframe.dataset.sandboxChannel = channel;\n container.appendChild(iframe);\n window.addEventListener('message', handleMessage);\n\n return iframe;\n }\n\n function dispose(): void {\n if (disposed) return;\n\n disposed = true;\n supersedePendingRender();\n controller.abort();\n resolveReady();\n\n if (iframe) {\n window.removeEventListener('message', handleMessage);\n iframe.remove();\n iframe = null;\n }\n\n listeners.clear();\n }\n\n function onMessage(handler: (message: SandboxMessage) => void): Unsubscribe {\n if (disposed) {\n warn('onMessage() called on a disposed sandbox — handler will never fire.');\n\n return () => {};\n }\n\n listeners.add(handler);\n\n return () => listeners.delete(handler);\n }\n\n function render(html: string, renderOptions?: { signal?: AbortSignal }): Promise<void> {\n if (disposed) {\n warn('render() called on a disposed sandbox.');\n\n return Promise.resolve();\n }\n\n if (renderOptions?.signal?.aborted) return Promise.resolve();\n\n if (!html.trim()) warn('render() called with empty HTML.');\n\n supersedePendingRender();\n generation += 1;\n\n const current = ensureIframe();\n const bootstrap = currentBootstrap();\n const documentOptions = { ...normalized, namedStyles: { ...namedStyles } };\n\n current.dataset.sandboxGeneration = String(generation);\n current.srcdoc = buildRuntimeDocument(html, documentOptions, bootstrap);\n\n const promise = new Promise<void>((resolve, reject) => {\n currentRender = { reject, resolve };\n });\n\n readyTimeout = setTimeout(() => {\n if (!currentRender) return;\n\n currentRender.reject(\n new SandboxTimeoutError(\n `render() did not receive a 'ready' signal from the sandbox document within ${READY_TIMEOUT_MS}ms. ` +\n 'The document is likely missing the bridge script — use buildDocument() to generate documents that include it.',\n ),\n );\n currentRender = null;\n readyTimeout = null;\n }, READY_TIMEOUT_MS);\n\n return promise;\n }\n\n function send(message: Record<string, unknown>): void {\n iframe?.contentWindow?.postMessage(envelope(currentBootstrap(), message), '*');\n }\n\n function replaceBody(html: string): void {\n if (disposed) {\n warn('replaceBody() called on a disposed sandbox.');\n\n return;\n }\n\n if (!bridgeReady || !iframe?.contentWindow) {\n warn('replaceBody() called before render() has resolved — bridge is not ready. Await render() first.');\n\n return;\n }\n\n send({ html, type: MSG_HTML_REPLACE });\n }\n\n function setState(key: string, value: unknown): void {\n if (disposed) {\n warn('setState() called on a disposed sandbox.');\n\n return;\n }\n\n if (!iframe?.contentWindow) {\n warn('setState() called before render() — sandbox has no document yet.');\n\n return;\n }\n\n if (!bridgeReady) {\n warn('setState() called before ready — state update may be lost. Await render() first.');\n }\n\n send({ key, type: MSG_STATE_UPDATE, value });\n }\n\n function setStateAll(record: Record<string, unknown>): void {\n if (disposed) {\n warn('setStateAll() called on a disposed sandbox.');\n\n return;\n }\n\n if (!iframe?.contentWindow) {\n warn('setStateAll() called before render() — sandbox has no document yet.');\n\n return;\n }\n\n if (!bridgeReady) {\n warn('setStateAll() called before ready — state updates may be lost. Await render() first.');\n }\n\n send({ record, type: MSG_STATE_UPDATE_ALL });\n }\n\n function updateStyle(id: string, css: string): void {\n if (disposed) return;\n\n devOnly(() => {\n if (!(id in namedStyles)) {\n warn(`updateStyle('${id}', …) — '${id}' is not a known namedStyles key.`);\n }\n });\n\n namedStyles[id] = css;\n\n if (bridgeReady && iframe?.contentWindow) send({ css, id, type: MSG_STYLE_PATCH });\n }\n\n return {\n get disposalSignal() {\n return controller.signal;\n },\n dispose,\n get disposed() {\n return disposed;\n },\n onMessage,\n ready,\n render,\n replaceBody,\n setState,\n setStateAll,\n [Symbol.dispose]() {\n dispose();\n },\n updateStyle,\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"_runtime.js","names":[],"sources":["../src/_runtime.ts"],"sourcesContent":["import { devOnly, warn } from './_dev.js';\nimport { buildDocumentFromOptions } from './_document.js';\nimport { normalizeSandboxOptions } from './_policy.js';\nimport {\n type BridgeBootstrap,\n createChannel,\n envelope,\n isProtocolMessage,\n MSG_CUSTOM,\n MSG_ERROR,\n MSG_HTML_REPLACE,\n MSG_READY,\n MSG_RESIZE,\n MSG_STATE_UPDATE,\n MSG_STATE_UPDATE_ALL,\n MSG_STYLE_PATCH,\n} from './_protocol.js';\nimport { SandboxTimeoutError } from './errors.js';\nimport type { SandboxHandle, SandboxMessage, SandboxOptions, Unsubscribe } from './types.js';\n\nconst READY_TIMEOUT_MS = 5000;\n\nexport function createSandbox(container: HTMLElement, options: SandboxOptions = {}): SandboxHandle {\n const normalized = normalizeSandboxOptions(options);\n const channel = createChannel();\n const namedStyles: Record<string, string> = { ...normalized.namedStyles };\n const listeners = new Set<(message: SandboxMessage) => void>();\n const controller = new AbortController();\n let iframe: HTMLIFrameElement | null = null;\n let disposed = false;\n let bridgeReady = false;\n let generation = 0;\n let readyTimeout: ReturnType<typeof setTimeout> | null = null;\n let currentRender: { reject: (error: unknown) => void; resolve: () => void } | null = null;\n\n let resolveReady!: () => void;\n const ready = new Promise<void>((resolve) => {\n resolveReady = resolve;\n });\n\n function currentBootstrap(): BridgeBootstrap {\n return { channel, generation };\n }\n\n function clearReadyTimeout(): void {\n if (readyTimeout === null) return;\n\n clearTimeout(readyTimeout);\n readyTimeout = null;\n }\n\n function supersedePendingRender(): void {\n clearReadyTimeout();\n currentRender?.resolve();\n currentRender = null;\n bridgeReady = false;\n }\n\n function broadcast(message: SandboxMessage): void {\n for (const listener of listeners) listener(message);\n }\n\n function handleMessage(event: MessageEvent): void {\n if (!iframe || event.source !== iframe.contentWindow) return;\n\n const bootstrap = currentBootstrap();\n\n if (!isProtocolMessage(event.data, bootstrap)) return;\n\n switch (event.data.type) {\n case MSG_CUSTOM:\n if (typeof event.data.event === 'string') {\n broadcast({ detail: event.data.detail, event: event.data.event, type: MSG_CUSTOM });\n }\n\n break;\n case MSG_ERROR:\n if (typeof event.data.message === 'string') {\n broadcast({\n message: event.data.message,\n ...(typeof event.data.stack === 'string' ? { stack: event.data.stack } : {}),\n type: MSG_ERROR,\n });\n }\n\n break;\n case MSG_READY:\n supersedePendingRender();\n resolveReady();\n bridgeReady = true;\n break;\n case MSG_RESIZE:\n if (typeof event.data.height === 'number' && Number.isFinite(event.data.height) && event.data.height >= 0) {\n broadcast({ height: event.data.height, type: MSG_RESIZE });\n }\n\n break;\n }\n }\n\n function ensureIframe(): HTMLIFrameElement {\n if (iframe) return iframe;\n\n iframe = document.createElement('iframe');\n iframe.setAttribute('sandbox', 'allow-scripts');\n iframe.setAttribute('referrerpolicy', 'no-referrer');\n iframe.dataset.sandboxChannel = channel;\n container.appendChild(iframe);\n window.addEventListener('message', handleMessage);\n\n return iframe;\n }\n\n function dispose(): void {\n if (disposed) return;\n\n disposed = true;\n supersedePendingRender();\n controller.abort();\n resolveReady();\n\n if (iframe) {\n window.removeEventListener('message', handleMessage);\n iframe.remove();\n iframe = null;\n }\n\n listeners.clear();\n }\n\n function onMessage(handler: (message: SandboxMessage) => void): Unsubscribe {\n if (disposed) {\n warn('onMessage() called on a disposed sandbox — handler will never fire.');\n\n return () => {};\n }\n\n listeners.add(handler);\n\n return () => listeners.delete(handler);\n }\n\n function render(html: string, renderOptions?: { signal?: AbortSignal }): Promise<void> {\n if (disposed) {\n warn('render() called on a disposed sandbox.');\n\n return Promise.resolve();\n }\n\n if (renderOptions?.signal?.aborted) return Promise.resolve();\n\n if (!html.trim()) warn('render() called with empty HTML.');\n\n supersedePendingRender();\n generation += 1;\n\n const current = ensureIframe();\n const bootstrap = currentBootstrap();\n const documentOptions = { ...normalized, namedStyles: { ...namedStyles } };\n\n current.dataset.sandboxGeneration = String(generation);\n current.srcdoc = buildDocumentFromOptions(html, documentOptions, bootstrap);\n\n const promise = new Promise<void>((resolve, reject) => {\n currentRender = { reject, resolve };\n });\n\n readyTimeout = setTimeout(() => {\n if (!currentRender) return;\n\n currentRender.reject(\n new SandboxTimeoutError(\n `render() did not receive a 'ready' signal from the sandbox document within ${READY_TIMEOUT_MS}ms. ` +\n 'The document is likely missing the bridge script — use buildDocument() to generate documents that include it.',\n ),\n );\n currentRender = null;\n readyTimeout = null;\n }, READY_TIMEOUT_MS);\n\n return promise;\n }\n\n function send(message: Record<string, unknown>): void {\n iframe?.contentWindow?.postMessage(envelope(currentBootstrap(), message), '*');\n }\n\n function replaceBody(html: string): void {\n if (disposed) {\n warn('replaceBody() called on a disposed sandbox.');\n\n return;\n }\n\n if (!bridgeReady || !iframe?.contentWindow) {\n warn('replaceBody() called before render() has resolved — bridge is not ready. Await render() first.');\n\n return;\n }\n\n send({ html, type: MSG_HTML_REPLACE });\n }\n\n function setState(key: string, value: unknown): void {\n if (disposed) {\n warn('setState() called on a disposed sandbox.');\n\n return;\n }\n\n if (!iframe?.contentWindow) {\n warn('setState() called before render() — sandbox has no document yet.');\n\n return;\n }\n\n if (!bridgeReady) {\n warn('setState() called before ready — state update may be lost. Await render() first.');\n }\n\n send({ key, type: MSG_STATE_UPDATE, value });\n }\n\n function setStateAll(record: Record<string, unknown>): void {\n if (disposed) {\n warn('setStateAll() called on a disposed sandbox.');\n\n return;\n }\n\n if (!iframe?.contentWindow) {\n warn('setStateAll() called before render() — sandbox has no document yet.');\n\n return;\n }\n\n if (!bridgeReady) {\n warn('setStateAll() called before ready — state updates may be lost. Await render() first.');\n }\n\n send({ record, type: MSG_STATE_UPDATE_ALL });\n }\n\n function updateStyle(id: string, css: string): void {\n if (disposed) return;\n\n devOnly(() => {\n if (!(id in namedStyles)) {\n warn(`updateStyle('${id}', …) — '${id}' is not a known namedStyles key.`);\n }\n });\n\n namedStyles[id] = css;\n\n if (bridgeReady && iframe?.contentWindow) send({ css, id, type: MSG_STYLE_PATCH });\n }\n\n return {\n get disposalSignal() {\n return controller.signal;\n },\n dispose,\n get disposed() {\n return disposed;\n },\n onMessage,\n ready,\n render,\n replaceBody,\n setState,\n setStateAll,\n [Symbol.dispose]() {\n dispose();\n },\n updateStyle,\n };\n}\n"],"mappings":"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"}
package/dist/errors.cjs CHANGED
@@ -1,2 +1,2 @@
1
- var e=class e extends Error{constructor(e,t){super(e,t),this.name=new.target.name,Object.setPrototypeOf(this,new.target.prototype)}static is(t){return t instanceof e}},t=class extends e{},n=class extends e{};exports.SandboxConfigurationError=n,exports.SandboxError=e,exports.SandboxTimeoutError=t;
1
+ var e=class extends Error{constructor(e,t){super(e,t),this.name=new.target.name,Object.setPrototypeOf(this,new.target.prototype)}},t=class extends e{},n=class extends e{};exports.SandboxConfigurationError=n,exports.SandboxError=e,exports.SandboxTimeoutError=t;
2
2
  //# sourceMappingURL=errors.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"errors.cjs","names":[],"sources":["../src/errors.ts"],"sourcesContent":["/** Base class for all sandbox errors. */\nexport class SandboxError extends Error {\n constructor(message: string, opts?: ErrorOptions) {\n super(message, opts);\n this.name = new.target.name;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n\n static is(err: unknown): err is SandboxError {\n return err instanceof SandboxError;\n }\n}\n\n/**\n * Thrown when render() does not receive a 'ready' signal from the sandbox document\n * within the timeout window. The document is most likely missing the bridge script —\n * use buildDocument() to generate documents that include it.\n */\nexport class SandboxTimeoutError extends SandboxError {}\n\n/** Thrown when Sandbox configuration cannot produce a valid document or CSP policy. */\nexport class SandboxConfigurationError extends SandboxError {}\n"],"mappings":"AACA,IAAa,EAAb,MAAa,UAAqB,KAAM,CACtC,YAAY,EAAiB,EAAqB,CAChD,MAAM,EAAS,CAAI,EACnB,KAAK,KAAO,WAAW,KACvB,OAAO,eAAe,KAAM,WAAW,SAAS,CAClD,CAEA,OAAO,GAAG,EAAmC,CAC3C,OAAO,aAAe,CACxB,CACF,EAOa,EAAb,cAAyC,CAAa,CAAC,EAG1C,EAAb,cAA+C,CAAa,CAAC"}
1
+ {"version":3,"file":"errors.cjs","names":[],"sources":["../src/errors.ts"],"sourcesContent":["/** Base class for all sandbox errors. */\nexport class SandboxError extends Error {\n constructor(message: string, opts?: ErrorOptions) {\n super(message, opts);\n this.name = new.target.name;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n/**\n * Thrown when render() does not receive a 'ready' signal from the sandbox document\n * within the timeout window. The document is most likely missing the bridge script —\n * use buildDocument() to generate documents that include it.\n */\nexport class SandboxTimeoutError extends SandboxError {}\n\n/** Thrown when Sandbox configuration cannot produce a valid document or CSP policy. */\nexport class SandboxConfigurationError extends SandboxError {}\n"],"mappings":"AACA,IAAa,EAAb,cAAkC,KAAM,CACtC,YAAY,EAAiB,EAAqB,CAChD,MAAM,EAAS,CAAI,EACnB,KAAK,KAAO,WAAW,KACvB,OAAO,eAAe,KAAM,WAAW,SAAS,CAClD,CACF,EAOa,EAAb,cAAyC,CAAa,CAAC,EAG1C,EAAb,cAA+C,CAAa,CAAC"}
package/dist/errors.d.ts CHANGED
@@ -1,7 +1,6 @@
1
1
  /** Base class for all sandbox errors. */
2
2
  export declare class SandboxError extends Error {
3
3
  constructor(message: string, opts?: ErrorOptions);
4
- static is(err: unknown): err is SandboxError;
5
4
  }
6
5
  /**
7
6
  * Thrown when render() does not receive a 'ready' signal from the sandbox document
@@ -1 +1 @@
1
- {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,yCAAyC;AACzC,qBAAa,YAAa,SAAQ,KAAK;gBACzB,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,YAAY;IAMhD,MAAM,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,GAAG,GAAG,IAAI,YAAY;CAG7C;AAED;;;;GAIG;AACH,qBAAa,mBAAoB,SAAQ,YAAY;CAAG;AAExD,uFAAuF;AACvF,qBAAa,yBAA0B,SAAQ,YAAY;CAAG"}
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,yCAAyC;AACzC,qBAAa,YAAa,SAAQ,KAAK;gBACzB,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,YAAY;CAKjD;AAED;;;;GAIG;AACH,qBAAa,mBAAoB,SAAQ,YAAY;CAAG;AAExD,uFAAuF;AACvF,qBAAa,yBAA0B,SAAQ,YAAY;CAAG"}
package/dist/errors.js CHANGED
@@ -1,11 +1,8 @@
1
1
  //#region src/errors.ts
2
- var e = class e extends Error {
2
+ var e = class extends Error {
3
3
  constructor(e, t) {
4
4
  super(e, t), this.name = new.target.name, Object.setPrototypeOf(this, new.target.prototype);
5
5
  }
6
- static is(t) {
7
- return t instanceof e;
8
- }
9
6
  }, t = class extends e {}, n = class extends e {};
10
7
  //#endregion
11
8
  export { n as SandboxConfigurationError, e as SandboxError, t as SandboxTimeoutError };
@@ -1 +1 @@
1
- {"version":3,"file":"errors.js","names":[],"sources":["../src/errors.ts"],"sourcesContent":["/** Base class for all sandbox errors. */\nexport class SandboxError extends Error {\n constructor(message: string, opts?: ErrorOptions) {\n super(message, opts);\n this.name = new.target.name;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n\n static is(err: unknown): err is SandboxError {\n return err instanceof SandboxError;\n }\n}\n\n/**\n * Thrown when render() does not receive a 'ready' signal from the sandbox document\n * within the timeout window. The document is most likely missing the bridge script —\n * use buildDocument() to generate documents that include it.\n */\nexport class SandboxTimeoutError extends SandboxError {}\n\n/** Thrown when Sandbox configuration cannot produce a valid document or CSP policy. */\nexport class SandboxConfigurationError extends SandboxError {}\n"],"mappings":";AACA,IAAa,IAAb,MAAa,UAAqB,MAAM;CACtC,YAAY,GAAiB,GAAqB;EAGhD,AAFA,MAAM,GAAS,CAAI,GACnB,KAAK,OAAO,WAAW,MACvB,OAAO,eAAe,MAAM,WAAW,SAAS;CAClD;CAEA,OAAO,GAAG,GAAmC;EAC3C,OAAO,aAAe;CACxB;AACF,GAOa,IAAb,cAAyC,EAAa,CAAC,GAG1C,IAAb,cAA+C,EAAa,CAAC"}
1
+ {"version":3,"file":"errors.js","names":[],"sources":["../src/errors.ts"],"sourcesContent":["/** Base class for all sandbox errors. */\nexport class SandboxError extends Error {\n constructor(message: string, opts?: ErrorOptions) {\n super(message, opts);\n this.name = new.target.name;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n/**\n * Thrown when render() does not receive a 'ready' signal from the sandbox document\n * within the timeout window. The document is most likely missing the bridge script —\n * use buildDocument() to generate documents that include it.\n */\nexport class SandboxTimeoutError extends SandboxError {}\n\n/** Thrown when Sandbox configuration cannot produce a valid document or CSP policy. */\nexport class SandboxConfigurationError extends SandboxError {}\n"],"mappings":";AACA,IAAa,IAAb,cAAkC,MAAM;CACtC,YAAY,GAAiB,GAAqB;EAGhD,AAFA,MAAM,GAAS,CAAI,GACnB,KAAK,OAAO,WAAW,MACvB,OAAO,eAAe,MAAM,WAAW,SAAS;CAClD;AACF,GAOa,IAAb,cAAyC,EAAa,CAAC,GAG1C,IAAb,cAA+C,EAAa,CAAC"}
package/dist/index.cjs CHANGED
@@ -1 +1 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./errors.cjs"),t=require("./_document.cjs"),n=require("./_runtime.cjs"),r=require("./_sandbox.cjs");exports.SandboxConfigurationError=e.SandboxConfigurationError,exports.SandboxError=e.SandboxError,exports.SandboxTimeoutError=e.SandboxTimeoutError,exports.buildCsp=r.buildCsp,exports.buildDocument=t.buildDocument,exports.createSandbox=n.createSandbox;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./errors.cjs"),t=require("./_policy.cjs"),n=require("./_document.cjs"),r=require("./_runtime.cjs");exports.SandboxConfigurationError=e.SandboxConfigurationError,exports.SandboxError=e.SandboxError,exports.SandboxTimeoutError=e.SandboxTimeoutError,exports.buildCsp=t.buildCsp,exports.buildDocument=n.buildDocument,exports.createSandbox=r.createSandbox;
package/dist/index.d.ts CHANGED
@@ -1,4 +1,6 @@
1
- export { buildCsp, buildDocument, createSandbox } from './_sandbox.js';
1
+ export { buildDocument } from './_document.js';
2
+ export { buildCsp } from './_policy.js';
3
+ export { createSandbox } from './_runtime.js';
2
4
  export { SandboxConfigurationError, SandboxError, SandboxTimeoutError } from './errors.js';
3
5
  export type { SandboxBridge, SandboxHandle, SandboxMessage, SandboxOptions, SandboxStateUpdateDetail, Unsubscribe, } from './types.js';
4
6
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AACvE,OAAO,EAAE,yBAAyB,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAC3F,YAAY,EACV,aAAa,EACb,aAAa,EACb,cAAc,EACd,cAAc,EACd,wBAAwB,EACxB,WAAW,GACZ,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAC/C,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AACxC,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAE,yBAAyB,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAC3F,YAAY,EACV,aAAa,EACb,aAAa,EACb,cAAc,EACd,cAAc,EACd,wBAAwB,EACxB,WAAW,GACZ,MAAM,YAAY,CAAC"}
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { SandboxConfigurationError as e, SandboxError as t, SandboxTimeoutError as n } from "./errors.js";
2
- import { buildDocument as r } from "./_document.js";
3
- import { createSandbox as i } from "./_runtime.js";
4
- import { buildCsp as a } from "./_sandbox.js";
5
- export { e as SandboxConfigurationError, t as SandboxError, n as SandboxTimeoutError, a as buildCsp, r as buildDocument, i as createSandbox };
2
+ import { buildCsp as r } from "./_policy.js";
3
+ import { buildDocument as i } from "./_document.js";
4
+ import { createSandbox as a } from "./_runtime.js";
5
+ export { e as SandboxConfigurationError, t as SandboxError, n as SandboxTimeoutError, r as buildCsp, i as buildDocument, a as createSandbox };
package/dist/sandbox.cjs CHANGED
@@ -1,4 +1,4 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});var e=class e extends Error{constructor(e,t){super(e,t),this.name=new.target.name,Object.setPrototypeOf(this,new.target.prototype)}static is(t){return t instanceof e}},t=class extends e{},n=class extends e{},r=/^[A-Za-z][A-Za-z0-9_-]*$/,i=/^[A-Za-z]{2,3}(?:-[A-Za-z0-9]{2,8})*$/,a=/^[A-Za-z0-9+/_-]+={0,2}$/;function o(e,t){throw new n(`${e} is invalid: ${String(t)}`)}function s(e,t){let n;try{n=new URL(e)}catch{return o(t,e)}return n.protocol!==`http:`&&n.protocol!==`https:`||n.username||n.password||n.pathname!==`/`||n.search||n.hash?o(t,e):n.origin}function c(e,t){return(e??[]).map(e=>s(e,t))}function l(e){let t;try{t=new URL(e)}catch{return o(`scripts`,e)}return t.protocol!==`http:`&&t.protocol!==`https:`?o(`scripts`,e):t.href}function u(e){let t={};for(let[n,i]of Object.entries(e??{}))(!r.test(n)||typeof i!=`string`)&&o(`namedStyles`,n),t[n]=i;return t}function d(e={}){let t=e.lang??`en`;i.test(t)||o(`lang`,t),e.nonce!==void 0&&(!a.test(e.nonce)||e.nonce.length===0)&&o(`nonce`,e.nonce),e.title!==void 0&&typeof e.title!=`string`&&o(`title`,e.title);let n=(e.scripts??[]).map(l);return{allowedFontOrigins:c(e.allowedFontOrigins,`allowedFontOrigins`),allowedImageOrigins:c(e.allowedImageOrigins,`allowedImageOrigins`),allowedScriptOrigins:c(e.allowedScriptOrigins,`allowedScriptOrigins`),allowedStyleOrigins:c(e.allowedStyleOrigins,`allowedStyleOrigins`),lang:t,namedStyles:u(e.namedStyles),nonce:e.nonce,scripts:n,title:e.title??``}}function f(e){let t=[`'unsafe-inline'`,...e.nonce?[`'nonce-${e.nonce}'`]:[],...e.allowedScriptOrigins,...e.scripts.map(e=>new URL(e).origin)].join(` `),n=[`'unsafe-inline'`,...e.allowedStyleOrigins].join(` `),r=[`data:`,...e.allowedImageOrigins].join(` `),i=e.allowedFontOrigins.join(` `)||`'none'`;return[`default-src 'none'`,`script-src ${t}`,`style-src ${n}`,`img-src ${r}`,`font-src ${i}`,`connect-src 'none'`,`form-action 'none'`,`base-uri 'none'`].join(`; `)}function p(e){return`
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});function e(e){return`
2
2
  window.__sandboxChannel = ${JSON.stringify(e.channel)};
3
3
  window.__sandboxGeneration = ${String(e.generation)};
4
4
  const __sandboxChannel = window.__sandboxChannel;
@@ -63,24 +63,24 @@ if (typeof ResizeObserver !== 'undefined') {
63
63
  post({ type: 'resize', height: h });
64
64
  }).observe(document.body);
65
65
  }
66
- `.trim()}function m(e){return e.replace(/<\/style/gi,`\\3C /style`)}function h(e){return e.replace(/&/g,`&amp;`).replace(/"/g,`&quot;`).replace(/</g,`&lt;`).replace(/>/g,`&gt;`)}function g(e){return e.replace(/&/g,`&amp;`).replace(/</g,`&lt;`).replace(/>/g,`&gt;`)}function _(e,t,n){let r=h(f(t)),i=Object.entries(t.namedStyles).map(([e,t])=>`<style id="${h(e)}">${m(t)}</style>`).join(`
67
- `),a=t.scripts.map(e=>`<script crossorigin="anonymous" src="${h(e)}"><\/script>`).join(`
68
- `),o=t.nonce?` nonce="${h(t.nonce)}"`:``,s=`<script${o}>window.__sandboxChannel=${JSON.stringify(n.channel)};window.__sandboxGeneration=${n.generation};<\/script>`;return`<!doctype html>
69
- <html lang="${h(t.lang)}">
66
+ `.trim()}var t=class extends Error{constructor(e,t){super(e,t),this.name=new.target.name,Object.setPrototypeOf(this,new.target.prototype)}},n=class extends t{},r=class extends t{},i=/^[A-Za-z][A-Za-z0-9_-]*$/,a=/^[A-Za-z]{2,3}(?:-[A-Za-z0-9]{2,8})*$/,o=/^[A-Za-z0-9+/_-]+={0,2}$/;function s(e,t){throw new r(`${e} is invalid: ${String(t)}`)}function c(e,t){let n;try{n=new URL(e)}catch{return s(t,e)}return n.protocol!==`http:`&&n.protocol!==`https:`||n.username||n.password||n.pathname!==`/`||n.search||n.hash?s(t,e):n.origin}function l(e,t){return(e??[]).map(e=>c(e,t))}function u(e){let t;try{t=new URL(e)}catch{return s(`scripts`,e)}return t.protocol!==`http:`&&t.protocol!==`https:`?s(`scripts`,e):t.href}function d(e){let t={};for(let[n,r]of Object.entries(e??{}))(!i.test(n)||typeof r!=`string`)&&s(`namedStyles`,n),t[n]=r;return t}function f(e={}){let t=e.lang??`en`;a.test(t)||s(`lang`,t),e.nonce!==void 0&&(!o.test(e.nonce)||e.nonce.length===0)&&s(`nonce`,e.nonce),e.title!==void 0&&typeof e.title!=`string`&&s(`title`,e.title);let n=(e.scripts??[]).map(u);return{allowedFontOrigins:l(e.allowedFontOrigins,`allowedFontOrigins`),allowedImageOrigins:l(e.allowedImageOrigins,`allowedImageOrigins`),allowedScriptOrigins:l(e.allowedScriptOrigins,`allowedScriptOrigins`),allowedStyleOrigins:l(e.allowedStyleOrigins,`allowedStyleOrigins`),lang:t,namedStyles:d(e.namedStyles),nonce:e.nonce,scripts:n,title:e.title??``}}function p(e){let t=[`'unsafe-inline'`,...e.nonce?[`'nonce-${e.nonce}'`]:[],...e.allowedScriptOrigins,...e.scripts.map(e=>new URL(e).origin)].join(` `),n=[`'unsafe-inline'`,...e.allowedStyleOrigins].join(` `),r=[`data:`,...e.allowedImageOrigins].join(` `),i=e.allowedFontOrigins.join(` `)||`'none'`;return[`default-src 'none'`,`script-src ${t}`,`style-src ${n}`,`img-src ${r}`,`font-src ${i}`,`connect-src 'none'`,`form-action 'none'`,`base-uri 'none'`].join(`; `)}function m(e={}){return p(f(e))}function h(e){return e.replace(/<\/style/gi,`\\3C /style`)}function g(e){return e.replace(/&/g,`&amp;`).replace(/"/g,`&quot;`).replace(/</g,`&lt;`).replace(/>/g,`&gt;`)}function _(e){return e.replace(/&/g,`&amp;`).replace(/</g,`&lt;`).replace(/>/g,`&gt;`)}function v(t,n,r){let i=g(p(n)),a=Object.entries(n.namedStyles).map(([e,t])=>`<style id="${g(e)}">${h(t)}</style>`).join(`
67
+ `),o=n.scripts.map(e=>`<script crossorigin="anonymous" src="${g(e)}"><\/script>`).join(`
68
+ `),s=n.nonce?` nonce="${g(n.nonce)}"`:``,c=`<script${s}>window.__sandboxChannel=${JSON.stringify(r.channel)};window.__sandboxGeneration=${r.generation};<\/script>`;return`<!doctype html>
69
+ <html lang="${g(n.lang)}">
70
70
  <head>
71
- <meta http-equiv="Content-Security-Policy" content="${r}">
72
- ${s}
71
+ <meta http-equiv="Content-Security-Policy" content="${i}">
72
+ ${c}
73
73
  <meta charset="utf-8">
74
74
  <meta name="viewport" content="width=device-width, initial-scale=1">
75
- <title>${g(t.title)}</title>
76
- ${i}
75
+ <title>${_(n.title)}</title>
76
+ ${a}
77
77
  </head>
78
78
  <body>
79
- ${a}
80
- ${e}
81
- <script${o}>
82
- ${p(n)}
79
+ ${o}
80
+ ${t}
81
+ <script${s}>
82
+ ${e(r)}
83
83
  <\/script>
84
84
  </body>
85
- </html>`}function v(e,t={}){return _(e,d(t),{channel:``,generation:0})}function y(e,t,n){return _(e,t,n)}var b=`custom`,x=`error`,S=`html-replace`,C=`ready`,w=`resize`,T=`state-update`,E=`state-update-all`,D=`style-patch`;function O(e,t){return typeof e==`object`&&!!e&&typeof e.channel==`string`&&e.channel===t.channel&&typeof e.generation==`number`&&e.generation===t.generation&&typeof e.type==`string`}function k(){if(typeof crypto.randomUUID==`function`)return crypto.randomUUID();let e=crypto.getRandomValues(new Uint32Array(4));return Array.from(e,e=>e.toString(16).padStart(8,`0`)).join(``)}function A(e,t){return{...t,channel:e.channel,generation:e.generation}}var j=5e3;function M(e,n={}){let r=d(n),i=k(),a={...r.namedStyles},o=new Set,s=new AbortController,c=null,l=!1,u=!1,f=0,p=null,m=null,h,g=new Promise(e=>{h=e});function _(){return{channel:i,generation:f}}function v(){p!==null&&(clearTimeout(p),p=null)}function M(){v(),m?.resolve(),m=null,u=!1}function N(e){for(let t of o)t(e)}function P(e){if(!c||e.source!==c.contentWindow)return;let t=_();if(O(e.data,t))switch(e.data.type){case b:typeof e.data.event==`string`&&N({detail:e.data.detail,event:e.data.event,type:b});break;case x:typeof e.data.message==`string`&&N({message:e.data.message,...typeof e.data.stack==`string`?{stack:e.data.stack}:{},type:x});break;case C:M(),h(),u=!0;break;case w:typeof e.data.height==`number`&&Number.isFinite(e.data.height)&&e.data.height>=0&&N({height:e.data.height,type:w})}}function F(){return c||(c=document.createElement(`iframe`),c.setAttribute(`sandbox`,`allow-scripts`),c.setAttribute(`referrerpolicy`,`no-referrer`),c.dataset.sandboxChannel=i,e.appendChild(c),window.addEventListener(`message`,P),c)}function I(){l||(l=!0,M(),s.abort(),h(),c&&=(window.removeEventListener(`message`,P),c.remove(),null),o.clear())}function L(e){return l?()=>{}:(o.add(e),()=>o.delete(e))}function R(e,n){if(l||n?.signal?.aborted)return Promise.resolve();e.trim(),M(),f+=1;let i=F(),o=_(),s={...r,namedStyles:{...a}};i.dataset.sandboxGeneration=String(f),i.srcdoc=y(e,s,o);let c=new Promise((e,t)=>{m={reject:t,resolve:e}});return p=setTimeout(()=>{m&&(m.reject(new t(`render() did not receive a 'ready' signal from the sandbox document within ${j}ms. The document is likely missing the bridge script — use buildDocument() to generate documents that include it.`)),m=null,p=null)},j),c}function z(e){c?.contentWindow?.postMessage(A(_(),e),`*`)}function B(e){l||!u||!c?.contentWindow||z({html:e,type:S})}function V(e,t){l||c?.contentWindow&&z({key:e,type:T,value:t})}function H(e){l||c?.contentWindow&&z({record:e,type:E})}function U(e,t){l||(a[e]=t,u&&c?.contentWindow&&z({css:t,id:e,type:D}))}return{get disposalSignal(){return s.signal},dispose:I,get disposed(){return l},onMessage:L,ready:g,render:R,replaceBody:B,setState:V,setStateAll:H,[Symbol.dispose](){I()},updateStyle:U}}function N(e={}){return f(d(e))}exports.SandboxConfigurationError=n,exports.SandboxError=e,exports.SandboxTimeoutError=t,exports.buildCsp=N,exports.buildDocument=v,exports.createSandbox=M;
85
+ </html>`}function y(e,t={}){return v(e,f(t),{channel:``,generation:0})}var b=`custom`,x=`error`,S=`html-replace`,C=`ready`,w=`resize`,T=`state-update`,E=`state-update-all`,D=`style-patch`;function O(e,t){return typeof e==`object`&&!!e&&typeof e.channel==`string`&&e.channel===t.channel&&typeof e.generation==`number`&&e.generation===t.generation&&typeof e.type==`string`}function k(){if(typeof crypto.randomUUID==`function`)return crypto.randomUUID();let e=crypto.getRandomValues(new Uint32Array(4));return Array.from(e,e=>e.toString(16).padStart(8,`0`)).join(``)}function A(e,t){return{...t,channel:e.channel,generation:e.generation}}var j=5e3;function M(e,t={}){let r=f(t),i=k(),a={...r.namedStyles},o=new Set,s=new AbortController,c=null,l=!1,u=!1,d=0,p=null,m=null,h,g=new Promise(e=>{h=e});function _(){return{channel:i,generation:d}}function y(){p!==null&&(clearTimeout(p),p=null)}function M(){y(),m?.resolve(),m=null,u=!1}function N(e){for(let t of o)t(e)}function P(e){if(!c||e.source!==c.contentWindow)return;let t=_();if(O(e.data,t))switch(e.data.type){case b:typeof e.data.event==`string`&&N({detail:e.data.detail,event:e.data.event,type:b});break;case x:typeof e.data.message==`string`&&N({message:e.data.message,...typeof e.data.stack==`string`?{stack:e.data.stack}:{},type:x});break;case C:M(),h(),u=!0;break;case w:typeof e.data.height==`number`&&Number.isFinite(e.data.height)&&e.data.height>=0&&N({height:e.data.height,type:w})}}function F(){return c||(c=document.createElement(`iframe`),c.setAttribute(`sandbox`,`allow-scripts`),c.setAttribute(`referrerpolicy`,`no-referrer`),c.dataset.sandboxChannel=i,e.appendChild(c),window.addEventListener(`message`,P),c)}function I(){l||(l=!0,M(),s.abort(),h(),c&&=(window.removeEventListener(`message`,P),c.remove(),null),o.clear())}function L(e){return l?()=>{}:(o.add(e),()=>o.delete(e))}function R(e,t){if(l||t?.signal?.aborted)return Promise.resolve();e.trim(),M(),d+=1;let i=F(),o=_(),s={...r,namedStyles:{...a}};i.dataset.sandboxGeneration=String(d),i.srcdoc=v(e,s,o);let c=new Promise((e,t)=>{m={reject:t,resolve:e}});return p=setTimeout(()=>{m&&(m.reject(new n(`render() did not receive a 'ready' signal from the sandbox document within ${j}ms. The document is likely missing the bridge script — use buildDocument() to generate documents that include it.`)),m=null,p=null)},j),c}function z(e){c?.contentWindow?.postMessage(A(_(),e),`*`)}function B(e){l||!u||!c?.contentWindow||z({html:e,type:S})}function V(e,t){l||c?.contentWindow&&z({key:e,type:T,value:t})}function H(e){l||c?.contentWindow&&z({record:e,type:E})}function U(e,t){l||(a[e]=t,u&&c?.contentWindow&&z({css:t,id:e,type:D}))}return{get disposalSignal(){return s.signal},dispose:I,get disposed(){return l},onMessage:L,ready:g,render:R,replaceBody:B,setState:V,setStateAll:H,[Symbol.dispose](){I()},updateStyle:U}}exports.SandboxConfigurationError=r,exports.SandboxError=t,exports.SandboxTimeoutError=n,exports.buildCsp=m,exports.buildDocument=y,exports.createSandbox=M;
86
86
  //# sourceMappingURL=sandbox.cjs.map