@frontmcp/uipack 1.11.1 → 1.11.3

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 (70) hide show
  1. package/CLAUDE.md +4 -4
  2. package/README.md +20 -15
  3. package/adapters/code-highlight.d.ts +20 -0
  4. package/adapters/code-highlight.d.ts.map +1 -0
  5. package/adapters/index.d.ts +4 -2
  6. package/adapters/index.d.ts.map +1 -1
  7. package/adapters/index.js +36 -16
  8. package/adapters/markdown.d.ts +10 -2
  9. package/adapters/markdown.d.ts.map +1 -1
  10. package/adapters/mdx.d.ts +34 -0
  11. package/adapters/mdx.d.ts.map +1 -0
  12. package/adapters/project-require.d.ts +22 -0
  13. package/adapters/project-require.d.ts.map +1 -0
  14. package/adapters/render-options.d.ts +28 -0
  15. package/adapters/render-options.d.ts.map +1 -0
  16. package/adapters/response-builder.d.ts +9 -0
  17. package/adapters/response-builder.d.ts.map +1 -1
  18. package/adapters/server-react.d.ts +22 -0
  19. package/adapters/server-react.d.ts.map +1 -0
  20. package/adapters/serving-mode.d.ts +4 -1
  21. package/adapters/serving-mode.d.ts.map +1 -1
  22. package/adapters/template-renderer.d.ts +42 -2
  23. package/adapters/template-renderer.d.ts.map +1 -1
  24. package/component/index.js +25 -11
  25. package/component/loader.d.ts +5 -0
  26. package/component/loader.d.ts.map +1 -1
  27. package/component/renderer.d.ts.map +1 -1
  28. package/component/server-render.d.ts +21 -0
  29. package/component/server-render.d.ts.map +1 -0
  30. package/component/transpiler.d.ts +17 -13
  31. package/component/transpiler.d.ts.map +1 -1
  32. package/component/types.d.ts +7 -0
  33. package/component/types.d.ts.map +1 -1
  34. package/esm/adapters/index.mjs +36 -16
  35. package/esm/component/index.mjs +25 -11
  36. package/esm/index.mjs +71 -18
  37. package/esm/package.json +24 -3
  38. package/esm/shell/index.mjs +34 -1
  39. package/index.d.ts +1 -1
  40. package/index.d.ts.map +1 -1
  41. package/index.js +72 -19
  42. package/package.json +24 -3
  43. package/resolver/cdn-registry.d.ts +1 -1
  44. package/resolver/cdn-registry.d.ts.map +1 -1
  45. package/resolver/esm-sh.resolver.d.ts +1 -1
  46. package/resolver/esm-sh.resolver.d.ts.map +1 -1
  47. package/resolver/import-map.d.ts +1 -1
  48. package/resolver/import-map.d.ts.map +1 -1
  49. package/resolver/import-rewriter.d.ts.map +1 -1
  50. package/shell/custom-shell-resolver.d.ts +1 -1
  51. package/shell/custom-shell-resolver.d.ts.map +1 -1
  52. package/shell/custom-shell-validator.d.ts +1 -1
  53. package/shell/custom-shell-validator.d.ts.map +1 -1
  54. package/shell/index.d.ts +2 -0
  55. package/shell/index.d.ts.map +1 -1
  56. package/shell/index.js +35 -2
  57. package/shell/sanitize-css.d.ts +18 -0
  58. package/shell/sanitize-css.d.ts.map +1 -0
  59. package/shell/sanitize-html.d.ts +28 -0
  60. package/shell/sanitize-html.d.ts.map +1 -0
  61. package/shell/url-widget-shell.d.ts +35 -0
  62. package/shell/url-widget-shell.d.ts.map +1 -0
  63. package/types/ui-config.d.ts +207 -198
  64. package/types/ui-config.d.ts.map +1 -1
  65. package/types/ui-runtime.d.ts +11 -12
  66. package/types/ui-runtime.d.ts.map +1 -1
  67. package/typings/cache/memory-cache.d.ts +1 -1
  68. package/typings/cache/memory-cache.d.ts.map +1 -1
  69. package/typings/type-fetcher.d.ts +2 -2
  70. package/typings/type-fetcher.d.ts.map +1 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@frontmcp/uipack",
3
- "version": "1.11.1",
3
+ "version": "1.11.3",
4
4
  "description": "React-free core that builds FrontMCP widget pages: HTML shell with CSP and bridge, template rendering, CDN import resolution",
5
5
  "author": "AgentFront <info@agentfront.dev>",
6
6
  "homepage": "https://frontmcp.dev/reference/ui/components#frontmcpuipack",
@@ -58,18 +58,39 @@
58
58
  "node": ">=24.0.0"
59
59
  },
60
60
  "dependencies": {
61
+ "entities": "^6.0.0",
61
62
  "zod": "^4.0.0"
62
63
  },
63
64
  "devDependencies": {
64
65
  "typescript": "^5.9.3"
65
66
  },
66
67
  "peerDependencies": {
67
- "@frontmcp/lazy-zod": "1.11.1",
68
- "esbuild": ">=0.27.0 <1"
68
+ "@frontmcp/lazy-zod": "1.11.3",
69
+ "@mdx-js/mdx": "^3.0.0",
70
+ "esbuild": ">=0.27.0 <1",
71
+ "highlight.js": "^11.0.0",
72
+ "react": "^18.0.0 || ^19.0.0",
73
+ "react-dom": "^18.0.0 || ^19.0.0",
74
+ "remark-gfm": "^4.0.0"
69
75
  },
70
76
  "peerDependenciesMeta": {
77
+ "@mdx-js/mdx": {
78
+ "optional": true
79
+ },
71
80
  "esbuild": {
72
81
  "optional": true
82
+ },
83
+ "highlight.js": {
84
+ "optional": true
85
+ },
86
+ "react": {
87
+ "optional": true
88
+ },
89
+ "react-dom": {
90
+ "optional": true
91
+ },
92
+ "remark-gfm": {
93
+ "optional": true
73
94
  }
74
95
  }
75
96
  }
@@ -6,7 +6,7 @@
6
6
  *
7
7
  * @packageDocumentation
8
8
  */
9
- import type { CDNRegistry, CDNRegistryEntry, CDNProvider } from './types';
9
+ import type { CDNProvider, CDNRegistry, CDNRegistryEntry } from './types';
10
10
  /**
11
11
  * Built-in CDN registry for popular packages.
12
12
  * esm.sh is prioritized as the primary CDN for ESM module loading.
@@ -1 +1 @@
1
- {"version":3,"file":"cdn-registry.d.ts","sourceRoot":"","sources":["../../src/resolver/cdn-registry.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAE1E;;;GAGG;AACH,eAAO,MAAM,oBAAoB,EAAE,WA4JlC,CAAC;AAEF;;GAEG;AACH,wBAAgB,aAAa,CAC3B,WAAW,EAAE,MAAM,EACnB,QAAQ,GAAE,WAAkC,GAC3C,gBAAgB,GAAG,SAAS,CAE9B;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAC9B,WAAW,EAAE,MAAM,EACnB,aAAa,GAAE,WAAW,EAAkD,EAC5E,QAAQ,GAAE,WAAkC,GAC3C,MAAM,GAAG,SAAS,CAoBpB;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,QAAQ,GAAE,WAAkC,GAAG,MAAM,EAAE,CAE5F;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,WAAW,EAAE,MAAM,EAAE,QAAQ,GAAE,WAAkC,GAAG,OAAO,CAE9G;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,cAAc,EAAE,WAAW,GAAG,WAAW,CAKxE;AAED;;GAEG;AACH,wBAAgB,0BAA0B,CACxC,WAAW,EAAE,MAAM,EACnB,QAAQ,GAAE,WAAkC,GAC3C,MAAM,EAAE,CAYV"}
1
+ {"version":3,"file":"cdn-registry.d.ts","sourceRoot":"","sources":["../../src/resolver/cdn-registry.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAE1E;;;GAGG;AACH,eAAO,MAAM,oBAAoB,EAAE,WA4JlC,CAAC;AAEF;;GAEG;AACH,wBAAgB,aAAa,CAC3B,WAAW,EAAE,MAAM,EACnB,QAAQ,GAAE,WAAkC,GAC3C,gBAAgB,GAAG,SAAS,CAE9B;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAC9B,WAAW,EAAE,MAAM,EACnB,aAAa,GAAE,WAAW,EAAkD,EAC5E,QAAQ,GAAE,WAAkC,GAC3C,MAAM,GAAG,SAAS,CAoBpB;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,QAAQ,GAAE,WAAkC,GAAG,MAAM,EAAE,CAE5F;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,WAAW,EAAE,MAAM,EAAE,QAAQ,GAAE,WAAkC,GAAG,OAAO,CAE9G;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,cAAc,EAAE,WAAW,GAAG,WAAW,CAKxE;AAED;;GAEG;AACH,wBAAgB,0BAA0B,CACxC,WAAW,EAAE,MAAM,EACnB,QAAQ,GAAE,WAAkC,GAC3C,MAAM,EAAE,CAYV"}
@@ -6,7 +6,7 @@
6
6
  *
7
7
  * @packageDocumentation
8
8
  */
