@xleddyl/nuxt-cms 0.9.3 → 0.10.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 (433) 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 -218
  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 -146
  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 +29 -5
  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 +42 -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 +9 -8
  124. package/dist/runtime/app/components/cms/TranslationBadges.d.vue.ts +7 -0
  125. package/dist/runtime/app/components/cms/TranslationBadges.vue +45 -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 +1152 -335
  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 +190 -53
  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 +29 -10
  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 +145 -29
  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/single-row.d.ts +3 -0
  351. package/dist/runtime/server/utils/single-row.js +4 -0
  352. package/dist/runtime/server/utils/site.d.ts +23 -0
  353. package/dist/runtime/server/utils/site.js +79 -0
  354. package/dist/runtime/server/utils/sitemap.d.ts +12 -0
  355. package/dist/runtime/server/utils/sitemap.js +109 -0
  356. package/dist/runtime/server/utils/user-management.d.ts +4 -0
  357. package/dist/runtime/server/utils/user-management.js +20 -0
  358. package/dist/runtime/server/utils/users.d.ts +1 -1
  359. package/dist/runtime/server/utils/users.js +1 -1
  360. package/dist/runtime/server/utils/visibility.d.ts +1 -0
  361. package/dist/runtime/server/utils/visibility.js +6 -1
  362. package/dist/runtime/server/utils/webhooks.d.ts +24 -0
  363. package/dist/runtime/server/utils/webhooks.js +90 -0
  364. package/dist/runtime/shared/block-paths.d.ts +66 -0
  365. package/dist/runtime/shared/block-paths.js +310 -0
  366. package/dist/runtime/shared/block-picker.d.ts +18 -0
  367. package/dist/runtime/shared/block-picker.js +31 -0
  368. package/dist/runtime/shared/block-signature.d.ts +4 -0
  369. package/dist/runtime/shared/block-signature.js +46 -0
  370. package/dist/runtime/shared/clipboard.d.ts +31 -0
  371. package/dist/runtime/shared/clipboard.js +206 -0
  372. package/dist/runtime/shared/conditions.d.ts +36 -0
  373. package/dist/runtime/shared/conditions.js +100 -0
  374. package/dist/runtime/shared/content-routes.d.ts +42 -0
  375. package/dist/runtime/shared/content-routes.js +237 -0
  376. package/dist/runtime/shared/duplicate.js +2 -1
  377. package/dist/runtime/shared/editor-layout.d.ts +18 -0
  378. package/dist/runtime/shared/editor-layout.js +9 -0
  379. package/dist/runtime/shared/field-options.d.ts +21 -0
  380. package/dist/runtime/shared/field-options.js +90 -0
  381. package/dist/runtime/shared/graphql-sdl.d.ts +1 -0
  382. package/dist/runtime/shared/graphql-sdl.js +50 -26
  383. package/dist/runtime/shared/history.d.ts +27 -0
  384. package/dist/runtime/shared/history.js +123 -0
  385. package/dist/runtime/shared/hooks.d.ts +45 -0
  386. package/dist/runtime/shared/hooks.js +28 -0
  387. package/dist/runtime/shared/index.d.ts +90 -21
  388. package/dist/runtime/shared/index.js +121 -37
  389. package/dist/runtime/shared/inline-text.d.ts +38 -0
  390. package/dist/runtime/shared/inline-text.js +85 -0
  391. package/dist/runtime/shared/layout.d.ts +2 -1
  392. package/dist/runtime/shared/layout.js +3 -0
  393. package/dist/runtime/shared/links.d.ts +48 -0
  394. package/dist/runtime/shared/links.js +155 -0
  395. package/dist/runtime/shared/list-filters.d.ts +2 -0
  396. package/dist/runtime/shared/list-filters.js +2 -0
  397. package/dist/runtime/shared/media-focal.d.ts +30 -0
  398. package/dist/runtime/shared/media-focal.js +52 -0
  399. package/dist/runtime/shared/migrations-dir.d.ts +14 -0
  400. package/dist/runtime/shared/migrations-dir.js +48 -2
  401. package/dist/runtime/shared/presets.d.ts +67 -0
  402. package/dist/runtime/shared/presets.js +127 -0
  403. package/dist/runtime/shared/preview-links.d.ts +64 -0
  404. package/dist/runtime/shared/preview-links.js +54 -0
  405. package/dist/runtime/shared/preview.d.ts +124 -21
  406. package/dist/runtime/shared/preview.js +419 -81
  407. package/dist/runtime/shared/redirects.d.ts +75 -0
  408. package/dist/runtime/shared/redirects.js +230 -0
  409. package/dist/runtime/shared/roles.d.ts +57 -0
  410. package/dist/runtime/shared/roles.js +293 -0
  411. package/dist/runtime/shared/save-state.d.ts +8 -0
  412. package/dist/runtime/shared/save-state.js +15 -0
  413. package/dist/runtime/shared/search.d.ts +16 -1
  414. package/dist/runtime/shared/search.js +41 -7
  415. package/dist/runtime/shared/seo.d.ts +167 -0
  416. package/dist/runtime/shared/seo.js +335 -0
  417. package/dist/runtime/shared/transfer.js +2 -1
  418. package/dist/runtime/shared/translations.d.ts +29 -0
  419. package/dist/runtime/shared/translations.js +123 -0
  420. package/dist/runtime/shared/users.d.ts +1 -1
  421. package/dist/runtime/shared/validation.d.ts +23 -1
  422. package/dist/runtime/shared/validation.js +214 -64
  423. package/dist/runtime/webhooks.d.ts +33 -0
  424. package/dist/runtime/webhooks.js +57 -0
  425. package/dist/types.d.mts +5 -1
  426. package/package.json +6 -2
  427. package/dist/runtime/app/components/cms/BlockOutline.vue +0 -88
  428. package/dist/runtime/app/components/cms/BlockPalette.vue +0 -31
  429. package/dist/runtime/app/components/cms/SettingsModal.d.vue.ts +0 -12
  430. package/dist/runtime/app/components/cms/SettingsModal.vue +0 -126
  431. package/dist/runtime/app/components/cms/SettingsModal.vue.d.ts +0 -12
  432. package/dist/runtime/app/composables/cms-field-focus.d.ts +0 -4
  433. package/dist/runtime/app/composables/cms-field-focus.js +0 -20
