@pro-laico/create-atomic-payload 0.1.4
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/bin/cli.js +159 -0
- package/package.json +29 -0
- package/template/.env.example +35 -0
- package/template/.gitattributes +2 -0
- package/template/.prettierrc.json +6 -0
- package/template/.vscode/extensions.json +3 -0
- package/template/.vscode/launch.json +24 -0
- package/template/.vscode/settings.json +86 -0
- package/template/.yarnrc +1 -0
- package/template/LICENSE.md +22 -0
- package/template/README.md +128 -0
- package/template/eslint.config.mjs +32 -0
- package/template/next-env.d.ts +6 -0
- package/template/next.config.ts +36 -0
- package/template/package.json +75 -0
- package/template/public/adminFavicon.svg +1 -0
- package/template/public/ogImage.webp +0 -0
- package/template/src/access/anyone.ts +3 -0
- package/template/src/access/authenticated.ts +7 -0
- package/template/src/access/authenticatedOrPublished.ts +6 -0
- package/template/src/app/(frontend)/[...slug]/page.tsx +48 -0
- package/template/src/app/(frontend)/layout.tsx +49 -0
- package/template/src/app/(frontend)/next/exit-preview/route.ts +7 -0
- package/template/src/app/(frontend)/next/preview/route.ts +45 -0
- package/template/src/app/(frontend)/next/seed/route.ts +31 -0
- package/template/src/app/(frontend)/not-found.tsx +93 -0
- package/template/src/app/(frontend)/page.tsx +5 -0
- package/template/src/app/(frontend)/sitemap.ts +14 -0
- package/template/src/app/(payload)/admin/[[...segments]]/not-found.tsx +24 -0
- package/template/src/app/(payload)/admin/[[...segments]]/page.tsx +24 -0
- package/template/src/app/(payload)/admin/importMap.js +85 -0
- package/template/src/app/(payload)/api/[...slug]/route.ts +19 -0
- package/template/src/app/(payload)/custom.scss +29 -0
- package/template/src/app/(payload)/layout.tsx +31 -0
- package/template/src/blocks/actions/blocks.ts +27 -0
- package/template/src/blocks/actions/cookieConsent/set/block.ts +17 -0
- package/template/src/blocks/actions/cookieConsent/set/filter.ts +3 -0
- package/template/src/blocks/actions/cookieConsent/set/options.ts +35 -0
- package/template/src/blocks/actions/cookieConsent/toDA/block.ts +14 -0
- package/template/src/blocks/actions/cookieConsent/toDA/filter.ts +3 -0
- package/template/src/blocks/actions/cookieConsent/toDA/options.ts +19 -0
- package/template/src/blocks/actions/dynamicStore/boolean/set/block.ts +15 -0
- package/template/src/blocks/actions/dynamicStore/boolean/set/filter.ts +4 -0
- package/template/src/blocks/actions/dynamicStore/boolean/set/options.ts +18 -0
- package/template/src/blocks/actions/dynamicStore/boolean/toDA/block.ts +10 -0
- package/template/src/blocks/actions/dynamicStore/boolean/toDA/filter.ts +3 -0
- package/template/src/blocks/actions/dynamicStore/boolean/toDA/options.ts +12 -0
- package/template/src/blocks/actions/dynamicStore/text/cycle/block.ts +41 -0
- package/template/src/blocks/actions/dynamicStore/text/cycle/filter.ts +4 -0
- package/template/src/blocks/actions/dynamicStore/text/cycle/options.ts +23 -0
- package/template/src/blocks/actions/dynamicStore/text/toDA/block.ts +10 -0
- package/template/src/blocks/actions/dynamicStore/text/toDA/filter.ts +3 -0
- package/template/src/blocks/actions/dynamicStore/text/toDA/options.ts +12 -0
- package/template/src/blocks/actions/filters.ts +27 -0
- package/template/src/blocks/actions/form/errorToDA/block.ts +18 -0
- package/template/src/blocks/actions/form/errorToDA/filter.ts +3 -0
- package/template/src/blocks/actions/form/errorToDA/options.ts +15 -0
- package/template/src/blocks/actions/form/reset/block.ts +18 -0
- package/template/src/blocks/actions/form/reset/filter.ts +3 -0
- package/template/src/blocks/actions/form/reset/options.ts +30 -0
- package/template/src/blocks/actions/form/statusToDA/block.ts +12 -0
- package/template/src/blocks/actions/form/statusToDA/filter.ts +3 -0
- package/template/src/blocks/actions/form/statusToDA/options.ts +15 -0
- package/template/src/blocks/actions/form/submit/block.ts +18 -0
- package/template/src/blocks/actions/form/submit/filter.ts +3 -0
- package/template/src/blocks/actions/form/submit/options.ts +35 -0
- package/template/src/blocks/actions/portal/set/block.ts +25 -0
- package/template/src/blocks/actions/portal/set/filter.ts +3 -0
- package/template/src/blocks/actions/portal/set/options.ts +43 -0
- package/template/src/blocks/actions/processor.ts +263 -0
- package/template/src/blocks/actions/theme/set/block.ts +10 -0
- package/template/src/blocks/actions/theme/set/filter.ts +3 -0
- package/template/src/blocks/actions/theme/set/options.ts +9 -0
- package/template/src/blocks/actions/zap.ts +4 -0
- package/template/src/blocks/children/atomic/block.ts +123 -0
- package/template/src/blocks/children/atomic/controlBar.ts +43 -0
- package/template/src/blocks/children/atomic/variants/button/typeField.ts +16 -0
- package/template/src/blocks/children/atomic/variants/button/variants/link/component.client.tsx +21 -0
- package/template/src/blocks/children/atomic/variants/button/variants/link/component.tsx +13 -0
- package/template/src/blocks/children/atomic/variants/button/variants/link/controlBar.ts +73 -0
- package/template/src/blocks/children/atomic/variants/button/variants/link/settings.ts +26 -0
- package/template/src/blocks/children/atomic/variants/button/variants/portal/controlBar.ts +35 -0
- package/template/src/blocks/children/atomic/variants/button/variants/portal/dialog/component.tsx +36 -0
- package/template/src/blocks/children/atomic/variants/button/variants/portal/dialog/settings.ts +24 -0
- package/template/src/blocks/children/atomic/variants/button/variants/portal/popover/component.tsx +41 -0
- package/template/src/blocks/children/atomic/variants/button/variants/portal/popover/settings.ts +111 -0
- package/template/src/blocks/children/atomic/variants/button/variants/regular/component.client.tsx +19 -0
- package/template/src/blocks/children/atomic/variants/button/variants/regular/component.tsx +11 -0
- package/template/src/blocks/children/atomic/variants/form/component.tsx +18 -0
- package/template/src/blocks/children/atomic/variants/form/controlBar.ts +22 -0
- package/template/src/blocks/children/atomic/variants/form/settings.ts +20 -0
- package/template/src/blocks/children/atomic/variants/input/autoCompleteOptions.ts +51 -0
- package/template/src/blocks/children/atomic/variants/input/controlBar.ts +13 -0
- package/template/src/blocks/children/atomic/variants/input/settings.ts +35 -0
- package/template/src/blocks/children/atomic/variants/input/typeField.ts +23 -0
- package/template/src/blocks/children/atomic/variants/input/variants/checkBox/component.client.tsx +12 -0
- package/template/src/blocks/children/atomic/variants/input/variants/checkBox/component.tsx +6 -0
- package/template/src/blocks/children/atomic/variants/input/variants/checkBox/settings.ts +9 -0
- package/template/src/blocks/children/atomic/variants/input/variants/number/component.client.tsx +12 -0
- package/template/src/blocks/children/atomic/variants/input/variants/number/component.tsx +6 -0
- package/template/src/blocks/children/atomic/variants/input/variants/number/settings.ts +9 -0
- package/template/src/blocks/children/atomic/variants/input/variants/radio/component.client.tsx +12 -0
- package/template/src/blocks/children/atomic/variants/input/variants/radio/component.tsx +6 -0
- package/template/src/blocks/children/atomic/variants/input/variants/radio/settings.ts +9 -0
- package/template/src/blocks/children/atomic/variants/input/variants/text/component.client.tsx +12 -0
- package/template/src/blocks/children/atomic/variants/input/variants/text/component.tsx +7 -0
- package/template/src/blocks/children/atomic/variants/input/variants/text/settings.ts +12 -0
- package/template/src/blocks/children/atomic/variants/tag/component.client.tsx +17 -0
- package/template/src/blocks/children/atomic/variants/tag/component.tsx +13 -0
- package/template/src/blocks/children/atomic/variants/tag/controlBar.ts +6 -0
- package/template/src/blocks/children/atomic/variants/tag/settings.ts +9 -0
- package/template/src/blocks/children/blocks.ts +13 -0
- package/template/src/blocks/children/icon/block.ts +41 -0
- package/template/src/blocks/children/icon/component.tsx +17 -0
- package/template/src/blocks/children/image/block.ts +80 -0
- package/template/src/blocks/children/image/component.tsx +21 -0
- package/template/src/blocks/children/richText/block.ts +50 -0
- package/template/src/blocks/children/richText/component/converters/index.tsx +10 -0
- package/template/src/blocks/children/richText/component/converters/internalLink.tsx +8 -0
- package/template/src/blocks/children/richText/component/index.tsx +10 -0
- package/template/src/blocks/children/richText/component.tsx +7 -0
- package/template/src/blocks/children/richText/defaultLexical.ts +65 -0
- package/template/src/blocks/children/simpleText/block.ts +41 -0
- package/template/src/blocks/children/simpleText/component.client.tsx +18 -0
- package/template/src/blocks/children/simpleText/component.tsx +11 -0
- package/template/src/blocks/children/svg/block.ts +39 -0
- package/template/src/blocks/children/svg/component.tsx +6 -0
- package/template/src/blocks/children/video/block.ts +70 -0
- package/template/src/blocks/children/video/component.tsx +11 -0
- package/template/src/blocks/children/zap.ts +54 -0
- package/template/src/blocks/submitForm/form/rateLimiting/blocks.ts +5 -0
- package/template/src/blocks/submitForm/form/rateLimiting/functions.ts +1 -0
- package/template/src/blocks/submitForm/form/rateLimiting/simpleSlidingWindow/block.ts +23 -0
- package/template/src/blocks/submitForm/form/rateLimiting/simpleSlidingWindow/serverFunction.ts +46 -0
- package/template/src/blocks/submitForm/form/sanitation/blocks.ts +6 -0
- package/template/src/blocks/submitForm/form/sanitation/combineTwoFields/block.ts +19 -0
- package/template/src/blocks/submitForm/form/sanitation/combineTwoFields/serverFunction.ts +22 -0
- package/template/src/blocks/submitForm/form/sanitation/functions.ts +1 -0
- package/template/src/blocks/submitForm/form/validation/blocks.ts +6 -0
- package/template/src/blocks/submitForm/form/validation/functions.ts +1 -0
- package/template/src/blocks/submitForm/form/validation/isUnique/block.ts +19 -0
- package/template/src/blocks/submitForm/form/validation/isUnique/serverFunction.ts +40 -0
- package/template/src/blocks/submitForm/form/zap.ts +8 -0
- package/template/src/blocks/submitForm/formProcessor.ts +222 -0
- package/template/src/blocks/submitForm/input/sanitation/blocks.ts +5 -0
- package/template/src/blocks/submitForm/input/sanitation/functions.ts +1 -0
- package/template/src/blocks/submitForm/input/sanitation/trimText/block.ts +24 -0
- package/template/src/blocks/submitForm/input/sanitation/trimText/serverFunction.ts +63 -0
- package/template/src/blocks/submitForm/input/useOn.ts +8 -0
- package/template/src/blocks/submitForm/input/validation/blocks.ts +6 -0
- package/template/src/blocks/submitForm/input/validation/contains/block.ts +12 -0
- package/template/src/blocks/submitForm/input/validation/contains/serverFunction.ts +23 -0
- package/template/src/blocks/submitForm/input/validation/doesNotContain/block.ts +12 -0
- package/template/src/blocks/submitForm/input/validation/doesNotContain/serverFunction.ts +23 -0
- package/template/src/blocks/submitForm/input/validation/functions.ts +2 -0
- package/template/src/blocks/submitForm/input/zap.ts +6 -0
- package/template/src/blocks/submitForm/serverFunction.ts +42 -0
- package/template/src/collections/designSets/collection.ts +44 -0
- package/template/src/collections/designSets/defaults.ts +20 -0
- package/template/src/collections/designSets/tabs/animation.ts +71 -0
- package/template/src/collections/designSets/tabs/colors.ts +31 -0
- package/template/src/collections/designSets/tabs/fonts.ts +53 -0
- package/template/src/collections/designSets/tabs/miscellaneous.ts +22 -0
- package/template/src/collections/designSets/tabs/prose.ts +151 -0
- package/template/src/collections/designSets/tabs/settings.ts +52 -0
- package/template/src/collections/designSets/tabs/sizes.ts +30 -0
- package/template/src/collections/designSets/tabs/storage.ts +51 -0
- package/template/src/collections/designSets/tabs/variables.ts +28 -0
- package/template/src/collections/favicons.ts +11 -0
- package/template/src/collections/fonts/collection.ts +20 -0
- package/template/src/collections/fonts/script.ts +199 -0
- package/template/src/collections/footers/collection.ts +48 -0
- package/template/src/collections/footers/component.tsx +13 -0
- package/template/src/collections/headers/collection.ts +47 -0
- package/template/src/collections/headers/component.tsx +13 -0
- package/template/src/collections/iconSets/collection.ts +80 -0
- package/template/src/collections/iconSets/defaults.ts +81 -0
- package/template/src/collections/icons.ts +20 -0
- package/template/src/collections/images.ts +29 -0
- package/template/src/collections/index.ts +17 -0
- package/template/src/collections/muxVideos.ts +13 -0
- package/template/src/collections/pages/collection.ts +88 -0
- package/template/src/collections/pages/tabs/SEO.ts +70 -0
- package/template/src/collections/pages/tabs/settings.ts +17 -0
- package/template/src/collections/posthogProperty.ts +48 -0
- package/template/src/collections/shortcutSets/collection.ts +30 -0
- package/template/src/collections/shortcutSets/defaults.ts +1 -0
- package/template/src/collections/shortcutSets/protectedNames.ts +135 -0
- package/template/src/collections/shortcutSets/tabs/settings.ts +13 -0
- package/template/src/collections/shortcutSets/tabs/shortcuts.ts +70 -0
- package/template/src/collections/users.ts +11 -0
- package/template/src/collections/zap.ts +59 -0
- package/template/src/components/child/SSRProps.ts +381 -0
- package/template/src/components/child/renderChildren.tsx +148 -0
- package/template/src/components/livePreviewListener.tsx +10 -0
- package/template/src/components/providers/formProvider.tsx +11 -0
- package/template/src/components/providers/tracking/gtm.tsx +11 -0
- package/template/src/components/providers/tracking/index.tsx +46 -0
- package/template/src/components/providers/tracking/postHog.tsx +41 -0
- package/template/src/components/providers/tracking/vercel.tsx +10 -0
- package/template/src/components/toast/index.module.css +142 -0
- package/template/src/components/toast/index.tsx +55 -0
- package/template/src/endpoints/seed/backendForm.ts +48 -0
- package/template/src/endpoints/seed/designSet.ts +476 -0
- package/template/src/endpoints/seed/footer.ts +389 -0
- package/template/src/endpoints/seed/header.ts +3511 -0
- package/template/src/endpoints/seed/iconSet.ts +19 -0
- package/template/src/endpoints/seed/icons/assets/check.svg +4 -0
- package/template/src/endpoints/seed/icons/assets/close.svg +4 -0
- package/template/src/endpoints/seed/icons/assets/cookie.svg +7 -0
- package/template/src/endpoints/seed/icons/assets/github.svg +1 -0
- package/template/src/endpoints/seed/icons/assets/logo.svg +11 -0
- package/template/src/endpoints/seed/icons/assets/menu.svg +4 -0
- package/template/src/endpoints/seed/icons/assets/theme.svg +4 -0
- package/template/src/endpoints/seed/icons/check.ts +14 -0
- package/template/src/endpoints/seed/icons/close.ts +14 -0
- package/template/src/endpoints/seed/icons/cookie.ts +14 -0
- package/template/src/endpoints/seed/icons/github.ts +14 -0
- package/template/src/endpoints/seed/icons/index.ts +7 -0
- package/template/src/endpoints/seed/icons/logo.ts +14 -0
- package/template/src/endpoints/seed/icons/menu.ts +14 -0
- package/template/src/endpoints/seed/icons/theme.ts +14 -0
- package/template/src/endpoints/seed/index.ts +100 -0
- package/template/src/endpoints/seed/pages/home.ts +858 -0
- package/template/src/endpoints/seed/pages/index.ts +4 -0
- package/template/src/endpoints/seed/pages/notFoundPage.ts +287 -0
- package/template/src/endpoints/seed/pages/prose.ts +1436 -0
- package/template/src/endpoints/seed/pages/testing.ts +2181 -0
- package/template/src/endpoints/seed/shortcutSet.ts +187 -0
- package/template/src/endpoints/seed/siteMetaData.ts +10 -0
- package/template/src/fields/actions/changeKey.ts +12 -0
- package/template/src/fields/actions/index.ts +6 -0
- package/template/src/fields/actions/initialValueCheckbox.ts +14 -0
- package/template/src/fields/actions/keyText.ts +10 -0
- package/template/src/fields/actions/persisted.ts +14 -0
- package/template/src/fields/actions/setData.ts +20 -0
- package/template/src/fields/actions/strict/index.ts +3 -0
- package/template/src/fields/actions/strict/keySelect.ts +28 -0
- package/template/src/fields/actions/strict/listenSelect.ts +28 -0
- package/template/src/fields/actions/strict/performSelect.ts +30 -0
- package/template/src/fields/actions/strict/registry/cookieConsent.ts +14 -0
- package/template/src/fields/actions/strict/registry/index.ts +6 -0
- package/template/src/fields/actions/strict/registry/theme.ts +9 -0
- package/template/src/fields/active.ts +16 -0
- package/template/src/fields/apf/index.ts +69 -0
- package/template/src/fields/apf/storage.ts +38 -0
- package/template/src/fields/blocks/actions.ts +30 -0
- package/template/src/fields/blocks/backdropChildren.ts +11 -0
- package/template/src/fields/blocks/children.ts +15 -0
- package/template/src/fields/blocks/submitForm/form.ts +24 -0
- package/template/src/fields/blocks/submitForm/input.ts +25 -0
- package/template/src/fields/className.ts +26 -0
- package/template/src/fields/coloredEnd.ts +5 -0
- package/template/src/fields/defaultOpen.ts +14 -0
- package/template/src/fields/designSets/value.ts +80 -0
- package/template/src/fields/devMode.ts +11 -0
- package/template/src/fields/favicon.ts +18 -0
- package/template/src/fields/for.ts +11 -0
- package/template/src/fields/keepMounted.ts +11 -0
- package/template/src/fields/modal.ts +16 -0
- package/template/src/fields/slug.ts +35 -0
- package/template/src/fields/staticDataAttributes.ts +29 -0
- package/template/src/fields/tabs/block/children/actions.ts +49 -0
- package/template/src/fields/tabs/block/children/backdrop.ts +17 -0
- package/template/src/fields/tabs/block/children/settings.ts +45 -0
- package/template/src/fields/tabs/block/children/submitForm/form.ts +23 -0
- package/template/src/fields/tabs/block/children/submitForm/input.ts +14 -0
- package/template/src/fields/tabs/block/children/tracking.ts +25 -0
- package/template/src/fields/tabs/collection/storage.ts +55 -0
- package/template/src/fields/tagType.ts +32 -0
- package/template/src/fields/testPath.ts +3 -0
- package/template/src/fields/uniqueTitle.ts +8 -0
- package/template/src/fields/validationMessage.ts +13 -0
- package/template/src/globals/index.ts +8 -0
- package/template/src/globals/settings.ts +36 -0
- package/template/src/globals/siteMetaData.ts +29 -0
- package/template/src/globals/storage.ts +15 -0
- package/template/src/globals/tracking/global.ts +25 -0
- package/template/src/globals/tracking/tabs/gtm.ts +18 -0
- package/template/src/globals/tracking/tabs/postHog.ts +35 -0
- package/template/src/hooks/collection/atomicHook/atomicHook.ts +223 -0
- package/template/src/hooks/collection/atomicHook/processors/cssProcessor.ts +60 -0
- package/template/src/hooks/collection/atomicHook/processors/processDesignSet/generatePreflights.ts +36 -0
- package/template/src/hooks/collection/atomicHook/processors/processDesignSet/index.ts +176 -0
- package/template/src/hooks/collection/atomicHook/processors/unsetActive.ts +24 -0
- package/template/src/hooks/collection/formatSVG.ts +157 -0
- package/template/src/hooks/collection/revalidate.ts +53 -0
- package/template/src/hooks/collection/sanitizeCollection.ts +5 -0
- package/template/src/hooks/field/apf.ts +59 -0
- package/template/src/hooks/field/formatSlug.ts +23 -0
- package/template/src/hooks/field/href.ts +6 -0
- package/template/src/hooks/field/publishedAt.ts +5 -0
- package/template/src/hooks/frontEnd/atomicStore/create.ts +69 -0
- package/template/src/hooks/frontEnd/atomicStore/index.tsx +20 -0
- package/template/src/hooks/frontEnd/atomicStore/slices/base.ts +7 -0
- package/template/src/hooks/frontEnd/atomicStore/slices/consent.ts +76 -0
- package/template/src/hooks/frontEnd/atomicStore/slices/dynamic.ts +51 -0
- package/template/src/hooks/frontEnd/useActions/dispatch/attributer/boolToDA/function.ts +14 -0
- package/template/src/hooks/frontEnd/useActions/dispatch/attributer/boolToDA/zap.ts +12 -0
- package/template/src/hooks/frontEnd/useActions/dispatch/attributer/cCToDA/function.ts +34 -0
- package/template/src/hooks/frontEnd/useActions/dispatch/attributer/cCToDA/zap.ts +17 -0
- package/template/src/hooks/frontEnd/useActions/dispatch/attributer/errorToDA/function.ts +22 -0
- package/template/src/hooks/frontEnd/useActions/dispatch/attributer/errorToDA/zap.ts +10 -0
- package/template/src/hooks/frontEnd/useActions/dispatch/attributer/function.ts +20 -0
- package/template/src/hooks/frontEnd/useActions/dispatch/attributer/statusToDA/function.ts +24 -0
- package/template/src/hooks/frontEnd/useActions/dispatch/attributer/statusToDA/zap.ts +10 -0
- package/template/src/hooks/frontEnd/useActions/dispatch/attributer/textToDA/function.ts +21 -0
- package/template/src/hooks/frontEnd/useActions/dispatch/attributer/textToDA/zap.ts +12 -0
- package/template/src/hooks/frontEnd/useActions/dispatch/attributer/zap.ts +15 -0
- package/template/src/hooks/frontEnd/useActions/dispatch/index.ts +2 -0
- package/template/src/hooks/frontEnd/useActions/dispatch/runner/cycleText/function.ts +30 -0
- package/template/src/hooks/frontEnd/useActions/dispatch/runner/cycleText/zap.ts +12 -0
- package/template/src/hooks/frontEnd/useActions/dispatch/runner/function.ts +21 -0
- package/template/src/hooks/frontEnd/useActions/dispatch/runner/resetForm/function.ts +7 -0
- package/template/src/hooks/frontEnd/useActions/dispatch/runner/resetForm/zap.ts +9 -0
- package/template/src/hooks/frontEnd/useActions/dispatch/runner/setBool/function.ts +10 -0
- package/template/src/hooks/frontEnd/useActions/dispatch/runner/setBool/zap.ts +11 -0
- package/template/src/hooks/frontEnd/useActions/dispatch/runner/setCCs/function.ts +33 -0
- package/template/src/hooks/frontEnd/useActions/dispatch/runner/setCCs/zap.ts +14 -0
- package/template/src/hooks/frontEnd/useActions/dispatch/runner/setThemes/function.ts +11 -0
- package/template/src/hooks/frontEnd/useActions/dispatch/runner/setThemes/zap.ts +10 -0
- package/template/src/hooks/frontEnd/useActions/dispatch/runner/submitForm/function.ts +32 -0
- package/template/src/hooks/frontEnd/useActions/dispatch/runner/submitForm/zap.ts +9 -0
- package/template/src/hooks/frontEnd/useActions/dispatch/runner/zap.ts +16 -0
- package/template/src/hooks/frontEnd/useActions/dispatch/zap.ts +2 -0
- package/template/src/hooks/frontEnd/useActions/index.ts +6 -0
- package/template/src/hooks/frontEnd/useActions/useActionContext.ts +21 -0
- package/template/src/hooks/frontEnd/useActions/useButtonActions.ts +17 -0
- package/template/src/hooks/frontEnd/useActions/useDaToText.ts +34 -0
- package/template/src/hooks/frontEnd/useActions/useForm.ts +114 -0
- package/template/src/hooks/frontEnd/useActions/usePortal.ts +33 -0
- package/template/src/hooks/frontEnd/useActions/useToDa.ts +12 -0
- package/template/src/hooks/global/revalidate.ts +26 -0
- package/template/src/payload.config.ts +78 -0
- package/template/src/plugins/blurDataUrls.ts +8 -0
- package/template/src/plugins/formBuilder.ts +40 -0
- package/template/src/plugins/index.ts +17 -0
- package/template/src/plugins/muxVideo.ts +13 -0
- package/template/src/plugins/nestedDocs.ts +9 -0
- package/template/src/plugins/vercelBlobStorage.ts +8 -0
- package/template/src/ts/JSONSchema.ts +93 -0
- package/template/src/ts/declarations.ts +24 -0
- package/template/src/ts/types/actions.ts +175 -0
- package/template/src/ts/types/apf.ts +108 -0
- package/template/src/ts/types/cache.ts +166 -0
- package/template/src/ts/types/css.ts +14 -0
- package/template/src/ts/types/forms.ts +214 -0
- package/template/src/ts/types/frontEnd.ts +115 -0
- package/template/src/ts/types/index.ts +49 -0
- package/template/src/ts/types/payload-types.ts +3684 -0
- package/template/src/ts/zap/ap.ts +82 -0
- package/template/src/ts/zap/index.ts +4 -0
- package/template/src/ui/apf/controls.tsx +88 -0
- package/template/src/ui/apf/field.tsx +81 -0
- package/template/src/ui/apf/index.scss +59 -0
- package/template/src/ui/apf/label.tsx +23 -0
- package/template/src/ui/assets/Icon.tsx +21 -0
- package/template/src/ui/assets/Logo.tsx +21 -0
- package/template/src/ui/assets/atomicIcon.tsx +27 -0
- package/template/src/ui/assets/warningIcon.ts +6 -0
- package/template/src/ui/blocks/actionBlock.tsx +44 -0
- package/template/src/ui/blocks/inputBlock.tsx +24 -0
- package/template/src/ui/decorative/coloredEnd.tsx +16 -0
- package/template/src/ui/decorative/index.scss +46 -0
- package/template/src/ui/fields/iconSelect/index.tsx +19 -0
- package/template/src/ui/fields/slug/index.scss +12 -0
- package/template/src/ui/fields/slug/index.tsx +72 -0
- package/template/src/ui/index.ts +32 -0
- package/template/src/ui/root/beforeDashboard/index.scss +22 -0
- package/template/src/ui/root/beforeDashboard/index.tsx +39 -0
- package/template/src/ui/root/beforeDashboard/seedButton/index.scss +12 -0
- package/template/src/ui/root/beforeDashboard/seedButton/index.tsx +84 -0
- package/template/src/ui/root/siteTriggers/index.scss +22 -0
- package/template/src/ui/root/siteTriggers/index.tsx +94 -0
- package/template/src/ui/root/siteTriggers/triggerVercelDeploy.ts +37 -0
- package/template/src/ui/rowLabels/animation.tsx +27 -0
- package/template/src/ui/rowLabels/atomic/index.scss +62 -0
- package/template/src/ui/rowLabels/atomic/index.tsx +96 -0
- package/template/src/ui/rowLabels/color.tsx +33 -0
- package/template/src/ui/rowLabels/designToken.tsx +30 -0
- package/template/src/ui/rowLabels/icon.tsx +32 -0
- package/template/src/ui/rowLabels/shortcut/index.scss +21 -0
- package/template/src/ui/rowLabels/shortcut/index.tsx +30 -0
- package/template/src/ui/rowLabels/simpleText.tsx +41 -0
- package/template/src/utilities/deepMerge.ts +30 -0
- package/template/src/utilities/extractSVG.ts +9 -0
- package/template/src/utilities/format/toKebabCase.ts +79 -0
- package/template/src/utilities/format/toTitleCase.ts +47 -0
- package/template/src/utilities/formatDurationWithTokens.ts +56 -0
- package/template/src/utilities/generateMetaData.ts +45 -0
- package/template/src/utilities/generatePreviewPath.ts +43 -0
- package/template/src/utilities/get/cache/getAtomicActions.ts +48 -0
- package/template/src/utilities/get/cache/getAtomicClasses.ts +20 -0
- package/template/src/utilities/get/cache/getDesignSet.ts +15 -0
- package/template/src/utilities/get/cache/getFooter.ts +17 -0
- package/template/src/utilities/get/cache/getFormSubmissions.ts +17 -0
- package/template/src/utilities/get/cache/getForms.ts +43 -0
- package/template/src/utilities/get/cache/getHeader.ts +17 -0
- package/template/src/utilities/get/cache/getIcon.ts +51 -0
- package/template/src/utilities/get/cache/getImage.ts +20 -0
- package/template/src/utilities/get/cache/getPage.ts +35 -0
- package/template/src/utilities/get/cache/getPages.ts +24 -0
- package/template/src/utilities/get/cache/getShortcutSet.ts +17 -0
- package/template/src/utilities/get/cache/getSiteCSS.ts +17 -0
- package/template/src/utilities/get/cache/getSiteMetadata.ts +14 -0
- package/template/src/utilities/get/cache/getSitemap.ts +50 -0
- package/template/src/utilities/get/cache/getTracking.ts +14 -0
- package/template/src/utilities/get/cache/index.ts +129 -0
- package/template/src/utilities/get/cache/react.ts +5 -0
- package/template/src/utilities/get/getImageURL.ts +20 -0
- package/template/src/utilities/get/getMeUser.ts +22 -0
- package/template/src/utilities/get/getURL.ts +20 -0
- package/template/src/utilities/log/cache.ts +8 -0
- package/template/src/utilities/log/manual.ts +11 -0
- package/template/src/utilities/log/revalidation.ts +6 -0
- package/template/src/utilities/mergeTags.ts +7 -0
- package/template/src/utilities/propertyApplicatorUtility.ts +20 -0
- package/template/src/utilities/revalidateTag.ts +55 -0
- package/template/src/utilities/runAPF.ts +10 -0
- package/template/src/utilities/sanitizeData.ts +24 -0
- package/template/src/utilities/seedNestedRelationship.ts +5 -0
- package/template/tailwind.config.js +9 -0
- package/template/tsconfig.json +49 -0
package/template/src/blocks/submitForm/form/rateLimiting/simpleSlidingWindow/serverFunction.ts
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
'use server'
|
|
2
|
+
import { FormFunction } from '@/ts/types'
|
|
3
|
+
import { FrlSimpleSlidingWindow as FrlSimpleSlidingWindowType } from '@/ts/types'
|
|
4
|
+
|
|
5
|
+
const lastCleanup: Record<string, number> = {}
|
|
6
|
+
const memoryStore: Record<string, Record<string, number[]>> = {}
|
|
7
|
+
|
|
8
|
+
export const FrlSimpleSlidingWindow: FormFunction<{ block: FrlSimpleSlidingWindowType }> = async (args) => {
|
|
9
|
+
const { context, response, block } = args
|
|
10
|
+
const { backendFormID, ip } = context
|
|
11
|
+
const { rateLimit, rateLimitPeriod, validationMessage } = block
|
|
12
|
+
|
|
13
|
+
// Ensure store for this formID exists. (The store unifies all front end forms rate limiting to the backend form.)
|
|
14
|
+
if (!memoryStore[backendFormID]) memoryStore[backendFormID] = {}
|
|
15
|
+
if (!lastCleanup[backendFormID]) lastCleanup[backendFormID] = 0
|
|
16
|
+
|
|
17
|
+
const now = Date.now()
|
|
18
|
+
const windowStart = now - rateLimitPeriod * 60000
|
|
19
|
+
|
|
20
|
+
const timestamps = memoryStore[backendFormID][ip] || []
|
|
21
|
+
const recentRequests = timestamps.filter((ts) => ts > windowStart)
|
|
22
|
+
|
|
23
|
+
// Add the current request to the store.
|
|
24
|
+
memoryStore[backendFormID][ip] = [...recentRequests, now]
|
|
25
|
+
|
|
26
|
+
// Only run cleanup for this formID if rateLimitPeriod has passed since last cleanup
|
|
27
|
+
if (now - lastCleanup[backendFormID] > rateLimitPeriod * 60000) {
|
|
28
|
+
Object.keys(memoryStore[backendFormID]).forEach((ipKey) => {
|
|
29
|
+
const filtered = memoryStore[backendFormID][ipKey].filter((ts) => ts > windowStart)
|
|
30
|
+
if (filtered.length === 0) delete memoryStore[backendFormID][ipKey]
|
|
31
|
+
else memoryStore[backendFormID][ipKey] = filtered
|
|
32
|
+
})
|
|
33
|
+
lastCleanup[backendFormID] = now
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (recentRequests.length >= rateLimit) {
|
|
37
|
+
const earliest = Math.min(...recentRequests)
|
|
38
|
+
const durationMs = earliest + rateLimitPeriod * 60000 - now
|
|
39
|
+
response.success = false
|
|
40
|
+
context.waitFor = durationMs
|
|
41
|
+
response.fm = validationMessage
|
|
42
|
+
return args
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return args
|
|
46
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { Block } from 'payload'
|
|
2
|
+
import { APField } from '@/fields/apf'
|
|
3
|
+
|
|
4
|
+
const d = {
|
|
5
|
+
addBetween: 'Adds a string between the two fields. Defaults to a space.',
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export const FsCombineTwoFields: Block = {
|
|
9
|
+
slug: 'FsCombineTwoFields',
|
|
10
|
+
interfaceName: 'FsCombineTwoFields',
|
|
11
|
+
admin: { disableBlockName: true },
|
|
12
|
+
labels: { singular: 'Combine Two Fields', plural: 'Combine Two Fields' },
|
|
13
|
+
fields: [
|
|
14
|
+
APField({ type: 'text', apf: ['form'], name: 'firstFieldName', required: true }),
|
|
15
|
+
APField({ type: 'text', apf: ['form'], name: 'addBetween', admin: { description: d.addBetween } }),
|
|
16
|
+
APField({ type: 'text', apf: ['form'], name: 'secondFieldName', required: true }),
|
|
17
|
+
APField({ type: 'text', apf: ['form'], name: 'outputFieldName', required: true }),
|
|
18
|
+
],
|
|
19
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
'use server'
|
|
2
|
+
import { FormFunction } from '@/ts/types'
|
|
3
|
+
import { FsCombineTwoFields as FsCombineTwoFieldsType } from '@/ts/types'
|
|
4
|
+
|
|
5
|
+
export const FsCombineTwoFields: FormFunction<{ block: FsCombineTwoFieldsType }> = async (args) => {
|
|
6
|
+
const { formData, block } = args
|
|
7
|
+
const { firstFieldName, secondFieldName, outputFieldName } = block
|
|
8
|
+
|
|
9
|
+
if (!formData.get(firstFieldName) || !formData.get(secondFieldName)) {
|
|
10
|
+
args.response.success = false
|
|
11
|
+
args.response.fm = `Combine Two Fields Block Needs: ${firstFieldName} and ${secondFieldName}`
|
|
12
|
+
return args
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const firstFieldValue = formData.get(firstFieldName)
|
|
16
|
+
const addBetween = block.addBetween || ' '
|
|
17
|
+
const secondFieldValue = formData.get(secondFieldName)
|
|
18
|
+
|
|
19
|
+
formData.set(outputFieldName, `${firstFieldValue}${addBetween}${secondFieldValue}`)
|
|
20
|
+
|
|
21
|
+
return args
|
|
22
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './combineTwoFields/serverFunction'
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './isUnique/serverFunction'
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { Block } from 'payload'
|
|
2
|
+
import { APField } from '@/fields/apf'
|
|
3
|
+
import { ValidationMessageField } from '@/fields/validationMessage'
|
|
4
|
+
|
|
5
|
+
const d = {
|
|
6
|
+
limit: 'The number of times the field can be used. It defaults to 1.',
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export const FvIsUnique: Block = {
|
|
10
|
+
slug: 'FvIsUnique',
|
|
11
|
+
interfaceName: 'FvIsUnique',
|
|
12
|
+
admin: { disableBlockName: true },
|
|
13
|
+
labels: { singular: 'Is Unique', plural: 'Is Unique' },
|
|
14
|
+
fields: [
|
|
15
|
+
APField({ type: 'text', apf: ['form'], name: 'fieldName', required: true }),
|
|
16
|
+
APField({ type: 'number', apf: ['form'], name: 'limit', required: true, admin: { description: d.limit } }),
|
|
17
|
+
ValidationMessageField,
|
|
18
|
+
],
|
|
19
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
'use server'
|
|
2
|
+
import getCached from '@/utilities/get/cache/react'
|
|
3
|
+
import { FvIsUnique as FvIsUniqueType } from '@/ts/types'
|
|
4
|
+
import { FilterSubmissionsByFieldAndValue, FormFunction } from '@/ts/types'
|
|
5
|
+
|
|
6
|
+
/** Filters form submissions based on field and value inputs. */
|
|
7
|
+
const filterSubmissionsByFieldAndValue: FilterSubmissionsByFieldAndValue = ({ submissions, fieldName, fieldValue }) => {
|
|
8
|
+
return submissions.filter((submission) => {
|
|
9
|
+
if (!submission.submissionData || !Array.isArray(submission.submissionData)) return false
|
|
10
|
+
return submission.submissionData.some((data) => data.field === fieldName && data.value === String(fieldValue))
|
|
11
|
+
})
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export const FvIsUnique: FormFunction<{ block: FvIsUniqueType }> = async (args) => {
|
|
15
|
+
const { formData, storedForm, response, block } = args
|
|
16
|
+
const { fieldName, validationMessage } = block
|
|
17
|
+
|
|
18
|
+
if (!formData.get(fieldName)) {
|
|
19
|
+
response.success = false
|
|
20
|
+
response.fm = `This form is missing a field named: ${fieldName}`
|
|
21
|
+
return args
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const cachedSubmissions = await getCached('form-submissions', storedForm.backendForm)
|
|
25
|
+
const submissions = filterSubmissionsByFieldAndValue({ submissions: cachedSubmissions, fieldName, fieldValue: formData.get(fieldName) })
|
|
26
|
+
|
|
27
|
+
if (submissions.length > 0) {
|
|
28
|
+
if (!formData.get(fieldName)) {
|
|
29
|
+
response.success = false
|
|
30
|
+
response.fm = `Field '${fieldName}' not found in form data.`
|
|
31
|
+
return args
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
response.success = false
|
|
35
|
+
response.fm = validationMessage
|
|
36
|
+
return args
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return args
|
|
40
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { z } from '@/ts/zap'
|
|
2
|
+
import sanitationBlocks from './sanitation/blocks'
|
|
3
|
+
import validationBlocks from './validation/blocks'
|
|
4
|
+
import rateLimitBlocks from './rateLimiting/blocks'
|
|
5
|
+
|
|
6
|
+
export const FormRateLimitBlockType = z.ap.add(z.enum(rateLimitBlocks.map((block) => block.slug)), { id: 'FormRateLimitBlockType' })
|
|
7
|
+
export const FormSanitationBlockType = z.ap.add(z.enum(sanitationBlocks.map((block) => block.slug)), { id: 'FormSanitationBlockType' })
|
|
8
|
+
export const FormValidationBlockType = z.ap.add(z.enum(validationBlocks.map((block) => block.slug)), { id: 'FormValidationBlockType' })
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
'use server'
|
|
2
|
+
//Function Imports
|
|
3
|
+
import { FvIsUnique } from '@/blocks/submitForm/form/validation/functions'
|
|
4
|
+
import { IsTrimText } from '@/blocks/submitForm/input/sanitation/functions'
|
|
5
|
+
import { FsCombineTwoFields } from '@/blocks/submitForm/form/sanitation/functions'
|
|
6
|
+
import { FrlSimpleSlidingWindow } from '@/blocks/submitForm/form/rateLimiting/functions'
|
|
7
|
+
import { IvContains, IvDoesNotContain } from '@/blocks/submitForm/input/validation/functions'
|
|
8
|
+
|
|
9
|
+
//Other Imports
|
|
10
|
+
import { CookiePreferences } from '@/ts/types/actions'
|
|
11
|
+
import {
|
|
12
|
+
AFPBase,
|
|
13
|
+
RunBlocksMethod,
|
|
14
|
+
FormFunction,
|
|
15
|
+
ProcessMethod,
|
|
16
|
+
FormFunctionsMap,
|
|
17
|
+
PreProcessMethod,
|
|
18
|
+
PostProcessMethod,
|
|
19
|
+
MessageProcessorMethod,
|
|
20
|
+
} from '@/ts/types/forms'
|
|
21
|
+
import type {
|
|
22
|
+
FormRateLimitBlocks,
|
|
23
|
+
FormSanitationBlocks,
|
|
24
|
+
FormValidationBlocks,
|
|
25
|
+
InputSanitationBlocks,
|
|
26
|
+
InputValidationBlocks,
|
|
27
|
+
StoredAtomicFormInput,
|
|
28
|
+
} from '@/ts/types'
|
|
29
|
+
import { formatDurationString } from '@/utilities/formatDurationWithTokens'
|
|
30
|
+
|
|
31
|
+
const formFunctions: FormFunctionsMap = {
|
|
32
|
+
FrlSimpleSlidingWindow,
|
|
33
|
+
FsCombineTwoFields,
|
|
34
|
+
FvIsUnique,
|
|
35
|
+
IsTrimText,
|
|
36
|
+
IvContains,
|
|
37
|
+
IvDoesNotContain,
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
class SubmitFormProcessor {
|
|
41
|
+
//Context
|
|
42
|
+
private success: boolean = true
|
|
43
|
+
private args: AFPBase | undefined
|
|
44
|
+
private CCPreferences: CookiePreferences | undefined
|
|
45
|
+
|
|
46
|
+
//Form Level Values
|
|
47
|
+
private formRateLimitBlocks: FormRateLimitBlocks | undefined
|
|
48
|
+
private formSanitationBlocks: FormSanitationBlocks | undefined
|
|
49
|
+
private formValidationBlocks: FormValidationBlocks | undefined
|
|
50
|
+
private formInputBlocks: StoredAtomicFormInput[] | undefined
|
|
51
|
+
|
|
52
|
+
//Input Level Values
|
|
53
|
+
private inputSanitationBlocks: InputSanitationBlocks | undefined
|
|
54
|
+
private inputValidationBlocks: InputValidationBlocks | undefined
|
|
55
|
+
|
|
56
|
+
private reset(target: 'context' | 'form' | 'input' | 'all') {
|
|
57
|
+
if (target === 'context') {
|
|
58
|
+
this.args = undefined
|
|
59
|
+
this.success = true
|
|
60
|
+
this.CCPreferences = undefined
|
|
61
|
+
}
|
|
62
|
+
if (target === 'form') {
|
|
63
|
+
this.formRateLimitBlocks = undefined
|
|
64
|
+
this.formSanitationBlocks = undefined
|
|
65
|
+
this.formValidationBlocks = undefined
|
|
66
|
+
this.formInputBlocks = undefined
|
|
67
|
+
}
|
|
68
|
+
if (target === 'input') {
|
|
69
|
+
this.inputSanitationBlocks = undefined
|
|
70
|
+
this.inputValidationBlocks = undefined
|
|
71
|
+
}
|
|
72
|
+
if (target === 'all') {
|
|
73
|
+
this.reset('context')
|
|
74
|
+
this.reset('form')
|
|
75
|
+
this.reset('input')
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
private preProcess: PreProcessMethod = (args) => {
|
|
80
|
+
const { submissionData, headers, storedForm } = args
|
|
81
|
+
const { formData, clientData, submissionID } = submissionData
|
|
82
|
+
this.formInputBlocks = storedForm.inputs
|
|
83
|
+
this.CCPreferences = clientData.preferences
|
|
84
|
+
this.formSanitationBlocks = storedForm.sanitation
|
|
85
|
+
this.formValidationBlocks = storedForm.validation
|
|
86
|
+
this.formRateLimitBlocks = storedForm.rateLimiting
|
|
87
|
+
this.args = {
|
|
88
|
+
formData,
|
|
89
|
+
storedForm,
|
|
90
|
+
response: { success: true, submissionID, formData: new FormData(), fm: '', im: {} },
|
|
91
|
+
context: {
|
|
92
|
+
headers,
|
|
93
|
+
clientData,
|
|
94
|
+
backendFormID: storedForm.id,
|
|
95
|
+
referer: headers.get('referer') || 'unknown',
|
|
96
|
+
ip: headers.get('x-forwarded-for') || headers.get('x-real-ip') || headers.get('cf-connecting-ip') || 'unknown',
|
|
97
|
+
},
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
process: ProcessMethod = async (args) => {
|
|
102
|
+
this.preProcess(args)
|
|
103
|
+
|
|
104
|
+
//DO NOT CHANGE ORDER.
|
|
105
|
+
await this.formRateLimitProcessor(true)
|
|
106
|
+
await this.inputProcessor()
|
|
107
|
+
await this.formSanitationProcessor()
|
|
108
|
+
await this.formValidationProcessor()
|
|
109
|
+
await this.formRateLimitProcessor(false)
|
|
110
|
+
|
|
111
|
+
return this.postProcess()
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
private async formRateLimitProcessor(start: boolean) {
|
|
115
|
+
if (!this.formRateLimitBlocks || !this.success) return
|
|
116
|
+
const rateLimitArray = this.formRateLimitBlocks.filter((rateLimit) => rateLimit.atStart === start)
|
|
117
|
+
for (const block of rateLimitArray) if (this.success) await this.runBlocks({ block, type: block.blockType })
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
private async formSanitationProcessor() {
|
|
121
|
+
if (!this.formSanitationBlocks || !this.success) return
|
|
122
|
+
for (const block of this.formSanitationBlocks) if (this.success) await this.runBlocks({ block, type: block.blockType })
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
private async formValidationProcessor() {
|
|
126
|
+
if (!this.formValidationBlocks || !this.success) return
|
|
127
|
+
for (const block of this.formValidationBlocks) if (this.success) await this.runBlocks({ block, type: block.blockType })
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
private async inputProcessor() {
|
|
131
|
+
if (!this.formInputBlocks || !this.success) return
|
|
132
|
+
for (const input of this.formInputBlocks) {
|
|
133
|
+
if ((!input.sanitationBlocks && !input.validationBlocks) || !input.inputName) continue
|
|
134
|
+
this.inputSanitationBlocks = input.sanitationBlocks
|
|
135
|
+
this.inputValidationBlocks = input.validationBlocks
|
|
136
|
+
await this.inputSanitationProcessor(input.inputName)
|
|
137
|
+
await this.inputValidationProcessor(input.inputName)
|
|
138
|
+
this.reset('input')
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
private async inputSanitationProcessor(inputName: string) {
|
|
143
|
+
if (!this.inputSanitationBlocks) return
|
|
144
|
+
for (const block of this.inputSanitationBlocks) await this.runBlocks({ block: { ...block, inputName }, type: block.blockType, persevere: true })
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
private async inputValidationProcessor(inputName: string) {
|
|
148
|
+
if (!this.inputValidationBlocks) return
|
|
149
|
+
for (const block of this.inputValidationBlocks) await this.runBlocks({ block: { ...block, inputName }, type: block.blockType, persevere: true })
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
private runBlocks: RunBlocksMethod = async ({ type, block, persevere }) => {
|
|
153
|
+
if (!this.args) throw new Error('Args is not defined in form processor.')
|
|
154
|
+
if (!this.args.response.success) if (!persevere) return
|
|
155
|
+
const augmentedArgs: Parameters<FormFunction>[0] = { ...this.args, block }
|
|
156
|
+
|
|
157
|
+
const fn = formFunctions[type]
|
|
158
|
+
if (!fn) throw new Error(`Unknown Server Function: ${type} in form processor runBlocksFunction`)
|
|
159
|
+
|
|
160
|
+
//TODO: Fix typing
|
|
161
|
+
this.args = await fn(augmentedArgs as any)
|
|
162
|
+
if (!this.args.response.success) this.success = false
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
private postProcess: PostProcessMethod = () => {
|
|
166
|
+
if (!this.args?.formData) throw new Error('Form data is not defined in form processor postProcess')
|
|
167
|
+
if (!this.CCPreferences) throw new Error('CCPreferences is not defined in form processor postProcess')
|
|
168
|
+
const { response, storedForm, context, formData } = this.args
|
|
169
|
+
const { clientData, referer, headers, ip, waitFor } = context
|
|
170
|
+
const submitToPayload = Array.from(this.args.formData.entries())
|
|
171
|
+
//Only accepts string values currently
|
|
172
|
+
.filter((entry): entry is [string, string] => typeof entry[1] === 'string')
|
|
173
|
+
.map(([key, value]) => ({ field: key, value }))
|
|
174
|
+
|
|
175
|
+
//Handle Data Collection
|
|
176
|
+
if (this.CCPreferences.userData) {
|
|
177
|
+
submitToPayload.push({ field: 'ip', value: ip })
|
|
178
|
+
submitToPayload.push({ field: 'timezone', value: clientData.timezone })
|
|
179
|
+
submitToPayload.push({ field: 'userAgent', value: headers.get('user-agent') || 'unknown' })
|
|
180
|
+
}
|
|
181
|
+
if (this.CCPreferences.analytics) {
|
|
182
|
+
submitToPayload.push({ field: 'referer', value: referer })
|
|
183
|
+
submitToPayload.push({ field: 'screenWidth', value: clientData.screenWidth })
|
|
184
|
+
submitToPayload.push({ field: 'screenHeight', value: clientData.screenHeight })
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// Process Form & Input Messages
|
|
188
|
+
let fm
|
|
189
|
+
if (response.fm) fm = response.fm
|
|
190
|
+
else if (this.success) fm = storedForm.sm || 'Form submitted successfully!'
|
|
191
|
+
else fm = storedForm.em || 'Failed to submit form.'
|
|
192
|
+
fm = this.messageProcessor({ vm: fm, formData, waitFor })
|
|
193
|
+
if (Object.keys(response.im).length > 0) {
|
|
194
|
+
for (const [key, vm] of Object.entries(response.im)) response.im[key] = this.messageProcessor({ vm, formData, waitFor })
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
//Submit Form Processor Response
|
|
198
|
+
const fps = { response: { ...response, fm }, submitToPayload }
|
|
199
|
+
this.reset('all')
|
|
200
|
+
return fps
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
private messageProcessor: MessageProcessorMethod = ({ vm, formData, waitFor }) => {
|
|
204
|
+
if (vm?.includes('{{') && vm?.includes('}}')) {
|
|
205
|
+
if (waitFor) vm = formatDurationString(waitFor, vm)
|
|
206
|
+
vm = vm.replace(/\{\{([^}]+)\}\}/g, (match: string, fieldKey: string) => {
|
|
207
|
+
// Check if the field exists in formData
|
|
208
|
+
if (formData.get(fieldKey) !== undefined) return String(formData.get(fieldKey))
|
|
209
|
+
// If field doesn't exist, return the original placeholder
|
|
210
|
+
return match
|
|
211
|
+
})
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
return vm
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
const submitFormProcessor = new SubmitFormProcessor()
|
|
219
|
+
|
|
220
|
+
export async function getSubmitFormProcessor() {
|
|
221
|
+
return submitFormProcessor
|
|
222
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './trimText/serverFunction'
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { Block } from 'payload'
|
|
2
|
+
import { APField } from '@/fields/apf'
|
|
3
|
+
|
|
4
|
+
const d = {
|
|
5
|
+
trimCharacters: 'The characters to trim. Comma seperated list. Defaults to just removing spaces.',
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
const options = [
|
|
9
|
+
{ label: 'Beginning', value: 'beginning' },
|
|
10
|
+
{ label: 'End', value: 'end' },
|
|
11
|
+
{ label: 'Both', value: 'both' },
|
|
12
|
+
]
|
|
13
|
+
|
|
14
|
+
export const IsTrimText: Block = {
|
|
15
|
+
slug: 'IsTrimText',
|
|
16
|
+
interfaceName: 'IsTrimText',
|
|
17
|
+
admin: { disableBlockName: true },
|
|
18
|
+
labels: { singular: 'Trim Text', plural: 'Trim Text' },
|
|
19
|
+
custom: { usedOn: ['text', 'textarea', 'email'] },
|
|
20
|
+
fields: [
|
|
21
|
+
APField({ type: 'select', apf: ['form'], required: true, name: 'trimType', defaultValue: 'both', options }),
|
|
22
|
+
APField({ type: 'text', apf: ['form'], required: true, name: 'trimCharacters', admin: { description: d.trimCharacters } }),
|
|
23
|
+
],
|
|
24
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
'use server'
|
|
2
|
+
import { FormFunction } from '@/ts/types'
|
|
3
|
+
import { IsTrimText as IsTrimTextType } from '@/ts/types'
|
|
4
|
+
|
|
5
|
+
export const IsTrimText: FormFunction<{ block: IsTrimTextType & { inputName: string } }> = async (args) => {
|
|
6
|
+
const { formData, response, block } = args
|
|
7
|
+
const { trimCharacters, trimType, inputName } = block
|
|
8
|
+
|
|
9
|
+
//Get the input value
|
|
10
|
+
const inputValue = formData.get(inputName)
|
|
11
|
+
if (typeof inputValue !== 'string') {
|
|
12
|
+
response.success = false
|
|
13
|
+
response.fm = `Input Value is not a string: ${inputName}`
|
|
14
|
+
return args
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
//Get the characters we can trim
|
|
18
|
+
const trimCharactersArray = trimCharacters
|
|
19
|
+
?.split(',')
|
|
20
|
+
.map((char: string) => char.trim())
|
|
21
|
+
.filter((char: string) => char.length > 0)
|
|
22
|
+
if (!trimCharactersArray) {
|
|
23
|
+
response.success = false
|
|
24
|
+
response.fm = `Trim Characters is required: ${inputName}`
|
|
25
|
+
return args
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
//Trim the input value based on the trim type
|
|
29
|
+
switch (trimType) {
|
|
30
|
+
case 'beginning':
|
|
31
|
+
for (const char of trimCharactersArray) {
|
|
32
|
+
if (char.length === 0) continue
|
|
33
|
+
const escapedChar = escapeRegex(char)
|
|
34
|
+
formData.set(inputName, inputValue.replace(new RegExp(`^${escapedChar}+`, 'g'), ''))
|
|
35
|
+
}
|
|
36
|
+
break
|
|
37
|
+
case 'end':
|
|
38
|
+
for (const char of trimCharactersArray) {
|
|
39
|
+
if (char.length === 0) continue
|
|
40
|
+
const escapedChar = escapeRegex(char)
|
|
41
|
+
formData.set(inputName, inputValue.replace(new RegExp(`${escapedChar}+$`, 'g'), ''))
|
|
42
|
+
}
|
|
43
|
+
break
|
|
44
|
+
case 'both':
|
|
45
|
+
for (const char of trimCharactersArray) {
|
|
46
|
+
if (char.length === 0) continue
|
|
47
|
+
const escapedChar = escapeRegex(char)
|
|
48
|
+
const regexPattern = `^${escapedChar}+|${escapedChar}+$`
|
|
49
|
+
formData.set(inputName, inputValue.replace(new RegExp(regexPattern, 'g'), ''))
|
|
50
|
+
}
|
|
51
|
+
break
|
|
52
|
+
default:
|
|
53
|
+
// If no valid trim type, return original value
|
|
54
|
+
break
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return args
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Helper function to escape regex special characters (for the trim characters)
|
|
61
|
+
const escapeRegex = (str: string) => {
|
|
62
|
+
return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
|
|
63
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import sanitationBlocks from './sanitation/blocks'
|
|
2
|
+
import validationBlocks from './validation/blocks'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Pre-computed mapping of block slugs to their usedOn field types.
|
|
6
|
+
* This is calculated once at module load time to avoid runtime recalculation.
|
|
7
|
+
*/
|
|
8
|
+
export const useOn = [...sanitationBlocks, ...validationBlocks].map((block) => ({ block: block.slug, usedOn: block.custom?.usedOn }))
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { Block } from 'payload'
|
|
2
|
+
import { APField } from '@/fields/apf'
|
|
3
|
+
import { ValidationMessageField } from '@/fields/validationMessage'
|
|
4
|
+
|
|
5
|
+
export const IvContains: Block = {
|
|
6
|
+
slug: 'IvContains',
|
|
7
|
+
interfaceName: 'IvContains',
|
|
8
|
+
admin: { disableBlockName: true },
|
|
9
|
+
labels: { singular: 'Contains Value', plural: 'Contains Value' },
|
|
10
|
+
custom: { usedOn: ['text', 'textarea', 'email'] },
|
|
11
|
+
fields: [APField({ type: 'text', apf: ['form'], name: 'containsValue', required: true }), ValidationMessageField],
|
|
12
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
'use server'
|
|
2
|
+
import { FormFunction } from '@/ts/types'
|
|
3
|
+
import { IvContains as IvContainsType } from '@/ts/types'
|
|
4
|
+
|
|
5
|
+
export const IvContains: FormFunction<{ block: IvContainsType & { inputName: string } }> = async (args) => {
|
|
6
|
+
const { formData, response, block } = args
|
|
7
|
+
const { containsValue, validationMessage, inputName } = block
|
|
8
|
+
|
|
9
|
+
const inputValue = formData.get(inputName)
|
|
10
|
+
if (typeof inputValue !== 'string') {
|
|
11
|
+
response.success = false
|
|
12
|
+
response.fm = `Input Value is not a string: ${inputName}`
|
|
13
|
+
return args
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
if (!inputValue.includes(containsValue)) {
|
|
17
|
+
response.success = false
|
|
18
|
+
response.im[inputName] = validationMessage
|
|
19
|
+
return args
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return args
|
|
23
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { Block } from 'payload'
|
|
2
|
+
import { APField } from '@/fields/apf'
|
|
3
|
+
import { ValidationMessageField } from '@/fields/validationMessage'
|
|
4
|
+
|
|
5
|
+
export const IvDoesNotContain: Block = {
|
|
6
|
+
slug: 'IvDoesNotContain',
|
|
7
|
+
interfaceName: 'IvDoesNotContain',
|
|
8
|
+
admin: { disableBlockName: true },
|
|
9
|
+
labels: { singular: 'Does Not Contain', plural: 'Does Not Contain' },
|
|
10
|
+
custom: { usedOn: ['text', 'textarea', 'email'] },
|
|
11
|
+
fields: [APField({ type: 'text', apf: ['form'], name: 'doesNotContainValue' }), ValidationMessageField],
|
|
12
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
'use server'
|
|
2
|
+
import { FormFunction } from '@/ts/types'
|
|
3
|
+
import { IvDoesNotContain as IvDoesNotContainType } from '@/ts/types'
|
|
4
|
+
|
|
5
|
+
export const IvDoesNotContain: FormFunction<{ block: IvDoesNotContainType & { inputName: string } }> = async (args) => {
|
|
6
|
+
const { formData, response, block } = args
|
|
7
|
+
const { doesNotContainValue, validationMessage, inputName } = block
|
|
8
|
+
|
|
9
|
+
const inputValue = formData.get(inputName)
|
|
10
|
+
if (typeof inputValue !== 'string') {
|
|
11
|
+
response.success = false
|
|
12
|
+
response.fm = `Input Value is not a string: ${inputName}`
|
|
13
|
+
return args
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
if (doesNotContainValue && inputValue.includes(doesNotContainValue)) {
|
|
17
|
+
response.success = false
|
|
18
|
+
response.im[inputName] = validationMessage
|
|
19
|
+
return args
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return args
|
|
23
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { z } from '@/ts/zap'
|
|
2
|
+
import sanitationBlocks from './sanitation/blocks'
|
|
3
|
+
import validationBlocks from './validation/blocks'
|
|
4
|
+
|
|
5
|
+
export const InputSanitationBlockType = z.ap.add(z.enum(sanitationBlocks.map((block) => block.slug)), { id: 'InputSanitationBlockType' })
|
|
6
|
+
export const InputValidationBlockType = z.ap.add(z.enum(validationBlocks.map((block) => block.slug)), { id: 'InputValidationBlockType' })
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
'use server'
|
|
2
|
+
import getCached from '@/utilities/get/cache/react'
|
|
3
|
+
import { SubmitFormFunction } from '@/ts/types'
|
|
4
|
+
import { getSubmitFormProcessor } from './formProcessor'
|
|
5
|
+
import { getServerSideURL } from '@/utilities/get/getURL'
|
|
6
|
+
import { draftMode, headers as nextHeaders } from 'next/headers'
|
|
7
|
+
|
|
8
|
+
const formProcessor = await getSubmitFormProcessor()
|
|
9
|
+
|
|
10
|
+
export const submitForm: SubmitFormFunction = async (submissionData) => {
|
|
11
|
+
const headers = await nextHeaders()
|
|
12
|
+
const { isEnabled: draft } = await draftMode()
|
|
13
|
+
const { blockID, submissionID, formData } = submissionData
|
|
14
|
+
|
|
15
|
+
try {
|
|
16
|
+
// Get the stored form
|
|
17
|
+
const backendForms = await getCached('backend-forms')
|
|
18
|
+
if (!backendForms) return { success: false, formData, submissionID, fm: 'No backend forms found.', im: {} }
|
|
19
|
+
const atomicForms = await getCached('atomic-forms', draft)
|
|
20
|
+
if (!atomicForms) return { success: false, formData, submissionID, fm: 'No stored atomic forms found.', im: {} }
|
|
21
|
+
const allForms = await getCached('all-forms', draft, atomicForms, backendForms)
|
|
22
|
+
if (!allForms) return { success: false, formData, submissionID, fm: 'No all forms found.', im: {} }
|
|
23
|
+
const storedForm = allForms.find((form) => form.id === blockID)
|
|
24
|
+
if (!storedForm || !storedForm.id) return { success: false, formData, submissionID, fm: 'No backend form found for this atomic form.', im: {} }
|
|
25
|
+
|
|
26
|
+
const { response, submitToPayload } = await formProcessor.process({ submissionData, headers, storedForm })
|
|
27
|
+
|
|
28
|
+
if (response.success) {
|
|
29
|
+
const req = await fetch(`${getServerSideURL()}/api/form-submissions`, {
|
|
30
|
+
body: JSON.stringify({ form: storedForm.backendFormID, submissionData: submitToPayload }),
|
|
31
|
+
headers: { 'Content-Type': 'application/json' },
|
|
32
|
+
method: 'POST',
|
|
33
|
+
})
|
|
34
|
+
if (!req.ok) return { success: false, formData, submissionID, fm: 'Failed to store form submission.', im: {} }
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return response
|
|
38
|
+
} catch (err: unknown) {
|
|
39
|
+
console.error(err)
|
|
40
|
+
return { success: false, formData, submissionID, fm: 'Unknown Error. Please try again later.', im: {} }
|
|
41
|
+
}
|
|
42
|
+
}
|