@jxsuite/studio 6.1.1 → 6.1.2

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 (637) hide show
  1. package/dist/chunks/{2020-va2wwra4.js → 2020-f2gkpy8d.js} +3 -3
  2. package/dist/chunks/{action-group-2mqby73c.js → action-group-4aan7g6g.js} +3 -3
  3. package/dist/chunks/adapter-4912g339.js +4 -0
  4. package/dist/chunks/cf-account-picker-wccaenh6.js +4 -0
  5. package/dist/chunks/cf-settings-br6105tr.js +4 -0
  6. package/dist/chunks/color-28ksk2qm.js +4 -0
  7. package/dist/chunks/color-area-0fj8a4ga.js +4 -0
  8. package/dist/chunks/color-field-xch8kx2g.js +4 -0
  9. package/dist/chunks/color-slider-jxd8v350.js +4 -0
  10. package/dist/chunks/combobox-p0efwjke.js +4 -0
  11. package/dist/chunks/components-db68vsn7.js +4 -0
  12. package/dist/chunks/content-source-1449qesq.js +4 -0
  13. package/dist/chunks/convert-to-repeater-5h457egj.js +4 -0
  14. package/dist/chunks/dialog-c4x05vyx.js +4 -0
  15. package/dist/chunks/editor-x9jn86a7.js +4 -0
  16. package/dist/chunks/entry-commands-may24cpt.js +4 -0
  17. package/dist/chunks/extension-sections-pvr14vxr.js +4 -0
  18. package/dist/chunks/file-ops-x9v54pcj.js +4 -0
  19. package/dist/chunks/files-j3knqf0s.js +4 -0
  20. package/dist/chunks/format-host-tyre2trb.js +4 -0
  21. package/dist/chunks/fs-events-64ma9htc.js +4 -0
  22. package/dist/chunks/git-panel-84ps5dex.js +4 -0
  23. package/dist/chunks/grid-view-d2wq9ezg.js +51 -0
  24. package/dist/chunks/icons-pnfz478q.js +4 -0
  25. package/dist/chunks/iframe-entry-fvbk89gm.js +5 -0
  26. package/dist/chunks/iframe-entry-jdcktez8.js +5 -0
  27. package/dist/chunks/iframe-entry-x0ygf2yr.js +5 -0
  28. package/dist/chunks/iframe-entry-zap785cw.js +5 -0
  29. package/dist/chunks/iframe-host-ck6vejt5.js +4 -0
  30. package/dist/chunks/index-b8xw3vy9.js +4 -0
  31. package/dist/chunks/{index-2veqmnhr.js → index-zpjmzqfk.js} +3 -3
  32. package/dist/chunks/{javascript-8nbvs12s.js → javascript-m54mnwp6.js} +3 -3
  33. package/dist/chunks/{jsonMode-s8kt9dsj.js → jsonMode-w15cmrcm.js} +8 -8
  34. package/dist/chunks/jx-validate-at3zn8wa.js +4 -0
  35. package/dist/chunks/layers-h4xp1pss.js +4 -0
  36. package/dist/chunks/layers-panel-m5hw1d7g.js +4 -0
  37. package/dist/chunks/listbox-e74qjyq6.js +4 -0
  38. package/dist/chunks/lit-html-8t8t3dnr.js +4 -0
  39. package/dist/chunks/media-picker-2cweexc5.js +4 -0
  40. package/dist/chunks/menu-n6yzswmy.js +4 -0
  41. package/dist/chunks/menu-ynw13y0s.js +4 -0
  42. package/dist/chunks/monaco-binding-7gx83x3r.js +4 -0
  43. package/dist/chunks/monaco-buffer-qzxn567r.js +4 -0
  44. package/dist/chunks/monaco-setup-gxf6656g.js +4 -0
  45. package/dist/chunks/notify-cj5zbrs2.js +4 -0
  46. package/dist/chunks/number-field-y62xq0ty.js +4 -0
  47. package/dist/chunks/parse-b7ddhr8m.js +4 -0
  48. package/dist/chunks/platform-3dfws9js.js +4 -0
  49. package/dist/chunks/popover-jt2gxmzs.js +4 -0
  50. package/dist/chunks/publish-panel-1gvxbj21.js +4 -0
  51. package/dist/chunks/quick-search-0dajrwqg.js +4 -0
  52. package/dist/chunks/references-49qgt404.js +4 -0
  53. package/dist/chunks/right-panel-jm1bwe53.js +4 -0
  54. package/dist/chunks/section-registry-6kwc4fky.js +4 -0
  55. package/dist/chunks/select-rzds841e.js +4 -0
  56. package/dist/chunks/split-n2gfpm5m.js +4 -0
  57. package/dist/chunks/{studio-1q1sh2ax.js → studio-0q988f9w.js} +3 -3
  58. package/dist/chunks/studio-0rt52vpq.js +5 -0
  59. package/dist/chunks/studio-18vgbhs5.js +5 -0
  60. package/dist/chunks/{studio-h46vtzk8.js → studio-1fxkaaea.js} +4 -4
  61. package/dist/chunks/studio-24mccdrj.js +5 -0
  62. package/dist/chunks/studio-2eh507zk.js +9 -0
  63. package/dist/chunks/studio-2hcbccfv.js +5 -0
  64. package/dist/chunks/studio-2j1cb95x.js +5 -0
  65. package/dist/chunks/studio-2jbs3rxv.js +5 -0
  66. package/dist/chunks/{studio-rv11kfwa.js → studio-485046te.js} +7 -7
  67. package/dist/chunks/studio-4h8k4dw9.js +5 -0
  68. package/dist/chunks/studio-5f6n18kx.js +5 -0
  69. package/dist/chunks/studio-5gthpky6.js +5 -0
  70. package/dist/chunks/studio-5ve6bbep.js +5 -0
  71. package/dist/chunks/studio-6ep3js6b.js +9 -0
  72. package/dist/chunks/studio-6wkmf3wz.js +9 -0
  73. package/dist/chunks/studio-841rf3cg.js +5 -0
  74. package/dist/chunks/studio-8gmwgheg.js +5 -0
  75. package/dist/chunks/studio-8qm0ep50.js +5 -0
  76. package/dist/chunks/{studio-8grwxtqk.js → studio-90pq9km1.js} +4 -4
  77. package/dist/chunks/studio-924p1tm1.js +6 -0
  78. package/dist/chunks/{studio-pre0skq6.js → studio-a3g98wjr.js} +4 -4
  79. package/dist/chunks/studio-a3shpz9y.js +5 -0
  80. package/dist/chunks/studio-amsbaaar.js +6 -0
  81. package/dist/chunks/studio-at5spjbc.js +7 -0
  82. package/dist/chunks/studio-b2xv945e.js +5 -0
  83. package/dist/chunks/studio-bn5nkafw.js +5 -0
  84. package/dist/chunks/studio-bw6q5xjf.js +9 -0
  85. package/dist/chunks/studio-c7q0t9x1.js +5 -0
  86. package/dist/chunks/studio-camnhc96.js +6 -0
  87. package/dist/chunks/studio-cffqvnzd.js +5 -0
  88. package/dist/chunks/studio-d81xfh1g.js +5 -0
  89. package/dist/chunks/studio-dgz8d0c1.js +5 -0
  90. package/dist/chunks/studio-efvfrsf8.js +5 -0
  91. package/dist/chunks/studio-er30bpcx.js +5 -0
  92. package/dist/chunks/studio-ezscgr64.js +5 -0
  93. package/dist/chunks/studio-ffrrncvz.js +5 -0
  94. package/dist/chunks/studio-fpphgn8y.js +10 -0
  95. package/dist/chunks/studio-j1kvhdjk.js +4 -0
  96. package/dist/chunks/{studio-vrmcjf9g.js → studio-j430n16g.js} +5 -5
  97. package/dist/chunks/studio-jjkg84nj.js +5 -0
  98. package/dist/chunks/studio-m0q32ars.js +4 -0
  99. package/dist/chunks/studio-m6bdst11.js +5 -0
  100. package/dist/chunks/studio-nv2cptd4.js +64 -0
  101. package/dist/chunks/studio-nwfrc98n.js +5 -0
  102. package/dist/chunks/studio-p1wgvp7r.js +5 -0
  103. package/dist/chunks/studio-pag2wncm.js +5 -0
  104. package/dist/chunks/studio-qvanvzfd.js +5 -0
  105. package/dist/chunks/studio-qwa64kt7.js +5 -0
  106. package/dist/chunks/studio-rk1zc4x3.js +928 -0
  107. package/dist/chunks/studio-se2r3ptc.js +5 -0
  108. package/dist/chunks/studio-sg2a0dh0.js +5 -0
  109. package/dist/chunks/studio-tjzjhe68.js +5 -0
  110. package/dist/chunks/{studio-wszjyh0j.js → studio-tq0rtfwj.js} +4 -4
  111. package/dist/chunks/{studio-kggey1jt.js → studio-v0jzqdjm.js} +4 -4
  112. package/dist/chunks/studio-v2w7q8r1.js +7 -0
  113. package/dist/chunks/studio-v5vjq1h0.js +4 -0
  114. package/dist/chunks/studio-v8aga3vp.js +14 -0
  115. package/dist/chunks/studio-vfcdrfmv.js +5 -0
  116. package/dist/chunks/studio-vmfkgdjf.js +5 -0
  117. package/dist/chunks/studio-wt1816jj.js +5 -0
  118. package/dist/chunks/studio-wz73q5kq.js +4 -0
  119. package/dist/chunks/studio-y04qtxvp.js +7 -0
  120. package/dist/chunks/studio-y21g8zzg.js +5 -0
  121. package/dist/chunks/{studio-zey7zsdw.js → studio-y64hrt8p.js} +7 -7
  122. package/dist/chunks/studio-ynn90f58.js +16 -0
  123. package/dist/chunks/studio-yxz682sx.js +5 -0
  124. package/dist/chunks/studio-zp7snvkq.js +5 -0
  125. package/dist/chunks/studio-zq4z6tm6.js +5 -0
  126. package/dist/chunks/swatch-group-ewh24n1f.js +4 -0
  127. package/dist/chunks/tabs-f5cw3tgp.js +4 -0
  128. package/dist/chunks/textfield-wewc8rq2.js +4 -0
  129. package/dist/chunks/toast-c9fn075p.js +4 -0
  130. package/dist/chunks/toast-host-ke5z4ng7.js +4 -0
  131. package/dist/chunks/{toolbar-2nnzqhrj.js → toolbar-44cm5cta.js} +3 -3
  132. package/dist/chunks/tooltip-5v8ngwj2.js +4 -0
  133. package/dist/chunks/tree-mdq3v5cw.js +4 -0
  134. package/dist/chunks/{tsMode-2frah6h1.js → tsMode-sf49ee9x.js} +7 -7
  135. package/dist/chunks/workspace-jtfahpee.js +4 -0
  136. package/dist/chunks/ws-client-nze0k6mv.js +4 -0
  137. package/dist/iframe-entry.js +16 -16
  138. package/dist/manifest.json +63 -63
  139. package/dist/studio.js +97 -97
  140. package/package.json +6 -6
  141. package/src/about/about-modal.ts +4 -3
  142. package/src/account/action-flow.ts +45 -38
  143. package/src/account-status.ts +7 -2
  144. package/src/browse/library-layouts.ts +8 -5
  145. package/src/browse/library-model.ts +18 -6
  146. package/src/browse/library-pane.ts +37 -21
  147. package/src/browse/library-preview.ts +14 -9
  148. package/src/browse/library-source.ts +1 -1
  149. package/src/canvas/asset-refs.ts +24 -9
  150. package/src/canvas/asset-resolve.ts +19 -23
  151. package/src/canvas/canvas-helpers.ts +7 -6
  152. package/src/canvas/canvas-live-render.ts +44 -53
  153. package/src/canvas/canvas-patcher.ts +30 -30
  154. package/src/canvas/canvas-perf.ts +11 -5
  155. package/src/canvas/canvas-render.ts +62 -41
  156. package/src/canvas/canvas-surface.ts +5 -3
  157. package/src/canvas/canvas-utils.ts +90 -49
  158. package/src/canvas/dialog-path.ts +9 -4
  159. package/src/canvas/dialog-state.ts +1 -2
  160. package/src/canvas/diff-marks.ts +9 -16
  161. package/src/canvas/diff-toolbar.ts +8 -7
  162. package/src/canvas/edit-width-drag.ts +4 -1
  163. package/src/canvas/edit-width.ts +1 -3
  164. package/src/canvas/iframe-channel.ts +27 -13
  165. package/src/canvas/iframe-drop.ts +13 -12
  166. package/src/canvas/iframe-editable-root.ts +29 -16
  167. package/src/canvas/iframe-entry.ts +80 -63
  168. package/src/canvas/iframe-eval.ts +73 -49
  169. package/src/canvas/iframe-host.ts +135 -96
  170. package/src/canvas/iframe-inline-edit.ts +49 -30
  171. package/src/canvas/iframe-insert.ts +5 -4
  172. package/src/canvas/iframe-interaction.ts +30 -25
  173. package/src/canvas/iframe-overlay.ts +1 -1
  174. package/src/canvas/iframe-patch.ts +18 -15
  175. package/src/canvas/iframe-position.ts +12 -6
  176. package/src/canvas/iframe-protocol.ts +12 -16
  177. package/src/canvas/iframe-render.ts +36 -34
  178. package/src/canvas/iframe-slash.ts +24 -11
  179. package/src/canvas/iframe-subtree.ts +6 -2
  180. package/src/canvas/path-mapping.ts +19 -12
  181. package/src/canvas/popover-path.ts +7 -3
  182. package/src/canvas/popover-state.ts +1 -2
  183. package/src/canvas/serialize-scope.ts +13 -5
  184. package/src/canvas/stage-scrollbar.ts +2 -1
  185. package/src/canvas/surface-registry.ts +21 -3
  186. package/src/collab/collab-commands.ts +7 -2
  187. package/src/collab/collab-session.ts +84 -45
  188. package/src/collab/collab-state.ts +4 -3
  189. package/src/collab/monaco-binding.ts +16 -13
  190. package/src/collab/monaco-cursors.ts +5 -2
  191. package/src/commands/budget.ts +3 -3
  192. package/src/commands/command-args.ts +103 -71
  193. package/src/commands/context.ts +22 -20
  194. package/src/commands/keymap.ts +47 -43
  195. package/src/commands/levels.ts +3 -3
  196. package/src/commands/live-context.ts +7 -7
  197. package/src/commands/reference.ts +2 -1
  198. package/src/commands/registry.ts +12 -10
  199. package/src/commands/run-reported.ts +15 -10
  200. package/src/component-props.ts +46 -30
  201. package/src/content/collection-match.ts +5 -4
  202. package/src/content/draft-state.ts +4 -3
  203. package/src/content/entry-commands.ts +3 -2
  204. package/src/content/entry-editor.ts +29 -17
  205. package/src/content/entry-fields.ts +12 -7
  206. package/src/content/entry-model.ts +21 -12
  207. package/src/editor/canvas-context-menu.ts +1 -2
  208. package/src/editor/canvas-slash-bridge.ts +3 -6
  209. package/src/editor/content-slice.ts +16 -14
  210. package/src/editor/context-menu.ts +35 -22
  211. package/src/editor/convert-targets.ts +30 -35
  212. package/src/editor/convert-to-component.ts +11 -5
  213. package/src/editor/convert-to-repeater.ts +34 -22
  214. package/src/editor/editable-tags.ts +17 -2
  215. package/src/editor/file-drop-action.ts +21 -22
  216. package/src/editor/inline-edit-apply.ts +35 -17
  217. package/src/editor/inline-edit.ts +66 -50
  218. package/src/editor/inline-format.ts +59 -56
  219. package/src/editor/inline-link.ts +40 -15
  220. package/src/editor/insert-zone-action.ts +1 -1
  221. package/src/editor/merge-tags.ts +58 -19
  222. package/src/editor/repeater-scope.ts +39 -28
  223. package/src/editor/shortcuts.ts +32 -20
  224. package/src/editor/slash-menu.ts +1 -6
  225. package/src/files/asset-versions.ts +4 -4
  226. package/src/files/components.ts +15 -10
  227. package/src/files/elements.ts +5 -6
  228. package/src/files/file-ops.ts +77 -36
  229. package/src/files/files.ts +90 -95
  230. package/src/files/media-meta.ts +2 -1
  231. package/src/files/media-paths.ts +3 -0
  232. package/src/files/serialize-document.ts +2 -2
  233. package/src/format/constraints.ts +1 -1
  234. package/src/format/convert-file.ts +27 -13
  235. package/src/format/format-choices.ts +2 -1
  236. package/src/format/format-host.ts +76 -50
  237. package/src/github/github-auth-status.ts +27 -3
  238. package/src/github/github-auth.ts +19 -9
  239. package/src/github/github-publish.ts +24 -20
  240. package/src/grid/cell-editors.ts +46 -31
  241. package/src/grid/cell-popovers.ts +5 -3
  242. package/src/grid/edit-buffer.ts +10 -9
  243. package/src/grid/grid-controller.ts +20 -22
  244. package/src/grid/grid-layout.ts +21 -5
  245. package/src/grid/grid-open.ts +3 -6
  246. package/src/grid/grid-panel.ts +11 -4
  247. package/src/grid/grid-source.ts +8 -8
  248. package/src/grid/grid-view.ts +14 -17
  249. package/src/grid/redirects-grid.ts +14 -5
  250. package/src/grid/redirects.ts +16 -14
  251. package/src/grid/schema-columns.ts +25 -19
  252. package/src/grid/sources/connector-source.ts +47 -20
  253. package/src/grid/sources/content-source.ts +25 -24
  254. package/src/grid/sources/csv-file-source.ts +2 -2
  255. package/src/grid/tabulator-tables.d.ts +55 -34
  256. package/src/hosting/stage.ts +7 -7
  257. package/src/i18n/i18n-commands.ts +1 -2
  258. package/src/media/media-pane.ts +4 -1
  259. package/src/new-project/add-repo-modal.ts +20 -19
  260. package/src/new-project/import-tab.ts +10 -14
  261. package/src/new-project/location-fields.ts +2 -1
  262. package/src/new-project/new-project-modal.ts +12 -9
  263. package/src/packages/jxsuite-update.ts +4 -3
  264. package/src/packages/pull-package-sync.ts +26 -25
  265. package/src/page-params.ts +97 -68
  266. package/src/panels/activity-panel.ts +17 -9
  267. package/src/panels/ai-chat/attached-context.ts +13 -7
  268. package/src/panels/ai-chat/chat-view.ts +80 -73
  269. package/src/panels/ai-chat/composer.ts +30 -33
  270. package/src/panels/ai-chat/sessions-view.ts +1 -2
  271. package/src/panels/ai-panel.ts +23 -20
  272. package/src/panels/block-action-bar.ts +46 -35
  273. package/src/panels/bottom-dock.ts +5 -3
  274. package/src/panels/canvas-dnd-bridge.ts +31 -24
  275. package/src/panels/data-explorer.ts +62 -25
  276. package/src/panels/data-grid.ts +14 -11
  277. package/src/panels/dnd.ts +108 -118
  278. package/src/panels/editors.ts +52 -21
  279. package/src/panels/elements-panel.ts +10 -3
  280. package/src/panels/events-panel.ts +84 -69
  281. package/src/panels/formula-workspace.ts +76 -51
  282. package/src/panels/frontmatter-fields.ts +24 -19
  283. package/src/panels/frontmatter-panel.ts +44 -34
  284. package/src/panels/git-diff-open.ts +4 -4
  285. package/src/panels/git-panel.ts +49 -61
  286. package/src/panels/head-panel.ts +131 -111
  287. package/src/panels/i18n-panel.ts +10 -3
  288. package/src/panels/imports-panel.ts +23 -47
  289. package/src/panels/jump-bar.ts +48 -29
  290. package/src/panels/layers-panel.ts +97 -74
  291. package/src/panels/left-panel.ts +3 -3
  292. package/src/panels/pane-context.ts +31 -22
  293. package/src/panels/pane-grid.ts +49 -20
  294. package/src/panels/panel-registry.ts +22 -37
  295. package/src/panels/properties-panel.ts +175 -121
  296. package/src/panels/quick-search.ts +53 -31
  297. package/src/panels/right-panel.ts +3 -3
  298. package/src/panels/seo-modal.ts +13 -17
  299. package/src/panels/settings-menu.ts +15 -15
  300. package/src/panels/signals-panel.ts +153 -131
  301. package/src/panels/statement-editor.ts +230 -140
  302. package/src/panels/style-panel.ts +218 -205
  303. package/src/panels/style-utils.ts +114 -51
  304. package/src/panels/stylebook-doc.ts +57 -54
  305. package/src/panels/stylebook-layers-panel.ts +9 -9
  306. package/src/panels/stylebook-panel.ts +13 -17
  307. package/src/panels/tab-drop.ts +27 -11
  308. package/src/panels/tab-strip.ts +36 -26
  309. package/src/platform-errors.ts +57 -43
  310. package/src/platform.ts +58 -30
  311. package/src/platforms/cloud.ts +345 -175
  312. package/src/platforms/default-platform.ts +10 -4
  313. package/src/platforms/devserver.ts +129 -117
  314. package/src/platforms/read-batcher.ts +16 -8
  315. package/src/project-list.ts +2 -1
  316. package/src/publish/deploy-checklist.ts +8 -2
  317. package/src/publish/pages-service.ts +28 -13
  318. package/src/publish/publish-commands.ts +5 -4
  319. package/src/publish/publish-panel.ts +10 -6
  320. package/src/recent-projects.ts +15 -8
  321. package/src/resize-edges.ts +26 -36
  322. package/src/services/a11y-report.ts +26 -19
  323. package/src/services/agent-seed.ts +23 -11
  324. package/src/services/ai-ask.ts +9 -12
  325. package/src/services/ai-command-tools.ts +68 -62
  326. package/src/services/ai-import-tools.ts +80 -67
  327. package/src/services/ai-models.ts +17 -13
  328. package/src/services/ai-project-tools.ts +68 -32
  329. package/src/services/ai-session-store.ts +19 -10
  330. package/src/services/ai-system-prompt.ts +46 -20
  331. package/src/services/ai-tools.ts +71 -27
  332. package/src/services/ai-write-report.ts +20 -12
  333. package/src/services/ai-writes.ts +4 -4
  334. package/src/services/automation.ts +58 -31
  335. package/src/services/cem-export.ts +149 -58
  336. package/src/services/clock.ts +6 -1
  337. package/src/services/code-services.ts +37 -31
  338. package/src/services/context-manager.ts +14 -10
  339. package/src/services/context-resolver.ts +20 -8
  340. package/src/services/data-service.ts +19 -15
  341. package/src/services/directory-picker.ts +18 -12
  342. package/src/services/document-assistant.ts +39 -19
  343. package/src/services/gated-registry.ts +10 -6
  344. package/src/services/harness/chat-reducer.ts +23 -1
  345. package/src/services/import-client.ts +91 -38
  346. package/src/services/import-seed.ts +8 -2
  347. package/src/services/jx-validate.ts +28 -31
  348. package/src/services/live-preview.ts +0 -0
  349. package/src/services/live-surfaces.ts +6 -3
  350. package/src/services/model-uri.ts +10 -2
  351. package/src/services/module-preloads.ts +12 -8
  352. package/src/services/monaco-buffer.ts +43 -24
  353. package/src/services/monaco-lazy.ts +7 -8
  354. package/src/services/monaco-setup.ts +23 -16
  355. package/src/services/notify.ts +44 -17
  356. package/src/services/popover-report.ts +25 -10
  357. package/src/services/preview-eval.ts +20 -8
  358. package/src/services/profile.ts +13 -6
  359. package/src/services/project-path.ts +13 -10
  360. package/src/services/references.ts +0 -0
  361. package/src/services/render-critic.ts +8 -7
  362. package/src/services/settings/kernel.ts +13 -4
  363. package/src/services/settings/write-queue.ts +9 -9
  364. package/src/services/token-lint.ts +12 -10
  365. package/src/services/tool-executor.ts +17 -5
  366. package/src/services/tool-outcomes.ts +44 -24
  367. package/src/services/trusted-types.ts +24 -7
  368. package/src/settings/contexts-section.ts +11 -8
  369. package/src/settings/contributed-section.ts +79 -60
  370. package/src/settings/css-vars-editor.ts +37 -16
  371. package/src/settings/defs-editor.ts +38 -35
  372. package/src/settings/extension-rows.ts +16 -8
  373. package/src/settings/extension-sections.ts +23 -13
  374. package/src/settings/extensions-section.ts +4 -1
  375. package/src/settings/general-settings.ts +11 -8
  376. package/src/settings/locales-section.ts +20 -12
  377. package/src/settings/preferences-dialog.ts +9 -6
  378. package/src/settings/preferences-keymap.ts +7 -5
  379. package/src/settings/preferences-sections.ts +11 -5
  380. package/src/settings/project-sections.ts +1 -1
  381. package/src/settings/schema-field-ui.ts +9 -0
  382. package/src/settings/settings-document.ts +5 -5
  383. package/src/shell/tree.ts +6 -5
  384. package/src/shell.ts +104 -81
  385. package/src/site-context.ts +37 -22
  386. package/src/state.ts +41 -49
  387. package/src/store.ts +54 -34
  388. package/src/studio.ts +25 -75
  389. package/src/style/live-preview.ts +1 -1
  390. package/src/style/project-styles.ts +6 -7
  391. package/src/style/token-ref.ts +5 -4
  392. package/src/surfaces/about.ts +18 -19
  393. package/src/surfaces/add-repo.ts +17 -19
  394. package/src/surfaces/ai-chat.ts +31 -36
  395. package/src/surfaces/ai-credentials-form.ts +6 -16
  396. package/src/surfaces/ai-managed-connect.ts +3 -4
  397. package/src/surfaces/ai-model-picker.ts +3 -5
  398. package/src/surfaces/block-action-bar.ts +22 -11
  399. package/src/surfaces/boot-failure.ts +4 -5
  400. package/src/surfaces/bottom-dock.ts +9 -18
  401. package/src/surfaces/canvas-stage.ts +12 -11
  402. package/src/surfaces/cf-account-picker.ts +17 -18
  403. package/src/surfaces/commandbar.ts +14 -9
  404. package/src/surfaces/convert-repeater.ts +17 -19
  405. package/src/surfaces/data-actions.ts +9 -7
  406. package/src/surfaces/dialog.ts +26 -28
  407. package/src/surfaces/diff-toolbar.ts +9 -7
  408. package/src/surfaces/doc-header.ts +10 -19
  409. package/src/surfaces/empty-state.ts +7 -10
  410. package/src/surfaces/entry-editor.ts +14 -11
  411. package/src/surfaces/expression-editor.ts +11 -25
  412. package/src/surfaces/files-panel.ts +27 -14
  413. package/src/surfaces/formula-palette.ts +4 -5
  414. package/src/surfaces/git-panel.ts +7 -15
  415. package/src/surfaces/github-auth.ts +16 -20
  416. package/src/surfaces/github-publish.ts +17 -22
  417. package/src/surfaces/grid-cell.ts +30 -31
  418. package/src/surfaces/grid-open.ts +10 -14
  419. package/src/surfaces/grid-panel.ts +13 -9
  420. package/src/surfaces/grid-replace.ts +13 -13
  421. package/src/surfaces/grid-views.ts +15 -18
  422. package/src/surfaces/inspector-dock.ts +13 -12
  423. package/src/surfaces/jump-bar.ts +5 -6
  424. package/src/surfaces/jxsuite-update.ts +16 -22
  425. package/src/surfaces/library-pane.ts +19 -20
  426. package/src/surfaces/logic-panel.ts +17 -30
  427. package/src/surfaces/logic-workspace.ts +13 -15
  428. package/src/surfaces/media-browser.ts +11 -10
  429. package/src/surfaces/media-field.ts +4 -5
  430. package/src/surfaces/media-pane.ts +8 -7
  431. package/src/surfaces/menu.ts +29 -23
  432. package/src/surfaces/navigator-dock.ts +11 -12
  433. package/src/surfaces/new-project.ts +27 -26
  434. package/src/surfaces/pane-context.ts +20 -25
  435. package/src/surfaces/pane-grid.ts +15 -10
  436. package/src/surfaces/panel-activity.ts +5 -6
  437. package/src/surfaces/panel-data.ts +3 -4
  438. package/src/surfaces/panel-deploy-checklist.ts +5 -6
  439. package/src/surfaces/panel-elements.ts +5 -7
  440. package/src/surfaces/panel-i18n.ts +5 -7
  441. package/src/surfaces/panel-imports.ts +6 -13
  442. package/src/surfaces/panel-outline.ts +25 -19
  443. package/src/surfaces/panel-page.ts +11 -18
  444. package/src/surfaces/panel-problems.ts +5 -7
  445. package/src/surfaces/panel-signals.ts +20 -34
  446. package/src/surfaces/panel-stylebook-layers.ts +5 -8
  447. package/src/surfaces/preferences.ts +21 -11
  448. package/src/surfaces/progress-modal.ts +15 -9
  449. package/src/surfaces/properties-panel.json +1 -1
  450. package/src/surfaces/properties-panel.ts +20 -42
  451. package/src/surfaces/publish.ts +18 -18
  452. package/src/surfaces/push-plan.ts +7 -8
  453. package/src/surfaces/rail.ts +13 -13
  454. package/src/surfaces/reference-field.ts +11 -15
  455. package/src/surfaces/schema-builder.ts +16 -22
  456. package/src/surfaces/schema-form.ts +15 -25
  457. package/src/surfaces/secret-field.ts +9 -6
  458. package/src/surfaces/seo.ts +21 -15
  459. package/src/surfaces/settings-contexts.ts +9 -7
  460. package/src/surfaces/settings-contributed.ts +14 -10
  461. package/src/surfaces/settings-css-vars.ts +5 -12
  462. package/src/surfaces/settings-defs.json +2 -2
  463. package/src/surfaces/settings-defs.ts +17 -21
  464. package/src/surfaces/settings-deploy.ts +8 -15
  465. package/src/surfaces/settings-extensions.ts +5 -6
  466. package/src/surfaces/settings-head.ts +33 -39
  467. package/src/surfaces/settings-locales.ts +8 -20
  468. package/src/surfaces/settings-overview.ts +5 -6
  469. package/src/surfaces/settings-packages.ts +8 -7
  470. package/src/surfaces/settings-pane.ts +9 -18
  471. package/src/surfaces/settings-rawjson.ts +5 -6
  472. package/src/surfaces/shell.ts +1 -2
  473. package/src/surfaces/slash-menu.ts +19 -9
  474. package/src/surfaces/statements.ts +13 -18
  475. package/src/surfaces/statusbar.ts +17 -14
  476. package/src/surfaces/style-panel.ts +18 -31
  477. package/src/surfaces/stylebook-chrome.ts +3 -5
  478. package/src/surfaces/tab-strip.ts +14 -13
  479. package/src/surfaces/target-line.ts +6 -7
  480. package/src/surfaces/welcome.ts +5 -7
  481. package/src/tabs/patch-ops.ts +4 -3
  482. package/src/tabs/project-config.ts +32 -21
  483. package/src/tabs/selection.ts +36 -8
  484. package/src/tabs/tab.ts +52 -41
  485. package/src/tabs/transact.ts +98 -53
  486. package/src/types.ts +32 -17
  487. package/src/ui/ai-credentials-form.ts +10 -13
  488. package/src/ui/ai-model-picker.ts +3 -3
  489. package/src/ui/cf-account-picker.ts +7 -9
  490. package/src/ui/color-selector.ts +9 -5
  491. package/src/ui/dynamic-slot.ts +7 -8
  492. package/src/ui/expression-editor.ts +112 -105
  493. package/src/ui/form-controls.ts +57 -48
  494. package/src/ui/formula-catalog.ts +239 -230
  495. package/src/ui/formula-chips.ts +33 -18
  496. package/src/ui/layers.ts +44 -31
  497. package/src/ui/media-picker.ts +18 -9
  498. package/src/ui/popover-surface.ts +20 -12
  499. package/src/ui/progress-modal.ts +13 -8
  500. package/src/ui/regions.ts +7 -6
  501. package/src/ui/schema-form.ts +113 -70
  502. package/src/ui/surface.ts +71 -8
  503. package/src/ui/timing.ts +9 -0
  504. package/src/ui/value-source.ts +44 -31
  505. package/src/ui/virtual-window.ts +3 -2
  506. package/src/utils/base64.ts +3 -1
  507. package/src/utils/edit-display.ts +73 -73
  508. package/src/utils/element-selectors.ts +3 -2
  509. package/src/utils/google-fonts.ts +15 -14
  510. package/src/utils/inherited-style.ts +18 -20
  511. package/src/utils/link-target.ts +1 -1
  512. package/src/utils/preview-format.ts +25 -3
  513. package/src/utils/strip-events.ts +49 -22
  514. package/src/utils/studio-utils.ts +29 -14
  515. package/src/view.ts +2 -3
  516. package/src/workspace/pane-derive.ts +10 -12
  517. package/src/workspace/session.ts +53 -43
  518. package/src/workspace/workspace.ts +40 -36
  519. package/dist/chunks/adapter-f93pafd7.js +0 -4
  520. package/dist/chunks/cf-account-picker-af1h381v.js +0 -4
  521. package/dist/chunks/cf-settings-125tdm0w.js +0 -4
  522. package/dist/chunks/color-area-jqhna8zy.js +0 -4
  523. package/dist/chunks/color-field-embq5ctg.js +0 -4
  524. package/dist/chunks/color-fpezvnkt.js +0 -4
  525. package/dist/chunks/color-slider-1qmw7wqy.js +0 -4
  526. package/dist/chunks/combobox-773hdzyj.js +0 -4
  527. package/dist/chunks/components-ax2f1fnn.js +0 -4
  528. package/dist/chunks/content-source-108aqtk1.js +0 -4
  529. package/dist/chunks/convert-to-repeater-ry5rmppr.js +0 -4
  530. package/dist/chunks/dialog-mtm9fq5t.js +0 -4
  531. package/dist/chunks/editor-pfgdmkb0.js +0 -4
  532. package/dist/chunks/entry-commands-t0k1q0kx.js +0 -4
  533. package/dist/chunks/extension-sections-6mwh2hf8.js +0 -4
  534. package/dist/chunks/file-ops-meej5mqf.js +0 -4
  535. package/dist/chunks/files-44vp8a2s.js +0 -4
  536. package/dist/chunks/format-host-7q1petb9.js +0 -4
  537. package/dist/chunks/fs-events-h2mwnxaz.js +0 -4
  538. package/dist/chunks/git-panel-zngbymvd.js +0 -4
  539. package/dist/chunks/grid-view-sx9vynsp.js +0 -51
  540. package/dist/chunks/icons-p44xhjf0.js +0 -4
  541. package/dist/chunks/iframe-entry-f7mqjwpm.js +0 -5
  542. package/dist/chunks/iframe-entry-haw7jkvz.js +0 -5
  543. package/dist/chunks/iframe-entry-z6qrytv3.js +0 -5
  544. package/dist/chunks/iframe-host-qk3ycq87.js +0 -4
  545. package/dist/chunks/index-wkyfjeqz.js +0 -4
  546. package/dist/chunks/jx-validate-psgd7vsx.js +0 -4
  547. package/dist/chunks/layers-panel-1kq2jyfk.js +0 -4
  548. package/dist/chunks/layers-xd92fg8d.js +0 -4
  549. package/dist/chunks/listbox-s8fkmnq8.js +0 -4
  550. package/dist/chunks/lit-html-ac4cwwr4.js +0 -4
  551. package/dist/chunks/media-picker-0svzkdyb.js +0 -4
  552. package/dist/chunks/menu-37d07z9m.js +0 -4
  553. package/dist/chunks/menu-5c55ea3d.js +0 -4
  554. package/dist/chunks/monaco-binding-z6r70pdt.js +0 -4
  555. package/dist/chunks/monaco-buffer-fz6gq5y7.js +0 -4
  556. package/dist/chunks/monaco-setup-q4axkgj7.js +0 -4
  557. package/dist/chunks/notify-0xgtn8q1.js +0 -4
  558. package/dist/chunks/number-field-gw7sq8rn.js +0 -4
  559. package/dist/chunks/parse-897fvqah.js +0 -4
  560. package/dist/chunks/platform-v1qctbe6.js +0 -4
  561. package/dist/chunks/popover-8htra4er.js +0 -4
  562. package/dist/chunks/publish-panel-ym1fmgq5.js +0 -4
  563. package/dist/chunks/quick-search-a54e6t5n.js +0 -4
  564. package/dist/chunks/references-gmqp82fs.js +0 -4
  565. package/dist/chunks/right-panel-v7t9awbk.js +0 -4
  566. package/dist/chunks/section-registry-vhyf3zsr.js +0 -4
  567. package/dist/chunks/select-n3v7gwas.js +0 -4
  568. package/dist/chunks/split-pff8f3ze.js +0 -4
  569. package/dist/chunks/studio-0bhx5hz6.js +0 -5
  570. package/dist/chunks/studio-0k1ddnyy.js +0 -6
  571. package/dist/chunks/studio-1b04pd0j.js +0 -64
  572. package/dist/chunks/studio-4dwbj6gb.js +0 -5
  573. package/dist/chunks/studio-4tanh828.js +0 -5
  574. package/dist/chunks/studio-55h4mstj.js +0 -4
  575. package/dist/chunks/studio-5tnvjkz4.js +0 -5
  576. package/dist/chunks/studio-60dqgb0c.js +0 -5
  577. package/dist/chunks/studio-61dp09qg.js +0 -9
  578. package/dist/chunks/studio-63epcrj2.js +0 -5
  579. package/dist/chunks/studio-74k29dy9.js +0 -5
  580. package/dist/chunks/studio-7vg6jcd3.js +0 -5
  581. package/dist/chunks/studio-7zx31knw.js +0 -9
  582. package/dist/chunks/studio-8bxk97km.js +0 -5
  583. package/dist/chunks/studio-933e30n4.js +0 -5
  584. package/dist/chunks/studio-98wnwhbg.js +0 -5
  585. package/dist/chunks/studio-9mccjwjh.js +0 -14
  586. package/dist/chunks/studio-a2ke1e4t.js +0 -5
  587. package/dist/chunks/studio-e3a2a6v3.js +0 -4
  588. package/dist/chunks/studio-e81q1vb9.js +0 -5
  589. package/dist/chunks/studio-epgrmqqm.js +0 -5
  590. package/dist/chunks/studio-ery42sqr.js +0 -4
  591. package/dist/chunks/studio-g1shz58g.js +0 -5
  592. package/dist/chunks/studio-gf0fz03c.js +0 -5
  593. package/dist/chunks/studio-gjtpe62q.js +0 -6
  594. package/dist/chunks/studio-gkskhg7m.js +0 -5
  595. package/dist/chunks/studio-gx4dnjzd.js +0 -5
  596. package/dist/chunks/studio-j03zga3y.js +0 -9
  597. package/dist/chunks/studio-jhpxeckz.js +0 -5
  598. package/dist/chunks/studio-k01r7ykp.js +0 -5
  599. package/dist/chunks/studio-kk7h30ne.js +0 -7
  600. package/dist/chunks/studio-kt1zqney.js +0 -5
  601. package/dist/chunks/studio-m3cwhvye.js +0 -5
  602. package/dist/chunks/studio-mcayt6hz.js +0 -5
  603. package/dist/chunks/studio-myjcghv3.js +0 -5
  604. package/dist/chunks/studio-n8bxwc3y.js +0 -4
  605. package/dist/chunks/studio-ngm8gvpb.js +0 -5
  606. package/dist/chunks/studio-nj5a01jy.js +0 -928
  607. package/dist/chunks/studio-pcgz8heb.js +0 -5
  608. package/dist/chunks/studio-qcsq0t15.js +0 -5
  609. package/dist/chunks/studio-qkstvve9.js +0 -5
  610. package/dist/chunks/studio-qv1pwd3c.js +0 -5
  611. package/dist/chunks/studio-rc6dvxjb.js +0 -7
  612. package/dist/chunks/studio-s8dmmz66.js +0 -5
  613. package/dist/chunks/studio-sp5xzbj4.js +0 -6
  614. package/dist/chunks/studio-szsjbj0g.js +0 -5
  615. package/dist/chunks/studio-t1xzawhr.js +0 -16
  616. package/dist/chunks/studio-t6b6qe31.js +0 -5
  617. package/dist/chunks/studio-tdcprbqb.js +0 -5
  618. package/dist/chunks/studio-vyc0b4he.js +0 -10
  619. package/dist/chunks/studio-w0cgf6jg.js +0 -5
  620. package/dist/chunks/studio-w3hskzqk.js +0 -5
  621. package/dist/chunks/studio-xgrgcdyh.js +0 -9
  622. package/dist/chunks/studio-xz2yxfcb.js +0 -5
  623. package/dist/chunks/studio-y6n42tgs.js +0 -5
  624. package/dist/chunks/studio-yb560vxr.js +0 -5
  625. package/dist/chunks/studio-yn9f8vtx.js +0 -5
  626. package/dist/chunks/studio-yw05w8f0.js +0 -7
  627. package/dist/chunks/studio-z16sgavc.js +0 -5
  628. package/dist/chunks/studio-zyqn40w4.js +0 -5
  629. package/dist/chunks/swatch-group-8qh9a3bm.js +0 -4
  630. package/dist/chunks/tabs-jwthg40w.js +0 -4
  631. package/dist/chunks/textfield-spy3hc77.js +0 -4
  632. package/dist/chunks/toast-4d35zd64.js +0 -4
  633. package/dist/chunks/toast-host-8sjmfed3.js +0 -4
  634. package/dist/chunks/tooltip-fd6g9xy3.js +0 -4
  635. package/dist/chunks/tree-h19v1jfz.js +0 -4
  636. package/dist/chunks/workspace-zt81g1ms.js +0 -4
  637. package/dist/chunks/ws-client-n2bh4hkf.js +0 -4