@@ -0,0 +1,207 @@
1
+ import type { H3Event } from 'h3';
2
+ import { z } from 'zod';
3
+ import type { CmsCreatedPreviewLink, CmsEntry, CmsPreviewGrant, CmsPreviewLink, CmsSessionUser } from '../../shared/index.js';
4
+ import type { WriteDb } from './write-statements.js';
5
+ export declare const previewLinkInputSchema: z.ZodObject<{
6
+ duration: z.ZodEnum<{
7
+ "1h": "1h";
8
+ "1d": "1d";
9
+ "7d": "7d";
10
+ "30d": "30d";
11
+ }>;
12
+ locale: z.ZodOptional<z.ZodNullable<z.ZodString>>;
13
+ }, z.core.$strict>;
14
+ export interface PreviewLinkAccess {
15
+ user: CmsSessionUser;
16
+ name: string;
17
+ entry: CmsEntry;
18
+ }
19
+ export declare function requirePreviewLinkAccess(event: H3Event, name: string, action: 'read' | 'update'): Promise<PreviewLinkAccess>;
20
+ export declare function createPreviewToken(): string;
21
+ export declare function hashPreviewToken(token: string): string;
22
+ export declare function listPreviewLinks({ name, entry }: PreviewLinkAccess, itemId: string): Promise<CmsPreviewLink[]>;
23
+ export declare function createPreviewLink({ name, entry, user }: PreviewLinkAccess, itemId: string, input: z.infer<typeof previewLinkInputSchema>): Promise<CmsCreatedPreviewLink>;
24
+ export declare function revokePreviewLink({ name }: PreviewLinkAccess, itemId: string, linkId: string): Promise<void>;
25
+ export declare function deleteItemPreviewLinksStatement(db: WriteDb, name: string, itemId: string): Omit<import("drizzle-orm/sqlite-core").SQLiteDeleteBase<import("drizzle-orm/sqlite-core").SQLiteTableWithColumns<{
26
+ name: "cms_preview_links";
27
+ schema: undefined;
28
+ columns: {
29
+ id: import("drizzle-orm/sqlite-core").SQLiteColumn<{
30
+ name: "id";
31
+ tableName: "cms_preview_links";
32
+ dataType: "string";
33
+ columnType: "SQLiteText";
34
+ data: string;
35
+ driverParam: string;
36
+ notNull: true;
37
+ hasDefault: false;
38
+ isPrimaryKey: true;
39
+ isAutoincrement: false;
40
+ hasRuntimeDefault: false;
41
+ enumValues: [string, ...string[]];
42
+ baseColumn: never;
43
+ identity: undefined;
44
+ generated: undefined;
45
+ }, {}, {
46
+ length: number | undefined;
47
+ }>;
48
+ tokenHash: import("drizzle-orm/sqlite-core").SQLiteColumn<{
49
+ name: "token_hash";
50
+ tableName: "cms_preview_links";
51
+ dataType: "string";
52
+ columnType: "SQLiteText";
53
+ data: string;
54
+ driverParam: string;
55
+ notNull: true;
56
+ hasDefault: false;
57
+ isPrimaryKey: false;
58
+ isAutoincrement: false;
59
+ hasRuntimeDefault: false;
60
+ enumValues: [string, ...string[]];
61
+ baseColumn: never;
62
+ identity: undefined;
63
+ generated: undefined;
64
+ }, {}, {
65
+ length: number | undefined;
66
+ }>;
67
+ entry: import("drizzle-orm/sqlite-core").SQLiteColumn<{
68
+ name: "entry";
69
+ tableName: "cms_preview_links";
70
+ dataType: "string";
71
+ columnType: "SQLiteText";
72
+ data: string;
73
+ driverParam: string;
74
+ notNull: true;
75
+ hasDefault: false;
76
+ isPrimaryKey: false;
77
+ isAutoincrement: false;
78
+ hasRuntimeDefault: false;
79
+ enumValues: [string, ...string[]];
80
+ baseColumn: never;
81
+ identity: undefined;
82
+ generated: undefined;
83
+ }, {}, {
84
+ length: number | undefined;
85
+ }>;
86
+ itemId: import("drizzle-orm/sqlite-core").SQLiteColumn<{
87
+ name: "item_id";
88
+ tableName: "cms_preview_links";
89
+ dataType: "string";
90
+ columnType: "SQLiteText";
91
+ data: string;
92
+ driverParam: string;
93
+ notNull: true;
94
+ hasDefault: false;
95
+ isPrimaryKey: false;
96
+ isAutoincrement: false;
97
+ hasRuntimeDefault: false;
98
+ enumValues: [string, ...string[]];
99
+ baseColumn: never;
100
+ identity: undefined;
101
+ generated: undefined;
102
+ }, {}, {
103
+ length: number | undefined;
104
+ }>;
105
+ locale: import("drizzle-orm/sqlite-core").SQLiteColumn<{
106
+ name: "locale";
107
+ tableName: "cms_preview_links";
108
+ dataType: "string";
109
+ columnType: "SQLiteText";
110
+ data: string;
111
+ driverParam: string;
112
+ notNull: false;
113
+ hasDefault: false;
114
+ isPrimaryKey: false;
115
+ isAutoincrement: false;
116
+ hasRuntimeDefault: false;
117
+ enumValues: [string, ...string[]];
118
+ baseColumn: never;
119
+ identity: undefined;
120
+ generated: undefined;
121
+ }, {}, {
122
+ length: number | undefined;
123
+ }>;
124
+ createdBy: import("drizzle-orm/sqlite-core").SQLiteColumn<{
125
+ name: "created_by";
126
+ tableName: "cms_preview_links";
127
+ dataType: "string";
128
+ columnType: "SQLiteText";
129
+ data: string;
130
+ driverParam: string;
131
+ notNull: false;
132
+ hasDefault: false;
133
+ isPrimaryKey: false;
134
+ isAutoincrement: false;
135
+ hasRuntimeDefault: false;
136
+ enumValues: [string, ...string[]];
137
+ baseColumn: never;
138
+ identity: undefined;
139
+ generated: undefined;
140
+ }, {}, {
141
+ length: number | undefined;
142
+ }>;
143
+ createdAt: import("drizzle-orm/sqlite-core").SQLiteColumn<{
144
+ name: "created_at";
145
+ tableName: "cms_preview_links";
146
+ dataType: "string";
147
+ columnType: "SQLiteText";
148
+ data: string;
149
+ driverParam: string;
150
+ notNull: true;
151
+ hasDefault: true;
152
+ isPrimaryKey: false;
153
+ isAutoincrement: false;
154
+ hasRuntimeDefault: false;
155
+ enumValues: [string, ...string[]];
156
+ baseColumn: never;
157
+ identity: undefined;
158
+ generated: undefined;
159
+ }, {}, {
160
+ length: number | undefined;
161
+ }>;
162
+ expiresAt: import("drizzle-orm/sqlite-core").SQLiteColumn<{
163
+ name: "expires_at";
164
+ tableName: "cms_preview_links";
165
+ dataType: "string";
166
+ columnType: "SQLiteText";
167
+ data: string;
168
+ driverParam: string;
169
+ notNull: true;
170
+ hasDefault: false;
171
+ isPrimaryKey: false;
172
+ isAutoincrement: false;
173
+ hasRuntimeDefault: false;
174
+ enumValues: [string, ...string[]];
175
+ baseColumn: never;
176
+ identity: undefined;
177
+ generated: undefined;
178
+ }, {}, {
179
+ length: number | undefined;
180
+ }>;
181
+ revokedAt: import("drizzle-orm/sqlite-core").SQLiteColumn<{
182
+ name: "revoked_at";
183
+ tableName: "cms_preview_links";
184
+ dataType: "string";
185
+ columnType: "SQLiteText";
186
+ data: string;
187
+ driverParam: string;
188
+ notNull: false;
189
+ hasDefault: false;
190
+ isPrimaryKey: false;
191
+ isAutoincrement: false;
192
+ hasRuntimeDefault: false;
193
+ enumValues: [string, ...string[]];
194
+ baseColumn: never;
195
+ identity: undefined;
196
+ generated: undefined;
197
+ }, {}, {
198
+ length: number | undefined;
199
+ }>;
200
+ };
201
+ dialect: "sqlite";
202
+ }>, "async" | "sync", unknown, undefined, false, "where">, "where">;
203
+ export declare function findPreviewGrant(token: string | null): Promise<CmsPreviewGrant | null>;
204
+ export declare function previewTokenOf(event: H3Event): string | null;
205
+ export declare function hasPreviewHeader(event: H3Event): boolean;
206
+ export declare function markPreviewResponse(event: H3Event): void;
207
+ export declare function readPreviewGrant(event: H3Event): Promise<CmsPreviewGrant | null>;
@@ -0,0 +1,161 @@
1
+ import { createHash, randomBytes } from "node:crypto";
2
+ import { and, asc, eq, gt, isNull, lte } from "drizzle-orm";
3
+ import { createError, getHeader, setResponseHeaders } from "h3";
4
+ import { z } from "zod";
5
+ import cmsConfig from "#cms-config";
6
+ import { useDb } from "#cms-db";
7
+ import { cms_preview_links } from "#cms-tables";
8
+ import {
9
+ PREVIEW_HEADER,
10
+ PREVIEW_LINK_DURATIONS,
11
+ PREVIEW_RESPONSE_HEADERS,
12
+ PREVIEW_TOKEN_BYTES,
13
+ contentItemPath,
14
+ isRoutedContent,
15
+ previewLinkExpiry,
16
+ previewLinkUrl,
17
+ previewTokenFrom
18
+ } from "../../shared/index.js";
19
+ import { normalizeTimestamp, nowTimestamp } from "../../shared/timestamps.js";
20
+ import { customId } from "./custom-id.js";
21
+ import { getContentI18n, resolveTable, tableColumns } from "./registry.js";
22
+ import { assertCmsPermission, requireCmsAccess } from "./permissions.js";
23
+ export const previewLinkInputSchema = z.object({
24
+ duration: z.enum(
25
+ PREVIEW_LINK_DURATIONS.map((option) => option.value)
26
+ ),
27
+ locale: z.string().max(32).nullish()
28
+ }).strict();
29
+ export async function requirePreviewLinkAccess(event, name, action) {
30
+ const { user, access } = await requireCmsAccess(event);
31
+ const entry = routedEntry(name);
32
+ assertCmsPermission(access, `${name}.${action}`);
33
+ return { user, name, entry };
34
+ }
35
+ export function createPreviewToken() {
36
+ return randomBytes(PREVIEW_TOKEN_BYTES).toString("base64url");
37
+ }
38
+ export function hashPreviewToken(token) {
39
+ return createHash("sha256").update(token).digest("hex");
40
+ }
41
+ function routedEntry(name) {
42
+ const entry = cmsConfig[name];
43
+ if (!entry || !isRoutedContent(entry))
44
+ throw createError({
45
+ statusCode: 400,
46
+ statusMessage: "Preview links need a content entry with a route"
47
+ });
48
+ return entry;
49
+ }
50
+ function previewLocale(locale) {
51
+ const { locales, defaultLocale } = getContentI18n();
52
+ if (!locale) return defaultLocale;
53
+ if (locales.length ? !locales.includes(locale) : locale !== defaultLocale)
54
+ throw createError({ statusCode: 400, statusMessage: `Unknown locale: ${locale}` });
55
+ return locale;
56
+ }
57
+ async function readItem(name, itemId) {
58
+ const table = resolveTable(name);
59
+ const id = table ? tableColumns(table).id : void 0;
60
+ const [row] = table && id ? await useDb().select().from(table).where(eq(id, itemId)).limit(1) : [];
61
+ if (!row) throw createError({ statusCode: 404, statusMessage: "Item not found" });
62
+ return row;
63
+ }
64
+ function toPreviewLink(row, path) {
65
+ return {
66
+ id: row.id,
67
+ entry: row.entry,
68
+ itemId: row.itemId,
69
+ locale: row.locale ?? null,
70
+ path,
71
+ createdBy: row.createdBy ?? null,
72
+ createdAt: String(normalizeTimestamp(row.createdAt)),
73
+ expiresAt: row.expiresAt
74
+ };
75
+ }
76
+ function activeCondition(now) {
77
+ return and(isNull(cms_preview_links.revokedAt), gt(cms_preview_links.expiresAt, now));
78
+ }
79
+ async function pruneStaleLinks(now) {
80
+ await useDb().delete(cms_preview_links).where(lte(cms_preview_links.expiresAt, now));
81
+ }
82
+ export async function listPreviewLinks({ name, entry }, itemId) {
83
+ const item = await readItem(name, itemId);
84
+ const rows = await useDb().select().from(cms_preview_links).where(
85
+ and(
86
+ eq(cms_preview_links.entry, name),
87
+ eq(cms_preview_links.itemId, itemId),
88
+ activeCondition(nowTimestamp())
89
+ )
90
+ ).orderBy(asc(cms_preview_links.expiresAt));
91
+ const { defaultLocale } = getContentI18n();
92
+ return rows.map(
93
+ (row) => toPreviewLink(row, contentItemPath(entry, item, row.locale ?? defaultLocale) ?? "")
94
+ );
95
+ }
96
+ export async function createPreviewLink({ name, entry, user }, itemId, input) {
97
+ const locale = previewLocale(input.locale);
98
+ const item = await readItem(name, itemId);
99
+ const path = contentItemPath(entry, item, locale);
100
+ if (!path)
101
+ throw createError({
102
+ statusCode: 400,
103
+ statusMessage: "The item has no address yet: give it a slug (and a publish date if the route uses one) and save"
104
+ });
105
+ const now = /* @__PURE__ */ new Date();
106
+ await pruneStaleLinks(now.toISOString());
107
+ const token = createPreviewToken();
108
+ const [row] = await useDb().insert(cms_preview_links).values({
109
+ id: customId("pvl"),
110
+ tokenHash: hashPreviewToken(token),
111
+ entry: name,
112
+ itemId,
113
+ locale,
114
+ createdBy: user.email,
115
+ createdAt: now.toISOString(),
116
+ expiresAt: previewLinkExpiry(input.duration, now)
117
+ }).returning();
118
+ return { link: toPreviewLink(row, path), url: previewLinkUrl(path, token) };
119
+ }
120
+ export async function revokePreviewLink({ name }, itemId, linkId) {
121
+ const [row] = await useDb().update(cms_preview_links).set({ revokedAt: nowTimestamp() }).where(
122
+ and(
123
+ eq(cms_preview_links.id, linkId),
124
+ eq(cms_preview_links.entry, name),
125
+ eq(cms_preview_links.itemId, itemId),
126
+ isNull(cms_preview_links.revokedAt)
127
+ )
128
+ ).returning({ id: cms_preview_links.id });
129
+ if (!row) throw createError({ statusCode: 404, statusMessage: "Preview link not found" });
130
+ }
131
+ export function deleteItemPreviewLinksStatement(db, name, itemId) {
132
+ return db.delete(cms_preview_links).where(and(eq(cms_preview_links.entry, name), eq(cms_preview_links.itemId, itemId)));
133
+ }
134
+ export async function findPreviewGrant(token) {
135
+ if (!token) return null;
136
+ const [row] = await useDb().select({
137
+ entry: cms_preview_links.entry,
138
+ itemId: cms_preview_links.itemId,
139
+ expiresAt: cms_preview_links.expiresAt
140
+ }).from(cms_preview_links).where(
141
+ and(
142
+ eq(cms_preview_links.tokenHash, hashPreviewToken(token)),
143
+ activeCondition(nowTimestamp())
144
+ )
145
+ ).limit(1);
146
+ return row ?? null;
147
+ }
148
+ export function previewTokenOf(event) {
149
+ return previewTokenFrom(getHeader(event, PREVIEW_HEADER));
150
+ }
151
+ export function hasPreviewHeader(event) {
152
+ return getHeader(event, PREVIEW_HEADER) !== void 0;
153
+ }
154
+ export function markPreviewResponse(event) {
155
+ setResponseHeaders(event, PREVIEW_RESPONSE_HEADERS);
156
+ }
157
+ export async function readPreviewGrant(event) {
158
+ if (!hasPreviewHeader(event)) return null;
159
+ markPreviewResponse(event);
160
+ return findPreviewGrant(previewTokenOf(event)).catch(() => null);
161
+ }
@@ -0,0 +1,31 @@
1
+ import { z } from 'zod';
2
+ import { runBatch } from '#cms-db';
3
+ import { cms_redirects } from '#cms-tables';
4
+ import type { CmsContentMoves, CmsContentRouteItem, CmsEntry, CmsRedirect, CmsRedirectInput, CmsRedirectPlan, CmsRedirectTarget } from '../../shared/index.js';
5
+ export declare const REDIRECTS_CACHE_TTL_MS = 30000;
6
+ type RedirectRow = typeof cms_redirects.$inferSelect;
7
+ type WriteDb = Parameters<Parameters<typeof runBatch>[0]>[0];
8
+ export declare const redirectInputSchema: z.ZodObject<{
9
+ from: z.ZodString;
10
+ to: z.ZodString;
11
+ status: z.ZodOptional<z.ZodLiteral<301 | 302 | 307 | 308>>;
12
+ keepQuery: z.ZodOptional<z.ZodBoolean>;
13
+ }, z.core.$strict>;
14
+ export declare function toRedirect(row: RedirectRow): CmsRedirect;
15
+ export declare function listRedirects(): Promise<CmsRedirect[]>;
16
+ export declare function readRedirectTable(): Promise<Map<string, CmsRedirectTarget>>;
17
+ export declare function invalidateRedirects(): void;
18
+ export declare function serializeRedirectWrite<T>(write: () => Promise<T>): Promise<T>;
19
+ export declare function createRedirect(input: CmsRedirectInput): Promise<CmsRedirect>;
20
+ export declare function updateRedirect(id: string, input: CmsRedirectInput): Promise<CmsRedirect>;
21
+ export declare function deleteRedirects(ids: string[]): Promise<number>;
22
+ export interface RedirectImportResult {
23
+ created: number;
24
+ updated: number;
25
+ }
26
+ export declare function importRedirects(inputs: CmsRedirectInput[]): Promise<RedirectImportResult>;
27
+ export declare function isLivePath(path: string): Promise<boolean>;
28
+ export declare function contentMovesOf(entry: CmsEntry, before: CmsContentRouteItem | undefined, after: CmsContentRouteItem): CmsContentMoves;
29
+ export declare function planContentRedirects(moves: CmsContentMoves): Promise<CmsRedirectPlan | null>;
30
+ export declare function redirectPlanStatements(db: WriteDb, plan: CmsRedirectPlan, now?: string): PromiseLike<unknown>[];
31
+ export {};
@@ -0,0 +1,240 @@
1
+ import { asc, eq, inArray } from "drizzle-orm";
2
+ import { createError } from "h3";
3
+ import { z } from "zod";
4
+ import cmsConfig from "#cms-config";
5
+ import { runBatch, useDb } from "#cms-db";
6
+ import { cms_redirects } from "#cms-tables";
7
+ import {
8
+ REDIRECT_FROM_MAX_LENGTH,
9
+ REDIRECT_STATUSES,
10
+ REDIRECT_TO_MAX_LENGTH,
11
+ contentItemMoves,
12
+ contentRouteLocales,
13
+ matchContentPath,
14
+ normalizeRedirectInput,
15
+ normalizeRedirectPath,
16
+ pageRoutes,
17
+ planRedirectMoves,
18
+ redirectErrors,
19
+ redirectFromErrors,
20
+ redirectTargetMap,
21
+ redirectToErrors
22
+ } from "../../shared/index.js";
23
+ import { normalizeTimestamp, nowTimestamp } from "../../shared/timestamps.js";
24
+ import { cachedValue } from "./cached-value.js";
25
+ import { findContentByPath } from "./content-routes.js";
26
+ import { customId } from "./custom-id.js";
27
+ import { mapConstraintErrors } from "./db-errors.js";
28
+ import { getContentI18n } from "./registry.js";
29
+ export const REDIRECTS_CACHE_TTL_MS = 3e4;
30
+ export const redirectInputSchema = z.object({
31
+ from: z.string().max(REDIRECT_FROM_MAX_LENGTH),
32
+ to: z.string().max(REDIRECT_TO_MAX_LENGTH),
33
+ status: z.literal(REDIRECT_STATUSES).optional(),
34
+ keepQuery: z.boolean().optional()
35
+ }).strict();
36
+ export function toRedirect(row) {
37
+ return {
38
+ id: row.id,
39
+ from: row.from,
40
+ to: row.to,
41
+ status: row.status,
42
+ keepQuery: !!row.keepQuery,
43
+ source: row.source === "auto" ? "auto" : "manual",
44
+ createdAt: String(normalizeTimestamp(row.createdAt)),
45
+ updatedAt: String(normalizeTimestamp(row.updatedAt))
46
+ };
47
+ }
48
+ export async function listRedirects() {
49
+ const rows = await useDb().select().from(cms_redirects).orderBy(asc(cms_redirects.from));
50
+ return rows.map(toRedirect);
51
+ }
52
+ async function loadRedirectTable() {
53
+ const rows = await useDb().select({
54
+ from: cms_redirects.from,
55
+ to: cms_redirects.to,
56
+ status: cms_redirects.status,
57
+ keepQuery: cms_redirects.keepQuery
58
+ }).from(cms_redirects);
59
+ return new Map(
60
+ rows.map((row) => [
61
+ row.from,
62
+ { to: row.to, status: row.status, keepQuery: !!row.keepQuery }
63
+ ])
64
+ );
65
+ }
66
+ const redirectsCache = cachedValue(loadRedirectTable, REDIRECTS_CACHE_TTL_MS);
67
+ export function readRedirectTable() {
68
+ return redirectsCache.get();
69
+ }
70
+ export function invalidateRedirects() {
71
+ redirectsCache.invalidate();
72
+ }
73
+ function invalid(errors) {
74
+ const duplicate = errors.some((error) => error.startsWith("A redirect from"));
75
+ return createError({
76
+ statusCode: duplicate ? 409 : 400,
77
+ statusMessage: duplicate ? "Duplicate redirect" : "Invalid redirect",
78
+ message: errors.join(". ")
79
+ });
80
+ }
81
+ function otherTargets(redirects, skipId) {
82
+ return redirectTargetMap(redirects.filter((redirect) => redirect.id !== skipId));
83
+ }
84
+ let pendingWrite = Promise.resolve();
85
+ export function serializeRedirectWrite(write) {
86
+ const run = pendingWrite.then(write);
87
+ pendingWrite = run.catch(() => {
88
+ });
89
+ return run;
90
+ }
91
+ export function createRedirect(input) {
92
+ return serializeRedirectWrite(() => writeNewRedirect(input));
93
+ }
94
+ async function writeNewRedirect(input) {
95
+ const errors = redirectErrors(input, otherTargets(await listRedirects()));
96
+ if (errors.length) throw invalid(errors);
97
+ const draft = normalizeRedirectInput(input);
98
+ const now = nowTimestamp();
99
+ const [row] = await mapConstraintErrors(
100
+ () => useDb().insert(cms_redirects).values({
101
+ id: customId("rdr"),
102
+ ...draft,
103
+ source: "manual",
104
+ createdAt: now,
105
+ updatedAt: now
106
+ }).returning()
107
+ );
108
+ invalidateRedirects();
109
+ return toRedirect(row);
110
+ }
111
+ export function updateRedirect(id, input) {
112
+ return serializeRedirectWrite(() => writeRedirectUpdate(id, input));
113
+ }
114
+ async function writeRedirectUpdate(id, input) {
115
+ const redirects = await listRedirects();
116
+ if (!redirects.some((redirect) => redirect.id === id))
117
+ throw createError({ statusCode: 404, statusMessage: "Redirect not found" });
118
+ const errors = redirectErrors(input, otherTargets(redirects, id));
119
+ if (errors.length) throw invalid(errors);
120
+ const draft = normalizeRedirectInput(input);
121
+ const [row] = await mapConstraintErrors(
122
+ () => useDb().update(cms_redirects).set({ ...draft, source: "manual", updatedAt: nowTimestamp() }).where(eq(cms_redirects.id, id)).returning()
123
+ );
124
+ invalidateRedirects();
125
+ return toRedirect(row);
126
+ }
127
+ export async function deleteRedirects(ids) {
128
+ const rows = await useDb().delete(cms_redirects).where(inArray(cms_redirects.id, ids)).returning({ id: cms_redirects.id });
129
+ invalidateRedirects();
130
+ return rows.length;
131
+ }
132
+ function importError(errors) {
133
+ const shown = errors.slice(0, 10);
134
+ if (errors.length > shown.length) shown.push(`and ${errors.length - shown.length} more`);
135
+ return createError({
136
+ statusCode: 400,
137
+ statusMessage: "Invalid redirects",
138
+ message: shown.join(". ")
139
+ });
140
+ }
141
+ export function importRedirects(inputs) {
142
+ return serializeRedirectWrite(() => writeRedirectImport(inputs));
143
+ }
144
+ async function writeRedirectImport(inputs) {
145
+ const errors = [];
146
+ inputs.forEach((input, index) => {
147
+ for (const error of [...redirectFromErrors(input.from), ...redirectToErrors(input.to)])
148
+ errors.push(`Row ${index + 1}: ${error}`);
149
+ });
150
+ if (errors.length) throw importError(errors);
151
+ const drafts = inputs.map(normalizeRedirectInput);
152
+ const existing = await listRedirects();
153
+ const byFrom = new Map(existing.map((redirect) => [redirect.from, redirect]));
154
+ const final = new Map(
155
+ existing.map((redirect) => [redirect.from, redirect])
156
+ );
157
+ const seen = /* @__PURE__ */ new Set();
158
+ drafts.forEach((draft, index) => {
159
+ if (seen.has(draft.from)) errors.push(`Row ${index + 1}: ${draft.from} is listed twice`);
160
+ seen.add(draft.from);
161
+ final.set(draft.from, draft);
162
+ });
163
+ const targets = redirectTargetMap([...final.values()]);
164
+ drafts.forEach((draft, index) => {
165
+ const others = new Map(targets);
166
+ others.delete(draft.from);
167
+ for (const error of redirectErrors(draft, others)) errors.push(`Row ${index + 1}: ${error}`);
168
+ });
169
+ if (errors.length) throw importError(errors);
170
+ const now = nowTimestamp();
171
+ let created = 0;
172
+ let updated = 0;
173
+ await mapConstraintErrors(
174
+ () => runBatch(
175
+ (db) => drafts.map((draft) => {
176
+ const current = byFrom.get(draft.from);
177
+ if (current) {
178
+ updated += 1;
179
+ return db.update(cms_redirects).set({ ...draft, source: "manual", updatedAt: now }).where(eq(cms_redirects.id, current.id));
180
+ }
181
+ created += 1;
182
+ return db.insert(cms_redirects).values({
183
+ id: customId("rdr"),
184
+ ...draft,
185
+ source: "manual",
186
+ createdAt: now,
187
+ updatedAt: now
188
+ });
189
+ })
190
+ )
191
+ );
192
+ invalidateRedirects();
193
+ return { created, updated };
194
+ }
195
+ function isStaticPath(path) {
196
+ return path.startsWith("/") && !/[[\]:*]/.test(path);
197
+ }
198
+ export async function isLivePath(path) {
199
+ const config = cmsConfig;
200
+ const normalized = normalizeRedirectPath(path);
201
+ for (const entry of Object.values(config)) {
202
+ if (entry.kind !== "page") continue;
203
+ if (pageRoutes(entry).some(
204
+ (route) => isStaticPath(route.path) && normalizeRedirectPath(route.path) === normalized
205
+ ))
206
+ return true;
207
+ }
208
+ for (const locale of contentRouteLocales(getContentI18n())) {
209
+ for (const match of matchContentPath(config, normalized, locale)) {
210
+ if (await findContentByPath(match.entry, normalized, locale)) return true;
211
+ }
212
+ }
213
+ return false;
214
+ }
215
+ export function contentMovesOf(entry, before, after) {
216
+ if (!before) return { moves: [], livePaths: [] };
217
+ return contentItemMoves(entry, before, after, contentRouteLocales(getContentI18n()));
218
+ }
219
+ export async function planContentRedirects(moves) {
220
+ if (!moves.moves.length) return null;
221
+ const existing = await useDb().select({ id: cms_redirects.id, from: cms_redirects.from, to: cms_redirects.to }).from(cms_redirects);
222
+ return planRedirectMoves(existing, moves.moves, moves.livePaths);
223
+ }
224
+ export function redirectPlanStatements(db, plan, now = nowTimestamp()) {
225
+ const statements = [];
226
+ if (plan.deletes.length)
227
+ statements.push(db.delete(cms_redirects).where(inArray(cms_redirects.id, plan.deletes)));
228
+ for (const { id, to } of plan.retargets) {
229
+ statements.push(
230
+ db.update(cms_redirects).set({ to, updatedAt: now }).where(eq(cms_redirects.id, id))
231
+ );
232
+ }
233
+ for (const { from, to } of plan.upserts) {
234
+ const values = { to, status: 301, keepQuery: true, source: "auto", updatedAt: now };
235
+ statements.push(
236
+ db.insert(cms_redirects).values({ id: customId("rdr"), from, createdAt: now, ...values }).onConflictDoUpdate({ target: cms_redirects.from, set: values })
237
+ );
238
+ }
239
+ return statements;
240
+ }
@@ -56,7 +56,10 @@ export function getRegistryEntry(event) {
56
56
  }
