@elytracms/studio 0.0.91 → 0.0.93

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 (353) hide show
  1. package/convex/asset-alt-migration.test.ts +127 -0
  2. package/convex/asset-replace.test.ts +168 -0
  3. package/convex/asset-revalidate.test.ts +6 -6
  4. package/convex/assets.ts +41 -5
  5. package/convex/cms.ts +537 -177
  6. package/convex/contract-parity.test.ts +173 -19
  7. package/convex/delivery.ts +26 -13
  8. package/convex/document-revalidate.test.ts +17 -16
  9. package/convex/orphan-hydration.test.ts +116 -0
  10. package/convex/presence-cost.test.ts +89 -0
  11. package/convex/rail-write-parity.test.ts +17 -14
  12. package/convex/referenceMaintenance.ts +15 -15
  13. package/convex/schema.ts +70 -5
  14. package/convex/triggers.ts +21 -8
  15. package/convex/write-limits.ts +1 -1
  16. package/dist/components/ai/ai-chat-panel.js +33 -22
  17. package/dist/components/ai/ai-chat-panel.js.map +1 -1
  18. package/dist/components/ai/proposal-card.js +2 -1
  19. package/dist/components/ai/proposal-card.js.map +1 -1
  20. package/dist/components/ai/translate-document-action.d.ts +8 -2
  21. package/dist/components/ai/translate-document-action.js.map +1 -1
  22. package/dist/components/ai/translate-document-dialog.d.ts +1 -1
  23. package/dist/components/ai/translate-document-dialog.js +14 -8
  24. package/dist/components/ai/translate-document-dialog.js.map +1 -1
  25. package/dist/components/ai/translate-skipped.d.ts +19 -0
  26. package/dist/components/ai/translate-skipped.js +46 -0
  27. package/dist/components/ai/translate-skipped.js.map +1 -0
  28. package/dist/components/app-views/default-modules.d.ts +23 -6
  29. package/dist/components/app-views/default-modules.js +33 -14
  30. package/dist/components/app-views/default-modules.js.map +1 -1
  31. package/dist/components/assets/asset-detail.js +18 -8
  32. package/dist/components/assets/asset-detail.js.map +1 -1
  33. package/dist/components/assets/asset-metadata.d.ts +15 -4
  34. package/dist/components/assets/asset-metadata.js +15 -2
  35. package/dist/components/assets/asset-metadata.js.map +1 -1
  36. package/dist/components/assets/asset-search.js +4 -1
  37. package/dist/components/assets/asset-search.js.map +1 -1
  38. package/dist/components/assets/asset-selection.d.ts +0 -8
  39. package/dist/components/assets/asset-selection.js +4 -23
  40. package/dist/components/assets/asset-selection.js.map +1 -1
  41. package/dist/components/assets/asset-thumb.js +3 -2
  42. package/dist/components/assets/asset-thumb.js.map +1 -1
  43. package/dist/components/assets/assets-collection-view-source.d.ts +3 -3
  44. package/dist/components/assets/assets-collection-view-source.js +9 -5
  45. package/dist/components/assets/assets-collection-view-source.js.map +1 -1
  46. package/dist/components/assets/assets-store.d.ts +14 -0
  47. package/dist/components/assets/assets-store.js +23 -1
  48. package/dist/components/assets/assets-store.js.map +1 -1
  49. package/dist/components/assets/replace-file.d.ts +22 -0
  50. package/dist/components/assets/replace-file.js +59 -0
  51. package/dist/components/assets/replace-file.js.map +1 -0
  52. package/dist/components/builder/blocks-model.d.ts +14 -26
  53. package/dist/components/builder/blocks-model.js +35 -41
  54. package/dist/components/builder/blocks-model.js.map +1 -1
  55. package/dist/components/builder/blocks-panel.d.ts +7 -3
  56. package/dist/components/builder/blocks-panel.js +6 -5
  57. package/dist/components/builder/blocks-panel.js.map +1 -1
  58. package/dist/components/builder/builder-store.d.ts +126 -30
  59. package/dist/components/builder/builder-store.js +169 -67
  60. package/dist/components/builder/builder-store.js.map +1 -1
  61. package/dist/components/builder/canvas-body.d.ts +30 -0
  62. package/dist/components/builder/canvas-body.js +38 -0
  63. package/dist/components/builder/canvas-body.js.map +1 -0
  64. package/dist/components/builder/canvas-chrome-css.js +7 -0
  65. package/dist/components/builder/canvas-chrome-css.js.map +1 -1
  66. package/dist/components/builder/canvas-dnd.d.ts +7 -7
  67. package/dist/components/builder/canvas-dnd.js +5 -5
  68. package/dist/components/builder/canvas-dnd.js.map +1 -1
  69. package/dist/components/builder/canvas-render-context.d.ts +30 -22
  70. package/dist/components/builder/canvas-render-context.js +44 -44
  71. package/dist/components/builder/canvas-render-context.js.map +1 -1
  72. package/dist/components/builder/canvas-runs.d.ts +45 -0
  73. package/dist/components/builder/canvas-runs.js +51 -0
  74. package/dist/components/builder/canvas-runs.js.map +1 -0
  75. package/dist/components/builder/canvas.d.ts +5 -4
  76. package/dist/components/builder/canvas.js +34 -6
  77. package/dist/components/builder/canvas.js.map +1 -1
  78. package/dist/components/builder/clipboard-actions.d.ts +15 -0
  79. package/dist/components/builder/clipboard-actions.js +50 -13
  80. package/dist/components/builder/clipboard-actions.js.map +1 -1
  81. package/dist/components/builder/composition-field-editor.d.ts +10 -16
  82. package/dist/components/builder/composition-field-editor.js +30 -40
  83. package/dist/components/builder/composition-field-editor.js.map +1 -1
  84. package/dist/components/builder/composition-patches.d.ts +7 -0
  85. package/dist/components/builder/composition-patches.js +256 -0
  86. package/dist/components/builder/composition-patches.js.map +1 -0
  87. package/dist/components/builder/delete-key.d.ts +5 -0
  88. package/dist/components/builder/delete-key.js +4 -0
  89. package/dist/components/builder/delete-key.js.map +1 -1
  90. package/dist/components/builder/insert-context.d.ts +17 -25
  91. package/dist/components/builder/insert-context.js +45 -92
  92. package/dist/components/builder/insert-context.js.map +1 -1
  93. package/dist/components/builder/page-tree.d.ts +3 -3
  94. package/dist/components/builder/page-tree.js +3 -3
  95. package/dist/components/builder/page-tree.js.map +1 -1
  96. package/dist/components/builder/placement-refusal.d.ts +18 -0
  97. package/dist/components/builder/placement-refusal.js +46 -0
  98. package/dist/components/builder/placement-refusal.js.map +1 -0
  99. package/dist/components/builder/property-inspector.js +4 -0
  100. package/dist/components/builder/property-inspector.js.map +1 -1
  101. package/dist/components/builder/reuse-context.js +65 -26
  102. package/dist/components/builder/reuse-context.js.map +1 -1
  103. package/dist/components/builder/reuse.d.ts +79 -8
  104. package/dist/components/builder/reuse.js +71 -23
  105. package/dist/components/builder/reuse.js.map +1 -1
  106. package/dist/components/builder/run-inspector.d.ts +11 -0
  107. package/dist/components/builder/run-inspector.js +33 -0
  108. package/dist/components/builder/run-inspector.js.map +1 -0
  109. package/dist/components/cms/asset-field.d.ts +38 -1
  110. package/dist/components/cms/asset-field.js +182 -58
  111. package/dist/components/cms/asset-field.js.map +1 -1
  112. package/dist/components/cms/asset-picker-core.d.ts +16 -0
  113. package/dist/components/cms/asset-picker-core.js +20 -0
  114. package/dist/components/cms/asset-picker-core.js.map +1 -1
  115. package/dist/components/cms/asset-picker.js +12 -18
  116. package/dist/components/cms/asset-picker.js.map +1 -1
  117. package/dist/components/cms/bulk-actions.d.ts +4 -20
  118. package/dist/components/cms/bulk-actions.js +3 -24
  119. package/dist/components/cms/bulk-actions.js.map +1 -1
  120. package/dist/components/cms/cell-edit.d.ts +5 -5
  121. package/dist/components/cms/cell-edit.js.map +1 -1
  122. package/dist/components/cms/cell.js.map +1 -1
  123. package/dist/components/cms/cms-store.d.ts +87 -45
  124. package/dist/components/cms/cms-store.js +347 -203
  125. package/dist/components/cms/cms-store.js.map +1 -1
  126. package/dist/components/cms/collection-table.js +7 -2
  127. package/dist/components/cms/collection-table.js.map +1 -1
  128. package/dist/components/cms/commit-policy.d.ts +24 -0
  129. package/dist/components/cms/commit-policy.js +37 -0
  130. package/dist/components/cms/commit-policy.js.map +1 -0
  131. package/dist/components/cms/detail-editor.js +83 -137
  132. package/dist/components/cms/detail-editor.js.map +1 -1
  133. package/dist/components/cms/document-diff-view.d.ts +3 -1
  134. package/dist/components/cms/document-diff-view.js +12 -7
  135. package/dist/components/cms/document-diff-view.js.map +1 -1
  136. package/dist/components/cms/draft-commit.d.ts +70 -0
  137. package/dist/components/cms/draft-commit.js +82 -0
  138. package/dist/components/cms/draft-commit.js.map +1 -0
  139. package/dist/components/cms/duplicate-document.d.ts +11 -13
  140. package/dist/components/cms/duplicate-document.js +26 -34
  141. package/dist/components/cms/duplicate-document.js.map +1 -1
  142. package/dist/components/cms/field-anchors.d.ts +7 -4
  143. package/dist/components/cms/field-anchors.js +9 -7
  144. package/dist/components/cms/field-anchors.js.map +1 -1
  145. package/dist/components/cms/field-collaboration.d.ts +47 -0
  146. package/dist/components/cms/field-collaboration.js +87 -0
  147. package/dist/components/cms/field-collaboration.js.map +1 -0
  148. package/dist/components/cms/field-control-lib.d.ts +22 -1
  149. package/dist/components/cms/field-control-lib.js +33 -4
  150. package/dist/components/cms/field-control-lib.js.map +1 -1
  151. package/dist/components/cms/field-control.js +17 -14
  152. package/dist/components/cms/field-control.js.map +1 -1
  153. package/dist/components/cms/gate-validation.d.ts +21 -30
  154. package/dist/components/cms/gate-validation.js +11 -22
  155. package/dist/components/cms/gate-validation.js.map +1 -1
  156. package/dist/components/cms/object-array-field.js +4 -4
  157. package/dist/components/cms/object-array-field.js.map +1 -1
  158. package/dist/components/cms/prop-fields.d.ts +7 -2
  159. package/dist/components/cms/prop-fields.js +13 -6
  160. package/dist/components/cms/prop-fields.js.map +1 -1
  161. package/dist/components/cms/reference-confirm.js +10 -4
  162. package/dist/components/cms/reference-confirm.js.map +1 -1
  163. package/dist/components/cms/rich-text/embed-picker.d.ts +1 -1
  164. package/dist/components/cms/rich-text/embed-picker.js.map +1 -1
  165. package/dist/components/cms/rich-text/insert.d.ts +20 -9
  166. package/dist/components/cms/rich-text/insert.js +25 -17
  167. package/dist/components/cms/rich-text/insert.js.map +1 -1
  168. package/dist/components/cms/use-document-draft.d.ts +96 -0
  169. package/dist/components/cms/use-document-draft.js +283 -0
  170. package/dist/components/cms/use-document-draft.js.map +1 -0
  171. package/dist/components/cms/use-document-versions.js +2 -2
  172. package/dist/components/cms/use-document-versions.js.map +1 -1
  173. package/dist/components/cms/use-live-url.d.ts +6 -12
  174. package/dist/components/cms/use-live-url.js +16 -15
  175. package/dist/components/cms/use-live-url.js.map +1 -1
  176. package/dist/components/cms/use-publish-controller.d.ts +13 -18
  177. package/dist/components/cms/use-publish-controller.js +24 -41
  178. package/dist/components/cms/use-publish-controller.js.map +1 -1
  179. package/dist/components/cms/use-published-perspective.d.ts +2 -3
  180. package/dist/components/cms/use-published-perspective.js +4 -3
  181. package/dist/components/cms/use-published-perspective.js.map +1 -1
  182. package/dist/components/cms/versions-pane.js +8 -1
  183. package/dist/components/cms/versions-pane.js.map +1 -1
  184. package/dist/components/collection-view/cms-collection-view-source.js +24 -7
  185. package/dist/components/collection-view/cms-collection-view-source.js.map +1 -1
  186. package/dist/components/components/transfer-dialog.js +28 -23
  187. package/dist/components/components/transfer-dialog.js.map +1 -1
  188. package/dist/components/components/transfer.d.ts +31 -21
  189. package/dist/components/components/transfer.js +49 -35
  190. package/dist/components/components/transfer.js.map +1 -1
  191. package/dist/components/project-list.js.map +1 -1
  192. package/dist/components/project-session.d.ts +6 -3
  193. package/dist/components/project-session.js +14 -8
  194. package/dist/components/project-session.js.map +1 -1
  195. package/dist/components/project-switcher.js.map +1 -1
  196. package/dist/components/rail-view-source.js +2 -1
  197. package/dist/components/rail-view-source.js.map +1 -1
  198. package/dist/components/section-nav.js +1 -1
  199. package/dist/components/section-nav.js.map +1 -1
  200. package/dist/lib/ai/apply-content.js +56 -116
  201. package/dist/lib/ai/apply-content.js.map +1 -1
  202. package/dist/lib/ai/chat-context.d.ts +8 -0
  203. package/dist/lib/ai/chat-context.js +37 -6
  204. package/dist/lib/ai/chat-context.js.map +1 -1
  205. package/dist/lib/ai/chat-state.d.ts +14 -1
  206. package/dist/lib/ai/chat-state.js.map +1 -1
  207. package/dist/lib/ai/constraints.d.ts +20 -5
  208. package/dist/lib/ai/constraints.js +125 -33
  209. package/dist/lib/ai/constraints.js.map +1 -1
  210. package/dist/lib/ai/fake-provider.d.ts +16 -3
  211. package/dist/lib/ai/fake-provider.js +22 -6
  212. package/dist/lib/ai/fake-provider.js.map +1 -1
  213. package/dist/lib/ai/index.d.ts +2 -0
  214. package/dist/lib/ai/index.js +2 -0
  215. package/dist/lib/ai/index.js.map +1 -1
  216. package/dist/lib/ai/leash.d.ts +34 -0
  217. package/dist/lib/ai/leash.js +28 -0
  218. package/dist/lib/ai/leash.js.map +1 -0
  219. package/dist/lib/ai/provenance.d.ts +1 -1
  220. package/dist/lib/ai/provenance.js.map +1 -1
  221. package/dist/lib/ai/rich-text-input.d.ts +8 -8
  222. package/dist/lib/ai/rich-text-input.js +2 -1
  223. package/dist/lib/ai/rich-text-input.js.map +1 -1
  224. package/dist/lib/ai/rich-text-translate.d.ts +27 -4
  225. package/dist/lib/ai/rich-text-translate.js +28 -10
  226. package/dist/lib/ai/rich-text-translate.js.map +1 -1
  227. package/dist/lib/ai/shape.d.ts +13 -13
  228. package/dist/lib/ai/shape.js +69 -93
  229. package/dist/lib/ai/shape.js.map +1 -1
  230. package/dist/lib/ai/tools.d.ts +36 -41
  231. package/dist/lib/ai/tools.js +85 -87
  232. package/dist/lib/ai/tools.js.map +1 -1
  233. package/dist/lib/ai/translate-document.d.ts +39 -5
  234. package/dist/lib/ai/translate-document.js +160 -51
  235. package/dist/lib/ai/translate-document.js.map +1 -1
  236. package/dist/lib/ai/types.d.ts +34 -23
  237. package/dist/lib/ai/types.js.map +1 -1
  238. package/dist/lib/ai/update-fields.d.ts +21 -12
  239. package/dist/lib/ai/update-fields.js +118 -177
  240. package/dist/lib/ai/update-fields.js.map +1 -1
  241. package/dist/lib/ai/writer-form.d.ts +116 -0
  242. package/dist/lib/ai/writer-form.js +429 -0
  243. package/dist/lib/ai/writer-form.js.map +1 -0
  244. package/dist/lib/ai-current-document.d.ts +11 -11
  245. package/dist/lib/ai-current-document.js +4 -4
  246. package/dist/lib/ai-current-document.js.map +1 -1
  247. package/dist/lib/assets/upload.d.ts +31 -2
  248. package/dist/lib/assets/upload.js +61 -6
  249. package/dist/lib/assets/upload.js.map +1 -1
  250. package/dist/lib/clipboard/os-clipboard.d.ts +10 -2
  251. package/dist/lib/clipboard/os-clipboard.js +8 -4
  252. package/dist/lib/clipboard/os-clipboard.js.map +1 -1
  253. package/dist/lib/clipboard/paste-target.d.ts +18 -9
  254. package/dist/lib/clipboard/paste-target.js +8 -7
  255. package/dist/lib/clipboard/paste-target.js.map +1 -1
  256. package/dist/lib/cms/field-patch.d.ts +15 -0
  257. package/dist/lib/cms/field-patch.js +25 -0
  258. package/dist/lib/cms/field-patch.js.map +1 -0
  259. package/dist/lib/cms/published-documents.d.ts +1 -1
  260. package/dist/lib/cms/published-documents.js +1 -1
  261. package/dist/lib/cms/published-documents.js.map +1 -1
  262. package/dist/lib/cms-views/view-model.d.ts +3 -3
  263. package/dist/lib/collection-view/__fixtures__/document-writes.d.ts +6 -0
  264. package/dist/lib/collection-view/__fixtures__/document-writes.js +23 -0
  265. package/dist/lib/collection-view/__fixtures__/document-writes.js.map +1 -0
  266. package/dist/lib/collection-view/collection-view-source.d.ts +69 -6
  267. package/dist/lib/collection-view/collection-view-source.js.map +1 -1
  268. package/dist/lib/data/collection-content.d.ts +4 -13
  269. package/dist/lib/data/collection-content.js +11 -5
  270. package/dist/lib/data/collection-content.js.map +1 -1
  271. package/dist/lib/dnd/drop-rules.d.ts +25 -31
  272. package/dist/lib/dnd/drop-rules.js +53 -59
  273. package/dist/lib/dnd/drop-rules.js.map +1 -1
  274. package/dist/lib/engine-version.d.ts +1 -1
  275. package/dist/lib/engine-version.js +1 -1
  276. package/dist/lib/engine-version.js.map +1 -1
  277. package/dist/lib/i18n/messages.de.js +72 -15
  278. package/dist/lib/i18n/messages.de.js.map +1 -1
  279. package/dist/lib/i18n/messages.en.d.ts +61 -12
  280. package/dist/lib/i18n/messages.en.js +76 -16
  281. package/dist/lib/i18n/messages.en.js.map +1 -1
  282. package/dist/lib/operations/__fixtures__/write-document.d.ts +30 -0
  283. package/dist/lib/operations/__fixtures__/write-document.js +16 -0
  284. package/dist/lib/operations/__fixtures__/write-document.js.map +1 -0
  285. package/dist/lib/operations/cms-persistence.d.ts +124 -31
  286. package/dist/lib/operations/cms-persistence.js +447 -68
  287. package/dist/lib/operations/cms-persistence.js.map +1 -1
  288. package/dist/lib/operations/config-manifest-lookup.d.ts +35 -0
  289. package/dist/lib/operations/config-manifest-lookup.js +56 -0
  290. package/dist/lib/operations/config-manifest-lookup.js.map +1 -0
  291. package/dist/lib/operations/project-runtime-config.d.ts +39 -0
  292. package/dist/lib/operations/project-runtime-config.js +54 -0
  293. package/dist/lib/operations/project-runtime-config.js.map +1 -0
  294. package/dist/lib/operations/publish-with-revision.d.ts +64 -0
  295. package/dist/lib/operations/publish-with-revision.js +66 -0
  296. package/dist/lib/operations/publish-with-revision.js.map +1 -0
  297. package/dist/lib/operations/runtime-validator.d.ts +32 -0
  298. package/dist/lib/operations/runtime-validator.js +18 -0
  299. package/dist/lib/operations/runtime-validator.js.map +1 -0
  300. package/dist/lib/operations/session-hydration.d.ts +31 -14
  301. package/dist/lib/operations/session-hydration.js +12 -16
  302. package/dist/lib/operations/session-hydration.js.map +1 -1
  303. package/dist/lib/operations/studio-operations.d.ts +59 -2
  304. package/dist/lib/operations/studio-operations.js +76 -14
  305. package/dist/lib/operations/studio-operations.js.map +1 -1
  306. package/dist/lib/persistence/convex-adapter.d.ts +13 -5
  307. package/dist/lib/persistence/convex-adapter.js +189 -74
  308. package/dist/lib/persistence/convex-adapter.js.map +1 -1
  309. package/dist/lib/persistence/convex-client.d.ts +65 -5
  310. package/dist/lib/persistence/convex-client.js +106 -3
  311. package/dist/lib/persistence/convex-client.js.map +1 -1
  312. package/dist/lib/persistence/index.js +17 -18
  313. package/dist/lib/persistence/index.js.map +1 -1
  314. package/dist/lib/persona/labels.js +4 -1
  315. package/dist/lib/persona/labels.js.map +1 -1
  316. package/dist/lib/query/operations-query.d.ts +1 -1
  317. package/dist/lib/query/operations-query.js +1 -1
  318. package/dist/lib/query/operations-query.js.map +1 -1
  319. package/dist/lib/references/impact.d.ts +21 -15
  320. package/dist/lib/references/impact.js +13 -26
  321. package/dist/lib/references/impact.js.map +1 -1
  322. package/dist/lib/references/references-store.d.ts +9 -0
  323. package/dist/lib/references/references-store.js +24 -4
  324. package/dist/lib/references/references-store.js.map +1 -1
  325. package/dist/lib/routes/route-issues.d.ts +6 -6
  326. package/dist/lib/routes/route-issues.js +26 -80
  327. package/dist/lib/routes/route-issues.js.map +1 -1
  328. package/dist/lib/workspace/config-issues.js +2 -1
  329. package/dist/lib/workspace/config-issues.js.map +1 -1
  330. package/dist/lib/workspace/index.d.ts +31 -1
  331. package/dist/lib/workspace/index.js +64 -17
  332. package/dist/lib/workspace/index.js.map +1 -1
  333. package/dist/lib/workspace/switcher-source.d.ts +3 -3
  334. package/dist/lib/workspace/switcher-source.js.map +1 -1
  335. package/dist/lib/workspace/workspace-source.d.ts +2 -2
  336. package/dist/lib/workspace/workspace-source.js +2 -1
  337. package/dist/lib/workspace/workspace-source.js.map +1 -1
  338. package/package.json +3 -3
  339. package/dist/components/cms/cms-composition-validators.d.ts +0 -16
  340. package/dist/components/cms/cms-composition-validators.js +0 -133
  341. package/dist/components/cms/cms-composition-validators.js.map +0 -1
  342. package/dist/components/cms/publish-clean.d.ts +0 -28
  343. package/dist/components/cms/publish-clean.js +0 -38
  344. package/dist/components/cms/publish-clean.js.map +0 -1
  345. package/dist/components/cms/use-save-mode.d.ts +0 -35
  346. package/dist/components/cms/use-save-mode.js +0 -54
  347. package/dist/components/cms/use-save-mode.js.map +0 -1
  348. package/dist/lib/assets/asset-placements.d.ts +0 -28
  349. package/dist/lib/assets/asset-placements.js +0 -83
  350. package/dist/lib/assets/asset-placements.js.map +0 -1
  351. package/dist/lib/cms/document-gate.d.ts +0 -47
  352. package/dist/lib/cms/document-gate.js +0 -61
  353. package/dist/lib/cms/document-gate.js.map +0 -1
