@xleddyl/nuxt-cms 0.9.4 → 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 (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 -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 +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,3 +1,4 @@
1
+ import type { CmsBlockPath } from './block-paths.js';
1
2
  import type { CmsConfig, CmsEntryKind } from './index.js';
2
3
  export declare const CMS_SEARCH_MIN_LENGTH = 2;
3
4
  export declare const CMS_SEARCH_MAX_LENGTH = 200;
@@ -35,8 +36,12 @@ export interface CmsSearchFocus {
35
36
  field?: string;
36
37
  locale?: string | null;
37
38
  block?: number | null;
39
+ blockPath?: CmsBlockPath | null;
38
40
  tab?: string;
39
41
  }
42
+ export type CmsSearchLinkFocus = Omit<CmsSearchFocus, 'block' | 'blockPath'> & {
43
+ block?: number | string | null;
44
+ };
40
45
  export declare function normalizeSearchQuery(value: string): string;
41
46
  export declare function isSearchableQuery(value: string): boolean;
42
47
  export declare function searchLikePattern(term: string): string;
@@ -44,7 +49,17 @@ export declare function decodeHtmlEntities(value: string): string;
44
49
  export declare function stripMarkup(html: string): string;
45
50
  export declare function searchSnippet(text: string, term: string): CmsSearchSnippet | null;
46
51
  export declare function searchFieldPath(...labels: string[]): string;
47
- export declare function cmsSearchLink(path: string, focus?: CmsSearchFocus): string;
52
+ export declare const CMS_TAB_QUERY = "tab";
53
+ export declare function cmsSearchLink(path: string, focus?: CmsSearchLinkFocus): string;
54
+ export declare const CMS_ENTRY_ROUTE_KEY = "entry";
55
+ export declare const CMS_ENTRY_TAB_ROUTE_KEY = "entrytab";
56
+ export declare const CMS_ENTRY_FOCUS_KEYS: readonly ["field", "locale", "block"];
57
+ export declare function cmsHashLink(path: string, entries: Record<string, string | number | null | undefined>): string;
58
+ export declare function cmsPageKey(route: {
59
+ path: string;
60
+ query: Record<string, unknown>;
61
+ }, omit?: string[]): string;
62
+ export declare function cmsEntryLink(collection: string, id: string, focus?: CmsSearchLinkFocus): string;
48
63
  export declare function readSearchFocus(query: Record<string, unknown>): CmsSearchFocus | null;
49
64
  export declare function searchCmsLabels(config: CmsConfig, query: string, limit?: number): {
50
65
  hits: CmsSearchHit[];
@@ -1,3 +1,4 @@
1
+ import { parseBlockPath } from "./block-paths.js";
1
2
  import { entryTabs, fieldTab, pageAllFields, pageRoutes } from "./index.js";
2
3
  export const CMS_SEARCH_MIN_LENGTH = 2;
3
4
  export const CMS_SEARCH_MAX_LENGTH = 200;
@@ -57,29 +58,58 @@ export function searchSnippet(text, term) {
57
58
  export function searchFieldPath(...labels) {
58
59
  return labels.join(CMS_SEARCH_PATH_SEPARATOR);
59
60
  }
61
+ export const CMS_TAB_QUERY = "tab";
60
62
  export function cmsSearchLink(path, focus = {}) {
61
63
  const params = new URLSearchParams();
62
64
  if (focus.field) params.set("field", focus.field);
63
65
  if (focus.locale) params.set("locale", focus.locale);
64
66
  if (focus.block != null) params.set("block", String(focus.block));
65
- if (focus.tab) params.set("tab", focus.tab);
67
+ if (focus.tab) params.set(CMS_TAB_QUERY, focus.tab);
66
68
  const query = params.toString();
67
69
  return query ? `${path}?${query}` : path;
68
70
  }
71
+ export const CMS_ENTRY_ROUTE_KEY = "entry";
72
+ export const CMS_ENTRY_TAB_ROUTE_KEY = "entrytab";
73
+ export const CMS_ENTRY_FOCUS_KEYS = ["field", "locale", "block"];
74
+ function escapeHashValue(value) {
75
+ return value.replace(/[%&]/g, (char) => char === "%" ? "%25" : "%26");
76
+ }
77
+ export function cmsHashLink(path, entries) {
78
+ const text = Object.entries(entries).filter(([, value]) => value != null && value !== "").map(([key, value]) => `${key}/${escapeHashValue(String(value))}`).join("&");
79
+ return text ? `${path}#${text}` : path;
80
+ }
81
+ export function cmsPageKey(route, omit = []) {
82
+ const query = Object.fromEntries(
83
+ Object.entries(route.query).filter(([key]) => !omit.includes(key))
84
+ );
85
+ return `${route.path}${JSON.stringify(query)}`;
86
+ }
87
+ export function cmsEntryLink(collection, id, focus = {}) {
88
+ return cmsHashLink(`/cms/${collection}`, {
89
+ [CMS_ENTRY_ROUTE_KEY]: id,
90
+ field: focus.field,
91
+ locale: focus.locale,
92
+ block: focus.block,
93
+ [CMS_ENTRY_TAB_ROUTE_KEY]: focus.tab
94
+ });
95
+ }
69
96
  export function readSearchFocus(query) {
70
97
  const text = (value) => {
71
98
  const first = Array.isArray(value) ? value[0] : value;
72
99
  return typeof first === "string" && first ? first : void 0;
73
100
  };
74
101
  const field = text(query.field);
75
- const tab = text(query.tab);
102
+ const tab = text(query[CMS_TAB_QUERY]);
76
103
  if (!field && !tab) return null;
77
- const block = Number.parseInt(text(query.block) ?? "", 10);
104
+ const blockText = text(query.block);
105
+ const block = Number.parseInt(blockText ?? "", 10);
106
+ const blockPath = field && blockText ? parseBlockPath(`${field}.${blockText}`) : null;
78
107
  return {
79
108
  ...field ? { field } : {},
80
109
  ...tab ? { tab } : {},
81
110
  locale: text(query.locale) ?? null,
82
- block: Number.isInteger(block) && block >= 0 ? block : null
111
+ block: Number.isInteger(block) && block >= 0 ? block : null,
112
+ blockPath: blockPath && blockPath.length % 2 === 0 ? blockPath : null
83
113
  };
84
114
  }
85
115
  function entryPath(name) {
@@ -104,14 +134,14 @@ function fieldLink(name, entry, key, overridePaths) {
104
134
  function overridePathsOf(entry, key) {
105
135
  return Object.entries(entry.overrides ?? {}).filter(([, fields]) => !!fields[key]).map(([path]) => path);
106
136
  }
107
- function blockCandidates(key, field, link) {
137
+ function blockCandidates(key, field, link, labels = [field.label]) {
108
138
  const candidates = [];
109
139
  for (const block of Object.values(field.blocks ?? {})) {
110
140
  candidates.push({
111
141
  type: "block",
112
142
  ...link,
113
143
  field: key,
114
- fieldLabel: searchFieldPath(field.label, block.label),
144
+ fieldLabel: searchFieldPath(...labels, block.label),
115
145
  texts: [block.label]
116
146
  });
117
147
  for (const blockField of Object.values(block.fields)) {
@@ -119,9 +149,13 @@ function blockCandidates(key, field, link) {
119
149
  type: "field",
120
150
  ...link,
121
151
  field: key,
122
- fieldLabel: searchFieldPath(field.label, block.label, blockField.label),
152
+ fieldLabel: searchFieldPath(...labels, block.label, blockField.label),
123
153
  texts: [blockField.label]
124
154
  });
155
+ if (blockField.type === "blocks")
156
+ candidates.push(
157
+ ...blockCandidates(key, blockField, link, [...labels, block.label, blockField.label])
158
+ );
125
159
  }
126
160
  }
127
161
  return candidates;
@@ -0,0 +1,167 @@
1
+ import type { CmsLocalePath } from './content-routes.js';
2
+ export declare const CMS_SITE_SETTINGS_KEY = "cms:site";
3
+ export declare const DEFAULT_TITLE_TEMPLATE = "%s | %siteName";
4
+ export declare const TITLE_PLACEHOLDER = "%s";
5
+ export declare const SITE_NAME_PLACEHOLDER = "%siteName";
6
+ export declare const SITEMAP_PATH = "/sitemap.xml";
7
+ export declare const ROBOTS_PATH = "/robots.txt";
8
+ export declare const SITEMAP_MAX_URLS = 50000;
9
+ export declare const SEO_ADMIN_PREFIX = "/cms";
10
+ export declare const HIDDEN_SITE_ROBOTS = "noindex, nofollow";
11
+ export declare const SITE_TEXT_LIMITS: {
12
+ readonly name: 200;
13
+ readonly titleTemplate: 200;
14
+ readonly description: 1000;
15
+ };
16
+ export declare const SITEMAP_CONFLICT_MODULES: string[];
17
+ export declare const ROBOTS_CONFLICT_MODULES: string[];
18
+ export type CmsLocaleText = Record<string, string> | null;
19
+ export interface CmsSiteSettings {
20
+ name: CmsLocaleText;
21
+ titleTemplate: string | null;
22
+ description: CmsLocaleText;
23
+ image: string | null;
24
+ hidden: boolean;
25
+ }
26
+ export declare const EMPTY_SITE_SETTINGS: CmsSiteSettings;
27
+ export declare function coerceSiteSettings(value: unknown): CmsSiteSettings;
28
+ export interface CmsSeoMedia {
29
+ url: string | null;
30
+ type?: string | null;
31
+ alt?: string | null;
32
+ width?: number | null;
33
+ height?: number | null;
34
+ mime?: string | null;
35
+ }
36
+ export interface CmsSite {
37
+ name: string | null;
38
+ titleTemplate: string | null;
39
+ description: string | null;
40
+ image: CmsSeoMedia | null;
41
+ hidden: boolean;
42
+ }
43
+ export interface CmsSeoSource {
44
+ title?: string | null;
45
+ seoTitle?: string | null;
46
+ description?: string | null;
47
+ excerpt?: string | null;
48
+ seoDescription?: string | null;
49
+ cover?: CmsSeoMedia | null;
50
+ seoImage?: CmsSeoMedia | null;
51
+ seoNoindex?: boolean | null;
52
+ path?: string | null;
53
+ paths?: readonly CmsLocalePath[] | null;
54
+ publishedAt?: string | null;
55
+ updatedAt?: string | null;
56
+ }
57
+ export type CmsSeoType = 'website' | 'article';
58
+ export interface CmsSeoOverrides {
59
+ title?: string | null;
60
+ description?: string | null;
61
+ image?: string | CmsSeoMedia | null;
62
+ path?: string | null;
63
+ alternates?: readonly CmsLocalePath[] | null;
64
+ noindex?: boolean | null;
65
+ type?: CmsSeoType;
66
+ titleTemplate?: string | false | null;
67
+ }
68
+ export interface CmsSeoContext {
69
+ siteUrl: string;
70
+ path: string;
71
+ defaultLocale: string;
72
+ }
73
+ export interface CmsSeoAlternate {
74
+ hreflang: string;
75
+ href: string;
76
+ }
77
+ export interface CmsSeoImage {
78
+ url: string;
79
+ alt: string | null;
80
+ width: number | null;
81
+ height: number | null;
82
+ type: string | null;
83
+ }
84
+ export interface CmsSeoMeta {
85
+ title: string;
86
+ pageTitle: string | null;
87
+ description: string | null;
88
+ canonical: string;
89
+ image: CmsSeoImage | null;
90
+ robots: string | null;
91
+ alternates: CmsSeoAlternate[];
92
+ type: CmsSeoType;
93
+ siteName: string | null;
94
+ publishedTime: string | null;
95
+ modifiedTime: string | null;
96
+ }
97
+ export declare function localeText(value: CmsLocaleText | undefined, locale: string, defaultLocale: string): string | null;
98
+ export declare function normalizeSiteUrl(url: string | null | undefined): string;
99
+ export declare function isAbsoluteUrl(value: string): boolean;
100
+ export declare function absoluteUrl(siteUrl: string, pathOrUrl: string): string;
101
+ export declare function applyTitleTemplate(template: string | null | undefined, title: string | null | undefined, siteName: string | null | undefined): string;
102
+ export declare function titleTemplateErrors(template: string): string[];
103
+ export declare function plainText(value: string | null | undefined): string | null;
104
+ export declare function seoAlternates(paths: readonly CmsLocalePath[] | null | undefined, siteUrl: string, defaultLocale: string): CmsSeoAlternate[];
105
+ export declare function resolveSeoMeta(source: CmsSeoSource | null | undefined, site: CmsSite | null | undefined, context: CmsSeoContext, overrides?: CmsSeoOverrides): CmsSeoMeta;
106
+ export interface SitemapUrl {
107
+ loc: string;
108
+ lastmod?: string | null;
109
+ alternates?: CmsSeoAlternate[];
110
+ }
111
+ export declare function escapeXml(value: string): string;
112
+ export declare const SITEMAP_URLSET_OPEN = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\" xmlns:xhtml=\"http://www.w3.org/1999/xhtml\">\n";
113
+ export declare const SITEMAP_URLSET_CLOSE = "</urlset>\n";
114
+ export declare function renderSitemapUrl(url: SitemapUrl): string;
115
+ export declare function renderSitemap(urls: readonly SitemapUrl[]): string;
116
+ export declare function renderSitemapIndex(locs: readonly string[]): string;
117
+ export declare function sitemapUrlsForPaths(paths: readonly CmsLocalePath[], siteUrl: string, defaultLocale: string, lastmod: string | null): SitemapUrl[];
118
+ export declare function isAdminPath(path: string): boolean;
119
+ export declare function hiddenSiteHeaderApplies(path: string): boolean;
120
+ export declare function sitemapLastmod(value: unknown): string | null;
121
+ export declare function pageSitemapUrls(paths: readonly string[], rows: readonly Record<string, unknown>[], siteUrl: string): SitemapUrl[];
122
+ export interface SitemapSourceSize {
123
+ source: string;
124
+ count: number;
125
+ urlsPerItem: number;
126
+ }
127
+ export interface SitemapChunk {
128
+ source: string;
129
+ offset: number;
130
+ limit: number;
131
+ }
132
+ export declare function sitemapUrlCount(sizes: readonly SitemapSourceSize[]): number;
133
+ export declare function planSitemapChunks(sizes: readonly SitemapSourceSize[], maxUrls?: number): SitemapChunk[];
134
+ export declare function sitemapPartUrl(siteUrl: string, part: number): string;
135
+ export interface RobotsOptions {
136
+ hidden: boolean;
137
+ sitemapUrl: string | null;
138
+ }
139
+ export declare function renderRobotsTxt(options: RobotsOptions): string;
140
+ export interface CmsSeoModuleOptions {
141
+ sitemap?: boolean;
142
+ robots?: boolean;
143
+ }
144
+ export interface CmsSiteModuleOptions {
145
+ url?: string;
146
+ trustForwardedHost?: boolean;
147
+ }
148
+ export declare const SEO_ROUTE_CACHE_CONTROL = "public, max-age=600, s-maxage=600";
149
+ export declare const SEO_ROUTE_PRIVATE_CACHE_CONTROL = "private, no-store";
150
+ export declare function seoRouteCacheControl(configuredSiteUrl: string | null | undefined): string;
151
+ export declare function isForwardedHostTrusted(value: unknown): boolean;
152
+ export declare function missingSiteUrlWarning(routes: {
153
+ sitemap: boolean;
154
+ robots: boolean;
155
+ }): string | null;
156
+ export declare function siteUrlErrors(url: unknown, at?: string): string[];
157
+ export declare function seoOptionErrors(seo: unknown, site: unknown): string[];
158
+ export interface SeoConflicts {
159
+ sitemap: string[];
160
+ robots: string[];
161
+ }
162
+ export interface ResolvedSeoSwitches {
163
+ sitemap: boolean;
164
+ robots: boolean;
165
+ warnings: string[];
166
+ }
167
+ export declare function resolveSeoSwitches(seo: CmsSeoModuleOptions | undefined, conflicts: SeoConflicts): ResolvedSeoSwitches;
@@ -0,0 +1,335 @@
1
+ import { normalizeTimestamp } from "./timestamps.js";
2
+ export const CMS_SITE_SETTINGS_KEY = "cms:site";
3
+ export const DEFAULT_TITLE_TEMPLATE = "%s | %siteName";
4
+ export const TITLE_PLACEHOLDER = "%s";
5
+ export const SITE_NAME_PLACEHOLDER = "%siteName";
6
+ export const SITEMAP_PATH = "/sitemap.xml";
7
+ export const ROBOTS_PATH = "/robots.txt";
8
+ export const SITEMAP_MAX_URLS = 5e4;
9
+ export const SEO_ADMIN_PREFIX = "/cms";
10
+ export const HIDDEN_SITE_ROBOTS = "noindex, nofollow";
11
+ export const SITE_TEXT_LIMITS = { name: 200, titleTemplate: 200, description: 1e3 };
12
+ export const SITEMAP_CONFLICT_MODULES = ["@nuxtjs/sitemap", "nuxt-simple-sitemap"];
13
+ export const ROBOTS_CONFLICT_MODULES = ["@nuxtjs/robots", "nuxt-simple-robots"];
14
+ export const EMPTY_SITE_SETTINGS = {
15
+ name: null,
16
+ titleTemplate: null,
17
+ description: null,
18
+ image: null,
19
+ hidden: false
20
+ };
21
+ function coerceLocaleText(value) {
22
+ if (!value || typeof value !== "object" || Array.isArray(value)) return null;
23
+ const entries = Object.entries(value).filter(
24
+ (entry) => typeof entry[1] === "string" && !!entry[1].trim()
25
+ );
26
+ return entries.length ? Object.fromEntries(entries) : null;
27
+ }
28
+ export function coerceSiteSettings(value) {
29
+ if (!value || typeof value !== "object" || Array.isArray(value))
30
+ return { ...EMPTY_SITE_SETTINGS };
31
+ const raw = value;
32
+ return {
33
+ name: coerceLocaleText(raw.name),
34
+ titleTemplate: typeof raw.titleTemplate === "string" && raw.titleTemplate.trim() ? raw.titleTemplate : null,
35
+ description: coerceLocaleText(raw.description),
36
+ image: typeof raw.image === "string" && raw.image ? raw.image : null,
37
+ hidden: raw.hidden === true
38
+ };
39
+ }
40
+ export function localeText(value, locale, defaultLocale) {
41
+ if (!value) return null;
42
+ const pick = (candidate) => typeof candidate === "string" && candidate.trim() ? candidate.trim() : null;
43
+ return pick(value[locale]) ?? pick(value[defaultLocale]) ?? Object.values(value).map(pick).find(Boolean) ?? null;
44
+ }
45
+ export function normalizeSiteUrl(url) {
46
+ return (url ?? "").trim().replace(/\/+$/, "");
47
+ }
48
+ export function isAbsoluteUrl(value) {
49
+ return /^[a-z][a-z\d+.-]*:/i.test(value) || value.startsWith("//");
50
+ }
51
+ export function absoluteUrl(siteUrl, pathOrUrl) {
52
+ if (isAbsoluteUrl(pathOrUrl)) return pathOrUrl;
53
+ const base = normalizeSiteUrl(siteUrl);
54
+ const path = pathOrUrl.startsWith("/") ? pathOrUrl : `/${pathOrUrl}`;
55
+ return `${base}${path}`;
56
+ }
57
+ function hasTitlePlaceholder(template) {
58
+ return template.split(SITE_NAME_PLACEHOLDER).join("").includes(TITLE_PLACEHOLDER);
59
+ }
60
+ export function applyTitleTemplate(template, title, siteName) {
61
+ const page = title?.trim() || "";
62
+ const site = siteName?.trim() || "";
63
+ if (!page) return site;
64
+ const pattern = template?.trim() || (site ? DEFAULT_TITLE_TEMPLATE : TITLE_PLACEHOLDER);
65
+ if (!hasTitlePlaceholder(pattern)) return page;
66
+ if (pattern.includes(SITE_NAME_PLACEHOLDER) && !site) return page;
67
+ if (site && page === site) return page;
68
+ return pattern.split(SITE_NAME_PLACEHOLDER).map((part) => part.split(TITLE_PLACEHOLDER).join(page)).join(site);
69
+ }
70
+ export function titleTemplateErrors(template) {
71
+ return hasTitlePlaceholder(template) ? [] : [`The title template needs ${TITLE_PLACEHOLDER} where the page title goes`];
72
+ }
73
+ const ENTITIES = {
74
+ amp: "&",
75
+ lt: "<",
76
+ gt: ">",
77
+ quot: '"',
78
+ apos: "'",
79
+ nbsp: " ",
80
+ "#39": "'"
81
+ };
82
+ export function plainText(value) {
83
+ if (typeof value !== "string") return null;
84
+ const text = value.replace(/<[^>]*>/g, " ").replace(/&(amp|lt|gt|quot|apos|nbsp|#39);/g, (_, name) => ENTITIES[name] ?? "").replace(/\s+/g, " ").trim();
85
+ return text || null;
86
+ }
87
+ export function seoAlternates(paths, siteUrl, defaultLocale) {
88
+ const byLocale = /* @__PURE__ */ new Map();
89
+ for (const { locale, path } of paths ?? []) {
90
+ if (locale && path && !byLocale.has(locale)) byLocale.set(locale, path);
91
+ }
92
+ if (new Set(byLocale.values()).size < 2) return [];
93
+ const links = [...byLocale].map(([locale, path]) => ({
94
+ hreflang: locale,
95
+ href: absoluteUrl(siteUrl, path)
96
+ }));
97
+ const fallback = byLocale.get(defaultLocale) ?? byLocale.values().next().value;
98
+ links.push({ hreflang: "x-default", href: absoluteUrl(siteUrl, fallback) });
99
+ return links;
100
+ }
101
+ function cleanText(value) {
102
+ return typeof value === "string" && value.trim() ? value.trim() : null;
103
+ }
104
+ function seoImageOf(media, siteUrl) {
105
+ if (!media?.url) return null;
106
+ if (media.type && media.type !== "image") return null;
107
+ return {
108
+ url: absoluteUrl(siteUrl, media.url),
109
+ alt: media.alt ?? null,
110
+ width: media.width ?? null,
111
+ height: media.height ?? null,
112
+ type: media.mime ?? null
113
+ };
114
+ }
115
+ function pickImage(candidates, siteUrl) {
116
+ for (const candidate of candidates) {
117
+ const image = typeof candidate === "string" ? seoImageOf({ url: candidate }, siteUrl) : seoImageOf(candidate, siteUrl);
118
+ if (image) return image;
119
+ }
120
+ return null;
121
+ }
122
+ export function resolveSeoMeta(source, site, context, overrides = {}) {
123
+ const item = source ?? {};
124
+ const siteName = cleanText(site?.name);
125
+ const pageTitle = cleanText(overrides.title) ?? cleanText(item.seoTitle) ?? cleanText(item.title) ?? null;
126
+ const template = overrides.titleTemplate === false ? TITLE_PLACEHOLDER : cleanText(overrides.titleTemplate) ?? cleanText(site?.titleTemplate);
127
+ const description = plainText(overrides.description) ?? plainText(item.seoDescription) ?? plainText(item.excerpt) ?? plainText(item.description) ?? plainText(site?.description);
128
+ const path = cleanText(overrides.path) ?? cleanText(item.path) ?? context.path;
129
+ const hidden = !!site?.hidden;
130
+ const noindex = overrides.noindex ?? item.seoNoindex ?? false;
131
+ return {
132
+ title: applyTitleTemplate(template, pageTitle, siteName),
133
+ pageTitle,
134
+ description,
135
+ canonical: absoluteUrl(context.siteUrl, path.replace(/[?#].*$/, "") || "/"),
136
+ image: pickImage(
137
+ overrides.image !== void 0 ? [overrides.image] : [item.seoImage, item.cover, site?.image],
138
+ context.siteUrl
139
+ ),
140
+ robots: hidden ? HIDDEN_SITE_ROBOTS : noindex ? "noindex" : null,
141
+ alternates: seoAlternates(
142
+ overrides.alternates ?? item.paths,
143
+ context.siteUrl,
144
+ context.defaultLocale
145
+ ),
146
+ type: overrides.type ?? (item.publishedAt ? "article" : "website"),
147
+ siteName,
148
+ publishedTime: cleanText(item.publishedAt),
149
+ modifiedTime: cleanText(item.updatedAt)
150
+ };
151
+ }
152
+ export function escapeXml(value) {
153
+ return value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&apos;");
154
+ }
155
+ export const SITEMAP_URLSET_OPEN = '<?xml version="1.0" encoding="UTF-8"?>\n<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:xhtml="http://www.w3.org/1999/xhtml">\n';
156
+ export const SITEMAP_URLSET_CLOSE = "</urlset>\n";
157
+ export function renderSitemapUrl(url) {
158
+ const lines = [" <url>", ` <loc>${escapeXml(url.loc)}</loc>`];
159
+ if (url.lastmod) lines.push(` <lastmod>${escapeXml(url.lastmod)}</lastmod>`);
160
+ for (const alternate of url.alternates ?? []) {
161
+ lines.push(
162
+ ` <xhtml:link rel="alternate" hreflang="${escapeXml(
163
+ alternate.hreflang
164
+ )}" href="${escapeXml(alternate.href)}"/>`
165
+ );
166
+ }
167
+ lines.push(" </url>");
168
+ return `${lines.join("\n")}
169
+ `;
170
+ }
171
+ export function renderSitemap(urls) {
172
+ return `${SITEMAP_URLSET_OPEN}${urls.map(renderSitemapUrl).join("")}${SITEMAP_URLSET_CLOSE}`;
173
+ }
174
+ export function renderSitemapIndex(locs) {
175
+ const items = locs.map((loc) => ` <sitemap>
176
+ <loc>${escapeXml(loc)}</loc>
177
+ </sitemap>
178
+ `);
179
+ return `<?xml version="1.0" encoding="UTF-8"?>
180
+ <sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
181
+ ${items.join(
182
+ ""
183
+ )}</sitemapindex>
184
+ `;
185
+ }
186
+ export function sitemapUrlsForPaths(paths, siteUrl, defaultLocale, lastmod) {
187
+ const alternates = seoAlternates(paths, siteUrl, defaultLocale);
188
+ const seen = /* @__PURE__ */ new Set();
189
+ const urls = [];
190
+ for (const { path } of paths) {
191
+ if (!path || seen.has(path) || isAdminPath(path)) continue;
192
+ seen.add(path);
193
+ urls.push({
194
+ loc: absoluteUrl(siteUrl, path),
195
+ lastmod,
196
+ ...alternates.length ? { alternates } : {}
197
+ });
198
+ }
199
+ return urls;
200
+ }
201
+ export function isAdminPath(path) {
202
+ return path === SEO_ADMIN_PREFIX || path.startsWith(`${SEO_ADMIN_PREFIX}/`);
203
+ }
204
+ const ROBOTS_HEADER_SKIPPED_PREFIXES = ["/_nuxt/", "/__nuxt"];
205
+ export function hiddenSiteHeaderApplies(path) {
206
+ const bare = path.replace(/[?#].*$/, "");
207
+ return !isAdminPath(bare) && !ROBOTS_HEADER_SKIPPED_PREFIXES.some((prefix) => bare.startsWith(prefix));
208
+ }
209
+ export function sitemapLastmod(value) {
210
+ const normalized = normalizeTimestamp(value);
211
+ return typeof normalized === "string" && normalized ? normalized : null;
212
+ }
213
+ export function pageSitemapUrls(paths, rows, siteUrl) {
214
+ const byPath = new Map(rows.map((row) => [row.path, row]));
215
+ const urls = [];
216
+ for (const path of paths) {
217
+ if (!path.startsWith("/") || /[[\]:*]/.test(path) || isAdminPath(path)) continue;
218
+ const row = byPath.get(path);
219
+ if (row?.seoNoindex === true) continue;
220
+ urls.push({ loc: absoluteUrl(siteUrl, path), lastmod: sitemapLastmod(row?.updatedAt) });
221
+ }
222
+ return urls;
223
+ }
224
+ export function sitemapUrlCount(sizes) {
225
+ return sizes.reduce((total, size) => total + size.count * Math.max(1, size.urlsPerItem), 0);
226
+ }
227
+ export function planSitemapChunks(sizes, maxUrls = SITEMAP_MAX_URLS) {
228
+ const chunks = [];
229
+ for (const { source, count, urlsPerItem } of sizes) {
230
+ const perChunk = Math.max(1, Math.floor(maxUrls / Math.max(1, urlsPerItem)));
231
+ for (let offset = 0; offset < count; offset += perChunk) {
232
+ chunks.push({ source, offset, limit: Math.min(perChunk, count - offset) });
233
+ }
234
+ }
235
+ return chunks;
236
+ }
237
+ export function sitemapPartUrl(siteUrl, part) {
238
+ return absoluteUrl(siteUrl, `${SITEMAP_PATH}?part=${part}`);
239
+ }
240
+ export function renderRobotsTxt(options) {
241
+ const lines = ["User-agent: *", `Disallow: ${SEO_ADMIN_PREFIX}/`];
242
+ if (!options.hidden && options.sitemapUrl) lines.push("", `Sitemap: ${options.sitemapUrl}`);
243
+ return `${lines.join("\n")}
244
+ `;
245
+ }
246
+ const SEO_OPTION_KEYS = ["sitemap", "robots"];
247
+ const SITE_OPTION_KEYS = ["url", "trustForwardedHost"];
248
+ export const SEO_ROUTE_CACHE_CONTROL = "public, max-age=600, s-maxage=600";
249
+ export const SEO_ROUTE_PRIVATE_CACHE_CONTROL = "private, no-store";
250
+ export function seoRouteCacheControl(configuredSiteUrl) {
251
+ return configuredSiteUrl ? SEO_ROUTE_CACHE_CONTROL : SEO_ROUTE_PRIVATE_CACHE_CONTROL;
252
+ }
253
+ export function isForwardedHostTrusted(value) {
254
+ return value === true || value === "true" || value === 1 || value === "1";
255
+ }
256
+ export function missingSiteUrlWarning(routes) {
257
+ const served = [
258
+ routes.sitemap ? "/sitemap.xml" : null,
259
+ routes.robots ? "/robots.txt" : null
260
+ ].filter((path) => !!path);
261
+ if (!served.length) return null;
262
+ return `[nuxt-cms] ${served.join(" and ")} ${served.length > 1 ? "are" : "is"} served but no site URL is set: set cms.site.url (or NUXT_PUBLIC_SITE_URL), otherwise the URLs come from the request host and the responses are sent with Cache-Control: private, no-store.`;
263
+ }
264
+ function isPlainObject(value) {
265
+ return !!value && typeof value === "object" && !Array.isArray(value);
266
+ }
267
+ export function siteUrlErrors(url, at = "cms.site.url") {
268
+ if (typeof url !== "string") return [`${at} must be a string`];
269
+ if (!url.trim()) return [];
270
+ let parsed;
271
+ try {
272
+ parsed = new URL(url.trim());
273
+ } catch {
274
+ return [`${at} must be an absolute URL like https://example.com, got '${url}'`];
275
+ }
276
+ if (parsed.protocol !== "http:" && parsed.protocol !== "https:")
277
+ return [`${at} must use http or https, got '${url}'`];
278
+ if (parsed.search || parsed.hash || url.includes("?") || url.includes("#"))
279
+ return [`${at} cannot hold a query or a hash, got '${url}'`];
280
+ if (parsed.username || parsed.password) return [`${at} cannot hold credentials`];
281
+ return [];
282
+ }
283
+ export function seoOptionErrors(seo, site) {
284
+ const errors = [];
285
+ if (seo !== void 0) {
286
+ if (!isPlainObject(seo)) {
287
+ errors.push("cms.seo must be an object like { sitemap: true, robots: true }");
288
+ } else {
289
+ for (const [key, value] of Object.entries(seo)) {
290
+ if (!SEO_OPTION_KEYS.includes(key))
291
+ errors.push(`cms.seo.${key} is not an option (use ${SEO_OPTION_KEYS.join(", ")})`);
292
+ else if (value !== void 0 && typeof value !== "boolean")
293
+ errors.push(`cms.seo.${key} must be true or false`);
294
+ }
295
+ }
296
+ }
297
+ if (site !== void 0) {
298
+ if (!isPlainObject(site)) {
299
+ errors.push("cms.site must be an object like { url: 'https://example.com' }");
300
+ } else {
301
+ for (const [key, value] of Object.entries(site)) {
302
+ if (!SITE_OPTION_KEYS.includes(key))
303
+ errors.push(`cms.site.${key} is not an option (use ${SITE_OPTION_KEYS.join(", ")})`);
304
+ else if (key === "trustForwardedHost") {
305
+ if (value !== void 0 && typeof value !== "boolean")
306
+ errors.push("cms.site.trustForwardedHost must be true or false");
307
+ } else if (value !== void 0) errors.push(...siteUrlErrors(value));
308
+ }
309
+ }
310
+ }
311
+ return errors;
312
+ }
313
+ function resolveSwitch(key, option, conflicts, route) {
314
+ if (option === false) return { enabled: false, warning: null };
315
+ if (!conflicts.length) return { enabled: true, warning: null };
316
+ const found = conflicts.join(", ");
317
+ if (option === true)
318
+ return {
319
+ enabled: true,
320
+ warning: `[nuxt-cms] cms.seo.${key} is on but ${found} also serves ${route}; only one of them answers. Set cms.seo.${key} to false to keep the other one.`
321
+ };
322
+ return {
323
+ enabled: false,
324
+ warning: `[nuxt-cms] ${found} found, so the cms ${route} is off. Set cms.seo.${key} to true or false to silence this.`
325
+ };
326
+ }
327
+ export function resolveSeoSwitches(seo, conflicts) {
328
+ const sitemap = resolveSwitch("sitemap", seo?.sitemap, conflicts.sitemap, SITEMAP_PATH);
329
+ const robots = resolveSwitch("robots", seo?.robots, conflicts.robots, ROBOTS_PATH);
330
+ return {
331
+ sitemap: sitemap.enabled,
332
+ robots: robots.enabled,
333
+ warnings: [sitemap.warning, robots.warning].filter((warning) => !!warning)
334
+ };
335
+ }
@@ -136,7 +136,8 @@ export function csvCellValue(field, text) {
136
136
  return { error: "Not a boolean (true or false)" };
137
137
  }
138
138
  if (field.type === "tags" && !text.trim().startsWith("[")) return { value: text.split(",") };
139
- if (field.type === "json" || isStringListField(field)) {
139
+ if (field.type === "link" && !text.trim().startsWith("{")) return { value: { url: text.trim() } };
140
+ if (field.type === "json" || field.type === "link" || isStringListField(field)) {
140
141
  try {
141
142
  return { value: JSON.parse(text) };
142
143
  } catch {
@@ -0,0 +1,29 @@
1
+ import type { CmsEntry, CmsI18n, FieldConfig } from './index.js';
2
+ export declare const TRANSLATIONS_COLUMN = "_translations";
3
+ export type TranslationState = 'complete' | 'partial' | 'missing';
4
+ export interface TranslationLocaleProgress {
5
+ filled: number;
6
+ total: number;
7
+ values: number;
8
+ state: TranslationState;
9
+ }
10
+ export type TranslationProgress = Record<string, TranslationLocaleProgress>;
11
+ export interface TranslationChange {
12
+ values: Record<string, unknown>;
13
+ count: number;
14
+ }
15
+ type Values = Record<string, unknown>;
16
+ export declare function isTranslationFilled(field: FieldConfig, value: unknown): boolean;
17
+ export declare function hasTranslatableContent(fields: Record<string, FieldConfig>): boolean;
18
+ export declare function entryHasTranslations(entry: Pick<CmsEntry, 'fields'> & Partial<Pick<CmsEntry, 'kind' | 'overrides'>>): boolean;
19
+ export declare function hasTranslationsColumn(entry: Pick<CmsEntry, 'kind' | 'fields'>, i18n: Pick<CmsI18n, 'locales'>): boolean;
20
+ export declare function translationProgress(fields: Record<string, FieldConfig>, values: Values | null | undefined, i18n: CmsI18n, keys?: readonly string[]): TranslationProgress;
21
+ export declare function translationSummary(progress: TranslationLocaleProgress | undefined): string;
22
+ export interface TranslationCopyOptions {
23
+ from: string;
24
+ to: string;
25
+ overwrite?: boolean;
26
+ }
27
+ export declare function copyTranslations(fields: Record<string, FieldConfig>, values: Values, i18n: CmsI18n, { from, to, overwrite }: TranslationCopyOptions): TranslationChange;
28
+ export declare function clearTranslations(fields: Record<string, FieldConfig>, values: Values, i18n: CmsI18n, locale: string): TranslationChange;
29
+ export {};