@jxsuite/studio 6.1.1 → 8.0.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 (785) hide show
  1. package/README.md +5 -5
  2. package/dist/chunks/2020-5wtzce5g.js +4 -0
  3. package/dist/chunks/{action-group-2mqby73c.js → action-group-4aan7g6g.js} +3 -3
  4. package/dist/chunks/adapter-5tphg7xe.js +4 -0
  5. package/dist/chunks/add-new-flow-psym14sn.js +4 -0
  6. package/dist/chunks/cf-account-picker-haqazq5r.js +4 -0
  7. package/dist/chunks/cf-settings-h2wrh6hq.js +4 -0
  8. package/dist/chunks/color-area-6rbra5dy.js +4 -0
  9. package/dist/chunks/color-field-gy56c94g.js +4 -0
  10. package/dist/chunks/color-m7r1vk54.js +4 -0
  11. package/dist/chunks/color-slider-sqqdyf6c.js +4 -0
  12. package/dist/chunks/combobox-72h32ejk.js +4 -0
  13. package/dist/chunks/components-r22xca09.js +4 -0
  14. package/dist/chunks/content-source-mmppmcyg.js +4 -0
  15. package/dist/chunks/convert-to-repeater-he70fc2b.js +4 -0
  16. package/dist/chunks/dialog-c4x05vyx.js +4 -0
  17. package/dist/chunks/editor-ccd9jwsa.js +4 -0
  18. package/dist/chunks/entry-commands-6qxz9e8p.js +4 -0
  19. package/dist/chunks/extension-sections-0egb88dm.js +4 -0
  20. package/dist/chunks/file-ops-qnab36ek.js +4 -0
  21. package/dist/chunks/files-rcn56qvm.js +4 -0
  22. package/dist/chunks/format-host-yxz0kjjs.js +4 -0
  23. package/dist/chunks/fs-events-d1qxq4z4.js +4 -0
  24. package/dist/chunks/grid-open-4z1g062t.js +4 -0
  25. package/dist/chunks/grid-view-qg1b5eqx.js +51 -0
  26. package/dist/chunks/icons-63bjtbs7.js +4 -0
  27. package/dist/chunks/iframe-entry-2zggzajv.js +5 -0
  28. package/dist/chunks/iframe-entry-76j8vwwx.js +5 -0
  29. package/dist/chunks/iframe-entry-99nr5zfb.js +5 -0
  30. package/dist/chunks/iframe-entry-pkgmcgp0.js +5 -0
  31. package/dist/chunks/iframe-host-ssv7kyj0.js +4 -0
  32. package/dist/chunks/{index-2veqmnhr.js → index-32eqzv1k.js} +3 -3
  33. package/dist/chunks/index-f0jn7nnp.js +4 -0
  34. package/dist/chunks/{javascript-8nbvs12s.js → javascript-pjp734q4.js} +3 -3
  35. package/dist/chunks/jsonMode-njkvsa02.js +13 -0
  36. package/dist/chunks/jx-validate-ttasrbh7.js +4 -0
  37. package/dist/chunks/layers-bgyr11tr.js +4 -0
  38. package/dist/chunks/layers-panel-7ez66zeq.js +4 -0
  39. package/dist/chunks/listbox-c421cf8c.js +4 -0
  40. package/dist/chunks/lit-html-v9gh687x.js +4 -0
  41. package/dist/chunks/media-library-sq468wts.js +4 -0
  42. package/dist/chunks/media-picker-shfe59pt.js +4 -0
  43. package/dist/chunks/menu-bdpzbfvs.js +4 -0
  44. package/dist/chunks/monaco-binding-vq1hgnn0.js +4 -0
  45. package/dist/chunks/monaco-buffer-3afgwvbp.js +4 -0
  46. package/dist/chunks/monaco-setup-xrd2cbkp.js +4 -0
  47. package/dist/chunks/notify-kzrjr3fv.js +4 -0
  48. package/dist/chunks/number-field-y62xq0ty.js +4 -0
  49. package/dist/chunks/parse-v77xtwv7.js +4 -0
  50. package/dist/chunks/platform-7v4rtd7m.js +4 -0
  51. package/dist/chunks/popover-b89sfej7.js +4 -0
  52. package/dist/chunks/publish-panel-2z9gw8ee.js +4 -0
  53. package/dist/chunks/publish-quick-qx2455cj.js +4 -0
  54. package/dist/chunks/publish-workspace-wrc1dgwx.js +4 -0
  55. package/dist/chunks/quick-search-n0t0eqxb.js +4 -0
  56. package/dist/chunks/references-9547rg5s.js +4 -0
  57. package/dist/chunks/right-panel-wsgnr9pn.js +4 -0
  58. package/dist/chunks/select-rzds841e.js +4 -0
  59. package/dist/chunks/source-control-kwktr9y6.js +4 -0
  60. package/dist/chunks/split-c9zfdgxf.js +4 -0
  61. package/dist/chunks/studio-03ct6yfv.js +9 -0
  62. package/dist/chunks/studio-07rcfje3.js +5 -0
  63. package/dist/chunks/studio-3e54qh39.js +7 -0
  64. package/dist/chunks/studio-3exxhz5g.js +5 -0
  65. package/dist/chunks/studio-3q40e3rj.js +5 -0
  66. package/dist/chunks/studio-3qeh9t0h.js +6 -0
  67. package/dist/chunks/studio-3qqjeep5.js +6 -0
  68. package/dist/chunks/studio-43sd2mam.js +4 -0
  69. package/dist/chunks/studio-4hp8pkyt.js +5 -0
  70. package/dist/chunks/studio-58xg6j2q.js +9 -0
  71. package/dist/chunks/studio-5g0rprdt.js +7 -0
  72. package/dist/chunks/studio-6m380wp7.js +5 -0
  73. package/dist/chunks/studio-80jyh1xh.js +4 -0
  74. package/dist/chunks/studio-83mk4bgg.js +9 -0
  75. package/dist/chunks/{studio-kggey1jt.js → studio-881z1xrx.js} +4 -4
  76. package/dist/chunks/studio-8m0y2qe7.js +5 -0
  77. package/dist/chunks/studio-8tr6cfrc.js +5 -0
  78. package/dist/chunks/studio-8vcvfs7r.js +6 -0
  79. package/dist/chunks/studio-9tmebf0s.js +5 -0
  80. package/dist/chunks/studio-a2bvaptz.js +5 -0
  81. package/dist/chunks/studio-b7y5mr30.js +5 -0
  82. package/dist/chunks/studio-bavb31r0.js +5 -0
  83. package/dist/chunks/studio-bbe4c90a.js +5 -0
  84. package/dist/chunks/studio-c05wdnt3.js +5 -0
  85. package/dist/chunks/studio-ccv2svc6.js +5 -0
  86. package/dist/chunks/studio-d5grtb9e.js +16 -0
  87. package/dist/chunks/studio-df0baea9.js +5 -0
  88. package/dist/chunks/studio-dgk4dqtx.js +7 -0
  89. package/dist/chunks/studio-e1g64q43.js +5 -0
  90. package/dist/chunks/studio-ed1hp6zf.js +6 -0
  91. package/dist/chunks/studio-ed3xx40h.js +7 -0
  92. package/dist/chunks/studio-f14e1zdj.js +5 -0
  93. package/dist/chunks/studio-fbhxxc5f.js +5 -0
  94. package/dist/chunks/studio-fyh0jc96.js +5 -0
  95. package/dist/chunks/studio-gcxk20n7.js +5 -0
  96. package/dist/chunks/studio-jaaz8ce9.js +5 -0
  97. package/dist/chunks/{studio-8grwxtqk.js → studio-jcnsdaep.js} +4 -4
  98. package/dist/chunks/studio-jsgf2q5k.js +7 -0
  99. package/dist/chunks/{studio-1q1sh2ax.js → studio-k3xxbagr.js} +3 -3
  100. package/dist/chunks/studio-k7evxqh4.js +5 -0
  101. package/dist/chunks/studio-kt3pjkwd.js +5 -0
  102. package/dist/chunks/studio-m8g16bgz.js +5 -0
  103. package/dist/chunks/studio-mn0476ag.js +5 -0
  104. package/dist/chunks/studio-mx1smyq0.js +5 -0
  105. package/dist/chunks/studio-n0c5h6mf.js +5 -0
  106. package/dist/chunks/{studio-rv11kfwa.js → studio-nh6d342n.js} +7 -7
  107. package/dist/chunks/studio-nqxqf8p2.js +4 -0
  108. package/dist/chunks/studio-p4nrkvqr.js +5 -0
  109. package/dist/chunks/{studio-h46vtzk8.js → studio-pbxa5fpc.js} +4 -4
  110. package/dist/chunks/studio-pgmvdv7z.js +7 -0
  111. package/dist/chunks/studio-ph84avkf.js +5 -0
  112. package/dist/chunks/{studio-wszjyh0j.js → studio-q0mvbaq6.js} +4 -4
  113. package/dist/chunks/studio-q0tccd43.js +5 -0
  114. package/dist/chunks/studio-q7rtx6zq.js +14 -0
  115. package/dist/chunks/{studio-pre0skq6.js → studio-qgh13jtz.js} +4 -4
  116. package/dist/chunks/studio-qmn1xc24.js +5 -0
  117. package/dist/chunks/studio-qwdqwkj0.js +5 -0
  118. package/dist/chunks/{studio-t6b6qe31.js → studio-r5qy30vx.js} +4 -4
  119. package/dist/chunks/studio-rj9eamf8.js +5 -0
  120. package/dist/chunks/studio-rptgsk96.js +5 -0
  121. package/dist/chunks/studio-rthyg42z.js +928 -0
  122. package/dist/chunks/studio-s19tp1xr.js +5 -0
  123. package/dist/chunks/studio-s32578pn.js +5 -0
  124. package/dist/chunks/studio-svb7yyve.js +5 -0
  125. package/dist/chunks/studio-syreb644.js +5 -0
  126. package/dist/chunks/studio-tf9jryb1.js +10 -0
  127. package/dist/chunks/studio-tfkznv39.js +5 -0
  128. package/dist/chunks/studio-tft6r105.js +5 -0
  129. package/dist/chunks/studio-txf2kysx.js +5 -0
  130. package/dist/chunks/studio-v8867ddv.js +12 -0
  131. package/dist/chunks/studio-vxq7fcvv.js +5 -0
  132. package/dist/chunks/studio-w4rz9hdk.js +5 -0
  133. package/dist/chunks/studio-wbcjbhy1.js +9 -0
  134. package/dist/chunks/studio-wc649wss.js +5 -0
  135. package/dist/chunks/studio-wys23mxz.js +5 -0
  136. package/dist/chunks/studio-x1x167jh.js +5 -0
  137. package/dist/chunks/studio-x9hsze61.js +5 -0
  138. package/dist/chunks/studio-y0n7yxea.js +9 -0
  139. package/dist/chunks/studio-y3ahhdpx.js +5 -0
  140. package/dist/chunks/studio-z97c48fk.js +5 -0
  141. package/dist/chunks/studio-zat62m0c.js +5 -0
  142. package/dist/chunks/studio-zcd2e7yz.js +5 -0
  143. package/dist/chunks/studio-zz9qe3rw.js +64 -0
  144. package/dist/chunks/swatch-group-ewh24n1f.js +4 -0
  145. package/dist/chunks/tabs-f5cw3tgp.js +4 -0
  146. package/dist/chunks/textfield-wewc8rq2.js +4 -0
  147. package/dist/chunks/toast-1gv0h53h.js +4 -0
  148. package/dist/chunks/toast-host-1yg5ar8d.js +4 -0
  149. package/dist/chunks/{toolbar-2nnzqhrj.js → toolbar-44cm5cta.js} +3 -3
  150. package/dist/chunks/tooltip-yypz28gq.js +4 -0
  151. package/dist/chunks/tree-9xa4hm7n.js +4 -0
  152. package/dist/chunks/tsMode-epyfz1hv.js +14 -0
  153. package/dist/chunks/workspace-dz7nxfhv.js +4 -0
  154. package/dist/chunks/workspace-home-xsd7hkjw.js +4 -0
  155. package/dist/chunks/ws-client-bv552sfx.js +4 -0
  156. package/dist/iframe-entry.js +20 -16
  157. package/dist/manifest.json +77 -63
  158. package/dist/studio.js +106 -107
  159. package/dist/workers/ts.worker.js +3 -3
  160. package/package.json +17 -16
  161. package/src/about/about-modal.ts +4 -3
  162. package/src/account/action-flow.ts +45 -38
  163. package/src/account-status.ts +7 -2
  164. package/src/browse/component-examples.ts +272 -0
  165. package/src/browse/library-commands.ts +64 -104
  166. package/src/browse/library-layouts.ts +270 -53
  167. package/src/browse/library-model.ts +194 -134
  168. package/src/browse/library-pane.ts +748 -440
  169. package/src/browse/library-preview.ts +161 -26
  170. package/src/browse/library-source.ts +308 -41
  171. package/src/browse/preview-root.ts +78 -0
  172. package/src/browse/preview-style.ts +155 -0
  173. package/src/canvas/asset-refs.ts +40 -10
  174. package/src/canvas/asset-resolve.ts +19 -23
  175. package/src/canvas/canvas-helpers.ts +7 -6
  176. package/src/canvas/canvas-live-render.ts +260 -77
  177. package/src/canvas/canvas-origin.ts +37 -12
  178. package/src/canvas/canvas-page-context.ts +112 -0
  179. package/src/canvas/canvas-patcher.ts +30 -30
  180. package/src/canvas/canvas-perf.ts +11 -5
  181. package/src/canvas/canvas-render.ts +175 -148
  182. package/src/canvas/canvas-surface.ts +5 -3
  183. package/src/canvas/canvas-utils.ts +147 -61
  184. package/src/canvas/dialog-path.ts +9 -4
  185. package/src/canvas/dialog-state.ts +1 -2
  186. package/src/canvas/diff-marks.ts +9 -16
  187. package/src/canvas/diff-toolbar.ts +8 -7
  188. package/src/canvas/edit-width-drag.ts +4 -1
  189. package/src/canvas/edit-width.ts +1 -3
  190. package/src/canvas/iframe-channel.ts +27 -13
  191. package/src/canvas/iframe-drop.ts +120 -12
  192. package/src/canvas/iframe-editable-root.ts +29 -16
  193. package/src/canvas/iframe-entry.ts +104 -75
  194. package/src/canvas/iframe-eval.ts +73 -49
  195. package/src/canvas/iframe-host.ts +269 -158
  196. package/src/canvas/iframe-inline-edit.ts +49 -30
  197. package/src/canvas/iframe-insert.ts +5 -4
  198. package/src/canvas/iframe-interaction.ts +30 -25
  199. package/src/canvas/iframe-keys.ts +11 -0
  200. package/src/canvas/iframe-overlay.ts +1 -1
  201. package/src/canvas/iframe-patch.ts +25 -21
  202. package/src/canvas/iframe-position.ts +12 -6
  203. package/src/canvas/iframe-protocol.ts +36 -21
  204. package/src/canvas/iframe-render.ts +84 -35
  205. package/src/canvas/iframe-slash.ts +24 -11
  206. package/src/canvas/iframe-subtree.ts +10 -3
  207. package/src/canvas/npm-modules.ts +22 -0
  208. package/src/canvas/path-mapping.ts +19 -12
  209. package/src/canvas/popover-path.ts +7 -3
  210. package/src/canvas/popover-state.ts +1 -2
  211. package/src/canvas/preview-navigate.ts +16 -0
  212. package/src/canvas/repeater-sources.ts +200 -0
  213. package/src/canvas/serialize-scope.ts +13 -5
  214. package/src/canvas/stage-scrollbar.ts +7 -2
  215. package/src/canvas/surface-registry.ts +27 -3
  216. package/src/collab/collab-commands.ts +7 -2
  217. package/src/collab/collab-session.ts +84 -45
  218. package/src/collab/collab-state.ts +4 -3
  219. package/src/collab/monaco-binding.ts +16 -13
  220. package/src/collab/monaco-cursors.ts +5 -2
  221. package/src/commands/app-commands.ts +16 -6
  222. package/src/commands/budget.ts +13 -11
  223. package/src/commands/command-args.ts +103 -71
  224. package/src/commands/context.ts +55 -28
  225. package/src/commands/defaults.ts +69 -45
  226. package/src/commands/keymap.ts +56 -43
  227. package/src/commands/levels.ts +14 -8
  228. package/src/commands/live-context.ts +9 -7
  229. package/src/commands/reference.ts +2 -1
  230. package/src/commands/registry.ts +22 -11
  231. package/src/commands/run-reported.ts +15 -10
  232. package/src/component-props.ts +46 -30
  233. package/src/content/collection-match.ts +11 -9
  234. package/src/content/collection-pages.ts +412 -0
  235. package/src/content/content-collections.ts +270 -0
  236. package/src/content/draft-state.ts +4 -3
  237. package/src/content/entry-commands.ts +54 -62
  238. package/src/content/entry-editor.ts +137 -32
  239. package/src/content/entry-fields.ts +25 -8
  240. package/src/content/entry-inspector.ts +225 -0
  241. package/src/content/entry-model.ts +38 -15
  242. package/src/content/entry-open.ts +80 -0
  243. package/src/content/entry-summaries.ts +440 -0
  244. package/src/content/file-record-ids.ts +80 -0
  245. package/src/content/file-records.ts +125 -0
  246. package/src/content/page-summaries.ts +129 -0
  247. package/src/content/record-entry.ts +201 -0
  248. package/src/content/writing-banner.ts +177 -0
  249. package/src/create/add-new-commands.ts +185 -0
  250. package/src/create/add-new-flow.ts +1116 -0
  251. package/src/create/add-new.ts +1014 -0
  252. package/src/create/element-name.ts +121 -0
  253. package/src/editor/canvas-context-menu.ts +1 -2
  254. package/src/editor/canvas-slash-bridge.ts +3 -6
  255. package/src/editor/content-slice.ts +16 -14
  256. package/src/editor/context-menu.ts +35 -22
  257. package/src/editor/convert-targets.ts +30 -35
  258. package/src/editor/convert-to-component.ts +78 -48
  259. package/src/editor/convert-to-repeater.ts +34 -22
  260. package/src/editor/editable-tags.ts +17 -2
  261. package/src/editor/file-drop-action.ts +29 -22
  262. package/src/editor/inline-edit-apply.ts +79 -17
  263. package/src/editor/inline-edit.ts +76 -50
  264. package/src/editor/inline-format.ts +59 -56
  265. package/src/editor/inline-link.ts +40 -15
  266. package/src/editor/insert-component.ts +91 -0
  267. package/src/editor/insert-zone-action.ts +14 -5
  268. package/src/editor/merge-tags.ts +58 -19
  269. package/src/editor/repeater-scope.ts +39 -28
  270. package/src/editor/shortcuts.ts +76 -42
  271. package/src/editor/slash-menu.ts +52 -14
  272. package/src/files/asset-versions.ts +4 -4
  273. package/src/files/components.ts +89 -20
  274. package/src/files/elements.ts +5 -6
  275. package/src/files/file-ops.ts +92 -41
  276. package/src/files/files.ts +248 -239
  277. package/src/files/fs-events.ts +18 -7
  278. package/src/files/media-meta.ts +97 -2
  279. package/src/files/media-paths.ts +3 -0
  280. package/src/files/media-types.ts +55 -0
  281. package/src/files/media-upload.ts +209 -52
  282. package/src/files/new-file-name.ts +156 -0
  283. package/src/files/serialize-document.ts +15 -5
  284. package/src/format/constraints.ts +1 -1
  285. package/src/format/convert-file.ts +27 -13
  286. package/src/format/format-choices.ts +2 -1
  287. package/src/format/format-host.ts +91 -50
  288. package/src/github/github-auth-status.ts +27 -3
  289. package/src/github/github-auth.ts +21 -11
  290. package/src/github/github-publish.ts +28 -23
  291. package/src/grid/cell-editors.ts +46 -31
  292. package/src/grid/cell-popovers.ts +5 -3
  293. package/src/grid/edit-buffer.ts +10 -9
  294. package/src/grid/grid-controller.ts +25 -23
  295. package/src/grid/grid-layout.ts +21 -5
  296. package/src/grid/grid-open.ts +3 -33
  297. package/src/grid/grid-panel.ts +65 -6
  298. package/src/grid/grid-reveal.ts +34 -0
  299. package/src/grid/grid-source.ts +9 -31
  300. package/src/grid/grid-view.ts +45 -23
  301. package/src/grid/redirects-grid.ts +14 -5
  302. package/src/grid/redirects.ts +16 -14
  303. package/src/grid/schema-columns.ts +25 -19
  304. package/src/grid/sources/connector-source.ts +47 -20
  305. package/src/grid/sources/content-source.ts +100 -31
  306. package/src/grid/sources/csv-file-source.ts +2 -2
  307. package/src/grid/tabulator-tables.d.ts +61 -34
  308. package/src/hosting/document.ts +2 -2
  309. package/src/hosting/stage.ts +7 -7
  310. package/src/i18n/i18n-commands.ts +3 -3
  311. package/src/media/media-commands.ts +181 -0
  312. package/src/media/media-library-model.ts +232 -0
  313. package/src/media/media-library.ts +1283 -0
  314. package/src/media/media-pane.ts +51 -20
  315. package/src/new-project/add-repo-modal.ts +20 -19
  316. package/src/new-project/import-tab.ts +10 -14
  317. package/src/new-project/location-fields.ts +2 -1
  318. package/src/new-project/new-project-modal.ts +12 -9
  319. package/src/packages/jxsuite-update.ts +4 -3
  320. package/src/packages/pull-package-sync.ts +26 -25
  321. package/src/page-params.ts +97 -68
  322. package/src/panels/activity-panel.ts +38 -14
  323. package/src/panels/ai-chat/attached-context.ts +13 -7
  324. package/src/panels/ai-chat/chat-markdown.ts +8 -8
  325. package/src/panels/ai-chat/chat-view.ts +80 -73
  326. package/src/panels/ai-chat/composer.ts +30 -33
  327. package/src/panels/ai-chat/sessions-view.ts +1 -2
  328. package/src/panels/ai-panel.ts +23 -20
  329. package/src/panels/block-action-bar.ts +57 -46
  330. package/src/panels/bottom-dock.ts +5 -3
  331. package/src/panels/canvas-dnd-bridge.ts +36 -26
  332. package/src/panels/chat-panel.ts +6 -6
  333. package/src/panels/collections-panel.ts +306 -0
  334. package/src/panels/component-preview.ts +35 -13
  335. package/src/panels/data-explorer.ts +63 -26
  336. package/src/panels/data-grid.ts +18 -11
  337. package/src/panels/dnd.ts +115 -138
  338. package/src/panels/editors.ts +52 -21
  339. package/src/panels/elements-panel.ts +19 -5
  340. package/src/panels/empty-state.ts +2 -2
  341. package/src/panels/events-panel.ts +84 -69
  342. package/src/panels/formula-workspace.ts +78 -54
  343. package/src/panels/frontmatter-fields.ts +33 -28
  344. package/src/panels/git-diff-open.ts +10 -6
  345. package/src/panels/head-panel.ts +488 -202
  346. package/src/panels/i18n-panel.ts +20 -12
  347. package/src/panels/imports-panel.ts +25 -47
  348. package/src/panels/jump-bar.ts +75 -31
  349. package/src/panels/layers-panel.ts +130 -101
  350. package/src/panels/left-panel.ts +25 -11
  351. package/src/panels/navigator-panels.ts +23 -11
  352. package/src/panels/pane-context.ts +140 -49
  353. package/src/panels/pane-grid.ts +55 -26
  354. package/src/panels/panel-registry.ts +36 -46
  355. package/src/panels/properties-panel.ts +182 -124
  356. package/src/panels/quick-search.ts +53 -31
  357. package/src/panels/right-panel.ts +201 -45
  358. package/src/panels/seo-modal.ts +54 -125
  359. package/src/panels/settings-menu.ts +63 -61
  360. package/src/panels/settings-pane.ts +268 -162
  361. package/src/panels/signals-panel.ts +156 -135
  362. package/src/panels/site-model.ts +367 -0
  363. package/src/panels/site-panel.ts +638 -0
  364. package/src/panels/statement-editor.ts +230 -140
  365. package/src/panels/style-panel.ts +253 -206
  366. package/src/panels/style-utils.ts +114 -51
  367. package/src/panels/stylebook-doc.ts +195 -60
  368. package/src/panels/stylebook-layers-panel.ts +48 -89
  369. package/src/panels/stylebook-panel.ts +60 -27
  370. package/src/panels/styles-panel.ts +327 -0
  371. package/src/panels/tab-drop.ts +27 -11
  372. package/src/panels/tab-strip.ts +143 -49
  373. package/src/platform-errors.ts +57 -43
  374. package/src/platform.ts +59 -31
  375. package/src/platforms/cloud.ts +373 -176
  376. package/src/platforms/default-platform.ts +14 -8
  377. package/src/platforms/devserver.ts +180 -142
  378. package/src/platforms/read-batcher.ts +16 -8
  379. package/src/project-list.ts +2 -1
  380. package/src/publish/deploy-checklist.ts +20 -9
  381. package/src/publish/pages-service.ts +66 -27
  382. package/src/publish/publish-changes.ts +491 -0
  383. package/src/publish/publish-commands.ts +88 -22
  384. package/src/publish/publish-ids.ts +49 -0
  385. package/src/publish/publish-panel.ts +10 -6
  386. package/src/publish/publish-quick.ts +148 -0
  387. package/src/publish/publish-workspace.ts +926 -0
  388. package/src/publish/source-control.ts +907 -0
  389. package/src/recent-projects.ts +15 -8
  390. package/src/resize-edges.ts +26 -36
  391. package/src/services/a11y-report.ts +26 -19
  392. package/src/services/agent-seed.ts +23 -11
  393. package/src/services/ai-ask.ts +9 -12
  394. package/src/services/ai-command-tools.ts +68 -62
  395. package/src/services/ai-import-tools.ts +80 -67
  396. package/src/services/ai-models.ts +17 -13
  397. package/src/services/ai-project-tools.ts +68 -32
  398. package/src/services/ai-session-store.ts +19 -10
  399. package/src/services/ai-system-prompt.ts +46 -20
  400. package/src/services/ai-tools.ts +71 -27
  401. package/src/services/ai-write-report.ts +20 -12
  402. package/src/services/ai-writes.ts +4 -4
  403. package/src/services/automation.ts +74 -51
  404. package/src/services/cem-export.ts +149 -58
  405. package/src/services/cf-settings.ts +4 -4
  406. package/src/services/clock.ts +6 -1
  407. package/src/services/code-services.ts +37 -31
  408. package/src/services/connection.ts +2 -2
  409. package/src/services/context-manager.ts +14 -10
  410. package/src/services/context-resolver.ts +20 -8
  411. package/src/services/data-service.ts +19 -15
  412. package/src/services/directory-picker.ts +20 -14
  413. package/src/services/document-assistant.ts +39 -19
  414. package/src/services/gated-registry.ts +10 -6
  415. package/src/services/harness/chat-reducer.ts +23 -1
  416. package/src/services/import-client.ts +91 -38
  417. package/src/services/import-seed.ts +8 -2
  418. package/src/services/jx-validate.ts +28 -31
  419. package/src/services/live-preview.ts +0 -0
  420. package/src/services/live-surfaces.ts +6 -3
  421. package/src/services/model-uri.ts +10 -2
  422. package/src/services/module-preloads.ts +12 -8
  423. package/src/services/monaco-buffer.ts +43 -24
  424. package/src/services/monaco-lazy.ts +7 -8
  425. package/src/services/monaco-setup.ts +23 -16
  426. package/src/services/notify.ts +44 -17
  427. package/src/services/popover-report.ts +25 -10
  428. package/src/services/preview-eval.ts +20 -8
  429. package/src/services/profile.ts +13 -6
  430. package/src/services/project-path.ts +13 -10
  431. package/src/services/references.ts +0 -0
  432. package/src/services/render-critic.ts +29 -9
  433. package/src/services/settings/definitions.ts +25 -14
  434. package/src/services/settings/kernel.ts +13 -4
  435. package/src/services/settings/write-queue.ts +9 -9
  436. package/src/services/token-lint.ts +12 -10
  437. package/src/services/tool-executor.ts +17 -5
  438. package/src/services/tool-outcomes.ts +44 -24
  439. package/src/services/trusted-types.ts +24 -7
  440. package/src/settings/contexts-section.ts +11 -8
  441. package/src/settings/contributed-section.ts +128 -70
  442. package/src/settings/css-vars-editor.ts +119 -32
  443. package/src/settings/defs-editor.ts +38 -35
  444. package/src/settings/developer-panels.ts +43 -0
  445. package/src/settings/extension-rows.ts +16 -8
  446. package/src/settings/extension-sections.ts +42 -14
  447. package/src/settings/extensions-section.ts +4 -1
  448. package/src/settings/general-settings.ts +101 -28
  449. package/src/settings/locales-section.ts +20 -12
  450. package/src/settings/preferences-dialog.ts +17 -7
  451. package/src/settings/preferences-keymap.ts +7 -5
  452. package/src/settings/preferences-sections.ts +11 -5
  453. package/src/settings/project-sections.ts +28 -11
  454. package/src/settings/schema-field-ui.ts +12 -1
  455. package/src/settings/section-registry.ts +116 -11
  456. package/src/settings/settings-dialog.ts +192 -0
  457. package/src/settings/settings-document.ts +186 -166
  458. package/src/shell/tree.ts +6 -5
  459. package/src/shell.ts +536 -477
  460. package/src/site-context.ts +101 -32
  461. package/src/state.ts +68 -57
  462. package/src/store.ts +54 -34
  463. package/src/studio.ts +219 -116
  464. package/src/style/live-preview.ts +1 -1
  465. package/src/style/project-styles.ts +40 -7
  466. package/src/style/stylebook-specimens.ts +89 -0
  467. package/src/style/stylebook-target.ts +26 -0
  468. package/src/style/tag-inheritance.ts +105 -0
  469. package/src/style/token-ref.ts +5 -4
  470. package/src/style/variables-focus.ts +61 -0
  471. package/src/style/variables-view.ts +235 -0
  472. package/src/surfaces/about.ts +18 -19
  473. package/src/surfaces/add-new.json +1482 -0
  474. package/src/surfaces/add-new.ts +325 -0
  475. package/src/surfaces/add-repo.ts +17 -19
  476. package/src/surfaces/ai-chat.ts +33 -38
  477. package/src/surfaces/ai-credentials-form.ts +6 -16
  478. package/src/surfaces/ai-managed-connect.ts +3 -4
  479. package/src/surfaces/ai-model-picker.ts +3 -5
  480. package/src/surfaces/block-action-bar.ts +22 -11
  481. package/src/surfaces/boot-failure.json +4 -3
  482. package/src/surfaces/boot-failure.ts +4 -5
  483. package/src/surfaces/bottom-dock.json +1 -1
  484. package/src/surfaces/bottom-dock.ts +9 -18
  485. package/src/surfaces/canvas-stage.json +30 -19
  486. package/src/surfaces/canvas-stage.ts +17 -16
  487. package/src/surfaces/cf-account-picker.ts +17 -18
  488. package/src/surfaces/collections-panel.json +615 -0
  489. package/src/surfaces/collections-panel.ts +168 -0
  490. package/src/surfaces/commandbar.json +241 -96
  491. package/src/surfaces/commandbar.ts +145 -105
  492. package/src/surfaces/convert-repeater.ts +17 -19
  493. package/src/surfaces/data-actions.ts +9 -7
  494. package/src/surfaces/dialog.ts +26 -28
  495. package/src/surfaces/diff-toolbar.ts +9 -7
  496. package/src/surfaces/empty-state.json +1 -1
  497. package/src/surfaces/empty-state.ts +7 -10
  498. package/src/surfaces/entry-editor.json +136 -0
  499. package/src/surfaces/entry-editor.ts +35 -11
  500. package/src/surfaces/entry-inspector.json +371 -0
  501. package/src/surfaces/entry-inspector.ts +143 -0
  502. package/src/surfaces/expression-editor.ts +11 -25
  503. package/src/surfaces/files-panel.ts +27 -14
  504. package/src/surfaces/formula-palette.ts +4 -5
  505. package/src/surfaces/github-auth.ts +16 -20
  506. package/src/surfaces/github-publish.ts +17 -22
  507. package/src/surfaces/grid-cell.ts +30 -31
  508. package/src/surfaces/grid-open.ts +10 -14
  509. package/src/surfaces/grid-panel.ts +13 -9
  510. package/src/surfaces/grid-replace.ts +13 -13
  511. package/src/surfaces/grid-views.ts +15 -18
  512. package/src/surfaces/inspector-dock.json +162 -14
  513. package/src/surfaces/inspector-dock.ts +59 -31
  514. package/src/surfaces/jump-bar.ts +5 -6
  515. package/src/surfaces/jxsuite-update.ts +16 -22
  516. package/src/surfaces/library-pane.json +670 -437
  517. package/src/surfaces/library-pane.ts +111 -77
  518. package/src/surfaces/logic-panel.ts +17 -30
  519. package/src/surfaces/logic-workspace.ts +13 -15
  520. package/src/surfaces/media-browser.json +62 -6
  521. package/src/surfaces/media-browser.ts +26 -11
  522. package/src/surfaces/media-field.json +1 -1
  523. package/src/surfaces/media-field.ts +4 -5
  524. package/src/surfaces/media-library.json +1586 -0
  525. package/src/surfaces/media-library.ts +282 -0
  526. package/src/surfaces/media-pane.ts +8 -7
  527. package/src/surfaces/media-pick-dialog.json +71 -0
  528. package/src/surfaces/media-pick-dialog.ts +132 -0
  529. package/src/surfaces/menu.ts +47 -23
  530. package/src/surfaces/navigator-dock.ts +11 -12
  531. package/src/surfaces/new-project.ts +27 -26
  532. package/src/surfaces/pane-context.json +144 -77
  533. package/src/surfaces/pane-context.ts +44 -25
  534. package/src/surfaces/pane-grid.ts +15 -10
  535. package/src/surfaces/panel-activity.ts +5 -6
  536. package/src/surfaces/panel-data.ts +3 -4
  537. package/src/surfaces/panel-deploy-checklist.json +12 -6
  538. package/src/surfaces/panel-deploy-checklist.ts +8 -7
  539. package/src/surfaces/panel-elements.ts +5 -7
  540. package/src/surfaces/panel-i18n.ts +5 -7
  541. package/src/surfaces/panel-imports.ts +6 -13
  542. package/src/surfaces/panel-outline.ts +25 -19
  543. package/src/surfaces/panel-page.json +72 -2
  544. package/src/surfaces/panel-page.ts +49 -25
  545. package/src/surfaces/panel-problems.ts +5 -7
  546. package/src/surfaces/panel-signals.json +1 -1
  547. package/src/surfaces/panel-signals.ts +25 -39
  548. package/src/surfaces/panel-stylebook-layers.json +71 -204
  549. package/src/surfaces/panel-stylebook-layers.ts +5 -29
  550. package/src/surfaces/preferences.json +120 -48
  551. package/src/surfaces/preferences.ts +29 -11
  552. package/src/surfaces/progress-modal.ts +15 -9
  553. package/src/surfaces/properties-panel.json +1 -1
  554. package/src/surfaces/properties-panel.ts +20 -42
  555. package/src/surfaces/publish-quick.json +428 -0
  556. package/src/surfaces/publish-quick.ts +165 -0
  557. package/src/surfaces/publish-workspace.json +2892 -0
  558. package/src/surfaces/publish-workspace.ts +391 -0
  559. package/src/surfaces/publish.ts +18 -18
  560. package/src/surfaces/push-plan.ts +7 -8
  561. package/src/surfaces/rail.json +1 -159
  562. package/src/surfaces/rail.ts +22 -79
  563. package/src/surfaces/reference-field.ts +11 -15
  564. package/src/surfaces/schema-builder.ts +16 -22
  565. package/src/surfaces/schema-form.json +10 -2
  566. package/src/surfaces/schema-form.ts +17 -25
  567. package/src/surfaces/secret-field.ts +9 -6
  568. package/src/surfaces/seo.json +1 -1
  569. package/src/surfaces/seo.ts +21 -15
  570. package/src/surfaces/settings-contexts.ts +9 -7
  571. package/src/surfaces/settings-contributed.json +5 -5
  572. package/src/surfaces/settings-contributed.ts +32 -12
  573. package/src/surfaces/settings-css-vars.json +44 -36
  574. package/src/surfaces/settings-css-vars.ts +82 -16
  575. package/src/surfaces/settings-defs.json +2 -2
  576. package/src/surfaces/settings-defs.ts +17 -21
  577. package/src/surfaces/settings-deploy.json +2 -15
  578. package/src/surfaces/settings-deploy.ts +9 -16
  579. package/src/surfaces/settings-dialog.json +51 -0
  580. package/src/surfaces/settings-dialog.ts +169 -0
  581. package/src/surfaces/settings-extensions.ts +5 -6
  582. package/src/surfaces/settings-head.ts +33 -39
  583. package/src/surfaces/settings-locales.ts +8 -20
  584. package/src/surfaces/settings-overview.json +3 -3
  585. package/src/surfaces/settings-overview.ts +14 -8
  586. package/src/surfaces/settings-packages.ts +8 -7
  587. package/src/surfaces/settings-pane.json +269 -46
  588. package/src/surfaces/settings-pane.ts +88 -36
  589. package/src/surfaces/settings-rawjson.ts +5 -6
  590. package/src/surfaces/shell.json +2 -1
  591. package/src/surfaces/shell.ts +1 -2
  592. package/src/surfaces/site-panel.json +1029 -0
  593. package/src/surfaces/site-panel.ts +233 -0
  594. package/src/surfaces/slash-menu.json +63 -21
  595. package/src/surfaces/slash-menu.ts +42 -9
  596. package/src/surfaces/statements.ts +13 -18
  597. package/src/surfaces/statusbar.ts +56 -29
  598. package/src/surfaces/style-panel.ts +18 -31
  599. package/src/surfaces/stylebook-chrome.ts +3 -5
  600. package/src/surfaces/styles-panel.json +735 -0
  601. package/src/surfaces/styles-panel.ts +195 -0
  602. package/src/surfaces/styles-variables.json +149 -0
  603. package/src/surfaces/styles-variables.ts +145 -0
  604. package/src/surfaces/tab-strip.json +4 -4
  605. package/src/surfaces/tab-strip.ts +14 -13
  606. package/src/surfaces/target-line.ts +6 -7
  607. package/src/surfaces/welcome.ts +6 -8
  608. package/src/surfaces/writing-banner.json +94 -0
  609. package/src/surfaces/writing-banner.ts +80 -0
  610. package/src/tabs/bare-repeaters.ts +101 -0
  611. package/src/tabs/patch-ops.ts +4 -3
  612. package/src/tabs/project-config.ts +32 -21
  613. package/src/tabs/selection.ts +36 -8
  614. package/src/tabs/tab.ts +99 -48
  615. package/src/tabs/transact.ts +98 -53
  616. package/src/types.ts +53 -43
  617. package/src/ui/ai-credentials-form.ts +10 -13
  618. package/src/ui/ai-model-picker.ts +3 -3
  619. package/src/ui/cf-account-picker.ts +7 -9
  620. package/src/ui/color-selector.ts +9 -5
  621. package/src/ui/dynamic-slot.ts +7 -8
  622. package/src/ui/expression-editor.ts +112 -105
  623. package/src/ui/form-controls.ts +104 -56
  624. package/src/ui/formula-catalog.ts +239 -230
  625. package/src/ui/formula-chips.ts +33 -18
  626. package/src/ui/layers.ts +57 -31
  627. package/src/ui/media-picker.ts +300 -47
  628. package/src/ui/popover-surface.ts +20 -12
  629. package/src/ui/progress-modal.ts +13 -8
  630. package/src/ui/regions.ts +14 -12
  631. package/src/ui/schema-form.ts +372 -97
  632. package/src/ui/surface.ts +71 -8
  633. package/src/ui/timing.ts +9 -0
  634. package/src/ui/value-source.ts +44 -31
  635. package/src/ui/virtual-window.ts +29 -3
  636. package/src/utils/base64.ts +6 -4
  637. package/src/utils/edit-display.ts +366 -111
  638. package/src/utils/element-selectors.ts +3 -2
  639. package/src/utils/google-fonts.ts +15 -14
  640. package/src/utils/inherited-style.ts +18 -20
  641. package/src/utils/link-target.ts +1 -1
  642. package/src/utils/local-day.ts +18 -0
  643. package/src/utils/preview-format.ts +25 -3
  644. package/src/utils/strip-events.ts +49 -22
  645. package/src/utils/studio-utils.ts +29 -14
  646. package/src/view.ts +2 -3
  647. package/src/workspace/pane-derive.ts +14 -16
  648. package/src/workspace/session.ts +81 -50
  649. package/src/workspace/tab-workspace.ts +137 -0
  650. package/src/workspace/workspace-back.ts +189 -0
  651. package/src/workspace/workspace-home.ts +133 -0
  652. package/src/workspace/workspace-ids.ts +129 -0
  653. package/src/workspace/workspace-switch.ts +372 -0
  654. package/src/workspace/workspace.ts +165 -47
  655. package/styles/shell-frame.css +30 -7
  656. package/styles/shell-frame.json +15 -3
  657. package/dist/chunks/2020-va2wwra4.js +0 -4
  658. package/dist/chunks/adapter-f93pafd7.js +0 -4
  659. package/dist/chunks/cf-account-picker-af1h381v.js +0 -4
  660. package/dist/chunks/cf-settings-125tdm0w.js +0 -4
  661. package/dist/chunks/color-area-jqhna8zy.js +0 -4
  662. package/dist/chunks/color-field-embq5ctg.js +0 -4
  663. package/dist/chunks/color-fpezvnkt.js +0 -4
  664. package/dist/chunks/color-slider-1qmw7wqy.js +0 -4
  665. package/dist/chunks/combobox-773hdzyj.js +0 -4
  666. package/dist/chunks/components-ax2f1fnn.js +0 -4
  667. package/dist/chunks/content-source-108aqtk1.js +0 -4
  668. package/dist/chunks/convert-to-repeater-ry5rmppr.js +0 -4
  669. package/dist/chunks/dialog-mtm9fq5t.js +0 -4
  670. package/dist/chunks/editor-pfgdmkb0.js +0 -4
  671. package/dist/chunks/entry-commands-t0k1q0kx.js +0 -4
  672. package/dist/chunks/extension-sections-6mwh2hf8.js +0 -4
  673. package/dist/chunks/file-ops-meej5mqf.js +0 -4
  674. package/dist/chunks/files-44vp8a2s.js +0 -4
  675. package/dist/chunks/format-host-7q1petb9.js +0 -4
  676. package/dist/chunks/fs-events-h2mwnxaz.js +0 -4
  677. package/dist/chunks/git-panel-zngbymvd.js +0 -4
  678. package/dist/chunks/grid-view-sx9vynsp.js +0 -51
  679. package/dist/chunks/icons-p44xhjf0.js +0 -4
  680. package/dist/chunks/iframe-entry-f7mqjwpm.js +0 -5
  681. package/dist/chunks/iframe-entry-haw7jkvz.js +0 -5
  682. package/dist/chunks/iframe-entry-z6qrytv3.js +0 -5
  683. package/dist/chunks/iframe-host-qk3ycq87.js +0 -4
  684. package/dist/chunks/index-wkyfjeqz.js +0 -4
  685. package/dist/chunks/jsonMode-s8kt9dsj.js +0 -13
  686. package/dist/chunks/jx-validate-psgd7vsx.js +0 -4
  687. package/dist/chunks/layers-panel-1kq2jyfk.js +0 -4
  688. package/dist/chunks/layers-xd92fg8d.js +0 -4
  689. package/dist/chunks/listbox-s8fkmnq8.js +0 -4
  690. package/dist/chunks/lit-html-ac4cwwr4.js +0 -4
  691. package/dist/chunks/media-picker-0svzkdyb.js +0 -4
  692. package/dist/chunks/menu-37d07z9m.js +0 -4
  693. package/dist/chunks/menu-5c55ea3d.js +0 -4
  694. package/dist/chunks/monaco-binding-z6r70pdt.js +0 -4
  695. package/dist/chunks/monaco-buffer-fz6gq5y7.js +0 -4
  696. package/dist/chunks/monaco-setup-q4axkgj7.js +0 -4
  697. package/dist/chunks/notify-0xgtn8q1.js +0 -4
  698. package/dist/chunks/number-field-gw7sq8rn.js +0 -4
  699. package/dist/chunks/parse-897fvqah.js +0 -4
  700. package/dist/chunks/platform-v1qctbe6.js +0 -4
  701. package/dist/chunks/popover-8htra4er.js +0 -4
  702. package/dist/chunks/publish-panel-ym1fmgq5.js +0 -4
  703. package/dist/chunks/quick-search-a54e6t5n.js +0 -4
  704. package/dist/chunks/references-gmqp82fs.js +0 -4
  705. package/dist/chunks/right-panel-v7t9awbk.js +0 -4
  706. package/dist/chunks/section-registry-vhyf3zsr.js +0 -4
  707. package/dist/chunks/select-n3v7gwas.js +0 -4
  708. package/dist/chunks/split-pff8f3ze.js +0 -4
  709. package/dist/chunks/studio-0bhx5hz6.js +0 -5
  710. package/dist/chunks/studio-0k1ddnyy.js +0 -6
  711. package/dist/chunks/studio-1b04pd0j.js +0 -64
  712. package/dist/chunks/studio-4dwbj6gb.js +0 -5
  713. package/dist/chunks/studio-4tanh828.js +0 -5
  714. package/dist/chunks/studio-55h4mstj.js +0 -4
  715. package/dist/chunks/studio-5tnvjkz4.js +0 -5
  716. package/dist/chunks/studio-60dqgb0c.js +0 -5
  717. package/dist/chunks/studio-61dp09qg.js +0 -9
  718. package/dist/chunks/studio-63epcrj2.js +0 -5
  719. package/dist/chunks/studio-74k29dy9.js +0 -5
  720. package/dist/chunks/studio-7vg6jcd3.js +0 -5
  721. package/dist/chunks/studio-7zx31knw.js +0 -9
  722. package/dist/chunks/studio-8bxk97km.js +0 -5
  723. package/dist/chunks/studio-933e30n4.js +0 -5
  724. package/dist/chunks/studio-98wnwhbg.js +0 -5
  725. package/dist/chunks/studio-9mccjwjh.js +0 -14
  726. package/dist/chunks/studio-a2ke1e4t.js +0 -5
  727. package/dist/chunks/studio-e3a2a6v3.js +0 -4
  728. package/dist/chunks/studio-e81q1vb9.js +0 -5
  729. package/dist/chunks/studio-epgrmqqm.js +0 -5
  730. package/dist/chunks/studio-ery42sqr.js +0 -4
  731. package/dist/chunks/studio-g1shz58g.js +0 -5
  732. package/dist/chunks/studio-gf0fz03c.js +0 -5
  733. package/dist/chunks/studio-gjtpe62q.js +0 -6
  734. package/dist/chunks/studio-gkskhg7m.js +0 -5
  735. package/dist/chunks/studio-gx4dnjzd.js +0 -5
  736. package/dist/chunks/studio-j03zga3y.js +0 -9
  737. package/dist/chunks/studio-jhpxeckz.js +0 -5
  738. package/dist/chunks/studio-k01r7ykp.js +0 -5
  739. package/dist/chunks/studio-kk7h30ne.js +0 -7
  740. package/dist/chunks/studio-kt1zqney.js +0 -5
  741. package/dist/chunks/studio-m3cwhvye.js +0 -5
  742. package/dist/chunks/studio-mcayt6hz.js +0 -5
  743. package/dist/chunks/studio-myjcghv3.js +0 -5
  744. package/dist/chunks/studio-n8bxwc3y.js +0 -4
  745. package/dist/chunks/studio-ngm8gvpb.js +0 -5
  746. package/dist/chunks/studio-nj5a01jy.js +0 -928
  747. package/dist/chunks/studio-pcgz8heb.js +0 -5
  748. package/dist/chunks/studio-qcsq0t15.js +0 -5
  749. package/dist/chunks/studio-qkstvve9.js +0 -5
  750. package/dist/chunks/studio-qv1pwd3c.js +0 -5
  751. package/dist/chunks/studio-rc6dvxjb.js +0 -7
  752. package/dist/chunks/studio-s8dmmz66.js +0 -5
  753. package/dist/chunks/studio-sp5xzbj4.js +0 -6
  754. package/dist/chunks/studio-szsjbj0g.js +0 -5
  755. package/dist/chunks/studio-t1xzawhr.js +0 -16
  756. package/dist/chunks/studio-tdcprbqb.js +0 -5
  757. package/dist/chunks/studio-vrmcjf9g.js +0 -7
  758. package/dist/chunks/studio-vyc0b4he.js +0 -10
  759. package/dist/chunks/studio-w0cgf6jg.js +0 -5
  760. package/dist/chunks/studio-w3hskzqk.js +0 -5
  761. package/dist/chunks/studio-xgrgcdyh.js +0 -9
  762. package/dist/chunks/studio-xz2yxfcb.js +0 -5
  763. package/dist/chunks/studio-y6n42tgs.js +0 -5
  764. package/dist/chunks/studio-yb560vxr.js +0 -5
  765. package/dist/chunks/studio-yn9f8vtx.js +0 -5
  766. package/dist/chunks/studio-yw05w8f0.js +0 -7
  767. package/dist/chunks/studio-z16sgavc.js +0 -5
  768. package/dist/chunks/studio-zey7zsdw.js +0 -12
  769. package/dist/chunks/studio-zyqn40w4.js +0 -5
  770. package/dist/chunks/swatch-group-8qh9a3bm.js +0 -4
  771. package/dist/chunks/tabs-jwthg40w.js +0 -4
  772. package/dist/chunks/textfield-spy3hc77.js +0 -4
  773. package/dist/chunks/toast-4d35zd64.js +0 -4
  774. package/dist/chunks/toast-host-8sjmfed3.js +0 -4
  775. package/dist/chunks/tooltip-fd6g9xy3.js +0 -4
  776. package/dist/chunks/tree-h19v1jfz.js +0 -4
  777. package/dist/chunks/tsMode-2frah6h1.js +0 -14
  778. package/dist/chunks/workspace-zt81g1ms.js +0 -4
  779. package/dist/chunks/ws-client-n2bh4hkf.js +0 -4
  780. package/src/panels/frontmatter-panel.ts +0 -701
  781. package/src/panels/git-panel.ts +0 -1120
  782. package/src/surfaces/doc-header.json +0 -776
  783. package/src/surfaces/doc-header.ts +0 -231
  784. package/src/surfaces/git-panel.json +0 -1880
  785. package/src/surfaces/git-panel.ts +0 -272