@@ -1 +0,0 @@
1
- {"version":3,"file":"use-save-mode.js","sourceRoot":"","sources":["../../../src/components/cms/use-save-mode.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,OAAO,CAAA;AAIzC;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,kBAAkB,CAAC,KAAgD;IACjF,OAAO,CAAC,KAAK,CAAC,YAAY,IAAI,KAAK,CAAC,KAAK,CAAA;AAC3C,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,WAAW,CAAC,KAK3B;IACC,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,KAAK,CAAA;IAClD,MAAM,YAAY,GAAG,CAAC,UAAU,CAAA;IAChC,MAAM,QAAQ,GAAG,MAAM,CAAC,KAAK,CAAC,CAAA;IAC9B,QAAQ,CAAC,OAAO,GAAG,KAAK,CAAA;IACxB,MAAM,QAAQ,GAAG,MAAM,CAAC,KAAK,CAAC,CAAA;IAC9B,QAAQ,CAAC,OAAO,GAAG,KAAK,CAAA;IACxB,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,CAAC,CAAA;IAChC,SAAS,CAAC,OAAO,GAAG,MAAM,CAAA;IAC1B,MAAM,eAAe,GAAG,MAAM,CAAC,YAAY,CAAC,CAAA;IAC5C,eAAe,CAAC,OAAO,GAAG,YAAY,CAAA;IAEtC,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,YAAY;YAAE,OAAM,CAAC,kDAAkD;QAC3E,IAAI,CAAC,KAAK;YAAE,OAAM;QAClB,MAAM,KAAK,GAAG,MAAM,CAAC,UAAU,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,IAAI,CAAC,CAAA;QACrF,OAAO,GAAG,EAAE,CAAC,MAAM,CAAC,YAAY,CAAC,KAAK,CAAC,CAAA;IACzC,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,YAAY,CAAC,CAAC,CAAA;IAEhC,6EAA6E;IAC7E,6EAA6E;IAC7E,4EAA4E;IAC5E,SAAS,CACP,GAAG,EAAE,CAAC,GAAG,EAAE;QACT,IAAI,kBAAkB,CAAC,EAAE,YAAY,EAAE,eAAe,CAAC,OAAO,EAAE,KAAK,EAAE,QAAQ,CAAC,OAAO,EAAE,CAAC;YACxF,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAA;IAC5C,CAAC,EACD,EAAE,CACH,CAAA;IAED,OAAO,EAAE,YAAY,EAAE,CAAA;AACzB,CAAC","sourcesContent":["import { useEffect, useRef } from 'react'\nimport type { CmsDocument } from '@elytracms/core/cms-core'\nimport type { CollectionViewSource } from '@elytracms/studio/lib/collection-view/collection-view-source'\n\n/**\n * EC-225 / EC-240 — the two persistence disciplines the detail editor supports,\n * as one pure decision so the autosave scheduler and the unmount flush can never\n * diverge on WHEN a dirty draft is persisted silently:\n *\n * - A **publishing** rail AUTOSAVES: the draft persists 1s after the last edit and\n * publish is the deliberate commit — so a dirty draft is flushed both on the\n * debounce timer and on unmount (navigating away inside the debounce window).\n * - A **non-publishing** rail (users, EC-240) SAVES EXPLICITLY: edits stay in the\n * draft until the Save button, and an `UnsavedChangesGuard` protects navigation —\n * so it NEVER persists silently (returns false here).\n */\nexport function shouldPersistDraft(input: { explicitSave: boolean; dirty: boolean }): boolean {\n return !input.explicitSave && input.dirty\n}\n\n/**\n * EC-225 autosave · EC-240 explicit save. Owns the debounced autosave timer and\n * the unmount flush for a publishing rail; a non-publishing rail persists only via\n * its Save button (the caller's `UnsavedChangesGuard` covers navigation). Refs let\n * the unmount flush read the latest values without re-subscribing.\n *\n * Returns `explicitSave` — the caller renders the Save button + guard (explicit)\n * or the autosave status text (autosave) from it.\n */\nexport function useSaveMode(input: {\n canPublish: boolean\n dirty: boolean\n draft: CmsDocument\n source: CollectionViewSource\n}): { explicitSave: boolean } {\n const { canPublish, dirty, draft, source } = input\n const explicitSave = !canPublish\n const draftRef = useRef(draft)\n draftRef.current = draft\n const dirtyRef = useRef(dirty)\n dirtyRef.current = dirty\n const sourceRef = useRef(source)\n sourceRef.current = source\n const explicitSaveRef = useRef(explicitSave)\n explicitSaveRef.current = explicitSave\n\n useEffect(() => {\n if (explicitSave) return // explicit rails persist only via the Save button\n if (!dirty) return\n const timer = window.setTimeout(() => sourceRef.current.save(draftRef.current), 1000)\n return () => window.clearTimeout(timer)\n }, [dirty, draft, explicitSave])\n\n // Flush a still-pending AUTOSAVE edit on unmount (navigating away inside the\n // debounce window) so nothing is lost. Explicit rails never flush silently —\n // their `UnsavedChangesGuard` catches the navigation instead. Unmount-only.\n useEffect(\n () => () => {\n if (shouldPersistDraft({ explicitSave: explicitSaveRef.current, dirty: dirtyRef.current }))\n sourceRef.current.save(draftRef.current)\n },\n [],\n )\n\n return { explicitSave }\n}\n"]}
@@ -1,28 +0,0 @@
1
- /** The ids the field should hold next. The shape follows the field's cardinality. */
2
- export type AssetPlacementTarget = {
3
- multiple: false;
4
- id: string | null;
5
- } | {
6
- multiple: true;
7
- ids: readonly string[];
8
- };
9
- /**
10
- * Return the field's next value with every placement's per-use sub-fields kept.
11
- *
12
- * - **Single field.** The placement's sub-fields carry over to whatever id now fills
13
- * it, so swapping the image keeps the caption. Re-picking the same id is a no-op,
14
- * and `null` clears the field (`undefined`).
15
- * - **Multiple field.** An id the value already held keeps its entry verbatim, with
16
- * its sub-fields and its form (a bare id stays bare). Entries are matched in order,
17
- * so an image placed twice keeps both placements. An id the value did not hold
18
- * becomes a new envelope. A held entry whose id is not in `ids` is removed, and an
19
- * emptied list is ABSENT (`undefined`, EC-586), never `[]`.
20
- *
21
- * The rule carries every key except `type`/`id`, the same set that `assetSubfieldsOf`
22
- * reads. That includes keys the config no longer declares (AD-14: the schema is a
23
- * lens, so a writer never deletes what the lens does not show).
24
- *
25
- * When nothing changes it returns `current` itself (the same reference), so a caller
26
- * can skip the write.
27
- */
28
- export declare function carryAssetPlacements(current: unknown, next: AssetPlacementTarget): unknown;
@@ -1,83 +0,0 @@
1
- /**
2
- * The per-use sub-field carry rule for an asset field's value (EC-558).
3
- *
4
- * An asset field that declares per-use sub-fields (EC-301) stores envelopes such as
5
- * `{ type: 'asset', id, caption }`. Those sub-fields are PLACEMENT data: they
6
- * describe this use of the image, not the image itself (owner ruling 2026-09-26;
7
- * data that describes the image belongs on the asset record's `meta`). A writer
8
- * that changes which image a placement shows must therefore keep the placement's
9
- * sub-fields. Before EC-558 only the detail editor did that. The table cell and AI
10
- * `updateFields` rebuilt the value from bare ids and lost them.
11
- *
12
- * {@link carryAssetPlacements} is the one declaration of that rule. Two operations
13
- * go through it:
14
- * - **append / pick**: the table cell and the detail editor
15
- * (`applyAssetSelection` / `appendAssetSelections` in
16
- * `components/assets/asset-selection.ts`). The next list is the held list plus
17
- * the picked ids, and a single field swaps its one placement's image.
18
- * - **replace-with-list**: AI `updateFields` (`lib/ai/update-fields.ts`). The next
19
- * list is the list the model sent.
20
- *
21
- * It lives in `lib/` because `lib/ai` may not import from `components/`, and both
22
- * sides need it. Its only dependency is `@elytracms/core/cms-core`, so the AI host
23
- * route pulls in nothing from the browser. Its natural home is next to `assetNode`
24
- * in `core/cms-core/envelopes.ts`. Move it there if a writer outside the studio
25
- * (import, CLI, MCP) appears.
26
- */
27
- import { assetNode, assetSubfieldsOf, readAssetId } from '@elytracms/core/cms-core';
28
- /**
29
- * A BRAND-NEW placement, which has no sub-fields yet: always the canonical envelope
30
- * (EC-586, ratified 2c — an asset value is `{ type: 'asset', id, … }`). There used to be
31
- * a second, bare spelling (`'bare'`, a plain id string) for fields without sub-fields;
32
- * the write lens wrapped it on save, so the in-session draft held a shape the stored one
33
- * did not, and a def-less "has unpublished changes" verdict read the two as different.
34
- */
35
- function newPlacement(id) {
36
- return assetNode(id);
37
- }
38
- /**
39
- * Return the field's next value with every placement's per-use sub-fields kept.
40
- *
41
- * - **Single field.** The placement's sub-fields carry over to whatever id now fills
42
- * it, so swapping the image keeps the caption. Re-picking the same id is a no-op,
43
- * and `null` clears the field (`undefined`).
44
- * - **Multiple field.** An id the value already held keeps its entry verbatim, with
45
- * its sub-fields and its form (a bare id stays bare). Entries are matched in order,
46
- * so an image placed twice keeps both placements. An id the value did not hold
47
- * becomes a new envelope. A held entry whose id is not in `ids` is removed, and an
48
- * emptied list is ABSENT (`undefined`, EC-586), never `[]`.
49
- *
50
- * The rule carries every key except `type`/`id`, the same set that `assetSubfieldsOf`
51
- * reads. That includes keys the config no longer declares (AD-14: the schema is a
52
- * lens, so a writer never deletes what the lens does not show).
53
- *
54
- * When nothing changes it returns `current` itself (the same reference), so a caller
55
- * can skip the write.
56
- */
57
- export function carryAssetPlacements(current, next) {
58
- if (!next.multiple) {
59
- if (next.id === null)
60
- return undefined;
61
- // `singleAssetIdOf` tolerates a legacy one-item array on a single field, so read
62
- // its placement the same way.
63
- const held = Array.isArray(current) ? current[0] : current;
64
- if (readAssetId(held) === next.id)
65
- return current;
66
- const subfields = assetSubfieldsOf(held);
67
- return Object.keys(subfields).length > 0 ? assetNode(next.id, subfields) : newPlacement(next.id);
68
- }
69
- const held = Array.isArray(current) ? current : [];
70
- const used = new Set();
71
- const out = next.ids.map((id) => {
72
- const index = held.findIndex((entry, i) => !used.has(i) && readAssetId(entry) === id);
73
- if (index < 0)
74
- return newPlacement(id);
75
- used.add(index);
76
- return held[index];
77
- });
78
- const unchanged = out.length === held.length && out.every((entry, i) => entry === held[i]);
79
- if (unchanged && Array.isArray(current))
80
- return current;
81
- return out.length === 0 ? undefined : out;
82
- }
83
- //# sourceMappingURL=asset-placements.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"asset-placements.js","sourceRoot":"","sources":["../../../src/lib/assets/asset-placements.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAA;AAOnF;;;;;;GAMG;AACH,SAAS,YAAY,CAAC,EAAU;IAC9B,OAAO,SAAS,CAAC,EAAE,CAAC,CAAA;AACtB,CAAC;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,UAAU,oBAAoB,CAAC,OAAgB,EAAE,IAA0B;IAC/E,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC;QACnB,IAAI,IAAI,CAAC,EAAE,KAAK,IAAI;YAAE,OAAO,SAAS,CAAA;QACtC,iFAAiF;QACjF,8BAA8B;QAC9B,MAAM,IAAI,GAAG,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAA;QAC1D,IAAI,WAAW,CAAC,IAAI,CAAC,KAAK,IAAI,CAAC,EAAE;YAAE,OAAO,OAAO,CAAA;QACjD,MAAM,SAAS,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAA;QACxC,OAAO,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;IAClG,CAAC;IAED,MAAM,IAAI,GAAG,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAE,OAAqB,CAAC,CAAC,CAAC,EAAE,CAAA;IACjE,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAA;IAC9B,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE;QAC9B,MAAM,KAAK,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,WAAW,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC,CAAA;QACrF,IAAI,KAAK,GAAG,CAAC;YAAE,OAAO,YAAY,CAAC,EAAE,CAAC,CAAA;QACtC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;QACf,OAAO,IAAI,CAAC,KAAK,CAAC,CAAA;IACpB,CAAC,CAAC,CAAA;IACF,MAAM,SAAS,GAAG,GAAG,CAAC,MAAM,KAAK,IAAI,CAAC,MAAM,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,CAAA;IAC1F,IAAI,SAAS,IAAI,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC;QAAE,OAAO,OAAO,CAAA;IACvD,OAAO,GAAG,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,CAAA;AAC3C,CAAC","sourcesContent":["/**\n * The per-use sub-field carry rule for an asset field's value (EC-558).\n *\n * An asset field that declares per-use sub-fields (EC-301) stores envelopes such as\n * `{ type: 'asset', id, caption }`. Those sub-fields are PLACEMENT data: they\n * describe this use of the image, not the image itself (owner ruling 2026-09-26;\n * data that describes the image belongs on the asset record's `meta`). A writer\n * that changes which image a placement shows must therefore keep the placement's\n * sub-fields. Before EC-558 only the detail editor did that. The table cell and AI\n * `updateFields` rebuilt the value from bare ids and lost them.\n *\n * {@link carryAssetPlacements} is the one declaration of that rule. Two operations\n * go through it:\n * - **append / pick**: the table cell and the detail editor\n * (`applyAssetSelection` / `appendAssetSelections` in\n * `components/assets/asset-selection.ts`). The next list is the held list plus\n * the picked ids, and a single field swaps its one placement's image.\n * - **replace-with-list**: AI `updateFields` (`lib/ai/update-fields.ts`). The next\n * list is the list the model sent.\n *\n * It lives in `lib/` because `lib/ai` may not import from `components/`, and both\n * sides need it. Its only dependency is `@elytracms/core/cms-core`, so the AI host\n * route pulls in nothing from the browser. Its natural home is next to `assetNode`\n * in `core/cms-core/envelopes.ts`. Move it there if a writer outside the studio\n * (import, CLI, MCP) appears.\n */\nimport { assetNode, assetSubfieldsOf, readAssetId } from '@elytracms/core/cms-core'\n\n/** The ids the field should hold next. The shape follows the field's cardinality. */\nexport type AssetPlacementTarget =\n | { multiple: false; id: string | null }\n | { multiple: true; ids: readonly string[] }\n\n/**\n * A BRAND-NEW placement, which has no sub-fields yet: always the canonical envelope\n * (EC-586, ratified 2c — an asset value is `{ type: 'asset', id, … }`). There used to be\n * a second, bare spelling (`'bare'`, a plain id string) for fields without sub-fields;\n * the write lens wrapped it on save, so the in-session draft held a shape the stored one\n * did not, and a def-less \"has unpublished changes\" verdict read the two as different.\n */\nfunction newPlacement(id: string): unknown {\n return assetNode(id)\n}\n\n/**\n * Return the field's next value with every placement's per-use sub-fields kept.\n *\n * - **Single field.** The placement's sub-fields carry over to whatever id now fills\n * it, so swapping the image keeps the caption. Re-picking the same id is a no-op,\n * and `null` clears the field (`undefined`).\n * - **Multiple field.** An id the value already held keeps its entry verbatim, with\n * its sub-fields and its form (a bare id stays bare). Entries are matched in order,\n * so an image placed twice keeps both placements. An id the value did not hold\n * becomes a new envelope. A held entry whose id is not in `ids` is removed, and an\n * emptied list is ABSENT (`undefined`, EC-586), never `[]`.\n *\n * The rule carries every key except `type`/`id`, the same set that `assetSubfieldsOf`\n * reads. That includes keys the config no longer declares (AD-14: the schema is a\n * lens, so a writer never deletes what the lens does not show).\n *\n * When nothing changes it returns `current` itself (the same reference), so a caller\n * can skip the write.\n */\nexport function carryAssetPlacements(current: unknown, next: AssetPlacementTarget): unknown {\n if (!next.multiple) {\n if (next.id === null) return undefined\n // `singleAssetIdOf` tolerates a legacy one-item array on a single field, so read\n // its placement the same way.\n const held = Array.isArray(current) ? current[0] : current\n if (readAssetId(held) === next.id) return current\n const subfields = assetSubfieldsOf(held)\n return Object.keys(subfields).length > 0 ? assetNode(next.id, subfields) : newPlacement(next.id)\n }\n\n const held = Array.isArray(current) ? (current as unknown[]) : []\n const used = new Set<number>()\n const out = next.ids.map((id) => {\n const index = held.findIndex((entry, i) => !used.has(i) && readAssetId(entry) === id)\n if (index < 0) return newPlacement(id)\n used.add(index)\n return held[index]\n })\n const unchanged = out.length === held.length && out.every((entry, i) => entry === held[i])\n if (unchanged && Array.isArray(current)) return current\n return out.length === 0 ? undefined : out\n}\n"]}
@@ -1,47 +0,0 @@
1
- import type { CmsDocument, CmsValidationIssue } from '@elytracms/core/cms-core';
2
- /**
3
- * The publish-gate seam (EC-497) — a framework-free module store, the same shape
4
- * as the current-document seam (`lib/ai-current-document`).
5
- *
6
- * `createOperations` is a module singleton built long before (and independently
7
- * of) any React tree, while gate-strength validation needs the live CMS session:
8
- * its document store, its asset oracle, its published-ness pointer. So the CMS
9
- * session PUBLISHES a validator here while mounted, and
10
- * `createStudioOperations` hands this module's reader to the operations layer
11
- * once, at bootstrap.
12
- *
13
- * **EC-546 — a gate that cannot see says so.** The first cut had the reader return
14
- * `undefined` with nothing registered, meaning "no session context here", and
15
- * the operations gate answered that by falling back to an optionless
16
- * `validateDocument` over the adapter's schema record: scalar rules only, no
17
- * store, no locale config, no composition or embed leash. Measured: a document
18
- * carrying a component outside its slot's `allow` published through
19
- * `createStudioOperations` whenever the stack was empty. That is the exact
20
- * weaker, mode-dependent gate EC-497 removed, kept alive by a mount-state side
21
- * channel. So the reader now answers with issues ONLY: with nothing registered it
22
- * returns one blocking `error` issue — the publish is refused and the refusal is
23
- * visible — and the operations layer no longer has a fallback to take (its
24
- * `DocumentValidator` cannot return `undefined`).
25
- *
26
- * This module imports nothing but types, so hanging the seam off it never drags
27
- * the CMS session (or the component registry behind the composition validators)
28
- * into the operations bootstrap's module graph.
29
- */
30
- export type SessionDocumentValidator = (document: CmsDocument) => readonly CmsValidationIssue[];
31
- /** The catalog key of the refusal the reader emits with no session mounted (EC-546). */
32
- export declare const NO_VALIDATION_SESSION_MESSAGE_KEY = "cms.issueMessage.noValidationSession";
33
- /** Publish the session's canonical document validator (`null` clears the stack). */
34
- export declare function setSessionDocumentValidator(next: SessionDocumentValidator | null): void;
35
- /**
36
- * Remove this validator — the unmount race guard. Removing an INNER session
37
- * leaves the outer one in place; removing one that already left is a no-op (a
38
- * remount registers the new validator before the old effect's cleanup runs).
39
- */
40
- export declare function clearSessionDocumentValidator(owned: SessionDocumentValidator): void;
41
- /**
42
- * The reader handed to `createOperations`. The innermost session's verdict, or —
43
- * with no session mounted — the blocking refusal described on
44
- * {@link SessionDocumentValidator}. Never `undefined`: the operations layer's
45
- * `DocumentValidator` has no fallback to offer and no longer accepts one (EC-546).
46
- */
47
- export declare function sessionValidateDocument(document: CmsDocument): readonly CmsValidationIssue[];
@@ -1,61 +0,0 @@
1
- /**
2
- * Registered sessions, innermost LAST — a stack, not a single slot, because more
3
- * than one `CmsProvider` can be mounted at a time: the "Use in document…"
4
- * transfer dialog mounts its own over the app's
5
- * (`components/transfer-dialog.tsx:92`). With a single slot, closing that dialog
6
- * would clear the seam and silently drop the publish gate back to its fallback
7
- * for the rest of the app's life — a regression invisible until something
8
- * published. Popping restores the outer session instead.
9
- */
10
- const registered = [];
11
- /** The catalog key of the refusal the reader emits with no session mounted (EC-546). */
12
- export const NO_VALIDATION_SESSION_MESSAGE_KEY = 'cms.issueMessage.noValidationSession';
13
- /**
14
- * The verdict with no session mounted: one blocking issue, never a pass and never
15
- * `undefined`. `custom-validation` is the code for a rule the engine's field
16
- * vocabulary does not name — this is a host rule ("publish only through a mounted
17
- * session"), not a finding about the document — and the message carries the
18
- * meaning. Published via the same `messageRef` the engine's issues use, so the
19
- * studio's operation-error banner renders it in the active locale (EC-494).
20
- */
21
- const NO_SESSION_REFUSAL = [
22
- {
23
- code: 'custom-validation',
24
- severity: 'error',
25
- message: 'No validation session is mounted — refusing to publish unvalidated.',
26
- messageRef: { key: NO_VALIDATION_SESSION_MESSAGE_KEY },
27
- path: [],
28
- },
29
- ];
30
- /** Publish the session's canonical document validator (`null` clears the stack). */
31
- export function setSessionDocumentValidator(next) {
32
- if (next === null) {
33
- registered.length = 0;
34
- return;
35
- }
36
- const at = registered.indexOf(next);
37
- if (at >= 0)
38
- registered.splice(at, 1);
39
- registered.push(next);
40
- }
41
- /**
42
- * Remove this validator — the unmount race guard. Removing an INNER session
43
- * leaves the outer one in place; removing one that already left is a no-op (a
44
- * remount registers the new validator before the old effect's cleanup runs).
45
- */
46
- export function clearSessionDocumentValidator(owned) {
47
- const at = registered.indexOf(owned);
48
- if (at >= 0)
49
- registered.splice(at, 1);
50
- }
51
- /**
52
- * The reader handed to `createOperations`. The innermost session's verdict, or —
53
- * with no session mounted — the blocking refusal described on
54
- * {@link SessionDocumentValidator}. Never `undefined`: the operations layer's
55
- * `DocumentValidator` has no fallback to offer and no longer accepts one (EC-546).
56
- */
57
- export function sessionValidateDocument(document) {
58
- const session = registered.at(-1);
59
- return session ? session(document) : NO_SESSION_REFUSAL;
60
- }
61
- //# sourceMappingURL=document-gate.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"document-gate.js","sourceRoot":"","sources":["../../../src/lib/cms/document-gate.ts"],"names":[],"mappings":"AAgCA;;;;;;;;GAQG;AACH,MAAM,UAAU,GAA+B,EAAE,CAAA;AAEjD,wFAAwF;AACxF,MAAM,CAAC,MAAM,iCAAiC,GAAG,sCAAsC,CAAA;AAEvF;;;;;;;GAOG;AACH,MAAM,kBAAkB,GAAkC;IACxD;QACE,IAAI,EAAE,mBAAmB;QACzB,QAAQ,EAAE,OAAO;QACjB,OAAO,EAAE,qEAAqE;QAC9E,UAAU,EAAE,EAAE,GAAG,EAAE,iCAAiC,EAAE;QACtD,IAAI,EAAE,EAAE;KACT;CACF,CAAA;AAED,oFAAoF;AACpF,MAAM,UAAU,2BAA2B,CAAC,IAAqC;IAC/E,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;QAClB,UAAU,CAAC,MAAM,GAAG,CAAC,CAAA;QACrB,OAAM;IACR,CAAC;IACD,MAAM,EAAE,GAAG,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,CAAA;IACnC,IAAI,EAAE,IAAI,CAAC;QAAE,UAAU,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC,CAAA;IACrC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AACvB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,6BAA6B,CAAC,KAA+B;IAC3E,MAAM,EAAE,GAAG,UAAU,CAAC,OAAO,CAAC,KAAK,CAAC,CAAA;IACpC,IAAI,EAAE,IAAI,CAAC;QAAE,UAAU,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC,CAAA;AACvC,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,uBAAuB,CAAC,QAAqB;IAC3D,MAAM,OAAO,GAAG,UAAU,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAA;IACjC,OAAO,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,kBAAkB,CAAA;AACzD,CAAC","sourcesContent":["import type { CmsDocument, CmsValidationIssue } from '@elytracms/core/cms-core'\n\n/**\n * The publish-gate seam (EC-497) — a framework-free module store, the same shape\n * as the current-document seam (`lib/ai-current-document`).\n *\n * `createOperations` is a module singleton built long before (and independently\n * of) any React tree, while gate-strength validation needs the live CMS session:\n * its document store, its asset oracle, its published-ness pointer. So the CMS\n * session PUBLISHES a validator here while mounted, and\n * `createStudioOperations` hands this module's reader to the operations layer\n * once, at bootstrap.\n *\n * **EC-546 — a gate that cannot see says so.** The first cut had the reader return\n * `undefined` with nothing registered, meaning \"no session context here\", and\n * the operations gate answered that by falling back to an optionless\n * `validateDocument` over the adapter's schema record: scalar rules only, no\n * store, no locale config, no composition or embed leash. Measured: a document\n * carrying a component outside its slot's `allow` published through\n * `createStudioOperations` whenever the stack was empty. That is the exact\n * weaker, mode-dependent gate EC-497 removed, kept alive by a mount-state side\n * channel. So the reader now answers with issues ONLY: with nothing registered it\n * returns one blocking `error` issue — the publish is refused and the refusal is\n * visible — and the operations layer no longer has a fallback to take (its\n * `DocumentValidator` cannot return `undefined`).\n *\n * This module imports nothing but types, so hanging the seam off it never drags\n * the CMS session (or the component registry behind the composition validators)\n * into the operations bootstrap's module graph.\n */\nexport type SessionDocumentValidator = (document: CmsDocument) => readonly CmsValidationIssue[]\n\n/**\n * Registered sessions, innermost LAST — a stack, not a single slot, because more\n * than one `CmsProvider` can be mounted at a time: the \"Use in document…\"\n * transfer dialog mounts its own over the app's\n * (`components/transfer-dialog.tsx:92`). With a single slot, closing that dialog\n * would clear the seam and silently drop the publish gate back to its fallback\n * for the rest of the app's life — a regression invisible until something\n * published. Popping restores the outer session instead.\n */\nconst registered: SessionDocumentValidator[] = []\n\n/** The catalog key of the refusal the reader emits with no session mounted (EC-546). */\nexport const NO_VALIDATION_SESSION_MESSAGE_KEY = 'cms.issueMessage.noValidationSession'\n\n/**\n * The verdict with no session mounted: one blocking issue, never a pass and never\n * `undefined`. `custom-validation` is the code for a rule the engine's field\n * vocabulary does not name — this is a host rule (\"publish only through a mounted\n * session\"), not a finding about the document — and the message carries the\n * meaning. Published via the same `messageRef` the engine's issues use, so the\n * studio's operation-error banner renders it in the active locale (EC-494).\n */\nconst NO_SESSION_REFUSAL: readonly CmsValidationIssue[] = [\n {\n code: 'custom-validation',\n severity: 'error',\n message: 'No validation session is mounted — refusing to publish unvalidated.',\n messageRef: { key: NO_VALIDATION_SESSION_MESSAGE_KEY },\n path: [],\n },\n]\n\n/** Publish the session's canonical document validator (`null` clears the stack). */\nexport function setSessionDocumentValidator(next: SessionDocumentValidator | null): void {\n if (next === null) {\n registered.length = 0\n return\n }\n const at = registered.indexOf(next)\n if (at >= 0) registered.splice(at, 1)\n registered.push(next)\n}\n\n/**\n * Remove this validator — the unmount race guard. Removing an INNER session\n * leaves the outer one in place; removing one that already left is a no-op (a\n * remount registers the new validator before the old effect's cleanup runs).\n */\nexport function clearSessionDocumentValidator(owned: SessionDocumentValidator): void {\n const at = registered.indexOf(owned)\n if (at >= 0) registered.splice(at, 1)\n}\n\n/**\n * The reader handed to `createOperations`. The innermost session's verdict, or —\n * with no session mounted — the blocking refusal described on\n * {@link SessionDocumentValidator}. Never `undefined`: the operations layer's\n * `DocumentValidator` has no fallback to offer and no longer accepts one (EC-546).\n */\nexport function sessionValidateDocument(document: CmsDocument): readonly CmsValidationIssue[] {\n const session = registered.at(-1)\n return session ? session(document) : NO_SESSION_REFUSAL\n}\n"]}