@phtngyn/cms 0.2.0-beta.8 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (524) hide show
  1. package/LICENSE +18 -10
  2. package/README.md +59 -404
  3. package/drizzle/20261003215543_initial/migration.sql +251 -0
  4. package/drizzle/20261003215543_initial/snapshot.json +1941 -0
  5. package/package.json +75 -71
  6. package/src/Authoring.d.ts +41 -49
  7. package/src/Authoring.js +1 -1
  8. package/src/Blocks-BrxSemnd.js +40 -0
  9. package/src/Client.d.ts +8186 -0
  10. package/src/Client.js +41 -0
  11. package/src/Collections.d.ts +142 -0
  12. package/src/Collections.js +142 -0
  13. package/src/Config-CMiwciub.js +130 -0
  14. package/src/Config.d.ts +172 -0
  15. package/src/Config.js +2 -0
  16. package/src/Configuration-Dk2k3OIc.js +73 -0
  17. package/src/DataTransfer-BmECvPHB.js +488 -0
  18. package/src/Database-DSsNCGft.d.ts +3 -0
  19. package/src/Delivery.d.ts +28 -0
  20. package/src/Delivery.js +7 -0
  21. package/src/Document-CKXMSEf1.js +293 -0
  22. package/src/Document-TgwYKJZM.d.ts +220 -0
  23. package/src/DocumentRenderer-Wz2xaNyf.js +394 -0
  24. package/src/EditorSchema-wrDv-id6.js +296 -0
  25. package/src/Fields-BegSgYhj.d.ts +166 -0
  26. package/src/Fields-ioGaMEh9.js +130 -0
  27. package/src/Forms-BuKAXQxr.d.ts +203 -0
  28. package/src/Forms.d.ts +48 -11
  29. package/src/Forms.js +342 -7
  30. package/src/I18n-Ckf9h0rC.js +154 -0
  31. package/src/I18n.d.ts +45 -2
  32. package/src/I18n.js +2 -1
  33. package/src/Image-CJWPLnhP.js +110 -0
  34. package/src/Links-CJYyy7rC.js +28 -0
  35. package/src/Links-Dx1yOni8.d.ts +28 -0
  36. package/src/Locales-Ch7a5xuA.js +67 -0
  37. package/src/Locales-jwbmJaOp.d.ts +43 -0
  38. package/src/Locales.d.ts +3 -0
  39. package/src/Locales.js +3 -0
  40. package/src/Media-BQ0uL4w7.d.ts +15 -0
  41. package/src/Media-DSyvd14o.js +87 -0
  42. package/src/Module.d.ts +2 -10
  43. package/src/Module.js +1040 -152
  44. package/src/Operations.d.ts +57 -0
  45. package/src/Operations.js +263 -0
  46. package/src/People-DvNZauWw.js +69 -0
  47. package/src/PreviewFocus-C_EelZO5.js +104 -0
  48. package/src/Query-C0kGJF5_.d.ts +261 -0
  49. package/src/RevisionPreview-IVwbJ9Wy.js +133 -0
  50. package/src/Routes-BaZvm2LE.js +126 -0
  51. package/src/Routes-DM1rRp3r.d.ts +15 -0
  52. package/src/S3MediaObjects-y-WacEi9.js +193 -0
  53. package/src/Seo-BcpqxoAs.d.ts +57 -0
  54. package/src/Seo-CjNUtUkj.js +254 -0
  55. package/src/StudioApi-CXLwwocX.js +833 -0
  56. package/src/StudioErrors-T5zLGQ1M.js +117 -0
  57. package/src/StudioErrors-kq-E44lQ.d.ts +104 -0
  58. package/src/StudioServer.d.ts +20 -0
  59. package/src/StudioServer.js +34 -0
  60. package/src/answers-DcTg0Xv2.js +41 -0
  61. package/src/cli.js +681 -187
  62. package/src/contracts-rprW3ZOB.js +130 -0
  63. package/src/forms-3xuf0Ym7.d.ts +206 -0
  64. package/src/localeConfiguration-BPbkLi7-.js +32 -0
  65. package/src/localeContext-DhF3SPvM.js +59 -0
  66. package/src/locales-6OD4XGIZ.js +12 -0
  67. package/src/nuxtDelivery-BYX_Cddb.js +466 -0
  68. package/src/plugin-DTYuDaQu.js +7171 -0
  69. package/src/previewContext-dt3ZUh-w.js +4 -0
  70. package/src/previewRegions-CXjk5cbP.js +145 -0
  71. package/src/previewSource-fb-q3ESM.js +144 -0
  72. package/src/rendering-D9LVeEKX.js +47 -0
  73. package/src/rolldown-runtime-8H4AJuhK.js +14 -0
  74. package/src/runtime/CmsImage.js +38 -0
  75. package/src/runtime/DocumentPage.vue +10 -0
  76. package/src/runtime/DocumentPageContent.js +48 -0
  77. package/src/runtime/DocumentRenderer.d.ts +129 -0
  78. package/src/runtime/DocumentRenderer.js +2 -0
  79. package/src/runtime/api.js +48 -6
  80. package/src/runtime/delivery/useCmsDocument.js +2 -0
  81. package/src/runtime/delivery/useCmsDocumentQuery.js +2 -0
  82. package/src/runtime/delivery/useCmsDocumentSeo.js +2 -114
  83. package/src/runtime/delivery/useCmsLocale.js +10 -0
  84. package/src/runtime/plugin.js +2 -40
  85. package/src/runtime/preview.css +85 -0
  86. package/src/runtime/preview.js +277 -0
  87. package/src/runtime/previewSource.js +82 -0
  88. package/src/runtime/revisionPrivacy.js +13 -0
  89. package/src/runtime/studio.js +10 -0
  90. package/src/runtime/studioIcons.js +36 -0
  91. package/src/validation-3pggwcnm.js +396 -0
  92. package/src/validation-DpUwPC8Y.js +224 -0
  93. package/studio/THIRD-PARTY-LICENSES.md +2406 -0
  94. package/studio/chunks/AccountPage-DL3DitDM.js +288 -0
  95. package/studio/chunks/AccountPage-DL3DitDM.js.br +0 -0
  96. package/studio/chunks/AccountPage-DL3DitDM.js.gz +0 -0
  97. package/studio/chunks/ActivityPage-CLqVUqTh.js +584 -0
  98. package/studio/chunks/ActivityPage-CLqVUqTh.js.br +0 -0
  99. package/studio/chunks/ActivityPage-CLqVUqTh.js.gz +0 -0
  100. package/studio/chunks/Alert-D0D24z_a.js +335 -0
  101. package/studio/chunks/Alert-D0D24z_a.js.br +0 -0
  102. package/studio/chunks/Alert-D0D24z_a.js.gz +0 -0
  103. package/studio/chunks/Badge-BBFs88TI.js +346 -0
  104. package/studio/chunks/Badge-BBFs88TI.js.br +0 -0
  105. package/studio/chunks/Badge-BBFs88TI.js.gz +0 -0
  106. package/studio/chunks/Button-BT3ztSPx.js +14319 -0
  107. package/studio/chunks/Button-BT3ztSPx.js.br +0 -0
  108. package/studio/chunks/Button-BT3ztSPx.js.gz +0 -0
  109. package/studio/chunks/Collapsible-CKnEYIlp.js +246 -0
  110. package/studio/chunks/Collapsible-CKnEYIlp.js.br +0 -0
  111. package/studio/chunks/Collapsible-CKnEYIlp.js.gz +0 -0
  112. package/studio/chunks/ContentInventory-D7nsFA6U.js +1745 -0
  113. package/studio/chunks/ContentInventory-D7nsFA6U.js.br +0 -0
  114. package/studio/chunks/ContentInventory-D7nsFA6U.js.gz +0 -0
  115. package/studio/chunks/ContentPage-DCxt6BeD.js +18 -0
  116. package/studio/chunks/ContentPage-DCxt6BeD.js.br +0 -0
  117. package/studio/chunks/ContentPage-DCxt6BeD.js.gz +0 -0
  118. package/studio/chunks/DashboardSearch-DjyMjJwF.js +2413 -0
  119. package/studio/chunks/DashboardSearch-DjyMjJwF.js.br +0 -0
  120. package/studio/chunks/DashboardSearch-DjyMjJwF.js.gz +0 -0
  121. package/studio/chunks/DocumentLocaleMenu-0EkkOr6_.js +26063 -0
  122. package/studio/chunks/DocumentLocaleMenu-0EkkOr6_.js.br +0 -0
  123. package/studio/chunks/DocumentLocaleMenu-0EkkOr6_.js.gz +0 -0
  124. package/studio/chunks/DropdownMenu-CA9fB0uZ.js +4400 -0
  125. package/studio/chunks/DropdownMenu-CA9fB0uZ.js.br +0 -0
  126. package/studio/chunks/DropdownMenu-CA9fB0uZ.js.gz +0 -0
  127. package/studio/chunks/EditorPage-D_PAYEE4.js +7799 -0
  128. package/studio/chunks/EditorPage-D_PAYEE4.js.br +0 -0
  129. package/studio/chunks/EditorPage-D_PAYEE4.js.gz +0 -0
  130. package/studio/chunks/FormField-CgM6l2Yn.js +198 -0
  131. package/studio/chunks/FormField-CgM6l2Yn.js.br +0 -0
  132. package/studio/chunks/FormField-CgM6l2Yn.js.gz +0 -0
  133. package/studio/chunks/HelpPage-C-vrFcT_.js +552 -0
  134. package/studio/chunks/HelpPage-C-vrFcT_.js.br +0 -0
  135. package/studio/chunks/HelpPage-C-vrFcT_.js.gz +0 -0
  136. package/studio/chunks/Kbd-Ot7TIhVZ.js +271 -0
  137. package/studio/chunks/Kbd-Ot7TIhVZ.js.br +0 -0
  138. package/studio/chunks/Kbd-Ot7TIhVZ.js.gz +0 -0
  139. package/studio/chunks/MediaFolderDialog-DYu-eu-q.js +101 -0
  140. package/studio/chunks/MediaFolderDialog-DYu-eu-q.js.br +0 -0
  141. package/studio/chunks/MediaFolderDialog-DYu-eu-q.js.gz +0 -0
  142. package/studio/chunks/MediaPage-D-jaWtdl.js +923 -0
  143. package/studio/chunks/MediaPage-D-jaWtdl.js.br +0 -0
  144. package/studio/chunks/MediaPage-D-jaWtdl.js.gz +0 -0
  145. package/studio/chunks/MediaPicker-BZs2wUFz.js +837 -0
  146. package/studio/chunks/MediaPicker-BZs2wUFz.js.br +0 -0
  147. package/studio/chunks/MediaPicker-BZs2wUFz.js.gz +0 -0
  148. package/studio/chunks/MediaUploadPanel-C7Kyg6aR.js +1173 -0
  149. package/studio/chunks/MediaUploadPanel-C7Kyg6aR.js.br +0 -0
  150. package/studio/chunks/MediaUploadPanel-C7Kyg6aR.js.gz +0 -0
  151. package/studio/chunks/Modal-D6hSvxHd.js +265 -0
  152. package/studio/chunks/Modal-D6hSvxHd.js.br +0 -0
  153. package/studio/chunks/Modal-D6hSvxHd.js.gz +0 -0
  154. package/studio/chunks/NewDocumentDialog-C8B6_r3J.js +277 -0
  155. package/studio/chunks/NewDocumentDialog-C8B6_r3J.js.br +0 -0
  156. package/studio/chunks/NewDocumentDialog-C8B6_r3J.js.gz +0 -0
  157. package/studio/chunks/Pagination-D9BSo5H2.js +573 -0
  158. package/studio/chunks/Pagination-D9BSo5H2.js.br +0 -0
  159. package/studio/chunks/Pagination-D9BSo5H2.js.gz +0 -0
  160. package/studio/chunks/PeoplePage-CWIXitBD.js +783 -0
  161. package/studio/chunks/PeoplePage-CWIXitBD.js.br +0 -0
  162. package/studio/chunks/PeoplePage-CWIXitBD.js.gz +0 -0
  163. package/studio/chunks/Popover-B63bkTMS.js +128 -0
  164. package/studio/chunks/Popover-B63bkTMS.js.br +0 -0
  165. package/studio/chunks/Popover-B63bkTMS.js.gz +0 -0
  166. package/studio/chunks/PublicationActionDialog-Cm_P0C3I.js +255 -0
  167. package/studio/chunks/PublicationActionDialog-Cm_P0C3I.js.br +0 -0
  168. package/studio/chunks/PublicationActionDialog-Cm_P0C3I.js.gz +0 -0
  169. package/studio/chunks/Routes-DLYHmulE.js +102 -0
  170. package/studio/chunks/Routes-DLYHmulE.js.br +0 -0
  171. package/studio/chunks/Routes-DLYHmulE.js.gz +0 -0
  172. package/studio/chunks/RovingFocusItem-QZNg-wWF.js +95 -0
  173. package/studio/chunks/RovingFocusItem-QZNg-wWF.js.br +0 -0
  174. package/studio/chunks/RovingFocusItem-QZNg-wWF.js.gz +0 -0
  175. package/studio/chunks/ScheduledPage-C0hqrkr5.js +332 -0
  176. package/studio/chunks/ScheduledPage-C0hqrkr5.js.br +0 -0
  177. package/studio/chunks/ScheduledPage-C0hqrkr5.js.gz +0 -0
  178. package/studio/chunks/Search-BEgCe9Aj.js +14646 -0
  179. package/studio/chunks/Search-BEgCe9Aj.js.br +0 -0
  180. package/studio/chunks/Search-BEgCe9Aj.js.gz +0 -0
  181. package/studio/chunks/Select-B50WZMW-.js +2145 -0
  182. package/studio/chunks/Select-B50WZMW-.js.br +0 -0
  183. package/studio/chunks/Select-B50WZMW-.js.gz +0 -0
  184. package/studio/chunks/SelectMenu-DSweWGMz.js +2109 -0
  185. package/studio/chunks/SelectMenu-DSweWGMz.js.br +0 -0
  186. package/studio/chunks/SelectMenu-DSweWGMz.js.gz +0 -0
  187. package/studio/chunks/SeoPage-CNNxGe4h.js +846 -0
  188. package/studio/chunks/SeoPage-CNNxGe4h.js.br +0 -0
  189. package/studio/chunks/SeoPage-CNNxGe4h.js.gz +0 -0
  190. package/studio/chunks/Skeleton-COz8dcrw.js +39 -0
  191. package/studio/chunks/Skeleton-COz8dcrw.js.br +2 -0
  192. package/studio/chunks/Skeleton-COz8dcrw.js.gz +0 -0
  193. package/studio/chunks/Slideover-QMMHAAys.js +289 -0
  194. package/studio/chunks/Slideover-QMMHAAys.js.br +0 -0
  195. package/studio/chunks/Slideover-QMMHAAys.js.gz +0 -0
  196. package/studio/chunks/StudioPage-ngEIDr5d.js +80 -0
  197. package/studio/chunks/StudioPage-ngEIDr5d.js.br +0 -0
  198. package/studio/chunks/StudioPage-ngEIDr5d.js.gz +0 -0
  199. package/studio/chunks/StudioPageToolbar-BwHnqyr6.js +2524 -0
  200. package/studio/chunks/StudioPageToolbar-BwHnqyr6.js.br +0 -0
  201. package/studio/chunks/StudioPageToolbar-BwHnqyr6.js.gz +0 -0
  202. package/studio/chunks/Switch-qKl1aDn7.js +484 -0
  203. package/studio/chunks/Switch-qKl1aDn7.js.br +0 -0
  204. package/studio/chunks/Switch-qKl1aDn7.js.gz +0 -0
  205. package/studio/chunks/ToolPage-DxoVAJVk.js +29 -0
  206. package/studio/chunks/ToolPage-DxoVAJVk.js.br +0 -0
  207. package/studio/chunks/ToolPage-DxoVAJVk.js.gz +0 -0
  208. package/studio/chunks/Tooltip-Bu15m_DB.js +693 -0
  209. package/studio/chunks/Tooltip-Bu15m_DB.js.br +0 -0
  210. package/studio/chunks/Tooltip-Bu15m_DB.js.gz +0 -0
  211. package/studio/chunks/TrashPage-lhqLLdoG.js +12 -0
  212. package/studio/chunks/TrashPage-lhqLLdoG.js.br +0 -0
  213. package/studio/chunks/TrashPage-lhqLLdoG.js.gz +0 -0
  214. package/studio/chunks/VersionsPage-Cqy6UAp9.js +2349 -0
  215. package/studio/chunks/VersionsPage-Cqy6UAp9.js.br +0 -0
  216. package/studio/chunks/VersionsPage-Cqy6UAp9.js.gz +0 -0
  217. package/studio/chunks/VisuallyHiddenInput-Cu8hQLRf.js +113 -0
  218. package/studio/chunks/VisuallyHiddenInput-Cu8hQLRf.js.br +0 -0
  219. package/studio/chunks/VisuallyHiddenInput-Cu8hQLRf.js.gz +0 -0
  220. package/studio/chunks/arrays-CUJkmV4I.js +10 -0
  221. package/studio/chunks/arrays-CUJkmV4I.js.br +0 -0
  222. package/studio/chunks/arrays-CUJkmV4I.js.gz +0 -0
  223. package/studio/chunks/base-DkTekJe8.js +213 -0
  224. package/studio/chunks/base-DkTekJe8.js.br +0 -0
  225. package/studio/chunks/base-DkTekJe8.js.gz +0 -0
  226. package/studio/chunks/content-DUGl3N4d.js +6012 -0
  227. package/studio/chunks/content-DUGl3N4d.js.br +0 -0
  228. package/studio/chunks/content-DUGl3N4d.js.gz +0 -0
  229. package/studio/chunks/destinations-DPIQVQa6.js +227 -0
  230. package/studio/chunks/destinations-DPIQVQa6.js.br +0 -0
  231. package/studio/chunks/destinations-DPIQVQa6.js.gz +0 -0
  232. package/studio/chunks/en-073cjKW4.js +152 -0
  233. package/studio/chunks/en-073cjKW4.js.br +0 -0
  234. package/studio/chunks/en-073cjKW4.js.gz +0 -0
  235. package/studio/chunks/en-Bn8mxPuf.js +134 -0
  236. package/studio/chunks/en-Bn8mxPuf.js.br +0 -0
  237. package/studio/chunks/en-Bn8mxPuf.js.gz +0 -0
  238. package/studio/chunks/en-C9OiaUDZ.js +251 -0
  239. package/studio/chunks/en-C9OiaUDZ.js.br +0 -0
  240. package/studio/chunks/en-C9OiaUDZ.js.gz +0 -0
  241. package/studio/chunks/en-CHAR6jzx.js +147 -0
  242. package/studio/chunks/en-CHAR6jzx.js.br +0 -0
  243. package/studio/chunks/en-CHAR6jzx.js.gz +0 -0
  244. package/studio/chunks/en-Cq4N1vEF.js +93 -0
  245. package/studio/chunks/en-Cq4N1vEF.js.br +2 -0
  246. package/studio/chunks/en-Cq4N1vEF.js.gz +0 -0
  247. package/studio/chunks/en-D2hRqlse.js +140 -0
  248. package/studio/chunks/en-D2hRqlse.js.br +0 -0
  249. package/studio/chunks/en-D2hRqlse.js.gz +0 -0
  250. package/studio/chunks/en-DiUC3-j6.js +144 -0
  251. package/studio/chunks/en-DiUC3-j6.js.br +0 -0
  252. package/studio/chunks/en-DiUC3-j6.js.gz +0 -0
  253. package/studio/chunks/english-Cs_Adu-u.js +8 -0
  254. package/studio/chunks/english-Cs_Adu-u.js.br +0 -0
  255. package/studio/chunks/english-Cs_Adu-u.js.gz +0 -0
  256. package/studio/chunks/esm-D6DqSiL1.js +752 -0
  257. package/studio/chunks/esm-D6DqSiL1.js.br +0 -0
  258. package/studio/chunks/esm-D6DqSiL1.js.gz +0 -0
  259. package/studio/chunks/externalRequest-CTzr2nDq.js +23 -0
  260. package/studio/chunks/externalRequest-CTzr2nDq.js.br +0 -0
  261. package/studio/chunks/externalRequest-CTzr2nDq.js.gz +0 -0
  262. package/studio/chunks/iconify-DR9ryCPv.js +1007 -0
  263. package/studio/chunks/iconify-DR9ryCPv.js.br +0 -0
  264. package/studio/chunks/iconify-DR9ryCPv.js.gz +0 -0
  265. package/studio/chunks/icons-D2MsAaXq.js +183 -0
  266. package/studio/chunks/icons-D2MsAaXq.js.br +0 -0
  267. package/studio/chunks/icons-D2MsAaXq.js.gz +0 -0
  268. package/studio/chunks/leaveGuards-D22fTGgr.js +26 -0
  269. package/studio/chunks/leaveGuards-D22fTGgr.js.br +0 -0
  270. package/studio/chunks/leaveGuards-D22fTGgr.js.gz +0 -0
  271. package/studio/chunks/lucideIcons-EyqyPBsX.js +238 -0
  272. package/studio/chunks/lucideIcons-EyqyPBsX.js.br +0 -0
  273. package/studio/chunks/lucideIcons-EyqyPBsX.js.gz +0 -0
  274. package/studio/chunks/mediaRoute--8cY8rUe.js +17 -0
  275. package/studio/chunks/mediaRoute--8cY8rUe.js.br +0 -0
  276. package/studio/chunks/mediaRoute--8cY8rUe.js.gz +0 -0
  277. package/studio/chunks/newDocumentPlanning-C26DHpvh.js +77 -0
  278. package/studio/chunks/newDocumentPlanning-C26DHpvh.js.br +0 -0
  279. package/studio/chunks/newDocumentPlanning-C26DHpvh.js.gz +0 -0
  280. package/studio/chunks/notifications-OKOLc40v.js +110 -0
  281. package/studio/chunks/notifications-OKOLc40v.js.br +0 -0
  282. package/studio/chunks/notifications-OKOLc40v.js.gz +0 -0
  283. package/studio/chunks/operations-CjNHyrEX.js +57 -0
  284. package/studio/chunks/operations-CjNHyrEX.js.br +0 -0
  285. package/studio/chunks/operations-CjNHyrEX.js.gz +0 -0
  286. package/studio/chunks/overlay-DnqFLZTc.js +1733 -0
  287. package/studio/chunks/overlay-DnqFLZTc.js.br +0 -0
  288. package/studio/chunks/overlay-DnqFLZTc.js.gz +0 -0
  289. package/studio/chunks/presentation-DF83w0hE.js +57 -0
  290. package/studio/chunks/presentation-DF83w0hE.js.br +0 -0
  291. package/studio/chunks/presentation-DF83w0hE.js.gz +0 -0
  292. package/studio/chunks/runtime-core.esm-bundler-DKFA9Rep.js +4557 -0
  293. package/studio/chunks/runtime-core.esm-bundler-DKFA9Rep.js.br +0 -0
  294. package/studio/chunks/runtime-core.esm-bundler-DKFA9Rep.js.gz +0 -0
  295. package/studio/chunks/searchPresentation-DFwxQkt3.js +76 -0
  296. package/studio/chunks/searchPresentation-DFwxQkt3.js.br +0 -0
  297. package/studio/chunks/searchPresentation-DFwxQkt3.js.gz +0 -0
  298. package/studio/chunks/status-DQv6ihkU.js +38 -0
  299. package/studio/chunks/status-DQv6ihkU.js.br +0 -0
  300. package/studio/chunks/status-DQv6ihkU.js.gz +0 -0
  301. package/studio/chunks/studioContext-I8HozGU1.js +4953 -0
  302. package/studio/chunks/studioContext-I8HozGU1.js.br +0 -0
  303. package/studio/chunks/studioContext-I8HozGU1.js.gz +0 -0
  304. package/studio/chunks/studioQueries-BR-9NT5F.js +73 -0
  305. package/studio/chunks/studioQueries-BR-9NT5F.js.br +0 -0
  306. package/studio/chunks/studioQueries-BR-9NT5F.js.gz +0 -0
  307. package/studio/chunks/studioSearch-ByaL-QpM.js +1095 -0
  308. package/studio/chunks/studioSearch-ByaL-QpM.js.br +0 -0
  309. package/studio/chunks/studioSearch-ByaL-QpM.js.gz +0 -0
  310. package/studio/chunks/useAcknowledgedDraft-0_c9sWI6.js +62 -0
  311. package/studio/chunks/useAcknowledgedDraft-0_c9sWI6.js.br +0 -0
  312. package/studio/chunks/useAcknowledgedDraft-0_c9sWI6.js.gz +0 -0
  313. package/studio/chunks/useApi-CUWMwLLw-B3Q3g2nf.js +189 -0
  314. package/studio/chunks/useApi-CUWMwLLw-B3Q3g2nf.js.br +0 -0
  315. package/studio/chunks/useApi-CUWMwLLw-B3Q3g2nf.js.gz +0 -0
  316. package/studio/chunks/useDocumentMessage-BAWvc38w.js +16 -0
  317. package/studio/chunks/useDocumentMessage-BAWvc38w.js.br +3 -0
  318. package/studio/chunks/useDocumentMessage-BAWvc38w.js.gz +0 -0
  319. package/studio/chunks/useFilter-DzyiTR7f.js +87 -0
  320. package/studio/chunks/useFilter-DzyiTR7f.js.br +0 -0
  321. package/studio/chunks/useFilter-DzyiTR7f.js.gz +0 -0
  322. package/studio/chunks/useFormControl-CL7sSCUo.js +8 -0
  323. package/studio/chunks/useFormControl-CL7sSCUo.js.br +0 -0
  324. package/studio/chunks/useFormControl-CL7sSCUo.js.gz +0 -0
  325. package/studio/chunks/useGraceArea-Chcy25IQ.js +154 -0
  326. package/studio/chunks/useGraceArea-Chcy25IQ.js.br +0 -0
  327. package/studio/chunks/useGraceArea-Chcy25IQ.js.gz +0 -0
  328. package/studio/chunks/useLeaveConfirmation-_iCSnKEp.js +44 -0
  329. package/studio/chunks/useLeaveConfirmation-_iCSnKEp.js.br +8 -0
  330. package/studio/chunks/useLeaveConfirmation-_iCSnKEp.js.gz +0 -0
  331. package/studio/chunks/useLinkCopy-CMjQteCy.js +35 -0
  332. package/studio/chunks/useLinkCopy-CMjQteCy.js.br +0 -0
  333. package/studio/chunks/useLinkCopy-CMjQteCy.js.gz +0 -0
  334. package/studio/chunks/usePointerMotion-DwRcwBNQ.js +16 -0
  335. package/studio/chunks/usePointerMotion-DwRcwBNQ.js.br +0 -0
  336. package/studio/chunks/usePointerMotion-DwRcwBNQ.js.gz +0 -0
  337. package/studio/chunks/useStudioNavigation-CLwtSYpb.js +298 -0
  338. package/studio/chunks/useStudioNavigation-CLwtSYpb.js.br +0 -0
  339. package/studio/chunks/useStudioNavigation-CLwtSYpb.js.gz +0 -0
  340. package/studio/chunks/useStudioPages-DR9qmYLg.js +79 -0
  341. package/studio/chunks/useStudioPages-DR9qmYLg.js.br +0 -0
  342. package/studio/chunks/useStudioPages-DR9qmYLg.js.gz +0 -0
  343. package/studio/chunks/utils-mdScC0v0.js +59 -0
  344. package/studio/chunks/utils-mdScC0v0.js.br +0 -0
  345. package/studio/chunks/utils-mdScC0v0.js.gz +0 -0
  346. package/studio/chunks/virtualizer-D1S0bZ4t.js +781 -0
  347. package/studio/chunks/virtualizer-D1S0bZ4t.js.br +0 -0
  348. package/studio/chunks/virtualizer-D1S0bZ4t.js.gz +0 -0
  349. package/studio/help/64f767fe29c2-save-and-publish.svg +7 -0
  350. package/studio/host.css +1 -1
  351. package/studio/host.css.br +0 -0
  352. package/studio/host.css.gz +0 -0
  353. package/studio/host.js +8793 -39395
  354. package/studio/host.js.br +0 -0
  355. package/studio/host.js.gz +0 -0
  356. package/CHANGELOG.md +0 -14
  357. package/bin/cms.mjs +0 -2
  358. package/src/ApplicationTypes.d.ts +0 -84
  359. package/src/ApplicationTypes.js +0 -1
  360. package/src/Configuration-CMweD9bn.js +0 -1191
  361. package/src/Configuration-CMweD9bn.js.map +0 -1
  362. package/src/Configuration.d.ts +0 -82
  363. package/src/Configuration.js +0 -8
  364. package/src/Configuration.js.map +0 -1
  365. package/src/Content.d.ts +0 -68
  366. package/src/Content.js +0 -373
  367. package/src/Content.js.map +0 -1
  368. package/src/ContentTransfer-BxwswWn3.js +0 -86
  369. package/src/ContentTransfer-BxwswWn3.js.map +0 -1
  370. package/src/ContentTransfer-Z9FHyLez.d.ts +0 -72
  371. package/src/DocumentEngine-tYtwbBjr.js +0 -978
  372. package/src/DocumentEngine-tYtwbBjr.js.map +0 -1
  373. package/src/DocumentModel.d.ts +0 -52
  374. package/src/DocumentModel.js +0 -66
  375. package/src/DocumentModel.js.map +0 -1
  376. package/src/Forms-CX-hwmJF.js +0 -391
  377. package/src/Forms-CX-hwmJF.js.map +0 -1
  378. package/src/Forms-CfNPTiCr.js +0 -110
  379. package/src/Forms-CfNPTiCr.js.map +0 -1
  380. package/src/Forms-R0HoTR-o.d.ts +0 -92
  381. package/src/Forms.js.map +0 -1
  382. package/src/HttpPaths-Be3vshPJ.js +0 -20
  383. package/src/HttpPaths-Be3vshPJ.js.map +0 -1
  384. package/src/I18n-wxswIRyY.d.ts +0 -30
  385. package/src/Media-j1bTritO.js +0 -112
  386. package/src/Media-j1bTritO.js.map +0 -1
  387. package/src/Module.js.map +0 -1
  388. package/src/References-CCPDAPve.js +0 -45
  389. package/src/References-CCPDAPve.js.map +0 -1
  390. package/src/S3MediaObjects-BXfjaZOu.js +0 -2756
  391. package/src/S3MediaObjects-BXfjaZOu.js.map +0 -1
  392. package/src/Seo-402YumpT.d.ts +0 -198
  393. package/src/cli/content.js +0 -101
  394. package/src/cli/content.js.map +0 -1
  395. package/src/cli.js.map +0 -1
  396. package/src/connection-BP80q4d-.js +0 -92
  397. package/src/connection-BP80q4d-.js.map +0 -1
  398. package/src/dev-lifecycle-3I_pozUl.js +0 -535
  399. package/src/dev-lifecycle-3I_pozUl.js.map +0 -1
  400. package/src/installation-DxqSSVbH.js +0 -9105
  401. package/src/installation-DxqSSVbH.js.map +0 -1
  402. package/src/internal/application-types.js +0 -43
  403. package/src/internal/application-types.js.map +0 -1
  404. package/src/internal/authoring-catalog.js +0 -158
  405. package/src/internal/authoring-catalog.js.map +0 -1
  406. package/src/internal/authoring-compiler.js +0 -146
  407. package/src/internal/authoring-compiler.js.map +0 -1
  408. package/src/internal/authoring-metadata.js +0 -191
  409. package/src/internal/authoring-metadata.js.map +0 -1
  410. package/src/internal/cms-config.js +0 -45
  411. package/src/internal/cms-config.js.map +0 -1
  412. package/src/internal/configuration.js +0 -228
  413. package/src/internal/configuration.js.map +0 -1
  414. package/src/internal/dev-lifecycle.js +0 -3
  415. package/src/internal/diagnostics.js +0 -47
  416. package/src/internal/diagnostics.js.map +0 -1
  417. package/src/internal/document-model.js +0 -376
  418. package/src/internal/document-model.js.map +0 -1
  419. package/src/internal/field-metadata.js +0 -7
  420. package/src/internal/field-metadata.js.map +0 -1
  421. package/src/internal/form-capabilities.js +0 -12
  422. package/src/internal/form-capabilities.js.map +0 -1
  423. package/src/internal/i18n.js +0 -73
  424. package/src/internal/i18n.js.map +0 -1
  425. package/src/internal/studio-app.js +0 -68
  426. package/src/internal/studio-app.js.map +0 -1
  427. package/src/location-CMNGO3lU.js +0 -35
  428. package/src/location-CMNGO3lU.js.map +0 -1
  429. package/src/metadata-DN9_K6Yl.js +0 -201
  430. package/src/metadata-DN9_K6Yl.js.map +0 -1
  431. package/src/models-5j67LMqW.js +0 -131
  432. package/src/models-5j67LMqW.js.map +0 -1
  433. package/src/models-VmGmG19-.js +0 -628
  434. package/src/models-VmGmG19-.js.map +0 -1
  435. package/src/runtime/api.js.map +0 -1
  436. package/src/runtime/blocks.js +0 -30
  437. package/src/runtime/blocks.js.map +0 -1
  438. package/src/runtime/collaboration.js +0 -45
  439. package/src/runtime/collaboration.js.map +0 -1
  440. package/src/runtime/delivery/DocumentField.js +0 -23
  441. package/src/runtime/delivery/DocumentField.js.map +0 -1
  442. package/src/runtime/delivery/DocumentRenderer.js +0 -61
  443. package/src/runtime/delivery/DocumentRenderer.js.map +0 -1
  444. package/src/runtime/delivery/DocumentScope.js +0 -41
  445. package/src/runtime/delivery/DocumentScope.js.map +0 -1
  446. package/src/runtime/delivery/blocks.js +0 -8
  447. package/src/runtime/delivery/blocks.js.map +0 -1
  448. package/src/runtime/delivery/context.js +0 -12
  449. package/src/runtime/delivery/context.js.map +0 -1
  450. package/src/runtime/delivery/document-page.js +0 -21
  451. package/src/runtime/delivery/document-page.js.map +0 -1
  452. package/src/runtime/delivery/document.js +0 -43
  453. package/src/runtime/delivery/document.js.map +0 -1
  454. package/src/runtime/delivery/error.js +0 -11
  455. package/src/runtime/delivery/error.js.map +0 -1
  456. package/src/runtime/delivery/plugin.js +0 -104
  457. package/src/runtime/delivery/plugin.js.map +0 -1
  458. package/src/runtime/delivery/preview.d.ts +0 -11
  459. package/src/runtime/delivery/preview.js +0 -6
  460. package/src/runtime/delivery/preview.js.map +0 -1
  461. package/src/runtime/delivery/types.d.ts +0 -2
  462. package/src/runtime/delivery/types.js +0 -1
  463. package/src/runtime/delivery/useCmsDocumentSeo.d.ts +0 -67
  464. package/src/runtime/delivery/useCmsDocumentSeo.js.map +0 -1
  465. package/src/runtime/delivery/useDocument.d.ts +0 -6
  466. package/src/runtime/delivery/useDocument.js +0 -23
  467. package/src/runtime/delivery/useDocument.js.map +0 -1
  468. package/src/runtime/delivery/useDocumentQuery.d.ts +0 -7
  469. package/src/runtime/delivery/useDocumentQuery.js +0 -29
  470. package/src/runtime/delivery/useDocumentQuery.js.map +0 -1
  471. package/src/runtime/forms/document.js +0 -38
  472. package/src/runtime/forms/document.js.map +0 -1
  473. package/src/runtime/forms/useCmsForm.js +0 -257
  474. package/src/runtime/forms/useCmsForm.js.map +0 -1
  475. package/src/runtime/i18n/translator.js +0 -58
  476. package/src/runtime/i18n/translator.js.map +0 -1
  477. package/src/runtime/i18n/useCmsI18n.d.ts +0 -13
  478. package/src/runtime/i18n/useCmsI18n.js +0 -38
  479. package/src/runtime/i18n/useCmsI18n.js.map +0 -1
  480. package/src/runtime/installation.js +0 -3
  481. package/src/runtime/plugin.js.map +0 -1
  482. package/src/runtime/preview/CmsStudioPreviewMarker.js +0 -29
  483. package/src/runtime/preview/CmsStudioPreviewMarker.js.map +0 -1
  484. package/src/runtime/preview/comark-document.js +0 -37
  485. package/src/runtime/preview/comark-document.js.map +0 -1
  486. package/src/runtime/preview/connection.js +0 -3
  487. package/src/runtime/preview/controller.js +0 -265
  488. package/src/runtime/preview/controller.js.map +0 -1
  489. package/src/runtime/preview/crypto.js +0 -16
  490. package/src/runtime/preview/crypto.js.map +0 -1
  491. package/src/runtime/preview/overlay.js +0 -122
  492. package/src/runtime/preview/overlay.js.map +0 -1
  493. package/src/runtime/preview/plugin.client.js +0 -68
  494. package/src/runtime/preview/plugin.client.js.map +0 -1
  495. package/src/runtime/preview/preview.css +0 -91
  496. package/src/runtime/preview/protocol.d.ts +0 -16
  497. package/src/runtime/preview/protocol.js +0 -23
  498. package/src/runtime/preview/protocol.js.map +0 -1
  499. package/src/runtime/preview/regions.js +0 -142
  500. package/src/runtime/preview/regions.js.map +0 -1
  501. package/src/runtime/preview/store.js +0 -4
  502. package/src/runtime/sitemap-entries.js +0 -17
  503. package/src/runtime/sitemap-entries.js.map +0 -1
  504. package/src/runtime/sitemap.js +0 -23
  505. package/src/runtime/sitemap.js.map +0 -1
  506. package/src/runtime/studio-app.js +0 -17
  507. package/src/runtime/studio-app.js.map +0 -1
  508. package/src/runtime/studio-document.js +0 -46
  509. package/src/runtime/studio-document.js.map +0 -1
  510. package/src/runtime/studio-entry.js +0 -19
  511. package/src/runtime/studio-entry.js.map +0 -1
  512. package/src/runtime/studio-navigation.js +0 -11
  513. package/src/runtime/studio-navigation.js.map +0 -1
  514. package/src/scalars-CA6kyipS.d.ts +0 -7
  515. package/src/scalars-CVZqT3L0.js +0 -22
  516. package/src/scalars-CVZqT3L0.js.map +0 -1
  517. package/src/store-X1e1o_MF.js +0 -209
  518. package/src/store-X1e1o_MF.js.map +0 -1
  519. package/src/types-DZ0IV-Ow.d.ts +0 -101
  520. package/studio/CreateDocumentDialog-C4_JBo1w.js +0 -335
  521. package/studio/SelectMenu-wXqxymUw.js +0 -34045
  522. package/studio/collaboration-DcK2F6v9.js +0 -4566
  523. package/studio/editor-P2rB7Csp.js +0 -30128
  524. package/studio/rolldown-runtime-Dy4uBu1J.js +0 -11
