@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.
- package/README.md +1 -1
- package/dist/module.d.mts +20 -1
- package/dist/module.json +1 -1
- package/dist/module.mjs +1037 -148
- package/dist/runtime/app/blocks/CmsBlocks.d.vue.ts +1 -1
- package/dist/runtime/app/blocks/CmsBlocks.vue +57 -9
- package/dist/runtime/app/blocks/CmsBlocks.vue.d.ts +1 -1
- package/dist/runtime/app/blocks/CmsField.d.ts +24 -0
- package/dist/runtime/app/blocks/CmsField.js +16 -0
- package/dist/runtime/app/blocks/node.d.ts +37 -0
- package/dist/runtime/app/blocks/node.js +17 -0
- package/dist/runtime/app/blocks/resolve.d.ts +18 -0
- package/dist/runtime/app/blocks/resolve.js +34 -0
- package/dist/runtime/app/components/cms/BlockPicker.d.vue.ts +22 -0
- package/dist/runtime/app/components/cms/BlockPicker.vue +87 -0
- package/dist/runtime/app/components/cms/BlockPicker.vue.d.ts +22 -0
- package/dist/runtime/app/components/cms/BlockPickerPopover.d.vue.ts +38 -0
- package/dist/runtime/app/components/cms/BlockPickerPopover.vue +44 -0
- package/dist/runtime/app/components/cms/BlockPickerPopover.vue.d.ts +38 -0
- package/dist/runtime/app/components/cms/BlockTree.d.vue.ts +29 -0
- package/dist/runtime/app/components/cms/BlockTree.vue +322 -0
- package/dist/runtime/app/components/cms/BlockTree.vue.d.ts +29 -0
- package/dist/runtime/app/components/cms/BlocksField.vue +569 -218
- package/dist/runtime/app/components/cms/BrandMark.vue +7 -13
- package/dist/runtime/app/components/cms/ConfirmGroups.vue +15 -13
- package/dist/runtime/app/components/cms/{BlockPalette.vue.d.ts → EditorHistory.d.vue.ts} +6 -5
- package/dist/runtime/app/components/cms/EditorHistory.vue +34 -0
- package/dist/runtime/app/components/cms/{BlockPalette.d.vue.ts → EditorHistory.vue.d.ts} +6 -5
- package/dist/runtime/app/components/cms/EntryDrawer.d.vue.ts +11 -5
- package/dist/runtime/app/components/cms/EntryDrawer.vue +183 -152
- package/dist/runtime/app/components/cms/EntryDrawer.vue.d.ts +11 -5
- package/dist/runtime/app/components/cms/EntryForm.d.vue.ts +16 -4
- package/dist/runtime/app/components/cms/EntryForm.vue +106 -146
- package/dist/runtime/app/components/cms/EntryForm.vue.d.ts +16 -4
- package/dist/runtime/app/components/cms/FieldInput.vue +10 -2
- package/dist/runtime/app/components/cms/FormSections.d.vue.ts +22 -0
- package/dist/runtime/app/components/cms/FormSections.vue +71 -0
- package/dist/runtime/app/components/cms/FormSections.vue.d.ts +22 -0
- package/dist/runtime/app/components/cms/ImportModal.vue +46 -58
- package/dist/runtime/app/components/cms/LinkField.d.vue.ts +16 -0
- package/dist/runtime/app/components/cms/LinkField.vue +250 -0
- package/dist/runtime/app/components/cms/LinkField.vue.d.ts +16 -0
- package/dist/runtime/app/components/cms/ListFilters.vue +10 -12
- package/dist/runtime/app/components/cms/LocaleSwitch.d.vue.ts +2 -1
- package/dist/runtime/app/components/cms/LocaleSwitch.vue +29 -5
- package/dist/runtime/app/components/cms/LocaleSwitch.vue.d.ts +2 -1
- package/dist/runtime/app/components/cms/MediaDetail.d.vue.ts +2 -0
- package/dist/runtime/app/components/cms/MediaDetail.vue +112 -83
- package/dist/runtime/app/components/cms/MediaDetail.vue.d.ts +2 -0
- package/dist/runtime/app/components/cms/MediaField.vue +35 -25
- package/dist/runtime/app/components/cms/MediaFolderPicker.vue +26 -71
- package/dist/runtime/app/components/cms/MediaGallery.d.vue.ts +1 -0
- package/dist/runtime/app/components/cms/MediaGallery.vue +442 -419
- package/dist/runtime/app/components/cms/MediaGallery.vue.d.ts +1 -0
- package/dist/runtime/app/components/cms/MediaThumb.vue +9 -25
- package/dist/runtime/app/components/cms/MediaUpload.vue +1 -1
- package/dist/runtime/app/components/cms/{BlockOutline.d.vue.ts → NestedBlockList.d.vue.ts} +5 -5
- package/dist/runtime/app/components/cms/NestedBlockList.vue +87 -0
- package/dist/runtime/app/components/cms/{BlockOutline.vue.d.ts → NestedBlockList.vue.d.ts} +5 -5
- package/dist/runtime/app/components/cms/PoweredBy.vue +12 -5
- package/dist/runtime/app/components/cms/PresetModal.d.vue.ts +18 -0
- package/dist/runtime/app/components/cms/PresetModal.vue +70 -0
- package/dist/runtime/app/components/cms/PresetModal.vue.d.ts +18 -0
- package/dist/runtime/app/components/cms/RelationField.vue +2 -8
- package/dist/runtime/app/components/cms/SettingsAccount.vue +60 -71
- package/dist/runtime/app/components/cms/SettingsColumns.vue +47 -69
- package/dist/runtime/app/components/cms/SettingsEmptyAdd.d.vue.ts +13 -0
- package/dist/runtime/app/components/cms/SettingsEmptyAdd.vue +21 -0
- package/dist/runtime/app/components/cms/SettingsEmptyAdd.vue.d.ts +13 -0
- package/dist/runtime/app/components/cms/SettingsEntries.d.vue.ts +13 -0
- package/dist/runtime/app/components/cms/SettingsEntries.vue +50 -0
- package/dist/runtime/app/components/cms/SettingsEntries.vue.d.ts +13 -0
- package/dist/runtime/app/components/cms/SettingsEntry.d.vue.ts +1 -10
- package/dist/runtime/app/components/cms/SettingsEntry.vue +11 -95
- package/dist/runtime/app/components/cms/SettingsEntry.vue.d.ts +1 -10
- package/dist/runtime/app/components/cms/SettingsEntryActions.d.vue.ts +7 -0
- package/dist/runtime/app/components/cms/SettingsEntryActions.vue +42 -0
- package/dist/runtime/app/components/cms/SettingsEntryActions.vue.d.ts +7 -0
- package/dist/runtime/app/components/cms/SettingsEntryTabs.d.vue.ts +7 -0
- package/dist/runtime/app/components/cms/SettingsEntryTabs.vue +21 -0
- package/dist/runtime/app/components/cms/SettingsEntryTabs.vue.d.ts +7 -0
- package/dist/runtime/app/components/cms/SettingsFormAction.d.vue.ts +3 -0
- package/dist/runtime/app/components/cms/SettingsFormAction.vue +17 -0
- package/dist/runtime/app/components/cms/SettingsFormAction.vue.d.ts +3 -0
- package/dist/runtime/app/components/cms/SettingsLayout.vue +18 -14
- package/dist/runtime/app/components/cms/SettingsPresetForm.d.vue.ts +11 -0
- package/dist/runtime/app/components/cms/SettingsPresetForm.vue +60 -0
- package/dist/runtime/app/components/cms/SettingsPresetForm.vue.d.ts +11 -0
- package/dist/runtime/app/components/cms/SettingsPresets.d.vue.ts +13 -0
- package/dist/runtime/app/components/cms/SettingsPresets.vue +65 -0
- package/dist/runtime/app/components/cms/SettingsPresets.vue.d.ts +13 -0
- package/dist/runtime/app/components/cms/SettingsRecordActions.d.vue.ts +32 -0
- package/dist/runtime/app/components/cms/SettingsRecordActions.vue +45 -0
- package/dist/runtime/app/components/cms/SettingsRecordActions.vue.d.ts +32 -0
- package/dist/runtime/app/components/cms/SettingsRedirectActions.d.vue.ts +3 -0
- package/dist/runtime/app/components/cms/SettingsRedirectActions.vue +59 -0
- package/dist/runtime/app/components/cms/SettingsRedirectActions.vue.d.ts +3 -0
- package/dist/runtime/app/components/cms/SettingsRedirectForm.d.vue.ts +11 -0
- package/dist/runtime/app/components/cms/SettingsRedirectForm.vue +77 -0
- package/dist/runtime/app/components/cms/SettingsRedirectForm.vue.d.ts +11 -0
- package/dist/runtime/app/components/cms/SettingsRedirects.d.vue.ts +13 -0
- package/dist/runtime/app/components/cms/SettingsRedirects.vue +117 -0
- package/dist/runtime/app/components/cms/SettingsRedirects.vue.d.ts +13 -0
- package/dist/runtime/app/components/cms/SettingsSecretCard.d.vue.ts +17 -0
- package/dist/runtime/app/components/cms/SettingsSecretCard.vue +43 -0
- package/dist/runtime/app/components/cms/SettingsSecretCard.vue.d.ts +17 -0
- package/dist/runtime/app/components/cms/SettingsSite.d.vue.ts +3 -0
- package/dist/runtime/app/components/cms/SettingsSite.vue +140 -0
- package/dist/runtime/app/components/cms/SettingsSite.vue.d.ts +3 -0
- package/dist/runtime/app/components/cms/SettingsUserCreate.d.vue.ts +8 -0
- package/dist/runtime/app/components/cms/SettingsUserCreate.vue +82 -0
- package/dist/runtime/app/components/cms/SettingsUserCreate.vue.d.ts +8 -0
- package/dist/runtime/app/components/cms/SettingsUserDetail.d.vue.ts +11 -0
- package/dist/runtime/app/components/cms/SettingsUserDetail.vue +179 -0
- package/dist/runtime/app/components/cms/SettingsUserDetail.vue.d.ts +11 -0
- package/dist/runtime/app/components/cms/SettingsUsers.d.vue.ts +9 -6
- package/dist/runtime/app/components/cms/SettingsUsers.vue +88 -234
- package/dist/runtime/app/components/cms/SettingsUsers.vue.d.ts +9 -6
- package/dist/runtime/app/components/cms/SharePreview.d.vue.ts +18 -0
- package/dist/runtime/app/components/cms/SharePreview.vue +219 -0
- package/dist/runtime/app/components/cms/SharePreview.vue.d.ts +18 -0
- package/dist/runtime/app/components/cms/SlugField.vue +5 -3
- package/dist/runtime/app/components/cms/StatusBadge.vue +9 -8
- package/dist/runtime/app/components/cms/TranslationBadges.d.vue.ts +7 -0
- package/dist/runtime/app/components/cms/TranslationBadges.vue +45 -0
- package/dist/runtime/app/components/cms/TranslationBadges.vue.d.ts +7 -0
- package/dist/runtime/app/components/cms/TranslationMenu.d.vue.ts +17 -0
- package/dist/runtime/app/components/cms/TranslationMenu.vue +28 -0
- package/dist/runtime/app/components/cms/TranslationMenu.vue.d.ts +17 -0
- package/dist/runtime/app/components/cms/VisualEditor.d.vue.ts +22 -4
- package/dist/runtime/app/components/cms/VisualEditor.vue +1152 -335
- package/dist/runtime/app/components/cms/VisualEditor.vue.d.ts +22 -4
- package/dist/runtime/app/components/cms/WelcomeModal.vue +32 -50
- package/dist/runtime/app/composables/cms-clipboard.d.ts +8 -0
- package/dist/runtime/app/composables/cms-clipboard.js +38 -0
- package/dist/runtime/app/composables/cms-confirm.d.ts +6 -8
- package/dist/runtime/app/composables/cms-confirm.js +5 -7
- package/dist/runtime/app/composables/cms-entry-disabled.d.ts +5 -1
- package/dist/runtime/app/composables/cms-entry-disabled.js +7 -0
- package/dist/runtime/app/composables/cms-entry-form.d.ts +15 -0
- package/dist/runtime/app/composables/cms-entry-form.js +40 -0
- package/dist/runtime/app/composables/cms-entry-settings.d.ts +30 -0
- package/dist/runtime/app/composables/cms-entry-settings.js +122 -0
- package/dist/runtime/app/composables/cms-entry.d.ts +5 -1
- package/dist/runtime/app/composables/cms-entry.js +36 -11
- package/dist/runtime/app/composables/cms-history.d.ts +10 -0
- package/dist/runtime/app/composables/cms-history.js +24 -0
- package/dist/runtime/app/composables/cms-link-targets.d.ts +10 -0
- package/dist/runtime/app/composables/cms-link-targets.js +40 -0
- package/dist/runtime/app/composables/cms-link-usage.d.ts +1 -0
- package/dist/runtime/app/composables/cms-link-usage.js +45 -0
- package/dist/runtime/app/composables/cms-media-library.d.ts +19 -9
- package/dist/runtime/app/composables/cms-media-library.js +31 -13
- package/dist/runtime/app/composables/cms-media-uploader.js +6 -20
- package/dist/runtime/app/composables/cms-permissions.d.ts +18 -0
- package/dist/runtime/app/composables/cms-permissions.js +54 -0
- package/dist/runtime/app/composables/cms-presets.d.ts +11 -0
- package/dist/runtime/app/composables/cms-presets.js +40 -0
- package/dist/runtime/app/composables/cms-preview-mode.d.ts +4 -0
- package/dist/runtime/app/composables/cms-preview-mode.js +8 -0
- package/dist/runtime/app/composables/cms-query.d.ts +3 -0
- package/dist/runtime/app/composables/cms-query.js +45 -20
- package/dist/runtime/app/composables/cms-record-list.d.ts +31 -0
- package/dist/runtime/app/composables/cms-record-list.js +75 -0
- package/dist/runtime/app/composables/cms-route.d.ts +6 -0
- package/dist/runtime/app/composables/cms-route.js +36 -0
- package/dist/runtime/app/composables/cms-runtime.d.ts +1 -0
- package/dist/runtime/app/composables/cms-save-handoff.d.ts +4 -0
- package/dist/runtime/app/composables/cms-save-handoff.js +19 -0
- package/dist/runtime/app/composables/cms-seo.d.ts +12 -0
- package/dist/runtime/app/composables/cms-seo.js +69 -0
- package/dist/runtime/app/composables/cms-settings-form.d.ts +13 -0
- package/dist/runtime/app/composables/cms-settings-form.js +29 -0
- package/dist/runtime/app/composables/cms-settings-sections.d.ts +26 -0
- package/dist/runtime/app/composables/cms-settings-sections.js +181 -0
- package/dist/runtime/app/composables/cms-settings-stores.d.ts +52 -0
- package/dist/runtime/app/composables/cms-settings-stores.js +156 -0
- package/dist/runtime/app/composables/cms-settings.d.ts +3 -3
- package/dist/runtime/app/composables/cms-settings.js +14 -8
- package/dist/runtime/app/composables/cms-site-disabled.d.ts +7 -0
- package/dist/runtime/app/composables/cms-site-disabled.js +8 -0
- package/dist/runtime/app/composables/cms-site.d.ts +7 -0
- package/dist/runtime/app/composables/cms-site.js +22 -0
- package/dist/runtime/app/composables/cms-toast.d.ts +2 -8
- package/dist/runtime/app/composables/cms-toast.js +3 -9
- package/dist/runtime/app/composables/cms-translation-actions.d.ts +15 -0
- package/dist/runtime/app/composables/cms-translation-actions.js +108 -0
- package/dist/runtime/app/css-url.d.ts +4 -0
- package/dist/runtime/app/image/CmsImage.d.vue.ts +89 -0
- package/dist/runtime/app/image/CmsImage.vue +91 -0
- package/dist/runtime/app/image/CmsImage.vue.d.ts +89 -0
- package/dist/runtime/app/layouts/cms-admin.d.vue.ts +2 -2
- package/dist/runtime/app/layouts/cms-admin.vue +98 -76
- package/dist/runtime/app/layouts/cms-admin.vue.d.ts +2 -2
- package/dist/runtime/app/layouts/cms-editor.vue +7 -2
- package/dist/runtime/app/links/CmsLink.d.vue.ts +18 -0
- package/dist/runtime/app/links/CmsLink.vue +18 -0
- package/dist/runtime/app/links/CmsLink.vue.d.ts +18 -0
- package/dist/runtime/app/middleware/cms-auth.js +13 -1
- package/dist/runtime/app/pages/admin-collection.vue +473 -297
- package/dist/runtime/app/pages/admin-content.vue +190 -53
- package/dist/runtime/app/pages/admin-entry.vue +79 -75
- package/dist/runtime/app/pages/admin-index.vue +18 -5
- package/dist/runtime/app/pages/admin-login.vue +1 -1
- package/dist/runtime/app/pages/admin-logout.vue +1 -1
- package/dist/runtime/app/pages/admin-media.vue +3 -3
- package/dist/runtime/app/pages/admin-preview.vue +112 -24
- package/dist/runtime/app/plugins/cms-field.d.ts +2 -0
- package/dist/runtime/app/plugins/cms-field.js +8 -0
- package/dist/runtime/app/plugins/cms-preview-banner.client.d.ts +2 -0
- package/dist/runtime/app/plugins/cms-preview-banner.client.js +19 -0
- package/dist/runtime/app/plugins/cms-preview.d.ts +2 -0
- package/dist/runtime/app/plugins/cms-preview.js +27 -0
- package/dist/runtime/app/preview/CmsPreviewBanner.d.vue.ts +7 -0
- package/dist/runtime/app/preview/CmsPreviewBanner.vue +63 -0
- package/dist/runtime/app/preview/CmsPreviewBanner.vue.d.ts +7 -0
- package/dist/runtime/app/preview/PreviewOverlay.d.vue.ts +17 -3
- package/dist/runtime/app/preview/PreviewOverlay.vue +629 -166
- package/dist/runtime/app/preview/PreviewOverlay.vue.d.ts +17 -3
- package/dist/runtime/app/preview/field-marker.d.ts +12 -0
- package/dist/runtime/app/preview/field-marker.js +20 -0
- package/dist/runtime/app/preview/inline-text.d.ts +15 -0
- package/dist/runtime/app/preview/inline-text.js +158 -0
- package/dist/runtime/app/utils/block-editor.d.ts +22 -0
- package/dist/runtime/app/utils/block-editor.js +12 -0
- package/dist/runtime/app/utils/keyboard.d.ts +6 -0
- package/dist/runtime/app/utils/keyboard.js +52 -0
- package/dist/runtime/app/utils/redirects.d.ts +6 -0
- package/dist/runtime/app/utils/redirects.js +7 -0
- package/dist/runtime/app/utils/ui.d.ts +8 -0
- package/dist/runtime/app/utils/ui.js +15 -1
- package/dist/runtime/app/utils/users.d.ts +15 -0
- package/dist/runtime/app/utils/users.js +14 -0
- package/dist/runtime/assets/cms.css +1 -1
- package/dist/runtime/generate.js +16 -2
- package/dist/runtime/server/api/collection-export.get.js +3 -2
- package/dist/runtime/server/api/collection-import.post.js +39 -11
- package/dist/runtime/server/api/collection.get.js +27 -9
- package/dist/runtime/server/api/collection.post.js +28 -11
- package/dist/runtime/server/api/collection.put.js +35 -13
- package/dist/runtime/server/api/item.delete.js +19 -7
- package/dist/runtime/server/api/item.get.js +3 -2
- package/dist/runtime/server/api/item.put.js +52 -18
- package/dist/runtime/server/api/link-usage.post.d.ts +5 -0
- package/dist/runtime/server/api/link-usage.post.js +21 -0
- package/dist/runtime/server/api/media-delete.post.js +4 -2
- package/dist/runtime/server/api/media-download.get.js +2 -2
- package/dist/runtime/server/api/media-folder.delete.js +8 -2
- package/dist/runtime/server/api/media-folder.patch.js +10 -2
- package/dist/runtime/server/api/media-folder.post.js +4 -2
- package/dist/runtime/server/api/media-move.post.js +7 -4
- package/dist/runtime/server/api/media-presign.post.js +2 -2
- package/dist/runtime/server/api/media-upload.put.js +2 -2
- package/dist/runtime/server/api/media-usage.post.d.ts +2 -4
- package/dist/runtime/server/api/media-usage.post.js +13 -9
- package/dist/runtime/server/api/media.delete.js +4 -2
- package/dist/runtime/server/api/media.get.js +22 -7
- package/dist/runtime/server/api/media.post.js +4 -2
- package/dist/runtime/server/api/media.put.js +33 -16
- package/dist/runtime/server/api/preset.delete.d.ts +4 -0
- package/dist/runtime/server/api/preset.delete.js +9 -0
- package/dist/runtime/server/api/preset.put.d.ts +3 -0
- package/dist/runtime/server/api/preset.put.js +23 -0
- package/dist/runtime/server/api/presets-field.get.d.ts +3 -0
- package/dist/runtime/server/api/presets-field.get.js +13 -0
- package/dist/runtime/server/api/presets-field.post.d.ts +3 -0
- package/dist/runtime/server/api/presets-field.post.js +36 -0
- package/dist/runtime/server/api/presets.get.d.ts +3 -0
- package/dist/runtime/server/api/presets.get.js +7 -0
- package/dist/runtime/server/api/preview-link.delete.d.ts +4 -0
- package/dist/runtime/server/api/preview-link.delete.js +15 -0
- package/dist/runtime/server/api/preview-links.get.d.ts +3 -0
- package/dist/runtime/server/api/preview-links.get.js +10 -0
- package/dist/runtime/server/api/preview-links.post.d.ts +3 -0
- package/dist/runtime/server/api/preview-links.post.js +17 -0
- package/dist/runtime/server/api/preview.get.d.ts +3 -0
- package/dist/runtime/server/api/preview.get.js +7 -0
- package/dist/runtime/server/api/redirect.delete.d.ts +4 -0
- package/dist/runtime/server/api/redirect.delete.js +10 -0
- package/dist/runtime/server/api/redirect.put.d.ts +3 -0
- package/dist/runtime/server/api/redirect.put.js +8 -0
- package/dist/runtime/server/api/redirects-import.post.d.ts +3 -0
- package/dist/runtime/server/api/redirects-import.post.js +13 -0
- package/dist/runtime/server/api/redirects.get.d.ts +3 -0
- package/dist/runtime/server/api/redirects.get.js +7 -0
- package/dist/runtime/server/api/redirects.post.d.ts +3 -0
- package/dist/runtime/server/api/redirects.post.js +7 -0
- package/dist/runtime/server/api/search.get.js +8 -3
- package/dist/runtime/server/api/settings.delete.js +2 -2
- package/dist/runtime/server/api/settings.get.js +4 -2
- package/dist/runtime/server/api/settings.put.js +2 -2
- package/dist/runtime/server/api/site.get.d.ts +3 -0
- package/dist/runtime/server/api/site.get.js +7 -0
- package/dist/runtime/server/api/site.put.d.ts +3 -0
- package/dist/runtime/server/api/site.put.js +16 -0
- package/dist/runtime/server/api/tags.get.js +3 -2
- package/dist/runtime/server/api/user.delete.js +8 -2
- package/dist/runtime/server/api/user.put.js +14 -4
- package/dist/runtime/server/api/users.get.js +2 -2
- package/dist/runtime/server/api/users.post.js +8 -4
- package/dist/runtime/server/middleware/hidden-site.d.ts +2 -0
- package/dist/runtime/server/middleware/hidden-site.js +8 -0
- package/dist/runtime/server/middleware/preview-links.d.ts +2 -0
- package/dist/runtime/server/middleware/preview-links.js +6 -0
- package/dist/runtime/server/middleware/redirects.d.ts +2 -0
- package/dist/runtime/server/middleware/redirects.js +18 -0
- package/dist/runtime/server/plugins/session-validate.js +4 -1
- package/dist/runtime/server/plugins/webhooks.d.ts +3 -0
- package/dist/runtime/server/plugins/webhooks.js +27 -0
- package/dist/runtime/server/routes/graphql.js +5 -3
- package/dist/runtime/server/routes/robots.d.ts +2 -0
- package/dist/runtime/server/routes/robots.js +16 -0
- package/dist/runtime/server/routes/sitemap.d.ts +2 -0
- package/dist/runtime/server/routes/sitemap.js +67 -0
- package/dist/runtime/server/utils/cached-value.d.ts +5 -0
- package/dist/runtime/server/utils/cached-value.js +24 -0
- package/dist/runtime/server/utils/content-routes.d.ts +5 -0
- package/dist/runtime/server/utils/content-routes.js +29 -0
- package/dist/runtime/server/utils/field-rules.d.ts +19 -0
- package/dist/runtime/server/utils/field-rules.js +72 -0
- package/dist/runtime/server/utils/graphql.d.ts +3 -1
- package/dist/runtime/server/utils/graphql.js +143 -28
- package/dist/runtime/server/utils/hooks.d.ts +14 -0
- package/dist/runtime/server/utils/hooks.js +71 -0
- package/dist/runtime/server/utils/import.d.ts +7 -2
- package/dist/runtime/server/utils/import.js +108 -14
- package/dist/runtime/server/utils/link-usage.d.ts +4 -0
- package/dist/runtime/server/utils/link-usage.js +28 -0
- package/dist/runtime/server/utils/media-references.d.ts +6 -1
- package/dist/runtime/server/utils/media-references.js +49 -20
- package/dist/runtime/server/utils/media-usage.d.ts +2 -0
- package/dist/runtime/server/utils/media-usage.js +5 -3
- package/dist/runtime/server/utils/page-rows.d.ts +2 -0
- package/dist/runtime/server/utils/page-rows.js +42 -29
- package/dist/runtime/server/utils/permissions.d.ts +14 -0
- package/dist/runtime/server/utils/permissions.js +43 -0
- package/dist/runtime/server/utils/presets.d.ts +18 -0
- package/dist/runtime/server/utils/presets.js +68 -0
- package/dist/runtime/server/utils/preview-links.d.ts +207 -0
- package/dist/runtime/server/utils/preview-links.js +161 -0
- package/dist/runtime/server/utils/redirects.d.ts +31 -0
- package/dist/runtime/server/utils/redirects.js +240 -0
- package/dist/runtime/server/utils/registry.js +4 -1
- package/dist/runtime/server/utils/relations.d.ts +8 -0
- package/dist/runtime/server/utils/relations.js +25 -6
- package/dist/runtime/server/utils/require-admin.d.ts +0 -1
- package/dist/runtime/server/utils/require-admin.js +4 -8
- package/dist/runtime/server/utils/search.d.ts +1 -0
- package/dist/runtime/server/utils/search.js +44 -19
- package/dist/runtime/server/utils/site.d.ts +23 -0
- package/dist/runtime/server/utils/site.js +79 -0
- package/dist/runtime/server/utils/sitemap.d.ts +12 -0
- package/dist/runtime/server/utils/sitemap.js +109 -0
- package/dist/runtime/server/utils/user-management.d.ts +4 -0
- package/dist/runtime/server/utils/user-management.js +20 -0
- package/dist/runtime/server/utils/users.d.ts +1 -1
- package/dist/runtime/server/utils/users.js +1 -1
- package/dist/runtime/server/utils/visibility.d.ts +1 -0
- package/dist/runtime/server/utils/visibility.js +6 -1
- package/dist/runtime/server/utils/webhooks.d.ts +24 -0
- package/dist/runtime/server/utils/webhooks.js +90 -0
- package/dist/runtime/shared/block-paths.d.ts +66 -0
- package/dist/runtime/shared/block-paths.js +310 -0
- package/dist/runtime/shared/block-picker.d.ts +18 -0
- package/dist/runtime/shared/block-picker.js +31 -0
- package/dist/runtime/shared/block-signature.d.ts +4 -0
- package/dist/runtime/shared/block-signature.js +46 -0
- package/dist/runtime/shared/clipboard.d.ts +31 -0
- package/dist/runtime/shared/clipboard.js +206 -0
- package/dist/runtime/shared/conditions.d.ts +36 -0
- package/dist/runtime/shared/conditions.js +100 -0
- package/dist/runtime/shared/content-routes.d.ts +42 -0
- package/dist/runtime/shared/content-routes.js +237 -0
- package/dist/runtime/shared/duplicate.js +2 -1
- package/dist/runtime/shared/editor-layout.d.ts +18 -0
- package/dist/runtime/shared/editor-layout.js +9 -0
- package/dist/runtime/shared/field-options.d.ts +21 -0
- package/dist/runtime/shared/field-options.js +90 -0
- package/dist/runtime/shared/graphql-sdl.d.ts +1 -0
- package/dist/runtime/shared/graphql-sdl.js +50 -26
- package/dist/runtime/shared/history.d.ts +27 -0
- package/dist/runtime/shared/history.js +123 -0
- package/dist/runtime/shared/hooks.d.ts +45 -0
- package/dist/runtime/shared/hooks.js +28 -0
- package/dist/runtime/shared/index.d.ts +90 -21
- package/dist/runtime/shared/index.js +121 -37
- package/dist/runtime/shared/inline-text.d.ts +38 -0
- package/dist/runtime/shared/inline-text.js +85 -0
- package/dist/runtime/shared/layout.d.ts +2 -1
- package/dist/runtime/shared/layout.js +3 -0
- package/dist/runtime/shared/links.d.ts +48 -0
- package/dist/runtime/shared/links.js +155 -0
- package/dist/runtime/shared/list-filters.d.ts +2 -0
- package/dist/runtime/shared/list-filters.js +2 -0
- package/dist/runtime/shared/media-focal.d.ts +30 -0
- package/dist/runtime/shared/media-focal.js +52 -0
- package/dist/runtime/shared/migrations-dir.d.ts +14 -0
- package/dist/runtime/shared/migrations-dir.js +48 -2
- package/dist/runtime/shared/presets.d.ts +67 -0
- package/dist/runtime/shared/presets.js +127 -0
- package/dist/runtime/shared/preview-links.d.ts +64 -0
- package/dist/runtime/shared/preview-links.js +54 -0
- package/dist/runtime/shared/preview.d.ts +124 -21
- package/dist/runtime/shared/preview.js +419 -81
- package/dist/runtime/shared/redirects.d.ts +75 -0
- package/dist/runtime/shared/redirects.js +230 -0
- package/dist/runtime/shared/roles.d.ts +57 -0
- package/dist/runtime/shared/roles.js +293 -0
- package/dist/runtime/shared/save-state.d.ts +8 -0
- package/dist/runtime/shared/save-state.js +15 -0
- package/dist/runtime/shared/search.d.ts +16 -1
- package/dist/runtime/shared/search.js +41 -7
- package/dist/runtime/shared/seo.d.ts +167 -0
- package/dist/runtime/shared/seo.js +335 -0
- package/dist/runtime/shared/transfer.js +2 -1
- package/dist/runtime/shared/translations.d.ts +29 -0
- package/dist/runtime/shared/translations.js +123 -0
- package/dist/runtime/shared/users.d.ts +1 -1
- package/dist/runtime/shared/validation.d.ts +23 -1
- package/dist/runtime/shared/validation.js +214 -64
- package/dist/runtime/webhooks.d.ts +33 -0
- package/dist/runtime/webhooks.js +57 -0
- package/dist/types.d.mts +5 -1
- package/package.json +6 -2
- package/dist/runtime/app/components/cms/BlockOutline.vue +0 -88
- package/dist/runtime/app/components/cms/BlockPalette.vue +0 -31
- package/dist/runtime/app/components/cms/SettingsModal.d.vue.ts +0 -12
- package/dist/runtime/app/components/cms/SettingsModal.vue +0 -126
- package/dist/runtime/app/components/cms/SettingsModal.vue.d.ts +0 -12
- package/dist/runtime/app/composables/cms-field-focus.d.ts +0 -4
- package/dist/runtime/app/composables/cms-field-focus.js +0 -20
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { BaseSQLiteDatabase, SQLiteTable } from 'drizzle-orm/sqlite-core';
|
|
2
|
-
import type { CmsEntry, FieldConfig, MediaUsage } from '../../shared/index.js';
|
|
2
|
+
import type { CmsEntry, CmsSiteSettings, FieldConfig, MediaUsage, MediaUsageReport } from '../../shared/index.js';
|
|
3
3
|
export interface MediaReference {
|
|
4
4
|
field: string;
|
|
5
5
|
key: string;
|
|
@@ -11,6 +11,11 @@ export interface MediaUsageSource {
|
|
|
11
11
|
entry: CmsEntry;
|
|
12
12
|
rows: Record<string, unknown>[];
|
|
13
13
|
}
|
|
14
|
+
export declare function usageTitle(entry: CmsEntry, row: Record<string, unknown>): string | null;
|
|
15
|
+
export declare function usageFields(entry: CmsEntry, row: Record<string, unknown>): Record<string, FieldConfig>;
|
|
14
16
|
export declare function collectMediaUsage(sources: MediaUsageSource[], keys: string[]): Record<string, MediaUsage[]>;
|
|
17
|
+
export declare const SITE_MEDIA_USAGE: Omit<MediaUsage, 'field'>;
|
|
18
|
+
export declare function addSiteMediaUsage(usage: Record<string, MediaUsage[]>, settings: Pick<CmsSiteSettings, 'image'>): Record<string, MediaUsage[]>;
|
|
19
|
+
export declare function redactMediaUsage(usage: Record<string, MediaUsage[]>, visible: (usage: MediaUsage) => boolean): MediaUsageReport;
|
|
15
20
|
export declare function assertKnownMedia(references: MediaReference[], lookup: MediaLookup): Promise<void>;
|
|
16
21
|
export declare function mediaKeysInTable(db: Pick<BaseSQLiteDatabase<'sync' | 'async', unknown>, 'select'>, table: SQLiteTable, keys: string[]): Promise<Set<string>>;
|
|
@@ -1,6 +1,14 @@
|
|
|
1
1
|
import { inArray } from "drizzle-orm";
|
|
2
2
|
import { createError } from "h3";
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
CMS_SITE_SETTINGS_KEY,
|
|
5
|
+
PAGE_PATH_FIELD,
|
|
6
|
+
blockReferenceLabel,
|
|
7
|
+
pageFields,
|
|
8
|
+
pageRouteOf,
|
|
9
|
+
selectOptionLabel,
|
|
10
|
+
walkBlocks
|
|
11
|
+
} from "../../shared/index.js";
|
|
4
12
|
const LOOKUP_CHUNK = 90;
|
|
5
13
|
function mediaKeysOf(value) {
|
|
6
14
|
if (typeof value === "string") return value ? [value] : [];
|
|
@@ -12,25 +20,21 @@ function mediaKeysOf(value) {
|
|
|
12
20
|
export function mediaReferences(fields, values) {
|
|
13
21
|
const references = [];
|
|
14
22
|
for (const [key, field] of Object.entries(fields)) {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
continue;
|
|
19
|
-
}
|
|
20
|
-
if (field.type !== "blocks" || !Array.isArray(value)) continue;
|
|
21
|
-
value.forEach((item, index) => {
|
|
22
|
-
const block = item ? field.blocks?.[String(item.type)] : void 0;
|
|
23
|
-
for (const [blockFieldKey, blockField] of Object.entries(block?.fields ?? {})) {
|
|
24
|
-
if (blockField.type !== "media") continue;
|
|
25
|
-
for (const mediaKey of mediaKeysOf(item?.[blockFieldKey])) {
|
|
26
|
-
references.push({ field: `${key}[${index}].${blockFieldKey}`, key: mediaKey });
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
});
|
|
23
|
+
if (field.type !== "media") continue;
|
|
24
|
+
for (const mediaKey of mediaKeysOf(values[key]))
|
|
25
|
+
references.push({ field: key, key: mediaKey });
|
|
30
26
|
}
|
|
27
|
+
walkBlocks(fields, values, ({ item, block, path }) => {
|
|
28
|
+
for (const [blockFieldKey, blockField] of Object.entries(block.fields)) {
|
|
29
|
+
if (blockField.type !== "media") continue;
|
|
30
|
+
for (const mediaKey of mediaKeysOf(item[blockFieldKey])) {
|
|
31
|
+
references.push({ field: blockReferenceLabel(path, blockFieldKey), key: mediaKey });
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
});
|
|
31
35
|
return references;
|
|
32
36
|
}
|
|
33
|
-
function
|
|
37
|
+
export function usageTitle(entry, row) {
|
|
34
38
|
if (entry.kind === "page") {
|
|
35
39
|
const path = row[PAGE_PATH_FIELD];
|
|
36
40
|
return pageRouteOf(entry, String(row.id))?.label ?? (typeof path === "string" ? path : null);
|
|
@@ -48,7 +52,7 @@ function titleOf(entry, row) {
|
|
|
48
52
|
}
|
|
49
53
|
return null;
|
|
50
54
|
}
|
|
51
|
-
function
|
|
55
|
+
export function usageFields(entry, row) {
|
|
52
56
|
const path = row[PAGE_PATH_FIELD];
|
|
53
57
|
return entry.kind === "page" && typeof path === "string" ? pageFields(entry, path) : entry.fields;
|
|
54
58
|
}
|
|
@@ -56,7 +60,7 @@ export function collectMediaUsage(sources, keys) {
|
|
|
56
60
|
const usage = Object.fromEntries(keys.map((key) => [key, []]));
|
|
57
61
|
for (const { name, entry, rows } of sources) {
|
|
58
62
|
for (const row of rows) {
|
|
59
|
-
for (const reference of mediaReferences(
|
|
63
|
+
for (const reference of mediaReferences(usageFields(entry, row), row)) {
|
|
60
64
|
const list = usage[reference.key];
|
|
61
65
|
if (!list) continue;
|
|
62
66
|
list.push({
|
|
@@ -64,7 +68,7 @@ export function collectMediaUsage(sources, keys) {
|
|
|
64
68
|
label: entry.label,
|
|
65
69
|
kind: entry.kind,
|
|
66
70
|
id: entry.kind === "single" ? null : String(row.id),
|
|
67
|
-
title:
|
|
71
|
+
title: usageTitle(entry, row),
|
|
68
72
|
field: reference.field
|
|
69
73
|
});
|
|
70
74
|
}
|
|
@@ -72,6 +76,31 @@ export function collectMediaUsage(sources, keys) {
|
|
|
72
76
|
}
|
|
73
77
|
return usage;
|
|
74
78
|
}
|
|
79
|
+
export const SITE_MEDIA_USAGE = {
|
|
80
|
+
collection: CMS_SITE_SETTINGS_KEY,
|
|
81
|
+
label: "Settings",
|
|
82
|
+
kind: "site",
|
|
83
|
+
id: null,
|
|
84
|
+
title: "Site settings"
|
|
85
|
+
};
|
|
86
|
+
export function addSiteMediaUsage(usage, settings) {
|
|
87
|
+
const list = settings.image ? usage[settings.image] : void 0;
|
|
88
|
+
if (list) list.push({ ...SITE_MEDIA_USAGE, field: "Share image" });
|
|
89
|
+
return usage;
|
|
90
|
+
}
|
|
91
|
+
export function redactMediaUsage(usage, visible) {
|
|
92
|
+
const report = { usage: {}, hidden: {} };
|
|
93
|
+
for (const [key, list] of Object.entries(usage)) {
|
|
94
|
+
const hidden = /* @__PURE__ */ new Set();
|
|
95
|
+
report.usage[key] = list.filter((item) => {
|
|
96
|
+
if (visible(item)) return true;
|
|
97
|
+
hidden.add(`${item.collection}\0${item.id ?? ""}`);
|
|
98
|
+
return false;
|
|
99
|
+
});
|
|
100
|
+
report.hidden[key] = hidden.size;
|
|
101
|
+
}
|
|
102
|
+
return report;
|
|
103
|
+
}
|
|
75
104
|
export async function assertKnownMedia(references, lookup) {
|
|
76
105
|
if (!references.length) return;
|
|
77
106
|
const known = await lookup([...new Set(references.map((reference) => reference.key))]);
|
|
@@ -1,2 +1,4 @@
|
|
|
1
1
|
import type { MediaUsage } from '../../shared/index.js';
|
|
2
|
+
import type { MediaUsageSource } from './media-references.js';
|
|
3
|
+
export declare function usageSources(include?: (name: string) => boolean): Promise<MediaUsageSource[]>;
|
|
2
4
|
export declare function loadMediaUsage(keys: string[]): Promise<Record<string, MediaUsage[]>>;
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import cmsConfig from "#cms-config";
|
|
2
2
|
import { useDb } from "#cms-db";
|
|
3
|
-
import { collectMediaUsage } from "./media-references.js";
|
|
3
|
+
import { addSiteMediaUsage, collectMediaUsage } from "./media-references.js";
|
|
4
4
|
import { readPages } from "./page-storage.js";
|
|
5
5
|
import { decodeRows, resolveTable } from "./registry.js";
|
|
6
|
-
|
|
6
|
+
import { readSiteSettings } from "./site.js";
|
|
7
|
+
export async function usageSources(include = () => true) {
|
|
7
8
|
const sources = [];
|
|
8
9
|
for (const [name, entry] of Object.entries(cmsConfig)) {
|
|
10
|
+
if (!include(name)) continue;
|
|
9
11
|
const table = resolveTable(name);
|
|
10
12
|
if (!table) continue;
|
|
11
13
|
const rows = entry.kind === "page" ? await readPages(name, entry, table) : decodeRows(entry, await useDb().select().from(table));
|
|
@@ -14,5 +16,5 @@ async function usageSources() {
|
|
|
14
16
|
return sources;
|
|
15
17
|
}
|
|
16
18
|
export async function loadMediaUsage(keys) {
|
|
17
|
-
return collectMediaUsage(await usageSources(), keys);
|
|
19
|
+
return addSiteMediaUsage(collectMediaUsage(await usageSources(), keys), await readSiteSettings());
|
|
18
20
|
}
|
|
@@ -26,10 +26,12 @@ export interface EncodedPage {
|
|
|
26
26
|
media: PageMediaRow[];
|
|
27
27
|
fieldKeys: string[];
|
|
28
28
|
mediaKeys: string[];
|
|
29
|
+
blockPrefixes: string[];
|
|
29
30
|
}
|
|
30
31
|
type Row = Record<string, unknown>;
|
|
31
32
|
export declare const PAGE_BLOCK_TYPE_KEY = "_type";
|
|
32
33
|
export declare function pageBlockKey(fieldKey: string, blockFieldKey: string): string;
|
|
34
|
+
export declare function pageBlockPrefix(fieldKey: string): string;
|
|
33
35
|
export declare function encodePageRows(entry: CmsEntry, pageId: string, values: Row): EncodedPage;
|
|
34
36
|
export declare function decodePageRow(entry: CmsEntry, row: Row): Row;
|
|
35
37
|
export declare function decodePageRows(entry: CmsEntry, rows: Row[]): Row[];
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import { and, eq, getTableColumns, getTableName, inArray, sql } from "drizzle-orm";
|
|
1
|
+
import { and, eq, getTableColumns, getTableName, inArray, or, sql } from "drizzle-orm";
|
|
2
2
|
import {
|
|
3
|
+
BLOCK_HIDDEN_KEY,
|
|
3
4
|
PAGE_PATH_FIELD,
|
|
5
|
+
declaresHiddenField,
|
|
4
6
|
isMultiSelect,
|
|
5
7
|
isTranslatableField,
|
|
6
8
|
isTranslatableMediaField,
|
|
@@ -49,21 +51,19 @@ function decodeBlockMedia(field, raw) {
|
|
|
49
51
|
export function pageBlockKey(fieldKey, blockFieldKey) {
|
|
50
52
|
return `${fieldKey}.${blockFieldKey}`;
|
|
51
53
|
}
|
|
52
|
-
function
|
|
53
|
-
|
|
54
|
-
const media = /* @__PURE__ */ new Set();
|
|
55
|
-
for (const block of Object.values(field.blocks ?? {})) {
|
|
56
|
-
for (const [blockFieldKey, blockField] of Object.entries(block.fields)) {
|
|
57
|
-
const blockKey = pageBlockKey(key, blockFieldKey);
|
|
58
|
-
if (blockField.type === "media") media.add(blockKey);
|
|
59
|
-
else fields.add(blockKey);
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
return { fields: [...fields], media: [...media] };
|
|
54
|
+
export function pageBlockPrefix(fieldKey) {
|
|
55
|
+
return pageBlockKey(fieldKey, "");
|
|
63
56
|
}
|
|
64
57
|
export function encodePageRows(entry, pageId, values) {
|
|
65
58
|
const rowFields = pageRowFields(entry);
|
|
66
|
-
const encoded = {
|
|
59
|
+
const encoded = {
|
|
60
|
+
columns: {},
|
|
61
|
+
fields: [],
|
|
62
|
+
media: [],
|
|
63
|
+
fieldKeys: [],
|
|
64
|
+
mediaKeys: [],
|
|
65
|
+
blockPrefixes: []
|
|
66
|
+
};
|
|
67
67
|
const pushField = (key, position, value) => encoded.fields.push({ pageId, key, position, value });
|
|
68
68
|
const pushMedia = (key, position, value) => encoded.media.push({ pageId, key, position, mediaKey: encodeMedia(value) });
|
|
69
69
|
for (const [key, value] of Object.entries(values)) {
|
|
@@ -73,21 +73,22 @@ export function encodePageRows(entry, pageId, values) {
|
|
|
73
73
|
continue;
|
|
74
74
|
}
|
|
75
75
|
if (field.type === "blocks") {
|
|
76
|
-
|
|
77
|
-
encoded.fieldKeys.push(...owned.fields);
|
|
78
|
-
encoded.mediaKeys.push(...owned.media);
|
|
76
|
+
encoded.blockPrefixes.push(pageBlockPrefix(key));
|
|
79
77
|
if (!Array.isArray(value)) continue;
|
|
80
78
|
value.forEach((item, position) => {
|
|
81
79
|
const type = String(item.type);
|
|
82
80
|
const block = field.blocks?.[type];
|
|
83
81
|
pushField(pageBlockKey(key, PAGE_BLOCK_TYPE_KEY), position, type);
|
|
84
|
-
for (const [blockFieldKey,
|
|
85
|
-
|
|
86
|
-
|
|
82
|
+
for (const [blockFieldKey, blockField] of Object.entries(block?.fields ?? {})) {
|
|
83
|
+
const blockValue = item[blockFieldKey];
|
|
84
|
+
if (blockValue == null) continue;
|
|
87
85
|
const blockKey = pageBlockKey(key, blockFieldKey);
|
|
88
|
-
if (blockField
|
|
86
|
+
if (blockField.type === "media") pushMedia(blockKey, position, blockValue);
|
|
89
87
|
else pushField(blockKey, position, encodeValue(blockField, blockValue));
|
|
90
88
|
}
|
|
89
|
+
const hidden = item[BLOCK_HIDDEN_KEY];
|
|
90
|
+
if (!declaresHiddenField(block) && typeof hidden === "boolean")
|
|
91
|
+
pushField(pageBlockKey(key, BLOCK_HIDDEN_KEY), position, JSON.stringify(hidden));
|
|
91
92
|
});
|
|
92
93
|
continue;
|
|
93
94
|
}
|
|
@@ -136,6 +137,10 @@ function decodeBlocks(key, field, fields, media) {
|
|
|
136
137
|
const raw = fields.get(blockKey)?.get(position);
|
|
137
138
|
item[blockFieldKey] = raw == null ? null : decodeValue(blockField, raw);
|
|
138
139
|
}
|
|
140
|
+
if (!declaresHiddenField(field.blocks?.[type])) {
|
|
141
|
+
const hidden = fields.get(pageBlockKey(key, BLOCK_HIDDEN_KEY))?.get(position);
|
|
142
|
+
if (hidden === "true" || hidden === "false") item[BLOCK_HIDDEN_KEY] = hidden === "true";
|
|
143
|
+
}
|
|
139
144
|
return item;
|
|
140
145
|
});
|
|
141
146
|
}
|
|
@@ -193,6 +198,16 @@ function chunks(items, size) {
|
|
|
193
198
|
}
|
|
194
199
|
return out;
|
|
195
200
|
}
|
|
201
|
+
function ownedRowConditions(key, keys, prefixes) {
|
|
202
|
+
const prefixed = prefixes.map(
|
|
203
|
+
(prefix) => sql`substr(${key}, 1, ${sql.raw(String(prefix.length))}) = ${prefix}`
|
|
204
|
+
);
|
|
205
|
+
const groups = chunks(keys, KEY_CHUNK);
|
|
206
|
+
if (!groups.length) return prefixed.length ? [or(...prefixed)] : [];
|
|
207
|
+
return groups.map(
|
|
208
|
+
(group, index) => index === 0 && prefixed.length ? or(inArray(key, group), ...prefixed) : inArray(key, group)
|
|
209
|
+
);
|
|
210
|
+
}
|
|
196
211
|
export function pageWriteStatements(db, dialect, tables, entry, route, values) {
|
|
197
212
|
const encoded = encodePageRows(entry, route.key, values);
|
|
198
213
|
const pageId = columnsOf(tables.page).id;
|
|
@@ -202,15 +217,13 @@ export function pageWriteStatements(db, dialect, tables, entry, route, values) {
|
|
|
202
217
|
const statements = [
|
|
203
218
|
db.insert(tables.page).values({ ...set, id: route.key, [PAGE_PATH_FIELD]: route.path }).onConflictDoUpdate({ target: pageId, set })
|
|
204
219
|
];
|
|
205
|
-
for (const keys of
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
db.delete(tables.media).where(and(eq(mediaColumns.pageId, route.key), inArray(mediaColumns.key, keys)))
|
|
213
|
-
);
|
|
220
|
+
for (const [table, columns, keys] of [
|
|
221
|
+
[tables.fields, fieldColumns, encoded.fieldKeys],
|
|
222
|
+
[tables.media, mediaColumns, encoded.mediaKeys]
|
|
223
|
+
]) {
|
|
224
|
+
for (const condition of ownedRowConditions(columns.key, keys, encoded.blockPrefixes)) {
|
|
225
|
+
statements.push(db.delete(table).where(and(eq(columns.pageId, route.key), condition)));
|
|
226
|
+
}
|
|
214
227
|
}
|
|
215
228
|
for (const rows of chunks(encoded.fields, INSERT_CHUNK)) {
|
|
216
229
|
statements.push(db.insert(tables.fields).values(rows));
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { H3Event } from 'h3';
|
|
2
|
+
import type { CmsEntry, CmsSessionUser } from '../../shared/index.js';
|
|
3
|
+
import type { CmsAccess } from '../../shared/roles.js';
|
|
4
|
+
export interface CmsAuthorized {
|
|
5
|
+
user: CmsSessionUser;
|
|
6
|
+
access: CmsAccess;
|
|
7
|
+
}
|
|
8
|
+
export declare function cmsAccessFor(role: string | null | undefined): CmsAccess;
|
|
9
|
+
export declare function forbidden(message: string): never;
|
|
10
|
+
export declare function assertCmsPermission(access: CmsAccess, permission: string): void;
|
|
11
|
+
export declare function requireCmsAccess(event: H3Event): Promise<CmsAuthorized>;
|
|
12
|
+
export declare function requireCmsPermission(event: H3Event, permission: string): Promise<CmsAuthorized>;
|
|
13
|
+
export declare function assertDeleteAllowed(access: CmsAccess, name: string, entry: Pick<CmsEntry, 'drafts'>, status: unknown): void;
|
|
14
|
+
export declare function assertPublishAllowed(access: CmsAccess, name: string, entry: Pick<CmsEntry, 'drafts'>, previous: unknown, next: unknown): void;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { createError } from "h3";
|
|
2
|
+
import cmsConfig from "#cms-config";
|
|
3
|
+
import cmsRoles from "#cms-roles";
|
|
4
|
+
import {
|
|
5
|
+
can,
|
|
6
|
+
deletePermissionError,
|
|
7
|
+
publishPermissionError,
|
|
8
|
+
resolveCmsAccess
|
|
9
|
+
} from "../../shared/roles.js";
|
|
10
|
+
import { requireAdmin } from "./require-admin.js";
|
|
11
|
+
export function cmsAccessFor(role) {
|
|
12
|
+
return resolveCmsAccess(role, cmsRoles, cmsConfig);
|
|
13
|
+
}
|
|
14
|
+
export function forbidden(message) {
|
|
15
|
+
throw createError({ statusCode: 403, statusMessage: message });
|
|
16
|
+
}
|
|
17
|
+
export function assertCmsPermission(access, permission) {
|
|
18
|
+
if (can(access, permission)) return;
|
|
19
|
+
if (!access.known) forbidden(`Your role '${access.role}' no longer exists`);
|
|
20
|
+
forbidden(`Missing permission: ${permission}`);
|
|
21
|
+
}
|
|
22
|
+
export async function requireCmsAccess(event) {
|
|
23
|
+
const cached = event.context.cmsAuthorized;
|
|
24
|
+
if (cached) return cached;
|
|
25
|
+
const user = await requireAdmin(event);
|
|
26
|
+
const authorized = { user, access: cmsAccessFor(user.role) };
|
|
27
|
+
event.context.cmsAuthorized = authorized;
|
|
28
|
+
return authorized;
|
|
29
|
+
}
|
|
30
|
+
export async function requireCmsPermission(event, permission) {
|
|
31
|
+
const authorized = await requireCmsAccess(event);
|
|
32
|
+
assertCmsPermission(authorized.access, permission);
|
|
33
|
+
return authorized;
|
|
34
|
+
}
|
|
35
|
+
export function assertDeleteAllowed(access, name, entry, status) {
|
|
36
|
+
assertCmsPermission(access, `${name}.delete`);
|
|
37
|
+
const message = deletePermissionError(access, name, entry, status);
|
|
38
|
+
if (message) forbidden(message);
|
|
39
|
+
}
|
|
40
|
+
export function assertPublishAllowed(access, name, entry, previous, next) {
|
|
41
|
+
const message = publishPermissionError(access, name, entry, previous, next);
|
|
42
|
+
if (message) forbidden(message);
|
|
43
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { H3Event } from 'h3';
|
|
2
|
+
import type { CmsSessionUser, FieldConfig } from '../../shared/index.js';
|
|
3
|
+
import type { CmsBlockPreset, CmsPresetAction } from '../../shared/presets.js';
|
|
4
|
+
import type { CmsAccess } from '../../shared/roles.js';
|
|
5
|
+
export declare function requirePresetAccess(event: H3Event, action: CmsPresetAction): Promise<{
|
|
6
|
+
user: CmsSessionUser;
|
|
7
|
+
access: CmsAccess;
|
|
8
|
+
}>;
|
|
9
|
+
export declare function presetBlocksField(event: H3Event): {
|
|
10
|
+
source: string;
|
|
11
|
+
field: FieldConfig;
|
|
12
|
+
};
|
|
13
|
+
export declare function presetIdParam(event: H3Event): string;
|
|
14
|
+
export declare function readPresetBody(event: H3Event): Promise<unknown>;
|
|
15
|
+
export declare function readPresets(): Promise<CmsBlockPreset[]>;
|
|
16
|
+
export declare function readPreset(id: string): Promise<CmsBlockPreset>;
|
|
17
|
+
export declare function writePreset(preset: CmsBlockPreset): Promise<void>;
|
|
18
|
+
export declare function deletePreset(id: string): Promise<void>;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { createError, getRequestHeader, getRouterParam, readRawBody } from "h3";
|
|
2
|
+
import { eq, like } from "drizzle-orm";
|
|
3
|
+
import { useDb } from "#cms-db";
|
|
4
|
+
import { cms_settings } from "#cms-tables";
|
|
5
|
+
import { blocksFieldAtSchemaPath, entryFieldsFor } from "../../shared/index.js";
|
|
6
|
+
import {
|
|
7
|
+
CMS_PRESET_KEY_PREFIX,
|
|
8
|
+
CMS_PRESET_MAX_BYTES,
|
|
9
|
+
parseStoredPreset,
|
|
10
|
+
presetKey,
|
|
11
|
+
presetPermission
|
|
12
|
+
} from "../../shared/presets.js";
|
|
13
|
+
import { getRegistryEntry } from "./registry.js";
|
|
14
|
+
import { assertCmsPermission, requireCmsAccess } from "./permissions.js";
|
|
15
|
+
const PRESET_ID = /^preset_[A-Za-z0-9]{1,64}$/;
|
|
16
|
+
export async function requirePresetAccess(event, action) {
|
|
17
|
+
const { user, access } = await requireCmsAccess(event);
|
|
18
|
+
assertCmsPermission(access, presetPermission(action, getRouterParam(event, "collection") ?? ""));
|
|
19
|
+
return { user, access };
|
|
20
|
+
}
|
|
21
|
+
export function presetBlocksField(event) {
|
|
22
|
+
const { name, entry } = getRegistryEntry(event);
|
|
23
|
+
const key = getRouterParam(event, "field") ?? "";
|
|
24
|
+
const field = blocksFieldAtSchemaPath(entryFieldsFor(entry), key);
|
|
25
|
+
if (!field) {
|
|
26
|
+
throw createError({ statusCode: 404, statusMessage: `Unknown blocks field: ${key}` });
|
|
27
|
+
}
|
|
28
|
+
return { source: `${name}.${key}`, field };
|
|
29
|
+
}
|
|
30
|
+
export function presetIdParam(event) {
|
|
31
|
+
const id = getRouterParam(event, "id") ?? "";
|
|
32
|
+
if (!PRESET_ID.test(id)) throw createError({ statusCode: 404, statusMessage: "Unknown preset" });
|
|
33
|
+
return id;
|
|
34
|
+
}
|
|
35
|
+
export async function readPresetBody(event) {
|
|
36
|
+
const tooLarge = () => createError({ statusCode: 413, statusMessage: "The preset is too large" });
|
|
37
|
+
if (Number(getRequestHeader(event, "content-length") ?? 0) > CMS_PRESET_MAX_BYTES)
|
|
38
|
+
throw tooLarge();
|
|
39
|
+
const text = await readRawBody(event, "utf8") ?? "";
|
|
40
|
+
if (new TextEncoder().encode(text).length > CMS_PRESET_MAX_BYTES) throw tooLarge();
|
|
41
|
+
try {
|
|
42
|
+
return JSON.parse(text);
|
|
43
|
+
} catch {
|
|
44
|
+
throw createError({ statusCode: 400, statusMessage: "Invalid JSON body" });
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
export async function readPresets() {
|
|
48
|
+
const rows = await useDb().select().from(cms_settings).where(like(cms_settings.key, `${CMS_PRESET_KEY_PREFIX}%`));
|
|
49
|
+
return rows.flatMap((row) => {
|
|
50
|
+
const preset = parseStoredPreset(row.value);
|
|
51
|
+
return preset && presetKey(preset.id) === row.key ? [preset] : [];
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
export async function readPreset(id) {
|
|
55
|
+
const [row] = await useDb().select().from(cms_settings).where(eq(cms_settings.key, presetKey(id)));
|
|
56
|
+
const preset = row ? parseStoredPreset(row.value) : null;
|
|
57
|
+
if (!preset) throw createError({ statusCode: 404, statusMessage: "Unknown preset" });
|
|
58
|
+
return preset;
|
|
59
|
+
}
|
|
60
|
+
export async function writePreset(preset) {
|
|
61
|
+
const key = presetKey(preset.id);
|
|
62
|
+
const value = JSON.stringify(preset);
|
|
63
|
+
const updatedAt = preset.updatedAt;
|
|
64
|
+
await useDb().insert(cms_settings).values({ key, value, updatedAt }).onConflictDoUpdate({ target: cms_settings.key, set: { value, updatedAt } });
|
|
65
|
+
}
|
|
66
|
+
export async function deletePreset(id) {
|
|
67
|
+
await useDb().delete(cms_settings).where(eq(cms_settings.key, presetKey(id)));
|
|
68
|
+
}
|
|
@@ -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>;
|