@panphora/clayjs 1.15.1 → 1.16.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 (506) hide show
  1. package/README.md +4 -5
  2. package/THIRD-PARTY-NOTICES.md +16 -0
  3. package/compat/highlight-11.9.0.min.js +1213 -0
  4. package/compat/highlight-LICENSE +29 -0
  5. package/compat/journal-assets.lock.json +22 -0
  6. package/compat/overtype-2.6.1.min.js +116 -0
  7. package/compat/overtype-LICENSE +21 -0
  8. package/dist/all.js +90 -0
  9. package/dist/clay-dom.js +84 -0
  10. package/dist/clay-events.js +103 -0
  11. package/dist/clay-internals.js +85 -0
  12. package/dist/clay-options.js +93 -0
  13. package/dist/clay-router.js +98 -0
  14. package/dist/clay-ui.js +95 -0
  15. package/dist/clay-utils.js +84 -0
  16. package/dist/clay.js +146 -0
  17. package/dist/clay.standalone.js +83090 -58706
  18. package/dist/m/attrs/add-from-T5LJXFFI.js +1 -0
  19. package/dist/m/attrs/onaftersave-OKSWEJQF.js +1 -0
  20. package/dist/m/attrs/refetch-on-save-NWPPXOCZ.js +1 -0
  21. package/dist/m/attrs/save-freeze-FUP4Q4X3.js +1 -0
  22. package/dist/m/c-2AZDZWCK.js +1 -0
  23. package/dist/m/c-2JL6E75N.js +1 -0
  24. package/dist/m/c-2M73252O.js +1 -0
  25. package/dist/m/c-2SPVQSHC.js +1 -0
  26. package/dist/m/c-33HUYEDI.js +1 -0
  27. package/dist/m/c-33JJ6CBX.js +2 -0
  28. package/dist/m/c-35NBGMZB.js +1 -0
  29. package/dist/m/c-3GJ4SDE2.js +1 -0
  30. package/dist/m/c-3IQRECYS.js +1 -0
  31. package/dist/m/c-3OWDMNJR.js +2 -0
  32. package/dist/m/c-46XYM55L.js +1 -0
  33. package/dist/m/c-4B6H4G5V.js +1 -0
  34. package/dist/m/c-4DRMS4QG.js +9 -0
  35. package/dist/m/c-4FFHZM32.js +1 -0
  36. package/dist/m/c-4JZDZFF6.js +1 -0
  37. package/dist/m/c-4L3BTFRK.js +1 -0
  38. package/dist/m/c-4Q2XTQ2N.js +2 -0
  39. package/dist/m/c-4WKFKEKF.js +1 -0
  40. package/dist/m/c-4YSCRICO.js +1 -0
  41. package/dist/m/c-54RCDCBU.js +1 -0
  42. package/dist/m/c-5M4YEKCX.js +4 -0
  43. package/dist/m/c-5R4PTRG2.js +1 -0
  44. package/dist/m/c-5V3MOVJT.js +1 -0
  45. package/dist/m/c-5VYOWDTI.js +1 -0
  46. package/dist/m/c-5Y6TNX5W.js +34 -0
  47. package/dist/m/c-5YIHJ3TJ.js +1 -0
  48. package/dist/m/c-66O32MV3.js +28 -0
  49. package/dist/m/c-6HMB24EV.js +1 -0
  50. package/dist/m/c-7DJDKPGL.js +1 -0
  51. package/dist/m/c-7O6AFR65.js +1 -0
  52. package/dist/m/c-7SWMYKAI.js +1 -0
  53. package/dist/m/c-7VGZ7RU5.js +1 -0
  54. package/dist/m/c-A7LS5UZW.js +1 -0
  55. package/dist/m/c-ANQTJ3B5.js +2 -0
  56. package/dist/m/c-AQLFEATB.js +1 -0
  57. package/dist/m/c-AYVOREBE.js +1 -0
  58. package/dist/m/c-B2ZXPOS3.js +3 -0
  59. package/dist/m/c-BBVGTQG7.js +1 -0
  60. package/dist/m/c-BMIZKMPV.js +1 -0
  61. package/dist/m/c-BTDI4Y23.js +1 -0
  62. package/dist/m/c-BWFVSBDF.js +1 -0
  63. package/dist/m/c-BYTKL6UX.js +1 -0
  64. package/dist/m/c-CFHW5AMY.js +6 -0
  65. package/dist/m/c-CJZSLMVQ.js +1 -0
  66. package/dist/m/c-CYWLPPUS.js +1 -0
  67. package/dist/m/c-CZUSOB7V.js +1 -0
  68. package/dist/m/c-DBE6ORSI.js +1 -0
  69. package/dist/m/c-DCFSEJZG.js +1 -0
  70. package/dist/m/c-DNZ5IFM6.js +1 -0
  71. package/dist/m/c-EDHUR4MX.js +1 -0
  72. package/dist/m/c-EJTGYSLN.js +1 -0
  73. package/dist/m/c-EY6UOM54.js +1 -0
  74. package/dist/m/c-F3CKJTJS.js +1 -0
  75. package/dist/m/c-F7Y6FLPY.js +1 -0
  76. package/dist/m/c-FA4DZVTC.js +1 -0
  77. package/dist/m/c-FILLTJA7.js +1 -0
  78. package/dist/m/c-G2BUZITR.js +1 -0
  79. package/dist/m/c-GB3JTV6E.js +1 -0
  80. package/dist/m/c-GBGWXTX4.js +1 -0
  81. package/dist/m/c-GHBCCVG4.js +1 -0
  82. package/dist/m/c-GJAEGGXY.js +1 -0
  83. package/dist/m/c-GOWBDM6J.js +1 -0
  84. package/dist/m/c-GQ6F6IDK.js +1 -0
  85. package/dist/m/c-H4LG442Q.js +1 -0
  86. package/dist/m/c-HA6INT6J.js +1 -0
  87. package/dist/m/c-HPURYVZS.js +2 -0
  88. package/dist/m/c-HRDCD3WN.js +67 -0
  89. package/dist/m/c-HT33EQRN.js +1 -0
  90. package/dist/m/c-HVYXIS72.js +1 -0
  91. package/dist/m/c-IB52R237.js +1 -0
  92. package/dist/m/c-IJUK2GPW.js +1 -0
  93. package/dist/m/c-IKWNE4R4.js +1 -0
  94. package/dist/m/c-IU3IYEU6.js +1 -0
  95. package/dist/m/c-IZ2EBRAJ.js +1 -0
  96. package/dist/m/c-J7CA54IP.js +1 -0
  97. package/dist/m/c-JAX2667S.js +6 -0
  98. package/dist/m/c-KI7M4AY3.js +1 -0
  99. package/dist/m/c-KIPQJX4B.js +1 -0
  100. package/dist/m/c-KKWLDOPM.js +1 -0
  101. package/dist/m/c-KR4UW4KW.js +1 -0
  102. package/dist/m/c-KY3VJGUA.js +8 -0
  103. package/dist/m/c-L4WQSC27.js +1 -0
  104. package/dist/m/c-LFPHCXY3.js +1 -0
  105. package/dist/m/c-LR4CGEPT.js +91 -0
  106. package/dist/m/c-LRPUO2MX.js +1 -0
  107. package/dist/m/c-LTGMXXKO.js +1 -0
  108. package/dist/m/c-LXENEBV7.js +1 -0
  109. package/dist/m/c-LZJPNR2W.js +1 -0
  110. package/dist/m/c-MMUIUUZG.js +2 -0
  111. package/dist/m/c-MTQHWQC3.js +1 -0
  112. package/dist/m/c-N326R2JD.js +1 -0
  113. package/dist/m/c-N7JPUPGC.js +1 -0
  114. package/dist/m/c-NMJRXKPC.js +8 -0
  115. package/dist/m/c-NRPJEVJS.js +1 -0
  116. package/dist/m/c-NUHP2XDB.js +1 -0
  117. package/dist/m/c-NZMNXVF6.js +1 -0
  118. package/dist/m/c-OCSZ4QGN.js +1 -0
  119. package/dist/m/c-OIBUTDXI.js +1 -0
  120. package/dist/m/c-OIDRZKAF.js +1 -0
  121. package/dist/m/c-OYTFP5QN.js +1 -0
  122. package/dist/m/c-P7KNDG34.js +1 -0
  123. package/dist/m/c-PPOSCAQD.js +1 -0
  124. package/dist/m/c-PQ5LK6QE.js +993 -0
  125. package/dist/m/c-PZ4XEPUP.js +2 -0
  126. package/dist/m/c-QHIWXHRO.js +1 -0
  127. package/dist/m/c-QHWJ5ZIJ.js +1 -0
  128. package/dist/m/c-QIX5BJYN.js +1 -0
  129. package/dist/m/c-QNKREOL6.js +1 -0
  130. package/dist/m/c-QQHEX6HA.js +1 -0
  131. package/dist/m/c-R7RMANJI.js +9 -0
  132. package/dist/m/c-RI4NT75Y.js +1 -0
  133. package/dist/m/c-RM7J7BV2.js +1 -0
  134. package/dist/m/c-RUJKSUQW.js +1 -0
  135. package/dist/m/c-RVMWGXEJ.js +1 -0
  136. package/dist/m/c-S7H2DRCB.js +1 -0
  137. package/dist/m/c-S7LK4KUE.js +1 -0
  138. package/dist/m/c-SGCCC4FW.js +25 -0
  139. package/dist/m/c-SGIA4IEQ.js +188 -0
  140. package/dist/m/c-SWRJFCNN.js +1 -0
  141. package/dist/m/c-T4VO4OCB.js +1 -0
  142. package/dist/m/c-TCCA5BZN.js +2 -0
  143. package/dist/m/c-TQEMVJCS.js +1 -0
  144. package/dist/m/c-TQZ2JYHD.js +1 -0
  145. package/dist/m/c-TR6RMDQ7.js +3 -0
  146. package/dist/m/c-TRS6TM6O.js +1 -0
  147. package/dist/m/c-UGHH4MB3.js +1 -0
  148. package/dist/m/c-UKHTLWUW.js +1 -0
  149. package/dist/m/c-UL2YUY52.js +1 -0
  150. package/dist/m/c-UNN7LWCT.js +1 -0
  151. package/dist/m/c-UXBMRDZB.js +235 -0
  152. package/dist/m/c-V7PZZRG7.js +1 -0
  153. package/dist/m/c-VAK7SG37.js +1 -0
  154. package/dist/m/c-VDSS4K3Z.js +1 -0
  155. package/dist/m/c-VFX45IZQ.js +1 -0
  156. package/dist/m/c-VHNSBD2M.js +1 -0
  157. package/dist/m/c-VKEDWYDF.js +1 -0
  158. package/dist/m/c-VL52ADDR.js +1 -0
  159. package/dist/m/c-WN5AY3OZ.js +1 -0
  160. package/dist/m/c-WNYBLIOZ.js +1 -0
  161. package/dist/m/c-WRBKEJD4.js +1 -0
  162. package/dist/m/c-WWDBYXLK.js +1 -0
  163. package/dist/m/c-WYFDLITL.js +1 -0
  164. package/dist/m/c-XN6MBKI6.js +67 -0
  165. package/dist/m/c-XNNW2CWK.js +1 -0
  166. package/dist/m/c-XPELB6E5.js +1 -0
  167. package/dist/m/c-XQXZAO7N.js +1 -0
  168. package/dist/m/c-Y6USGTS5.js +5 -0
  169. package/dist/m/c-YDH7Q3NY.js +1 -0
  170. package/dist/m/c-YG2NJYS6.js +135 -0
  171. package/dist/m/c-Z36J63PP.js +1 -0
  172. package/dist/m/c-Z4VRC7GU.js +7 -0
  173. package/dist/m/c-Z6K52OLP.js +19 -0
  174. package/dist/m/c-ZDY2MDAA.js +21 -0
  175. package/dist/m/c-ZE46QDIH.js +1 -0
  176. package/dist/m/c-ZUCOKOHT.js +1 -0
  177. package/dist/m/core/admin-attrs-VGNLAUDK.js +1 -0
  178. package/dist/m/core/autosave-E4PEFPZ6.js +1 -0
  179. package/dist/m/core/conflict-notice-VQ6Y64PH.js +1 -0
  180. package/dist/m/core/draft-mode-WSQAT67S.js +1 -0
  181. package/dist/m/core/host-permission-XN3K2IW3.js +1 -0
  182. package/dist/m/core/is-edit-mode-JXHDVGUL.js +1 -0
  183. package/dist/m/core/persist-HKHA66IY.js +3 -0
  184. package/dist/m/core/recovery-TBBSICE2.js +1 -0
  185. package/dist/m/core/save-WUCHTQBE.js +1 -0
  186. package/dist/m/core/save-core-FJVHT5M3.js +1 -0
  187. package/dist/m/core/snapshot-F3SWDZMM.js +1 -0
  188. package/dist/m/core/unsaved-warning-STKBHE6G.js +1 -0
  189. package/dist/m/dom/all-APS5ZSKP.js +1 -0
  190. package/dist/m/dom/dom-helpers-L7OSR6S4.js +1 -0
  191. package/dist/m/events/index-23DPTUT4.js +1 -0
  192. package/dist/m/internals/index-WOVAP3RU.js +1 -0
  193. package/dist/m/lib/cache-bust-CGWT6ZJI.js +1 -0
  194. package/dist/m/lib/region-policy-SB2AWVG5.js +1 -0
  195. package/dist/m/loader-HXX6YNH5.js +1 -0
  196. package/dist/m/manifest-F22DEDAC.js +1 -0
  197. package/dist/m/manifest-edit-C3C7376B.js +1 -0
  198. package/dist/m/manifest.json +3491 -0
  199. package/dist/m/options/options-2LH76JQ3.js +1 -0
  200. package/dist/m/page/editor-XUTB2HB2.js +189 -0
  201. package/dist/m/plugins/ai-edit-ZQ4CGWIP.js +6 -0
  202. package/dist/m/plugins/bind-text-NX46N5UV.js +1 -0
  203. package/dist/m/plugins/cms-HP3LSTPN.js +2293 -0
  204. package/dist/m/plugins/demo-ZIBFAA3R.js +1 -0
  205. package/dist/m/plugins/derive-UAAA4V4S.js +1 -0
  206. package/dist/m/plugins/indicator-PV4YW2ID.js +1 -0
  207. package/dist/m/plugins/live-NUTTXSBS.js +1 -0
  208. package/dist/m/plugins/menu-HCKO3DSP.js +138 -0
  209. package/dist/m/plugins/message-LQ6EDH4V.js +1 -0
  210. package/dist/m/plugins/page-KSUH7G6J.js +2 -0
  211. package/dist/m/plugins/page-view-W73OW7WI.js +1 -0
  212. package/dist/m/plugins/people-AJJ32YCG.js +1 -0
  213. package/dist/m/plugins/quickcrop-QNY3PKLD.js +26 -0
  214. package/dist/m/plugins/quickcrop-QNY3PKLD.js.LEGAL.txt +7 -0
  215. package/dist/m/plugins/richclay-RC3L2F6X.js +517 -0
  216. package/dist/m/plugins/richclay-RC3L2F6X.js.LEGAL.txt +1 -0
  217. package/dist/m/plugins/sortable-YRMQX3ZU.js +1 -0
  218. package/dist/m/plugins/source-KHK5UUSK.js +1 -0
  219. package/dist/m/plugins/undo-OF2L3CXU.js +1 -0
  220. package/dist/m/plugins/unsent-HJFLQJ2O.js +1 -0
  221. package/dist/m/plugins/upgrade-ZNYODP5Y.js +1 -0
  222. package/dist/m/plugins/upload-XSGNILUY.js +1 -0
  223. package/dist/m/plugins/visitor-drafts-XK5GW55Q.js +21 -0
  224. package/dist/m/plugins/visitor-drafts-owner-KSSH75EV.js +1 -0
  225. package/dist/m/plugins/wire-ZWVWKF76.js +1 -0
  226. package/dist/m/reader-core-ILWLXVMP.js +68 -0
  227. package/dist/m/route/route-KOCZSEGN.js +1 -0
  228. package/dist/m/sync/live-sync-4AUVXVJU.js +1 -0
  229. package/dist/m/ui/index-EVHKMKBL.js +1 -0
  230. package/dist/m/utils/index-4TJCVLT7.js +1 -0
  231. package/dist/m/vendor/Sortable.vendor-A755ITLN.js +3 -0
  232. package/dist/m/vendor/Sortable.vendor-A755ITLN.js.LEGAL.txt +1 -0
  233. package/dist/m/vendor/sap-core.vendor-A7BMUYZT.js +6 -0
  234. package/dist/offline-manifest.json +3800 -0
  235. package/dist/page/themes/light-1.css +406 -0
  236. package/dist/server/core.cjs +23662 -22860
  237. package/dist/server/offline-runtime.cjs +4954 -0
  238. package/dist/server/offline-runtime.mjs +4923 -0
  239. package/dist/server/rooms.mjs +9 -0
  240. package/docs/guide.md +1078 -669
  241. package/entries/all.js +2 -0
  242. package/entries/clay-data.js +1 -1
  243. package/entries/clay-dom.js +2 -0
  244. package/entries/clay-events.js +2 -0
  245. package/entries/clay-internals.js +2 -0
  246. package/entries/clay-options.js +2 -0
  247. package/entries/clay-router.js +2 -0
  248. package/entries/clay-ui.js +2 -0
  249. package/entries/clay-utils.js +2 -0
  250. package/entries/clay.js +2 -0
  251. package/entries/sap.js +6 -6
  252. package/fonts/ibm-plex-mono-LICENSE +93 -0
  253. package/fonts/ibm-plex-mono-latin-300-normal.woff2 +0 -0
  254. package/fonts/ibm-plex-mono-latin-400-italic.woff2 +0 -0
  255. package/fonts/ibm-plex-mono-latin-400-normal.woff2 +0 -0
  256. package/fonts/ibm-plex-mono-latin-500-normal.woff2 +0 -0
  257. package/fonts/ibm-plex-mono-latin-600-normal.woff2 +0 -0
  258. package/fonts/ibm-plex-sans-LICENSE +93 -0
  259. package/fonts/ibm-plex-sans-latin-400-normal.woff2 +0 -0
  260. package/fonts/ibm-plex-sans-latin-500-normal.woff2 +0 -0
  261. package/fonts/ibm-plex-sans-latin-600-normal.woff2 +0 -0
  262. package/fonts/ibm-plex.css +71 -0
  263. package/fonts/inter-LICENSE +93 -0
  264. package/fonts/inter-cyrillic-ext-wght-normal.woff2 +0 -0
  265. package/fonts/inter-cyrillic-wght-normal.woff2 +0 -0
  266. package/fonts/inter-greek-ext-wght-normal.woff2 +0 -0
  267. package/fonts/inter-greek-wght-normal.woff2 +0 -0
  268. package/fonts/inter-latin-ext-wght-normal.woff2 +0 -0
  269. package/fonts/inter-latin-wght-normal.woff2 +0 -0
  270. package/fonts/inter-vietnamese-wght-normal.woff2 +0 -0
  271. package/fonts/inter.css +62 -0
  272. package/fonts/newsreader-LICENSE +93 -0
  273. package/fonts/newsreader-latin-ext-opsz-normal.woff2 +0 -0
  274. package/fonts/newsreader-latin-opsz-normal.woff2 +0 -0
  275. package/fonts/newsreader-vietnamese-opsz-normal.woff2 +0 -0
  276. package/fonts/newsreader.css +26 -0
  277. package/fonts/work-sans-LICENSE +93 -0
  278. package/fonts/work-sans-latin-wght-normal.woff2 +0 -0
  279. package/fonts/work-sans.css +8 -0
  280. package/package.json +20 -3
  281. package/packed-contract.json +1 -0
  282. package/src/attrs/add-from.js +27 -4
  283. package/src/attrs/save-freeze.js +7 -52
  284. package/src/core/admin-attrs.js +119 -12
  285. package/src/core/admin-contenteditable.js +12 -10
  286. package/src/core/admin-inputs.js +14 -15
  287. package/src/core/admin-onclick.js +2 -0
  288. package/src/core/autosave.js +74 -21
  289. package/src/core/conflict-download.js +22 -0
  290. package/src/core/conflict-notice-ui.js +1173 -0
  291. package/src/core/conflict-notice.js +140 -697
  292. package/src/core/edit-mode.js +147 -14
  293. package/src/core/etag.js +30 -12
  294. package/src/core/host-meta.js +72 -8
  295. package/src/core/host-permission.js +29 -0
  296. package/src/core/is-edit-mode.js +145 -12
  297. package/src/core/mode-key.js +125 -0
  298. package/src/core/mode-lifecycle.js +544 -0
  299. package/src/core/mode-receipt.js +30 -0
  300. package/src/core/mode-refusal.js +13 -0
  301. package/src/core/mode-resources.js +52 -0
  302. package/src/core/mode-support.js +82 -0
  303. package/src/core/mode-switch.js +259 -0
  304. package/src/core/mode-transition.js +112 -0
  305. package/src/core/page-data-write.js +305 -0
  306. package/src/core/page-data.js +26 -227
  307. package/src/core/page-format-wire.js +4 -0
  308. package/src/core/page-format.js +58 -0
  309. package/src/core/persist.js +37 -9
  310. package/src/core/preserve-authored.js +114 -0
  311. package/src/core/recovery.js +772 -0
  312. package/src/core/runtime-url.js +105 -0
  313. package/src/core/save-core.js +109 -12
  314. package/src/core/save-replace.js +72 -0
  315. package/src/core/save-size-notice.js +134 -0
  316. package/src/core/save-size.js +140 -0
  317. package/src/core/save.js +805 -118
  318. package/src/core/snapshot.js +121 -11
  319. package/src/core/source-map.js +157 -9
  320. package/src/core/unsaved-warning.js +14 -4
  321. package/src/core/upgrade-run.js +408 -0
  322. package/src/core/version.js +18 -0
  323. package/src/lib/assets.js +30 -0
  324. package/src/lib/autosave-debug-gate.js +50 -0
  325. package/src/lib/autosave-scheduler.js +141 -0
  326. package/src/lib/boot-imports.js +8 -0
  327. package/src/lib/derived.js +3 -1
  328. package/src/lib/dirty-gate.js +15 -0
  329. package/src/lib/doc-storage.js +33 -0
  330. package/src/lib/effect.js +9 -4
  331. package/src/lib/mutation.js +4 -2
  332. package/src/lib/offline-runtime.js +226 -0
  333. package/src/lib/preload.js +48 -0
  334. package/src/lib/root-attrs.js +1 -1
  335. package/src/lib/trash.js +18 -0
  336. package/src/lib/undo/capture-move.js +152 -0
  337. package/src/live/local-channel.js +61 -0
  338. package/src/live/local-lane.js +60 -9
  339. package/src/live/server-lane.js +6 -3
  340. package/src/loader-logic.js +76 -15
  341. package/src/loader.js +218 -30
  342. package/src/page/adopt-boot.js +76 -22
  343. package/src/page/adopt.js +25 -4
  344. package/src/page/awareness.js +230 -0
  345. package/src/page/blocks.js +79 -5
  346. package/src/page/blocksel.js +20 -4
  347. package/src/page/board-face.js +13 -0
  348. package/src/page/board-panel.js +5 -17
  349. package/src/page/board-style.js +2 -13
  350. package/src/page/board-view.js +1 -11
  351. package/src/page/board-views.js +17 -0
  352. package/src/page/board.js +2 -2
  353. package/src/page/boot-pack.js +26 -0
  354. package/src/page/boot.js +237 -0
  355. package/src/page/checklist.js +1 -1
  356. package/src/page/chrome.js +411 -61
  357. package/src/page/csv-import.js +17 -2
  358. package/src/page/document-title-dom.js +40 -0
  359. package/src/page/document-title-runtime.js +76 -0
  360. package/src/page/document-title.js +9 -0
  361. package/src/page/drag.js +48 -13
  362. package/src/page/drop.js +2 -1
  363. package/src/page/editor.js +330 -86
  364. package/src/page/feature-loader.js +72 -0
  365. package/src/page/features/board.js +12 -0
  366. package/src/page/features/code.js +13 -0
  367. package/src/page/features/media.js +290 -0
  368. package/src/page/features/registry.js +23 -0
  369. package/src/page/features/table.js +383 -0
  370. package/src/page/{tool-view.js → features/tool.js} +33 -2
  371. package/src/page/format-codec.js +215 -0
  372. package/src/page/format-gate.js +179 -0
  373. package/src/page/format-level.js +157 -0
  374. package/src/page/highlight-slot.js +23 -0
  375. package/src/page/highlight.js +30 -16
  376. package/src/page/history-intent.js +78 -0
  377. package/src/page/inline.js +18 -25
  378. package/src/page/items.js +52 -11
  379. package/src/page/link.js +1 -0
  380. package/src/page/markdown.js +86 -1
  381. package/src/page/media-views.js +3 -0
  382. package/src/page/media.js +33 -245
  383. package/src/page/outline-cache.js +11 -0
  384. package/src/page/placeholder.js +27 -7
  385. package/src/page/projection.js +196 -50
  386. package/src/page/reader-patch.js +306 -0
  387. package/src/page/recover.js +1 -1
  388. package/src/page/rich/page-tool.js +1 -4
  389. package/src/page/runtime-owner.js +27 -0
  390. package/src/page/save-projection.js +7 -4
  391. package/src/page/schema.js +14 -0
  392. package/src/page/table-rect-key.js +3 -0
  393. package/src/page/table-select.js +4 -3
  394. package/src/page/table-style.js +1 -1
  395. package/src/page/table-views.js +3 -0
  396. package/src/page/table.js +8 -293
  397. package/src/page/themes/light-1.css +139 -2
  398. package/src/page/themes/light-1.source.css +269 -0
  399. package/src/page/tool-capability.js +3 -0
  400. package/src/page/tool-views.js +3 -0
  401. package/src/page/view.js +390 -107
  402. package/src/page/ybind/awareness.js +172 -0
  403. package/src/page/ybind/binding.js +9 -1
  404. package/src/page/ybind/bridge.js +50 -47
  405. package/src/page/ybind/decode.js +52 -19
  406. package/src/page/ybind/doc.js +27 -2
  407. package/src/page/ybind/group.js +12 -3
  408. package/src/page/ybind/index.js +2 -0
  409. package/src/page/ybind/lineage.js +71 -0
  410. package/src/page/ybind/marks.js +25 -1
  411. package/src/page/ybind/migrate.js +48 -13
  412. package/src/page/ybind/moves.js +32 -21
  413. package/src/page/ybind/positions.js +50 -0
  414. package/src/page/ybind/provider.js +84 -22
  415. package/src/page/ybind/recovery-proof.js +191 -0
  416. package/src/page/ybind/recovery-replay.js +130 -0
  417. package/src/page/ybind/tokens.js +15 -6
  418. package/src/page/ybind/walk.js +10 -3
  419. package/src/page/ybind/writer.js +48 -4
  420. package/src/plugins/ai-edit.js +167 -32
  421. package/src/plugins/bind-text.js +218 -0
  422. package/src/plugins/cms.js +93 -0
  423. package/src/plugins/indicator.js +57 -5
  424. package/src/plugins/live.js +282 -34
  425. package/src/plugins/menu/claygoo.svg.js +1 -0
  426. package/src/plugins/menu/seo-head.js +323 -0
  427. package/src/plugins/menu/seo.js +849 -0
  428. package/src/plugins/menu.js +425 -0
  429. package/src/plugins/page-view.js +131 -0
  430. package/src/plugins/page.js +1022 -275
  431. package/src/plugins/people.js +158 -31
  432. package/src/plugins/richclay.js +119 -9
  433. package/src/plugins/sortable.js +370 -60
  434. package/src/plugins/source.js +189 -366
  435. package/src/plugins/undo.js +289 -19
  436. package/src/plugins/unsent.js +132 -0
  437. package/src/plugins/upgrade-run.js +1 -0
  438. package/src/plugins/upgrade.js +210 -0
  439. package/src/plugins/upload-task.js +571 -0
  440. package/src/plugins/upload-ui.js +265 -0
  441. package/src/plugins/upload.js +34 -153
  442. package/src/plugins/visitor-drafts/inert.js +32 -0
  443. package/src/plugins/visitor-drafts/owner-chip.js +3 -0
  444. package/src/plugins/visitor-drafts/prompt.js +2 -2
  445. package/src/plugins/visitor-drafts-owner.js +85 -0
  446. package/src/plugins/visitor-drafts.js +31 -42
  447. package/src/plugins/wire.js +82 -1
  448. package/src/reader-core.js +26 -0
  449. package/src/recovery/conflicts.js +287 -0
  450. package/src/recovery/identity.js +154 -0
  451. package/src/recovery/store.js +792 -0
  452. package/src/recovery/undo.js +257 -0
  453. package/src/server/checkpoint/index.js +68 -4
  454. package/src/server/offline-runtime/index.js +214 -0
  455. package/src/server/rooms/index.js +2 -1
  456. package/src/server/rooms/live-data-rooms.js +2 -2
  457. package/src/server/rooms/page-admission.js +33 -0
  458. package/src/server/rooms/page-lineage.js +56 -0
  459. package/src/server/rooms/page-rebase.js +11 -5
  460. package/src/server/rooms/page-state.js +2 -0
  461. package/src/server/rooms/page-write-admission.js +9 -3
  462. package/src/source/session.js +705 -0
  463. package/src/sync/conflict-revert.js +5 -4
  464. package/src/sync/conflicts-edit.js +119 -0
  465. package/src/sync/conflicts-facade.js +49 -0
  466. package/src/sync/conflicts.js +99 -1
  467. package/src/sync/editing-marker.js +37 -6
  468. package/src/sync/editing-sender.js +8 -1
  469. package/src/sync/live-sync-edit.js +63 -0
  470. package/src/sync/live-sync.js +364 -119
  471. package/src/sync/local-presence.js +187 -0
  472. package/src/sync/merge-declarations.js +10 -0
  473. package/src/sync/merge-engine.js +12 -0
  474. package/src/sync/presence-store.js +412 -0
  475. package/src/sync/presence-target.js +243 -0
  476. package/src/sync/presence.js +72 -41
  477. package/src/sync/saved-handoff.js +200 -0
  478. package/src/sync/saved-stream.js +535 -0
  479. package/src/sync/version-guard.js +92 -0
  480. package/src/sync/wire-profile.js +81 -0
  481. package/src/ui/bevel-controls.js +2 -8
  482. package/src/ui/page-scheme.js +7 -0
  483. package/src/ui/skins/cms.js +1 -1
  484. package/src/ui/theme-config.js +150 -0
  485. package/src/ui/theme.js +6 -138
  486. package/src/ui/toast-lazy.js +11 -0
  487. package/src/vendor/LICENSES-optional.md +253 -0
  488. package/src/vendor/highlight.vendor.js +3 -0
  489. package/src/vendor/hljs-bash.vendor.js +2 -0
  490. package/src/vendor/hljs-css.vendor.js +2 -0
  491. package/src/vendor/hljs-javascript.vendor.js +2 -0
  492. package/src/vendor/hljs-json.vendor.js +2 -0
  493. package/src/vendor/hljs-python.vendor.js +2 -0
  494. package/src/vendor/hljs-xml.vendor.js +2 -0
  495. package/src/vendor/hyper-html-api-data.vendor.js +1 -1
  496. package/src/vendor/hyper-html-api-upgrade.vendor.js +5 -0
  497. package/src/vendor/hyper-morph-identity.vendor.js +2 -0
  498. package/src/vendor/hyper-morph-json.vendor.js +3 -0
  499. package/src/vendor/hyper-morph.vendor.js +6 -6
  500. package/src/vendor/hyper-undo.vendor.js +1 -1
  501. package/src/vendor/hypercms.vendor.js +169 -84
  502. package/src/vendor/marked.vendor.js +68 -0
  503. package/src/vendor/overtype.vendor.js +994 -0
  504. package/src/vendor/richclay.vendor.js +17 -17
  505. package/src/vendor/sap-core.vendor.js +5 -5
  506. package/src/vendor/sap-ownership.vendor.js +11 -7