package/LICENSE CHANGED
@@ -1,13 +1,21 @@
1
- Copyright (c) 2026 Phat (phtngyn). All rights reserved.
1
+ MIT License
2
2
 
3
- This software and its accompanying documentation are proprietary.
4
- No permission is granted to use, copy, modify, distribute, sublicense, or
5
- sell this software or its documentation without prior written permission
6
- from the copyright holder, except as required by applicable law.
3
+ Copyright (c) 2026 Phat (phtngyn)
7
4
 
8
- Public availability of this software does not grant a license to it.
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
9
11
 
10
- Third-party software included in or used by this project remains subject
11
- to its own copyright notices and license terms. This notice applies only
12
- to original code and documentation owned by the copyright holder and does
13
- not restrict rights granted under those third-party licenses.
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,17 +1,17 @@
1
- # `@phtngyn/cms`
1
+ # @phtngyn/cms
2
2
 
3
- A CMS for Nuxt with an embedded Studio, collaborative editing, PostgreSQL persistence, and S3-compatible media storage. Install one module, configure your services in `cms.config.ts`, and create your first administrator in Studio. Database migrations and authentication are managed by the module.
3
+ A single-site Nuxt CMS with an embedded Studio. This package includes the CMS server, Studio, database migrations, and the `cms` CLI. Studio runs at `/_cms/app` on your website.
4
4
 
