@elytracms/studio 0.0.1

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 (558) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +3 -0
  3. package/convex/assets.ts +107 -0
  4. package/convex/auth.config.ts +15 -0
  5. package/convex/auth.ts +50 -0
  6. package/convex/cliTokens.ts +63 -0
  7. package/convex/cms.ts +174 -0
  8. package/convex/content.ts +316 -0
  9. package/convex/delivery.ts +266 -0
  10. package/convex/functions.ts +35 -0
  11. package/convex/graphs.ts +51 -0
  12. package/convex/guard.ts +67 -0
  13. package/convex/http.ts +30 -0
  14. package/convex/members.ts +83 -0
  15. package/convex/publishing.ts +102 -0
  16. package/convex/references.ts +168 -0
  17. package/convex/schema.ts +173 -0
  18. package/convex/sync.ts +322 -0
  19. package/convex/tsconfig.json +12 -0
  20. package/convex/users.ts +23 -0
  21. package/convex/webhooks.ts +85 -0
  22. package/dist/components/assets/asset-library.d.ts +14 -0
  23. package/dist/components/assets/asset-library.js +191 -0
  24. package/dist/components/assets/asset-library.js.map +1 -0
  25. package/dist/components/assets/asset-metadata.d.ts +34 -0
  26. package/dist/components/assets/asset-metadata.js +40 -0
  27. package/dist/components/assets/asset-metadata.js.map +1 -0
  28. package/dist/components/assets/asset-search.d.ts +7 -0
  29. package/dist/components/assets/asset-search.js +12 -0
  30. package/dist/components/assets/asset-search.js.map +1 -0
  31. package/dist/components/assets/asset-selection.d.ts +17 -0
  32. package/dist/components/assets/asset-selection.js +33 -0
  33. package/dist/components/assets/asset-selection.js.map +1 -0
  34. package/dist/components/assets/assets-store.d.ts +51 -0
  35. package/dist/components/assets/assets-store.js +153 -0
  36. package/dist/components/assets/assets-store.js.map +1 -0
  37. package/dist/components/auth-context.d.ts +38 -0
  38. package/dist/components/auth-context.js +88 -0
  39. package/dist/components/auth-context.js.map +1 -0
  40. package/dist/components/backend-gate.d.ts +19 -0
  41. package/dist/components/backend-gate.js +63 -0
  42. package/dist/components/backend-gate.js.map +1 -0
  43. package/dist/components/breadcrumb-context.d.ts +39 -0
  44. package/dist/components/breadcrumb-context.js +38 -0
  45. package/dist/components/breadcrumb-context.js.map +1 -0
  46. package/dist/components/builder/blocks-model.d.ts +80 -0
  47. package/dist/components/builder/blocks-model.js +181 -0
  48. package/dist/components/builder/blocks-model.js.map +1 -0
  49. package/dist/components/builder/blocks-panel.d.ts +44 -0
  50. package/dist/components/builder/blocks-panel.js +147 -0
  51. package/dist/components/builder/blocks-panel.js.map +1 -0
  52. package/dist/components/builder/builder-store.d.ts +69 -0
  53. package/dist/components/builder/builder-store.js +294 -0
  54. package/dist/components/builder/builder-store.js.map +1 -0
  55. package/dist/components/builder/canvas-stylesheet.d.ts +4 -0
  56. package/dist/components/builder/canvas-stylesheet.js +24 -0
  57. package/dist/components/builder/canvas-stylesheet.js.map +1 -0
  58. package/dist/components/builder/canvas.d.ts +8 -0
  59. package/dist/components/builder/canvas.js +723 -0
  60. package/dist/components/builder/canvas.js.map +1 -0
  61. package/dist/components/builder/clipboard-actions.d.ts +93 -0
  62. package/dist/components/builder/clipboard-actions.js +246 -0
  63. package/dist/components/builder/clipboard-actions.js.map +1 -0
  64. package/dist/components/builder/composition-field-editor.d.ts +11 -0
  65. package/dist/components/builder/composition-field-editor.js +150 -0
  66. package/dist/components/builder/composition-field-editor.js.map +1 -0
  67. package/dist/components/builder/composition-scope.d.ts +16 -0
  68. package/dist/components/builder/composition-scope.js +7 -0
  69. package/dist/components/builder/composition-scope.js.map +1 -0
  70. package/dist/components/builder/drag-session.d.ts +41 -0
  71. package/dist/components/builder/drag-session.js +51 -0
  72. package/dist/components/builder/drag-session.js.map +1 -0
  73. package/dist/components/builder/fixture-thumbnail.d.ts +18 -0
  74. package/dist/components/builder/fixture-thumbnail.js +97 -0
  75. package/dist/components/builder/fixture-thumbnail.js.map +1 -0
  76. package/dist/components/builder/inline-edit.d.ts +142 -0
  77. package/dist/components/builder/inline-edit.js +136 -0
  78. package/dist/components/builder/inline-edit.js.map +1 -0
  79. package/dist/components/builder/insert-context.d.ts +14 -0
  80. package/dist/components/builder/insert-context.js +65 -0
  81. package/dist/components/builder/insert-context.js.map +1 -0
  82. package/dist/components/builder/insert-menu.d.ts +9 -0
  83. package/dist/components/builder/insert-menu.js +9 -0
  84. package/dist/components/builder/insert-menu.js.map +1 -0
  85. package/dist/components/builder/layout-inspector.d.ts +14 -0
  86. package/dist/components/builder/layout-inspector.js +84 -0
  87. package/dist/components/builder/layout-inspector.js.map +1 -0
  88. package/dist/components/builder/node-factory.d.ts +17 -0
  89. package/dist/components/builder/node-factory.js +90 -0
  90. package/dist/components/builder/node-factory.js.map +1 -0
  91. package/dist/components/builder/page-tree.d.ts +3 -0
  92. package/dist/components/builder/page-tree.js +207 -0
  93. package/dist/components/builder/page-tree.js.map +1 -0
  94. package/dist/components/builder/property-inspector.d.ts +1 -0
  95. package/dist/components/builder/property-inspector.js +233 -0
  96. package/dist/components/builder/property-inspector.js.map +1 -0
  97. package/dist/components/builder/rich-text-toolbar.d.ts +4 -0
  98. package/dist/components/builder/rich-text-toolbar.js +104 -0
  99. package/dist/components/builder/rich-text-toolbar.js.map +1 -0
  100. package/dist/components/builder/spacing-handles.d.ts +22 -0
  101. package/dist/components/builder/spacing-handles.js +213 -0
  102. package/dist/components/builder/spacing-handles.js.map +1 -0
  103. package/dist/components/cms/asset-picker.d.ts +12 -0
  104. package/dist/components/cms/asset-picker.js +60 -0
  105. package/dist/components/cms/asset-picker.js.map +1 -0
  106. package/dist/components/cms/bulk-actions.d.ts +60 -0
  107. package/dist/components/cms/bulk-actions.js +95 -0
  108. package/dist/components/cms/bulk-actions.js.map +1 -0
  109. package/dist/components/cms/bulk-bar.d.ts +23 -0
  110. package/dist/components/cms/bulk-bar.js +26 -0
  111. package/dist/components/cms/bulk-bar.js.map +1 -0
  112. package/dist/components/cms/cell-edit.d.ts +91 -0
  113. package/dist/components/cms/cell-edit.js +144 -0
  114. package/dist/components/cms/cell-edit.js.map +1 -0
  115. package/dist/components/cms/cell.d.ts +29 -0
  116. package/dist/components/cms/cell.js +127 -0
  117. package/dist/components/cms/cell.js.map +1 -0
  118. package/dist/components/cms/cms-index.d.ts +8 -0
  119. package/dist/components/cms/cms-index.js +23 -0
  120. package/dist/components/cms/cms-index.js.map +1 -0
  121. package/dist/components/cms/cms-store.d.ts +188 -0
  122. package/dist/components/cms/cms-store.js +702 -0
  123. package/dist/components/cms/cms-store.js.map +1 -0
  124. package/dist/components/cms/collection-table.d.ts +6 -0
  125. package/dist/components/cms/collection-table.js +250 -0
  126. package/dist/components/cms/collection-table.js.map +1 -0
  127. package/dist/components/cms/collections-sidebar.d.ts +9 -0
  128. package/dist/components/cms/collections-sidebar.js +25 -0
  129. package/dist/components/cms/collections-sidebar.js.map +1 -0
  130. package/dist/components/cms/detail-editor.d.ts +7 -0
  131. package/dist/components/cms/detail-editor.js +386 -0
  132. package/dist/components/cms/detail-editor.js.map +1 -0
  133. package/dist/components/cms/doc-state.d.ts +13 -0
  134. package/dist/components/cms/doc-state.js +18 -0
  135. package/dist/components/cms/doc-state.js.map +1 -0
  136. package/dist/components/cms/document-editor-context.d.ts +48 -0
  137. package/dist/components/cms/document-editor-context.js +23 -0
  138. package/dist/components/cms/document-editor-context.js.map +1 -0
  139. package/dist/components/cms/editable-cell.d.ts +22 -0
  140. package/dist/components/cms/editable-cell.js +176 -0
  141. package/dist/components/cms/editable-cell.js.map +1 -0
  142. package/dist/components/cms/field-control.d.ts +8 -0
  143. package/dist/components/cms/field-control.js +149 -0
  144. package/dist/components/cms/field-control.js.map +1 -0
  145. package/dist/components/cms/filter-builder.d.ts +12 -0
  146. package/dist/components/cms/filter-builder.js +84 -0
  147. package/dist/components/cms/filter-builder.js.map +1 -0
  148. package/dist/components/cms/import-export.d.ts +6 -0
  149. package/dist/components/cms/import-export.js +33 -0
  150. package/dist/components/cms/import-export.js.map +1 -0
  151. package/dist/components/cms/new-page-dialog.d.ts +22 -0
  152. package/dist/components/cms/new-page-dialog.js +42 -0
  153. package/dist/components/cms/new-page-dialog.js.map +1 -0
  154. package/dist/components/cms/reference-confirm.d.ts +25 -0
  155. package/dist/components/cms/reference-confirm.js +124 -0
  156. package/dist/components/cms/reference-confirm.js.map +1 -0
  157. package/dist/components/cms/relation-picker.d.ts +16 -0
  158. package/dist/components/cms/relation-picker.js +47 -0
  159. package/dist/components/cms/relation-picker.js.map +1 -0
  160. package/dist/components/cms/use-cell-edit.d.ts +33 -0
  161. package/dist/components/cms/use-cell-edit.js +125 -0
  162. package/dist/components/cms/use-cell-edit.js.map +1 -0
  163. package/dist/components/cms/versions-model.d.ts +15 -0
  164. package/dist/components/cms/versions-model.js +23 -0
  165. package/dist/components/cms/versions-model.js.map +1 -0
  166. package/dist/components/cms/versions-pane.d.ts +14 -0
  167. package/dist/components/cms/versions-pane.js +86 -0
  168. package/dist/components/cms/versions-pane.js.map +1 -0
  169. package/dist/components/cms/view-bar.d.ts +11 -0
  170. package/dist/components/cms/view-bar.js +80 -0
  171. package/dist/components/cms/view-bar.js.map +1 -0
  172. package/dist/components/collab/collab-context.d.ts +34 -0
  173. package/dist/components/collab/collab-context.js +52 -0
  174. package/dist/components/collab/collab-context.js.map +1 -0
  175. package/dist/components/collab/collab-seed.d.ts +27 -0
  176. package/dist/components/collab/collab-seed.js +42 -0
  177. package/dist/components/collab/collab-seed.js.map +1 -0
  178. package/dist/components/components/component-detail.d.ts +9 -0
  179. package/dist/components/components/component-detail.js +30 -0
  180. package/dist/components/components/component-detail.js.map +1 -0
  181. package/dist/components/components/component-status.d.ts +10 -0
  182. package/dist/components/components/component-status.js +30 -0
  183. package/dist/components/components/component-status.js.map +1 -0
  184. package/dist/components/components/components-index.d.ts +8 -0
  185. package/dist/components/components/components-index.js +42 -0
  186. package/dist/components/components/components-index.js.map +1 -0
  187. package/dist/components/components/field-inspector.d.ts +9 -0
  188. package/dist/components/components/field-inspector.js +38 -0
  189. package/dist/components/components/field-inspector.js.map +1 -0
  190. package/dist/components/components/fixture-runner.d.ts +10 -0
  191. package/dist/components/components/fixture-runner.js +24 -0
  192. package/dist/components/components/fixture-runner.js.map +1 -0
  193. package/dist/components/components/registry-browser.d.ts +4 -0
  194. package/dist/components/components/registry-browser.js +64 -0
  195. package/dist/components/components/registry-browser.js.map +1 -0
  196. package/dist/components/current-user-menu.d.ts +13 -0
  197. package/dist/components/current-user-menu.js +31 -0
  198. package/dist/components/current-user-menu.js.map +1 -0
  199. package/dist/components/dev-login-badge.d.ts +9 -0
  200. package/dist/components/dev-login-badge.js +18 -0
  201. package/dist/components/dev-login-badge.js.map +1 -0
  202. package/dist/components/extensions/extensions-view.d.ts +7 -0
  203. package/dist/components/extensions/extensions-view.js +126 -0
  204. package/dist/components/extensions/extensions-view.js.map +1 -0
  205. package/dist/components/guards.d.ts +27 -0
  206. package/dist/components/guards.js +46 -0
  207. package/dist/components/guards.js.map +1 -0
  208. package/dist/components/inspector/inspector-sidebar.d.ts +26 -0
  209. package/dist/components/inspector/inspector-sidebar.js +17 -0
  210. package/dist/components/inspector/inspector-sidebar.js.map +1 -0
  211. package/dist/components/operation-error.d.ts +17 -0
  212. package/dist/components/operation-error.js +54 -0
  213. package/dist/components/operation-error.js.map +1 -0
  214. package/dist/components/playground-badge.d.ts +10 -0
  215. package/dist/components/playground-badge.js +19 -0
  216. package/dist/components/playground-badge.js.map +1 -0
  217. package/dist/components/project-list.d.ts +15 -0
  218. package/dist/components/project-list.js +52 -0
  219. package/dist/components/project-list.js.map +1 -0
  220. package/dist/components/project-session.d.ts +46 -0
  221. package/dist/components/project-session.js +107 -0
  222. package/dist/components/project-session.js.map +1 -0
  223. package/dist/components/project-switcher.d.ts +11 -0
  224. package/dist/components/project-switcher.js +44 -0
  225. package/dist/components/project-switcher.js.map +1 -0
  226. package/dist/components/references/builder-deep-link.d.ts +12 -0
  227. package/dist/components/references/builder-deep-link.js +53 -0
  228. package/dist/components/references/builder-deep-link.js.map +1 -0
  229. package/dist/components/references/references-panel.d.ts +17 -0
  230. package/dist/components/references/references-panel.js +66 -0
  231. package/dist/components/references/references-panel.js.map +1 -0
  232. package/dist/components/routes/redirect-chain.d.ts +9 -0
  233. package/dist/components/routes/redirect-chain.js +16 -0
  234. package/dist/components/routes/redirect-chain.js.map +1 -0
  235. package/dist/components/routes/redirect-manager.d.ts +13 -0
  236. package/dist/components/routes/redirect-manager.js +24 -0
  237. package/dist/components/routes/redirect-manager.js.map +1 -0
  238. package/dist/components/routes/route-list.d.ts +35 -0
  239. package/dist/components/routes/route-list.js +69 -0
  240. package/dist/components/routes/route-list.js.map +1 -0
  241. package/dist/components/routes/routes-shell.d.ts +14 -0
  242. package/dist/components/routes/routes-shell.js +68 -0
  243. package/dist/components/routes/routes-shell.js.map +1 -0
  244. package/dist/components/section-nav.d.ts +17 -0
  245. package/dist/components/section-nav.js +33 -0
  246. package/dist/components/section-nav.js.map +1 -0
  247. package/dist/components/section-state.d.ts +24 -0
  248. package/dist/components/section-state.js +78 -0
  249. package/dist/components/section-state.js.map +1 -0
  250. package/dist/components/section-surface.d.ts +31 -0
  251. package/dist/components/section-surface.js +46 -0
  252. package/dist/components/section-surface.js.map +1 -0
  253. package/dist/components/sections.d.ts +38 -0
  254. package/dist/components/sections.js +72 -0
  255. package/dist/components/sections.js.map +1 -0
  256. package/dist/components/settings-form.d.ts +10 -0
  257. package/dist/components/settings-form.js +17 -0
  258. package/dist/components/settings-form.js.map +1 -0
  259. package/dist/components/studio-context.d.ts +22 -0
  260. package/dist/components/studio-context.js +48 -0
  261. package/dist/components/studio-context.js.map +1 -0
  262. package/dist/components/studio-project-screen.d.ts +19 -0
  263. package/dist/components/studio-project-screen.js +195 -0
  264. package/dist/components/studio-project-screen.js.map +1 -0
  265. package/dist/components/studio-shell.d.ts +18 -0
  266. package/dist/components/studio-shell.js +64 -0
  267. package/dist/components/studio-shell.js.map +1 -0
  268. package/dist/components/theme-context.d.ts +17 -0
  269. package/dist/components/theme-context.js +26 -0
  270. package/dist/components/theme-context.js.map +1 -0
  271. package/dist/components/workspace-gate.d.ts +12 -0
  272. package/dist/components/workspace-gate.js +27 -0
  273. package/dist/components/workspace-gate.js.map +1 -0
  274. package/dist/components/workspace-projects.d.ts +13 -0
  275. package/dist/components/workspace-projects.js +18 -0
  276. package/dist/components/workspace-projects.js.map +1 -0
  277. package/dist/lib/assets/delete-asset.d.ts +34 -0
  278. package/dist/lib/assets/delete-asset.js +34 -0
  279. package/dist/lib/assets/delete-asset.js.map +1 -0
  280. package/dist/lib/assets/image-dimensions.d.ts +18 -0
  281. package/dist/lib/assets/image-dimensions.js +26 -0
  282. package/dist/lib/assets/image-dimensions.js.map +1 -0
  283. package/dist/lib/assets/index.d.ts +9 -0
  284. package/dist/lib/assets/index.js +10 -0
  285. package/dist/lib/assets/index.js.map +1 -0
  286. package/dist/lib/assets/upload-state.d.ts +53 -0
  287. package/dist/lib/assets/upload-state.js +59 -0
  288. package/dist/lib/assets/upload-state.js.map +1 -0
  289. package/dist/lib/assets/upload.d.ts +56 -0
  290. package/dist/lib/assets/upload.js +125 -0
  291. package/dist/lib/assets/upload.js.map +1 -0
  292. package/dist/lib/auth/auth-adapter.d.ts +57 -0
  293. package/dist/lib/auth/auth-adapter.js +13 -0
  294. package/dist/lib/auth/auth-adapter.js.map +1 -0
  295. package/dist/lib/auth/convex-auth-adapter.d.ts +39 -0
  296. package/dist/lib/auth/convex-auth-adapter.js +171 -0
  297. package/dist/lib/auth/convex-auth-adapter.js.map +1 -0
  298. package/dist/lib/auth/dev-auto-login-adapter.d.ts +25 -0
  299. package/dist/lib/auth/dev-auto-login-adapter.js +40 -0
  300. package/dist/lib/auth/dev-auto-login-adapter.js.map +1 -0
  301. package/dist/lib/auth/index.d.ts +28 -0
  302. package/dist/lib/auth/index.js +61 -0
  303. package/dist/lib/auth/index.js.map +1 -0
  304. package/dist/lib/auth/local-auth-adapter.d.ts +57 -0
  305. package/dist/lib/auth/local-auth-adapter.js +78 -0
  306. package/dist/lib/auth/local-auth-adapter.js.map +1 -0
  307. package/dist/lib/auth/route-guard.d.ts +33 -0
  308. package/dist/lib/auth/route-guard.js +51 -0
  309. package/dist/lib/auth/route-guard.js.map +1 -0
  310. package/dist/lib/auth-errors.d.ts +42 -0
  311. package/dist/lib/auth-errors.js +74 -0
  312. package/dist/lib/auth-errors.js.map +1 -0
  313. package/dist/lib/bindings/section-bindings.d.ts +24 -0
  314. package/dist/lib/bindings/section-bindings.js +9 -0
  315. package/dist/lib/bindings/section-bindings.js.map +1 -0
  316. package/dist/lib/clipboard/index.d.ts +7 -0
  317. package/dist/lib/clipboard/index.js +8 -0
  318. package/dist/lib/clipboard/index.js.map +1 -0
  319. package/dist/lib/clipboard/os-clipboard.d.ts +46 -0
  320. package/dist/lib/clipboard/os-clipboard.js +105 -0
  321. package/dist/lib/clipboard/os-clipboard.js.map +1 -0
  322. package/dist/lib/clipboard/paste-issues.d.ts +34 -0
  323. package/dist/lib/clipboard/paste-issues.js +67 -0
  324. package/dist/lib/clipboard/paste-issues.js.map +1 -0
  325. package/dist/lib/clipboard/paste-target.d.ts +20 -0
  326. package/dist/lib/clipboard/paste-target.js +28 -0
  327. package/dist/lib/clipboard/paste-target.js.map +1 -0
  328. package/dist/lib/cms/published-documents.d.ts +30 -0
  329. package/dist/lib/cms/published-documents.js +75 -0
  330. package/dist/lib/cms/published-documents.js.map +1 -0
  331. package/dist/lib/cms-views/index.d.ts +9 -0
  332. package/dist/lib/cms-views/index.js +10 -0
  333. package/dist/lib/cms-views/index.js.map +1 -0
  334. package/dist/lib/cms-views/selection.d.ts +29 -0
  335. package/dist/lib/cms-views/selection.js +46 -0
  336. package/dist/lib/cms-views/selection.js.map +1 -0
  337. package/dist/lib/cms-views/view-model.d.ts +192 -0
  338. package/dist/lib/cms-views/view-model.js +353 -0
  339. package/dist/lib/cms-views/view-model.js.map +1 -0
  340. package/dist/lib/cms-views/views-store.d.ts +70 -0
  341. package/dist/lib/cms-views/views-store.js +129 -0
  342. package/dist/lib/cms-views/views-store.js.map +1 -0
  343. package/dist/lib/data/collection-content.d.ts +105 -0
  344. package/dist/lib/data/collection-content.js +196 -0
  345. package/dist/lib/data/collection-content.js.map +1 -0
  346. package/dist/lib/data/data-store.d.ts +97 -0
  347. package/dist/lib/data/data-store.js +205 -0
  348. package/dist/lib/data/data-store.js.map +1 -0
  349. package/dist/lib/data/index.d.ts +4 -0
  350. package/dist/lib/data/index.js +8 -0
  351. package/dist/lib/data/index.js.map +1 -0
  352. package/dist/lib/data/providers.d.ts +143 -0
  353. package/dist/lib/data/providers.js +255 -0
  354. package/dist/lib/data/providers.js.map +1 -0
  355. package/dist/lib/data/sample-capture.d.ts +30 -0
  356. package/dist/lib/data/sample-capture.js +70 -0
  357. package/dist/lib/data/sample-capture.js.map +1 -0
  358. package/dist/lib/data/sources-store.d.ts +42 -0
  359. package/dist/lib/data/sources-store.js +120 -0
  360. package/dist/lib/data/sources-store.js.map +1 -0
  361. package/dist/lib/dnd/drop-rules.d.ts +219 -0
  362. package/dist/lib/dnd/drop-rules.js +257 -0
  363. package/dist/lib/dnd/drop-rules.js.map +1 -0
  364. package/dist/lib/dnd/gap-drag.d.ts +66 -0
  365. package/dist/lib/dnd/gap-drag.js +95 -0
  366. package/dist/lib/dnd/gap-drag.js.map +1 -0
  367. package/dist/lib/locale/binding-fallback.d.ts +28 -0
  368. package/dist/lib/locale/binding-fallback.js +66 -0
  369. package/dist/lib/locale/binding-fallback.js.map +1 -0
  370. package/dist/lib/locale/fallback.d.ts +43 -0
  371. package/dist/lib/locale/fallback.js +52 -0
  372. package/dist/lib/locale/fallback.js.map +1 -0
  373. package/dist/lib/locale/index.d.ts +6 -0
  374. package/dist/lib/locale/index.js +7 -0
  375. package/dist/lib/locale/index.js.map +1 -0
  376. package/dist/lib/locale/locale-store.d.ts +40 -0
  377. package/dist/lib/locale/locale-store.js +61 -0
  378. package/dist/lib/locale/locale-store.js.map +1 -0
  379. package/dist/lib/locale/locale-switcher.d.ts +10 -0
  380. package/dist/lib/locale/locale-switcher.js +24 -0
  381. package/dist/lib/locale/locale-switcher.js.map +1 -0
  382. package/dist/lib/locale/route-variant.d.ts +14 -0
  383. package/dist/lib/locale/route-variant.js +11 -0
  384. package/dist/lib/locale/route-variant.js.map +1 -0
  385. package/dist/lib/locale/use-studio-locale.d.ts +10 -0
  386. package/dist/lib/locale/use-studio-locale.js +8 -0
  387. package/dist/lib/locale/use-studio-locale.js.map +1 -0
  388. package/dist/lib/operations/asset-repository.d.ts +15 -0
  389. package/dist/lib/operations/asset-repository.js +56 -0
  390. package/dist/lib/operations/asset-repository.js.map +1 -0
  391. package/dist/lib/operations/cms-persistence.d.ts +35 -0
  392. package/dist/lib/operations/cms-persistence.js +75 -0
  393. package/dist/lib/operations/cms-persistence.js.map +1 -0
  394. package/dist/lib/operations/graph-commands.d.ts +140 -0
  395. package/dist/lib/operations/graph-commands.js +86 -0
  396. package/dist/lib/operations/graph-commands.js.map +1 -0
  397. package/dist/lib/operations/graph-persistence.d.ts +27 -0
  398. package/dist/lib/operations/graph-persistence.js +35 -0
  399. package/dist/lib/operations/graph-persistence.js.map +1 -0
  400. package/dist/lib/operations/index.d.ts +13 -0
  401. package/dist/lib/operations/index.js +14 -0
  402. package/dist/lib/operations/index.js.map +1 -0
  403. package/dist/lib/operations/operations-package.d.ts +6 -0
  404. package/dist/lib/operations/operations-package.js +7 -0
  405. package/dist/lib/operations/operations-package.js.map +1 -0
  406. package/dist/lib/operations/persist-queue.d.ts +16 -0
  407. package/dist/lib/operations/persist-queue.js +18 -0
  408. package/dist/lib/operations/persist-queue.js.map +1 -0
  409. package/dist/lib/operations/session-hydration.d.ts +84 -0
  410. package/dist/lib/operations/session-hydration.js +112 -0
  411. package/dist/lib/operations/session-hydration.js.map +1 -0
  412. package/dist/lib/operations/studio-operations.d.ts +59 -0
  413. package/dist/lib/operations/studio-operations.js +92 -0
  414. package/dist/lib/operations/studio-operations.js.map +1 -0
  415. package/dist/lib/persistence/backend-mode.d.ts +69 -0
  416. package/dist/lib/persistence/backend-mode.js +120 -0
  417. package/dist/lib/persistence/backend-mode.js.map +1 -0
  418. package/dist/lib/persistence/convex-adapter.d.ts +34 -0
  419. package/dist/lib/persistence/convex-adapter.js +681 -0
  420. package/dist/lib/persistence/convex-adapter.js.map +1 -0
  421. package/dist/lib/persistence/convex-blob-storage.d.ts +57 -0
  422. package/dist/lib/persistence/convex-blob-storage.js +97 -0
  423. package/dist/lib/persistence/convex-blob-storage.js.map +1 -0
  424. package/dist/lib/persistence/convex-client.d.ts +19 -0
  425. package/dist/lib/persistence/convex-client.js +40 -0
  426. package/dist/lib/persistence/convex-client.js.map +1 -0
  427. package/dist/lib/persistence/index.d.ts +30 -0
  428. package/dist/lib/persistence/index.js +60 -0
  429. package/dist/lib/persistence/index.js.map +1 -0
  430. package/dist/lib/persona/labels.d.ts +23 -0
  431. package/dist/lib/persona/labels.js +122 -0
  432. package/dist/lib/persona/labels.js.map +1 -0
  433. package/dist/lib/rail.d.ts +11 -0
  434. package/dist/lib/rail.js +26 -0
  435. package/dist/lib/rail.js.map +1 -0
  436. package/dist/lib/references/impact.d.ts +64 -0
  437. package/dist/lib/references/impact.js +62 -0
  438. package/dist/lib/references/impact.js.map +1 -0
  439. package/dist/lib/references/index.d.ts +7 -0
  440. package/dist/lib/references/index.js +8 -0
  441. package/dist/lib/references/index.js.map +1 -0
  442. package/dist/lib/references/reference-model.d.ts +125 -0
  443. package/dist/lib/references/reference-model.js +242 -0
  444. package/dist/lib/references/reference-model.js.map +1 -0
  445. package/dist/lib/references/references-store.d.ts +65 -0
  446. package/dist/lib/references/references-store.js +221 -0
  447. package/dist/lib/references/references-store.js.map +1 -0
  448. package/dist/lib/registry/index.d.ts +65 -0
  449. package/dist/lib/registry/index.js +114 -0
  450. package/dist/lib/registry/index.js.map +1 -0
  451. package/dist/lib/registry/preview.d.ts +15 -0
  452. package/dist/lib/registry/preview.js +110 -0
  453. package/dist/lib/registry/preview.js.map +1 -0
  454. package/dist/lib/registry/project-components.d.ts +16 -0
  455. package/dist/lib/registry/project-components.js +152 -0
  456. package/dist/lib/registry/project-components.js.map +1 -0
  457. package/dist/lib/routing/index.d.ts +10 -0
  458. package/dist/lib/routing/index.js +11 -0
  459. package/dist/lib/routing/index.js.map +1 -0
  460. package/dist/lib/routing/routing-analysis.d.ts +26 -0
  461. package/dist/lib/routing/routing-analysis.js +37 -0
  462. package/dist/lib/routing/routing-analysis.js.map +1 -0
  463. package/dist/lib/routing/routing-store.d.ts +50 -0
  464. package/dist/lib/routing/routing-store.js +72 -0
  465. package/dist/lib/routing/routing-store.js.map +1 -0
  466. package/dist/lib/starters/kit-session.d.ts +5 -0
  467. package/dist/lib/starters/kit-session.js +17 -0
  468. package/dist/lib/starters/kit-session.js.map +1 -0
  469. package/dist/lib/theme.d.ts +21 -0
  470. package/dist/lib/theme.js +32 -0
  471. package/dist/lib/theme.js.map +1 -0
  472. package/dist/lib/utils.d.ts +11 -0
  473. package/dist/lib/utils.js +28 -0
  474. package/dist/lib/utils.js.map +1 -0
  475. package/dist/lib/webhooks/config.d.ts +15 -0
  476. package/dist/lib/webhooks/config.js +64 -0
  477. package/dist/lib/webhooks/config.js.map +1 -0
  478. package/dist/lib/webhooks/dispatcher.d.ts +67 -0
  479. package/dist/lib/webhooks/dispatcher.js +61 -0
  480. package/dist/lib/webhooks/dispatcher.js.map +1 -0
  481. package/dist/lib/webhooks/index.d.ts +11 -0
  482. package/dist/lib/webhooks/index.js +10 -0
  483. package/dist/lib/webhooks/index.js.map +1 -0
  484. package/dist/lib/webhooks/signing.d.ts +15 -0
  485. package/dist/lib/webhooks/signing.js +24 -0
  486. package/dist/lib/webhooks/signing.js.map +1 -0
  487. package/dist/lib/webhooks/tags.d.ts +25 -0
  488. package/dist/lib/webhooks/tags.js +173 -0
  489. package/dist/lib/webhooks/tags.js.map +1 -0
  490. package/dist/lib/working-graph.d.ts +82 -0
  491. package/dist/lib/working-graph.js +113 -0
  492. package/dist/lib/working-graph.js.map +1 -0
  493. package/dist/lib/workspace/index.d.ts +109 -0
  494. package/dist/lib/workspace/index.js +206 -0
  495. package/dist/lib/workspace/index.js.map +1 -0
  496. package/dist/lib/workspace/switcher-source.d.ts +39 -0
  497. package/dist/lib/workspace/switcher-source.js +23 -0
  498. package/dist/lib/workspace/switcher-source.js.map +1 -0
  499. package/dist/lib/workspace/workspace-source.d.ts +47 -0
  500. package/dist/lib/workspace/workspace-source.js +67 -0
  501. package/dist/lib/workspace/workspace-source.js.map +1 -0
  502. package/dist/router/index.d.ts +32 -0
  503. package/dist/router/index.js +32 -0
  504. package/dist/router/index.js.map +1 -0
  505. package/dist/router/match.d.ts +75 -0
  506. package/dist/router/match.js +87 -0
  507. package/dist/router/match.js.map +1 -0
  508. package/dist/router/search.d.ts +22 -0
  509. package/dist/router/search.js +16 -0
  510. package/dist/router/search.js.map +1 -0
  511. package/dist/ui/avatar.d.ts +17 -0
  512. package/dist/ui/avatar.js +38 -0
  513. package/dist/ui/avatar.js.map +1 -0
  514. package/dist/ui/badge.d.ts +9 -0
  515. package/dist/ui/badge.js +23 -0
  516. package/dist/ui/badge.js.map +1 -0
  517. package/dist/ui/button.d.ts +11 -0
  518. package/dist/ui/button.js +30 -0
  519. package/dist/ui/button.js.map +1 -0
  520. package/dist/ui/card.d.ts +11 -0
  521. package/dist/ui/card.js +23 -0
  522. package/dist/ui/card.js.map +1 -0
  523. package/dist/ui/dialog.d.ts +12 -0
  524. package/dist/ui/dialog.js +27 -0
  525. package/dist/ui/dialog.js.map +1 -0
  526. package/dist/ui/dropdown-menu.d.ts +15 -0
  527. package/dist/ui/dropdown-menu.js +24 -0
  528. package/dist/ui/dropdown-menu.js.map +1 -0
  529. package/dist/ui/field.d.ts +15 -0
  530. package/dist/ui/field.js +14 -0
  531. package/dist/ui/field.js.map +1 -0
  532. package/dist/ui/index.d.ts +14 -0
  533. package/dist/ui/index.js +15 -0
  534. package/dist/ui/index.js.map +1 -0
  535. package/dist/ui/input.d.ts +3 -0
  536. package/dist/ui/input.js +7 -0
  537. package/dist/ui/input.js.map +1 -0
  538. package/dist/ui/inspector.d.ts +18 -0
  539. package/dist/ui/inspector.js +14 -0
  540. package/dist/ui/inspector.js.map +1 -0
  541. package/dist/ui/layout.d.ts +45 -0
  542. package/dist/ui/layout.js +48 -0
  543. package/dist/ui/layout.js.map +1 -0
  544. package/dist/ui/panel.d.ts +12 -0
  545. package/dist/ui/panel.js +20 -0
  546. package/dist/ui/panel.js.map +1 -0
  547. package/dist/ui/separator.d.ts +6 -0
  548. package/dist/ui/separator.js +7 -0
  549. package/dist/ui/separator.js.map +1 -0
  550. package/dist/ui/toolbar.d.ts +9 -0
  551. package/dist/ui/toolbar.js +16 -0
  552. package/dist/ui/toolbar.js.map +1 -0
  553. package/dist/ui/typography.d.ts +50 -0
  554. package/dist/ui/typography.js +43 -0
  555. package/dist/ui/typography.js.map +1 -0
  556. package/package.json +149 -0
  557. package/src/styles/studio.css +101 -0
  558. package/src/styles/tokens.css +63 -0
