@xleddyl/nuxt-cms 0.9.4 → 0.10.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 (431) hide show
  1. package/README.md +1 -1
  2. package/dist/module.d.mts +20 -1
  3. package/dist/module.json +1 -1
  4. package/dist/module.mjs +1037 -148
  5. package/dist/runtime/app/blocks/CmsBlocks.d.vue.ts +1 -1
  6. package/dist/runtime/app/blocks/CmsBlocks.vue +57 -9
  7. package/dist/runtime/app/blocks/CmsBlocks.vue.d.ts +1 -1
  8. package/dist/runtime/app/blocks/CmsField.d.ts +24 -0
  9. package/dist/runtime/app/blocks/CmsField.js +16 -0
  10. package/dist/runtime/app/blocks/node.d.ts +37 -0
  11. package/dist/runtime/app/blocks/node.js +17 -0
  12. package/dist/runtime/app/blocks/resolve.d.ts +18 -0
  13. package/dist/runtime/app/blocks/resolve.js +34 -0
  14. package/dist/runtime/app/components/cms/BlockPicker.d.vue.ts +22 -0
  15. package/dist/runtime/app/components/cms/BlockPicker.vue +87 -0
  16. package/dist/runtime/app/components/cms/BlockPicker.vue.d.ts +22 -0
  17. package/dist/runtime/app/components/cms/BlockPickerPopover.d.vue.ts +38 -0
  18. package/dist/runtime/app/components/cms/BlockPickerPopover.vue +44 -0
  19. package/dist/runtime/app/components/cms/BlockPickerPopover.vue.d.ts +38 -0
  20. package/dist/runtime/app/components/cms/BlockTree.d.vue.ts +29 -0
  21. package/dist/runtime/app/components/cms/BlockTree.vue +322 -0
  22. package/dist/runtime/app/components/cms/BlockTree.vue.d.ts +29 -0
  23. package/dist/runtime/app/components/cms/BlocksField.vue +569 -219
  24. package/dist/runtime/app/components/cms/BrandMark.vue +7 -13
  25. package/dist/runtime/app/components/cms/ConfirmGroups.vue +15 -13
  26. package/dist/runtime/app/components/cms/{BlockPalette.vue.d.ts → EditorHistory.d.vue.ts} +6 -5
  27. package/dist/runtime/app/components/cms/EditorHistory.vue +34 -0
  28. package/dist/runtime/app/components/cms/{BlockPalette.d.vue.ts → EditorHistory.vue.d.ts} +6 -5
  29. package/dist/runtime/app/components/cms/EntryDrawer.d.vue.ts +11 -5
  30. package/dist/runtime/app/components/cms/EntryDrawer.vue +183 -152
  31. package/dist/runtime/app/components/cms/EntryDrawer.vue.d.ts +11 -5
  32. package/dist/runtime/app/components/cms/EntryForm.d.vue.ts +16 -4
  33. package/dist/runtime/app/components/cms/EntryForm.vue +106 -147
  34. package/dist/runtime/app/components/cms/EntryForm.vue.d.ts +16 -4
  35. package/dist/runtime/app/components/cms/FieldInput.vue +10 -2
  36. package/dist/runtime/app/components/cms/FormSections.d.vue.ts +22 -0
  37. package/dist/runtime/app/components/cms/FormSections.vue +71 -0
  38. package/dist/runtime/app/components/cms/FormSections.vue.d.ts +22 -0
  39. package/dist/runtime/app/components/cms/ImportModal.vue +46 -58
  40. package/dist/runtime/app/components/cms/LinkField.d.vue.ts +16 -0
  41. package/dist/runtime/app/components/cms/LinkField.vue +250 -0
  42. package/dist/runtime/app/components/cms/LinkField.vue.d.ts +16 -0
  43. package/dist/runtime/app/components/cms/ListFilters.vue +10 -12
  44. package/dist/runtime/app/components/cms/LocaleSwitch.d.vue.ts +2 -1
  45. package/dist/runtime/app/components/cms/LocaleSwitch.vue +19 -11
  46. package/dist/runtime/app/components/cms/LocaleSwitch.vue.d.ts +2 -1
  47. package/dist/runtime/app/components/cms/MediaDetail.d.vue.ts +2 -0
  48. package/dist/runtime/app/components/cms/MediaDetail.vue +112 -83
  49. package/dist/runtime/app/components/cms/MediaDetail.vue.d.ts +2 -0
  50. package/dist/runtime/app/components/cms/MediaField.vue +35 -25
  51. package/dist/runtime/app/components/cms/MediaFolderPicker.vue +26 -71
  52. package/dist/runtime/app/components/cms/MediaGallery.d.vue.ts +1 -0
  53. package/dist/runtime/app/components/cms/MediaGallery.vue +442 -419
  54. package/dist/runtime/app/components/cms/MediaGallery.vue.d.ts +1 -0
  55. package/dist/runtime/app/components/cms/MediaThumb.vue +9 -25
  56. package/dist/runtime/app/components/cms/MediaUpload.vue +1 -1
  57. package/dist/runtime/app/components/cms/{BlockOutline.d.vue.ts → NestedBlockList.d.vue.ts} +5 -5
  58. package/dist/runtime/app/components/cms/NestedBlockList.vue +87 -0
  59. package/dist/runtime/app/components/cms/{BlockOutline.vue.d.ts → NestedBlockList.vue.d.ts} +5 -5
  60. package/dist/runtime/app/components/cms/PoweredBy.vue +12 -5
  61. package/dist/runtime/app/components/cms/PresetModal.d.vue.ts +18 -0
  62. package/dist/runtime/app/components/cms/PresetModal.vue +70 -0
  63. package/dist/runtime/app/components/cms/PresetModal.vue.d.ts +18 -0
  64. package/dist/runtime/app/components/cms/RelationField.vue +2 -8
  65. package/dist/runtime/app/components/cms/SettingsAccount.vue +60 -71
  66. package/dist/runtime/app/components/cms/SettingsColumns.vue +47 -69
  67. package/dist/runtime/app/components/cms/SettingsEmptyAdd.d.vue.ts +13 -0
  68. package/dist/runtime/app/components/cms/SettingsEmptyAdd.vue +21 -0
  69. package/dist/runtime/app/components/cms/SettingsEmptyAdd.vue.d.ts +13 -0
  70. package/dist/runtime/app/components/cms/SettingsEntries.d.vue.ts +13 -0
  71. package/dist/runtime/app/components/cms/SettingsEntries.vue +50 -0
  72. package/dist/runtime/app/components/cms/SettingsEntries.vue.d.ts +13 -0
  73. package/dist/runtime/app/components/cms/SettingsEntry.d.vue.ts +1 -10
  74. package/dist/runtime/app/components/cms/SettingsEntry.vue +11 -95
  75. package/dist/runtime/app/components/cms/SettingsEntry.vue.d.ts +1 -10
  76. package/dist/runtime/app/components/cms/SettingsEntryActions.d.vue.ts +7 -0
  77. package/dist/runtime/app/components/cms/SettingsEntryActions.vue +40 -0
  78. package/dist/runtime/app/components/cms/SettingsEntryActions.vue.d.ts +7 -0
  79. package/dist/runtime/app/components/cms/SettingsEntryTabs.d.vue.ts +7 -0
  80. package/dist/runtime/app/components/cms/SettingsEntryTabs.vue +21 -0
  81. package/dist/runtime/app/components/cms/SettingsEntryTabs.vue.d.ts +7 -0
  82. package/dist/runtime/app/components/cms/SettingsFormAction.d.vue.ts +3 -0
  83. package/dist/runtime/app/components/cms/SettingsFormAction.vue +17 -0
  84. package/dist/runtime/app/components/cms/SettingsFormAction.vue.d.ts +3 -0
  85. package/dist/runtime/app/components/cms/SettingsLayout.vue +18 -14
  86. package/dist/runtime/app/components/cms/SettingsPresetForm.d.vue.ts +11 -0
  87. package/dist/runtime/app/components/cms/SettingsPresetForm.vue +60 -0
  88. package/dist/runtime/app/components/cms/SettingsPresetForm.vue.d.ts +11 -0
  89. package/dist/runtime/app/components/cms/SettingsPresets.d.vue.ts +13 -0
  90. package/dist/runtime/app/components/cms/SettingsPresets.vue +65 -0
  91. package/dist/runtime/app/components/cms/SettingsPresets.vue.d.ts +13 -0
  92. package/dist/runtime/app/components/cms/SettingsRecordActions.d.vue.ts +32 -0
  93. package/dist/runtime/app/components/cms/SettingsRecordActions.vue +45 -0
  94. package/dist/runtime/app/components/cms/SettingsRecordActions.vue.d.ts +32 -0
  95. package/dist/runtime/app/components/cms/SettingsRedirectActions.d.vue.ts +3 -0
  96. package/dist/runtime/app/components/cms/SettingsRedirectActions.vue +59 -0
  97. package/dist/runtime/app/components/cms/SettingsRedirectActions.vue.d.ts +3 -0
  98. package/dist/runtime/app/components/cms/SettingsRedirectForm.d.vue.ts +11 -0
  99. package/dist/runtime/app/components/cms/SettingsRedirectForm.vue +77 -0
  100. package/dist/runtime/app/components/cms/SettingsRedirectForm.vue.d.ts +11 -0
  101. package/dist/runtime/app/components/cms/SettingsRedirects.d.vue.ts +13 -0
  102. package/dist/runtime/app/components/cms/SettingsRedirects.vue +117 -0
  103. package/dist/runtime/app/components/cms/SettingsRedirects.vue.d.ts +13 -0
  104. package/dist/runtime/app/components/cms/SettingsSecretCard.d.vue.ts +17 -0
  105. package/dist/runtime/app/components/cms/SettingsSecretCard.vue +43 -0
  106. package/dist/runtime/app/components/cms/SettingsSecretCard.vue.d.ts +17 -0
  107. package/dist/runtime/app/components/cms/SettingsSite.d.vue.ts +3 -0
  108. package/dist/runtime/app/components/cms/SettingsSite.vue +140 -0
  109. package/dist/runtime/app/components/cms/SettingsSite.vue.d.ts +3 -0
  110. package/dist/runtime/app/components/cms/SettingsUserCreate.d.vue.ts +8 -0
  111. package/dist/runtime/app/components/cms/SettingsUserCreate.vue +82 -0
  112. package/dist/runtime/app/components/cms/SettingsUserCreate.vue.d.ts +8 -0
  113. package/dist/runtime/app/components/cms/SettingsUserDetail.d.vue.ts +11 -0
  114. package/dist/runtime/app/components/cms/SettingsUserDetail.vue +179 -0
  115. package/dist/runtime/app/components/cms/SettingsUserDetail.vue.d.ts +11 -0
  116. package/dist/runtime/app/components/cms/SettingsUsers.d.vue.ts +9 -6
  117. package/dist/runtime/app/components/cms/SettingsUsers.vue +88 -234
  118. package/dist/runtime/app/components/cms/SettingsUsers.vue.d.ts +9 -6
  119. package/dist/runtime/app/components/cms/SharePreview.d.vue.ts +18 -0
  120. package/dist/runtime/app/components/cms/SharePreview.vue +219 -0
  121. package/dist/runtime/app/components/cms/SharePreview.vue.d.ts +18 -0
  122. package/dist/runtime/app/components/cms/SlugField.vue +5 -3
  123. package/dist/runtime/app/components/cms/StatusBadge.vue +8 -8
  124. package/dist/runtime/app/components/cms/TranslationBadges.d.vue.ts +7 -0
  125. package/dist/runtime/app/components/cms/TranslationBadges.vue +44 -0
  126. package/dist/runtime/app/components/cms/TranslationBadges.vue.d.ts +7 -0
  127. package/dist/runtime/app/components/cms/TranslationMenu.d.vue.ts +17 -0
  128. package/dist/runtime/app/components/cms/TranslationMenu.vue +28 -0
  129. package/dist/runtime/app/components/cms/TranslationMenu.vue.d.ts +17 -0
  130. package/dist/runtime/app/components/cms/VisualEditor.d.vue.ts +22 -4
  131. package/dist/runtime/app/components/cms/VisualEditor.vue +1153 -338
  132. package/dist/runtime/app/components/cms/VisualEditor.vue.d.ts +22 -4
  133. package/dist/runtime/app/components/cms/WelcomeModal.vue +32 -50
  134. package/dist/runtime/app/composables/cms-clipboard.d.ts +8 -0
  135. package/dist/runtime/app/composables/cms-clipboard.js +38 -0
  136. package/dist/runtime/app/composables/cms-confirm.d.ts +6 -8
  137. package/dist/runtime/app/composables/cms-confirm.js +5 -7
  138. package/dist/runtime/app/composables/cms-entry-disabled.d.ts +5 -1
  139. package/dist/runtime/app/composables/cms-entry-disabled.js +7 -0
  140. package/dist/runtime/app/composables/cms-entry-form.d.ts +15 -0
  141. package/dist/runtime/app/composables/cms-entry-form.js +40 -0
  142. package/dist/runtime/app/composables/cms-entry-settings.d.ts +30 -0
  143. package/dist/runtime/app/composables/cms-entry-settings.js +122 -0
  144. package/dist/runtime/app/composables/cms-entry.d.ts +5 -1
  145. package/dist/runtime/app/composables/cms-entry.js +36 -11
  146. package/dist/runtime/app/composables/cms-history.d.ts +10 -0
  147. package/dist/runtime/app/composables/cms-history.js +24 -0
  148. package/dist/runtime/app/composables/cms-link-targets.d.ts +10 -0
  149. package/dist/runtime/app/composables/cms-link-targets.js +40 -0
  150. package/dist/runtime/app/composables/cms-link-usage.d.ts +1 -0
  151. package/dist/runtime/app/composables/cms-link-usage.js +45 -0
  152. package/dist/runtime/app/composables/cms-media-library.d.ts +19 -9
  153. package/dist/runtime/app/composables/cms-media-library.js +31 -13
  154. package/dist/runtime/app/composables/cms-media-uploader.js +6 -20
  155. package/dist/runtime/app/composables/cms-permissions.d.ts +18 -0
  156. package/dist/runtime/app/composables/cms-permissions.js +54 -0
  157. package/dist/runtime/app/composables/cms-presets.d.ts +11 -0
  158. package/dist/runtime/app/composables/cms-presets.js +40 -0
  159. package/dist/runtime/app/composables/cms-preview-mode.d.ts +4 -0
  160. package/dist/runtime/app/composables/cms-preview-mode.js +8 -0
  161. package/dist/runtime/app/composables/cms-query.d.ts +3 -0
  162. package/dist/runtime/app/composables/cms-query.js +45 -20
  163. package/dist/runtime/app/composables/cms-record-list.d.ts +31 -0
  164. package/dist/runtime/app/composables/cms-record-list.js +75 -0
  165. package/dist/runtime/app/composables/cms-route.d.ts +6 -0
  166. package/dist/runtime/app/composables/cms-route.js +36 -0
  167. package/dist/runtime/app/composables/cms-runtime.d.ts +1 -0
  168. package/dist/runtime/app/composables/cms-save-handoff.d.ts +4 -0
  169. package/dist/runtime/app/composables/cms-save-handoff.js +19 -0
  170. package/dist/runtime/app/composables/cms-seo.d.ts +12 -0
  171. package/dist/runtime/app/composables/cms-seo.js +69 -0
  172. package/dist/runtime/app/composables/cms-settings-form.d.ts +13 -0
  173. package/dist/runtime/app/composables/cms-settings-form.js +29 -0
  174. package/dist/runtime/app/composables/cms-settings-sections.d.ts +26 -0
  175. package/dist/runtime/app/composables/cms-settings-sections.js +181 -0
  176. package/dist/runtime/app/composables/cms-settings-stores.d.ts +52 -0
  177. package/dist/runtime/app/composables/cms-settings-stores.js +156 -0
  178. package/dist/runtime/app/composables/cms-settings.d.ts +3 -3
  179. package/dist/runtime/app/composables/cms-settings.js +14 -8
  180. package/dist/runtime/app/composables/cms-site-disabled.d.ts +7 -0
  181. package/dist/runtime/app/composables/cms-site-disabled.js +8 -0
  182. package/dist/runtime/app/composables/cms-site.d.ts +7 -0
  183. package/dist/runtime/app/composables/cms-site.js +22 -0
  184. package/dist/runtime/app/composables/cms-toast.d.ts +2 -8
  185. package/dist/runtime/app/composables/cms-toast.js +3 -9
  186. package/dist/runtime/app/composables/cms-translation-actions.d.ts +15 -0
  187. package/dist/runtime/app/composables/cms-translation-actions.js +108 -0
  188. package/dist/runtime/app/css-url.d.ts +4 -0
  189. package/dist/runtime/app/image/CmsImage.d.vue.ts +89 -0
  190. package/dist/runtime/app/image/CmsImage.vue +91 -0
  191. package/dist/runtime/app/image/CmsImage.vue.d.ts +89 -0
  192. package/dist/runtime/app/layouts/cms-admin.d.vue.ts +2 -2
  193. package/dist/runtime/app/layouts/cms-admin.vue +98 -76
  194. package/dist/runtime/app/layouts/cms-admin.vue.d.ts +2 -2
  195. package/dist/runtime/app/layouts/cms-editor.vue +7 -2
  196. package/dist/runtime/app/links/CmsLink.d.vue.ts +18 -0
  197. package/dist/runtime/app/links/CmsLink.vue +18 -0
  198. package/dist/runtime/app/links/CmsLink.vue.d.ts +18 -0
  199. package/dist/runtime/app/middleware/cms-auth.js +13 -1
  200. package/dist/runtime/app/pages/admin-collection.vue +473 -297
  201. package/dist/runtime/app/pages/admin-content.vue +191 -54
  202. package/dist/runtime/app/pages/admin-entry.vue +79 -75
  203. package/dist/runtime/app/pages/admin-index.vue +18 -5
  204. package/dist/runtime/app/pages/admin-login.vue +1 -1
  205. package/dist/runtime/app/pages/admin-logout.vue +1 -1
  206. package/dist/runtime/app/pages/admin-media.vue +3 -3
  207. package/dist/runtime/app/pages/admin-preview.vue +112 -24
  208. package/dist/runtime/app/plugins/cms-field.d.ts +2 -0
  209. package/dist/runtime/app/plugins/cms-field.js +8 -0
  210. package/dist/runtime/app/plugins/cms-preview-banner.client.d.ts +2 -0
  211. package/dist/runtime/app/plugins/cms-preview-banner.client.js +19 -0
  212. package/dist/runtime/app/plugins/cms-preview.d.ts +2 -0
  213. package/dist/runtime/app/plugins/cms-preview.js +27 -0
  214. package/dist/runtime/app/preview/CmsPreviewBanner.d.vue.ts +7 -0
  215. package/dist/runtime/app/preview/CmsPreviewBanner.vue +63 -0
  216. package/dist/runtime/app/preview/CmsPreviewBanner.vue.d.ts +7 -0
  217. package/dist/runtime/app/preview/PreviewOverlay.d.vue.ts +17 -3
  218. package/dist/runtime/app/preview/PreviewOverlay.vue +629 -166
  219. package/dist/runtime/app/preview/PreviewOverlay.vue.d.ts +17 -3
  220. package/dist/runtime/app/preview/field-marker.d.ts +12 -0
  221. package/dist/runtime/app/preview/field-marker.js +20 -0
  222. package/dist/runtime/app/preview/inline-text.d.ts +15 -0
  223. package/dist/runtime/app/preview/inline-text.js +158 -0
  224. package/dist/runtime/app/utils/block-editor.d.ts +22 -0
  225. package/dist/runtime/app/utils/block-editor.js +12 -0
  226. package/dist/runtime/app/utils/keyboard.d.ts +6 -0
  227. package/dist/runtime/app/utils/keyboard.js +52 -0
  228. package/dist/runtime/app/utils/redirects.d.ts +6 -0
  229. package/dist/runtime/app/utils/redirects.js +7 -0
  230. package/dist/runtime/app/utils/ui.d.ts +8 -0
  231. package/dist/runtime/app/utils/ui.js +15 -1
  232. package/dist/runtime/app/utils/users.d.ts +15 -0
  233. package/dist/runtime/app/utils/users.js +14 -0
  234. package/dist/runtime/assets/cms.css +1 -1
  235. package/dist/runtime/generate.js +16 -2
  236. package/dist/runtime/server/api/collection-export.get.js +3 -2
  237. package/dist/runtime/server/api/collection-import.post.js +39 -11
  238. package/dist/runtime/server/api/collection.get.js +27 -9
  239. package/dist/runtime/server/api/collection.post.js +28 -11
  240. package/dist/runtime/server/api/collection.put.js +35 -13
  241. package/dist/runtime/server/api/item.delete.js +19 -7
  242. package/dist/runtime/server/api/item.get.js +3 -2
  243. package/dist/runtime/server/api/item.put.js +52 -18
  244. package/dist/runtime/server/api/link-usage.post.d.ts +5 -0
  245. package/dist/runtime/server/api/link-usage.post.js +21 -0
  246. package/dist/runtime/server/api/media-delete.post.js +4 -2
  247. package/dist/runtime/server/api/media-download.get.js +2 -2
  248. package/dist/runtime/server/api/media-folder.delete.js +8 -2
  249. package/dist/runtime/server/api/media-folder.patch.js +10 -2
  250. package/dist/runtime/server/api/media-folder.post.js +4 -2
  251. package/dist/runtime/server/api/media-move.post.js +7 -4
  252. package/dist/runtime/server/api/media-presign.post.js +2 -2
  253. package/dist/runtime/server/api/media-upload.put.js +2 -2
  254. package/dist/runtime/server/api/media-usage.post.d.ts +2 -4
  255. package/dist/runtime/server/api/media-usage.post.js +13 -9
  256. package/dist/runtime/server/api/media.delete.js +4 -2
  257. package/dist/runtime/server/api/media.get.js +22 -7
  258. package/dist/runtime/server/api/media.post.js +4 -2
  259. package/dist/runtime/server/api/media.put.js +33 -16
  260. package/dist/runtime/server/api/preset.delete.d.ts +4 -0
  261. package/dist/runtime/server/api/preset.delete.js +9 -0
  262. package/dist/runtime/server/api/preset.put.d.ts +3 -0
  263. package/dist/runtime/server/api/preset.put.js +23 -0
  264. package/dist/runtime/server/api/presets-field.get.d.ts +3 -0
  265. package/dist/runtime/server/api/presets-field.get.js +13 -0
  266. package/dist/runtime/server/api/presets-field.post.d.ts +3 -0
  267. package/dist/runtime/server/api/presets-field.post.js +36 -0
  268. package/dist/runtime/server/api/presets.get.d.ts +3 -0
  269. package/dist/runtime/server/api/presets.get.js +7 -0
  270. package/dist/runtime/server/api/preview-link.delete.d.ts +4 -0
  271. package/dist/runtime/server/api/preview-link.delete.js +15 -0
  272. package/dist/runtime/server/api/preview-links.get.d.ts +3 -0
  273. package/dist/runtime/server/api/preview-links.get.js +10 -0
  274. package/dist/runtime/server/api/preview-links.post.d.ts +3 -0
  275. package/dist/runtime/server/api/preview-links.post.js +17 -0
  276. package/dist/runtime/server/api/preview.get.d.ts +3 -0
  277. package/dist/runtime/server/api/preview.get.js +7 -0
  278. package/dist/runtime/server/api/redirect.delete.d.ts +4 -0
  279. package/dist/runtime/server/api/redirect.delete.js +10 -0
  280. package/dist/runtime/server/api/redirect.put.d.ts +3 -0
  281. package/dist/runtime/server/api/redirect.put.js +8 -0
  282. package/dist/runtime/server/api/redirects-import.post.d.ts +3 -0
  283. package/dist/runtime/server/api/redirects-import.post.js +13 -0
  284. package/dist/runtime/server/api/redirects.get.d.ts +3 -0
  285. package/dist/runtime/server/api/redirects.get.js +7 -0
  286. package/dist/runtime/server/api/redirects.post.d.ts +3 -0
  287. package/dist/runtime/server/api/redirects.post.js +7 -0
  288. package/dist/runtime/server/api/search.get.js +8 -3
  289. package/dist/runtime/server/api/settings.delete.js +2 -2
  290. package/dist/runtime/server/api/settings.get.js +4 -2
  291. package/dist/runtime/server/api/settings.put.js +2 -2
  292. package/dist/runtime/server/api/site.get.d.ts +3 -0
  293. package/dist/runtime/server/api/site.get.js +7 -0
  294. package/dist/runtime/server/api/site.put.d.ts +3 -0
  295. package/dist/runtime/server/api/site.put.js +16 -0
  296. package/dist/runtime/server/api/tags.get.js +3 -2
  297. package/dist/runtime/server/api/user.delete.js +8 -2
  298. package/dist/runtime/server/api/user.put.js +14 -4
  299. package/dist/runtime/server/api/users.get.js +2 -2
  300. package/dist/runtime/server/api/users.post.js +8 -4
  301. package/dist/runtime/server/middleware/hidden-site.d.ts +2 -0
  302. package/dist/runtime/server/middleware/hidden-site.js +8 -0
  303. package/dist/runtime/server/middleware/preview-links.d.ts +2 -0
  304. package/dist/runtime/server/middleware/preview-links.js +6 -0
  305. package/dist/runtime/server/middleware/redirects.d.ts +2 -0
  306. package/dist/runtime/server/middleware/redirects.js +18 -0
  307. package/dist/runtime/server/plugins/session-validate.js +4 -1
  308. package/dist/runtime/server/plugins/webhooks.d.ts +3 -0
  309. package/dist/runtime/server/plugins/webhooks.js +27 -0
  310. package/dist/runtime/server/routes/graphql.js +5 -3
  311. package/dist/runtime/server/routes/robots.d.ts +2 -0
  312. package/dist/runtime/server/routes/robots.js +16 -0
  313. package/dist/runtime/server/routes/sitemap.d.ts +2 -0
  314. package/dist/runtime/server/routes/sitemap.js +67 -0
  315. package/dist/runtime/server/utils/cached-value.d.ts +5 -0
  316. package/dist/runtime/server/utils/cached-value.js +24 -0
  317. package/dist/runtime/server/utils/content-routes.d.ts +5 -0
  318. package/dist/runtime/server/utils/content-routes.js +29 -0
  319. package/dist/runtime/server/utils/field-rules.d.ts +19 -0
  320. package/dist/runtime/server/utils/field-rules.js +72 -0
  321. package/dist/runtime/server/utils/graphql.d.ts +3 -1
  322. package/dist/runtime/server/utils/graphql.js +143 -28
  323. package/dist/runtime/server/utils/hooks.d.ts +14 -0
  324. package/dist/runtime/server/utils/hooks.js +71 -0
  325. package/dist/runtime/server/utils/import.d.ts +7 -2
  326. package/dist/runtime/server/utils/import.js +108 -14
  327. package/dist/runtime/server/utils/link-usage.d.ts +4 -0
  328. package/dist/runtime/server/utils/link-usage.js +28 -0
  329. package/dist/runtime/server/utils/media-references.d.ts +6 -1
  330. package/dist/runtime/server/utils/media-references.js +49 -20
  331. package/dist/runtime/server/utils/media-usage.d.ts +2 -0
  332. package/dist/runtime/server/utils/media-usage.js +5 -3
  333. package/dist/runtime/server/utils/page-rows.d.ts +2 -0
  334. package/dist/runtime/server/utils/page-rows.js +42 -29
  335. package/dist/runtime/server/utils/permissions.d.ts +14 -0
  336. package/dist/runtime/server/utils/permissions.js +43 -0
  337. package/dist/runtime/server/utils/presets.d.ts +18 -0
  338. package/dist/runtime/server/utils/presets.js +68 -0
  339. package/dist/runtime/server/utils/preview-links.d.ts +207 -0
  340. package/dist/runtime/server/utils/preview-links.js +161 -0
  341. package/dist/runtime/server/utils/redirects.d.ts +31 -0
  342. package/dist/runtime/server/utils/redirects.js +240 -0
  343. package/dist/runtime/server/utils/registry.js +4 -1
  344. package/dist/runtime/server/utils/relations.d.ts +8 -0
  345. package/dist/runtime/server/utils/relations.js +25 -6
  346. package/dist/runtime/server/utils/require-admin.d.ts +0 -1
  347. package/dist/runtime/server/utils/require-admin.js +4 -8
  348. package/dist/runtime/server/utils/search.d.ts +1 -0
  349. package/dist/runtime/server/utils/search.js +44 -19
  350. package/dist/runtime/server/utils/site.d.ts +23 -0
  351. package/dist/runtime/server/utils/site.js +79 -0
  352. package/dist/runtime/server/utils/sitemap.d.ts +12 -0
  353. package/dist/runtime/server/utils/sitemap.js +109 -0
  354. package/dist/runtime/server/utils/user-management.d.ts +4 -0
  355. package/dist/runtime/server/utils/user-management.js +20 -0
  356. package/dist/runtime/server/utils/users.d.ts +1 -1
  357. package/dist/runtime/server/utils/users.js +1 -1
  358. package/dist/runtime/server/utils/visibility.d.ts +1 -0
  359. package/dist/runtime/server/utils/visibility.js +6 -1
  360. package/dist/runtime/server/utils/webhooks.d.ts +24 -0
  361. package/dist/runtime/server/utils/webhooks.js +90 -0
  362. package/dist/runtime/shared/block-paths.d.ts +66 -0
  363. package/dist/runtime/shared/block-paths.js +310 -0
  364. package/dist/runtime/shared/block-picker.d.ts +18 -0
  365. package/dist/runtime/shared/block-picker.js +31 -0
  366. package/dist/runtime/shared/block-signature.d.ts +4 -0
  367. package/dist/runtime/shared/block-signature.js +46 -0
  368. package/dist/runtime/shared/clipboard.d.ts +31 -0
  369. package/dist/runtime/shared/clipboard.js +206 -0
  370. package/dist/runtime/shared/conditions.d.ts +36 -0
  371. package/dist/runtime/shared/conditions.js +100 -0
  372. package/dist/runtime/shared/content-routes.d.ts +42 -0
  373. package/dist/runtime/shared/content-routes.js +237 -0
  374. package/dist/runtime/shared/duplicate.js +2 -1
  375. package/dist/runtime/shared/editor-layout.d.ts +18 -0
  376. package/dist/runtime/shared/editor-layout.js +9 -0
  377. package/dist/runtime/shared/field-options.d.ts +21 -0
  378. package/dist/runtime/shared/field-options.js +90 -0
  379. package/dist/runtime/shared/graphql-sdl.d.ts +1 -0
  380. package/dist/runtime/shared/graphql-sdl.js +50 -26
  381. package/dist/runtime/shared/history.d.ts +27 -0
  382. package/dist/runtime/shared/history.js +123 -0
  383. package/dist/runtime/shared/hooks.d.ts +45 -0
  384. package/dist/runtime/shared/hooks.js +28 -0
  385. package/dist/runtime/shared/index.d.ts +90 -21
  386. package/dist/runtime/shared/index.js +121 -37
  387. package/dist/runtime/shared/inline-text.d.ts +38 -0
  388. package/dist/runtime/shared/inline-text.js +85 -0
  389. package/dist/runtime/shared/layout.d.ts +2 -1
  390. package/dist/runtime/shared/layout.js +3 -0
  391. package/dist/runtime/shared/links.d.ts +48 -0
  392. package/dist/runtime/shared/links.js +155 -0
  393. package/dist/runtime/shared/list-filters.d.ts +2 -0
  394. package/dist/runtime/shared/list-filters.js +2 -0
  395. package/dist/runtime/shared/media-focal.d.ts +30 -0
  396. package/dist/runtime/shared/media-focal.js +52 -0
  397. package/dist/runtime/shared/migrations-dir.d.ts +14 -0
  398. package/dist/runtime/shared/migrations-dir.js +48 -2
  399. package/dist/runtime/shared/presets.d.ts +67 -0
  400. package/dist/runtime/shared/presets.js +127 -0
  401. package/dist/runtime/shared/preview-links.d.ts +64 -0
  402. package/dist/runtime/shared/preview-links.js +54 -0
  403. package/dist/runtime/shared/preview.d.ts +124 -21
  404. package/dist/runtime/shared/preview.js +419 -81
  405. package/dist/runtime/shared/redirects.d.ts +75 -0
  406. package/dist/runtime/shared/redirects.js +230 -0
  407. package/dist/runtime/shared/roles.d.ts +57 -0
  408. package/dist/runtime/shared/roles.js +293 -0
  409. package/dist/runtime/shared/save-state.d.ts +8 -0
  410. package/dist/runtime/shared/save-state.js +15 -0
  411. package/dist/runtime/shared/search.d.ts +16 -1
  412. package/dist/runtime/shared/search.js +41 -7
  413. package/dist/runtime/shared/seo.d.ts +167 -0
  414. package/dist/runtime/shared/seo.js +335 -0
  415. package/dist/runtime/shared/transfer.js +2 -1
  416. package/dist/runtime/shared/translations.d.ts +29 -0
  417. package/dist/runtime/shared/translations.js +123 -0
  418. package/dist/runtime/shared/users.d.ts +1 -1
  419. package/dist/runtime/shared/validation.d.ts +23 -1
  420. package/dist/runtime/shared/validation.js +214 -64
  421. package/dist/runtime/webhooks.d.ts +33 -0
  422. package/dist/runtime/webhooks.js +57 -0
  423. package/dist/types.d.mts +5 -1
  424. package/package.json +6 -2
  425. package/dist/runtime/app/components/cms/BlockOutline.vue +0 -88
  426. package/dist/runtime/app/components/cms/BlockPalette.vue +0 -31
  427. package/dist/runtime/app/components/cms/SettingsModal.d.vue.ts +0 -12
  428. package/dist/runtime/app/components/cms/SettingsModal.vue +0 -126
  429. package/dist/runtime/app/components/cms/SettingsModal.vue.d.ts +0 -12
  430. package/dist/runtime/app/composables/cms-field-focus.d.ts +0 -4
  431. package/dist/runtime/app/composables/cms-field-focus.js +0 -20