@@ -0,0 +1,156 @@
1
+ /**
2
+ * The rules a new file's name is held to, with no dialog and no write attached.
3
+ *
4
+ * `createFileIn` (`files/files.ts`) used to keep these inside one closure over its prompt, which
5
+ * was right while the prompt was the only creation flow there was. Add new (`create/add-new.ts`,
6
+ * `specs/studio.md` §9.1.1) composes a name the same way and must refuse the same things — a blank
7
+ * name, a name that escapes the destination, a name that is already taken — and a second copy of
8
+ * those rules would disagree with the first the first time either was fixed. So the composing and
9
+ * the judging live here, DOM-free, and both flows call them; only the write, and what each flow
10
+ * does around it, differs.
11
+ *
12
+ * Nothing here lists a directory. The caller supplies the `taken` names it listed, because when
13
+ * that listing happens is the caller's concern: before the prompt opens for New File, and once per
14
+ * destination directory for Add new, whose destination moves as the reader types.
15
+ *
16
+ * @docs studio/interface
17
+ */
18
+
19
+ /**
20
+ * The picker row meaning "I will type the whole name myself".
21
+ *
22
+ * It is what keeps the format picker from being a cage. `New File…` is the only generic
23
+ * file-creation affordance in Studio and both backends create intermediate directories on write, so
24
+ * without this row `styles/main.css`, `public/robots.txt`, `.gitignore` and a `credits.txt` beside
25
+ * a collection's images all become uncreatable — and the picker would have taken away more than it
26
+ * gave. The picker stays the authority on the extension; this is one of its answers.
27
+ */
28
+ export const OTHER_FORMAT = "__other__";
29
+
30
+ /** How the extension of a new file is settled. */
31
+ export type FormatChoice =
32
+ /** Picker over every creatable format, plus Other…. The field is a NAME, taken verbatim. */
33
+ | { kind: "choose"; defaultExt?: string; docKind?: "page" | "component" | "content" }
34
+ /**
35
+ * Picker holding ONE format, plus Other… — the collection's own extension. The field is a NAME.
36
+ * `because` is the sentence a refusal quotes when Other… would smuggle a foreign document in.
37
+ */
38
+ | { kind: "locked"; ext: string; because: string }
39
+ /** No picker. The field is a DISPLAY NAME, slugified, and `ext` is appended. */
40
+ | { kind: "fixed"; ext: string };
41
+
42
+ /** A display name, reduced to a file stem. Lowercase by design: this is a slug. */
43
+ export function slugify(input: string): string {
44
+ return input
45
+ .trim()
46
+ .toLowerCase()
47
+ .replaceAll(/\s+/g, "-")
48
+ .replaceAll(/[^a-z\d-]/g, "");
49
+ }
50
+
51
+ /** The extension of a file name, including the dot, or `""`. */
52
+ export function extensionOfName(name: string): string {
53
+ const dot = name.lastIndexOf(".");
54
+ return dot > 0 ? name.slice(dot) : "";
55
+ }
56
+
57
+ /**
58
+ * The file name a field value and a pick compose to — three modes, not two.
59
+ *
60
+ * The verbatim STEM mode is not a convenience. The slugifier lowercases and strips everything
61
+ * outside `[a-z0-9-]`, which turns `[slug]` into `slug` — and eight shipped starters carry
62
+ * `pages/[slug].json`, `[sku].json`, `[...slug].json`. A picker that slugified would make a dynamic
63
+ * route uncreatable and would say nothing about it.
64
+ *
65
+ * @param input What the reader typed.
66
+ * @param picked The picker's value: an extension, {@link OTHER_FORMAT}, or `""` with no picker.
67
+ * @param choice How the extension is settled; absent takes the whole name verbatim.
68
+ */
69
+ export function composeNewFileName(input: string, picked: string, choice?: FormatChoice): string {
70
+ const trimmed = input.trim();
71
+ if (choice === undefined || picked === OTHER_FORMAT) {
72
+ return trimmed;
73
+ }
74
+ if (choice.kind === "fixed") {
75
+ const slug = slugify(trimmed);
76
+ return slug === "" ? "" : `${slug}${choice.ext}`;
77
+ }
78
+ return trimmed.toLowerCase().endsWith(picked.toLowerCase()) ? trimmed : `${trimmed}${picked}`;
79
+ }
80
+
81
+ /** What a name is judged against: where it is going, and what is already there. */
82
+ export interface NewFileNameCheck {
83
+ /** Destination directory, project-relative. `"."` is the project root. */
84
+ dir: string;
85
+ choice?: FormatChoice | undefined;
86
+ /** The destination's entries, LOWER-CASED: APFS and NTFS compare without case, and so does this. */
87
+ taken: ReadonlySet<string>;
88
+ /** Extensions that are documents, lower-cased (`knownDocumentExtensions()`). */
89
+ known?: ReadonlySet<string>;
90
+ /** The picker's rows, for naming a pick in a refusal. */
91
+ rows?: readonly { label: string; value: string }[] | null;
92
+ }
93
+
94
+ /**
95
+ * The refusal a name earns, or `""` when it is usable.
96
+ *
97
+ * In order: blank, a display name that slugifies to nothing, a path that starts or ends with a
98
+ * slash, a `..` segment, a subfolder where the field is a name rather than a whole file name, an
99
+ * extension that contradicts the pick, a document smuggled through Other… past a collection's lock,
100
+ * and finally a name already taken in the destination. The first that applies is the sentence.
101
+ *
102
+ * @param value What the reader typed.
103
+ * @param picked The picker's value, as {@link composeNewFileName} takes it.
104
+ * @param check The destination and what it already holds.
105
+ */
106
+ export function validateNewFileName(
107
+ value: string,
108
+ picked: string,
109
+ check: NewFileNameCheck,
110
+ ): string {
111
+ const { choice, dir, known = new Set<string>(), rows = null, taken } = check;
112
+ const trimmed = value.trim();
113
+ if (!trimmed) {
114
+ return choice?.kind === "fixed" ? "Enter a name." : "Enter a file name.";
115
+ }
116
+ if (choice?.kind === "fixed" && slugify(trimmed) === "") {
117
+ return "Enter at least one letter or number.";
118
+ }
119
+ const normalized = trimmed.replaceAll("\\", "/");
120
+ if (normalized.startsWith("/") || normalized.endsWith("/")) {
121
+ return "Enter a name, not a path that starts or ends with a slash.";
122
+ }
123
+ if (normalized.split("/").includes("..")) {
124
+ return "A name cannot step outside the destination folder.";
125
+ }
126
+ // A slash is the tree's ONLY way to make a directory — both backends create them on write — so
127
+ // It is allowed exactly where the field is a whole file name, and refused where it is a name.
128
+ if (normalized.includes("/") && choice !== undefined && picked !== OTHER_FORMAT) {
129
+ return `Pick Other… to create a file in a subfolder of ${dir === "." ? "the project root" : dir}.`;
130
+ }
131
+ /* A name whose extension MATCHES the pick is fine and is composed once, never doubled;
132
+ refusing every trailing extension would reject this dialog's own `untitled.json` default.
133
+ A name ending in an extension no format claims is a stem that happens to have a dot. */
134
+ const typedExt = extensionOfName(normalized);
135
+ if (
136
+ picked !== "" &&
137
+ picked !== OTHER_FORMAT &&
138
+ typedExt !== "" &&
139
+ typedExt.toLowerCase() !== picked.toLowerCase() &&
140
+ known.has(typedExt.toLowerCase())
141
+ ) {
142
+ const label = rows?.find((row) => row.value === picked)?.label ?? picked;
143
+ return `You picked ${label}; this name ends in ${typedExt}.`;
144
+ }
145
+ if (choice?.kind === "locked" && picked === OTHER_FORMAT) {
146
+ const foreign = typedExt !== "" && typedExt.toLowerCase() !== choice.ext.toLowerCase();
147
+ if (foreign && known.has(typedExt.toLowerCase())) {
148
+ return choice.because;
149
+ }
150
+ }
151
+ /* No emptiness check here: every way `composeNewFileName` can answer "" is already refused
152
+ above — a blank field by the first rule, a display name that slugifies to nothing by the
153
+ second. */
154
+ const candidate = composeNewFileName(value, picked, choice);
155
+ return taken.has(candidate.toLowerCase()) ? `${candidate} already exists in ${dir}/.` : "";
156
+ }
@@ -20,6 +20,7 @@ import {
20
20
  loadFormats,
21
21
  } from "../format/format-host";