@@ -0,0 +1,702 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react';
3
+ import { createCollectionRegistry, createDocumentStore, documentKey, documentSchema, resolveField, sampleDocuments, sampleFilterableCollections, sampleLocaleConfig, samplePublishedKeys, singletonDocId, titleFieldOf, validateDocument, } from '@elytracms/cms-core';
4
+ import { validateCompositionValue } from '@elytracms/project-graph';
5
+ import { collectComponentEmbeds, parseRichTextValue } from '@elytracms/rich-text';
6
+ import { configureStudioLocales, useStudioLocale } from '@elytracms/studio/lib/locale';
7
+ import { getStudioRegistry } from '@elytracms/studio/lib/registry';
8
+ import { slugify } from '@elytracms/studio/lib/utils';
9
+ import { createCmsPersister, getStudioOperations } from '@elytracms/studio/lib/operations';
10
+ import { ALL_VIEW_ID, canonicalViewState, defaultViewState, deleteSavedView, loadSavedViews, newViewId, normalizeViewState, saveSavedView, viewStatesEqual, } from '@elytracms/studio/lib/cms-views';
11
+ import { useOptionalAssets } from '../assets/assets-store';
12
+ import { commitCellEdit } from './cell-edit';
13
+ import { runBulkAction } from './bulk-actions';
14
+ /** Demo per-field access (brief §8.4, EC-078). Read-only fields render disabled. */
15
+ const READ_ONLY_FIELDS = {
16
+ asset: ['url'],
17
+ };
18
+ /**
19
+ * Mint a collision-safe, slug-derived page id (EC-192): the slug of the page name,
20
+ * suffixed `-2`/`-3`/… until it is free among the ids already taken. Empty or
21
+ * symbol-only names fall back to `page`. Pure so the id rule is testable without
22
+ * the store; `createPage` applies it against the live page documents.
23
+ */
24
+ export function nextPageId(name, taken) {
25
+ const base = slugify(name) || 'page';
26
+ let id = base;
27
+ for (let n = 2; taken.has(id); n += 1)
28
+ id = `${base}-${n}`;
29
+ return id;
30
+ }
31
+ /**
32
+ * EC-188: validate a `blocks` composition field value against the field's `allow`
33
+ * vocabulary + the code-owned component registry (the leash), mapping graph
34
+ * issues into plain CMS findings. Injected into `validateDocument` so cms-core
35
+ * stays free of `@elytracms/project-graph`. Never throws — a malformed (non-node)
36
+ * value degrades to a single finding, matching the "validation is first-class,
37
+ * never a crash" rule.
38
+ */
39
+ function validateComposition(value, field) {
40
+ if (value == null)
41
+ return [];
42
+ const roots = Array.isArray(value) ? value : [value];
43
+ if (!roots.every((r) => r != null && typeof r === 'object' && 'componentId' in r)) {
44
+ return [{ message: 'is not a valid composition (expected component nodes)', severity: 'error' }];
45
+ }
46
+ const components = getStudioRegistry().registry.lookup;
47
+ return validateCompositionValue(value, {
48
+ allow: field.allow,
49
+ components,
50
+ }).map((issue) => ({
51
+ message: issue.message,
52
+ severity: issue.severity,
53
+ nodePath: issue.path.join('/'),
54
+ }));
55
+ }
56
+ /**
57
+ * EC-189: validate the composition embeds inside a `richText` field value. Each
58
+ * `componentEmbed` holds a single `ComponentNode` constrained by the field's
59
+ * `allow` vocabulary (the SAME leash a `blocks` field uses). Parse the value, walk
60
+ * its embeds at any depth, and validate each embedded node via
61
+ * `validateCompositionValue`; findings carry the rich-text node path joined with
62
+ * the in-embed graph path. Injected into `validateDocument` so cms-core depends on
63
+ * neither `@elytracms/project-graph` nor `@elytracms/rich-text`. Never throws — a
64
+ * malformed embed degrades to a single finding.
65
+ */
66
+ function validateRichTextEmbeds(value, field) {
67
+ if (value == null)
68
+ return [];
69
+ const parsed = parseRichTextValue(value);
70
+ // A plain-string / schema-invalid rich-text value carries no embeds to check
71
+ // here (scalar type validation owns reporting a malformed value).
72
+ if (!parsed.ok)
73
+ return [];
74
+ const components = getStudioRegistry().registry.lookup;
75
+ const out = [];
76
+ for (const occurrence of collectComponentEmbeds(parsed.value.doc)) {
77
+ if (!occurrence.embedded) {
78
+ out.push({
79
+ message: `embed at ${occurrence.nodePath} is missing a valid embedded component`,
80
+ severity: 'error',
81
+ nodePath: occurrence.nodePath,
82
+ });
83
+ continue;
84
+ }
85
+ for (const issue of validateCompositionValue(occurrence.embedded, {
86
+ allow: field.allow,
87
+ components,
88
+ })) {
89
+ out.push({
90
+ message: issue.message,
91
+ severity: issue.severity,
92
+ nodePath: `${occurrence.nodePath}/attrs/node/${issue.path.join('/')}`,
93
+ });
94
+ }
95
+ }
96
+ return out;
97
+ }
98
+ const CmsContext = createContext(null);
99
+ function primaryField(collection) {
100
+ return titleFieldOf(collection)?.name ?? collection.fields[0]?.name ?? 'id';
101
+ }
102
+ /** The unnamed built-in view: no filters, no sort, every field visible. */
103
+ function defaultView(collection) {
104
+ return {
105
+ id: ALL_VIEW_ID,
106
+ name: 'All documents',
107
+ state: collection
108
+ ? defaultViewState(collection)
109
+ : { filters: [], sort: null, columns: [], hidden: [] },
110
+ };
111
+ }
112
+ /**
113
+ * The CMS session store (EC-141): documents and collections are optimistic,
114
+ * synchronous session state (live validation while typing); every mutation —
115
+ * create/save/delete/state transitions — is mirrored onto the operations
116
+ * layer (`documents.*` / `schema.*` commands) through {@link createCmsPersister}.
117
+ * Failed/denied commands surface as {@link CmsStore.persistError}.
118
+ */
119
+ export function CmsProvider({ children, projectId, initialCollections, initialDocuments, initialPublishedKeys, initialLocaleConfig, }) {
120
+ const [documents, setDocuments] = useState(() => (initialDocuments ?? sampleDocuments).map((d) => structuredClone(d)));
121
+ // Published-ness as the version POINTER (EC-224), decoupled from the flat
122
+ // `state` enum: seeded from hydration's pointer set, or — when none is supplied
123
+ // — the canonical sample published set for the playground. A kit's imported
124
+ // content (`initialDocuments` without a pointer set) starts unpublished
125
+ // (drafts) until an editor publishes it. The flat `state` is never consulted.
126
+ const [publishedKeys, setPublishedKeys] = useState(() => {
127
+ if (initialPublishedKeys)
128
+ return new Set(initialPublishedKeys);
129
+ return new Set(initialDocuments ? [] : samplePublishedKeys);
130
+ });
131
+ // Named saved views per collection (EC-169): loaded from the operations
132
+ // layer (project-scoped, shared across editors) and mutated through it.
133
+ const [savedViews, setSavedViews] = useState({});
134
+ const [activeViews, setActiveViews] = useState({});
135
+ // The live table state per collection where it diverges from the active
136
+ // view; absent key = exactly the active view's state (not dirty).
137
+ const [tableStates, setTableStates] = useState({});
138
+ // Collections are stateful so AI-generated schemas (EC-097) can be accepted
139
+ // into the session. The session schema IS the source the sort/filter
140
+ // offering follows (EC-177 gap 3): hydrated sessions receive the persisted
141
+ // schema via `initialCollections`; the fixture fallback is the canonical
142
+ // cms-core sample schema WITH its declared `filterable` flags — no
143
+ // session-side widenings, so the studio never offers a field the backend's
144
+ // delivery engine would reject.
145
+ const [collections, setCollections] = useState(() => [
146
+ ...(initialCollections ?? sampleFilterableCollections),
147
+ ]);
148
+ const [persistError, setPersistError] = useState(null);
149
+ const seq = useRef(0);
150
+ // Latest session state for the persister's lazy baseline (no re-subscribing).
151
+ const collectionsRef = useRef(collections);
152
+ collectionsRef.current = collections;
153
+ const documentsRef = useRef(documents);
154
+ documentsRef.current = documents;
155
+ const persisterRef = useRef(null);
156
+ if (persisterRef.current === null && projectId !== undefined) {
157
+ persisterRef.current = createCmsPersister({
158
+ projectId,
159
+ getOperations: async () => (await getStudioOperations()).operations,
160
+ getCollections: () => collectionsRef.current,
161
+ getDocuments: () => documentsRef.current,
162
+ onError: setPersistError,
163
+ });
164
+ }
165
+ const registry = useMemo(() => createCollectionRegistry(collections), [collections]);
166
+ const store = useMemo(() => createDocumentStore(documents), [documents]);
167
+ const localeConfig = initialLocaleConfig ?? sampleLocaleConfig;
168
+ // Asset existence is validated against the REAL asset library (assets live in
169
+ // their own repository, not as CMS documents). With the ambient AssetsProvider
170
+ // present, the oracle is the set of uploaded asset ids — but only once loaded;
171
+ // while it loads we are optimistic so a valid upload is never transiently
172
+ // flagged "unknown". With no provider (tests/fixtures), the oracle is absent
173
+ // and asset existence falls back to the document store.
174
+ const assetStore = useOptionalAssets();
175
+ const assetExists = useMemo(() => {
176
+ if (!assetStore)
177
+ return undefined;
178
+ if (assetStore.status !== 'ready')
179
+ return () => true;
180
+ const ids = new Set(assetStore.assets.map((asset) => asset.id));
181
+ return (id) => ids.has(id);
182
+ }, [assetStore]);
183
+ // The ambient studio locale (EC-176): this session's locale config drives
184
+ // the switcher options; every CMS surface follows the one active locale.
185
+ const { locale: activeLocale } = useStudioLocale();
186
+ useEffect(() => {
187
+ configureStudioLocales(localeConfig);
188
+ }, [localeConfig]);
189
+ const getCollection = useCallback((id) => registry.get(id), [registry]);
190
+ const getDocument = useCallback((ref) => documents.find((d) => d.collection === ref.collection && d.id === ref.id), [documents]);
191
+ const titleOf = useCallback((ref) => {
192
+ const doc = documents.find((d) => d.collection === ref.collection && d.id === ref.id);
193
+ const collection = registry.get(ref.collection);
194
+ if (!doc || !collection)
195
+ return ref.id;
196
+ // Resolve through the locale layer in the ambient active locale (EC-176)
197
+ // with EC-018 fallback, so localized titles follow the switcher.
198
+ const { value } = resolveField(collection, doc, primaryField(collection), activeLocale, localeConfig);
199
+ return typeof value === 'string' && value ? value : ref.id;
200
+ }, [documents, registry, localeConfig, activeLocale]);
201
+ const saveDocument = useCallback((doc) => {
202
+ setDocuments((prev) => {
203
+ const i = prev.findIndex((d) => d.collection === doc.collection && d.id === doc.id);
204
+ if (i < 0)
205
+ return [...prev, doc];
206
+ const next = [...prev];
207
+ next[i] = doc;
208
+ return next;
209
+ });
210
+ persisterRef.current?.upsertDocument(doc);
211
+ }, []);
212
+ const commitFieldEdit = useCallback((input) => {
213
+ const replaceWith = (doc) => setDocuments((prev) => prev.map((d) => (d.collection === doc.collection && d.id === doc.id ? doc : d)));
214
+ const persister = persisterRef.current;
215
+ return commitCellEdit({
216
+ registry,
217
+ documents: documentsRef.current,
218
+ localeConfig,
219
+ applySession: replaceWith,
220
+ rollbackSession: replaceWith,
221
+ ...(persister && projectId !== undefined
222
+ ? {
223
+ dispatch: async (next) => {
224
+ // Make sure the persisted baseline + every queued mutation
225
+ // landed first, then issue the commit's single command.
226
+ await persister.ensureBaseline();
227
+ const { operations } = await getStudioOperations();
228
+ return operations.documents.upsert({ projectId, document: next });
229
+ },
230
+ }
231
+ : {}),
232
+ }, input);
233
+ }, [registry, localeConfig, projectId]);
234
+ const createDocument = useCallback((collectionId) => {
235
+ seq.current += 1;
236
+ const id = `new-${collectionId}-${seq.current}`;
237
+ const doc = { collection: collectionId, id, values: {} };
238
+ setDocuments((prev) => [...prev, doc]);
239
+ persisterRef.current?.upsertDocument(doc);
240
+ return { collection: collectionId, id };
241
+ }, []);
242
+ // EC-192: create a named page document with a stable, slug-derived id (not an
243
+ // opaque `new-page-N`), so the route bound to it reads as a real address and
244
+ // the id survives as the canonical key. Collision-safe against existing page
245
+ // ids. The route itself is written by the caller (NewPageDialog) through the
246
+ // operations layer, so the two writes stay in their own concerns.
247
+ const createPage = useCallback((input) => {
248
+ const collectionId = 'page';
249
+ const taken = new Set(documentsRef.current.filter((d) => d.collection === collectionId).map((d) => d.id));
250
+ const id = nextPageId(input.name, taken);
251
+ const doc = {
252
+ collection: collectionId,
253
+ id,
254
+ values: { name: input.name },
255
+ };
256
+ setDocuments((prev) => [...prev, doc]);
257
+ persisterRef.current?.upsertDocument(doc);
258
+ return { collection: collectionId, id };
259
+ }, []);
260
+ // EC-217: a singleton collection has exactly one document, keyed by the
261
+ // collection id (`singletonDocId`). The detail editor opens through this, so
262
+ // the single document is materialized on first visit (an empty draft, persisted
263
+ // like any create). Idempotent: never duplicates if it already exists.
264
+ const ensureSingletonDocument = useCallback((collectionId) => {
265
+ const collection = registry.get(collectionId);
266
+ const id = collection ? singletonDocId(collection) : collectionId;
267
+ const ref = { collection: collectionId, id };
268
+ const exists = documentsRef.current.some((d) => d.collection === collectionId && d.id === id);
269
+ if (!exists) {
270
+ const doc = { collection: collectionId, id, values: {} };
271
+ setDocuments((prev) => prev.some((d) => d.collection === collectionId && d.id === id) ? prev : [...prev, doc]);
272
+ persisterRef.current?.upsertDocument(doc);
273
+ }
274
+ return ref;
275
+ }, [registry]);
276
+ const deleteDocument = useCallback((ref) => {
277
+ setDocuments((prev) => prev.filter((d) => !(d.collection === ref.collection && d.id === ref.id)));
278
+ persisterRef.current?.deleteDocument(ref);
279
+ }, []);
280
+ // EC-224: published-ness IS the version pointer (`publishedKeys`) — the SOLE
281
+ // studio source of truth, read via `isPublished`. The live row stays a
282
+ // continuous draft (Sanity model); no flat `state` mirror is maintained. Every
283
+ // reader now consults the pointer (the table badge/$state via `isPublished`,
284
+ // the preview engine via the pin), so the flat field is read by nothing here.
285
+ const setPublished = useCallback((ref, published) => {
286
+ const key = documentKey(ref);
287
+ setPublishedKeys((prev) => {
288
+ if (prev.has(key) === published)
289
+ return prev;
290
+ const next = new Set(prev);
291
+ if (published)
292
+ next.add(key);
293
+ else
294
+ next.delete(key);
295
+ return next;
296
+ });
297
+ }, []);
298
+ const isPublished = useCallback((ref) => publishedKeys.has(documentKey(ref)), [publishedKeys]);
299
+ // Reconcile published-ness for a ref against the AUTHORITATIVE backend record
300
+ // (EC-225): the optimistic flip is a guess; once the queued op settles we read
301
+ // the actual pin so the badge can never claim a state the backend refused
302
+ // (a publish blocked by field rules, an unpublish blocked by a strict ref).
303
+ const reconcilePublished = useCallback(async (ref) => {
304
+ if (projectId === undefined)
305
+ return;
306
+ const { operations } = await getStudioOperations();
307
+ const record = await operations.documents.get({ projectId, ref });
308
+ if (record.ok)
309
+ setPublished(ref, record.value.publishedVersion !== undefined);
310
+ }, [projectId, setPublished]);
311
+ const publishDocument = useCallback(async (ref) => {
312
+ setPublished(ref, true); // optimistic
313
+ persisterRef.current?.publishDocument(ref);
314
+ await persisterRef.current?.flush();
315
+ await reconcilePublished(ref);
316
+ }, [setPublished, reconcilePublished]);
317
+ const unpublishDocument = useCallback(async (ref) => {
318
+ setPublished(ref, false); // optimistic
319
+ persisterRef.current?.unpublishDocument(ref);
320
+ await persisterRef.current?.flush();
321
+ await reconcilePublished(ref);
322
+ }, [setPublished, reconcilePublished]);
323
+ const loadDocumentVersions = useCallback(async (ref) => {
324
+ // No persisted backend (fixture/playground): no recorded history.
325
+ if (projectId === undefined)
326
+ return { versions: [] };
327
+ const { operations } = await getStudioOperations();
328
+ const [versionsRes, recordRes] = await Promise.all([
329
+ operations.documents.listVersions({ projectId, ref }),
330
+ operations.documents.get({ projectId, ref }),
331
+ ]);
332
+ if (!versionsRes.ok) {
333
+ setPersistError(versionsRes.error);
334
+ return { versions: [] };
335
+ }
336
+ // The pinned (live) version comes off the document record; a never-saved
337
+ // doc simply has no record (and no versions) — not an error to surface.
338
+ const publishedVersion = recordRes.ok ? recordRes.value.publishedVersion : undefined;
339
+ return {
340
+ versions: versionsRes.value,
341
+ ...(publishedVersion !== undefined ? { publishedVersion } : {}),
342
+ };
343
+ }, [projectId]);
344
+ const restoreDocumentVersion = useCallback(async (ref, version) => {
345
+ if (projectId === undefined)
346
+ return null;
347
+ // Land any queued edits before the restore reads the current draft to
348
+ // snapshot it (same ordering contract as commitFieldEdit/runBulk).
349
+ await persisterRef.current?.ensureBaseline();
350
+ const { operations } = await getStudioOperations();
351
+ const result = await operations.documents.restore({ projectId, ref, version });
352
+ if (!result.ok) {
353
+ setPersistError(result.error);
354
+ return null;
355
+ }
356
+ const restored = result.value.document;
357
+ setDocuments((prev) => prev.map((d) => d.collection === restored.collection && d.id === restored.id ? restored : d));
358
+ return restored;
359
+ }, [projectId]);
360
+ const validate = useCallback((doc) => validateDocument(registry, doc, {
361
+ store,
362
+ localeConfig,
363
+ validateComposition,
364
+ validateRichTextEmbeds,
365
+ // EC-224: the EC-173 weak-reference warning sources published-ness from
366
+ // the version pointer, so editing a published doc that references an
367
+ // unpublished target surfaces the fallback warning again (it had gone
368
+ // inert once the flat `state` mirror was dropped in B-3b).
369
+ isPublished,
370
+ assetExists,
371
+ }), [registry, store, localeConfig, isPublished, assetExists]);
372
+ const importDocuments = useCallback((collectionId, raw) => {
373
+ const report = { added: 0, rejected: [] };
374
+ // Pre-parse so intra-batch relation/asset targets resolve during validation.
375
+ const parsedBatch = [];
376
+ const schemaFails = [];
377
+ for (const item of raw) {
378
+ const parsed = documentSchema.safeParse({ ...item, collection: collectionId });
379
+ if (parsed.success)
380
+ parsedBatch.push(parsed.data);
381
+ else
382
+ schemaFails.push({ item, error: parsed });
383
+ }
384
+ for (const { item, error } of schemaFails) {
385
+ report.rejected.push({
386
+ id: item?.id ?? '(no id)',
387
+ issues: (error.success ? [] : error.error.issues).map((e) => ({
388
+ code: 'invalid-field-value',
389
+ severity: 'error',
390
+ message: e.message,
391
+ path: e.path.map((p) => (typeof p === 'symbol' ? String(p) : p)),
392
+ })),
393
+ });
394
+ }
395
+ // Validate each against existing docs PLUS the rest of the batch.
396
+ const batchStore = createDocumentStore([...documents, ...parsedBatch]);
397
+ const accepted = [];
398
+ for (const doc of parsedBatch) {
399
+ const issues = validateDocument(registry, doc, { store: batchStore, localeConfig, assetExists });
400
+ const errors = issues.filter((iss) => iss.severity === 'error');
401
+ if (errors.length > 0)
402
+ report.rejected.push({ id: doc.id, issues: errors });
403
+ else
404
+ accepted.push(doc);
405
+ }
406
+ if (accepted.length > 0) {
407
+ setDocuments((prev) => {
408
+ const next = [...prev];
409
+ for (const doc of accepted) {
410
+ const i = next.findIndex((d) => d.collection === doc.collection && d.id === doc.id);
411
+ if (i < 0)
412
+ next.push(doc);
413
+ else
414
+ next[i] = doc;
415
+ }
416
+ return next;
417
+ });
418
+ for (const doc of accepted)
419
+ persisterRef.current?.upsertDocument(doc);
420
+ // EC-224: imports land as the working DRAFT. Publish-ness is the version
421
+ // pointer (`publishedKeys`), set by publishing — never carried in the
422
+ // imported row — so an import never auto-publishes; the editor publishes
423
+ // explicitly afterward.
424
+ report.added = accepted.length;
425
+ }
426
+ return report;
427
+ }, [registry, documents, localeConfig, assetExists]);
428
+ const isFieldReadOnly = useCallback((collectionId, field) => {
429
+ return (field.form?.readOnly === true ||
430
+ (READ_ONLY_FIELDS[collectionId]?.includes(field.name) ?? false));
431
+ }, []);
432
+ // --- Saved views (EC-169) -------------------------------------------------
433
+ // Load the project's persisted views once (operations query). Views saved by
434
+ // other editors/sessions on the same project show up here.
435
+ useEffect(() => {
436
+ if (projectId === undefined)
437
+ return;
438
+ let cancelled = false;
439
+ void getStudioOperations()
440
+ .then(({ operations }) => loadSavedViews(operations, projectId))
441
+ .then((result) => {
442
+ if (cancelled)
443
+ return;
444
+ if (!result.ok) {
445
+ setPersistError(result.error);
446
+ return;
447
+ }
448
+ const grouped = {};
449
+ for (const record of result.value) {
450
+ ;
451
+ (grouped[record.collection] ??= []).push({
452
+ id: record.id,
453
+ name: record.name,
454
+ state: record.state,
455
+ });
456
+ }
457
+ setSavedViews(grouped);
458
+ });
459
+ return () => {
460
+ cancelled = true;
461
+ };
462
+ }, [projectId]);
463
+ const viewsOf = useCallback((collectionId) => [
464
+ defaultView(registry.get(collectionId)),
465
+ ...(savedViews[collectionId] ?? []),
466
+ ], [registry, savedViews]);
467
+ const activeViewOf = useCallback((collectionId) => {
468
+ const id = activeViews[collectionId] ?? ALL_VIEW_ID;
469
+ return (viewsOf(collectionId).find((view) => view.id === id) ??
470
+ defaultView(registry.get(collectionId)));
471
+ }, [activeViews, viewsOf, registry]);
472
+ const tableStateOf = useCallback((collectionId) => tableStates[collectionId] ?? activeViewOf(collectionId).state, [tableStates, activeViewOf]);
473
+ const dropTableState = useCallback((collectionId) => {
474
+ setTableStates((prev) => {
475
+ if (!(collectionId in prev))
476
+ return prev;
477
+ const next = { ...prev };
478
+ delete next[collectionId];
479
+ return next;
480
+ });
481
+ }, []);
482
+ const setActiveView = useCallback((collectionId, viewId) => {
483
+ setActiveViews((prev) => ({ ...prev, [collectionId]: viewId }));
484
+ dropTableState(collectionId);
485
+ }, [dropTableState]);
486
+ /**
487
+ * Run one persisted view mutation: pending content mutations + the persisted
488
+ * baseline land first (so the system collection never pre-empts the content
489
+ * schema), then exactly one operations command. Failures surface as
490
+ * `persistError` and report `false` — the session is only updated on success.
491
+ */
492
+ const dispatchViewMutation = useCallback(async (run) => {
493
+ if (projectId === undefined)
494
+ return true; // fixture-only session: views stay session-local
495
+ await persisterRef.current?.ensureBaseline();
496
+ const { operations } = await getStudioOperations();
497
+ const result = await run(operations, projectId);
498
+ if (!result.ok) {
499
+ setPersistError(result.error);
500
+ return false;
501
+ }
502
+ return true;
503
+ }, [projectId]);
504
+ const saveViewAs = useCallback(async (collectionId, name) => {
505
+ const trimmed = name.trim();
506
+ if (trimmed === '')
507
+ return false;
508
+ const id = newViewId();
509
+ const state = normalizeViewState(tableStateOf(collectionId));
510
+ const ok = await dispatchViewMutation((operations, pid) => saveSavedView(operations, pid, { id, name: trimmed, collection: collectionId, state }));
511
+ if (!ok)
512
+ return false;
513
+ setSavedViews((prev) => ({
514
+ ...prev,
515
+ [collectionId]: [...(prev[collectionId] ?? []), { id, name: trimmed, state }],
516
+ }));
517
+ setActiveViews((prev) => ({ ...prev, [collectionId]: id }));
518
+ dropTableState(collectionId);
519
+ return true;
520
+ }, [dispatchViewMutation, tableStateOf, dropTableState]);
521
+ const saveActiveView = useCallback(async (collectionId) => {
522
+ const activeId = activeViews[collectionId] ?? ALL_VIEW_ID;
523
+ if (activeId === ALL_VIEW_ID)
524
+ return false; // the default view is not persistable
525
+ const current = (savedViews[collectionId] ?? []).find((view) => view.id === activeId);
526
+ if (!current)
527
+ return false;
528
+ const state = normalizeViewState(tableStateOf(collectionId));
529
+ const ok = await dispatchViewMutation((operations, pid) => saveSavedView(operations, pid, {
530
+ id: activeId,
531
+ name: current.name,
532
+ collection: collectionId,
533
+ state,
534
+ }));
535
+ if (!ok)
536
+ return false;
537
+ setSavedViews((prev) => ({
538
+ ...prev,
539
+ [collectionId]: (prev[collectionId] ?? []).map((view) => view.id === activeId ? { ...view, state } : view),
540
+ }));
541
+ dropTableState(collectionId);
542
+ return true;
543
+ }, [activeViews, savedViews, dispatchViewMutation, tableStateOf, dropTableState]);
544
+ const deleteView = useCallback(async (collectionId, viewId) => {
545
+ if (viewId === ALL_VIEW_ID)
546
+ return false;
547
+ // One documents.delete against the views system collection — content
548
+ // documents are untouched by construction.
549
+ const ok = await dispatchViewMutation((operations, pid) => deleteSavedView(operations, pid, viewId));
550
+ if (!ok)
551
+ return false;
552
+ setSavedViews((prev) => ({
553
+ ...prev,
554
+ [collectionId]: (prev[collectionId] ?? []).filter((view) => view.id !== viewId),
555
+ }));
556
+ if ((activeViews[collectionId] ?? ALL_VIEW_ID) === viewId) {
557
+ setActiveViews((prev) => ({ ...prev, [collectionId]: ALL_VIEW_ID }));
558
+ dropTableState(collectionId);
559
+ }
560
+ return true;
561
+ }, [dispatchViewMutation, activeViews, dropTableState]);
562
+ // --- Bulk actions (EC-169) ------------------------------------------------
563
+ const runBulk = useCallback(async (collectionId, ids, action) => {
564
+ let dispatch;
565
+ const persister = persisterRef.current;
566
+ if (persister && projectId !== undefined) {
567
+ // Pending queued mutations + baseline land first, then one awaited
568
+ // command per item (same ordering contract as commitFieldEdit).
569
+ await persister.ensureBaseline();
570
+ const { operations } = await getStudioOperations();
571
+ dispatch = (bulkAction, ref) => bulkAction === 'delete'
572
+ ? operations.documents.delete({ projectId, ref })
573
+ : bulkAction === 'publish'
574
+ ? operations.documents.publish({ projectId, ref })
575
+ : operations.documents.unpublish({ projectId, ref });
576
+ }
577
+ return runBulkAction({
578
+ documents: documentsRef.current,
579
+ titleOf,
580
+ validate: (doc) => validateDocument(registry, doc, {
581
+ store: createDocumentStore(documentsRef.current),
582
+ localeConfig,
583
+ // EC-225: include the composition validators so a bulk PUBLISH
584
+ // gates blocks/richText validity the same way the detail editor
585
+ // does — the operations-layer publish gate has no component
586
+ // registry, so composition validity is a studio-validation invariant.
587
+ validateComposition,
588
+ validateRichTextEmbeds,
589
+ assetExists,
590
+ }),
591
+ // EC-224: a succeeded publish/unpublish moves the version pointer
592
+ // (`publishedKeys`); the flat `state` mirror is updated in lockstep.
593
+ applyState: (ref, state) => setPublished(ref, state === 'published'),
594
+ applyDelete: (ref) => setDocuments((prev) => prev.filter((d) => !(d.collection === ref.collection && d.id === ref.id))),
595
+ ...(dispatch ? { dispatch } : {}),
596
+ }, collectionId, ids, action);
597
+ }, [projectId, titleOf, registry, localeConfig, setPublished, assetExists]);
598
+ const store$ = useMemo(() => ({
599
+ ...(projectId !== undefined ? { projectId } : {}),
600
+ collections,
601
+ localeConfig,
602
+ activeLocale,
603
+ getCollection,
604
+ documentsOf: (collectionId) => documents.filter((d) => d.collection === collectionId),
605
+ getDocument,
606
+ titleOf,
607
+ saveDocument,
608
+ commitFieldEdit,
609
+ createDocument,
610
+ createPage,
611
+ ensureSingletonDocument,
612
+ deleteDocument,
613
+ isPublished,
614
+ publishDocument,
615
+ unpublishDocument,
616
+ loadDocumentVersions,
617
+ restoreDocumentVersion,
618
+ importDocuments,
619
+ validate,
620
+ isFieldReadOnly,
621
+ viewsOf,
622
+ activeViewId: (collectionId) => activeViews[collectionId] ?? ALL_VIEW_ID,
623
+ setActiveView,
624
+ tableStateOf,
625
+ setTableState: (collectionId, update) => setTableStates((prev) => {
626
+ const current = prev[collectionId] ?? activeViewOf(collectionId).state;
627
+ const next = typeof update === 'function' ? update(current) : update;
628
+ return { ...prev, [collectionId]: next };
629
+ }),
630
+ isViewDirty: (collectionId) => {
631
+ const working = tableStates[collectionId];
632
+ if (working === undefined)
633
+ return false;
634
+ const active = activeViewOf(collectionId).state;
635
+ const collection = registry.get(collectionId);
636
+ if (collection === undefined)
637
+ return !viewStatesEqual(working, active);
638
+ // Compare schema-resolved forms (EC-213): a column-order reconciliation
639
+ // or a stale `hidden` entry must not read as an unsaved edit.
640
+ return !viewStatesEqual(canonicalViewState(collection, working), canonicalViewState(collection, active));
641
+ },
642
+ resetTableState: dropTableState,
643
+ saveActiveView,
644
+ saveViewAs,
645
+ deleteView,
646
+ runBulk,
647
+ addCollection: (def) => setCollections((prev) => [...prev.filter((c) => c.id !== def.id), def]),
648
+ persistError,
649
+ clearPersistError: () => setPersistError(null),
650
+ ensurePersistedBaseline: () => persisterRef.current?.ensureBaseline() ?? Promise.resolve(),
651
+ flushPersistence: () => persisterRef.current?.flush() ?? Promise.resolve(),
652
+ }), [
653
+ projectId,
654
+ collections,
655
+ documents,
656
+ localeConfig,
657
+ activeLocale,
658
+ getCollection,
659
+ getDocument,
660
+ titleOf,
661
+ saveDocument,
662
+ commitFieldEdit,
663
+ createDocument,
664
+ createPage,
665
+ ensureSingletonDocument,
666
+ deleteDocument,
667
+ isPublished,
668
+ publishDocument,
669
+ unpublishDocument,
670
+ loadDocumentVersions,
671
+ restoreDocumentVersion,
672
+ importDocuments,
673
+ validate,
674
+ isFieldReadOnly,
675
+ viewsOf,
676
+ activeViews,
677
+ activeViewOf,
678
+ tableStates,
679
+ tableStateOf,
680
+ setActiveView,
681
+ dropTableState,
682
+ saveActiveView,
683
+ saveViewAs,
684
+ deleteView,
685
+ runBulk,
686
+ registry,
687
+ persistError,
688
+ ]);
689
+ return _jsx(CmsContext.Provider, { value: store$, children: children });
690
+ }
691
+ export function useCms() {
692
+ const store = useContext(CmsContext);
693
+ if (!store)
694
+ throw new Error('useCms must be used within a <CmsProvider>.');
695
+ return store;
696
+ }
697
+ /** Export a locale-aware label for a field (form label or name). */
698
+ export function fieldLabel(field) {
699
+ return field.form?.label ?? field.name;
700
+ }
701
+ export { primaryField };
702
+ //# sourceMappingURL=cms-store.js.map