@jxsuite/studio 6.1.0 → 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 (645) hide show
  1. package/dist/chunks/2020-f2gkpy8d.js +4 -0
  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-gybvv7a6.js → index-zpjmzqfk.js} +3 -3
  32. package/dist/chunks/{javascript-rnvdp3k4.js → javascript-m54mnwp6.js} +3 -3
  33. package/dist/chunks/jsonMode-w15cmrcm.js +13 -0
  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-5g0ag7c0.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-pxg4ap1e.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-qbj760tx.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-anyrgzvb.js → studio-90pq9km1.js} +4 -4
  77. package/dist/chunks/studio-924p1tm1.js +6 -0
  78. package/dist/chunks/{studio-v2bvmbjj.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-txjjzrsm.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-0x3jyb8r.js → studio-tq0rtfwj.js} +4 -4
  111. package/dist/chunks/{studio-cpxkgjrj.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-y64hrt8p.js +12 -0
  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-sf49ee9x.js +14 -0
  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 +98 -98
  140. package/dist/workers/ts.worker.js +3 -3
  141. package/package.json +11 -11
  142. package/src/about/about-modal.ts +4 -3
  143. package/src/account/action-flow.ts +45 -38
  144. package/src/account-status.ts +7 -2
  145. package/src/browse/library-layouts.ts +8 -5
  146. package/src/browse/library-model.ts +18 -6
  147. package/src/browse/library-pane.ts +37 -21
  148. package/src/browse/library-preview.ts +14 -9
  149. package/src/browse/library-source.ts +1 -1
  150. package/src/canvas/asset-refs.ts +24 -9
  151. package/src/canvas/asset-resolve.ts +19 -23
  152. package/src/canvas/canvas-helpers.ts +7 -6
  153. package/src/canvas/canvas-live-render.ts +44 -53
  154. package/src/canvas/canvas-patcher.ts +30 -30
  155. package/src/canvas/canvas-perf.ts +11 -5
  156. package/src/canvas/canvas-render.ts +66 -42
  157. package/src/canvas/canvas-surface.ts +5 -3
  158. package/src/canvas/canvas-utils.ts +163 -64
  159. package/src/canvas/dialog-path.ts +9 -4
  160. package/src/canvas/dialog-state.ts +1 -2
  161. package/src/canvas/diff-marks.ts +9 -16
  162. package/src/canvas/diff-toolbar.ts +8 -7
  163. package/src/canvas/edit-width-drag.ts +4 -1
  164. package/src/canvas/edit-width.ts +1 -3
  165. package/src/canvas/iframe-channel.ts +27 -13
  166. package/src/canvas/iframe-drop.ts +13 -12
  167. package/src/canvas/iframe-editable-root.ts +29 -16
  168. package/src/canvas/iframe-entry.ts +80 -63
  169. package/src/canvas/iframe-eval.ts +73 -49
  170. package/src/canvas/iframe-host.ts +203 -118
  171. package/src/canvas/iframe-inline-edit.ts +69 -32
  172. package/src/canvas/iframe-insert.ts +5 -4
  173. package/src/canvas/iframe-interaction.ts +37 -26
  174. package/src/canvas/iframe-overlay.ts +1 -1
  175. package/src/canvas/iframe-patch.ts +18 -15
  176. package/src/canvas/iframe-position.ts +12 -6
  177. package/src/canvas/iframe-protocol.ts +15 -16
  178. package/src/canvas/iframe-render.ts +41 -36
  179. package/src/canvas/iframe-slash.ts +24 -11
  180. package/src/canvas/iframe-subtree.ts +6 -2
  181. package/src/canvas/path-mapping.ts +19 -12
  182. package/src/canvas/popover-path.ts +7 -3
  183. package/src/canvas/popover-state.ts +1 -2
  184. package/src/canvas/serialize-scope.ts +13 -5
  185. package/src/canvas/stage-scrollbar.ts +2 -1
  186. package/src/canvas/surface-registry.ts +21 -3
  187. package/src/collab/collab-commands.ts +7 -2
  188. package/src/collab/collab-session.ts +84 -45
  189. package/src/collab/collab-state.ts +4 -3
  190. package/src/collab/monaco-binding.ts +16 -13
  191. package/src/collab/monaco-cursors.ts +5 -2
  192. package/src/commands/budget.ts +3 -3
  193. package/src/commands/command-args.ts +103 -71
  194. package/src/commands/context.ts +22 -20
  195. package/src/commands/defaults.ts +4 -1
  196. package/src/commands/keymap.ts +47 -43
  197. package/src/commands/levels.ts +3 -3
  198. package/src/commands/live-context.ts +10 -8
  199. package/src/commands/reference.ts +2 -1
  200. package/src/commands/registry.ts +12 -10
  201. package/src/commands/run-reported.ts +15 -10
  202. package/src/component-props.ts +46 -30
  203. package/src/content/collection-match.ts +5 -4
  204. package/src/content/draft-state.ts +4 -3
  205. package/src/content/entry-commands.ts +3 -2
  206. package/src/content/entry-editor.ts +29 -17
  207. package/src/content/entry-fields.ts +12 -7
  208. package/src/content/entry-model.ts +21 -12
  209. package/src/editor/canvas-context-menu.ts +1 -2
  210. package/src/editor/canvas-slash-bridge.ts +3 -6
  211. package/src/editor/content-slice.ts +16 -14
  212. package/src/editor/context-menu.ts +35 -22
  213. package/src/editor/convert-targets.ts +30 -35
  214. package/src/editor/convert-to-component.ts +11 -5
  215. package/src/editor/convert-to-repeater.ts +34 -22
  216. package/src/editor/editable-tags.ts +17 -2
  217. package/src/editor/file-drop-action.ts +21 -22
  218. package/src/editor/inline-edit-apply.ts +35 -17
  219. package/src/editor/inline-edit.ts +66 -50
  220. package/src/editor/inline-format.ts +59 -56
  221. package/src/editor/inline-link.ts +40 -15
  222. package/src/editor/insert-zone-action.ts +1 -1
  223. package/src/editor/merge-tags.ts +58 -19
  224. package/src/editor/repeater-scope.ts +39 -28
  225. package/src/editor/shortcuts.ts +87 -47
  226. package/src/editor/slash-menu.ts +1 -6
  227. package/src/files/asset-versions.ts +4 -4
  228. package/src/files/components.ts +15 -10
  229. package/src/files/elements.ts +5 -6
  230. package/src/files/file-ops.ts +77 -36
  231. package/src/files/files.ts +90 -95
  232. package/src/files/media-meta.ts +2 -1
  233. package/src/files/media-paths.ts +6 -1
  234. package/src/files/serialize-document.ts +2 -2
  235. package/src/format/constraints.ts +1 -1
  236. package/src/format/convert-file.ts +27 -13
  237. package/src/format/format-choices.ts +2 -1
  238. package/src/format/format-host.ts +76 -50
  239. package/src/github/github-auth-status.ts +27 -3
  240. package/src/github/github-auth.ts +19 -9
  241. package/src/github/github-publish.ts +24 -20
  242. package/src/grid/cell-editors.ts +46 -31
  243. package/src/grid/cell-popovers.ts +5 -3
  244. package/src/grid/edit-buffer.ts +10 -9
  245. package/src/grid/grid-controller.ts +20 -22
  246. package/src/grid/grid-layout.ts +21 -5
  247. package/src/grid/grid-open.ts +3 -6
  248. package/src/grid/grid-panel.ts +11 -4
  249. package/src/grid/grid-source.ts +8 -8
  250. package/src/grid/grid-view.ts +14 -17
  251. package/src/grid/redirects-grid.ts +14 -5
  252. package/src/grid/redirects.ts +16 -14
  253. package/src/grid/schema-columns.ts +25 -19
  254. package/src/grid/sources/connector-source.ts +47 -20
  255. package/src/grid/sources/content-source.ts +25 -24
  256. package/src/grid/sources/csv-file-source.ts +2 -2
  257. package/src/grid/tabulator-tables.d.ts +55 -34
  258. package/src/hosting/stage.ts +7 -7
  259. package/src/i18n/i18n-commands.ts +1 -2
  260. package/src/media/media-pane.ts +4 -1
  261. package/src/new-project/add-repo-modal.ts +20 -19
  262. package/src/new-project/import-tab.ts +10 -14
  263. package/src/new-project/location-fields.ts +2 -1
  264. package/src/new-project/new-project-modal.ts +12 -9
  265. package/src/packages/jxsuite-update.ts +4 -3
  266. package/src/packages/pull-package-sync.ts +26 -25
  267. package/src/page-params.ts +97 -68
  268. package/src/panels/activity-panel.ts +17 -9
  269. package/src/panels/ai-chat/attached-context.ts +13 -7
  270. package/src/panels/ai-chat/chat-view.ts +80 -73
  271. package/src/panels/ai-chat/composer.ts +30 -33
  272. package/src/panels/ai-chat/sessions-view.ts +1 -2
  273. package/src/panels/ai-panel.ts +23 -20
  274. package/src/panels/block-action-bar.ts +46 -35
  275. package/src/panels/bottom-dock.ts +5 -3
  276. package/src/panels/canvas-dnd-bridge.ts +31 -24
  277. package/src/panels/data-explorer.ts +62 -25
  278. package/src/panels/data-grid.ts +14 -11
  279. package/src/panels/dnd.ts +108 -118
  280. package/src/panels/editors.ts +55 -22
  281. package/src/panels/elements-panel.ts +10 -3
  282. package/src/panels/events-panel.ts +84 -69
  283. package/src/panels/formula-workspace.ts +76 -51
  284. package/src/panels/frontmatter-fields.ts +24 -19
  285. package/src/panels/frontmatter-panel.ts +44 -34
  286. package/src/panels/git-diff-open.ts +4 -4
  287. package/src/panels/git-panel.ts +49 -61
  288. package/src/panels/head-panel.ts +131 -111
  289. package/src/panels/i18n-panel.ts +10 -3
  290. package/src/panels/imports-panel.ts +23 -47
  291. package/src/panels/jump-bar.ts +48 -29
  292. package/src/panels/layers-panel.ts +97 -74
  293. package/src/panels/left-panel.ts +3 -3
  294. package/src/panels/pane-context.ts +31 -22
  295. package/src/panels/pane-grid.ts +49 -20
  296. package/src/panels/panel-registry.ts +22 -37
  297. package/src/panels/properties-panel.ts +175 -121
  298. package/src/panels/quick-search.ts +53 -31
  299. package/src/panels/right-panel.ts +3 -3
  300. package/src/panels/seo-modal.ts +13 -17
  301. package/src/panels/settings-menu.ts +15 -15
  302. package/src/panels/signals-panel.ts +153 -131
  303. package/src/panels/statement-editor.ts +230 -140
  304. package/src/panels/style-panel.ts +254 -216
  305. package/src/panels/style-utils.ts +114 -51
  306. package/src/panels/stylebook-doc.ts +57 -54
  307. package/src/panels/stylebook-layers-panel.ts +9 -9
  308. package/src/panels/stylebook-panel.ts +13 -17
  309. package/src/panels/tab-drop.ts +27 -11
  310. package/src/panels/tab-strip.ts +36 -26
  311. package/src/platform-errors.ts +57 -43
  312. package/src/platform.ts +58 -30
  313. package/src/platforms/cloud.ts +345 -175
  314. package/src/platforms/default-platform.ts +10 -4
  315. package/src/platforms/devserver.ts +174 -127
  316. package/src/platforms/read-batcher.ts +16 -8
  317. package/src/project-list.ts +2 -1
  318. package/src/publish/deploy-checklist.ts +8 -2
  319. package/src/publish/pages-service.ts +28 -13
  320. package/src/publish/publish-commands.ts +5 -4
  321. package/src/publish/publish-panel.ts +10 -6
  322. package/src/recent-projects.ts +15 -8
  323. package/src/resize-edges.ts +26 -36
  324. package/src/services/a11y-report.ts +26 -19
  325. package/src/services/agent-seed.ts +23 -11
  326. package/src/services/ai-ask.ts +9 -12
  327. package/src/services/ai-command-tools.ts +68 -62
  328. package/src/services/ai-import-tools.ts +80 -67
  329. package/src/services/ai-models.ts +17 -13
  330. package/src/services/ai-project-tools.ts +68 -32
  331. package/src/services/ai-session-store.ts +19 -10
  332. package/src/services/ai-system-prompt.ts +46 -20
  333. package/src/services/ai-tools.ts +71 -27
  334. package/src/services/ai-write-report.ts +20 -12
  335. package/src/services/ai-writes.ts +4 -4
  336. package/src/services/automation.ts +58 -31
  337. package/src/services/cem-export.ts +149 -58
  338. package/src/services/clock.ts +6 -1
  339. package/src/services/code-services.ts +37 -31
  340. package/src/services/context-manager.ts +14 -10
  341. package/src/services/context-resolver.ts +20 -8
  342. package/src/services/data-service.ts +19 -15
  343. package/src/services/directory-picker.ts +18 -12
  344. package/src/services/document-assistant.ts +39 -19
  345. package/src/services/gated-registry.ts +10 -6
  346. package/src/services/harness/chat-reducer.ts +23 -1
  347. package/src/services/import-client.ts +91 -38
  348. package/src/services/import-seed.ts +8 -2
  349. package/src/services/jx-validate.ts +28 -31
  350. package/src/services/live-preview.ts +0 -0
  351. package/src/services/live-surfaces.ts +6 -3
  352. package/src/services/model-uri.ts +10 -2
  353. package/src/services/module-preloads.ts +12 -8
  354. package/src/services/monaco-buffer.ts +43 -24
  355. package/src/services/monaco-lazy.ts +7 -8
  356. package/src/services/monaco-setup.ts +23 -16
  357. package/src/services/notify.ts +44 -17
  358. package/src/services/popover-report.ts +25 -10
  359. package/src/services/preview-eval.ts +20 -8
  360. package/src/services/profile.ts +13 -6
  361. package/src/services/project-path.ts +13 -10
  362. package/src/services/references.ts +0 -0
  363. package/src/services/render-critic.ts +8 -7
  364. package/src/services/settings/kernel.ts +13 -4
  365. package/src/services/settings/write-queue.ts +9 -9
  366. package/src/services/token-lint.ts +12 -10
  367. package/src/services/tool-executor.ts +17 -5
  368. package/src/services/tool-outcomes.ts +44 -24
  369. package/src/services/trusted-types.ts +24 -7
  370. package/src/settings/contexts-section.ts +11 -8
  371. package/src/settings/contributed-section.ts +79 -60
  372. package/src/settings/css-vars-editor.ts +37 -16
  373. package/src/settings/defs-editor.ts +38 -35
  374. package/src/settings/extension-rows.ts +16 -8
  375. package/src/settings/extension-sections.ts +23 -13
  376. package/src/settings/extensions-section.ts +4 -1
  377. package/src/settings/general-settings.ts +11 -8
  378. package/src/settings/locales-section.ts +20 -12
  379. package/src/settings/preferences-dialog.ts +9 -6
  380. package/src/settings/preferences-keymap.ts +7 -5
  381. package/src/settings/preferences-sections.ts +11 -5
  382. package/src/settings/project-sections.ts +1 -1
  383. package/src/settings/schema-field-ui.ts +9 -0
  384. package/src/settings/settings-document.ts +5 -5
  385. package/src/shell/tree.ts +6 -5
  386. package/src/shell.ts +104 -81
  387. package/src/site-context.ts +37 -22
  388. package/src/state.ts +41 -49
  389. package/src/store.ts +54 -34
  390. package/src/studio.ts +39 -77
  391. package/src/style/live-preview.ts +1 -1
  392. package/src/style/project-styles.ts +6 -7
  393. package/src/style/token-ref.ts +5 -4
  394. package/src/surfaces/about.ts +18 -19
  395. package/src/surfaces/add-repo.ts +17 -19
  396. package/src/surfaces/ai-chat.ts +31 -36
  397. package/src/surfaces/ai-credentials-form.ts +6 -16
  398. package/src/surfaces/ai-managed-connect.ts +3 -4
  399. package/src/surfaces/ai-model-picker.ts +3 -5
  400. package/src/surfaces/block-action-bar.ts +22 -11
  401. package/src/surfaces/boot-failure.ts +4 -5
  402. package/src/surfaces/bottom-dock.ts +9 -18
  403. package/src/surfaces/canvas-stage.ts +12 -11
  404. package/src/surfaces/cf-account-picker.ts +17 -18
  405. package/src/surfaces/commandbar.ts +14 -9
  406. package/src/surfaces/convert-repeater.ts +17 -19
  407. package/src/surfaces/data-actions.ts +9 -7
  408. package/src/surfaces/dialog.ts +26 -28
  409. package/src/surfaces/diff-toolbar.ts +9 -7
  410. package/src/surfaces/doc-header.ts +10 -19
  411. package/src/surfaces/empty-state.ts +7 -10
  412. package/src/surfaces/entry-editor.ts +14 -11
  413. package/src/surfaces/expression-editor.ts +11 -25
  414. package/src/surfaces/files-panel.ts +27 -14
  415. package/src/surfaces/formula-palette.ts +4 -5
  416. package/src/surfaces/git-panel.ts +7 -15
  417. package/src/surfaces/github-auth.ts +16 -20
  418. package/src/surfaces/github-publish.ts +17 -22
  419. package/src/surfaces/grid-cell.ts +30 -31
  420. package/src/surfaces/grid-open.ts +10 -14
  421. package/src/surfaces/grid-panel.ts +13 -9
  422. package/src/surfaces/grid-replace.ts +13 -13
  423. package/src/surfaces/grid-views.ts +15 -18
  424. package/src/surfaces/inspector-dock.ts +13 -12
  425. package/src/surfaces/jump-bar.ts +5 -6
  426. package/src/surfaces/jxsuite-update.ts +16 -22
  427. package/src/surfaces/library-pane.ts +25 -20
  428. package/src/surfaces/logic-panel.ts +17 -30
  429. package/src/surfaces/logic-workspace.ts +13 -15
  430. package/src/surfaces/media-browser.ts +11 -10
  431. package/src/surfaces/media-field.ts +4 -5
  432. package/src/surfaces/media-pane.ts +8 -7
  433. package/src/surfaces/menu.ts +29 -23
  434. package/src/surfaces/navigator-dock.ts +11 -12
  435. package/src/surfaces/new-project.ts +27 -26
  436. package/src/surfaces/pane-context.ts +20 -25
  437. package/src/surfaces/pane-grid.ts +15 -10
  438. package/src/surfaces/panel-activity.ts +5 -6
  439. package/src/surfaces/panel-data.ts +3 -4
  440. package/src/surfaces/panel-deploy-checklist.ts +5 -6
  441. package/src/surfaces/panel-elements.ts +5 -7
  442. package/src/surfaces/panel-i18n.ts +5 -7
  443. package/src/surfaces/panel-imports.ts +6 -13
  444. package/src/surfaces/panel-outline.ts +25 -19
  445. package/src/surfaces/panel-page.ts +11 -18
  446. package/src/surfaces/panel-problems.ts +5 -7
  447. package/src/surfaces/panel-signals.ts +20 -34
  448. package/src/surfaces/panel-stylebook-layers.ts +5 -8
  449. package/src/surfaces/preferences.ts +21 -11
  450. package/src/surfaces/progress-modal.ts +15 -9
  451. package/src/surfaces/properties-panel.json +1 -1
  452. package/src/surfaces/properties-panel.ts +20 -42
  453. package/src/surfaces/publish.ts +18 -18
  454. package/src/surfaces/push-plan.ts +7 -8
  455. package/src/surfaces/rail.json +126 -73
  456. package/src/surfaces/rail.ts +38 -12
  457. package/src/surfaces/reference-field.ts +11 -15
  458. package/src/surfaces/schema-builder.ts +16 -22
  459. package/src/surfaces/schema-form.ts +15 -25
  460. package/src/surfaces/secret-field.ts +9 -6
  461. package/src/surfaces/seo.ts +21 -15
  462. package/src/surfaces/settings-contexts.ts +9 -7
  463. package/src/surfaces/settings-contributed.ts +14 -10
  464. package/src/surfaces/settings-css-vars.ts +5 -12
  465. package/src/surfaces/settings-defs.json +2 -2
  466. package/src/surfaces/settings-defs.ts +17 -21
  467. package/src/surfaces/settings-deploy.ts +8 -15
  468. package/src/surfaces/settings-extensions.ts +5 -6
  469. package/src/surfaces/settings-head.ts +33 -39
  470. package/src/surfaces/settings-locales.ts +8 -20
  471. package/src/surfaces/settings-overview.ts +5 -6
  472. package/src/surfaces/settings-packages.ts +8 -7
  473. package/src/surfaces/settings-pane.ts +9 -18
  474. package/src/surfaces/settings-rawjson.ts +5 -6
  475. package/src/surfaces/shell.ts +1 -2
  476. package/src/surfaces/slash-menu.ts +19 -9
  477. package/src/surfaces/statements.ts +13 -18
  478. package/src/surfaces/statusbar.ts +17 -14
  479. package/src/surfaces/style-panel.ts +18 -31
  480. package/src/surfaces/stylebook-chrome.ts +3 -5
  481. package/src/surfaces/tab-strip.ts +14 -13
  482. package/src/surfaces/target-line.ts +6 -7
  483. package/src/surfaces/welcome.ts +5 -7
  484. package/src/tabs/patch-ops.ts +4 -3
  485. package/src/tabs/project-config.ts +32 -21
  486. package/src/tabs/selection.ts +36 -8
  487. package/src/tabs/tab.ts +52 -41
  488. package/src/tabs/transact.ts +98 -53
  489. package/src/tabs/typing.ts +31 -0
  490. package/src/types.ts +32 -17
  491. package/src/ui/ai-credentials-form.ts +10 -13
  492. package/src/ui/ai-model-picker.ts +3 -3
  493. package/src/ui/cf-account-picker.ts +7 -9
  494. package/src/ui/color-selector.ts +9 -5
  495. package/src/ui/dynamic-slot.ts +7 -8
  496. package/src/ui/expression-editor.ts +112 -105
  497. package/src/ui/form-controls.ts +57 -48
  498. package/src/ui/formula-catalog.ts +239 -230
  499. package/src/ui/formula-chips.ts +33 -18
  500. package/src/ui/layers.ts +44 -31
  501. package/src/ui/media-picker.ts +18 -9
  502. package/src/ui/popover-surface.ts +20 -12
  503. package/src/ui/progress-modal.ts +13 -8
  504. package/src/ui/regions.ts +7 -6
  505. package/src/ui/schema-form.ts +113 -70
  506. package/src/ui/surface.ts +71 -8
  507. package/src/ui/timing.ts +9 -0
  508. package/src/ui/value-source.ts +44 -31
  509. package/src/ui/virtual-window.ts +3 -2
  510. package/src/utils/base64.ts +3 -1
  511. package/src/utils/edit-display.ts +103 -74
  512. package/src/utils/element-selectors.ts +3 -2
  513. package/src/utils/google-fonts.ts +15 -14
  514. package/src/utils/inherited-style.ts +18 -20
  515. package/src/utils/link-target.ts +1 -1
  516. package/src/utils/preview-format.ts +25 -3
  517. package/src/utils/strip-events.ts +49 -22
  518. package/src/utils/studio-utils.ts +29 -14
  519. package/src/view.ts +2 -3
  520. package/src/workspace/pane-derive.ts +10 -12
  521. package/src/workspace/session.ts +53 -43
  522. package/src/workspace/workspace.ts +47 -36
  523. package/dist/chunks/2020-nkxms0ay.js +0 -4
  524. package/dist/chunks/adapter-m948ab5f.js +0 -4
  525. package/dist/chunks/cf-account-picker-n8hr38v7.js +0 -4
  526. package/dist/chunks/cf-settings-356xdtne.js +0 -4
  527. package/dist/chunks/color-area-jqhna8zy.js +0 -4
  528. package/dist/chunks/color-field-embq5ctg.js +0 -4
  529. package/dist/chunks/color-fpezvnkt.js +0 -4
  530. package/dist/chunks/color-slider-1qmw7wqy.js +0 -4
  531. package/dist/chunks/combobox-773hdzyj.js +0 -4
  532. package/dist/chunks/components-yk3t844e.js +0 -4
  533. package/dist/chunks/content-source-bawmyc09.js +0 -4
  534. package/dist/chunks/convert-to-repeater-7wns8kf1.js +0 -4
  535. package/dist/chunks/dialog-mtm9fq5t.js +0 -4
  536. package/dist/chunks/editor-6sc8nacq.js +0 -4
  537. package/dist/chunks/entry-commands-8ay9fh81.js +0 -4
  538. package/dist/chunks/extension-sections-na7rj3nr.js +0 -4
  539. package/dist/chunks/file-ops-gye0qw56.js +0 -4
  540. package/dist/chunks/files-dmc2xvcq.js +0 -4
  541. package/dist/chunks/format-host-t76b53f8.js +0 -4
  542. package/dist/chunks/fs-events-cg4tpz06.js +0 -4
  543. package/dist/chunks/git-panel-yef7bshy.js +0 -4
  544. package/dist/chunks/grid-view-7tt4bxw1.js +0 -51
  545. package/dist/chunks/icons-qbh8akb1.js +0 -4
  546. package/dist/chunks/iframe-entry-f7mqjwpm.js +0 -5
  547. package/dist/chunks/iframe-entry-haw7jkvz.js +0 -5
  548. package/dist/chunks/iframe-entry-z6qrytv3.js +0 -5
  549. package/dist/chunks/iframe-host-tmz30gfp.js +0 -4
  550. package/dist/chunks/index-nag78a9h.js +0 -4
  551. package/dist/chunks/jsonMode-zhwsprqk.js +0 -13
  552. package/dist/chunks/jx-validate-3gbp5nkn.js +0 -4
  553. package/dist/chunks/layers-fvz99859.js +0 -4
  554. package/dist/chunks/layers-panel-gchmbf9p.js +0 -4
  555. package/dist/chunks/listbox-s8fkmnq8.js +0 -4
  556. package/dist/chunks/lit-html-9agdspkt.js +0 -4
  557. package/dist/chunks/media-picker-rhjvyy00.js +0 -4
  558. package/dist/chunks/menu-2e4y9j7b.js +0 -4
  559. package/dist/chunks/menu-37d07z9m.js +0 -4
  560. package/dist/chunks/monaco-binding-2jnhjjvr.js +0 -4
  561. package/dist/chunks/monaco-buffer-rp21359g.js +0 -4
  562. package/dist/chunks/monaco-setup-vhh7gayr.js +0 -4
  563. package/dist/chunks/notify-h3www560.js +0 -4
  564. package/dist/chunks/number-field-gw7sq8rn.js +0 -4
  565. package/dist/chunks/parse-897fvqah.js +0 -4
  566. package/dist/chunks/platform-hz34wcd7.js +0 -4
  567. package/dist/chunks/popover-8htra4er.js +0 -4
  568. package/dist/chunks/publish-panel-exsmjzyj.js +0 -4
  569. package/dist/chunks/quick-search-pgaqeh0m.js +0 -4
  570. package/dist/chunks/references-2cgdxnb8.js +0 -4
  571. package/dist/chunks/right-panel-jf856w5w.js +0 -4
  572. package/dist/chunks/section-registry-jnf8r5gy.js +0 -4
  573. package/dist/chunks/select-n3v7gwas.js +0 -4
  574. package/dist/chunks/split-pff8f3ze.js +0 -4
  575. package/dist/chunks/studio-0f55h9ye.js +0 -5
  576. package/dist/chunks/studio-0sqdhnew.js +0 -12
  577. package/dist/chunks/studio-19x1c75w.js +0 -5
  578. package/dist/chunks/studio-2sqcndak.js +0 -5
  579. package/dist/chunks/studio-3aey7dd3.js +0 -5
  580. package/dist/chunks/studio-3bpdkq2s.js +0 -5
  581. package/dist/chunks/studio-47y6fbpf.js +0 -5
  582. package/dist/chunks/studio-4m3826v2.js +0 -5
  583. package/dist/chunks/studio-4nx2dj1g.js +0 -4
  584. package/dist/chunks/studio-4xv5s47r.js +0 -9
  585. package/dist/chunks/studio-5g4t8v6w.js +0 -5
  586. package/dist/chunks/studio-5py436sf.js +0 -5
  587. package/dist/chunks/studio-77kt594t.js +0 -5
  588. package/dist/chunks/studio-8f87n763.js +0 -10
  589. package/dist/chunks/studio-8mb00b84.js +0 -5
  590. package/dist/chunks/studio-8p51gq2h.js +0 -6
  591. package/dist/chunks/studio-954ds834.js +0 -5
  592. package/dist/chunks/studio-9ft45c83.js +0 -9
  593. package/dist/chunks/studio-a2138x5k.js +0 -7
  594. package/dist/chunks/studio-a9yzstqj.js +0 -5
  595. package/dist/chunks/studio-acdksxx6.js +0 -5
  596. package/dist/chunks/studio-ar8jcf2y.js +0 -5
  597. package/dist/chunks/studio-bmn4mn9j.js +0 -7
  598. package/dist/chunks/studio-e7xxa0sj.js +0 -5
  599. package/dist/chunks/studio-ecaz25vk.js +0 -5
  600. package/dist/chunks/studio-ery42sqr.js +0 -4
  601. package/dist/chunks/studio-fzdywr6p.js +0 -9
  602. package/dist/chunks/studio-g5fmf0c1.js +0 -5
  603. package/dist/chunks/studio-g7nse7zb.js +0 -5
  604. package/dist/chunks/studio-geq1ea6k.js +0 -14
  605. package/dist/chunks/studio-ghkb32r8.js +0 -5
  606. package/dist/chunks/studio-ghrhy2y7.js +0 -5
  607. package/dist/chunks/studio-grawhey1.js +0 -5
  608. package/dist/chunks/studio-h0xgswew.js +0 -5
  609. package/dist/chunks/studio-h9c4p2tx.js +0 -5
  610. package/dist/chunks/studio-jyzj5cxs.js +0 -5
  611. package/dist/chunks/studio-mgx8yhnz.js +0 -64
  612. package/dist/chunks/studio-mpb04y1d.js +0 -6
  613. package/dist/chunks/studio-n17mty64.js +0 -5
  614. package/dist/chunks/studio-nwh2eqsk.js +0 -6
  615. package/dist/chunks/studio-q1h883bt.js +0 -16
  616. package/dist/chunks/studio-q4tv82h7.js +0 -9
  617. package/dist/chunks/studio-qpqa7vk3.js +0 -5
  618. package/dist/chunks/studio-qqz8e5gk.js +0 -5
  619. package/dist/chunks/studio-qvasen3f.js +0 -5
  620. package/dist/chunks/studio-rggdb3hm.js +0 -5
  621. package/dist/chunks/studio-sghy936h.js +0 -4
  622. package/dist/chunks/studio-skprc6ef.js +0 -5
  623. package/dist/chunks/studio-tt2nactf.js +0 -5
  624. package/dist/chunks/studio-tyasmc39.js +0 -5
  625. package/dist/chunks/studio-vk9ezads.js +0 -5
  626. package/dist/chunks/studio-vzacdfsc.js +0 -4
  627. package/dist/chunks/studio-w4c0xmrw.js +0 -5
  628. package/dist/chunks/studio-wfjqhhbk.js +0 -5
  629. package/dist/chunks/studio-wgh5kxpj.js +0 -5
  630. package/dist/chunks/studio-xasj0796.js +0 -5
  631. package/dist/chunks/studio-y78s8r2n.js +0 -5
  632. package/dist/chunks/studio-z8w183sh.js +0 -5
  633. package/dist/chunks/studio-zscd9ty4.js +0 -928
  634. package/dist/chunks/studio-zxp13sss.js +0 -7
  635. package/dist/chunks/studio-zygnmm01.js +0 -5
  636. package/dist/chunks/swatch-group-8qh9a3bm.js +0 -4
  637. package/dist/chunks/tabs-jwthg40w.js +0 -4
  638. package/dist/chunks/textfield-spy3hc77.js +0 -4
  639. package/dist/chunks/toast-4d35zd64.js +0 -4
  640. package/dist/chunks/toast-host-8sjmfed3.js +0 -4
  641. package/dist/chunks/tooltip-fd6g9xy3.js +0 -4
  642. package/dist/chunks/tree-h19v1jfz.js +0 -4
  643. package/dist/chunks/tsMode-gr0m4dzr.js +0 -14
  644. package/dist/chunks/workspace-m15qtcqp.js +0 -4
  645. package/dist/chunks/ws-client-nf61frr1.js +0 -4
@@ -39,9 +39,13 @@ import type { TransactionRecord } from "../tabs/patch-ops";
39
39
  import type { Tab } from "../tabs/tab";
40
40
  import type { JxDocOp } from "@jxsuite/schema/doc-ops";
41
41
  import type { CollabHandle } from "@jxsuite/collab/provider";
42
- import type { JxMutableNode } from "@jxsuite/schema/types";
42
+ import type { JxDocumentValue, JxMutableNode, JxPath } from "@jxsuite/schema/types";
43
43
  import type * as CollabNS from "@jxsuite/collab";
44
+ import type { CollabAwarenessState } from "@jxsuite/collab/awareness-types";
45
+ import type { DocumentRecord } from "@jxsuite/collab/schema";
46
+ import type * as Y from "yjs";
44
47
  import { collabState, registerCollabPath, unregisterCollabPath } from "./collab-state";
48
+ import type { PeerPresence } from "./collab-state";
45
49
  import { notify } from "../services/notify";
46
50
 
47
51
  type CollabModule = typeof CollabNS;
@@ -89,7 +93,7 @@ export function configureCollabSerializer(fn: ((tab: Tab) => Promise<string>) |
89
93
  export type CollabParser = (
90
94
  tab: Tab,
91
95
  text: string,
92
- ) => Promise<{ document: JxMutableNode; frontmatter?: Record<string, unknown> }>;
96
+ ) => Promise<{ document: JxMutableNode; frontmatter?: DocumentRecord }>;
93
97
 
94
98
  let _parse: CollabParser | null = null;
95
99
 
@@ -158,11 +162,43 @@ interface TabRuntime {
158
162
  optedOut: { value: boolean };
159
163
  }
160
164
 
165
+ /**
166
+ * What a session's undo manager hands its stack listeners. A stack item's `meta` is Yjs's scratch
167
+ * map for whoever owns the manager, and the two listeners in createSession are its only users: the
168
+ * one key they write is the selection snapshot.
169
+ */
170
+ interface StackItemEvent {
171
+ stackItem: { meta: Map<"selection", JxPath[]> };
172
+ }
173
+
161
174
  const runtimes = new WeakMap<Tab, TabRuntime>();
162
175
 
163
176
  /** Callers hold either the raw tab or a reactive proxy of it; key runtimes by the raw object. */
164
177
  function rawTab(tab: Tab): Tab {
165
- return toRaw(tab as unknown as object) as Tab;
178
+ return toRaw(tab);
179
+ }
180
+
181
+ /**
182
+ * The document's shared frontmatter map, at the value type its writers keep.
183
+ *
184
+ * `frontmatterMap` hands back an untyped `Y.Map`, but only three writers ever touch it: the first
185
+ * client's `seedStructure` (a {@link DocumentRecord}) and the two mirrors in this module, which copy
186
+ * entries of a {@link DocumentRecord}. A key a parser left cleared may hold `undefined`, as
187
+ * DocumentRecord itself allows.
188
+ */
189
+ function sharedFrontmatterOf(collab: CollabModule, doc: Y.Doc): Y.Map<JxDocumentValue | undefined> {
190
+ // SAFETY: every write to this map is a DocumentRecord entry (see the doc comment above).
191
+ return collab.frontmatterMap(doc) as Y.Map<JxDocumentValue | undefined>;
192
+ }
193
+
194
+ /**
195
+ * Whether the session is still synced, read fresh.
196
+ *
197
+ * A detach flips `synced` while an awaited parse or serialization is in flight; the narrowing
198
+ * TypeScript carries over from a check made before the `await` cannot see that.
199
+ */
200
+ function stillSynced(session: ActiveSession): boolean {
201
+ return session.synced;
166
202
  }
167
203
 
168
204
  function runtimeOf(tab: Tab): TabRuntime | undefined {
@@ -238,7 +274,7 @@ function onTransact(tab: Tab, record: TransactionRecord, origin: TransactOrigin)
238
274
  if (!session || !session.synced) {
239
275
  return;
240
276
  }
241
- session.lastSeenRef = toRaw(tab.doc.document) as object;
277
+ session.lastSeenRef = toRaw(tab.doc.document);
242
278
  if (origin === "remote") {
243
279
  // The reconciler keeps source text fresh regardless of WHO edited the structure. The tab's
244
280
  // Dirty state is driven by the server's room-level `doc-dirty` broadcast (see onDirty in
@@ -307,7 +343,7 @@ function publishRecord(session: ActiveSession, record: TransactionRecord): void
307
343
  function publishDiff(session: ActiveSession): void {
308
344
  const { collab, handle, tab } = session;
309
345
  const before = collab.yDocToJson(handle.doc);
310
- const after = jsonClone(toRaw(tab.doc.document)) as JxMutableNode;
346
+ const after = jsonClone(toRaw(tab.doc.document));
311
347
  const ops = collab.diffDocs(before, after);
312
348
  if (ops === null) {
313
349
  collab.replaceYStructure(handle.doc, after, collab.LOCAL_ORIGIN);
@@ -326,7 +362,7 @@ function reconcileTabFromY(session: ActiveSession): void {
326
362
  transactDoc(
327
363
  session.tab,
328
364
  (t) => {
329
- const target = t.doc.document as Record<string, unknown>;
365
+ const target = t.doc.document;
330
366
  for (const key of Object.keys(target)) {
331
367
  if (!(key in next)) {
332
368
  delete target[key];
@@ -348,7 +384,7 @@ function isReconciler(session: ActiveSession): boolean {
348
384
  const { awareness } = session.handle;
349
385
  let lowest = awareness.clientID;
350
386
  for (const [clientId, state] of awareness.getStates()) {
351
- if ((state as { canWrite?: boolean }).canWrite !== false && clientId < lowest) {
387
+ if (state["canWrite"] !== false && clientId < lowest) {
352
388
  lowest = clientId;
353
389
  }
354
390
  }
@@ -416,7 +452,7 @@ async function sourceParseNow(session: ActiveSession): Promise<void> {
416
452
  // Unparseable source: keep the last good structure (the preview goes stale, not wrong).
417
453
  return;
418
454
  }
419
- if (!session.synced || collab.canonicalRevOf(handle.doc) !== rev) {
455
+ if (!stillSynced(session) || collab.canonicalRevOf(handle.doc) !== rev) {
420
456
  // The lock flipped while parsing; this mirror was computed against a dead representation.
421
457
  return;
422
458
  }
@@ -430,7 +466,7 @@ async function sourceParseNow(session: ActiveSession): Promise<void> {
430
466
  collab.replaceYStructure(handle.doc, parsed.document, collab.MIRROR_ORIGIN);
431
467
  }
432
468
  }
433
- const frontmatter = collab.frontmatterMap(handle.doc);
469
+ const frontmatter = sharedFrontmatterOf(collab, handle.doc);
434
470
  const next = parsed.frontmatter ?? {};
435
471
  handle.doc.transact(() => {
436
472
  // Detached copy: keys are deleted while iterating.
@@ -541,12 +577,7 @@ export function collabSourceContext(tab: Tab): {
541
577
  reason: a client that cannot write cannot be the one holding a write. */
542
578
  const others = collab
543
579
  .otherSourceEditors(handle.awareness, session.path, handle.awareness.clientID)
544
- .filter((clientId) => {
545
- const peer = handle.awareness.getStates().get(clientId) as
546
- | { canWrite?: boolean }
547
- | undefined;
548
- return peer?.canWrite !== false;
549
- });
580
+ .filter((clientId) => handle.awareness.getStates().get(clientId)?.["canWrite"] !== false);
550
581
  if (others.length === 0) {
551
582
  // Freshen the structure mirror once more, then hand the lock back.
552
583
  void sourceParseNow(session).then(() => {
@@ -729,16 +760,15 @@ async function attachSession(tab: Tab): Promise<void> {
729
760
  handle.destroy();
730
761
  return;
731
762
  }
732
- let timer: ReturnType<typeof setTimeout> | null = null;
763
+ // Assigned synchronously: a Promise executor runs before its constructor returns.
764
+ let timer: ReturnType<typeof setTimeout> | undefined;
733
765
  const timeout = new Promise<never>((_, reject) => {
734
766
  timer = setTimeout(() => reject(new Error("collab-sync-timeout")), SYNC_TIMEOUT_MS);
735
767
  });
736
768
  try {
737
769
  await Promise.race([handle.whenSynced, timeout]);
738
770
  } finally {
739
- if (timer) {
740
- clearTimeout(timer);
741
- }
771
+ clearTimeout(timer);
742
772
  }
743
773
  if (runtime.generation !== generation) {
744
774
  handle.destroy();
@@ -804,7 +834,7 @@ function detachSession(tab: Tab): void {
804
834
  // Re-base the op-log history on the current document for solo editing.
805
835
  tab.history.snapshots = [
806
836
  {
807
- document: jsonClone(toRaw(tab.doc.document)) as Record<string, unknown>,
837
+ document: jsonClone(toRaw(tab.doc.document)),
808
838
  selection: cloneSelection(tab.session.selection),
809
839
  },
810
840
  ];
@@ -828,7 +858,7 @@ function createSession(
828
858
  collab,
829
859
  disposers: [],
830
860
  handle,
831
- lastSeenRef: toRaw(tab.doc.document) as object,
861
+ lastSeenRef: toRaw(tab.doc.document),
832
862
  mirrorTimer: null,
833
863
  path,
834
864
  sourceLockOwner: null,
@@ -843,7 +873,7 @@ function createSession(
843
873
  const meta = collab.metaMap(handle.doc);
844
874
  if (meta.get("structureSeeded") === true) {
845
875
  const yJson = collab.yDocToJson(handle.doc);
846
- const tabJson = jsonClone(toRaw(tab.doc.document)) as JxMutableNode;
876
+ const tabJson = jsonClone(toRaw(tab.doc.document));
847
877
  if (!collab.deepEqual(yJson, tabJson)) {
848
878
  const ops = collab.diffDocs(tabJson, yJson);
849
879
  if (ops === null) {
@@ -855,19 +885,21 @@ function createSession(
855
885
  }
856
886
  }
857
887
  session.applyingRemoteFrontmatter = true;
858
- const sharedFrontmatter = collab.frontmatterMap(handle.doc);
888
+ const sharedFrontmatter = sharedFrontmatterOf(collab, handle.doc);
859
889
  for (const [key, value] of sharedFrontmatter.entries()) {
860
- tab.doc.content.frontmatter[key] = value as never;
890
+ tab.doc.content.frontmatter[key] = value;
861
891
  }
862
892
  session.applyingRemoteFrontmatter = false;
863
893
  } else if (session.canWrite) {
864
- collab.seedStructure(handle.doc, jsonClone(toRaw(tab.doc.document)) as JxMutableNode, {
865
- frontmatter: jsonClone(toRaw(tab.doc.content.frontmatter)),
894
+ collab.seedStructure(handle.doc, jsonClone(toRaw(tab.doc.document)), {
895
+ /* SAFETY: frontmatter is parsed YAML/JSON held as plain values, and jsonClone round-trips it
896
+ * through JSON, so every value is JSON data, which JxDocumentValue includes. */
897
+ frontmatter: jsonClone(toRaw(tab.doc.content.frontmatter)) as DocumentRecord,
866
898
  origin: collab.SEED_ORIGIN,
867
899
  sourceFormat: tab.doc.sourceFormat,
868
900
  });
869
901
  }
870
- session.lastSeenRef = toRaw(tab.doc.document) as object;
902
+ session.lastSeenRef = toRaw(tab.doc.document);
871
903
 
872
904
  // The server owns the room-level unsaved state: `onDirty` fires synchronously with the current
873
905
  // Value on subscribe (delivered during the open handshake), so attaching to a clean room clears
@@ -902,11 +934,11 @@ function createSession(
902
934
  { trackedOrigins: new Set([collab.LOCAL_ORIGIN]) },
903
935
  );
904
936
  session.undoManager = undoManager;
905
- const onStackAdd = ({ stackItem }: { stackItem: { meta: Map<unknown, unknown> } }) => {
937
+ const onStackAdd = ({ stackItem }: StackItemEvent) => {
906
938
  stackItem.meta.set("selection", cloneSelection(tab.session.selection));
907
939
  };
908
- const onStackPop = ({ stackItem }: { stackItem: { meta: Map<unknown, unknown> } }) => {
909
- const selection = stackItem.meta.get("selection") as (string | number)[][] | undefined;
940
+ const onStackPop = ({ stackItem }: StackItemEvent) => {
941
+ const selection = stackItem.meta.get("selection");
910
942
  tab.session.selection = cloneSelection(selection ?? []);
911
943
  };
912
944
  undoManager.on("stack-item-added", onStackAdd);
@@ -928,11 +960,14 @@ function createSession(
928
960
 
929
961
  // Inbound: remote structure transactions → JxDocOps → the surgical pipeline.
930
962
  const structure = collab.structureMap(handle.doc);
931
- const structureObserver = (events: unknown, transaction: { origin: unknown }) => {
963
+ const structureObserver = (
964
+ events: Y.YEvent<Y.AbstractType<unknown>>[],
965
+ transaction: { origin: unknown },
966
+ ) => {
932
967
  if (transaction.origin === collab.LOCAL_ORIGIN || !session.synced) {
933
968
  return;
934
969
  }
935
- const ops = collab.yEventsToDocOps(events as never);
970
+ const ops = collab.yEventsToDocOps(events);
936
971
  if (ops === null) {
937
972
  reconcileTabFromY(session);
938
973
  return;
@@ -963,7 +998,7 @@ function createSession(
963
998
  // The source reconciler (lowest write clientID in source mode) parses Y.Text back into the
964
999
  // Structure tree on a debounce, so every client's canvas previews source edits live.
965
1000
  const source = collab.sourceText(handle.doc);
966
- const sourceObserver = (_event: unknown, transaction: { origin: unknown }) => {
1001
+ const sourceObserver = (_event: Y.YTextEvent, transaction: { origin: unknown }) => {
967
1002
  if (transaction.origin === collab.MIRROR_ORIGIN || !session.synced) {
968
1003
  return;
969
1004
  }
@@ -981,13 +1016,13 @@ function createSession(
981
1016
  void sourceParseNow(session);
982
1017
  }, 600);
983
1018
  };
984
- source.observe(sourceObserver as never);
985
- session.disposers.push(() => source.unobserve(sourceObserver as never));
1019
+ source.observe(sourceObserver);
1020
+ session.disposers.push(() => source.unobserve(sourceObserver));
986
1021
 
987
1022
  // Inbound frontmatter (per-field).
988
- const frontmatter = collab.frontmatterMap(handle.doc);
1023
+ const frontmatter = sharedFrontmatterOf(collab, handle.doc);
989
1024
  const frontmatterObserver = (
990
- event: { changes: { keys: Map<string, { action: string }> }; target: unknown },
1025
+ event: Y.YMapEvent<JxDocumentValue | undefined>,
991
1026
  transaction: { origin: unknown },
992
1027
  ) => {
993
1028
  if (transaction.origin === collab.LOCAL_ORIGIN || !session.synced) {
@@ -999,15 +1034,15 @@ function createSession(
999
1034
  if (change.action === "delete") {
1000
1035
  delete tab.doc.content.frontmatter[key];
1001
1036
  } else {
1002
- tab.doc.content.frontmatter[key] = frontmatter.get(key) as never;
1037
+ tab.doc.content.frontmatter[key] = frontmatter.get(key);
1003
1038
  }
1004
1039
  }
1005
1040
  } finally {
1006
1041
  session.applyingRemoteFrontmatter = false;
1007
1042
  }
1008
1043
  };
1009
- frontmatter.observe(frontmatterObserver as never);
1010
- session.disposers.push(() => frontmatter.unobserve(frontmatterObserver as never));
1044
+ frontmatter.observe(frontmatterObserver);
1045
+ session.disposers.push(() => frontmatter.unobserve(frontmatterObserver));
1011
1046
 
1012
1047
  // Outbound frontmatter: mutateUpdateFrontmatter bypasses transactDoc, so watch the map deeply.
1013
1048
  tab.scope.run(() => {
@@ -1021,7 +1056,8 @@ function createSession(
1021
1056
  if (session.applyingRemoteFrontmatter || !session.synced || !session.canWrite) {
1022
1057
  return;
1023
1058
  }
1024
- const local = JSON.parse(json) as Record<string, unknown>;
1059
+ // SAFETY: `json` is JSON.stringify of the frontmatter record above, so it parses to one.
1060
+ const local = JSON.parse(json) as DocumentRecord;
1025
1061
  handle.doc.transact(() => {
1026
1062
  // Detached copy: keys are deleted while iterating.
1027
1063
  const sharedKeys = [...frontmatter.keys()];
@@ -1060,13 +1096,13 @@ function createSession(
1060
1096
  // Flush) reconciles by diff. Deferred one microtask so the transact observer marks its own
1061
1097
  // Refs first (the assignment happens mid-transaction, before the observer runs).
1062
1098
  effect(() => {
1063
- const ref = toRaw(tab.doc.document) as object;
1099
+ const ref = toRaw(tab.doc.document);
1064
1100
  queueMicrotask(() => {
1065
1101
  const current = runtimeOf(tab)?.session;
1066
1102
  if (current !== session || !session.synced || !session.canWrite) {
1067
1103
  return;
1068
1104
  }
1069
- const nowRef = toRaw(tab.doc.document) as object;
1105
+ const nowRef = toRaw(tab.doc.document);
1070
1106
  if (nowRef !== ref || nowRef === session.lastSeenRef) {
1071
1107
  return;
1072
1108
  }
@@ -1081,10 +1117,13 @@ function createSession(
1081
1117
  // Presence roster + status.
1082
1118
  const state = collabState(tab);
1083
1119
  const awarenessObserver = () => {
1084
- const peers: { clientId: number; state: never }[] = [];
1120
+ const peers: PeerPresence[] = [];
1085
1121
  for (const [clientId, peerState] of handle.awareness.getStates()) {
1086
1122
  if (clientId !== handle.awareness.clientID && peerState["user"]) {
1087
- peers.push({ clientId, state: peerState as never });
1123
+ /* SAFETY: every Studio client publishes its state through the setLocalState call in
1124
+ * createSession above, which writes a CollabAwarenessState; a state with no `user` (a
1125
+ * client mid-handshake) was skipped by the check above. */
1126
+ peers.push({ clientId, state: peerState as CollabAwarenessState });
1088
1127
  }
1089
1128
  }
1090
1129
  state.peers = peers;
@@ -60,17 +60,18 @@ const attachedPaths = new Map<string, number>();
60
60
  export function collabState(tab: Tab): TabCollabState {
61
61
  // Key on the raw tab: writers (the collab session, via ensureCollab's raw tab) and readers
62
62
  // (toolbar/tab-strip, via reactive `workspace.tabs.get` proxies) must resolve the same entry.
63
- const key = toRaw(tab as unknown as object) as Tab;
63
+ const key = toRaw(tab);
64
64
  let state = states.get(key);
65
65
  if (!state) {
66
- state = reactive({
66
+ const initial: TabCollabState = {
67
67
  active: false,
68
68
  attachError: "",
69
69
  peers: [],
70
70
  readOnly: false,
71
71
  sourceCanonical: false,
72
72
  status: "unavailable",
73
- }) as TabCollabState;
73
+ };
74
+ state = reactive(initial);
74
75
  states.set(key, state);
75
76
  }
76
77
  return state;
@@ -34,6 +34,7 @@ import {
34
34
  createAbsolutePositionFromRelativePosition,
35
35
  createRelativePositionFromTypeIndex,
36
36
  } from "@jxsuite/collab";
37
+ import { isString } from "@jxsuite/schema/guards";
37
38
  import type * as Y from "yjs";
38
39
  import type { editor } from "monaco-editor";
39
40
  import type { AwarenessLike } from "./monaco-cursors";
@@ -43,7 +44,8 @@ import type { AwarenessLike } from "./monaco-cursors";
43
44
  * `./monaco-cursors.ts` already defines for the style manager) plus the one writer it needs.
44
45
  */
45
46
  export interface BindingAwareness extends AwarenessLike {
46
- setLocalStateField: (field: string, value: unknown) => void;
47
+ /** Publishes this client's caret; `selection` is the one field the binding owns. */
48
+ setLocalStateField: (field: "selection", value: RelativeSelection | null) => void;
47
49
  }
48
50
 
49
51
  export interface MonacoYTextBindingOptions {
@@ -60,14 +62,17 @@ export interface MonacoYTextBindingOptions {
60
62
  }
61
63
 
62
64
  /** A caret snapshotted as two positions that survive a concurrent edit. */
63
- interface RelativeSelection {
65
+ export interface RelativeSelection {
64
66
  anchor: Y.RelativePosition;
65
67
  head: Y.RelativePosition;
66
68
  }
67
69
 
68
- /** A peer's published caret, as it arrives over the wire (JSON, hence `unknown` halves). */
70
+ /**
71
+ * A peer's published caret, as it arrives over the wire: the JSON of a {@link RelativeSelection},
72
+ * with every level optional because an older or partial state may omit it.
73
+ */
69
74
  interface PeerSelectionState {
70
- selection?: { anchor?: unknown; head?: unknown } | null;
75
+ selection?: { anchor?: Y.RelativePosition; head?: Y.RelativePosition } | null;
71
76
  }
72
77
 
73
78
  /**
@@ -178,18 +183,16 @@ export function bindMonacoToYText(options: MonacoYTextBindingOptions): () => voi
178
183
  if (clientId === awareness.clientID) {
179
184
  continue;
180
185
  }
186
+ /* SAFETY: `selection` is reserved for this binding (awareness-types.ts), so every writer
187
+ * publishes relativeSelectionOf's RelativeSelection or null. Its JSON round trip keeps the
188
+ * plain fields createAbsolutePositionFromRelativePosition reads, and every level is optional
189
+ * and checked below, so a peer that publishes none is skipped. */
181
190
  const { selection } = (raw ?? {}) as PeerSelectionState;
182
191
  if (!selection?.anchor || !selection.head) {
183
192
  continue;
184
193
  }
185
- const anchor = createAbsolutePositionFromRelativePosition(
186
- selection.anchor as Y.RelativePosition,
187
- doc,
188
- );
189
- const head = createAbsolutePositionFromRelativePosition(
190
- selection.head as Y.RelativePosition,
191
- doc,
192
- );
194
+ const anchor = createAbsolutePositionFromRelativePosition(selection.anchor, doc);
195
+ const head = createAbsolutePositionFromRelativePosition(selection.head, doc);
193
196
  if (!anchor || !head || anchor.type !== text || head.type !== text) {
194
197
  continue;
195
198
  }
@@ -289,7 +292,7 @@ export function bindMonacoToYText(options: MonacoYTextBindingOptions): () => voi
289
292
  embeds (`insert` is then an object or another type), and a Monaco buffer has nowhere to
290
293
  put one — upstream cast the field to string and produced `"[object Object]"` in the
291
294
  document. The same clause catches an op carrying none of the three fields. */
292
- if (typeof op.insert !== "string") {
295
+ if (!isString(op.insert)) {
293
296
  throw new TypeError(
294
297
  "bindMonacoToYText: unsupported Y.Text delta op — a text buffer can only apply " +
295
298
  "string inserts",
@@ -14,7 +14,7 @@ export interface AwarenessLike {
14
14
  off: (event: "change", cb: () => void) => void;
15
15
  }
16
16
 
17
- interface PeerStateShape {
17
+ interface PeerPresence {
18
18
  user?: { color?: string; name?: string; login?: string };
19
19
  }
20
20
 
@@ -40,7 +40,10 @@ export function cursorStylesheet(awareness: AwarenessLike): string {
40
40
  if (clientId === awareness.clientID) {
41
41
  continue;
42
42
  }
43
- const { user } = raw as PeerStateShape;
43
+ /* SAFETY: y-protocols keeps only non-null state objects in getStates() (a peer clearing its
44
+ * state removes the entry), and every member of PeerPresence is optional and read through
45
+ * optional chaining below, so a peer that publishes no `user` is skipped, not misread. */
46
+ const { user } = raw as PeerPresence;
44
47
  if (!user?.color) {
45
48
  continue;
46
49
  }
@@ -112,9 +112,9 @@ export interface BudgetViolation {
112
112
 
113
113
  /** Commands declaring the primary Command Bar cluster. */
114
114
  export function primaryCommandIds(commands: readonly BudgetableRecord[]): string[] {
115
- return commands
116
- .filter((command) => (command.menus ?? []).includes("commandbar/primary"))
117
- .map((command) => command.id);
115
+ return commands.flatMap((command) =>
116
+ (command.menus ?? []).includes("commandbar/primary") ? [command.id] : [],
117
+ );
118
118
  }
119
119
 
120
120
  /**