5
- ## Working on this package
5
+ ## Requirements
6
6
 
7
- This is the consumer guide. For implementation changes, start at [Module](./src/Module.ts) for Nuxt registration, [Configuration](./src/Configuration.ts) and [configuration compilation](./src/internal/configuration.ts) for setup, [runtime](./src/runtime/) for delivery, and [package exports and scripts](./package.json) for the current public surface. Follow the feature into its owning package and tests before changing behavior; examples below illustrate usage rather than define the current contract. The [canonical example](../../examples/nuxt/README.md) exercises the module end to end.
7
+ Use Node 24.11 or later in the Node 24 release line, Nuxt 5 nightly, and Vue 3.6 prerelease. The [package manifest](./package.json) defines the supported ranges. This beta release requires a long-lived Node process, writable persistent storage for SQLite, and an S3-compatible bucket for media. Run one CMS server process per installation.
8
8
 
9
9
  ## Install
10
10
 
11
- Requires Node.js 24, Nuxt `>=4.5.0 <5`, and Vue `>=3.6.0-rc.6 <4`. Deploy as a Node server with WebSocket support; static hosting is not supported.
11
+ In a Nuxt project, install the CMS and its framework peers. These commands use the nightly and Vue versions tested for this release; recheck them when upgrading the CMS.
12
12
 