@@ -1,13 +1,15 @@
1
1
  import { defineEventHandler } from "h3";
2
+ import cmsConfig from "#cms-config";
2
3
  import { useDb } from "#cms-db";
3
4
  import { cms_settings } from "#cms-tables";
4
- import { requireAdmin } from "../utils/require-admin.js";
5
+ import { requireCmsAccess } from "../utils/permissions.js";
5
6
  import { parseSettingsValue } from "../utils/settings.js";
6
7
  export default defineEventHandler(async (event) => {
7
- await requireAdmin(event);
8
+ await requireCmsAccess(event);
8
9
  const rows = await useDb().select().from(cms_settings);
9
10
  return Object.fromEntries(
10
11
  rows.flatMap((row) => {
12
+ if (!Object.hasOwn(cmsConfig, row.key)) return [];
11
13
  const value = parseSettingsValue(row.value);
12
14
  return value ? [[row.key, value]] : [];
13
15
  })
@@ -1,10 +1,10 @@
1
1
  import { defineEventHandler, readValidatedBody } from "h3";
2
2
  import { useDb } from "#cms-db";
3
3
  import { cms_settings } from "#cms-tables";
4
- import { requireAdmin } from "../utils/require-admin.js";
4
+ import { requireCmsPermission } from "../utils/permissions.js";
5
5
  import { entrySettingsSchema, requireSettingsKey } from "../utils/settings.js";
6
6
  export default defineEventHandler(async (event) => {
7
- await requireAdmin(event);
7
+ await requireCmsPermission(event, "settings.manage");
8
8
  const key = requireSettingsKey(event);
9
9
  const body = await readValidatedBody(event, entrySettingsSchema.parse);
10
10
  const value = JSON.stringify(body);
@@ -0,0 +1,3 @@
1
+ import type { CmsSiteSettings } from '../../shared/index.js';
2
+ declare const _default: import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<CmsSiteSettings>>;
3
+ export default _default;
@@ -0,0 +1,7 @@
1
+ import { defineEventHandler } from "h3";
2
+ import { requireCmsPermission } from "../utils/permissions.js";
3
+ import { readSiteSettings } from "../utils/site.js";
4
+ export default defineEventHandler(async (event) => {
5
+ await requireCmsPermission(event, "settings.manage");
6
+ return readSiteSettings();
7
+ });
@@ -0,0 +1,3 @@
1
+ import type { CmsSiteSettings } from '../../shared/index.js';
2
+ declare const _default: import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<CmsSiteSettings>>;
3
+ export default _default;
@@ -0,0 +1,16 @@
1
+ import { defineEventHandler, readValidatedBody } from "h3";
2
+ import { assertKnownMedia } from "../utils/media-references.js";
3
+ import { mediaLookup } from "../utils/media-check.js";
4
+ import { getContentI18n } from "../utils/registry.js";
5
+ import { requireCmsPermission } from "../utils/permissions.js";
6
+ import { siteSettingsSchema, writeSiteSettings } from "../utils/site.js";
7
+ export default defineEventHandler(async (event) => {
8
+ await requireCmsPermission(event, "settings.manage");
9
+ const settings = await readValidatedBody(event, siteSettingsSchema(getContentI18n()).parse);
10
+ if (settings.image) {
11
+ const lookup = await mediaLookup();
12
+ if (lookup) await assertKnownMedia([{ field: "image", key: settings.image }], lookup);
13
+ }
14
+ await writeSiteSettings(settings);
15
+ return settings;
16
+ });
@@ -3,10 +3,11 @@ import { useDb } from "#cms-db";
3
3
  import { distinctTags, entryFieldsFor } from "../../shared/index.js";
4
4
  import { readPages } from "../utils/page-storage.js";
5
5
  import { getRegistryEntry, tableColumns } from "../utils/registry.js";
6
- import { requireAdmin } from "../utils/require-admin.js";
6
+ import { assertCmsPermission, requireCmsAccess } from "../utils/permissions.js";
7
7
  export default defineEventHandler(async (event) => {
8
- await requireAdmin(event);
8
+ const { access } = await requireCmsAccess(event);
9
9
  const { name, entry, table } = getRegistryEntry(event);
10
+ assertCmsPermission(access, `${name}.read`);
10
11
  const key = getRouterParam(event, "field") ?? "";
11
12
  const fields = entryFieldsFor(entry);
12
13
  const field = Object.hasOwn(fields, key) ? fields[key] : void 0;
@@ -2,10 +2,16 @@ import { eq } from "drizzle-orm";
2
2
  import { createError, defineEventHandler, getRouterParam } from "h3";
3
3
  import { useDb } from "#cms-db";
4
4
  import { cms_users } from "#cms-tables";
5
- import { requireSuperAdmin } from "../utils/require-admin.js";
5
+ import { forbidden, requireCmsPermission } from "../utils/permissions.js";
6
+ import { assertCanManageAccount } from "../utils/user-management.js";
7
+ import { findUserById } from "../utils/users.js";
6
8
  export default defineEventHandler(async (event) => {
7
- await requireSuperAdmin(event);
9
+ const { user, access } = await requireCmsPermission(event, "users.manage");
8
10
  const id = getRouterParam(event, "id") ?? "";
11
+ const target = await findUserById(id);
12
+ if (!target) throw createError({ statusCode: 404, statusMessage: "User not found" });
13
+ if (target.id === user.id) forbidden("You cannot delete your own account");
14
+ assertCanManageAccount(access, target.role);
9
15
  const [row] = await useDb().delete(cms_users).where(eq(cms_users.id, id)).returning();
10
16
  if (!row) throw createError({ statusCode: 404, statusMessage: "User not found" });
11
17
  return { ok: true };
@@ -5,17 +5,27 @@ import { useDb } from "#cms-db";
5
5
  import { cms_users } from "#cms-tables";
6
6
  import { MIN_PASSWORD_LENGTH } from "../../shared/index.js";
7
7
  import { hashPassword } from "../utils/password.js";
8
- import { requireSuperAdmin } from "../utils/require-admin.js";
9
- import { toAccount } from "../utils/users.js";
8
+ import { forbidden, requireCmsPermission } from "../utils/permissions.js";
9
+ import { assertCanGrantRole, assertCanManageAccount } from "../utils/user-management.js";
10
+ import { findUserById, toAccount } from "../utils/users.js";
10
11
  const bodySchema = z.object({
11
12
  name: z.string().trim().max(120).nullish(),
12
- password: z.string().min(MIN_PASSWORD_LENGTH).max(256).optional()
13
+ password: z.string().min(MIN_PASSWORD_LENGTH).max(256).optional(),
14
+ role: z.string().trim().min(1).max(64).optional()
13
15
  });
14
16
  export default defineEventHandler(async (event) => {
15
- await requireSuperAdmin(event);
17
+ const { user, access } = await requireCmsPermission(event, "users.manage");
16
18
  const id = getRouterParam(event, "id") ?? "";
17
19
  const body = await readValidatedBody(event, bodySchema.parse);
20
+ const target = await findUserById(id);
21
+ if (!target) throw createError({ statusCode: 404, statusMessage: "User not found" });
22
+ assertCanManageAccount(access, target.role);
18
23
  const set = { updatedAt: (/* @__PURE__ */ new Date()).toISOString() };
24
+ if (body.role !== void 0 && body.role !== target.role) {
25
+ if (target.id === user.id) forbidden("You cannot change your own role");
26
+ assertCanGrantRole(access, body.role);
27
+ set.role = body.role;
28
+ }
19
29
  if (body.name !== void 0) set.name = body.name || null;
20
30
  if (body.password) {
21
31
  set.passwordHash = await hashPassword(body.password);
@@ -2,10 +2,10 @@ import { asc } from "drizzle-orm";
2
2
  import { defineEventHandler } from "h3";
3
3
  import { useDb } from "#cms-db";
4
4
  import { cms_users } from "#cms-tables";
5
- import { requireSuperAdmin } from "../utils/require-admin.js";
5
+ import { requireCmsPermission } from "../utils/permissions.js";
6
6
  import { toAccount } from "../utils/users.js";
7
7
  export default defineEventHandler(async (event) => {
8
- await requireSuperAdmin(event);
8
+ await requireCmsPermission(event, "users.manage");
9
9
  const rows = await useDb().select().from(cms_users).orderBy(asc(cms_users.createdAt));
10
10
  return rows.map(toAccount);
11
11
  });
@@ -6,16 +6,20 @@ import { MIN_PASSWORD_LENGTH } from "../../shared/index.js";
6
6
  import { customId } from "../utils/custom-id.js";
7
7
  import { mapConstraintErrors } from "../utils/db-errors.js";
8
8
  import { hashPassword } from "../utils/password.js";
9
- import { isSuperAdminEmail, requireSuperAdmin } from "../utils/require-admin.js";
9
+ import { requireCmsPermission } from "../utils/permissions.js";
10
+ import { isSuperAdminEmail } from "../utils/require-admin.js";
11
+ import { assertCanGrantRole } from "../utils/user-management.js";
10
12
  import { findUserByEmail, toAccount } from "../utils/users.js";
11
13
  const bodySchema = z.object({
12
14
  email: z.string().trim().toLowerCase().email().max(254),
13
15
  name: z.string().trim().max(120).nullish(),
14
- password: z.string().min(MIN_PASSWORD_LENGTH).max(256)
16
+ password: z.string().min(MIN_PASSWORD_LENGTH).max(256),
17
+ role: z.string().trim().min(1).max(64).default("admin")
15
18
  });
16
19
  export default defineEventHandler(async (event) => {
17
- await requireSuperAdmin(event);
20
+ const { access } = await requireCmsPermission(event, "users.manage");
18
21
  const body = await readValidatedBody(event, bodySchema.parse);
22
+ assertCanGrantRole(access, body.role);
19
23
  if (isSuperAdminEmail(event, body.email) || await findUserByEmail(body.email)) {
20
24
  throw createError({ statusCode: 409, statusMessage: "A user with this email already exists" });
21
25
  }
@@ -26,7 +30,7 @@ export default defineEventHandler(async (event) => {
26
30
  id: customId("usr"),
27
31
  email: body.email,
28
32
  name: body.name || null,
29
- role: "admin",
33
+ role: body.role,
30
34
  passwordHash,
31
35
  createdAt: now,
32
36
  updatedAt: now
@@ -0,0 +1,2 @@
1
+ declare const _default: import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<void>>;
2
+ export default _default;
@@ -0,0 +1,8 @@
1
+ import { defineEventHandler, setResponseHeader } from "h3";
2
+ import { HIDDEN_SITE_ROBOTS, hiddenSiteHeaderApplies } from "../../shared/index.js";
3
+ import { readCachedSiteSettings } from "../utils/site.js";
4
+ export default defineEventHandler(async (event) => {
5
+ if (!hiddenSiteHeaderApplies(event.path)) return;
6
+ const settings = await readCachedSiteSettings().catch(() => null);
7
+ if (settings?.hidden) setResponseHeader(event, "x-robots-tag", HIDDEN_SITE_ROBOTS);
8
+ });
@@ -0,0 +1,2 @@
1
+ declare const _default: import("h3").EventHandler<import("h3").EventHandlerRequest, void>;
2
+ export default _default;
@@ -0,0 +1,6 @@
1
+ import { defineEventHandler } from "h3";
2
+ import { hasPreviewQuery } from "../../shared/index.js";
3
+ import { hasPreviewHeader, markPreviewResponse } from "../utils/preview-links.js";
4
+ export default defineEventHandler((event) => {
5
+ if (hasPreviewQuery(event.path) || hasPreviewHeader(event)) markPreviewResponse(event);
6
+ });
@@ -0,0 +1,2 @@
1
+ declare const _default: import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<void>>;
2
+ export default _default;
@@ -0,0 +1,18 @@
1
+ import { defineEventHandler, sendRedirect } from "h3";
2
+ import { normalizeRedirectPath, redirectApplies, redirectLocation } from "../../shared/index.js";
3
+ import { isLivePath, readRedirectTable } from "../utils/redirects.js";
4
+ export default defineEventHandler(async (event) => {
5
+ if (event.method !== "GET" && event.method !== "HEAD") return;
6
+ const [pathname = "/", search = ""] = event.path.split(/\?(.*)/s);
7
+ if (!redirectApplies(pathname)) return;
8
+ const table = await readRedirectTable().catch(() => null);
9
+ if (!table?.size) return;
10
+ const path = normalizeRedirectPath(pathname);
11
+ const redirect = table.get(path);
12
+ if (!redirect || await isLivePath(path).catch(() => false)) return;
13
+ return sendRedirect(
14
+ event,
15
+ redirectLocation(redirect.to, search, redirect.keepQuery),
16
+ redirect.status
17
+ );
18
+ });
@@ -6,7 +6,10 @@ export default () => {
6
6
  const user = session.user;
7
7
  if (!user?.id) return;
8
8
  const row = await findUserById(user.id);
9
- if (row && user.passwordStamp === passwordStamp(row.passwordHash)) return;
9
+ if (row && user.passwordStamp === passwordStamp(row.passwordHash)) {
10
+ user.role = row.role;
11
+ return;
12
+ }
10
13
  await clearUserSession(event);
11
14
  throw createError({ statusCode: 401, statusMessage: "Session expired" });
12
15
  });
@@ -0,0 +1,3 @@
1
+ import type { NitroApp } from 'nitropack/types';
2
+ declare const _default: (nitroApp: NitroApp) => void;
3
+ export default _default;
@@ -0,0 +1,27 @@
1
+ import { useRuntimeConfig } from "#imports";
2
+ import { CMS_ENTRY_CHANGE_HOOK, CMS_MEDIA_CHANGE_HOOK } from "../../shared/hooks.js";
3
+ import {
4
+ deliverWebhooks,
5
+ entryWebhookPayload,
6
+ mediaWebhookPayload,
7
+ webhookTargets
8
+ } from "../utils/webhooks.js";
9
+ function targetsFor(event) {
10
+ const { webhooks } = useRuntimeConfig(event).cms;
11
+ return webhookTargets(webhooks);
12
+ }
13
+ function deliver(payload, { event }) {
14
+ const targets = targetsFor(event);
15
+ return targets.length ? deliverWebhooks(targets, payload) : void 0;
16
+ }
17
+ export default (nitroApp) => {
18
+ const hooks = nitroApp.hooks;
19
+ hooks.hook(
20
+ CMS_ENTRY_CHANGE_HOOK,
21
+ (change, context) => deliver(entryWebhookPayload(change), context)
22
+ );
23
+ hooks.hook(
24
+ CMS_MEDIA_CHANGE_HOOK,
25
+ (change, context) => deliver(mediaWebhookPayload(change), context)
26
+ );
27
+ };
@@ -3,6 +3,7 @@ import { defineEventHandler } from "h3";
3
3
  import { useRuntimeConfig } from "#imports";
4
4
  import { buildCmsSchema, createGraphqlContext } from "../utils/graphql.js";
5
5
  import { createBreadthRule, createDepthRule, createIntrospectionRule } from "../utils/graphql-depth.js";
6
+ import { readPreviewGrant } from "../utils/preview-links.js";
6
7
  import { CMS_GRAPHQL_BATCH_LIMIT } from "../../shared/index.js";
7
8
  function buildYoga(options) {
8
9
  return createYoga({
@@ -12,7 +13,7 @@ function buildYoga(options) {
12
13
  graphiql: options.graphiql,
13
14
  cors: false,
14
15
  batching: { limit: CMS_GRAPHQL_BATCH_LIMIT },
15
- context: () => createGraphqlContext(),
16
+ context: ({ cmsPreview }) => createGraphqlContext(cmsPreview ?? null),
16
17
  plugins: [
17
18
  {
18
19
  onValidate({
@@ -27,10 +28,11 @@ function buildYoga(options) {
27
28
  });
28
29
  }
29
30
  let yoga = null;
30
- export default defineEventHandler((event) => {
31
+ export default defineEventHandler(async (event) => {
31
32
  if (!yoga) {
32
33
  const { graphql } = useRuntimeConfig(event).cms;
33
34
  yoga = buildYoga(graphql);
34
35
  }
35
- return yoga(event.node.req, event.node.res);
36
+ const cmsPreview = await readPreviewGrant(event);
37
+ return yoga(event.node.req, event.node.res, { cmsPreview });
36
38
  });
@@ -0,0 +1,2 @@
1
+ declare const _default: import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<string>>;
2
+ export default _default;
@@ -0,0 +1,16 @@
1
+ import { defineEventHandler, setResponseHeaders } from "h3";
2
+ import { useRuntimeConfig } from "#imports";
3
+ import { SITEMAP_PATH, absoluteUrl, renderRobotsTxt } from "../../shared/index.js";
4
+ import { readSiteSettings, resolveSiteUrl, seoRouteCacheHeader } from "../utils/site.js";
5
+ export default defineEventHandler(async (event) => {
6
+ const { seo } = useRuntimeConfig(event).cms;
7
+ const settings = await readSiteSettings();
8
+ setResponseHeaders(event, {
9
+ "content-type": "text/plain; charset=utf-8",
10
+ "cache-control": seoRouteCacheHeader(event)
11
+ });
12
+ return renderRobotsTxt({
13
+ hidden: settings.hidden,
14
+ sitemapUrl: seo?.robotsSitemap ? absoluteUrl(resolveSiteUrl(event), SITEMAP_PATH) : null
15
+ });
16
+ });
@@ -0,0 +1,2 @@
1
+ declare const _default: import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<string | void>>;
2
+ export default _default;
@@ -0,0 +1,67 @@
1
+ import { createError, defineEventHandler, getQuery, sendStream, setResponseHeaders } from "h3";
2
+ import {
3
+ SITEMAP_MAX_URLS,
4
+ SITEMAP_URLSET_CLOSE,
5
+ SITEMAP_URLSET_OPEN,
6
+ planSitemapChunks,
7
+ renderSitemap,
8
+ renderSitemapIndex,
9
+ renderSitemapUrl,
10
+ sitemapPartUrl,
11
+ sitemapUrlCount
12
+ } from "../../shared/index.js";
13
+ import { getContentI18n } from "../utils/registry.js";
14
+ import { readSiteSettings, resolveSiteUrl, seoRouteCacheHeader } from "../utils/site.js";
15
+ import { planSitemap, sitemapChunkUrls } from "../utils/sitemap.js";
16
+ async function* urlsetParts(batches) {
17
+ yield SITEMAP_URLSET_OPEN;
18
+ for await (const batch of batches) {
19
+ if (batch.length) yield batch.map(renderSitemapUrl).join("");
20
+ }
21
+ yield SITEMAP_URLSET_CLOSE;
22
+ }
23
+ function textStream(parts) {
24
+ const encoder = new TextEncoder();
25
+ return new ReadableStream({
26
+ async pull(controller) {
27
+ const { value, done } = await parts.next();
28
+ if (done) controller.close();
29
+ else controller.enqueue(encoder.encode(value));
30
+ },
31
+ async cancel() {
32
+ await parts.return(void 0);
33
+ }
34
+ });
35
+ }
36
+ function streamUrlset(event, plan, chunks, context) {
37
+ return sendStream(event, textStream(urlsetParts(sitemapChunkUrls(plan, chunks, context))));
38
+ }
39
+ function requestedPart(event) {
40
+ const part = getQuery(event).part;
41
+ if (part === void 0) return null;
42
+ const value = Number(part);
43
+ if (!Number.isInteger(value) || value < 1)
44
+ throw createError({ statusCode: 404, statusMessage: "Sitemap not found" });
45
+ return value;
46
+ }
47
+ export default defineEventHandler(async (event) => {
48
+ const part = requestedPart(event);
49
+ setResponseHeaders(event, {
50
+ "content-type": "application/xml; charset=utf-8",
51
+ "cache-control": seoRouteCacheHeader(event)
52
+ });
53
+ const settings = await readSiteSettings();
54
+ if (settings.hidden) return renderSitemap([]);
55
+ const context = { siteUrl: resolveSiteUrl(event), i18n: getContentI18n() };
56
+ const plan = await planSitemap(context);
57
+ const paged = sitemapUrlCount(plan.sizes) > SITEMAP_MAX_URLS;
58
+ const chunks = paged ? planSitemapChunks(plan.sizes) : plan.sizes.map((size) => ({ source: size.source, offset: 0, limit: size.count }));
59
+ if (part === null && paged)
60
+ return renderSitemapIndex(
61
+ chunks.map((_, index) => sitemapPartUrl(context.siteUrl, index + 1))
62
+ );
63
+ if (part === null || !paged && part === 1) return streamUrlset(event, plan, chunks, context);
64
+ const chunk = paged ? chunks[part - 1] : void 0;
65
+ if (!chunk) throw createError({ statusCode: 404, statusMessage: "Sitemap not found" });
66
+ return streamUrlset(event, plan, [chunk], context);
67
+ });
@@ -0,0 +1,5 @@
1
+ export interface CachedValue<T> {
2
+ get(): Promise<T>;
3
+ invalidate(): void;
4
+ }
5
+ export declare function cachedValue<T>(load: () => Promise<T>, ttlMs: number, now?: () => number): CachedValue<T>;
@@ -0,0 +1,24 @@
1
+ export function cachedValue(load, ttlMs, now = Date.now) {
2
+ let value = null;
3
+ let pending = null;
4
+ let generation = 0;
5
+ return {
6
+ async get() {
7
+ if (value && value.expiresAt > now()) return value.data;
8
+ if (pending) return pending;
9
+ const started = generation;
10
+ pending = load().then((data) => {
11
+ if (started === generation) value = { data, expiresAt: now() + ttlMs };
12
+ return data;
13
+ }).finally(() => {
14
+ if (started === generation) pending = null;
15
+ });
16
+ return pending;
17
+ },
18
+ invalidate() {
19
+ generation += 1;
20
+ value = null;
21
+ pending = null;
22
+ }
23
+ };
24
+ }
@@ -0,0 +1,5 @@
1
+ export interface FindContentByPathOptions {
2
+ includeDrafts?: boolean;
3
+ previewId?: string;
4
+ }
5
+ export declare function findContentByPath(name: string, path: string, locale: string, options?: FindContentByPathOptions): Promise<Record<string, unknown> | null>;
@@ -0,0 +1,29 @@
1
+ import { and, eq } from "drizzle-orm";
2
+ import cmsConfig from "#cms-config";
3
+ import { useDb } from "#cms-db";
4
+ import {
5
+ CONTENT_SLUG_FIELD,
6
+ contentPathParamsMatch,
7
+ contentRoutePattern,
8
+ isRoutedContent,
9
+ matchContentPattern
10
+ } from "../../shared/index.js";
11
+ import { resolveTable, tableColumns } from "./registry.js";
12
+ import { visibleOrPreviewConditions } from "./visibility.js";
13
+ export async function findContentByPath(name, path, locale, options = {}) {
14
+ const entry = cmsConfig[name];
15
+ if (!entry || !isRoutedContent(entry)) return null;
16
+ const pattern = contentRoutePattern(entry.route, locale);
17
+ const params = pattern ? matchContentPattern(pattern, path) : null;
18
+ const table = resolveTable(name);
19
+ if (!params || !table) return null;
20
+ const columns = tableColumns(table);
21
+ const conditions = [];
22
+ if (params.slug) conditions.push(eq(columns[CONTENT_SLUG_FIELD], params.slug));
23
+ if (params.id) conditions.push(eq(columns.id, params.id));
24
+ if (!options.includeDrafts)
25
+ conditions.push(...visibleOrPreviewConditions(entry, columns, options.previewId));
26
+ const [row] = await useDb().select().from(table).where(and(...conditions)).limit(1);
27
+ const found = row;
28
+ return found && contentPathParamsMatch(params, found) ? found : null;
29
+ }
@@ -0,0 +1,19 @@
1
+ import type { SQLiteTable } from 'drizzle-orm/sqlite-core';
2
+ import type { H3Event } from 'h3';
3
+ import type { CmsEntry } from '../../shared/index.js';
4
+ export interface CmsFieldIssue {
5
+ path: (string | number)[];
6
+ message: string;
7
+ }
8
+ export declare function fieldIssuesError(statusCode: number, statusMessage: string, issues: CmsFieldIssue[]): import("h3").H3Error<{
9
+ issues: CmsFieldIssue[];
10
+ }>;
11
+ export declare function readEntryBody(event: H3Event, entry: CmsEntry, options?: {
12
+ path?: string;
13
+ create?: boolean;
14
+ }): Promise<Record<string, unknown>>;
15
+ export declare function immutableSelection(entry: CmsEntry, table: SQLiteTable): {
16
+ [k: string]: import("drizzle-orm/sqlite-core").AnySQLiteColumn;
17
+ };
18
+ export declare function assertImmutableValues(entry: CmsEntry, saved: Record<string, unknown> | null | undefined, values: Record<string, unknown>): void;
19
+ export declare function assertUniqueValues(entry: CmsEntry, table: SQLiteTable, values: Record<string, unknown>, id: string | null): Promise<void>;
@@ -0,0 +1,72 @@
1
+ import { and, eq, ne, sql } from "drizzle-orm";
2
+ import { createError, readBody } from "h3";
3
+ import { useDb } from "#cms-db";
4
+ import { pageFields } from "../../shared/index.js";
5
+ import {
6
+ changedImmutableKeys,
7
+ immutableFieldKeys,
8
+ isCaseInsensitiveUnique,
9
+ isUniqueValueField,
10
+ uniqueCompareValue,
11
+ withEntryDefaults
12
+ } from "../../shared/field-options.js";
13
+ import { validationMessages } from "../../shared/validation.js";
14
+ import { buildValidator, getContentI18n, idColumn, tableColumns } from "./registry.js";
15
+ export function fieldIssuesError(statusCode, statusMessage, issues) {
16
+ return createError({
17
+ statusCode,
18
+ statusMessage,
19
+ message: issues.map(
20
+ (issue) => issue.path.length ? `${issue.path.join(".")}: ${issue.message}` : issue.message
21
+ ).join("; "),
22
+ data: { issues }
23
+ });
24
+ }
25
+ function isPlainObject(value) {
26
+ return !!value && typeof value === "object" && !Array.isArray(value);
27
+ }
28
+ export async function readEntryBody(event, entry, options = {}) {
29
+ const raw = await readBody(event);
30
+ const fields = options.path ? pageFields(entry, options.path) : entry.fields;
31
+ const input = options.create && isPlainObject(raw) ? withEntryDefaults(fields, raw, getContentI18n()) : raw;
32
+ const result = buildValidator(entry, options.path).safeParse(input);
33
+ if (result.success) return result.data;
34
+ throw fieldIssuesError(
35
+ 400,
36
+ "Validation Error",
37
+ result.error.issues.map((issue) => ({
38
+ path: issue.path.map((part) => typeof part === "number" ? part : String(part)),
39
+ message: issue.message
40
+ }))
41
+ );
42
+ }
43
+ export function immutableSelection(entry, table) {
44
+ const columns = tableColumns(table);
45
+ return Object.fromEntries(
46
+ immutableFieldKeys(entry.fields).filter((key) => columns[key]).map((key) => [key, columns[key]])
47
+ );
48
+ }
49
+ export function assertImmutableValues(entry, saved, values) {
50
+ const keys = changedImmutableKeys(entry.fields, saved, values);
51
+ if (!keys.length) return;
52
+ const message = validationMessages().immutable;
53
+ throw fieldIssuesError(
54
+ 400,
55
+ "A field cannot be changed once saved",
56
+ keys.map((key) => ({ path: [key], message }))
57
+ );
58
+ }
59
+ export async function assertUniqueValues(entry, table, values, id) {
60
+ const columns = tableColumns(table);
61
+ const message = validationMessages().unique;
62
+ const issues = [];
63
+ for (const [key, field] of Object.entries(entry.fields)) {
64
+ const column = columns[key];
65
+ const value = values[key];
66
+ if (!isUniqueValueField(field) || !column || value === null || value === void 0) continue;
67
+ const same = isCaseInsensitiveUnique(field) ? sql`lower(${column}) = ${uniqueCompareValue(field, value)}` : eq(column, value);
68
+ const [match] = await useDb().select({ id: idColumn(table) }).from(table).where(id === null ? same : and(same, ne(idColumn(table), id))).limit(1);
69
+ if (match) issues.push({ path: [key], message });
70
+ }
71
+ if (issues.length) throw fieldIssuesError(409, "Duplicate value for a unique field", issues);
72
+ }
@@ -1,5 +1,7 @@
1
+ import type { CmsPreviewGrant } from '../../shared/index.js';
1
2
  interface Ctx {
2
3
  loaders: Map<string, BatchLoader<unknown, unknown>>;
4
+ preview: CmsPreviewGrant | null;
3
5
  }
4
6
  declare class BatchLoader<K, V> {
5
7
  private batchFn;
@@ -10,5 +12,5 @@ declare class BatchLoader<K, V> {
10
12
  private flush;
11
13
  }
12
14
  export declare function buildCmsSchema(): import("graphql-yoga").GraphQLSchemaWithContext<Ctx & import("graphql-yoga").YogaInitialContext>;
13
- export declare function createGraphqlContext(): Ctx;
15
+ export declare function createGraphqlContext(preview?: CmsPreviewGrant | null): Ctx;
14
16
  export {};