@panphora/clayjs 1.17.0 → 1.18.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 (467) hide show
  1. package/dist/all.js +1 -1
  2. package/dist/clay-dom.js +1 -1
  3. package/dist/clay-events.js +1 -1
  4. package/dist/clay-internals.js +1 -1
  5. package/dist/clay-options.js +1 -1
  6. package/dist/clay-router.js +1 -1
  7. package/dist/clay-ui.js +1 -1
  8. package/dist/clay-utils.js +1 -1
  9. package/dist/clay.js +1 -1
  10. package/dist/clay.standalone.js +72474 -62090
  11. package/dist/m/attrs/{save-freeze-MYNVXREN.js → save-freeze-LWGF6XUN.js} +1 -1
  12. package/dist/m/c-2GRUM77Q.js +30 -0
  13. package/dist/m/c-2KIEGNC4.js +1 -0
  14. package/dist/m/{c-AMSNPOCX.js → c-2KL3BD52.js} +1 -1
  15. package/dist/m/c-2ZZBC45O.js +1 -0
  16. package/dist/m/c-372N6H3B.js +1 -0
  17. package/dist/m/{c-4WKFKEKF.js → c-3G2DGZUP.js} +1 -1
  18. package/dist/m/c-3LDGIBMN.js +1 -0
  19. package/dist/m/c-3O7OBDCM.js +1 -0
  20. package/dist/m/c-4ASQPRQL.js +1 -0
  21. package/dist/m/c-4TXNLX4K.js +6 -0
  22. package/dist/m/c-4YU3BR4D.js +6 -0
  23. package/dist/m/c-5734MF2P.js +1 -0
  24. package/dist/m/c-57XDY6HC.js +1 -0
  25. package/dist/m/{c-KAU6E43D.js → c-5B4YBZXC.js} +1 -1
  26. package/dist/m/c-5ONTYIUI.js +1 -0
  27. package/dist/m/c-5OOVFCJM.js +1 -0
  28. package/dist/m/{c-3XIRD4NU.js → c-5T6NZHNM.js} +1 -1
  29. package/dist/m/{c-74MGYWZF.js → c-5ZQV7KC4.js} +1 -1
  30. package/dist/m/{c-7OLLJPWP.js → c-6DB2OLRJ.js} +1 -1
  31. package/dist/m/c-6DNRCPNM.js +1 -0
  32. package/dist/m/c-6UGWFMQC.js +2 -0
  33. package/dist/m/c-7K4SCQB7.js +1 -0
  34. package/dist/m/c-7MG5RU63.js +1 -0
  35. package/dist/m/c-7PRJCA3E.js +1 -0
  36. package/dist/m/c-A6L3FMUS.js +1 -0
  37. package/dist/m/c-AMU3BPPR.js +4 -0
  38. package/dist/m/{c-Y5HBBIQ4.js → c-AMYEFA2E.js} +1 -1
  39. package/dist/m/c-AQYCG7QW.js +1 -0
  40. package/dist/m/c-ATKAOH23.js +1 -0
  41. package/dist/m/c-B5CS55WR.js +1 -0
  42. package/dist/m/c-B5UJQT7W.js +1 -0
  43. package/dist/m/c-B7J4K2AE.js +3 -0
  44. package/dist/m/c-BHZYSHW4.js +1 -0
  45. package/dist/m/{c-VHM5XQHK.js → c-BIJALSRD.js} +1 -1
  46. package/dist/m/c-BJ7YQ5QZ.js +1 -0
  47. package/dist/m/{c-KIPQJX4B.js → c-BRLCTNMC.js} +1 -1
  48. package/dist/m/{c-VE6ZMYMC.js → c-BUAYFEV5.js} +1 -1
  49. package/dist/m/c-C6IPRG34.js +1 -0
  50. package/dist/m/{c-KU3ZFADW.js → c-CAS3NND4.js} +1 -1
  51. package/dist/m/{c-PS5ARVWR.js → c-CCQ25GFY.js} +1 -1
  52. package/dist/m/c-CJFDLD43.js +1 -0
  53. package/dist/m/c-COPTL5WB.js +1 -0
  54. package/dist/m/c-D3E4WJ4M.js +166 -0
  55. package/dist/m/c-D5IKEKXW.js +7 -0
  56. package/dist/m/c-DHBRA6DL.js +1 -0
  57. package/dist/m/c-DKLS74XB.js +72 -0
  58. package/dist/m/c-DVYGFTSK.js +3 -0
  59. package/dist/m/c-E3ZXARWA.js +1 -0
  60. package/dist/m/c-EK63G3CG.js +1 -0
  61. package/dist/m/c-ERQSNR6K.js +13 -0
  62. package/dist/m/c-EVYAISP3.js +1 -0
  63. package/dist/m/c-EXKHPOVC.js +3 -0
  64. package/dist/m/{c-QJ4OM3G6.js → c-FWKHM4E7.js} +1 -1
  65. package/dist/m/{c-4Q2XTQ2N.js → c-GBKB5WDL.js} +1 -1
  66. package/dist/m/c-GNDL3TKB.js +1 -0
  67. package/dist/m/c-GRWMD6O5.js +1 -0
  68. package/dist/m/c-GRXHHFPO.js +1 -0
  69. package/dist/m/c-HG2C77BM.js +4 -0
  70. package/dist/m/c-HHGJBU4D.js +1 -0
  71. package/dist/m/c-HMV6P4RX.js +1 -0
  72. package/dist/m/c-HMYWIHFG.js +1 -0
  73. package/dist/m/c-HT2DKBV2.js +1 -0
  74. package/dist/m/c-I2SCCUEW.js +1 -0
  75. package/dist/m/{c-TJ6WOJL3.js → c-ICJYHABF.js} +2 -2
  76. package/dist/m/c-IMZCWYHR.js +7 -0
  77. package/dist/m/c-IVMD3FEM.js +1 -0
  78. package/dist/m/{c-WDC5GVKU.js → c-IVTRVENZ.js} +1 -1
  79. package/dist/m/c-JKZJIUIP.js +1 -0
  80. package/dist/m/{c-UDUUJPFZ.js → c-JNLX3RJB.js} +1 -1
  81. package/dist/m/c-K3ADYNLU.js +1 -0
  82. package/dist/m/c-KGHVFRR3.js +1 -0
  83. package/dist/m/{c-5QWQ7A5L.js → c-KJJPV77R.js} +1 -1
  84. package/dist/m/{c-CZUSOB7V.js → c-KNPDOMDY.js} +1 -1
  85. package/dist/m/{c-EZU56NQV.js → c-KP64LT2A.js} +2 -2
  86. package/dist/m/c-KQ7E3PYY.js +1 -0
  87. package/dist/m/c-L3F5ZLIV.js +1 -0
  88. package/dist/m/{c-3RUU4TPX.js → c-L42OLXWM.js} +3 -2
  89. package/dist/m/c-L5VFATT6.js +1 -0
  90. package/dist/m/c-L7JL5TL3.js +3 -0
  91. package/dist/m/c-LKSL4AUJ.js +1 -0
  92. package/dist/m/c-M6FNQCTQ.js +1 -0
  93. package/dist/m/c-MCOOHCSG.js +1 -0
  94. package/dist/m/c-MHI3GYKF.js +1 -0
  95. package/dist/m/c-MWXFLW4J.js +1 -0
  96. package/dist/m/{c-5RJFTLSF.js → c-NEL7HQW3.js} +1 -1
  97. package/dist/m/{c-DCXOXBF3.js → c-NQJRVJ56.js} +1 -1
  98. package/dist/m/c-NWX3MFT4.js +1 -0
  99. package/dist/m/{c-HPURYVZS.js → c-OJYM642Q.js} +1 -1
  100. package/dist/m/c-OKXI52N7.js +1 -0
  101. package/dist/m/{c-R3L7ZJGB.js → c-OPLUZR3A.js} +1 -1
  102. package/dist/m/{c-GSFIGKOP.js → c-OTMKN2OO.js} +1 -1
  103. package/dist/m/{c-6NC5I2TV.js → c-OYRZ7XG2.js} +1 -1
  104. package/dist/m/{c-EVCQ3BKA.js → c-P3OFYUMA.js} +1 -1
  105. package/dist/m/c-PLN76GF3.js +6 -0
  106. package/dist/m/c-PLP4JKFC.js +1 -0
  107. package/dist/m/c-Q26MME6N.js +1 -0
  108. package/dist/m/{c-S7H2DRCB.js → c-Q3XOWZEV.js} +1 -1
  109. package/dist/m/{c-FRLHSY7E.js → c-QIKT6SKM.js} +1 -1
  110. package/dist/m/c-QIXT3Q7C.js +28 -0
  111. package/dist/m/c-QO4HNGCQ.js +1 -0
  112. package/dist/m/{c-JU3NK25H.js → c-R27DWQKX.js} +1 -1
  113. package/dist/m/{c-RSMOODDU.js → c-R2XUODVY.js} +1 -1
  114. package/dist/m/{c-QNKREOL6.js → c-R7LBFMF5.js} +1 -1
  115. package/dist/m/c-RND3G2S2.js +1 -0
  116. package/dist/m/{c-Q622NS2Y.js → c-S2U6NJU4.js} +1 -1
  117. package/dist/m/c-SPZPGD3R.js +1 -0
  118. package/dist/m/c-SW4YEG2D.js +8 -0
  119. package/dist/m/c-T637T7SN.js +1 -0
  120. package/dist/m/c-TJAXGIRV.js +1 -0
  121. package/dist/m/{c-RYUXUUBX.js → c-TNEM3RNM.js} +1 -1
  122. package/dist/m/c-TTB5EK4S.js +32 -0
  123. package/dist/m/c-U7SHNWDH.js +1 -0
  124. package/dist/m/c-UDHIVLYH.js +20 -0
  125. package/dist/m/{c-BBVGTQG7.js → c-UGNV5MFB.js} +1 -1
  126. package/dist/m/{c-QICP2YR5.js → c-UORXLSD3.js} +1 -1
  127. package/dist/m/c-UPD33ZPE.js +1 -0
  128. package/dist/m/c-URSMSFCB.js +1 -0
  129. package/dist/m/c-UY4QX42B.js +1 -0
  130. package/dist/m/c-V44KWI2L.js +4 -0
  131. package/dist/m/c-VILENZTD.js +1 -0
  132. package/dist/m/{c-HDDEEL77.js → c-VJYEVRYK.js} +1 -1
  133. package/dist/m/{c-SMBZG5X4.js → c-VR2BJ4AN.js} +1 -1
  134. package/dist/m/c-W4JCVLAB.js +1 -0
  135. package/dist/m/c-W6DQSHXI.js +135 -0
  136. package/dist/m/c-WBGWGOM7.js +1 -0
  137. package/dist/m/{c-4L3BTFRK.js → c-WCXLG3MV.js} +1 -1
  138. package/dist/m/c-WGW764WX.js +1 -0
  139. package/dist/m/c-WMRJKQ2V.js +5 -0
  140. package/dist/m/c-WNTYKCDG.js +1 -0
  141. package/dist/m/c-WQWIRWO3.js +72 -0
  142. package/dist/m/c-X5LNHET5.js +1 -0
  143. package/dist/m/{c-I2ZATQCD.js → c-X5TSXZYJ.js} +2 -2
  144. package/dist/m/c-XGH4GS2T.js +1 -0
  145. package/dist/m/c-Y6F2FORL.js +1 -0
  146. package/dist/m/c-YBKHUAK7.js +10 -0
  147. package/dist/m/c-YBSS55KU.js +20 -0
  148. package/dist/m/c-YCLU4UNT.js +2 -0
  149. package/dist/m/c-YVZ2L7CE.js +1 -0
  150. package/dist/m/c-ZK4GIZH2.js +1 -0
  151. package/dist/m/c-ZRXJD4G6.js +1 -0
  152. package/dist/m/c-ZWBI4HYK.js +1 -0
  153. package/dist/m/core/{admin-attrs-QHOKPJ7W.js → admin-attrs-YY7T5FGU.js} +1 -1
  154. package/dist/m/core/autosave-S6OMNDCK.js +1 -0
  155. package/dist/m/core/conflict-notice-IWHMHH43.js +1 -0
  156. package/dist/m/core/{host-permission-FNXVEFNE.js → host-permission-6EVJGNPL.js} +1 -1
  157. package/dist/m/core/is-edit-mode-GCX6767E.js +1 -0
  158. package/dist/m/core/{persist-JFYRHMRJ.js → persist-UKXV5KLA.js} +1 -1
  159. package/dist/m/core/recovery-DRFZRJED.js +1 -0
  160. package/dist/m/core/save-LYY7K6U7.js +1 -0
  161. package/dist/m/core/save-core-MKRPSEEO.js +1 -0
  162. package/dist/m/core/snapshot-NU3YM6GR.js +1 -0
  163. package/dist/m/core/unsaved-warning-7QTKEN7Z.js +1 -0
  164. package/dist/m/internals/{index-PVXGPUDA.js → index-TGLQINN3.js} +1 -1
  165. package/dist/m/loader-3BBNZZGM.js +1 -0
  166. package/dist/m/manifest-F449FF98.js +1 -0
  167. package/dist/m/manifest-edit-4396A009.js +1 -0
  168. package/dist/m/manifest.json +2111 -1573
  169. package/dist/m/page/{editor-NNJA4OKD.js → editor-6LRB3GE4.js} +123 -21
  170. package/dist/m/plugins/ai-edit-UTV7YO2I.js +6 -0
  171. package/dist/m/plugins/{cms-HP3LSTPN.js → cms-LRAOZHT7.js} +9 -9
  172. package/dist/m/plugins/{demo-RM5IR6AO.js → demo-OYO5GCAO.js} +1 -1
  173. package/dist/m/plugins/{derive-UAAA4V4S.js → derive-FRE5JJQE.js} +1 -1
  174. package/dist/m/plugins/indicator-4VDXWYTD.js +1 -0
  175. package/dist/m/plugins/live-AD4H6XSL.js +1 -0
  176. package/dist/m/plugins/menu-M5WW7DBF.js +1 -0
  177. package/dist/m/plugins/page-MD3T2ZX3.js +2 -0
  178. package/dist/m/plugins/page-view-PAWVZNFY.js +1 -0
  179. package/dist/m/plugins/{people-SGPJKANK.js → people-JCHVPF7P.js} +1 -1
  180. package/dist/m/plugins/quickcrop-BQ5YYFCH.js +26 -0
  181. package/dist/m/plugins/{richclay-NRQDSWX6.js → richclay-KLGETK77.js} +2 -2
  182. package/dist/m/plugins/sortable-4S6SQC3D.js +1 -0
  183. package/dist/m/plugins/source-TJXOIOYY.js +1 -0
  184. package/dist/m/plugins/undo-NLPGCJQY.js +1 -0
  185. package/dist/m/plugins/{unsent-HJFLQJ2O.js → unsent-OA4RGBUT.js} +1 -1
  186. package/dist/m/plugins/upgrade-HSUNDNJD.js +1 -0
  187. package/dist/m/plugins/{upload-WLYKK6TL.js → upload-NHGJXZK2.js} +1 -1
  188. package/dist/m/plugins/visitor-drafts-BW43DGY3.js +20 -0
  189. package/dist/m/plugins/visitor-drafts-owner-7ODQG7JX.js +1 -0
  190. package/dist/m/plugins/{wire-4N6GYAF6.js → wire-VBWXEXU2.js} +1 -1
  191. package/dist/m/reader-core-4W2KYEWQ.js +77 -0
  192. package/dist/m/route/route-62CHXL5B.js +1 -0
  193. package/dist/m/sync/live-sync-MO5DH33W.js +1 -0
  194. package/dist/m/ui/index-IVWN2QC4.js +1 -0
  195. package/dist/m/vendor/sap-core.vendor-RN4ZVY4X.js +6 -0
  196. package/dist/offline-manifest.json +1367 -930
  197. package/dist/page/themes/light-1.css +8 -7
  198. package/dist/server/core.cjs +1440 -288
  199. package/dist/server/offline-runtime.cjs +63 -63
  200. package/dist/server/offline-runtime.mjs +63 -63
  201. package/dist/server/page-compaction-worker.cjs +3710 -0
  202. package/dist/server/rooms.mjs +5 -0
  203. package/docs/guide.md +653 -101
  204. package/entries/sap.js +5 -5
  205. package/package.json +1 -1
  206. package/src/core/admin-contenteditable.js +5 -2
  207. package/src/core/admin-inputs.js +1 -0
  208. package/src/core/admin-onclick.js +2 -1
  209. package/src/core/conflict-notice-ui.js +4 -7
  210. package/src/core/download.js +2 -2
  211. package/src/core/host-meta.js +38 -0
  212. package/src/core/is-edit-mode.js +17 -1
  213. package/src/core/mode-key.js +125 -19
  214. package/src/core/mode-support.js +5 -0
  215. package/src/core/mode-transition.js +20 -6
  216. package/src/core/preserve-authored.js +4 -4
  217. package/src/core/recovery.js +121 -33
  218. package/src/core/save-accepted.js +33 -0
  219. package/src/core/save-core.js +106 -31
  220. package/src/core/save-job.js +108 -0
  221. package/src/core/save-prepare.js +53 -0
  222. package/src/core/save-size-notice.js +3 -1
  223. package/src/core/save-slices.js +15 -0
  224. package/src/core/save.js +557 -127
  225. package/src/core/serialize-steps.js +109 -0
  226. package/src/core/snapshot.js +170 -39
  227. package/src/core/source-map.js +83 -38
  228. package/src/core/stale-host-notice.js +1 -0
  229. package/src/core/upgrade-run.js +59 -8
  230. package/src/dom/active-element.js +5 -0
  231. package/src/lib/assets.js +1 -0
  232. package/src/lib/slice.js +65 -0
  233. package/src/lib/uimotion.js +774 -0
  234. package/src/lib/unsaved-state.js +2 -2
  235. package/src/live/fast-lane.js +10 -3
  236. package/src/live/local-lane.js +202 -11
  237. package/src/live/ops.js +16 -0
  238. package/src/live/page-compaction.js +162 -0
  239. package/src/live/server-lane.js +1 -0
  240. package/src/live/store.js +11 -3
  241. package/src/loader-logic.js +3 -1
  242. package/src/loader.js +14 -4
  243. package/src/page/adopt-boot.js +2 -1
  244. package/src/page/awareness.js +33 -2
  245. package/src/page/blocks.js +89 -27
  246. package/src/page/boot-pack.js +1 -1
  247. package/src/page/chart-tables.js +21 -3
  248. package/src/page/chart.js +406 -63
  249. package/src/page/checklist.js +10 -135
  250. package/src/page/checkpoint-proof.js +7 -1
  251. package/src/page/chrome.js +250 -51
  252. package/src/page/clipboard-shape.js +126 -0
  253. package/src/page/drag.js +33 -3
  254. package/src/page/editor.js +136 -25
  255. package/src/page/export-assets.js +357 -0
  256. package/src/page/export-html.js +209 -0
  257. package/src/page/export-markdown.js +361 -0
  258. package/src/page/features/checklist.js +428 -0
  259. package/src/page/features/export-html.js +189 -0
  260. package/src/page/features/export-markdown.js +169 -0
  261. package/src/page/features/import-markdown.js +349 -0
  262. package/src/page/features/media.js +61 -5
  263. package/src/page/features/registry.js +18 -0
  264. package/src/page/features/table.js +373 -83
  265. package/src/page/features/title-cover.js +331 -0
  266. package/src/page/features/title-icon.js +213 -0
  267. package/src/page/features/toc.js +87 -0
  268. package/src/page/format-command.js +25 -1
  269. package/src/page/format-gate.js +68 -18
  270. package/src/page/format-host.js +17 -0
  271. package/src/page/format-native-commands.js +21 -5
  272. package/src/page/image-actions.js +64 -0
  273. package/src/page/import-markdown.js +262 -0
  274. package/src/page/items.js +135 -17
  275. package/src/page/markdown.js +6 -2
  276. package/src/page/media.js +35 -119
  277. package/src/page/placeholder.js +14 -1
  278. package/src/page/projection.js +98 -10
  279. package/src/page/recover.js +10 -12
  280. package/src/page/recovery-ui.js +464 -0
  281. package/src/page/rich/chart.js +63 -7
  282. package/src/page/save-projection.js +28 -0
  283. package/src/page/save-states.js +13 -3
  284. package/src/page/schema.js +19 -3
  285. package/src/page/table-paste.js +3 -1
  286. package/src/page/table-style.js +4 -4
  287. package/src/page/table.js +44 -2
  288. package/src/page/themes/light-1.css +8 -7
  289. package/src/page/themes/light-1.source.css +8 -7
  290. package/src/page/toc-link.js +31 -0
  291. package/src/page/toc.js +5 -0
  292. package/src/page/view-hooks.js +38 -12
  293. package/src/page/view.js +13 -0
  294. package/src/page/ybind/binding.js +88 -5
  295. package/src/page/ybind/bridge.js +187 -20
  296. package/src/page/ybind/containment.js +162 -0
  297. package/src/page/ybind/doc.js +17 -9
  298. package/src/page/ybind/file-debt.js +63 -0
  299. package/src/page/ybind/layout.js +7 -2
  300. package/src/page/ybind/marks.js +1 -1
  301. package/src/page/ybind/moves.js +5 -4
  302. package/src/page/ybind/origins.js +106 -4
  303. package/src/page/ybind/parts.js +8 -1
  304. package/src/page/ybind/provider.js +113 -17
  305. package/src/page/ybind/recovery-proof.js +32 -9
  306. package/src/page/ybind/recovery-replay.js +558 -15
  307. package/src/page/ybind/recovery.js +174 -45
  308. package/src/page/ybind/table.js +67 -11
  309. package/src/page/ybind/walk-delta.js +258 -0
  310. package/src/page/ybind/walk.js +54 -29
  311. package/src/page/ybind/writer.js +1 -1
  312. package/src/plugins/ai-edit.js +13 -9
  313. package/src/plugins/indicator-chip.js +91 -0
  314. package/src/plugins/indicator.js +13 -80
  315. package/src/plugins/live.js +89 -14
  316. package/src/plugins/menu/actions.js +196 -0
  317. package/src/plugins/menu/people.js +279 -0
  318. package/src/plugins/menu/placement.js +121 -0
  319. package/src/plugins/menu/preferences.js +9 -0
  320. package/src/plugins/menu/seo.js +316 -397
  321. package/src/plugins/menu/style.js +171 -0
  322. package/src/plugins/menu/variants.js +296 -0
  323. package/src/plugins/menu.js +186 -183
  324. package/src/plugins/page-view.js +3 -2
  325. package/src/plugins/page.js +249 -44
  326. package/src/plugins/sortable.js +8 -1
  327. package/src/plugins/source.js +6 -0
  328. package/src/plugins/upgrade.js +51 -17
  329. package/src/plugins/upload-ui.js +12 -17
  330. package/src/plugins/visitor-drafts/bottom-ui.js +12 -4
  331. package/src/plugins/visitor-drafts/intro-style.js +7 -2
  332. package/src/plugins/visitor-drafts/intro.js +5 -3
  333. package/src/plugins/visitor-drafts/owner-chip.js +8 -12
  334. package/src/plugins/visitor-drafts/prompt.js +11 -9
  335. package/src/plugins/visitor-drafts/source.js +4 -3
  336. package/src/plugins/visitor-drafts/store.js +138 -9
  337. package/src/plugins/visitor-drafts/ui-memory.js +2 -2
  338. package/src/plugins/visitor-drafts-owner.js +4 -6
  339. package/src/plugins/visitor-drafts.js +5 -3
  340. package/src/recovery/store.js +1 -1
  341. package/src/route/route.js +4 -0
  342. package/src/server/rooms/index.js +5 -1
  343. package/src/server/rooms/live-data-rooms.js +302 -50
  344. package/src/server/rooms/page-compaction-worker.js +12 -0
  345. package/src/server/rooms/page-compactor.js +92 -0
  346. package/src/server/rooms/page-room-conformance.js +461 -0
  347. package/src/source/parse-steps.js +94 -0
  348. package/src/source/session.js +233 -57
  349. package/src/sync/editing-sender.js +12 -0
  350. package/src/sync/live-sync-edit.js +22 -2
  351. package/src/sync/live-sync.js +150 -23
  352. package/src/sync/page-relay.js +52 -0
  353. package/src/sync/presence-store.js +44 -4
  354. package/src/sync/presence.js +6 -3
  355. package/src/sync/saved-stream.js +11 -6
  356. package/src/ui/bevel-controls.js +1 -0
  357. package/src/ui/bevel-dialog.js +5 -2
  358. package/src/ui/editor-ui.js +77 -0
  359. package/src/ui/page-colour.js +281 -0
  360. package/src/ui/toast.js +16 -7
  361. package/src/vendor/hyper-html-api-upgrade.vendor.js +2 -2
  362. package/src/vendor/hyper-undo.vendor.js +1 -1
  363. package/src/vendor/hypercms.vendor.js +9 -9
  364. package/src/vendor/parse5.vendor.js +2 -2
  365. package/src/vendor/sap-core.vendor.js +5 -5
  366. package/dist/m/c-2SPVQSHC.js +0 -1
  367. package/dist/m/c-336SGU5W.js +0 -1
  368. package/dist/m/c-3H6BZDNJ.js +0 -6
  369. package/dist/m/c-4DFEJ2PO.js +0 -3
  370. package/dist/m/c-56QRZTZH.js +0 -1
  371. package/dist/m/c-5J4E7O4Y.js +0 -4
  372. package/dist/m/c-5LKDWQTL.js +0 -19
  373. package/dist/m/c-5V3MOVJT.js +0 -1
  374. package/dist/m/c-6AZOGAPE.js +0 -1
  375. package/dist/m/c-6CRUUXOX.js +0 -5
  376. package/dist/m/c-6HMB24EV.js +0 -1
  377. package/dist/m/c-6KEVEQ7L.js +0 -1
  378. package/dist/m/c-A3E3NIMC.js +0 -1
  379. package/dist/m/c-BQ6LOBEE.js +0 -1
  380. package/dist/m/c-BTDI4Y23.js +0 -1
  381. package/dist/m/c-CJ3A7ZKE.js +0 -1
  382. package/dist/m/c-CQHPGKX2.js +0 -1
  383. package/dist/m/c-DFS4XZJV.js +0 -2
  384. package/dist/m/c-DNENWY4O.js +0 -1
  385. package/dist/m/c-E4LIR5X5.js +0 -1
  386. package/dist/m/c-FDNHHZY5.js +0 -1
  387. package/dist/m/c-FROJUZMV.js +0 -1
  388. package/dist/m/c-G2JPKCTP.js +0 -1
  389. package/dist/m/c-GB6TU7WV.js +0 -1
  390. package/dist/m/c-GFJJEBTU.js +0 -1
  391. package/dist/m/c-GJAEGGXY.js +0 -1
  392. package/dist/m/c-GOWBDM6J.js +0 -1
  393. package/dist/m/c-HFKUVACH.js +0 -1
  394. package/dist/m/c-HHDFCNHV.js +0 -1
  395. package/dist/m/c-IEM4NTCS.js +0 -1
  396. package/dist/m/c-JDCX26UP.js +0 -25
  397. package/dist/m/c-KGVGROZT.js +0 -1
  398. package/dist/m/c-KQ6TYJAP.js +0 -135
  399. package/dist/m/c-LFPHCXY3.js +0 -1
  400. package/dist/m/c-LRPUO2MX.js +0 -1
  401. package/dist/m/c-LWLBHLVC.js +0 -3
  402. package/dist/m/c-M2L47S2X.js +0 -7
  403. package/dist/m/c-MFP2ZWD4.js +0 -1
  404. package/dist/m/c-MKSQ4Y57.js +0 -1
  405. package/dist/m/c-NUFFJVVJ.js +0 -1
  406. package/dist/m/c-NUHSPT5P.js +0 -1
  407. package/dist/m/c-O72HVYSA.js +0 -1
  408. package/dist/m/c-OIBUTDXI.js +0 -1
  409. package/dist/m/c-OW5QIGG3.js +0 -1
  410. package/dist/m/c-PGRCK73F.js +0 -1
  411. package/dist/m/c-Q7NQD65V.js +0 -1
  412. package/dist/m/c-QH63LQOS.js +0 -1
  413. package/dist/m/c-R7IWVINQ.js +0 -1
  414. package/dist/m/c-RM7J7BV2.js +0 -1
  415. package/dist/m/c-S4ZEH46B.js +0 -9
  416. package/dist/m/c-SDAXDM2D.js +0 -1
  417. package/dist/m/c-SMGU7RT3.js +0 -235
  418. package/dist/m/c-SPIORRYS.js +0 -1
  419. package/dist/m/c-SWLRT66R.js +0 -1
  420. package/dist/m/c-TCJTVAFN.js +0 -1
  421. package/dist/m/c-TQEMVJCS.js +0 -1
  422. package/dist/m/c-TYLXX4NF.js +0 -21
  423. package/dist/m/c-U62OB4BT.js +0 -1
  424. package/dist/m/c-U6YWUAR3.js +0 -8
  425. package/dist/m/c-UDCSU5G5.js +0 -2
  426. package/dist/m/c-VI5RMSVY.js +0 -1
  427. package/dist/m/c-VRZN56XY.js +0 -1
  428. package/dist/m/c-W5MCHEGA.js +0 -1
  429. package/dist/m/c-WNYBLIOZ.js +0 -1
  430. package/dist/m/c-WWXIDH4O.js +0 -28
  431. package/dist/m/c-XCNTK76U.js +0 -1
  432. package/dist/m/c-XMS6DPBR.js +0 -1
  433. package/dist/m/c-ZUCOKOHT.js +0 -1
  434. package/dist/m/c-ZVPVXTJF.js +0 -4
  435. package/dist/m/c-ZVRKXKM7.js +0 -1
  436. package/dist/m/core/autosave-HRYGUWV6.js +0 -1
  437. package/dist/m/core/conflict-notice-6MROJN2L.js +0 -1
  438. package/dist/m/core/is-edit-mode-KTWA3O5N.js +0 -1
  439. package/dist/m/core/recovery-FLTCC2OC.js +0 -1
  440. package/dist/m/core/save-HQZ4S667.js +0 -1
  441. package/dist/m/core/save-core-KGQWFUNH.js +0 -1
  442. package/dist/m/core/snapshot-EGQZNT45.js +0 -1
  443. package/dist/m/core/unsaved-warning-IDJLD66H.js +0 -1
  444. package/dist/m/loader-S4I7GKXR.js +0 -1
  445. package/dist/m/manifest-4C419D67.js +0 -1
  446. package/dist/m/manifest-edit-B077F288.js +0 -1
  447. package/dist/m/plugins/ai-edit-QN4PMMNL.js +0 -6
  448. package/dist/m/plugins/indicator-URDBBOQO.js +0 -1
  449. package/dist/m/plugins/live-HFWD4OIH.js +0 -1
  450. package/dist/m/plugins/menu-3HIEQSI6.js +0 -138
  451. package/dist/m/plugins/page-JOKB6XPR.js +0 -2
  452. package/dist/m/plugins/page-view-NXOJHNW6.js +0 -1
  453. package/dist/m/plugins/quickcrop-QNY3PKLD.js +0 -26
  454. package/dist/m/plugins/sortable-GWT4PWDV.js +0 -1
  455. package/dist/m/plugins/source-4ZRSAIYM.js +0 -1
  456. package/dist/m/plugins/undo-VDA5P7FH.js +0 -1
  457. package/dist/m/plugins/upgrade-W7FG5VFG.js +0 -1
  458. package/dist/m/plugins/visitor-drafts-LIDY7NH6.js +0 -21
  459. package/dist/m/plugins/visitor-drafts-owner-ZXCKBZE7.js +0 -1
  460. package/dist/m/reader-core-DXYCURFF.js +0 -68
  461. package/dist/m/route/route-KOCZSEGN.js +0 -1
  462. package/dist/m/sync/live-sync-J7VMYTKS.js +0 -1
  463. package/dist/m/ui/index-3JLVI27O.js +0 -1
  464. package/dist/m/vendor/sap-core.vendor-A7BMUYZT.js +0 -6
  465. /package/dist/m/{c-FILLTJA7.js → c-QTTJYJMA.js} +0 -0
  466. /package/dist/m/plugins/{quickcrop-QNY3PKLD.js.LEGAL.txt → quickcrop-BQ5YYFCH.js.LEGAL.txt} +0 -0
  467. /package/dist/m/plugins/{richclay-NRQDSWX6.js.LEGAL.txt → richclay-KLGETK77.js.LEGAL.txt} +0 -0
