@panphora/clayjs 1.16.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 (511) 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 +72519 -59839
  11. package/dist/m/attrs/refetch-on-save-ZUE7PSCI.js +1 -0
  12. package/dist/m/attrs/save-freeze-LWGF6XUN.js +1 -0
  13. package/dist/m/c-2GRUM77Q.js +30 -0
  14. package/dist/m/c-2KIEGNC4.js +1 -0
  15. package/dist/m/{c-5R4PTRG2.js → c-2KL3BD52.js} +1 -1
  16. package/dist/m/c-2YYDMLNZ.js +1 -0
  17. package/dist/m/c-2ZZBC45O.js +1 -0
  18. package/dist/m/c-372N6H3B.js +1 -0
  19. package/dist/m/{c-4WKFKEKF.js → c-3G2DGZUP.js} +1 -1
  20. package/dist/m/c-3LDGIBMN.js +1 -0
  21. package/dist/m/c-3O7OBDCM.js +1 -0
  22. package/dist/m/c-4ASQPRQL.js +1 -0
  23. package/dist/m/c-4TXNLX4K.js +6 -0
  24. package/dist/m/c-4YU3BR4D.js +6 -0
  25. package/dist/m/c-5734MF2P.js +1 -0
  26. package/dist/m/c-57XDY6HC.js +1 -0
  27. package/dist/m/{c-VFX45IZQ.js → c-5B4YBZXC.js} +1 -1
  28. package/dist/m/c-5ONTYIUI.js +1 -0
  29. package/dist/m/c-5OOVFCJM.js +1 -0
  30. package/dist/m/c-5T6NZHNM.js +1 -0
  31. package/dist/m/{c-YDH7Q3NY.js → c-5ZQV7KC4.js} +1 -1
  32. package/dist/m/{c-Z36J63PP.js → c-6DB2OLRJ.js} +1 -1
  33. package/dist/m/c-6DNRCPNM.js +1 -0
  34. package/dist/m/c-6UGWFMQC.js +2 -0
  35. package/dist/m/c-7K4SCQB7.js +1 -0
  36. package/dist/m/c-7MG5RU63.js +1 -0
  37. package/dist/m/c-7PRJCA3E.js +1 -0
  38. package/dist/m/c-A6L3FMUS.js +1 -0
  39. package/dist/m/c-AMU3BPPR.js +4 -0
  40. package/dist/m/c-AMYEFA2E.js +1 -0
  41. package/dist/m/c-AQYCG7QW.js +1 -0
  42. package/dist/m/c-ATKAOH23.js +1 -0
  43. package/dist/m/c-B3JM5ZXC.js +1 -0
  44. package/dist/m/c-B5CS55WR.js +1 -0
  45. package/dist/m/c-B5UJQT7W.js +1 -0
  46. package/dist/m/c-B7J4K2AE.js +3 -0
  47. package/dist/m/c-BHZYSHW4.js +1 -0
  48. package/dist/m/c-BIJALSRD.js +1 -0
  49. package/dist/m/c-BJ7YQ5QZ.js +1 -0
  50. package/dist/m/c-BPF2NSPV.js +1 -0
  51. package/dist/m/{c-KIPQJX4B.js → c-BRLCTNMC.js} +1 -1
  52. package/dist/m/c-BUAYFEV5.js +1 -0
  53. package/dist/m/c-C6IPRG34.js +1 -0
  54. package/dist/m/{c-2JL6E75N.js → c-CAS3NND4.js} +1 -1
  55. package/dist/m/{c-4DRMS4QG.js → c-CCQ25GFY.js} +1 -1
  56. package/dist/m/c-CJFDLD43.js +1 -0
  57. package/dist/m/c-COPTL5WB.js +1 -0
  58. package/dist/m/c-D3E4WJ4M.js +166 -0
  59. package/dist/m/c-D5IKEKXW.js +7 -0
  60. package/dist/m/c-DHBRA6DL.js +1 -0
  61. package/dist/m/c-DKLS74XB.js +72 -0
  62. package/dist/m/c-DVYGFTSK.js +3 -0
  63. package/dist/m/c-E3ZXARWA.js +1 -0
  64. package/dist/m/c-EK63G3CG.js +1 -0
  65. package/dist/m/c-ERQSNR6K.js +13 -0
  66. package/dist/m/c-EVYAISP3.js +1 -0
  67. package/dist/m/c-EXKHPOVC.js +3 -0
  68. package/dist/m/{c-7VGZ7RU5.js → c-FWKHM4E7.js} +1 -1
  69. package/dist/m/{c-4Q2XTQ2N.js → c-GBKB5WDL.js} +1 -1
  70. package/dist/m/c-GNDL3TKB.js +1 -0
  71. package/dist/m/c-GRWMD6O5.js +1 -0
  72. package/dist/m/c-GRXHHFPO.js +1 -0
  73. package/dist/m/{c-OYTFP5QN.js → c-GY422N3Q.js} +1 -1
  74. package/dist/m/c-HAWFNBYG.js +1 -0
  75. package/dist/m/c-HG2C77BM.js +4 -0
  76. package/dist/m/c-HHGJBU4D.js +1 -0
  77. package/dist/m/c-HMV6P4RX.js +1 -0
  78. package/dist/m/c-HMYWIHFG.js +1 -0
  79. package/dist/m/c-HT2DKBV2.js +1 -0
  80. package/dist/m/c-I2SCCUEW.js +1 -0
  81. package/dist/m/{c-HRDCD3WN.js → c-ICJYHABF.js} +2 -2
  82. package/dist/m/c-IMZCWYHR.js +7 -0
  83. package/dist/m/c-IVMD3FEM.js +1 -0
  84. package/dist/m/c-IVTRVENZ.js +1 -0
  85. package/dist/m/c-IW6GGOU2.js +1 -0
  86. package/dist/m/c-JKZJIUIP.js +1 -0
  87. package/dist/m/{c-NZMNXVF6.js → c-JNLX3RJB.js} +1 -1
  88. package/dist/m/c-JRKY44DK.js +1 -0
  89. package/dist/m/c-K3ADYNLU.js +1 -0
  90. package/dist/m/c-KBS3UV6B.js +1 -0
  91. package/dist/m/c-KGHVFRR3.js +1 -0
  92. package/dist/m/c-KJJPV77R.js +1 -0
  93. package/dist/m/{c-CZUSOB7V.js → c-KNPDOMDY.js} +1 -1
  94. package/dist/m/{c-5Y6TNX5W.js → c-KP64LT2A.js} +2 -2
  95. package/dist/m/c-KQ7E3PYY.js +1 -0
  96. package/dist/m/c-L3F5ZLIV.js +1 -0
  97. package/dist/m/{c-LR4CGEPT.js → c-L42OLXWM.js} +3 -2
  98. package/dist/m/c-L5VFATT6.js +1 -0
  99. package/dist/m/c-L7JL5TL3.js +3 -0
  100. package/dist/m/c-LKSL4AUJ.js +1 -0
  101. package/dist/m/c-M6FNQCTQ.js +1 -0
  102. package/dist/m/c-MCOOHCSG.js +1 -0
  103. package/dist/m/c-MHI3GYKF.js +1 -0
  104. package/dist/m/c-MWXFLW4J.js +1 -0
  105. package/dist/m/c-NEL7HQW3.js +1 -0
  106. package/dist/m/c-NQJRVJ56.js +1 -0
  107. package/dist/m/c-NWX3MFT4.js +1 -0
  108. package/dist/m/{c-HPURYVZS.js → c-OJYM642Q.js} +1 -1
  109. package/dist/m/c-OKXI52N7.js +1 -0
  110. package/dist/m/{c-MMUIUUZG.js → c-OPLUZR3A.js} +1 -1
  111. package/dist/m/{c-J7CA54IP.js → c-OTMKN2OO.js} +1 -1
  112. package/dist/m/{c-LTGMXXKO.js → c-OYRZ7XG2.js} +1 -1
  113. package/dist/m/c-P3OFYUMA.js +1 -0
  114. package/dist/m/c-PLN76GF3.js +6 -0
  115. package/dist/m/c-PLP4JKFC.js +1 -0
  116. package/dist/m/c-Q26MME6N.js +1 -0
  117. package/dist/m/{c-S7H2DRCB.js → c-Q3XOWZEV.js} +1 -1
  118. package/dist/m/{c-SWRJFCNN.js → c-QIKT6SKM.js} +1 -1
  119. package/dist/m/c-QIXT3Q7C.js +28 -0
  120. package/dist/m/c-QO4HNGCQ.js +1 -0
  121. package/dist/m/c-R27DWQKX.js +1 -0
  122. package/dist/m/{c-HVYXIS72.js → c-R2XUODVY.js} +1 -1
  123. package/dist/m/{c-QNKREOL6.js → c-R7LBFMF5.js} +1 -1
  124. package/dist/m/c-RND3G2S2.js +1 -0
  125. package/dist/m/c-S2U6NJU4.js +1 -0
  126. package/dist/m/c-SPZPGD3R.js +1 -0
  127. package/dist/m/c-SW4YEG2D.js +8 -0
  128. package/dist/m/c-SZGYW5HT.js +1 -0
  129. package/dist/m/c-T637T7SN.js +1 -0
  130. package/dist/m/c-TJAXGIRV.js +1 -0
  131. package/dist/m/{c-KKWLDOPM.js → c-TNEM3RNM.js} +1 -1
  132. package/dist/m/c-TTB5EK4S.js +32 -0
  133. package/dist/m/c-U7SHNWDH.js +1 -0
  134. package/dist/m/c-UDHIVLYH.js +20 -0
  135. package/dist/m/{c-BBVGTQG7.js → c-UGNV5MFB.js} +1 -1
  136. package/dist/m/{c-TQZ2JYHD.js → c-UORXLSD3.js} +1 -1
  137. package/dist/m/c-UPD33ZPE.js +1 -0
  138. package/dist/m/c-URSMSFCB.js +1 -0
  139. package/dist/m/c-UY4QX42B.js +1 -0
  140. package/dist/m/c-V44KWI2L.js +4 -0
  141. package/dist/m/c-VG5XIN4T.js +1 -0
  142. package/dist/m/c-VILENZTD.js +1 -0
  143. package/dist/m/{c-33HUYEDI.js → c-VJYEVRYK.js} +1 -1
  144. package/dist/m/c-VR2BJ4AN.js +1 -0
  145. package/dist/m/c-W4JCVLAB.js +1 -0
  146. package/dist/m/c-W6DQSHXI.js +135 -0
  147. package/dist/m/c-WBGWGOM7.js +1 -0
  148. package/dist/m/{c-4L3BTFRK.js → c-WCXLG3MV.js} +1 -1
  149. package/dist/m/c-WGW764WX.js +1 -0
  150. package/dist/m/c-WMRJKQ2V.js +5 -0
  151. package/dist/m/c-WNTYKCDG.js +1 -0
  152. package/dist/m/c-WQWIRWO3.js +72 -0
  153. package/dist/m/c-X5LNHET5.js +1 -0
  154. package/dist/m/c-X5TSXZYJ.js +2 -0
  155. package/dist/m/c-XGH4GS2T.js +1 -0
  156. package/dist/m/c-Y6F2FORL.js +1 -0
  157. package/dist/m/c-YBKHUAK7.js +10 -0
  158. package/dist/m/c-YBSS55KU.js +20 -0
  159. package/dist/m/c-YCLU4UNT.js +2 -0
  160. package/dist/m/c-YVZ2L7CE.js +1 -0
  161. package/dist/m/c-ZK4GIZH2.js +1 -0
  162. package/dist/m/c-ZRXJD4G6.js +1 -0
  163. package/dist/m/c-ZWBI4HYK.js +1 -0
  164. package/dist/m/{c-HT33EQRN.js → c-ZWIOJGMT.js} +1 -1
  165. package/dist/m/core/admin-attrs-YY7T5FGU.js +1 -0
  166. package/dist/m/core/autosave-S6OMNDCK.js +1 -0
  167. package/dist/m/core/conflict-notice-IWHMHH43.js +1 -0
  168. package/dist/m/core/host-permission-6EVJGNPL.js +1 -0
  169. package/dist/m/core/is-edit-mode-GCX6767E.js +1 -0
  170. package/dist/m/core/{persist-HKHA66IY.js → persist-UKXV5KLA.js} +1 -1
  171. package/dist/m/core/recovery-DRFZRJED.js +1 -0
  172. package/dist/m/core/save-LYY7K6U7.js +1 -0
  173. package/dist/m/core/save-core-MKRPSEEO.js +1 -0
  174. package/dist/m/core/snapshot-NU3YM6GR.js +1 -0
  175. package/dist/m/core/unsaved-warning-7QTKEN7Z.js +1 -0
  176. package/dist/m/events/index-RN2JNGBV.js +1 -0
  177. package/dist/m/internals/index-TGLQINN3.js +1 -0
  178. package/dist/m/lib/cache-bust-MUMFXZK6.js +1 -0
  179. package/dist/m/loader-3BBNZZGM.js +1 -0
  180. package/dist/m/manifest-F449FF98.js +1 -0
  181. package/dist/m/manifest-edit-4396A009.js +1 -0
  182. package/dist/m/manifest.json +2509 -1474
  183. package/dist/m/options/options-EJMS3K24.js +1 -0
  184. package/dist/m/page/editor-6LRB3GE4.js +304 -0
  185. package/dist/m/plugins/ai-edit-UTV7YO2I.js +6 -0
  186. package/dist/m/plugins/{cms-HP3LSTPN.js → cms-LRAOZHT7.js} +9 -9
  187. package/dist/m/plugins/demo-OYO5GCAO.js +1 -0
  188. package/dist/m/plugins/{derive-UAAA4V4S.js → derive-FRE5JJQE.js} +1 -1
  189. package/dist/m/plugins/indicator-4VDXWYTD.js +1 -0
  190. package/dist/m/plugins/live-AD4H6XSL.js +1 -0
  191. package/dist/m/plugins/menu-M5WW7DBF.js +1 -0
  192. package/dist/m/plugins/page-MD3T2ZX3.js +2 -0
  193. package/dist/m/plugins/page-view-PAWVZNFY.js +1 -0
  194. package/dist/m/plugins/people-JCHVPF7P.js +1 -0
  195. package/dist/m/plugins/quickcrop-BQ5YYFCH.js +26 -0
  196. package/dist/m/plugins/{richclay-RC3L2F6X.js → richclay-KLGETK77.js} +2 -2
  197. package/dist/m/plugins/sortable-4S6SQC3D.js +1 -0
  198. package/dist/m/plugins/source-TJXOIOYY.js +1 -0
  199. package/dist/m/plugins/undo-NLPGCJQY.js +1 -0
  200. package/dist/m/plugins/{unsent-HJFLQJ2O.js → unsent-OA4RGBUT.js} +1 -1
  201. package/dist/m/plugins/upgrade-HSUNDNJD.js +1 -0
  202. package/dist/m/plugins/upload-NHGJXZK2.js +1 -0
  203. package/dist/m/plugins/visitor-drafts-BW43DGY3.js +20 -0
  204. package/dist/m/plugins/visitor-drafts-owner-7ODQG7JX.js +1 -0
  205. package/dist/m/plugins/wire-VBWXEXU2.js +1 -0
  206. package/dist/m/reader-core-4W2KYEWQ.js +77 -0
  207. package/dist/m/route/route-62CHXL5B.js +1 -0
  208. package/dist/m/sync/live-sync-MO5DH33W.js +1 -0
  209. package/dist/m/ui/index-IVWN2QC4.js +1 -0
  210. package/dist/m/vendor/sap-core.vendor-RN4ZVY4X.js +6 -0
  211. package/dist/offline-manifest.json +1560 -889
  212. package/dist/page/themes/light-1.css +33 -8
  213. package/dist/server/core.cjs +1554 -311
  214. package/dist/server/offline-runtime.cjs +63 -63
  215. package/dist/server/offline-runtime.mjs +63 -63
  216. package/dist/server/page-compaction-worker.cjs +3710 -0
  217. package/dist/server/rooms.mjs +5 -0
  218. package/docs/guide.md +653 -101
  219. package/entries/sap.js +5 -5
  220. package/package.json +1 -1
  221. package/src/core/admin-contenteditable.js +5 -2
  222. package/src/core/admin-inputs.js +1 -0
  223. package/src/core/admin-onclick.js +2 -1
  224. package/src/core/boot-phase.js +2 -1
  225. package/src/core/conflict-download.js +3 -29
  226. package/src/core/conflict-notice-ui.js +4 -7
  227. package/src/core/download.js +32 -0
  228. package/src/core/host-meta.js +56 -0
  229. package/src/core/is-edit-mode.js +17 -1
  230. package/src/core/mode-key.js +125 -19
  231. package/src/core/mode-support.js +5 -0
  232. package/src/core/mode-transition.js +20 -6
  233. package/src/core/preserve-authored.js +4 -4
  234. package/src/core/recovery.js +121 -33
  235. package/src/core/save-accepted.js +33 -0
  236. package/src/core/save-core.js +111 -32
  237. package/src/core/save-job.js +108 -0
  238. package/src/core/save-prepare.js +53 -0
  239. package/src/core/save-size-notice.js +3 -1
  240. package/src/core/save-slices.js +15 -0
  241. package/src/core/save.js +557 -127
  242. package/src/core/serialize-steps.js +109 -0
  243. package/src/core/snapshot.js +209 -40
  244. package/src/core/source-map.js +83 -38
  245. package/src/core/stale-host-notice.js +1 -0
  246. package/src/core/upgrade-run.js +59 -8
  247. package/src/dom/active-element.js +5 -0
  248. package/src/lib/assets.js +1 -0
  249. package/src/lib/autosave-scheduler.js +3 -4
  250. package/src/lib/slice.js +65 -0
  251. package/src/lib/uimotion.js +774 -0
  252. package/src/lib/unsaved-state.js +2 -2
  253. package/src/live/fast-lane.js +10 -3
  254. package/src/live/local-lane.js +202 -11
  255. package/src/live/ops.js +16 -0
  256. package/src/live/page-compaction.js +162 -0
  257. package/src/live/server-lane.js +1 -0
  258. package/src/live/store.js +11 -3
  259. package/src/loader-logic.js +3 -1
  260. package/src/loader.js +14 -4
  261. package/src/page/adopt-boot.js +2 -1
  262. package/src/page/awareness.js +33 -2
  263. package/src/page/blocks.js +122 -27
  264. package/src/page/board-views.js +2 -16
  265. package/src/page/boot-pack.js +1 -1
  266. package/src/page/chart-tables.js +29 -0
  267. package/src/page/chart.js +411 -72
  268. package/src/page/checklist.js +10 -135
  269. package/src/page/checkpoint-proof.js +295 -0
  270. package/src/page/chrome.js +257 -40
  271. package/src/page/clipboard-shape.js +126 -0
  272. package/src/page/document-title-dom.js +12 -0
  273. package/src/page/document-title-runtime.js +15 -1
  274. package/src/page/document-title.js +4 -1
  275. package/src/page/drag.js +33 -3
  276. package/src/page/editor.js +207 -31
  277. package/src/page/emoji-data.js +162 -0
  278. package/src/page/export-assets.js +357 -0
  279. package/src/page/export-html.js +209 -0
  280. package/src/page/export-markdown.js +361 -0
  281. package/src/page/features/board.js +12 -3
  282. package/src/page/features/chart.js +11 -0
  283. package/src/page/features/checklist.js +428 -0
  284. package/src/page/features/dates.js +180 -0
  285. package/src/page/features/emoji.js +187 -0
  286. package/src/page/features/export-html.js +189 -0
  287. package/src/page/features/export-markdown.js +169 -0
  288. package/src/page/features/import-markdown.js +349 -0
  289. package/src/page/features/media.js +61 -5
  290. package/src/page/features/mentions.js +188 -0
  291. package/src/page/features/registry.js +24 -1
  292. package/src/page/features/table.js +375 -85
  293. package/src/page/features/title-cover.js +331 -0
  294. package/src/page/features/title-icon.js +213 -0
  295. package/src/page/features/toc.js +87 -0
  296. package/src/page/format-command.js +33 -0
  297. package/src/page/format-gate.js +68 -18
  298. package/src/page/format-host.js +71 -0
  299. package/src/page/format-native-commands.js +158 -0
  300. package/src/page/format-native.js +42 -0
  301. package/src/page/image-actions.js +64 -0
  302. package/src/page/import-markdown.js +262 -0
  303. package/src/page/inline.js +32 -8
  304. package/src/page/items.js +141 -11
  305. package/src/page/markdown.js +30 -2
  306. package/src/page/media.js +35 -119
  307. package/src/page/mention-picker.js +99 -0
  308. package/src/page/merge.js +1 -1
  309. package/src/page/placeholder.js +14 -1
  310. package/src/page/projection.js +156 -25
  311. package/src/page/recover.js +10 -12
  312. package/src/page/recovery-ui.js +464 -0
  313. package/src/page/rich/chart.js +63 -7
  314. package/src/page/save-projection.js +67 -0
  315. package/src/page/save-states.js +14 -4
  316. package/src/page/schema.js +52 -3
  317. package/src/page/table-paste.js +3 -1
  318. package/src/page/table-style.js +4 -4
  319. package/src/page/table.js +44 -2
  320. package/src/page/themes/content.css +25 -1
  321. package/src/page/themes/light-1.css +33 -8
  322. package/src/page/themes/light-1.source.css +8 -7
  323. package/src/page/toc-link.js +31 -0
  324. package/src/page/toc.js +5 -0
  325. package/src/page/view-hooks.js +58 -0
  326. package/src/page/view.js +13 -0
  327. package/src/page/ybind/binding.js +116 -6
  328. package/src/page/ybind/bridge.js +187 -20
  329. package/src/page/ybind/containment.js +162 -0
  330. package/src/page/ybind/doc.js +17 -9
  331. package/src/page/ybind/file-debt.js +63 -0
  332. package/src/page/ybind/layout.js +7 -2
  333. package/src/page/ybind/marks.js +2 -1
  334. package/src/page/ybind/moves.js +5 -4
  335. package/src/page/ybind/origins.js +106 -4
  336. package/src/page/ybind/parts.js +8 -1
  337. package/src/page/ybind/provider.js +125 -18
  338. package/src/page/ybind/recovery-proof.js +32 -9
  339. package/src/page/ybind/recovery-replay.js +905 -4
  340. package/src/page/ybind/recovery.js +174 -45
  341. package/src/page/ybind/table.js +67 -11
  342. package/src/page/ybind/walk-delta.js +258 -0
  343. package/src/page/ybind/walk.js +54 -29
  344. package/src/page/ybind/writer.js +1 -1
  345. package/src/plugins/ai-edit.js +13 -9
  346. package/src/plugins/indicator-chip.js +91 -0
  347. package/src/plugins/indicator.js +13 -80
  348. package/src/plugins/live.js +126 -15
  349. package/src/plugins/menu/actions.js +196 -0
  350. package/src/plugins/menu/people.js +279 -0
  351. package/src/plugins/menu/placement.js +121 -0
  352. package/src/plugins/menu/preferences.js +9 -0
  353. package/src/plugins/menu/seo.js +316 -397
  354. package/src/plugins/menu/style.js +171 -0
  355. package/src/plugins/menu/variants.js +296 -0
  356. package/src/plugins/menu.js +186 -183
  357. package/src/plugins/page-view.js +3 -2
  358. package/src/plugins/page.js +362 -43
  359. package/src/plugins/sortable.js +8 -1
  360. package/src/plugins/source.js +6 -0
  361. package/src/plugins/upgrade.js +51 -17
  362. package/src/plugins/upload-ui.js +12 -17
  363. package/src/plugins/visitor-drafts/bottom-ui.js +12 -4
  364. package/src/plugins/visitor-drafts/intro-style.js +7 -2
  365. package/src/plugins/visitor-drafts/intro.js +7 -4
  366. package/src/plugins/visitor-drafts/owner-chip.js +8 -12
  367. package/src/plugins/visitor-drafts/prompt.js +11 -9
  368. package/src/plugins/visitor-drafts/source.js +4 -3
  369. package/src/plugins/visitor-drafts/store.js +138 -9
  370. package/src/plugins/visitor-drafts/ui-memory.js +2 -2
  371. package/src/plugins/visitor-drafts-owner.js +4 -6
  372. package/src/plugins/visitor-drafts.js +5 -3
  373. package/src/recovery/store.js +1 -1
  374. package/src/route/route.js +4 -0
  375. package/src/server/checkpoint/index.js +2 -2
  376. package/src/server/rooms/index.js +5 -1
  377. package/src/server/rooms/live-data-rooms.js +302 -50
  378. package/src/server/rooms/page-compaction-worker.js +12 -0
  379. package/src/server/rooms/page-compactor.js +92 -0
  380. package/src/server/rooms/page-room-conformance.js +461 -0
  381. package/src/source/parse-steps.js +94 -0
  382. package/src/source/session.js +233 -57
  383. package/src/sync/editing-sender.js +12 -0
  384. package/src/sync/live-sync-edit.js +22 -2
  385. package/src/sync/live-sync.js +150 -23
  386. package/src/sync/page-relay.js +52 -0
  387. package/src/sync/presence-store.js +44 -4
  388. package/src/sync/presence.js +6 -3
  389. package/src/sync/saved-stream.js +28 -14
  390. package/src/ui/bevel-controls.js +1 -0
  391. package/src/ui/bevel-dialog.js +5 -2
  392. package/src/ui/editor-ui.js +77 -0
  393. package/src/ui/page-colour.js +281 -0
  394. package/src/ui/toast.js +16 -7
  395. package/src/vendor/hyper-html-api-upgrade.vendor.js +2 -2
  396. package/src/vendor/hyper-undo.vendor.js +1 -1
  397. package/src/vendor/hypercms.vendor.js +9 -9
  398. package/src/vendor/parse5.vendor.js +2 -2
  399. package/src/vendor/sap-core.vendor.js +5 -5
  400. package/dist/m/attrs/refetch-on-save-NWPPXOCZ.js +0 -1
  401. package/dist/m/attrs/save-freeze-FUP4Q4X3.js +0 -1
  402. package/dist/m/c-2M73252O.js +0 -1
  403. package/dist/m/c-2SPVQSHC.js +0 -1
  404. package/dist/m/c-35NBGMZB.js +0 -1
  405. package/dist/m/c-3IQRECYS.js +0 -1
  406. package/dist/m/c-4B6H4G5V.js +0 -1
  407. package/dist/m/c-4FFHZM32.js +0 -1
  408. package/dist/m/c-4YSCRICO.js +0 -1
  409. package/dist/m/c-54RCDCBU.js +0 -1
  410. package/dist/m/c-5M4YEKCX.js +0 -4
  411. package/dist/m/c-5V3MOVJT.js +0 -1
  412. package/dist/m/c-66O32MV3.js +0 -28
  413. package/dist/m/c-6HMB24EV.js +0 -1
  414. package/dist/m/c-7O6AFR65.js +0 -1
  415. package/dist/m/c-ANQTJ3B5.js +0 -2
  416. package/dist/m/c-AYVOREBE.js +0 -1
  417. package/dist/m/c-B2ZXPOS3.js +0 -3
  418. package/dist/m/c-BMIZKMPV.js +0 -1
  419. package/dist/m/c-BTDI4Y23.js +0 -1
  420. package/dist/m/c-CJZSLMVQ.js +0 -1
  421. package/dist/m/c-DBE6ORSI.js +0 -1
  422. package/dist/m/c-EDHUR4MX.js +0 -1
  423. package/dist/m/c-EY6UOM54.js +0 -1
  424. package/dist/m/c-F3CKJTJS.js +0 -1
  425. package/dist/m/c-F7Y6FLPY.js +0 -1
  426. package/dist/m/c-FA4DZVTC.js +0 -1
  427. package/dist/m/c-G2BUZITR.js +0 -1
  428. package/dist/m/c-GB3JTV6E.js +0 -1
  429. package/dist/m/c-GBGWXTX4.js +0 -1
  430. package/dist/m/c-GHBCCVG4.js +0 -1
  431. package/dist/m/c-GJAEGGXY.js +0 -1
  432. package/dist/m/c-GOWBDM6J.js +0 -1
  433. package/dist/m/c-IB52R237.js +0 -1
  434. package/dist/m/c-IKWNE4R4.js +0 -1
  435. package/dist/m/c-IU3IYEU6.js +0 -1
  436. package/dist/m/c-IZ2EBRAJ.js +0 -1
  437. package/dist/m/c-KR4UW4KW.js +0 -1
  438. package/dist/m/c-KY3VJGUA.js +0 -8
  439. package/dist/m/c-LFPHCXY3.js +0 -1
  440. package/dist/m/c-LRPUO2MX.js +0 -1
  441. package/dist/m/c-LXENEBV7.js +0 -1
  442. package/dist/m/c-NMJRXKPC.js +0 -8
  443. package/dist/m/c-OIBUTDXI.js +0 -1
  444. package/dist/m/c-PPOSCAQD.js +0 -1
  445. package/dist/m/c-QIX5BJYN.js +0 -1
  446. package/dist/m/c-QQHEX6HA.js +0 -1
  447. package/dist/m/c-R7RMANJI.js +0 -9
  448. package/dist/m/c-RI4NT75Y.js +0 -1
  449. package/dist/m/c-RM7J7BV2.js +0 -1
  450. package/dist/m/c-RUJKSUQW.js +0 -1
  451. package/dist/m/c-SGCCC4FW.js +0 -25
  452. package/dist/m/c-T4VO4OCB.js +0 -1
  453. package/dist/m/c-TQEMVJCS.js +0 -1
  454. package/dist/m/c-TR6RMDQ7.js +0 -3
  455. package/dist/m/c-UKHTLWUW.js +0 -1
  456. package/dist/m/c-UNN7LWCT.js +0 -1
  457. package/dist/m/c-UXBMRDZB.js +0 -235
  458. package/dist/m/c-V7PZZRG7.js +0 -1
  459. package/dist/m/c-VL52ADDR.js +0 -1
  460. package/dist/m/c-WNYBLIOZ.js +0 -1
  461. package/dist/m/c-WWDBYXLK.js +0 -1
  462. package/dist/m/c-XNNW2CWK.js +0 -1
  463. package/dist/m/c-Y6USGTS5.js +0 -5
  464. package/dist/m/c-YG2NJYS6.js +0 -135
  465. package/dist/m/c-Z4VRC7GU.js +0 -7
  466. package/dist/m/c-Z6K52OLP.js +0 -19
  467. package/dist/m/c-ZDY2MDAA.js +0 -21
  468. package/dist/m/c-ZUCOKOHT.js +0 -1
  469. package/dist/m/core/admin-attrs-VGNLAUDK.js +0 -1
  470. package/dist/m/core/autosave-E4PEFPZ6.js +0 -1
  471. package/dist/m/core/conflict-notice-VQ6Y64PH.js +0 -1
  472. package/dist/m/core/host-permission-XN3K2IW3.js +0 -1
  473. package/dist/m/core/is-edit-mode-JXHDVGUL.js +0 -1
  474. package/dist/m/core/recovery-TBBSICE2.js +0 -1
  475. package/dist/m/core/save-WUCHTQBE.js +0 -1
  476. package/dist/m/core/save-core-FJVHT5M3.js +0 -1
  477. package/dist/m/core/snapshot-F3SWDZMM.js +0 -1
  478. package/dist/m/core/unsaved-warning-STKBHE6G.js +0 -1
  479. package/dist/m/events/index-23DPTUT4.js +0 -1
  480. package/dist/m/internals/index-WOVAP3RU.js +0 -1
  481. package/dist/m/lib/cache-bust-CGWT6ZJI.js +0 -1
  482. package/dist/m/loader-HXX6YNH5.js +0 -1
  483. package/dist/m/manifest-F22DEDAC.js +0 -1
  484. package/dist/m/manifest-edit-C3C7376B.js +0 -1
  485. package/dist/m/options/options-2LH76JQ3.js +0 -1
  486. package/dist/m/page/editor-XUTB2HB2.js +0 -189
  487. package/dist/m/plugins/ai-edit-ZQ4CGWIP.js +0 -6
  488. package/dist/m/plugins/demo-ZIBFAA3R.js +0 -1
  489. package/dist/m/plugins/indicator-PV4YW2ID.js +0 -1
  490. package/dist/m/plugins/live-NUTTXSBS.js +0 -1
  491. package/dist/m/plugins/menu-HCKO3DSP.js +0 -138
  492. package/dist/m/plugins/page-KSUH7G6J.js +0 -2
  493. package/dist/m/plugins/page-view-W73OW7WI.js +0 -1
  494. package/dist/m/plugins/people-AJJ32YCG.js +0 -1
  495. package/dist/m/plugins/quickcrop-QNY3PKLD.js +0 -26
  496. package/dist/m/plugins/sortable-YRMQX3ZU.js +0 -1
  497. package/dist/m/plugins/source-KHK5UUSK.js +0 -1
  498. package/dist/m/plugins/undo-OF2L3CXU.js +0 -1
  499. package/dist/m/plugins/upgrade-ZNYODP5Y.js +0 -1
  500. package/dist/m/plugins/upload-XSGNILUY.js +0 -1
  501. package/dist/m/plugins/visitor-drafts-XK5GW55Q.js +0 -21
  502. package/dist/m/plugins/visitor-drafts-owner-KSSH75EV.js +0 -1
  503. package/dist/m/plugins/wire-ZWVWKF76.js +0 -1
  504. package/dist/m/reader-core-ILWLXVMP.js +0 -68
  505. package/dist/m/route/route-KOCZSEGN.js +0 -1
  506. package/dist/m/sync/live-sync-4AUVXVJU.js +0 -1
  507. package/dist/m/ui/index-EVHKMKBL.js +0 -1
  508. package/dist/m/vendor/sap-core.vendor-A7BMUYZT.js +0 -6
  509. /package/dist/m/{c-FILLTJA7.js → c-QTTJYJMA.js} +0 -0
  510. /package/dist/m/plugins/{quickcrop-QNY3PKLD.js.LEGAL.txt → quickcrop-BQ5YYFCH.js.LEGAL.txt} +0 -0
  511. /package/dist/m/plugins/{richclay-RC3L2F6X.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: {
@@ -53849,6 +53863,12 @@ var schema = new Qr.Schema({
53849
53863
  "data-checked": n.attrs.checked ? "true" : "false"
53850
53864
  }), 0]
53851
53865
  },