22
22
  import { serializeJson } from "@jxsuite/schema/json-layout";
23
+ import { restoreBareRepeaters } from "../tabs/bare-repeaters";
23
24
  import type { Tab } from "../tabs/tab";
24
25
 
25
26
  /**
@@ -40,15 +41,19 @@ export async function serializeDocument(tab: Tab): Promise<string> {
40
41
  await loadFormats();
41
42
  const sourceFormat = formatByName(tab.doc.sourceFormat);
42
43
  if (sourceFormat?.capabilities.serialize) {
43
- const fm = tab.doc.content?.frontmatter || {};
44
+ const fm = tab.doc.content.frontmatter;
44
45
  const doc = tab.doc.document;
45
46
  const fullDoc = { ...fm, ...doc, children: doc.children ?? [] };
46
- return formatSerialize(sourceFormat.name, fullDoc, { mode: "roundtrip" });
47
+ // The text the file was read as, so what the author did not edit keeps its own spelling.
48
+ return formatSerialize(sourceFormat.name, fullDoc, {
49
+ mode: "roundtrip",
50
+ ...(tab.doc.source !== null && { source: tab.doc.source }),
51
+ });
47
52
  }
48
53
  if (tab.doc.mode === "content") {
49
54
  const format = defaultContentFormat();
50
55
  if (format) {
51
- const fm = tab.doc.content?.frontmatter ?? {};
56
+ const fm = tab.doc.content.frontmatter;
52
57
  const hasFrontmatter = Object.keys(fm).length > 0;
53
58
  const fullDoc = { ...fm, ...tab.doc.document };
54
59
  return formatSerialize(format.name, fullDoc, {
@@ -62,6 +67,11 @@ export async function serializeDocument(tab: Tab): Promise<string> {
62
67
  a blank line sits, which characters were escaped — and it is null for a document with no JSON
63
68
  source, where every object expands and every array is laid by fit: the formatter's own answer
64
69
  for stringified output. Either way the text ends with one newline, as every formatted file
65
- does. */
66
- return serializeJson(tab.doc.document, tab.doc.layout ?? null);
70
+ does. A repeater the file wrote as a node's whole `children` is written that way again
71
+ (`tabs/bare-repeaters.ts`), so the member form the editor works in never reaches the disk —
72
+ which is also what keeps the layout's pointers, taken from the file's own text, lined up. */
73
+ return serializeJson(
74
+ restoreBareRepeaters(tab.doc.document, tab.doc.bareRepeaters ?? null),
75
+ tab.doc.layout ?? null,
76
+ );
67
77
  }