@@ -31176,6 +31176,8 @@ module.exports = __toCommonJS(server_core_exports);
31176
31176
  // src/server/rooms/index.js
31177
31177
  var rooms_exports = {};
31178
31178
  __export(rooms_exports, {
31179
+ COMPACTION: () => COMPACTION,
31180
+ COMPACTOR: () => COMPACTOR,
31179
31181
  LIVE_LIMITS: () => LIVE_LIMITS,
31180
31182
  PAGE_FORMAT: () => PAGE_FORMAT,
31181
31183
  PAGE_FORMAT_EXTENSION: () => PAGE_FORMAT_EXTENSION,
@@ -31187,6 +31189,7 @@ __export(rooms_exports, {
31187
31189
  RANGE_LIMIT: () => RANGE_LIMIT,
31188
31190
  RECEIPT_LIMIT: () => RECEIPT_LIMIT,
31189
31191
  REFUSED_MS: () => REFUSED_MS,
31192
+ ROOM_ERROR_STATUS: () => ROOM_ERROR_STATUS,
31190
31193
  applyOp: () => applyOp,
31191
31194
  applyOps: () => applyOps,
31192
31195
  applyTracked: () => applyTracked,
@@ -31203,6 +31206,7 @@ __export(rooms_exports, {
31203
31206
  coalesce: () => coalesce,
31204
31207
  composePage: () => composePage,
31205
31208
  contains: () => contains2,
31209
+ createPageCompactor: () => createPageCompactor,
31206
31210
  createRooms: () => createRooms,
31207
31211
  descendants: () => descendants,
31208
31212
  diffOps: () => diffOps,
@@ -31220,6 +31224,7 @@ __export(rooms_exports, {
31220
31224
  makePageTransition: () => makePageTransition,
31221
31225
  overlaps: () => overlaps,
31222
31226
  pageBaseline: () => pageBaseline,
31227
+ pageCompactionWorkerUrl: () => pageCompactionWorkerUrl,
31223
31228
  pageFormatFloor: () => pageFormatFloor,
31224
31229
  pageLineageLost: () => pageLineageLost,
31225
31230
  pageRev: () => pageRev,
@@ -36588,8 +36593,8 @@ function filterParsed(selector, elements, options) {
36588
36593
  }
36589
36594
  for (let i = 0; i < filteredSelectors.length && (found === null || found === void 0 ? void 0 : found.size) !== elements.length; i++) {
36590
36595
  const filteredSelector = filteredSelectors[i];
36591
- const missing = found ? elements.filter((e19) => isTag2(e19) && !found.has(e19)) : elements;
36592
- if (missing.length === 0)
36596
+ const missing2 = found ? elements.filter((e19) => isTag2(e19) && !found.has(e19)) : elements;
36597
+ if (missing2.length === 0)
36593
36598
  break;
36594
36599
  const filtered = filterBySelector(filteredSelector, elements, options);
36595
36600
  if (filtered.length) {
@@ -52343,8 +52348,8 @@ function Aa(r44, e19, t, n, i) {
52343
52348
  let O2 = r44.input.lastSelectionTime > Date.now() - 50 ? r44.input.lastSelectionOrigin : null, I2 = rr(r44, O2);
52344
52349
  if (I2 && !r44.state.selection.eq(I2)) {
52345
52350
  if (B && me && r44.input.lastKeyCode === 13 && Date.now() - 100 < r44.input.lastKeyCodeTime && r44.someProp("handleKeyDown", (xo2) => xo2(r44, Be(13, "Enter")))) return;
52346
- let H = r44.state.tr.setSelection(I2);
52347
- O2 == "pointer" ? H.setMeta("pointer", true) : O2 == "key" && H.scrollIntoView(), s && H.setMeta("composition", s), r44.dispatch(H);
52351
+ let H2 = r44.state.tr.setSelection(I2);
52352
+ O2 == "pointer" ? H2.setMeta("pointer", true) : O2 == "key" && H2.scrollIntoView(), s && H2.setMeta("composition", s), r44.dispatch(H2);
52348
52353
  }
52349
52354
  return;
52350
52355
  }
@@ -52386,8 +52391,8 @@ function Aa(r44, e19, t, n, i) {
52386
52391
  let N2 = p.start, re2 = p.endA, De2 = (O2) => {
52387
52392
  let I2 = O2 || r44.state.tr.replace(N2, re2, f.doc.slice(p.start - f.from, p.endB - f.from));
52388
52393
  if (f.sel) {
52389
- let H = Yi(r44, I2.doc, f.sel);
52390
- H && !(B && r44.composing && H.empty && (p.start != p.endB || r44.input.lastChromeDelete < Date.now() - 100) && (H.head == N2 || H.head == I2.mapping.map(re2) - 1) || G && H.empty && H.head == N2) && I2.setSelection(H);
52394
+ let H2 = Yi(r44, I2.doc, f.sel);
52395
+ H2 && !(B && r44.composing && H2.empty && (p.start != p.endB || r44.input.lastChromeDelete < Date.now() - 100) && (H2.head == N2 || H2.head == I2.mapping.map(re2) - 1) || G && H2.empty && H2.head == N2) && I2.setSelection(H2);
52391
52396
  }
52392
52397
  return s && I2.setMeta("composition", s), I2.scrollIntoView();
52393
52398
  }, Pt2;
@@ -52400,7 +52405,7 @@ function Aa(r44, e19, t, n, i) {
52400
52405
  Pt2.type == "add" ? O2.addMark(N2, re2, Pt2.mark) : O2.removeMark(N2, re2, Pt2.mark), r44.dispatch(O2);
52401
52406
  } else if (m2.parent.child(m2.index()).isText && m2.index() == g2.index() - (g2.textOffset ? 0 : 1)) {
52402
52407
  let O2 = m2.parent.textBetween(m2.parentOffset, g2.parentOffset), I2 = () => De2(r44.state.tr.insertText(O2, N2, re2));
52403
- r44.someProp("handleTextInput", (H) => H(r44, N2, re2, O2, I2)) || r44.dispatch(I2());
52408
+ r44.someProp("handleTextInput", (H2) => H2(r44, N2, re2, O2, I2)) || r44.dispatch(I2());
52404
52409
  } else r44.dispatch(De2());
52405
52410
  else r44.dispatch(De2());
52406
52411
  }
@@ -53806,6 +53811,7 @@ function safeHref(raw) {
53806
53811
  if (/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(s)) return `mailto:${s}`;
53807
53812
  return null;
53808
53813
  }
53814
+ var safeSrc = (s) => s && /^data:image\/(png|jpeg|gif|webp);/i.test(s) && s.length <= 21e5 ? s : safeHref(s);
53809
53815
  function safeFileHref(raw) {
53810
53816
  if (typeof raw !== "string") return null;
53811
53817
  const href = safeHref(raw);
@@ -53828,7 +53834,15 @@ var schema = new Qr.Schema({
53828
53834
  group: "block",
53829
53835
  content: "inline*",
53830
53836
  defining: true,
53831
- attrs: { ...block, level: { default: 2 } },
53837
+ attrs: {
53838
+ ...block,
53839
+ level: { default: 2 },
53840
+ pageIcon: { default: null },
53841
+ pageCoverSrc: { default: null },
53842
+ pageCoverAlt: { default: "" },
53843
+ pageCoverX: { default: 50 },
53844
+ pageCoverY: { default: 50 }
53845
+ },
53832
53846
  toDOM: (n) => [`h${n.attrs.level}`, ref(n), 0]
53833
53847
  },
53834
53848
  list_item: {
@@ -53873,8 +53887,8 @@ var schema = new Qr.Schema({
53873
53887
  toggle: {
53874
53888
  group: "block",
53875
53889
  content: "inline*",
53876
- attrs: { ...block, open: { default: false } },
53877
- toDOM: (n) => ["div", ref(n, { class: "page-toggle", "data-open": n.attrs.open ? "true" : "false" }), 0]
53890
+ attrs: { ...block, open: { default: false }, level: { default: null } },
53891
+ toDOM: (n) => ["div", ref(n, { class: "page-toggle", "data-open": n.attrs.open ? "true" : "false", ...n.attrs.level ? { "data-level": String(n.attrs.level) } : {} }), 0]
53878
53892
  },
53879
53893
  divider: {
53880
53894
  group: "block",
@@ -53882,6 +53896,14 @@ var schema = new Qr.Schema({
53882
53896
  attrs: block,
53883
53897
  toDOM: (n) => ["hr", ref(n)]
53884
53898
  },
53899
+ // A table of contents holds no headings: its entries are derived from the document
53900
+ // whenever it is drawn, so a rename, a move or a deletion needs no repair here.
53901
+ toc: {
53902
+ group: "block",
53903
+ atom: true,
53904
+ attrs: { ...block, maxLevel: { default: null } },
53905
+ toDOM: (n) => ["div", ref(n, { class: "page-toc", "data-type": "toc", ...n.attrs.maxLevel ? { "data-max-level": String(n.attrs.maxLevel) } : {} })]
53906
+ },
53885
53907
  image: {
53886
53908
  group: "block",
53887
53909
  atom: true,
@@ -54348,13 +54370,15 @@ function ticks(min, max, count) {
54348
54370
  for (let n = Math.ceil(min / step); n <= Math.floor(max / step); n++) out.push(Number((n * step).toPrecision(12)));
54349
54371
  return out.length ? out : [Number(min.toFixed(2)), Number(max.toFixed(2))];
54350
54372
  }
54373
+ var missing = (chart, reason) => ({ state: "missing", reason, sourceId: chart.source ?? null, title: chart.title ?? "" });
54351
54374
  function chartModel(chart, table) {
54352
- if (!table) return { state: "missing", reason: "table" };
54375
+ if (!table) return missing(chart, "table");
54353
54376
  const cols = table.cols ?? [];
54354
54377
  const rows = table.rows ?? [];
54355
54378
  const x3 = cols.find((col) => col.id === chart.x);
54356
- if (!x3 || !chart.series?.length || chart.series.some((id) => !cols.some((col) => col.id === id))) return { state: "missing", reason: "column" };
54357
- const series = chart.series.map((id, index2) => {
54379
+ if (!x3 || !chart.series?.length || chart.series.some((id) => !cols.some((col) => col.id === id))) return missing(chart, "column");
54380
+ const plotted = chart.type === "pie" ? chart.series.slice(0, 1) : chart.series;
54381
+ const series = plotted.map((id, index2) => {
54358
54382
  const col = cols.find((item) => item.id === id);
54359
54383
  const points2 = rows.map((row, rowIndex) => ({
54360
54384
  id: `${chart.id}:${row.id}:${id}`,
@@ -54392,8 +54416,60 @@ function chartModel(chart, table) {
54392
54416
  domain: [min, max]
54393
54417
  };
54394
54418
  }
54419
+ var PIE = { width: 560, height: 232, cx: 150, cy: 116, radius: 84 };
54420
+ var PIE_COLOURS = 6;
54421
+ var pieHeight = (rows) => Math.max(PIE.height, 54 + (rows - 1) * 36 + 24);
54422
+ function chartCaption(series) {
54423
+ const valid = series.points.filter((point) => point.value !== null);
54424
+ return `${series.name}: ${valid.length ? `${fmt(valid[0].value)} to ${fmt(valid.at(-1).value)}` : "no values"}`;
54425
+ }
54426
+ function pieSlices(model) {
54427
+ const series = model.series[0];
54428
+ if (!series) return [];
54429
+ const positive = series.points.filter((point) => point.value !== null && point.value > 0);
54430
+ const total = positive.reduce((sum, point) => sum + point.value, 0);
54431
+ if (!total) return [];
54432
+ const points = positive.length <= PIE_COLOURS ? positive : [
54433
+ ...positive.slice(0, PIE_COLOURS - 1),
54434
+ { id: `${positive[0].id.split(":")[0]}:other`, xLabel: "Other", value: positive.slice(PIE_COLOURS - 1).reduce((sum, point) => sum + point.value, 0), highlight: positive.slice(PIE_COLOURS - 1).some((point) => point.highlight) }
54435
+ ];
54436
+ let angle = -Math.PI / 2;
54437
+ return points.map((point, index2) => {
54438
+ const fraction = point.value / total;
54439
+ const slice2 = { point, color: `var(--chart-${index2 % 6 + 1})`, fraction, percent: Math.round(fraction * 100), from: angle, to: angle + fraction * Math.PI * 2 };
54440
+ angle = slice2.to;
54441
+ return slice2;
54442
+ });
54443
+ }
54444
+ function renderPie(model, slices, width) {
54445
+ const box = pieHeight(slices.length);
54446
+ const height = fmt(width * box / PIE.width);
54447
+ const caption = model.series[0] ? chartCaption(model.series[0]) : "no values";
54448
+ const parts = [`<svg xmlns="http://www.w3.org/2000/svg" role="img" width="${width}" height="${height}" viewBox="0 0 ${PIE.width} ${box}">`, `<title>${esc(model.title)}</title>`, `<desc>${esc(caption)}</desc>`];
54449
+ if (!slices.length) parts.push(`<text x="${PIE.width / 2}" y="${PIE.cy}" text-anchor="middle">No positive values to chart</text>`);
54450
+ slices.forEach((slice2) => {
54451
+ const point = ` data-point="${esc(slice2.point.id)}"${slice2.point.highlight ? ' data-highlight="true"' : ""}`;
54452
+ if (slice2.fraction >= 0.999) {
54453
+ parts.push(`<circle${point} cx="${PIE.cx}" cy="${PIE.cy}" r="${PIE.radius}" fill="${slice2.color}"/>`);
54454
+ return;
54455
+ }
54456
+ const x1 = fmt(PIE.cx + PIE.radius * Math.cos(slice2.from));
54457
+ const y1 = fmt(PIE.cy + PIE.radius * Math.sin(slice2.from));
54458
+ const x22 = fmt(PIE.cx + PIE.radius * Math.cos(slice2.to));
54459
+ const y2 = fmt(PIE.cy + PIE.radius * Math.sin(slice2.to));
54460
+ parts.push(`<path${point} d="M ${PIE.cx} ${PIE.cy} L ${x1} ${y1} A ${PIE.radius} ${PIE.radius} 0 ${slice2.fraction > 0.5 ? 1 : 0} 1 ${x22} ${y2} Z" fill="${slice2.color}" stroke="var(--page-bg)" stroke-width="2"/>`);
54461
+ });
54462
+ slices.forEach((slice2, index2) => {
54463
+ const yy = fmt(54 + index2 * 36);
54464
+ const point = ` data-point="${esc(slice2.point.id)}"${slice2.point.highlight ? ' data-highlight="true"' : ""}`;
54465
+ parts.push(`<g${point}><rect x="290" y="${fmt(54 + index2 * 36 - 10)}" width="11" height="11" fill="${slice2.color}"/><text x="310" y="${yy}">${esc(slice2.point.xLabel)}</text><text x="530" y="${yy}" text-anchor="end">${fmt(slice2.point.value)} (${slice2.percent}%)</text></g>`);
54466
+ });
54467
+ parts.push("</svg>");
54468
+ return parts.join("");
54469
+ }
54395
54470
  function renderChartSvg(model, { width = 640, height = 320, narrow = false } = {}) {
54396
54471
  if (model.state === "missing") return `<svg xmlns="http://www.w3.org/2000/svg" role="img" width="${width}" height="80" viewBox="0 0 ${width} 80"><title>Chart source missing</title><text x="12" y="44">Chart source missing</text></svg>`;
54472
+ if (model.type === "pie") return renderPie(model, pieSlices(model), width);
54397
54473
  const margin = { left: 52, right: 72, top: 28, bottom: 48 };
54398
54474
  const plotW = Math.max(1, width - margin.left - margin.right);
54399
54475
  const plotH = Math.max(1, height - margin.top - margin.bottom);
@@ -54402,10 +54478,7 @@ function renderChartSvg(model, { width = 640, height = 320, narrow = false } = {
54402
54478
  const n = model.xLabels.length;
54403
54479
  const x3 = (index2) => margin.left + (n <= 1 ? plotW / 2 : index2 * plotW / (n - 1));
54404
54480
  const parts = [`<svg xmlns="http://www.w3.org/2000/svg" role="img" width="${width}" height="${height}" viewBox="0 0 ${width} ${height}">`, `<title>${esc(model.title)}</title>`];
54405
- const caption = model.series.map((item) => {
54406
- const valid = item.points.filter((point) => point.value !== null);
54407
- return `${item.name}: ${valid.length ? `${fmt(valid[0].value)} to ${fmt(valid.at(-1).value)}` : "no values"}`;
54408
- }).join("; ");
54481
+ const caption = model.series.map(chartCaption).join("; ");
54409
54482
  parts.push(`<desc>${esc(caption)}</desc>`);
54410
54483
  for (const tick of narrow ? model.narrowTicks : model.yTicks) {
54411
54484
  const yy = fmt(y2(tick));
@@ -54474,13 +54547,14 @@ var STRUCTURAL = /* @__PURE__ */ new Set(["id", "t", "parent", "c", "m"]);
54474
54547
  var knownType = (t) => Object.hasOwn(DEFAULTS, t);
54475
54548
  var DEFAULTS = {
54476
54549
  paragraph: { parent: null },
54477
- heading: { parent: null, level: 2 },
54550
+ heading: { parent: null, level: 2, pageIcon: null, pageCoverSrc: null, pageCoverAlt: "", pageCoverX: 50, pageCoverY: 50 },
54478
54551
  list_item: { parent: null, kind: "bullet", indent: 0, checked: false, owner: null, due: null },
54479
54552
  callout: { parent: null },
54480
54553
  quote: { parent: null },
54481
54554
  code_block: { parent: null, lang: "" },
54482
- toggle: { parent: null, open: false },
54555
+ toggle: { parent: null, open: false, level: null },
54483
54556
  divider: { parent: null },
54557
+ toc: { parent: null, maxLevel: null },
54484
54558
  image: { parent: null, src: "", alt: "", caption: "", width: null, align: null },
54485
54559
  file: { parent: null, src: "", name: "", size: null, mime: null },
54486
54560
  table: { parent: null, cols: {}, sort: null },
@@ -54490,6 +54564,39 @@ var DEFAULTS = {
54490
54564
  preserved: { parent: null, html: "" }
54491
54565
  };
54492
54566
  var TEXT = /* @__PURE__ */ new Set(["paragraph", "heading", "list_item", "callout", "quote", "code_block", "toggle"]);
54567
+ var TOC_LABEL = "Table of contents";
54568
+ var TOC_ANCHOR = "page-block-";
54569
+ var blockAnchor = (id) => `${TOC_ANCHOR}${b64url(String(id ?? ""))}`;
54570
+ var TOC_MAX_LEVEL = 3;
54571
+ var tocLevel = (item) => item.t === "heading" ? Math.min(6, Math.max(1, Number.isInteger(item.level) ? item.level : 2)) : item.t === "toggle" && (item.level === 1 || item.level === 2 || item.level === 3) ? item.level : 0;
54572
+ var tocTitle = (item) => item.t === "heading" && (item.level ?? 2) === 1 && (item.parent ?? null) === null;
54573
+ var tocMax = (value) => Number.isInteger(value) && value >= 1 && value <= 6 ? value : TOC_MAX_LEVEL;
54574
+ var tocText = (item) => String(item.c ?? "").replace(/[\s\uFFFC]+/gu, " ").trim() || "Untitled";
54575
+ function tocEntries(model, maxLevel = TOC_MAX_LEVEL) {
54576
+ const max = tocMax(maxLevel);
54577
+ const title = model.find(tocTitle) ?? null;
54578
+ const out = [];
54579
+ for (const item of model) {
54580
+ const level3 = tocLevel(item);
54581
+ if (!item.id || !level3 || level3 > max || item === title) continue;
54582
+ out.push({ id: item.id, level: level3, text: tocText(item) });
54583
+ }
54584
+ return out;
54585
+ }
54586
+ function tocHtml(item, model) {
54587
+ const entries = tocEntries(model, item.maxLevel);
54588
+ const root2 = { level: 0, children: [] };
54589
+ const stack = [root2];
54590
+ for (const entry of entries) {
54591
+ while (stack.length > 1 && stack[stack.length - 1].level >= entry.level) stack.pop();
54592
+ const node = { ...entry, children: [] };
54593
+ stack[stack.length - 1].children.push(node);
54594
+ stack.push(node);
54595
+ }
54596
+ const list = (nodes) => `<ul>${nodes.map((node) => `<li><a href="#${blockAnchor(node.id)}">${escText(node.text)}</a>${node.children.length ? list(node.children) : ""}</li>`).join("")}</ul>`;
54597
+ const level3 = item.maxLevel == null ? "" : ` data-max-level="${escAttr(item.maxLevel)}"`;
54598
+ return `<nav aria-label="${TOC_LABEL}" data-type="toc" data-id="${escAttr(item.id ?? "")}"${level3}>${entries.length ? list(root2.children) : ""}</nav>`;
54599
+ }
54493
54600
  var same = (a, b2) => canon(a) === canon(b2);
54494
54601
  function orderedIds(map2) {
54495
54602
  return Object.keys(map2).sort((x3, y2) => {
@@ -54674,6 +54781,7 @@ var omitDefaults = (t, fields) => {
54674
54781
  for (const [k2, v3] of Object.entries(fields)) if (!(k2 in DEFAULTS[t]) || !same(v3, DEFAULTS[t][k2])) out[k2] = v3;
54675
54782
  return out;
54676
54783
  };
54784
+ var focal = (v3) => Math.min(100, Math.max(0, Number.isFinite(+v3) && v3 !== null && v3 !== "" ? +v3 : 50));
54677
54785
  var columnWidth = (value) => typeof value === "number" && Number.isFinite(value) && value > 0 ? Math.round(value) : null;
54678
54786
  function cellModel(value) {
54679
54787
  if (value === null || typeof value !== "object" || typeof value.c !== "string") return normalizeText(cellText(value), null).c;
@@ -54712,9 +54820,10 @@ var recordOfItem = (item) => {
54712
54820
  const { t, parent: _p, id: _i3, ...fields } = item;
54713
54821
  return { t, ...fields };
54714
54822
  };
54823
+ var VISIBLE = { table: /* @__PURE__ */ new Set(["rows"]) };
54715
54824
  var extrasOfItem = (item) => {
54716
54825
  const out = {};
54717
- for (const [k2, v3] of Object.entries(item)) if (!STRUCTURAL.has(k2) && !(knownType(item.t) && Object.hasOwn(DEFAULTS[item.t], k2))) out[k2] = v3;
54826
+ for (const [k2, v3] of Object.entries(item)) if (!STRUCTURAL.has(k2) && !VISIBLE[item.t]?.has(k2) && !(knownType(item.t) && Object.hasOwn(DEFAULTS[item.t], k2))) out[k2] = v3;
54718
54827
  return Object.keys(out).length ? envelopeOf(out) : "";
54719
54828
  };
54720
54829
  var extrasOfBlock = (t, b2) => {
@@ -54738,7 +54847,8 @@ function projectOne({ id, b: b2, t, parent: parent2, indent }) {
54738
54847
  for (const k2 of Object.keys(extras)) delete attrs[k2];
54739
54848
  const fields = { ...attrs, parent: parent2 };
54740
54849
  if (t === "list_item") fields.indent = indent;
54741
- if (t === "heading") fields.level = clampLevel(attrs.level ?? 2);
54850
+ if (t === "heading") Object.assign(fields, { level: clampLevel(attrs.level ?? 2), pageCoverSrc: safeSrc(fields.pageCoverSrc ?? null), pageCoverX: focal(fields.pageCoverX), pageCoverY: focal(fields.pageCoverY) });
54851
+ if (t === "toggle") fields.level = toggleLevel(attrs.level);
54742
54852
  if (t === "image" && fields.width != null) fields.width = widthOf(String(fields.width));
54743
54853
  if (t === "image") fields.align = alignOf(fields.align);
54744
54854
  if (t === "image" && typeof fields.caption === "string") fields.caption = normalizeText(fields.caption, null).c;
@@ -54766,7 +54876,21 @@ function projectOne({ id, b: b2, t, parent: parent2, indent }) {
54766
54876
  }
54767
54877
  return item;
54768
54878
  }
54879
+ function knownRecordItem(id, record5, parent2) {
54880
+ const { t } = record5;
54881
+ const malformed = new SyntaxError(`page: an envelope names the known block type ${t}`);
54882
+ if (TEXT.has(t) ? record5.c != null && typeof record5.c !== "string" : record5.c != null || record5.m != null) throw malformed;
54883
+ let item;
54884
+ try {
54885
+ item = projectOne({ id, b: record5, t, parent: parent2, indent: 0 });
54886
+ } catch {
54887
+ throw malformed;
54888
+ }
54889
+ const fields = DEFAULTS[t];
54890
+ return Object.fromEntries(Object.entries(item).filter(([k2]) => k2 === "id" || k2 === "t" || STRUCTURAL.has(k2) || k2 === "rows" || Object.hasOwn(fields, k2)));
54891
+ }
54769
54892
  var clampLevel = (l) => Math.min(6, Math.max(1, Number.isInteger(l) ? l : 2));
54893
+ var toggleLevel = (l) => l === 1 || l === 2 || l === 3 ? l : null;
54770
54894
  var widthOf = (s) => /^\d+$/.test(s) ? Number(s) : s;
54771
54895
  var alignOf = (a) => a === "left" || a === "right" ? a : null;
54772
54896
  function project(blocks) {
@@ -54828,7 +54952,9 @@ function renderInline(c, m2, marksEnvelopes = true) {
54828
54952
  return html3;
54829
54953
  }
54830
54954
  var inlineOf = (item) => renderInline(item.c ?? "", item.m);
54955
+ var titleHtml = (item) => `<header${attr2("data-id", item.id)} data-page-heading="1"${extrasOfItem(item)}>${item.pageCoverSrc ? `<img data-page-cover${attr2("src", item.pageCoverSrc)}${attr2("alt", item.pageCoverAlt ?? "")} style="object-position:${item.pageCoverX ?? 50}% ${item.pageCoverY ?? 50}%">` : ""}${item.pageIcon ? `<span data-page-icon aria-hidden="true">${escText(item.pageIcon)}</span>` : ""}<h1>${inlineOf(item)}</h1></header>`;
54831
54956
  var toolData = (item) => item.artifact || item.rev || item.state && Object.keys(item.state).length ? `<script type="application/json" data-tool>${canon({ artifact: item.artifact ?? null, rev: item.rev ?? null, state: item.state ?? {} }).replace(/</g, "\\u003c")}</script>` : "";
54957
+ var headerId = (tableId, colId) => `${tableId}-${colId}`;
54832
54958
  var cellHtml = (cell) => typeof cell === "string" ? escText(cell) : cell && typeof cell === "object" ? renderInline(String(cell.c ?? ""), cell.m) : "";
54833
54959
  var dataAttrs = (obj) => Object.entries(obj).map(([k2, v3]) => attr2(`data-${k2}`, v3)).join("");
54834
54960
  function renderLeaf(item, clean, tables) {
@@ -54857,9 +54983,12 @@ function renderLeaf(item, clean, tables) {
54857
54983
  return `<div${at2} data-type="file"${attr2("data-src", item.src ?? "")}${attr2("data-name", item.name ?? "")}${attr2("data-size", item.size ?? null)}${attr2("data-mime", item.mime ?? null)}><a${attr2("href", href)} rel="noopener noreferrer">${escText(item.name || "file")}</a></div>`;
54858
54984
  }
54859
54985
  case "table": {
54860
- const head = item.cols.map((c) => `<th${attr2("data-col", c.id)}${attr2("data-kind", c.kind ?? null)}${attr2("data-width", c.width ?? null)}${attr2("style", c.width ? `width:${c.width}px` : null)}>${escText(c.name)}</th>`).join("");
54861
- const body = item.rows.map((r44) => `<tr${attr2("data-id", r44.id)}>${item.cols.map((c) => `<td>${cellHtml(r44.cells[c.id])}</td>`).join("")}</tr>`).join("\n");
54862
- return `<table${at2}${attr2("data-sort", item.sort != null ? JSON.stringify(item.sort) : null)}>
54986
+ const head = item.cols.map((c) => {
54987
+ const sorted = item.sort?.col === c.id ? item.sort.dir === "desc" ? "descending" : "ascending" : null;
54988
+ return `<th${attr2("data-col", c.id)}${attr2("id", headerId(item.id, c.id))}${attr2("data-kind", c.kind ?? null)}${attr2("data-width", c.width ?? null)}${attr2("style", c.width ? `width:${c.width}px` : null)} scope="col"${attr2("aria-sort", sorted)}>${escText(c.name)}</th>`;
54989
+ }).join("");
54990
+ const body = item.rows.map((r44) => `<tr${attr2("data-id", r44.id)}>${item.cols.map((c) => `<td${attr2("headers", headerId(item.id, c.id))}>${cellHtml(r44.cells[c.id])}</td>`).join("")}</tr>`).join("\n");
54991
+ return `<table${at2} aria-label="Table"${attr2("data-sort", item.sort != null ? JSON.stringify(item.sort) : null)}>
54863
54992
  <thead><tr>${head}</tr></thead>
54864
54993
  <tbody>
54865
54994
  ${body}
@@ -54911,9 +55040,10 @@ function fragmentCleaner(doc) {
54911
55040
  function renderModel(model, { fallbackOf = () => "", clean = RAW } = {}) {
54912
55041
  const lines = [];
54913
55042
  const tables = new Map(model.filter((item) => item.t === "table").map((item) => [item.id, item]));
55043
+ const title = model.find(tocTitle) ?? null;
54914
55044
  const stack = [null];
54915
55045
  const lists = [];
54916
- const add2 = (s) => {
55046
+ const add3 = (s) => {
54917
55047
  if (lists.length) lines[lines.length - 1] += s;
54918
55048
  else lines.push(s);
54919
55049
  };
@@ -54928,7 +55058,7 @@ function renderModel(model, { fallbackOf = () => "", clean = RAW } = {}) {
54928
55058
  const parent2 = item.parent ?? null;
54929
55059
  while (stack.length > 1 && stack[stack.length - 1] !== parent2) {
54930
55060
  closeLists();
54931
- add2("</details>");
55061
+ add3("</details>");
54932
55062
  stack.pop();
54933
55063
  }
54934
55064
  if (item.t !== "list_item") closeLists();
@@ -54936,35 +55066,44 @@ function renderModel(model, { fallbackOf = () => "", clean = RAW } = {}) {
54936
55066
  const d = item.indent ?? 0;
54937
55067
  const tag = item.kind === "ordered" ? "ol" : "ul";
54938
55068
  while (lists.length > d + 1) {
54939
- add2(`</li></${lists[lists.length - 1]}>`);
55069
+ add3(`</li></${lists[lists.length - 1]}>`);
54940
55070
  lists.pop();
54941
55071
  }
54942
55072
  if (lists.length === d + 1) {
54943
- add2(lists[d] === tag ? "</li>" : `</li></${lists[d]}>`);
55073
+ add3(lists[d] === tag ? "</li>" : `</li></${lists[d]}>`);
54944
55074
  if (lists[d] !== tag) lists.pop();
54945
55075
  }
54946
55076
  if (lists.length < d + 1) {
54947
- add2(`<${tag}>`);
55077
+ add3(`<${tag}>`);
54948
55078
  lists.push(tag);
54949
55079
  }
54950
55080
  const box = item.kind === "check" ? `<input type="checkbox" disabled${item.checked ? " checked" : ""}>` : "";
54951
- add2(`<li${attr2("data-id", item.id)}${attr2("data-owner", item.owner ?? null)}${attr2("data-due", item.due ?? null)}${extrasOfItem(item)}>${box}${inlineOf(item)}`);
55081
+ add3(`<li${attr2("data-id", item.id)}${attr2("data-owner", item.owner ?? null)}${attr2("data-due", item.due ?? null)}${extrasOfItem(item)}>${box}${inlineOf(item)}`);
54952
55082
  continue;
54953
55083
  }
54954
55084
  if (item.t === "toggle") {
54955
- add2(`<details${attr2("data-id", item.id)}${extrasOfItem(item)}${item.open ? " open" : ""}><summary>${inlineOf(item)}</summary>`);
55085
+ const h = toggleLevel(item.level);
55086
+ add3(`<details${attr2("data-id", item.id)}${extrasOfItem(item)}${item.open ? " open" : ""}>${h ? `<summary><h${h}>${inlineOf(item)}</h${h}></summary>` : `<summary>${inlineOf(item)}</summary>`}`);
54956
55087
  stack.push(item.id);
54957
55088
  continue;
54958
55089
  }
54959
55090
  if (item.t === "tool") {
54960
- add2(`<section${attr2("data-id", item.id)} data-type="tool">${toolData(item)}${clean.fallback(fallbackOf(item.id))}</section>`);
55091
+ add3(`<section${attr2("data-id", item.id)} data-type="tool">${toolData(item)}${clean.fallback(fallbackOf(item.id))}</section>`);
55092
+ continue;
55093
+ }
55094
+ if (item.t === "toc") {
55095
+ add3(tocHtml(item, model));
55096
+ continue;
55097
+ }
55098
+ if (item === title && (item.pageIcon || item.pageCoverSrc)) {
55099
+ add3(titleHtml(item));
54961
55100
  continue;
54962
55101
  }
54963
- add2(renderLeaf(item, clean, tables));
55102
+ add3(renderLeaf(item, clean, tables));
54964
55103
  }
54965
55104
  closeLists();
54966
55105
  while (stack.length > 1) {
54967
- add2("</details>");
55106
+ add3("</details>");
54968
55107
  stack.pop();
54969
55108
  }
54970
55109
  return lines.join("\n");
@@ -55084,7 +55223,11 @@ function parseArticle(article) {
55084
55223
  const P3 = { parent: parent2 };
55085
55224
  const record5 = envelopeAt(el3);
55086
55225
  if (record5 && typeof record5.t === "string") {
55087
- if (knownType(record5.t) || record5.t === "opaque_block") throw new SyntaxError(`page: an envelope names the known block type ${record5.t}`);
55226
+ if (record5.t === "opaque_block") throw new SyntaxError(`page: an envelope names the known block type ${record5.t}`);
55227
+ if (knownType(record5.t)) {
55228
+ items.push(knownRecordItem(idOf(el3), record5, parent2));
55229
+ return;
55230
+ }
55088
55231
  const { t, ...fields } = record5;
55089
55232
  items.push({ id: idOf(el3), t, parent: parent2, ...fields });
55090
55233
  return;
@@ -55092,6 +55235,13 @@ function parseArticle(article) {
55092
55235
  const onlyImage = tag === "P" && el3.children.length === 1 && el3.children[0].tagName === "IMG" && !el3.textContent.trim();
55093
55236
  if (tag === "P" && !onlyImage) return push(el3, "paragraph", parent2, { ...omitDefaults("paragraph", P3), ...tf2(el3) });
55094
55237
  if (/^H[1-6]$/.test(tag)) return push(el3, "heading", parent2, { ...omitDefaults("heading", { ...P3, level: +tag[1] }), ...tf2(el3) });
55238
+ if (tag === "HEADER" && el3.getAttribute("data-page-heading") === ENVELOPE) {
55239
+ const icon = el3.querySelector(":scope > [data-page-icon]");
55240
+ const cover = el3.querySelector(":scope > img");
55241
+ const [, x3, y2] = /object-position:\s*([-\d.]+)%\s+([-\d.]+)%/.exec(cover?.getAttribute("style") ?? "") ?? [];
55242
+ const cover0 = cover ? { pageCoverSrc: safeSrc(cover.getAttribute("src")), pageCoverAlt: cover.getAttribute("alt") ?? "", pageCoverX: focal(x3), pageCoverY: focal(y2) } : {};
55243
+ return push(el3, "heading", parent2, { ...omitDefaults("heading", { ...P3, level: 1, pageIcon: icon ? icon.textContent : null, ...cover0 }), ...tf2(el3.querySelector(":scope > h1")) });
55244
+ }
55095
55245
  if (tag === "ASIDE") return push(el3, "callout", parent2, { ...omitDefaults("callout", P3), ...tf2(el3) });
55096
55246
  if (tag === "BLOCKQUOTE") return push(el3, "quote", parent2, { ...omitDefaults("quote", P3), ...tf2(el3) });
55097
55247
  if (tag === "PRE") {
@@ -55099,11 +55249,16 @@ function parseArticle(article) {
55099
55249
  return push(el3, "code_block", parent2, { ...omitDefaults("code_block", { ...P3, lang: el3.getAttribute("data-lang") || "" }), c: (code || el3).textContent });
55100
55250
  }
55101
55251
  if (tag === "HR") return push(el3, "divider", parent2, omitDefaults("divider", P3));
55252
+ if (tag === "NAV" && el3.getAttribute("aria-label") === TOC_LABEL) {
55253
+ const maxLevel = +(el3.getAttribute("data-max-level") ?? 0);
55254
+ return push(el3, "toc", parent2, omitDefaults("toc", { ...P3, maxLevel: maxLevel >= 1 && maxLevel <= 6 ? maxLevel : null }));
55255
+ }
55102
55256
  if (tag === "UL" || tag === "OL") return list(el3, parent2, 0);
55103
55257
  if (tag === "DETAILS") {
55104
55258
  const summary = el3.querySelector(":scope > summary");
55259
+ const head = summary?.querySelector(":scope > h1, :scope > h2, :scope > h3");
55105
55260
  const at2 = items.length;
55106
- push(el3, "toggle", parent2, { ...omitDefaults("toggle", { ...P3, open: el3.hasAttribute("open") }), ...tf2(summary) });
55261
+ push(el3, "toggle", parent2, { ...omitDefaults("toggle", { ...P3, open: el3.hasAttribute("open"), level: head ? Number(head.tagName[1]) : null }), ...tf2(summary) });
55107
55262
  const body = el3.ownerDocument.createElement("div");
55108
55263
  for (const n of [...el3.childNodes]) if (n !== summary) body.appendChild(n.cloneNode(true));
55109
55264
  walk2(body, { ref: at2 });
@@ -55170,9 +55325,9 @@ function parseArticle(article) {
55170
55325
  const columns = [], cards = [];
55171
55326
  for (const div of el3.querySelectorAll(":scope > div[data-col], :scope > div")) {
55172
55327
  const col = div.getAttribute("data-col");
55173
- const missing = div.hasAttribute("data-missing");
55174
- const ref2 = missing ? { id: col } : { id: col, name: text3(div.querySelector(":scope > h4")) };
55175
- if (!missing) columns.push(ref2);
55328
+ const missing2 = div.hasAttribute("data-missing");
55329
+ const ref2 = missing2 ? { id: col } : { id: col, name: text3(div.querySelector(":scope > h4")) };
55330
+ if (!missing2) columns.push(ref2);
55176
55331
  for (const li3 of div.querySelectorAll(":scope > ul > li")) {
55177
55332
  cards.push({ id: li3.getAttribute("data-id"), colRef: ref2, title: text3(li3), ...li3.hasAttribute("data-owner") ? { owner: li3.getAttribute("data-owner") } : {}, ...li3.hasAttribute("data-due") ? { due: li3.getAttribute("data-due") } : {} });
55178
55333
  }
@@ -55667,6 +55822,7 @@ var _e2 = (e19, t, n = 0) => {
55667
55822
  n < e19.length && _e2(e19, t, n + 1);
55668
55823
  }
55669
55824
  };
55825
+ var nr2 = (e19) => e19;
55670
55826
  var Se2 = (e19, t) => {
55671
55827
  if (e19 === t) return true;
55672
55828
  if (e19 == null || t == null || e19.constructor !== t.constructor && (e19.constructor || Object) !== (t.constructor || Object)) return false;
@@ -55733,13 +55889,24 @@ var ys2 = ws2("production");
55733
55889
  var Do2 = Gt2 && ms2(process.env.FORCE_COLOR, ["true", "1", "2"]);
55734
55890
  var xs2 = Do2 || !sr2("--no-colors") && !ws2("no-color") && (!Gt2 || process.stdout.isTTY) && (!Gt2 || sr2("--color") || Ee2("COLORTERM") !== null || (Ee2("TERM") || "").includes("color"));
55735
55891
  var bs2 = (e19) => new Uint8Array(e19);
55892
+ var To2 = (e19) => {
55893
+ let t = "";
55894
+ for (let n = 0; n < e19.byteLength; n++) t += ge2(e19[n]);
55895
+ return btoa(t);
55896
+ };
55897
+ var vo2 = (e19) => Buffer.from(e19.buffer, e19.byteOffset, e19.byteLength).toString("base64");
55736
55898
  var Vo2 = (e19) => {
55737
55899
  let t = atob(e19), n = bs2(t.length);
55738
55900
  for (let r44 = 0; r44 < t.length; r44++) n[r44] = t.charCodeAt(r44);
55739
55901
  return n;
55740
55902
  };
55741
55903
  var Oo2 = (e19) => new Uint8Array(Buffer.from(e19, "base64"));
55904
+ var No2 = en2 ? To2 : vo2;
55742
55905
  var Lo2 = en2 ? Vo2 : Oo2;
55906
+ var ks2 = (e19) => {
55907
+ let t = bs2(e19.byteLength);
55908
+ return t.set(e19), t;
55909
+ };
55743
55910
  var ir2 = class {
55744
55911
  constructor(t, n) {
55745
55912
  this.left = t, this.right = n;
@@ -56372,6 +56539,44 @@ var At2 = class {
56372
56539
  return w2(this.restDecoder);
56373
56540
  }
56374
56541
  };
56542
+ var H = class extends At2 {
56543
+ readLeftID() {
56544
+ return m(w2(this.restDecoder), w2(this.restDecoder));
56545
+ }
56546
+ readRightID() {
56547
+ return m(w2(this.restDecoder), w2(this.restDecoder));
56548
+ }
56549
+ readClient() {
56550
+ return w2(this.restDecoder);
56551
+ }
56552
+ readInfo() {
56553
+ return St2(this.restDecoder);
56554
+ }
56555
+ readString() {
56556
+ return ht2(this.restDecoder);
56557
+ }
56558
+ readParentInfo() {
56559
+ return w2(this.restDecoder) === 1;
56560
+ }
56561
+ readTypeRef() {
56562
+ return w2(this.restDecoder);
56563
+ }
56564
+ readLen() {
56565
+ return w2(this.restDecoder);
56566
+ }
56567
+ readAny() {
56568
+ return Ft2(this.restDecoder);
56569
+ }
56570
+ readBuf() {
56571
+ return ks2(F2(this.restDecoder));
56572
+ }
56573
+ readJSON() {
56574
+ return JSON.parse(ht2(this.restDecoder));
56575
+ }
56576
+ readKey() {
56577
+ return ht2(this.restDecoder);
56578
+ }
56579
+ };
56375
56580
  var Cn2 = class {
56376
56581
  constructor(t) {
56377
56582
  this.dsCurrVal = 0, this.restDecoder = t;
@@ -56680,6 +56885,19 @@ var Fr2 = (e19, t, n, r44 = j2) => {
56680
56885
  let s = V2(t);
56681
56886
  ai2(s, e19, n, new r44(s));
56682
56887
  };
56888
+ var Ac = (e19, t, n = /* @__PURE__ */ new Map()) => {
56889
+ $r2(e19, t.store, n), tt2(e19, ci2(t.store));
56890
+ };
56891
+ var Ic = (e19, t = new Uint8Array([0]), n = new X2()) => {
56892
+ let r44 = ui2(t);
56893
+ Ac(n, e19, r44);
56894
+ let s = [n.toUint8Array()];
56895
+ if (e19.store.pendingDs && s.push(e19.store.pendingDs), e19.store.pendingStructs && s.push(bi2(e19.store.pendingStructs.update, t)), s.length > 1) {
56896
+ if (n.constructor === ct2) return Gc(s.map((i, o) => o === 0 ? i : Xc(i)));
56897
+ if (n.constructor === X2) return Tn2(s);
56898
+ }
56899
+ return s[0];
56900
+ };
56683
56901
  var hi2 = (e19) => {
56684
56902
  let t = /* @__PURE__ */ new Map(), n = w2(e19.restDecoder);
56685
56903
  for (let r44 = 0; r44 < n; r44++) {
@@ -56930,11 +57148,17 @@ var et2 = class {
56930
57148
  return this.curr;
56931
57149
  }
56932
57150
  };
57151
+ var qc = (e19, t = j2) => {
57152
+ let n = [], r44 = new t(V2(e19)), s = new et2(r44, false);
57153
+ for (let i = s.curr; i !== null; i = s.next()) n.push(i);
57154
+ return { structs: n, ds: ot2(r44) };
57155
+ };
56933
57156
  var Le2 = class {
56934
57157
  constructor(t) {
56935
57158
  this.currClient = 0, this.startClock = 0, this.written = 0, this.encoder = t, this.clientStructs = [];
56936
57159
  }
56937
57160
  };
57161
+ var Gc = (e19) => Tn2(e19, H, ct2);
56938
57162
  var zc = (e19, t = ee2, n = j2) => {
56939
57163
  let r44 = new t(), s = new et2(new n(V2(e19)), false), i = s.curr;
56940
57164
  if (i !== null) {
@@ -56989,6 +57213,21 @@ var Tn2 = (e19, t = j2, n = X2) => {
56989
57213
  let l = r44.map((a) => ot2(a)), h = te2(l);
56990
57214
  return tt2(o, h), o.toUint8Array();
56991
57215
  };
57216
+ var bi2 = (e19, t, n = j2, r44 = X2) => {
57217
+ let s = ui2(t), i = new r44(), o = new Le2(i), c = new n(V2(e19)), l = new et2(c, false);
57218
+ for (; l.curr; ) {
57219
+ let a = l.curr, u = a.id.client, d = s.get(u) || 0;
57220
+ if (l.curr.constructor === N) {
57221
+ l.next();
57222
+ continue;
57223
+ }
57224
+ if (a.id.clock + a.length > d) for (dt2(o, a, it2(d - a.id.clock, 0)), l.next(); l.curr && l.curr.id.client === u; ) dt2(o, l.curr, 0), l.next();
57225
+ else for (; l.curr && l.curr.id.client === u && l.curr.id.clock + l.curr.length <= d; ) l.next();
57226
+ }
57227
+ qr2(o);
57228
+ let h = ot2(c);
57229
+ return tt2(i, h), i.toUint8Array();
57230
+ };
56992
57231
  var ki2 = (e19) => {
56993
57232
  e19.written > 0 && (e19.clientStructs.push({ written: e19.written, restEncoder: q2(e19.encoder.restEncoder) }), e19.encoder.restEncoder = kt2(), e19.written = 0);
56994
57233
  };
@@ -57004,6 +57243,14 @@ var qr2 = (e19) => {
57004
57243
  g(t, r44.written), Rt2(t, r44.restEncoder);
57005
57244
  }
57006
57245
  };
57246
+ var Bn2 = (e19, t, n, r44) => {
57247
+ let s = new n(V2(e19)), i = new et2(s, false), o = new r44(), c = new Le2(o);
57248
+ for (let h = i.curr; h !== null; h = i.next()) dt2(c, t(h), 0);
57249
+ qr2(c);
57250
+ let l = ot2(s);
57251
+ return tt2(o, l), o.toUint8Array();
57252
+ };
57253
+ var Xc = (e19) => Bn2(e19, nr2, j2, ct2);
57007
57254
  var ni2 = "You must not compute changes after the event-handler fired.";
57008
57255
  var ne2 = class {
57009
57256
  constructor(t, n) {
@@ -58735,9 +58982,14 @@ ji2[qi2] = true;
58735
58982
  var NET = "page-net";
58736
58983
  var PAGE_ROOTS = Object.freeze(["flow", "attrs", "gone", "boardFields", "tableFields", "origins"]);
58737
58984
  var SKIP = /* @__PURE__ */ new Set(["id", "pos"]);
58738
- var attrKeys = (type) => [...Object.keys(type.spec.attrs || {}).filter((k2) => !SKIP.has(k2)), ...type.name === "table" ? ["rows"] : []];
58985
+ var KEYS = /* @__PURE__ */ new WeakMap();
58986
+ var attrKeys = (type) => {
58987
+ let keys = KEYS.get(type);
58988
+ if (!keys) KEYS.set(type, keys = Object.freeze([...Object.keys(type.spec.attrs || {}).filter((k2) => !SKIP.has(k2)), ...type.name === "table" ? ["rows"] : []]));
58989
+ return keys;
58990
+ };
58739
58991
  var defaultOf = (type, k2) => type.name === "table" && k2 === "rows" ? {} : type.spec.attrs[k2].default;
58740
- var sameJson = (a, b2) => JSON.stringify(a) === JSON.stringify(b2);
58992
+ var sameJson = (a, b2) => a === b2 || JSON.stringify(a) === JSON.stringify(b2);
58741
58993
  var idKey = (id) => `${id.client}.${id.clock}`;
58742
58994
  var parseKey = (k2) => {
58743
58995
  const i = k2.indexOf(".");
@@ -58774,6 +59026,16 @@ var boundaryRecord = (value) => {
58774
59026
  return value.recoveryOf === void 0 ? { blockId: value.blockId, kind: value.kind } : { blockId: value.blockId, kind: value.kind, recoveryOf: value.recoveryOf };
58775
59027
  };
58776
59028
  var sameBoundary = (a, b2) => a.blockId === b2.blockId && a.kind === b2.kind && a.recoveryOf === b2.recoveryOf;
59029
+ var markerKey = (key) => {
59030
+ let parts;
59031
+ try {
59032
+ parts = JSON.parse(key);
59033
+ } catch {
59034
+ return null;
59035
+ }
59036
+ if (!Array.isArray(parts) || parts.length !== 3 || parts[0] !== "boundary" && parts[0] !== "alias") return null;
59037
+ return isClock(parts[1]) && isClock(parts[2]) ? parts : null;
59038
+ };
58777
59039
  var recordKey = (key) => {
58778
59040
  if (typeof key !== "string" || key.charCodeAt(0) !== 91) return null;
58779
59041
  let parts;
@@ -58789,6 +59051,7 @@ var recordKey = (key) => {
58789
59051
  function createOriginIndex(origins) {
58790
59052
  const spans = /* @__PURE__ */ new Map();
58791
59053
  const aliases2 = /* @__PURE__ */ new Map();
59054
+ const aliasClocks = /* @__PURE__ */ new Map();
58792
59055
  const boundaries = /* @__PURE__ */ new Map();
58793
59056
  const lower = (list, clock) => {
58794
59057
  let lo3 = 0, hi3 = list.length;
@@ -58799,13 +59062,61 @@ function createOriginIndex(origins) {
58799
59062
  }
58800
59063
  return lo3;
58801
59064
  };
59065
+ const lowerClock = (list, clock) => {
59066
+ let lo3 = 0, hi3 = list.length;
59067
+ while (lo3 < hi3) {
59068
+ const mid = lo3 + hi3 >> 1;
59069
+ if (list[mid] < clock) lo3 = mid + 1;
59070
+ else hi3 = mid;
59071
+ }
59072
+ return lo3;
59073
+ };
59074
+ const markAlias = (client, clock, present) => {
59075
+ const list = aliasClocks.get(client) ?? [];
59076
+ const at2 = lowerClock(list, clock);
59077
+ const there = list[at2] === clock;
59078
+ if (present && !there) list.splice(at2, 0, clock);
59079
+ else if (!present && there) list.splice(at2, 1);
59080
+ if (list.length) aliasClocks.set(client, list);
59081
+ else aliasClocks.delete(client);
59082
+ };
59083
+ const markerRecords = [];
59084
+ const markerEntries = /* @__PURE__ */ new Map();
59085
+ const markerCounts = /* @__PURE__ */ new Map();
59086
+ const markerClocks = /* @__PURE__ */ new Map();
59087
+ const trackMarker = (key, live) => {
59088
+ let entry = markerEntries.get(key);
59089
+ if (entry === void 0) {
59090
+ const parts = markerKey(key);
59091
+ entry = parts ? { kind: parts[0], client: parts[1], clock: parts[2], live: false } : null;
59092
+ markerEntries.set(key, entry);
59093
+ if (entry) markerRecords.push(entry);
59094
+ }
59095
+ if (!entry || entry.live === live) return;
59096
+ entry.live = live;
59097
+ const counts = markerCounts.get(entry.client) ?? markerCounts.set(entry.client, /* @__PURE__ */ new Map()).get(entry.client);
59098
+ const list = markerClocks.get(entry.client) ?? markerClocks.set(entry.client, []).get(entry.client);
59099
+ const n = (counts.get(entry.clock) ?? 0) + (live ? 1 : -1);
59100
+ if (n) counts.set(entry.clock, n);
59101
+ else counts.delete(entry.clock);
59102
+ const at2 = lowerClock(list, entry.clock);
59103
+ if (live && n === 1) list.splice(at2, 0, entry.clock);
59104
+ else if (!live && n === 0) list.splice(at2, 1);
59105
+ if (!list.length) {
59106
+ markerClocks.delete(entry.client);
59107
+ markerCounts.delete(entry.client);
59108
+ }
59109
+ };
58802
59110
  const apply2 = (key, value) => {
59111
+ trackMarker(key, value !== void 0);
58803
59112
  const parts = recordKey(key);
58804
59113
  if (!parts) return;
58805
59114
  const [kind, client, clock] = parts;
58806
59115
  if (kind === "alias") {
58807
- if (value && isClock(value.sourceClient) && isClock(value.sourceClock)) aliases2.set(idKey2(client, clock), { client: value.sourceClient, clock: value.sourceClock });
59116
+ const valid = Boolean(value && isClock(value.sourceClient) && isClock(value.sourceClock));
59117
+ if (valid) aliases2.set(idKey2(client, clock), { client: value.sourceClient, clock: value.sourceClock });
58808
59118
  else aliases2.delete(idKey2(client, clock));
59119
+ markAlias(client, clock, valid);
58809
59120
  return;
58810
59121
  }
58811
59122
  if (kind === "boundary") {
@@ -58823,13 +59134,17 @@ function createOriginIndex(origins) {
58823
59134
  if (list.length) spans.set(client, list);
58824
59135
  else spans.delete(client);
58825
59136
  };
58826
- for (const [key, value] of origins) apply2(key, value);
59137
+ for (const key of origins._map.keys()) apply2(key, origins.get(key));
58827
59138
  const observer = (event) => {
58828
59139
  for (const key of event.keysChanged) apply2(key, origins.get(key));
58829
59140
  };
58830
59141
  origins.observe(observer);
59142
+ const hasAlias = (client, clock) => {
59143
+ const list = aliasClocks.get(client);
59144
+ return list !== void 0 && list[lowerClock(list, clock)] === clock;
59145
+ };
58831
59146
  const resolve = (id) => {
58832
- const alias = aliases2.get(idKey2(id.client, id.clock));
59147
+ const alias = hasAlias(id.client, id.clock) ? aliases2.get(idKey2(id.client, id.clock)) : void 0;
58833
59148
  if (alias) return { client: alias.client, clock: alias.clock };
58834
59149
  const list = spans.get(id.client);
58835
59150
  if (!list) return { client: id.client, clock: id.clock };
@@ -58847,8 +59162,44 @@ function createOriginIndex(origins) {
58847
59162
  if (offset >= record5.length) return { client: id.client, clock: id.clock };
58848
59163
  return { client: record5.sourceClient, clock: record5.sourceClock + offset };
58849
59164
  };
59165
+ const resolveRange = (client, clock, length) => {
59166
+ const out = [];
59167
+ const push = (sourceClient, sourceClock, size) => {
59168
+ const last2 = out[out.length - 1];
59169
+ if (last2 && last2.client === sourceClient && last2.clock + last2.length === sourceClock) last2.length += size;
59170
+ else out.push({ client: sourceClient, clock: sourceClock, length: size });
59171
+ };
59172
+ const list = spans.get(client) ?? [];
59173
+ const marks = aliasClocks.get(client) ?? [];
59174
+ const end2 = clock + length;
59175
+ let s = lower(list, clock + 1) - 1, a = lowerClock(marks, clock), at2 = clock;
59176
+ while (at2 < end2) {
59177
+ if (a < marks.length && marks[a] === at2) {
59178
+ const target = aliases2.get(idKey2(client, at2));
59179
+ push(target.client, target.clock, 1);
59180
+ at2 += 1;
59181
+ a += 1;
59182
+ } else {
59183
+ let stop = end2;
59184
+ if (a < marks.length && marks[a] < stop) stop = marks[a];
59185
+ if (s + 1 < list.length && list[s + 1].clock < stop) stop = list[s + 1].clock;
59186
+ const span2 = s >= 0 ? list[s] : null;
59187
+ if (span2 && at2 < span2.clock + span2.length) {
59188
+ stop = Math.min(stop, span2.clock + span2.length);
59189
+ push(span2.sourceClient, span2.sourceClock + at2 - span2.clock, stop - at2);
59190
+ } else push(client, at2, stop - at2);
59191
+ at2 = stop;
59192
+ }
59193
+ while (s + 1 < list.length && list[s + 1].clock <= at2) s += 1;
59194
+ }
59195
+ return out;
59196
+ };
58850
59197
  const boundaryOf = (id) => {
58851
59198
  if (!id || !isClock(id.client) || !isClock(id.clock)) return null;
59199
+ if (!hasAlias(id.client, id.clock)) {
59200
+ const record6 = boundaries.get(idKey2(id.client, id.clock));
59201
+ return record6 ? { ...record6 } : null;
59202
+ }
58852
59203
  let key = idKey2(id.client, id.clock);
58853
59204
  const seen = /* @__PURE__ */ new Set();
58854
59205
  while (!seen.has(key)) {
@@ -58917,13 +59268,19 @@ function createOriginIndex(origins) {
58917
59268
  const previous = boundaryRecord(existing);
58918
59269
  if (!previous || !sameBoundary(previous, record5)) throw conflicting(key);
58919
59270
  };
59271
+ const markers = () => {
59272
+ for (const t of origins.doc?._transactionCleanups ?? []) if (t.changed.has(origins)) return null;
59273
+ return { records: markerRecords, clocks: markerClocks };
59274
+ };
58920
59275
  return {
58921
59276
  origins,
58922
59277
  resolve,
59278
+ resolveRange,
58923
59279
  recordSpans,
58924
59280
  recordAlias,
58925
59281
  recordBoundary,
58926
59282
  boundaryOf,
59283
+ markers,
58927
59284
  get size() {
58928
59285
  return origins.size;
58929
59286
  },
@@ -58935,7 +59292,13 @@ function createOriginIndex(origins) {
58935
59292
 
58936
59293
  // src/page/ybind/parts.js
58937
59294
  var PART_KEY = /^(.+)\.(\d+)\.(\d+)$/;
58938
- var BASE64 = /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}(?:==)?|[A-Za-z0-9+/]{3}=?)?$/;
59295
+ var NOT_BASE64 = /[^A-Za-z0-9+/]/;
59296
+ function isBase64(text4) {
59297
+ const pad = text4.endsWith("==") ? 2 : text4.endsWith("=") ? 1 : 0;
59298
+ const body = text4.length - pad;
59299
+ if (NOT_BASE64.test(pad ? text4.slice(0, body) : text4)) return false;
59300
+ return pad ? body % 4 + pad === 4 : body % 4 !== 1;
59301
+ }
58939
59302
  function entriesOf2(y2) {
58940
59303
  const whole = [];
58941
59304
  const parts = /* @__PURE__ */ new Map();
@@ -58957,6 +59320,75 @@ function entriesOf2(y2) {
58957
59320
  return whole;
58958
59321
  }
58959
59322
 
59323
+ // src/page/ybind/containment.js
59324
+ function merged(map2) {
59325
+ for (const [client, list] of map2) {
59326
+ list.sort((a, b2) => a[0] - b2[0]);
59327
+ const out = [];
59328
+ for (const range of list) {
59329
+ const last2 = out[out.length - 1];
59330
+ if (last2 && range[0] <= last2[1]) {
59331
+ if (range[1] > last2[1]) last2[1] = range[1];
59332
+ } else out.push([range[0], range[1]]);
59333
+ }
59334
+ map2.set(client, out);
59335
+ }
59336
+ return map2;
59337
+ }
59338
+ var add2 = (map2, client, from, to3) => {
59339
+ if (to3 <= from) return;
59340
+ const list = map2.get(client);
59341
+ if (list) list.push([from, to3]);
59342
+ else map2.set(client, [[from, to3]]);
59343
+ };
59344
+ function rangesOf(update2) {
59345
+ const { structs, ds: ds3 } = qc(update2);
59346
+ const items = /* @__PURE__ */ new Map();
59347
+ for (const struct of structs) if (!(struct instanceof N)) add2(items, struct.id.client, struct.id.clock, struct.id.clock + struct.length);
59348
+ const deletes = /* @__PURE__ */ new Map();
59349
+ for (const [client, list] of ds3.clients) for (const { clock, len } of list) add2(deletes, client, clock, clock + len);
59350
+ return { items: merged(items), deletes: merged(deletes) };
59351
+ }
59352
+ function unite(list) {
59353
+ if (list.length === 1) return list[0];
59354
+ const items = /* @__PURE__ */ new Map();
59355
+ const deletes = /* @__PURE__ */ new Map();
59356
+ for (const ranges of list) {
59357
+ for (const [client, spans] of ranges.items) for (const [from, to3] of spans) add2(items, client, from, to3);
59358
+ for (const [client, spans] of ranges.deletes) for (const [from, to3] of spans) add2(deletes, client, from, to3);
59359
+ }
59360
+ return { items: merged(items), deletes: merged(deletes) };
59361
+ }
59362
+ function inside(spans, from, to3) {
59363
+ if (!spans) return false;
59364
+ let lo3 = 0, hi3 = spans.length - 1;
59365
+ while (lo3 <= hi3) {
59366
+ const mid = lo3 + hi3 >> 1;
59367
+ const span2 = spans[mid];
59368
+ if (from < span2[0]) hi3 = mid - 1;
59369
+ else if (from >= span2[1]) lo3 = mid + 1;
59370
+ else return to3 <= span2[1];
59371
+ }
59372
+ return false;
59373
+ }
59374
+ function within(state, ranges) {
59375
+ if (state.complete === false) return false;
59376
+ for (const [client, spans] of ranges.items) for (const [from, to3] of spans) if (!inside(state.items.get(client), from, to3)) return false;
59377
+ for (const [client, spans] of ranges.deletes) for (const [from, to3] of spans) if (!inside(state.deletes.get(client), from, to3)) return false;
59378
+ return true;
59379
+ }
59380
+ function docRanges(doc) {
59381
+ if (doc.store.pendingStructs || doc.store.pendingDs) return { complete: false };
59382
+ const items = /* @__PURE__ */ new Map();
59383
+ for (const [client, structs] of doc.store.clients) {
59384
+ const last2 = structs[structs.length - 1];
59385
+ add2(items, client, 0, last2.id.clock + last2.length);
59386
+ }
59387
+ const deletes = /* @__PURE__ */ new Map();
59388
+ for (const [client, list] of ci2(doc.store).clients) for (const { clock, len } of list) add2(deletes, client, clock, clock + len);
59389
+ return { complete: true, items, deletes: merged(deletes) };
59390
+ }
59391
+
58960
59392
  // src/page/ybind/recovery-proof.js
58961
59393
  var encoder = typeof TextEncoder === "function" ? new TextEncoder() : null;
58962
59394
 
@@ -59006,7 +59438,7 @@ function docFromValue(value, { strict = false } = {}) {
59006
59438
  try {
59007
59439
  for (const [key, value2] of entries) {
59008
59440
  const text4 = strict ? value2.replace(/[\t\n\f\r ]/g, "") : value2;
59009
- if (strict && !BASE64.test(text4)) throw new YDecodeError("invalid-update", `Invalid base64 in Yjs update: ${key}`);
59441
+ if (strict && !isBase64(text4)) throw new YDecodeError("invalid-update", `Invalid base64 in Yjs update: ${key}`);
59010
59442
  Fr2(d, dec(text4), NET);
59011
59443
  }
59012
59444
  if (strict && (d.store.pendingStructs || d.store.pendingDs)) {
@@ -59061,8 +59493,8 @@ function resolveBoardFields(fields, blockId = null) {
59061
59493
  const columns = pick(groups, "column", columnOf, true);
59062
59494
  const cards = pick(groups, "card", cardOf, true);
59063
59495
  const columnIds = orderedIds(columns);
59064
- const missing = [...new Set(Object.values(cards).map((card) => card.col))].filter((id) => !Object.hasOwn(columns, id)).sort();
59065
- const cardIds = [...columnIds, ...missing].flatMap((columnId) => orderedIds(Object.fromEntries(Object.entries(cards).filter(([, card]) => card.col === columnId))));
59496
+ const missing2 = [...new Set(Object.values(cards).map((card) => card.col))].filter((id) => !Object.hasOwn(columns, id)).sort();
59497
+ const cardIds = [...columnIds, ...missing2].flatMap((columnId) => orderedIds(Object.fromEntries(Object.entries(cards).filter(([, card]) => card.col === columnId))));
59066
59498
  return {
59067
59499
  columns: Object.fromEntries(columnIds.map((id) => [id, columns[id]])),
59068
59500
  cards: Object.fromEntries(cardIds.map((id) => [id, cards[id]]))
@@ -59109,9 +59541,75 @@ function keepOne(live, dead) {
59109
59541
  });
59110
59542
  if (first2) live[first2] = dead[first2];
59111
59543
  }
59544
+ function tableFieldOwner(key, value) {
59545
+ let tuple;
59546
+ try {
59547
+ tuple = JSON.parse(key);
59548
+ } catch {
59549
+ return null;
59550
+ }
59551
+ if (!Array.isArray(tuple) || tuple.length !== 4) return null;
59552
+ const [owner, kind, entityId, field] = tuple;
59553
+ if (!validId2(owner) || !validId2(entityId)) return null;
59554
+ if (kind === "cell") return validId2(field) && validCell(value) ? owner : null;
59555
+ return Object.hasOwn(TABLE_FIELDS, kind) && TABLE_FIELDS[kind].includes(field) && validValue(field, value) ? owner : null;
59556
+ }
59557
+ var fieldIndexes = /* @__PURE__ */ new WeakMap();
59558
+ var fieldIndexOf = (fields) => {
59559
+ const known = fieldIndexes.get(fields);
59560
+ if (known) return known;
59561
+ const entries = /* @__PURE__ */ new Map(), byOwner = /* @__PURE__ */ new Map(), invalid = /* @__PURE__ */ new Set();
59562
+ const apply2 = (key) => {
59563
+ let entry = entries.get(key);
59564
+ if (!entry) {
59565
+ let tuple = null;
59566
+ try {
59567
+ tuple = JSON.parse(key);
59568
+ } catch {
59569
+ tuple = null;
59570
+ }
59571
+ const owner = Array.isArray(tuple) && tuple.length === 4 && validId2(tuple[0]) ? tuple[0] : null;
59572
+ entry = { key, tuple, live: false, value: void 0 };
59573
+ entries.set(key, entry);
59574
+ if (owner !== null) (byOwner.get(owner) ?? byOwner.set(owner, []).get(owner)).push(entry);
59575
+ }
59576
+ entry.live = fields.has(key);
59577
+ entry.value = entry.live ? fields.get(key) : void 0;
59578
+ if (entry.live && tableFieldOwner(key, entry.value) === null) invalid.add(key);
59579
+ else invalid.delete(key);
59580
+ };
59581
+ for (const key of fields._map.keys()) apply2(key);
59582
+ fields.observe((event) => {
59583
+ for (const key of event.keysChanged) apply2(key);
59584
+ });
59585
+ const index2 = {
59586
+ owned(blockId) {
59587
+ for (const t of fields.doc._transactionCleanups) for (const key of t.changed.get(fields) ?? []) apply2(key);
59588
+ return invalid.size ? null : byOwner.get(blockId) ?? [];
59589
+ }
59590
+ };
59591
+ fieldIndexes.set(fields, index2);
59592
+ return index2;
59593
+ };
59594
+ var ownedFields = (fields, blockId) => blockId !== null && fields instanceof se2 && fields.doc ? fieldIndexOf(fields).owned(blockId) : null;
59112
59595
  function resolveTableFields(fields, blockId = null, seed = null) {
59113
59596
  const rows = /* @__PURE__ */ new Map(), cols = /* @__PURE__ */ new Map(), cells = /* @__PURE__ */ new Map();
59114
- for (const [key, value] of fields) {
59597
+ const take = (kind, entityId, field, value) => {
59598
+ if (kind === "cell") {
59599
+ const row = cells.get(entityId) ?? /* @__PURE__ */ new Map();
59600
+ row.set(field, value);
59601
+ cells.set(entityId, row);
59602
+ return;
59603
+ }
59604
+ const bucket = kind === "row" ? rows : cols;
59605
+ const entity = bucket.get(entityId) ?? {};
59606
+ entity[field] = value;
59607
+ bucket.set(entityId, entity);
59608
+ };
59609
+ const owned = ownedFields(fields, blockId);
59610
+ if (owned) {
59611
+ for (const entry of owned) if (entry.live) take(entry.tuple[1], entry.tuple[2], entry.tuple[3], entry.value);
59612
+ } else for (const [key, value] of fields) {
59115
59613
  let tuple;
59116
59614
  try {
59117
59615
  tuple = JSON.parse(key);
@@ -59125,16 +59623,7 @@ function resolveTableFields(fields, blockId = null, seed = null) {
59125
59623
  if (!validId2(field) || !validCell(value)) fail2(key);
59126
59624
  } else if (!Object.hasOwn(TABLE_FIELDS, kind) || !TABLE_FIELDS[kind].includes(field) || !validValue(field, value)) fail2(key);
59127
59625
  if (owner !== blockId) continue;
59128
- if (kind === "cell") {
59129
- const row = cells.get(entityId) ?? /* @__PURE__ */ new Map();
59130
- row.set(field, value);
59131
- cells.set(entityId, row);
59132
- continue;
59133
- }
59134
- const bucket = kind === "row" ? rows : cols;
59135
- const entity = bucket.get(entityId) ?? {};
59136
- entity[field] = value;
59137
- bucket.set(entityId, entity);
59626
+ take(kind, entityId, field, value);
59138
59627
  }
59139
59628
  const outCols = { ...record2(seed?.cols) ? seed.cols : {} };
59140
59629
  const outRows = { ...record2(seed?.rows) ? seed.rows : {} };
@@ -59190,7 +59679,7 @@ function marksFromAttributes(a, blockType) {
59190
59679
  const marks = [];
59191
59680
  let unknown = null;
59192
59681
  for (const [n, v3] of best) {
59193
- if (schema.marks[n] && (!NATIVE_NAMES.has(n) || nativeAttrs(n, v3))) marks.push(schema.marks[n].create(v3 === true ? null : v3));
59682
+ if (schema.marks[n] && (!NATIVE_NAMES.has(n) || nativeAttrs(n, v3 === true ? {} : v3))) marks.push(schema.marks[n].create(v3 === true ? null : v3));
59194
59683
  else (unknown ??= {})[n] = v3;
59195
59684
  }
59196
59685
  if (unknown) {
@@ -59327,15 +59816,112 @@ var recordOf2 = (value, key, out) => {
59327
59816
  if (end2 !== null && !parsePhysicalKey(end2)) fail3(`Invalid gone record: ${key}`);
59328
59817
  out.removals.push({ key, sourceKey: key, source, operationId: null, blockId: value.b, end: end2, sv: [], legacy: true });
59329
59818
  };
59330
- function parseGoneIntents(gone, { strict = false } = {}) {
59331
- const out = { removals: [], restores: [], copyActive: /* @__PURE__ */ new Set(), attrs: /* @__PURE__ */ new Map(), textDeletes: [] };
59332
- gone.forEach((value, key) => {
59333
- try {
59334
- recordOf2(value, key, out);
59335
- } catch (error) {
59336
- if (strict || !(error instanceof RecoveryError)) throw error;
59819
+ var emptyIntents = () => ({ removals: [], restores: [], copyActive: /* @__PURE__ */ new Set(), attrs: /* @__PURE__ */ new Map(), textDeletes: [] });
59820
+ var frozen = (value) => {
59821
+ if (value !== null && typeof value === "object" && !Object.isFrozen(value)) {
59822
+ for (const key of Object.keys(value)) frozen(value[key]);
59823
+ Object.freeze(value);
59824
+ }
59825
+ return value;
59826
+ };
59827
+ var parsedRecord = (value, key) => {
59828
+ const out = emptyIntents();
59829
+ try {
59830
+ recordOf2(value, key, out);
59831
+ } catch (error) {
59832
+ if (!(error instanceof RecoveryError)) throw error;
59833
+ return null;
59834
+ }
59835
+ for (const list of [out.removals, out.restores, out.textDeletes]) for (const record5 of list) frozen(record5);
59836
+ for (const fields of out.attrs.values()) for (const fieldValue of fields.values()) frozen(fieldValue);
59837
+ return out;
59838
+ };
59839
+ var parsedGone = /* @__PURE__ */ new WeakMap();
59840
+ var foldRecord = (out, record5) => {
59841
+ for (const removal of record5.removals) out.removals.push(removal);
59842
+ for (const restore of record5.restores) out.restores.push(restore);
59843
+ for (const textDelete of record5.textDeletes) out.textDeletes.push(textDelete);
59844
+ for (const sourceKey of record5.copyActive) out.copyActive.add(sourceKey);
59845
+ for (const [sourceKey, fields] of record5.attrs) {
59846
+ const into = out.attrs.get(sourceKey) ?? /* @__PURE__ */ new Map();
59847
+ for (const [field, fieldValue] of fields) into.set(field, fieldValue);
59848
+ out.attrs.set(sourceKey, into);
59849
+ }
59850
+ };
59851
+ var goneIndexes = /* @__PURE__ */ new WeakMap();
59852
+ var goneIndexOf = (gone) => {
59853
+ const known = goneIndexes.get(gone);
59854
+ if (known) return known;
59855
+ const entries = /* @__PURE__ */ new Map();
59856
+ let totals = null;
59857
+ let added = [];
59858
+ const update2 = (key) => {
59859
+ const live = gone.has(key);
59860
+ const value = live ? gone.get(key) : void 0;
59861
+ const entry = entries.get(key);
59862
+ if (entry && entry.live === live && entry.value === value) return;
59863
+ const record5 = live ? parsedRecord(value, key) : null;
59864
+ if (!entry) {
59865
+ const next2 = { live, value, record: record5 };
59866
+ entries.set(key, next2);
59867
+ if (live && record5 && totals) added.push(record5);
59868
+ return;
59869
+ }
59870
+ entry.live = live;
59871
+ entry.value = value;
59872
+ entry.record = record5;
59873
+ totals = null;
59874
+ };
59875
+ for (const key of gone._map.keys()) update2(key);
59876
+ gone.observe((event) => {
59877
+ for (const key of event.keysChanged) update2(key);
59878
+ });
59879
+ const index2 = {
59880
+ intents() {
59881
+ for (const t of gone.doc._transactionCleanups) for (const key of t.changed.get(gone) ?? []) update2(key);
59882
+ if (!totals) {
59883
+ totals = emptyIntents();
59884
+ for (const entry of entries.values()) if (entry.record) foldRecord(totals, entry.record);
59885
+ added = [];
59886
+ } else if (added.length) {
59887
+ for (const record5 of added) foldRecord(totals, record5);
59888
+ added = [];
59889
+ }
59890
+ return {
59891
+ removals: totals.removals.slice(),
59892
+ restores: totals.restores.slice(),
59893
+ copyActive: new Set(totals.copyActive),
59894
+ attrs: new Map([...totals.attrs].map(([sourceKey, fields]) => [sourceKey, new Map(fields)])),
59895
+ textDeletes: totals.textDeletes.slice()
59896
+ };
59337
59897
  }
59898
+ };
59899
+ goneIndexes.set(gone, index2);
59900
+ return index2;
59901
+ };
59902
+ function parseGoneIntents(gone, { strict = false, kept = true } = {}) {
59903
+ const out = emptyIntents();
59904
+ if (strict) {
59905
+ gone.forEach((value, key) => recordOf2(value, key, out));
59906
+ return out;
59907
+ }
59908
+ if (kept && gone instanceof se2 && gone.doc) return goneIndexOf(gone).intents();
59909
+ if (!kept) {
59910
+ gone.forEach((value, key) => {
59911
+ const record5 = parsedRecord(value, key);
59912
+ if (record5) foldRecord(out, record5);
59913
+ });
59914
+ return out;
59915
+ }
59916
+ const previous = parsedGone.get(gone) ?? /* @__PURE__ */ new Map();
59917
+ const parsed2 = /* @__PURE__ */ new Map();
59918
+ gone.forEach((value, key) => {
59919
+ const hit = previous.get(key);
59920
+ const entry = hit && hit.value === value ? hit : { value, record: parsedRecord(value, key) };
59921
+ parsed2.set(key, entry);
59922
+ if (entry.record) foldRecord(out, entry.record);
59338
59923
  });
59924
+ parsedGone.set(gone, parsed2);
59339
59925
  return out;
59340
59926
  }
59341
59927
  var typeNode = (name) => schema.nodes[name] ?? schema.nodes.paragraph;
@@ -59408,8 +59994,19 @@ function walkFlow(pd, index2) {
59408
59994
  const liveSources = new Set(liveBySource.keys());
59409
59995
  const movedSources = /* @__PURE__ */ new Set();
59410
59996
  const retired = [];
59997
+ const copyBoundary = (client, clock) => {
59998
+ const sourceKey = `${client}.${clock}`;
59999
+ const record5 = index2.boundaryOf({ client, clock });
60000
+ if (!record5 || record5.kind !== "copy") return;
60001
+ if (intents.copyActive.has(sourceKey)) {
60002
+ if (record5.recoveryOf) movedSources.add(record5.recoveryOf);
60003
+ } else if (liveSources.has(sourceKey)) retired.push({ key: copyActiveKey(sourceKey), sourceKey, source: { client, clock }, operationId: null, blockId: record5.blockId, end: null, sv: [], legacy: false, implicit: true });
60004
+ };
60005
+ const markers = index2.markers?.() ?? null;
59411
60006
  const candidateSets = /* @__PURE__ */ new Map();
59412
- for (const key of pd.origins.keys()) {
60007
+ if (markers) {
60008
+ for (const entry of markers.records) if (entry.live && entry.kind === "boundary") copyBoundary(entry.client, entry.clock);
60009
+ } else for (const key of pd.origins.keys()) {
59413
60010
  let parts;
59414
60011
  try {
59415
60012
  parts = JSON.parse(key);
@@ -59419,15 +60016,7 @@ function walkFlow(pd, index2) {
59419
60016
  if (!Array.isArray(parts) || parts.length !== 3 || parts[0] !== "boundary" && parts[0] !== "alias") continue;
59420
60017
  const [, client, clock] = parts;
59421
60018
  if (!Number.isSafeInteger(client) || client < 0 || !Number.isSafeInteger(clock) || clock < 0) continue;
59422
- if (parts[0] === "boundary") {
59423
- const sourceKey = `${client}.${clock}`;
59424
- const record5 = index2.boundaryOf({ client, clock });
59425
- if (record5 && record5.kind === "copy") {
59426
- if (intents.copyActive.has(sourceKey)) {
59427
- if (record5.recoveryOf) movedSources.add(record5.recoveryOf);
59428
- } else if (liveSources.has(sourceKey)) retired.push({ key: copyActiveKey(sourceKey), sourceKey, source: { client, clock }, operationId: null, blockId: record5.blockId, end: null, sv: [], legacy: false, implicit: true });
59429
- }
59430
- }
60019
+ if (parts[0] === "boundary") copyBoundary(client, clock);
59431
60020
  const clocks = candidateSets.get(client) ?? candidateSets.set(client, /* @__PURE__ */ new Set()).get(client);
59432
60021
  clocks.add(clock);
59433
60022
  }
@@ -59489,7 +60078,7 @@ function walkFlow(pd, index2) {
59489
60078
  for (const key of restore.covers) set.add(key);
59490
60079
  }
59491
60080
  const recoveredMarkers = /* @__PURE__ */ new Map();
59492
- for (let it3 = pd.flow._start; it3; it3 = it3.right) {
60081
+ if (restoredSources.size) for (let it3 = pd.flow._start; it3; it3 = it3.right) {
59493
60082
  if (it3.deleted) continue;
59494
60083
  const source = it3.content instanceof wt2 ? markerSource(it3, it3.content.embed && it3.content.embed.b) : null;
59495
60084
  if (source === null) continue;
@@ -59507,9 +60096,14 @@ function walkFlow(pd, index2) {
59507
60096
  const segs = [];
59508
60097
  const orphans = [];
59509
60098
  const hidden = [];
59510
- const fences = [];
60099
+ const fences = [], stops = [];
59511
60100
  let cur = null, prevId = "start", hiding = null, at2 = 0;
59512
60101
  const cattrs = {};
60102
+ let styled = null;
60103
+ const fmt2 = () => {
60104
+ for (const key in cattrs) return { ...cattrs };
60105
+ return null;
60106
+ };
59513
60107
  const typeOf = (id) => {
59514
60108
  const m2 = pd.attrs.get(id);
59515
60109
  return m2 && m2.get("t") || "paragraph";
@@ -59524,12 +60118,16 @@ function walkFlow(pd, index2) {
59524
60118
  const id = `recovered:${sourceKey}`;
59525
60119
  const t = root2 ? root2.type : "paragraph";
59526
60120
  const opaque = !Object.hasOwn(schema.nodes, t);
59527
- cur = { kind: "b", id, baseId: id, brk: { client: it3.id.client, clock: it3.id.clock }, implicit: false, runs: [], len: 1, atom: !opaque && !schema.nodes[t]?.isTextblock, opaque, recovered: true, restored: !moved, sourceKey, t, fields: root2 ? root2.attrs : null };
60121
+ const f = fmt2();
60122
+ if (cur) cur.fmtOut = f;
60123
+ cur = { kind: "b", id, baseId: id, brk: { client: it3.id.client, clock: it3.id.clock }, implicit: false, runs: [], len: 1, atom: !opaque && !schema.nodes[t]?.isTextblock, opaque, recovered: true, restored: !moved, sourceKey, t, fields: root2 ? root2.attrs : null, fmtIn: f, fmtOut: null };
59528
60124
  segs.push(cur);
59529
60125
  prevId = id;
59530
60126
  };
59531
60127
  const open = (id, brk, implicit) => {
59532
- cur = { kind: "b", id, baseId: id, brk, implicit, runs: [], len: implicit ? 0 : 1, atom: false, items: !implicit && (markerCount.get(id) ?? 0) > 1 ? [] : null };
60128
+ const f = fmt2();
60129
+ if (cur) cur.fmtOut = f;
60130
+ cur = { kind: "b", id, baseId: id, brk, implicit, runs: [], len: implicit ? 0 : 1, atom: false, items: !implicit && (markerCount.get(id) ?? 0) > 1 ? [] : null, fmtIn: f, fmtOut: null };
59533
60131
  if (!implicit) {
59534
60132
  cur.t = typeOf(id);
59535
60133
  cur.opaque = !Object.hasOwn(schema.nodes, cur.t);
@@ -59551,15 +60149,15 @@ function walkFlow(pd, index2) {
59551
60149
  if (a.legacy && a.text) orphans.push({ key: a.key, id: a.blockId, text: a.text, h: hashText(a.text) });
59552
60150
  hidden.push({ key: a.key, sourceKey: a.sourceKey, blockId: a.blockId, end: a.end, sv: a.sv, at: a.at, live: a.live, items: a.items });
59553
60151
  };
59554
- const matchesEnd = (it3, end2) => {
59555
- if (covers(it3, end2)) return true;
60152
+ const matchesEnd = (it3, end2, after2 = -1) => {
60153
+ if (covers(it3, end2) && end2.clock > after2) return true;
59556
60154
  return markerIdsWithin(it3).some((id) => {
59557
- if (!pd.origins.has(aliasKey(id.client, id.clock))) return false;
60155
+ if (id.clock <= after2 || !pd.origins.has(aliasKey(id.client, id.clock))) return false;
59558
60156
  const resolved = index2.resolve(id);
59559
60157
  return resolved.client === end2.client && resolved.clock === end2.clock;
59560
60158
  });
59561
60159
  };
59562
- const markerClocks = new Map([...candidateSets].map(([client, clocks]) => [client, [...clocks].sort((a, b2) => a - b2)]));
60160
+ const markerClocks = markers ? markers.clocks : new Map([...candidateSets].map(([client, clocks]) => [client, [...clocks].sort((a, b2) => a - b2)]));
59563
60161
  const markerIdsWithin = (it3) => {
59564
60162
  const clocks = markerClocks.get(it3.id.client) ?? [];
59565
60163
  let lo3 = 0, hi3 = clocks.length;
@@ -59572,6 +60170,14 @@ function walkFlow(pd, index2) {
59572
60170
  for (let i = lo3; i < clocks.length && clocks[i] < it3.id.clock + it3.length; i++) ids.push({ client: it3.id.client, clock: clocks[i] });
59573
60171
  return ids;
59574
60172
  };
60173
+ const deletedEdgesIn = (it3, after2 = -1) => it3.deleted ? markerIdsWithin(it3).flatMap((id) => {
60174
+ if (id.clock <= after2) return [];
60175
+ const sourceKey = idKey(index2.resolve(id));
60176
+ const record5 = index2.boundaryOf(id);
60177
+ if (!record5 || record5.kind !== "removed" && record5.kind !== "copy" || liveSources.has(sourceKey)) return [];
60178
+ return [{ blockId: record5.blockId, sourceKey }];
60179
+ }) : [];
60180
+ const endsIn = (it3, a, { deletedEdges, boundary = false, edge, after: after2 = -1 }) => a.end ? matchesEnd(it3, a.end, after2) : a.implicit ? boundary || deletedEdges.some((e19) => e19.sourceKey !== a.sourceKey) : boundary && edge !== a.blockId || deletedEdges.some((e19) => e19.blockId !== a.blockId);
59575
60181
  const proj = [];
59576
60182
  const endsOf = (removal) => ({ blockId: removal.blockId, end: removal.end ? parseKey(removal.end) : null, implicit: removal.implicit === true, sourceKey: removal.sourceKey });
59577
60183
  for (let it3 = pd.flow._start; it3; it3 = it3.right) {
@@ -59580,13 +60186,8 @@ function walkFlow(pd, index2) {
59580
60186
  if (hiding || proj.length) {
59581
60187
  const edge = !it3.deleted && it3.content instanceof wt2 ? it3.content.embed.b : void 0;
59582
60188
  const boundary = edge !== void 0 && boundarySource(it3, edge) === null;
59583
- const deletedEdges = it3.deleted ? markerIdsWithin(it3).flatMap((id) => {
59584
- const sourceKey = idKey(index2.resolve(id));
59585
- const record5 = index2.boundaryOf(id);
59586
- if (!record5 || record5.kind !== "removed" || liveSources.has(sourceKey)) return [];
59587
- return [{ blockId: record5.blockId, sourceKey }];
59588
- }) : [];
59589
- const ends = (a) => a.end ? matchesEnd(it3, a.end) : a.implicit ? boundary || deletedEdges.some((e19) => e19.sourceKey !== a.sourceKey) : boundary && edge !== a.blockId || deletedEdges.some((e19) => e19.blockId !== a.blockId);
60189
+ const deletedEdges = deletedEdgesIn(it3);
60190
+ const ends = (a) => endsIn(it3, a, { deletedEdges, boundary, edge });
59590
60191
  if (hiding) {
59591
60192
  const keep = [];
59592
60193
  for (const a of hiding.active) {
@@ -59603,6 +60204,7 @@ function walkFlow(pd, index2) {
59603
60204
  }
59604
60205
  const removals2 = removalStarts.get(it3);
59605
60206
  if (removals2) {
60207
+ if (it3.deleted) stops.push({ client: it3.id.client, clock: it3.id.clock, len: it3.length });
59606
60208
  if (!hiding && exposed(removals2[0].sourceKey)) {
59607
60209
  if (!it3.deleted) hideUnit(it3.length);
59608
60210
  proj.push({ active: removals2.map(endsOf), sourceKey: removals2[0].sourceKey, root: null });
@@ -59611,14 +60213,20 @@ function walkFlow(pd, index2) {
59611
60213
  if (!hiding && it3.deleted) fences.push({ client: it3.id.client, clock: it3.id.clock });
59612
60214
  for (const removal of removals2) {
59613
60215
  const a = { legacy: false, implicit: removal.implicit === true, key: removal.key, sourceKey: removal.sourceKey, blockId: removal.blockId, end: removal.end ? parseKey(removal.end) : null, sv: removal.sv, at: here, live: !it3.deleted, items: [] };
60216
+ const after2 = it3.deleted && covers(it3, removal.source) ? removal.source.clock : null;
60217
+ if (after2 !== null && endsIn(it3, a, { deletedEdges: deletedEdgesIn(it3, after2), after: after2 })) {
60218
+ settle(a);
60219
+ continue;
60220
+ }
59614
60221
  if (hiding) hiding.active.push(a);
59615
60222
  else hiding = { active: [a], len: 0, resume: cur };
59616
60223
  }
59617
- if (!it3.deleted) hiding.len += it3.length;
60224
+ if (hiding && !it3.deleted) hiding.len += it3.length;
59618
60225
  continue;
59619
60226
  }
59620
60227
  const start = starts.get(it3);
59621
60228
  if (start) {
60229
+ if (it3.deleted) stops.push({ client: it3.id.client, clock: it3.id.clock, len: it3.length });
59622
60230
  if (!hiding && exposed(start.key)) {
59623
60231
  if (!it3.deleted) hideUnit(it3.length);
59624
60232
  proj.push({ active: [{ blockId: start.blockId, end: start.end }], sourceKey: start.key, root: null });
@@ -59635,6 +60243,7 @@ function walkFlow(pd, index2) {
59635
60243
  if (c instanceof C2) {
59636
60244
  if (c.value === null) delete cattrs[c.key];
59637
60245
  else cattrs[c.key] = c.value;
60246
+ styled = null;
59638
60247
  continue;
59639
60248
  }
59640
60249
  if (hiding) {
@@ -59685,8 +60294,12 @@ function walkFlow(pd, index2) {
59685
60294
  }
59686
60295
  if (c instanceof nt2) {
59687
60296
  if (!cur || cur.atom) open(`~${prevId}`, null, true);
59688
- const marks = marksFromAttributes(cattrs, cur.t);
59689
- cur.runs.push({ text: c.str, marks, mk: marksKey(marks) });
60297
+ const code = cur.t === "code_block";
60298
+ if (!styled || styled.code !== code) {
60299
+ const marks = marksFromAttributes(cattrs, cur.t);
60300
+ styled = { code, marks, mk: marksKey(marks) };
60301
+ }
60302
+ cur.runs.push({ text: c.str, marks: styled.marks, mk: styled.mk });
59690
60303
  if (cur.items) cur.items.push({ at: here, id: idKey(it3.id), client: it3.id.client, clock: it3.id.clock, length: it3.length, kind: "text", text: c.str, blockId: null, raw: { ...cattrs } });
59691
60304
  cur.len += c.str.length;
59692
60305
  }
@@ -59695,6 +60308,7 @@ function walkFlow(pd, index2) {
59695
60308
  for (const a of hiding.active) settle(a);
59696
60309
  flush();
59697
60310
  }
60311
+ if (cur) cur.fmtOut = fmt2();
59698
60312
  const groups = /* @__PURE__ */ new Map();
59699
60313
  for (const s of segs) {
59700
60314
  if (s.kind !== "b" || s.implicit) continue;
@@ -59741,7 +60355,7 @@ function walkFlow(pd, index2) {
59741
60355
  }
59742
60356
  tokens += s.len;
59743
60357
  }
59744
- return { visible, holes, orphans, tokens, copies, hidden, removals: lostCopies.length ? [...removals, ...lostCopies] : removals, fences };
60358
+ return { visible, holes, orphans, tokens, copies, hidden, removals: lostCopies.length ? [...removals, ...lostCopies] : removals, fences, stops };
59745
60359
  }
59746
60360
 
59747
60361
  // src/page/ybind/decode.js
@@ -60070,16 +60684,16 @@ var REGISTRY = {
60070
60684
  "pos"
60071
60685
  ]
60072
60686
  };
60073
- var frozen = null;
60687
+ var frozen2 = null;
60074
60688
  function floorZero() {
60075
- if (!frozen) {
60076
- frozen = Object.freeze({
60689
+ if (!frozen2) {
60690
+ frozen2 = Object.freeze({
60077
60691
  types: Object.freeze([...REGISTRY.types]),
60078
60692
  marks: Object.freeze([...REGISTRY.marks]),
60079
60693
  fields: Object.freeze([...REGISTRY.fields])
60080
60694
  });
60081
60695
  }
60082
- return frozen;
60696
+ return frozen2;
60083
60697
  }
60084
60698
  var CODE2 = /^[A-Za-z]$/;
60085
60699
  function newerMark(key) {
@@ -60815,8 +61429,8 @@ function align(baseRoot, sideRoot, o) {
60815
61429
  const keysAgree = (b2, s) => {
60816
61430
  const kb = baseId(b2);
60817
61431
  if (!kb) return true;
60818
- const ks2 = sideId(s);
60819
- return !ks2 || kb === ks2;
61432
+ const ks3 = sideId(s);
61433
+ return !ks3 || kb === ks3;
60820
61434
  };
60821
61435
  const nameB = (u) => {
60822
61436
  const k2 = baseKey(u);
@@ -60935,8 +61549,8 @@ function align(baseRoot, sideRoot, o) {
60935
61549
  for (const u of unitsOf3(bEl)) {
60936
61550
  const t = map2.get(u);
60937
61551
  if (!t || identityPaired.has(u)) continue;
60938
- const within2 = isEl3(t) ? sEl.contains(t) : sEl.contains(t.nodes[0]);
60939
- if (!within2) continue;
61552
+ const within3 = isEl3(t) ? sEl.contains(t) : sEl.contains(t.nodes[0]);
61553
+ if (!within3) continue;
60940
61554
  drop(u, t);
60941
61555
  if (isEl3(u)) walk2(u, t);
60942
61556
  }
@@ -60963,12 +61577,12 @@ function align(baseRoot, sideRoot, o) {
60963
61577
  alignKids(b2, s);
60964
61578
  }
60965
61579
  }
60966
- function within(el3, list) {
61580
+ function within2(el3, list) {
60967
61581
  if (codeLike(el3)) return;
60968
61582
  for (const u of unitsOf3(el3))
60969
61583
  if (isEl3(u)) {
60970
61584
  list.push(u);
60971
- within(u, list);
61585
+ within2(u, list);
60972
61586
  }
60973
61587
  }
60974
61588
  function alignKids(bEl, sEl) {
@@ -61008,7 +61622,7 @@ function align(baseRoot, sideRoot, o) {
61008
61622
  if (!map2.has(u)) {
61009
61623
  if (isEl3(u)) {
61010
61624
  unpairedBase.push(u);
61011
- within(u, unpairedBase);
61625
+ within2(u, unpairedBase);
61012
61626
  openB = true;
61013
61627
  }
61014
61628
  continue;
@@ -61018,7 +61632,7 @@ function align(baseRoot, sideRoot, o) {
61018
61632
  for (const u of sUnits)
61019
61633
  if (!reverse.has(u) && isEl3(u)) {
61020
61634
  unpairedSide.push(u);
61021
- within(u, unpairedSide);
61635
+ within2(u, unpairedSide);
61022
61636
  openS = true;
61023
61637
  }
61024
61638
  if (openB && openS) slotParents.push([bEl, sEl]);
@@ -61233,15 +61847,15 @@ function align(baseRoot, sideRoot, o) {
61233
61847
  if (map2.has(b2) || !isEl3(b2) || codeLike(b2)) continue;
61234
61848
  const bucket = buckets.get(meta(b2).sig);
61235
61849
  if (!bucket || !bucket.length) continue;
61236
- const bi2 = posB.get(b2);
61237
- let near = bucket.filter((c) => !reverse.has(c.el)).map((c) => ({ c, d: Math.abs(c.index - bi2) }));
61850
+ const bi3 = posB.get(b2);
61851
+ let near = bucket.filter((c) => !reverse.has(c.el)).map((c) => ({ c, d: Math.abs(c.index - bi3) }));
61238
61852
  near.sort((x3, y2) => x3.d - y2.d);
61239
61853
  if (near.length > NEAREST_WINDOW) near = near.slice(0, NEAREST_WINDOW);
61240
61854
  for (const { c, d } of near) {
61241
61855
  if (!keysAgree(b2, c.el)) continue;
61242
61856
  const sc2 = score(b2, c.el);
61243
61857
  if (sc2 && sc2.coef >= 0.5)
61244
- cands.push({ b: b2, s: c.el, coef: sc2.coef, share: sc2.share, d, bi: bi2 });
61858
+ cands.push({ b: b2, s: c.el, coef: sc2.coef, share: sc2.share, d, bi: bi3 });
61245
61859
  }
61246
61860
  }
61247
61861
  cands.sort(
@@ -61331,9 +61945,9 @@ function align(baseRoot, sideRoot, o) {
61331
61945
  return null;
61332
61946
  };
61333
61947
  return (b2, s) => {
61334
- const bi2 = posB.get(b2), si3 = posS.get(s);
61335
- if (bi2 === si3) return true;
61336
- const ab = anchor(bUnits, bi2, (u) => map2.has(u)), as2 = anchor(sUnits, si3, (u) => reverse.has(u));
61948
+ const bi3 = posB.get(b2), si3 = posS.get(s);
61949
+ if (bi3 === si3) return true;
61950
+ const ab = anchor(bUnits, bi3, (u) => map2.has(u)), as2 = anchor(sUnits, si3, (u) => reverse.has(u));
61337
61951
  return ab ? map2.get(ab) === as2 : !as2;
61338
61952
  };
61339
61953
  }
@@ -61569,12 +62183,12 @@ function myers(a, b2, maxD) {
61569
62183
  function wordsFirst(a, b2, maxD) {
61570
62184
  const brk = (t) => t.k === BREAK3;
61571
62185
  if (!a.some(brk) && !b2.some(brk)) return myers(a, b2, maxD);
61572
- const ai3 = [], bi2 = [];
62186
+ const ai3 = [], bi3 = [];
61573
62187
  for (let i = 0; i < a.length; i++) if (!brk(a[i])) ai3.push(i);
61574
- for (let i = 0; i < b2.length; i++) if (!brk(b2[i])) bi2.push(i);
62188
+ for (let i = 0; i < b2.length; i++) if (!brk(b2[i])) bi3.push(i);
61575
62189
  const top = myers(
61576
62190
  ai3.map((i) => a[i]),
61577
- bi2.map((i) => b2[i]),
62191
+ bi3.map((i) => b2[i]),
61578
62192
  maxD
61579
62193
  );
61580
62194
  if (!top) return null;
@@ -61591,7 +62205,7 @@ function wordsFirst(a, b2, maxD) {
61591
62205
  };
61592
62206
  for (const [op, i, j3] of top) {
61593
62207
  if (op !== 0) continue;
61594
- if (!gapTo(ai3[i], bi2[j3])) return null;
62208
+ if (!gapTo(ai3[i], bi3[j3])) return null;
61595
62209
  ops.push([0, x3, y2]);
61596
62210
  x3++;
61597
62211
  y2++;
@@ -61893,11 +62507,11 @@ function sharesFew(a, b2) {
61893
62507
  return inter / Math.min(na3.length, nb.length) < REWRITE_SHARE;
61894
62508
  }
61895
62509
  var keysOf = (h, B3) => {
61896
- const ks2 = /* @__PURE__ */ new Set();
61897
- for (const t of h.toks) if (typeof t.k !== "string") ks2.add(t.k.el);
62510
+ const ks3 = /* @__PURE__ */ new Set();
62511
+ for (const t of h.toks) if (typeof t.k !== "string") ks3.add(t.k.el);
61898
62512
  for (let i = h.bs; i < h.be; i++)
61899
- if (typeof B3[i].k !== "string") ks2.add(B3[i].k.el);
61900
- return ks2;
62513
+ if (typeof B3[i].k !== "string") ks3.add(B3[i].k.el);
62514
+ return ks3;
61901
62515
  };
61902
62516
  var sameToks = (a, b2) => a.length === b2.length && a.every((t, i) => t.k === b2[i].k);
61903
62517
  function merge3Tokens(B3, L3, R3, policy = "remote") {
@@ -62017,9 +62631,9 @@ function merge3Tokens(B3, L3, R3, policy = "remote") {
62017
62631
  units.forEach((u, i) => {
62018
62632
  for (const [og, info] of groups) {
62019
62633
  if (find4(i) === find4(og) || !(info.L && info.R)) continue;
62020
- const inside = u.bs < info.be && u.be > info.bs;
62634
+ const inside2 = u.bs < info.be && u.be > info.bs;
62021
62635
  const textInsertAtEdge = isInsert(u) && hasText(u) && (u.bs === info.be || u.bs === info.bs);
62022
- if ((inside || textInsertAtEdge) && union(i, og)) grew = true;
62636
+ if ((inside2 || textInsertAtEdge) && union(i, og)) grew = true;
62023
62637
  }
62024
62638
  });
62025
62639
  }
@@ -62062,9 +62676,9 @@ function merge3Tokens(B3, L3, R3, policy = "remote") {
62062
62676
  const rank = (e19) => e19.kind === "R" ? 1 : 0;
62063
62677
  emitUnits.sort((a, b2) => {
62064
62678
  if (a.bs !== b2.bs) return a.bs - b2.bs;
62065
- const ai3 = a.bs === a.be, bi2 = b2.bs === b2.be;
62066
- if (ai3 !== bi2) return ai3 ? -1 : 1;
62067
- if (ai3 && bi2 && a.kind !== "conflict" && b2.kind !== "conflict") {
62679
+ const ai3 = a.bs === a.be, bi3 = b2.bs === b2.be;
62680
+ if (ai3 !== bi3) return ai3 ? -1 : 1;
62681
+ if (ai3 && bi3 && a.kind !== "conflict" && b2.kind !== "conflict") {
62068
62682
  const at3 = a.u.toks, bt3 = b2.u.toks;
62069
62683
  const allOpen = (t) => t.length && t.every((x3) => x3.kind === "open");
62070
62684
  const allClose = (t) => t.length && t.every((x3) => x3.kind === "close");
@@ -62157,8 +62771,8 @@ function merge3Tokens(B3, L3, R3, policy = "remote") {
62157
62771
  for (const seg of segments) {
62158
62772
  if (seg.source === "base") {
62159
62773
  seg.toks = seg.toks.map((t, i) => {
62160
- const bi2 = seg.bs + i;
62161
- const lt3 = cosL.get(bi2), rt3 = cosR.get(bi2);
62774
+ const bi3 = seg.bs + i;
62775
+ const lt3 = cosL.get(bi3), rt3 = cosR.get(bi3);
62162
62776
  const pick2 = lt3 && rt3 ? policy === "remote" ? rt3 : lt3 : lt3 || rt3 || t;
62163
62777
  return pick2 === t ? t : { ...pick2, cosmetic: true };
62164
62778
  });
@@ -62381,11 +62995,11 @@ function compileOccurrenceMap({
62381
62995
  const length = run.to - run.from;
62382
62996
  if (!charge(length)) return fallback("work-limit");
62383
62997
  for (let k2 = 0; k2 < length; k2++) {
62384
- const bi2 = run.from + k2, si3 = run.target + k2;
62998
+ const bi3 = run.from + k2, si3 = run.target + k2;
62385
62999
  budget.comparisons++;
62386
- if (base.text[bi2] !== side.text[si3])
63000
+ if (base.text[bi3] !== side.text[si3])
62387
63001
  return fallback("unequal-occurrence");
62388
- const ba2 = base.atomAt.get(bi2), sa3 = side.atomAt.get(si3);
63002
+ const ba2 = base.atomAt.get(bi3), sa3 = side.atomAt.get(si3);
62389
63003
  if (!!ba2 !== !!sa3 || ba2 && baseAtomKey(ba2) !== sideAtomKey(sa3))
62390
63004
  return fallback("different-atom");
62391
63005
  }
@@ -62451,27 +63065,27 @@ function boundaryOccurrences({
62451
63065
  last2.to++;
62452
63066
  else runs.push({ from, to: from + 1, target, destination, kind });
62453
63067
  };
62454
- let bi2 = 0, si3 = 0, changedBoundary = false;
63068
+ let bi3 = 0, si3 = 0, changedBoundary = false;
62455
63069
  try {
62456
- while (bi2 < base.text.length || si3 < side.text.length) {
62457
- if (bi2 < base.text.length && si3 < side.text.length && base.text[bi2] === side.text[si3]) {
62458
- const ba2 = base.atomAt.get(bi2), sa3 = side.atomAt.get(si3);
63070
+ while (bi3 < base.text.length || si3 < side.text.length) {
63071
+ if (bi3 < base.text.length && si3 < side.text.length && base.text[bi3] === side.text[si3]) {
63072
+ const ba2 = base.atomAt.get(bi3), sa3 = side.atomAt.get(si3);
62459
63073
  if (!!ba2 !== !!sa3 || ba2 && baseOf2(sa3.el) !== ba2.el)
62460
63074
  return { status: "none" };
62461
- append3(bi2++, si3++);
63075
+ append3(bi3++, si3++);
62462
63076
  continue;
62463
63077
  }
62464
- if (!soft(base.text, bi2) && !soft(side.text, si3))
63078
+ if (!soft(base.text, bi3) && !soft(side.text, si3))
62465
63079
  return { status: "none" };
62466
- const bs3 = bi2, ss3 = si3;
62467
- while (soft(base.text, bi2)) bi2++;
63080
+ const bs3 = bi3, ss3 = si3;
63081
+ while (soft(base.text, bi3)) bi3++;
62468
63082
  while (soft(side.text, si3)) si3++;
62469
- const bt3 = base.text.slice(bs3, bi2), st3 = side.text.slice(ss3, si3);
63083
+ const bt3 = base.text.slice(bs3, bi3), st3 = side.text.slice(ss3, si3);
62470
63084
  if (bt3.includes(BREAK3) || st3.includes(BREAK3)) changedBoundary = true;
62471
63085
  let tail = 0;
62472
- while (tail < bi2 - bs3 && tail < si3 - ss3 && base.text[bi2 - tail - 1] === side.text[si3 - tail - 1])
63086
+ while (tail < bi3 - bs3 && tail < si3 - ss3 && base.text[bi3 - tail - 1] === side.text[si3 - tail - 1])
62473
63087
  tail++;
62474
- for (let k2 = tail; k2 > 0; k2--) append3(bi2 - k2, si3 - k2);
63088
+ for (let k2 = tail; k2 > 0; k2--) append3(bi3 - k2, si3 - k2);
62475
63089
  }
62476
63090
  } catch (error) {
62477
63091
  if (error === exhausted)
@@ -62955,9 +63569,9 @@ var offsets = (toks) => {
62955
63569
  function sideDiff(fs3, bToks, sToks, d) {
62956
63570
  const bOff = offsets(bToks), sOff = offsets(sToks);
62957
63571
  const hunks = [];
62958
- let bi2 = 0, si3 = 0;
63572
+ let bi3 = 0, si3 = 0;
62959
63573
  for (const h of d.hunks) {
62960
- si3 += h.bs - bi2;
63574
+ si3 += h.bs - bi3;
62961
63575
  const ste = si3 + h.toks.length;
62962
63576
  hunks.push({
62963
63577
  bs: bOff[h.bs],
@@ -62969,7 +63583,7 @@ function sideDiff(fs3, bToks, sToks, d) {
62969
63583
  lead: !!h.lead
62970
63584
  });
62971
63585
  si3 = ste;
62972
- bi2 = h.be;
63586
+ bi3 = h.be;
62973
63587
  }
62974
63588
  const respell = /* @__PURE__ */ new Map();
62975
63589
  for (const c of d.cosmetic) respell.set(c.bi, c.tok.raw);
@@ -63282,8 +63896,8 @@ function mergeInline(o) {
63282
63896
  const byTwin = !!(L3 && L3.reverse && L3.map && R3 && R3.reverse && R3.map);
63283
63897
  const atomizers = { base: null, local: null, remote: null };
63284
63898
  if (!o.prepared && byTwin && o.moveIn) {
63285
- const within = (nodes2) => (x3) => nodes2.some((n2) => n2 === x3 || n2.nodeType === 1 && n2.contains(x3));
63286
- const inL = within(o.local), inR = within(o.remote), inB = within(o.base);
63899
+ const within2 = (nodes2) => (x3) => nodes2.some((n2) => n2 === x3 || n2.nodeType === 1 && n2.contains(x3));
63900
+ const inL = within2(o.local), inR = within2(o.remote), inB = within2(o.base);
63287
63901
  const moved = /* @__PURE__ */ new Set();
63288
63902
  const visit = (el3) => {
63289
63903
  if (!MARK_TAGS.has(el3.tagName)) return;
@@ -63303,8 +63917,8 @@ function mergeInline(o) {
63303
63917
  }
63304
63918
  const skip = { base: /* @__PURE__ */ new Set(), local: /* @__PURE__ */ new Set(), remote: /* @__PURE__ */ new Set() };
63305
63919
  if (!o.prepared && byTwin && o.moveIn) {
63306
- const within = (nodes2) => (x3) => nodes2.some((n2) => n2 === x3 || n2.nodeType === 1 && n2.contains(x3));
63307
- const inL = within(o.local), inR = within(o.remote);
63920
+ const within2 = (nodes2) => (x3) => nodes2.some((n2) => n2 === x3 || n2.nodeType === 1 && n2.contains(x3));
63921
+ const inL = within2(o.local), inR = within2(o.remote);
63308
63922
  for (const a of flatten2(o.base, { ...o, atomize: atomizers.base }).atoms) {
63309
63923
  const lt3 = L3.map.get(a.el), rt3 = R3.map.get(a.el);
63310
63924
  const outL = !!lt3 && !inL(lt3), outR = !!rt3 && !inR(rt3);
@@ -64878,7 +65492,7 @@ function planLineage({
64878
65492
  const p = n.parentNode;
64879
65493
  return p && p.nodeType === 11 ? hostOf.get(p) || null : p;
64880
65494
  };
64881
- const inside = (x3, M3) => {
65495
+ const inside2 = (x3, M3) => {
64882
65496
  for (let n = x3; n; n = up(n)) if (n === M3) return true;
64883
65497
  return false;
64884
65498
  };
@@ -64923,7 +65537,7 @@ function planLineage({
64923
65537
  for (const o of outs) {
64924
65538
  if (o === LOST || !inTree.has(o)) return "output-not-placed";
64925
65539
  if (!M3) return "survives-elsewhere";
64926
- if (!inside(o, M3)) return "escaped";
65540
+ if (!inside2(o, M3)) return "escaped";
64927
65541
  owned.push(o);
64928
65542
  }
64929
65543
  } else if (!covered && !decided && !decidedAt(c) && !segLocal.has(c))
@@ -65120,7 +65734,7 @@ function planNativeTransfers({
65120
65734
  for (const side of ["local", "remote"]) {
65121
65735
  const removed = /* @__PURE__ */ new Map(), inserted = /* @__PURE__ */ new Map();
65122
65736
  let hasReplacement = false;
65123
- const add2 = (map2, text4, h) => {
65737
+ const add3 = (map2, text4, h) => {
65124
65738
  if (map2.has(text4)) map2.set(text4, null);
65125
65739
  else map2.set(text4, h);
65126
65740
  };
@@ -65130,10 +65744,10 @@ function planNativeTransfers({
65130
65744
  if (h.bs < h.be && h.text === "") {
65131
65745
  const text4 = B3.slice(h.bs, h.be);
65132
65746
  if (!charge(text4.length * 2)) return null;
65133
- if (/\S/.test(text4)) add2(removed, text4, h);
65747
+ if (/\S/.test(text4)) add3(removed, text4, h);
65134
65748
  } else if (h.bs === h.be && /\S/.test(h.text)) {
65135
65749
  if (!charge(h.text.length * 2)) return null;
65136
- add2(inserted, h.text, h);
65750
+ add3(inserted, h.text, h);
65137
65751
  } else if (h.bs < h.be) hasReplacement = true;
65138
65752
  }
65139
65753
  for (const [text4, deletion] of removed) {
@@ -65237,16 +65851,16 @@ function planNativeTransfers({
65237
65851
  }
65238
65852
  const maps = {};
65239
65853
  for (const side of ["local", "remote"]) {
65240
- let bi2 = 0, si3 = 0;
65854
+ let bi3 = 0, si3 = 0;
65241
65855
  const retained = [];
65242
65856
  for (const h of hunks[side]) {
65243
65857
  if (!charge(1)) return null;
65244
- if (h.bs > bi2) retained.push({ from: bi2, to: h.bs, target: si3 });
65245
- bi2 = h.be;
65858
+ if (h.bs > bi3) retained.push({ from: bi3, to: h.bs, target: si3 });
65859
+ bi3 = h.be;
65246
65860
  si3 = h.se;
65247
65861
  }
65248
- if (bi2 < flats.base.text.length)
65249
- retained.push({ from: bi2, to: flats.base.text.length, target: si3 });
65862
+ if (bi3 < flats.base.text.length)
65863
+ retained.push({ from: bi3, to: flats.base.text.length, target: si3 });
65250
65864
  const moved = transfers.filter((event) => event.side === side).map((event) => ({
65251
65865
  from: event.bs,
65252
65866
  to: event.be,
@@ -65608,7 +66222,7 @@ function mergeObjects(base, local, remote, opts, path, keyPath) {
65608
66222
  ...Object.keys(remote)
65609
66223
  ]);
65610
66224
  for (const key of keys) {
65611
- const merged = mergePresence(
66225
+ const merged2 = mergePresence(
65612
66226
  has3(base, key) ? base[key] : MISSING,
65613
66227
  has3(local, key) ? local[key] : MISSING,
65614
66228
  has3(remote, key) ? remote[key] : MISSING,
@@ -65616,7 +66230,7 @@ function mergeObjects(base, local, remote, opts, path, keyPath) {
65616
66230
  keySegment(path, key),
65617
66231
  childKeyPath(keyPath, key)
65618
66232
  );
65619
- if (merged !== MISSING) setKey(result, key, merged);
66233
+ if (merged2 !== MISSING) setKey(result, key, merged2);
65620
66234
  }
65621
66235
  return result;
65622
66236
  }
@@ -65707,7 +66321,7 @@ function mergeArrays(base, local, remote, opts, path, keyPath) {
65707
66321
  const baseMap = toMap(baseArr);
65708
66322
  const localMap = toMap(local);
65709
66323
  const remoteMap = toMap(remote);
65710
- const merged = /* @__PURE__ */ new Map();
66324
+ const merged2 = /* @__PURE__ */ new Map();
65711
66325
  const allIds = /* @__PURE__ */ new Set([
65712
66326
  ...baseMap.keys(),
65713
66327
  ...localMap.keys(),
@@ -65722,16 +66336,16 @@ function mergeArrays(base, local, remote, opts, path, keyPath) {
65722
66336
  segments.get(id),
65723
66337
  keyPath
65724
66338
  );
65725
- if (value !== MISSING) merged.set(id, value);
66339
+ if (value !== MISSING) merged2.set(id, value);
65726
66340
  }
65727
66341
  const order2 = [];
65728
66342
  for (const item of remote) {
65729
66343
  const id = idOf(item);
65730
- if (merged.has(id)) order2.push(id);
66344
+ if (merged2.has(id)) order2.push(id);
65731
66345
  }
65732
66346
  for (let i = 0; i < local.length; i++) {
65733
66347
  const id = idOf(local[i]);
65734
- if (!merged.has(id) || order2.includes(id)) continue;
66348
+ if (!merged2.has(id) || order2.includes(id)) continue;
65735
66349
  let insertAt = 0;
65736
66350
  for (let j3 = i - 1; j3 >= 0; j3--) {
65737
66351
  const prevIndex = order2.indexOf(idOf(local[j3]));
@@ -65742,7 +66356,7 @@ function mergeArrays(base, local, remote, opts, path, keyPath) {
65742
66356
  }
65743
66357
  order2.splice(insertAt, 0, id);
65744
66358
  }
65745
- return order2.map((id) => merged.get(id));
66359
+ return order2.map((id) => merged2.get(id));
65746
66360
  }
65747
66361
  function resolveOptions(options) {
65748
66362
  const keyPaths = /* @__PURE__ */ new Map();
@@ -65805,17 +66419,17 @@ function mergeScriptText(baseText, localText, remoteText, options = {}) {
65805
66419
  if (local === MISSING) return { text: remoteText, warnings, conflicts };
65806
66420
  if (remote === MISSING) return { text: localText, warnings, conflicts };
65807
66421
  const base = tryParse(baseText, "base");
65808
- const merged = mergeJson(base === MISSING ? void 0 : base, local, remote, {
66422
+ const merged2 = mergeJson(base === MISSING ? void 0 : base, local, remote, {
65809
66423
  ...options,
65810
66424
  onConflict: (c) => {
65811
66425
  conflicts.push(c);
65812
66426
  options.onConflict?.(c);
65813
66427
  }
65814
66428
  });
65815
- if (deepEqual(merged, remote))
66429
+ if (deepEqual(merged2, remote))
65816
66430
  return { text: remoteText, warnings, conflicts };
65817
- if (deepEqual(merged, local)) return { text: localText, warnings, conflicts };
65818
- return { text: serializeLike(merged, remoteText), warnings, conflicts };
66431
+ if (deepEqual(merged2, local)) return { text: localText, warnings, conflicts };
66432
+ return { text: serializeLike(merged2, remoteText), warnings, conflicts };
65819
66433
  }
65820
66434
 
65821
66435
  // node_modules/hyper-morph/src/recovery-dom.js
@@ -65930,7 +66544,7 @@ function createRecovery(ctx) {
65930
66544
  const order2 = /* @__PURE__ */ new Map();
65931
66545
  const outOwners = /* @__PURE__ */ new WeakMap();
65932
66546
  let seq = 0;
65933
- const add2 = (src, n) => {
66547
+ const add3 = (src, n) => {
65934
66548
  let list = outputs.get(src);
65935
66549
  if (!list) outputs.set(src, list = []);
65936
66550
  list.push(n);
@@ -65941,8 +66555,8 @@ function createRecovery(ctx) {
65941
66555
  if (p && !p.pinned)
65942
66556
  for (const v3 of [p.base, p.local, p.remote]) {
65943
66557
  if (!v3) continue;
65944
- if (Array.isArray(v3)) for (const x3 of v3) add2(x3, n);
65945
- else add2(v3, n);
66558
+ if (Array.isArray(v3)) for (const x3 of v3) add3(x3, n);
66559
+ else add3(v3, n);
65946
66560
  }
65947
66561
  if (isTemplate(n)) {
65948
66562
  outOwners.set(n.content, n);
@@ -66361,7 +66975,7 @@ function createRecovery(ctx) {
66361
66975
  return `${prefix}:${n}`;
66362
66976
  };
66363
66977
  const text4 = (rec, meta) => {
66364
- let U3, bs3, be3, encoding = "plain", base, local, remote, merged, anchor;
66978
+ let U3, bs3, be3, encoding = "plain", base, local, remote, merged2, anchor;
66365
66979
  const runSide = (u, k0, k1, sd, bk) => {
66366
66980
  if (!u) {
66367
66981
  const g2 = gapIn(bk, sd);
@@ -66391,7 +67005,7 @@ function createRecovery(ctx) {
66391
67005
  remote = runSide(rRun, c.rs, c.re, "remote", bRun);
66392
67006
  const mv = node ? node.nodeValue : "";
66393
67007
  const pt3 = (k2) => node ? { kind: "text", node, offset: k2 } : gapOut(bRun);
66394
- merged = link(
67008
+ merged2 = link(
66395
67009
  plain4(
66396
67010
  mv,
66397
67011
  c.ms,
@@ -66418,7 +67032,7 @@ function createRecovery(ctx) {
66418
67032
  local = whole(rec.local, p.local, "local");
66419
67033
  remote = whole(rec.remote, p.remote, "remote");
66420
67034
  const s = wholeSpanOut(el3);
66421
- merged = link(
67035
+ merged2 = link(
66422
67036
  plain4(rec.resolved, 0, rec.resolved.length, s, s),
66423
67037
  { kind: "wholeStart", node: el3 },
66424
67038
  { kind: "wholeEnd", node: el3 },
@@ -66449,7 +67063,7 @@ function createRecovery(ctx) {
66449
67063
  const v3 = rec.resolved;
66450
67064
  const pt3 = (k2) => node ? { kind: "text", node, offset: k2 } : gapOut(bRun);
66451
67065
  const s = { start: staticPoint(pt3(0)), end: staticPoint(pt3(v3.length)) };
66452
- merged = link(
67066
+ merged2 = link(
66453
67067
  plain4(v3, 0, v3.length, s, s),
66454
67068
  pt3(0),
66455
67069
  pt3(v3.length),
@@ -66485,8 +67099,8 @@ function createRecovery(ctx) {
66485
67099
  start: pt3(rawPoint(f, 0, "start")),
66486
67100
  end: pt3(rawPoint(f, f.text.length, "end"))
66487
67101
  });
66488
- const ks3 = rs3 ? measure(F3, rs3) : null, ke4 = re2 ? measure(F3, re2) : null;
66489
- const S2 = ks3 === null ? 0 : ks3;
67102
+ const ks4 = rs3 ? measure(F3, rs3) : null, ke4 = re2 ? measure(F3, re2) : null;
67103
+ const S2 = ks4 === null ? 0 : ks4;
66490
67104
  const E3 = Math.max(S2, ke4 === null ? F3.text.length : ke4);
66491
67105
  const s0 = pt3(rawPoint(F3, 0, "start"));
66492
67106
  return side(F3.text, S2, E3, sliceHtml(F3, S2, E3), span2, {
@@ -66524,10 +67138,10 @@ function createRecovery(ctx) {
66524
67138
  segmentGap
66525
67139
  ), De2 = ms3 === me3 ? Ds3 : mergedPoint(M3, me3, "end", segmentGap);
66526
67140
  const S0 = fo3.text.length ? outDesc(fo3, 0, "start", M3.node) : segmentGap(), S1 = fo3.text.length ? outDesc(fo3, fo3.text.length, "end", M3.node) : S0;
66527
- const ks2 = measure(fo3, Ds3), ke3 = measure(fo3, De2);
66528
- const s = ks2 === null ? 0 : ks2;
67141
+ const ks3 = measure(fo3, Ds3), ke3 = measure(fo3, De2);
67142
+ const s = ks3 === null ? 0 : ks3;
66529
67143
  const e19 = Math.max(s, ke3 === null ? fo3.text.length : ke3);
66530
- merged = link(
67144
+ merged2 = link(
66531
67145
  side(
66532
67146
  fo3.text,
66533
67147
  s,
@@ -66541,7 +67155,7 @@ function createRecovery(ctx) {
66541
67155
  S0,
66542
67156
  S1
66543
67157
  );
66544
- const linked = links.spans.get(merged);
67158
+ const linked = links.spans.get(merged2);
66545
67159
  linked.flat = fo3;
66546
67160
  if (!fo3.text.length) {
66547
67161
  const p = staticPoint(S0);
@@ -66567,7 +67181,7 @@ function createRecovery(ctx) {
66567
67181
  base,
66568
67182
  local,
66569
67183
  remote,
66570
- merged,
67184
+ merged: merged2,
66571
67185
  liveSpan: null,
66572
67186
  liveScope: null
66573
67187
  }
@@ -66766,10 +67380,10 @@ function createMoveDestinations({
66766
67380
  const outputAuthority = /* @__PURE__ */ new WeakMap();
66767
67381
  const attached = /* @__PURE__ */ new WeakSet();
66768
67382
  const visiting = /* @__PURE__ */ new Set();
66769
- const add2 = (source, entry) => {
67383
+ const add3 = (source, entry) => {
66770
67384
  if (!source) return;
66771
67385
  if (Array.isArray(source)) {
66772
- for (const node of source) add2(node, entry);
67386
+ for (const node of source) add3(node, entry);
66773
67387
  return;
66774
67388
  }
66775
67389
  let entries = outputs.get(source);
@@ -66781,7 +67395,7 @@ function createMoveDestinations({
66781
67395
  const stack = [source];
66782
67396
  while (stack.length) {
66783
67397
  const node = stack.pop();
66784
- add2(node, entry);
67398
+ add3(node, entry);
66785
67399
  for (const child of childrenOf(node).childNodes) stack.push(child);
66786
67400
  }
66787
67401
  };
@@ -66799,7 +67413,7 @@ function createMoveDestinations({
66799
67413
  for (const source of [p.base, p.local, p.remote])
66800
67414
  representedSubtree(source, { ...entry, kind: "unchanged" });
66801
67415
  } else if (p) {
66802
- for (const source of [p.base, p.local, p.remote]) add2(source, entry);
67416
+ for (const source of [p.base, p.local, p.remote]) add3(source, entry);
66803
67417
  if (isElement(p.local)) {
66804
67418
  for (const child of childrenOf(p.local).children)
66805
67419
  if (ignored(child))
@@ -67414,10 +68028,10 @@ function createCrossParentConsumer({
67414
68028
  const authority = /* @__PURE__ */ new WeakMap();
67415
68029
  const outputs = /* @__PURE__ */ new WeakMap();
67416
68030
  const children2 = (node) => node.tagName === "TEMPLATE" && node.content ? node.content : node;
67417
- const add2 = (source, node) => {
68031
+ const add3 = (source, node) => {
67418
68032
  if (!source) return;
67419
68033
  if (Array.isArray(source)) {
67420
- for (const part of source) add2(part, node);
68034
+ for (const part of source) add3(part, node);
67421
68035
  return;
67422
68036
  }
67423
68037
  let list = outputs.get(source);
@@ -67431,7 +68045,7 @@ function createCrossParentConsumer({
67431
68045
  const authoritative = inherited || !!(p && remoteWins(p.remote || p.base));
67432
68046
  authority.set(node, authoritative);
67433
68047
  if (p)
67434
- for (const source of [p.base, p.local, p.remote]) add2(source, node);
68048
+ for (const source of [p.base, p.local, p.remote]) add3(source, node);
67435
68049
  if (p?.pinned || p?.unchanged) return;
67436
68050
  for (const child of children2(node).childNodes)
67437
68051
  index2(child, node, authoritative);
@@ -68171,19 +68785,19 @@ function certificateGroups({
68171
68785
  budget.remaining -= cost;
68172
68786
  const edits = diffTokens(B3, S2, depth);
68173
68787
  const pairs = [];
68174
- let bi2 = 0, si3 = 0;
68788
+ let bi3 = 0, si3 = 0;
68175
68789
  for (const h of edits.hunks) {
68176
- while (bi2 < h.bs) {
68177
- if (B3[bi2].raw === S2[si3].raw) pairs.push([B3[bi2], S2[si3]]);
68178
- bi2++;
68790
+ while (bi3 < h.bs) {
68791
+ if (B3[bi3].raw === S2[si3].raw) pairs.push([B3[bi3], S2[si3]]);
68792
+ bi3++;
68179
68793
  si3++;
68180
68794
  }
68181
- bi2 = h.be;
68795
+ bi3 = h.be;
68182
68796
  si3 += h.toks.length;
68183
68797
  }
68184
- while (bi2 < B3.length && si3 < S2.length) {
68185
- if (B3[bi2].raw === S2[si3].raw) pairs.push([B3[bi2], S2[si3]]);
68186
- bi2++;
68798
+ while (bi3 < B3.length && si3 < S2.length) {
68799
+ if (B3[bi3].raw === S2[si3].raw) pairs.push([B3[bi3], S2[si3]]);
68800
+ bi3++;
68187
68801
  si3++;
68188
68802
  }
68189
68803
  return pairs;
@@ -68440,13 +69054,13 @@ function certificateGroups({
68440
69054
  if (M3.flat.atoms.length) continue;
68441
69055
  const otherUsed = reserved.get(other);
68442
69056
  charge(budget, M3.flat.text.length * 3);
68443
- let missing = "", otherKept = false;
69057
+ let missing2 = "", otherKept = false;
68444
69058
  for (let i = 0; i < M3.flat.text.length; i++) {
68445
69059
  if (SPACE2.test(M3.flat.text[i])) continue;
68446
69060
  if (otherUsed[i]) otherKept = true;
68447
- else missing += M3.flat.text[i];
69061
+ else missing2 += M3.flat.text[i];
68448
69062
  }
68449
- if (otherKept && missing === remainder) {
69063
+ if (otherKept && missing2 === remainder) {
68450
69064
  ambiguousSources ||= /* @__PURE__ */ new Set();
68451
69065
  ambiguousSources.add(source);
68452
69066
  ambiguousSources.add(other);
@@ -68456,21 +69070,21 @@ function certificateGroups({
68456
69070
  if (competing) continue;
68457
69071
  const after3 = models.get(target).flat.text;
68458
69072
  charge(budget, to3 - from + after3.length);
68459
- let bi2 = from, si3 = 0;
68460
- while (bi2 < to3 && si3 < after3.length) {
68461
- while (bi2 < to3 && SPACE2.test(text4[bi2])) bi2++;
69073
+ let bi3 = from, si3 = 0;
69074
+ while (bi3 < to3 && si3 < after3.length) {
69075
+ while (bi3 < to3 && SPACE2.test(text4[bi3])) bi3++;
68462
69076
  while (si3 < after3.length && SPACE2.test(after3[si3])) si3++;
68463
- if (bi2 >= to3 || si3 >= after3.length) break;
69077
+ if (bi3 >= to3 || si3 >= after3.length) break;
68464
69078
  append3(
68465
69079
  exactTransfers ||= [],
68466
69080
  source,
68467
69081
  target,
68468
- bi2,
68469
- bi2 + 1,
69082
+ bi3,
69083
+ bi3 + 1,
68470
69084
  si3,
68471
69085
  budget
68472
69086
  );
68473
- bi2++;
69087
+ bi3++;
68474
69088
  si3++;
68475
69089
  }
68476
69090
  used.fill(1, from, to3);
@@ -68509,14 +69123,14 @@ function certificateGroups({
68509
69123
  if ((!bhard || !shard) && !exactTransfers) continue;
68510
69124
  const matches = exactTransfers || [];
68511
69125
  if (bhard && shard && bhard === shard) {
68512
- let ti2 = 0, tj = 0, bi2 = 0, sj = 0;
69126
+ let ti2 = 0, tj = 0, bi3 = 0, sj = 0;
68513
69127
  while (ti2 < bt3.length && tj < st3.length) {
68514
69128
  const x3 = bt3[ti2], y2 = st3[tj];
68515
- while (bi2 < x3.raw.length && SPACE2.test(x3.raw[bi2])) bi2++;
69129
+ while (bi3 < x3.raw.length && SPACE2.test(x3.raw[bi3])) bi3++;
68516
69130
  while (sj < y2.raw.length && SPACE2.test(y2.raw[sj])) sj++;
68517
- if (bi2 === x3.raw.length) {
69131
+ if (bi3 === x3.raw.length) {
68518
69132
  ti2++;
68519
- bi2 = 0;
69133
+ bi3 = 0;
68520
69134
  continue;
68521
69135
  }
68522
69136
  if (sj === y2.raw.length) {
@@ -68534,12 +69148,12 @@ function certificateGroups({
68534
69148
  matches,
68535
69149
  x3.unit,
68536
69150
  y2.unit,
68537
- x3.from + bi2,
68538
- x3.from + bi2 + 1,
69151
+ x3.from + bi3,
69152
+ x3.from + bi3 + 1,
68539
69153
  y2.from + sj,
68540
69154
  budget
68541
69155
  );
68542
- bi2++;
69156
+ bi3++;
68543
69157
  sj++;
68544
69158
  }
68545
69159
  } else if (bhard && shard) {
@@ -69068,18 +69682,18 @@ function certifiedOrigins({
69068
69682
  if (depth < 1) throw exhausted;
69069
69683
  charge(4 * (depth + 1) * (size + depth + 1));
69070
69684
  const edits = diffTokens(B3, S2, depth);
69071
- let bi2 = 0, si3 = 0;
69685
+ let bi3 = 0, si3 = 0;
69072
69686
  const equal = () => {
69073
- const x3 = B3[bi2++], y2 = S2[si3++];
69687
+ const x3 = B3[bi3++], y2 = S2[si3++];
69074
69688
  charge(x3.len);
69075
69689
  if (x3.raw === y2.raw) append3(runs, x3.from, x3.to, y2.from, "retained");
69076
69690
  };
69077
69691
  for (const h of edits.hunks) {
69078
- while (bi2 < h.bs) equal();
69079
- bi2 = h.be;
69692
+ while (bi3 < h.bs) equal();
69693
+ bi3 = h.be;
69080
69694
  si3 += h.toks.length;
69081
69695
  }
69082
- while (bi2 < B3.length && si3 < S2.length) equal();
69696
+ while (bi3 < B3.length && si3 < S2.length) equal();
69083
69697
  };
69084
69698
  const compile4 = (side) => {
69085
69699
  const selected = certificates.filter(
@@ -69087,7 +69701,7 @@ function certifiedOrigins({
69087
69701
  );
69088
69702
  if (!selected.length) return null;
69089
69703
  const anchors = [];
69090
- const add2 = (run, models, kind) => {
69704
+ const add3 = (run, models, kind) => {
69091
69705
  if (!sets[0].has(run.source) || !sets[side].has(run.target)) return;
69092
69706
  const bp = project2(models.get(run.source).flat, flats[0]);
69093
69707
  const sp = project2(models.get(run.target).flat, flats[side]);
@@ -69102,9 +69716,9 @@ function certifiedOrigins({
69102
69716
  for (const cert of selected) {
69103
69717
  if (!retainedArrays.has(cert.retained)) {
69104
69718
  retainedArrays.add(cert.retained);
69105
- for (const run of cert.retained) add2(run, cert.models, "retained");
69719
+ for (const run of cert.retained) add3(run, cert.models, "retained");
69106
69720
  }
69107
- for (const run of cert.runs) add2(run, cert.models, "transfer");
69721
+ for (const run of cert.runs) add3(run, cert.models, "transfer");
69108
69722
  }
69109
69723
  anchors.sort((a, b2) => {
69110
69724
  charge(1);
@@ -69121,15 +69735,15 @@ function certifiedOrigins({
69121
69735
  } else ordered.push(run);
69122
69736
  }
69123
69737
  const runs = [];
69124
- let bi2 = 0, si3 = 0;
69738
+ let bi3 = 0, si3 = 0;
69125
69739
  for (const run of ordered) {
69126
69740
  if (run.target < si3) throw exhausted;
69127
- gap(runs, side, bi2, run.from, si3, run.target);
69741
+ gap(runs, side, bi3, run.from, si3, run.target);
69128
69742
  runs.push(run);
69129
- bi2 = run.to;
69743
+ bi3 = run.to;
69130
69744
  si3 = run.target + run.to - run.from;
69131
69745
  }
69132
- gap(runs, side, bi2, flats[0].text.length, si3, flats[side].text.length);
69746
+ gap(runs, side, bi3, flats[0].text.length, si3, flats[side].text.length);
69133
69747
  const result = compileOccurrenceMap({
69134
69748
  base: flats[0],
69135
69749
  side: flats[side],
@@ -71545,10 +72159,10 @@ function mergePageModels(base, current, incoming, { doc, merge3: merge33, mergeJ
71545
72159
  }
71546
72160
  const res = merge33(inlineOf2(was, doc), inlineOf2(l, doc), inlineOf2(r44, doc));
71547
72161
  for (const k2 of res.conflicts) conflicts.push({ id, kind: "text", local: k2.local?.textContent ?? null, remote: k2.remote?.textContent ?? null });
71548
- const [merged] = parseModel(res.root, { seed: "", known: /* @__PURE__ */ new Map() });
72162
+ const [merged2] = parseModel(res.root, { seed: "", known: /* @__PURE__ */ new Map() });
71549
72163
  for (const t of [c2.get(id), i2.get(id)]) {
71550
- t.c = merged.c;
71551
- if (merged.m) t.m = merged.m;
72164
+ t.c = merged2.c;
72165
+ if (merged2.m) t.m = merged2.m;
71552
72166
  else delete t.m;
71553
72167
  }
71554
72168
  }
@@ -71630,7 +72244,7 @@ function rebasePage({ storedHtml, state, incomingHtml, baseHtml, createDocument
71630
72244
  const base = articleOf(baseHtml, doc);
71631
72245
  const stored = articleOf(storedHtml, doc);
71632
72246
  if (!incoming || !base || !stored) return null;
71633
- const merged = mergePageModels(
72247
+ const merged2 = mergePageModels(
71634
72248
  parseModel(base.article, { seed: rev, known }),
71635
72249
  parseModel(stored.article, { seed: state.rev, known }),
71636
72250
  parseModel(incoming.article, { seed: rev, known }),
@@ -71638,13 +72252,13 @@ function rebasePage({ storedHtml, state, incomingHtml, baseHtml, createDocument
71638
72252
  );
71639
72253
  const fallbackOf = (id) => typeof blocks[id]?.artifact?.fallbackHtml === "string" ? blocks[id].artifact.fallbackHtml : "";
71640
72254
  const inner = `
71641
- ${renderModel(merged.items, { fallbackOf, clean: fragmentCleaner(doc) })}
72255
+ ${renderModel(merged2.items, { fallbackOf, clean: fragmentCleaner(doc) })}
71642
72256
  `;
71643
72257
  const [innerStart, innerEnd] = incoming.inner;
71644
72258
  const open = stampOpen(incomingHtml, incoming.startTag, state.rev);
71645
72259
  const body = incomingHtml.slice(0, incoming.startTag.startOffset) + open + inner + incomingHtml.slice(innerEnd);
71646
72260
  const html3 = withPageFormatFloor(body, Math.max(pageFormatFloor(storedHtml), pageFormatFloor(incomingHtml)));
71647
- return { html: html3, conflicts: merged.conflicts };
72261
+ return { html: html3, conflicts: merged2.conflicts };
71648
72262
  }
71649
72263
  function closestBase(candidates, incomingHtml, createDocument) {
71650
72264
  if (candidates.length <= 1) return candidates[0] ?? null;
@@ -72020,6 +72634,163 @@ function pageTransitionState(transition, clientId) {
72020
72634
  // src/server/rooms/live-data-rooms.js
72021
72635
  var import_node_crypto3 = require("node:crypto");
72022
72636
  var import_node_util = require("node:util");
72637
+
72638
+ // src/live/page-compaction.js
72639
+ var COMPACTION = Object.freeze({
72640
+ version: 1,
72641
+ loose: 32,
72642
+ soft: 16,
72643
+ activeBytes: 3840 * 1024,
72644
+ deleteReserve: 64 * 1024,
72645
+ newPerFrame: 4,
72646
+ tailFloor: 64 * 1024,
72647
+ leaseMs: 60 * 1e3,
72648
+ retired: 8192
72649
+ });
72650
+ var ROOM_ERROR_STATUS = Object.freeze({
72651
+ "checkpoint-required": 503,
72652
+ "page-full": 409,
72653
+ "compaction-failed": 409,
72654
+ "page-immutable": 409,
72655
+ "page-batch": 409,
72656
+ "page-update-invalid": 422,
72657
+ "page-upgrade": 404
72658
+ });
72659
+ var CLIENT_KEY = /^[ur][0-9a-z]+(-[0-9a-z]+){2}$/;
72660
+ var HOST_KEY = /^[ctf][0-9a-z]{8}-[0-9a-z]+(-[0-9a-z]+)?$/;
72661
+ var CHECKPOINT_KEY = /^(seed|c[0-9a-z]{8}-[0-9a-z]+)$/;
72662
+ var isCheckpointKey = (key) => CHECKPOINT_KEY.test(key);
72663
+ function pageShape(y2, limits = COMPACTION) {
72664
+ let checkpoints = 0, loose = 0, parts = 0, legacy = 0;
72665
+ for (const key of Object.keys(y2)) {
72666
+ if (PART_KEY.test(key)) {
72667
+ parts++;
72668
+ continue;
72669
+ }
72670
+ if (isCheckpointKey(key)) checkpoints++;
72671
+ else loose++;
72672
+ if (!CLIENT_KEY.test(key) && !HOST_KEY.test(key) && key !== "seed") legacy++;
72673
+ }
72674
+ return { checkpoints, loose, parts, legacy, normal: parts === 0 && checkpoints <= 1 && loose <= limits.loose };
72675
+ }
72676
+ function planCompaction(y2, { overflow = false } = {}, limits = COMPACTION) {
72677
+ const shape = pageShape(y2, limits);
72678
+ const entries = entriesOf2(y2);
72679
+ const checkpoint = entries.filter(([key]) => isCheckpointKey(key));
72680
+ const loose = entries.filter(([key]) => !isCheckpointKey(key));
72681
+ const looseBytes = loose.reduce((sum, [, v3]) => sum + v3.length, 0);
72682
+ const checkpointBytes = checkpoint.reduce((sum, [, v3]) => sum + v3.length, 0);
72683
+ const full = !shape.normal || overflow || looseBytes > Math.max(limits.tailFloor, checkpointBytes / 4);
72684
+ if (full) return { kind: "full", sources: entries };
72685
+ if (loose.length < 2 || shape.loose < limits.soft) return null;
72686
+ return { kind: "tail", sources: loose };
72687
+ }
72688
+ function buildCandidate({ kind, sources, encode = Ic }) {
72689
+ const updates = sources.map(([, v3]) => Lo2(v3));
72690
+ if (kind === "tail") {
72691
+ const merged2 = Tn2(updates);
72692
+ const index2 = rangesOf(merged2);
72693
+ for (const update2 of updates) if (!within(index2, rangesOf(update2))) return { failure: "not-covered" };
72694
+ return { update: No2(merged2) };
72695
+ }
72696
+ const doc = new Ct2({ gc: true });
72697
+ try {
72698
+ for (const update2 of updates) Fr2(doc, update2);
72699
+ if (doc.store.pendingStructs || doc.store.pendingDs) {
72700
+ const merged2 = Tn2(updates);
72701
+ const index3 = rangesOf(merged2);
72702
+ for (const update2 of updates) if (!within(index3, rangesOf(update2))) return { failure: "not-covered" };
72703
+ return { update: No2(merged2), pending: true };
72704
+ }
72705
+ const index2 = docRanges(doc);
72706
+ for (const update2 of updates) if (!within(index2, rangesOf(update2))) return { failure: "not-covered" };
72707
+ const out = No2(encode(doc));
72708
+ const check = new Ct2({ gc: true });
72709
+ try {
72710
+ Fr2(check, Lo2(out));
72711
+ const stored = docRanges(check);
72712
+ if (!stored.complete) return { failure: "not-covered" };
72713
+ for (const update2 of updates) if (!within(stored, rangesOf(update2))) return { failure: "not-covered" };
72714
+ } finally {
72715
+ check.destroy();
72716
+ }
72717
+ return { update: out };
72718
+ } catch (error) {
72719
+ return { failure: "invalid-update", message: error?.message || String(error) };
72720
+ } finally {
72721
+ doc.destroy();
72722
+ }
72723
+ }
72724
+ function checkUpdate(text4) {
72725
+ if (typeof text4 !== "string" || !isBase64(text4)) return null;
72726
+ try {
72727
+ const { items, deletes } = rangesOf(Lo2(text4));
72728
+ let deleted = 0;
72729
+ for (const spans of deletes.values()) for (const [from, to3] of spans) deleted += to3 - from;
72730
+ return { deleted, inserts: items.size > 0 };
72731
+ } catch {
72732
+ return null;
72733
+ }
72734
+ }
72735
+ function admitPageOps({ y: y2, ops, state, limits }) {
72736
+ if (state.compaction !== limits.version) return { error: "page-upgrade" };
72737
+ let added = 0;
72738
+ let deleted = 0;
72739
+ let inserts = false;
72740
+ for (const op of ops) {
72741
+ const key = op.path?.[1];
72742
+ if (op.op !== "set" || typeof key !== "string" || !CLIENT_KEY.test(key)) return { error: "page-immutable" };
72743
+ if (Object.hasOwn(y2, key)) {
72744
+ if (y2[key] !== op.value) return { error: "page-immutable" };
72745
+ continue;
72746
+ }
72747
+ if (state.retired.has(key)) return { error: "page-immutable" };
72748
+ const checked = checkUpdate(op.value);
72749
+ if (!checked) return { error: "page-update-invalid" };
72750
+ added += 1;
72751
+ deleted += checked.deleted;
72752
+ inserts ||= checked.inserts;
72753
+ }
72754
+ if (added > limits.newPerFrame) return { error: "page-batch" };
72755
+ if (state.failed) return { added, deleted, inserts, limit: limits.activeBytes + (inserts ? 0 : limits.deleteReserve), shape: null, failed: true };
72756
+ const shape = pageShape(y2, limits);
72757
+ if (!shape.normal || shape.loose + added > limits.loose) return { error: "checkpoint-required", retryAfter: 0 };
72758
+ return { added, deleted, inserts, limit: limits.activeBytes + (inserts ? 0 : limits.deleteReserve), shape };
72759
+ }
72760
+ var UNIQUE_KEY = (key) => CLIENT_KEY.test(key) || HOST_KEY.test(key);
72761
+ function createRangeCache(max = 256) {
72762
+ const cache = /* @__PURE__ */ new Map();
72763
+ return (key, value) => {
72764
+ const hit = cache.get(key);
72765
+ if (hit && hit.value === value) return hit.ranges;
72766
+ const ranges = rangesOf(Lo2(value));
72767
+ cache.delete(key);
72768
+ cache.set(key, { value, ranges });
72769
+ if (cache.size > max) cache.delete(cache.keys().next().value);
72770
+ return ranges;
72771
+ };
72772
+ }
72773
+ function unionFileEntries({ y: y2, fileY, retired, rangesFor, keyFor = (i, key) => key }) {
72774
+ const roomEntries = entriesOf2(y2);
72775
+ const have = new Map(roomEntries);
72776
+ let index2 = null;
72777
+ const adds = [];
72778
+ for (const [key, value] of entriesOf2(fileY ?? {})) {
72779
+ if (have.get(key) === value) continue;
72780
+ if (retired.has(key) && UNIQUE_KEY(key)) continue;
72781
+ let ranges;
72782
+ try {
72783
+ ranges = rangesOf(Lo2(value));
72784
+ } catch {
72785
+ continue;
72786
+ }
72787
+ index2 ??= unite(roomEntries.map(([k2, v3]) => rangesFor(k2, v3)));
72788
+ if (!within(index2, ranges)) adds.push([key, value]);
72789
+ }
72790
+ return adds.map(([key, value], i) => [keyFor(i, key), value]);
72791
+ }
72792
+
72793
+ // src/server/rooms/live-data-rooms.js
72023
72794
  var byteLength = (text4) => Buffer.byteLength(text4, "utf8");
72024
72795
  var sizeOf = (value) => byteLength(serializeLive(value));
72025
72796
  var LIVE_LIMITS = Object.freeze({
@@ -72038,6 +72809,7 @@ var LIVE_LIMITS = Object.freeze({
72038
72809
  movesBytes: 1024 * 1024
72039
72810
  });
72040
72811
  var PAGE4 = /^page(\.[0-9]+)?$/;
72812
+ var COMPACTOR = "compactor";
72041
72813
  var isContainer2 = (v3) => v3 !== null && typeof v3 === "object";
72042
72814
  function seedStores(html3, { pageOnly = false, heldBytes = 0, heldCount = 0 } = {}) {
72043
72815
  const stores = /* @__PURE__ */ new Map();
@@ -72131,7 +72903,32 @@ var PersistentReservationError = class extends Error {
72131
72903
  this.code = code;
72132
72904
  }
72133
72905
  };
72134
- function createRooms({ now = Date.now, newEpoch = import_node_crypto3.randomUUID, liveBytes = LIVE_LIMITS.liveBytes } = {}) {
72906
+ function createRooms({ now = Date.now, newEpoch = import_node_crypto3.randomUUID, liveBytes = LIVE_LIMITS.liveBytes, compaction = null } = {}) {
72907
+ const hostLimits = compaction ? Object.freeze({ ...COMPACTION, ...typeof compaction === "object" ? compaction : {} }) : null;
72908
+ const jobs = /* @__PURE__ */ new WeakMap();
72909
+ let onDue = () => {
72910
+ };
72911
+ const hostMode = (yjs) => hostLimits && yjs ? { fence: 0, job: null, lastFull: null, deletesSince: 0, contentSeq: 0, failed: null, retired: /* @__PURE__ */ new Set(), legacy: /* @__PURE__ */ new Set(), ranges: createRangeCache() } : null;
72912
+ const projectRoom = (room) => {
72913
+ const compaction2 = room.compaction;
72914
+ if (!compaction2) return structuredClone(room);
72915
+ room.compaction = null;
72916
+ let projected;
72917
+ try {
72918
+ projected = structuredClone(room);
72919
+ } finally {
72920
+ room.compaction = compaction2;
72921
+ }
72922
+ projected.compaction = { ...structuredClone({ ...compaction2, job: null, ranges: null }), ranges: createRangeCache() };
72923
+ return projected;
72924
+ };
72925
+ const due = (room, overflow = false) => {
72926
+ if (!room.compaction || room.compaction.job || room.compaction.failed) return;
72927
+ try {
72928
+ onDue(room, { overflow });
72929
+ } catch {
72930
+ }
72931
+ };
72135
72932
  const rooms = /* @__PURE__ */ new Map();
72136
72933
  const pageReservations = /* @__PURE__ */ new Map();
72137
72934
  const reservedNodes = /* @__PURE__ */ new Map();
@@ -72152,7 +72949,8 @@ function createRooms({ now = Date.now, newEpoch = import_node_crypto3.randomUUID
72152
72949
  lastSentAt: /* @__PURE__ */ new Map(),
72153
72950
  seen: /* @__PURE__ */ new Map(),
72154
72951
  emptySince: null,
72155
- ...inspectPage(html3).kind === "yjs" && { pageTransition: makePageTransition() }
72952
+ ...inspectPage(html3).kind === "yjs" && { pageTransition: makePageTransition() },
72953
+ compaction: hostMode(inspectPage(html3).kind === "yjs")
72156
72954
  });
72157
72955
  const roomBytes = (room) => {
72158
72956
  let total = 0;
@@ -72160,10 +72958,91 @@ function createRooms({ now = Date.now, newEpoch = import_node_crypto3.randomUUID
72160
72958
  return total;
72161
72959
  };
72162
72960
  const heldBy = (room) => {
72163
- let total = (room.receiptBytes ?? 0) + (room.pageTransition?.bytes ?? 0);
72961
+ let total = (room.receiptBytes ?? 0) + (room.pageTransition?.bytes ?? 0) + (room.compaction?.job?.reserved ?? 0);
72164
72962
  for (const s of room.stores.values()) total += s.bytes + s.logBytes;
72165
72963
  return total;
72166
72964
  };
72965
+ const admit = (room, store, frame, ops) => {
72966
+ const state = room.compaction;
72967
+ const answer = admitPageOps({ y: store.value.y, ops, state: { ...room.compaction, compaction: frame.compaction }, limits: hostLimits });
72968
+ if (answer.error) {
72969
+ if (answer.error === "checkpoint-required") due(room);
72970
+ return answer;
72971
+ }
72972
+ const { added, deleted, limit, shape } = answer;
72973
+ return {
72974
+ limit,
72975
+ over() {
72976
+ if (answer.failed || state.lastFull && state.deletesSince === 0) return { error: "page-full" };
72977
+ due(room, true);
72978
+ return { error: "checkpoint-required", retryAfter: 0 };
72979
+ },
72980
+ admitted(bytes) {
72981
+ state.deletesSince += deleted;
72982
+ state.contentSeq = room.seq;
72983
+ if (answer.failed) return;
72984
+ if (bytes > hostLimits.activeBytes) due(room, true);
72985
+ else if (shape.loose + added >= hostLimits.soft) due(room);
72986
+ }
72987
+ };
72988
+ };
72989
+ const mergePageFile = (room, store, value) => {
72990
+ const state = room.compaction;
72991
+ if (value.g !== store.value.g) return null;
72992
+ const adds = unionFileEntries({
72993
+ y: store.value.y,
72994
+ fileY: value.y,
72995
+ retired: state.retired,
72996
+ rangesFor: state.ranges,
72997
+ keyFor: (i) => `f${textHash(room.epoch).slice(0, 8)}-${(room.seq + 1).toString(36)}-${i.toString(36)}`
72998
+ });
72999
+ const seq = room.seq + 1;
73000
+ const taken = /* @__PURE__ */ new Set();
73001
+ const ops = [];
73002
+ for (const [key, v3] of adds) {
73003
+ if (Object.hasOwn(store.value.y, key) || taken.has(key)) continue;
73004
+ taken.add(key);
73005
+ ops.push(validateOp({ op: "set", path: ["y", key], value: v3 }));
73006
+ }
73007
+ if (!ops.length) return null;
73008
+ const fits = (n) => n <= LIVE_LIMITS.storeBytes && roomBytes(room) - store.bytes + n <= LIVE_LIMITS.roomBytes;
73009
+ let next2 = applyOps(cloneJson(store.value), ops);
73010
+ let bytes = sizeOf(next2);
73011
+ if (!fits(bytes)) {
73012
+ const built = buildCandidate({ kind: "full", sources: [...entriesOf2(store.value.y), ...adds] });
73013
+ if (!built.update || built.pending) return "dropped";
73014
+ const retire = Object.keys(store.value.y);
73015
+ ops.length = 0;
73016
+ for (const key of retire) ops.push(validateOp({ op: "del", path: ["y", key] }));
73017
+ ops.push(validateOp({ op: "set", path: ["y", `c${textHash(room.epoch).slice(0, 8)}-${seq.toString(36)}`], value: built.update }));
73018
+ next2 = applyOps(cloneJson(store.value), ops);
73019
+ bytes = sizeOf(next2);
73020
+ if (!fits(bytes)) return "dropped";
73021
+ for (const [key] of entriesOf2(store.value.y)) {
73022
+ state.retired.add(key);
73023
+ if (state.retired.size > hostLimits.retired) state.retired.delete(state.retired.values().next().value);
73024
+ }
73025
+ }
73026
+ const logged = byteLength(JSON.stringify(ops));
73027
+ store.value = next2;
73028
+ store.bytes = bytes;
73029
+ room.seq = seq;
73030
+ store.last = seq;
73031
+ store.log.push({ seq, ops, bytes: logged, merge: true });
73032
+ store.inFile.add(seq);
73033
+ store.logBytes += logged;
73034
+ evict(store);
73035
+ state.contentSeq = seq;
73036
+ state.lastFull = null;
73037
+ due(room);
73038
+ return true;
73039
+ };
73040
+ const endJob = (job) => {
73041
+ if (job.room.compaction?.job !== job) return false;
73042
+ job.room.compaction.job = null;
73043
+ if (rooms.get(job.room.key) === job.room) used -= job.reserved;
73044
+ return true;
73045
+ };
72167
73046
  const pageSource = (key, nodeId) => {
72168
73047
  if (nodeId == null) throw new PageConversionError("invalid-document");
72169
73048
  if (pageReservations.has(key) || persistentReservations.has(key) || reservedNodes.has(String(nodeId))) throw new PageConversionError("page-converting");
@@ -72233,62 +73112,77 @@ function createRooms({ now = Date.now, newEpoch = import_node_crypto3.randomUUID
72233
73112
  if (tag.name !== "page" || !isYPageValue(value)) continue;
72234
73113
  } else if (isYPageValue(value, { complete: false })) continue;
72235
73114
  }
73115
+ const host = Boolean(room.compaction && tag.name === "page" && room.pageTransition?.format === "yjs");
72236
73116
  const before2 = store.landed;
72237
73117
  const base = baseOf(room, store, tag.at);
72238
73118
  const stamped = placed(room, store, tag.at) && tag.at.hash === textHash(serializeLive(value));
72239
- if (base < store.floor) {
73119
+ if (!host && base < store.floor) {
72240
73120
  store.landed = -1;
72241
73121
  if (before2 !== -1) landed.push(tag.name);
72242
73122
  continue;
72243
73123
  }
72244
73124
  const by = restored ? null : provenBy(room, tag.name, tag, stamped);
72245
73125
  const frames = tag.at?.epoch === room.epoch ? frameSet(by) : [];
72246
- const ancestry = descendants(by);
72247
- const own = (entry) => {
72248
- if (!by) return false;
72249
- if (!entry.merge) return contains2(frames, entry.from, entry.n);
72250
- const p = entry.provenance;
72251
- return by.v === 2 && p && p.at.epoch === tag.at.epoch && p.at.seq === tag.at.seq && contains2(ancestry, ...p.capture);
72252
- };
72253
- if (stamped) store.inFile.clear();
72254
- const entries = [];
72255
- for (const entry of store.log) {
72256
- if (entry.seq <= base) continue;
72257
- if (own(entry)) store.inFile.add(entry.seq);
72258
- else if (stamped || !store.inFile.has(entry.seq)) entries.push(entry);
72259
- }
72260
- for (const entry of entries) {
72261
- for (const op of entry.ops) {
72262
- try {
72263
- checkOp(value, op);
72264
- value = applyOp(value, op);
72265
- } catch {
72266
- }
72267
- }
72268
- }
72269
- const text4 = serializeLive(value);
72270
- if (text4 !== serializeLive(store.value)) {
72271
- const bytes = byteLength(text4);
72272
- if (bytes > LIVE_LIMITS.storeBytes || roomBytes(room) - store.bytes + bytes > LIVE_LIMITS.roomBytes) {
73126
+ if (host) {
73127
+ const merged2 = mergePageFile(room, store, value);
73128
+ if (merged2 === "dropped") {
72273
73129
  room.stores.delete(tag.name);
72274
73130
  valueChanged = true;
72275
73131
  continue;
72276
73132
  }
72277
- const ops = diffOps(store.value, value);
72278
- store.value = value;
72279
- store.bytes = bytes;
72280
- room.seq += 1;
72281
- store.last = room.seq;
72282
- const provenance = by?.v === 2 ? { at: { epoch: tag.at.epoch, seq: tag.at.seq }, by: by.frames, capture: by.capture } : null;
72283
- const logged = byteLength(JSON.stringify(provenance ? { ops, provenance } : ops));
72284
- store.log.push({ seq: room.seq, ops, bytes: logged, merge: true, ...provenance && { provenance } });
72285
- store.inFile.add(room.seq);
72286
- store.logBytes += logged;
72287
- evict(store);
72288
- valueChanged = true;
73133
+ if (merged2) valueChanged = true;
73134
+ if (stamped && tag.at.epoch === room.epoch) {
73135
+ store.landed = tag.at.seq >= room.compaction.contentSeq ? store.last : tag.at.seq;
73136
+ if (store.landed !== before2) landed.push(tag.name);
73137
+ }
73138
+ } else {
73139
+ const ancestry = descendants(by);
73140
+ const own = (entry) => {
73141
+ if (!by) return false;
73142
+ if (!entry.merge) return contains2(frames, entry.from, entry.n);
73143
+ const p = entry.provenance;
73144
+ return by.v === 2 && p && p.at.epoch === tag.at.epoch && p.at.seq === tag.at.seq && contains2(ancestry, ...p.capture);
73145
+ };
73146
+ if (stamped) store.inFile.clear();
73147
+ const entries = [];
73148
+ for (const entry of store.log) {
73149
+ if (entry.seq <= base) continue;
73150
+ if (own(entry)) store.inFile.add(entry.seq);
73151
+ else if (stamped || !store.inFile.has(entry.seq)) entries.push(entry);
73152
+ }
73153
+ for (const entry of entries) {
73154
+ for (const op of entry.ops) {
73155
+ try {
73156
+ checkOp(value, op);
73157
+ value = applyOp(value, op);
73158
+ } catch {
73159
+ }
73160
+ }
73161
+ }
73162
+ const text4 = serializeLive(value);
73163
+ if (text4 !== serializeLive(store.value)) {
73164
+ const bytes = byteLength(text4);
73165
+ if (bytes > LIVE_LIMITS.storeBytes || roomBytes(room) - store.bytes + bytes > LIVE_LIMITS.roomBytes) {
73166
+ room.stores.delete(tag.name);
73167
+ valueChanged = true;
73168
+ continue;
73169
+ }
73170
+ const ops = diffOps(store.value, value);
73171
+ store.value = value;
73172
+ store.bytes = bytes;
73173
+ room.seq += 1;
73174
+ store.last = room.seq;
73175
+ const provenance = by?.v === 2 ? { at: { epoch: tag.at.epoch, seq: tag.at.seq }, by: by.frames, capture: by.capture } : null;
73176
+ const logged = byteLength(JSON.stringify(provenance ? { ops, provenance } : ops));
73177
+ store.log.push({ seq: room.seq, ops, bytes: logged, merge: true, ...provenance && { provenance } });
73178
+ store.inFile.add(room.seq);
73179
+ store.logBytes += logged;
73180
+ evict(store);
73181
+ valueChanged = true;
73182
+ }
73183
+ store.landed = entries.length ? base : store.last;
73184
+ if (store.landed !== before2) landed.push(tag.name);
72289
73185
  }
72290
- store.landed = entries.length ? base : store.last;
72291
- if (store.landed !== before2) landed.push(tag.name);
72292
73186
  if (by?.v === 2) {
72293
73187
  for (const [client, ranges] of frames) {
72294
73188
  if (!saveReceipt(room, tag.name + "\n" + client, ranges, store.last, LIVE_LIMITS.receipts, pageReservations.get(key)?.receipts)) {
@@ -72359,6 +73253,7 @@ function createRooms({ now = Date.now, newEpoch = import_node_crypto3.randomUUID
72359
73253
  reservation.result = null;
72360
73254
  return null;
72361
73255
  }
73256
+ if (room.compaction?.job) endJob(room.compaction.job);
72362
73257
  const before2 = heldBy(room);
72363
73258
  const { stores, transition } = reservation.target;
72364
73259
  for (const name of room.stores.keys()) if (PAGE4.test(name)) room.stores.delete(name);
@@ -72375,6 +73270,7 @@ function createRooms({ now = Date.now, newEpoch = import_node_crypto3.randomUUID
72375
73270
  bytes += store.bytes;
72376
73271
  }
72377
73272
  room.pageTransition = transition;
73273
+ if (hostLimits) room.compaction = hostMode(transition.format === "yjs");
72378
73274
  reservation.target = null;
72379
73275
  used += heldBy(room) - before2 - reservation.budget;
72380
73276
  reservation.budget = 0;
@@ -72454,7 +73350,7 @@ function createRooms({ now = Date.now, newEpoch = import_node_crypto3.randomUUID
72454
73350
  if (!store || store.ephemeral) throw new PersistentReservationError("invalid-target");
72455
73351
  }
72456
73352
  const currentHeld = heldBy(record5.room);
72457
- const projected = structuredClone(record5.room);
73353
+ const projected = projectRoom(record5.room);
72458
73354
  reconcileFile(projected, record5.key, html3, {});
72459
73355
  for (const [name, store] of record5.room.stores) {
72460
73356
  if (!store.ephemeral && !projected.stores.has(name)) throw new PersistentReservationError("budget");
@@ -72633,6 +73529,8 @@ function createRooms({ now = Date.now, newEpoch = import_node_crypto3.randomUUID
72633
73529
  }
72634
73530
  const nKey = frame.name + "\n" + clientId;
72635
73531
  const last2 = room.lastN.get(nKey);
73532
+ const admission = room.compaction && frame.name === "page" && !receiptHas(last2, frame.n) ? admit(room, store, frame, ops) : null;
73533
+ if (admission?.error) return admission;
72636
73534
  if (receiptHas(last2, frame.n)) return { duplicate: true, seq: frame.n <= last2.n ? last2.seq : last2.savedSeq, epoch: room.epoch };
72637
73535
  if ((room.retiredReceipts?.get(nKey) ?? 0) > (frame.receiptGeneration ?? 0)) return { error: "receipt-expired" };
72638
73536
  let victim = null;
@@ -72680,8 +73578,13 @@ function createRooms({ now = Date.now, newEpoch = import_node_crypto3.randomUUID
72680
73578
  }
72681
73579
  if (bytes > LIVE_LIMITS.storeBytes || roomBytes(room) - store.bytes + bytes > LIVE_LIMITS.roomBytes) {
72682
73580
  undo();
73581
+ if (admission) return admission.over(bytes);
72683
73582
  return { error: "too-large" };
72684
73583
  }
73584
+ if (admission && bytes > admission.limit) {
73585
+ undo();
73586
+ return admission.over(bytes);
73587
+ }
72685
73588
  const logged = done.length ? byteLength(JSON.stringify(ops)) : 0;
72686
73589
  const grows = done.length ? bytes - store.bytes + logAfter(store, logged) - store.logBytes : 0;
72687
73590
  const retiredBytes = victim === null ? 0 : receiptBytes(room.lastN.get(victim));
@@ -72705,18 +73608,36 @@ function createRooms({ now = Date.now, newEpoch = import_node_crypto3.randomUUID
72705
73608
  room.lastSentAt.set(clientId, now());
72706
73609
  room.seen.set(clientId, now());
72707
73610
  if (PAGE4.test(frame.name) && typeof frame.adopted === "string" && frame.adopted.length <= 64) room.adopted = frame.adopted;
73611
+ if (admission && done.length) admission.admitted(bytes);
72708
73612
  const writerGone = room.writer && connected && !connected.includes(room.writer);
72709
73613
  if ((!room.writer || writerGone) && (!connected || connected.includes(clientId))) room.writer = clientId;
72710
73614
  return { seq: room.seq, epoch: room.epoch, name: frame.name, ops, writer: room.writer, checkpoint: pressed(store), receiptGeneration: room.receiptGeneration ?? 0, ...transition && { pageGeneration: transition.id } };
72711
73615
  },
72712
73616
  /** Everything a joining tab needs, with clientId's own receipt per store. Values are the room's own objects: serialize, never mutate. With since in this room's epoch, moves carries each store's log entries after since.seq (null where the log no longer reaches back that far). */
72713
- state(room, clientId = null, since = void 0) {
73617
+ state(room, clientId = null, since = void 0, { compaction: capable } = {}) {
72714
73618
  const stores = {};
73619
+ const legacy = room.compaction?.legacy;
73620
+ if (legacy && clientId && capable !== void 0) {
73621
+ if (capable === hostLimits.version) legacy.delete(clientId);
73622
+ else legacy.add(clientId);
73623
+ }
73624
+ const hidden = Boolean(legacy && (capable !== void 0 ? capable !== hostLimits.version : clientId && legacy.has(clientId)));
72715
73625
  for (const [name, s] of room.stores) {
73626
+ if (hidden && name === "page") continue;
72716
73627
  const seen = {};
72717
73628
  const mine = clientId ? room.lastN.get(name + "\n" + clientId) : null;
72718
73629
  if (mine) seen[clientId] = mine.n;
72719
- stores[name] = { value: s.value, ephemeral: s.ephemeral, from: s.from, landed: s.landed, floor: s.floor, last: s.last, seen, ...mine?.saved?.length && { saved: mine.saved } };
73630
+ stores[name] = {
73631
+ value: s.value,
73632
+ ephemeral: s.ephemeral,
73633
+ from: s.from,
73634
+ landed: s.landed,
73635
+ floor: s.floor,
73636
+ last: s.last,
73637
+ seen,
73638
+ ...mine?.saved?.length && { saved: mine.saved },
73639
+ ...name === "page" && room.compaction && { compaction: { v: hostLimits.version, loose: hostLimits.loose, activeBytes: hostLimits.activeBytes } }
73640
+ };
72720
73641
  }
72721
73642
  const provenance = { provenanceVersion: 2, receiptGeneration: room.receiptGeneration ?? 0 };
72722
73643
  if (room.pageTransition) {
@@ -72754,7 +73675,10 @@ function createRooms({ now = Date.now, newEpoch = import_node_crypto3.randomUUID
72754
73675
  if (room.writer !== clientId) return { writerChanged: false, writer: room.writer };
72755
73676
  let best = null;
72756
73677
  let bestAt = -1;
72757
- for (const id of remaining.filter((candidate) => room.seen.has(candidate))) {
73678
+ const seen = remaining.filter((candidate) => room.seen.has(candidate));
73679
+ const legacy = room.compaction?.legacy;
73680
+ const capable = legacy ? seen.filter((candidate) => !legacy.has(candidate)) : seen;
73681
+ for (const id of capable.length ? capable : seen) {
72758
73682
  const at2 = room.lastSentAt.get(id) ?? 0;
72759
73683
  if (at2 > bestAt) {
72760
73684
  best = id;
@@ -72775,6 +73699,9 @@ function createRooms({ now = Date.now, newEpoch = import_node_crypto3.randomUUID
72775
73699
  */
72776
73700
  sweep(connectedOf = () => [], { mayExpire = () => true } = {}) {
72777
73701
  const t = now();
73702
+ for (const room of rooms.values()) {
73703
+ if (room.compaction?.job && t >= room.compaction.job.deadline) endJob(room.compaction.job);
73704
+ }
72778
73705
  for (const [key, room] of rooms) {
72779
73706
  if (!roomIsDirty(room) && mayExpire(room) && !pageReservations.has(key) && !persistentReservations.has(key) && room.emptySince !== null && t - room.emptySince >= LIVE_LIMITS.retainMs) {
72780
73707
  used -= heldBy(room);
@@ -72822,6 +73749,120 @@ function createRooms({ now = Date.now, newEpoch = import_node_crypto3.randomUUID
72822
73749
  }
72823
73750
  return changed;
72824
73751
  },
73752
+ onCompactionDue(listener) {
73753
+ onDue = typeof listener === "function" ? listener : () => {
73754
+ };
73755
+ },
73756
+ beginCompaction(room, { overflow = false } = {}) {
73757
+ const state = room?.compaction;
73758
+ if (!state || rooms.get(room.key) !== room || state.failed) return null;
73759
+ if (state.job) {
73760
+ if (now() < state.job.deadline) return null;
73761
+ endJob(state.job);
73762
+ }
73763
+ const store = room.stores.get("page");
73764
+ if (!store || pageReservations.has(room.key) || persistentReservations.has(room.key)) return null;
73765
+ const plan = planCompaction(store.value.y, { overflow }, hostLimits);
73766
+ if (!plan) return null;
73767
+ const reserved = plan.sources.reduce((sum, [k2, v3]) => sum + k2.length + v3.length, 0);
73768
+ if (used + reserved > liveBytes) return null;
73769
+ state.fence += 1;
73770
+ const token = Object.freeze({ key: room.key, epoch: room.epoch, fence: state.fence });
73771
+ const job = {
73772
+ token,
73773
+ room,
73774
+ store,
73775
+ epoch: room.epoch,
73776
+ generation: room.pageTransition?.id ?? null,
73777
+ kind: plan.kind,
73778
+ sources: new Map(plan.sources),
73779
+ physical: Object.keys(store.value.y),
73780
+ reserved,
73781
+ deadline: now() + hostLimits.leaseMs,
73782
+ deletesAtBegin: state.deletesSince
73783
+ };
73784
+ state.job = job;
73785
+ used += reserved;
73786
+ jobs.set(token, job);
73787
+ return { token, kind: plan.kind, sources: plan.sources };
73788
+ },
73789
+ abandonCompaction(token, { failed = null } = {}) {
73790
+ const job = jobs.get(token);
73791
+ if (!job) return false;
73792
+ jobs.delete(token);
73793
+ const ended = endJob(job);
73794
+ if (ended && failed) job.room.compaction.failed = { reason: failed, at: now() };
73795
+ return ended;
73796
+ },
73797
+ commitCompaction(token, result) {
73798
+ const job = jobs.get(token);
73799
+ if (!job) return { refused: "stale-token" };
73800
+ jobs.delete(token);
73801
+ const { room, store } = job;
73802
+ if (!endJob(job)) return { refused: "stale-token" };
73803
+ if (rooms.get(room.key) !== room || room.epoch !== job.epoch || room.stores.get("page") !== store || (room.pageTransition?.id ?? null) !== job.generation) return { refused: "stale-token" };
73804
+ const y2 = store.value.y;
73805
+ const retire = job.physical.filter((k2) => {
73806
+ const part = PART_KEY.exec(k2);
73807
+ return job.sources.has(part ? part[1] : k2) || part && job.kind === "full";
73808
+ });
73809
+ if (retire.some((k2) => !Object.hasOwn(y2, k2))) return { refused: "sources-changed" };
73810
+ const held = new Map(entriesOf2(Object.fromEntries(retire.map((k2) => [k2, y2[k2]]))));
73811
+ for (const [k2, v3] of job.sources) if (held.get(k2) !== v3) return { refused: "sources-changed" };
73812
+ if (typeof result?.update !== "string" || !checkUpdate(result.update)) return { refused: "bad-candidate" };
73813
+ const key = `${job.kind === "full" ? "c" : "t"}${textHash(room.epoch).slice(0, 8)}-${(room.seq + 1).toString(36)}`;
73814
+ if (Object.hasOwn(y2, key)) return { refused: "bad-candidate" };
73815
+ const ops = [...retire.map((k2) => ({ op: "del", path: ["y", k2] })), { op: "set", path: ["y", key], value: result.update }].map(validateOp);
73816
+ let value = store.value;
73817
+ let bytes = store.bytes;
73818
+ const done = [];
73819
+ for (const op of ops) {
73820
+ const rec = applyTracked(value, op);
73821
+ if (!rec) continue;
73822
+ done.push(rec);
73823
+ bytes += sizeChange(rec, sizeOf, bytes);
73824
+ value = rec.root;
73825
+ }
73826
+ if (bytes > hostLimits.activeBytes && bytes > store.bytes) {
73827
+ for (let i = done.length - 1; i >= 0; i--) undoTracked(done[i]);
73828
+ if (job.kind === "full" && retire.length === Object.keys(y2).length) {
73829
+ room.compaction.lastFull = { bytes: store.bytes, seq: room.seq, deletesAtBegin: job.deletesAtBegin };
73830
+ room.compaction.deletesSince -= job.deletesAtBegin;
73831
+ }
73832
+ return { refused: "too-large" };
73833
+ }
73834
+ const clean = store.landed === store.last;
73835
+ const logged = byteLength(JSON.stringify(ops));
73836
+ used += bytes - store.bytes + logAfter(store, logged) - store.logBytes;
73837
+ store.value = value;
73838
+ store.bytes = bytes;
73839
+ room.seq += 1;
73840
+ store.last = room.seq;
73841
+ if (clean) store.landed = store.last;
73842
+ store.log.push({ seq: room.seq, ops, bytes: logged, from: COMPACTOR, n: 0 });
73843
+ store.logBytes += logged;
73844
+ evict(store);
73845
+ const state = room.compaction;
73846
+ for (const k2 of job.sources.keys()) {
73847
+ state.retired.add(k2);
73848
+ if (state.retired.size > hostLimits.retired) state.retired.delete(state.retired.values().next().value);
73849
+ }
73850
+ if (job.kind === "full") {
73851
+ state.lastFull = { bytes, seq: room.seq, deletesAtBegin: job.deletesAtBegin };
73852
+ state.deletesSince -= job.deletesAtBegin;
73853
+ }
73854
+ if (pageShape(store.value.y, hostLimits).loose >= hostLimits.soft || !pageShape(store.value.y, hostLimits).normal) due(room);
73855
+ return {
73856
+ seq: room.seq,
73857
+ epoch: room.epoch,
73858
+ name: "page",
73859
+ ops,
73860
+ from: COMPACTOR,
73861
+ kind: job.kind,
73862
+ landed: store.landed,
73863
+ ...room.pageTransition && { pageGeneration: room.pageTransition.id }
73864
+ };
73865
+ },
72825
73866
  /** Every room's key. */
72826
73867
  keys() {
72827
73868
  return [...rooms.keys()];
@@ -72836,6 +73877,117 @@ function createRooms({ now = Date.now, newEpoch = import_node_crypto3.randomUUID
72836
73877
  };
72837
73878
  }
72838
73879
 
73880
+ // src/server/rooms/page-compactor.js
73881
+ var import_node_worker_threads = require("node:worker_threads");
73882
+ var import_node_url = require("node:url");
73883
+ var import_meta = {};
73884
+ var RETRY_MS = [1e3, 5e3, 3e4];
73885
+ var MODULE_URL = typeof __dirname === "string" ? (0, import_node_url.pathToFileURL)(`${__dirname}/`).href : import_meta.url;
73886
+ var WORKER_FILE = true ? "./page-compaction-worker.cjs" : "./page-compaction-worker.js";
73887
+ var pageCompactionWorkerUrl = () => new URL(WORKER_FILE, MODULE_URL);
73888
+ function createPageCompactor({
73889
+ rooms,
73890
+ onCommit = () => {
73891
+ },
73892
+ workerUrl = pageCompactionWorkerUrl(),
73893
+ timeoutMs = 3e4,
73894
+ WorkerClass = import_node_worker_threads.Worker,
73895
+ setTimer = setTimeout,
73896
+ clearTimer = clearTimeout
73897
+ } = {}) {
73898
+ const queue = /* @__PURE__ */ new Map();
73899
+ const retries = /* @__PURE__ */ new Map();
73900
+ let worker = null;
73901
+ let running = null;
73902
+ let ids = 0;
73903
+ let closed = false;
73904
+ const spawn = () => {
73905
+ const instance = new WorkerClass(workerUrl);
73906
+ worker = instance;
73907
+ instance.unref?.();
73908
+ instance.on("message", (message) => {
73909
+ if (worker === instance) finish(message);
73910
+ });
73911
+ instance.on("error", () => {
73912
+ if (worker === instance) crashed();
73913
+ });
73914
+ instance.on("exit", () => {
73915
+ if (worker !== instance) return;
73916
+ worker = null;
73917
+ if (running) crashed();
73918
+ });
73919
+ };
73920
+ function crashed() {
73921
+ const job = running;
73922
+ if (!job) return;
73923
+ running = null;
73924
+ clearTimer(job.timer);
73925
+ worker?.terminate?.();
73926
+ worker = null;
73927
+ const tries = (retries.get(job.room) ?? 0) + 1;
73928
+ retries.set(job.room, tries);
73929
+ rooms.abandonCompaction(job.token, tries > RETRY_MS.length ? { failed: "crashed" } : {});
73930
+ if (tries <= RETRY_MS.length) setTimer(() => due(job.room, { overflow: job.overflow }), RETRY_MS[tries - 1]);
73931
+ pump();
73932
+ }
73933
+ function finish({ id, ...result }) {
73934
+ const job = running;
73935
+ if (!job || job.id !== id) return;
73936
+ running = null;
73937
+ clearTimer(job.timer);
73938
+ if (result.failure) {
73939
+ rooms.abandonCompaction(job.token, { failed: result.failure });
73940
+ } else {
73941
+ const answer = rooms.commitCompaction(job.token, result);
73942
+ if (answer.seq !== void 0) {
73943
+ retries.delete(job.room);
73944
+ try {
73945
+ onCommit(job.room, answer);
73946
+ } catch {
73947
+ }
73948
+ }
73949
+ }
73950
+ pump();
73951
+ }
73952
+ function pump() {
73953
+ if (closed || running || !queue.size) return;
73954
+ const [room, { overflow }] = queue.entries().next().value;
73955
+ queue.delete(room);
73956
+ const begun = rooms.beginCompaction(room, { overflow });
73957
+ if (!begun) {
73958
+ pump();
73959
+ return;
73960
+ }
73961
+ if (!worker) spawn();
73962
+ const id = ++ids;
73963
+ running = { id, room, overflow, token: begun.token, timer: setTimer(crashed, timeoutMs) };
73964
+ worker.postMessage({ id, kind: begun.kind, sources: begun.sources });
73965
+ }
73966
+ function due(room, { overflow = false } = {}) {
73967
+ const queued = queue.get(room);
73968
+ queue.set(room, { overflow: overflow || Boolean(queued?.overflow) });
73969
+ queueMicrotask(pump);
73970
+ }
73971
+ rooms.onCompactionDue(due);
73972
+ return {
73973
+ get running() {
73974
+ return running !== null;
73975
+ },
73976
+ close() {
73977
+ closed = true;
73978
+ rooms.onCompactionDue(null);
73979
+ if (running) {
73980
+ clearTimer(running.timer);
73981
+ rooms.abandonCompaction(running.token);
73982
+ running = null;
73983
+ }
73984
+ const current = worker;
73985
+ worker = null;
73986
+ return current?.terminate?.();
73987
+ }
73988
+ };
73989
+ }
73990
+
72839
73991
  // src/server/checkpoint/index.js
72840
73992
  var checkpoint_exports = {};
72841
73993
  __export(checkpoint_exports, {
@@ -72968,8 +74120,8 @@ function titleTextOf(node) {
72968
74120
  function titleAt(placement) {
72969
74121
  const head = placement.head?.sourceCodeLocation;
72970
74122
  if (head?.startTag) return head.startTag.endOffset;
72971
- const inside = (placement.head?.childNodes ?? []).find((node) => node.sourceCodeLocation);
72972
- if (inside) return inside.sourceCodeLocation.startOffset;
74123
+ const inside2 = (placement.head?.childNodes ?? []).find((node) => node.sourceCodeLocation);
74124
+ if (inside2) return inside2.sourceCodeLocation.startOffset;
72973
74125
  const body = placement.body?.sourceCodeLocation;
72974
74126
  if (body?.startTag) return body.startTag.startOffset;
72975
74127
  const first2 = (placement.body?.childNodes ?? []).find((node) => node.sourceCodeLocation);
@@ -72986,8 +74138,8 @@ function titleEdit(placement, title) {
72986
74138
  }
72987
74139
  function holdsEdit(found, blocks, doc) {
72988
74140
  const current = readBack(blocks, doc);
72989
- const merged = mergePageModels(found.baseItems, current, found.parsed, { doc, merge3: merge32, mergeJson });
72990
- return canon(merged.items) === canon(current);
74141
+ const merged2 = mergePageModels(found.baseItems, current, found.parsed, { doc, merge3: merge32, mergeJson });
74142
+ return canon(merged2.items) === canon(current);
72991
74143
  }
72992
74144
  var lastAdoption = { html: null, answer: false };
72993
74145
  function needsAdoption(html3, { createDocument }) {