13
13
  ```sh
14
- pnpm add @phtngyn/cms@beta effect
14
+ pnpm add @phtngyn/cms@0.3.0 nuxt@npm:nuxt-nightly@5.0.0-2610091554-2b103c9 vue@3.6.0-rc.10
15
15
  ```
16
16
 
17
17
  Register the module in `nuxt.config.ts`:
@@ -22,436 +22,91 @@ export default defineNuxtConfig({
22
22
  })
23
23
  ```
24
24
 
25
- ## Configure
25
+ Create `app/cms/collections.ts`:
26
26
 
27
- Create a PostgreSQL database and an S3-compatible bucket. The database user must be able to create and migrate CMS tables. Storage credentials need bucket access and object read, write, copy, list, and delete permissions. Configure public reads through your bucket or CDN; the module does not configure public access policies.
27
+ ```ts
28
+ import { defineCmsCollections, defineCmsCollection, field } from '@phtngyn/cms/Collections'
29
+
30
+ export default defineCmsCollections([
31
+ defineCmsCollection({
32
+ collection: 'pages',
33
+ label: 'Pages',
34
+ pattern: '/:path*',
35
+ fields: { title: field.text({ required: true }) },
36
+ }),
37
+ ])
38
+ ```
28
39
 
29
- Create `cms.config.ts` beside `nuxt.config.ts`:
40
+ Create `cms.config.ts`. Replace the bucket and region with your own; this example uses an existing bucket and the AWS credential provider chain.
30
41
 
31
42
  ```ts