57
57
  export function buildValidator(entry, path) {
58
58
  const fields = path ? pageFields(entry, path) : entry.fields;
59
- return buildEntrySchema({ ...entry, fields, path }, getContentI18n());
59
+ return buildEntrySchema(
60
+ { ...entry, fields, path, config: cmsConfig },
61
+ getContentI18n()
62
+ );
60
63
  }
61
64
  export function requirePageRoute(entry, key) {
62
65
  const route = pageRouteOf(entry, key);
@@ -11,4 +11,12 @@ export declare function assertRelationTargets(entry: CmsEntry, lists: Record<str
11
11
  export declare function manyToManyStatements(db: CmsDb, name: string, sourceId: string, lists: Record<string, string[]>): PromiseLike<unknown>[];
12
12
  export declare function relationTitles(db: CmsDb, entry: CmsEntry, rows: Row[]): Promise<Record<string, Record<string, unknown>>>;
13
13
  export declare function attachManyToMany<T extends Row>(db: CmsDb, name: string, entry: CmsEntry, rows: T[]): Promise<T[]>;
14
+ export interface SavedReadBack<T> {
15
+ row: T;
16
+ error: unknown;
17
+ }
18
+ export declare function readBackSaved<T extends Row>(name: string, entry: CmsEntry, row: T): Promise<SavedReadBack<T>>;
19
+ export declare function savedReadBackError(error: unknown): import("h3").H3Error<{
20
+ saved: boolean;
21
+ }>;
14
22
  export {};