9
- import type { ImportResolver, CDNRegistry, CDNProvider } from './types';
9
+ import type { CDNProvider, CDNRegistry, ImportResolver } from './types';
10
10
  /**
11
11
  * Options for configuring the esm.sh resolver.
12
12
  */
@@ -1 +1 @@
1
- {"version":3,"file":"esm-sh.resolver.d.ts","sourceRoot":"","sources":["../../src/resolver/esm-sh.resolver.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAkC,WAAW,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAIxG;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,uCAAuC;IACvC,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,6CAA6C;IAC7C,QAAQ,CAAC,EAAE,WAAW,CAAC;IACvB,8BAA8B;IAC9B,aAAa,CAAC,EAAE,WAAW,EAAE,CAAC;CAC/B;AAID;;;;;;;;;;;;GAYG;AACH;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,2BAA2B,CACzC,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EACjC,WAAW,CAAC,EAAE,oBAAoB,GACjC,cAAc,GAAG;IAAE,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,CAmBxD;AAED,wBAAgB,mBAAmB,CAAC,OAAO,GAAE,oBAAyB,GAAG,cAAc,CAoEtF"}
1
+ {"version":3,"file":"esm-sh.resolver.d.ts","sourceRoot":"","sources":["../../src/resolver/esm-sh.resolver.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,cAAc,EAAkC,MAAM,SAAS,CAAC;AAExG;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,uCAAuC;IACvC,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,6CAA6C;IAC7C,QAAQ,CAAC,EAAE,WAAW,CAAC;IACvB,8BAA8B;IAC9B,aAAa,CAAC,EAAE,WAAW,EAAE,CAAC;CAC/B;AAID;;;;;;;;;;;;GAYG;AACH;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,2BAA2B,CACzC,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EACjC,WAAW,CAAC,EAAE,oBAAoB,GACjC,cAAc,GAAG;IAAE,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,CAmBxD;AAED,wBAAgB,mBAAmB,CAAC,OAAO,GAAE,oBAAyB,GAAG,cAAc,CAoEtF"}
@@ -6,7 +6,7 @@
6
6
  * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script/type/importmap
7
7
  * @packageDocumentation
8
8
  */
9
- import type { ImportMap, ResolvedImport, ResolvedDependency } from './types';
9
+ import type { ImportMap, ResolvedDependency, ResolvedImport } from './types';
10
10
  /**
11
11
  * Create an import map from a record of specifier → ResolvedImport.
12
12
  */
@@ -1 +1 @@
1
- {"version":3,"file":"import-map.d.ts","sourceRoot":"","sources":["../../src/resolver/import-map.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAG7E;;GAEG;AACH,wBAAgB,2BAA2B,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,GAAG,SAAS,CAiB/F;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,YAAY,EAAE,kBAAkB,EAAE,GAAG,SAAS,CAe7E;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,GAAG,IAAI,EAAE,SAAS,EAAE,GAAG,SAAS,CAsB/D;AAED;;GAEG;AACH,wBAAgB,0BAA0B,CAAC,GAAG,EAAE,SAAS,GAAG,MAAM,CAGjE;AAED;;GAEG;AACH,wBAAgB,kCAAkC,CAAC,GAAG,EAAE,SAAS,GAAG,MAAM,CAGzE;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,YAAY,EAAE,kBAAkB,EAAE,GAAG,MAAM,EAAE,CAWlF;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,YAAY,EAAE,kBAAkB,EAAE,EAAE,OAAO,GAAE;IAAE,MAAM,CAAC,EAAE,OAAO,CAAA;CAAO,GAAG,MAAM,CAYrH;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,OAAO,GAAG;IAAE,KAAK,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,EAAE,CAAA;CAAE,CAwCpF"}
1
+ {"version":3,"file":"import-map.d.ts","sourceRoot":"","sources":["../../src/resolver/import-map.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,KAAK,EAAE,SAAS,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAE7E;;GAEG;AACH,wBAAgB,2BAA2B,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,GAAG,SAAS,CAiB/F;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,YAAY,EAAE,kBAAkB,EAAE,GAAG,SAAS,CAe7E;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,GAAG,IAAI,EAAE,SAAS,EAAE,GAAG,SAAS,CAsB/D;AAED;;GAEG;AACH,wBAAgB,0BAA0B,CAAC,GAAG,EAAE,SAAS,GAAG,MAAM,CAGjE;AAED;;GAEG;AACH,wBAAgB,kCAAkC,CAAC,GAAG,EAAE,SAAS,GAAG,MAAM,CAGzE;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,YAAY,EAAE,kBAAkB,EAAE,GAAG,MAAM,EAAE,CAWlF;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,YAAY,EAAE,kBAAkB,EAAE,EAAE,OAAO,GAAE;IAAE,MAAM,CAAC,EAAE,OAAO,CAAA;CAAO,GAAG,MAAM,CAYrH;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,OAAO,GAAG;IAAE,KAAK,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,EAAE,CAAA;CAAE,CAwCpF"}
@@ -1 +1 @@
1
- {"version":3,"file":"import-rewriter.d.ts","sourceRoot":"","sources":["../../src/resolver/import-rewriter.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC;AAIrE;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,GAAE,eAAoB,GAAG,oBAAoB,CAuElG"}
1
+ {"version":3,"file":"import-rewriter.d.ts","sourceRoot":"","sources":["../../src/resolver/import-rewriter.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,OAAO,KAAK,EAAE,eAAe,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC;AAErE;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,GAAE,eAAoB,GAAG,oBAAoB,CAuElG"}
@@ -7,8 +7,8 @@
7
7
  *
8
8
  * @packageDocumentation
9
9
  */
10
- import type { CustomShellSource, ResolvedShellTemplate } from './custom-shell-types';
11
10
  import type { ImportResolver } from '../resolver/types';
11
+ import { type CustomShellSource, type ResolvedShellTemplate } from './custom-shell-types';
12
12
  /** Options for resolving shell templates */
13
13
  export interface ResolveShellOptions {
14
14
  /** Custom import resolver (for npm sources) */
@@ -1 +1 @@
1
- {"version":3,"file":"custom-shell-resolver.d.ts","sourceRoot":"","sources":["../../src/shell/custom-shell-resolver.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,qBAAqB,EAAkB,MAAM,sBAAsB,CAAC;AAGrG,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAQxD,4CAA4C;AAC5C,MAAM,WAAW,mBAAmB;IAClC,+CAA+C;IAC/C,QAAQ,CAAC,EAAE,cAAc,CAAC;IAC1B,oCAAoC;IACpC,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAsB,oBAAoB,CACxC,MAAM,EAAE,iBAAiB,EACzB,OAAO,CAAC,EAAE,mBAAmB,GAC5B,OAAO,CAAC,qBAAqB,CAAC,CA2ChC;AAED;;GAEG;AACH,wBAAgB,uBAAuB,IAAI,IAAI,CAE9C"}
1
+ {"version":3,"file":"custom-shell-resolver.d.ts","sourceRoot":"","sources":["../../src/shell/custom-shell-resolver.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAIL,KAAK,iBAAiB,EAEtB,KAAK,qBAAqB,EAC3B,MAAM,sBAAsB,CAAC;AAS9B,4CAA4C;AAC5C,MAAM,WAAW,mBAAmB;IAClC,+CAA+C;IAC/C,QAAQ,CAAC,EAAE,cAAc,CAAC;IAC1B,oCAAoC;IACpC,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAsB,oBAAoB,CACxC,MAAM,EAAE,iBAAiB,EACzB,OAAO,CAAC,EAAE,mBAAmB,GAC5B,OAAO,CAAC,qBAAqB,CAAC,CA2ChC;AAED;;GAEG;AACH,wBAAgB,uBAAuB,IAAI,IAAI,CAE9C"}
@@ -6,7 +6,7 @@
6
6
  *
7
7
  * @packageDocumentation
8
8
  */
9
- import type { ShellTemplateValidation } from './custom-shell-types';
9
+ import { type ShellTemplateValidation } from './custom-shell-types';
10
10
  /**
11
11
  * Validate a shell template string for placeholder presence.
12
12
  *
@@ -1 +1 @@
1
- {"version":3,"file":"custom-shell-validator.d.ts","sourceRoot":"","sources":["../../src/shell/custom-shell-validator.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAQH,OAAO,KAAK,EAAwB,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AAE1F;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,GAAG,uBAAuB,CAgB/E"}
1
+ {"version":3,"file":"custom-shell-validator.d.ts","sourceRoot":"","sources":["../../src/shell/custom-shell-validator.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAML,KAAK,uBAAuB,EAC7B,MAAM,sBAAsB,CAAC;AAE9B;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,GAAG,uBAAuB,CAgB/E"}
package/shell/index.d.ts CHANGED
@@ -9,9 +9,11 @@
9
9
  export type { ShellConfig, ShellResult, CSPConfig, WidgetSizing, ShellMountDescriptor, ShellDataInjectionDescriptor, } from './types';
10
10
  export { buildShell } from './builder';
11
11
  export { buildSizingStyleTag } from './sizing-css';
12
+ export { buildUrlWidgetShell, widgetUrlOrigin, type UrlWidgetShellOptions } from './url-widget-shell';
12
13
  export { DEFAULT_CDN_DOMAINS, DEFAULT_CSP_DIRECTIVES, RESTRICTIVE_CSP_DIRECTIVES, buildCSPDirectives, buildCSPMetaTag, validateCSPDomain, sanitizeCSPDomains, } from './csp';
13
14
  export { buildDataInjectionScript, buildCustomDataInjectionScript, createTemplateHelpers, hasSizing, type TemplateHelpers, } from './data-injector';
14
15
  export { html, trustedHtml, isTrustedHtml, type TrustedHtml } from './trusted-html';
16
+ export { sanitizeHtml, describeContentSecurityProblems, DEFAULT_MAX_MARKUP_LENGTH } from './sanitize-html';
15
17
  export type { ShellPlaceholderName, InlineShellSource, UrlShellSource, NpmShellSource, CustomShellSource, ShellTemplateValidation, ResolvedShellTemplate, ShellPlaceholderValues, } from './custom-shell-types';
16
18
  export { SHELL_PLACEHOLDER_NAMES, SHELL_PLACEHOLDERS, REQUIRED_PLACEHOLDERS, OPTIONAL_PLACEHOLDERS, isInlineShellSource, isUrlShellSource, isNpmShellSource, } from './custom-shell-types';
17
19
  export { validateShellTemplate } from './custom-shell-validator';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/shell/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,YAAY,EACV,WAAW,EACX,WAAW,EACX,SAAS,EACT,YAAY,EACZ,oBAAoB,EACpB,4BAA4B,GAC7B,MAAM,SAAS,CAAC;AAGjB,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAGvC,OAAO,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAGnD,OAAO,EACL,mBAAmB,EACnB,sBAAsB,EACtB,0BAA0B,EAC1B,kBAAkB,EAClB,eAAe,EACf,iBAAiB,EACjB,kBAAkB,GACnB,MAAM,OAAO,CAAC;AAGf,OAAO,EACL,wBAAwB,EACxB,8BAA8B,EAC9B,qBAAqB,EACrB,SAAS,EACT,KAAK,eAAe,GACrB,MAAM,iBAAiB,CAAC;AAGzB,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,aAAa,EAAE,KAAK,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAGpF,YAAY,EACV,oBAAoB,EACpB,iBAAiB,EACjB,cAAc,EACd,cAAc,EACd,iBAAiB,EACjB,uBAAuB,EACvB,qBAAqB,EACrB,sBAAsB,GACvB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACL,uBAAuB,EACvB,kBAAkB,EAClB,qBAAqB,EACrB,qBAAqB,EACrB,mBAAmB,EACnB,gBAAgB,EAChB,gBAAgB,GACjB,MAAM,sBAAsB,CAAC;AAG9B,OAAO,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AAGjE,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAG5D,OAAO,EAAE,oBAAoB,EAAE,uBAAuB,EAAE,MAAM,yBAAyB,CAAC;AACxF,YAAY,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/shell/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,YAAY,EACV,WAAW,EACX,WAAW,EACX,SAAS,EACT,YAAY,EACZ,oBAAoB,EACpB,4BAA4B,GAC7B,MAAM,SAAS,CAAC;AAGjB,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAGvC,OAAO,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAGnD,OAAO,EAAE,mBAAmB,EAAE,eAAe,EAAE,KAAK,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAGtG,OAAO,EACL,mBAAmB,EACnB,sBAAsB,EACtB,0BAA0B,EAC1B,kBAAkB,EAClB,eAAe,EACf,iBAAiB,EACjB,kBAAkB,GACnB,MAAM,OAAO,CAAC;AAGf,OAAO,EACL,wBAAwB,EACxB,8BAA8B,EAC9B,qBAAqB,EACrB,SAAS,EACT,KAAK,eAAe,GACrB,MAAM,iBAAiB,CAAC;AAGzB,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,aAAa,EAAE,KAAK,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAGpF,OAAO,EAAE,YAAY,EAAE,+BAA+B,EAAE,yBAAyB,EAAE,MAAM,iBAAiB,CAAC;AAG3G,YAAY,EACV,oBAAoB,EACpB,iBAAiB,EACjB,cAAc,EACd,cAAc,EACd,iBAAiB,EACjB,uBAAuB,EACvB,qBAAqB,EACrB,sBAAsB,GACvB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACL,uBAAuB,EACvB,kBAAkB,EAClB,qBAAqB,EACrB,qBAAqB,EACrB,mBAAmB,EACnB,gBAAgB,EAChB,gBAAgB,GACjB,MAAM,sBAAsB,CAAC;AAG9B,OAAO,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AAGjE,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAG5D,OAAO,EAAE,oBAAoB,EAAE,uBAAuB,EAAE,MAAM,yBAAyB,CAAC;AACxF,YAAY,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC"}
package/shell/index.js CHANGED
@@ -1,4 +1,4 @@
1
- "use strict";var __defProp=Object.defineProperty;var __getOwnPropDesc=Object.getOwnPropertyDescriptor;var __getOwnPropNames=Object.getOwnPropertyNames;var __hasOwnProp=Object.prototype.hasOwnProperty;var __export=(target,all)=>{for(var name in all)__defProp(target,name,{get:all[name],enumerable:true})};var __copyProps=(to,from,except,desc)=>{if(from&&typeof from==="object"||typeof from==="function"){for(let key of __getOwnPropNames(from))if(!__hasOwnProp.call(to,key)&&key!==except)__defProp(to,key,{get:()=>from[key],enumerable:!(desc=__getOwnPropDesc(from,key))||desc.enumerable})}return to};var __toCommonJS=mod=>__copyProps(__defProp({},"__esModule",{value:true}),mod);var shell_exports={};__export(shell_exports,{DEFAULT_CDN_DOMAINS:()=>DEFAULT_CDN_DOMAINS,DEFAULT_CSP_DIRECTIVES:()=>DEFAULT_CSP_DIRECTIVES,OPTIONAL_PLACEHOLDERS:()=>OPTIONAL_PLACEHOLDERS,REQUIRED_PLACEHOLDERS:()=>REQUIRED_PLACEHOLDERS,RESTRICTIVE_CSP_DIRECTIVES:()=>RESTRICTIVE_CSP_DIRECTIVES,SHELL_PLACEHOLDERS:()=>SHELL_PLACEHOLDERS,SHELL_PLACEHOLDER_NAMES:()=>SHELL_PLACEHOLDER_NAMES,applyShellTemplate:()=>applyShellTemplate,buildCSPDirectives:()=>buildCSPDirectives,buildCSPMetaTag:()=>buildCSPMetaTag,buildCustomDataInjectionScript:()=>buildCustomDataInjectionScript,buildDataInjectionScript:()=>buildDataInjectionScript,buildShell:()=>buildShell,buildSizingStyleTag:()=>buildSizingStyleTag,clearShellTemplateCache:()=>clearShellTemplateCache,createTemplateHelpers:()=>createTemplateHelpers,hasSizing:()=>hasSizing,html:()=>html,isInlineShellSource:()=>isInlineShellSource,isNpmShellSource:()=>isNpmShellSource,isTrustedHtml:()=>isTrustedHtml,isUrlShellSource:()=>isUrlShellSource,resolveShellTemplate:()=>resolveShellTemplate,sanitizeCSPDomains:()=>sanitizeCSPDomains,trustedHtml:()=>trustedHtml,validateCSPDomain:()=>validateCSPDomain,validateShellTemplate:()=>validateShellTemplate});module.exports=__toCommonJS(shell_exports);var WIDGET_CALL_META_KEY="frontmcp/widgetCall";var MCP_APPS_DISPLAY_MODES=["inline","fullscreen","pip"];function generateBridgeIIFE(options={}){const{debug=false,trustedOrigins=[],minify=false}=options;const adapters=options.adapters||["openai","ext-apps","claude","gemini","generic"];const parts=[];parts.push("(function() {");parts.push('"use strict";');parts.push("");if(debug){parts.push('function log(msg) { console.log("[FrontMcpBridge] " + msg); }')}else{parts.push("function log() {}")}parts.push("");parts.push("var DEFAULT_SAFE_AREA = { top: 0, bottom: 0, left: 0, right: 0 };");parts.push("");parts.push(generateContextDetection());parts.push("");parts.push(generateBaseCapabilities());parts.push("");if(adapters.includes("openai")){parts.push(generateOpenAIAdapter());parts.push("")}if(adapters.includes("ext-apps")){parts.push(generateExtAppsAdapter(trustedOrigins));parts.push("")}if(adapters.includes("claude")){parts.push(generateClaudeAdapter());parts.push("")}if(adapters.includes("gemini")){parts.push(generateGeminiAdapter());parts.push("")}if(adapters.includes("generic")){parts.push(generateGenericAdapter());parts.push("")}parts.push(generatePlatformDetection(adapters));parts.push("");parts.push(generateBridgeClass());parts.push("");parts.push("var bridge = new FrontMcpBridge();");parts.push("bridge.initialize().then(function() {");parts.push(' log("Bridge initialized with adapter: " + bridge.adapterId);');parts.push(' window.dispatchEvent(new CustomEvent("bridge:ready", { detail: { adapter: bridge.adapterId } }));');parts.push(" if (window.__mcpDisplayMode) bridge.requestDisplayMode(window.__mcpDisplayMode).catch(function() {});");parts.push("}).catch(function(err) {");parts.push(' console.error("[FrontMcpBridge] Init failed:", err);');parts.push(' window.dispatchEvent(new CustomEvent("bridge:error", { detail: { error: err } }));');parts.push("});");parts.push("");parts.push("window.FrontMcpBridge = bridge;");parts.push("");parts.push(generateAutoResize());parts.push("function __showLoading() {");parts.push(' var root = document.getElementById("root");');parts.push(" if (root && !root.hasChildNodes()) {");parts.push(` root.innerHTML = '<div style="display:flex;align-items:center;justify-content:center;padding:2rem;color:#6b7280;font-family:system-ui,sans-serif"><div style="text-align:center"><div style="width:24px;height:24px;border:2px solid #e5e7eb;border-top-color:#3b82f6;border-radius:50%;animation:__spin 0.6s linear infinite;margin:0 auto 12px"></div><div style="font-size:0.875rem">Loading widget...</div></div></div><style>@keyframes __spin{to{transform:rotate(360deg)}}</style>';`);parts.push(" }");parts.push("}");parts.push('if (document.readyState === "loading") {');parts.push(' document.addEventListener("DOMContentLoaded", __showLoading);');parts.push("} else {");parts.push(" __showLoading();");parts.push("}");parts.push("})();");const code=parts.join("\n");if(minify){return minifyJS(code)}return code}function generateAutoResize(){return`
1
+ "use strict";var __defProp=Object.defineProperty;var __getOwnPropDesc=Object.getOwnPropertyDescriptor;var __getOwnPropNames=Object.getOwnPropertyNames;var __hasOwnProp=Object.prototype.hasOwnProperty;var __export=(target,all)=>{for(var name in all)__defProp(target,name,{get:all[name],enumerable:true})};var __copyProps=(to,from,except,desc)=>{if(from&&typeof from==="object"||typeof from==="function"){for(let key of __getOwnPropNames(from))if(!__hasOwnProp.call(to,key)&&key!==except)__defProp(to,key,{get:()=>from[key],enumerable:!(desc=__getOwnPropDesc(from,key))||desc.enumerable})}return to};var __toCommonJS=mod=>__copyProps(__defProp({},"__esModule",{value:true}),mod);var shell_exports={};__export(shell_exports,{DEFAULT_CDN_DOMAINS:()=>DEFAULT_CDN_DOMAINS,DEFAULT_CSP_DIRECTIVES:()=>DEFAULT_CSP_DIRECTIVES,DEFAULT_MAX_MARKUP_LENGTH:()=>DEFAULT_MAX_MARKUP_LENGTH,OPTIONAL_PLACEHOLDERS:()=>OPTIONAL_PLACEHOLDERS,REQUIRED_PLACEHOLDERS:()=>REQUIRED_PLACEHOLDERS,RESTRICTIVE_CSP_DIRECTIVES:()=>RESTRICTIVE_CSP_DIRECTIVES,SHELL_PLACEHOLDERS:()=>SHELL_PLACEHOLDERS,SHELL_PLACEHOLDER_NAMES:()=>SHELL_PLACEHOLDER_NAMES,applyShellTemplate:()=>applyShellTemplate,buildCSPDirectives:()=>buildCSPDirectives,buildCSPMetaTag:()=>buildCSPMetaTag,buildCustomDataInjectionScript:()=>buildCustomDataInjectionScript,buildDataInjectionScript:()=>buildDataInjectionScript,buildShell:()=>buildShell,buildSizingStyleTag:()=>buildSizingStyleTag,buildUrlWidgetShell:()=>buildUrlWidgetShell,clearShellTemplateCache:()=>clearShellTemplateCache,createTemplateHelpers:()=>createTemplateHelpers,describeContentSecurityProblems:()=>describeContentSecurityProblems,hasSizing:()=>hasSizing,html:()=>html,isInlineShellSource:()=>isInlineShellSource,isNpmShellSource:()=>isNpmShellSource,isTrustedHtml:()=>isTrustedHtml,isUrlShellSource:()=>isUrlShellSource,resolveShellTemplate:()=>resolveShellTemplate,sanitizeCSPDomains:()=>sanitizeCSPDomains,sanitizeHtml:()=>sanitizeHtml,trustedHtml:()=>trustedHtml,validateCSPDomain:()=>validateCSPDomain,validateShellTemplate:()=>validateShellTemplate,widgetUrlOrigin:()=>widgetUrlOrigin});module.exports=__toCommonJS(shell_exports);var WIDGET_CALL_META_KEY="frontmcp/widgetCall";var MCP_APPS_DISPLAY_MODES=["inline","fullscreen","pip"];function generateBridgeIIFE(options={}){const{debug=false,trustedOrigins=[],minify=false}=options;const adapters=options.adapters||["openai","ext-apps","claude","gemini","generic"];const parts=[];parts.push("(function() {");parts.push('"use strict";');parts.push("");if(debug){parts.push('function log(msg) { console.log("[FrontMcpBridge] " + msg); }')}else{parts.push("function log() {}")}parts.push("");parts.push("var DEFAULT_SAFE_AREA = { top: 0, bottom: 0, left: 0, right: 0 };");parts.push("");parts.push(generateContextDetection());parts.push("");parts.push(generateBaseCapabilities());parts.push("");if(adapters.includes("openai")){parts.push(generateOpenAIAdapter());parts.push("")}if(adapters.includes("ext-apps")){parts.push(generateExtAppsAdapter(trustedOrigins));parts.push("")}if(adapters.includes("claude")){parts.push(generateClaudeAdapter());parts.push("")}if(adapters.includes("gemini")){parts.push(generateGeminiAdapter());parts.push("")}if(adapters.includes("generic")){parts.push(generateGenericAdapter());parts.push("")}parts.push(generatePlatformDetection(adapters));parts.push("");parts.push(generateBridgeClass());parts.push("");parts.push("var bridge = new FrontMcpBridge();");parts.push("bridge.initialize().then(function() {");parts.push(' log("Bridge initialized with adapter: " + bridge.adapterId);');parts.push(' window.dispatchEvent(new CustomEvent("bridge:ready", { detail: { adapter: bridge.adapterId } }));');parts.push(" if (window.__mcpDisplayMode) bridge.requestDisplayMode(window.__mcpDisplayMode).catch(function() {});");parts.push("}).catch(function(err) {");parts.push(' console.error("[FrontMcpBridge] Init failed:", err);');parts.push(' window.dispatchEvent(new CustomEvent("bridge:error", { detail: { error: err } }));');parts.push("});");parts.push("");parts.push("window.FrontMcpBridge = bridge;");parts.push("");parts.push(generateAutoResize());parts.push("function __showLoading() {");parts.push(' var root = document.getElementById("root");');parts.push(" if (root && !root.hasChildNodes()) {");parts.push(` root.innerHTML = '<div style="display:flex;align-items:center;justify-content:center;padding:2rem;color:#6b7280;font-family:system-ui,sans-serif"><div style="text-align:center"><div style="width:24px;height:24px;border:2px solid #e5e7eb;border-top-color:#3b82f6;border-radius:50%;animation:__spin 0.6s linear infinite;margin:0 auto 12px"></div><div style="font-size:0.875rem">Loading widget...</div></div></div><style>@keyframes __spin{to{transform:rotate(360deg)}}</style>';`);parts.push(" }");parts.push("}");parts.push('if (document.readyState === "loading") {');parts.push(' document.addEventListener("DOMContentLoaded", __showLoading);');parts.push("} else {");parts.push(" __showLoading();");parts.push("}");parts.push("})();");const code=parts.join("\n");if(minify){return minifyJS(code)}return code}function generateAutoResize(){return`
2
2
  function __applySizingCss(sizing) {
3
3
  if (typeof document === 'undefined' || !document.documentElement) return;
4
4
  function toLen(v) { return typeof v === 'number' ? v + 'px' : v; }
@@ -1206,4 +1206,37 @@ ${headParts.map(p=>` ${p}`).join("\n")}
1206
1206
  ${content}
1207
1207
  </body>
1208
1208
  </html>`;return{html:html2,hash:simpleHash(html2),size:Buffer.byteLength(html2,"utf-8")}}function buildCustomShell(content,customShell,ctx){let template;if(typeof customShell==="string"){const validation=validateShellTemplate(customShell);if(!validation.valid){throw new Error(`Custom shell template is missing required placeholder(s): ${validation.missingRequired.map(n=>`{{${n}}}`).join(", ")}`)}template=customShell}else{template=customShell.template}const cspTag=buildCSPMetaTag(ctx.csp);const dataScript=resolveDataInjectionScript({dataInjection:ctx.dataInjection,toolName:ctx.toolName,input:ctx.input,output:ctx.output,structuredContent:ctx.structuredContent,sizing:ctx.sizing,displayMode:ctx.displayMode});const sizingStyle=buildSizingStyleTag(ctx.sizing);const dataWithSizing=sizingStyle?`${dataScript}
1209
- ${sizingStyle}`:dataScript;let bridgeHtml="";if(ctx.includeBridge){const bridgeScript=generateBridgeIIFE({minify:true});bridgeHtml=`<script>${bridgeScript}</script>`}const html2=applyShellTemplate(template,{csp:cspTag,data:dataWithSizing,bridge:bridgeHtml,content,title:ctx.title?escapeHtmlForTag(ctx.title):""});return{html:html2,hash:simpleHash(html2),size:Buffer.byteLength(html2,"utf-8")}}function simpleHash(str){let hash=0;for(let i=0;i<str.length;i++){const char=str.charCodeAt(i);hash=(hash<<5)-hash+char|0}return Math.abs(hash).toString(16).padStart(8,"0")}function escapeHtmlForTag(str){return str.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}var DEFAULT_TIMEOUT_MS=1e4;var templateCache=new Map;async function resolveShellTemplate(source,options){if(isInlineShellSource(source)){return resolveInline(source.inline)}if(isUrlShellSource(source)){const cacheKey=`url:${source.url}`;if(!options?.noCache){const cached=templateCache.get(cacheKey);if(cached)return cached}const template=await fetchWithTimeout(source.url,source.timeout??DEFAULT_TIMEOUT_MS);const resolved=buildResolved(template,"url");if(!options?.noCache){templateCache.set(cacheKey,resolved)}return resolved}if(isNpmShellSource(source)){const specifier=source.version?`${source.npm}@${source.version}`:source.npm;const cacheKey=`npm:${specifier}`;if(!options?.noCache){const cached=templateCache.get(cacheKey);if(cached)return cached}const template=await resolveNpmTemplate(source,specifier,options?.resolver);const resolved=buildResolved(template,"npm");if(!options?.noCache){templateCache.set(cacheKey,resolved)}return resolved}throw new Error('Invalid custom shell source: must have "inline", "url", or "npm" property')}function clearShellTemplateCache(){templateCache.clear()}function resolveInline(template){return buildResolved(template,"inline")}function buildResolved(template,sourceType){const validation=validateShellTemplate(template);if(!validation.valid){throw new Error(`Custom shell template is missing required placeholder(s): ${validation.missingRequired.map(n=>`{{${n}}}`).join(", ")}`)}return{template,sourceType,validation}}async function fetchWithTimeout(url,timeoutMs){const controller=new AbortController;const timer=setTimeout(()=>controller.abort(),timeoutMs);try{const response=await fetch(url,{signal:controller.signal});if(!response.ok){throw new Error(`Failed to fetch shell template from ${url}: HTTP ${response.status}`)}return await response.text()}catch(err){if(err instanceof Error&&err.name==="AbortError"){throw new Error(`Shell template fetch timed out after ${timeoutMs}ms: ${url}`)}throw err}finally{clearTimeout(timer)}}async function resolveNpmTemplate(source,specifier,resolver){const cdnUrl=resolveNpmToCdnUrl(specifier,resolver);const moduleText=await fetchWithTimeout(cdnUrl,DEFAULT_TIMEOUT_MS);return extractTemplateFromModule(moduleText,source.exportName)}function resolveNpmToCdnUrl(specifier,resolver){if(resolver){const resolved=resolver.resolve(specifier);if(resolved){return resolved.value}}return`https://esm.sh/${specifier}`}function extractTemplateFromModule(moduleText,exportName){if(exportName&&exportName!=="default"){const namedPattern=new RegExp(`export\\s+(?:const|let|var)\\s+${escapeRegExp(exportName)}\\s*=\\s*\`([\\s\\S]*?)\``);const namedMatch=moduleText.match(namedPattern);if(namedMatch){return namedMatch[1]}throw new Error(`Could not extract named export "${exportName}" from npm shell package. The package must export a template literal string.`)}const defaultPattern=/export\s+default\s+`([\s\S]*?)`/;const defaultMatch=moduleText.match(defaultPattern);if(defaultMatch){return defaultMatch[1]}throw new Error("Could not extract default export from npm shell package. The package must export a template literal string (e.g., export default `<html>...</html>`).")}function escapeRegExp(str){return str.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}0&&(module.exports={DEFAULT_CDN_DOMAINS,DEFAULT_CSP_DIRECTIVES,OPTIONAL_PLACEHOLDERS,REQUIRED_PLACEHOLDERS,RESTRICTIVE_CSP_DIRECTIVES,SHELL_PLACEHOLDERS,SHELL_PLACEHOLDER_NAMES,applyShellTemplate,buildCSPDirectives,buildCSPMetaTag,buildCustomDataInjectionScript,buildDataInjectionScript,buildShell,buildSizingStyleTag,clearShellTemplateCache,createTemplateHelpers,hasSizing,html,isInlineShellSource,isNpmShellSource,isTrustedHtml,isUrlShellSource,resolveShellTemplate,sanitizeCSPDomains,trustedHtml,validateCSPDomain,validateShellTemplate});
1209
+ ${sizingStyle}`:dataScript;let bridgeHtml="";if(ctx.includeBridge){const bridgeScript=generateBridgeIIFE({minify:true});bridgeHtml=`<script>${bridgeScript}</script>`}const html2=applyShellTemplate(template,{csp:cspTag,data:dataWithSizing,bridge:bridgeHtml,content,title:ctx.title?escapeHtmlForTag(ctx.title):""});return{html:html2,hash:simpleHash(html2),size:Buffer.byteLength(html2,"utf-8")}}function simpleHash(str){let hash=0;for(let i=0;i<str.length;i++){const char=str.charCodeAt(i);hash=(hash<<5)-hash+char|0}return Math.abs(hash).toString(16).padStart(8,"0")}function escapeHtmlForTag(str){return str.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}var FRAME_ID="frontmcp-widget";function widgetUrlOrigin(url){return parseWidgetUrl(url).origin}function parseWidgetUrl(url){let parsed;try{parsed=new URL(url)}catch{throw new Error("Widget URL is not an absolute URL")}if(parsed.protocol!=="https:"&&parsed.protocol!=="http:"){throw new Error("Widget URL must use https: (or http: for local development)")}return parsed}function buildUrlWidgetShell(options){const{href,origin}=parseWidgetUrl(options.url);const title=options.title??"Widget";const csp=`default-src 'none'; script-src 'unsafe-inline'; style-src 'unsafe-inline'; frame-src ${origin}`;return`<!DOCTYPE html>
1210
+ <html lang="en">
1211
+ <head>
1212
+ <meta charset="UTF-8">
1213
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
1214
+ <meta http-equiv="Content-Security-Policy" content="${escapeAttribute2(csp)}">
1215
+ <title>${escapeText(title)}</title>
1216
+ <style>html,body{margin:0;padding:0;height:100%;overflow:hidden}#${FRAME_ID}{display:block;border:0;width:100%;height:100%}#frontmcp-widget-blocked{font:14px/1.4 system-ui,sans-serif;padding:12px}</style>
1217
+ </head>
1218
+ <body>
1219
+ <iframe id="${FRAME_ID}" src="${escapeAttribute2(href)}" title="${escapeAttribute2(title)}"></iframe>
1220
+ <script>${buildRelayScript(origin)}</script>
1221
+ </body>
1222
+ </html>`}function buildRelayScript(widgetOrigin){const originLiteral=JSON.stringify(widgetOrigin).replace(/</g,"\\u003c");return`(function () {
1223
+ var frame = document.getElementById(${JSON.stringify(FRAME_ID)});
1224
+ var widgetOrigin = ${originLiteral};
1225
+ var hostOrigin = null;
1226
+ window.addEventListener('message', function (event) {
1227
+ if (event.source === frame.contentWindow) {
1228
+ if (event.origin !== widgetOrigin) return;
1229
+ window.parent.postMessage(event.data, hostOrigin || '*');
1230
+ } else if (event.source === window.parent) {
1231
+ if (!hostOrigin && event.origin && event.origin !== 'null') hostOrigin = event.origin;
1232
+ if (frame.contentWindow) frame.contentWindow.postMessage(event.data, widgetOrigin);
1233
+ }
1234
+ });
1235
+ document.addEventListener('securitypolicyviolation', function (event) {
1236
+ if (String(event.effectiveDirective || event.violatedDirective).indexOf('frame-src') !== 0) return;
1237
+ var note = document.createElement('p');
1238
+ note.id = 'frontmcp-widget-blocked';
1239
+ note.textContent = 'This widget loads from ' + widgetOrigin + ', which this host does not allow.';
1240
+ frame.replaceWith(note);
1241
+ });
1242
+ })();`}function escapeAttribute2(value){return value.replace(/&/g,"&amp;").replace(/"/g,"&quot;").replace(/'/g,"&#39;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}function escapeText(value){return value.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}var import_entities=require("entities");var CSS_ESCAPE=/\\(?:([0-9a-fA-F]{1,6})[ \t\n\r\f]?|([^\n\r\f0-9a-fA-F]))/g;var CSS_COMMENT=/\/\*[\s\S]*?(?:\*\/|$)/g;function unescapeCss(text){return text.replace(CSS_ESCAPE,(_match,hex,character)=>{if(hex===void 0)return character??"";const codePoint=parseInt(hex,16);const valid=codePoint>0&&codePoint<=1114111&&(codePoint<55296||codePoint>57343);return valid?String.fromCodePoint(codePoint):"\uFFFD"})}function sanitizeStyleText(css){return removeImports(css.replace(/</g,"\\3c ").replace(/&(?=[#A-Za-z0-9])/g,"\\26 "))}function removeImports(css){const kept=[];let start=0;let index=css.indexOf("@");while(index!==-1){const nameEnd=identEnd(css,index+1);if(unescapeCss(css.slice(index+1,nameEnd)).toLowerCase()==="import"){kept.push(css.slice(start,index)," ");start=statementEnd(css,nameEnd);index=css.indexOf("@",start)}else{index=css.indexOf("@",index+1)}}kept.push(css.slice(start));return kept.join("")}function commentEnd(css,start){const end=css.indexOf("*/",start+2);return end===-1?css.length:end+2}function stringEnd(css,start){const quote=css[start];let index=start+1;while(index<css.length&&css[index]!==quote&&css[index]!=="\n"){index+=css[index]==="\\"?2:1}return Math.min(index+1,css.length)}function isIdentCharacter(character){return character==="-"||/\w/.test(character)||character.charCodeAt(0)>=128}function identEnd(css,start){let index=start;while(index<css.length){if(css[index]==="\\"&&css[index+1]!==void 0&&css[index+1]!=="\n"){index+=2}else if(isIdentCharacter(css[index])){index++}else{break}}return index}function statementEnd(css,start){let depth=0;let index=start;while(index<css.length){const character=css[index];if(character==="/"&&css[index+1]==="*"){index=commentEnd(css,index);continue}if(character==='"'||character==="'"){index=stringEnd(css,index);continue}if(character==="("||character==="["||character==="{")depth++;if(character===")"||character==="]")depth=Math.max(0,depth-1);if(character==="}"){if(depth===0)return index;depth--;if(depth===0)return index+1}if(character===";"&&depth===0)return index+1;index++}return css.length}function sanitizeStyleAttribute(style){const declarations=splitDeclarations(style);const kept=declarations.filter(declaration=>!isFixedPosition(declaration));return kept.length===declarations.length?style:kept.join(";")}function splitDeclarations(style){const declarations=[];let depth=0;let start=0;let index=0;while(index<style.length){const character=style[index];if(character==="/"&&style[index+1]==="*"){index=commentEnd(style,index);continue}if(character==='"'||character==="'"){index=stringEnd(style,index);continue}if(character==="(")depth++;if(character===")")depth=Math.max(0,depth-1);if(character===";"&&depth===0){declarations.push(style.slice(start,index));start=index+1}index++}declarations.push(style.slice(start));return declarations}function isFixedPosition(declaration){const text=declaration.replace(CSS_COMMENT,"");const colon=text.indexOf(":");if(colon===-1)return false;const property=unescapeCss(text.slice(0,colon)).trim().toLowerCase();const value=unescapeCss(text.slice(colon+1)).toLowerCase();return property==="position"&&/fixed|sticky|var\(/.test(value)}var DEFAULT_MAX_MARKUP_LENGTH=2*1024*1024;var POLICY_FLAGS=["allowUnsafeLinks","allowInlineScripts","allowToolCallAttributes","bypassSanitization"];var WHITESPACE=/[\t\n\f\r ]/;var TAG_NAME=/^[A-Za-z][A-Za-z0-9-]*$/;var ATTRIBUTE_NAME_BREAKERS=/[\s"'<>/=]/;var COMMENT_END=/--!?>/g;var RAW_TEXT_CONTENT={script:content=>content,style:sanitizeStyleText,textarea:content=>content.replace(/</g,"&lt;"),title:content=>content.replace(/</g,"&lt;"),xmp:content=>content.replace(/</g,"&lt;"),iframe:()=>"",noembed:()=>"",noframes:()=>"",noscript:()=>""};var RAW_TEXT_END=Object.fromEntries(Object.keys(RAW_TEXT_CONTENT).map(name=>[name,new RegExp(`</${name}(?=[\\t\\n\\f\\r />])`,"gi")]));var DROPPED_TAGS=new Set(["base","meta","object","embed","applet","animate","animatecolor","animatemotion","animatetransform","set"]);var URL_ATTRIBUTES=new Set(["href","xlink:href","src","action","formaction","poster","background","cite","data","codebase","classid","archive","longdesc","lowsrc","dynsrc","manifest","icon","profile"]);var URL_LIST_ATTRIBUTES=new Set(["srcset","imagesrcset","ping"]);var SCRIPT_SOURCE_ATTRIBUTES=new Set(["src","href","xlink:href"]);var TOOL_CALL_ATTRIBUTES=new Set(["data-tool-call","data-tool-args"]);var NAVIGATION_ATTRIBUTES={a:new Set(["href","xlink:href"]),area:new Set(["href","xlink:href"]),form:new Set(["action"]),button:new Set(["formaction"]),input:new Set(["formaction"])};var SAFE_SCHEMES=new Set(["http","https","mailto"]);var RASTER_IMAGE_DATA_URL=/^data:image\/(png|gif|jpeg|webp|avif)[;,]/i;var URL_SCHEME=/^([A-Za-z][A-Za-z0-9+.-]*):/;function sanitizeHtml(markup,policy={}){const problems=describeContentSecurityProblems(policy);if(problems.length>0)throw new TypeError(problems.join(" "));if(policy.bypassSanitization)return markup;const maxLength=policy.maxMarkupLength??DEFAULT_MAX_MARKUP_LENGTH;if(markup.length>maxLength){throw new RangeError(`The markup is ${markup.length} characters, over the ${maxLength} that \`ui.contentSecurity\` sanitizes (\`maxMarkupLength\`), so it is not rendered.`)}const output=[];let index=0;while(index<markup.length){const open=markup.indexOf("<",index);if(open===-1){output.push(markup.slice(index));break}output.push(markup.slice(index,open));const next=markup[open+1]??"";if(next==="!"||next==="?"){index=skipDeclaration(markup,open)}else if(next==="/"){index=writeEndTag(markup,open,output)}else if(isAsciiLetter(next)){index=writeElement(markup,open,output,policy)}else{output.push("&lt;");index=open+1}}return output.join("")}function describeContentSecurityProblems(policy){if(!isPlainObject(policy)){return[`\`ui.contentSecurity\` must be an object of flags, and it is ${describeValue(policy)}.`]}const problems=[];for(const[key,value]of Object.entries(policy)){if(value===void 0)continue;if(POLICY_FLAGS.includes(key)){if(typeof value!=="boolean"){problems.push(`\`ui.contentSecurity.${key}\` must be true or false, and it is ${describeValue(value)}.`)}}else if(key==="maxMarkupLength"){if(!Number.isSafeInteger(value)||value<=0){problems.push(`\`ui.contentSecurity.maxMarkupLength\` must be a positive integer, and it is ${describeValue(value)}.`)}}else{problems.push(`\`ui.contentSecurity\` has no \`${key}\` option; its options are \`${POLICY_FLAGS.join("`, `")}\` and \`maxMarkupLength\`.`)}}return problems}function isPlainObject(value){if(typeof value!=="object"||value===null)return false;const prototype=Object.getPrototypeOf(value);return prototype===Object.prototype||prototype===null}function describeValue(value){if(value===null||Array.isArray(value))return JSON.stringify(value);return typeof value==="object"||typeof value==="function"?`a ${typeof value}`:`${typeof value} ${JSON.stringify(value)}`}function isAsciiLetter(character){return/^[A-Za-z]$/.test(character)}function asciiLowerCase(text){return text.replace(/[A-Z]/g,letter=>letter.toLowerCase())}function skipDeclaration(markup,open){if(markup.startsWith("<!--",open)){COMMENT_END.lastIndex=open+2;const close2=COMMENT_END.exec(markup);return close2?close2.index+close2[0].length:markup.length}const close=markup.indexOf(">",open);return close===-1?markup.length:close+1}function writeEndTag(markup,open,output){if(!isAsciiLetter(markup[open+2]??"")){return markup.startsWith("</>",open)?open+3:skipDeclaration(markup,open)}const tag=parseTag(markup,open+2);if(!tag)return markup.length;if(TAG_NAME.test(tag.name)&&!DROPPED_TAGS.has(asciiLowerCase(tag.name)))output.push(`</${tag.name}>`);return tag.end}function writeElement(markup,open,output,policy){const tag=parseTag(markup,open+1);if(!tag)return markup.length;const name=asciiLowerCase(tag.name);if(name==="plaintext"){output.push(markup.slice(tag.end).replace(/</g,"&lt;"));return markup.length}const keepContent=RAW_TEXT_CONTENT[name];if(keepContent){const{content,end}=readRawText(markup,tag.end,name);if(name==="script"&&!isAllowedScript(tag,policy))return end;output.push(`<${tag.name}${writeAttributes(name,tag.attributes,policy)}>${keepContent(content)}</${tag.name}>`);return end}if(TAG_NAME.test(tag.name)&&!DROPPED_TAGS.has(name)&&!isCrossOriginStylesheet(name,tag.attributes)){output.push(`<${tag.name}${writeAttributes(name,tag.attributes,policy)}${tag.selfClosing?" /":""}>`)}return tag.end}function isAllowedScript(tag,policy){return policy.allowInlineScripts===true&&!tag.attributes.some(({name})=>SCRIPT_SOURCE_ATTRIBUTES.has(asciiLowerCase(name)))}function isCrossOriginStylesheet(tagName,attributes){if(tagName!=="link")return false;const rel=attributeValue(attributes,"rel");const href=attributeValue(attributes,"href");if(rel===void 0||href===void 0||!/(^|[\t\n\f\r ])stylesheet($|[\t\n\f\r ])/i.test(rel))return false;const url=urlAsParsed(href);return URL_SCHEME.test(url)||/^[\\/]{2}/.test(url)}function attributeValue(attributes,name){const attribute=attributes.find(candidate=>asciiLowerCase(candidate.name)===name);return attribute?.value===void 0?void 0:decodeAttributeValue(attribute.value)}function readRawText(markup,start,name){const endTag=RAW_TEXT_END[name];endTag.lastIndex=start;const match=endTag.exec(markup);if(!match)return{content:markup.slice(start),end:markup.length};const tag=parseTag(markup,match.index+2);return{content:markup.slice(start,match.index),end:tag?tag.end:markup.length}}function parseTag(markup,start){let index=start;while(index<markup.length&&!/[\t\n\f\r />]/.test(markup[index]))index++;const tag={name:markup.slice(start,index),attributes:[],selfClosing:false,end:0};while(index<markup.length){const character=markup[index];if(WHITESPACE.test(character)){index++}else if(character===">"){tag.end=index+1;return tag}else if(character==="/"){index++;if(markup[index]===">"){tag.selfClosing=true;tag.end=index+1;return tag}}else{index=readAttribute(markup,index,tag.attributes)}}return void 0}function readAttribute(markup,start,attributes){let index=start+1;while(index<markup.length&&!/[\t\n\f\r />=]/.test(markup[index]))index++;const attribute={name:markup.slice(start,index),value:void 0};attributes.push(attribute);let afterName=index;while(afterName<markup.length&&WHITESPACE.test(markup[afterName]))afterName++;if(markup[afterName]!=="=")return afterName;index=afterName+1;while(index<markup.length&&WHITESPACE.test(markup[index]))index++;const quote=markup[index];if(quote==='"'||quote==="'"){const close=markup.indexOf(quote,index+1);if(close===-1)return markup.length;attribute.value=markup.slice(index+1,close);return close+1}if(quote===">"){attribute.value="";return index}const valueStart=index;while(index<markup.length&&!/[\t\n\f\r >]/.test(markup[index]))index++;attribute.value=markup.slice(valueStart,index);return index}function decodeAttributeValue(raw){return(0,import_entities.decodeHTMLAttribute)(raw).split("\0").join("\uFFFD")}function escapeAttributeValue(value){return value.replace(/&/g,"&amp;").replace(/"/g,"&quot;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}function writeAttributes(tagName,attributes,policy){const seen=new Set;let written="";for(const attribute of attributes){const name=asciiLowerCase(attribute.name);if(seen.has(name))continue;seen.add(name);if(!isWritableAttributeName(attribute.name)||name==="srcdoc")continue;if(name.startsWith("on")&&!policy.allowInlineScripts)continue;if(TOOL_CALL_ATTRIBUTES.has(name)&&!policy.allowToolCallAttributes)continue;if(attribute.value===void 0){written+=` ${attribute.name}`;continue}const value=decodeAttributeValue(attribute.value);if(!isAllowedValue(tagName,name,value,policy))continue;written+=` ${attribute.name}="${escapeAttributeValue(name==="style"?sanitizeStyleAttribute(value):value)}"`}return written}function isWritableAttributeName(name){if(name.length===0||ATTRIBUTE_NAME_BREAKERS.test(name))return false;return[...name].every(character=>character.charCodeAt(0)>31&&character.charCodeAt(0)!==127)}function isAllowedValue(tagName,attributeName,value,policy){if(URL_ATTRIBUTES.has(attributeName)){return isAllowedUrl(value,{imageData:tagName==="img"&&attributeName==="src",navigation:policy.allowUnsafeLinks===true&&NAVIGATION_ATTRIBUTES[tagName]?.has(attributeName)===true})}if(URL_LIST_ATTRIBUTES.has(attributeName)){const separator=attributeName==="ping"?/\s+/:/,/;return value.split(separator).every(candidate=>isAllowedUrl(candidate.trim().split(/\s+/)[0]??"",{}))}return true}function urlAsParsed(value){const url=value.replace(/[\t\n\r]/g,"");let start=0;while(start<url.length&&(url.charCodeAt(start)<=32||/\s/.test(url[start])))start++;return url.slice(start)}function isAllowedUrl(value,allowed){const url=urlAsParsed(value);const scheme=URL_SCHEME.exec(url)?.[1].toLowerCase();if(scheme===void 0||SAFE_SCHEMES.has(scheme))return true;if(scheme==="data")return allowed.imageData===true&&RASTER_IMAGE_DATA_URL.test(url);return allowed.navigation===true}var DEFAULT_TIMEOUT_MS=1e4;var templateCache=new Map;async function resolveShellTemplate(source,options){if(isInlineShellSource(source)){return resolveInline(source.inline)}if(isUrlShellSource(source)){const cacheKey=`url:${source.url}`;if(!options?.noCache){const cached=templateCache.get(cacheKey);if(cached)return cached}const template=await fetchWithTimeout(source.url,source.timeout??DEFAULT_TIMEOUT_MS);const resolved=buildResolved(template,"url");if(!options?.noCache){templateCache.set(cacheKey,resolved)}return resolved}if(isNpmShellSource(source)){const specifier=source.version?`${source.npm}@${source.version}`:source.npm;const cacheKey=`npm:${specifier}`;if(!options?.noCache){const cached=templateCache.get(cacheKey);if(cached)return cached}const template=await resolveNpmTemplate(source,specifier,options?.resolver);const resolved=buildResolved(template,"npm");if(!options?.noCache){templateCache.set(cacheKey,resolved)}return resolved}throw new Error('Invalid custom shell source: must have "inline", "url", or "npm" property')}function clearShellTemplateCache(){templateCache.clear()}function resolveInline(template){return buildResolved(template,"inline")}function buildResolved(template,sourceType){const validation=validateShellTemplate(template);if(!validation.valid){throw new Error(`Custom shell template is missing required placeholder(s): ${validation.missingRequired.map(n=>`{{${n}}}`).join(", ")}`)}return{template,sourceType,validation}}async function fetchWithTimeout(url,timeoutMs){const controller=new AbortController;const timer=setTimeout(()=>controller.abort(),timeoutMs);try{const response=await fetch(url,{signal:controller.signal});if(!response.ok){throw new Error(`Failed to fetch shell template from ${url}: HTTP ${response.status}`)}return await response.text()}catch(err){if(err instanceof Error&&err.name==="AbortError"){throw new Error(`Shell template fetch timed out after ${timeoutMs}ms: ${url}`)}throw err}finally{clearTimeout(timer)}}async function resolveNpmTemplate(source,specifier,resolver){const cdnUrl=resolveNpmToCdnUrl(specifier,resolver);const moduleText=await fetchWithTimeout(cdnUrl,DEFAULT_TIMEOUT_MS);return extractTemplateFromModule(moduleText,source.exportName)}function resolveNpmToCdnUrl(specifier,resolver){if(resolver){const resolved=resolver.resolve(specifier);if(resolved){return resolved.value}}return`https://esm.sh/${specifier}`}function extractTemplateFromModule(moduleText,exportName){if(exportName&&exportName!=="default"){const namedPattern=new RegExp(`export\\s+(?:const|let|var)\\s+${escapeRegExp(exportName)}\\s*=\\s*\`([\\s\\S]*?)\``);const namedMatch=moduleText.match(namedPattern);if(namedMatch){return namedMatch[1]}throw new Error(`Could not extract named export "${exportName}" from npm shell package. The package must export a template literal string.`)}const defaultPattern=/export\s+default\s+`([\s\S]*?)`/;const defaultMatch=moduleText.match(defaultPattern);if(defaultMatch){return defaultMatch[1]}throw new Error("Could not extract default export from npm shell package. The package must export a template literal string (e.g., export default `<html>...</html>`).")}function escapeRegExp(str){return str.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}0&&(module.exports={DEFAULT_CDN_DOMAINS,DEFAULT_CSP_DIRECTIVES,DEFAULT_MAX_MARKUP_LENGTH,OPTIONAL_PLACEHOLDERS,REQUIRED_PLACEHOLDERS,RESTRICTIVE_CSP_DIRECTIVES,SHELL_PLACEHOLDERS,SHELL_PLACEHOLDER_NAMES,applyShellTemplate,buildCSPDirectives,buildCSPMetaTag,buildCustomDataInjectionScript,buildDataInjectionScript,buildShell,buildSizingStyleTag,buildUrlWidgetShell,clearShellTemplateCache,createTemplateHelpers,describeContentSecurityProblems,hasSizing,html,isInlineShellSource,isNpmShellSource,isTrustedHtml,isUrlShellSource,resolveShellTemplate,sanitizeCSPDomains,sanitizeHtml,trustedHtml,validateCSPDomain,validateShellTemplate,widgetUrlOrigin});
@@ -0,0 +1,18 @@
1
+ /**
2
+ * The CSS part of `ui.contentSecurity`: `@import` rules are removed from style elements, and
3
+ * `position: fixed` and `position: sticky` declarations from style attributes. Other CSS is kept.
4
+ *
5
+ * @packageDocumentation
6
+ */
7
+ /**
8
+ * The text of a `<style>` element, written so that the HTML parser reads it the same way as raw
9
+ * text (in HTML) and as character data (in SVG or MathML): no `<`, and no `&` that could start a
10
+ * character reference, each written as a CSS escape. `@import` rules are removed.
11
+ */
12
+ export declare function sanitizeStyleText(css: string): string;
13
+ /**
14
+ * A style attribute without `position: fixed` or `position: sticky` declarations (nor `position`
15
+ * set from a custom property), which would let the markup lay itself over the whole widget.
16
+ */
17
+ export declare function sanitizeStyleAttribute(style: string): string;
18
+ //# sourceMappingURL=sanitize-css.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sanitize-css.d.ts","sourceRoot":"","sources":["../../src/shell/sanitize-css.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAgBH;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAErD;AAsFD;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAI5D"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Widget markup sanitizer for `ui.contentSecurity`.
3
+ *
4
+ * The markup is tokenized the way the HTML tokenizer reads it and written back out: every tag is
5
+ * rebuilt from its parsed name and attributes, text never carries a `<`, and each attribute value is
6
+ * decoded once, checked, and written back escaped, so the browser reads exactly the value that was
7
+ * checked. Comments, doctypes and processing instructions are dropped. Every scan moves forward
8
+ * through the markup, so the time it takes grows linearly with its length.
9
+ *
10
+ * @packageDocumentation
11
+ */
12
+ import type { UIContentSecurity } from '../types/ui-config';
13
+ /** The longest markup {@link sanitizeHtml} takes by default, in characters: 2 Mi. */
14
+ export declare const DEFAULT_MAX_MARKUP_LENGTH: number;
15
+ /**
16
+ * Sanitize widget markup according to `ui.contentSecurity`. See {@link UIContentSecurity} for what
17
+ * it removes and what each flag keeps.
18
+ *
19
+ * @throws TypeError when `policy` isn't a `ui.contentSecurity` object, and RangeError when the
20
+ * markup is longer than `policy.maxMarkupLength`; the markup is never returned unsanitized
21
+ */
22
+ export declare function sanitizeHtml(markup: string, policy?: UIContentSecurity): string;
23
+ /**
24
+ * Why a value can't be a `ui.contentSecurity` policy, one sentence each: it must be a plain object
25
+ * whose flags are booleans and whose `maxMarkupLength` is a positive integer.
26
+ */
27
+ export declare function describeContentSecurityProblems(policy: unknown): string[];
28
+ //# sourceMappingURL=sanitize-html.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sanitize-html.d.ts","sourceRoot":"","sources":["../../src/shell/sanitize-html.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAIH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAG5D,qFAAqF;AACrF,eAAO,MAAM,yBAAyB,QAAkB,CAAC;AA+FzD;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,GAAE,iBAAsB,GAAG,MAAM,CAoCnF;AAED;;;GAGG;AACH,wBAAgB,+BAA+B,CAAC,MAAM,EAAE,OAAO,GAAG,MAAM,EAAE,CAwBzE"}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * URL Widget Shell
3
+ *
4
+ * The page a `ui://` widget resource serves for a widget that loads from a URL
5
+ * (`servingMode: 'direct-url'` or `'custom-url'`). MCP Apps hosts and the OpenAI Apps
6
+ * SDK render widgets from `ui://` resources only, so the resource is this small page:
7
+ * it frames the widget URL and relays the host's postMessage traffic (the MCP Apps
8
+ * JSON-RPC bridge) between the host and the framed page.
9
+ *
10
+ * @packageDocumentation
11
+ */
12
+ /** Options for {@link buildUrlWidgetShell}. */
13
+ export interface UrlWidgetShellOptions {
14
+ /** Absolute `https:` (or `http:`) URL of the widget page. It must hold no call's data. */
15
+ url: string;
16
+ /** Accessible name of the frame, e.g. the tool name. */
17
+ title?: string;
18
+ }
19
+ /**
20
+ * The origin a widget URL loads from: the source the host must allow as a frame
21
+ * (`frameDomains` / `frame_domains`).
22
+ *
23
+ * @throws When the URL is not an absolute `http:` or `https:` URL
24
+ */
25
+ export declare function widgetUrlOrigin(url: string): string;
26
+ /**
27
+ * Build the page that frames a URL-served widget and relays the bridge messages.
28
+ *
29
+ * - Messages from the framed page (its origin only) go to the host.
30
+ * - Messages from the host go to the framed page, addressed to its origin, so a page the
31
+ * frame navigated to elsewhere never receives them.
32
+ * - When the host's Content Security Policy blocks the frame, the page says so.
33
+ */
34
+ export declare function buildUrlWidgetShell(options: UrlWidgetShellOptions): string;
35
+ //# sourceMappingURL=url-widget-shell.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"url-widget-shell.d.ts","sourceRoot":"","sources":["../../src/shell/url-widget-shell.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,+CAA+C;AAC/C,MAAM,WAAW,qBAAqB;IACpC,0FAA0F;IAC1F,GAAG,EAAE,MAAM,CAAC;IACZ,wDAAwD;IACxD,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAID;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAEnD;AAeD;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,qBAAqB,GAAG,MAAM,CAmB1E"}