@@ -18,8 +18,9 @@
18
18
  // where in the log it starts, the moves after that go back on top, and the
19
19
  // merge itself is logged as a diff so a later file stamped before it keeps it.
20
20
 
21
+ import { localChannel } from "./local-channel.js";
21
22
  import { applyOp, applyTracked, checkOp, cloneJson, undoTracked, validateOp, serializeLive, textHash, diffOps } from "./ops.js";
22
- import { HyperMorph } from "../vendor/hyper-morph.vendor.js";
23
+ import { parseJsonRelaxed } from "../vendor/hyper-morph-json.vendor.js";
23
24
  import { movesSince } from "./moves.js";
24
25
 
25
26
  const VERSION = 4;
@@ -52,6 +53,16 @@ function applyAll(value, ops) {
52
53
 
53
54
  const encoder = new TextEncoder();
54
55
 
56
+ // Floor 1 moves the durable lane to its own channel scope: a tab that cannot read
57
+ // floor 1 never receives future-format updates, and its writes are refused by the
58
+ // host floor. The message protocol inside the scope is unchanged.
59
+ export const FORMAT_SCOPE = "page-format:1";
60
+
61
+ export function localLaneKey(floor = 0, path = window.location.pathname) {
62
+ const base = "clay-live:" + path;
63
+ return floor >= 1 ? `${base}:${FORMAT_SCOPE}` : base;
64
+ }
65
+
55
66
  export function localLaneSupported() {
56
67
  return typeof BroadcastChannel === "function" && typeof navigator !== "undefined" && typeof navigator.locks?.request === "function";
57
68
  }
@@ -66,10 +77,16 @@ function randomId() {
66
77
  * @param {() => Map<string, {value: any, ephemeral: boolean}>} options.seed -
67
78
  * what this tab holds for each live tag, used for stores the room does not have yet
68
79
  * @param {string} [options.key]
80
+ * @param {object} [options.channel] - the document's channel, when a presence
81
+ * service in this tab already owns one: the two share it rather than open a second
69
82
  */
70
- export function localTransport({ seed, key = "clay-live:" + window.location.pathname }) {
83
+ // `key` is the room's channel without a floor suffix; `floor` scopes it.
84
+ export function localTransport({ seed, key = "clay-live:" + window.location.pathname, channel: shared = null, floor = 0 }) {
71
85
  const clientId = randomId();
86
+ let scopeFloor = floor >= 1 ? 1 : 0;
87
+ let laneKey = scopeFloor ? `${key}:${FORMAT_SCOPE}` : key;
72
88
  let channel = null;
89
+ let unsubscribe = null;
73
90
  let handlers = null;
74
91
  let room = null;
75
92
  let stopped = false;
@@ -101,7 +118,7 @@ export function localTransport({ seed, key = "clay-live:" + window.location.path
101
118
  let mirror = { epoch: null, seq: 0, sequencer: null, closedBy: null, stale: false, seen: new Map(), stores: new Map() };
102
119
 
103
120
  function post(message) {
104
- channel?.postMessage({ v: VERSION, ...message });
121
+ channel?.post(message);
105
122
  }
106
123
 
107
124
  // Over either cap the oldest entries go, and a file older than them can no
@@ -164,7 +181,7 @@ export function localTransport({ seed, key = "clay-live:" + window.location.path
164
181
  function alreadyMerged(m, frame) {
165
182
  if (!m?.file) return false;
166
183
  if (frame.seq != null && m.file.seq != null) return frame.seq <= m.file.seq;
167
- return m.file.hash === textHash(serializeLive(HyperMorph.parseJsonRelaxed(frame.text)));
184
+ return m.file.hash === textHash(serializeLive(parseJsonRelaxed(frame.text)));
168
185
  }
169
186
 
170
187
  function dropMerged() {
@@ -319,7 +336,7 @@ export function localTransport({ seed, key = "clay-live:" + window.location.path
319
336
  if (lockRequested || stopped) return;
320
337
  lockRequested = true;
321
338
  navigator.locks
322
- .request(key, async () => {
339
+ .request(laneKey, async () => {
323
340
  if (stopped) return undefined;
324
341
  const ordered = await closedFor(mirror.sequencer);
325
342
  if (stopped) return undefined;
@@ -393,7 +410,7 @@ export function localTransport({ seed, key = "clay-live:" + window.location.path
393
410
  if (!m || m.ephemeral) return null;
394
411
  let value;
395
412
  try {
396
- value = cloneJson(HyperMorph.parseJsonRelaxed(text));
413
+ value = cloneJson(parseJsonRelaxed(text));
397
414
  } catch {
398
415
  return null;
399
416
  }
@@ -559,12 +576,45 @@ export function localTransport({ seed, key = "clay-live:" + window.location.path
559
576
  handlers.open({ clientId, lane: "live" });
560
577
  }
561
578
 
579
+ // The floor rose and an accepted receipt covers the pending work: close this
580
+ // scope's room (its closed state carries every store and the position the
581
+ // receipt covers), then join the new one. An interrupted switch leaves this tab
582
+ // where it was, on floor 0's scope, with every store and its pending work
583
+ // intact; the caller retries it from the receipt.
584
+ function switchScope(next, { covered = false } = {}) {
585
+ const want = next >= 1 ? 1 : 0;
586
+ const held = { floor: scopeFloor, scope: laneKey };
587
+ if (want <= scopeFloor) return { status: "already", ...held };
588
+ if (stopped || !channel) return { status: "refused", code: "lane-stopped", ...held };
589
+ if (shared) return { status: "refused", code: "shared-channel", ...held };
590
+ if (!covered) return { status: "refused", code: "uncovered", ...held };
591
+ closeRoom();
592
+ unsubscribe?.();
593
+ laneKey = want ? `${key}:${FORMAT_SCOPE}` : key;
594
+ scopeFloor = want;
595
+ channel = localChannel(laneKey);
596
+ unsubscribe = channel.subscribe("durable", (data) => onMessage({ data }));
597
+ mirror.sequencer = mirror.closedBy = null;
598
+ lockRequested = false;
599
+ requestLock();
600
+ handlers.close();
601
+ handlers.open({ clientId, lane: "live" });
602
+ return { status: "switched", floor: scopeFloor, scope: laneKey };
603
+ }
604
+
562
605
  return {
563
606
  clientId,
607
+ get scope() {
608
+ return laneKey;
609
+ },
610
+ get floor() {
611
+ return scopeFloor;
612
+ },
613
+ switchScope,
564
614
  start(next) {
565
615
  handlers = next;
566
- channel = new BroadcastChannel(key);
567
- channel.onmessage = onMessage;
616
+ channel = shared ?? localChannel(laneKey);
617
+ unsubscribe = channel.subscribe("durable", (data) => onMessage({ data }));
568
618
  window.addEventListener("pagehide", onPageHide);
569
619
  window.addEventListener("pageshow", onPageShow);
570
620
  requestLock();
@@ -576,7 +626,8 @@ export function localTransport({ seed, key = "clay-live:" + window.location.path
576
626
  window.removeEventListener("pagehide", onPageHide);
577
627
  window.removeEventListener("pageshow", onPageShow);
578
628
  for (const resolve of waiting.values()) resolve(null);
579
- channel?.close();
629
+ unsubscribe?.();
630
+ unsubscribe = null;
580
631
  channel = null;
581
632
  };
582
633
  },
@@ -1,8 +1,11 @@
1
1
  import { onStream } from "./stream-bridge.js";
2
+ import { PAGE_FORMAT, PAGE_FORMAT_HEADER } from "../core/page-format.js";
2
3
 
3
4
  // The host side of clay.live's fast lane on a host that advertises `live-data`:
4
5
  // one POST per frame of ops, one GET for the room's whole state. Both name the
5
- // document with Document-URL, as the sync relay and presence do.
6
+ // document with Document-URL, as the sync relay and presence do, and both declare
7
+ // the page format this client writes: registration, operation and checkpoint are
8
+ // page-writing paths, so each one carries the capability the floor decides on.
6
9
 
7
10
  const DATA_PATH = "/_/sync/data";
8
11
 
@@ -21,7 +24,7 @@ export async function relayData(clientId, frame) {
21
24
  const response = await fetch(url.href, {
22
25
  method: "POST",
23
26
  credentials: "same-origin",
24
- headers: { "Content-Type": "application/json", "Document-URL": window.location.href },
27
+ headers: { "Content-Type": "application/json", "Document-URL": window.location.href, [PAGE_FORMAT_HEADER]: String(PAGE_FORMAT) },
25
28
  body: JSON.stringify(frame),
26
29
  });
27
30
  let body = null;
@@ -47,7 +50,7 @@ export async function fetchLiveState(clientId, since = null, { signal } = {}) {
47
50
  const response = await fetch(url.href, {
48
51
  credentials: "same-origin",
49
52
  cache: "no-store",
50
- headers: { "Document-URL": window.location.href },
53
+ headers: { "Document-URL": window.location.href, [PAGE_FORMAT_HEADER]: String(PAGE_FORMAT) },
51
54
  signal,
52
55
  });
53
56
  if (!response.ok) {
@@ -1,9 +1,14 @@
1
1
  export const CORE_WAVES = {
2
2
  always: [
3
3
  "lib/mutation.js", // first: everything hangs off the hub; cms/sync need it in view mode too
4
+ // Second: records what the served file wrote for the attributes edit mode rewrites,
5
+ // and the authored contents of [freeze] regions, while the page is still in view.
6
+ // Read-only, and the one thing a view to edit to view cycle has to hand back.
7
+ "core/preserve-authored.js",
4
8
  "core/edit-mode.js", // both modes — matches today: 'edit-mode' is NOT in EDIT_MODE_ONLY
5
9
  // (hyperclay.js:251-273 lists 'edit-mode-helpers', not 'edit-mode');
6
10
  // toggleEditMode must exist in view mode, it's the way IN
11
+ "core/mode-key.js", // the way into edit for a document with no toggle of its own
7
12
  // always, deliberately: it speaks only when the host is too old to save to, which
8
13
  // is exactly the case where edit mode is off, so the editOnly wave would never
9
14
  // reach it. It draws nothing on any other page.
@@ -11,13 +16,16 @@ export const CORE_WAVES = {
11
16
  "core/page-data.js",
12
17
  ],
13
18
  editOnly: [
14
- "vendor/hyper-morph.vendor.js",
15
19
  "core/snapshot.js",
16
20
  // Before save.js: it takes the boot baseline as it evaluates, and a snapshot
17
21
  // transform registered after that made an untouched page read as unsaved.
18
22
  "core/persist.js", "core/admin-attrs.js",
19
23
  "core/save-core.js", "core/save.js",
20
24
  "core/conflict-notice.js",
25
+ // The recovery facade: a queue and a status, no storage of its own. It imports
26
+ // the IndexedDB store and the identity only when an adapter registers, which is
27
+ // why neither is in a plan's static graph.
28
+ "core/recovery.js",
21
29
  "core/unsaved-warning.js", "core/autosave.js",
22
30
  "attrs/save-freeze.js", "attrs/onaftersave.js", "attrs/refetch-on-save.js", "attrs/add-from.js",
23
31
  "lib/cache-bust.js",
@@ -32,8 +40,12 @@ export const PLUGIN_PATHS = {
32
40
  // tab still shows the game, and its writes stay in that tab.
33
41
  live: { path: "plugins/live.js", editOnly: false, default: false },
34
42
  page: { path: "plugins/page.js", editOnly: true, default: false },
43
+ // The reader half of `page`, added by resolveModules for a Document in view mode
44
+ // and never named in a URL: the reader's article follows each saved file.
45
+ "page-view": { path: "plugins/page-view.js", editOnly: false, default: false, internal: true },
35
46
  sortable: { path: "plugins/sortable.js", editOnly: true, default: false },
36
47
  undo: { path: "plugins/undo.js", editOnly: true, default: false },
48
+ unsent: { path: "plugins/unsent.js", editOnly: true, default: false },
37
49
  cms: { path: "plugins/cms.js", editOnly: false, default: false },
38
50
  quickcrop: { path: "plugins/quickcrop.js", editOnly: false, default: false },
39
51
  // editOnly, because a file picker only ever appears in edit mode: the cms
@@ -42,6 +54,10 @@ export const PLUGIN_PATHS = {
42
54
  upload: { path: "plugins/upload.js", editOnly: true, default: false },
43
55
  // Who is editing and who wrote what. Not editOnly: a reader still sees names.
44
56
  people: { path: "plugins/people.js", editOnly: false, default: false },
57
+ // An Edit switch and claygoo in the top right, for anyone who can edit. Not
58
+ // editOnly: an owner who opens a document in view needs the switch that gets
59
+ // them into edit, and the group draws nothing for a reader who cannot edit.
60
+ menu: { path: "plugins/menu.js", editOnly: false, default: false },
45
61
  wire: { path: "plugins/wire.js", editOnly: false, default: false },
46
62
  // A visitor's contact form to the document's owner. Not editOnly: visitors are
47
63
  // who send messages.
@@ -59,10 +75,19 @@ export const PLUGIN_PATHS = {
59
75
  // verify is sent as the ordinary full serialization, so the floor is the behaviour
60
76
  // it replaces. `exclude=source` turns it off.
61
77
  source: { path: "plugins/source.js", editOnly: true, default: true },
62
- "visitor-drafts": { path: "plugins/visitor-drafts.js", editOnly: false, default: false },
78
+ // Only draft mode loads the draft store and its UI. Everyone else, readers and the
79
+ // owner editing the original, gets the owner module: the chip when it applies and
80
+ // the inert `clay.visitorDrafts`, without the drafts UI's 24 KB.
81
+ "visitor-drafts": { path: "plugins/visitor-drafts.js", ownerPath: "plugins/visitor-drafts-owner.js", editOnly: false, default: false },
82
+ // An editor textarea outside the saved records, bound to one record's text
83
+ // element. Edit mode only: the page that asks for it is the page whose owner
84
+ // writes in it.
85
+ "bind-text": { path: "plugins/bind-text.js", editOnly: true, default: false },
63
86
  // The sapjs core. Loaded for any page with a [sap] root at boot (resolveModules'
64
87
  // hasSap), in view mode too: a reader's tab paints the same totals.
65
88
  derive: { path: "plugins/derive.js", editOnly: false, default: false },
89
+ // The update check a starter template copy gets from its own hyper-source meta.
90
+ upgrade: { path: "plugins/upgrade.js", editOnly: false, default: false },
66
91
  };
67
92
 
68
93
  // One literal import per module the loader can ask for, so a bundler can see the
@@ -80,12 +105,15 @@ export const MODULES = {
80
105
  "lib/region-policy.js": () => import("./lib/region-policy.js"),
81
106
  "lib/mutation.js": () => import("./lib/mutation.js"),
82
107
  "core/edit-mode.js": () => import("./core/edit-mode.js"),
108
+ "core/mode-key.js": () => import("./core/mode-key.js"),
83
109
  "core/stale-host-notice.js": () => import("./core/stale-host-notice.js"),
84
110
  "core/page-data.js": () => import("./core/page-data.js"),
111
+ "core/preserve-authored.js": () => import("./core/preserve-authored.js"),
85
112
  "core/snapshot.js": () => import("./core/snapshot.js"),
86
113
  "core/save-core.js": () => import("./core/save-core.js"),
87
114
  "core/save.js": () => import("./core/save.js"),
88
115
  "core/conflict-notice.js": () => import("./core/conflict-notice.js"),
116
+ "core/recovery.js": () => import("./core/recovery.js"),
89
117
  "core/unsaved-warning.js": () => import("./core/unsaved-warning.js"),
90
118
  "core/persist.js": () => import("./core/persist.js"),
91
119
  "core/admin-attrs.js": () => import("./core/admin-attrs.js"),
@@ -95,30 +123,35 @@ export const MODULES = {
95
123
  "attrs/refetch-on-save.js": () => import("./attrs/refetch-on-save.js"),
96
124
  "attrs/add-from.js": () => import("./attrs/add-from.js"),
97
125
  "lib/cache-bust.js": () => import("./lib/cache-bust.js"),
98
- "vendor/hyper-morph.vendor.js": () => import("./vendor/hyper-morph.vendor.js"),
99
126
  "plugins/richclay.js": () => import("./plugins/richclay.js"),
100
127
  "plugins/indicator.js": () => import("./plugins/indicator.js"),
101
128
  "sync/live-sync.js": () => import("./sync/live-sync.js"),
102
129
  "plugins/live.js": () => import("./plugins/live.js"),
103
130
  "plugins/page.js": () => import("./plugins/page.js"),
131
+ "plugins/page-view.js": () => import("./plugins/page-view.js"),
104
132
  "plugins/sortable.js": () => import("./plugins/sortable.js"),
105
133
  "plugins/undo.js": () => import("./plugins/undo.js"),
134
+ "plugins/unsent.js": () => import("./plugins/unsent.js"),
106
135
  "plugins/cms.js": () => import("./plugins/cms.js"),
107
136
  "plugins/quickcrop.js": () => import("./plugins/quickcrop.js"),
108
137
  "plugins/upload.js": () => import("./plugins/upload.js"),
109
138
  "plugins/people.js": () => import("./plugins/people.js"),
139
+ "plugins/menu.js": () => import("./plugins/menu.js"),
110
140
  "plugins/wire.js": () => import("./plugins/wire.js"),
111
141
  "plugins/message.js": () => import("./plugins/message.js"),
112
142
  "plugins/ai-edit.js": () => import("./plugins/ai-edit.js"),
113
143
  "plugins/demo.js": () => import("./plugins/demo.js"),
114
144
  "plugins/visitor-drafts.js": () => import("./plugins/visitor-drafts.js"),
145
+ "plugins/visitor-drafts-owner.js": () => import("./plugins/visitor-drafts-owner.js"),
146
+ "plugins/bind-text.js": () => import("./plugins/bind-text.js"),
115
147
  "plugins/source.js": () => import("./plugins/source.js"),
116
148
  "plugins/derive.js": () => import("./plugins/derive.js"),
149
+ "plugins/upgrade.js": () => import("./plugins/upgrade.js"),
117
150
  };
118
151
 
119
152
  // `source` is last on purpose: its install captures a save clone, so it wants every
120
153
  // plugin that registers a document transform to have registered it first.
121
- const PLUGIN_ORDER = ["visitor-drafts", "richclay", "indicator", "sortable", "undo", "quickcrop", "upload", "people", "cms", "sync", "live", "page", "message", "wire", "ai-edit", "demo", "derive", "source"];
154
+ const PLUGIN_ORDER = ["visitor-drafts", "richclay", "indicator", "sortable", "undo", "unsent", "quickcrop", "upload", "people", "menu", "upgrade", "cms", "page-view", "sync", "live", "page", "message", "wire", "ai-edit", "demo", "derive", "bind-text", "source"];
122
155
 
123
156
  // A plugin that cannot do its whole job alone. hypercms reads the cropper through
124
157
  // a capability lookup (`clay.quickcrop`) and silently uploads the raw file when it
@@ -147,13 +180,21 @@ const PLUGIN_ORDER = ["visitor-drafts", "richclay", "indicator", "sortable", "un
147
180
  // files answers `unsupported` and the editor offers to embed the file instead.
148
181
  const IMPLIES = { cms: ["quickcrop", "upload"], "ai-edit": ["wire"], page: ["live", "sync", "upload"] };
149
182
 
183
+ // A Document's editor owns its article's rich text, so richclay (for [editable]) has
184
+ // nothing to do there; plugins=page,richclay still loads it.
185
+ const DISPLACES = { page: ["richclay"] };
186
+ // No first paint or keystroke waits for these. source keeps the file's bytes outside
187
+ // the edited parts stable; a save before it installs is the ordinary full serialization.
188
+ // upgrade only asks the host for a newer version once `clay.ready` resolves.
189
+ const LATE = new Set(["source", "sortable", "menu", "upgrade"]);
190
+
150
191
  function parseCsv(params, key, enabled, apply) {
151
192
  const raw = params.get(key);
152
193
  if (!raw) return;
153
194
  for (const token of raw.split(",")) {
154
195
  const name = token.trim();
155
196
  if (!name) continue;
156
- if (!PLUGIN_PATHS[name]) {
197
+ if (!PLUGIN_PATHS[name] || PLUGIN_PATHS[name].internal) {
157
198
  console.warn(`clayjs: unknown plugin "${name}"`);
158
199
  continue;
159
200
  }
@@ -163,13 +204,17 @@ function parseCsv(params, key, enabled, apply) {
163
204
 
164
205
  // Each of these talks to the host or writes outside the visitor's own record, so a
165
206
  // page that keeps its edits in this browser cannot carry them.
166
- const DRAFT_DROPS = ["sync", "live", "page", "upload", "quickcrop", "cms", "people", "wire", "ai-edit", "demo", "source"];
207
+ const DRAFT_DROPS = ["sync", "live", "page", "upload", "quickcrop", "cms", "people", "menu", "upgrade", "wire", "ai-edit", "demo", "source"];
167
208
 
168
209
  // [refetch-on-save] swaps its element for a fresh GET of the same URL after every
169
- // save, which on a visitor's own draft is a request to the host.
170
- const DRAFT_DROPS_CORE = ["attrs/refetch-on-save.js"];
210
+ // save, which on a visitor's own draft is a request to the host. The conflict notice
211
+ // answers a host's 412, which a save into this browser never returns.
212
+ const DRAFT_DROPS_CORE = ["attrs/refetch-on-save.js", "core/conflict-notice.js"];
213
+
214
+ // Only that host's copies auto-add the update check; another source names it.
215
+ const TEMPLATE_SOURCE_PREFIX = "https://hyperclay.com/templates/";
171
216
 
172
- export function resolveModules(params, isEditMode, { isDraftMode = false, hasSap = false } = {}) {
217
+ export function resolveModules(params, isEditMode, { isDraftMode = false, hasSap = false, canEdit = false, templateSource = null } = {}) {
173
218
  const core = [...CORE_WAVES.always];
174
219
  if (isEditMode) core.push(...CORE_WAVES.editOnly);
175
220
 
@@ -185,11 +230,16 @@ export function resolveModules(params, isEditMode, { isDraftMode = false, hasSap
185
230
  if (hasSap) enabled.add("derive");
186
231
  // ai-edit cannot run without the wire, so excluding the wire excludes it too.
187
232
  if (excluded.has("wire")) enabled.delete("ai-edit");
188
- // A default-on plugin that this mode drops brings nothing with it. An explicitly
189
- // asked for plugin still brings what it implies.
233
+ if (!isEditMode && !isDraftMode && enabled.has("page")) enabled.add("page-view");
234
+ // A plugin this mode does not load brings nothing with it, whether a default put
235
+ // it in the set or the tag named it. A page that wants what an edit-only plugin
236
+ // implies in view mode names that plugin too. `page` is the case that matters
237
+ // most: a reader loads its reader half and no generic sync, live data service or
238
+ // upload, so `plugins=page` in view mode resolves to page-view alone and the
239
+ // saved transport page-view owns is the only stream.
190
240
  for (const name of [...enabled]) {
191
241
  if (excluded.has(name)) continue;
192
- if (!explicit.has(name) && PLUGIN_PATHS[name].editOnly && !isEditMode) continue;
242
+ if (PLUGIN_PATHS[name].editOnly && !isEditMode) continue;
193
243
  for (const implied of IMPLIES[name] || []) enabled.add(implied);
194
244
  }
195
245
  for (const name of excluded) enabled.delete(name);
@@ -202,13 +252,24 @@ export function resolveModules(params, isEditMode, { isDraftMode = false, hasSap
202
252
  enabled.add("visitor-drafts");
203
253
  }
204
254
 
255
+ // A copy of a starter template upgrades with no authored tag, so copies shipped
256
+ // between the metas and this plugin upgrade too.
257
+ if (!isDraftMode && canEdit && !excluded.has("upgrade") && templateSource &&
258
+ templateSource.startsWith(TEMPLATE_SOURCE_PREFIX)) {
259
+ enabled.add("upgrade");
260
+ }
261
+
262
+ for (const [owner, names] of Object.entries(DISPLACES)) {
263
+ if (enabled.has(owner)) for (const name of names) if (!explicit.has(name)) enabled.delete(name);
264
+ }
265
+
205
266
  const plugins = [];
267
+ const late = [];
206
268
  for (const name of PLUGIN_ORDER) {
207
269
  if (!enabled.has(name)) continue;
208
270
  const spec = PLUGIN_PATHS[name];
209
271
  if (spec.editOnly && !isEditMode) continue;
210
- plugins.push(spec.path);
272
+ (LATE.has(name) ? late : plugins).push(spec.ownerPath && !isDraftMode ? spec.ownerPath : spec.path);
211
273
  }
212
-
213
- return { core, plugins };
274
+ return { core, plugins, late };
214
275
  }