@ulearning/ai-generative-frame 0.0.0-stage → 1.0.0-next.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 (323) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +233 -2
  3. package/dist/assistant-ui/entry.d.ts +34 -0
  4. package/dist/assistant-ui/entry.d.ts.map +1 -0
  5. package/dist/assistant-ui/entry.js +50 -0
  6. package/dist/assistant-ui/entry.js.map +1 -0
  7. package/dist/assistant-ui/extension.d.ts +18 -0
  8. package/dist/assistant-ui/extension.d.ts.map +1 -0
  9. package/dist/assistant-ui/extension.js +0 -0
  10. package/dist/assistant-ui/history.d.ts +15 -0
  11. package/dist/assistant-ui/history.d.ts.map +1 -0
  12. package/dist/assistant-ui/history.js +39 -0
  13. package/dist/assistant-ui/history.js.map +1 -0
  14. package/dist/assistant-ui/modelContext.d.ts +45 -0
  15. package/dist/assistant-ui/modelContext.d.ts.map +1 -0
  16. package/dist/assistant-ui/modelContext.js +88 -0
  17. package/dist/assistant-ui/modelContext.js.map +1 -0
  18. package/dist/assistant-ui/snapshotSaver.d.ts +11 -0
  19. package/dist/assistant-ui/snapshotSaver.d.ts.map +1 -0
  20. package/dist/assistant-ui/snapshotSaver.js +83 -0
  21. package/dist/assistant-ui/snapshotSaver.js.map +1 -0
  22. package/dist/assistant-ui/tool-calls.d.ts +21 -0
  23. package/dist/assistant-ui/tool-calls.d.ts.map +1 -0
  24. package/dist/assistant-ui/tool-calls.js +65 -0
  25. package/dist/assistant-ui/tool-calls.js.map +1 -0
  26. package/dist/assistant-ui/toolkit.d.ts +96 -0
  27. package/dist/assistant-ui/toolkit.d.ts.map +1 -0
  28. package/dist/assistant-ui/toolkit.js +456 -0
  29. package/dist/assistant-ui/toolkit.js.map +1 -0
  30. package/dist/assistant-ui/useSharedContext.d.ts +14 -0
  31. package/dist/assistant-ui/useSharedContext.d.ts.map +1 -0
  32. package/dist/assistant-ui/useSharedContext.js +27 -0
  33. package/dist/assistant-ui/useSharedContext.js.map +1 -0
  34. package/dist/assistant-ui.d.ts +3 -0
  35. package/dist/assistant-ui.d.ts.map +1 -0
  36. package/dist/assistant-ui.js +1 -0
  37. package/dist/bootstrap.d.ts +23 -0
  38. package/dist/bootstrap.d.ts.map +1 -0
  39. package/dist/bootstrap.js +78 -0
  40. package/dist/bootstrap.js.map +1 -0
  41. package/dist/csp.d.ts +25 -0
  42. package/dist/csp.d.ts.map +1 -0
  43. package/dist/csp.js +78 -0
  44. package/dist/csp.js.map +1 -0
  45. package/dist/index.d.ts +6 -0
  46. package/dist/index.d.ts.map +1 -0
  47. package/dist/index.js +5 -0
  48. package/dist/json-schema.d.ts +70 -0
  49. package/dist/json-schema.d.ts.map +1 -0
  50. package/dist/json-schema.js +163 -0
  51. package/dist/json-schema.js.map +1 -0
  52. package/dist/preview.d.ts +30 -0
  53. package/dist/preview.d.ts.map +1 -0
  54. package/dist/preview.js +60 -0
  55. package/dist/preview.js.map +1 -0
  56. package/dist/prompts/guidance.d.ts +41 -0
  57. package/dist/prompts/guidance.d.ts.map +1 -0
  58. package/dist/prompts/guidance.js +268 -0
  59. package/dist/prompts/guidance.js.map +1 -0
  60. package/dist/prompts.d.ts +2 -0
  61. package/dist/prompts.d.ts.map +1 -0
  62. package/dist/prompts.js +1 -0
  63. package/dist/protocol.d.ts +114 -0
  64. package/dist/protocol.d.ts.map +1 -0
  65. package/dist/protocol.js +49 -0
  66. package/dist/protocol.js.map +1 -0
  67. package/dist/repair/repair.d.ts +72 -0
  68. package/dist/repair/repair.d.ts.map +1 -0
  69. package/dist/repair/repair.js +103 -0
  70. package/dist/repair/repair.js.map +1 -0
  71. package/dist/repair.d.ts +2 -0
  72. package/dist/repair.d.ts.map +1 -0
  73. package/dist/repair.js +1 -0
  74. package/dist/rpc.d.ts +60 -0
  75. package/dist/rpc.d.ts.map +1 -0
  76. package/dist/rpc.js +127 -0
  77. package/dist/rpc.js.map +1 -0
  78. package/dist/runtime/diagnostics.d.ts +17 -0
  79. package/dist/runtime/diagnostics.d.ts.map +1 -0
  80. package/dist/runtime/diagnostics.js +128 -0
  81. package/dist/runtime/diagnostics.js.map +1 -0
  82. package/dist/runtime/generated.d.ts +2 -0
  83. package/dist/runtime/generated.d.ts.map +1 -0
  84. package/dist/runtime/generated.js +5 -0
  85. package/dist/runtime/generated.js.map +1 -0
  86. package/dist/runtime/index.d.ts +7 -0
  87. package/dist/runtime/index.d.ts.map +1 -0
  88. package/dist/runtime/index.js +264 -0
  89. package/dist/runtime/index.js.map +1 -0
  90. package/dist/runtime/morph.d.ts +51 -0
  91. package/dist/runtime/morph.d.ts.map +1 -0
  92. package/dist/runtime/morph.js +251 -0
  93. package/dist/runtime/morph.js.map +1 -0
  94. package/dist/runtime/screenshot.d.ts +23 -0
  95. package/dist/runtime/screenshot.d.ts.map +1 -0
  96. package/dist/runtime/screenshot.js +188 -0
  97. package/dist/runtime/screenshot.js.map +1 -0
  98. package/dist/runtime/size.d.ts +10 -0
  99. package/dist/runtime/size.d.ts.map +1 -0
  100. package/dist/runtime/size.js +21 -0
  101. package/dist/runtime/size.js.map +1 -0
  102. package/dist/runtime/storage.d.ts +4 -0
  103. package/dist/runtime/storage.d.ts.map +1 -0
  104. package/dist/runtime/storage.js +38 -0
  105. package/dist/runtime/storage.js.map +1 -0
  106. package/dist/spec/actions.d.ts +40 -0
  107. package/dist/spec/actions.d.ts.map +1 -0
  108. package/dist/spec/actions.js +53 -0
  109. package/dist/spec/actions.js.map +1 -0
  110. package/dist/spec/assistant-ui/thread.d.ts +66 -0
  111. package/dist/spec/assistant-ui/thread.d.ts.map +1 -0
  112. package/dist/spec/assistant-ui/thread.js +252 -0
  113. package/dist/spec/assistant-ui/thread.js.map +1 -0
  114. package/dist/spec/assistant-ui/toolkit.d.ts +33 -0
  115. package/dist/spec/assistant-ui/toolkit.d.ts.map +1 -0
  116. package/dist/spec/assistant-ui/toolkit.js +142 -0
  117. package/dist/spec/assistant-ui/toolkit.js.map +1 -0
  118. package/dist/spec/assistant-ui/web.d.ts +6 -0
  119. package/dist/spec/assistant-ui/web.d.ts.map +1 -0
  120. package/dist/spec/assistant-ui/web.js +48 -0
  121. package/dist/spec/assistant-ui/web.js.map +1 -0
  122. package/dist/spec/assistant-ui.d.ts +3 -0
  123. package/dist/spec/assistant-ui.d.ts.map +1 -0
  124. package/dist/spec/assistant-ui.js +1 -0
  125. package/dist/spec/calc.d.ts +8 -0
  126. package/dist/spec/calc.d.ts.map +1 -0
  127. package/dist/spec/calc.js +498 -0
  128. package/dist/spec/calc.js.map +1 -0
  129. package/dist/spec/catalog.d.ts +52 -0
  130. package/dist/spec/catalog.d.ts.map +1 -0
  131. package/dist/spec/catalog.js +104 -0
  132. package/dist/spec/catalog.js.map +1 -0
  133. package/dist/spec/expressions.d.ts +45 -0
  134. package/dist/spec/expressions.d.ts.map +1 -0
  135. package/dist/spec/expressions.js +199 -0
  136. package/dist/spec/expressions.js.map +1 -0
  137. package/dist/spec/patch.d.ts +20 -0
  138. package/dist/spec/patch.d.ts.map +1 -0
  139. package/dist/spec/patch.js +77 -0
  140. package/dist/spec/patch.js.map +1 -0
  141. package/dist/spec/pending.d.ts +15 -0
  142. package/dist/spec/pending.d.ts.map +1 -0
  143. package/dist/spec/pending.js +33 -0
  144. package/dist/spec/pending.js.map +1 -0
  145. package/dist/spec/pointer.d.ts +17 -0
  146. package/dist/spec/pointer.d.ts.map +1 -0
  147. package/dist/spec/pointer.js +88 -0
  148. package/dist/spec/pointer.js.map +1 -0
  149. package/dist/spec/prompt.d.ts +29 -0
  150. package/dist/spec/prompt.d.ts.map +1 -0
  151. package/dist/spec/prompt.js +145 -0
  152. package/dist/spec/prompt.js.map +1 -0
  153. package/dist/spec/render-spec.d.ts +50 -0
  154. package/dist/spec/render-spec.d.ts.map +1 -0
  155. package/dist/spec/render-spec.js +104 -0
  156. package/dist/spec/render-spec.js.map +1 -0
  157. package/dist/spec/resolve.d.ts +39 -0
  158. package/dist/spec/resolve.d.ts.map +1 -0
  159. package/dist/spec/resolve.js +51 -0
  160. package/dist/spec/resolve.js.map +1 -0
  161. package/dist/spec/resolved.d.ts +3 -0
  162. package/dist/spec/resolved.d.ts.map +1 -0
  163. package/dist/spec/resolved.js +36 -0
  164. package/dist/spec/resolved.js.map +1 -0
  165. package/dist/spec/state.d.ts +34 -0
  166. package/dist/spec/state.d.ts.map +1 -0
  167. package/dist/spec/state.js +111 -0
  168. package/dist/spec/state.js.map +1 -0
  169. package/dist/spec/stream.d.ts +50 -0
  170. package/dist/spec/stream.d.ts.map +1 -0
  171. package/dist/spec/stream.js +168 -0
  172. package/dist/spec/stream.js.map +1 -0
  173. package/dist/spec/tools.d.ts +3 -0
  174. package/dist/spec/tools.d.ts.map +1 -0
  175. package/dist/spec/tools.js +3 -0
  176. package/dist/spec/tree.d.ts +21 -0
  177. package/dist/spec/tree.d.ts.map +1 -0
  178. package/dist/spec/tree.js +27 -0
  179. package/dist/spec/tree.js.map +1 -0
  180. package/dist/spec/types.d.ts +66 -0
  181. package/dist/spec/types.d.ts.map +1 -0
  182. package/dist/spec/types.js +9 -0
  183. package/dist/spec/types.js.map +1 -0
  184. package/dist/spec/validate.d.ts +32 -0
  185. package/dist/spec/validate.d.ts.map +1 -0
  186. package/dist/spec/validate.js +264 -0
  187. package/dist/spec/validate.js.map +1 -0
  188. package/dist/spec/vue/SpecRenderer.d.ts +43 -0
  189. package/dist/spec/vue/SpecRenderer.d.ts.map +1 -0
  190. package/dist/spec/vue/SpecRenderer.js +357 -0
  191. package/dist/spec/vue/SpecRenderer.js.map +1 -0
  192. package/dist/spec/vue/useSpecStream.d.ts +19 -0
  193. package/dist/spec/vue/useSpecStream.d.ts.map +1 -0
  194. package/dist/spec/vue/useSpecStream.js +115 -0
  195. package/dist/spec/vue/useSpecStream.js.map +1 -0
  196. package/dist/spec/vue.d.ts +3 -0
  197. package/dist/spec/vue.d.ts.map +1 -0
  198. package/dist/spec/vue.js +3 -0
  199. package/dist/spec.d.ts +12 -0
  200. package/dist/spec.d.ts.map +1 -0
  201. package/dist/spec.js +8 -0
  202. package/dist/theme.d.ts +38 -0
  203. package/dist/theme.d.ts.map +1 -0
  204. package/dist/theme.js +370 -0
  205. package/dist/theme.js.map +1 -0
  206. package/dist/tools/define.d.ts +43 -0
  207. package/dist/tools/define.d.ts.map +1 -0
  208. package/dist/tools/define.js +31 -0
  209. package/dist/tools/define.js.map +1 -0
  210. package/dist/tools/edits.d.ts +19 -0
  211. package/dist/tools/edits.d.ts.map +1 -0
  212. package/dist/tools/edits.js +55 -0
  213. package/dist/tools/edits.js.map +1 -0
  214. package/dist/tools/registry.d.ts +19 -0
  215. package/dist/tools/registry.d.ts.map +1 -0
  216. package/dist/tools/registry.js +33 -0
  217. package/dist/tools/registry.js.map +1 -0
  218. package/dist/tools/tools.d.ts +88 -0
  219. package/dist/tools/tools.d.ts.map +1 -0
  220. package/dist/tools/tools.js +235 -0
  221. package/dist/tools/tools.js.map +1 -0
  222. package/dist/tools.d.ts +5 -0
  223. package/dist/tools.d.ts.map +1 -0
  224. package/dist/tools.js +5 -0
  225. package/dist/version.d.ts +2 -0
  226. package/dist/version.d.ts.map +1 -0
  227. package/dist/version.js +5 -0
  228. package/dist/version.js.map +1 -0
  229. package/dist/vue/Widget.d.ts +16 -0
  230. package/dist/vue/Widget.d.ts.map +1 -0
  231. package/dist/vue/Widget.js +58 -0
  232. package/dist/vue/Widget.js.map +1 -0
  233. package/dist/vue/sync.d.ts +19 -0
  234. package/dist/vue/sync.d.ts.map +1 -0
  235. package/dist/vue/sync.js +31 -0
  236. package/dist/vue/sync.js.map +1 -0
  237. package/dist/vue/themeStore.d.ts +23 -0
  238. package/dist/vue/themeStore.d.ts.map +1 -0
  239. package/dist/vue/themeStore.js +115 -0
  240. package/dist/vue/themeStore.js.map +1 -0
  241. package/dist/vue/useThemeTokens.d.ts +6 -0
  242. package/dist/vue/useThemeTokens.d.ts.map +1 -0
  243. package/dist/vue/useThemeTokens.js +49 -0
  244. package/dist/vue/useThemeTokens.js.map +1 -0
  245. package/dist/vue/useWidget.d.ts +10 -0
  246. package/dist/vue/useWidget.d.ts.map +1 -0
  247. package/dist/vue/useWidget.js +81 -0
  248. package/dist/vue/useWidget.js.map +1 -0
  249. package/dist/vue.d.ts +5 -0
  250. package/dist/vue.d.ts.map +1 -0
  251. package/dist/vue.js +4 -0
  252. package/dist/widget.d.ts +129 -0
  253. package/dist/widget.d.ts.map +1 -0
  254. package/dist/widget.js +655 -0
  255. package/dist/widget.js.map +1 -0
  256. package/package.json +125 -3
  257. package/src/assistant-ui/entry.ts +124 -0
  258. package/src/assistant-ui/extension.ts +19 -0
  259. package/src/assistant-ui/history.ts +63 -0
  260. package/src/assistant-ui/modelContext.ts +162 -0
  261. package/src/assistant-ui/snapshotSaver.ts +116 -0
  262. package/src/assistant-ui/tool-calls.ts +115 -0
  263. package/src/assistant-ui/toolkit.tsx +747 -0
  264. package/src/assistant-ui/useSharedContext.ts +40 -0
  265. package/src/assistant-ui.ts +14 -0
  266. package/src/bootstrap.ts +112 -0
  267. package/src/csp.ts +96 -0
  268. package/src/index.ts +44 -0
  269. package/src/json-schema.ts +353 -0
  270. package/src/preview.ts +120 -0
  271. package/src/prompts/guidance.ts +369 -0
  272. package/src/prompts.ts +8 -0
  273. package/src/protocol.ts +141 -0
  274. package/src/repair/repair.ts +202 -0
  275. package/src/repair.ts +11 -0
  276. package/src/rpc.ts +228 -0
  277. package/src/runtime/diagnostics.ts +165 -0
  278. package/src/runtime/generated.ts +2 -0
  279. package/src/runtime/index.ts +343 -0
  280. package/src/runtime/morph.ts +352 -0
  281. package/src/runtime/screenshot.ts +288 -0
  282. package/src/runtime/size.ts +17 -0
  283. package/src/runtime/storage.ts +49 -0
  284. package/src/spec/actions.ts +111 -0
  285. package/src/spec/assistant-ui/thread.ts +381 -0
  286. package/src/spec/assistant-ui/toolkit.tsx +295 -0
  287. package/src/spec/assistant-ui/web.tsx +63 -0
  288. package/src/spec/assistant-ui.ts +2 -0
  289. package/src/spec/calc.ts +598 -0
  290. package/src/spec/catalog.ts +196 -0
  291. package/src/spec/expressions.ts +301 -0
  292. package/src/spec/patch.ts +112 -0
  293. package/src/spec/pending.ts +36 -0
  294. package/src/spec/pointer.ts +170 -0
  295. package/src/spec/prompt.ts +243 -0
  296. package/src/spec/render-spec.ts +144 -0
  297. package/src/spec/resolve.ts +123 -0
  298. package/src/spec/resolved.ts +53 -0
  299. package/src/spec/state.ts +193 -0
  300. package/src/spec/stream.ts +230 -0
  301. package/src/spec/tools.ts +17 -0
  302. package/src/spec/tree.ts +37 -0
  303. package/src/spec/types.ts +51 -0
  304. package/src/spec/validate.ts +429 -0
  305. package/src/spec/vue/SpecRenderer.tsx +544 -0
  306. package/src/spec/vue/__tests__/harness.ts +50 -0
  307. package/src/spec/vue/useSpecStream.ts +162 -0
  308. package/src/spec/vue.ts +13 -0
  309. package/src/spec.ts +55 -0
  310. package/src/theme.ts +423 -0
  311. package/src/tools/define.ts +65 -0
  312. package/src/tools/edits.ts +73 -0
  313. package/src/tools/registry.ts +44 -0
  314. package/src/tools/tools.ts +361 -0
  315. package/src/tools.ts +32 -0
  316. package/src/version.ts +4 -0
  317. package/src/vue/Widget.tsx +74 -0
  318. package/src/vue/sync.ts +36 -0
  319. package/src/vue/themeStore.ts +157 -0
  320. package/src/vue/useThemeTokens.ts +71 -0
  321. package/src/vue/useWidget.ts +117 -0
  322. package/src/vue.ts +8 -0
  323. package/src/widget.ts +1080 -0