@@ -43,7 +43,16 @@ import {
43
43
  tagExpressionSchema,
44
44
  tagNameSchema,
45
45
  } from "@jxsuite/schema/defs";
46
- import { isFunctionDef, isRef, isTemplateString } from "@jxsuite/schema/guards";
46
+ import {
47
+ isFunctionDef,
48
+ isJsonObject,
49
+ isNonNullObject,
50
+ isRef,
51
+ isString,
52
+ isTemplateString,
53
+ } from "@jxsuite/schema/guards";
54
+ import type { ReadonlyJsonObject, ReadonlyJsonValue } from "@jxsuite/schema/project-schemas";
55
+ import type { JsonValue, JxDocumentValue } from "@jxsuite/schema/types";
47
56
 
48
57
  /** A rung of the value ladder — one way a document position can produce its value. */
49
58
  export type SlotMode = "literal" | "ref" | "template" | "expression" | "function";
@@ -73,7 +82,7 @@ export const VALUE_SOURCE_HINTS: Record<SlotMode, string> = {
73
82
  };
74
83
 
75
84
  /** Detect which rung of the ladder a raw document value occupies. */
76
- export function slotMode(value: unknown): SlotMode {
85
+ export function slotMode(value: JxDocumentValue | JsonValue | undefined): SlotMode {
77
86
  if (isRef(value)) {
78
87
  return "ref";
79
88
  }
@@ -83,7 +92,7 @@ export function slotMode(value: unknown): SlotMode {
83
92
  if (isTemplateString(value)) {
84
93
  return "template";
85
94
  }
86
- if (value && typeof value === "object" && "$expression" in value) {
95
+ if (isNonNullObject(value) && "$expression" in value) {
87
96
  return "expression";
88
97
  }
89
98
  return "literal";
@@ -91,8 +100,6 @@ export function slotMode(value: unknown): SlotMode {
91
100
 
92
101
  // ─── Schema walk ────────────────────────────────────────────────────────────
93
102
 
94
- type SchemaNode = Record<string, unknown>;
95
-
96
103
  /**
97
104
  * The `on*` property shape that `@jxsuite/schema`'s generator synthesises for every EventHandler
98
105
  * IDL attribute (`buildEventHandlerProperties`). It is the only slot position with no declared
@@ -107,40 +114,45 @@ export const EVENT_HANDLER_SCHEMA = {
107
114
  } as const;
108
115
 
109
116
  /** The `$defs` a slot position can actually reach. Anything else is a bug, not a silent no-rung. */
110
- const REACHABLE_DEFS: Record<string, SchemaNode> = {
111
- ExpressionEntry: expressionEntrySchema as unknown as SchemaNode,
112
- FunctionDef: functionDefSchema as unknown as SchemaNode,
113
- RefObject: refObjectSchema as unknown as SchemaNode,
114
- StyleObject: styleObjectSchema as unknown as SchemaNode,
115
- };
117
+ const REACHABLE_DEFS = new Map<string, ReadonlyJsonObject>([
118
+ ["ExpressionEntry", expressionEntrySchema],
119
+ ["FunctionDef", functionDefSchema],
120
+ ["RefObject", refObjectSchema],
121
+ ["StyleObject", styleObjectSchema],
122
+ ]);
116
123
 
117
124
  /** A `{ $ref: … }` binding object: `required: ["$ref"]` with a `$ref` property. */
118
- function isRefObjectSchema(node: SchemaNode): boolean {
119
- const { required } = node;
125
+ function isRefObjectSchema(node: ReadonlyJsonObject): boolean {
126
+ const { properties, required } = node;
120
127
  return (
121
128
  Array.isArray(required) &&
122
129
  required.includes("$ref") &&
123
- Boolean((node.properties as SchemaNode | undefined)?.$ref)
130
+ isJsonObject(properties) &&
131
+ Boolean(properties.$ref)
124
132
  );
125
133
  }
126
134
 
127
135
  /** A `{ $expression: … }` entry. */
128
- function isExpressionEntrySchema(node: SchemaNode): boolean {
136
+ function isExpressionEntrySchema(node: ReadonlyJsonObject): boolean {
129
137
  const { required } = node;
130
138
  return Array.isArray(required) && required.includes("$expression");
131
139
  }
132
140
 
133
141
  /** A `$prototype: "Function"` declaration. */
134
- function isFunctionDefSchema(node: SchemaNode): boolean {
135
- const proto = (node.properties as SchemaNode | undefined)?.$prototype as SchemaNode | undefined;
136
- return proto?.const === "Function";
142
+ function isFunctionDefSchema(node: ReadonlyJsonObject): boolean {
143
+ const { properties } = node;
144
+ return (
145
+ isJsonObject(properties) &&
146
+ isJsonObject(properties.$prototype) &&
147
+ properties.$prototype.const === "Function"
148
+ );
137
149
  }
138
150
 
139
151
  /**
140
152
  * A string branch that will accept `${…}`. A pattern/enum/const-constrained string will not — a
141
153
  * `TagName` or a `#/state/…` pointer is a string, but not a place a template may be typed.
142
154
  */
143
- function isFreeStringSchema(node: SchemaNode): boolean {
155
+ function isFreeStringSchema(node: ReadonlyJsonObject): boolean {
144
156
  return (
145
157
  node.type === "string" &&
146
158
  node.pattern === undefined &&
@@ -155,23 +167,24 @@ interface WalkState {
155
167
  found: Set<SlotMode>;
156
168
  /** Pointers the walk could not resolve — surfaced so a schema move fails loudly. */
157
169
  unresolved: Set<string>;
158
- seen: Set<SchemaNode>;
170
+ seen: Set<ReadonlyJsonObject>;
159
171
  }
160
172
 
161
- function walk(node: unknown, state: WalkState): void {
162
- if (!node || typeof node !== "object") {
173
+ function walk(schema: ReadonlyJsonValue | undefined, state: WalkState): void {
174
+ /* An array is an object too, but it names no keyword: the walk below found nothing in one, so
175
+ refusing it here is the same answer reached sooner. */
176
+ if (!isJsonObject(schema)) {
163
177
  return;
164
178
  }
165
- const schema = node as SchemaNode;
166
179
  if (state.seen.has(schema)) {
167
180
  return;
168
181
  }
169
182
  state.seen.add(schema);
170
183
 
171
- const pointer = typeof schema.$ref === "string" ? schema.$ref : undefined;
184
+ const pointer = isString(schema.$ref) ? schema.$ref : undefined;
172
185
  if (pointer !== undefined && Object.keys(schema).length === 1) {
173
186
  const name = pointer.startsWith("#/$defs/") ? pointer.slice("#/$defs/".length) : pointer;
174
- const target = REACHABLE_DEFS[name];
187
+ const target = REACHABLE_DEFS.get(name);
175
188
  if (target) {
176
189
  walk(target, state);
177
190
  } else {
@@ -218,7 +231,7 @@ function walk(node: unknown, state: WalkState): void {
218
231
  state.found.add("literal");
219
232
  return;
220
233
  }
221
- if (typeof schema.type === "string" && SCALAR_TYPES.has(schema.type)) {
234
+ if (isString(schema.type) && SCALAR_TYPES.has(schema.type)) {
222
235
  state.found.add("literal");
223
236
  }
224
237
  }
@@ -230,7 +243,7 @@ export interface DerivedCaps {
230
243
  }
231
244
 
232
245
  /** Derive the rungs a subschema permits, and report any pointer the walk could not follow. */
233
- export function deriveSlotCapsDetailed(schema: unknown): DerivedCaps {
246
+ export function deriveSlotCapsDetailed(schema: ReadonlyJsonValue | undefined): DerivedCaps {
234
247
  const state: WalkState = { found: new Set(), seen: new Set(), unresolved: new Set() };
235
248
  walk(schema, state);
236
249
  return {
@@ -240,7 +253,7 @@ export function deriveSlotCapsDetailed(schema: unknown): DerivedCaps {
240
253
  }
241
254
 
242
255
  /** Derive the rungs a subschema permits, in ladder order. */
243
- export function deriveSlotCaps(schema: unknown): SlotMode[] {
256
+ export function deriveSlotCaps(schema: ReadonlyJsonValue | undefined): SlotMode[] {
244
257
  return deriveSlotCapsDetailed(schema).caps;
245
258
  }
246
259
 
@@ -322,7 +335,7 @@ export type SlotPosition = keyof typeof SLOT_POSITION_SCHEMAS;
322
335
  * There is deliberately no third form. A caller may not state which rungs it wants: the rungs are
323
336
  * derived from a schema or they are not derived at all.
324
337
  */
325
- export type SlotCapsSource = SlotPosition | { schema: unknown };
338
+ export type SlotCapsSource = SlotPosition | { schema: ReadonlyJsonValue };
326
339
 
327
340
  const capsCache = new Map<SlotPosition, SlotMode[]>();
328
341
 
@@ -339,7 +352,7 @@ export function capsForPosition(position: SlotPosition): SlotMode[] {
339
352
 
340
353
  /** The rungs on offer for a {@link SlotCapsSource} — a named position, or a schema handed in. */
341
354
  export function slotCaps(source: SlotCapsSource): SlotMode[] {
342
- return typeof source === "string" ? capsForPosition(source) : deriveSlotCaps(source.schema);
355
+ return isString(source) ? capsForPosition(source) : deriveSlotCaps(source.schema);
343
356
  }
344
357
 
345
358
  /**
@@ -351,7 +364,7 @@ export function slotCaps(source: SlotCapsSource): SlotMode[] {
351
364
  * own config at runtime — which no plugin schema declares because it is not the plugin's to
352
365
  * declare. Both are stated here, once, rather than assumed at each form.
353
366
  */
354
- export function configFieldSchema(field: unknown): { anyOf: unknown[] } {
367
+ export function configFieldSchema(field: ReadonlyJsonValue): ReadonlyJsonObject {
355
368
  const declared = deriveSlotCaps(field).length > 0 ? field : { type: "string" };
356
369
  return { anyOf: [declared, { $ref: "#/$defs/RefObject" }] };
357
370
  }
@@ -28,6 +28,7 @@
28
28
 
29
29
  /// <reference lib="dom" />
30
30
 
31
+ import { isFunction } from "@jxsuite/schema/guards";
31
32
  import { rectOf } from "../utils/geometry";
32
33
 
33
34
  /** The measurement a window is computed from. Everything is in CSS pixels. */
@@ -244,7 +245,7 @@ export function createVirtualWindow(options: VirtualWindowOptions): VirtualWindo
244
245
  };
245
246
 
246
247
  let resizeObserver: ResizeObserver | null = null;
247
- if (typeof ResizeObserver === "function") {
248
+ if (isFunction(globalThis.ResizeObserver)) {
248
249
  resizeObserver = new ResizeObserver(measureNextFrame);
249
250
  resizeObserver.observe(scroller);
250
251
  if (list) {
@@ -373,7 +374,7 @@ export function listWindow(
373
374
  return computeWindow({
374
375
  columns: spec.columns ?? 1,
375
376
  count: spec.count,
376
- ...(spec.overscanRows === undefined ? {} : { overscanRows: spec.overscanRows }),
377
+ overscanRows: spec.overscanRows ?? DEFAULT_OVERSCAN_ROWS,
377
378
  rowHeight: spec.rowHeight,
378
379
  scrollTop: listScrollTop(scroller, list),
379
380
  viewportHeight: scroller.clientHeight,
@@ -11,6 +11,8 @@
11
11
  * backends answer a base64 string for the same reason they accept one, and the caller wants bytes.
12
12
  */
13
13
 
14
+ import { isString } from "@jxsuite/schema/guards";
15
+
14
16
  /** Bytes per `String.fromCodePoint` call — spreading a whole large file blows the call stack. */
15
17
  const CHUNK = 32_768;
16
18
 
@@ -28,7 +30,7 @@ export function bytesToBase64(bytes: Uint8Array): string {
28
30
  * have always received base64 strings, so existing callers keep working.
29
31
  */
30
32
  export async function toBase64(data: string | File | Blob | ArrayBuffer): Promise<string> {
31
- if (typeof data === "string") {
33
+ if (isString(data)) {
32
34
  return data;
33
35
  }
34
36
  const buffer = data instanceof ArrayBuffer ? data : await data.arrayBuffer();
@@ -5,11 +5,14 @@
5
5
  * placeholders).
6
6
  */
7
7
 
8
- import type { JxMutableNode } from "@jxsuite/schema/types";
9
- import { displayTagName } from "@jxsuite/schema/guards";
8
+ import type { JxDocumentValue, JxMutableNode } from "@jxsuite/schema/types";
9
+ import { displayTagName, isNodeObject, isNonNullObject, isString } from "@jxsuite/schema/guards";
10
+ import { isDocumentContainer } from "./strip-events";
11
+ import type { RebuiltNode } from "./strip-events";
10
12
 
11
13
  const mediaTags = new Set(["img", "video", "source", "iframe", "audio"]);
12
- const TRANSPARENT_PX =
14
+ /** A 1×1 transparent GIF: what an unresolvable `src` binding shows in edit mode. */
15
+ export const TRANSPARENT_PX =
13
16
  "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7";
14
17
  // A neutral, visible gray placeholder for image-like bindings in edit mode (e.g. a component `image`
15
18
  // Prop bound to ${...}). The component renders <img src={prop}> internally, so a transparent pixel
@@ -161,6 +164,7 @@ export function templateToEditDisplay(str: string) {
161
164
  export function restoreTemplateExpressions(el: HTMLElement) {
162
165
  const walker = document.createTreeWalker(el, NodeFilter.SHOW_TEXT);
163
166
  while (walker.nextNode()) {
167
+ // SAFETY: the walker was created with NodeFilter.SHOW_TEXT, so every node it stops on is Text.
164
168
  const node = walker.currentNode as Text;
165
169
  if (node.data.includes("\u276A")) {
166
170
  node.data = node.data.replaceAll(/\u276A\s*(.*?)\s*\u276B/g, "${$1}");
@@ -175,52 +179,64 @@ export function restoreTemplateExpressions(el: HTMLElement) {
175
179
  * edit-only device — it is never compiled or rendered in preview.
176
180
  *
177
181
  * @param {JxMutableNode} arrayObj
178
- * @returns {Record<string, unknown>}
182
+ * @returns {JxMutableNode}
179
183
  */
180
- function arrayToPerimeter(arrayObj: JxMutableNode): Record<string, unknown> {
184
+ function arrayToPerimeter(arrayObj: JxMutableNode): JxMutableNode {
181
185
  const template = arrayObj.map;
182
186
  return {
183
- children:
184
- template && typeof template === "object"
185
- ? [prepareForEditMode(template as JxMutableNode)]
186
- : [],
187
+ children: isNonNullObject(template) ? [prepareForEditMode(template)] : [],
187
188
  className: "repeater-perimeter",
188
189
  tagName: "div",
189
190
  };
190
191
  }
191
192
 
193
+ /**
194
+ * The text a `$ref` binding shows in edit mode: its pointer, with the `#/state/` prefix dropped.
195
+ *
196
+ * @param {string} ref
197
+ */
198
+ function refDisplayLabel(ref: string): string {
199
+ const label = ref.startsWith("#/state/") ? ref.slice(8) : ref;
200
+ return `{${label}}`;
201
+ }
202
+
192
203
  /**
193
204
  * Prepare a document for edit-mode rendering. Replaces template strings with readable literal text,
194
205
  * $prototype:Array with placeholders, and $ref bindings with display labels. Preserves state so the
195
- * runtime can still initialise scope.
206
+ * runtime can still initialise scope. Arrays are prepared member by member, and primitives and a
207
+ * cleared (`undefined`) key return unchanged, so the walker can recurse through any document
208
+ * value.
196
209
  *
197
210
  * @param {JxMutableNode} node
198
211
  * @returns {JxMutableNode}
199
212
  */
200
- export function prepareForEditMode(node: JxMutableNode): JxMutableNode {
201
- if (!node || typeof node !== "object") {
202
- return node;
203
- }
213
+ export function prepareForEditMode(node: JxMutableNode): JxMutableNode;
214
+ export function prepareForEditMode(node: JxDocumentValue): JxDocumentValue;
215
+ export function prepareForEditMode(node: JxDocumentValue | undefined): JxDocumentValue | undefined;
216
+ export function prepareForEditMode(node: JxDocumentValue | undefined): JxDocumentValue | undefined {
204
217
  if (Array.isArray(node)) {
205
218
  // Arrays of nodes round-trip element-wise; the array itself is not a node.
206
- return (node as JxMutableNode[]).map((n) => prepareForEditMode(n)) as unknown as JxMutableNode;
219
+ return node.map((n) => prepareForEditMode(n));
220
+ }
221
+ if (!isNodeObject(node)) {
222
+ return node;
207
223
  }
208
224
 
209
225
  // A mapped-array node itself → its edit-mode perimeter (e.g. when the patcher re-renders an
210
226
  // Array node directly). Members inside a children array funnel here via the children branch.
211
- if ((node as Record<string, unknown>).$prototype === "Array") {
212
- return arrayToPerimeter(node) as unknown as JxMutableNode;
227
+ if (node.$prototype === "Array") {
228
+ return arrayToPerimeter(node);
213
229
  }
214
230
 
215
- const /** @type {Record<string, unknown>} */ obj = node as Record<string, unknown>;
231
+ const obj = node;
216
232
 
217
- const out: Record<string, unknown> = {};
233
+ const out: RebuiltNode = {};
218
234
  let needsMediaPlaceholder = false;
219
- const isMediaElement = mediaTags.has((obj.tagName as string) || "");
235
+ const isMediaElement = isString(obj.tagName) && mediaTags.has(obj.tagName);
220
236
 
221
237
  // Check if this media element lacks a resolvable src (top-level or in attributes)
222
238
  if (isMediaElement) {
223
- const attrs = obj.attributes as Record<string, unknown> | undefined;
239
+ const attrs = obj.attributes;
224
240
  const topSrc = obj.src;
225
241
  const attrSrc = attrs?.src;
226
242
  const topPoster = obj.poster;
@@ -235,11 +251,11 @@ export function prepareForEditMode(node: JxMutableNode): JxMutableNode {
235
251
  for (const [k, v] of Object.entries(obj)) {
236
252
  if (k === "state" || k === "$media" || k === "$elements") {
237
253
  out[k] = v; // Preserve as-is for runtime resolution
238
- } else if (k === "$props" && v && typeof v === "object") {
254
+ } else if (k === "$props" && isDocumentContainer(v)) {
239
255
  // Process $props values: convert template strings to display format
240
- const propsOut: Record<string, unknown> = {};
256
+ const propsOut: RebuiltNode = {};
241
257
  for (const [pk, pv] of Object.entries(v)) {
242
- if (typeof pv === "string" && pv.includes("${")) {
258
+ if (isString(pv) && pv.includes("${")) {
243
259
  // Image-like prop → neutral placeholder (the component renders it as an <img src>); link
244
260
  // Targets → inert ""; everything else → the readable ❪ expr ❫ binding text.
245
261
  if (isImageUrlKey(pk)) {
@@ -249,10 +265,8 @@ export function prepareForEditMode(node: JxMutableNode): JxMutableNode {
249
265
  } else {
250
266
  propsOut[pk] = templateToEditDisplay(pv);
251
267
  }
252
- } else if (pv && typeof pv === "object" && (pv as Record<string, unknown>).$ref) {
253
- const ref = (pv as Record<string, unknown>).$ref as string;
254
- const label = ref.startsWith("#/state/") ? ref.slice(8) : ref;
255
- propsOut[pk] = `{${label}}`;
268
+ } else if (isNodeObject(pv) && pv.$ref) {
269
+ propsOut[pk] = refDisplayLabel(pv.$ref);
256
270
  } else {
257
271
  propsOut[pk] = pv;
258
272
  }
@@ -262,25 +276,21 @@ export function prepareForEditMode(node: JxMutableNode): JxMutableNode {
262
276
  if (Array.isArray(v)) {
263
277
  // Each member recurses; array pseudo-elements become a single repeater-perimeter element
264
278
  // (via the top-level array case) so they stay a 1:1 DOM node among their siblings.
265
- out.children = v.map((c) => prepareForEditMode(c as JxMutableNode));
266
- } else if (
267
- v &&
268
- typeof v === "object" &&
269
- (v as Record<string, unknown>).$prototype === "Array"
270
- ) {
279
+ out.children = v.map((c) => prepareForEditMode(c));
280
+ } else if (isNodeObject(v) && v.$prototype === "Array") {
271
281
  // Legacy whole-children repeater → a single perimeter as the sole child.
272
- out.children = [prepareForEditMode(v as JxMutableNode)];
282
+ out.children = [prepareForEditMode(v)];
273
283
  } else {
274
- out.children = prepareForEditMode(v as JxMutableNode);
284
+ out.children = prepareForEditMode(v);
275
285
  }
276
- } else if (k === "cases" && obj.$switch && v && typeof v === "object") {
286
+ } else if (k === "cases" && obj.$switch && isDocumentContainer(v)) {
277
287
  // Replace $switch cases with a placeholder showing the first case or a label
278
- const caseKeys = Object.keys(v);
279
- if (caseKeys.length > 0) {
280
- const firstCase = (v as Record<string, unknown>)[caseKeys[0]!];
288
+ const [firstEntry] = Object.entries(v);
289
+ if (firstEntry) {
290
+ const [, firstCase] = firstEntry;
281
291
  out.children =
282
- firstCase && typeof firstCase === "object" && !(firstCase as Record<string, unknown>).$ref
283
- ? [prepareForEditMode(firstCase as JxMutableNode)]
292
+ isDocumentContainer(firstCase) && !(isNodeObject(firstCase) && firstCase.$ref)
293
+ ? [prepareForEditMode(firstCase)]
284
294
  : [
285
295
  {
286
296
  style: {
@@ -294,29 +304,26 @@ export function prepareForEditMode(node: JxMutableNode): JxMutableNode {
294
304
  padding: "6px 10px",
295
305
  },
296
306
  tagName: "div",
297
- textContent: `[$switch: ${caseKeys.join(" | ")}]`,
307
+ textContent: `[$switch: ${Object.keys(v).join(" | ")}]`,
298
308
  },
299
309
  ];
300
310
  }
301
- } else if (k === "attributes" && isMediaElement && v && typeof v === "object") {
311
+ } else if (k === "attributes" && isMediaElement && isDocumentContainer(v)) {
302
312
  // Process attributes for media elements: replace src/poster with transparent pixel
303
- const attrs = v as Record<string, unknown>;
304
- const processed: Record<string, unknown> = {};
305
- for (const [ak, av] of Object.entries(attrs)) {
313
+ const processed: RebuiltNode = {};
314
+ for (const [ak, av] of Object.entries(v)) {
306
315
  if (ak === "src" || ak === "poster") {
307
- if (typeof av === "string" && av !== "" && !av.includes("${")) {
316
+ if (isString(av) && av !== "" && !av.includes("${")) {
308
317
  processed[ak] = av;
309
318
  } else {
310
319
  needsMediaPlaceholder = true;
311
320
  processed[ak] = TRANSPARENT_PX;
312
321
  }
313
- } else if (typeof av === "string" && av.includes("${")) {
322
+ } else if (isString(av) && av.includes("${")) {
314
323
  const isUrlAttr = ak === "href" || ak === "action";
315
324
  processed[ak] = isUrlAttr ? "" : templateToEditDisplay(av);
316
- } else if (av && typeof av === "object" && (av as Record<string, unknown>).$ref) {
317
- const ref = (av as Record<string, unknown>).$ref as string;
318
- const label = ref.startsWith("#/state/") ? ref.slice(8) : ref;
319
- processed[ak] = `{${label}}`;
325
+ } else if (isNodeObject(av) && av.$ref) {
326
+ processed[ak] = refDisplayLabel(av.$ref);
320
327
  } else {
321
328
  processed[ak] = av;
322
329
  }
@@ -327,10 +334,10 @@ export function prepareForEditMode(node: JxMutableNode): JxMutableNode {
327
334
  cannot be resolved; omitting the property lets the cascade answer, which is exactly what
328
335
  the `""` this used to write meant while declarations went inline. As a RULE, `color: ` is
329
336
  a malformed declaration instead of a no-op. Mirrored by iframe-patch's editModeStyle. */
330
- if (v && typeof v === "object") {
331
- const s: Record<string, unknown> = {};
337
+ if (isDocumentContainer(v)) {
338
+ const s: RebuiltNode = {};
332
339
  for (const [sk, sv] of Object.entries(v)) {
333
- if (typeof sv !== "string" || !sv.includes("${")) {
340
+ if (!isString(sv) || !sv.includes("${")) {
334
341
  s[sk] = sv;
335
342
  }
336
343
  }
@@ -338,10 +345,9 @@ export function prepareForEditMode(node: JxMutableNode): JxMutableNode {
338
345
  } else {
339
346
  out.style = v;
340
347
  }
341
- } else if (typeof v === "string" && v.includes("${")) {
348
+ } else if (isString(v) && v.includes("${")) {
342
349
  // Template string in a display property → show raw expression
343
- const isMediaSrc =
344
- (k === "src" || k === "poster") && mediaTags.has((obj.tagName as string) || "");
350
+ const isMediaSrc = (k === "src" || k === "poster") && isMediaElement;
345
351
  if (isMediaSrc) {
346
352
  needsMediaPlaceholder = true;
347
353
  out[k] = TRANSPARENT_PX;
@@ -349,42 +355,36 @@ export function prepareForEditMode(node: JxMutableNode): JxMutableNode {
349
355
  const isUrlAttr = k === "src" || k === "href" || k === "poster" || k === "action";
350
356
  out[k] = isUrlAttr ? "" : templateToEditDisplay(v);
351
357
  }
352
- } else if (v && typeof v === "object" && (v as Record<string, unknown>).$ref) {
358
+ } else if (isNodeObject(v) && v.$ref) {
353
359
  // $ref binding → show ref path as literal text
354
- const ref = (v as Record<string, unknown>).$ref as string;
355
- const label = ref.startsWith("#/state/") ? ref.slice(8) : ref;
356
- const isMediaSrc =
357
- (k === "src" || k === "poster") && mediaTags.has((obj.tagName as string) || "");
360
+ const label = refDisplayLabel(v.$ref);
361
+ const isMediaSrc = (k === "src" || k === "poster") && isMediaElement;
358
362
  if (isMediaSrc) {
359
363
  needsMediaPlaceholder = true;
360
364
  out[k] = TRANSPARENT_PX;
361
365
  } else {
362
- out[k] = `{${label}}`;
366
+ out[k] = label;
363
367
  }
364
368
  } else {
365
369
  // Empty src/poster on media elements → use transparent pixel placeholder
366
- if (
367
- (k === "src" || k === "poster") &&
368
- v === "" &&
369
- mediaTags.has((obj.tagName as string) || "")
370
- ) {
370
+ if ((k === "src" || k === "poster") && v === "" && isMediaElement) {
371
371
  needsMediaPlaceholder = true;
372
372
  out[k] = TRANSPARENT_PX;
373
373
  } else {
374
- out[k] = prepareForEditMode(v as JxMutableNode);
374
+ out[k] = prepareForEditMode(v);
375
375
  }
376
376
  }
377
377
  }
378
378
 
379
379
  // Mark empty elements with placeholder classes for design-mode visibility
380
- const placeholderClass = computeEmptyPlaceholderClass(out as JxMutableNode);
380
+ const placeholderClass = computeEmptyPlaceholderClass(out);
381
381
  if (placeholderClass) {
382
382
  out.className = out.className ? `${out.className} ${placeholderClass}` : placeholderClass;
383
383
  }
384
384
 
385
385
  // Media elements with missing/dynamic src get a placeholder class
386
386
  if (needsMediaPlaceholder) {
387
- const cls = (out.className as string) || "";
387
+ const cls = isString(out.className) ? out.className : "";
388
388
  if (!cls.includes("empty-media-placeholder")) {
389
389
  out.className = cls ? `${cls} empty-media-placeholder` : "empty-media-placeholder";
390
390
  }
@@ -14,7 +14,7 @@
14
14
  */
15
15
 
16
16
  import { COMMON_SELECTORS } from "../store";
17
- import { displayTagName } from "@jxsuite/schema/guards";
17
+ import { displayTagName, isNonNullObject } from "@jxsuite/schema/guards";
18
18
  import { isPopover } from "@jxsuite/schema/overlays";
19
19
  import type { JxMutableNode } from "@jxsuite/schema/types";
20
20
 
@@ -62,7 +62,8 @@ function extraSelectorsFor(node: JxMutableNode): string[] {
62
62
  * @returns The offerable selectors.
63
63
  */
64
64
  export function selectorsForNode(node: JxMutableNode | null | undefined): string[] {
65
- if (!node || typeof node !== "object") {
65
+ // The style panel reads the node with getNodeAtPath, which can answer a bare string text child.
66
+ if (!isNonNullObject(node)) {
66
67
  return [...COMMON_SELECTORS];
67
68
  }
68
69
  return [...new Set([...COMMON_SELECTORS, ...extraSelectorsFor(node)])];
@@ -1,5 +1,6 @@
1
1
  /** Google Fonts helpers — shared between head-panel (per-page) and head-editor (project-level). */
2
2
 
3
+ import { isString } from "@jxsuite/schema/guards";
3
4
  import type { JxHeadEntry } from "@jxsuite/schema/types";
4
5
 
5
6
  export const GFONTS_CSS_PREFIX = "https://fonts.googleapis.com/css2?";
@@ -11,29 +12,30 @@ export const GFONTS_PRECONNECT_ORIGINS = [
11
12
  /**
12
13
  * Check if a `$head` entry is a Google Fonts stylesheet link.
13
14
  *
14
- * @param {JxHeadEntry} entry
15
+ * @param {JxHeadEntry | null | undefined} entry A `$head` slot; a JSON array can hold `null`.
15
16
  * @returns {boolean}
16
17
  */
17
- export function isGoogleFontEntry(entry: JxHeadEntry) {
18
+ export function isGoogleFontEntry(entry: JxHeadEntry | null | undefined) {
18
19
  return (
19
20
  entry?.tagName === "link" &&
20
- entry?.attributes?.rel === "stylesheet" &&
21
- typeof entry?.attributes?.href === "string" &&
22
- (entry.attributes.href as string).startsWith(GFONTS_CSS_PREFIX)
21
+ entry.attributes?.rel === "stylesheet" &&
22
+ isString(entry.attributes.href) &&
23
+ entry.attributes.href.startsWith(GFONTS_CSS_PREFIX)
23
24
  );
24
25
  }
25
26
 
26
27
  /**
27
28
  * Check if a `$head` entry is a Google Fonts preconnect link.
28
29
  *
29
- * @param {JxHeadEntry} entry
30
+ * @param {JxHeadEntry | null | undefined} entry A `$head` slot; a JSON array can hold `null`.
30
31
  * @returns {boolean}
31
32
  */
32
- export function isGoogleFontPreconnect(entry: JxHeadEntry) {
33
+ export function isGoogleFontPreconnect(entry: JxHeadEntry | null | undefined) {
33
34
  return (
34
35
  entry?.tagName === "link" &&
35
- entry?.attributes?.rel === "preconnect" &&
36
- GFONTS_PRECONNECT_ORIGINS.includes(entry?.attributes?.href as string)
36
+ entry.attributes?.rel === "preconnect" &&
37
+ isString(entry.attributes.href) &&
38
+ GFONTS_PRECONNECT_ORIGINS.includes(entry.attributes.href)
37
39
  );
38
40
  }
39
41
 
@@ -68,14 +70,13 @@ export function buildGoogleFontUrl(family: string) {
68
70
  */
69
71
  export function ensureGoogleFontPreconnects(head: JxHeadEntry[]) {
70
72
  for (const origin of GFONTS_PRECONNECT_ORIGINS) {
73
+ // A `$head` array is JSON, so a slot can hold `null` whatever the element type says.
71
74
  const exists = head.some(
72
- (e: JxHeadEntry) =>
73
- e?.tagName === "link" &&
74
- e?.attributes?.rel === "preconnect" &&
75
- e?.attributes?.href === origin,
75
+ (e: JxHeadEntry | null | undefined) =>
76
+ e?.tagName === "link" && e.attributes?.rel === "preconnect" && e.attributes.href === origin,
76
77
  );
77
78
  if (!exists) {
78
- const attrs: Record<string, string | boolean> = {
79
+ const attrs: NonNullable<JxHeadEntry["attributes"]> = {
79
80
  href: origin,
80
81
  rel: "preconnect",
81
82
  };