@10x-media/form-builder 0.1.0-beta.0 → 0.1.0-beta.2
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/CHANGELOG.md +68 -0
- package/README.md +45 -1402
- package/dist/actions/buildActionBlocks.js +19 -0
- package/dist/actions/buildActionBlocks.js.map +1 -0
- package/dist/actions/builtin/confirmation.js +49 -0
- package/dist/actions/builtin/confirmation.js.map +1 -0
- package/dist/actions/builtin/emailTeam.js +46 -0
- package/dist/actions/builtin/emailTeam.js.map +1 -0
- package/dist/actions/builtin/index.d.ts +7 -0
- package/dist/actions/builtin/index.js +13 -0
- package/dist/actions/builtin/index.js.map +1 -0
- package/dist/actions/builtin/signedWebhook.js +49 -0
- package/dist/actions/builtin/signedWebhook.js.map +1 -0
- package/dist/actions/defineAction.d.ts +36 -0
- package/dist/actions/defineAction.js +6 -0
- package/dist/actions/defineAction.js.map +1 -0
- package/dist/actions/dispatch.js +48 -0
- package/dist/actions/dispatch.js.map +1 -0
- package/dist/actions/registry.d.ts +16 -0
- package/dist/actions/registry.js +16 -0
- package/dist/actions/registry.js.map +1 -0
- package/dist/actions/runActions.d.ts +9 -0
- package/dist/actions/runActions.js +34 -0
- package/dist/actions/runActions.js.map +1 -0
- package/dist/actions/sign.d.ts +7 -0
- package/dist/actions/sign.js +9 -0
- package/dist/actions/sign.js.map +1 -0
- package/dist/actions/task.js +82 -0
- package/dist/actions/task.js.map +1 -0
- package/dist/aggregation/aggregateResponses.d.ts +31 -0
- package/dist/aggregation/aggregateResponses.js +86 -0
- package/dist/aggregation/aggregateResponses.js.map +1 -0
- package/dist/aggregation/aggregateRows.d.ts +10 -0
- package/dist/aggregation/aggregateRows.js +64 -0
- package/dist/aggregation/aggregateRows.js.map +1 -0
- package/dist/aggregation/resolveResultsRequest.d.ts +32 -0
- package/dist/aggregation/resolveResultsRequest.js +56 -0
- package/dist/aggregation/resolveResultsRequest.js.map +1 -0
- package/dist/aggregation/types.d.ts +39 -0
- package/dist/calc/computeCalcFields.d.ts +15 -0
- package/dist/calc/computeCalcFields.js +27 -0
- package/dist/calc/computeCalcFields.js.map +1 -0
- package/dist/calc/evaluate.d.ts +8 -0
- package/dist/calc/evaluate.js +59 -0
- package/dist/calc/evaluate.js.map +1 -0
- package/dist/calc/normalizeCalc.d.ts +8 -0
- package/dist/calc/normalizeCalc.js +100 -0
- package/dist/calc/normalizeCalc.js.map +1 -0
- package/dist/calc/types.d.ts +28 -0
- package/dist/client/ConditionBuilder.js +121 -0
- package/dist/client/ConditionBuilder.js.map +1 -0
- package/dist/client/ConditionRow.js +150 -0
- package/dist/client/ConditionRow.js.map +1 -0
- package/dist/client/FlowBuilder.d.ts +15 -0
- package/dist/client/FlowBuilder.js +408 -0
- package/dist/client/FlowBuilder.js.map +1 -0
- package/dist/client/FormConditionField.d.ts +21 -0
- package/dist/client/FormConditionField.js +33 -0
- package/dist/client/FormConditionField.js.map +1 -0
- package/dist/client/synthesizeClientField.js +46 -0
- package/dist/client/synthesizeClientField.js.map +1 -0
- package/dist/collections/formSubmissions.js +157 -0
- package/dist/collections/formSubmissions.js.map +1 -0
- package/dist/collections/forms.js +198 -0
- package/dist/collections/forms.js.map +1 -0
- package/dist/collections/uploads.d.ts +30 -0
- package/dist/collections/uploads.js +55 -0
- package/dist/collections/uploads.js.map +1 -0
- package/dist/conditions/conditionType.js +14 -0
- package/dist/conditions/conditionType.js.map +1 -0
- package/dist/conditions/evaluate.d.ts +17 -0
- package/dist/conditions/evaluate.js +94 -0
- package/dist/conditions/evaluate.js.map +1 -0
- package/dist/conditions/fieldTypes.d.ts +9 -0
- package/dist/{fieldTypes-CzhhJXjg.js → conditions/fieldTypes.js} +2 -2
- package/dist/conditions/fieldTypes.js.map +1 -0
- package/dist/conditions/normalizeConditions.js +47 -0
- package/dist/conditions/normalizeConditions.js.map +1 -0
- package/dist/conditions/types.d.ts +8 -0
- package/dist/consent/buildConsentSourceConfig.js +49 -0
- package/dist/consent/buildConsentSourceConfig.js.map +1 -0
- package/dist/consent/builtin/index.d.ts +7 -0
- package/dist/consent/builtin/index.js +11 -0
- package/dist/consent/builtin/index.js.map +1 -0
- package/dist/consent/builtin/pageReference.js +75 -0
- package/dist/consent/builtin/pageReference.js.map +1 -0
- package/dist/consent/builtin/static.js +44 -0
- package/dist/consent/builtin/static.js.map +1 -0
- package/dist/consent/captureConsent.d.ts +28 -0
- package/dist/consent/captureConsent.js +26 -0
- package/dist/consent/captureConsent.js.map +1 -0
- package/dist/consent/defineConsentSource.d.ts +35 -0
- package/dist/consent/defineConsentSource.js +6 -0
- package/dist/consent/defineConsentSource.js.map +1 -0
- package/dist/consent/registry.d.ts +16 -0
- package/dist/consent/registry.js +16 -0
- package/dist/consent/registry.js.map +1 -0
- package/dist/consent/resolveConsentLinks.d.ts +19 -0
- package/dist/consent/resolveConsentLinks.js +26 -0
- package/dist/consent/resolveConsentLinks.js.map +1 -0
- package/dist/consent/resolvePublishedVersionRef.d.ts +17 -0
- package/dist/consent/resolvePublishedVersionRef.js +27 -0
- package/dist/consent/resolvePublishedVersionRef.js.map +1 -0
- package/dist/events/noopSink.js +6 -0
- package/dist/events/noopSink.js.map +1 -0
- package/dist/events/resolveEventSink.js +8 -0
- package/dist/events/resolveEventSink.js.map +1 -0
- package/dist/events/types.d.ts +31 -0
- package/dist/exports/client.d.ts +3 -21
- package/dist/exports/client.js +3 -319
- package/dist/exports/i18n.d.ts +3 -138
- package/dist/exports/i18n.js +2 -2
- package/dist/exports/react.d.ts +45 -550
- package/dist/exports/react.js +39 -1563
- package/dist/exports/rsc.d.ts +2 -16
- package/dist/exports/rsc.js +1 -54
- package/dist/exports/types.d.ts +28 -5
- package/dist/fields/buildFieldBlocks.js +60 -0
- package/dist/fields/buildFieldBlocks.js.map +1 -0
- package/dist/fields/builtin/calculation.js +24 -0
- package/dist/fields/builtin/calculation.js.map +1 -0
- package/dist/fields/builtin/checkbox.js +13 -0
- package/dist/fields/builtin/checkbox.js.map +1 -0
- package/dist/fields/builtin/consent.js +32 -0
- package/dist/fields/builtin/consent.js.map +1 -0
- package/dist/fields/builtin/email.js +18 -0
- package/dist/fields/builtin/email.js.map +1 -0
- package/dist/fields/builtin/file.js +40 -0
- package/dist/fields/builtin/file.js.map +1 -0
- package/dist/fields/builtin/index.js +27 -0
- package/dist/fields/builtin/index.js.map +1 -0
- package/dist/fields/builtin/number.js +17 -0
- package/dist/fields/builtin/number.js.map +1 -0
- package/dist/fields/builtin/repeater.js +44 -0
- package/dist/fields/builtin/repeater.js.map +1 -0
- package/dist/fields/builtin/select.js +44 -0
- package/dist/fields/builtin/select.js.map +1 -0
- package/dist/fields/builtin/text.js +13 -0
- package/dist/fields/builtin/text.js.map +1 -0
- package/dist/fields/builtin/textarea.js +13 -0
- package/dist/fields/builtin/textarea.js.map +1 -0
- package/dist/fields/defineFormField.d.ts +13 -0
- package/dist/fields/defineFormField.js +12 -0
- package/dist/fields/defineFormField.js.map +1 -0
- package/dist/fields/registry.d.ts +10 -0
- package/dist/fields/registry.js +24 -0
- package/dist/fields/registry.js.map +1 -0
- package/dist/fields/sharedConfig.js +89 -0
- package/dist/fields/sharedConfig.js.map +1 -0
- package/dist/fields/types.d.ts +89 -0
- package/dist/flow/engine.d.ts +17 -0
- package/dist/flow/engine.js +24 -0
- package/dist/flow/engine.js.map +1 -0
- package/dist/flow/normalizeFlow.js +35 -0
- package/dist/flow/normalizeFlow.js.map +1 -0
- package/dist/{types-DsJ_6kGJ.d.ts → flow/types.d.ts} +2 -2
- package/dist/index.d.ts +93 -4
- package/dist/index.js +43 -1890
- package/dist/index.js.map +1 -1
- package/dist/plugin/access.js +12 -0
- package/dist/plugin/access.js.map +1 -0
- package/dist/plugin/collectionOverrides.d.ts +22 -0
- package/dist/plugin/registerCollections.js +68 -0
- package/dist/plugin/registerCollections.js.map +1 -0
- package/dist/plugin/registerTranslations.js +19 -0
- package/dist/plugin/registerTranslations.js.map +1 -0
- package/dist/prefill/valuesFromSearchParams.d.ts +18 -0
- package/dist/prefill/valuesFromSearchParams.js +45 -0
- package/dist/prefill/valuesFromSearchParams.js.map +1 -0
- package/dist/presentations/defaults.d.ts +33 -0
- package/dist/presentations/defaults.js +35 -0
- package/dist/presentations/defaults.js.map +1 -0
- package/dist/presentations/registry.d.ts +15 -0
- package/dist/presentations/registry.js +15 -0
- package/dist/presentations/registry.js.map +1 -0
- package/dist/presentations/types.d.ts +18 -0
- package/dist/react/Form.d.ts +110 -0
- package/dist/react/Form.js +499 -0
- package/dist/react/Form.js.map +1 -0
- package/dist/react/FormContext.d.ts +16 -0
- package/dist/react/FormContext.js +14 -0
- package/dist/react/FormContext.js.map +1 -0
- package/dist/react/FormLayout.d.ts +20 -0
- package/dist/react/FormLayout.js +14 -0
- package/dist/react/FormLayout.js.map +1 -0
- package/dist/react/FormResults.d.ts +25 -0
- package/dist/react/FormResults.js +85 -0
- package/dist/react/FormResults.js.map +1 -0
- package/dist/react/Honeypot.d.ts +22 -0
- package/dist/react/Honeypot.js +38 -0
- package/dist/react/Honeypot.js.map +1 -0
- package/dist/react/Poll.d.ts +32 -0
- package/dist/react/Poll.js +77 -0
- package/dist/react/Poll.js.map +1 -0
- package/dist/react/cn.d.ts +6 -0
- package/dist/react/cn.js +8 -0
- package/dist/react/cn.js.map +1 -0
- package/dist/react/contract.d.ts +32 -0
- package/dist/react/contract.js +7 -0
- package/dist/react/contract.js.map +1 -0
- package/dist/react/events.js +14 -0
- package/dist/react/events.js.map +1 -0
- package/dist/react/fetchResults.d.ts +25 -0
- package/dist/react/fetchResults.js +31 -0
- package/dist/react/fetchResults.js.map +1 -0
- package/dist/react/presentation/Backdrop.d.ts +18 -0
- package/dist/react/presentation/Backdrop.js +14 -0
- package/dist/react/presentation/Backdrop.js.map +1 -0
- package/dist/react/presentation/DialogSurface.d.ts +35 -0
- package/dist/react/presentation/DialogSurface.js +56 -0
- package/dist/react/presentation/DialogSurface.js.map +1 -0
- package/dist/react/presentation/presentations.d.ts +7 -0
- package/dist/react/presentation/presentations.js +32 -0
- package/dist/react/presentation/presentations.js.map +1 -0
- package/dist/react/presentation/registry.d.ts +11 -0
- package/dist/react/presentation/registry.js +12 -0
- package/dist/react/presentation/registry.js.map +1 -0
- package/dist/react/presentation/types.d.ts +19 -0
- package/dist/react/presentation/useDismiss.d.ts +19 -0
- package/dist/react/presentation/useDismiss.js +33 -0
- package/dist/react/presentation/useDismiss.js.map +1 -0
- package/dist/react/presentation/useFocusTrap.d.ts +8 -0
- package/dist/react/presentation/useFocusTrap.js +35 -0
- package/dist/react/presentation/useFocusTrap.js.map +1 -0
- package/dist/react/presentation/useScrollLock.d.ts +6 -0
- package/dist/react/presentation/useScrollLock.js +18 -0
- package/dist/react/presentation/useScrollLock.js.map +1 -0
- package/dist/react/primitives/Checkbox.d.ts +26 -0
- package/dist/react/primitives/Checkbox.js +20 -0
- package/dist/react/primitives/Checkbox.js.map +1 -0
- package/dist/react/primitives/FieldShell.d.ts +31 -0
- package/dist/react/primitives/FieldShell.js +51 -0
- package/dist/react/primitives/FieldShell.js.map +1 -0
- package/dist/react/primitives/Input.d.ts +30 -0
- package/dist/react/primitives/Input.js +21 -0
- package/dist/react/primitives/Input.js.map +1 -0
- package/dist/react/primitives/Select.d.ts +34 -0
- package/dist/react/primitives/Select.js +26 -0
- package/dist/react/primitives/Select.js.map +1 -0
- package/dist/react/primitives/Textarea.d.ts +28 -0
- package/dist/react/primitives/Textarea.js +20 -0
- package/dist/react/primitives/Textarea.js.map +1 -0
- package/dist/react/recall.js +20 -0
- package/dist/react/recall.js.map +1 -0
- package/dist/react/registry.d.ts +16 -0
- package/dist/react/registry.js +16 -0
- package/dist/react/registry.js.map +1 -0
- package/dist/react/renderers/calculation.js +30 -0
- package/dist/react/renderers/calculation.js.map +1 -0
- package/dist/react/renderers/checkbox.js +35 -0
- package/dist/react/renderers/checkbox.js.map +1 -0
- package/dist/react/renderers/consent.js +54 -0
- package/dist/react/renderers/consent.js.map +1 -0
- package/dist/react/renderers/email.js +37 -0
- package/dist/react/renderers/email.js.map +1 -0
- package/dist/react/renderers/file.js +92 -0
- package/dist/react/renderers/file.js.map +1 -0
- package/dist/react/renderers/index.d.ts +8 -0
- package/dist/react/renderers/index.js +28 -0
- package/dist/react/renderers/index.js.map +1 -0
- package/dist/react/renderers/number.js +40 -0
- package/dist/react/renderers/number.js.map +1 -0
- package/dist/react/renderers/repeater.js +113 -0
- package/dist/react/renderers/repeater.js.map +1 -0
- package/dist/react/renderers/select.js +38 -0
- package/dist/react/renderers/select.js.map +1 -0
- package/dist/react/renderers/text.js +37 -0
- package/dist/react/renderers/text.js.map +1 -0
- package/dist/react/renderers/textarea.js +36 -0
- package/dist/react/renderers/textarea.js.map +1 -0
- package/dist/react/resolveForm.js +16 -0
- package/dist/react/resolveForm.js.map +1 -0
- package/dist/react/state.d.ts +15 -0
- package/dist/react/state.js +70 -0
- package/dist/react/state.js.map +1 -0
- package/dist/react/submitForm.d.ts +31 -0
- package/dist/react/submitForm.js +58 -0
- package/dist/react/submitForm.js.map +1 -0
- package/dist/react/toFormDocument.d.ts +24 -0
- package/dist/react/toFormDocument.js +22 -0
- package/dist/react/toFormDocument.js.map +1 -0
- package/dist/react/uploadFile.d.ts +23 -0
- package/dist/react/uploadFile.js +39 -0
- package/dist/react/uploadFile.js.map +1 -0
- package/dist/react/useField.d.ts +14 -0
- package/dist/react/useField.js +49 -0
- package/dist/react/useField.js.map +1 -0
- package/dist/react/useFormState.d.ts +8 -0
- package/dist/react/useFormState.js +9 -0
- package/dist/react/useFormState.js.map +1 -0
- package/dist/react/useFormStep.d.ts +8 -0
- package/dist/react/useFormStep.js +9 -0
- package/dist/react/useFormStep.js.map +1 -0
- package/dist/react/validateField.js +30 -0
- package/dist/react/validateField.js.map +1 -0
- package/dist/recall/interpolate.d.ts +10 -0
- package/dist/recall/interpolate.js +16 -0
- package/dist/recall/interpolate.js.map +1 -0
- package/dist/recall/resolver.d.ts +22 -0
- package/dist/recall/resolver.js +36 -0
- package/dist/recall/resolver.js.map +1 -0
- package/dist/spam/captcha.d.ts +12 -0
- package/dist/spam/captcha.js +11 -0
- package/dist/spam/captcha.js.map +1 -0
- package/dist/spam/constants.d.ts +12 -0
- package/dist/spam/constants.js +15 -0
- package/dist/spam/constants.js.map +1 -0
- package/dist/spam/identify.d.ts +12 -0
- package/dist/spam/identify.js +20 -0
- package/dist/spam/identify.js.map +1 -0
- package/dist/spam/rateLimiter.d.ts +18 -0
- package/dist/spam/rateLimiter.js +41 -0
- package/dist/spam/rateLimiter.js.map +1 -0
- package/dist/spam/reserved.js +30 -0
- package/dist/spam/reserved.js.map +1 -0
- package/dist/spam/resolveSpam.d.ts +12 -0
- package/dist/spam/resolveSpam.js +42 -0
- package/dist/spam/resolveSpam.js.map +1 -0
- package/dist/spam/spamGuard.js +68 -0
- package/dist/spam/spamGuard.js.map +1 -0
- package/dist/spam/types.d.ts +73 -0
- package/dist/spam/uploadHooks.js +33 -0
- package/dist/spam/uploadHooks.js.map +1 -0
- package/dist/submissions/SubmissionAnswers.d.ts +14 -0
- package/dist/submissions/SubmissionAnswers.js +133 -0
- package/dist/submissions/SubmissionAnswers.js.map +1 -0
- package/dist/submissions/SubmissionAnswersClient.js +142 -0
- package/dist/submissions/SubmissionAnswersClient.js.map +1 -0
- package/dist/submissions/runSubmission.js +257 -0
- package/dist/submissions/runSubmission.js.map +1 -0
- package/dist/submissions/types.d.ts +34 -0
- package/dist/submissions/validateSubmission.js +59 -0
- package/dist/submissions/validateSubmission.js.map +1 -0
- package/dist/translations/en.d.ts +12 -0
- package/dist/{translations-edMqq_2e.js → translations/en.js} +29 -23
- package/dist/translations/en.js.map +1 -0
- package/dist/translations/index.d.ts +14 -0
- package/dist/translations/index.js +26 -0
- package/dist/translations/index.js.map +1 -0
- package/dist/translations/keys.d.ts +157 -0
- package/dist/{keys-N5xGiUsh.js → translations/keys.js} +28 -3
- package/dist/translations/keys.js.map +1 -0
- package/dist/translations/makeTranslate.d.ts +11 -0
- package/dist/translations/makeTranslate.js +11 -0
- package/dist/translations/makeTranslate.js.map +1 -0
- package/dist/translations/server.js +25 -0
- package/dist/translations/server.js.map +1 -0
- package/dist/translations/useTranslation.js +12 -0
- package/dist/translations/useTranslation.js.map +1 -0
- package/dist/uploads/captureFileRef.d.ts +27 -0
- package/dist/uploads/captureFileRef.js +34 -0
- package/dist/uploads/captureFileRef.js.map +1 -0
- package/dist/uploads/resolveFileRef.d.ts +26 -0
- package/dist/uploads/resolveFileRef.js +44 -0
- package/dist/uploads/resolveFileRef.js.map +1 -0
- package/dist/uploads/types.d.ts +20 -0
- package/dist/validation/buildRuleBlocks.js +46 -0
- package/dist/validation/buildRuleBlocks.js.map +1 -0
- package/dist/validation/builtin/email.js +19 -0
- package/dist/validation/builtin/email.js.map +1 -0
- package/dist/validation/builtin/index.js +27 -0
- package/dist/validation/builtin/index.js.map +1 -0
- package/dist/validation/builtin/matchesField.js +20 -0
- package/dist/validation/builtin/matchesField.js.map +1 -0
- package/dist/validation/builtin/max.js +21 -0
- package/dist/validation/builtin/max.js.map +1 -0
- package/dist/validation/builtin/maxLength.js +26 -0
- package/dist/validation/builtin/maxLength.js.map +1 -0
- package/dist/validation/builtin/min.js +21 -0
- package/dist/validation/builtin/min.js.map +1 -0
- package/dist/validation/builtin/minLength.js +26 -0
- package/dist/validation/builtin/minLength.js.map +1 -0
- package/dist/validation/builtin/notAlreadySubmitted.js +32 -0
- package/dist/validation/builtin/notAlreadySubmitted.js.map +1 -0
- package/dist/validation/builtin/oneOf.js +34 -0
- package/dist/validation/builtin/oneOf.js.map +1 -0
- package/dist/validation/builtin/pattern.js +41 -0
- package/dist/validation/builtin/pattern.js.map +1 -0
- package/dist/validation/builtin/url.js +22 -0
- package/dist/validation/builtin/url.js.map +1 -0
- package/dist/validation/defineValidationRule.d.ts +12 -0
- package/dist/validation/defineValidationRule.js +11 -0
- package/dist/validation/defineValidationRule.js.map +1 -0
- package/dist/validation/message.js +14 -0
- package/dist/validation/message.js.map +1 -0
- package/dist/validation/registry.d.ts +10 -0
- package/dist/validation/registry.js +20 -0
- package/dist/validation/registry.js.map +1 -0
- package/dist/validation/runValidation.js +111 -0
- package/dist/validation/runValidation.js.map +1 -0
- package/dist/validation/types.d.ts +76 -0
- package/package.json +8 -5
- package/styles/form-builder.css +201 -11
- package/dist/constants-B-BUfetP.d.ts +0 -288
- package/dist/exports/client.js.map +0 -1
- package/dist/exports/react.js.map +0 -1
- package/dist/exports/rsc.js.map +0 -1
- package/dist/fieldTypes-B8jkNRob.d.ts +0 -188
- package/dist/fieldTypes-CzhhJXjg.js.map +0 -1
- package/dist/index-DfFYGbVF.d.ts +0 -481
- package/dist/keys-N5xGiUsh.js.map +0 -1
- package/dist/registry-CoCyhtvB.js +0 -282
- package/dist/registry-CoCyhtvB.js.map +0 -1
- package/dist/resolver-OeQyVH2N.js +0 -665
- package/dist/resolver-OeQyVH2N.js.map +0 -1
- package/dist/translations-edMqq_2e.js.map +0 -1
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { keys } from "../../translations/keys.js";
|
|
2
|
+
import { defineValidationRule } from "../defineValidationRule.js";
|
|
3
|
+
//#region src/validation/builtin/email.ts
|
|
4
|
+
const EMAIL_PATTERN = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
5
|
+
const emailRule = defineValidationRule({
|
|
6
|
+
type: "email",
|
|
7
|
+
label: keys.ruleEmail,
|
|
8
|
+
appliesTo: [
|
|
9
|
+
"text",
|
|
10
|
+
"textarea",
|
|
11
|
+
"email"
|
|
12
|
+
],
|
|
13
|
+
defaultMessage: keys.ruleEmailMessage,
|
|
14
|
+
validate: ({ value, message }) => value == null || value === "" || EMAIL_PATTERN.test(value) ? true : message()
|
|
15
|
+
});
|
|
16
|
+
//#endregion
|
|
17
|
+
export { emailRule };
|
|
18
|
+
|
|
19
|
+
//# sourceMappingURL=email.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"email.js","names":[],"sources":["../../../src/validation/builtin/email.ts"],"sourcesContent":["import { keys } from '../../translations/keys'\nimport { defineValidationRule } from '../defineValidationRule'\n\nconst EMAIL_PATTERN = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/\n\nexport const emailRule = defineValidationRule<Record<string, never>, string>({\n\ttype: 'email',\n\tlabel: keys.ruleEmail,\n\tappliesTo: ['text', 'textarea', 'email'],\n\tdefaultMessage: keys.ruleEmailMessage,\n\tvalidate: ({ value, message }) =>\n\t\tvalue == null || value === '' || EMAIL_PATTERN.test(value) ? true : message(),\n})\n"],"mappings":";;;AAGA,MAAM,gBAAgB;AAEtB,MAAa,YAAY,qBAAoD;CAC5E,MAAM;CACN,OAAO,KAAK;CACZ,WAAW;EAAC;EAAQ;EAAY;CAAO;CACvC,gBAAgB,KAAK;CACrB,WAAW,EAAE,OAAO,cACnB,SAAS,QAAQ,UAAU,MAAM,cAAc,KAAK,KAAK,IAAI,OAAO,QAAQ;AAC9E,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { emailRule } from "./email.js";
|
|
2
|
+
import { matchesFieldRule } from "./matchesField.js";
|
|
3
|
+
import { maxRule } from "./max.js";
|
|
4
|
+
import { maxLengthRule } from "./maxLength.js";
|
|
5
|
+
import { minRule } from "./min.js";
|
|
6
|
+
import { minLengthRule } from "./minLength.js";
|
|
7
|
+
import { notAlreadySubmittedRule } from "./notAlreadySubmitted.js";
|
|
8
|
+
import { oneOfRule } from "./oneOf.js";
|
|
9
|
+
import { patternRule } from "./pattern.js";
|
|
10
|
+
import { urlRule } from "./url.js";
|
|
11
|
+
//#region src/validation/builtin/index.ts
|
|
12
|
+
const defaultValidationRules = [
|
|
13
|
+
minLengthRule,
|
|
14
|
+
maxLengthRule,
|
|
15
|
+
minRule,
|
|
16
|
+
maxRule,
|
|
17
|
+
patternRule,
|
|
18
|
+
emailRule,
|
|
19
|
+
urlRule,
|
|
20
|
+
oneOfRule,
|
|
21
|
+
matchesFieldRule,
|
|
22
|
+
notAlreadySubmittedRule
|
|
23
|
+
];
|
|
24
|
+
//#endregion
|
|
25
|
+
export { defaultValidationRules };
|
|
26
|
+
|
|
27
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../../src/validation/builtin/index.ts"],"sourcesContent":["import type { AnyValidationRuleDefinition } from '../types'\nimport { emailRule } from './email'\nimport { matchesFieldRule } from './matchesField'\nimport { maxRule } from './max'\nimport { maxLengthRule } from './maxLength'\nimport { minRule } from './min'\nimport { minLengthRule } from './minLength'\nimport { notAlreadySubmittedRule } from './notAlreadySubmitted'\nimport { oneOfRule } from './oneOf'\nimport { patternRule } from './pattern'\nimport { urlRule } from './url'\n\n// Rules are authored with precise param/value generics; the registry stores them erased (params\n// re-narrow per matched rule at execution). One cast per rule, no `any`.\nexport const defaultValidationRules: AnyValidationRuleDefinition[] = [\n\tminLengthRule as AnyValidationRuleDefinition,\n\tmaxLengthRule as AnyValidationRuleDefinition,\n\tminRule as AnyValidationRuleDefinition,\n\tmaxRule as AnyValidationRuleDefinition,\n\tpatternRule as AnyValidationRuleDefinition,\n\temailRule as AnyValidationRuleDefinition,\n\turlRule as AnyValidationRuleDefinition,\n\toneOfRule as AnyValidationRuleDefinition,\n\tmatchesFieldRule as AnyValidationRuleDefinition,\n\tnotAlreadySubmittedRule as AnyValidationRuleDefinition,\n]\n"],"mappings":";;;;;;;;;;;AAcA,MAAa,yBAAwD;CACpE;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACD"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { keys } from "../../translations/keys.js";
|
|
2
|
+
import { labelFor } from "../../translations/server.js";
|
|
3
|
+
import { defineValidationRule } from "../defineValidationRule.js";
|
|
4
|
+
//#region src/validation/builtin/matchesField.ts
|
|
5
|
+
const matchesFieldRule = defineValidationRule({
|
|
6
|
+
type: "matchesField",
|
|
7
|
+
label: keys.ruleMatchesField,
|
|
8
|
+
params: [{
|
|
9
|
+
name: "field",
|
|
10
|
+
type: "text",
|
|
11
|
+
required: true,
|
|
12
|
+
label: labelFor(keys.ruleParamField)
|
|
13
|
+
}],
|
|
14
|
+
defaultMessage: keys.ruleMatchesFieldMessage,
|
|
15
|
+
validate: ({ value, params, siblingData, message }) => value === siblingData[params.field] ? true : message()
|
|
16
|
+
});
|
|
17
|
+
//#endregion
|
|
18
|
+
export { matchesFieldRule };
|
|
19
|
+
|
|
20
|
+
//# sourceMappingURL=matchesField.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"matchesField.js","names":[],"sources":["../../../src/validation/builtin/matchesField.ts"],"sourcesContent":["import { keys } from '../../translations/keys'\nimport { labelFor } from '../../translations/server'\nimport { defineValidationRule } from '../defineValidationRule'\n\nexport const matchesFieldRule = defineValidationRule<{ field: string }, unknown>({\n\ttype: 'matchesField',\n\tlabel: keys.ruleMatchesField,\n\tparams: [{ name: 'field', type: 'text', required: true, label: labelFor(keys.ruleParamField) }],\n\tdefaultMessage: keys.ruleMatchesFieldMessage,\n\tvalidate: ({ value, params, siblingData, message }) =>\n\t\tvalue === siblingData[params.field] ? true : message(),\n})\n"],"mappings":";;;;AAIA,MAAa,mBAAmB,qBAAiD;CAChF,MAAM;CACN,OAAO,KAAK;CACZ,QAAQ,CAAC;EAAE,MAAM;EAAS,MAAM;EAAQ,UAAU;EAAM,OAAO,SAAS,KAAK,cAAc;CAAE,CAAC;CAC9F,gBAAgB,KAAK;CACrB,WAAW,EAAE,OAAO,QAAQ,aAAa,cACxC,UAAU,YAAY,OAAO,SAAS,OAAO,QAAQ;AACvD,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { keys } from "../../translations/keys.js";
|
|
2
|
+
import { labelFor } from "../../translations/server.js";
|
|
3
|
+
import { defineValidationRule } from "../defineValidationRule.js";
|
|
4
|
+
//#region src/validation/builtin/max.ts
|
|
5
|
+
const maxRule = defineValidationRule({
|
|
6
|
+
type: "max",
|
|
7
|
+
label: keys.ruleMax,
|
|
8
|
+
appliesTo: ["number"],
|
|
9
|
+
params: [{
|
|
10
|
+
name: "max",
|
|
11
|
+
type: "number",
|
|
12
|
+
required: true,
|
|
13
|
+
label: labelFor(keys.ruleParamMax)
|
|
14
|
+
}],
|
|
15
|
+
defaultMessage: keys.ruleMaxMessage,
|
|
16
|
+
validate: ({ value, params, message }) => value == null || value <= params.max ? true : message({ max: params.max })
|
|
17
|
+
});
|
|
18
|
+
//#endregion
|
|
19
|
+
export { maxRule };
|
|
20
|
+
|
|
21
|
+
//# sourceMappingURL=max.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"max.js","names":[],"sources":["../../../src/validation/builtin/max.ts"],"sourcesContent":["import { keys } from '../../translations/keys'\nimport { labelFor } from '../../translations/server'\nimport { defineValidationRule } from '../defineValidationRule'\n\nexport const maxRule = defineValidationRule<{ max: number }, number>({\n\ttype: 'max',\n\tlabel: keys.ruleMax,\n\tappliesTo: ['number'],\n\tparams: [{ name: 'max', type: 'number', required: true, label: labelFor(keys.ruleParamMax) }],\n\tdefaultMessage: keys.ruleMaxMessage,\n\tvalidate: ({ value, params, message }) =>\n\t\tvalue == null || value <= params.max ? true : message({ max: params.max }),\n})\n"],"mappings":";;;;AAIA,MAAa,UAAU,qBAA8C;CACpE,MAAM;CACN,OAAO,KAAK;CACZ,WAAW,CAAC,QAAQ;CACpB,QAAQ,CAAC;EAAE,MAAM;EAAO,MAAM;EAAU,UAAU;EAAM,OAAO,SAAS,KAAK,YAAY;CAAE,CAAC;CAC5F,gBAAgB,KAAK;CACrB,WAAW,EAAE,OAAO,QAAQ,cAC3B,SAAS,QAAQ,SAAS,OAAO,MAAM,OAAO,QAAQ,EAAE,KAAK,OAAO,IAAI,CAAC;AAC3E,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { keys } from "../../translations/keys.js";
|
|
2
|
+
import { labelFor } from "../../translations/server.js";
|
|
3
|
+
import { defineValidationRule } from "../defineValidationRule.js";
|
|
4
|
+
//#region src/validation/builtin/maxLength.ts
|
|
5
|
+
const maxLengthRule = defineValidationRule({
|
|
6
|
+
type: "maxLength",
|
|
7
|
+
label: keys.ruleMaxLength,
|
|
8
|
+
appliesTo: [
|
|
9
|
+
"text",
|
|
10
|
+
"textarea",
|
|
11
|
+
"email"
|
|
12
|
+
],
|
|
13
|
+
params: [{
|
|
14
|
+
name: "max",
|
|
15
|
+
type: "number",
|
|
16
|
+
required: true,
|
|
17
|
+
min: 0,
|
|
18
|
+
label: labelFor(keys.ruleParamMax)
|
|
19
|
+
}],
|
|
20
|
+
defaultMessage: keys.ruleMaxLengthMessage,
|
|
21
|
+
validate: ({ value, params, message }) => value == null || value === "" || value.length <= params.max ? true : message({ max: params.max })
|
|
22
|
+
});
|
|
23
|
+
//#endregion
|
|
24
|
+
export { maxLengthRule };
|
|
25
|
+
|
|
26
|
+
//# sourceMappingURL=maxLength.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"maxLength.js","names":[],"sources":["../../../src/validation/builtin/maxLength.ts"],"sourcesContent":["import { keys } from '../../translations/keys'\nimport { labelFor } from '../../translations/server'\nimport { defineValidationRule } from '../defineValidationRule'\n\nexport const maxLengthRule = defineValidationRule<{ max: number }, string>({\n\ttype: 'maxLength',\n\tlabel: keys.ruleMaxLength,\n\tappliesTo: ['text', 'textarea', 'email'],\n\tparams: [\n\t\t{ name: 'max', type: 'number', required: true, min: 0, label: labelFor(keys.ruleParamMax) },\n\t],\n\tdefaultMessage: keys.ruleMaxLengthMessage,\n\tvalidate: ({ value, params, message }) =>\n\t\tvalue == null || value === '' || value.length <= params.max\n\t\t\t? true\n\t\t\t: message({ max: params.max }),\n})\n"],"mappings":";;;;AAIA,MAAa,gBAAgB,qBAA8C;CAC1E,MAAM;CACN,OAAO,KAAK;CACZ,WAAW;EAAC;EAAQ;EAAY;CAAO;CACvC,QAAQ,CACP;EAAE,MAAM;EAAO,MAAM;EAAU,UAAU;EAAM,KAAK;EAAG,OAAO,SAAS,KAAK,YAAY;CAAE,CAC3F;CACA,gBAAgB,KAAK;CACrB,WAAW,EAAE,OAAO,QAAQ,cAC3B,SAAS,QAAQ,UAAU,MAAM,MAAM,UAAU,OAAO,MACrD,OACA,QAAQ,EAAE,KAAK,OAAO,IAAI,CAAC;AAChC,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { keys } from "../../translations/keys.js";
|
|
2
|
+
import { labelFor } from "../../translations/server.js";
|
|
3
|
+
import { defineValidationRule } from "../defineValidationRule.js";
|
|
4
|
+
//#region src/validation/builtin/min.ts
|
|
5
|
+
const minRule = defineValidationRule({
|
|
6
|
+
type: "min",
|
|
7
|
+
label: keys.ruleMin,
|
|
8
|
+
appliesTo: ["number"],
|
|
9
|
+
params: [{
|
|
10
|
+
name: "min",
|
|
11
|
+
type: "number",
|
|
12
|
+
required: true,
|
|
13
|
+
label: labelFor(keys.ruleParamMin)
|
|
14
|
+
}],
|
|
15
|
+
defaultMessage: keys.ruleMinMessage,
|
|
16
|
+
validate: ({ value, params, message }) => value == null || value >= params.min ? true : message({ min: params.min })
|
|
17
|
+
});
|
|
18
|
+
//#endregion
|
|
19
|
+
export { minRule };
|
|
20
|
+
|
|
21
|
+
//# sourceMappingURL=min.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"min.js","names":[],"sources":["../../../src/validation/builtin/min.ts"],"sourcesContent":["import { keys } from '../../translations/keys'\nimport { labelFor } from '../../translations/server'\nimport { defineValidationRule } from '../defineValidationRule'\n\nexport const minRule = defineValidationRule<{ min: number }, number>({\n\ttype: 'min',\n\tlabel: keys.ruleMin,\n\tappliesTo: ['number'],\n\tparams: [{ name: 'min', type: 'number', required: true, label: labelFor(keys.ruleParamMin) }],\n\tdefaultMessage: keys.ruleMinMessage,\n\tvalidate: ({ value, params, message }) =>\n\t\tvalue == null || value >= params.min ? true : message({ min: params.min }),\n})\n"],"mappings":";;;;AAIA,MAAa,UAAU,qBAA8C;CACpE,MAAM;CACN,OAAO,KAAK;CACZ,WAAW,CAAC,QAAQ;CACpB,QAAQ,CAAC;EAAE,MAAM;EAAO,MAAM;EAAU,UAAU;EAAM,OAAO,SAAS,KAAK,YAAY;CAAE,CAAC;CAC5F,gBAAgB,KAAK;CACrB,WAAW,EAAE,OAAO,QAAQ,cAC3B,SAAS,QAAQ,SAAS,OAAO,MAAM,OAAO,QAAQ,EAAE,KAAK,OAAO,IAAI,CAAC;AAC3E,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { keys } from "../../translations/keys.js";
|
|
2
|
+
import { labelFor } from "../../translations/server.js";
|
|
3
|
+
import { defineValidationRule } from "../defineValidationRule.js";
|
|
4
|
+
//#region src/validation/builtin/minLength.ts
|
|
5
|
+
const minLengthRule = defineValidationRule({
|
|
6
|
+
type: "minLength",
|
|
7
|
+
label: keys.ruleMinLength,
|
|
8
|
+
appliesTo: [
|
|
9
|
+
"text",
|
|
10
|
+
"textarea",
|
|
11
|
+
"email"
|
|
12
|
+
],
|
|
13
|
+
params: [{
|
|
14
|
+
name: "min",
|
|
15
|
+
type: "number",
|
|
16
|
+
required: true,
|
|
17
|
+
min: 0,
|
|
18
|
+
label: labelFor(keys.ruleParamMin)
|
|
19
|
+
}],
|
|
20
|
+
defaultMessage: keys.ruleMinLengthMessage,
|
|
21
|
+
validate: ({ value, params, message }) => value == null || value === "" || value.length >= params.min ? true : message({ min: params.min })
|
|
22
|
+
});
|
|
23
|
+
//#endregion
|
|
24
|
+
export { minLengthRule };
|
|
25
|
+
|
|
26
|
+
//# sourceMappingURL=minLength.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"minLength.js","names":[],"sources":["../../../src/validation/builtin/minLength.ts"],"sourcesContent":["import { keys } from '../../translations/keys'\nimport { labelFor } from '../../translations/server'\nimport { defineValidationRule } from '../defineValidationRule'\n\nexport const minLengthRule = defineValidationRule<{ min: number }, string>({\n\ttype: 'minLength',\n\tlabel: keys.ruleMinLength,\n\tappliesTo: ['text', 'textarea', 'email'],\n\tparams: [\n\t\t{ name: 'min', type: 'number', required: true, min: 0, label: labelFor(keys.ruleParamMin) },\n\t],\n\tdefaultMessage: keys.ruleMinLengthMessage,\n\tvalidate: ({ value, params, message }) =>\n\t\tvalue == null || value === '' || value.length >= params.min\n\t\t\t? true\n\t\t\t: message({ min: params.min }),\n})\n"],"mappings":";;;;AAIA,MAAa,gBAAgB,qBAA8C;CAC1E,MAAM;CACN,OAAO,KAAK;CACZ,WAAW;EAAC;EAAQ;EAAY;CAAO;CACvC,QAAQ,CACP;EAAE,MAAM;EAAO,MAAM;EAAU,UAAU;EAAM,KAAK;EAAG,OAAO,SAAS,KAAK,YAAY;CAAE,CAC3F;CACA,gBAAgB,KAAK;CACrB,WAAW,EAAE,OAAO,QAAQ,cAC3B,SAAS,QAAQ,UAAU,MAAM,MAAM,UAAU,OAAO,MACrD,OACA,QAAQ,EAAE,KAAK,OAAO,IAAI,CAAC;AAChC,CAAC"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { keys } from "../../translations/keys.js";
|
|
2
|
+
import { defineValidationRule } from "../defineValidationRule.js";
|
|
3
|
+
//#region src/validation/builtin/notAlreadySubmitted.ts
|
|
4
|
+
const FORM_SUBMISSIONS_SLUG = "form-submissions";
|
|
5
|
+
const SCAN_LIMIT = 500;
|
|
6
|
+
/**
|
|
7
|
+
* Server-only async exemplar: rejects a value already present for the same form. Scans up to
|
|
8
|
+
* `SCAN_LIMIT` recent submissions in JS (the values live in a json column, so a portable DB query is
|
|
9
|
+
* not available); a future phase can add an indexed dedup column for scale.
|
|
10
|
+
*/
|
|
11
|
+
const notAlreadySubmittedRule = defineValidationRule({
|
|
12
|
+
type: "notAlreadySubmitted",
|
|
13
|
+
label: keys.ruleNotAlreadySubmitted,
|
|
14
|
+
client: false,
|
|
15
|
+
defaultMessage: keys.ruleNotAlreadySubmittedMessage,
|
|
16
|
+
validate: async ({ value, field, payload, req, formId, message }) => {
|
|
17
|
+
if (value == null || value === "" || !payload || formId == null) return true;
|
|
18
|
+
return (await payload.find({
|
|
19
|
+
collection: FORM_SUBMISSIONS_SLUG,
|
|
20
|
+
where: { form: { equals: formId } },
|
|
21
|
+
limit: SCAN_LIMIT,
|
|
22
|
+
depth: 0,
|
|
23
|
+
req
|
|
24
|
+
})).docs.some((doc) => {
|
|
25
|
+
return (doc.values ?? []).some((entry) => entry.field === field.name && entry.value === value);
|
|
26
|
+
}) ? message() : true;
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
//#endregion
|
|
30
|
+
export { notAlreadySubmittedRule };
|
|
31
|
+
|
|
32
|
+
//# sourceMappingURL=notAlreadySubmitted.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"notAlreadySubmitted.js","names":[],"sources":["../../../src/validation/builtin/notAlreadySubmitted.ts"],"sourcesContent":["import { keys } from '../../translations/keys'\nimport { defineValidationRule } from '../defineValidationRule'\n\nconst FORM_SUBMISSIONS_SLUG = 'form-submissions'\nconst SCAN_LIMIT = 500\n\n/**\n * Server-only async exemplar: rejects a value already present for the same form. Scans up to\n * `SCAN_LIMIT` recent submissions in JS (the values live in a json column, so a portable DB query is\n * not available); a future phase can add an indexed dedup column for scale.\n */\nexport const notAlreadySubmittedRule = defineValidationRule<Record<string, never>, unknown>({\n\ttype: 'notAlreadySubmitted',\n\tlabel: keys.ruleNotAlreadySubmitted,\n\tclient: false,\n\tdefaultMessage: keys.ruleNotAlreadySubmittedMessage,\n\tvalidate: async ({ value, field, payload, req, formId, message }) => {\n\t\tif (value == null || value === '' || !payload || formId == null) {\n\t\t\treturn true\n\t\t}\n\t\tconst result = await payload.find({\n\t\t\tcollection: FORM_SUBMISSIONS_SLUG,\n\t\t\twhere: { form: { equals: formId } },\n\t\t\tlimit: SCAN_LIMIT,\n\t\t\tdepth: 0,\n\t\t\treq,\n\t\t})\n\t\tconst clash = result.docs.some((doc) => {\n\t\t\tconst values = (doc as { values?: { field: string; value: unknown }[] }).values ?? []\n\t\t\treturn values.some((entry) => entry.field === field.name && entry.value === value)\n\t\t})\n\t\treturn clash ? message() : true\n\t},\n})\n"],"mappings":";;;AAGA,MAAM,wBAAwB;AAC9B,MAAM,aAAa;;;;;;AAOnB,MAAa,0BAA0B,qBAAqD;CAC3F,MAAM;CACN,OAAO,KAAK;CACZ,QAAQ;CACR,gBAAgB,KAAK;CACrB,UAAU,OAAO,EAAE,OAAO,OAAO,SAAS,KAAK,QAAQ,cAAc;EACpE,IAAI,SAAS,QAAQ,UAAU,MAAM,CAAC,WAAW,UAAU,MAC1D,OAAO;EAaR,QAJc,MAPO,QAAQ,KAAK;GACjC,YAAY;GACZ,OAAO,EAAE,MAAM,EAAE,QAAQ,OAAO,EAAE;GAClC,OAAO;GACP,OAAO;GACP;EACD,CAAC,GACoB,KAAK,MAAM,QAAQ;GAEvC,QADgB,IAAyD,UAAU,CAAC,GACtE,MAAM,UAAU,MAAM,UAAU,MAAM,QAAQ,MAAM,UAAU,KAAK;EAClF,CACW,IAAI,QAAQ,IAAI;CAC5B;AACD,CAAC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { keys } from "../../translations/keys.js";
|
|
2
|
+
import { labelFor } from "../../translations/server.js";
|
|
3
|
+
import { defineValidationRule } from "../defineValidationRule.js";
|
|
4
|
+
//#region src/validation/builtin/oneOf.ts
|
|
5
|
+
const oneOfRule = defineValidationRule({
|
|
6
|
+
type: "oneOf",
|
|
7
|
+
label: keys.ruleOneOf,
|
|
8
|
+
appliesTo: [
|
|
9
|
+
"text",
|
|
10
|
+
"textarea",
|
|
11
|
+
"select"
|
|
12
|
+
],
|
|
13
|
+
params: [{
|
|
14
|
+
name: "values",
|
|
15
|
+
type: "array",
|
|
16
|
+
label: labelFor(keys.ruleParamValues),
|
|
17
|
+
fields: [{
|
|
18
|
+
name: "value",
|
|
19
|
+
type: "text",
|
|
20
|
+
required: true
|
|
21
|
+
}]
|
|
22
|
+
}],
|
|
23
|
+
defaultMessage: keys.ruleOneOfMessage,
|
|
24
|
+
validate: ({ value, params, message }) => {
|
|
25
|
+
if (value == null || value === "") return true;
|
|
26
|
+
const allowed = (params.values ?? []).map((entry) => entry.value);
|
|
27
|
+
if (allowed.length === 0) return true;
|
|
28
|
+
return allowed.includes(value) ? true : message();
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
//#endregion
|
|
32
|
+
export { oneOfRule };
|
|
33
|
+
|
|
34
|
+
//# sourceMappingURL=oneOf.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oneOf.js","names":[],"sources":["../../../src/validation/builtin/oneOf.ts"],"sourcesContent":["import { keys } from '../../translations/keys'\nimport { labelFor } from '../../translations/server'\nimport { defineValidationRule } from '../defineValidationRule'\n\nexport const oneOfRule = defineValidationRule<{ values?: { value: string }[] }, string>({\n\ttype: 'oneOf',\n\tlabel: keys.ruleOneOf,\n\tappliesTo: ['text', 'textarea', 'select'],\n\tparams: [\n\t\t{\n\t\t\tname: 'values',\n\t\t\ttype: 'array',\n\t\t\tlabel: labelFor(keys.ruleParamValues),\n\t\t\tfields: [{ name: 'value', type: 'text', required: true }],\n\t\t},\n\t],\n\tdefaultMessage: keys.ruleOneOfMessage,\n\tvalidate: ({ value, params, message }) => {\n\t\tif (value == null || value === '') {\n\t\t\treturn true\n\t\t}\n\t\tconst allowed = (params.values ?? []).map((entry) => entry.value)\n\t\tif (allowed.length === 0) {\n\t\t\treturn true\n\t\t}\n\t\treturn allowed.includes(value) ? true : message()\n\t},\n})\n"],"mappings":";;;;AAIA,MAAa,YAAY,qBAA+D;CACvF,MAAM;CACN,OAAO,KAAK;CACZ,WAAW;EAAC;EAAQ;EAAY;CAAQ;CACxC,QAAQ,CACP;EACC,MAAM;EACN,MAAM;EACN,OAAO,SAAS,KAAK,eAAe;EACpC,QAAQ,CAAC;GAAE,MAAM;GAAS,MAAM;GAAQ,UAAU;EAAK,CAAC;CACzD,CACD;CACA,gBAAgB,KAAK;CACrB,WAAW,EAAE,OAAO,QAAQ,cAAc;EACzC,IAAI,SAAS,QAAQ,UAAU,IAC9B,OAAO;EAER,MAAM,WAAW,OAAO,UAAU,CAAC,GAAG,KAAK,UAAU,MAAM,KAAK;EAChE,IAAI,QAAQ,WAAW,GACtB,OAAO;EAER,OAAO,QAAQ,SAAS,KAAK,IAAI,OAAO,QAAQ;CACjD;AACD,CAAC"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { keys } from "../../translations/keys.js";
|
|
2
|
+
import { labelFor } from "../../translations/server.js";
|
|
3
|
+
import { defineValidationRule } from "../defineValidationRule.js";
|
|
4
|
+
//#region src/validation/builtin/pattern.ts
|
|
5
|
+
const tryRegExp = (pattern, flags) => {
|
|
6
|
+
try {
|
|
7
|
+
return new RegExp(pattern, flags);
|
|
8
|
+
} catch {
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
};
|
|
12
|
+
const patternRule = defineValidationRule({
|
|
13
|
+
type: "pattern",
|
|
14
|
+
label: keys.rulePattern,
|
|
15
|
+
appliesTo: [
|
|
16
|
+
"text",
|
|
17
|
+
"textarea",
|
|
18
|
+
"email"
|
|
19
|
+
],
|
|
20
|
+
params: [{
|
|
21
|
+
name: "pattern",
|
|
22
|
+
type: "text",
|
|
23
|
+
required: true,
|
|
24
|
+
label: labelFor(keys.ruleParamPattern)
|
|
25
|
+
}, {
|
|
26
|
+
name: "flags",
|
|
27
|
+
type: "text",
|
|
28
|
+
label: labelFor(keys.ruleParamFlags)
|
|
29
|
+
}],
|
|
30
|
+
defaultMessage: keys.rulePatternMessage,
|
|
31
|
+
validate: ({ value, params, message }) => {
|
|
32
|
+
if (value == null || value === "") return true;
|
|
33
|
+
const regex = tryRegExp(params.pattern, params.flags);
|
|
34
|
+
if (!regex) return true;
|
|
35
|
+
return regex.test(value) ? true : message();
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
//#endregion
|
|
39
|
+
export { patternRule };
|
|
40
|
+
|
|
41
|
+
//# sourceMappingURL=pattern.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pattern.js","names":[],"sources":["../../../src/validation/builtin/pattern.ts"],"sourcesContent":["import { keys } from '../../translations/keys'\nimport { labelFor } from '../../translations/server'\nimport { defineValidationRule } from '../defineValidationRule'\n\nconst tryRegExp = (pattern: string, flags?: string): RegExp | undefined => {\n\ttry {\n\t\treturn new RegExp(pattern, flags)\n\t} catch {\n\t\treturn undefined\n\t}\n}\n\nexport const patternRule = defineValidationRule<{ pattern: string; flags?: string }, string>({\n\ttype: 'pattern',\n\tlabel: keys.rulePattern,\n\tappliesTo: ['text', 'textarea', 'email'],\n\tparams: [\n\t\t{ name: 'pattern', type: 'text', required: true, label: labelFor(keys.ruleParamPattern) },\n\t\t{ name: 'flags', type: 'text', label: labelFor(keys.ruleParamFlags) },\n\t],\n\tdefaultMessage: keys.rulePatternMessage,\n\tvalidate: ({ value, params, message }) => {\n\t\tif (value == null || value === '') {\n\t\t\treturn true\n\t\t}\n\t\tconst regex = tryRegExp(params.pattern, params.flags)\n\t\tif (!regex) {\n\t\t\treturn true\n\t\t}\n\t\treturn regex.test(value) ? true : message()\n\t},\n})\n"],"mappings":";;;;AAIA,MAAM,aAAa,SAAiB,UAAuC;CAC1E,IAAI;EACH,OAAO,IAAI,OAAO,SAAS,KAAK;CACjC,QAAQ;EACP;CACD;AACD;AAEA,MAAa,cAAc,qBAAkE;CAC5F,MAAM;CACN,OAAO,KAAK;CACZ,WAAW;EAAC;EAAQ;EAAY;CAAO;CACvC,QAAQ,CACP;EAAE,MAAM;EAAW,MAAM;EAAQ,UAAU;EAAM,OAAO,SAAS,KAAK,gBAAgB;CAAE,GACxF;EAAE,MAAM;EAAS,MAAM;EAAQ,OAAO,SAAS,KAAK,cAAc;CAAE,CACrE;CACA,gBAAgB,KAAK;CACrB,WAAW,EAAE,OAAO,QAAQ,cAAc;EACzC,IAAI,SAAS,QAAQ,UAAU,IAC9B,OAAO;EAER,MAAM,QAAQ,UAAU,OAAO,SAAS,OAAO,KAAK;EACpD,IAAI,CAAC,OACJ,OAAO;EAER,OAAO,MAAM,KAAK,KAAK,IAAI,OAAO,QAAQ;CAC3C;AACD,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { keys } from "../../translations/keys.js";
|
|
2
|
+
import { defineValidationRule } from "../defineValidationRule.js";
|
|
3
|
+
//#region src/validation/builtin/url.ts
|
|
4
|
+
const isUrl = (value) => {
|
|
5
|
+
try {
|
|
6
|
+
const url = new URL(value);
|
|
7
|
+
return url.protocol === "http:" || url.protocol === "https:";
|
|
8
|
+
} catch {
|
|
9
|
+
return false;
|
|
10
|
+
}
|
|
11
|
+
};
|
|
12
|
+
const urlRule = defineValidationRule({
|
|
13
|
+
type: "url",
|
|
14
|
+
label: keys.ruleUrl,
|
|
15
|
+
appliesTo: ["text", "textarea"],
|
|
16
|
+
defaultMessage: keys.ruleUrlMessage,
|
|
17
|
+
validate: ({ value, message }) => value == null || value === "" || isUrl(value) ? true : message()
|
|
18
|
+
});
|
|
19
|
+
//#endregion
|
|
20
|
+
export { urlRule };
|
|
21
|
+
|
|
22
|
+
//# sourceMappingURL=url.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"url.js","names":[],"sources":["../../../src/validation/builtin/url.ts"],"sourcesContent":["import { keys } from '../../translations/keys'\nimport { defineValidationRule } from '../defineValidationRule'\n\nconst isUrl = (value: string): boolean => {\n\ttry {\n\t\tconst url = new URL(value)\n\t\treturn url.protocol === 'http:' || url.protocol === 'https:'\n\t} catch {\n\t\treturn false\n\t}\n}\n\nexport const urlRule = defineValidationRule<Record<string, never>, string>({\n\ttype: 'url',\n\tlabel: keys.ruleUrl,\n\tappliesTo: ['text', 'textarea'],\n\tdefaultMessage: keys.ruleUrlMessage,\n\tvalidate: ({ value, message }) =>\n\t\tvalue == null || value === '' || isUrl(value) ? true : message(),\n})\n"],"mappings":";;;AAGA,MAAM,SAAS,UAA2B;CACzC,IAAI;EACH,MAAM,MAAM,IAAI,IAAI,KAAK;EACzB,OAAO,IAAI,aAAa,WAAW,IAAI,aAAa;CACrD,QAAQ;EACP,OAAO;CACR;AACD;AAEA,MAAa,UAAU,qBAAoD;CAC1E,MAAM;CACN,OAAO,KAAK;CACZ,WAAW,CAAC,QAAQ,UAAU;CAC9B,gBAAgB,KAAK;CACrB,WAAW,EAAE,OAAO,cACnB,SAAS,QAAQ,UAAU,MAAM,MAAM,KAAK,IAAI,OAAO,QAAQ;AACjE,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { ValidationParams, ValidationRuleDefinition } from "./types.js";
|
|
2
|
+
|
|
3
|
+
//#region src/validation/defineValidationRule.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* Define a validation rule type once: its `params` become a Payload `Field[]` in the per-field
|
|
6
|
+
* constraint list, its typed `validate` runs in the one engine on client and server. Built-in rules
|
|
7
|
+
* use this same primitive, so custom rules are never second-class.
|
|
8
|
+
*/
|
|
9
|
+
declare const defineValidationRule: <TParams extends ValidationParams, TValue = unknown, TData extends Record<string, unknown> = Record<string, unknown>>(rule: ValidationRuleDefinition<TParams, TValue, TData>) => ValidationRuleDefinition<TParams, TValue, TData>;
|
|
10
|
+
//#endregion
|
|
11
|
+
export { defineValidationRule };
|
|
12
|
+
//# sourceMappingURL=defineValidationRule.d.ts.map
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
//#region src/validation/defineValidationRule.ts
|
|
2
|
+
/**
|
|
3
|
+
* Define a validation rule type once: its `params` become a Payload `Field[]` in the per-field
|
|
4
|
+
* constraint list, its typed `validate` runs in the one engine on client and server. Built-in rules
|
|
5
|
+
* use this same primitive, so custom rules are never second-class.
|
|
6
|
+
*/
|
|
7
|
+
const defineValidationRule = (rule) => rule;
|
|
8
|
+
//#endregion
|
|
9
|
+
export { defineValidationRule };
|
|
10
|
+
|
|
11
|
+
//# sourceMappingURL=defineValidationRule.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"defineValidationRule.js","names":[],"sources":["../../src/validation/defineValidationRule.ts"],"sourcesContent":["import type { ValidationParams, ValidationRuleDefinition } from './types'\n\n/**\n * Define a validation rule type once: its `params` become a Payload `Field[]` in the per-field\n * constraint list, its typed `validate` runs in the one engine on client and server. Built-in rules\n * use this same primitive, so custom rules are never second-class.\n */\nexport const defineValidationRule = <\n\tTParams extends ValidationParams,\n\tTValue = unknown,\n\tTData extends Record<string, unknown> = Record<string, unknown>,\n>(\n\trule: ValidationRuleDefinition<TParams, TValue, TData>\n): ValidationRuleDefinition<TParams, TValue, TData> => rule\n"],"mappings":";;;;;;AAOA,MAAa,wBAKZ,SACsD"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
//#region src/validation/message.ts
|
|
2
|
+
/** Replace `{key}` placeholders with `String(vars[key])`; unknown placeholders are left as-is. */
|
|
3
|
+
const resolveMessage = (template, vars) => template.replace(/\{(\w+)\}/g, (match, key) => Object.hasOwn(vars, key) ? String(vars[key]) : match);
|
|
4
|
+
/**
|
|
5
|
+
* Race a (possibly async) rule against a deadline so a hung server rule cannot stall the submit path.
|
|
6
|
+
* On timeout the `fallback` is resolved (the engine treats a timed-out rule as a non-blocking skip).
|
|
7
|
+
*/
|
|
8
|
+
const withTimeout = (promise, ms, fallback) => Promise.race([promise, new Promise((resolve) => {
|
|
9
|
+
setTimeout(() => resolve(fallback), ms);
|
|
10
|
+
})]);
|
|
11
|
+
//#endregion
|
|
12
|
+
export { resolveMessage, withTimeout };
|
|
13
|
+
|
|
14
|
+
//# sourceMappingURL=message.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"message.js","names":[],"sources":["../../src/validation/message.ts"],"sourcesContent":["/** Replace `{key}` placeholders with `String(vars[key])`; unknown placeholders are left as-is. */\nexport const resolveMessage = (template: string, vars: Record<string, unknown>): string =>\n\ttemplate.replace(/\\{(\\w+)\\}/g, (match, key: string) =>\n\t\tObject.hasOwn(vars, key) ? String(vars[key]) : match\n\t)\n\n/**\n * Race a (possibly async) rule against a deadline so a hung server rule cannot stall the submit path.\n * On timeout the `fallback` is resolved (the engine treats a timed-out rule as a non-blocking skip).\n */\nexport const withTimeout = <T>(promise: Promise<T>, ms: number, fallback: T): Promise<T> =>\n\tPromise.race([\n\t\tpromise,\n\t\tnew Promise<T>((resolve) => {\n\t\t\tsetTimeout(() => resolve(fallback), ms)\n\t\t}),\n\t])\n"],"mappings":";;AACA,MAAa,kBAAkB,UAAkB,SAChD,SAAS,QAAQ,eAAe,OAAO,QACtC,OAAO,OAAO,MAAM,GAAG,IAAI,OAAO,KAAK,IAAI,IAAI,KAChD;;;;;AAMD,MAAa,eAAkB,SAAqB,IAAY,aAC/D,QAAQ,KAAK,CACZ,SACA,IAAI,SAAY,YAAY;CAC3B,iBAAiB,QAAQ,QAAQ,GAAG,EAAE;AACvC,CAAC,CACF,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { AnyValidationRuleDefinition } from "./types.js";
|
|
2
|
+
|
|
3
|
+
//#region src/validation/registry.d.ts
|
|
4
|
+
type ValidationRuleRegistry = Map<string, AnyValidationRuleDefinition>;
|
|
5
|
+
/** Per-rule opt-in: `false` removes a built-in, `true` keeps it, an object adds a new rule or replaces one. */
|
|
6
|
+
type ValidationRuleOption = boolean | AnyValidationRuleDefinition;
|
|
7
|
+
type ValidationRulesConfig = Record<string, ValidationRuleOption>;
|
|
8
|
+
//#endregion
|
|
9
|
+
export { ValidationRuleOption, ValidationRuleRegistry, ValidationRulesConfig };
|
|
10
|
+
//# sourceMappingURL=registry.d.ts.map
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
//#region src/validation/registry.ts
|
|
2
|
+
const buildRuleRegistry = (rules) => {
|
|
3
|
+
const registry = /* @__PURE__ */ new Map();
|
|
4
|
+
for (const rule of rules) registry.set(rule.type, rule);
|
|
5
|
+
return registry;
|
|
6
|
+
};
|
|
7
|
+
/** Resolve the active rule registry from the built-in defaults and the plugin `rules` option. */
|
|
8
|
+
const resolveValidationRules = (defaults, config = {}) => {
|
|
9
|
+
const registry = buildRuleRegistry(defaults);
|
|
10
|
+
for (const [type, option] of Object.entries(config)) if (option === false) registry.delete(type);
|
|
11
|
+
else if (option === true) {} else registry.set(type, {
|
|
12
|
+
...option,
|
|
13
|
+
type
|
|
14
|
+
});
|
|
15
|
+
return registry;
|
|
16
|
+
};
|
|
17
|
+
//#endregion
|
|
18
|
+
export { buildRuleRegistry, resolveValidationRules };
|
|
19
|
+
|
|
20
|
+
//# sourceMappingURL=registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.js","names":[],"sources":["../../src/validation/registry.ts"],"sourcesContent":["import type { AnyValidationRuleDefinition } from './types'\n\nexport type ValidationRuleRegistry = Map<string, AnyValidationRuleDefinition>\n\n/** Per-rule opt-in: `false` removes a built-in, `true` keeps it, an object adds a new rule or replaces one. */\nexport type ValidationRuleOption = boolean | AnyValidationRuleDefinition\n\nexport type ValidationRulesConfig = Record<string, ValidationRuleOption>\n\nexport const buildRuleRegistry = (rules: AnyValidationRuleDefinition[]): ValidationRuleRegistry => {\n\tconst registry: ValidationRuleRegistry = new Map()\n\tfor (const rule of rules) {\n\t\tregistry.set(rule.type, rule)\n\t}\n\treturn registry\n}\n\n/** Resolve the active rule registry from the built-in defaults and the plugin `rules` option. */\nexport const resolveValidationRules = (\n\tdefaults: AnyValidationRuleDefinition[],\n\tconfig: ValidationRulesConfig = {}\n): ValidationRuleRegistry => {\n\tconst registry = buildRuleRegistry(defaults)\n\tfor (const [type, option] of Object.entries(config)) {\n\t\tif (option === false) {\n\t\t\tregistry.delete(type)\n\t\t} else if (option === true) {\n\t\t\t// keep the default; a no-op when no default exists for this key\n\t\t} else {\n\t\t\tregistry.set(type, { ...option, type })\n\t\t}\n\t}\n\treturn registry\n}\n"],"mappings":";AASA,MAAa,qBAAqB,UAAiE;CAClG,MAAM,2BAAmC,IAAI,IAAI;CACjD,KAAK,MAAM,QAAQ,OAClB,SAAS,IAAI,KAAK,MAAM,IAAI;CAE7B,OAAO;AACR;;AAGA,MAAa,0BACZ,UACA,SAAgC,CAAC,MACL;CAC5B,MAAM,WAAW,kBAAkB,QAAQ;CAC3C,KAAK,MAAM,CAAC,MAAM,WAAW,OAAO,QAAQ,MAAM,GACjD,IAAI,WAAW,OACd,SAAS,OAAO,IAAI;MACd,IAAI,WAAW,MAAM,CAE5B,OACC,SAAS,IAAI,MAAM;EAAE,GAAG;EAAQ;CAAK,CAAC;CAGxC,OAAO;AACR"}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { keys } from "../translations/keys.js";
|
|
2
|
+
import { resolveMessage, withTimeout } from "./message.js";
|
|
3
|
+
//#region src/validation/runValidation.ts
|
|
4
|
+
const RULE_TIMEOUT_MS = 5e3;
|
|
5
|
+
const isEmpty = (value) => value == null || value === "" || Array.isArray(value) && value.length === 0;
|
|
6
|
+
/** Build the per-instance message resolver: custom override (a literal template) or the localized default. */
|
|
7
|
+
const makeMessage = (instance, defaultMessageKey, t) => {
|
|
8
|
+
const { blockType: _blockType, message: _message, severity: _severity, ...params } = instance;
|
|
9
|
+
const template = typeof instance.message === "string" && instance.message.length > 0 ? instance.message : t(defaultMessageKey);
|
|
10
|
+
return (vars = {}) => resolveMessage(template, {
|
|
11
|
+
...params,
|
|
12
|
+
...vars
|
|
13
|
+
});
|
|
14
|
+
};
|
|
15
|
+
const toIssue = (result, fallbackSeverity) => {
|
|
16
|
+
if (result === true) return null;
|
|
17
|
+
if (typeof result === "string") return {
|
|
18
|
+
message: result,
|
|
19
|
+
severity: fallbackSeverity
|
|
20
|
+
};
|
|
21
|
+
return {
|
|
22
|
+
message: result.message,
|
|
23
|
+
severity: result.severity ?? fallbackSeverity
|
|
24
|
+
};
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* The one validation engine, run per field on client and server. Order: required, the field type's
|
|
28
|
+
* intrinsic validator, then each declarative rule instance. Server-only rules are skipped in client
|
|
29
|
+
* mode; every rule is wrapped in try/catch + a timeout so a bad rule cannot crash or stall the submit
|
|
30
|
+
* path (a thrown or timed-out rule fails open, logged on the server). Only `error`-severity issues
|
|
31
|
+
* block submission; the caller filters severity.
|
|
32
|
+
*/
|
|
33
|
+
const runValidation = async (input) => {
|
|
34
|
+
const { field, fieldDefinition, value, fieldType, ruleRegistry, answers, locale, t, operation, event, mode, req, payload, formId, timeoutMs } = input;
|
|
35
|
+
const timeout = timeoutMs ?? RULE_TIMEOUT_MS;
|
|
36
|
+
const errors = [];
|
|
37
|
+
if (field.required && isEmpty(value)) return { errors: [{
|
|
38
|
+
message: t(keys.validationRequired),
|
|
39
|
+
severity: "error"
|
|
40
|
+
}] };
|
|
41
|
+
if (isEmpty(value) && field.blockType !== "repeater") return { errors: [] };
|
|
42
|
+
if (fieldDefinition?.validate) try {
|
|
43
|
+
const ran = fieldDefinition.validate({
|
|
44
|
+
value,
|
|
45
|
+
config: field,
|
|
46
|
+
siblingData: answers,
|
|
47
|
+
data: answers,
|
|
48
|
+
locale,
|
|
49
|
+
t
|
|
50
|
+
});
|
|
51
|
+
const result = ran instanceof Promise ? await withTimeout(ran, timeout, true) : ran;
|
|
52
|
+
if (result !== true) errors.push({
|
|
53
|
+
message: result,
|
|
54
|
+
severity: "error"
|
|
55
|
+
});
|
|
56
|
+
} catch (error) {
|
|
57
|
+
req?.payload?.logger?.error?.({
|
|
58
|
+
err: error,
|
|
59
|
+
field: field.name
|
|
60
|
+
}, "form-builder intrinsic field validator threw");
|
|
61
|
+
}
|
|
62
|
+
if (fieldDefinition?.schema) try {
|
|
63
|
+
const outcome = await fieldDefinition.schema["~standard"].validate(value);
|
|
64
|
+
if (outcome.issues) for (const issue of outcome.issues) errors.push({
|
|
65
|
+
message: issue.message,
|
|
66
|
+
severity: "error"
|
|
67
|
+
});
|
|
68
|
+
} catch (error) {
|
|
69
|
+
req?.payload?.logger?.error?.({
|
|
70
|
+
err: error,
|
|
71
|
+
field: field.name
|
|
72
|
+
}, "form-builder field schema threw");
|
|
73
|
+
}
|
|
74
|
+
const instances = Array.isArray(field.validations) ? field.validations : [];
|
|
75
|
+
for (const instance of instances) {
|
|
76
|
+
const rule = ruleRegistry.get(instance.blockType);
|
|
77
|
+
if (!rule) continue;
|
|
78
|
+
if (mode === "client" && rule.client === false) continue;
|
|
79
|
+
const message = makeMessage(instance, rule.defaultMessage, t);
|
|
80
|
+
const fallbackSeverity = instance.severity ?? rule.severity ?? "error";
|
|
81
|
+
try {
|
|
82
|
+
const ran = rule.validate({
|
|
83
|
+
value,
|
|
84
|
+
params: instance,
|
|
85
|
+
siblingData: answers,
|
|
86
|
+
data: answers,
|
|
87
|
+
field,
|
|
88
|
+
fieldType,
|
|
89
|
+
operation,
|
|
90
|
+
event,
|
|
91
|
+
locale,
|
|
92
|
+
message,
|
|
93
|
+
req: mode === "server" ? req : void 0,
|
|
94
|
+
payload: mode === "server" ? payload : void 0,
|
|
95
|
+
formId: mode === "server" ? formId : void 0
|
|
96
|
+
});
|
|
97
|
+
const issue = toIssue(ran instanceof Promise ? await withTimeout(ran, timeout, true) : ran, fallbackSeverity);
|
|
98
|
+
if (issue) errors.push(issue);
|
|
99
|
+
} catch (error) {
|
|
100
|
+
req?.payload?.logger?.error?.({
|
|
101
|
+
err: error,
|
|
102
|
+
rule: rule.type
|
|
103
|
+
}, "form-builder validation rule threw");
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return { errors };
|
|
107
|
+
};
|
|
108
|
+
//#endregion
|
|
109
|
+
export { runValidation };
|
|
110
|
+
|
|
111
|
+
//# sourceMappingURL=runValidation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runValidation.js","names":[],"sources":["../../src/validation/runValidation.ts"],"sourcesContent":["import type { Payload, PayloadRequest } from 'payload'\nimport type { AnyFormFieldDefinition, Translate } from '../fields/types'\nimport type { FormFieldInstance } from '../submissions/types'\nimport { keys } from '../translations/keys'\nimport { resolveMessage, withTimeout } from './message'\nimport type { ValidationRuleRegistry } from './registry'\nimport type { MessageFn, ValidationRuleResult, ValidationSeverity } from './types'\n\nconst RULE_TIMEOUT_MS = 5000\n\nexport type ValidationIssue = { message: string; severity: ValidationSeverity }\n\nexport type RunValidationInput = {\n\tfield: FormFieldInstance\n\tfieldDefinition?: AnyFormFieldDefinition\n\tvalue: unknown\n\tfieldType: string\n\truleRegistry: ValidationRuleRegistry\n\tanswers: Record<string, unknown>\n\tlocale: string\n\tt: Translate\n\toperation: 'create' | 'update'\n\tevent: 'onChange' | 'submit'\n\tmode: 'client' | 'server'\n\treq?: PayloadRequest\n\tpayload?: Payload\n\tformId?: number | string\n\t/** Override the per-rule timeout in ms. Defaults to RULE_TIMEOUT_MS; primarily for tests. */\n\ttimeoutMs?: number\n}\n\nexport type RunValidationResult = { errors: ValidationIssue[] }\n\nconst isEmpty = (value: unknown): boolean =>\n\tvalue == null || value === '' || (Array.isArray(value) && value.length === 0)\n\ntype RuleInstance = { blockType: string; message?: string; severity?: ValidationSeverity } & Record<\n\tstring,\n\tunknown\n>\n\n/** Build the per-instance message resolver: custom override (a literal template) or the localized default. */\nconst makeMessage = (\n\tinstance: RuleInstance,\n\tdefaultMessageKey: string,\n\tt: Translate\n): MessageFn => {\n\tconst { blockType: _blockType, message: _message, severity: _severity, ...params } = instance\n\tconst template =\n\t\ttypeof instance.message === 'string' && instance.message.length > 0\n\t\t\t? instance.message\n\t\t\t: t(defaultMessageKey)\n\treturn (vars = {}) => resolveMessage(template, { ...params, ...vars })\n}\n\nconst toIssue = (\n\tresult: ValidationRuleResult,\n\tfallbackSeverity: ValidationSeverity\n): ValidationIssue | null => {\n\tif (result === true) {\n\t\treturn null\n\t}\n\tif (typeof result === 'string') {\n\t\treturn { message: result, severity: fallbackSeverity }\n\t}\n\treturn { message: result.message, severity: result.severity ?? fallbackSeverity }\n}\n\n/**\n * The one validation engine, run per field on client and server. Order: required, the field type's\n * intrinsic validator, then each declarative rule instance. Server-only rules are skipped in client\n * mode; every rule is wrapped in try/catch + a timeout so a bad rule cannot crash or stall the submit\n * path (a thrown or timed-out rule fails open, logged on the server). Only `error`-severity issues\n * block submission; the caller filters severity.\n */\nexport const runValidation = async (input: RunValidationInput): Promise<RunValidationResult> => {\n\tconst {\n\t\tfield,\n\t\tfieldDefinition,\n\t\tvalue,\n\t\tfieldType,\n\t\truleRegistry,\n\t\tanswers,\n\t\tlocale,\n\t\tt,\n\t\toperation,\n\t\tevent,\n\t\tmode,\n\t\treq,\n\t\tpayload,\n\t\tformId,\n\t\ttimeoutMs,\n\t} = input\n\tconst timeout = timeoutMs ?? RULE_TIMEOUT_MS\n\tconst errors: ValidationIssue[] = []\n\n\tif (field.required && isEmpty(value)) {\n\t\treturn { errors: [{ message: t(keys.validationRequired), severity: 'error' }] }\n\t}\n\t// Repeaters coerced to [] must reach fieldDefinition.validate so minRows is enforced;\n\t// all other empty fields have no intrinsic rules to run.\n\tif (isEmpty(value) && field.blockType !== 'repeater') {\n\t\treturn { errors: [] }\n\t}\n\n\tif (fieldDefinition?.validate) {\n\t\ttry {\n\t\t\tconst ran = fieldDefinition.validate({\n\t\t\t\tvalue,\n\t\t\t\tconfig: field,\n\t\t\t\tsiblingData: answers,\n\t\t\t\tdata: answers,\n\t\t\t\tlocale,\n\t\t\t\tt,\n\t\t\t})\n\t\t\tconst result = ran instanceof Promise ? await withTimeout(ran, timeout, true) : ran\n\t\t\tif (result !== true) {\n\t\t\t\terrors.push({ message: result, severity: 'error' })\n\t\t\t}\n\t\t} catch (error) {\n\t\t\treq?.payload?.logger?.error?.(\n\t\t\t\t{ err: error, field: field.name },\n\t\t\t\t'form-builder intrinsic field validator threw'\n\t\t\t)\n\t\t}\n\t}\n\n\tif (fieldDefinition?.schema) {\n\t\ttry {\n\t\t\tconst outcome = await fieldDefinition.schema['~standard'].validate(value)\n\t\t\tif (outcome.issues) {\n\t\t\t\tfor (const issue of outcome.issues) {\n\t\t\t\t\terrors.push({ message: issue.message, severity: 'error' })\n\t\t\t\t}\n\t\t\t}\n\t\t} catch (error) {\n\t\t\treq?.payload?.logger?.error?.(\n\t\t\t\t{ err: error, field: field.name },\n\t\t\t\t'form-builder field schema threw'\n\t\t\t)\n\t\t}\n\t}\n\n\tconst instances = (Array.isArray(field.validations) ? field.validations : []) as RuleInstance[]\n\tfor (const instance of instances) {\n\t\tconst rule = ruleRegistry.get(instance.blockType)\n\t\tif (!rule) {\n\t\t\tcontinue\n\t\t}\n\t\tif (mode === 'client' && rule.client === false) {\n\t\t\tcontinue\n\t\t}\n\t\tconst message = makeMessage(instance, rule.defaultMessage, t)\n\t\tconst fallbackSeverity: ValidationSeverity = instance.severity ?? rule.severity ?? 'error'\n\t\ttry {\n\t\t\tconst ran = rule.validate({\n\t\t\t\tvalue,\n\t\t\t\tparams: instance,\n\t\t\t\tsiblingData: answers,\n\t\t\t\tdata: answers,\n\t\t\t\tfield,\n\t\t\t\tfieldType,\n\t\t\t\toperation,\n\t\t\t\tevent,\n\t\t\t\tlocale,\n\t\t\t\tmessage,\n\t\t\t\treq: mode === 'server' ? req : undefined,\n\t\t\t\tpayload: mode === 'server' ? payload : undefined,\n\t\t\t\tformId: mode === 'server' ? formId : undefined,\n\t\t\t})\n\t\t\tconst result = ran instanceof Promise ? await withTimeout(ran, timeout, true) : ran\n\t\t\tconst issue = toIssue(result, fallbackSeverity)\n\t\t\tif (issue) {\n\t\t\t\terrors.push(issue)\n\t\t\t}\n\t\t} catch (error) {\n\t\t\treq?.payload?.logger?.error?.(\n\t\t\t\t{ err: error, rule: rule.type },\n\t\t\t\t'form-builder validation rule threw'\n\t\t\t)\n\t\t}\n\t}\n\n\treturn { errors }\n}\n"],"mappings":";;;AAQA,MAAM,kBAAkB;AAyBxB,MAAM,WAAW,UAChB,SAAS,QAAQ,UAAU,MAAO,MAAM,QAAQ,KAAK,KAAK,MAAM,WAAW;;AAQ5E,MAAM,eACL,UACA,mBACA,MACe;CACf,MAAM,EAAE,WAAW,YAAY,SAAS,UAAU,UAAU,WAAW,GAAG,WAAW;CACrF,MAAM,WACL,OAAO,SAAS,YAAY,YAAY,SAAS,QAAQ,SAAS,IAC/D,SAAS,UACT,EAAE,iBAAiB;CACvB,QAAQ,OAAO,CAAC,MAAM,eAAe,UAAU;EAAE,GAAG;EAAQ,GAAG;CAAK,CAAC;AACtE;AAEA,MAAM,WACL,QACA,qBAC4B;CAC5B,IAAI,WAAW,MACd,OAAO;CAER,IAAI,OAAO,WAAW,UACrB,OAAO;EAAE,SAAS;EAAQ,UAAU;CAAiB;CAEtD,OAAO;EAAE,SAAS,OAAO;EAAS,UAAU,OAAO,YAAY;CAAiB;AACjF;;;;;;;;AASA,MAAa,gBAAgB,OAAO,UAA4D;CAC/F,MAAM,EACL,OACA,iBACA,OACA,WACA,cACA,SACA,QACA,GACA,WACA,OACA,MACA,KACA,SACA,QACA,cACG;CACJ,MAAM,UAAU,aAAa;CAC7B,MAAM,SAA4B,CAAC;CAEnC,IAAI,MAAM,YAAY,QAAQ,KAAK,GAClC,OAAO,EAAE,QAAQ,CAAC;EAAE,SAAS,EAAE,KAAK,kBAAkB;EAAG,UAAU;CAAQ,CAAC,EAAE;CAI/E,IAAI,QAAQ,KAAK,KAAK,MAAM,cAAc,YACzC,OAAO,EAAE,QAAQ,CAAC,EAAE;CAGrB,IAAI,iBAAiB,UACpB,IAAI;EACH,MAAM,MAAM,gBAAgB,SAAS;GACpC;GACA,QAAQ;GACR,aAAa;GACb,MAAM;GACN;GACA;EACD,CAAC;EACD,MAAM,SAAS,eAAe,UAAU,MAAM,YAAY,KAAK,SAAS,IAAI,IAAI;EAChF,IAAI,WAAW,MACd,OAAO,KAAK;GAAE,SAAS;GAAQ,UAAU;EAAQ,CAAC;CAEpD,SAAS,OAAO;EACf,KAAK,SAAS,QAAQ,QACrB;GAAE,KAAK;GAAO,OAAO,MAAM;EAAK,GAChC,8CACD;CACD;CAGD,IAAI,iBAAiB,QACpB,IAAI;EACH,MAAM,UAAU,MAAM,gBAAgB,OAAO,aAAa,SAAS,KAAK;EACxE,IAAI,QAAQ,QACX,KAAK,MAAM,SAAS,QAAQ,QAC3B,OAAO,KAAK;GAAE,SAAS,MAAM;GAAS,UAAU;EAAQ,CAAC;CAG5D,SAAS,OAAO;EACf,KAAK,SAAS,QAAQ,QACrB;GAAE,KAAK;GAAO,OAAO,MAAM;EAAK,GAChC,iCACD;CACD;CAGD,MAAM,YAAa,MAAM,QAAQ,MAAM,WAAW,IAAI,MAAM,cAAc,CAAC;CAC3E,KAAK,MAAM,YAAY,WAAW;EACjC,MAAM,OAAO,aAAa,IAAI,SAAS,SAAS;EAChD,IAAI,CAAC,MACJ;EAED,IAAI,SAAS,YAAY,KAAK,WAAW,OACxC;EAED,MAAM,UAAU,YAAY,UAAU,KAAK,gBAAgB,CAAC;EAC5D,MAAM,mBAAuC,SAAS,YAAY,KAAK,YAAY;EACnF,IAAI;GACH,MAAM,MAAM,KAAK,SAAS;IACzB;IACA,QAAQ;IACR,aAAa;IACb,MAAM;IACN;IACA;IACA;IACA;IACA;IACA;IACA,KAAK,SAAS,WAAW,MAAM,KAAA;IAC/B,SAAS,SAAS,WAAW,UAAU,KAAA;IACvC,QAAQ,SAAS,WAAW,SAAS,KAAA;GACtC,CAAC;GAED,MAAM,QAAQ,QADC,eAAe,UAAU,MAAM,YAAY,KAAK,SAAS,IAAI,IAAI,KAClD,gBAAgB;GAC9C,IAAI,OACH,OAAO,KAAK,KAAK;EAEnB,SAAS,OAAO;GACf,KAAK,SAAS,QAAQ,QACrB;IAAE,KAAK;IAAO,MAAM,KAAK;GAAK,GAC9B,oCACD;EACD;CACD;CAEA,OAAO,EAAE,OAAO;AACjB"}
|