@@ -0,0 +1,78 @@
1
+ import { DEFAULT_LIGHT_TOKENS, themeVariables } from "./theme.js";
2
+ import { buildCsp } from "./csp.js";
3
+ import "./runtime/generated.js";
4
+ // src/bootstrap.ts
5
+ const escapeAttribute = (value) => value.replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/</g, "&lt;");
6
+ const escapeScript = (value) => value.replace(/<\/(script)/gi, "<\\/$1");
7
+ const escapeStyle = (value) => value.replace(/<\/(style)/gi, "<\\/$1");
8
+ const SAFE_VARIABLE = /^--[\w-]+$/;
9
+ const SAFE_VALUE = /^[^;{}<>]*$/;
10
+ const rootDeclarations = (variables) => Object.entries(variables).filter(([name, value]) => SAFE_VARIABLE.test(name) && SAFE_VALUE.test(value)).map(([name, value]) => `${name}:${value};`).join("");
11
+ /**
12
+ * Base styles: transparent page, host typography, and themed form controls,
13
+ * so plain markup already matches the host before any widget CSS loads.
14
+ */
15
+ const BASE_CSS = `
16
+ *,*::before,*::after{box-sizing:border-box}
17
+ html,body{margin:0;padding:0;background:transparent}
18
+ html{overflow-y:hidden}
19
+ body{font-family:var(--font-sans);font-size:16px;line-height:1.5;color:var(--color-text);-webkit-font-smoothing:antialiased;overflow-wrap:anywhere}
20
+ #gf-root{display:flow-root;width:100%}
21
+ #gf-root[data-kind=svg]>svg{display:block;width:100%;height:auto}
22
+ h1,h2,h3,h4{line-height:1.25;margin:0 0 .5em;font-weight:600}
23
+ h1{font-size:22px}h2{font-size:18px}h3{font-size:16px}h4{font-size:14px}
24
+ p{margin:0 0 .75em}
25
+ a{color:var(--color-accent)}
26
+ code,kbd,pre,samp{font-family:var(--font-mono);font-size:.9em}
27
+ small{color:var(--color-text-muted)}
28
+ table{border-collapse:collapse;width:100%;font-size:14px;font-variant-numeric:tabular-nums}
29
+ th{font-weight:500;color:var(--color-text-muted);text-align:left}
30
+ th,td{padding:6px 10px;border-bottom:1px solid var(--color-border)}
31
+ button,input,select,textarea{font:inherit;color:inherit}
32
+ button{cursor:pointer;padding:6px 14px;border-radius:var(--radius-md);border:1px solid var(--color-border-strong);background:var(--color-surface);transition:background-color .15s,border-color .15s}
33
+ button:hover{background:var(--color-surface-muted)}
34
+ button:active{transform:translateY(1px)}
35
+ button:disabled{opacity:.5;cursor:not-allowed}
36
+ input:not([type=checkbox]):not([type=radio]):not([type=range]),select,textarea{padding:6px 10px;border-radius:var(--radius-sm);border:1px solid var(--color-border-strong);background:var(--color-surface)}
37
+ input[type=checkbox],input[type=radio],input[type=range],progress,meter{accent-color:var(--color-accent)}
38
+ :focus-visible{outline:2px solid var(--color-accent);outline-offset:2px}
39
+ .sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}
40
+ @media (prefers-reduced-motion:reduce){*,*::before,*::after{animation-duration:.01ms!important;animation-iteration-count:1!important;transition-duration:.01ms!important;scroll-behavior:auto!important}}
41
+ `.trim();
42
+ /**
43
+ * The document every widget frame loads once. It carries the CSP, the theme,
44
+ * and the runtime; widget code arrives later over the private port.
45
+ */
46
+ function buildBootstrapHtml(options) {
47
+ const tokens = options.tokens ?? DEFAULT_LIGHT_TOKENS;
48
+ const csp = typeof options.csp === "string" ? options.csp : buildCsp(options.csp);
49
+ const config = JSON.stringify({
50
+ hostOrigin: options.hostOrigin,
51
+ animate: options.animate ?? true
52
+ }).replace(/</g, "\\u003c");
53
+ return [
54
+ "<!doctype html>",
55
+ `<html lang="en" data-theme="${tokens.colorScheme}" style="color-scheme:${tokens.colorScheme};background:transparent">`,
56
+ "<head>",
57
+ "<meta charset=\"utf-8\">",
58
+ `<meta http-equiv="Content-Security-Policy" content="${escapeAttribute(csp)}">`,
59
+ "<meta name=\"viewport\" content=\"width=device-width,initial-scale=1\">",
60
+ `<style id="gf-base">:root{${rootDeclarations(themeVariables(tokens))}}\n${BASE_CSS}${options.css ? `\n${escapeStyle(options.css)}` : ""}</style>`,
61
+ "</head>",
62
+ "<body><div id=\"gf-root\"></div>",
63
+ `<script id="gf-config" type="application/json">${config}<\/script>`,
64
+ `<script>${escapeScript(options.runtime ?? "(function(){let e={write:`genframe/write`,end:`genframe/end`,replace:`genframe/replace`,screenshot:`genframe/screenshot`,inspect:`genframe/inspect`,clearStorage:`genframe/clear-storage`,hostContextChanged:`ui/notifications/host-context-changed`,toolInputPartial:`ui/notifications/tool-input-partial`,toolInput:`ui/notifications/tool-input`,toolResult:`ui/notifications/tool-result`,ready:`genframe/ready`,initialize:`ui/initialize`,initialized:`ui/notifications/initialized`,sizeChanged:`ui/notifications/size-changed`,openLink:`ui/open-link`,message:`ui/message`,callTool:`tools/call`,requestDisplayMode:`ui/request-display-mode`,updateModelContext:`ui/update-model-context`,copyText:`genframe/copy-text`,widgetState:`genframe/widget-state`,log:`genframe/log`,error:`genframe/error`},t=/^<svg[\\s>/]/i;function n(e){let n=e.trimStart();if(n.startsWith(`<?xml`)){let e=n.indexOf(`>`);if(e===-1)return`html`;n=n.slice(e+1).trimStart()}for(;n.startsWith(`<!--`);){let e=n.indexOf(`-->`,4);if(e===-1)return`html`;n=n.slice(e+3).trimStart()}return t.test(n)?`svg`:`html`}let r={parseError:-32700,invalidRequest:-32600,methodNotFound:-32601,invalidParams:-32602,internalError:-32603};var i=class extends Error{code;data;constructor(e,t,n){super(t),this.name=`RpcError`,this.code=e,this.data=n}};let a=e=>typeof e==`object`&&!!e;function o(e){return a(e)&&e.jsonrpc===`2.0`}let s=e=>e instanceof i?{code:e.code,message:e.message,...e.data===void 0?{}:{data:e.data}}:{code:r.internalError,message:e instanceof Error?e.message:String(e)};function c(e,t={}){let n=1,a=!1,c=/* @__PURE__ */ new Map,l=t=>{a||e.postMessage(t)},u=async(e,n)=>{try{if(!t.onRequest)throw new i(r.methodNotFound,`Unknown method: ${e.method}`);let a=await t.onRequest(e.method,e.params);n({jsonrpc:`2.0`,id:e.id,result:a??null})}catch(t){n({jsonrpc:`2.0`,id:e.id,error:s(t)})}},d=(e,n=l)=>{if(a||!o(e))return;let r=`id`in e&&(typeof e.id==`string`||typeof e.id==`number`);if(`method`in e&&typeof e.method==`string`){if(r)u(e,n);else try{t.onNotification?.(e.method,e.params)}catch{}return}if(!r)return;let s=e,d=c.get(s.id);d&&(c.delete(s.id),d.timer!==void 0&&clearTimeout(d.timer),s.error?d.reject(new i(s.error.code,s.error.message,s.error.data)):d.resolve(s.result))},f=e=>d(e.data);return e.addEventListener(`message`,f),e.start?.(),{request(e,t,r){if(a)return Promise.reject(/* @__PURE__ */ Error(`RPC peer is disposed`));let i=n++;return new Promise((n,a)=>{let o=r?.timeoutMs,s=o===void 0?void 0:setTimeout(()=>{c.delete(i),a(/* @__PURE__ */ Error(`${e} timed out after ${o}ms`))},o);c.set(i,{resolve:n,reject:a,timer:s}),l({jsonrpc:`2.0`,id:i,method:e,...t===void 0?{}:{params:t}})})},notify(e,t){l({jsonrpc:`2.0`,method:e,...t===void 0?{}:{params:t}})},receive:d,dispose(){if(!a){a=!0,e.removeEventListener(`message`,f);for(let e of c.values())e.timer!==void 0&&clearTimeout(e.timer),e.reject(/* @__PURE__ */ Error(`RPC peer is disposed`));c.clear()}}}}let l=`1.0.0-next.0`,u=1e3,d=[`log`,`info`,`warn`,`error`,`debug`],f=e=>e.length>u?`${e.slice(0,u)}…`:e,p=e=>{if(typeof e==`string`)return e;if(e instanceof Error)return e.stack??`${e.name}: ${e.message}`;if(typeof e==`object`&&e){if(typeof Node<`u`&&e instanceof Node)return`<${e.nodeName.toLowerCase()}>`;try{return JSON.stringify(e)}catch{return String(e)}}return String(e)};function m(e,t={}){let n=[],r=[],i=e=>{let r={...e,message:f(e.message)};n.length<50&&n.push(r),t.onError?.(r)},a=t=>{let n=t.target;if(n&&n!==e&&n instanceof e.Element){let e=n.getAttribute(`src`)??n.getAttribute(`href`)??void 0;i({kind:`resource`,message:`Failed to load <${n.localName}>${e?` ${e}`:``}`,...e?{source:e}:{}});return}let r=t,a=r.error instanceof Error?r.error.stack:void 0;i({kind:`error`,message:r.message||p(r.error),...r.filename?{source:r.filename}:{},...r.lineno?{line:r.lineno}:{},...r.colno?{column:r.colno}:{},...a?{stack:f(a)}:{}})},o=e=>{let t=e.reason,n=t instanceof Error?t.stack:void 0;i({kind:`unhandledrejection`,message:t instanceof Error?t.message:p(t),...n?{stack:f(n)}:{}})},s=e=>{i({kind:`csp`,message:`Blocked by Content Security Policy (${e.effectiveDirective}): ${e.blockedURI||`inline`}`,...e.blockedURI?{source:e.blockedURI}:{},...e.lineNumber?{line:e.lineNumber}:{}})};e.addEventListener(`error`,a,!0),e.addEventListener(`unhandledrejection`,o),e.document.addEventListener(`securitypolicyviolation`,s);let c=/* @__PURE__ */ new Map;for(let n of d){let i=e.console[n];c.set(n,i),e.console[n]=(...a)=>{let o={level:n,message:f(a.map(p).join(` `))};r.push(o),r.length>200&&r.shift(),t.onConsole?.(o),i.apply(e.console,a)}}return{errors:n,console:r,record:i,dispose(){e.removeEventListener(`error`,a,!0),e.removeEventListener(`unhandledrejection`,o),e.document.removeEventListener(`securitypolicyviolation`,s);for(let[t,n]of c)e.console[t]=n}}}function h(e){let t=e.getBoundingClientRect();if(t.height<2||t.width<2)return!0;if((e.textContent??``).trim().length>0)return!1;for(let t of Array.from(e.querySelectorAll(`svg, canvas, img, video, picture, iframe, input, button, select, textarea, progress, meter`))){let e=t.getBoundingClientRect();if(e.width>=2&&e.height>=2)return!1}for(let t of Array.from(e.querySelectorAll(`*`))){let n=e.ownerDocument.defaultView?.getComputedStyle(t);if(!n||!(n.backgroundColor!==`rgba(0, 0, 0, 0)`&&n.backgroundColor!==`transparent`||n.backgroundImage!==`none`||parseFloat(n.borderTopWidth)>0))continue;let r=t.getBoundingClientRect();if(r.width>=2&&r.height>=2)return!1}return!0}let g=/* @__PURE__ */ new Set([`style`,`script`,`meta`,`link`,`title`,`base`]);function _(e){let t=e.toLowerCase().lastIndexOf(`<style`);if(t===-1)return e;let n=e.charAt(t+6);return n!==``&&!/[\\s>/]/.test(n)||e.toLowerCase().includes(`</style`,t)?e:e.slice(0,t)}function v(e,t){let n=e.createElement(`template`);n.innerHTML=t;let r=n.content,i=[];for(let t of Array.from(r.querySelectorAll(`script`)))t.replaceWith(e.createComment(`gf-script`)),i.push(t);return{fragment:r,scripts:i}}let y=(e,t)=>{if(e.nodeType!==t.nodeType)return!1;if(e.nodeType!==Node.ELEMENT_NODE)return!0;let n=e,r=t;return n.localName===r.localName&&n.namespaceURI===r.namespaceURI&&n.getAttribute(`id`)===r.getAttribute(`id`)},b=(e,t)=>{for(let n of Array.from(t.attributes))if(e.getAttributeNS(n.namespaceURI,n.localName)!==n.value)try{n.namespaceURI?e.setAttributeNS(n.namespaceURI,n.name,n.value):e.setAttribute(n.name,n.value)}catch{}for(let n of Array.from(e.attributes))t.hasAttributeNS(n.namespaceURI,n.localName)||e.removeAttributeNS(n.namespaceURI,n.localName)},x=(e,t,n)=>{if(e.nodeType!==Node.ELEMENT_NODE){e.nodeValue!==t.nodeValue&&(e.nodeValue=t.nodeValue);return}let r=e,i=t;b(r,i),r instanceof HTMLTemplateElement&&i instanceof HTMLTemplateElement?r.innerHTML!==i.innerHTML&&r.content.replaceChildren(i.content):S(r,i,n)};function S(e,t,n){let r=Array.from(t.childNodes),i=e.firstChild;for(let t=0;t<r.length;t++){let a=r[t];if(!i){e.appendChild(a),n.onAdded(a);continue}if(y(i,a)){x(i,a,n),i=i.nextSibling;continue}let o=r[t+1];if(o&&y(i,o)){e.insertBefore(a,i),n.onAdded(a);continue}let s=i.nextSibling;s&&y(s,a)?(i.remove(),x(s,a,n),i=s.nextSibling):(e.replaceChild(a,i),n.onAdded(a),i=s)}for(;i;){let e=i.nextSibling;i.remove(),i=e}}let C=e=>{let t=!1,n=()=>{t||(t=!0,cancelAnimationFrame(r),clearTimeout(i),e())},r=requestAnimationFrame(n),i=setTimeout(n,50);return()=>{t=!0,cancelAnimationFrame(r),clearTimeout(i)}},w=(e=()=>{})=>(t,n)=>{let r=t.ownerDocument.createElementNS(n.namespaceURI??`http://www.w3.org/1999/xhtml`,`script`);for(let e of Array.from(n.attributes))try{r.setAttribute(e.name,e.value)}catch{}r.textContent=n.textContent;let i=r.getAttribute(`src`)??r.getAttribute(`href`);return i?new Promise(n=>{let a=setTimeout(()=>{e(`Script timed out: ${i}`,i),n()},15e3);r.addEventListener(`load`,()=>{clearTimeout(a),n()}),r.addEventListener(`error`,()=>{clearTimeout(a),e(`Script failed to load: ${i}`,i),n()}),t.replaceWith(r)}):(t.replaceWith(r),Promise.resolve())},T=e=>{if(e.nodeType!==Node.ELEMENT_NODE)return;let t=e;g.has(t.localName)||typeof t.animate!=`function`||t.animate([{opacity:0},{opacity:1}],{duration:200,easing:`ease-out`})};function E(e){let{root:t}=e,r=t.ownerDocument,i=e.schedule??C,a=e.runScript??w(e.onScriptError),o=``,s=`html`,c=!1,l=!1,u,d,f=[],p={onAdded(t){e.animate?.()&&T(t)}},m=i=>{u?.(),u=void 0;let a=i?o:_(o);if(a===d)return;d=a,s=n(o),t.dataset.kind=s;let c=v(r,a);f=c.scripts,S(t,c.fragment,p),e.onRender?.(s)},h=async()=>{let e=r.createTreeWalker(t,NodeFilter.SHOW_COMMENT),n=[];for(let t=e.nextNode();t;t=e.nextNode())t.nodeValue===`gf-script`&&n.push(t);let i=f;for(let e=0;e<n.length&&e<i.length;e++)await a(n[e],i[e]);i.length>0&&!l&&(l=!0,r.dispatchEvent(new Event(`DOMContentLoaded`,{bubbles:!0})),r.defaultView?.dispatchEvent(new Event(`load`)))};return{get source(){return o},get kind(){return s},get ended(){return c},get scriptsRan(){return l},write(e){if(c)throw Error(`Cannot write after end; use replace`);e&&(o+=e,u??=i(()=>{u=void 0,m(!1)}))},async end(){c||(c=!0,m(!0),await h())},async replace(e){c=!0,o=e,m(!0),await h()},flush(){u&&m(c)}}}let D=`http://www.w3.org/1999/xhtml`,O=`http://www.w3.org/2000/svg`,k=4096,A=/* @__PURE__ */ new Set([`script`,`noscript`,`template`]),j=e=>{let t=/* @__PURE__ */ new Map,n,r,i,a=()=>{if(n)return;i=e.createElement(`div`),i.setAttribute(`aria-hidden`,`true`),i.style.cssText=`all:initial;position:absolute;left:-99999px;top:0;visibility:hidden;contain:strict;width:0;height:0;`;let t=i.attachShadow({mode:`closed`});n=e.createElement(`div`),r=e.createElementNS(O,`svg`),n.appendChild(r),t.appendChild(n),e.body.appendChild(i)};return{get(i){let o=`${i.namespaceURI}|${i.localName}`,s=t.get(o);if(s)return s;a();let c=e.createElementNS(i.namespaceURI??D,i.localName);(i.namespaceURI===O?r:n).appendChild(c);let l=e.defaultView.getComputedStyle(c);s=/* @__PURE__ */ new Map;for(let e=0;e<l.length;e++){let t=l.item(e);s.set(t,l.getPropertyValue(t))}return c.remove(),t.set(o,s),s},dispose(){i?.remove()}}},M=(e,t,n)=>{let r=document.createElement(`canvas`);return r.width=Math.max(1,t),r.height=Math.max(1,n),r.getContext(`2d`).drawImage(e,0,0,t,n),r.toDataURL(`image/png`)},N=(e,t,n)=>{if(e.nodeType===Node.TEXT_NODE)return e.cloneNode();if(e.nodeType!==Node.ELEMENT_NODE)return null;let r=e;if(A.has(r.localName))return null;let i=r.ownerDocument.defaultView,a=i.getComputedStyle(r),o;if(r instanceof i.HTMLCanvasElement){o=r.ownerDocument.createElement(`img`);try{o.setAttribute(`src`,r.toDataURL(`image/png`))}catch{}}else if(r instanceof i.HTMLImageElement&&r.complete&&r.naturalWidth>0&&!r.src.startsWith(`data:`)){o=r.cloneNode(!1);try{o.setAttribute(`src`,M(r,r.naturalWidth,r.naturalHeight))}catch{}}else o=r.cloneNode(!1);r instanceof i.HTMLInputElement?r.type===`checkbox`||r.type===`radio`?r.checked?o.setAttribute(`checked`,``):o.removeAttribute(`checked`):o.setAttribute(`value`,r.value):r instanceof i.HTMLTextAreaElement?o.textContent=r.value:r instanceof i.HTMLSelectElement&&o.setAttribute(`data-gf-value`,r.value);let s=t.get(r),c=[];for(let e=0;e<a.length;e++){let t=a.item(e);if(t.startsWith(`--`))continue;let r=a.getPropertyValue(t);(r!==s.get(t)||n&&r!==n.getPropertyValue(t))&&c.push(`${t}:${r}`)}if((a.animationName!==`none`||a.transitionProperty!==`none`)&&c.push(`animation:none`,`transition:none`),o.setAttribute(`style`,c.join(`;`)),!(r instanceof i.HTMLTextAreaElement))for(let e of Array.from(r.childNodes)){let n=N(e,t,a);n&&o.appendChild(n)}if(r instanceof i.HTMLSelectElement)for(let e of Array.from(o.querySelectorAll(`option`)))(e.getAttribute(`value`)===r.value||e.textContent===r.value)&&e.setAttribute(`selected`,``);return o},P=e=>{let t=[];for(let n of Array.from(e.styleSheets)){let e;try{e=n.cssRules}catch{continue}for(let n of Array.from(e))n.constructor.name===`CSSFontFaceRule`&&!/url\\((?!\\s*[\"']?data:)/i.test(n.cssText)&&t.push(n.cssText)}return t.join(`\n`)},F=e=>{let t=e.getBoundingClientRect(),n=Math.max(1,Math.ceil(t.width));return{layoutWidth:n,width:Math.max(n,Math.ceil(e.scrollWidth)),height:Math.max(1,Math.ceil(Math.max(t.height,e.scrollHeight)))}},I=e=>new Promise((t,n)=>{let r=new Image;r.onload=()=>t(r),r.onerror=()=>n(/* @__PURE__ */ Error(`The serialized widget failed to rasterize`)),r.src=e});async function L(e,t={}){let n=e.ownerDocument,r=n.defaultView;await n.fonts?.ready;let{layoutWidth:i,width:a,height:o}=F(e),s=j(n),c;try{c=N(e,s,r.getComputedStyle(n.body))}finally{s.dispose()}let l=n.createElementNS(D,`div`);l.setAttribute(`style`,`width:${a}px;height:${o}px;overflow:hidden;`),c&&l.appendChild(c),c instanceof Element&&c.setAttribute(`style`,`${c.getAttribute(`style`)??``};width:${i}px;margin:0;`);let u=P(n),d=new XMLSerializer().serializeToString(l),f=`<svg xmlns=\"${O}\" width=\"${a}\" height=\"${o}\" viewBox=\"0 0 ${a} ${o}\"><foreignObject x=\"0\" y=\"0\" width=\"100%\" height=\"100%\">`+(u?`<style xmlns=\"${D}\">${u.replace(/</g,`\\\\3c `)}</style>`:``)+d+`</foreignObject></svg>`,p=await I(`data:image/svg+xml;charset=utf-8,${encodeURIComponent(f)}`),m=t.scale??Math.min(r.devicePixelRatio||1,2),h=Math.max(.1,Math.min(m,k/a,k/o)),g=n.createElement(`canvas`);g.width=Math.round(a*h),g.height=Math.round(o*h);let _=g.getContext(`2d`);if(!_)throw Error(`Canvas 2D context is unavailable`);let v=t.background??r.getComputedStyle(n.documentElement).getPropertyValue(`--color-background`).trim();return v&&(_.fillStyle=v,_.fillRect(0,0,g.width,g.height)),_.scale(h,h),_.drawImage(p,0,0,a,o),{dataUrl:g.toDataURL(`image/png`),width:a,height:o}}function R(e){let t=e.getBoundingClientRect();return{width:Math.ceil(t.width),height:Math.ceil(t.height)}}function z(e){let t=R(e);return t.width>0?t:void 0}async function B(e){let t=[],n=async(e,n)=>{try{await n()!==!1&&t.push(e)}catch{}};return await n(`localStorage`,()=>e.localStorage.clear()),await n(`sessionStorage`,()=>e.sessionStorage.clear()),await n(`indexedDB`,async()=>{let t=e.indexedDB;if(typeof t?.databases!=`function`)return!1;let n=await t.databases();return await Promise.all(n.map(({name:e})=>e&&new Promise(n=>{let r=t.deleteDatabase(e);r.onsuccess=r.onerror=r.onblocked=()=>n()}))),!0}),await n(`cacheStorage`,async()=>{if(!e.caches)return!1;for(let t of await e.caches.keys())await e.caches.delete(t);return!0}),await n(`cookies`,()=>{for(let t of e.document.cookie.split(`;`)){let n=t.split(`=`)[0]?.trim();n&&(e.document.cookie=`${n}=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/`)}}),{cleared:t}}let V=/^--[\\w-]+$/;function H(t=window){let n=t.document,a=n.getElementById(`gf-config`),o=JSON.parse(a?.textContent??`{}`);a?.remove();let s=n.getElementById(`gf-root`)??n.body,u,d={},f=null,p=null,g=null,_={width:0,height:0},v=m(t,{onError:t=>u?.notify(e.error,t),onConsole:t=>{(t.level===`warn`||t.level===`error`)&&u?.notify(e.log,t)}}),y=t.matchMedia?.(`(prefers-reduced-motion: reduce)`),b=E({root:s,animate:()=>o.animate!==!1&&!y?.matches,onScriptError:(e,t)=>v.record({kind:`script`,message:e,...t?{source:t}:{}})}),x=()=>R(s),S,C=()=>{S=void 0;let t=z(s);if(!t)return;let r=d.containerDimensions?.maxHeight;n.documentElement.style.overflowY=typeof r==`number`&&t.height>r?`auto`:`hidden`,(t.width!==_.width||t.height!==_.height)&&(_=t,u?.notify(e.sizeChanged,t))},w=()=>{S??=t.requestAnimationFrame(C)};typeof t.ResizeObserver==`function`&&new t.ResizeObserver(w).observe(s);let T=e=>{let r=d.theme;d={...d,...e};let i=n.documentElement.style,a=!1;(e.theme===`light`||e.theme===`dark`)&&(i.colorScheme=e.theme,n.documentElement.dataset.theme=e.theme,a=e.theme!==r);let o=e.styles?.variables;if(o&&typeof o==`object`){for(let[e,t]of Object.entries(o))V.test(e)&&typeof t==`string`&&i.setProperty(e,t);a=!0}a&&t.dispatchEvent(new CustomEvent(`themechange`,{detail:{theme:d.theme,variables:d.styles?.variables}}))},D=()=>{if(!u)throw Error(`generative-frame is not connected to its host`);return u},O=t=>D().request(e.message,{role:`user`,content:[{type:`text`,text:String(t)}]}),k=t=>D().request(e.openLink,{url:String(t)}),A=(t,n)=>D().request(e.callTool,{name:t,...n===void 0?{}:{arguments:n}}),j=t=>D().request(e.requestDisplayMode,{mode:t}),M=t=>D().request(e.updateModelContext,t),N=async t=>{await D().request(e.copyText,{text:String(t)})},P={version:l,get theme(){return d.theme},get context(){return d},get toolInput(){return f},get toolOutput(){return p},get state(){return g},sendPrompt:O,openLink:k,callTool:A,requestDisplayMode:j,updateModelContext:M,copyText:N,setState:t=>{g=t,D().notify(e.widgetState,{state:t})},on(e,n){return t.addEventListener(e,n),()=>t.removeEventListener(e,n)}},F=t;F.genframe=P,F.sendPrompt=O,F.openLink=k,t.navigator.clipboard?Object.defineProperty(t.navigator.clipboard,\"writeText\",{configurable:!0,value:N}):Object.defineProperty(t.navigator,\"clipboard\",{configurable:!0,value:{writeText:N}}),t.open=(e=>(e!==void 0&&k(String(e)).catch(()=>{}),null)),n.addEventListener(`click`,e=>{if(e.defaultPrevented||!(e.target instanceof t.Element))return;let n=e.target.closest(`a[href]`);if(!n)return;let r=n.getAttribute(`href`)??``;if(r.startsWith(`#`))return;let i;try{i=new URL(r,o.hostOrigin)}catch{return}(i.protocol===`http:`||i.protocol===`https:`)&&(e.preventDefault(),k(i.href).catch(()=>{}))},!0);let I=()=>({size:x(),blank:h(s),errorCount:v.errors.length}),H=()=>({kind:b.kind,ended:b.ended,size:x(),blank:b.ended?h(s):!1,errors:[...v.errors],console:[...v.console]}),U=async(n,a)=>{let o=a??{};switch(n){case e.end:return await b.end(),w(),I();case e.replace:if(typeof o.code!=`string`)throw new i(r.invalidParams,`replace requires a string 'code'`);return await b.replace(o.code),w(),I();case e.screenshot:return b.flush(),L(s,o);case e.inspect:return b.flush(),H();case e.clearStorage:return B(t);default:throw new i(r.methodNotFound,`Unknown method: ${n}`)}},W=(n,r)=>{let i=r??{};switch(n){case e.write:typeof i.chunk==`string`&&b.write(i.chunk);return;case e.hostContextChanged:T(i);return;case e.toolInputPartial:case e.toolInput:{let r=i.arguments;f=r&&typeof r==`object`?r:{},t.dispatchEvent(new CustomEvent(`toolinput`,{detail:{arguments:f,partial:n===e.toolInputPartial}}));return}case e.toolResult:p=i.structuredContent===void 0?i:i.structuredContent,t.dispatchEvent(new CustomEvent(`toolresult`,{detail:i}));return;default:return}},G=(t,n)=>{u=c(t,{onRequest:U,onNotification:W}),g=n.state??null,T(n.context??{}),u.notify(e.ready,{version:l}),w();for(let t of v.errors)u.notify(e.error,t)},K=0,q=()=>{K++,K>100&&t.clearInterval(Y),t.parent.postMessage({type:`genframe:ready`},o.hostOrigin)},J=e=>{if(e.source!==t.parent||e.origin!==o.hostOrigin)return;let n=e.data;n?.type===`genframe:init`&&e.ports[0]&&(t.removeEventListener(`message`,J),t.clearInterval(Y),G(e.ports[0],n))};t.addEventListener(`message`,J);let Y=t.setInterval(q,100);q()}H()})();")}<\/script>`,
65
+ "</body>",
66
+ "</html>"
67
+ ].join("\n");
68
+ }
69
+ /** Host context sent with init and on every theme change. */
70
+ function themeContext(tokens) {
71
+ return {
72
+ theme: tokens.colorScheme,
73
+ styles: { variables: themeVariables(tokens) }
74
+ };
75
+ }
76
+ export { buildBootstrapHtml, themeContext };
77
+
78
+ //# sourceMappingURL=bootstrap.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bootstrap.js","names":[],"sources":["../src/bootstrap.ts"],"sourcesContent":["import { buildCsp, type CspOptions } from \"./csp\";\nimport type { HostContext } from \"./protocol\";\nimport { runtimeSource } from \"./runtime/generated\";\nimport {\n DEFAULT_LIGHT_TOKENS,\n themeVariables,\n type ThemeTokens,\n} from \"./theme\";\n\nconst escapeAttribute = (value: string) =>\n value.replace(/&/g, \"&amp;\").replace(/\"/g, \"&quot;\").replace(/</g, \"&lt;\");\n\nconst escapeScript = (value: string) =>\n value.replace(/<\\/(script)/gi, \"<\\\\/$1\");\n\nconst escapeStyle = (value: string) => value.replace(/<\\/(style)/gi, \"<\\\\/$1\");\n\nconst SAFE_VARIABLE = /^--[\\w-]+$/;\nconst SAFE_VALUE = /^[^;{}<>]*$/;\n\nconst rootDeclarations = (variables: Record<string, string>) =>\n Object.entries(variables)\n .filter(\n ([name, value]) => SAFE_VARIABLE.test(name) && SAFE_VALUE.test(value),\n )\n .map(([name, value]) => `${name}:${value};`)\n .join(\"\");\n\n/**\n * Base styles: transparent page, host typography, and themed form controls,\n * so plain markup already matches the host before any widget CSS loads.\n */\nconst BASE_CSS = `\n*,*::before,*::after{box-sizing:border-box}\nhtml,body{margin:0;padding:0;background:transparent}\nhtml{overflow-y:hidden}\nbody{font-family:var(--font-sans);font-size:16px;line-height:1.5;color:var(--color-text);-webkit-font-smoothing:antialiased;overflow-wrap:anywhere}\n#gf-root{display:flow-root;width:100%}\n#gf-root[data-kind=svg]>svg{display:block;width:100%;height:auto}\nh1,h2,h3,h4{line-height:1.25;margin:0 0 .5em;font-weight:600}\nh1{font-size:22px}h2{font-size:18px}h3{font-size:16px}h4{font-size:14px}\np{margin:0 0 .75em}\na{color:var(--color-accent)}\ncode,kbd,pre,samp{font-family:var(--font-mono);font-size:.9em}\nsmall{color:var(--color-text-muted)}\ntable{border-collapse:collapse;width:100%;font-size:14px;font-variant-numeric:tabular-nums}\nth{font-weight:500;color:var(--color-text-muted);text-align:left}\nth,td{padding:6px 10px;border-bottom:1px solid var(--color-border)}\nbutton,input,select,textarea{font:inherit;color:inherit}\nbutton{cursor:pointer;padding:6px 14px;border-radius:var(--radius-md);border:1px solid var(--color-border-strong);background:var(--color-surface);transition:background-color .15s,border-color .15s}\nbutton:hover{background:var(--color-surface-muted)}\nbutton:active{transform:translateY(1px)}\nbutton:disabled{opacity:.5;cursor:not-allowed}\ninput:not([type=checkbox]):not([type=radio]):not([type=range]),select,textarea{padding:6px 10px;border-radius:var(--radius-sm);border:1px solid var(--color-border-strong);background:var(--color-surface)}\ninput[type=checkbox],input[type=radio],input[type=range],progress,meter{accent-color:var(--color-accent)}\n:focus-visible{outline:2px solid var(--color-accent);outline-offset:2px}\n.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}\n@media (prefers-reduced-motion:reduce){*,*::before,*::after{animation-duration:.01ms!important;animation-iteration-count:1!important;transition-duration:.01ms!important;scroll-behavior:auto!important}}\n`.trim();\n\nexport type BootstrapOptions = {\n /** The embedding page's origin; the frame only talks to this origin. */\n hostOrigin: string;\n csp?: CspOptions | string;\n tokens?: ThemeTokens;\n /** Fade in elements as they stream in. Always off under reduced motion. */\n animate?: boolean;\n /** Extra CSS appended after the base styles. */\n css?: string;\n /** Overrides the bundled runtime, mainly for tests. */\n runtime?: string;\n};\n\n/**\n * The document every widget frame loads once. It carries the CSP, the theme,\n * and the runtime; widget code arrives later over the private port.\n */\nexport function buildBootstrapHtml(options: BootstrapOptions): string {\n const tokens = options.tokens ?? DEFAULT_LIGHT_TOKENS;\n const csp =\n typeof options.csp === \"string\" ? options.csp : buildCsp(options.csp);\n const config = JSON.stringify({\n hostOrigin: options.hostOrigin,\n animate: options.animate ?? true,\n }).replace(/</g, \"\\\\u003c\");\n\n return [\n \"<!doctype html>\",\n `<html lang=\"en\" data-theme=\"${tokens.colorScheme}\" style=\"color-scheme:${tokens.colorScheme};background:transparent\">`,\n \"<head>\",\n '<meta charset=\"utf-8\">',\n `<meta http-equiv=\"Content-Security-Policy\" content=\"${escapeAttribute(csp)}\">`,\n '<meta name=\"viewport\" content=\"width=device-width,initial-scale=1\">',\n `<style id=\"gf-base\">:root{${rootDeclarations(themeVariables(tokens))}}\\n${BASE_CSS}${\n options.css ? `\\n${escapeStyle(options.css)}` : \"\"\n }</style>`,\n \"</head>\",\n '<body><div id=\"gf-root\"></div>',\n `<script id=\"gf-config\" type=\"application/json\">${config}</script>`,\n `<script>${escapeScript(options.runtime ?? runtimeSource)}</script>`,\n \"</body>\",\n \"</html>\",\n ].join(\"\\n\");\n}\n\n/** Host context sent with init and on every theme change. */\nexport function themeContext(tokens: ThemeTokens): HostContext {\n return {\n theme: tokens.colorScheme,\n styles: { variables: themeVariables(tokens) },\n };\n}\n"],"mappings":";;;;AASA,MAAM,mBAAmB,UACvB,MAAM,QAAQ,MAAM,OAAO,CAAC,CAAC,QAAQ,MAAM,QAAQ,CAAC,CAAC,QAAQ,MAAM,MAAM;AAE3E,MAAM,gBAAgB,UACpB,MAAM,QAAQ,iBAAiB,QAAQ;AAEzC,MAAM,eAAe,UAAkB,MAAM,QAAQ,gBAAgB,QAAQ;AAE7E,MAAM,gBAAgB;AACtB,MAAM,aAAa;AAEnB,MAAM,oBAAoB,cACxB,OAAO,QAAQ,SAAS,CAAC,CACtB,QACE,CAAC,MAAM,WAAW,cAAc,KAAK,IAAI,KAAK,WAAW,KAAK,KAAK,CACtE,CAAC,CACA,KAAK,CAAC,MAAM,WAAW,GAAG,KAAK,GAAG,MAAM,EAAE,CAAC,CAC3C,KAAK,EAAE;;;;;AAMZ,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;EA0Bf,KAAK;;;;;AAmBP,SAAgB,mBAAmB,SAAmC;CACpE,MAAM,SAAS,QAAQ,UAAU;CACjC,MAAM,MACJ,OAAO,QAAQ,QAAQ,WAAW,QAAQ,MAAM,SAAS,QAAQ,GAAG;CACtE,MAAM,SAAS,KAAK,UAAU;EAC5B,YAAY,QAAQ;EACpB,SAAS,QAAQ,WAAW;CAC9B,CAAC,CAAC,CAAC,QAAQ,MAAM,SAAS;CAE1B,OAAO;EACL;EACA,+BAA+B,OAAO,YAAY,wBAAwB,OAAO,YAAY;EAC7F;EACA;EACA,uDAAuD,gBAAgB,GAAG,EAAE;EAC5E;EACA,6BAA6B,iBAAiB,eAAe,MAAM,CAAC,EAAE,KAAK,WACzE,QAAQ,MAAM,KAAK,YAAY,QAAQ,GAAG,MAAM,GACjD;EACD;EACA;EACA,kDAAkD,OAAO;EACzD,WAAW,aAAa,QAAQ,WAAA,0zkBAAwB,EAAE;EAC1D;EACA;CACF,CAAC,CAAC,KAAK,IAAI;AACb;;AAGA,SAAgB,aAAa,QAAkC;CAC7D,OAAO;EACL,OAAO,OAAO;EACd,QAAQ,EAAE,WAAW,eAAe,MAAM,EAAE;CAC9C;AACF"}
package/dist/csp.d.ts ADDED
@@ -0,0 +1,25 @@
1
+ /** Script, style, image, and font hosts widgets may load from by default. */
2
+ export declare const DEFAULT_CDN_ORIGINS: readonly string[];
3
+ /** Google Fonts stylesheet origins for an explicit `fontStyleOrigins` opt-in. */
4
+ export declare const DEFAULT_FONT_STYLE_ORIGINS: readonly string[];
5
+ /** Google Fonts file origins for an explicit `fontOrigins` opt-in. */
6
+ export declare const DEFAULT_FONT_ORIGINS: readonly string[];
7
+ export type CspOptions = {
8
+ /** Origins for scripts, styles, images, fonts, and media. Defaults to `DEFAULT_CDN_ORIGINS`. */
9
+ cdnOrigins?: readonly string[];
10
+ /** Extra origins for font stylesheets, allowed only in `style-src`. Empty by default. */
11
+ fontStyleOrigins?: readonly string[];
12
+ /** Extra origins for font files, allowed only in `font-src`. Empty by default. */
13
+ fontOrigins?: readonly string[];
14
+ /** Origins `fetch`, XHR, and WebSocket may reach. Empty by default, blocking those requests. */
15
+ connectOrigins?: readonly string[];
16
+ /** Extra image origins, such as an image proxy. */
17
+ imageOrigins?: readonly string[];
18
+ /** Origins that may be embedded in nested frames. Empty by default. */
19
+ frameOrigins?: readonly string[];
20
+ /** Allows `eval` and `new Function`, which some charting libraries need. Off by default. */
21
+ allowEval?: boolean;
22
+ };
23
+ /** Builds the Content-Security-Policy every widget frame enforces. */
24
+ export declare function buildCsp(options?: CspOptions): string;
25
+ //# sourceMappingURL=csp.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"csp.d.ts","mappings":"AAAA;AACA,eAAO,MAAM,mBAAmB,EAAE,SAAS,MAAM,EAKhD;AAED;AACA,eAAO,MAAM,0BAA0B,EAAE,SAAS,MAAM,EAEvD;AAED;AACA,eAAO,MAAM,oBAAoB,EAAE,SAAS,MAAM,EAEjD;AAED,MAAM,MAAM,UAAU,GAAG;IACvB;IACA,UAAU,CAAC,EAAE,SAAS,MAAM,EAAE;IAC9B;IACA,gBAAgB,CAAC,EAAE,SAAS,MAAM,EAAE;IACpC;IACA,WAAW,CAAC,EAAE,SAAS,MAAM,EAAE;IAC/B;IACA,cAAc,CAAC,EAAE,SAAS,MAAM,EAAE;IAClC;IACA,YAAY,CAAC,EAAE,SAAS,MAAM,EAAE;IAChC;IACA,YAAY,CAAC,EAAE,SAAS,MAAM,EAAE;IAChC;IACA,SAAS,CAAC,EAAE,OAAO;CACpB;AAiCD;AACA,wBAAgB,QAAQ,CAAC,OAAO,GAAE,UAAe,GAAG,MAAM","names":[],"ignoreList":[],"sources":["../src/csp.ts"],"sourcesContent":[null]}
package/dist/csp.js ADDED
@@ -0,0 +1,78 @@
1
+ // src/csp.ts
2
+ /** Script, style, image, and font hosts widgets may load from by default. */
3
+ const DEFAULT_CDN_ORIGINS = [
4
+ "https://cdnjs.cloudflare.com",
5
+ "https://cdn.jsdelivr.net",
6
+ "https://unpkg.com",
7
+ "https://esm.sh"
8
+ ];
9
+ /** Google Fonts stylesheet origins for an explicit `fontStyleOrigins` opt-in. */
10
+ const DEFAULT_FONT_STYLE_ORIGINS = ["https://fonts.googleapis.com"];
11
+ /** Google Fonts file origins for an explicit `fontOrigins` opt-in. */
12
+ const DEFAULT_FONT_ORIGINS = ["https://fonts.gstatic.com"];
13
+ const KEYWORDS = /* @__PURE__ */ new Set([
14
+ "'self'",
15
+ "'none'",
16
+ "data:",
17
+ "blob:",
18
+ "https:"
19
+ ]);
20
+ const isSafeSource = (value, allowWebSocket) => {
21
+ if (KEYWORDS.has(value)) return true;
22
+ if (!(allowWebSocket ? /^(?:https?|wss?):\/\//i : /^https?:\/\//i).test(value) || /[\s;'"`,]/.test(value)) return false;
23
+ try {
24
+ const url = new URL(value.replace("://*.", "://wildcard."));
25
+ return url.username === "" && url.password === "" && url.search === "" && url.hash === "";
26
+ } catch {
27
+ return false;
28
+ }
29
+ };
30
+ const sources = (values, allowWebSocket = false) => [...new Set((values ?? []).filter((value) => typeof value === "string" && isSafeSource(value, allowWebSocket)))];
31
+ /** Builds the Content-Security-Policy every widget frame enforces. */
32
+ function buildCsp(options = {}) {
33
+ const cdn = sources(options.cdnOrigins ?? DEFAULT_CDN_ORIGINS);
34
+ const connect = sources(options.connectOrigins, true);
35
+ const frames = sources(options.frameOrigins);
36
+ const images = sources(options.imageOrigins);
37
+ const fontStyles = sources(options.fontStyleOrigins);
38
+ const fonts = sources(options.fontOrigins);
39
+ const directive = (name, values) => `${name} ${values.length > 0 ? values.join(" ") : "'none'"}`;
40
+ return [
41
+ "default-src 'none'",
42
+ directive("script-src", [
43
+ "'unsafe-inline'",
44
+ ...options.allowEval ? ["'unsafe-eval'"] : [],
45
+ ...cdn
46
+ ]),
47
+ directive("style-src", [
48
+ "'unsafe-inline'",
49
+ ...cdn,
50
+ ...fontStyles
51
+ ]),
52
+ directive("img-src", [
53
+ "data:",
54
+ "blob:",
55
+ ...cdn,
56
+ ...images
57
+ ]),
58
+ directive("font-src", [
59
+ "data:",
60
+ ...cdn,
61
+ ...fonts
62
+ ]),
63
+ directive("media-src", [
64
+ "data:",
65
+ "blob:",
66
+ ...cdn
67
+ ]),
68
+ directive("connect-src", connect),
69
+ directive("frame-src", frames),
70
+ "worker-src blob:",
71
+ "object-src 'none'",
72
+ "base-uri 'none'",
73
+ "form-action 'none'"
74
+ ].join("; ");
75
+ }
76
+ export { DEFAULT_CDN_ORIGINS, DEFAULT_FONT_ORIGINS, DEFAULT_FONT_STYLE_ORIGINS, buildCsp };
77
+
78
+ //# sourceMappingURL=csp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"csp.js","names":[],"sources":["../src/csp.ts"],"sourcesContent":["/** Script, style, image, and font hosts widgets may load from by default. */\nexport const DEFAULT_CDN_ORIGINS: readonly string[] = [\n \"https://cdnjs.cloudflare.com\",\n \"https://cdn.jsdelivr.net\",\n \"https://unpkg.com\",\n \"https://esm.sh\",\n];\n\n/** Google Fonts stylesheet origins for an explicit `fontStyleOrigins` opt-in. */\nexport const DEFAULT_FONT_STYLE_ORIGINS: readonly string[] = [\n \"https://fonts.googleapis.com\",\n];\n\n/** Google Fonts file origins for an explicit `fontOrigins` opt-in. */\nexport const DEFAULT_FONT_ORIGINS: readonly string[] = [\n \"https://fonts.gstatic.com\",\n];\n\nexport type CspOptions = {\n /** Origins for scripts, styles, images, fonts, and media. Defaults to `DEFAULT_CDN_ORIGINS`. */\n cdnOrigins?: readonly string[];\n /** Extra origins for font stylesheets, allowed only in `style-src`. Empty by default. */\n fontStyleOrigins?: readonly string[];\n /** Extra origins for font files, allowed only in `font-src`. Empty by default. */\n fontOrigins?: readonly string[];\n /** Origins `fetch`, XHR, and WebSocket may reach. Empty by default, blocking those requests. */\n connectOrigins?: readonly string[];\n /** Extra image origins, such as an image proxy. */\n imageOrigins?: readonly string[];\n /** Origins that may be embedded in nested frames. Empty by default. */\n frameOrigins?: readonly string[];\n /** Allows `eval` and `new Function`, which some charting libraries need. Off by default. */\n allowEval?: boolean;\n};\n\nconst KEYWORDS = new Set([\"'self'\", \"'none'\", \"data:\", \"blob:\", \"https:\"]);\n\nconst isSafeSource = (value: string, allowWebSocket: boolean): boolean => {\n if (KEYWORDS.has(value)) return true;\n const scheme = allowWebSocket ? /^(?:https?|wss?):\\/\\//i : /^https?:\\/\\//i;\n if (!scheme.test(value) || /[\\s;'\"`,]/.test(value)) return false;\n try {\n const url = new URL(value.replace(\"://*.\", \"://wildcard.\"));\n return (\n url.username === \"\" &&\n url.password === \"\" &&\n url.search === \"\" &&\n url.hash === \"\"\n );\n } catch {\n return false;\n }\n};\n\nconst sources = (\n values: readonly string[] | undefined,\n allowWebSocket = false,\n) => [\n ...new Set(\n (values ?? []).filter(\n (value) =>\n typeof value === \"string\" && isSafeSource(value, allowWebSocket),\n ),\n ),\n];\n\n/** Builds the Content-Security-Policy every widget frame enforces. */\nexport function buildCsp(options: CspOptions = {}): string {\n const cdn = sources(options.cdnOrigins ?? DEFAULT_CDN_ORIGINS);\n const connect = sources(options.connectOrigins, true);\n const frames = sources(options.frameOrigins);\n const images = sources(options.imageOrigins);\n const fontStyles = sources(options.fontStyleOrigins);\n const fonts = sources(options.fontOrigins);\n const directive = (name: string, values: readonly string[]) =>\n `${name} ${values.length > 0 ? values.join(\" \") : \"'none'\"}`;\n\n return [\n \"default-src 'none'\",\n directive(\"script-src\", [\n \"'unsafe-inline'\",\n ...(options.allowEval ? [\"'unsafe-eval'\"] : []),\n ...cdn,\n ]),\n directive(\"style-src\", [\"'unsafe-inline'\", ...cdn, ...fontStyles]),\n directive(\"img-src\", [\"data:\", \"blob:\", ...cdn, ...images]),\n directive(\"font-src\", [\"data:\", ...cdn, ...fonts]),\n directive(\"media-src\", [\"data:\", \"blob:\", ...cdn]),\n directive(\"connect-src\", connect),\n directive(\"frame-src\", frames),\n \"worker-src blob:\",\n \"object-src 'none'\",\n \"base-uri 'none'\",\n \"form-action 'none'\",\n ].join(\"; \");\n}\n"],"mappings":";;AACA,MAAa,sBAAyC;CACpD;CACA;CACA;CACA;AACF;;AAGA,MAAa,6BAAgD,CAC3D,8BACF;;AAGA,MAAa,uBAA0C,CACrD,2BACF;AAmBA,MAAM,2BAAW,IAAI,IAAI;CAAC;CAAU;CAAU;CAAS;CAAS;AAAQ,CAAC;AAEzE,MAAM,gBAAgB,OAAe,mBAAqC;CACxE,IAAI,SAAS,IAAI,KAAK,GAAG,OAAO;CAEhC,IAAI,EADW,iBAAiB,2BAA2B,gBAAA,CAC/C,KAAK,KAAK,KAAK,YAAY,KAAK,KAAK,GAAG,OAAO;CAC3D,IAAI;EACF,MAAM,MAAM,IAAI,IAAI,MAAM,QAAQ,SAAS,cAAc,CAAC;EAC1D,OACE,IAAI,aAAa,MACjB,IAAI,aAAa,MACjB,IAAI,WAAW,MACf,IAAI,SAAS;CAEjB,QAAQ;EACN,OAAO;CACT;AACF;AAEA,MAAM,WACJ,QACA,iBAAiB,UACd,CACH,GAAG,IAAI,KACJ,UAAU,CAAC,EAAA,CAAG,QACZ,UACC,OAAO,UAAU,YAAY,aAAa,OAAO,cAAc,CACnE,CACF,CACF;;AAGA,SAAgB,SAAS,UAAsB,CAAC,GAAW;CACzD,MAAM,MAAM,QAAQ,QAAQ,cAAc,mBAAmB;CAC7D,MAAM,UAAU,QAAQ,QAAQ,gBAAgB,IAAI;CACpD,MAAM,SAAS,QAAQ,QAAQ,YAAY;CAC3C,MAAM,SAAS,QAAQ,QAAQ,YAAY;CAC3C,MAAM,aAAa,QAAQ,QAAQ,gBAAgB;CACnD,MAAM,QAAQ,QAAQ,QAAQ,WAAW;CACzC,MAAM,aAAa,MAAc,WAC/B,GAAG,KAAK,GAAG,OAAO,SAAS,IAAI,OAAO,KAAK,GAAG,IAAI;CAEpD,OAAO;EACL;EACA,UAAU,cAAc;GACtB;GACA,GAAI,QAAQ,YAAY,CAAC,eAAe,IAAI,CAAC;GAC7C,GAAG;EACL,CAAC;EACD,UAAU,aAAa;GAAC;GAAmB,GAAG;GAAK,GAAG;EAAU,CAAC;EACjE,UAAU,WAAW;GAAC;GAAS;GAAS,GAAG;GAAK,GAAG;EAAM,CAAC;EAC1D,UAAU,YAAY;GAAC;GAAS,GAAG;GAAK,GAAG;EAAK,CAAC;EACjD,UAAU,aAAa;GAAC;GAAS;GAAS,GAAG;EAAG,CAAC;EACjD,UAAU,eAAe,OAAO;EAChC,UAAU,aAAa,MAAM;EAC7B;EACA;EACA;EACA;CACF,CAAC,CAAC,KAAK,IAAI;AACb"}
@@ -0,0 +1,6 @@
1
+ export { clearWidgetStorage, createWidget, widgetStorageSalt, type CreateWidgetOptions, type Screenshot, type ToolCallRequest, type UiMessageParams, type WidgetEventMap, type WidgetHandle, type WidgetHandlers, type WidgetInspection, } from "./widget.js";
2
+ export { previewWidget, type PreviewOptions, type PreviewResult, } from "./preview.js";
3
+ export { buildCsp, DEFAULT_CDN_ORIGINS, type CspOptions } from "./csp.js";
4
+ export { readThemeTokens, defaultThemeTokens, DEFAULT_LIGHT_TOKENS, DEFAULT_DARK_TOKENS, type ThemeTokens, type ThemeTokenName, type ThemeTokenSources, } from "./theme.js";
5
+ export type { ColorScheme, ClearStorageResult, ConsoleEntry, ConsoleLevel, DisplayMode, EndResult, FrameInspection, HostContext, McpAppInitializeParams, ScreenshotOptions, WidgetError, WidgetErrorKind, WidgetKind, WidgetSize, } from "./protocol.js";
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","mappings":"AAAA,OAAO,EACL,kBAAkB,EAClB,YAAY,EACZ,iBAAiB,EACjB,KAAK,mBAAmB,EACxB,KAAK,UAAU,EACf,KAAK,eAAe,EACpB,KAAK,eAAe,EACpB,KAAK,cAAc,EACnB,KAAK,YAAY,EACjB,KAAK,cAAc,EACnB,KAAK,gBAAgB,GACtB,MAAM,aAAU;AACjB,OAAO,EACL,aAAa,EACb,KAAK,cAAc,EACnB,KAAK,aAAa,GACnB,MAAM,cAAW;AAClB,OAAO,EAAE,QAAQ,EAAE,mBAAmB,EAAE,KAAK,UAAU,EAAE,MAAM,UAAO;AACtE,OAAO,EACL,eAAe,EACf,kBAAkB,EAClB,oBAAoB,EACpB,mBAAmB,EACnB,KAAK,WAAW,EAChB,KAAK,cAAc,EACnB,KAAK,iBAAiB,GACvB,MAAM,YAAS;AAChB,YAAY,EACV,WAAW,EACX,kBAAkB,EAClB,YAAY,EACZ,YAAY,EACZ,WAAW,EACX,SAAS,EACT,eAAe,EACf,WAAW,EACX,sBAAsB,EACtB,iBAAiB,EACjB,WAAW,EACX,eAAe,EACf,UAAU,EACV,UAAU,GACX,MAAM,eAAY","names":[],"ignoreList":[],"sources":["../src/index.ts"],"sourcesContent":[null]}
package/dist/index.js ADDED
@@ -0,0 +1,5 @@
1
+ import { DEFAULT_DARK_TOKENS, DEFAULT_LIGHT_TOKENS, defaultThemeTokens, readThemeTokens } from "./theme.js";
2
+ import { DEFAULT_CDN_ORIGINS, buildCsp } from "./csp.js";
3
+ import { clearWidgetStorage, createWidget, widgetStorageSalt } from "./widget.js";
4
+ import { previewWidget } from "./preview.js";
5
+ export { DEFAULT_CDN_ORIGINS, DEFAULT_DARK_TOKENS, DEFAULT_LIGHT_TOKENS, buildCsp, clearWidgetStorage, createWidget, defaultThemeTokens, previewWidget, readThemeTokens, widgetStorageSalt };
@@ -0,0 +1,70 @@
1
+ /** The JSON Schema subset this package writes and validates. */
2
+ export type JsonSchema = {
3
+ type?: JsonSchemaType | readonly JsonSchemaType[];
4
+ description?: string;
5
+ properties?: Record<string, JsonSchema>;
6
+ required?: readonly string[];
7
+ items?: JsonSchema;
8
+ enum?: readonly unknown[];
9
+ const?: unknown;
10
+ anyOf?: readonly JsonSchema[];
11
+ oneOf?: readonly JsonSchema[];
12
+ minItems?: number;
13
+ maxItems?: number;
14
+ minLength?: number;
15
+ maxLength?: number;
16
+ minimum?: number;
17
+ maximum?: number;
18
+ additionalProperties?: boolean | JsonSchema;
19
+ default?: unknown;
20
+ };
21
+ export type JsonSchemaType = "string" | "number" | "integer" | "boolean" | "object" | "array" | "null";
22
+ /** A validation failure at a JSON Pointer inside the validated value. */
23
+ export type SchemaIssue = {
24
+ path: string;
25
+ message: string;
26
+ };
27
+ /** The parts of a Standard Schema this package uses. */
28
+ export type StandardSchemaLike = {
29
+ readonly "~standard": {
30
+ readonly version: 1;
31
+ readonly vendor: string;
32
+ readonly validate: (value: unknown) => StandardResult | Promise<StandardResult>;
33
+ readonly jsonSchema?: {
34
+ readonly input: (options: {
35
+ target: string;
36
+ }) => Record<string, unknown>;
37
+ };
38
+ };
39
+ };
40
+ type StandardResult = {
41
+ readonly issues?: ReadonlyArray<{
42
+ readonly message: string;
43
+ readonly path?: ReadonlyArray<PropertyKey | {
44
+ readonly key: PropertyKey;
45
+ }> | undefined;
46
+ }> | undefined;
47
+ };
48
+ export declare const isStandardSchema: (value: unknown) => value is StandardSchemaLike;
49
+ /** JSON Schema for a schema that is either JSON Schema or a Standard Schema exposing one. */
50
+ export declare const toJsonSchema: (schema: JsonSchema | StandardSchemaLike | undefined) => JsonSchema | undefined;
51
+ declare const deepEqual: (a: unknown, b: unknown) => boolean;
52
+ export { deepEqual };
53
+ export type ValidateOptions = {
54
+ /** Values for which this returns true are accepted without checking, e.g. expressions. */
55
+ skip?: (value: unknown) => boolean;
56
+ };
57
+ /**
58
+ * Validates a value against the JSON Schema subset above and returns every
59
+ * issue found. Keywords outside the subset are ignored.
60
+ */
61
+ export declare function validateJsonSchema(schema: JsonSchema, value: unknown, options?: ValidateOptions, path?: string): SchemaIssue[];
62
+ /**
63
+ * Validates against JSON Schema or a Standard Schema. A Standard Schema that
64
+ * validates asynchronously is not awaited and reports no issues, and neither
65
+ * does one whose value contains a skipped placeholder.
66
+ */
67
+ export declare function validateSchema(schema: JsonSchema | StandardSchemaLike, value: unknown, options?: ValidateOptions): SchemaIssue[];
68
+ /** A compact TypeScript-like rendering of a schema, for prompts. */
69
+ export declare const describeSchema: (schema: JsonSchema | undefined) => string;
70
+ //# sourceMappingURL=json-schema.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"json-schema.d.ts","mappings":"AAAA;AACA,MAAM,MAAM,UAAU,GAAG;IACvB,IAAI,CAAC,EAAE,cAAc,GAAG,SAAS,cAAc,EAAE;IACjD,WAAW,CAAC,EAAE,MAAM;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC;IACvC,QAAQ,CAAC,EAAE,SAAS,MAAM,EAAE;IAC5B,KAAK,CAAC,EAAE,UAAU;IAClB,IAAI,CAAC,EAAE,SAAS,OAAO,EAAE;IACzB,KAAK,CAAC,EAAE,OAAO;IACf,KAAK,CAAC,EAAE,SAAS,UAAU,EAAE;IAC7B,KAAK,CAAC,EAAE,SAAS,UAAU,EAAE;IAC7B,QAAQ,CAAC,EAAE,MAAM;IACjB,QAAQ,CAAC,EAAE,MAAM;IACjB,SAAS,CAAC,EAAE,MAAM;IAClB,SAAS,CAAC,EAAE,MAAM;IAClB,OAAO,CAAC,EAAE,MAAM;IAChB,OAAO,CAAC,EAAE,MAAM;IAChB,oBAAoB,CAAC,EAAE,OAAO,GAAG,UAAU;IAC3C,OAAO,CAAC,EAAE,OAAO;CAClB;AAED,MAAM,MAAM,cAAc,GACtB,QAAQ,GACR,QAAQ,GACR,SAAS,GACT,SAAS,GACT,QAAQ,GACR,OAAO,GACP,MAAM;AAEV;AACA,MAAM,MAAM,WAAW,GAAG;IAAE,IAAI,EAAE,MAAM;IAAE,OAAO,EAAE,MAAM;CAAE;AAE3D;AACA,MAAM,MAAM,kBAAkB,GAAG;IAC/B,QAAQ,CAAC,WAAW,EAAE;QACpB,QAAQ,CAAC,OAAO,EAAE,CAAC;QACnB,QAAQ,CAAC,MAAM,EAAE,MAAM;QACvB,QAAQ,CAAC,QAAQ,EAAE,CACjB,KAAK,EAAE,OAAO,KACX,cAAc,GAAG,OAAO,CAAC,cAAc,CAAC;QAC7C,QAAQ,CAAC,UAAU,CAAC,EAAE;YACpB,QAAQ,CAAC,KAAK,EAAE,CAAC,OAAO,EAAE;gBAAE,MAAM,EAAE,MAAM;aAAE,KAAK,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;SACzE;KACF;CACF;AAED,KAAK,cAAc,GAAG;IACpB,QAAQ,CAAC,MAAM,CAAC,EACZ,aAAa,CAAC;QACZ,QAAQ,CAAC,OAAO,EAAE,MAAM;QACxB,QAAQ,CAAC,IAAI,CAAC,EACV,aAAa,CAAC,WAAW,GAAG;YAAE,QAAQ,CAAC,GAAG,EAAE,WAAW;SAAE,CAAC,GAC1D,SAAS;KACd,CAAC,GACF,SAAS;CACd;AAED,eAAO,MAAM,gBAAgB,GAAI,OAAO,OAAO,KAAG,KAAK,IAAI,kBAIiB;AAE5E;AACA,eAAO,MAAM,YAAY,GACvB,QAAQ,UAAU,GAAG,kBAAkB,GAAG,SAAS,KAClD,UAAU,GAAG,SAUf;AAmBD,cAAM,SAAS,GAAI,GAAG,OAAO,EAAE,GAAG,OAAO,KAAG,OAe3C;AAED,OAAO,EAAE,SAAS,EAAE;AAEpB,MAAM,MAAM,eAAe,GAAG;IAC5B;IACA,IAAI,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,OAAO;CACnC;AAED;;;;AAIA,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,UAAU,EAClB,KAAK,EAAE,OAAO,EACd,OAAO,GAAE,eAAoB,EAC7B,IAAI,SAAK,GACR,WAAW,EAAE;AAyIhB;;;;;AAKA,wBAAgB,cAAc,CAC5B,MAAM,EAAE,UAAU,GAAG,kBAAkB,EACvC,KAAK,EAAE,OAAO,EACd,OAAO,GAAE,eAAoB,GAC5B,WAAW,EAAE;AA2EhB;AACA,eAAO,MAAM,cAAc,GAAI,QAAQ,UAAU,GAAG,SAAS,KAAG,MACvC","names":[],"ignoreList":[],"sources":["../src/json-schema.ts"],"sourcesContent":[null]}
@@ -0,0 +1,163 @@
1
+ // src/json-schema.ts
2
+ const isStandardSchema = (value) => typeof value === "object" && value !== null && "~standard" in value && typeof value["~standard"]?.validate === "function";
3
+ /** JSON Schema for a schema that is either JSON Schema or a Standard Schema exposing one. */
4
+ const toJsonSchema = (schema) => {
5
+ if (!schema) return void 0;
6
+ if (!isStandardSchema(schema)) return schema;
7
+ try {
8
+ return schema["~standard"].jsonSchema?.input({ target: "draft-2020-12" });
9
+ } catch {
10
+ return;
11
+ }
12
+ };
13
+ const escapeToken = (token) => String(token).replace(/~/g, "~0").replace(/\//g, "~1");
14
+ const typeOf = (value) => {
15
+ if (value === null) return "null";
16
+ if (Array.isArray(value)) return "array";
17
+ if (typeof value === "number") return Number.isInteger(value) ? "integer" : "number";
18
+ return typeof value;
19
+ };
20
+ const matchesType = (value, type) => {
21
+ const actual = typeOf(value);
22
+ if (type === "number") return actual === "number" || actual === "integer";
23
+ return actual === type;
24
+ };
25
+ const deepEqual = (a, b) => {
26
+ if (a === b) return true;
27
+ if (typeof a !== "object" || typeof b !== "object" || !a || !b) return false;
28
+ if (Array.isArray(a) !== Array.isArray(b)) return false;
29
+ const keysA = Object.keys(a);
30
+ const keysB = Object.keys(b);
31
+ return keysA.length === keysB.length && keysA.every((key) => deepEqual(a[key], b[key]));
32
+ };
33
+ /**
34
+ * Validates a value against the JSON Schema subset above and returns every
35
+ * issue found. Keywords outside the subset are ignored.
36
+ */
37
+ function validateJsonSchema(schema, value, options = {}, path = "") {
38
+ if (options.skip?.(value)) return [];
39
+ const issues = [];
40
+ const at = path || "/";
41
+ if (schema.anyOf || schema.oneOf) {
42
+ if (!(schema.anyOf ?? schema.oneOf).some((branch) => validateJsonSchema(branch, value, options, path).length === 0)) {
43
+ issues.push({
44
+ path: at,
45
+ message: "does not match any allowed shape"
46
+ });
47
+ return issues;
48
+ }
49
+ }
50
+ if (schema.type !== void 0) {
51
+ const types = typeof schema.type === "string" ? [schema.type] : schema.type;
52
+ if (!types.some((type) => matchesType(value, type))) {
53
+ issues.push({
54
+ path: at,
55
+ message: `expected ${types.join(" or ")}, got ${typeOf(value)}`
56
+ });
57
+ return issues;
58
+ }
59
+ }
60
+ if (schema.const !== void 0 && !deepEqual(schema.const, value)) issues.push({
61
+ path: at,
62
+ message: `must be ${JSON.stringify(schema.const)}`
63
+ });
64
+ if (schema.enum && !schema.enum.some((option) => deepEqual(option, value))) issues.push({
65
+ path: at,
66
+ message: `must be one of ${schema.enum.map((o) => JSON.stringify(o)).join(", ")}`
67
+ });
68
+ if (typeof value === "string") {
69
+ if (schema.minLength !== void 0 && value.length < schema.minLength) issues.push({
70
+ path: at,
71
+ message: `must be at least ${schema.minLength} characters`
72
+ });
73
+ if (schema.maxLength !== void 0 && value.length > schema.maxLength) issues.push({
74
+ path: at,
75
+ message: `must be at most ${schema.maxLength} characters`
76
+ });
77
+ }
78
+ if (typeof value === "number") {
79
+ if (schema.minimum !== void 0 && value < schema.minimum) issues.push({
80
+ path: at,
81
+ message: `must be >= ${schema.minimum}`
82
+ });
83
+ if (schema.maximum !== void 0 && value > schema.maximum) issues.push({
84
+ path: at,
85
+ message: `must be <= ${schema.maximum}`
86
+ });
87
+ }
88
+ if (Array.isArray(value)) {
89
+ if (schema.minItems !== void 0 && value.length < schema.minItems) issues.push({
90
+ path: at,
91
+ message: `must have at least ${schema.minItems} items`
92
+ });
93
+ if (schema.maxItems !== void 0 && value.length > schema.maxItems) issues.push({
94
+ path: at,
95
+ message: `must have at most ${schema.maxItems} items`
96
+ });
97
+ if (schema.items) value.forEach((item, index) => issues.push(...validateJsonSchema(schema.items, item, options, `${path}/${index}`)));
98
+ }
99
+ if (typeOf(value) === "object") {
100
+ const record = value;
101
+ for (const key of schema.required ?? []) if (record[key] === void 0) issues.push({
102
+ path: `${path}/${escapeToken(key)}`,
103
+ message: "is required"
104
+ });
105
+ for (const [key, child] of Object.entries(record)) {
106
+ const childPath = `${path}/${escapeToken(key)}`;
107
+ const childSchema = schema.properties?.[key];
108
+ if (childSchema) {
109
+ if (child !== void 0) issues.push(...validateJsonSchema(childSchema, child, options, childPath));
110
+ } else if (schema.additionalProperties === false) issues.push({
111
+ path: childPath,
112
+ message: "is not an allowed property"
113
+ });
114
+ else if (typeof schema.additionalProperties === "object") issues.push(...validateJsonSchema(schema.additionalProperties, child, options, childPath));
115
+ }
116
+ }
117
+ return issues;
118
+ }
119
+ const containsSkipped = (value, skip) => skip(value) || typeof value === "object" && value !== null && Object.values(value).some((child) => containsSkipped(child, skip));
120
+ /**
121
+ * Validates against JSON Schema or a Standard Schema. A Standard Schema that
122
+ * validates asynchronously is not awaited and reports no issues, and neither
123
+ * does one whose value contains a skipped placeholder.
124
+ */
125
+ function validateSchema(schema, value, options = {}) {
126
+ if (!isStandardSchema(schema)) return validateJsonSchema(schema, value, options);
127
+ if (options.skip && containsSkipped(value, options.skip)) return [];
128
+ const result = schema["~standard"].validate(value);
129
+ if (result instanceof Promise) return [];
130
+ return (result.issues ?? []).map((issue) => ({
131
+ path: (issue.path ?? []).map((segment) => `/${escapeToken(String(typeof segment === "object" && segment !== null ? segment.key : segment))}`).join("") || "/",
132
+ message: issue.message
133
+ }));
134
+ }
135
+ const describeType = (schema, depth) => {
136
+ if (!schema) return "unknown";
137
+ if (schema.const !== void 0) return JSON.stringify(schema.const);
138
+ if (schema.enum) return schema.enum.map((o) => JSON.stringify(o)).join(" | ");
139
+ const branches = schema.anyOf ?? schema.oneOf;
140
+ if (branches) return branches.map((b) => describeType(b, depth)).join(" | ");
141
+ const types = schema.type === void 0 ? [] : typeof schema.type === "string" ? [schema.type] : [...schema.type];
142
+ if (types.length > 1) return types.map((type) => describeType({
143
+ ...schema,
144
+ type
145
+ }, depth)).join(" | ");
146
+ switch (types[0]) {
147
+ case "integer": return "integer";
148
+ case "array": return `${describeType(schema.items, depth)}[]`.replace(/^(.* \| .*)\[\]$/, "($1)[]");
149
+ case "object": return schema.properties && depth < 3 ? describeObject(schema, depth + 1) : "object";
150
+ case void 0: return schema.properties ? describeObject(schema, depth + 1) : "unknown";
151
+ default: return types[0];
152
+ }
153
+ };
154
+ const describeObject = (schema, depth) => {
155
+ const required = new Set(schema.required ?? []);
156
+ const fields = Object.entries(schema.properties ?? {}).map(([key, child]) => `${key}${required.has(key) ? "" : "?"}: ${describeType(child, depth)}`);
157
+ return fields.length ? `{ ${fields.join("; ")} }` : "{}";
158
+ };
159
+ /** A compact TypeScript-like rendering of a schema, for prompts. */
160
+ const describeSchema = (schema) => describeType(schema, 0);
161
+ export { deepEqual, describeSchema, isStandardSchema, toJsonSchema, validateJsonSchema, validateSchema };
162
+
163
+ //# sourceMappingURL=json-schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"json-schema.js","names":[],"sources":["../src/json-schema.ts"],"sourcesContent":["/** The JSON Schema subset this package writes and validates. */\nexport type JsonSchema = {\n type?: JsonSchemaType | readonly JsonSchemaType[];\n description?: string;\n properties?: Record<string, JsonSchema>;\n required?: readonly string[];\n items?: JsonSchema;\n enum?: readonly unknown[];\n const?: unknown;\n anyOf?: readonly JsonSchema[];\n oneOf?: readonly JsonSchema[];\n minItems?: number;\n maxItems?: number;\n minLength?: number;\n maxLength?: number;\n minimum?: number;\n maximum?: number;\n additionalProperties?: boolean | JsonSchema;\n default?: unknown;\n};\n\nexport type JsonSchemaType =\n | \"string\"\n | \"number\"\n | \"integer\"\n | \"boolean\"\n | \"object\"\n | \"array\"\n | \"null\";\n\n/** A validation failure at a JSON Pointer inside the validated value. */\nexport type SchemaIssue = { path: string; message: string };\n\n/** The parts of a Standard Schema this package uses. */\nexport type StandardSchemaLike = {\n readonly \"~standard\": {\n readonly version: 1;\n readonly vendor: string;\n readonly validate: (\n value: unknown,\n ) => StandardResult | Promise<StandardResult>;\n readonly jsonSchema?: {\n readonly input: (options: { target: string }) => Record<string, unknown>;\n };\n };\n};\n\ntype StandardResult = {\n readonly issues?:\n | ReadonlyArray<{\n readonly message: string;\n readonly path?:\n | ReadonlyArray<PropertyKey | { readonly key: PropertyKey }>\n | undefined;\n }>\n | undefined;\n};\n\nexport const isStandardSchema = (value: unknown): value is StandardSchemaLike =>\n typeof value === \"object\" &&\n value !== null &&\n \"~standard\" in value &&\n typeof (value as StandardSchemaLike)[\"~standard\"]?.validate === \"function\";\n\n/** JSON Schema for a schema that is either JSON Schema or a Standard Schema exposing one. */\nexport const toJsonSchema = (\n schema: JsonSchema | StandardSchemaLike | undefined,\n): JsonSchema | undefined => {\n if (!schema) return undefined;\n if (!isStandardSchema(schema)) return schema;\n try {\n return schema[\"~standard\"].jsonSchema?.input({\n target: \"draft-2020-12\",\n }) as JsonSchema | undefined;\n } catch {\n return undefined;\n }\n};\n\nconst escapeToken = (token: string | number) =>\n String(token).replace(/~/g, \"~0\").replace(/\\//g, \"~1\");\n\nconst typeOf = (value: unknown): JsonSchemaType => {\n if (value === null) return \"null\";\n if (Array.isArray(value)) return \"array\";\n if (typeof value === \"number\")\n return Number.isInteger(value) ? \"integer\" : \"number\";\n return typeof value as JsonSchemaType;\n};\n\nconst matchesType = (value: unknown, type: JsonSchemaType) => {\n const actual = typeOf(value);\n if (type === \"number\") return actual === \"number\" || actual === \"integer\";\n return actual === type;\n};\n\nconst deepEqual = (a: unknown, b: unknown): boolean => {\n if (a === b) return true;\n if (typeof a !== \"object\" || typeof b !== \"object\" || !a || !b) return false;\n if (Array.isArray(a) !== Array.isArray(b)) return false;\n const keysA = Object.keys(a);\n const keysB = Object.keys(b);\n return (\n keysA.length === keysB.length &&\n keysA.every((key) =>\n deepEqual(\n (a as Record<string, unknown>)[key],\n (b as Record<string, unknown>)[key],\n ),\n )\n );\n};\n\nexport { deepEqual };\n\nexport type ValidateOptions = {\n /** Values for which this returns true are accepted without checking, e.g. expressions. */\n skip?: (value: unknown) => boolean;\n};\n\n/**\n * Validates a value against the JSON Schema subset above and returns every\n * issue found. Keywords outside the subset are ignored.\n */\nexport function validateJsonSchema(\n schema: JsonSchema,\n value: unknown,\n options: ValidateOptions = {},\n path = \"\",\n): SchemaIssue[] {\n if (options.skip?.(value)) return [];\n const issues: SchemaIssue[] = [];\n const at = path || \"/\";\n\n if (schema.anyOf || schema.oneOf) {\n const branches = (schema.anyOf ?? schema.oneOf)!;\n const passes = branches.some(\n (branch) => validateJsonSchema(branch, value, options, path).length === 0,\n );\n if (!passes) {\n issues.push({ path: at, message: \"does not match any allowed shape\" });\n return issues;\n }\n }\n\n if (schema.type !== undefined) {\n const types = typeof schema.type === \"string\" ? [schema.type] : schema.type;\n if (!types.some((type) => matchesType(value, type))) {\n issues.push({\n path: at,\n message: `expected ${types.join(\" or \")}, got ${typeOf(value)}`,\n });\n return issues;\n }\n }\n\n if (schema.const !== undefined && !deepEqual(schema.const, value)) {\n issues.push({\n path: at,\n message: `must be ${JSON.stringify(schema.const)}`,\n });\n }\n if (schema.enum && !schema.enum.some((option) => deepEqual(option, value))) {\n issues.push({\n path: at,\n message: `must be one of ${schema.enum.map((o) => JSON.stringify(o)).join(\", \")}`,\n });\n }\n\n if (typeof value === \"string\") {\n if (schema.minLength !== undefined && value.length < schema.minLength) {\n issues.push({\n path: at,\n message: `must be at least ${schema.minLength} characters`,\n });\n }\n if (schema.maxLength !== undefined && value.length > schema.maxLength) {\n issues.push({\n path: at,\n message: `must be at most ${schema.maxLength} characters`,\n });\n }\n }\n\n if (typeof value === \"number\") {\n if (schema.minimum !== undefined && value < schema.minimum) {\n issues.push({ path: at, message: `must be >= ${schema.minimum}` });\n }\n if (schema.maximum !== undefined && value > schema.maximum) {\n issues.push({ path: at, message: `must be <= ${schema.maximum}` });\n }\n }\n\n if (Array.isArray(value)) {\n if (schema.minItems !== undefined && value.length < schema.minItems) {\n issues.push({\n path: at,\n message: `must have at least ${schema.minItems} items`,\n });\n }\n if (schema.maxItems !== undefined && value.length > schema.maxItems) {\n issues.push({\n path: at,\n message: `must have at most ${schema.maxItems} items`,\n });\n }\n if (schema.items) {\n value.forEach((item, index) =>\n issues.push(\n ...validateJsonSchema(\n schema.items!,\n item,\n options,\n `${path}/${index}`,\n ),\n ),\n );\n }\n }\n\n if (typeOf(value) === \"object\") {\n const record = value as Record<string, unknown>;\n for (const key of schema.required ?? []) {\n if (record[key] === undefined) {\n issues.push({\n path: `${path}/${escapeToken(key)}`,\n message: \"is required\",\n });\n }\n }\n for (const [key, child] of Object.entries(record)) {\n const childPath = `${path}/${escapeToken(key)}`;\n const childSchema = schema.properties?.[key];\n if (childSchema) {\n if (child !== undefined) {\n issues.push(\n ...validateJsonSchema(childSchema, child, options, childPath),\n );\n }\n } else if (schema.additionalProperties === false) {\n issues.push({ path: childPath, message: \"is not an allowed property\" });\n } else if (typeof schema.additionalProperties === \"object\") {\n issues.push(\n ...validateJsonSchema(\n schema.additionalProperties,\n child,\n options,\n childPath,\n ),\n );\n }\n }\n }\n\n return issues;\n}\n\nconst containsSkipped = (\n value: unknown,\n skip: (value: unknown) => boolean,\n): boolean =>\n skip(value) ||\n (typeof value === \"object\" &&\n value !== null &&\n Object.values(value).some((child) => containsSkipped(child, skip)));\n\n/**\n * Validates against JSON Schema or a Standard Schema. A Standard Schema that\n * validates asynchronously is not awaited and reports no issues, and neither\n * does one whose value contains a skipped placeholder.\n */\nexport function validateSchema(\n schema: JsonSchema | StandardSchemaLike,\n value: unknown,\n options: ValidateOptions = {},\n): SchemaIssue[] {\n if (!isStandardSchema(schema)) {\n return validateJsonSchema(schema, value, options);\n }\n // A Standard Schema cannot be told to accept placeholders, so values that\n // contain one are left to the component.\n if (options.skip && containsSkipped(value, options.skip)) return [];\n const result = schema[\"~standard\"].validate(value);\n if (result instanceof Promise) return [];\n return (result.issues ?? []).map((issue) => ({\n path:\n (issue.path ?? [])\n .map(\n (segment) =>\n `/${escapeToken(\n String(\n typeof segment === \"object\" && segment !== null\n ? segment.key\n : segment,\n ),\n )}`,\n )\n .join(\"\") || \"/\",\n message: issue.message,\n }));\n}\n\nconst describeType = (\n schema: JsonSchema | undefined,\n depth: number,\n): string => {\n if (!schema) return \"unknown\";\n if (schema.const !== undefined) return JSON.stringify(schema.const);\n if (schema.enum) return schema.enum.map((o) => JSON.stringify(o)).join(\" | \");\n const branches = schema.anyOf ?? schema.oneOf;\n if (branches) return branches.map((b) => describeType(b, depth)).join(\" | \");\n const types =\n schema.type === undefined\n ? []\n : typeof schema.type === \"string\"\n ? [schema.type]\n : [...schema.type];\n if (types.length > 1) {\n return types\n .map((type) => describeType({ ...schema, type }, depth))\n .join(\" | \");\n }\n switch (types[0]) {\n case \"integer\":\n return \"integer\";\n case \"array\":\n return `${describeType(schema.items, depth)}[]`.replace(\n /^(.* \\| .*)\\[\\]$/,\n \"($1)[]\",\n );\n case \"object\":\n return schema.properties && depth < 3\n ? describeObject(schema, depth + 1)\n : \"object\";\n case undefined:\n return schema.properties ? describeObject(schema, depth + 1) : \"unknown\";\n default:\n return types[0];\n }\n};\n\nconst describeObject = (schema: JsonSchema, depth: number): string => {\n const required = new Set(schema.required ?? []);\n const fields = Object.entries(schema.properties ?? {}).map(\n ([key, child]) =>\n `${key}${required.has(key) ? \"\" : \"?\"}: ${describeType(child, depth)}`,\n );\n return fields.length ? `{ ${fields.join(\"; \")} }` : \"{}\";\n};\n\n/** A compact TypeScript-like rendering of a schema, for prompts. */\nexport const describeSchema = (schema: JsonSchema | undefined): string =>\n describeType(schema, 0);\n"],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ import type { ColorScheme, ConsoleEntry, WidgetError, WidgetKind } from "./protocol.js";
2
+ import { type CreateWidgetOptions } from "./widget.js";
3
+ export type PreviewOptions = Pick<CreateWidgetOptions, "product" | "frame" | "id" | "unsafeShimDomain" | "opaqueOrigin" | "csp" | "css" | "readyTimeoutMs"> & {
4
+ /** Layout width in CSS pixels. Defaults to 680. */
5
+ width?: number;
6
+ appearance?: ColorScheme;
7
+ tokens?: CreateWidgetOptions["tokens"];
8
+ /** Capture a PNG. Defaults to true. */
9
+ screenshot?: boolean;
10
+ /** Time to let scripts, fonts, and animations settle after `end`. Defaults to 600ms. */
11
+ settleMs?: number;
12
+ };
13
+ export type PreviewResult = {
14
+ ok: boolean;
15
+ kind: WidgetKind;
16
+ width: number;
17
+ height: number;
18
+ blank: boolean;
19
+ errors: WidgetError[];
20
+ console: ConsoleEntry[];
21
+ screenshot?: string;
22
+ /** Why the screenshot is missing, when capture was requested and failed. */
23
+ screenshotError?: string;
24
+ };
25
+ /**
26
+ * Renders complete widget code in an offscreen frame and reports what
27
+ * happened: errors, console output, size, blank detection, and a screenshot.
28
+ */
29
+ export declare function previewWidget(code: string, options?: PreviewOptions): Promise<PreviewResult>;
30
+ //# sourceMappingURL=preview.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"preview.d.ts","mappings":"AAAA,OAAO,KAAK,EACV,WAAW,EACX,YAAY,EACZ,WAAW,EACX,UAAU,EACX,MAAM,eAAY;AAEnB,OAAO,EAEL,KAAK,mBAAmB,EAEzB,MAAM,aAAU;AAEjB,MAAM,MAAM,cAAc,GAAG,IAAI,CAC/B,mBAAmB,EACjB,SAAS,GACT,OAAO,GACP,IAAI,GACJ,kBAAkB,GAClB,cAAc,GACd,KAAK,GACL,KAAK,GACL,gBAAgB,CACnB,GAAG;IACF;IACA,KAAK,CAAC,EAAE,MAAM;IACd,UAAU,CAAC,EAAE,WAAW;IACxB,MAAM,CAAC,EAAE,mBAAmB,CAAC,QAAQ,CAAC;IACtC;IACA,UAAU,CAAC,EAAE,OAAO;IACpB;IACA,QAAQ,CAAC,EAAE,MAAM;CAClB;AAED,MAAM,MAAM,aAAa,GAAG;IAC1B,EAAE,EAAE,OAAO;IACX,IAAI,EAAE,UAAU;IAChB,KAAK,EAAE,MAAM;IACb,MAAM,EAAE,MAAM;IACd,KAAK,EAAE,OAAO;IACd,MAAM,EAAE,WAAW,EAAE;IACrB,OAAO,EAAE,YAAY,EAAE;IACvB,UAAU,CAAC,EAAE,MAAM;IACnB;IACA,eAAe,CAAC,EAAE,MAAM;CACzB;AAED;;;;AAIA,wBAAsB,aAAa,CACjC,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE,cAAmB,GAC3B,OAAO,CAAC,aAAa,CAAC","names":[],"ignoreList":[],"sources":["../src/preview.ts"],"sourcesContent":[null]}