53866
+ quote: {
53867
+ group: "block",
53868
+ content: "inline*",
53869
+ attrs: block,
53870
+ toDOM: (n) => ["blockquote", ref(n), 0]
53871
+ },
53852
53872
  callout: {
53853
53873
  group: "block",
53854
53874
  content: "inline*",
@@ -53867,8 +53887,8 @@ var schema = new Qr.Schema({
53867
53887
  toggle: {
53868
53888
  group: "block",
53869
53889
  content: "inline*",
53870
- attrs: { ...block, open: { default: false } },
53871
- 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]
53872
53892
  },
53873
53893
  divider: {
53874
53894
  group: "block",
@@ -53876,6 +53896,14 @@ var schema = new Qr.Schema({
53876
53896
  attrs: block,
53877
53897
  toDOM: (n) => ["hr", ref(n)]
53878
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
+ },
53879
53907
  image: {
53880
53908
  group: "block",
53881
53909
  atom: true,
@@ -53977,6 +54005,33 @@ var schema = new Qr.Schema({
53977
54005
  attrs: { href: {} },
53978
54006
  inclusive: false,
53979
54007
  toDOM: (m2) => ["a", { href: safeHref(m2.attrs.href) }, 0]
54008
+ },
54009
+ // A person mention is ordinary text with this mark over it: the name is the label
54010
+ // and `id` is the people registry's reference. It links nowhere and notifies nobody.
54011
+ mention: {
54012
+ attrs: { id: {} },
54013
+ inclusive: false,
54014
+ excludes: "mention date link",
54015
+ toDOM: (m2) => ["span", { "data-page-mention": m2.attrs.id }, 0]
54016
+ },
54017
+ // A date mention is the calendar date as ordinary ISO text with this mark over it:
54018
+ // `date` is YYYY-MM-DD, and no time, zone, reminder or relative word is stored.
54019
+ date: {
54020
+ attrs: { date: {} },
54021
+ inclusive: false,
54022
+ excludes: "mention date link",
54023
+ toDOM: (m2) => ["time", { datetime: m2.attrs.date, "data-page-date": "" }, 0]
54024
+ },
54025
+ // The floor-1 formats (format-native.js): written as named descriptors,
54026
+ // drawn as the elements the saved article keeps for them.
54027
+ underline: { toDOM: () => ["u", 0] },
54028
+ text_color: {
54029
+ attrs: { color: {} },
54030
+ toDOM: (m2) => ["span", { "data-color": m2.attrs.color }, 0]
54031
+ },
54032
+ highlight: {
54033
+ attrs: { color: {} },
54034
+ toDOM: (m2) => ["mark", { "data-color": m2.attrs.color }, 0]
53980
54035
  }
53981
54036
  }
53982
54037
  });
@@ -54125,23 +54180,44 @@ function entriesOfYjs(fields) {
54125
54180
  return normalizeEntries(entries);
54126
54181
  }
54127
54182
 
54183
+ // src/page/format-native.js
54184
+ var NATIVE_NAMES = /* @__PURE__ */ new Set(["underline", "text_color", "highlight"]);
54185
+ var PALETTE = ["gray", "brown", "orange", "yellow", "green", "blue", "purple", "pink", "red"];
54186
+ var COLORS = new Set(PALETTE);
54187
+ function nativeAttrs(name, attrs) {
54188
+ const plain4 = attrs !== null && typeof attrs === "object" && !Array.isArray(attrs);
54189
+ if (name === "underline") return plain4 && Object.keys(attrs).length === 0 ? {} : null;
54190
+ if (name === "text_color" || name === "highlight") {
54191
+ const keys = plain4 ? Object.keys(attrs) : [];
54192
+ return keys.length === 1 && keys[0] === "color" && COLORS.has(attrs.color) ? { color: attrs.color } : null;
54193
+ }
54194
+ return null;
54195
+ }
54196
+
54128
54197
  // src/page/inline.js
54129
54198
  var CODES = { strong: "b", em: "i", strike: "s", code: "c", link: "a" };
54199
+ var NATIVE = /* @__PURE__ */ new Set(["underline", "text_color", "highlight"]);
54130
54200
  var NAMES = Object.fromEntries(Object.entries(CODES).map(([name, code]) => [code, name]));
54131
54201
  function markKey(marks) {
54132
54202
  let key = "";
54203
+ const named = [];
54133
54204
  for (const mark of marks) {
54134
54205
  if (isOpaque(mark)) {
54135
54206
  key += keyOf(mark.attrs.entries);
54136
54207
  continue;
54137
54208
  }
54138
54209
  const code = CODES[mark.type.name];
54139
- if (!code) throw new TypeError(`page: the mark ${mark.type.name} has no key code`);
54210
+ if (!code) {
54211
+ const native = nativeAttrs(mark.type.name, mark.attrs);
54212
+ if (!native && NATIVE.has(mark.type.name)) throw new TypeError(`page: the mark ${mark.type.name} has no key code`);
54213
+ named.push({ name: mark.type.name, attrs: native ?? mark.attrs });
54214
+ continue;
54215
+ }
54140
54216
  key += code;
54141
54217
  const names = Object.keys(mark.type.attrs);
54142
54218
  if (names.length) key += JSON.stringify(names.map((name) => mark.attrs[name]));
54143
54219
  }
54144
- return key;
54220
+ return named.length ? key + keyOf(named) : key;
54145
54221
  }
54146
54222
  var parsed = /* @__PURE__ */ new WeakMap();
54147
54223
  function marksOf(schema2, key) {
@@ -54153,15 +54229,23 @@ function marksOf(schema2, key) {
54153
54229
  marks = [];
54154
54230
  const opaque = [];
54155
54231
  for (const desc of descriptors(key)) {
54156
- const name = desc.code === void 0 ? null : NAMES[desc.code];
54232
+ if (desc.code === void 0) {
54233
+ const native = nativeAttrs(desc.name, desc.attrs);
54234
+ const type = schema2.marks[desc.name];
54235
+ if (native) marks = type.create(native).addToSet(marks);
54236
+ else if (type && !NATIVE.has(desc.name) && Object.keys(desc.attrs ?? {}).every((field) => Object.hasOwn(type.attrs, field))) marks = type.create(desc.attrs).addToSet(marks);
54237
+ else opaque.push(desc);
54238
+ continue;
54239
+ }
54240
+ const name = NAMES[desc.code];
54157
54241
  if (!name) {
54158
54242
  opaque.push(desc);
54159
54243
  continue;
54160
54244
  }
54161
- const type = schema2.marks[name];
54162
- if (!type) throw new TypeError(`page: unknown mark code ${desc.code} in ${key}`);
54163
- const attrs = desc.attrs ? Object.fromEntries(Object.keys(type.attrs).map((field, j3) => [field, desc.attrs[j3]])) : null;
54164
- marks = type.create(attrs).addToSet(marks);
54245
+ const coded = schema2.marks[name];
54246
+ if (!coded) throw new TypeError(`page: unknown mark code ${desc.code} in ${key}`);
54247
+ const attrs = desc.attrs ? Object.fromEntries(Object.keys(coded.attrs).map((field, j3) => [field, desc.attrs[j3]])) : null;
54248
+ marks = coded.create(attrs).addToSet(marks);
54165
54249
  }
54166
54250
  if (opaque.length) marks = opaqueMark(entriesOf(opaque)).addToSet(marks);
54167
54251
  cache.set(key, marks);
@@ -54286,13 +54370,15 @@ function ticks(min, max, count) {
54286
54370
  for (let n = Math.ceil(min / step); n <= Math.floor(max / step); n++) out.push(Number((n * step).toPrecision(12)));
54287
54371
  return out.length ? out : [Number(min.toFixed(2)), Number(max.toFixed(2))];
54288
54372
  }
54373
+ var missing = (chart, reason) => ({ state: "missing", reason, sourceId: chart.source ?? null, title: chart.title ?? "" });
54289
54374
  function chartModel(chart, table) {
54290
- if (!table) return { state: "missing", reason: "table" };
54375
+ if (!table) return missing(chart, "table");
54291
54376
  const cols = table.cols ?? [];
54292
54377
  const rows = table.rows ?? [];
54293
54378
  const x3 = cols.find((col) => col.id === chart.x);
54294
- if (!x3 || !chart.series?.length || chart.series.some((id) => !cols.some((col) => col.id === id))) return { state: "missing", reason: "column" };
54295
- 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) => {
54296
54382
  const col = cols.find((item) => item.id === id);
54297
54383
  const points2 = rows.map((row, rowIndex) => ({
54298
54384
  id: `${chart.id}:${row.id}:${id}`,
@@ -54330,8 +54416,60 @@ function chartModel(chart, table) {
54330
54416
  domain: [min, max]
54331
54417
  };
54332
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
+ }
54333
54470
  function renderChartSvg(model, { width = 640, height = 320, narrow = false } = {}) {
54334
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);
54335
54473
  const margin = { left: 52, right: 72, top: 28, bottom: 48 };
54336
54474
  const plotW = Math.max(1, width - margin.left - margin.right);
54337
54475
  const plotH = Math.max(1, height - margin.top - margin.bottom);
@@ -54340,10 +54478,7 @@ function renderChartSvg(model, { width = 640, height = 320, narrow = false } = {
54340
54478
  const n = model.xLabels.length;
54341
54479
  const x3 = (index2) => margin.left + (n <= 1 ? plotW / 2 : index2 * plotW / (n - 1));
54342
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>`];
54343
- const caption = model.series.map((item) => {
54344
- const valid = item.points.filter((point) => point.value !== null);
54345
- return `${item.name}: ${valid.length ? `${fmt(valid[0].value)} to ${fmt(valid.at(-1).value)}` : "no values"}`;
54346
- }).join("; ");
54481
+ const caption = model.series.map(chartCaption).join("; ");
54347
54482
  parts.push(`<desc>${esc(caption)}</desc>`);
54348
54483
  for (const tick of narrow ? model.narrowTicks : model.yTicks) {
54349
54484
  const yy = fmt(y2(tick));
@@ -54404,17 +54539,22 @@ var KNOWN = new Set(CODES2);
54404
54539
  var OPAQUE = "data-clay-page-opaque";
54405
54540
  var VALUE = "data-clay-page-value";
54406
54541
  var MARKS = "data-clay-page-marks";
54542
+ var MENTION = "data-page-mention";
54543
+ var DATE = "data-page-date";
54544
+ var DAY = /^\d{4}-\d{2}-\d{2}$/;
54407
54545
  var ENVELOPE = "1";
54408
54546
  var STRUCTURAL = /* @__PURE__ */ new Set(["id", "t", "parent", "c", "m"]);
54409
54547
  var knownType = (t) => Object.hasOwn(DEFAULTS, t);
54410
54548
  var DEFAULTS = {
54411
54549
  paragraph: { parent: null },
54412
- heading: { parent: null, level: 2 },
54550
+ heading: { parent: null, level: 2, pageIcon: null, pageCoverSrc: null, pageCoverAlt: "", pageCoverX: 50, pageCoverY: 50 },
54413
54551
  list_item: { parent: null, kind: "bullet", indent: 0, checked: false, owner: null, due: null },
54414
54552
  callout: { parent: null },
54553
+ quote: { parent: null },
54415
54554
  code_block: { parent: null, lang: "" },
54416
- toggle: { parent: null, open: false },
54555
+ toggle: { parent: null, open: false, level: null },
54417
54556
  divider: { parent: null },
54557
+ toc: { parent: null, maxLevel: null },
54418
54558
  image: { parent: null, src: "", alt: "", caption: "", width: null, align: null },
54419
54559
  file: { parent: null, src: "", name: "", size: null, mime: null },
54420
54560
  table: { parent: null, cols: {}, sort: null },
@@ -54423,7 +54563,40 @@ var DEFAULTS = {
54423
54563
  tool: { parent: null, artifact: null, rev: null, state: {} },
54424
54564
  preserved: { parent: null, html: "" }
54425
54565
  };
54426
- var TEXT = /* @__PURE__ */ new Set(["paragraph", "heading", "list_item", "callout", "code_block", "toggle"]);
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
+ }
54427
54600
  var same = (a, b2) => canon(a) === canon(b2);
54428
54601
  function orderedIds(map2) {
54429
54602
  return Object.keys(map2).sort((x3, y2) => {
@@ -54497,20 +54670,26 @@ function runsOf2(units) {
54497
54670
  return out;
54498
54671
  }
54499
54672
  function marksOfKey(key) {
54500
- const marks = {};
54501
- if (!key || key[0] === "@") return { marks, entries: [] };
54673
+ const marks = {}, native = [];
54674
+ if (!key || key[0] === "@") return { marks, native: [], entries: [] };
54502
54675
  const opaque = [];
54503
54676
  for (const desc of descriptors(key)) {
54504
- if (desc.name === void 0 && KNOWN.has(desc.code)) marks[desc.code] = desc.attrs ?? true;
54677
+ if (desc.name === void 0) {
54678
+ if (KNOWN.has(desc.code)) marks[desc.code] = desc.attrs ?? true;
54679
+ else opaque.push(desc);
54680
+ continue;
54681
+ }
54682
+ const attrs = nativeAttrs(desc.name, desc.attrs);
54683
+ if (attrs) native.push({ name: desc.name, attrs });
54505
54684
  else opaque.push(desc);
54506
54685
  }
54507
- return { marks, entries: opaque.length ? entriesOf(opaque) : [] };
54686
+ return { marks, native, entries: opaque.length ? entriesOf(opaque) : [] };
54508
54687
  }
54509
54688
  var unitKey = (key, text4, i) => {
54510
54689
  if (!key) return "";
54511
54690
  if (key[0] === "@") return key === BREAK2 && text4[i] === ATOM2 ? key : "";
54512
- const { marks, entries } = marksOfKey(key);
54513
- return keyOfMarks(safeMarks(marks), entries);
54691
+ const { marks, native, entries } = marksOfKey(key);
54692
+ return keyOfMarks(safeMarks(marks), native.length ? [...entries, ...entriesOf(native)] : entries);
54514
54693
  };
54515
54694
  var SCRIPT_URL = /^(javascript|vbscript|data):/i;
54516
54695
  var safeMarks = (marks) => {
@@ -54602,6 +54781,7 @@ var omitDefaults = (t, fields) => {
54602
54781
  for (const [k2, v3] of Object.entries(fields)) if (!(k2 in DEFAULTS[t]) || !same(v3, DEFAULTS[t][k2])) out[k2] = v3;
54603
54782
  return out;
54604
54783
  };
54784
+ var focal = (v3) => Math.min(100, Math.max(0, Number.isFinite(+v3) && v3 !== null && v3 !== "" ? +v3 : 50));
54605
54785
  var columnWidth = (value) => typeof value === "number" && Number.isFinite(value) && value > 0 ? Math.round(value) : null;
54606
54786
  function cellModel(value) {
54607
54787
  if (value === null || typeof value !== "object" || typeof value.c !== "string") return normalizeText(cellText(value), null).c;
@@ -54640,9 +54820,10 @@ var recordOfItem = (item) => {
54640
54820
  const { t, parent: _p, id: _i3, ...fields } = item;
54641
54821
  return { t, ...fields };
54642
54822
  };
54823
+ var VISIBLE = { table: /* @__PURE__ */ new Set(["rows"]) };
54643
54824
  var extrasOfItem = (item) => {
54644
54825
  const out = {};
54645
- 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;
54646
54827
  return Object.keys(out).length ? envelopeOf(out) : "";
54647
54828
  };
54648
54829
  var extrasOfBlock = (t, b2) => {
@@ -54666,7 +54847,8 @@ function projectOne({ id, b: b2, t, parent: parent2, indent }) {
54666
54847
  for (const k2 of Object.keys(extras)) delete attrs[k2];
54667
54848
  const fields = { ...attrs, parent: parent2 };
54668
54849
  if (t === "list_item") fields.indent = indent;
54669
- 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);
54670
54852
  if (t === "image" && fields.width != null) fields.width = widthOf(String(fields.width));
54671
54853
  if (t === "image") fields.align = alignOf(fields.align);
54672
54854
  if (t === "image" && typeof fields.caption === "string") fields.caption = normalizeText(fields.caption, null).c;
@@ -54694,7 +54876,21 @@ function projectOne({ id, b: b2, t, parent: parent2, indent }) {
54694
54876
  }
54695
54877
  return item;
54696
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
+ }
54697
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;
54698
54894
  var widthOf = (s) => /^\d+$/.test(s) ? Number(s) : s;
54699
54895
  var alignOf = (a) => a === "left" || a === "right" ? a : null;
54700
54896
  function project(blocks) {
@@ -54715,6 +54911,7 @@ var revOf = (model) => hash64(canon(model));
54715
54911
  var escText = (s) => s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/\r/g, "&#13;");
54716
54912
  var escAttr = (s) => escText(String(s)).replace(/"/g, "&quot;");
54717
54913
  var attr2 = (name, value) => value === null || value === void 0 ? "" : ` ${name}="${escAttr(value)}"`;
54914
+ var NATIVE_TAGS = { underline: "u", text_color: "span", highlight: "mark" };
54718
54915
  function renderInline(c, m2, marksEnvelopes = true) {
54719
54916
  const units = unitsOf2(m2, c.length) || [];
54720
54917
  let html3 = "";
@@ -54732,14 +54929,20 @@ function renderInline(c, m2, marksEnvelopes = true) {
54732
54929
  }
54733
54930
  let j3 = i + 1;
54734
54931
  while (j3 < c.length && (units[j3] || "") === key && !(c[j3] === ATOM2 && key[0] === "@")) j3++;
54735
- const { marks, entries } = marksOfKey(key);
54932
+ const { marks, native, entries } = marksOfKey(key);
54736
54933
  const want = NEST.filter((code) => marks[code]).map((code) => ({ code, sig: code + JSON.stringify(marks[code]), tag: code === "a" ? "a" : TAGS[code], href: code === "a" ? marks.a[0] : null }));
54737
- if (entries.length && marksEnvelopes) want.push({ sig: `marks${canon(entries)}`, tag: "span", entries });
54934
+ for (const n of native) want.push({ sig: `native${n.name}${canon(n.attrs)}`, tag: NATIVE_TAGS[n.name], color: n.attrs.color ?? null });
54935
+ const mention = entries.find((entry) => entry.name === "mention");
54936
+ const date = entries.find((entry) => entry.name === "date");
54937
+ const day = date && DAY.test(String(date.attrs.date)) ? String(date.attrs.date) : null;
54938
+ if (entries.length && marksEnvelopes) want.push({ sig: `marks${canon(entries)}`, tag: day ? "time" : "span", entries, mention: mention?.attrs.id, day });
54738
54939
  let keep = 0;
54739
54940
  while (keep < open.length && keep < want.length && open[keep].sig === want[keep].sig) keep++;
54740
54941
  closeTo(keep);
54741
54942
  for (const w3 of want.slice(keep)) {
54742
- html3 += w3.entries ? `<span${marksEnvelope(w3.entries)}>` : w3.tag === "a" ? `<a${attr2("href", w3.href)}>` : `<${w3.tag}>`;
54943
+ if (w3.entries) html3 += w3.day ? `<time${attr2("datetime", w3.day)}${attr2(DATE, "")}${marksEnvelope(w3.entries)}>` : `<span${marksEnvelope(w3.entries)}${attr2(MENTION, w3.mention)}>`;
54944
+ else if (w3.tag === "a") html3 += `<a${attr2("href", w3.href)}>`;
54945
+ else html3 += w3.color ? `<${w3.tag}${attr2("data-color", w3.color)}>` : `<${w3.tag}>`;
54743
54946
  open.push(w3);
54744
54947
  }
54745
54948
  html3 += escText(c.slice(i, j3));
@@ -54749,7 +54952,9 @@ function renderInline(c, m2, marksEnvelopes = true) {
54749
54952
  return html3;
54750
54953
  }
54751
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>`;
54752
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}`;
54753
54958
  var cellHtml = (cell) => typeof cell === "string" ? escText(cell) : cell && typeof cell === "object" ? renderInline(String(cell.c ?? ""), cell.m) : "";
54754
54959
  var dataAttrs = (obj) => Object.entries(obj).map(([k2, v3]) => attr2(`data-${k2}`, v3)).join("");
54755
54960
  function renderLeaf(item, clean, tables) {
@@ -54765,6 +54970,8 @@ function renderLeaf(item, clean, tables) {
54765
54970
  }
54766
54971
  case "callout":
54767
54972
  return `<aside${at2} class="page-callout">${inlineOf(item)}</aside>`;
54973
+ case "quote":
54974
+ return `<blockquote${at2}>${inlineOf(item)}</blockquote>`;
54768
54975
  case "code_block":
54769
54976
  return `<pre${at2}${attr2("data-lang", item.lang || null)}><code>${escText(item.c ?? "")}</code></pre>`;
54770
54977
  case "divider":
@@ -54776,9 +54983,12 @@ function renderLeaf(item, clean, tables) {
54776
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>`;
54777
54984
  }
54778
54985
  case "table": {
54779
- 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("");
54780
- 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");
54781
- 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)}>
54782
54992
  <thead><tr>${head}</tr></thead>
54783
54993
  <tbody>
54784
54994
  ${body}
@@ -54830,9 +55040,10 @@ function fragmentCleaner(doc) {
54830
55040
  function renderModel(model, { fallbackOf = () => "", clean = RAW } = {}) {
54831
55041
  const lines = [];
54832
55042
  const tables = new Map(model.filter((item) => item.t === "table").map((item) => [item.id, item]));
55043
+ const title = model.find(tocTitle) ?? null;
54833
55044
  const stack = [null];
54834
55045
  const lists = [];
54835
- const add2 = (s) => {
55046
+ const add3 = (s) => {
54836
55047
  if (lists.length) lines[lines.length - 1] += s;
54837
55048
  else lines.push(s);
54838
55049
  };
@@ -54847,7 +55058,7 @@ function renderModel(model, { fallbackOf = () => "", clean = RAW } = {}) {
54847
55058
  const parent2 = item.parent ?? null;
54848
55059
  while (stack.length > 1 && stack[stack.length - 1] !== parent2) {
54849
55060
  closeLists();
54850
- add2("</details>");
55061
+ add3("</details>");
54851
55062
  stack.pop();
54852
55063
  }
54853
55064
  if (item.t !== "list_item") closeLists();
@@ -54855,35 +55066,44 @@ function renderModel(model, { fallbackOf = () => "", clean = RAW } = {}) {
54855
55066
  const d = item.indent ?? 0;
54856
55067
  const tag = item.kind === "ordered" ? "ol" : "ul";
54857
55068
  while (lists.length > d + 1) {
54858
- add2(`</li></${lists[lists.length - 1]}>`);
55069
+ add3(`</li></${lists[lists.length - 1]}>`);
54859
55070
  lists.pop();
54860
55071
  }
54861
55072
  if (lists.length === d + 1) {
54862
- add2(lists[d] === tag ? "</li>" : `</li></${lists[d]}>`);
55073
+ add3(lists[d] === tag ? "</li>" : `</li></${lists[d]}>`);
54863
55074
  if (lists[d] !== tag) lists.pop();
54864
55075
  }
54865
55076
  if (lists.length < d + 1) {
54866
- add2(`<${tag}>`);
55077
+ add3(`<${tag}>`);
54867
55078
  lists.push(tag);
54868
55079
  }
54869
55080
  const box = item.kind === "check" ? `<input type="checkbox" disabled${item.checked ? " checked" : ""}>` : "";
54870
- 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)}`);
54871
55082
  continue;
54872
55083
  }
54873
55084
  if (item.t === "toggle") {
54874
- 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>`}`);
54875
55087
  stack.push(item.id);
54876
55088
  continue;
54877
55089
  }
54878
55090
  if (item.t === "tool") {
54879
- 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));
54880
55096
  continue;
54881
55097
  }
54882
- add2(renderLeaf(item, clean, tables));
55098
+ if (item === title && (item.pageIcon || item.pageCoverSrc)) {
55099
+ add3(titleHtml(item));
55100
+ continue;
55101
+ }
55102
+ add3(renderLeaf(item, clean, tables));
54883
55103
  }
54884
55104
  closeLists();
54885
55105
  while (stack.length > 1) {
54886
- add2("</details>");
55106
+ add3("</details>");
54887
55107
  stack.pop();
54888
55108
  }
54889
55109
  return lines.join("\n");
@@ -54894,6 +55114,13 @@ function renderBlocks(blocks, opts) {
54894
55114
  }
54895
55115
  var DROP_TAGS = /* @__PURE__ */ new Set(["SCRIPT", "STYLE", "TEMPLATE", "NOSCRIPT"]);
54896
55116
  var INLINE_TAGS = /* @__PURE__ */ new Set(["A", "ABBR", "B", "BDI", "BDO", "BR", "CITE", "CODE", "DATA", "DEL", "DFN", "EM", "FONT", "I", "INS", "KBD", "LABEL", "MARK", "Q", "S", "SAMP", "SMALL", "SPAN", "STRIKE", "STRONG", "SUB", "SUP", "TIME", "U", "VAR", "WBR"]);
55117
+ function nativeOfEl(tag, el3) {
55118
+ if (tag === "u") return { name: "underline", attrs: {} };
55119
+ if (tag !== "mark" && tag !== "span") return null;
55120
+ if (tag === "span" && !el3.hasAttribute("data-color")) return null;
55121
+ const name = tag === "mark" ? "highlight" : "text_color";
55122
+ return { name, attrs: { color: el3.getAttribute("data-color") } };
55123
+ }
54897
55124
  function inlineOfEl(el3, skip = () => false) {
54898
55125
  let c = "";
54899
55126
  const units = [];
@@ -54919,7 +55146,7 @@ function inlineOfEl(el3, skip = () => false) {
54919
55146
  continue;
54920
55147
  }
54921
55148
  const next2 = { ...marks };
54922
- if (tag === "span" && child.hasAttribute(MARKS)) {
55149
+ if ((tag === "span" || tag === "time") && child.hasAttribute(MARKS)) {
54923
55150
  walk2(child, next2, normalizeEntries([...entries, ...entriesOfEnvelope(child.getAttribute(MARKS))]));
54924
55151
  continue;
54925
55152
  }
@@ -54928,7 +55155,8 @@ function inlineOfEl(el3, skip = () => false) {
54928
55155
  else if (tag === "s" || tag === "del" || tag === "strike") next2.s = true;
54929
55156
  else if (tag === "code") next2.c = true;
54930
55157
  else if (tag === "a" && child.hasAttribute("href")) next2.a = [child.getAttribute("href")];
54931
- walk2(child, next2, entries);
55158
+ const named = nativeOfEl(tag, child);
55159
+ walk2(child, next2, named ? [...entries, named] : entries);
54932
55160
  }
54933
55161
  };
54934
55162
  walk2(el3, {}, []);
@@ -54995,7 +55223,11 @@ function parseArticle(article) {
54995
55223
  const P3 = { parent: parent2 };
54996
55224
  const record5 = envelopeAt(el3);
54997
55225
  if (record5 && typeof record5.t === "string") {
54998
- 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
+ }
54999
55231
  const { t, ...fields } = record5;
55000
55232
  items.push({ id: idOf(el3), t, parent: parent2, ...fields });
55001
55233
  return;
@@ -55003,17 +55235,30 @@ function parseArticle(article) {
55003
55235
  const onlyImage = tag === "P" && el3.children.length === 1 && el3.children[0].tagName === "IMG" && !el3.textContent.trim();
55004
55236
  if (tag === "P" && !onlyImage) return push(el3, "paragraph", parent2, { ...omitDefaults("paragraph", P3), ...tf2(el3) });
55005
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
+ }
55006
55245
  if (tag === "ASIDE") return push(el3, "callout", parent2, { ...omitDefaults("callout", P3), ...tf2(el3) });
55246
+ if (tag === "BLOCKQUOTE") return push(el3, "quote", parent2, { ...omitDefaults("quote", P3), ...tf2(el3) });
55007
55247
  if (tag === "PRE") {
55008
55248
  const code = el3.querySelector(":scope > code");
55009
55249
  return push(el3, "code_block", parent2, { ...omitDefaults("code_block", { ...P3, lang: el3.getAttribute("data-lang") || "" }), c: (code || el3).textContent });
55010
55250
  }
55011
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
+ }
55012
55256
  if (tag === "UL" || tag === "OL") return list(el3, parent2, 0);
55013
55257
  if (tag === "DETAILS") {
55014
55258
  const summary = el3.querySelector(":scope > summary");
55259
+ const head = summary?.querySelector(":scope > h1, :scope > h2, :scope > h3");
55015
55260
  const at2 = items.length;
55016
- 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) });
55017
55262
  const body = el3.ownerDocument.createElement("div");
55018
55263
  for (const n of [...el3.childNodes]) if (n !== summary) body.appendChild(n.cloneNode(true));
55019
55264
  walk2(body, { ref: at2 });
@@ -55080,9 +55325,9 @@ function parseArticle(article) {
55080
55325
  const columns = [], cards = [];
55081
55326
  for (const div of el3.querySelectorAll(":scope > div[data-col], :scope > div")) {
55082
55327
  const col = div.getAttribute("data-col");
55083
- const missing = div.hasAttribute("data-missing");
55084
- const ref2 = missing ? { id: col } : { id: col, name: text3(div.querySelector(":scope > h4")) };
55085
- 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);
55086
55331
  for (const li3 of div.querySelectorAll(":scope > ul > li")) {
55087
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") } : {} });
55088
55333
  }
@@ -55577,6 +55822,7 @@ var _e2 = (e19, t, n = 0) => {
55577
55822
  n < e19.length && _e2(e19, t, n + 1);
55578
55823
  }
55579
55824
  };
55825
+ var nr2 = (e19) => e19;
55580
55826
  var Se2 = (e19, t) => {
55581
55827
  if (e19 === t) return true;
55582
55828
  if (e19 == null || t == null || e19.constructor !== t.constructor && (e19.constructor || Object) !== (t.constructor || Object)) return false;
@@ -55643,13 +55889,24 @@ var ys2 = ws2("production");
55643
55889
  var Do2 = Gt2 && ms2(process.env.FORCE_COLOR, ["true", "1", "2"]);
55644
55890
  var xs2 = Do2 || !sr2("--no-colors") && !ws2("no-color") && (!Gt2 || process.stdout.isTTY) && (!Gt2 || sr2("--color") || Ee2("COLORTERM") !== null || (Ee2("TERM") || "").includes("color"));
55645
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");
55646
55898
  var Vo2 = (e19) => {
55647
55899
  let t = atob(e19), n = bs2(t.length);
55648
55900
  for (let r44 = 0; r44 < t.length; r44++) n[r44] = t.charCodeAt(r44);
55649
55901
  return n;
55650
55902
  };
55651
55903
  var Oo2 = (e19) => new Uint8Array(Buffer.from(e19, "base64"));
55904
+ var No2 = en2 ? To2 : vo2;
55652
55905
  var Lo2 = en2 ? Vo2 : Oo2;
55906
+ var ks2 = (e19) => {
55907
+ let t = bs2(e19.byteLength);
55908
+ return t.set(e19), t;
55909
+ };
55653
55910
  var ir2 = class {
55654
55911
  constructor(t, n) {
55655
55912
  this.left = t, this.right = n;
@@ -56282,6 +56539,44 @@ var At2 = class {
56282
56539
  return w2(this.restDecoder);
56283
56540
  }
56284
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
+ };
56285
56580
  var Cn2 = class {
56286
56581
  constructor(t) {
56287
56582
  this.dsCurrVal = 0, this.restDecoder = t;
@@ -56590,6 +56885,19 @@ var Fr2 = (e19, t, n, r44 = j2) => {
56590
56885
  let s = V2(t);
56591
56886
  ai2(s, e19, n, new r44(s));
56592
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
+ };
56593
56901
  var hi2 = (e19) => {
56594
56902
  let t = /* @__PURE__ */ new Map(), n = w2(e19.restDecoder);
56595
56903
  for (let r44 = 0; r44 < n; r44++) {
@@ -56840,11 +57148,17 @@ var et2 = class {
56840
57148
  return this.curr;
56841
57149
  }
56842
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
+ };
56843
57156
  var Le2 = class {
56844
57157
  constructor(t) {
56845
57158
  this.currClient = 0, this.startClock = 0, this.written = 0, this.encoder = t, this.clientStructs = [];
56846
57159
  }
56847
57160
  };
57161
+ var Gc = (e19) => Tn2(e19, H, ct2);
56848
57162
  var zc = (e19, t = ee2, n = j2) => {
56849
57163
  let r44 = new t(), s = new et2(new n(V2(e19)), false), i = s.curr;
56850
57164
  if (i !== null) {
@@ -56899,6 +57213,21 @@ var Tn2 = (e19, t = j2, n = X2) => {
56899
57213
  let l = r44.map((a) => ot2(a)), h = te2(l);
56900
57214
  return tt2(o, h), o.toUint8Array();
56901
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
+ };
56902
57231
  var ki2 = (e19) => {
56903
57232
  e19.written > 0 && (e19.clientStructs.push({ written: e19.written, restEncoder: q2(e19.encoder.restEncoder) }), e19.encoder.restEncoder = kt2(), e19.written = 0);
56904
57233
  };
@@ -56914,6 +57243,14 @@ var qr2 = (e19) => {
56914
57243
  g(t, r44.written), Rt2(t, r44.restEncoder);
56915
57244
  }
56916
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);
56917
57254
  var ni2 = "You must not compute changes after the event-handler fired.";
56918
57255
  var ne2 = class {
56919
57256
  constructor(t, n) {
@@ -58645,9 +58982,14 @@ ji2[qi2] = true;
58645
58982
  var NET = "page-net";
58646
58983
  var PAGE_ROOTS = Object.freeze(["flow", "attrs", "gone", "boardFields", "tableFields", "origins"]);
58647
58984
  var SKIP = /* @__PURE__ */ new Set(["id", "pos"]);
58648
- 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
+ };
58649
58991
  var defaultOf = (type, k2) => type.name === "table" && k2 === "rows" ? {} : type.spec.attrs[k2].default;
58650
- var sameJson = (a, b2) => JSON.stringify(a) === JSON.stringify(b2);
58992
+ var sameJson = (a, b2) => a === b2 || JSON.stringify(a) === JSON.stringify(b2);
58651
58993
  var idKey = (id) => `${id.client}.${id.clock}`;
58652
58994
  var parseKey = (k2) => {
58653
58995
  const i = k2.indexOf(".");
@@ -58684,6 +59026,16 @@ var boundaryRecord = (value) => {
58684
59026
  return value.recoveryOf === void 0 ? { blockId: value.blockId, kind: value.kind } : { blockId: value.blockId, kind: value.kind, recoveryOf: value.recoveryOf };
58685
59027
  };
58686
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
+ };
58687
59039
  var recordKey = (key) => {
58688
59040
  if (typeof key !== "string" || key.charCodeAt(0) !== 91) return null;
58689
59041
  let parts;
@@ -58699,6 +59051,7 @@ var recordKey = (key) => {
58699
59051
  function createOriginIndex(origins) {
58700
59052
  const spans = /* @__PURE__ */ new Map();
58701
59053
  const aliases2 = /* @__PURE__ */ new Map();
59054
+ const aliasClocks = /* @__PURE__ */ new Map();
58702
59055
  const boundaries = /* @__PURE__ */ new Map();
58703
59056
  const lower = (list, clock) => {
58704
59057
  let lo3 = 0, hi3 = list.length;
@@ -58709,13 +59062,61 @@ function createOriginIndex(origins) {
58709
59062
  }
58710
59063
  return lo3;
58711
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
+ };
58712
59110
  const apply2 = (key, value) => {
59111
+ trackMarker(key, value !== void 0);
58713
59112
  const parts = recordKey(key);
58714
59113
  if (!parts) return;
58715
59114
  const [kind, client, clock] = parts;
58716
59115
  if (kind === "alias") {
58717
- 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 });
58718
59118
  else aliases2.delete(idKey2(client, clock));
59119
+ markAlias(client, clock, valid);
58719
59120
  return;
58720
59121
  }
58721
59122
  if (kind === "boundary") {
@@ -58733,13 +59134,17 @@ function createOriginIndex(origins) {
58733
59134
  if (list.length) spans.set(client, list);
58734
59135
  else spans.delete(client);
58735
59136
  };
58736
- for (const [key, value] of origins) apply2(key, value);
59137
+ for (const key of origins._map.keys()) apply2(key, origins.get(key));
58737
59138
  const observer = (event) => {
58738
59139
  for (const key of event.keysChanged) apply2(key, origins.get(key));
58739
59140
  };
58740
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
+ };
58741
59146
  const resolve = (id) => {
58742
- 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;
58743
59148
  if (alias) return { client: alias.client, clock: alias.clock };
58744
59149
  const list = spans.get(id.client);
58745
59150
  if (!list) return { client: id.client, clock: id.clock };
@@ -58757,8 +59162,44 @@ function createOriginIndex(origins) {
58757
59162
  if (offset >= record5.length) return { client: id.client, clock: id.clock };
58758
59163
  return { client: record5.sourceClient, clock: record5.sourceClock + offset };
58759
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
+ };
58760
59197
  const boundaryOf = (id) => {
58761
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
+ }
58762
59203
  let key = idKey2(id.client, id.clock);
58763
59204
  const seen = /* @__PURE__ */ new Set();
58764
59205
  while (!seen.has(key)) {
@@ -58827,13 +59268,19 @@ function createOriginIndex(origins) {
58827
59268
  const previous = boundaryRecord(existing);
58828
59269
  if (!previous || !sameBoundary(previous, record5)) throw conflicting(key);
58829
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
+ };
58830
59275
  return {
58831
59276
  origins,
58832
59277
  resolve,
59278
+ resolveRange,
58833
59279
  recordSpans,
58834
59280
  recordAlias,
58835
59281
  recordBoundary,
58836
59282
  boundaryOf,
59283
+ markers,
58837
59284
  get size() {
58838
59285
  return origins.size;
58839
59286
  },
@@ -58845,7 +59292,13 @@ function createOriginIndex(origins) {
58845
59292
 
58846
59293
  // src/page/ybind/parts.js
58847
59294
  var PART_KEY = /^(.+)\.(\d+)\.(\d+)$/;
58848
- 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
+ }
58849
59302
  function entriesOf2(y2) {
58850
59303
  const whole = [];
58851
59304
  const parts = /* @__PURE__ */ new Map();
@@ -58867,6 +59320,75 @@ function entriesOf2(y2) {
58867
59320
  return whole;
58868
59321
  }
58869
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
+
58870
59392
  // src/page/ybind/recovery-proof.js
58871
59393
  var encoder = typeof TextEncoder === "function" ? new TextEncoder() : null;
58872
59394
 
@@ -58916,7 +59438,7 @@ function docFromValue(value, { strict = false } = {}) {
58916
59438
  try {
58917
59439
  for (const [key, value2] of entries) {
58918
59440
  const text4 = strict ? value2.replace(/[\t\n\f\r ]/g, "") : value2;
58919
- 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}`);
58920
59442
  Fr2(d, dec(text4), NET);
58921
59443
  }
58922
59444
  if (strict && (d.store.pendingStructs || d.store.pendingDs)) {
@@ -58971,8 +59493,8 @@ function resolveBoardFields(fields, blockId = null) {
58971
59493
  const columns = pick(groups, "column", columnOf, true);
58972
59494
  const cards = pick(groups, "card", cardOf, true);
58973
59495
  const columnIds = orderedIds(columns);
58974
- const missing = [...new Set(Object.values(cards).map((card) => card.col))].filter((id) => !Object.hasOwn(columns, id)).sort();
58975
- 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))));
58976
59498
  return {
58977
59499
  columns: Object.fromEntries(columnIds.map((id) => [id, columns[id]])),
58978
59500
  cards: Object.fromEntries(cardIds.map((id) => [id, cards[id]]))
@@ -59019,9 +59541,75 @@ function keepOne(live, dead) {
59019
59541
  });
59020
59542
  if (first2) live[first2] = dead[first2];
59021
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;
59022
59595
  function resolveTableFields(fields, blockId = null, seed = null) {
59023
59596
  const rows = /* @__PURE__ */ new Map(), cols = /* @__PURE__ */ new Map(), cells = /* @__PURE__ */ new Map();
59024
- 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) {
59025
59613
  let tuple;
59026
59614
  try {
59027
59615
  tuple = JSON.parse(key);
@@ -59035,16 +59623,7 @@ function resolveTableFields(fields, blockId = null, seed = null) {
59035
59623
  if (!validId2(field) || !validCell(value)) fail2(key);
59036
59624
  } else if (!Object.hasOwn(TABLE_FIELDS, kind) || !TABLE_FIELDS[kind].includes(field) || !validValue(field, value)) fail2(key);
59037
59625
  if (owner !== blockId) continue;
59038
- if (kind === "cell") {
59039
- const row = cells.get(entityId) ?? /* @__PURE__ */ new Map();
59040
- row.set(field, value);
59041
- cells.set(entityId, row);
59042
- continue;
59043
- }
59044
- const bucket = kind === "row" ? rows : cols;
59045
- const entity = bucket.get(entityId) ?? {};
59046
- entity[field] = value;
59047
- bucket.set(entityId, entity);
59626
+ take(kind, entityId, field, value);
59048
59627
  }
59049
59628
  const outCols = { ...record2(seed?.cols) ? seed.cols : {} };
59050
59629
  const outRows = { ...record2(seed?.rows) ? seed.rows : {} };
@@ -59100,7 +59679,7 @@ function marksFromAttributes(a, blockType) {
59100
59679
  const marks = [];
59101
59680
  let unknown = null;
59102
59681
  for (const [n, v3] of best) {
59103
- if (schema.marks[n]) 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));
59104
59683
  else (unknown ??= {})[n] = v3;
59105
59684
  }
59106
59685
  if (unknown) {
@@ -59237,15 +59816,112 @@ var recordOf2 = (value, key, out) => {
59237
59816
  if (end2 !== null && !parsePhysicalKey(end2)) fail3(`Invalid gone record: ${key}`);
59238
59817
  out.removals.push({ key, sourceKey: key, source, operationId: null, blockId: value.b, end: end2, sv: [], legacy: true });
59239
59818
  };
59240
- function parseGoneIntents(gone, { strict = false } = {}) {
59241
- const out = { removals: [], restores: [], copyActive: /* @__PURE__ */ new Set(), attrs: /* @__PURE__ */ new Map(), textDeletes: [] };
59242
- gone.forEach((value, key) => {
59243
- try {
59244
- recordOf2(value, key, out);
59245
- } catch (error) {
59246
- 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;
59247
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);
59248
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
+ };
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);
59923
+ });
59924
+ parsedGone.set(gone, parsed2);
59249
59925
  return out;
59250
59926
  }
59251
59927
  var typeNode = (name) => schema.nodes[name] ?? schema.nodes.paragraph;
@@ -59318,8 +59994,19 @@ function walkFlow(pd, index2) {
59318
59994
  const liveSources = new Set(liveBySource.keys());
59319
59995
  const movedSources = /* @__PURE__ */ new Set();
59320
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;
59321
60006
  const candidateSets = /* @__PURE__ */ new Map();
59322
- 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()) {
59323
60010
  let parts;
59324
60011
  try {
59325
60012
  parts = JSON.parse(key);
@@ -59329,15 +60016,7 @@ function walkFlow(pd, index2) {
59329
60016
  if (!Array.isArray(parts) || parts.length !== 3 || parts[0] !== "boundary" && parts[0] !== "alias") continue;
59330
60017
  const [, client, clock] = parts;
59331
60018
  if (!Number.isSafeInteger(client) || client < 0 || !Number.isSafeInteger(clock) || clock < 0) continue;
59332
- if (parts[0] === "boundary") {
59333
- const sourceKey = `${client}.${clock}`;
59334
- const record5 = index2.boundaryOf({ client, clock });
59335
- if (record5 && record5.kind === "copy") {
59336
- if (intents.copyActive.has(sourceKey)) {
59337
- if (record5.recoveryOf) movedSources.add(record5.recoveryOf);
59338
- } 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 });
59339
- }
59340
- }
60019
+ if (parts[0] === "boundary") copyBoundary(client, clock);
59341
60020
  const clocks = candidateSets.get(client) ?? candidateSets.set(client, /* @__PURE__ */ new Set()).get(client);
59342
60021
  clocks.add(clock);
59343
60022
  }
@@ -59399,7 +60078,7 @@ function walkFlow(pd, index2) {
59399
60078
  for (const key of restore.covers) set.add(key);
59400
60079
  }
59401
60080
  const recoveredMarkers = /* @__PURE__ */ new Map();
59402
- for (let it3 = pd.flow._start; it3; it3 = it3.right) {
60081
+ if (restoredSources.size) for (let it3 = pd.flow._start; it3; it3 = it3.right) {
59403
60082
  if (it3.deleted) continue;
59404
60083
  const source = it3.content instanceof wt2 ? markerSource(it3, it3.content.embed && it3.content.embed.b) : null;
59405
60084
  if (source === null) continue;
@@ -59417,9 +60096,14 @@ function walkFlow(pd, index2) {
59417
60096
  const segs = [];
59418
60097
  const orphans = [];
59419
60098
  const hidden = [];
59420
- const fences = [];
60099
+ const fences = [], stops = [];
59421
60100
  let cur = null, prevId = "start", hiding = null, at2 = 0;
59422
60101
  const cattrs = {};
60102
+ let styled = null;
60103
+ const fmt2 = () => {
60104
+ for (const key in cattrs) return { ...cattrs };
60105
+ return null;
60106
+ };
59423
60107
  const typeOf = (id) => {
59424
60108
  const m2 = pd.attrs.get(id);
59425
60109
  return m2 && m2.get("t") || "paragraph";
@@ -59434,12 +60118,16 @@ function walkFlow(pd, index2) {
59434
60118
  const id = `recovered:${sourceKey}`;
59435
60119
  const t = root2 ? root2.type : "paragraph";
59436
60120
  const opaque = !Object.hasOwn(schema.nodes, t);
59437
- 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 };
59438
60124
  segs.push(cur);
59439
60125
  prevId = id;
59440
60126
  };
59441
60127
  const open = (id, brk, implicit) => {
59442
- 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 };
59443
60131
  if (!implicit) {
59444
60132
  cur.t = typeOf(id);
59445
60133
  cur.opaque = !Object.hasOwn(schema.nodes, cur.t);
@@ -59461,15 +60149,15 @@ function walkFlow(pd, index2) {
59461
60149
  if (a.legacy && a.text) orphans.push({ key: a.key, id: a.blockId, text: a.text, h: hashText(a.text) });
59462
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 });
59463
60151
  };
59464
- const matchesEnd = (it3, end2) => {
59465
- if (covers(it3, end2)) return true;
60152
+ const matchesEnd = (it3, end2, after2 = -1) => {
60153
+ if (covers(it3, end2) && end2.clock > after2) return true;
59466
60154
  return markerIdsWithin(it3).some((id) => {
59467
- 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;
59468
60156
  const resolved = index2.resolve(id);
59469
60157
  return resolved.client === end2.client && resolved.clock === end2.clock;
59470
60158
  });
59471
60159
  };
59472
- 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)]));
59473
60161
  const markerIdsWithin = (it3) => {
59474
60162
  const clocks = markerClocks.get(it3.id.client) ?? [];
59475
60163
  let lo3 = 0, hi3 = clocks.length;
@@ -59482,6 +60170,14 @@ function walkFlow(pd, index2) {
59482
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] });
59483
60171
  return ids;
59484
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);
59485
60181
  const proj = [];
59486
60182
  const endsOf = (removal) => ({ blockId: removal.blockId, end: removal.end ? parseKey(removal.end) : null, implicit: removal.implicit === true, sourceKey: removal.sourceKey });
59487
60183
  for (let it3 = pd.flow._start; it3; it3 = it3.right) {
@@ -59490,13 +60186,8 @@ function walkFlow(pd, index2) {
59490
60186
  if (hiding || proj.length) {
59491
60187
  const edge = !it3.deleted && it3.content instanceof wt2 ? it3.content.embed.b : void 0;
59492
60188
  const boundary = edge !== void 0 && boundarySource(it3, edge) === null;
59493
- const deletedEdges = it3.deleted ? markerIdsWithin(it3).flatMap((id) => {
59494
- const sourceKey = idKey(index2.resolve(id));
59495
- const record5 = index2.boundaryOf(id);
59496
- if (!record5 || record5.kind !== "removed" || liveSources.has(sourceKey)) return [];
59497
- return [{ blockId: record5.blockId, sourceKey }];
59498
- }) : [];
59499
- 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 });
59500
60191
  if (hiding) {
59501
60192
  const keep = [];
59502
60193
  for (const a of hiding.active) {
@@ -59513,6 +60204,7 @@ function walkFlow(pd, index2) {
59513
60204
  }
59514
60205
  const removals2 = removalStarts.get(it3);
59515
60206
  if (removals2) {
60207
+ if (it3.deleted) stops.push({ client: it3.id.client, clock: it3.id.clock, len: it3.length });
59516
60208
  if (!hiding && exposed(removals2[0].sourceKey)) {
59517
60209
  if (!it3.deleted) hideUnit(it3.length);
59518
60210
  proj.push({ active: removals2.map(endsOf), sourceKey: removals2[0].sourceKey, root: null });
@@ -59521,14 +60213,20 @@ function walkFlow(pd, index2) {
59521
60213
  if (!hiding && it3.deleted) fences.push({ client: it3.id.client, clock: it3.id.clock });
59522
60214
  for (const removal of removals2) {
59523
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
+ }
59524
60221
  if (hiding) hiding.active.push(a);
59525
60222
  else hiding = { active: [a], len: 0, resume: cur };
59526
60223
  }
59527
- if (!it3.deleted) hiding.len += it3.length;
60224
+ if (hiding && !it3.deleted) hiding.len += it3.length;
59528
60225
  continue;
59529
60226
  }
59530
60227
  const start = starts.get(it3);
59531
60228
  if (start) {
60229
+ if (it3.deleted) stops.push({ client: it3.id.client, clock: it3.id.clock, len: it3.length });
59532
60230
  if (!hiding && exposed(start.key)) {
59533
60231
  if (!it3.deleted) hideUnit(it3.length);
59534
60232
  proj.push({ active: [{ blockId: start.blockId, end: start.end }], sourceKey: start.key, root: null });
@@ -59545,6 +60243,7 @@ function walkFlow(pd, index2) {
59545
60243
  if (c instanceof C2) {
59546
60244
  if (c.value === null) delete cattrs[c.key];
59547
60245
  else cattrs[c.key] = c.value;
60246
+ styled = null;
59548
60247
  continue;
59549
60248
  }
59550
60249
  if (hiding) {
@@ -59595,8 +60294,12 @@ function walkFlow(pd, index2) {
59595
60294
  }
59596
60295
  if (c instanceof nt2) {
59597
60296
  if (!cur || cur.atom) open(`~${prevId}`, null, true);
59598
- const marks = marksFromAttributes(cattrs, cur.t);
59599
- 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 });
59600
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 } });
59601
60304
  cur.len += c.str.length;
59602
60305
  }
@@ -59605,6 +60308,7 @@ function walkFlow(pd, index2) {
59605
60308
  for (const a of hiding.active) settle(a);
59606
60309
  flush();
59607
60310
  }
60311
+ if (cur) cur.fmtOut = fmt2();
59608
60312
  const groups = /* @__PURE__ */ new Map();
59609
60313
  for (const s of segs) {
59610
60314
  if (s.kind !== "b" || s.implicit) continue;
@@ -59651,7 +60355,7 @@ function walkFlow(pd, index2) {
59651
60355
  }
59652
60356
  tokens += s.len;
59653
60357
  }
59654
- 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 };
59655
60359
  }
59656
60360
 
59657
60361
  // src/page/ybind/decode.js
@@ -59980,16 +60684,16 @@ var REGISTRY = {
59980
60684
  "pos"
59981
60685
  ]
59982
60686
  };
59983
- var frozen = null;
60687
+ var frozen2 = null;
59984
60688
  function floorZero() {
59985
- if (!frozen) {
59986
- frozen = Object.freeze({
60689
+ if (!frozen2) {
60690
+ frozen2 = Object.freeze({
59987
60691
  types: Object.freeze([...REGISTRY.types]),
59988
60692
  marks: Object.freeze([...REGISTRY.marks]),
59989
60693
  fields: Object.freeze([...REGISTRY.fields])
59990
60694
  });
59991
60695
  }
59992
- return frozen;
60696
+ return frozen2;
59993
60697
  }
59994
60698
  var CODE2 = /^[A-Za-z]$/;
59995
60699
  function newerMark(key) {
@@ -60725,8 +61429,8 @@ function align(baseRoot, sideRoot, o) {
60725
61429
  const keysAgree = (b2, s) => {
60726
61430
  const kb = baseId(b2);
60727
61431
  if (!kb) return true;
60728
- const ks2 = sideId(s);
60729
- return !ks2 || kb === ks2;
61432
+ const ks3 = sideId(s);
61433
+ return !ks3 || kb === ks3;
60730
61434
  };
60731
61435
  const nameB = (u) => {
60732
61436
  const k2 = baseKey(u);
@@ -60845,8 +61549,8 @@ function align(baseRoot, sideRoot, o) {
60845
61549
  for (const u of unitsOf3(bEl)) {
60846
61550
  const t = map2.get(u);
60847
61551
  if (!t || identityPaired.has(u)) continue;
60848
- const within2 = isEl3(t) ? sEl.contains(t) : sEl.contains(t.nodes[0]);
60849
- if (!within2) continue;
61552
+ const within3 = isEl3(t) ? sEl.contains(t) : sEl.contains(t.nodes[0]);
61553
+ if (!within3) continue;
60850
61554
  drop(u, t);
60851
61555
  if (isEl3(u)) walk2(u, t);
60852
61556
  }
@@ -60873,12 +61577,12 @@ function align(baseRoot, sideRoot, o) {
60873
61577
  alignKids(b2, s);
60874
61578
  }
60875
61579
  }
60876
- function within(el3, list) {
61580
+ function within2(el3, list) {
60877
61581
  if (codeLike(el3)) return;
60878
61582
  for (const u of unitsOf3(el3))
60879
61583
  if (isEl3(u)) {
60880
61584
  list.push(u);
60881
- within(u, list);
61585
+ within2(u, list);
60882
61586
  }
60883
61587
  }
60884
61588
  function alignKids(bEl, sEl) {
@@ -60918,7 +61622,7 @@ function align(baseRoot, sideRoot, o) {
60918
61622
  if (!map2.has(u)) {
60919
61623
  if (isEl3(u)) {
60920
61624
  unpairedBase.push(u);
60921
- within(u, unpairedBase);
61625
+ within2(u, unpairedBase);
60922
61626
  openB = true;
60923
61627
  }
60924
61628
  continue;
@@ -60928,7 +61632,7 @@ function align(baseRoot, sideRoot, o) {
60928
61632
  for (const u of sUnits)
60929
61633
  if (!reverse.has(u) && isEl3(u)) {
60930
61634
  unpairedSide.push(u);
60931
- within(u, unpairedSide);
61635
+ within2(u, unpairedSide);
60932
61636
  openS = true;
60933
61637
  }
60934
61638
  if (openB && openS) slotParents.push([bEl, sEl]);
@@ -61143,15 +61847,15 @@ function align(baseRoot, sideRoot, o) {
61143
61847
  if (map2.has(b2) || !isEl3(b2) || codeLike(b2)) continue;
61144
61848
  const bucket = buckets.get(meta(b2).sig);
61145
61849
  if (!bucket || !bucket.length) continue;
61146
- const bi2 = posB.get(b2);
61147
- 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) }));
61148
61852
  near.sort((x3, y2) => x3.d - y2.d);
61149
61853
  if (near.length > NEAREST_WINDOW) near = near.slice(0, NEAREST_WINDOW);
61150
61854
  for (const { c, d } of near) {
61151
61855
  if (!keysAgree(b2, c.el)) continue;
61152
61856
  const sc2 = score(b2, c.el);
61153
61857
  if (sc2 && sc2.coef >= 0.5)
61154
- 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 });
61155
61859
  }
61156
61860
  }
61157
61861
  cands.sort(
@@ -61241,9 +61945,9 @@ function align(baseRoot, sideRoot, o) {
61241
61945
  return null;
61242
61946
  };
61243
61947
  return (b2, s) => {
61244
- const bi2 = posB.get(b2), si3 = posS.get(s);
61245
- if (bi2 === si3) return true;
61246
- 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));
61247
61951
  return ab ? map2.get(ab) === as2 : !as2;
61248
61952
  };
61249
61953
  }
@@ -61479,12 +62183,12 @@ function myers(a, b2, maxD) {
61479
62183
  function wordsFirst(a, b2, maxD) {
61480
62184
  const brk = (t) => t.k === BREAK3;
61481
62185
  if (!a.some(brk) && !b2.some(brk)) return myers(a, b2, maxD);
61482
- const ai3 = [], bi2 = [];
62186
+ const ai3 = [], bi3 = [];
61483
62187
  for (let i = 0; i < a.length; i++) if (!brk(a[i])) ai3.push(i);
61484
- 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);
61485
62189
  const top = myers(
61486
62190
  ai3.map((i) => a[i]),
61487
- bi2.map((i) => b2[i]),
62191
+ bi3.map((i) => b2[i]),
61488
62192
  maxD
61489
62193
  );
61490
62194
  if (!top) return null;
@@ -61501,7 +62205,7 @@ function wordsFirst(a, b2, maxD) {
61501
62205
  };
61502
62206
  for (const [op, i, j3] of top) {
61503
62207
  if (op !== 0) continue;
61504
- if (!gapTo(ai3[i], bi2[j3])) return null;
62208
+ if (!gapTo(ai3[i], bi3[j3])) return null;
61505
62209
  ops.push([0, x3, y2]);
61506
62210
  x3++;
61507
62211
  y2++;
@@ -61803,11 +62507,11 @@ function sharesFew(a, b2) {
61803
62507
  return inter / Math.min(na3.length, nb.length) < REWRITE_SHARE;
61804
62508
  }
61805
62509
  var keysOf = (h, B3) => {
61806
- const ks2 = /* @__PURE__ */ new Set();
61807
- 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);
61808
62512
  for (let i = h.bs; i < h.be; i++)
61809
- if (typeof B3[i].k !== "string") ks2.add(B3[i].k.el);
61810
- return ks2;
62513
+ if (typeof B3[i].k !== "string") ks3.add(B3[i].k.el);
62514
+ return ks3;
61811
62515
  };
61812
62516
  var sameToks = (a, b2) => a.length === b2.length && a.every((t, i) => t.k === b2[i].k);
61813
62517
  function merge3Tokens(B3, L3, R3, policy = "remote") {
@@ -61927,9 +62631,9 @@ function merge3Tokens(B3, L3, R3, policy = "remote") {
61927
62631
  units.forEach((u, i) => {
61928
62632
  for (const [og, info] of groups) {
61929
62633
  if (find4(i) === find4(og) || !(info.L && info.R)) continue;
61930
- const inside = u.bs < info.be && u.be > info.bs;
62634
+ const inside2 = u.bs < info.be && u.be > info.bs;
61931
62635
  const textInsertAtEdge = isInsert(u) && hasText(u) && (u.bs === info.be || u.bs === info.bs);
61932
- if ((inside || textInsertAtEdge) && union(i, og)) grew = true;
62636
+ if ((inside2 || textInsertAtEdge) && union(i, og)) grew = true;
61933
62637
  }
61934
62638
  });
61935
62639
  }
@@ -61972,9 +62676,9 @@ function merge3Tokens(B3, L3, R3, policy = "remote") {
61972
62676
  const rank = (e19) => e19.kind === "R" ? 1 : 0;
61973
62677
  emitUnits.sort((a, b2) => {
61974
62678
  if (a.bs !== b2.bs) return a.bs - b2.bs;
61975
- const ai3 = a.bs === a.be, bi2 = b2.bs === b2.be;
61976
- if (ai3 !== bi2) return ai3 ? -1 : 1;
61977
- 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") {
61978
62682
  const at3 = a.u.toks, bt3 = b2.u.toks;
61979
62683
  const allOpen = (t) => t.length && t.every((x3) => x3.kind === "open");
61980
62684
  const allClose = (t) => t.length && t.every((x3) => x3.kind === "close");
@@ -62067,8 +62771,8 @@ function merge3Tokens(B3, L3, R3, policy = "remote") {
62067
62771
  for (const seg of segments) {
62068
62772
  if (seg.source === "base") {
62069
62773
  seg.toks = seg.toks.map((t, i) => {
62070
- const bi2 = seg.bs + i;
62071
- 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);
62072
62776
  const pick2 = lt3 && rt3 ? policy === "remote" ? rt3 : lt3 : lt3 || rt3 || t;
62073
62777
  return pick2 === t ? t : { ...pick2, cosmetic: true };
62074
62778
  });
@@ -62291,11 +62995,11 @@ function compileOccurrenceMap({
62291
62995
  const length = run.to - run.from;
62292
62996
  if (!charge(length)) return fallback("work-limit");
62293
62997
  for (let k2 = 0; k2 < length; k2++) {
62294
- const bi2 = run.from + k2, si3 = run.target + k2;
62998
+ const bi3 = run.from + k2, si3 = run.target + k2;
62295
62999
  budget.comparisons++;
62296
- if (base.text[bi2] !== side.text[si3])
63000
+ if (base.text[bi3] !== side.text[si3])
62297
63001
  return fallback("unequal-occurrence");
62298
- const ba2 = base.atomAt.get(bi2), sa3 = side.atomAt.get(si3);
63002
+ const ba2 = base.atomAt.get(bi3), sa3 = side.atomAt.get(si3);
62299
63003
  if (!!ba2 !== !!sa3 || ba2 && baseAtomKey(ba2) !== sideAtomKey(sa3))
62300
63004
  return fallback("different-atom");
62301
63005
  }
@@ -62361,27 +63065,27 @@ function boundaryOccurrences({
62361
63065
  last2.to++;
62362
63066
  else runs.push({ from, to: from + 1, target, destination, kind });
62363
63067
  };
62364
- let bi2 = 0, si3 = 0, changedBoundary = false;
63068
+ let bi3 = 0, si3 = 0, changedBoundary = false;
62365
63069
  try {
62366
- while (bi2 < base.text.length || si3 < side.text.length) {
62367
- if (bi2 < base.text.length && si3 < side.text.length && base.text[bi2] === side.text[si3]) {
62368
- 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);
62369
63073
  if (!!ba2 !== !!sa3 || ba2 && baseOf2(sa3.el) !== ba2.el)
62370
63074
  return { status: "none" };
62371
- append3(bi2++, si3++);
63075
+ append3(bi3++, si3++);
62372
63076
  continue;
62373
63077
  }
62374
- if (!soft(base.text, bi2) && !soft(side.text, si3))
63078
+ if (!soft(base.text, bi3) && !soft(side.text, si3))
62375
63079
  return { status: "none" };
62376
- const bs3 = bi2, ss3 = si3;
62377
- while (soft(base.text, bi2)) bi2++;
63080
+ const bs3 = bi3, ss3 = si3;
63081
+ while (soft(base.text, bi3)) bi3++;
62378
63082
  while (soft(side.text, si3)) si3++;
62379
- 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);
62380
63084
  if (bt3.includes(BREAK3) || st3.includes(BREAK3)) changedBoundary = true;
62381
63085
  let tail = 0;
62382
- 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])
62383
63087
  tail++;
62384
- 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);
62385
63089
  }
62386
63090
  } catch (error) {
62387
63091
  if (error === exhausted)
@@ -62865,9 +63569,9 @@ var offsets = (toks) => {
62865
63569
  function sideDiff(fs3, bToks, sToks, d) {
62866
63570
  const bOff = offsets(bToks), sOff = offsets(sToks);
62867
63571
  const hunks = [];
62868
- let bi2 = 0, si3 = 0;
63572
+ let bi3 = 0, si3 = 0;
62869
63573
  for (const h of d.hunks) {
62870
- si3 += h.bs - bi2;
63574
+ si3 += h.bs - bi3;
62871
63575
  const ste = si3 + h.toks.length;
62872
63576
  hunks.push({
62873
63577
  bs: bOff[h.bs],
@@ -62879,7 +63583,7 @@ function sideDiff(fs3, bToks, sToks, d) {
62879
63583
  lead: !!h.lead
62880
63584
  });
62881
63585
  si3 = ste;
62882
- bi2 = h.be;
63586
+ bi3 = h.be;
62883
63587
  }
62884
63588
  const respell = /* @__PURE__ */ new Map();
62885
63589
  for (const c of d.cosmetic) respell.set(c.bi, c.tok.raw);
@@ -63192,8 +63896,8 @@ function mergeInline(o) {
63192
63896
  const byTwin = !!(L3 && L3.reverse && L3.map && R3 && R3.reverse && R3.map);
63193
63897
  const atomizers = { base: null, local: null, remote: null };
63194
63898
  if (!o.prepared && byTwin && o.moveIn) {
63195
- const within = (nodes2) => (x3) => nodes2.some((n2) => n2 === x3 || n2.nodeType === 1 && n2.contains(x3));
63196
- 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);
63197
63901
  const moved = /* @__PURE__ */ new Set();
63198
63902
  const visit = (el3) => {
63199
63903
  if (!MARK_TAGS.has(el3.tagName)) return;
@@ -63213,8 +63917,8 @@ function mergeInline(o) {
63213
63917
  }
63214
63918
  const skip = { base: /* @__PURE__ */ new Set(), local: /* @__PURE__ */ new Set(), remote: /* @__PURE__ */ new Set() };
63215
63919
  if (!o.prepared && byTwin && o.moveIn) {
63216
- const within = (nodes2) => (x3) => nodes2.some((n2) => n2 === x3 || n2.nodeType === 1 && n2.contains(x3));
63217
- 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);
63218
63922
  for (const a of flatten2(o.base, { ...o, atomize: atomizers.base }).atoms) {
63219
63923
  const lt3 = L3.map.get(a.el), rt3 = R3.map.get(a.el);
63220
63924
  const outL = !!lt3 && !inL(lt3), outR = !!rt3 && !inR(rt3);
@@ -64788,7 +65492,7 @@ function planLineage({
64788
65492
  const p = n.parentNode;
64789
65493
  return p && p.nodeType === 11 ? hostOf.get(p) || null : p;
64790
65494
  };
64791
- const inside = (x3, M3) => {
65495
+ const inside2 = (x3, M3) => {
64792
65496
  for (let n = x3; n; n = up(n)) if (n === M3) return true;
64793
65497
  return false;
64794
65498
  };
@@ -64833,7 +65537,7 @@ function planLineage({
64833
65537
  for (const o of outs) {
64834
65538
  if (o === LOST || !inTree.has(o)) return "output-not-placed";
64835
65539
  if (!M3) return "survives-elsewhere";
64836
- if (!inside(o, M3)) return "escaped";
65540
+ if (!inside2(o, M3)) return "escaped";
64837
65541
  owned.push(o);
64838
65542
  }
64839
65543
  } else if (!covered && !decided && !decidedAt(c) && !segLocal.has(c))
@@ -65030,7 +65734,7 @@ function planNativeTransfers({
65030
65734
  for (const side of ["local", "remote"]) {
65031
65735
  const removed = /* @__PURE__ */ new Map(), inserted = /* @__PURE__ */ new Map();
65032
65736
  let hasReplacement = false;
65033
- const add2 = (map2, text4, h) => {
65737
+ const add3 = (map2, text4, h) => {
65034
65738
  if (map2.has(text4)) map2.set(text4, null);
65035
65739
  else map2.set(text4, h);
65036
65740
  };
@@ -65040,10 +65744,10 @@ function planNativeTransfers({
65040
65744
  if (h.bs < h.be && h.text === "") {
65041
65745
  const text4 = B3.slice(h.bs, h.be);
65042
65746
  if (!charge(text4.length * 2)) return null;
65043
- if (/\S/.test(text4)) add2(removed, text4, h);
65747
+ if (/\S/.test(text4)) add3(removed, text4, h);
65044
65748
  } else if (h.bs === h.be && /\S/.test(h.text)) {
65045
65749
  if (!charge(h.text.length * 2)) return null;
65046
- add2(inserted, h.text, h);
65750
+ add3(inserted, h.text, h);
65047
65751
  } else if (h.bs < h.be) hasReplacement = true;
65048
65752
  }
65049
65753
  for (const [text4, deletion] of removed) {
@@ -65147,16 +65851,16 @@ function planNativeTransfers({
65147
65851
  }
65148
65852
  const maps = {};
65149
65853
  for (const side of ["local", "remote"]) {
65150
- let bi2 = 0, si3 = 0;
65854
+ let bi3 = 0, si3 = 0;
65151
65855
  const retained = [];
65152
65856
  for (const h of hunks[side]) {
65153
65857
  if (!charge(1)) return null;
65154
- if (h.bs > bi2) retained.push({ from: bi2, to: h.bs, target: si3 });
65155
- bi2 = h.be;
65858
+ if (h.bs > bi3) retained.push({ from: bi3, to: h.bs, target: si3 });
65859
+ bi3 = h.be;
65156
65860
  si3 = h.se;
65157
65861
  }
65158
- if (bi2 < flats.base.text.length)
65159
- 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 });
65160
65864
  const moved = transfers.filter((event) => event.side === side).map((event) => ({
65161
65865
  from: event.bs,
65162
65866
  to: event.be,
@@ -65518,7 +66222,7 @@ function mergeObjects(base, local, remote, opts, path, keyPath) {
65518
66222
  ...Object.keys(remote)
65519
66223
  ]);
65520
66224
  for (const key of keys) {
65521
- const merged = mergePresence(
66225
+ const merged2 = mergePresence(
65522
66226
  has3(base, key) ? base[key] : MISSING,
65523
66227
  has3(local, key) ? local[key] : MISSING,
65524
66228
  has3(remote, key) ? remote[key] : MISSING,
@@ -65526,7 +66230,7 @@ function mergeObjects(base, local, remote, opts, path, keyPath) {
65526
66230
  keySegment(path, key),
65527
66231
  childKeyPath(keyPath, key)
65528
66232
  );
65529
- if (merged !== MISSING) setKey(result, key, merged);
66233
+ if (merged2 !== MISSING) setKey(result, key, merged2);
65530
66234
  }
65531
66235
  return result;
65532
66236
  }
@@ -65617,7 +66321,7 @@ function mergeArrays(base, local, remote, opts, path, keyPath) {
65617
66321
  const baseMap = toMap(baseArr);
65618
66322
  const localMap = toMap(local);
65619
66323
  const remoteMap = toMap(remote);
65620
- const merged = /* @__PURE__ */ new Map();
66324
+ const merged2 = /* @__PURE__ */ new Map();
65621
66325
  const allIds = /* @__PURE__ */ new Set([
65622
66326
  ...baseMap.keys(),
65623
66327
  ...localMap.keys(),
@@ -65632,16 +66336,16 @@ function mergeArrays(base, local, remote, opts, path, keyPath) {
65632
66336
  segments.get(id),
65633
66337
  keyPath
65634
66338
  );
65635
- if (value !== MISSING) merged.set(id, value);
66339
+ if (value !== MISSING) merged2.set(id, value);
65636
66340
  }
65637
66341
  const order2 = [];
65638
66342
  for (const item of remote) {
65639
66343
  const id = idOf(item);
65640
- if (merged.has(id)) order2.push(id);
66344
+ if (merged2.has(id)) order2.push(id);
65641
66345
  }
65642
66346
  for (let i = 0; i < local.length; i++) {
65643
66347
  const id = idOf(local[i]);
65644
- if (!merged.has(id) || order2.includes(id)) continue;
66348
+ if (!merged2.has(id) || order2.includes(id)) continue;
65645
66349
  let insertAt = 0;
65646
66350
  for (let j3 = i - 1; j3 >= 0; j3--) {
65647
66351
  const prevIndex = order2.indexOf(idOf(local[j3]));
@@ -65652,7 +66356,7 @@ function mergeArrays(base, local, remote, opts, path, keyPath) {
65652
66356
  }
65653
66357
  order2.splice(insertAt, 0, id);
65654
66358
  }
65655
- return order2.map((id) => merged.get(id));
66359
+ return order2.map((id) => merged2.get(id));
65656
66360
  }
65657
66361
  function resolveOptions(options) {
65658
66362
  const keyPaths = /* @__PURE__ */ new Map();
@@ -65715,17 +66419,17 @@ function mergeScriptText(baseText, localText, remoteText, options = {}) {
65715
66419
  if (local === MISSING) return { text: remoteText, warnings, conflicts };
65716
66420
  if (remote === MISSING) return { text: localText, warnings, conflicts };
65717
66421
  const base = tryParse(baseText, "base");
65718
- const merged = mergeJson(base === MISSING ? void 0 : base, local, remote, {
66422
+ const merged2 = mergeJson(base === MISSING ? void 0 : base, local, remote, {
65719
66423
  ...options,
65720
66424
  onConflict: (c) => {
65721
66425
  conflicts.push(c);
65722
66426
  options.onConflict?.(c);
65723
66427
  }
65724
66428
  });
65725
- if (deepEqual(merged, remote))
66429
+ if (deepEqual(merged2, remote))
65726
66430
  return { text: remoteText, warnings, conflicts };
65727
- if (deepEqual(merged, local)) return { text: localText, warnings, conflicts };
65728
- 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 };
65729
66433
  }
65730
66434
 
65731
66435
  // node_modules/hyper-morph/src/recovery-dom.js
@@ -65840,7 +66544,7 @@ function createRecovery(ctx) {
65840
66544
  const order2 = /* @__PURE__ */ new Map();
65841
66545
  const outOwners = /* @__PURE__ */ new WeakMap();
65842
66546
  let seq = 0;
65843
- const add2 = (src, n) => {
66547
+ const add3 = (src, n) => {
65844
66548
  let list = outputs.get(src);
65845
66549
  if (!list) outputs.set(src, list = []);
65846
66550
  list.push(n);
@@ -65851,8 +66555,8 @@ function createRecovery(ctx) {
65851
66555
  if (p && !p.pinned)
65852
66556
  for (const v3 of [p.base, p.local, p.remote]) {
65853
66557
  if (!v3) continue;
65854
- if (Array.isArray(v3)) for (const x3 of v3) add2(x3, n);
65855
- else add2(v3, n);
66558
+ if (Array.isArray(v3)) for (const x3 of v3) add3(x3, n);
66559
+ else add3(v3, n);
65856
66560
  }
65857
66561
  if (isTemplate(n)) {
65858
66562
  outOwners.set(n.content, n);
@@ -66271,7 +66975,7 @@ function createRecovery(ctx) {
66271
66975
  return `${prefix}:${n}`;
66272
66976
  };
66273
66977
  const text4 = (rec, meta) => {
66274
- let U3, bs3, be3, encoding = "plain", base, local, remote, merged, anchor;
66978
+ let U3, bs3, be3, encoding = "plain", base, local, remote, merged2, anchor;
66275
66979
  const runSide = (u, k0, k1, sd, bk) => {
66276
66980
  if (!u) {
66277
66981
  const g2 = gapIn(bk, sd);
@@ -66301,7 +67005,7 @@ function createRecovery(ctx) {
66301
67005
  remote = runSide(rRun, c.rs, c.re, "remote", bRun);
66302
67006
  const mv = node ? node.nodeValue : "";
66303
67007
  const pt3 = (k2) => node ? { kind: "text", node, offset: k2 } : gapOut(bRun);
66304
- merged = link(
67008
+ merged2 = link(
66305
67009
  plain4(
66306
67010
  mv,
66307
67011
  c.ms,
@@ -66328,7 +67032,7 @@ function createRecovery(ctx) {
66328
67032
  local = whole(rec.local, p.local, "local");
66329
67033
  remote = whole(rec.remote, p.remote, "remote");
66330
67034
  const s = wholeSpanOut(el3);
66331
- merged = link(
67035
+ merged2 = link(
66332
67036
  plain4(rec.resolved, 0, rec.resolved.length, s, s),
66333
67037
  { kind: "wholeStart", node: el3 },
66334
67038
  { kind: "wholeEnd", node: el3 },
@@ -66359,7 +67063,7 @@ function createRecovery(ctx) {
66359
67063
  const v3 = rec.resolved;
66360
67064
  const pt3 = (k2) => node ? { kind: "text", node, offset: k2 } : gapOut(bRun);
66361
67065
  const s = { start: staticPoint(pt3(0)), end: staticPoint(pt3(v3.length)) };
66362
- merged = link(
67066
+ merged2 = link(
66363
67067
  plain4(v3, 0, v3.length, s, s),
66364
67068
  pt3(0),
66365
67069
  pt3(v3.length),
@@ -66395,8 +67099,8 @@ function createRecovery(ctx) {
66395
67099
  start: pt3(rawPoint(f, 0, "start")),
66396
67100
  end: pt3(rawPoint(f, f.text.length, "end"))
66397
67101
  });
66398
- const ks3 = rs3 ? measure(F3, rs3) : null, ke4 = re2 ? measure(F3, re2) : null;
66399
- 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;
66400
67104
  const E3 = Math.max(S2, ke4 === null ? F3.text.length : ke4);
66401
67105
  const s0 = pt3(rawPoint(F3, 0, "start"));
66402
67106
  return side(F3.text, S2, E3, sliceHtml(F3, S2, E3), span2, {
@@ -66434,10 +67138,10 @@ function createRecovery(ctx) {
66434
67138
  segmentGap
66435
67139
  ), De2 = ms3 === me3 ? Ds3 : mergedPoint(M3, me3, "end", segmentGap);
66436
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;
66437
- const ks2 = measure(fo3, Ds3), ke3 = measure(fo3, De2);
66438
- const s = ks2 === null ? 0 : ks2;
67141
+ const ks3 = measure(fo3, Ds3), ke3 = measure(fo3, De2);
67142
+ const s = ks3 === null ? 0 : ks3;
66439
67143
  const e19 = Math.max(s, ke3 === null ? fo3.text.length : ke3);
66440
- merged = link(
67144
+ merged2 = link(
66441
67145
  side(
66442
67146
  fo3.text,
66443
67147
  s,
@@ -66451,7 +67155,7 @@ function createRecovery(ctx) {
66451
67155
  S0,
66452
67156
  S1
66453
67157
  );
66454
- const linked = links.spans.get(merged);
67158
+ const linked = links.spans.get(merged2);
66455
67159
  linked.flat = fo3;
66456
67160
  if (!fo3.text.length) {
66457
67161
  const p = staticPoint(S0);
@@ -66477,7 +67181,7 @@ function createRecovery(ctx) {
66477
67181
  base,
66478
67182
  local,
66479
67183
  remote,
66480
- merged,
67184
+ merged: merged2,
66481
67185
  liveSpan: null,
66482
67186
  liveScope: null
66483
67187
  }
@@ -66676,10 +67380,10 @@ function createMoveDestinations({
66676
67380
  const outputAuthority = /* @__PURE__ */ new WeakMap();
66677
67381
  const attached = /* @__PURE__ */ new WeakSet();
66678
67382
  const visiting = /* @__PURE__ */ new Set();
66679
- const add2 = (source, entry) => {
67383
+ const add3 = (source, entry) => {
66680
67384
  if (!source) return;
66681
67385
  if (Array.isArray(source)) {
66682
- for (const node of source) add2(node, entry);
67386
+ for (const node of source) add3(node, entry);
66683
67387
  return;
66684
67388
  }
66685
67389
  let entries = outputs.get(source);
@@ -66691,7 +67395,7 @@ function createMoveDestinations({
66691
67395
  const stack = [source];
66692
67396
  while (stack.length) {
66693
67397
  const node = stack.pop();
66694
- add2(node, entry);
67398
+ add3(node, entry);
66695
67399
  for (const child of childrenOf(node).childNodes) stack.push(child);
66696
67400
  }
66697
67401
  };
@@ -66709,7 +67413,7 @@ function createMoveDestinations({
66709
67413
  for (const source of [p.base, p.local, p.remote])
66710
67414
  representedSubtree(source, { ...entry, kind: "unchanged" });
66711
67415
  } else if (p) {
66712
- 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);
66713
67417
  if (isElement(p.local)) {
66714
67418
  for (const child of childrenOf(p.local).children)
66715
67419
  if (ignored(child))
@@ -67324,10 +68028,10 @@ function createCrossParentConsumer({
67324
68028
  const authority = /* @__PURE__ */ new WeakMap();
67325
68029
  const outputs = /* @__PURE__ */ new WeakMap();
67326
68030
  const children2 = (node) => node.tagName === "TEMPLATE" && node.content ? node.content : node;
67327
- const add2 = (source, node) => {
68031
+ const add3 = (source, node) => {
67328
68032
  if (!source) return;
67329
68033
  if (Array.isArray(source)) {
67330
- for (const part of source) add2(part, node);
68034
+ for (const part of source) add3(part, node);
67331
68035
  return;
67332
68036
  }
67333
68037
  let list = outputs.get(source);
@@ -67341,7 +68045,7 @@ function createCrossParentConsumer({
67341
68045
  const authoritative = inherited || !!(p && remoteWins(p.remote || p.base));
67342
68046
  authority.set(node, authoritative);
67343
68047
  if (p)
67344
- 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);
67345
68049
  if (p?.pinned || p?.unchanged) return;
67346
68050
  for (const child of children2(node).childNodes)
67347
68051
  index2(child, node, authoritative);
@@ -68081,19 +68785,19 @@ function certificateGroups({
68081
68785
  budget.remaining -= cost;
68082
68786
  const edits = diffTokens(B3, S2, depth);
68083
68787
  const pairs = [];
68084
- let bi2 = 0, si3 = 0;
68788
+ let bi3 = 0, si3 = 0;
68085
68789
  for (const h of edits.hunks) {
68086
- while (bi2 < h.bs) {
68087
- if (B3[bi2].raw === S2[si3].raw) pairs.push([B3[bi2], S2[si3]]);
68088
- bi2++;
68790
+ while (bi3 < h.bs) {
68791
+ if (B3[bi3].raw === S2[si3].raw) pairs.push([B3[bi3], S2[si3]]);
68792
+ bi3++;
68089
68793
  si3++;
68090
68794
  }
68091
- bi2 = h.be;
68795
+ bi3 = h.be;
68092
68796
  si3 += h.toks.length;
68093
68797
  }
68094
- while (bi2 < B3.length && si3 < S2.length) {
68095
- if (B3[bi2].raw === S2[si3].raw) pairs.push([B3[bi2], S2[si3]]);
68096
- 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++;
68097
68801
  si3++;
68098
68802
  }
68099
68803
  return pairs;
@@ -68350,13 +69054,13 @@ function certificateGroups({
68350
69054
  if (M3.flat.atoms.length) continue;
68351
69055
  const otherUsed = reserved.get(other);
68352
69056
  charge(budget, M3.flat.text.length * 3);
68353
- let missing = "", otherKept = false;
69057
+ let missing2 = "", otherKept = false;
68354
69058
  for (let i = 0; i < M3.flat.text.length; i++) {
68355
69059
  if (SPACE2.test(M3.flat.text[i])) continue;
68356
69060
  if (otherUsed[i]) otherKept = true;
68357
- else missing += M3.flat.text[i];
69061
+ else missing2 += M3.flat.text[i];
68358
69062
  }
68359
- if (otherKept && missing === remainder) {
69063
+ if (otherKept && missing2 === remainder) {
68360
69064
  ambiguousSources ||= /* @__PURE__ */ new Set();
68361
69065
  ambiguousSources.add(source);
68362
69066
  ambiguousSources.add(other);
@@ -68366,21 +69070,21 @@ function certificateGroups({
68366
69070
  if (competing) continue;
68367
69071
  const after3 = models.get(target).flat.text;
68368
69072
  charge(budget, to3 - from + after3.length);
68369
- let bi2 = from, si3 = 0;
68370
- while (bi2 < to3 && si3 < after3.length) {
68371
- 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++;
68372
69076
  while (si3 < after3.length && SPACE2.test(after3[si3])) si3++;
68373
- if (bi2 >= to3 || si3 >= after3.length) break;
69077
+ if (bi3 >= to3 || si3 >= after3.length) break;
68374
69078
  append3(
68375
69079
  exactTransfers ||= [],
68376
69080
  source,
68377
69081
  target,
68378
- bi2,
68379
- bi2 + 1,
69082
+ bi3,
69083
+ bi3 + 1,
68380
69084
  si3,
68381
69085
  budget
68382
69086
  );
68383
- bi2++;
69087
+ bi3++;
68384
69088
  si3++;
68385
69089
  }
68386
69090
  used.fill(1, from, to3);
@@ -68419,14 +69123,14 @@ function certificateGroups({
68419
69123
  if ((!bhard || !shard) && !exactTransfers) continue;
68420
69124
  const matches = exactTransfers || [];
68421
69125
  if (bhard && shard && bhard === shard) {
68422
- let ti2 = 0, tj = 0, bi2 = 0, sj = 0;
69126
+ let ti2 = 0, tj = 0, bi3 = 0, sj = 0;
68423
69127
  while (ti2 < bt3.length && tj < st3.length) {
68424
69128
  const x3 = bt3[ti2], y2 = st3[tj];
68425
- while (bi2 < x3.raw.length && SPACE2.test(x3.raw[bi2])) bi2++;
69129
+ while (bi3 < x3.raw.length && SPACE2.test(x3.raw[bi3])) bi3++;
68426
69130
  while (sj < y2.raw.length && SPACE2.test(y2.raw[sj])) sj++;
68427
- if (bi2 === x3.raw.length) {
69131
+ if (bi3 === x3.raw.length) {
68428
69132
  ti2++;
68429
- bi2 = 0;
69133
+ bi3 = 0;
68430
69134
  continue;
68431
69135
  }
68432
69136
  if (sj === y2.raw.length) {
@@ -68444,12 +69148,12 @@ function certificateGroups({
68444
69148
  matches,
68445
69149
  x3.unit,
68446
69150
  y2.unit,
68447
- x3.from + bi2,
68448
- x3.from + bi2 + 1,
69151
+ x3.from + bi3,
69152
+ x3.from + bi3 + 1,
68449
69153
  y2.from + sj,
68450
69154
  budget
68451
69155
  );
68452
- bi2++;
69156
+ bi3++;
68453
69157
  sj++;
68454
69158
  }
68455
69159
  } else if (bhard && shard) {
@@ -68978,18 +69682,18 @@ function certifiedOrigins({
68978
69682
  if (depth < 1) throw exhausted;
68979
69683
  charge(4 * (depth + 1) * (size + depth + 1));
68980
69684
  const edits = diffTokens(B3, S2, depth);
68981
- let bi2 = 0, si3 = 0;
69685
+ let bi3 = 0, si3 = 0;
68982
69686
  const equal = () => {
68983
- const x3 = B3[bi2++], y2 = S2[si3++];
69687
+ const x3 = B3[bi3++], y2 = S2[si3++];
68984
69688
  charge(x3.len);
68985
69689
  if (x3.raw === y2.raw) append3(runs, x3.from, x3.to, y2.from, "retained");
68986
69690
  };
68987
69691
  for (const h of edits.hunks) {
68988
- while (bi2 < h.bs) equal();
68989
- bi2 = h.be;
69692
+ while (bi3 < h.bs) equal();
69693
+ bi3 = h.be;
68990
69694
  si3 += h.toks.length;
68991
69695
  }
68992
- while (bi2 < B3.length && si3 < S2.length) equal();
69696
+ while (bi3 < B3.length && si3 < S2.length) equal();
68993
69697
  };
68994
69698
  const compile4 = (side) => {
68995
69699
  const selected = certificates.filter(
@@ -68997,7 +69701,7 @@ function certifiedOrigins({
68997
69701
  );
68998
69702
  if (!selected.length) return null;
68999
69703
  const anchors = [];
69000
- const add2 = (run, models, kind) => {
69704
+ const add3 = (run, models, kind) => {
69001
69705
  if (!sets[0].has(run.source) || !sets[side].has(run.target)) return;
69002
69706
  const bp = project2(models.get(run.source).flat, flats[0]);
69003
69707
  const sp = project2(models.get(run.target).flat, flats[side]);
@@ -69012,9 +69716,9 @@ function certifiedOrigins({
69012
69716
  for (const cert of selected) {
69013
69717
  if (!retainedArrays.has(cert.retained)) {
69014
69718
  retainedArrays.add(cert.retained);
69015
- for (const run of cert.retained) add2(run, cert.models, "retained");
69719
+ for (const run of cert.retained) add3(run, cert.models, "retained");
69016
69720
  }
69017
- for (const run of cert.runs) add2(run, cert.models, "transfer");
69721
+ for (const run of cert.runs) add3(run, cert.models, "transfer");
69018
69722
  }
69019
69723
  anchors.sort((a, b2) => {
69020
69724
  charge(1);
@@ -69031,15 +69735,15 @@ function certifiedOrigins({
69031
69735
  } else ordered.push(run);
69032
69736
  }
69033
69737
  const runs = [];
69034
- let bi2 = 0, si3 = 0;
69738
+ let bi3 = 0, si3 = 0;
69035
69739
  for (const run of ordered) {
69036
69740
  if (run.target < si3) throw exhausted;
69037
- gap(runs, side, bi2, run.from, si3, run.target);
69741
+ gap(runs, side, bi3, run.from, si3, run.target);
69038
69742
  runs.push(run);
69039
- bi2 = run.to;
69743
+ bi3 = run.to;
69040
69744
  si3 = run.target + run.to - run.from;
69041
69745
  }
69042
- 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);
69043
69747
  const result = compileOccurrenceMap({
69044
69748
  base: flats[0],
69045
69749
  side: flats[side],
@@ -71394,7 +72098,7 @@ function merge32(base, local, remote, options = {}) {
71394
72098
  }
71395
72099
 
71396
72100
  // src/page/merge.js
71397
- var TEXT2 = /* @__PURE__ */ new Set(["paragraph", "heading", "list_item", "callout", "code_block", "toggle"]);
72101
+ var TEXT2 = /* @__PURE__ */ new Set(["paragraph", "heading", "list_item", "callout", "quote", "code_block", "toggle"]);
71398
72102
  var same2 = (a, b2) => canon(a) === canon(b2);
71399
72103
  function inlineOf2(item, doc) {
71400
72104
  const article = doc.createElement("article");
@@ -71455,10 +72159,10 @@ function mergePageModels(base, current, incoming, { doc, merge3: merge33, mergeJ
71455
72159
  }
71456
72160
  const res = merge33(inlineOf2(was, doc), inlineOf2(l, doc), inlineOf2(r44, doc));
71457
72161
  for (const k2 of res.conflicts) conflicts.push({ id, kind: "text", local: k2.local?.textContent ?? null, remote: k2.remote?.textContent ?? null });
71458
- const [merged] = parseModel(res.root, { seed: "", known: /* @__PURE__ */ new Map() });
72162
+ const [merged2] = parseModel(res.root, { seed: "", known: /* @__PURE__ */ new Map() });
71459
72163
  for (const t of [c2.get(id), i2.get(id)]) {
71460
- t.c = merged.c;
71461
- if (merged.m) t.m = merged.m;
72164
+ t.c = merged2.c;
72165
+ if (merged2.m) t.m = merged2.m;
71462
72166
  else delete t.m;
71463
72167
  }
71464
72168
  }
@@ -71540,7 +72244,7 @@ function rebasePage({ storedHtml, state, incomingHtml, baseHtml, createDocument
71540
72244
  const base = articleOf(baseHtml, doc);
71541
72245
  const stored = articleOf(storedHtml, doc);
71542
72246
  if (!incoming || !base || !stored) return null;
71543
- const merged = mergePageModels(
72247
+ const merged2 = mergePageModels(
71544
72248
  parseModel(base.article, { seed: rev, known }),
71545
72249
  parseModel(stored.article, { seed: state.rev, known }),
71546
72250
  parseModel(incoming.article, { seed: rev, known }),
@@ -71548,13 +72252,13 @@ function rebasePage({ storedHtml, state, incomingHtml, baseHtml, createDocument
71548
72252
  );
71549
72253
  const fallbackOf = (id) => typeof blocks[id]?.artifact?.fallbackHtml === "string" ? blocks[id].artifact.fallbackHtml : "";
71550
72254
  const inner = `
71551
- ${renderModel(merged.items, { fallbackOf, clean: fragmentCleaner(doc) })}
72255
+ ${renderModel(merged2.items, { fallbackOf, clean: fragmentCleaner(doc) })}
71552
72256
  `;
71553
72257
  const [innerStart, innerEnd] = incoming.inner;
71554
72258
  const open = stampOpen(incomingHtml, incoming.startTag, state.rev);
71555
72259
  const body = incomingHtml.slice(0, incoming.startTag.startOffset) + open + inner + incomingHtml.slice(innerEnd);
71556
72260
  const html3 = withPageFormatFloor(body, Math.max(pageFormatFloor(storedHtml), pageFormatFloor(incomingHtml)));
71557
- return { html: html3, conflicts: merged.conflicts };
72261
+ return { html: html3, conflicts: merged2.conflicts };
71558
72262
  }
71559
72263
  function closestBase(candidates, incomingHtml, createDocument) {
71560
72264
  if (candidates.length <= 1) return candidates[0] ?? null;
@@ -71930,6 +72634,163 @@ function pageTransitionState(transition, clientId) {
71930
72634
  // src/server/rooms/live-data-rooms.js
71931
72635
  var import_node_crypto3 = require("node:crypto");
71932
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
71933
72794
  var byteLength = (text4) => Buffer.byteLength(text4, "utf8");
71934
72795
  var sizeOf = (value) => byteLength(serializeLive(value));
71935
72796
  var LIVE_LIMITS = Object.freeze({
@@ -71948,6 +72809,7 @@ var LIVE_LIMITS = Object.freeze({
71948
72809
  movesBytes: 1024 * 1024
71949
72810
  });
71950
72811
  var PAGE4 = /^page(\.[0-9]+)?$/;
72812
+ var COMPACTOR = "compactor";
71951
72813
  var isContainer2 = (v3) => v3 !== null && typeof v3 === "object";
71952
72814
  function seedStores(html3, { pageOnly = false, heldBytes = 0, heldCount = 0 } = {}) {
71953
72815
  const stores = /* @__PURE__ */ new Map();
@@ -72041,7 +72903,32 @@ var PersistentReservationError = class extends Error {
72041
72903
  this.code = code;
72042
72904
  }
72043
72905
  };
72044
- 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
+ };
72045
72932
  const rooms = /* @__PURE__ */ new Map();
72046
72933
  const pageReservations = /* @__PURE__ */ new Map();
72047
72934
  const reservedNodes = /* @__PURE__ */ new Map();
@@ -72062,7 +72949,8 @@ function createRooms({ now = Date.now, newEpoch = import_node_crypto3.randomUUID
72062
72949
  lastSentAt: /* @__PURE__ */ new Map(),
72063
72950
  seen: /* @__PURE__ */ new Map(),
72064
72951
  emptySince: null,
72065
- ...inspectPage(html3).kind === "yjs" && { pageTransition: makePageTransition() }
72952
+ ...inspectPage(html3).kind === "yjs" && { pageTransition: makePageTransition() },
72953
+ compaction: hostMode(inspectPage(html3).kind === "yjs")
72066
72954
  });
72067
72955
  const roomBytes = (room) => {
72068
72956
  let total = 0;
@@ -72070,10 +72958,91 @@ function createRooms({ now = Date.now, newEpoch = import_node_crypto3.randomUUID
72070
72958
  return total;
72071
72959
  };
72072
72960
  const heldBy = (room) => {
72073
- let total = (room.receiptBytes ?? 0) + (room.pageTransition?.bytes ?? 0);
72961
+ let total = (room.receiptBytes ?? 0) + (room.pageTransition?.bytes ?? 0) + (room.compaction?.job?.reserved ?? 0);
72074
72962
  for (const s of room.stores.values()) total += s.bytes + s.logBytes;
72075
72963
  return total;
72076
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
+ };
72077
73046
  const pageSource = (key, nodeId) => {
72078
73047
  if (nodeId == null) throw new PageConversionError("invalid-document");
72079
73048
  if (pageReservations.has(key) || persistentReservations.has(key) || reservedNodes.has(String(nodeId))) throw new PageConversionError("page-converting");
@@ -72143,62 +73112,77 @@ function createRooms({ now = Date.now, newEpoch = import_node_crypto3.randomUUID
72143
73112
  if (tag.name !== "page" || !isYPageValue(value)) continue;
72144
73113
  } else if (isYPageValue(value, { complete: false })) continue;
72145
73114
  }
73115
+ const host = Boolean(room.compaction && tag.name === "page" && room.pageTransition?.format === "yjs");
72146
73116
  const before2 = store.landed;
72147
73117
  const base = baseOf(room, store, tag.at);
72148
73118
  const stamped = placed(room, store, tag.at) && tag.at.hash === textHash(serializeLive(value));
72149
- if (base < store.floor) {
73119
+ if (!host && base < store.floor) {
72150
73120
  store.landed = -1;
72151
73121
  if (before2 !== -1) landed.push(tag.name);
72152
73122
  continue;
72153
73123
  }
72154
73124
  const by = restored ? null : provenBy(room, tag.name, tag, stamped);
72155
73125
  const frames = tag.at?.epoch === room.epoch ? frameSet(by) : [];
72156
- const ancestry = descendants(by);
72157
- const own = (entry) => {
72158
- if (!by) return false;
72159
- if (!entry.merge) return contains2(frames, entry.from, entry.n);
72160
- const p = entry.provenance;
72161
- return by.v === 2 && p && p.at.epoch === tag.at.epoch && p.at.seq === tag.at.seq && contains2(ancestry, ...p.capture);
72162
- };
72163
- if (stamped) store.inFile.clear();
72164
- const entries = [];
72165
- for (const entry of store.log) {
72166
- if (entry.seq <= base) continue;
72167
- if (own(entry)) store.inFile.add(entry.seq);
72168
- else if (stamped || !store.inFile.has(entry.seq)) entries.push(entry);
72169
- }
72170
- for (const entry of entries) {
72171
- for (const op of entry.ops) {
72172
- try {
72173
- checkOp(value, op);
72174
- value = applyOp(value, op);
72175
- } catch {
72176
- }
72177
- }
72178
- }
72179
- const text4 = serializeLive(value);
72180
- if (text4 !== serializeLive(store.value)) {
72181
- const bytes = byteLength(text4);
72182
- 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") {
72183
73129
  room.stores.delete(tag.name);
72184
73130
  valueChanged = true;
72185
73131
  continue;
72186
73132
  }
72187
- const ops = diffOps(store.value, value);
72188
- store.value = value;
72189
- store.bytes = bytes;
72190
- room.seq += 1;
72191
- store.last = room.seq;
72192
- const provenance = by?.v === 2 ? { at: { epoch: tag.at.epoch, seq: tag.at.seq }, by: by.frames, capture: by.capture } : null;
72193
- const logged = byteLength(JSON.stringify(provenance ? { ops, provenance } : ops));
72194
- store.log.push({ seq: room.seq, ops, bytes: logged, merge: true, ...provenance && { provenance } });
72195
- store.inFile.add(room.seq);
72196
- store.logBytes += logged;
72197
- evict(store);
72198
- 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);
72199
73185
  }
72200
- store.landed = entries.length ? base : store.last;
72201
- if (store.landed !== before2) landed.push(tag.name);
72202
73186
  if (by?.v === 2) {
72203
73187
  for (const [client, ranges] of frames) {
72204
73188
  if (!saveReceipt(room, tag.name + "\n" + client, ranges, store.last, LIVE_LIMITS.receipts, pageReservations.get(key)?.receipts)) {
@@ -72269,6 +73253,7 @@ function createRooms({ now = Date.now, newEpoch = import_node_crypto3.randomUUID
72269
73253
  reservation.result = null;
72270
73254
  return null;
72271
73255
  }
73256
+ if (room.compaction?.job) endJob(room.compaction.job);
72272
73257
  const before2 = heldBy(room);
72273
73258
  const { stores, transition } = reservation.target;
72274
73259
  for (const name of room.stores.keys()) if (PAGE4.test(name)) room.stores.delete(name);
@@ -72285,6 +73270,7 @@ function createRooms({ now = Date.now, newEpoch = import_node_crypto3.randomUUID
72285
73270
  bytes += store.bytes;
72286
73271
  }
72287
73272
  room.pageTransition = transition;
73273
+ if (hostLimits) room.compaction = hostMode(transition.format === "yjs");
72288
73274
  reservation.target = null;
72289
73275
  used += heldBy(room) - before2 - reservation.budget;
72290
73276
  reservation.budget = 0;
@@ -72364,7 +73350,7 @@ function createRooms({ now = Date.now, newEpoch = import_node_crypto3.randomUUID
72364
73350
  if (!store || store.ephemeral) throw new PersistentReservationError("invalid-target");
72365
73351
  }
72366
73352
  const currentHeld = heldBy(record5.room);
72367
- const projected = structuredClone(record5.room);
73353
+ const projected = projectRoom(record5.room);
72368
73354
  reconcileFile(projected, record5.key, html3, {});
72369
73355
  for (const [name, store] of record5.room.stores) {
72370
73356
  if (!store.ephemeral && !projected.stores.has(name)) throw new PersistentReservationError("budget");
@@ -72543,6 +73529,8 @@ function createRooms({ now = Date.now, newEpoch = import_node_crypto3.randomUUID
72543
73529
  }
72544
73530
  const nKey = frame.name + "\n" + clientId;
72545
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;
72546
73534
  if (receiptHas(last2, frame.n)) return { duplicate: true, seq: frame.n <= last2.n ? last2.seq : last2.savedSeq, epoch: room.epoch };
72547
73535
  if ((room.retiredReceipts?.get(nKey) ?? 0) > (frame.receiptGeneration ?? 0)) return { error: "receipt-expired" };
72548
73536
  let victim = null;
@@ -72590,8 +73578,13 @@ function createRooms({ now = Date.now, newEpoch = import_node_crypto3.randomUUID
72590
73578
  }
72591
73579
  if (bytes > LIVE_LIMITS.storeBytes || roomBytes(room) - store.bytes + bytes > LIVE_LIMITS.roomBytes) {
72592
73580
  undo();
73581
+ if (admission) return admission.over(bytes);
72593
73582
  return { error: "too-large" };
72594
73583
  }
73584
+ if (admission && bytes > admission.limit) {
73585
+ undo();
73586
+ return admission.over(bytes);
73587
+ }
72595
73588
  const logged = done.length ? byteLength(JSON.stringify(ops)) : 0;
72596
73589
  const grows = done.length ? bytes - store.bytes + logAfter(store, logged) - store.logBytes : 0;
72597
73590
  const retiredBytes = victim === null ? 0 : receiptBytes(room.lastN.get(victim));
@@ -72615,18 +73608,36 @@ function createRooms({ now = Date.now, newEpoch = import_node_crypto3.randomUUID
72615
73608
  room.lastSentAt.set(clientId, now());
72616
73609
  room.seen.set(clientId, now());
72617
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);
72618
73612
  const writerGone = room.writer && connected && !connected.includes(room.writer);
72619
73613
  if ((!room.writer || writerGone) && (!connected || connected.includes(clientId))) room.writer = clientId;
72620
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 } };
72621
73615
  },
72622
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). */
72623
- state(room, clientId = null, since = void 0) {
73617
+ state(room, clientId = null, since = void 0, { compaction: capable } = {}) {
72624
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)));
72625
73625
  for (const [name, s] of room.stores) {
73626
+ if (hidden && name === "page") continue;
72626
73627
  const seen = {};
72627
73628
  const mine = clientId ? room.lastN.get(name + "\n" + clientId) : null;
72628
73629
  if (mine) seen[clientId] = mine.n;
72629
- 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
+ };
72630
73641
  }
72631
73642
  const provenance = { provenanceVersion: 2, receiptGeneration: room.receiptGeneration ?? 0 };
72632
73643
  if (room.pageTransition) {
@@ -72664,7 +73675,10 @@ function createRooms({ now = Date.now, newEpoch = import_node_crypto3.randomUUID
72664
73675
  if (room.writer !== clientId) return { writerChanged: false, writer: room.writer };
72665
73676
  let best = null;
72666
73677
  let bestAt = -1;
72667
- 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) {
72668
73682
  const at2 = room.lastSentAt.get(id) ?? 0;
72669
73683
  if (at2 > bestAt) {
72670
73684
  best = id;
@@ -72685,6 +73699,9 @@ function createRooms({ now = Date.now, newEpoch = import_node_crypto3.randomUUID
72685
73699
  */
72686
73700
  sweep(connectedOf = () => [], { mayExpire = () => true } = {}) {
72687
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
+ }
72688
73705
  for (const [key, room] of rooms) {
72689
73706
  if (!roomIsDirty(room) && mayExpire(room) && !pageReservations.has(key) && !persistentReservations.has(key) && room.emptySince !== null && t - room.emptySince >= LIVE_LIMITS.retainMs) {
72690
73707
  used -= heldBy(room);
@@ -72732,6 +73749,120 @@ function createRooms({ now = Date.now, newEpoch = import_node_crypto3.randomUUID
72732
73749
  }
72733
73750
  return changed;
72734
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
+ },
72735
73866
  /** Every room's key. */
72736
73867
  keys() {
72737
73868
  return [...rooms.keys()];
@@ -72746,6 +73877,117 @@ function createRooms({ now = Date.now, newEpoch = import_node_crypto3.randomUUID
72746
73877
  };
72747
73878
  }
72748
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
+
72749
73991
  // src/server/checkpoint/index.js
72750
73992
  var checkpoint_exports = {};
72751
73993
  __export(checkpoint_exports, {
@@ -72757,11 +73999,12 @@ __export(checkpoint_exports, {
72757
73999
 
72758
74000
  // src/page/document-title.js
72759
74001
  var UNTITLED = "Untitled";
72760
- function documentTitle(items, { custom = false, currentTitle = "" } = {}) {
74002
+ function documentTitle(items, { custom = false, currentTitle = "", keepWithoutHeading = false } = {}) {
72761
74003
  if (custom) return currentTitle;
72762
74004
  const first2 = items.find(
72763
74005
  (item) => item.t === "heading" && (item.level ?? 2) === 1 && item.parent == null
72764
74006
  );
74007
+ if (!first2 && keepWithoutHeading && !["", UNTITLED].includes(String(currentTitle).trim())) return currentTitle;
72765
74008
  return String(first2?.c ?? "").replace(/[\s\uFFFC]+/gu, " ").trim() || UNTITLED;
72766
74009
  }
72767
74010
 
@@ -72877,8 +74120,8 @@ function titleTextOf(node) {
72877
74120
  function titleAt(placement) {
72878
74121
  const head = placement.head?.sourceCodeLocation;
72879
74122
  if (head?.startTag) return head.startTag.endOffset;
72880
- const inside = (placement.head?.childNodes ?? []).find((node) => node.sourceCodeLocation);
72881
- if (inside) return inside.sourceCodeLocation.startOffset;
74123
+ const inside2 = (placement.head?.childNodes ?? []).find((node) => node.sourceCodeLocation);
74124
+ if (inside2) return inside2.sourceCodeLocation.startOffset;
72882
74125
  const body = placement.body?.sourceCodeLocation;
72883
74126
  if (body?.startTag) return body.startTag.startOffset;
72884
74127
  const first2 = (placement.body?.childNodes ?? []).find((node) => node.sourceCodeLocation);
@@ -72895,8 +74138,8 @@ function titleEdit(placement, title) {
72895
74138
  }
72896
74139
  function holdsEdit(found, blocks, doc) {
72897
74140
  const current = readBack(blocks, doc);
72898
- const merged = mergePageModels(found.baseItems, current, found.parsed, { doc, merge3: merge32, mergeJson });
72899
- 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);
72900
74143
  }
72901
74144
  var lastAdoption = { html: null, answer: false };
72902
74145
  function needsAdoption(html3, { createDocument }) {
@@ -72973,7 +74216,7 @@ function renderCheckpoint(currentHtml, capture, { createDocument, recovery = fal
72973
74216
  edits.push({ start: articleLoc.startTag.startOffset, end: articleLoc.startTag.endOffset, text: articleStart.slice(0, -1) + rev + ">" });
72974
74217
  edits.push({ start: articleLoc.startTag.endOffset, end: articleLoc.endTag.startOffset, text: rendered.html });
72975
74218
  if (!customTitleOf(placement.titleModes)) {
72976
- const edit = titleEdit(placement, documentTitle(rendered.model));
74219
+ const edit = titleEdit(placement, documentTitle(rendered.model, { currentTitle: titleTextOf(placement.title), keepWithoutHeading: true }));
72977
74220
  if (edit) edits.push(edit);
72978
74221
  }
72979
74222
  return { kind: "ok", html: replace(currentHtml, edits), revision: rendered.rev };
@@ -72986,7 +74229,7 @@ function isCheckpointCurrent(currentHtml, capture) {
72986
74229
  const rendered = renderBlocks(decoded.blocks);
72987
74230
  const articleLoc = placement.article.sourceCodeLocation;
72988
74231
  if (attr3(placement.article, "data-rev") !== rendered.rev || currentHtml.slice(articleLoc.startTag.endOffset, articleLoc.endTag.startOffset) !== rendered.html) return false;
72989
- if (!customTitleOf(placement.titleModes) && titleTextOf(placement.title) !== documentTitle(rendered.model)) return false;
74232
+ if (!customTitleOf(placement.titleModes) && titleTextOf(placement.title) !== documentTitle(rendered.model, { currentTitle: titleTextOf(placement.title), keepWithoutHeading: true })) return false;
72990
74233
  return capture.stores.every((store) => {
72991
74234
  const node = placement.tags.get(store.name);
72992
74235
  const loc = node.sourceCodeLocation;