katecms 0.0.0-stage → 1.0.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -3
- package/dist/module.d.mts +93 -0
- package/dist/module.json +9 -0
- package/dist/module.mjs +579 -0
- package/dist/runtime/assets/img/katecms-logo.svg +17 -0
- package/dist/runtime/composables/getCollection.d.ts +62 -0
- package/dist/runtime/composables/getCollection.js +167 -0
- package/dist/runtime/composables/getOptions.d.ts +22 -0
- package/dist/runtime/composables/getOptions.js +22 -0
- package/dist/runtime/composables/getQueryCollection.d.ts +95 -0
- package/dist/runtime/composables/getQueryCollection.js +199 -0
- package/dist/runtime/composables/getTerms.d.ts +79 -0
- package/dist/runtime/composables/getTerms.js +148 -0
- package/dist/runtime/composables/useAuth.d.ts +14 -0
- package/dist/runtime/composables/useAuth.js +33 -0
- package/dist/runtime/composables/useAuthCooldown.d.ts +6 -0
- package/dist/runtime/composables/useAuthCooldown.js +44 -0
- package/dist/runtime/composables/useCmsPaths.d.ts +15 -0
- package/dist/runtime/composables/useCmsPaths.js +21 -0
- package/dist/runtime/composables/useKateCmsExtensions.d.ts +49 -0
- package/dist/runtime/composables/useKateCmsExtensions.js +29 -0
- package/dist/runtime/composables/useMediaLibrary.d.ts +84 -0
- package/dist/runtime/composables/useMediaLibrary.js +140 -0
- package/dist/runtime/composables/useMenuAccess.d.ts +8 -0
- package/dist/runtime/composables/useMenuAccess.js +16 -0
- package/dist/runtime/internal/admin/AdminHeader.d.vue.ts +24 -0
- package/dist/runtime/internal/admin/AdminHeader.vue +91 -0
- package/dist/runtime/internal/admin/AdminHeader.vue.d.ts +24 -0
- package/dist/runtime/internal/admin/AppMenu.d.vue.ts +3 -0
- package/dist/runtime/internal/admin/AppMenu.vue +244 -0
- package/dist/runtime/internal/admin/AppMenu.vue.d.ts +3 -0
- package/dist/runtime/internal/admin/AppUser.d.vue.ts +3 -0
- package/dist/runtime/internal/admin/AppUser.vue +227 -0
- package/dist/runtime/internal/admin/AppUser.vue.d.ts +3 -0
- package/dist/runtime/internal/admin/CollectionEntryForm.d.vue.ts +41 -0
- package/dist/runtime/internal/admin/CollectionEntryForm.vue +916 -0
- package/dist/runtime/internal/admin/CollectionEntryForm.vue.d.ts +41 -0
- package/dist/runtime/internal/admin/ConfirmDialog.d.vue.ts +28 -0
- package/dist/runtime/internal/admin/ConfirmDialog.vue +136 -0
- package/dist/runtime/internal/admin/ConfirmDialog.vue.d.ts +28 -0
- package/dist/runtime/internal/admin/DictionaryTermForm.d.vue.ts +33 -0
- package/dist/runtime/internal/admin/DictionaryTermForm.vue +328 -0
- package/dist/runtime/internal/admin/DictionaryTermForm.vue.d.ts +33 -0
- package/dist/runtime/internal/admin/EntryRevisions.d.vue.ts +15 -0
- package/dist/runtime/internal/admin/EntryRevisions.vue +125 -0
- package/dist/runtime/internal/admin/EntryRevisions.vue.d.ts +15 -0
- package/dist/runtime/internal/admin/MediaLibraryFilters.d.vue.ts +16 -0
- package/dist/runtime/internal/admin/MediaLibraryFilters.vue +153 -0
- package/dist/runtime/internal/admin/MediaLibraryFilters.vue.d.ts +16 -0
- package/dist/runtime/internal/admin/MediaLibraryModal.d.vue.ts +65 -0
- package/dist/runtime/internal/admin/MediaLibraryModal.vue +451 -0
- package/dist/runtime/internal/admin/MediaLibraryModal.vue.d.ts +65 -0
- package/dist/runtime/internal/admin/OptionPageForm.d.vue.ts +26 -0
- package/dist/runtime/internal/admin/OptionPageForm.vue +222 -0
- package/dist/runtime/internal/admin/OptionPageForm.vue.d.ts +26 -0
- package/dist/runtime/internal/admin/UserAvatarField.d.vue.ts +12 -0
- package/dist/runtime/internal/admin/UserAvatarField.vue +305 -0
- package/dist/runtime/internal/admin/UserAvatarField.vue.d.ts +12 -0
- package/dist/runtime/internal/fields/AccordionField.d.vue.ts +0 -0
- package/dist/runtime/internal/fields/AccordionField.vue +220 -0
- package/dist/runtime/internal/fields/AccordionField.vue.d.ts +0 -0
- package/dist/runtime/internal/fields/ButtonGroupField.d.vue.ts +0 -0
- package/dist/runtime/internal/fields/ButtonGroupField.vue +109 -0
- package/dist/runtime/internal/fields/ButtonGroupField.vue.d.ts +0 -0
- package/dist/runtime/internal/fields/CheckboxField.d.vue.ts +0 -0
- package/dist/runtime/internal/fields/CheckboxField.vue +190 -0
- package/dist/runtime/internal/fields/CheckboxField.vue.d.ts +0 -0
- package/dist/runtime/internal/fields/ColorPickerField.d.vue.ts +0 -0
- package/dist/runtime/internal/fields/ColorPickerField.vue +791 -0
- package/dist/runtime/internal/fields/ColorPickerField.vue.d.ts +0 -0
- package/dist/runtime/internal/fields/DatePickerField.d.vue.ts +0 -0
- package/dist/runtime/internal/fields/DatePickerField.vue +26 -0
- package/dist/runtime/internal/fields/DatePickerField.vue.d.ts +0 -0
- package/dist/runtime/internal/fields/DateTimePickerField.d.vue.ts +0 -0
- package/dist/runtime/internal/fields/DateTimePickerField.vue +26 -0
- package/dist/runtime/internal/fields/DateTimePickerField.vue.d.ts +0 -0
- package/dist/runtime/internal/fields/DictionaryField.d.vue.ts +0 -0
- package/dist/runtime/internal/fields/DictionaryField.vue +345 -0
- package/dist/runtime/internal/fields/DictionaryField.vue.d.ts +0 -0
- package/dist/runtime/internal/fields/EmailField.d.vue.ts +0 -0
- package/dist/runtime/internal/fields/EmailField.vue +21 -0
- package/dist/runtime/internal/fields/EmailField.vue.d.ts +0 -0
- package/dist/runtime/internal/fields/FileField.d.vue.ts +0 -0
- package/dist/runtime/internal/fields/FileField.vue +408 -0
- package/dist/runtime/internal/fields/FileField.vue.d.ts +0 -0
- package/dist/runtime/internal/fields/FlexibleContentField.d.vue.ts +0 -0
- package/dist/runtime/internal/fields/FlexibleContentField.vue +1114 -0
- package/dist/runtime/internal/fields/FlexibleContentField.vue.d.ts +0 -0
- package/dist/runtime/internal/fields/GalleryField.d.vue.ts +0 -0
- package/dist/runtime/internal/fields/GalleryField.vue +584 -0
- package/dist/runtime/internal/fields/GalleryField.vue.d.ts +0 -0
- package/dist/runtime/internal/fields/GroupField.d.vue.ts +0 -0
- package/dist/runtime/internal/fields/GroupField.vue +111 -0
- package/dist/runtime/internal/fields/GroupField.vue.d.ts +0 -0
- package/dist/runtime/internal/fields/ImageField.d.vue.ts +0 -0
- package/dist/runtime/internal/fields/ImageField.vue +638 -0
- package/dist/runtime/internal/fields/ImageField.vue.d.ts +0 -0
- package/dist/runtime/internal/fields/ImageSelectField.d.vue.ts +0 -0
- package/dist/runtime/internal/fields/ImageSelectField.vue +179 -0
- package/dist/runtime/internal/fields/ImageSelectField.vue.d.ts +0 -0
- package/dist/runtime/internal/fields/LinkField.d.vue.ts +0 -0
- package/dist/runtime/internal/fields/LinkField.vue +303 -0
- package/dist/runtime/internal/fields/LinkField.vue.d.ts +0 -0
- package/dist/runtime/internal/fields/NumberField.d.vue.ts +0 -0
- package/dist/runtime/internal/fields/NumberField.vue +25 -0
- package/dist/runtime/internal/fields/NumberField.vue.d.ts +0 -0
- package/dist/runtime/internal/fields/OembedField.d.vue.ts +0 -0
- package/dist/runtime/internal/fields/OembedField.vue +161 -0
- package/dist/runtime/internal/fields/OembedField.vue.d.ts +0 -0
- package/dist/runtime/internal/fields/OpenStreetMapField.d.vue.ts +0 -0
- package/dist/runtime/internal/fields/OpenStreetMapField.vue +1502 -0
- package/dist/runtime/internal/fields/OpenStreetMapField.vue.d.ts +0 -0
- package/dist/runtime/internal/fields/PageLinkField.d.vue.ts +0 -0
- package/dist/runtime/internal/fields/PageLinkField.vue +153 -0
- package/dist/runtime/internal/fields/PageLinkField.vue.d.ts +0 -0
- package/dist/runtime/internal/fields/PasswordField.d.vue.ts +0 -0
- package/dist/runtime/internal/fields/PasswordField.vue +108 -0
- package/dist/runtime/internal/fields/PasswordField.vue.d.ts +0 -0
- package/dist/runtime/internal/fields/PostObjectField.d.vue.ts +0 -0
- package/dist/runtime/internal/fields/PostObjectField.vue +151 -0
- package/dist/runtime/internal/fields/PostObjectField.vue.d.ts +0 -0
- package/dist/runtime/internal/fields/RadioField.d.vue.ts +0 -0
- package/dist/runtime/internal/fields/RadioField.vue +163 -0
- package/dist/runtime/internal/fields/RadioField.vue.d.ts +0 -0
- package/dist/runtime/internal/fields/RangeField.d.vue.ts +0 -0
- package/dist/runtime/internal/fields/RangeField.vue +48 -0
- package/dist/runtime/internal/fields/RangeField.vue.d.ts +0 -0
- package/dist/runtime/internal/fields/RelationshipField.d.vue.ts +0 -0
- package/dist/runtime/internal/fields/RelationshipField.vue +525 -0
- package/dist/runtime/internal/fields/RelationshipField.vue.d.ts +0 -0
- package/dist/runtime/internal/fields/RepeaterField.d.vue.ts +0 -0
- package/dist/runtime/internal/fields/RepeaterField.vue +856 -0
- package/dist/runtime/internal/fields/RepeaterField.vue.d.ts +0 -0
- package/dist/runtime/internal/fields/SelectField.d.vue.ts +21 -0
- package/dist/runtime/internal/fields/SelectField.vue +101 -0
- package/dist/runtime/internal/fields/SelectField.vue.d.ts +21 -0
- package/dist/runtime/internal/fields/SeparatorField.d.vue.ts +0 -0
- package/dist/runtime/internal/fields/SeparatorField.vue +63 -0
- package/dist/runtime/internal/fields/SeparatorField.vue.d.ts +0 -0
- package/dist/runtime/internal/fields/TabField.d.vue.ts +0 -0
- package/dist/runtime/internal/fields/TabField.vue +210 -0
- package/dist/runtime/internal/fields/TabField.vue.d.ts +0 -0
- package/dist/runtime/internal/fields/TextField.d.vue.ts +0 -0
- package/dist/runtime/internal/fields/TextField.vue +22 -0
- package/dist/runtime/internal/fields/TextField.vue.d.ts +0 -0
- package/dist/runtime/internal/fields/TextareaField.d.vue.ts +0 -0
- package/dist/runtime/internal/fields/TextareaField.vue +62 -0
- package/dist/runtime/internal/fields/TextareaField.vue.d.ts +0 -0
- package/dist/runtime/internal/fields/TimePickerField.d.vue.ts +0 -0
- package/dist/runtime/internal/fields/TimePickerField.vue +24 -0
- package/dist/runtime/internal/fields/TimePickerField.vue.d.ts +0 -0
- package/dist/runtime/internal/fields/TrueFalseField.d.vue.ts +0 -0
- package/dist/runtime/internal/fields/TrueFalseField.vue +151 -0
- package/dist/runtime/internal/fields/TrueFalseField.vue.d.ts +0 -0
- package/dist/runtime/internal/fields/UrlField.d.vue.ts +0 -0
- package/dist/runtime/internal/fields/UrlField.vue +21 -0
- package/dist/runtime/internal/fields/UrlField.vue.d.ts +0 -0
- package/dist/runtime/internal/fields/UserField.d.vue.ts +0 -0
- package/dist/runtime/internal/fields/UserField.vue +164 -0
- package/dist/runtime/internal/fields/UserField.vue.d.ts +0 -0
- package/dist/runtime/internal/fields/WysiwygField.d.vue.ts +0 -0
- package/dist/runtime/internal/fields/WysiwygField.vue +971 -0
- package/dist/runtime/internal/fields/WysiwygField.vue.d.ts +0 -0
- package/dist/runtime/internal/parts/DateTimeControl.d.vue.ts +90 -0
- package/dist/runtime/internal/parts/DateTimeControl.vue +568 -0
- package/dist/runtime/internal/parts/DateTimeControl.vue.d.ts +90 -0
- package/dist/runtime/internal/parts/FieldAddon.d.vue.ts +0 -0
- package/dist/runtime/internal/parts/FieldAddon.vue +43 -0
- package/dist/runtime/internal/parts/FieldAddon.vue.d.ts +0 -0
- package/dist/runtime/internal/parts/FieldInstructions.d.vue.ts +0 -0
- package/dist/runtime/internal/parts/FieldInstructions.vue +24 -0
- package/dist/runtime/internal/parts/FieldInstructions.vue.d.ts +0 -0
- package/dist/runtime/internal/parts/FieldLabel.d.vue.ts +0 -0
- package/dist/runtime/internal/parts/FieldLabel.vue +40 -0
- package/dist/runtime/internal/parts/FieldLabel.vue.d.ts +0 -0
- package/dist/runtime/internal/parts/FieldWrapper.d.vue.ts +0 -0
- package/dist/runtime/internal/parts/FieldWrapper.vue +47 -0
- package/dist/runtime/internal/parts/FieldWrapper.vue.d.ts +0 -0
- package/dist/runtime/internal/parts/ImageCropper.d.vue.ts +17 -0
- package/dist/runtime/internal/parts/ImageCropper.vue +363 -0
- package/dist/runtime/internal/parts/ImageCropper.vue.d.ts +17 -0
- package/dist/runtime/internal/parts/InputControl.d.vue.ts +0 -0
- package/dist/runtime/internal/parts/InputControl.vue +163 -0
- package/dist/runtime/internal/parts/InputControl.vue.d.ts +0 -0
- package/dist/runtime/internal/ui/UiButton.d.vue.ts +35 -0
- package/dist/runtime/internal/ui/UiButton.vue +204 -0
- package/dist/runtime/internal/ui/UiButton.vue.d.ts +35 -0
- package/dist/runtime/internal/ui/UiNotice.d.vue.ts +40 -0
- package/dist/runtime/internal/ui/UiNotice.vue +253 -0
- package/dist/runtime/internal/ui/UiNotice.vue.d.ts +40 -0
- package/dist/runtime/internal/ui/UiSelect.d.vue.ts +61 -0
- package/dist/runtime/internal/ui/UiSelect.vue +1212 -0
- package/dist/runtime/internal/ui/UiSelect.vue.d.ts +61 -0
- package/dist/runtime/middleware/auth-guard.d.ts +9 -0
- package/dist/runtime/middleware/auth-guard.js +37 -0
- package/dist/runtime/pages/admin/collections/[id].d.vue.ts +3 -0
- package/dist/runtime/pages/admin/collections/[id].vue +423 -0
- package/dist/runtime/pages/admin/collections/[id].vue.d.ts +3 -0
- package/dist/runtime/pages/admin/collections/create.d.vue.ts +3 -0
- package/dist/runtime/pages/admin/collections/create.vue +179 -0
- package/dist/runtime/pages/admin/collections/create.vue.d.ts +3 -0
- package/dist/runtime/pages/admin/collections/index.d.vue.ts +3 -0
- package/dist/runtime/pages/admin/collections/index.vue +828 -0
- package/dist/runtime/pages/admin/collections/index.vue.d.ts +3 -0
- package/dist/runtime/pages/admin/demo-fields.d.vue.ts +3 -0
- package/dist/runtime/pages/admin/demo-fields.vue +1327 -0
- package/dist/runtime/pages/admin/demo-fields.vue.d.ts +3 -0
- package/dist/runtime/pages/admin/dictionaries/[id].d.vue.ts +3 -0
- package/dist/runtime/pages/admin/dictionaries/[id].vue +213 -0
- package/dist/runtime/pages/admin/dictionaries/[id].vue.d.ts +3 -0
- package/dist/runtime/pages/admin/dictionaries/index.d.vue.ts +3 -0
- package/dist/runtime/pages/admin/dictionaries/index.vue +387 -0
- package/dist/runtime/pages/admin/dictionaries/index.vue.d.ts +3 -0
- package/dist/runtime/pages/admin/index.d.vue.ts +3 -0
- package/dist/runtime/pages/admin/index.vue +138 -0
- package/dist/runtime/pages/admin/index.vue.d.ts +3 -0
- package/dist/runtime/pages/admin/login.d.vue.ts +3 -0
- package/dist/runtime/pages/admin/login.vue +373 -0
- package/dist/runtime/pages/admin/login.vue.d.ts +3 -0
- package/dist/runtime/pages/admin/media.d.vue.ts +3 -0
- package/dist/runtime/pages/admin/media.vue +1054 -0
- package/dist/runtime/pages/admin/media.vue.d.ts +3 -0
- package/dist/runtime/pages/admin/options/[page].d.vue.ts +3 -0
- package/dist/runtime/pages/admin/options/[page].vue +151 -0
- package/dist/runtime/pages/admin/options/[page].vue.d.ts +3 -0
- package/dist/runtime/pages/admin/register.d.vue.ts +3 -0
- package/dist/runtime/pages/admin/register.vue +391 -0
- package/dist/runtime/pages/admin/register.vue.d.ts +3 -0
- package/dist/runtime/pages/admin/users/[id].d.vue.ts +3 -0
- package/dist/runtime/pages/admin/users/[id].vue +337 -0
- package/dist/runtime/pages/admin/users/[id].vue.d.ts +3 -0
- package/dist/runtime/pages/admin/users/create.d.vue.ts +3 -0
- package/dist/runtime/pages/admin/users/create.vue +201 -0
- package/dist/runtime/pages/admin/users/create.vue.d.ts +3 -0
- package/dist/runtime/pages/admin/users/index.d.vue.ts +3 -0
- package/dist/runtime/pages/admin/users/index.vue +329 -0
- package/dist/runtime/pages/admin/users/index.vue.d.ts +3 -0
- package/dist/runtime/pages/index.d.vue.ts +3 -0
- package/dist/runtime/pages/index.vue +399 -0
- package/dist/runtime/pages/index.vue.d.ts +3 -0
- package/dist/runtime/server/api/_katecms/auth/login.post.d.ts +5 -0
- package/dist/runtime/server/api/_katecms/auth/login.post.js +44 -0
- package/dist/runtime/server/api/_katecms/auth/logout.post.d.ts +4 -0
- package/dist/runtime/server/api/_katecms/auth/logout.post.js +6 -0
- package/dist/runtime/server/api/_katecms/auth/register.post.d.ts +19 -0
- package/dist/runtime/server/api/_katecms/auth/register.post.js +83 -0
- package/dist/runtime/server/api/_katecms/auth/state.get.d.ts +9 -0
- package/dist/runtime/server/api/_katecms/auth/state.get.js +12 -0
- package/dist/runtime/server/api/_katecms/collections/[collection]/[id].delete.d.ts +15 -0
- package/dist/runtime/server/api/_katecms/collections/[collection]/[id].delete.js +59 -0
- package/dist/runtime/server/api/_katecms/collections/[collection]/[id].get.d.ts +4 -0
- package/dist/runtime/server/api/_katecms/collections/[collection]/[id].get.js +50 -0
- package/dist/runtime/server/api/_katecms/collections/[collection]/[id].patch.d.ts +4 -0
- package/dist/runtime/server/api/_katecms/collections/[collection]/[id].patch.js +130 -0
- package/dist/runtime/server/api/_katecms/collections/[collection]/revisions/[revisionId].post.d.ts +4 -0
- package/dist/runtime/server/api/_katecms/collections/[collection]/revisions/[revisionId].post.js +123 -0
- package/dist/runtime/server/api/_katecms/collections/[collection]/revisions.get.d.ts +6 -0
- package/dist/runtime/server/api/_katecms/collections/[collection]/revisions.get.js +31 -0
- package/dist/runtime/server/api/_katecms/collections/[collection].get.d.ts +8 -0
- package/dist/runtime/server/api/_katecms/collections/[collection].get.js +135 -0
- package/dist/runtime/server/api/_katecms/collections/[collection].post.d.ts +4 -0
- package/dist/runtime/server/api/_katecms/collections/[collection].post.js +91 -0
- package/dist/runtime/server/api/_katecms/dictionaries/[dictionary]/[id].delete.d.ts +7 -0
- package/dist/runtime/server/api/_katecms/dictionaries/[dictionary]/[id].delete.js +31 -0
- package/dist/runtime/server/api/_katecms/dictionaries/[dictionary]/[id].get.d.ts +4 -0
- package/dist/runtime/server/api/_katecms/dictionaries/[dictionary]/[id].get.js +45 -0
- package/dist/runtime/server/api/_katecms/dictionaries/[dictionary]/[id].patch.d.ts +4 -0
- package/dist/runtime/server/api/_katecms/dictionaries/[dictionary]/[id].patch.js +83 -0
- package/dist/runtime/server/api/_katecms/dictionaries/[dictionary].get.d.ts +4 -0
- package/dist/runtime/server/api/_katecms/dictionaries/[dictionary].get.js +38 -0
- package/dist/runtime/server/api/_katecms/dictionaries/[dictionary].post.d.ts +4 -0
- package/dist/runtime/server/api/_katecms/dictionaries/[dictionary].post.js +64 -0
- package/dist/runtime/server/api/_katecms/media/[id]/regenerate.post.d.ts +8 -0
- package/dist/runtime/server/api/_katecms/media/[id]/regenerate.post.js +30 -0
- package/dist/runtime/server/api/_katecms/media/[id].delete.d.ts +7 -0
- package/dist/runtime/server/api/_katecms/media/[id].delete.js +22 -0
- package/dist/runtime/server/api/_katecms/media/[id].get.d.ts +9 -0
- package/dist/runtime/server/api/_katecms/media/[id].get.js +17 -0
- package/dist/runtime/server/api/_katecms/media/[id].patch.d.ts +6 -0
- package/dist/runtime/server/api/_katecms/media/[id].patch.js +48 -0
- package/dist/runtime/server/api/_katecms/media/index.get.d.ts +5 -0
- package/dist/runtime/server/api/_katecms/media/index.get.js +75 -0
- package/dist/runtime/server/api/_katecms/media/index.post.d.ts +9 -0
- package/dist/runtime/server/api/_katecms/media/index.post.js +84 -0
- package/dist/runtime/server/api/_katecms/media/regenerate.post.d.ts +7 -0
- package/dist/runtime/server/api/_katecms/media/regenerate.post.js +30 -0
- package/dist/runtime/server/api/_katecms/menu.get.d.ts +8 -0
- package/dist/runtime/server/api/_katecms/menu.get.js +14 -0
- package/dist/runtime/server/api/_katecms/oembed.get.d.ts +2 -0
- package/dist/runtime/server/api/_katecms/oembed.get.js +53 -0
- package/dist/runtime/server/api/_katecms/options/[page].get.d.ts +7 -0
- package/dist/runtime/server/api/_katecms/options/[page].get.js +28 -0
- package/dist/runtime/server/api/_katecms/options/[page].patch.d.ts +4 -0
- package/dist/runtime/server/api/_katecms/options/[page].patch.js +36 -0
- package/dist/runtime/server/api/_katecms/query.get.d.ts +24 -0
- package/dist/runtime/server/api/_katecms/query.get.js +270 -0
- package/dist/runtime/server/api/_katecms/relation/entries.get.d.ts +17 -0
- package/dist/runtime/server/api/_katecms/relation/entries.get.js +74 -0
- package/dist/runtime/server/api/_katecms/relation/terms.get.d.ts +17 -0
- package/dist/runtime/server/api/_katecms/relation/terms.get.js +51 -0
- package/dist/runtime/server/api/_katecms/resolve.get.d.ts +17 -0
- package/dist/runtime/server/api/_katecms/resolve.get.js +116 -0
- package/dist/runtime/server/api/_katecms/terms.get.d.ts +20 -0
- package/dist/runtime/server/api/_katecms/terms.get.js +201 -0
- package/dist/runtime/server/api/_katecms/users/[id].delete.d.ts +11 -0
- package/dist/runtime/server/api/_katecms/users/[id].delete.js +45 -0
- package/dist/runtime/server/api/_katecms/users/[id].patch.d.ts +19 -0
- package/dist/runtime/server/api/_katecms/users/[id].patch.js +129 -0
- package/dist/runtime/server/api/_katecms/users.get.d.ts +10 -0
- package/dist/runtime/server/api/_katecms/users.get.js +34 -0
- package/dist/runtime/server/api/_katecms/users.post.d.ts +10 -0
- package/dist/runtime/server/api/_katecms/users.post.js +62 -0
- package/dist/runtime/server/api/uploads/[...key].get.d.ts +3 -0
- package/dist/runtime/server/api/uploads/[...key].get.js +28 -0
- package/dist/runtime/server/kit.d.ts +5 -0
- package/dist/runtime/server/kit.js +5 -0
- package/dist/runtime/server/middleware/admin-headers.d.ts +3 -0
- package/dist/runtime/server/middleware/admin-headers.js +12 -0
- package/dist/runtime/server/plugins/auto-migrate.d.ts +2 -0
- package/dist/runtime/server/plugins/auto-migrate.js +45 -0
- package/dist/runtime/server/tsconfig.json +3 -0
- package/dist/runtime/server/utils/auth-attempts.d.ts +22 -0
- package/dist/runtime/server/utils/auth-attempts.js +42 -0
- package/dist/runtime/server/utils/auth-rate-limit.d.ts +11 -0
- package/dist/runtime/server/utils/auth-rate-limit.js +36 -0
- package/dist/runtime/server/utils/client-address.d.ts +16 -0
- package/dist/runtime/server/utils/client-address.js +23 -0
- package/dist/runtime/server/utils/collections.d.ts +42 -0
- package/dist/runtime/server/utils/collections.js +300 -0
- package/dist/runtime/server/utils/db.d.ts +3 -0
- package/dist/runtime/server/utils/db.js +25 -0
- package/dist/runtime/server/utils/dictionaries.d.ts +53 -0
- package/dist/runtime/server/utils/dictionaries.js +301 -0
- package/dist/runtime/server/utils/media-list.d.ts +18 -0
- package/dist/runtime/server/utils/media-list.js +84 -0
- package/dist/runtime/server/utils/media.d.ts +12 -0
- package/dist/runtime/server/utils/media.js +77 -0
- package/dist/runtime/server/utils/oembed-fetch.d.ts +4 -0
- package/dist/runtime/server/utils/oembed-fetch.js +142 -0
- package/dist/runtime/server/utils/options.d.ts +17 -0
- package/dist/runtime/server/utils/options.js +66 -0
- package/dist/runtime/server/utils/permissions.d.ts +13 -0
- package/dist/runtime/server/utils/permissions.js +20 -0
- package/dist/runtime/server/utils/public-fields-query.d.ts +6 -0
- package/dist/runtime/server/utils/public-fields-query.js +8 -0
- package/dist/runtime/server/utils/public-term.d.ts +8 -0
- package/dist/runtime/server/utils/public-term.js +80 -0
- package/dist/runtime/server/utils/regenerate.d.ts +12 -0
- package/dist/runtime/server/utils/regenerate.js +40 -0
- package/dist/runtime/server/utils/relation.d.ts +18 -0
- package/dist/runtime/server/utils/relation.js +77 -0
- package/dist/runtime/server/utils/request-address.d.ts +6 -0
- package/dist/runtime/server/utils/request-address.js +10 -0
- package/dist/runtime/server/utils/revisions.d.ts +20 -0
- package/dist/runtime/server/utils/revisions.js +172 -0
- package/dist/runtime/server/utils/session.d.ts +18 -0
- package/dist/runtime/server/utils/session.js +71 -0
- package/dist/runtime/server/utils/upload-headers.d.ts +2 -0
- package/dist/runtime/server/utils/upload-headers.js +30 -0
- package/dist/runtime/server/utils/users.d.ts +13 -0
- package/dist/runtime/server/utils/users.js +47 -0
- package/dist/runtime/utils/admin-users.d.ts +20 -0
- package/dist/runtime/utils/admin-users.js +19 -0
- package/dist/runtime/utils/auth-error.d.ts +6 -0
- package/dist/runtime/utils/auth-error.js +11 -0
- package/dist/runtime/utils/cms-paths.d.ts +5 -0
- package/dist/runtime/utils/cms-paths.js +13 -0
- package/dist/runtime/utils/collections.d.ts +176 -0
- package/dist/runtime/utils/collections.js +30 -0
- package/dist/runtime/utils/dictionaries.d.ts +65 -0
- package/dist/runtime/utils/dictionaries.js +14 -0
- package/dist/runtime/utils/field-errors.d.ts +4 -0
- package/dist/runtime/utils/field-errors.js +9 -0
- package/dist/runtime/utils/field-values.d.ts +19 -0
- package/dist/runtime/utils/field-values.js +82 -0
- package/dist/runtime/utils/helpers.d.ts +4 -0
- package/dist/runtime/utils/helpers.js +20 -0
- package/dist/runtime/utils/media-library-query.d.ts +54 -0
- package/dist/runtime/utils/media-library-query.js +190 -0
- package/dist/runtime/utils/options.d.ts +19 -0
- package/dist/runtime/utils/options.js +3 -0
- package/dist/runtime/utils/preview.d.ts +22 -0
- package/dist/runtime/utils/preview.js +33 -0
- package/dist/runtime/utils/relation.d.ts +33 -0
- package/dist/runtime/utils/relation.js +23 -0
- package/dist/runtime/utils/slugify.d.ts +2 -0
- package/dist/runtime/utils/slugify.js +4 -0
- package/dist/types.d.mts +7 -0
- package/package.json +84 -3
- package/src/admin-components.ts +124 -0
- package/src/module.ts +592 -0
- package/src/runtime/assets/img/katecms-logo.svg +17 -0
- package/src/runtime/assets/styles/_functions.scss +70 -0
- package/src/runtime/assets/styles/_index.scss +3 -0
- package/src/runtime/assets/styles/_mixins.scss +256 -0
- package/src/runtime/assets/styles/_variables.scss +35 -0
- package/src/runtime/composables/getCollection.ts +253 -0
- package/src/runtime/composables/getOptions.ts +42 -0
- package/src/runtime/composables/getQueryCollection.ts +325 -0
- package/src/runtime/composables/getTerms.ts +231 -0
- package/src/runtime/composables/useAuth.ts +43 -0
- package/src/runtime/composables/useAuthCooldown.ts +52 -0
- package/src/runtime/composables/useCmsPaths.ts +24 -0
- package/src/runtime/composables/useKateCmsExtensions.ts +81 -0
- package/src/runtime/composables/useMediaLibrary.ts +168 -0
- package/src/runtime/composables/useMenuAccess.ts +25 -0
- package/src/runtime/internal/admin/AdminHeader.vue +106 -0
- package/src/runtime/internal/admin/AppMenu.vue +290 -0
- package/src/runtime/internal/admin/AppUser.vue +260 -0
- package/src/runtime/internal/admin/CollectionEntryForm.vue +1044 -0
- package/src/runtime/internal/admin/ConfirmDialog.vue +164 -0
- package/src/runtime/internal/admin/DictionaryTermForm.vue +400 -0
- package/src/runtime/internal/admin/EntryRevisions.vue +145 -0
- package/src/runtime/internal/admin/MediaLibraryFilters.vue +186 -0
- package/src/runtime/internal/admin/MediaLibraryModal.vue +526 -0
- package/src/runtime/internal/admin/OptionPageForm.vue +277 -0
- package/src/runtime/internal/admin/UserAvatarField.vue +337 -0
- package/src/runtime/internal/fields/AccordionField.vue +258 -0
- package/src/runtime/internal/fields/ButtonGroupField.vue +144 -0
- package/src/runtime/internal/fields/CheckboxField.vue +228 -0
- package/src/runtime/internal/fields/ColorPickerField.vue +926 -0
- package/src/runtime/internal/fields/DatePickerField.vue +33 -0
- package/src/runtime/internal/fields/DateTimePickerField.vue +33 -0
- package/src/runtime/internal/fields/DictionaryField.vue +403 -0
- package/src/runtime/internal/fields/EmailField.vue +28 -0
- package/src/runtime/internal/fields/FileField.vue +480 -0
- package/src/runtime/internal/fields/FlexibleContentField.vue +1296 -0
- package/src/runtime/internal/fields/GalleryField.vue +677 -0
- package/src/runtime/internal/fields/GroupField.vue +136 -0
- package/src/runtime/internal/fields/ImageField.vue +730 -0
- package/src/runtime/internal/fields/ImageSelectField.vue +213 -0
- package/src/runtime/internal/fields/LinkField.vue +338 -0
- package/src/runtime/internal/fields/NumberField.vue +32 -0
- package/src/runtime/internal/fields/OembedField.vue +187 -0
- package/src/runtime/internal/fields/OpenStreetMapField.vue +1716 -0
- package/src/runtime/internal/fields/PageLinkField.vue +186 -0
- package/src/runtime/internal/fields/PasswordField.vue +127 -0
- package/src/runtime/internal/fields/PostObjectField.vue +187 -0
- package/src/runtime/internal/fields/RadioField.vue +195 -0
- package/src/runtime/internal/fields/RangeField.vue +62 -0
- package/src/runtime/internal/fields/RelationshipField.vue +604 -0
- package/src/runtime/internal/fields/RepeaterField.vue +999 -0
- package/src/runtime/internal/fields/SelectField.vue +118 -0
- package/src/runtime/internal/fields/SeparatorField.vue +77 -0
- package/src/runtime/internal/fields/TabField.vue +249 -0
- package/src/runtime/internal/fields/TextField.vue +29 -0
- package/src/runtime/internal/fields/TextareaField.vue +61 -0
- package/src/runtime/internal/fields/TimePickerField.vue +31 -0
- package/src/runtime/internal/fields/TrueFalseField.vue +181 -0
- package/src/runtime/internal/fields/UrlField.vue +28 -0
- package/src/runtime/internal/fields/UserField.vue +203 -0
- package/src/runtime/internal/fields/WysiwygField.vue +1061 -0
- package/src/runtime/internal/parts/DateTimeControl.vue +657 -0
- package/src/runtime/internal/parts/FieldAddon.vue +60 -0
- package/src/runtime/internal/parts/FieldInstructions.vue +38 -0
- package/src/runtime/internal/parts/FieldLabel.vue +56 -0
- package/src/runtime/internal/parts/FieldWrapper.vue +63 -0
- package/src/runtime/internal/parts/ImageCropper.vue +415 -0
- package/src/runtime/internal/parts/InputControl.vue +189 -0
- package/src/runtime/internal/ui/UiButton.vue +274 -0
- package/src/runtime/internal/ui/UiNotice.vue +302 -0
- package/src/runtime/internal/ui/UiSelect.vue +1420 -0
- package/src/runtime/middleware/auth-guard.ts +52 -0
- package/src/runtime/pages/admin/collections/[id].vue +486 -0
- package/src/runtime/pages/admin/collections/create.vue +208 -0
- package/src/runtime/pages/admin/collections/index.vue +955 -0
- package/src/runtime/pages/admin/demo-fields.vue +1354 -0
- package/src/runtime/pages/admin/dictionaries/[id].vue +246 -0
- package/src/runtime/pages/admin/dictionaries/index.vue +438 -0
- package/src/runtime/pages/admin/index.vue +155 -0
- package/src/runtime/pages/admin/login.vue +159 -0
- package/src/runtime/pages/admin/media.vue +1176 -0
- package/src/runtime/pages/admin/options/[page].vue +174 -0
- package/src/runtime/pages/admin/register.vue +179 -0
- package/src/runtime/pages/admin/users/[id].vue +382 -0
- package/src/runtime/pages/admin/users/create.vue +232 -0
- package/src/runtime/pages/admin/users/index.vue +374 -0
- package/src/runtime/pages/index.vue +265 -0
- package/src/runtime/server/api/_katecms/auth/login.post.ts +62 -0
- package/src/runtime/server/api/_katecms/auth/logout.post.ts +7 -0
- package/src/runtime/server/api/_katecms/auth/register.post.ts +112 -0
- package/src/runtime/server/api/_katecms/auth/state.get.ts +19 -0
- package/src/runtime/server/api/_katecms/collections/[collection]/[id].delete.ts +77 -0
- package/src/runtime/server/api/_katecms/collections/[collection]/[id].get.ts +57 -0
- package/src/runtime/server/api/_katecms/collections/[collection]/[id].patch.ts +157 -0
- package/src/runtime/server/api/_katecms/collections/[collection]/revisions/[revisionId].post.ts +133 -0
- package/src/runtime/server/api/_katecms/collections/[collection]/revisions.get.ts +35 -0
- package/src/runtime/server/api/_katecms/collections/[collection].get.ts +177 -0
- package/src/runtime/server/api/_katecms/collections/[collection].post.ts +111 -0
- package/src/runtime/server/api/_katecms/dictionaries/[dictionary]/[id].delete.ts +37 -0
- package/src/runtime/server/api/_katecms/dictionaries/[dictionary]/[id].get.ts +51 -0
- package/src/runtime/server/api/_katecms/dictionaries/[dictionary]/[id].patch.ts +101 -0
- package/src/runtime/server/api/_katecms/dictionaries/[dictionary].get.ts +43 -0
- package/src/runtime/server/api/_katecms/dictionaries/[dictionary].post.ts +78 -0
- package/src/runtime/server/api/_katecms/media/[id]/regenerate.post.ts +39 -0
- package/src/runtime/server/api/_katecms/media/[id].delete.ts +28 -0
- package/src/runtime/server/api/_katecms/media/[id].get.ts +25 -0
- package/src/runtime/server/api/_katecms/media/[id].patch.ts +60 -0
- package/src/runtime/server/api/_katecms/media/index.get.ts +96 -0
- package/src/runtime/server/api/_katecms/media/index.post.ts +104 -0
- package/src/runtime/server/api/_katecms/media/regenerate.post.ts +38 -0
- package/src/runtime/server/api/_katecms/menu.get.ts +19 -0
- package/src/runtime/server/api/_katecms/oembed.get.ts +62 -0
- package/src/runtime/server/api/_katecms/options/[page].get.ts +35 -0
- package/src/runtime/server/api/_katecms/options/[page].patch.ts +46 -0
- package/src/runtime/server/api/_katecms/query.get.ts +332 -0
- package/src/runtime/server/api/_katecms/relation/entries.get.ts +98 -0
- package/src/runtime/server/api/_katecms/relation/terms.get.ts +61 -0
- package/src/runtime/server/api/_katecms/resolve.get.ts +148 -0
- package/src/runtime/server/api/_katecms/terms.get.ts +258 -0
- package/src/runtime/server/api/_katecms/users/[id].delete.ts +57 -0
- package/src/runtime/server/api/_katecms/users/[id].patch.ts +177 -0
- package/src/runtime/server/api/_katecms/users.get.ts +48 -0
- package/src/runtime/server/api/_katecms/users.post.ts +85 -0
- package/src/runtime/server/api/uploads/[...key].get.ts +33 -0
- package/src/runtime/server/kit.ts +5 -0
- package/src/runtime/server/middleware/admin-headers.ts +14 -0
- package/src/runtime/server/plugins/auto-migrate.ts +53 -0
- package/src/runtime/server/tsconfig.json +3 -0
- package/src/runtime/server/utils/auth-attempts.ts +71 -0
- package/src/runtime/server/utils/auth-rate-limit.ts +48 -0
- package/src/runtime/server/utils/client-address.ts +41 -0
- package/src/runtime/server/utils/collections.ts +381 -0
- package/src/runtime/server/utils/db.ts +36 -0
- package/src/runtime/server/utils/dictionaries.ts +397 -0
- package/src/runtime/server/utils/media-list.ts +131 -0
- package/src/runtime/server/utils/media.ts +94 -0
- package/src/runtime/server/utils/oembed-fetch.ts +157 -0
- package/src/runtime/server/utils/options.ts +86 -0
- package/src/runtime/server/utils/permissions.ts +44 -0
- package/src/runtime/server/utils/public-fields-query.ts +14 -0
- package/src/runtime/server/utils/public-term.ts +98 -0
- package/src/runtime/server/utils/regenerate.ts +56 -0
- package/src/runtime/server/utils/relation.ts +96 -0
- package/src/runtime/server/utils/request-address.ts +16 -0
- package/src/runtime/server/utils/revisions.ts +256 -0
- package/src/runtime/server/utils/session.ts +112 -0
- package/src/runtime/server/utils/upload-headers.ts +35 -0
- package/src/runtime/server/utils/users.ts +67 -0
- package/src/runtime/utils/admin-users.ts +43 -0
- package/src/runtime/utils/auth-error.ts +22 -0
- package/src/runtime/utils/cms-paths.ts +17 -0
- package/src/runtime/utils/collections.ts +228 -0
- package/src/runtime/utils/dictionaries.ts +89 -0
- package/src/runtime/utils/field-errors.ts +12 -0
- package/src/runtime/utils/field-values.ts +101 -0
- package/src/runtime/utils/helpers.ts +33 -0
- package/src/runtime/utils/media-library-query.ts +263 -0
- package/src/runtime/utils/options.ts +25 -0
- package/src/runtime/utils/preview.ts +56 -0
- package/src/runtime/utils/relation.ts +60 -0
- package/src/runtime/utils/slugify.ts +10 -0
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { createError, defineEventHandler, getRequestURL, setHeader } from "h3";
|
|
2
|
+
import { getMediaStorage } from "../../utils/media.js";
|
|
3
|
+
import { uploadResponseHeaders } from "../../utils/upload-headers.js";
|
|
4
|
+
export default defineEventHandler(async (event) => {
|
|
5
|
+
const pathname = getRequestURL(event).pathname;
|
|
6
|
+
const prefix = "/uploads/";
|
|
7
|
+
if (!pathname.startsWith(prefix)) {
|
|
8
|
+
throw createError({ statusCode: 404, statusMessage: "File not found." });
|
|
9
|
+
}
|
|
10
|
+
const key = decodeURIComponent(pathname.slice(prefix.length));
|
|
11
|
+
const storage = getMediaStorage();
|
|
12
|
+
let data;
|
|
13
|
+
try {
|
|
14
|
+
if (!key || !await storage.exists(key)) {
|
|
15
|
+
throw createError({ statusCode: 404, statusMessage: "File not found." });
|
|
16
|
+
}
|
|
17
|
+
data = await storage.get(key);
|
|
18
|
+
} catch (error) {
|
|
19
|
+
if (error && typeof error === "object" && "statusCode" in error) {
|
|
20
|
+
throw error;
|
|
21
|
+
}
|
|
22
|
+
throw createError({ statusCode: 404, statusMessage: "File not found." });
|
|
23
|
+
}
|
|
24
|
+
for (const [name, value] of Object.entries(uploadResponseHeaders(key))) {
|
|
25
|
+
setHeader(event, name, value);
|
|
26
|
+
}
|
|
27
|
+
return data;
|
|
28
|
+
});
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { getDb } from './utils/db.js';
|
|
2
|
+
export { requireUser } from './utils/session.js';
|
|
3
|
+
export { requireEntryPermission, requirePermission } from './utils/permissions.js';
|
|
4
|
+
export { clientAddress, trustedProxyHops } from './utils/client-address.js';
|
|
5
|
+
export { eventClientAddress } from './utils/request-address.js';
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { getDb } from "./utils/db.js";
|
|
2
|
+
export { requireUser } from "./utils/session.js";
|
|
3
|
+
export { requireEntryPermission, requirePermission } from "./utils/permissions.js";
|
|
4
|
+
export { clientAddress, trustedProxyHops } from "./utils/client-address.js";
|
|
5
|
+
export { eventClientAddress } from "./utils/request-address.js";
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { appendResponseHeader, defineEventHandler, getRequestURL, setResponseHeader } from "h3";
|
|
2
|
+
import { useRuntimeConfig } from "#imports";
|
|
3
|
+
import { isCmsAdminPath } from "../../utils/cms-paths.js";
|
|
4
|
+
export default defineEventHandler((event) => {
|
|
5
|
+
const adminPath = String(useRuntimeConfig().katecms?.adminPath || "admin");
|
|
6
|
+
const path = getRequestURL(event).pathname;
|
|
7
|
+
if (!isCmsAdminPath(path, adminPath)) {
|
|
8
|
+
return;
|
|
9
|
+
}
|
|
10
|
+
setResponseHeader(event, "X-Content-Type-Options", "nosniff");
|
|
11
|
+
appendResponseHeader(event, "Content-Security-Policy", "frame-ancestors 'none'");
|
|
12
|
+
});
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { defineNitroPlugin } from "nitropack/runtime";
|
|
2
|
+
import { useRuntimeConfig } from "#imports";
|
|
3
|
+
import {
|
|
4
|
+
createPostgresDb,
|
|
5
|
+
migratePostgres,
|
|
6
|
+
migrateSqlite,
|
|
7
|
+
resolveDatabaseTarget,
|
|
8
|
+
syncCollectionFieldIndexes
|
|
9
|
+
} from "@katecms/core";
|
|
10
|
+
function trimEnv(value) {
|
|
11
|
+
return typeof value === "string" ? value.trim() : "";
|
|
12
|
+
}
|
|
13
|
+
export default defineNitroPlugin(async () => {
|
|
14
|
+
const katecms = useRuntimeConfig().katecms;
|
|
15
|
+
const database = katecms?.database;
|
|
16
|
+
const driver = trimEnv(database?.driver);
|
|
17
|
+
const url = trimEnv(database?.url) || (driver === "postgres" ? trimEnv(process.env.DATABASE_URL) : "");
|
|
18
|
+
const target = resolveDatabaseTarget({
|
|
19
|
+
driver,
|
|
20
|
+
url,
|
|
21
|
+
sqliteFilename: database?.sqliteFilename
|
|
22
|
+
});
|
|
23
|
+
if (target.driver === "postgres") {
|
|
24
|
+
await migratePostgres(target.url);
|
|
25
|
+
const db = createPostgresDb(target.url);
|
|
26
|
+
try {
|
|
27
|
+
const result = await syncCollectionFieldIndexes(
|
|
28
|
+
db,
|
|
29
|
+
katecms?.collections ?? {}
|
|
30
|
+
);
|
|
31
|
+
for (const warning of result.warnings) {
|
|
32
|
+
console.warn(`[KateCMS] ${warning}`);
|
|
33
|
+
}
|
|
34
|
+
if (result.created.length > 0 || result.dropped.length > 0) {
|
|
35
|
+
console.info(
|
|
36
|
+
`[KateCMS] Field indexes: created ${result.created.length}, dropped ${result.dropped.length}`
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
} finally {
|
|
40
|
+
await db.destroy();
|
|
41
|
+
}
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
await migrateSqlite({ filename: target.filename });
|
|
45
|
+
});
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { AuthRateLimitDecision } from '@katecms/core';
|
|
2
|
+
export interface AuthAttemptKeys {
|
|
3
|
+
/** Action, address, and email. Cleared after a successful attempt. */
|
|
4
|
+
pair: string;
|
|
5
|
+
/** Action and address. Stays after success so one login does not reopen the address. */
|
|
6
|
+
ip: string;
|
|
7
|
+
/** Action and email. Cleared after a successful attempt. */
|
|
8
|
+
email: string;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Three buckets for one login or registration attempt.
|
|
12
|
+
* Empty addresses and emails share an `unknown` bucket.
|
|
13
|
+
*/
|
|
14
|
+
export declare function authAttemptKeys(action: 'login' | 'register', ip: string, email: string): AuthAttemptKeys;
|
|
15
|
+
/** Longest cooldown among the given buckets, or 0 when every bucket allows the attempt. */
|
|
16
|
+
export declare function authAttemptRetryAfterMs(key: string | AuthAttemptKeys): number;
|
|
17
|
+
export declare function recordAuthAttemptFailure(key: string | AuthAttemptKeys): AuthRateLimitDecision;
|
|
18
|
+
/**
|
|
19
|
+
* Drop the email and pair buckets. An address bucket is left in place.
|
|
20
|
+
* A string key (password change) is cleared on its own.
|
|
21
|
+
*/
|
|
22
|
+
export declare function recordAuthAttemptSuccess(key: string | AuthAttemptKeys): void;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { createAuthRateLimiter } from "@katecms/core";
|
|
2
|
+
const limiter = createAuthRateLimiter();
|
|
3
|
+
export function authAttemptKeys(action, ip, email) {
|
|
4
|
+
const address = ip.trim() || "unknown";
|
|
5
|
+
const normalized = email.trim().toLowerCase() || "unknown";
|
|
6
|
+
return {
|
|
7
|
+
pair: `${action}:pair:${address}:${normalized}`,
|
|
8
|
+
ip: `${action}:ip:${address}`,
|
|
9
|
+
email: `${action}:email:${normalized}`
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
function asKeys(key) {
|
|
13
|
+
return typeof key === "string" ? [key] : [key.pair, key.ip, key.email];
|
|
14
|
+
}
|
|
15
|
+
export function authAttemptRetryAfterMs(key) {
|
|
16
|
+
let retryAfterMs = 0;
|
|
17
|
+
for (const item of asKeys(key)) {
|
|
18
|
+
const decision = limiter.check(item);
|
|
19
|
+
if (!decision.allowed) {
|
|
20
|
+
retryAfterMs = Math.max(retryAfterMs, decision.retryAfterMs);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
return retryAfterMs;
|
|
24
|
+
}
|
|
25
|
+
export function recordAuthAttemptFailure(key) {
|
|
26
|
+
let longest = { allowed: true, retryAfterMs: 0 };
|
|
27
|
+
for (const item of asKeys(key)) {
|
|
28
|
+
const decision = limiter.recordFailure(item);
|
|
29
|
+
if (decision.retryAfterMs > longest.retryAfterMs) {
|
|
30
|
+
longest = decision;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return longest;
|
|
34
|
+
}
|
|
35
|
+
export function recordAuthAttemptSuccess(key) {
|
|
36
|
+
if (typeof key === "string") {
|
|
37
|
+
limiter.recordSuccess(key);
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
limiter.recordSuccess(key.pair);
|
|
41
|
+
limiter.recordSuccess(key.email);
|
|
42
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { H3Event } from 'h3';
|
|
2
|
+
import { authAttemptKeys, recordAuthAttemptFailure, recordAuthAttemptSuccess } from './auth-attempts.js';
|
|
3
|
+
import type { AuthAttemptKeys } from './auth-attempts.js';
|
|
4
|
+
export { authAttemptKeys, recordAuthAttemptFailure, recordAuthAttemptSuccess };
|
|
5
|
+
export type { AuthAttemptKeys };
|
|
6
|
+
export declare function getAuthAttemptKeys(event: H3Event, action: 'login' | 'register', email: string): AuthAttemptKeys;
|
|
7
|
+
export declare function assertAuthAttemptAllowed(event: H3Event, key: string | AuthAttemptKeys): void;
|
|
8
|
+
export declare function throwTooManyAttempts(event: H3Event, retryAfterMs: number): never;
|
|
9
|
+
export declare function invalidCredentialsError(retryAfterMs?: number): import("h3").H3Error<{
|
|
10
|
+
retryAfterMs: number;
|
|
11
|
+
}>;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { createError, setHeader } from "h3";
|
|
2
|
+
import {
|
|
3
|
+
authAttemptKeys,
|
|
4
|
+
authAttemptRetryAfterMs,
|
|
5
|
+
recordAuthAttemptFailure,
|
|
6
|
+
recordAuthAttemptSuccess
|
|
7
|
+
} from "./auth-attempts.js";
|
|
8
|
+
import { eventClientAddress } from "./request-address.js";
|
|
9
|
+
export { authAttemptKeys, recordAuthAttemptFailure, recordAuthAttemptSuccess };
|
|
10
|
+
export function getAuthAttemptKeys(event, action, email) {
|
|
11
|
+
return authAttemptKeys(action, eventClientAddress(event), email);
|
|
12
|
+
}
|
|
13
|
+
export function assertAuthAttemptAllowed(event, key) {
|
|
14
|
+
const retryAfterMs = authAttemptRetryAfterMs(key);
|
|
15
|
+
if (retryAfterMs > 0) {
|
|
16
|
+
throwTooManyAttempts(event, retryAfterMs);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
export function throwTooManyAttempts(event, retryAfterMs) {
|
|
20
|
+
const retryAfterSec = Math.max(1, Math.ceil(retryAfterMs / 1e3));
|
|
21
|
+
setHeader(event, "Retry-After", retryAfterSec);
|
|
22
|
+
throw createError({
|
|
23
|
+
statusCode: 429,
|
|
24
|
+
statusMessage: "Too Many Requests",
|
|
25
|
+
message: `Too many attempts. Try again in ${retryAfterSec} sec.`,
|
|
26
|
+
data: { retryAfterMs }
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
export function invalidCredentialsError(retryAfterMs = 0) {
|
|
30
|
+
return createError({
|
|
31
|
+
statusCode: 401,
|
|
32
|
+
statusMessage: "Unauthorized",
|
|
33
|
+
message: "Invalid email or password.",
|
|
34
|
+
data: { retryAfterMs }
|
|
35
|
+
});
|
|
36
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* How many reverse proxies may append to `X-Forwarded-For`.
|
|
3
|
+
* `MIRAICMS_TRUST_PROXY=1` trusts one proxy and uses the address it added.
|
|
4
|
+
* Unset means the header is ignored and the socket address is used.
|
|
5
|
+
*/
|
|
6
|
+
export declare function trustedProxyHops(raw?: string | undefined): number;
|
|
7
|
+
/**
|
|
8
|
+
* Client address for the auth limiter.
|
|
9
|
+
* With `hops` 0 the forwarded header is ignored, so a caller cannot pick a new
|
|
10
|
+
* bucket by sending another `X-Forwarded-For`.
|
|
11
|
+
*/
|
|
12
|
+
export declare function clientAddress(options: {
|
|
13
|
+
forwardedFor?: string | null;
|
|
14
|
+
hops: number;
|
|
15
|
+
socketAddress?: string | null;
|
|
16
|
+
}): string;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export function trustedProxyHops(raw = process.env.MIRAICMS_TRUST_PROXY) {
|
|
2
|
+
const value = (raw ?? "").trim().toLowerCase();
|
|
3
|
+
if (!value || value === "0" || value === "false" || value === "off") {
|
|
4
|
+
return 0;
|
|
5
|
+
}
|
|
6
|
+
if (value === "true" || value === "on") {
|
|
7
|
+
return 1;
|
|
8
|
+
}
|
|
9
|
+
const hops = Number(value);
|
|
10
|
+
if (!Number.isInteger(hops) || hops < 1) {
|
|
11
|
+
return 0;
|
|
12
|
+
}
|
|
13
|
+
return hops;
|
|
14
|
+
}
|
|
15
|
+
export function clientAddress(options) {
|
|
16
|
+
const socket = options.socketAddress?.trim() || "unknown";
|
|
17
|
+
if (options.hops < 1) {
|
|
18
|
+
return socket;
|
|
19
|
+
}
|
|
20
|
+
const parts = (options.forwardedFor ?? "").split(",").map((part) => part.trim()).filter(Boolean);
|
|
21
|
+
const index = parts.length - options.hops;
|
|
22
|
+
return index >= 0 && parts[index] ? parts[index] : socket;
|
|
23
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { findUserById } from '@katecms/core';
|
|
2
|
+
import type { Collection, CollectionDefinition, CollectionListStatus, CollectionParentOption, CollectionStatus, Collections, RoleMap, SafeUser } from '@katecms/core';
|
|
3
|
+
import type { AdminCollectionMeta, AdminEntry, ParentOption, PublicDictionaryTerm } from '../../utils/collections.js';
|
|
4
|
+
export declare function fail(statusCode: number, message: string): never;
|
|
5
|
+
export declare function getCollections(): Collections;
|
|
6
|
+
export declare function getCollectionDefinition(slug: string): CollectionDefinition | undefined;
|
|
7
|
+
export declare function requireCollection(slug: string): CollectionDefinition;
|
|
8
|
+
export declare function toCollectionMeta(slug: string, def: CollectionDefinition): AdminCollectionMeta;
|
|
9
|
+
export declare function collectionRevisionsEnabled(def: CollectionDefinition): boolean;
|
|
10
|
+
export declare function toAdminEntry(row: Collection, slugPath: string, flags?: {
|
|
11
|
+
canUpdate?: boolean;
|
|
12
|
+
canDelete?: boolean;
|
|
13
|
+
depth?: number;
|
|
14
|
+
authorName?: string | null;
|
|
15
|
+
dictionaryIds?: Record<string, number[]>;
|
|
16
|
+
dictionaries?: Record<string, PublicDictionaryTerm[]>;
|
|
17
|
+
}): AdminEntry;
|
|
18
|
+
export declare function entryFlags(actor: SafeUser, row: Collection, roles: RoleMap): {
|
|
19
|
+
canUpdate: boolean;
|
|
20
|
+
canDelete: boolean;
|
|
21
|
+
};
|
|
22
|
+
export declare function toParentOption(row: CollectionParentOption): ParentOption;
|
|
23
|
+
export declare function readCollectionSlug(raw: string | undefined): string;
|
|
24
|
+
export declare function readEntryId(raw: string | undefined): number;
|
|
25
|
+
export declare function readTitle(value: unknown): string;
|
|
26
|
+
export declare function readSlug(value: unknown): string;
|
|
27
|
+
export declare function readStatus(value: unknown, fallback?: CollectionStatus): CollectionStatus;
|
|
28
|
+
export declare function readFields(value: unknown): Record<string, unknown>;
|
|
29
|
+
/** Reject published entries that are missing visible required fields. */
|
|
30
|
+
export declare function requirePublishedFields(def: CollectionDefinition, status: CollectionStatus, fields: Record<string, unknown>): void;
|
|
31
|
+
export declare function readParentId(value: unknown): number | null;
|
|
32
|
+
export declare function readAuthorId(value: unknown): number;
|
|
33
|
+
/** Resolve `authorId` from the request. Assigning another user requires `users:read`. */
|
|
34
|
+
export declare function resolveAuthorId(db: Parameters<typeof findUserById>[0], actor: SafeUser, roles: RoleMap, requested: unknown, fallback: number): Promise<number>;
|
|
35
|
+
export declare function readMenuOrder(value: unknown, fallback?: number): number;
|
|
36
|
+
/** `undefined` = omit from patch; `null` = clear. */
|
|
37
|
+
export declare function readPublishedAt(value: unknown): Date | null | undefined;
|
|
38
|
+
export declare function readListStatus(value: unknown): CollectionListStatus;
|
|
39
|
+
export declare function readPage(value: unknown): number;
|
|
40
|
+
export declare function readPerPage(value: unknown, fallback?: number): number;
|
|
41
|
+
export declare function readSearch(value: unknown): string;
|
|
42
|
+
export declare function rethrowCollectionWriteError(error: unknown): never;
|
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
import { createError } from "h3";
|
|
2
|
+
import { useRuntimeConfig } from "#imports";
|
|
3
|
+
import {
|
|
4
|
+
can,
|
|
5
|
+
canOnEntry,
|
|
6
|
+
collectionPerPage,
|
|
7
|
+
DEFAULT_COLLECTION_PER_PAGE,
|
|
8
|
+
findUserById,
|
|
9
|
+
formatRequiredFieldsError,
|
|
10
|
+
isUniqueConstraintError,
|
|
11
|
+
parseDate,
|
|
12
|
+
UNLIMITED_COLLECTION_PER_PAGE,
|
|
13
|
+
validateRequiredFields
|
|
14
|
+
} from "@katecms/core";
|
|
15
|
+
const ENTRY_STATUSES = ["published", "draft", "trash"];
|
|
16
|
+
const LIST_STATUSES = ["published", "draft", "trash", "active", "all"];
|
|
17
|
+
const SLUG_PATTERN = /^[a-z0-9]+(?:-[a-z0-9]+)*$/i;
|
|
18
|
+
const STATUS_PHRASE = {
|
|
19
|
+
400: "Bad Request",
|
|
20
|
+
403: "Forbidden",
|
|
21
|
+
404: "Not Found",
|
|
22
|
+
409: "Conflict",
|
|
23
|
+
422: "Unprocessable Entity"
|
|
24
|
+
};
|
|
25
|
+
export function fail(statusCode, message) {
|
|
26
|
+
throw createError({
|
|
27
|
+
statusCode,
|
|
28
|
+
statusMessage: STATUS_PHRASE[statusCode] ?? "Error",
|
|
29
|
+
message
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
export function getCollections() {
|
|
33
|
+
return useRuntimeConfig().katecms?.collections ?? {};
|
|
34
|
+
}
|
|
35
|
+
export function getCollectionDefinition(slug) {
|
|
36
|
+
return getCollections()[slug];
|
|
37
|
+
}
|
|
38
|
+
export function requireCollection(slug) {
|
|
39
|
+
const collection = getCollectionDefinition(slug);
|
|
40
|
+
if (!collection) {
|
|
41
|
+
fail(404, "Collection not found.");
|
|
42
|
+
}
|
|
43
|
+
return collection;
|
|
44
|
+
}
|
|
45
|
+
export function toCollectionMeta(slug, def) {
|
|
46
|
+
return {
|
|
47
|
+
slug,
|
|
48
|
+
labels: {
|
|
49
|
+
name: def.labels.name,
|
|
50
|
+
singularName: def.labels.singularName ?? def.labels.name
|
|
51
|
+
},
|
|
52
|
+
hierarchical: def.hierarchical === true,
|
|
53
|
+
autosave: def.autosave === true,
|
|
54
|
+
revisions: def.revisions !== false,
|
|
55
|
+
public: def.public !== false,
|
|
56
|
+
has_archive: typeof def.has_archive === "string" ? def.has_archive : def.has_archive === true,
|
|
57
|
+
perPage: collectionPerPage(def),
|
|
58
|
+
rewrite: def.rewrite,
|
|
59
|
+
fields: def.fields ?? {}
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
export function collectionRevisionsEnabled(def) {
|
|
63
|
+
return def.revisions !== false;
|
|
64
|
+
}
|
|
65
|
+
function toIso(value) {
|
|
66
|
+
if (value == null) {
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
if (value instanceof Date) {
|
|
70
|
+
return Number.isNaN(value.getTime()) ? null : value.toISOString();
|
|
71
|
+
}
|
|
72
|
+
const date = new Date(value);
|
|
73
|
+
return Number.isNaN(date.getTime()) ? null : date.toISOString();
|
|
74
|
+
}
|
|
75
|
+
export function toAdminEntry(row, slugPath, flags) {
|
|
76
|
+
return {
|
|
77
|
+
id: row.id,
|
|
78
|
+
type: row.type,
|
|
79
|
+
status: row.status,
|
|
80
|
+
slug: row.slug,
|
|
81
|
+
slugPath: slugPath || row.slug,
|
|
82
|
+
title: row.title,
|
|
83
|
+
fields: row.fields ?? {},
|
|
84
|
+
parentId: row.parent_id,
|
|
85
|
+
menuOrder: row.menu_order,
|
|
86
|
+
authorId: row.author_id,
|
|
87
|
+
createdAt: toIso(row.created_at) ?? (/* @__PURE__ */ new Date(0)).toISOString(),
|
|
88
|
+
updatedAt: toIso(row.updated_at) ?? (/* @__PURE__ */ new Date(0)).toISOString(),
|
|
89
|
+
publishedAt: toIso(row.published_at),
|
|
90
|
+
...flags
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
export function entryFlags(actor, row, roles) {
|
|
94
|
+
const entry = { authorId: row.author_id };
|
|
95
|
+
return {
|
|
96
|
+
canUpdate: canOnEntry(actor, "collections", "update", entry, {
|
|
97
|
+
roles,
|
|
98
|
+
scope: row.type,
|
|
99
|
+
userId: actor.id
|
|
100
|
+
}),
|
|
101
|
+
canDelete: canOnEntry(actor, "collections", "delete", entry, {
|
|
102
|
+
roles,
|
|
103
|
+
scope: row.type,
|
|
104
|
+
userId: actor.id
|
|
105
|
+
})
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
export function toParentOption(row) {
|
|
109
|
+
return {
|
|
110
|
+
id: row.id,
|
|
111
|
+
title: row.title,
|
|
112
|
+
slug: row.slug,
|
|
113
|
+
parentId: row.parentId,
|
|
114
|
+
slugPath: row.slugPath,
|
|
115
|
+
depth: row.depth
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
export function readCollectionSlug(raw) {
|
|
119
|
+
const slug = typeof raw === "string" ? raw.trim() : "";
|
|
120
|
+
if (!slug) {
|
|
121
|
+
fail(400, "Collection is required.");
|
|
122
|
+
}
|
|
123
|
+
return slug;
|
|
124
|
+
}
|
|
125
|
+
export function readEntryId(raw) {
|
|
126
|
+
const id = Number(raw);
|
|
127
|
+
if (!Number.isInteger(id) || id <= 0) {
|
|
128
|
+
fail(400, "Invalid entry id.");
|
|
129
|
+
}
|
|
130
|
+
return id;
|
|
131
|
+
}
|
|
132
|
+
export function readTitle(value) {
|
|
133
|
+
if (typeof value !== "string" || !value.trim()) {
|
|
134
|
+
fail(422, "Title is required.");
|
|
135
|
+
}
|
|
136
|
+
return value.trim();
|
|
137
|
+
}
|
|
138
|
+
export function readSlug(value) {
|
|
139
|
+
if (typeof value !== "string" || !value.trim()) {
|
|
140
|
+
fail(422, "Slug is required.");
|
|
141
|
+
}
|
|
142
|
+
const slug = value.trim();
|
|
143
|
+
if (!SLUG_PATTERN.test(slug)) {
|
|
144
|
+
fail(422, "Slug may contain only letters, numbers, and hyphens.");
|
|
145
|
+
}
|
|
146
|
+
return slug;
|
|
147
|
+
}
|
|
148
|
+
export function readStatus(value, fallback = "draft") {
|
|
149
|
+
if (value === void 0 || value === null || value === "") {
|
|
150
|
+
return fallback;
|
|
151
|
+
}
|
|
152
|
+
if (typeof value !== "string" || !ENTRY_STATUSES.includes(value)) {
|
|
153
|
+
fail(422, "Invalid status.");
|
|
154
|
+
}
|
|
155
|
+
return value;
|
|
156
|
+
}
|
|
157
|
+
export function readFields(value) {
|
|
158
|
+
if (value === void 0 || value === null) {
|
|
159
|
+
return {};
|
|
160
|
+
}
|
|
161
|
+
if (typeof value !== "object" || Array.isArray(value)) {
|
|
162
|
+
fail(422, "Invalid field values.");
|
|
163
|
+
}
|
|
164
|
+
return value;
|
|
165
|
+
}
|
|
166
|
+
export function requirePublishedFields(def, status, fields) {
|
|
167
|
+
if (status !== "published") {
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
const issues = validateRequiredFields(def.fields ?? {}, fields);
|
|
171
|
+
if (issues.length > 0) {
|
|
172
|
+
fail(422, formatRequiredFieldsError(issues));
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
export function readParentId(value) {
|
|
176
|
+
if (value === void 0 || value === null || value === "") {
|
|
177
|
+
return null;
|
|
178
|
+
}
|
|
179
|
+
const id = typeof value === "number" ? value : Number(value);
|
|
180
|
+
if (!Number.isInteger(id) || id <= 0) {
|
|
181
|
+
fail(422, "Invalid parent.");
|
|
182
|
+
}
|
|
183
|
+
return id;
|
|
184
|
+
}
|
|
185
|
+
export function readAuthorId(value) {
|
|
186
|
+
const id = typeof value === "number" ? value : Number(value);
|
|
187
|
+
if (!Number.isInteger(id) || id <= 0) {
|
|
188
|
+
fail(422, "Invalid author.");
|
|
189
|
+
}
|
|
190
|
+
return id;
|
|
191
|
+
}
|
|
192
|
+
export async function resolveAuthorId(db, actor, roles, requested, fallback) {
|
|
193
|
+
if (requested === void 0 || requested === null || requested === "") {
|
|
194
|
+
return fallback;
|
|
195
|
+
}
|
|
196
|
+
const id = readAuthorId(requested);
|
|
197
|
+
if (id === fallback) {
|
|
198
|
+
return id;
|
|
199
|
+
}
|
|
200
|
+
if (id !== actor.id && !can(actor, "users", "read", { roles })) {
|
|
201
|
+
fail(403, "Insufficient permissions.");
|
|
202
|
+
}
|
|
203
|
+
const user = await findUserById(db, id);
|
|
204
|
+
if (!user) {
|
|
205
|
+
fail(422, "Author not found.");
|
|
206
|
+
}
|
|
207
|
+
return id;
|
|
208
|
+
}
|
|
209
|
+
export function readMenuOrder(value, fallback = 0) {
|
|
210
|
+
if (value === void 0 || value === null || value === "") {
|
|
211
|
+
return fallback;
|
|
212
|
+
}
|
|
213
|
+
const n = typeof value === "number" ? value : Number(value);
|
|
214
|
+
if (!Number.isInteger(n)) {
|
|
215
|
+
fail(422, "Invalid menu order.");
|
|
216
|
+
}
|
|
217
|
+
return n;
|
|
218
|
+
}
|
|
219
|
+
export function readPublishedAt(value) {
|
|
220
|
+
if (value === void 0) {
|
|
221
|
+
return void 0;
|
|
222
|
+
}
|
|
223
|
+
if (value === null || value === "") {
|
|
224
|
+
return null;
|
|
225
|
+
}
|
|
226
|
+
if (typeof value === "number" && Number.isFinite(value)) {
|
|
227
|
+
const date = new Date(value);
|
|
228
|
+
if (!Number.isNaN(date.getTime())) {
|
|
229
|
+
return date;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
if (typeof value === "string") {
|
|
233
|
+
const iso = new Date(value);
|
|
234
|
+
if (!Number.isNaN(iso.getTime())) {
|
|
235
|
+
return iso;
|
|
236
|
+
}
|
|
237
|
+
const parsed = parseDate(value, "YYYY-MM-DD HH:mm") ?? parseDate(value, "YYYY-MM-DD");
|
|
238
|
+
if (parsed) {
|
|
239
|
+
return parsed;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
fail(422, "Invalid publish date.");
|
|
243
|
+
}
|
|
244
|
+
export function readListStatus(value) {
|
|
245
|
+
if (value === void 0 || value === null || value === "") {
|
|
246
|
+
return "active";
|
|
247
|
+
}
|
|
248
|
+
if (value === "all") {
|
|
249
|
+
return "active";
|
|
250
|
+
}
|
|
251
|
+
if (typeof value === "string" && LIST_STATUSES.includes(value)) {
|
|
252
|
+
return value;
|
|
253
|
+
}
|
|
254
|
+
fail(400, "Invalid status filter.");
|
|
255
|
+
}
|
|
256
|
+
export function readPage(value) {
|
|
257
|
+
if (value === void 0 || value === null || value === "") {
|
|
258
|
+
return 1;
|
|
259
|
+
}
|
|
260
|
+
const n = Number(value);
|
|
261
|
+
if (!Number.isInteger(n) || n < 1) {
|
|
262
|
+
fail(400, "Invalid page.");
|
|
263
|
+
}
|
|
264
|
+
return n;
|
|
265
|
+
}
|
|
266
|
+
export function readPerPage(value, fallback = DEFAULT_COLLECTION_PER_PAGE) {
|
|
267
|
+
if (value === void 0 || value === null || value === "") {
|
|
268
|
+
if (fallback === UNLIMITED_COLLECTION_PER_PAGE) {
|
|
269
|
+
return UNLIMITED_COLLECTION_PER_PAGE;
|
|
270
|
+
}
|
|
271
|
+
if (!Number.isInteger(fallback) || fallback < 1) {
|
|
272
|
+
return DEFAULT_COLLECTION_PER_PAGE;
|
|
273
|
+
}
|
|
274
|
+
return fallback;
|
|
275
|
+
}
|
|
276
|
+
const n = Number(value);
|
|
277
|
+
if (n === UNLIMITED_COLLECTION_PER_PAGE) {
|
|
278
|
+
return UNLIMITED_COLLECTION_PER_PAGE;
|
|
279
|
+
}
|
|
280
|
+
if (!Number.isInteger(n) || n < 1) {
|
|
281
|
+
fail(400, "Invalid page size.");
|
|
282
|
+
}
|
|
283
|
+
return n;
|
|
284
|
+
}
|
|
285
|
+
export function readSearch(value) {
|
|
286
|
+
if (typeof value !== "string") {
|
|
287
|
+
return "";
|
|
288
|
+
}
|
|
289
|
+
return value.trim().slice(0, 200);
|
|
290
|
+
}
|
|
291
|
+
export function rethrowCollectionWriteError(error) {
|
|
292
|
+
if (isUniqueConstraintError(error)) {
|
|
293
|
+
fail(409, "An entry with this slug already exists.");
|
|
294
|
+
}
|
|
295
|
+
const message = error instanceof Error ? error.message : "";
|
|
296
|
+
if (/parent/i.test(message) || /descendant/i.test(message) || /hierarchy/i.test(message)) {
|
|
297
|
+
fail(422, message.startsWith("collections:") ? "Invalid parent entry." : message);
|
|
298
|
+
}
|
|
299
|
+
throw error;
|
|
300
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { useRuntimeConfig } from "#imports";
|
|
2
|
+
import {
|
|
3
|
+
createPostgresDb,
|
|
4
|
+
createSqliteDb,
|
|
5
|
+
resolveDatabaseTarget
|
|
6
|
+
} from "@katecms/core";
|
|
7
|
+
let db;
|
|
8
|
+
function trimEnv(value) {
|
|
9
|
+
return typeof value === "string" ? value.trim() : "";
|
|
10
|
+
}
|
|
11
|
+
export function getDb() {
|
|
12
|
+
if (db) {
|
|
13
|
+
return db;
|
|
14
|
+
}
|
|
15
|
+
const database = useRuntimeConfig().katecms?.database;
|
|
16
|
+
const driver = trimEnv(database?.driver);
|
|
17
|
+
const url = trimEnv(database?.url) || (driver === "postgres" ? trimEnv(process.env.DATABASE_URL) : "");
|
|
18
|
+
const target = resolveDatabaseTarget({
|
|
19
|
+
driver,
|
|
20
|
+
url,
|
|
21
|
+
sqliteFilename: database?.sqliteFilename
|
|
22
|
+
});
|
|
23
|
+
db = target.driver === "postgres" ? createPostgresDb(target.url) : createSqliteDb({ filename: target.filename });
|
|
24
|
+
return db;
|
|
25
|
+
}
|