32
- import { defineCmsConfig } from '@phtngyn/cms/Configuration'
33
- import { pageSchema } from './page.schema'
43
+ import { defineCmsConfig } from '@phtngyn/cms/Config'
34
44
 
35
45
  export default defineCmsConfig({
36
- documents: {
37
- collections: {
38
- pages: {
39
- label: 'Page',
40
- route: '/:path*',
41
- schema: pageSchema,
42
- },
43
- },
46
+ seo: { siteName: 'My website' },
47
+ runtime: {
48
+ origin: 'http://127.0.0.1:3000',
49
+ s3: { bucket: 'my-cms-media', region: 'us-east-1' },
44
50
  },
45
- installation: {
46
- database: { schema: 'cms' },
47
- media: {
48
- prefix: 'cms/',
49
- },
51
+ $development: {
52
+ bootstrap: { administrator: { name: 'Administrator' } },
50
53
  },
51
54
  })
52
55
  ```
53
56
 
54
- Keep environment-specific values in Nuxt runtime configuration. The module supplies empty `runtimeConfig.cms` defaults, so a production build needs no credentials. Nitro reads these values only when the built server starts:
57
+ For another S3 provider, set `runtime.s3.endpoint` and, if required, `forcePathStyle`. Give each installation a separate bucket or prefix. Supply credentials and initial administrator details in a git-ignored `.env`:
55
58
 
56
59
  ```dotenv
57
- NUXT_CMS_BASE_URL=http://localhost:3000
58
- NUXT_CMS_DATABASE_URL=postgres://cms:cms@localhost:5432/cms
59
- NUXT_CMS_INITIALIZATION_TOKEN=replace-with-a-distinct-32-character-random-token
60
- NUXT_CMS_SECRET=replace-with-at-least-32-random-characters
61
- NUXT_CMS_MEDIA_BUCKET=cms-media
62
- NUXT_CMS_MEDIA_PUBLIC_BASE_URL=http://localhost:8333/cms-media
63
- NUXT_CMS_MEDIA_REGION=us-east-1
64
- NUXT_CMS_MEDIA_ENDPOINT=http://localhost:8333
65
- NUXT_CMS_MEDIA_FORCE_PATH_STYLE=true
66
- NUXT_CMS_MEDIA_ACCESS_KEY_ID=cms-media
67
- NUXT_CMS_MEDIA_SECRET_ACCESS_KEY=cms-media-secret
60
+ NUXT_CMS_S3_ACCESS_KEY_ID=your-access-key
61
+ NUXT_CMS_S3_SECRET_ACCESS_KEY=your-secret-key
62
+ NUXT_CMS_BOOTSTRAP_ADMINISTRATOR_EMAIL=you@example.com
63
+ NUXT_CMS_BOOTSTRAP_ADMINISTRATOR_PASSWORD=choose-a-password-of-at-least-eight-characters
68
64
  ```
69
65
 
70
- Generate distinct random values of at least 32 characters for the secret and initialization token, and keep them server-side. The same built artifact can be started against another environment by changing only these runtime values.
71
-
72
- For storage using the AWS credential chain, omit both credential variables. Set `NUXT_CMS_MEDIA_PROVISION_BUCKET=true` to create a missing bucket automatically and grant bucket-creation permission. Set authored `installation.media: false` to build without uploads.
73
-
74
- The PostgreSQL schema and S3 prefix are the installation's ownership boundary. CMS creates and migrates only the configured schema, and every media object stays under the configured prefix.
75
-
76
- ## Local development lifecycle
77
-
78
- Use the supported lifecycle before starting Nuxt:
66
+ Start the installation:
79
67
 
80
68
  ```sh
81
- cms dev doctor
82
- cms configuration check
83
- cms --json configuration check > configuration-report.json
84
- CMS_EMAIL=admin@example.test CMS_PASSWORD=admin@example.test cms dev bootstrap --content ./content --publish
85
- cms dev reset --database --media
86
- cms dev reset --database --media --yes --bootstrap --content ./content --publish
69
+ pnpm exec cms dev
87
70
  ```
88
71
 
89
- All lifecycle commands accept `--root <directory>`, `--env-file <path>`, `--verbose`, and `--json`. Values already present in the process override the explicit environment file, which overrides `<root>/.env`, which overrides Nuxt runtime-config defaults.
90
-
91
- `doctor` is read-only and reports pass, fail, or not-verified for configuration, PostgreSQL, migrations, S3, public media, packaged assets, readiness, and WebSockets. Add `--full` to validate pending migrations in a rolled-back transaction and probe database writes plus an actual publicly readable S3 object, or `--json` for editor and CI integrations. `bootstrap` prepares the Nuxt authoring catalog, provisions infrastructure, runs migrations, creates or updates the requested local administrator, and optionally plans and applies content without requiring a running server. Passwords come from `CMS_PASSWORD` or a private prompt.
72
+ The CLI generates a private installation secret in `.env`, starts Nuxt, and creates the initial administrator for a fresh installation. SQLite defaults to `.data/cms.sqlite`. In a second terminal, run `pnpm exec cms doctor`; once ready, open `http://127.0.0.1:3000/_cms/app` and sign in. Distributed installations use the included Studio assets.
92
73
 
93
- `reset` is a dry run unless `--yes` is present. It refuses to run while the configured CMS is live and can remove only the configured PostgreSQL schema and S3 prefix. Choose `--database`, `--media`, or both.
94
-
95
- `configuration check` is the read-only local and CI gate for authored configuration changes. It compares `cms.config.ts` plus discovered blocks and forms with the installation's accepted serializable catalog, validates every authored and published Document, and emits the same underlying report used during startup. Human output names each required remediation; `--json` emits the versioned report without presentation text. Compatible reports exit successfully. Reports with affected Documents exit unsuccessfully, so CI can use the command directly.
96
-
97
- Runtime startup records the first valid catalog and later compatible candidates. It never rewrites Documents to make a candidate fit. Field renames or removals, route or locale changes, unavailable blocks, narrower block permissions, and narrower form capabilities must be resolved through a separate explicit content change before startup can adopt the candidate.
98
-
99
- ## Content CLI
100
-
101
- The installed package provides a `cms` command for importing a plain Markdown folder, exporting Studio-authored Markdown, and moving content between running CMS installations. Create the first administrator in Studio, then sign in to the CLI with that administrator's email and password. The CLI prompts for the site URL, administrator email, and password when they are missing. For noninteractive use, set `CMS_URL`, `CMS_EMAIL`, and `CMS_PASSWORD`; `--url` and `--email` can replace the first two variables. Use HTTPS outside localhost.
74
+ ## Build and deploy
102
75
 
103
76
  ```sh
104
- CMS_URL=https://source.example.com CMS_EMAIL=admin@example.com cms content export ./content
105
- CMS_URL=https://target.example.com CMS_EMAIL=admin@example.com cms content diff ./content
106
- CMS_URL=https://target.example.com CMS_EMAIL=admin@example.com cms content plan ./content
107
- CMS_URL=https://target.example.com CMS_EMAIL=admin@example.com cms content apply ./content
108
- CMS_URL=https://target.example.com CMS_EMAIL=admin@example.com cms content plan ./seed --publish
109
- CMS_URL=https://target.example.com CMS_EMAIL=admin@example.com cms content apply ./seed --publish
110
- ```
111
-
112
- Export chooses deterministic filesystem paths and writes a version 2 `.cms-content.json` index containing each document's stable identity, revisioned placement, revision ID, publication state, and content hash. Filesystem paths are only an import/export concern; moving a document in Studio does not rename anything in core document state. Commit the Markdown and index together to review changes. Export preserves indexed paths when possible, refuses to replace locally edited Markdown or index entries, and does not delete files that disappeared from the CMS. Remove stale files and index entries yourself after review. `diff` compares local Markdown, placement, and publication state with the current target and reports target-only documents. `plan` validates the whole incoming set and lists creates, updates, publications, unpublications, and conflicts without writing. `apply` plans again, then commits the batch atomically against the generation it just inspected. Run `plan` and `diff` before applying, especially when targeting another environment.
113
-
114
- The export index and every indexed Markdown path must stay inside the selected content directory without symlinked path components. Import and export reject symlinks at those boundaries.
115
-
116
- For a folder without `.cms-content.json`, the CLI reads nested `.md` and `.mdc` files and infers an initial collection, locale, parent, and slug from folders. A collection or locale directory is optional when configuration makes it unambiguous; `index.md` represents the home document or the entry represented by its containing folder. This inference happens only on the first unindexed import. These sources are eligible for publication with `--publish`. Imports create drafts by default. Existing content with different Markdown is a conflict until you pass `--overwrite` to `plan` and `apply`. For an exported folder, `--publish` synchronizes the indexed publication state: entries marked `published: true` are published and entries marked `published: false` are unpublished. Without it, imported changes remain drafts and existing target publication stays unchanged. The CLI does not delete target documents or move a target-only document. A concurrent change after planning causes `apply` to fail; review and retry.
117
-
118
- The command tree is intentionally shared: future CMS operations can be added beside `content` without separate executables.
119
-
120
- The same workflow is available to Node scripts without parsing CLI output:
121
-
122
- ```ts
123
- import { createCmsContentClient, readCmsContentDirectory } from '@phtngyn/cms/Content'
124
-
125
- const source = await readCmsContentDirectory('./content')
126
- const client = createCmsContentClient({
127
- baseUrl: 'http://localhost:3000',
128
- credentials: {
129
- email: process.env.CMS_EMAIL!,
130
- password: process.env.CMS_PASSWORD!,
131
- },
132
- })
133
-
134
- const plan = await client.plan(source, { overwrite: false, publish: true })
135
-
136
- if (plan.valid) await client.apply(plan)
137
-
138
- const document = await client.readDocument('8c62d2a7-b839-450a-bc08-5eccb420dc60')
139
- await client.export({ directory: './content' })
140
- ```
141
-
142
- Plans expose creates, updates, publications, unpublications, conflicts, issues, unchanged entries, and target-only sources. They are bound to their client, source, options, and generation; `apply(plan)` never replans. `readDocument(id)` returns the authored Markdown and exact publication state. `CmsContentError.code` provides stable authentication, not-found, conflict, validation, generation, filesystem, response, and network failure categories.
143
-
144
- ## Search and sharing
145
-
146
- The module installs the focused Nuxt robots, sitemap, schema.org, and SEO utility modules. Published CMS pages receive canonical, robots, social-sharing, and structured-data metadata automatically. The sitemap contains only published, indexable documents and uses their publication revision time for `lastmod`; localized variants are emitted as alternatives when they share a document key.
147
-
148
- Administrators can edit and publish site-wide SEO defaults at `/_cms/seo`. Editors can override search and sharing fields per document, while omitted values inherit the site-wide revision. Draft preview uses working SEO settings; ordinary website requests use published settings.
149
-
150
- The initial site-wide revision is derived from `baseUrl`. To seed explicit defaults and restrict the structured identity choices Studio offers, add `seo` to `cms.config.ts`:
151
-
152
- ```ts
153
- seo: {
154
- defaults: {
155
- canonicalOrigin: 'https://example.com',
156
- siteName: 'Example',
157
- titleTemplate: '%s · Example',
158
- defaultDescription: 'Example publishes useful things.',
159
- index: true,
160
- follow: true,
161
- identity: {
162
- type: 'Organization',
163
- name: 'Example',
164
- url: 'https://example.com',
165
- },
166
- },
167
- capabilities: {
168
- identityTypes: ['Organization'],
169
- structuredDataTypes: ['WebPage', 'Article'],
170
- generatedSocialImageTemplateIds: [],
171
- },
172
- },
173
- ```
174
-
175
- Keep raw robots directives and Nuxt module configuration in application code. The CMS owns semantic index/follow choices and generated page metadata; it does not accept arbitrary JSON-LD or inline HTML.
176
-
177
- ## Collection schemas
178
-
179
- Collections use **Standard Schema V1** for validation and **Standard JSON Schema V1** for the input structure Studio renders. This lets you keep your chosen validation library. Both contracts must be available on the collection schema; Standard Schema validation alone cannot describe controls. Studio requests draft 2020-12 JSON Schema input, resolves non-recursive local references, and runs the original validator when validating documents.
180
-
181
- The public standards types come directly from `@standard-schema/spec`. For a validator whose JSON Schema adapter is separate, `defineCmsSchema()` combines both contracts and applies library-neutral presentation to nested field paths:
182
-
183
- ```ts
184
- import { defineCmsSchema } from '@phtngyn/cms/DocumentModel'
185
-
186
- const pageSchema = defineCmsSchema({
187
- validator: page,
188
- jsonSchema: {
189
- input: () => createInputSchema(page),
190
- output: () => createOutputSchema(page),
191
- },
192
- fields: {
193
- description: { label: 'Description', input: 'textarea' },
194
- 'seo.description': { input: 'textarea' },
195
- },
196
- })
77
+ pnpm exec nuxt build
78
+ node .output/server/index.mjs
197
79
  ```
198
80
 
199
- For a validator that already implements both standards, pass it directly as `schema`. Otherwise, adapt its validator and input/output JSON Schema converters:
200
-
201
- ```ts
202
- const pageSchema = {
203
- '~standard': {
204
- ...validator['~standard'],
205
- jsonSchema: {
206
- input: () => inputJsonSchema,
207
- output: () => outputJsonSchema,
208
- },
209
- },
210
- }
211
- ```
212
-
213
- Supply actual draft 2020-12 schemas from the chosen library, using its input and output conversion modes respectively. Studio reads the input structure; the validator remains responsible for execution. A missing input converter produces a configuration error naming Standard JSON Schema V1. Foreign schemas use JSON Schema `title`, `description`, `default`, `x-cms-input`, and `x-cms-options` for presentation.
214
-
215
- Effect schemas are also accepted directly. The CMS derives Studio inputs from their encoded structure and runs the original decoder, preserving defaults, transformations, and asynchronous validation. Decoders must not require external Effect services, and their output must be a JSON-compatible object.
216
-
217
- ```ts
218
- import { Schema } from 'effect'
219
- import { CalendarDate, field, managedMediaReference } from '@phtngyn/cms/DocumentModel'
220
-
221
- const pageSchema = Schema.Struct({
222
- description: field(Schema.String, { default: '', input: 'textarea' }),
223
- publishedAt: Schema.optionalKey(field(CalendarDate, { label: 'Published on' })),
224
- contributors: field(
225
- Schema.Array(
226
- Schema.Struct({
227
- id: Schema.String,
228
- name: Schema.NonEmptyString,
229
- role: field(Schema.String, { default: 'Contributor' }),
230
- }),
231
- ),
232
- { default: [], label: 'Contributors' },
233
- ),
234
- socialImage: Schema.optionalKey(managedMediaReference),
235
- title: Schema.NonEmptyString,
236
- })
237
- ```
238
-
239
- Use `Schema.optionalKey` for optional fields, `Schema.NullOr` for explicit nulls, and `Schema.Finite` for numeric fields. A `field` default supplies Studio's initial value and applies only when the containing key is absent; invalid explicit values still fail. `field` can also give enum values distinct human labels through `options`. `CalendarDate` validates calendar dates stored as `YYYY-MM-DD` strings. Advanced Effect schemas, transformations, and defaults remain supported directly. `effect` is an intentional runtime dependency and is installed explicitly because authored schemas expose its public types.
240
-
241
- Studio supports strings, calendar dates, finite numbers, booleans, string arrays, choices, nested objects, repeatable objects, document references, and managed-media references. Repeatable object schemas must contain a required string `id`; Studio owns that identity and provides add, duplicate, remove, and reorder operations. `documentReference` and `managedMediaReference` store identity-backed source strings and project them to current routes or URLs for preview and delivery. Non-recursive local references are resolved. Ambiguous unions, structural intersections, recursive schemas, and unsupported field shapes fail configuration rather than producing incomplete forms.
242
-
243
- ## Start editing
244
-
245
- 1. Start your Nuxt application and open its `/_cms` route. In this repository, `pnpm dev` runs the canonical example at `http://localhost:3000/_cms`.
246
- 2. Enter your initialization token and create the first administrator. Initialization then closes.
247
- 3. Create a page in Studio, edit it, and publish it. The module provides page routing and rendering; your app must render `<NuxtPage />` in `app/app.vue` if it has a custom app shell. Existing app routes can provide custom page layouts.
248
-
249
- Studio is bundled with the module; no separate Studio deployment or auth setup is required. Readiness is available at `/_cms/health/ready`. Component schemas update through HMR during development. CMS configuration changes use Nuxt’s restart lifecycle.
250
-
251
- ## Preview drafts
81
+ Set `NUXT_CMS_ORIGIN` to the public website origin, `NUXT_CMS_DATABASE_FILE` to a persistent SQLite path, `NUXT_CMS_INSTALLATION_SECRET` to the retained installation secret, and the matching `NUXT_CMS_S3_*` values for media storage. Builds accept missing deployment credentials; server readiness requires usable configuration. Prepare a new secret with `cms prepare` before startup. For a fresh production installation, configure `bootstrap` in the production profile and run `cms setup --envName production` against the running server to create the administrator.
252
82
 
253
- Studio previews render authored documents through the same Nuxt routes, layouts, components, `useDocument`, and `useDocumentQuery` used by the website. A page can be previewed before its first publication. Preview mode follows internal navigation and survives iframe reloads; ordinary website requests continue to read published content.
83
+ ## Authoring and operations
254
84
 
255
- Draft delivery requires the current Studio session and document access permission. Preview URLs contain only iframe coordination information, never an access token. Preview HTML and draft API responses are private and uncached. Once the page renders, the editor bridge overlays current collaborative edits without waiting for publication or replacing Nuxt HMR.
85
+ Define editable Vue blocks in `app/cms/blocks/` with `@phtngyn/cms/Authoring`. The module registers `CmsDocumentRenderer`, `CmsImage`, and document, query, SEO, and locale composables. Use `@phtngyn/cms/Delivery` for explicit imports.
256
86
 
257
- ## Customize
87
+ `cms --help` lists installed commands and flags. Configuration belongs in `cms.config.ts`; `nuxt.config.ts` registers the module. Use `$development`, `$production`, or `$env` profiles for environment-specific values, and select a CLI profile with `--envName`. Paths are relative to the consuming project; use `--project <directory>` from another directory.
258
88
 
259
- - Define collections with Effect Schema in `documents.collections`. Import `field` from `@phtngyn/cms/DocumentModel` to add field labels and input hints.
260
- - Use the auto-imported `useDocument` and `useDocumentQuery` composables and `DocumentRenderer`, `DocumentScope`, and `DocumentField` components for custom rendering.
261
- - Import `defineCmsBlock` from `@phtngyn/cms/Authoring` to declare editable props and slots in your Nuxt Vue components.
262
- - Import Markdown folders with `cms content plan` and `cms content apply` after creating the first administrator.
89
+ For local S3 provisioning, declare `provision: { compose: { file: './compose.yaml', service: 'your-s3-service' }, createBucket: true }` in the development profile. The site owns that Compose file and its credentials. `cms prepare` starts the configured service and creates a missing bucket; omit `provision` when managing storage yourself.
263
90
 
264
- Nuxt generates `#cms/types` whenever configuration, collection schemas, or authored blocks change. It includes collection, form, block, locale, message-key, and interpolation-parameter types. Collection schema outputs, including repeatable objects and references, flow through `useDocument<'pages'>()` and `useDocumentQuery()`. Filtering and sorting remain limited to typed scalar paths and scalar lists; repeatable-object predicates are intentionally excluded. Registered form names and configured capabilities narrow `CmsFormDefinition<'contact-form'>`.
265
-
266
- ```ts
267
- import type { CmsCollection, CmsFormDefinition, CmsLocale } from '#cms/types'
268
-
269
- const page: CmsCollection<'pages'> | null = useDocument<'pages'>('/').data.value
270
- const locale: CmsLocale = 'de'
271
- const form = {} as CmsFormDefinition<'contact-form'>
272
- ```
273
-
274
- `useCmsI18n().t()` autocompletes configured keys and requires the exact placeholders in each message. Nuxt preparation rejects extra locale keys and inconsistent placeholders. Missing translations are allowed only when the configured fallback locale supplies the canonical message.
275
-
276
- CMS also synchronizes owned document routes with Nuxt Site Config. The delivered document locale wins, the route prefix applies while delivery resolves, and non-CMS routes retain the application's Site Config. Set `i18n.siteConfig: 'localized-routes'` to give CMS-derived language metadata to custom localized routes too; document canonical URLs, alternates, and SEO remain document-only. The default `documents` scope avoids conflicts with another application i18n module.
277
-
278
- ## Studio and authoring during development
279
-
280
- Studio at `/_cms` is a separate HTML document, Vue application, and Tailwind build. It owns its Nuxt UI settings, styles, and overlays independently of the website. Your app root and layouts apply only to the website. Both applications use the same Nuxt server; no separate Studio server or port is required.
281
-
282
- Only components that declare `defineCmsBlock` appear in the authoring catalog. Nuxt compiles their Vue props, slots, imported types, and presentation into one generated `#cms/authoring` module. Studio’s entry imports this module through Nuxt’s Vite graph, so isolation does not require a custom HMR transport. A separate Vue component map supplies Comark’s renderer, so adding or removing a block does not reinitialize Studio. Valid semantic changes update Studio and rebuild the Nitro worker automatically, keeping the development listener running. Invalid changes show a Vite error and retain the last valid catalog.
283
-
284
- An open editor reads the new catalog without reseeding content or replacing its collaborative document. Publishing waits until the collaboration server and editor use the same catalog revision. Installation configuration changes still use Nuxt’s configuration restart lifecycle.
285
-
286
- ## Component authoring and collection permissions
287
-
288
- Keep the Vue props, slots, defaults, and `defineCmsBlock` declaration together in the component's `<script setup lang="ts">`. Only declared fields and regions appear in Studio. Text regions accept one plain paragraph. Inline-text regions keep that single-paragraph shape while offering their declared inline formatting `features`. Rich-text regions accept multiple paragraphs and offer only their declared inline and list `features`. Optional slots can be removed and added again. Initial content seeds new blocks; it never overwrites existing content when a declaration changes. Render optional slot wrappers conditionally to avoid empty layout space.
289
-
290
- Render declared fields through ordinary Vue slot outlets. Studio follows each slot's rendered content through application components automatically: clicking a card title selects its title content, clicking its description selects the description, and clicking the remaining card surface selects the card block. Nuxt rejects an authored block when a declared slot has no matching outlet, so rendered fields cannot silently disappear from preview selection.
291
-
292
- A collection can restrict available component blocks:
293
-
294
- ```ts
295
- pages: {
296
- label: 'Page',
297
- route: '/:path*',
298
- schema: Schema.Struct({ title: Schema.String }),
299
- body: {
300
- blocks: ['content-hero'],
301
- groups: ['Editorial'],
302
- },
303
- },
304
- ```
305
-
306
- Block names and groups form a union. Omitting `body` permits all declared blocks; `body: {}` permits none. Ordinary text remains available. Unknown selectors fail configuration validation. Studio insertion and server publication use the same document-owned rules, including blocks inside other content. A restriction change preserves existing content and reports what must be corrected before publication.
307
-
308
- Clearing an optional property removes its stored override, so a Vue default can apply. Reset writes the current declared default. Nullable fields also offer an explicit no-value choice; empty strings, zero, and false remain actual values.
309
-
310
- ### Images, links, and composition
311
-
312
- String props can declare `input: 'image'` or `input: 'link'`. Studio uses the existing media library for image selection/upload and the document catalog for internal links. Internal selections are stored as `cms-document:<uuid>?route=<last-known-route>`: identity remains authoritative while the readable route provides a fallback when the target is unavailable. Studio resolves these references against authored documents and website delivery resolves them against published documents, so moving a target changes rendered links without rewriting Markdown. External links remain ordinary URLs. Image descriptions belong to a separate Vue prop; Studio does not invent an alt-text field or change your component's rendering. URL syntax and allowed schemes are checked before publication, and semantic props participate in the existing document/media reference index, including inside objects and lists.
313
-
314
- Slots with `input: 'blocks'` accept nested components. Optional `blocks` and `groups` selectors restrict direct children; omitting both permits all collection-allowed blocks. Collection permissions apply at every depth. Studio offers insertion, selection, deletion and sibling reordering inside each region. Existing content is retained when a schema change makes it invalid.
315
-
316
- For repeatable cards or chapters with formatted copy, give the parent a blocks slot restricted to an item block. Declare the item's title, icon, link, and layout choices as props, and its copy as a `rich-text` slot. Studio keeps each child block's identity and order, so the item needs no separate `id` prop. The [example section](../../examples/nuxt/app/components/documents/ContentSection.vue) hosts repeatable [cards](../../examples/nuxt/app/components/documents/ContentCard.vue); the English and German homepages show their Markdown source.
317
-
318
- Use object props for structured data and slots for composed content:
319
-
320
- ```ts
321
- interface Props {
322
- settings?: { compact: boolean }
323
- features?: Array<{ id: string; title: string; link?: string }>
324
- }
325
- // Inside the component's defineCmsBlock declaration:
326
- props: {
327
- settings: {
328
- label: 'Settings', input: 'object',
329
- fields: { compact: { label: 'Compact spacing', input: 'toggle' } },
330
- },
331
- features: {
332
- label: 'Features', input: 'list',
333
- fields: {
334
- title: { label: 'Title', input: 'text' },
335
- link: { label: 'Link', input: 'link' },
336
- },
337
- },
338
- },
339
- ```
340
-
341
- Every list item needs a required `id: string` in its Vue type. Studio generates and preserves this value; use it as the item's Vue `:key`. Do not declare an editable control for `id`. Object/list shapes, requiredness and string choices come from Vue, including nested fields. Literal factory defaults such as `() => []` and `() => ({ compact: false })` are supported. Computed defaults and recursive types are not editable contracts.
342
-
343
- Collaboration merges object fields and list-item fields independently. List ordering is separate from item values; simultaneous insertions at the same position retain both items in deterministic identity order. Removing an item takes precedence over concurrent edits to it. Competing edits to the same field use Yjs conflict resolution. Authoring schemas and controls update through the existing HMR path without reseeding content.
344
-
345
- ## Headless forms
346
-
347
- Register a form under the kebab-case name of your Nuxt Vue renderer. `defineCmsForm` is a normal TypeScript helper, not a compiler macro. It declares the question types and validation rules editors may use:
348
-
349
- ```ts
350
- import { defineCmsConfig } from '@phtngyn/cms/Configuration'
351
- import { defineCmsForm } from '@phtngyn/cms/Forms'
352
-
353
- // Inside your existing defineCmsConfig configuration:
354
- forms: {
355
- 'contact-form': {
356
- definition: defineCmsForm({
357
- label: 'Contact form',
358
- fieldTypes: ['text', 'email', 'textarea', 'number', 'checkbox', 'select'],
359
- rules: ['required', 'minLength', 'maxLength', 'min', 'max'],
360
- }),
361
- onSubmit: async ({ form, request, values }) => {
362
- // Server only: deliver or persist validated answers here.
363
- // values are keyed by stable question IDs; form.steps contains their labels.
364
- return { status: 'accepted', reference: request.id }
365
- },
366
- },
367
- },
368
- ```
369
-
370
- Create `ContactForm.vue` with an optional `cmsForm?: CmsFormDefinition` prop. The registration supplies its Studio authoring controls; do not also declare `defineCmsBlock` for that renderer. Forms appear in the Forms block group and follow collection block permissions. Editors add steps, questions, choices and permitted rules in the property panel. One step produces a single-step form. Question and option IDs are managed by Studio; labels can change without changing identities. Select answers contain option IDs. There is no website input markup or CSS supplied by CMS.
371
-
372
- A valid authored form receives `cmsForm` from `DocumentRenderer`. Incomplete drafts do not; show a helpful placeholder until the form is valid. Mount your custom form contents only when that definition exists:
373
-
374
- ```ts
375
- import type { CmsFormDefinition } from '#cms/types'
376
-
377
- const props = defineProps<{ definition: CmsFormDefinition<'contact-form'> }>()
378
- const {
379
- steps,
380
- errors,
381
- currentStep,
382
- stepIndex,
383
- isFirstStep,
384
- isLastStep,
385
- submitting,
386
- isSuccess,
387
- isPreview,
388
- submitError,
389
- canSubmit,
390
- visibleControls,
391
- invalidControls,
392
- firstInvalidControlId,
393
- control,
394
- next,
395
- previous,
396
- validate,
397
- submit,
398
- reset,
399
- } = useCmsForm(() => props.definition)
400
- ```
401
-
402
- The composable accepts a value, ref, or getter and returns destructurable refs and functions. Iterate `visibleControls`; each reactive control exposes plain template properties: `field`, writable `value`, `dirty`, `touched`, `valid`, `error`, `attrs`, `helpAttrs`, `errorAttrs`, and `touch()`. Bind `attrs` to the native control. CMS keeps stable IDs and ARIA relationships aligned without nested `.value` access inside a `v-for`. Valid number answers become numbers, empty answers become null, and invalid number text remains visible to validation. `canSubmit`, `invalidControls`, and `firstInvalidControlId` centralize form-level behavior, while `submitError` and `errors._form` cover transport and server failures.
403
-
404
- `next()` validates the current step, `previous()` preserves answers, and `submit()` validates every step and returns whether submission succeeded. A required checkbox must be checked.
405
-
406
- Definition replacements preserve answers for matching IDs and field types within the same form, clear validation state, and cancel pending client requests. `reset()` clears answers and submission state. The composable prevents overlapping submissions and repeat submission after success until reset. Scope disposal cancels client work. Cancellation cannot undo a server handler that has already started. An optional `submit(payload, signal)` transport override supports advanced integrations; it must return `CmsFormResult` and preserve server-side validation.
407
-
408
- The endpoint resolves the current published form and checks its exact serialized revision, including capabilities and question settings. Stale pages must reload. Draft preview validates locally without invoking the handler. Invalid structure prevents publication; invalid answers and unknown answer keys never reach the handler. The application handler explicitly returns `accepted`, `invalid`, or `unavailable`; trusted validation errors may target current field IDs or `_form`. Unexpected failures are correlated by request ID in server logs without recording answers and return only a generic public failure.
409
-
410
- Requests are limited to 128 KiB and 60 submissions per minute per server process, shared across forms. Browser requests with a foreign Origin are rejected. For deployments with multiple replicas or stronger spam protection, enforce a shared limit or challenge at your edge. There is no automatic retry, durable deduplication, inbox, email delivery, upload, branching, or save-and-resume in this release. Application handlers should account for retries after an uncertain network outcome. Configuration changes use Nuxt's restart lifecycle.
411
-
412
- See `examples/nuxt/app/components/FormContents.vue` for a Tailwind-rendered example. Its server handler acknowledges submissions without storing answers.
413
-
414
- ## Website languages
415
-
416
- Declare languages and developer-owned website strings together in `cms.config.ts`:
417
-
418
- ```ts
419
- i18n: {
420
- defaultLocale: 'en',
421
- fallbackLocale: 'en',
422
- prefix: 'always',
423
- locales: {
424
- en: { name: 'English', messages: {
425
- navigation: { home: 'Home' },
426
- footer: { copyright: '© {year} Acme' },
427
- } },
428
- de: { name: 'Deutsch', messages: {
429
- navigation: { home: 'Startseite' },
430
- } },
431
- },
432
- },
433
- ```
434
-
435
- Omit `prefix` to keep the default locale unprefixed (`/` for English and `/de` for German). Set it to
436
- `'always'` to prefix every locale (`/en` and `/de`); requests to a non-canonical form redirect permanently.
437
-
438
- Locale is part of stable document identity and route derivation. For an unindexed import, locale codes may be inferred from the first directory (`en/index.md`, `de/index.md`); the generated export index preserves the identity afterward. Markdown contains the editor-authored language already and needs no translation key. Revisions store identity, placement, and Markdown, while collaborative working edits checkpoint into Markdown. Import a Markdown folder with the admin CLI; subsequent changes require another plan and apply, with `--overwrite` for different Markdown.
439
-
440
- Use the auto-imported composable in website components:
441
-
442
- ```ts
443
- const { t, locale, localePath, switchLocalePath } = useCmsI18n()
444
- const navigation = computed(() => [{ label: t('navigation.home'), to: localePath('/') }])
445
- const germanVersion = computed(() => switchLocalePath('de'))
446
- t('footer.copyright', { year: 2026 })
447
- ```
91
+ To transfer authored content and media, use `cms export ./site.cms.zip`, then `cms import ./site.cms.zip --dry-run` on the destination before importing. A populated destination requires `--replace` to replace its content. Credentials and sessions remain local. To seed a fresh installation, set `bootstrap.snapshot` to an exported archive's project-relative path.
448
92
 
449
- `locale` is a read-only computed value derived from the current URL, including in Studio's website preview. `localePath(path, code?)` builds a path using the configured locale prefix policy; the code defaults to the current locale. `switchLocalePath(code)` changes the current URL's prefix while preserving its query and fragment. For documents with different authored slugs, pass the destination's unprefixed path as the second argument: `switchLocalePath('de', '/ueber-uns')`. The CMS does not infer relationships between different slugs. The Nuxt module sets the document's HTML `lang` automatically. Lists can explicitly pass `locale.value` to `useDocumentQuery`.
93
+ Public entry points include:
450
94
 
451
- Message keys receive generated TypeScript completion. Dictionaries contain nested plain strings; dots are reserved for key paths. Named `{parameters}` accept strings and numbers; missing parameters remain visible. Messages fall back from the URL locale to `fallbackLocale`, then to the key. Omit `fallbackLocale` (or set it to `null`) to disable fallback. The same explicit fallback policy applies to document lookup. Development warns about missing requested-locale messages. Render messages as text, and use native `Intl` for date and number formatting.
95
+ | Entry point | Purpose |
96
+ | --------------------------- | ---------------------------------------------------- |
97
+ | `@phtngyn/cms/Config` | Site configuration |
98
+ | `@phtngyn/cms/Collections` | Collection and field definitions |
99
+ | `@phtngyn/cms/Authoring` | Editable block and form metadata |
100
+ | `@phtngyn/cms/Delivery` | Document, query, SEO, and locale composables |
101
+ | `@phtngyn/cms/Forms` | Visitor form controls and submission state |
102
+ | `@phtngyn/cms/Locales` | Content language registry and URL helpers |
103
+ | `@phtngyn/cms/I18n` | Site-owned message catalogs and translation |
104
+ | `@phtngyn/cms/Client` | Node client for administrator scripts |
105
+ | `@phtngyn/cms/Operations` | Offline installation backup and restore |
106
+ | `@phtngyn/cms/StudioServer` | Protect site-owned server tools with Studio sessions |
452
107
 
453
- Only validated public i18n data enters the website bundle. Installation credentials and handlers stay server-side. Small dictionaries can stay inline; larger ones can be imported into the same config. Configuration changes restart Nuxt. Omitting `i18n` creates unlocalized document identities; the composable returns an empty locale and untranslated keys.
108
+ The installed exports include TypeScript declarations. Snapshot transfer is separate from offline backup: stop the installation before accessing its SQLite and media stores for recovery.
454
109
 
455
110
  ## License
456
111
 
457
- Proprietary. Copyright (c) 2026 Phat (phtngyn). All rights reserved. Use, copying, modification, and redistribution require prior written permission. Third-party components retain their own licenses.
112
+ Original CMS code is licensed under [MIT](./LICENSE). Bundled Studio dependencies retain their own licenses, included in `studio/THIRD-PARTY-LICENSES.md`.