@@ -84,7 +84,7 @@ export function createNestingValidator(elements?: ElementsHints): NestingValidat
84
84
  *
85
85
  * Returned as a plain object because it crosses to the canvas frame with the render message.
86
86
  */
87
- export function formatEditableVerdicts(elements?: ElementsHints): Record<string, boolean> {
87
+ export function formatEditableVerdicts(elements?: ElementsHints) {
88
88
  const verdicts: Record<string, boolean> = {};
89
89
  for (const [tag, rule] of Object.entries(elements?.nesting ?? {})) {
90
90
  // "_root" is the document itself, not an element.
@@ -29,6 +29,10 @@ import {
29
29
  import { convertTargetExtensions, convertTargets } from "./format-choices";
30
30
  import { parseJsonDocument, serializeJson } from "@jxsuite/schema/json-layout";
31
31
  import type { JsonLayout } from "@jxsuite/schema/json-layout";
32
+ import { isString } from "@jxsuite/schema/guards";
33
+ import type { JsonValue, JxMutableNode } from "@jxsuite/schema/types";
34
+ import type { CommandArgValues } from "../commands/command-args";
35
+ import type { FormatFrontmatter } from "./format-host";
32
36
  import type { AnyCommand, CommandRegistry } from "../commands/registry";
33
37
 
34
38
  /** What a conversion will do, resolved in full before the reader is asked to confirm it. */
@@ -72,14 +76,17 @@ function withExtension(path: string, ext: string): string {
72
76
  async function readDocument(
73
77
  path: string,
74
78
  source: string,
75
- ): Promise<{ document: Record<string, unknown>; frontmatter: Record<string, unknown> }> {
79
+ ): Promise<{ document: JxMutableNode; frontmatter: FormatFrontmatter }> {
76
80
  const { formatForPath } = await import("./format-host");
77
81
  if (formatForPath(path)) {
78
82
  const { parseSourceForPath } = await import("../files/file-ops");
79
83
  const parsed = await parseSourceForPath(path, source);
80
84
  return { document: parsed.document, frontmatter: parsed.frontmatter };
81
85
  }
82
- return { document: JSON.parse(source) as Record<string, unknown>, frontmatter: {} };
86
+ /* SAFETY: a path no format claims is a `.json` document in pages/ or components/ (the only files
87
+ `convertTargets` offers a conversion for), and that file's schema requires a top-level object;
88
+ `JSON.parse` without a reviver yields a JSON value, so the object is a Jx document. */
89
+ return { document: JSON.parse(source) as JxMutableNode, frontmatter: {} };
83
90
  }
84
91
 
85
92
  /**
@@ -94,8 +101,8 @@ async function readDocument(
94
101
  */
95
102
  async function writeDocument(
96
103
  targetExt: string,
97
- document: Record<string, unknown>,
98
- frontmatter: Record<string, unknown>,
104
+ document: JxMutableNode,
105
+ frontmatter: FormatFrontmatter,
99
106
  ): Promise<string> {
100
107
  const merged = { ...frontmatter, ...document };
101
108
  if (targetExt === ".json") {
@@ -194,7 +201,9 @@ export async function buildPlan(
194
201
  errors, which is indistinguishable from a valid document. Claiming validity on the strength of
195
202
  a schema that was never compiled is the "never render 0" defect one layer down. */
196
203
  const { validateDocOrNull } = await import("../services/jx-validate");
197
- const errors = await validateDocOrNull(JSON.parse(text));
204
+ /* SAFETY: `text` is what `serializeJson` just wrote, and `JSON.parse` without a reviver yields
205
+ a JSON value. */
206
+ const errors = await validateDocOrNull(JSON.parse(text) as JsonValue);
198
207
  if (errors === null) {
199
208
  lines.push(
200
209
  "The result could not be checked against the document schema — that is not the same as " +
@@ -292,7 +301,9 @@ export async function convertFile(path: string, targetExt?: string): Promise<str
292
301
 
293
302
  let original: string;
294
303
  try {
295
- original = (await platform.readFile(path)) ?? "";
304
+ // The read crosses the PAL's wire, which can answer without a `content` field: read that as empty.
305
+ const read = await platform.readFile(path);
306
+ original = isString(read) ? read : "";
296
307
  } catch (error) {
297
308
  return fail(`Could not read ${path}.`, errorMessage(error));
298
309
  }
@@ -373,8 +384,8 @@ async function rebuildTab(from: string, to: string, text: string): Promise<void>
373
384
  const { formatForPath } = await import("./format-host");
374
385
  renameTab(from, to, to);
375
386
  const format = formatForPath(to);
376
- let document: Record<string, unknown>;
377
- let frontmatter: Record<string, unknown> | undefined;
387
+ let document: JxMutableNode;
388
+ let frontmatter: FormatFrontmatter | undefined;
378
389
  // The layout of the JSON just written, as every other JSON reader records it (`files/files.ts`,
379
390
  // `files/file-ops.ts`): the text is the serializer's own, so the record says what a layout-less
380
391
  // Write would do anyway — but the tab reads its file rather than assuming it.
@@ -392,14 +403,17 @@ async function rebuildTab(from: string, to: string, text: string): Promise<void>
392
403
  // Points at the file, and reopening it is one click.
393
404
  return;
394
405
  }
395
- openTab({
406
+ const options: Parameters<typeof openTab>[0] = {
396
407
  document,
397
408
  documentPath: to,
398
- ...(frontmatter === undefined ? {} : { frontmatter }),
399
409
  id: to,
400
410
  layout,
401
411
  sourceFormat: format?.name ?? null,
402
- });
412
+ };
413
+ if (frontmatter !== undefined) {
414
+ options.frontmatter = frontmatter;
415
+ }
416
+ openTab(options);
403
417
  }
404
418
 
405
419
  const CANNOT_CONVERT =
@@ -499,8 +513,8 @@ export function fileFormatCommands(): AnyCommand[] {
499
513
  undo: "none",
500
514
  /* No `aiTool`, by studio-ui-guidelines.md §12.4's second deletion rule: `run` awaits a
501
515
  confirm dialog the person answers. */
502
- run: async (_ctx, args: Record<string, unknown>) => {
503
- const target = typeof args.format === "string" ? args.format : undefined;
516
+ run: async (_ctx, args: CommandArgValues) => {
517
+ const target = isString(args.format) ? args.format : undefined;
504
518
  await convertFile(
505
519
  stringArg("file.convertFormat", args, "source"),
506
520
  ...(target === undefined ? [] : [target]),
@@ -11,6 +11,7 @@
11
11
  * context menu is built during a render and cannot await anything.
12
12
  */
13
13
 
14
+ import { isString } from "@jxsuite/schema/guards";
14
15
  import { collectionForFile } from "../content/collection-match";
15
16
  import { documentExtensions, formatByExtension, formatForPath, getFormats } from "./format-host";
16
17
  import { projectState } from "../store";
@@ -76,7 +77,7 @@ function declaresDocumentKind(kinds: readonly string[]): boolean {
76
77
  */
77
78
  function isLayoutPath(path: string): boolean {
78
79
  const declared = projectState?.projectConfig?.layout;
79
- if (typeof declared !== "string") {
80
+ if (!isString(declared)) {
80
81
  return false;
81
82
  }
82
83
  return normalize(declared).toLowerCase() === normalize(path).toLowerCase();
@@ -9,8 +9,15 @@
9
9
 
10
10
  import { setProjectSchemasForMonaco } from "../services/monaco-lazy";
11
11
  import { getPlatform } from "../platform";
12
- import type { ExtensionCatalogEntry, ExtensionsInfo } from "../types";
13
- import type { JxMutableNode } from "@jxsuite/schema/types";
12
+ import type {
13
+ ExtensionCatalogEntry,
14
+ ExtensionsInfo,
15
+ FormatActionRequest,
16
+ ProjectSchemasResponse,
17
+ StudioPlatform,
18
+ } from "../types";
19
+ import { isString } from "@jxsuite/schema/guards";
20
+ import type { JxDocumentValue, JxMutableNode } from "@jxsuite/schema/types";
14
21
 
15
22
  export interface StudioFormatHints {
16
23
  icon?: string;
@@ -25,6 +32,10 @@ export interface StudioFormatHints {
25
32
  inline?: string[];
26
33
  void?: string[];
27
34
  textOnly?: string[];
35
+ /**
36
+ * Per-parent child rules. The registry arrives over the wire unvalidated, so a rule may be a
37
+ * JSON `null`, which every reader treats as a tag the format leaves undeclared.
38
+ */
28
39
  nesting?: Record<
29
40
  string,
30
41
  {
@@ -32,10 +43,9 @@ export interface StudioFormatHints {
32
43
  inline?: boolean;
33
44
  directive?: boolean;
34
45
  only?: string[];
35
- }
46
+ } | null
36
47
  >;
37
48
  };
38
- [key: string]: unknown;
39
49
  }
40
50
 
41
51
  export interface StudioFormat {
@@ -57,10 +67,11 @@ export function loadFormats(): Promise<StudioFormat[]> {
57
67
  if (!_loaded) {
58
68
  _loaded = (async () => {
59
69
  try {
60
- const platform = getPlatform() as {
61
- listFormats?: () => Promise<StudioFormat[]>;
62
- };
63
- _formats = (await platform.listFormats?.()) ?? [];
70
+ const platform = getPlatform();
71
+ /* SAFETY: every backend's formats route serializes its format registry as the records this
72
+ Module declares (`StudioFormat`); the PAL types the payload `unknown[]` only because this
73
+ Module, not `types.ts`, owns that shape. */
74
+ _formats = ((await platform.listFormats?.()) as StudioFormat[] | undefined) ?? [];
64
75
  } catch {
65
76
  _formats = [];
66
77
  }
@@ -100,9 +111,7 @@ export function loadExtensions(): Promise<ExtensionsInfo[]> {
100
111
  if (!_extensionsLoaded) {
101
112
  _extensionsLoaded = (async () => {
102
113
  try {
103
- const platform = getPlatform() as {
104
- listExtensions?: () => Promise<ExtensionsInfo[]>;
105
- };
114
+ const platform = getPlatform();
106
115
  _extensions = (await platform.listExtensions?.()) ?? [];
107
116
  } catch {
108
117
  _extensions = [];
@@ -144,9 +153,7 @@ export function loadExtensionCatalog(): Promise<ExtensionCatalogEntry[]> {
144
153
  if (!_catalogLoaded) {
145
154
  _catalogLoaded = (async () => {
146
155
  try {
147
- const platform = getPlatform() as {
148
- listExtensionCatalog?: () => Promise<ExtensionCatalogEntry[]>;
149
- };
156
+ const platform = getPlatform();
150
157
  _catalog = (await platform.listExtensionCatalog?.()) ?? [];
151
158
  } catch {
152
159
  _catalog = [];
@@ -180,10 +187,10 @@ export function setExtensionCatalog(catalog: ExtensionCatalogEntry[]) {
180
187
  * @param {object} platform - The studio platform (only `fetchProjectSchemas` is consulted)
181
188
  * @returns {Promise<void>} Resolves once both consumers have been updated
182
189
  */
183
- async function shareProjectSchemas(platform: {
184
- fetchProjectSchemas?: () => Promise<{ project?: unknown; document?: unknown }>;
185
- }): Promise<void> {
186
- let schemas: { project?: unknown; document?: unknown } | null = null;
190
+ async function shareProjectSchemas(
191
+ platform: Pick<StudioPlatform, "fetchProjectSchemas">,
192
+ ): Promise<void> {
193
+ let schemas: ProjectSchemasResponse | null = null;
187
194
  try {
188
195
  schemas = (await platform.fetchProjectSchemas?.()) ?? null;
189
196
  } catch {
@@ -208,9 +215,7 @@ async function shareProjectSchemas(platform: {
208
215
  *
209
216
  * @param {object} platform - The studio platform (only `fetchProjectSchemas` is consulted here)
210
217
  */
211
- export function refreshExtensionUi(platform: {
212
- fetchProjectSchemas?: () => Promise<{ project?: unknown; document?: unknown }>;
213
- }): void {
218
+ export function refreshExtensionUi(platform: Pick<StudioPlatform, "fetchProjectSchemas">): void {
214
219
  void shareProjectSchemas(platform);
215
220
  // `installed` and `bundled` are per-project facts, so an install or a project switch can move
216
221
  // Them even when the shipped half has not changed.
@@ -279,15 +284,40 @@ export function documentExtensions(kind?: string): string[] {
279
284
  return [...exts];
280
285
  }
281
286
 
287
+ /**
288
+ * The extensions the build routes under `pages/`: `.json`, and every extension a page format claims
289
+ * (`discoverPages` in `@jxsuite/compiler` walks with the same set). Waits for the registry, so a
290
+ * Markdown page is never judged unroutable because the formats had not landed yet.
291
+ */
292
+ export async function routedPageExtensions(): Promise<string[]> {
293
+ await loadFormats();
294
+ return [".json", ...documentExtensions("page")];
295
+ }
296
+
282
297
  /** The default format for new content documents (first content-kind serializer). */
283
298
  export function defaultContentFormat(): StudioFormat | undefined {
284
299
  return _formats.find((f) => f.capabilities.serialize && f.documentKinds.includes("content"));
285
300
  }
286
301
 
287
- async function formatAction(payload: Record<string, unknown>): Promise<unknown> {
288
- const platform = getPlatform() as {
289
- formatAction?: (payload: Record<string, unknown>) => Promise<unknown>;
290
- };
302
+ /** The options a format capability is invoked with. */
303
+ export interface FormatActionOptions {
304
+ /** `"roundtrip"` asks the format to preserve what it can of the source's own spelling. */
305
+ mode?: string;
306
+ /** Whether the serializer writes a frontmatter block. */
307
+ frontmatter?: boolean;
308
+ /**
309
+ * The text the document was read from: a roundtrip serializer keeps the spelling of whatever did
310
+ * not change (`@jxsuite/parser`'s `source` option).
311
+ */
312
+ source?: string;
313
+ }
314
+
315
+ /**
316
+ * Send one request to the format route (POST /__studio/format, or the desktop RPC of the same
317
+ * name). A serialize request carries the caller's document through unchanged.
318
+ */
319
+ async function formatAction(payload: FormatActionRequest): Promise<JxMutableNode | string> {
320
+ const platform = getPlatform();
291
321
  if (!platform.formatAction) {
292
322
  throw new Error("Platform does not support format actions");
293
323
  }
@@ -298,8 +328,11 @@ async function formatAction(payload: Record<string, unknown>): Promise<unknown>
298
328
  export async function formatParse(
299
329
  name: string,
300
330
  source: string,
301
- options?: Record<string, unknown>,
331
+ options?: FormatActionOptions,
302
332
  ): Promise<JxMutableNode> {
333
+ /* SAFETY: a format class's `parse` capability returns the Jx document it built from the source —
334
+ The contract every format class implements (specs/extensions.md) — and nothing here inspects
335
+ It before `splitFormatDocument` reads its keys. */
303
336
  return (await formatAction({
304
337
  action: "parse",
305
338
  format: name,
@@ -308,12 +341,19 @@ export async function formatParse(
308
341
  })) as JxMutableNode;
309
342
  }
310
343
 
311
- /** Serialize a Jx document to source text via the named format's serialize capability. */
344
+ /**
345
+ * Serialize a Jx document to source text via the named format's serialize capability.
346
+ *
347
+ * `doc` is relayed to the format class verbatim: the document merged with its frontmatter, whose
348
+ * open keys are whatever the format's own parser produced.
349
+ */
312
350
  export async function formatSerialize(
313
351
  name: string,
314
- doc: Record<string, unknown>,
315
- options?: Record<string, unknown>,
352
+ doc: JxMutableNode,
353
+ options?: FormatActionOptions,
316
354
  ): Promise<string> {
355
+ /* SAFETY: a format class's `serialize` capability returns the source text it wrote — the contract
356
+ Every format class implements (specs/extensions.md) — so the answer is a string. */
317
357
  return (await formatAction({
318
358
  action: "serialize",
319
359
  doc,
@@ -322,42 +362,47 @@ export async function formatSerialize(
322
362
  })) as string;
323
363
  }
324
364
 
365
+ /** A document's frontmatter: the open keys of a Jx node, as a format's parser left them. */
366
+ export type FormatFrontmatter = Record<string, JxDocumentValue | undefined>;
367
+
368
+ /** What {@link splitFormatDocument} makes of a parsed format document. */
369
+ export interface SplitFormatDocument {
370
+ document: JxMutableNode;
371
+ frontmatter: FormatFrontmatter;
372
+ mode: "component" | "content";
373
+ }
374
+
325
375
  /**
326
376
  * Split a parsed format document into { document, frontmatter, mode } per the format's
327
377
  * `$studio.documentMode` hints. Component documents (e.g. a frontmatter `tagName` with a hyphen)
328
378
  * keep their full shape; content documents separate frontmatter metadata from the body children.
329
379
  */
330
- export function splitFormatDocument(format: StudioFormat | undefined, doc: JxMutableNode) {
380
+ export function splitFormatDocument(
381
+ format: StudioFormat | undefined,
382
+ doc: JxMutableNode,
383
+ ): SplitFormatDocument {
331
384
  const hints = format?.studio?.documentMode;
332
385
  const componentWhen = hints?.componentWhen;
333
386
  if (componentWhen?.frontmatterKey) {
334
387
  const value = doc[componentWhen.frontmatterKey];
335
388
  const pattern = componentWhen.matches ? new RegExp(componentWhen.matches) : /./;
336
- if (typeof value === "string" && pattern.test(value)) {
337
- return {
338
- document: doc,
339
- frontmatter: {} as Record<string, unknown>,
340
- mode: "component",
341
- };
389
+ if (isString(value) && pattern.test(value)) {
390
+ return { document: doc, frontmatter: {}, mode: "component" };
342
391
  }
343
392
  }
344
393
  if (hints?.default === "component") {
345
- return {
346
- document: doc,
347
- frontmatter: {} as Record<string, unknown>,
348
- mode: "component",
349
- };
394
+ return { document: doc, frontmatter: {}, mode: "component" };
350
395
  }
351
396
 
352
397
  // Content document — children form the root-level body; other keys are frontmatter
353
- const children = (doc.children as unknown[]) ?? [];
354
- if (children.length === 0) {
398
+ const children = doc.children ?? [];
399
+ if (Array.isArray(children) && children.length === 0) {
355
400
  children.push({ children: [], tagName: "p" });
356
401
  }
357
402
 
358
403
  const documentKeys = new Set(["state", "imports"]);
359
- const contentDoc: Record<string, unknown> = { children };
360
- const frontmatter: Record<string, unknown> = {};
404
+ const contentDoc: JxMutableNode = { children };
405
+ const frontmatter: FormatFrontmatter = {};
361
406
  for (const [key, value] of Object.entries(doc)) {
362
407
  if (key === "children") {
363
408
  continue;
@@ -369,9 +414,5 @@ export function splitFormatDocument(format: StudioFormat | undefined, doc: JxMut
369
414
  }
370
415
  }
371
416
 
372
- return {
373
- document: contentDoc as JxMutableNode,
374
- frontmatter,
375
- mode: "content",
376
- };
417
+ return { document: contentDoc, frontmatter, mode: "content" };
377
418
  }
@@ -18,6 +18,14 @@
18
18
 
19
19
  const STORAGE_KEY = "jx_github_token";
20
20
 
21
+ /**
22
+ * The GitHub OAuth app every Jx sign-in authorizes against: the browser's device flow in
23
+ * `github-auth.ts`, and the desktop launcher's RFC 8252 loopback redirect
24
+ * (`packages/desktop/src/github-signin.ts`). Here, in the module with no UI dependency, because the
25
+ * launcher's main process imports it too.
26
+ */
27
+ export const GITHUB_OAUTH_CLIENT_ID = "Ov23liYVlMFpgjOEPXJH";
28
+
21
29
  /**
22
30
  * The desktop launcher's RFC 8252 sign-in, when this build is running inside one.
23
31
  *
@@ -30,13 +38,29 @@ export interface NativeGithubAuth {
30
38
  status: () => Promise<{ stored: boolean }>;
31
39
  }
32
40
 
33
- export function nativeAuth(): NativeGithubAuth | null {
41
+ /**
42
+ * Whether the registered platform object carries a launcher's `githubAuth` member.
43
+ *
44
+ * Presence is the whole test, as it always was: the member is written only by a launcher's adapter
45
+ * (`packages/desktop/src/platform.ts`), which installs a {@link NativeGithubAuth}, and a browser
46
+ * build has no member at all.
47
+ */
48
+ function carriesNativeAuth(platform: unknown): platform is { githubAuth: NativeGithubAuth } {
34
49
  return (
35
- (globalThis as unknown as { __jxPlatform?: { githubAuth?: NativeGithubAuth } }).__jxPlatform
36
- ?.githubAuth ?? null
50
+ typeof platform === "object" &&
51
+ platform !== null &&
52
+ "githubAuth" in platform &&
53
+ platform.githubAuth != null
37
54
  );
38
55
  }
39
56
 
57
+ export function nativeAuth(): NativeGithubAuth | null {
58
+ // `globalThis` as a plain object: its declared type knows nothing of the launcher's slot.
59
+ const host: object = globalThis;
60
+ const platform = "__jxPlatform" in host ? host.__jxPlatform : undefined;
61
+ return carriesNativeAuth(platform) ? platform.githubAuth : null;
62
+ }
63
+
40
64
  /**
41
65
  * The token the desktop store handed us this session.
42
66
  *