@10x-media/form-builder 0.1.0-beta.2 → 0.1.0-beta.20
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 +354 -0
- package/README.md +7 -5
- package/dist/actions/assertNoBlockCollision.js +18 -0
- package/dist/actions/assertNoBlockCollision.js.map +1 -0
- package/dist/actions/body/converters.d.ts +20 -0
- package/dist/actions/body/converters.js +57 -0
- package/dist/actions/body/converters.js.map +1 -0
- package/dist/actions/body/escapeHtml.d.ts +6 -0
- package/dist/actions/body/escapeHtml.js +14 -0
- package/dist/actions/body/escapeHtml.js.map +1 -0
- package/dist/actions/body/serializeBody.d.ts +55 -0
- package/dist/actions/body/serializeBody.js +78 -0
- package/dist/actions/body/serializeBody.js.map +1 -0
- package/dist/actions/body/serializeSlate.js +31 -0
- package/dist/actions/body/serializeSlate.js.map +1 -0
- package/dist/actions/body/textOfBody.d.ts +13 -0
- package/dist/actions/body/textOfBody.js +35 -0
- package/dist/actions/body/textOfBody.js.map +1 -0
- package/dist/actions/body/wildcards.d.ts +10 -0
- package/dist/actions/body/wildcards.js +33 -0
- package/dist/actions/body/wildcards.js.map +1 -0
- package/dist/actions/buildActionBlocks.js +12 -9
- package/dist/actions/buildActionBlocks.js.map +1 -1
- package/dist/actions/builtin/confirmation.js +47 -43
- package/dist/actions/builtin/confirmation.js.map +1 -1
- package/dist/actions/builtin/emailAction.d.ts +20 -0
- package/dist/actions/builtin/emailAction.js +120 -0
- package/dist/actions/builtin/emailAction.js.map +1 -0
- package/dist/actions/builtin/emailTeam.js +20 -38
- package/dist/actions/builtin/emailTeam.js.map +1 -1
- package/dist/actions/builtin/index.d.ts +16 -1
- package/dist/actions/builtin/index.js +21 -7
- package/dist/actions/builtin/index.js.map +1 -1
- package/dist/actions/builtin/signedWebhook.js +6 -2
- package/dist/actions/builtin/signedWebhook.js.map +1 -1
- package/dist/actions/defineAction.d.ts +8 -5
- package/dist/actions/defineAction.js.map +1 -1
- package/dist/actions/dispatch.js +3 -2
- package/dist/actions/dispatch.js.map +1 -1
- package/dist/actions/emailRecipients.d.ts +12 -0
- package/dist/actions/emailRecipients.js +146 -0
- package/dist/actions/emailRecipients.js.map +1 -0
- package/dist/actions/fromAddresses.d.ts +37 -0
- package/dist/actions/fromAddresses.js +131 -0
- package/dist/actions/fromAddresses.js.map +1 -0
- package/dist/actions/recipientSources.d.ts +34 -0
- package/dist/actions/recipientSources.js +11 -0
- package/dist/actions/recipientSources.js.map +1 -0
- package/dist/actions/registry.d.ts +2 -1
- package/dist/actions/registry.js +2 -6
- package/dist/actions/registry.js.map +1 -1
- package/dist/actions/runActions.js +10 -1
- package/dist/actions/runActions.js.map +1 -1
- package/dist/actions/task.js +40 -15
- package/dist/actions/task.js.map +1 -1
- package/dist/aggregation/aggregateResponses.d.ts +9 -0
- package/dist/aggregation/aggregateResponses.js +8 -14
- package/dist/aggregation/aggregateResponses.js.map +1 -1
- package/dist/aggregation/resolveResultsRequest.d.ts +41 -6
- package/dist/aggregation/resolveResultsRequest.js +97 -11
- package/dist/aggregation/resolveResultsRequest.js.map +1 -1
- package/dist/calc/computeCalcFields.d.ts +5 -3
- package/dist/calc/computeCalcFields.js +6 -4
- package/dist/calc/computeCalcFields.js.map +1 -1
- package/dist/calc/evaluate.d.ts +26 -3
- package/dist/calc/evaluate.js +34 -13
- package/dist/calc/evaluate.js.map +1 -1
- package/dist/calc/formatCalc.d.ts +11 -0
- package/dist/calc/formatCalc.js +35 -0
- package/dist/calc/formatCalc.js.map +1 -0
- package/dist/calc/formatCalcValue.d.ts +17 -0
- package/dist/calc/formatCalcValue.js +17 -0
- package/dist/calc/formatCalcValue.js.map +1 -0
- package/dist/calc/normalizeCalc.d.ts +17 -3
- package/dist/calc/normalizeCalc.js +42 -33
- package/dist/calc/normalizeCalc.js.map +1 -1
- package/dist/calc/registry.d.ts +43 -0
- package/dist/calc/registry.js +27 -0
- package/dist/calc/registry.js.map +1 -0
- package/dist/calc/resolveCalcContext.d.ts +36 -0
- package/dist/calc/resolveCalcContext.js +87 -0
- package/dist/calc/resolveCalcContext.js.map +1 -0
- package/dist/calc/types.d.ts +25 -4
- package/dist/calc/types.js +23 -0
- package/dist/calc/types.js.map +1 -0
- package/dist/client/ByteSizeField.d.ts +29 -0
- package/dist/client/ByteSizeField.js +58 -0
- package/dist/client/ByteSizeField.js.map +1 -0
- package/dist/client/CalcExpressionBuilder.d.ts +20 -0
- package/dist/client/CalcExpressionBuilder.js +890 -0
- package/dist/client/CalcExpressionBuilder.js.map +1 -0
- package/dist/client/ClosePollButton.d.ts +15 -0
- package/dist/client/ClosePollButton.js +80 -0
- package/dist/client/ClosePollButton.js.map +1 -0
- package/dist/client/CondensedArray.d.ts +15 -0
- package/dist/client/CondensedArray.js +97 -0
- package/dist/client/CondensedArray.js.map +1 -0
- package/dist/client/ConditionBuilder.js +2 -1
- package/dist/client/ConditionBuilder.js.map +1 -1
- package/dist/client/ConsentBlockLabel.d.ts +15 -0
- package/dist/client/ConsentBlockLabel.js +71 -0
- package/dist/client/ConsentBlockLabel.js.map +1 -0
- package/dist/client/ConsentSourceRowLabel.d.ts +9 -0
- package/dist/client/ConsentSourceRowLabel.js +21 -0
- package/dist/client/ConsentSourceRowLabel.js.map +1 -0
- package/dist/client/EndpointOptionsSelect.d.ts +55 -0
- package/dist/client/EndpointOptionsSelect.js +112 -0
- package/dist/client/EndpointOptionsSelect.js.map +1 -0
- package/dist/client/FieldBlockLabel.d.ts +18 -0
- package/dist/client/FieldBlockLabel.js +34 -0
- package/dist/client/FieldBlockLabel.js.map +1 -0
- package/dist/client/FieldNameSelect.d.ts +37 -0
- package/dist/client/FieldNameSelect.js +72 -0
- package/dist/client/FieldNameSelect.js.map +1 -0
- package/dist/client/FlowBuilder.d.ts +2 -2
- package/dist/client/FlowBuilder.js +137 -88
- package/dist/client/FlowBuilder.js.map +1 -1
- package/dist/client/FormConditionField.js +1 -4
- package/dist/client/FormConditionField.js.map +1 -1
- package/dist/client/RecipientsSelect.d.ts +37 -0
- package/dist/client/RecipientsSelect.js +197 -0
- package/dist/client/RecipientsSelect.js.map +1 -0
- package/dist/client/RuleDescription.d.ts +21 -0
- package/dist/client/RuleDescription.js +19 -0
- package/dist/client/RuleDescription.js.map +1 -0
- package/dist/client/admin.css +557 -0
- package/dist/client/endpointOptions.d.ts +11 -0
- package/dist/client/endpointOptions.js +38 -0
- package/dist/client/endpointOptions.js.map +1 -0
- package/dist/client/flowAuthoring.js +142 -0
- package/dist/client/flowAuthoring.js.map +1 -0
- package/dist/client/synthesizeClientField.js +21 -10
- package/dist/client/synthesizeClientField.js.map +1 -1
- package/dist/client/toStaticLabel.js +13 -0
- package/dist/client/toStaticLabel.js.map +1 -0
- package/dist/collections/buttonFields.d.ts +34 -0
- package/dist/collections/buttonFields.js +35 -0
- package/dist/collections/buttonFields.js.map +1 -0
- package/dist/collections/cells/FieldCountCell.d.ts +15 -0
- package/dist/collections/cells/FieldCountCell.js +18 -0
- package/dist/collections/cells/FieldCountCell.js.map +1 -0
- package/dist/collections/cells/FlowStepsCell.d.ts +14 -0
- package/dist/collections/cells/FlowStepsCell.js +17 -0
- package/dist/collections/cells/FlowStepsCell.js.map +1 -0
- package/dist/collections/formSubmissions.js +112 -27
- package/dist/collections/formSubmissions.js.map +1 -1
- package/dist/collections/forms.js +449 -112
- package/dist/collections/forms.js.map +1 -1
- package/dist/collections/formsEndpoints.js +106 -0
- package/dist/collections/formsEndpoints.js.map +1 -0
- package/dist/collections/redirectFields.d.ts +29 -0
- package/dist/collections/settingsFields.d.ts +31 -0
- package/dist/collections/settingsFields.js +45 -0
- package/dist/collections/settingsFields.js.map +1 -0
- package/dist/conditions/conditionType.js +9 -2
- package/dist/conditions/conditionType.js.map +1 -1
- package/dist/conditions/evaluate.js +1 -1
- package/dist/conditions/evaluate.js.map +1 -1
- package/dist/conditions/fieldTypes.d.ts +3 -1
- package/dist/conditions/fieldTypes.js +4 -1
- package/dist/conditions/fieldTypes.js.map +1 -1
- package/dist/conditions/normalizeConditions.js +20 -6
- package/dist/conditions/normalizeConditions.js.map +1 -1
- package/dist/consent/applyConsentStatements.d.ts +14 -0
- package/dist/consent/applyConsentStatements.js +17 -0
- package/dist/consent/applyConsentStatements.js.map +1 -0
- package/dist/consent/captureConsent.d.ts +39 -11
- package/dist/consent/captureConsent.js +63 -13
- package/dist/consent/captureConsent.js.map +1 -1
- package/dist/consent/consentSourcesField.d.ts +66 -0
- package/dist/consent/consentSourcesField.js +98 -0
- package/dist/consent/consentSourcesField.js.map +1 -0
- package/dist/consent/effectiveStatement.js +16 -0
- package/dist/consent/effectiveStatement.js.map +1 -0
- package/dist/consent/resolveConsentEntries.d.ts +24 -0
- package/dist/consent/resolveConsentEntries.js +40 -0
- package/dist/consent/resolveConsentEntries.js.map +1 -0
- package/dist/consent/resolveConsentSourcesRequest.d.ts +37 -0
- package/dist/consent/resolveConsentSourcesRequest.js +54 -0
- package/dist/consent/resolveConsentSourcesRequest.js.map +1 -0
- package/dist/consent/resolveConsentStatements.d.ts +45 -0
- package/dist/consent/resolveConsentStatements.js +46 -0
- package/dist/consent/resolveConsentStatements.js.map +1 -0
- package/dist/consent/resolvePublishedVersionRef.d.ts +17 -11
- package/dist/consent/resolvePublishedVersionRef.js +13 -10
- package/dist/consent/resolvePublishedVersionRef.js.map +1 -1
- package/dist/consent/types.d.ts +69 -0
- package/dist/context/formContext.d.ts +30 -0
- package/dist/context/formContext.js +54 -0
- package/dist/context/formContext.js.map +1 -0
- package/dist/email/departments.d.ts +59 -0
- package/dist/email/departments.js +87 -0
- package/dist/email/departments.js.map +1 -0
- package/dist/email/departmentsField.d.ts +53 -0
- package/dist/email/departmentsField.js +73 -0
- package/dist/email/departmentsField.js.map +1 -0
- package/dist/exports/client.d.ts +14 -1
- package/dist/exports/client.js +14 -1
- package/dist/exports/i18n.d.ts +5 -2
- package/dist/exports/i18n.js +5 -2
- package/dist/exports/react.d.ts +34 -10
- package/dist/exports/react.js +24 -4
- package/dist/exports/rsc.d.ts +10 -1
- package/dist/exports/rsc.js +10 -1
- package/dist/exports/types.d.ts +20 -12
- package/dist/fields/buildFieldBlocks.js +46 -25
- package/dist/fields/buildFieldBlocks.js.map +1 -1
- package/dist/fields/builtin/calculation.d.ts +17 -0
- package/dist/fields/builtin/calculation.js +193 -18
- package/dist/fields/builtin/calculation.js.map +1 -1
- package/dist/fields/builtin/checkbox.js +23 -0
- package/dist/fields/builtin/checkbox.js.map +1 -1
- package/dist/fields/builtin/consent.js +49 -14
- package/dist/fields/builtin/consent.js.map +1 -1
- package/dist/fields/builtin/country.d.ts +13 -0
- package/dist/fields/builtin/country.js +30 -0
- package/dist/fields/builtin/country.js.map +1 -0
- package/dist/fields/builtin/date.js +31 -0
- package/dist/fields/builtin/date.js.map +1 -0
- package/dist/fields/builtin/email.js +8 -1
- package/dist/fields/builtin/email.js.map +1 -1
- package/dist/fields/builtin/file.d.ts +15 -0
- package/dist/fields/builtin/file.js +95 -8
- package/dist/fields/builtin/file.js.map +1 -1
- package/dist/fields/builtin/index.d.ts +30 -0
- package/dist/fields/builtin/index.js +37 -10
- package/dist/fields/builtin/index.js.map +1 -1
- package/dist/fields/builtin/message.js +30 -0
- package/dist/fields/builtin/message.js.map +1 -0
- package/dist/fields/builtin/repeater.js +8 -3
- package/dist/fields/builtin/repeater.js.map +1 -1
- package/dist/fields/builtin/select.js +28 -4
- package/dist/fields/builtin/select.js.map +1 -1
- package/dist/fields/builtin/state.d.ts +13 -0
- package/dist/fields/builtin/state.js +30 -0
- package/dist/fields/builtin/state.js.map +1 -0
- package/dist/fields/builtin/text.js +7 -0
- package/dist/fields/builtin/text.js.map +1 -1
- package/dist/fields/data/regions.d.ts +21 -0
- package/dist/fields/data/regions.js +1238 -0
- package/dist/fields/data/regions.js.map +1 -0
- package/dist/fields/fieldKey.d.ts +15 -0
- package/dist/fields/fieldKey.js +16 -0
- package/dist/fields/fieldKey.js.map +1 -0
- package/dist/fields/fieldNamesOfType.js +30 -0
- package/dist/fields/fieldNamesOfType.js.map +1 -0
- package/dist/fields/instanceOptions.js +20 -0
- package/dist/fields/instanceOptions.js.map +1 -0
- package/dist/fields/localizedIf.d.ts +13 -0
- package/dist/fields/localizedIf.js +12 -0
- package/dist/fields/localizedIf.js.map +1 -0
- package/dist/fields/registry.d.ts +3 -1
- package/dist/fields/registry.js +23 -8
- package/dist/fields/registry.js.map +1 -1
- package/dist/fields/sharedConfig.js +125 -59
- package/dist/fields/sharedConfig.js.map +1 -1
- package/dist/fields/types.d.ts +78 -9
- package/dist/flow/engine.d.ts +6 -4
- package/dist/flow/engine.js +11 -6
- package/dist/flow/engine.js.map +1 -1
- package/dist/flow/normalizeFlow.js +28 -9
- package/dist/flow/normalizeFlow.js.map +1 -1
- package/dist/flow/stepLabel.js +15 -0
- package/dist/flow/stepLabel.js.map +1 -0
- package/dist/flow/types.d.ts +12 -3
- package/dist/flow/types.js +11 -0
- package/dist/flow/types.js.map +1 -0
- package/dist/form/pollState.d.ts +23 -0
- package/dist/form/pollState.js +17 -0
- package/dist/form/pollState.js.map +1 -0
- package/dist/form/toFormDocument.d.ts +110 -0
- package/dist/form/toFormDocument.js +89 -0
- package/dist/form/toFormDocument.js.map +1 -0
- package/dist/form/types.d.ts +73 -0
- package/dist/index.d.ts +67 -61
- package/dist/index.js +120 -25
- package/dist/index.js.map +1 -1
- package/dist/options.d.ts +281 -0
- package/dist/plugin/applyRegistryConfig.d.ts +11 -0
- package/dist/plugin/applyRegistryConfig.js +20 -0
- package/dist/plugin/applyRegistryConfig.js.map +1 -0
- package/dist/plugin/customState.js +26 -0
- package/dist/plugin/customState.js.map +1 -0
- package/dist/plugin/registerCollections.js +43 -40
- package/dist/plugin/registerCollections.js.map +1 -1
- package/dist/plugin/uploadsCollection.d.ts +16 -0
- package/dist/plugin/uploadsCollection.js +53 -0
- package/dist/plugin/uploadsCollection.js.map +1 -0
- package/dist/poll/applyPollOptions.js +18 -0
- package/dist/poll/applyPollOptions.js.map +1 -0
- package/dist/poll/buildPollOptionSourceFields.js +50 -0
- package/dist/poll/buildPollOptionSourceFields.js.map +1 -0
- package/dist/poll/closeJob.d.ts +53 -0
- package/dist/poll/closeJob.js +121 -0
- package/dist/poll/closeJob.js.map +1 -0
- package/dist/poll/definePollOptionSource.d.ts +44 -0
- package/dist/poll/definePollOptionSource.js +6 -0
- package/dist/poll/definePollOptionSource.js.map +1 -0
- package/dist/poll/definePollType.d.ts +34 -0
- package/dist/poll/definePollType.js +6 -0
- package/dist/poll/definePollType.js.map +1 -0
- package/dist/poll/effectivePollOptions.d.ts +38 -0
- package/dist/poll/effectivePollOptions.js +64 -0
- package/dist/poll/effectivePollOptions.js.map +1 -0
- package/dist/poll/mostVoted.d.ts +21 -0
- package/dist/poll/mostVoted.js +32 -0
- package/dist/poll/mostVoted.js.map +1 -0
- package/dist/poll/outcomeBeforeChange.js +91 -0
- package/dist/poll/outcomeBeforeChange.js.map +1 -0
- package/dist/poll/outcomeFields.d.ts +38 -0
- package/dist/poll/outcomeFields.js +52 -0
- package/dist/poll/outcomeFields.js.map +1 -0
- package/dist/poll/pollTypeRegistry.d.ts +34 -0
- package/dist/poll/pollTypeRegistry.js +69 -0
- package/dist/poll/pollTypeRegistry.js.map +1 -0
- package/dist/poll/registry.d.ts +17 -0
- package/dist/poll/registry.js +12 -0
- package/dist/poll/registry.js.map +1 -0
- package/dist/poll/resolvePollCloseRequest.js +106 -0
- package/dist/poll/resolvePollCloseRequest.js.map +1 -0
- package/dist/poll/resolvePollOptions.d.ts +29 -0
- package/dist/poll/resolvePollOptions.js +52 -0
- package/dist/poll/resolvePollOptions.js.map +1 -0
- package/dist/poll/resolvePollOptionsRequest.js +50 -0
- package/dist/poll/resolvePollOptionsRequest.js.map +1 -0
- package/dist/poll/resolvePollOutcome.d.ts +40 -0
- package/dist/poll/resolvePollOutcome.js +90 -0
- package/dist/poll/resolvePollOutcome.js.map +1 -0
- package/dist/poll/resultsField.js +21 -0
- package/dist/poll/resultsField.js.map +1 -0
- package/dist/poll/votes/aggregateFromVotes.d.ts +27 -0
- package/dist/poll/votes/aggregateFromVotes.js +54 -0
- package/dist/poll/votes/aggregateFromVotes.js.map +1 -0
- package/dist/poll/votes/answerValues.js +16 -0
- package/dist/poll/votes/answerValues.js.map +1 -0
- package/dist/poll/votes/bumpPollVote.js +88 -0
- package/dist/poll/votes/bumpPollVote.js.map +1 -0
- package/dist/poll/votes/recountPollVotes.d.ts +20 -0
- package/dist/poll/votes/recountPollVotes.js +63 -0
- package/dist/poll/votes/recountPollVotes.js.map +1 -0
- package/dist/poll/votes/voteTallyHook.js +76 -0
- package/dist/poll/votes/voteTallyHook.js.map +1 -0
- package/dist/poll/votes/votesCollection.d.ts +19 -0
- package/dist/poll/votes/votesCollection.js +89 -0
- package/dist/poll/votes/votesCollection.js.map +1 -0
- package/dist/prefill/valuesFromSearchParams.js +5 -9
- package/dist/prefill/valuesFromSearchParams.js.map +1 -1
- package/dist/presentations/types.d.ts +3 -2
- package/dist/react/Form.d.ts +77 -35
- package/dist/react/Form.js +368 -222
- package/dist/react/Form.js.map +1 -1
- package/dist/react/FormContext.d.ts +51 -1
- package/dist/react/FormContext.js.map +1 -1
- package/dist/react/FormControls.d.ts +55 -0
- package/dist/react/FormControls.js +56 -0
- package/dist/react/FormControls.js.map +1 -0
- package/dist/react/FormFields.d.ts +18 -0
- package/dist/react/FormFields.js +114 -0
- package/dist/react/FormFields.js.map +1 -0
- package/dist/react/FormLayout.d.ts +4 -2
- package/dist/react/FormLayout.js +3 -2
- package/dist/react/FormLayout.js.map +1 -1
- package/dist/react/FormResults.d.ts +8 -3
- package/dist/react/FormResults.js +50 -29
- package/dist/react/FormResults.js.map +1 -1
- package/dist/react/FormSteps.d.ts +17 -0
- package/dist/react/FormSteps.js +35 -0
- package/dist/react/FormSteps.js.map +1 -0
- package/dist/react/Poll.d.ts +40 -6
- package/dist/react/Poll.js +137 -33
- package/dist/react/Poll.js.map +1 -1
- package/dist/react/adapters.d.ts +35 -0
- package/dist/react/adapters.js +11 -0
- package/dist/react/adapters.js.map +1 -0
- package/dist/react/captcha/HcaptchaCaptcha.d.ts +31 -0
- package/dist/react/captcha/HcaptchaCaptcha.js +53 -0
- package/dist/react/captcha/HcaptchaCaptcha.js.map +1 -0
- package/dist/react/captcha/RecaptchaCaptcha.d.ts +44 -0
- package/dist/react/captcha/RecaptchaCaptcha.js +93 -0
- package/dist/react/captcha/RecaptchaCaptcha.js.map +1 -0
- package/dist/react/captcha/TurnstileCaptcha.d.ts +31 -0
- package/dist/react/captcha/TurnstileCaptcha.js +53 -0
- package/dist/react/captcha/TurnstileCaptcha.js.map +1 -0
- package/dist/react/captcha/types.d.ts +8 -0
- package/dist/react/captcha/useCaptchaScript.js +63 -0
- package/dist/react/captcha/useCaptchaScript.js.map +1 -0
- package/dist/react/captcha/vendors.js +8 -0
- package/dist/react/captcha/vendors.js.map +1 -0
- package/dist/react/contract.d.ts +2 -3
- package/dist/react/contract.js.map +1 -1
- package/dist/react/fetchResults.d.ts +1 -1
- package/dist/react/fetchResults.js +1 -1
- package/dist/react/fetchResults.js.map +1 -1
- package/dist/react/presentation/DialogSurface.js +1 -4
- package/dist/react/presentation/DialogSurface.js.map +1 -1
- package/dist/react/primitives/Checkbox.d.ts +6 -2
- package/dist/react/primitives/Checkbox.js +4 -2
- package/dist/react/primitives/Checkbox.js.map +1 -1
- package/dist/react/primitives/ChoiceGroup.d.ts +40 -0
- package/dist/react/primitives/ChoiceGroup.js +33 -0
- package/dist/react/primitives/ChoiceGroup.js.map +1 -0
- package/dist/react/primitives/FieldShell.d.ts +13 -5
- package/dist/react/primitives/FieldShell.js +35 -32
- package/dist/react/primitives/FieldShell.js.map +1 -1
- package/dist/react/primitives/Input.d.ts +4 -2
- package/dist/react/primitives/Input.js +2 -1
- package/dist/react/primitives/Input.js.map +1 -1
- package/dist/react/renderers/calculation.js +7 -5
- package/dist/react/renderers/calculation.js.map +1 -1
- package/dist/react/renderers/checkbox.js +3 -5
- package/dist/react/renderers/checkbox.js.map +1 -1
- package/dist/react/renderers/consent.js +84 -36
- package/dist/react/renderers/consent.js.map +1 -1
- package/dist/react/renderers/date.js +33 -0
- package/dist/react/renderers/date.js.map +1 -0
- package/dist/react/renderers/email.js +4 -5
- package/dist/react/renderers/email.js.map +1 -1
- package/dist/react/renderers/file.js +29 -14
- package/dist/react/renderers/file.js.map +1 -1
- package/dist/react/renderers/index.js +7 -0
- package/dist/react/renderers/index.js.map +1 -1
- package/dist/react/renderers/message.js +41 -0
- package/dist/react/renderers/message.js.map +1 -0
- package/dist/react/renderers/number.js +1 -4
- package/dist/react/renderers/number.js.map +1 -1
- package/dist/react/renderers/region.js +43 -0
- package/dist/react/renderers/region.js.map +1 -0
- package/dist/react/renderers/repeater.js +32 -14
- package/dist/react/renderers/repeater.js.map +1 -1
- package/dist/react/renderers/select.js +21 -6
- package/dist/react/renderers/select.js.map +1 -1
- package/dist/react/renderers/text.js +4 -5
- package/dist/react/renderers/text.js.map +1 -1
- package/dist/react/renderers/textarea.js +1 -4
- package/dist/react/renderers/textarea.js.map +1 -1
- package/dist/react/state.d.ts +40 -3
- package/dist/react/state.js +66 -9
- package/dist/react/state.js.map +1 -1
- package/dist/react/uploadFile.d.ts +2 -2
- package/dist/react/uploadFile.js +1 -1
- package/dist/react/uploadFile.js.map +1 -1
- package/dist/react/useCalcValues.d.ts +10 -0
- package/dist/react/useCalcValues.js +13 -0
- package/dist/react/useCalcValues.js.map +1 -0
- package/dist/react/useField.d.ts +0 -1
- package/dist/react/useField.js +6 -6
- package/dist/react/useField.js.map +1 -1
- package/dist/react/useFormState.d.ts +1 -1
- package/dist/react/useFormState.js +1 -1
- package/dist/react/useFormState.js.map +1 -1
- package/dist/react/validateField.js +3 -6
- package/dist/react/validateField.js.map +1 -1
- package/dist/recall/interpolate.d.ts +4 -3
- package/dist/recall/interpolate.js +5 -4
- package/dist/recall/interpolate.js.map +1 -1
- package/dist/recall/resolver.d.ts +1 -1
- package/dist/recall/resolver.js +15 -3
- package/dist/recall/resolver.js.map +1 -1
- package/dist/spam/captcha.d.ts +4 -3
- package/dist/spam/captcha.js +4 -3
- package/dist/spam/captcha.js.map +1 -1
- package/dist/spam/clientIp.js +9 -0
- package/dist/spam/clientIp.js.map +1 -0
- package/dist/spam/constants.js +13 -1
- package/dist/spam/constants.js.map +1 -1
- package/dist/spam/identify.js +3 -6
- package/dist/spam/identify.js.map +1 -1
- package/dist/spam/providers/hcaptcha.d.ts +17 -0
- package/dist/spam/providers/hcaptcha.js +18 -0
- package/dist/spam/providers/hcaptcha.js.map +1 -0
- package/dist/spam/providers/recaptcha.d.ts +23 -0
- package/dist/spam/providers/recaptcha.js +23 -0
- package/dist/spam/providers/recaptcha.js.map +1 -0
- package/dist/spam/providers/siteverify.js +34 -0
- package/dist/spam/providers/siteverify.js.map +1 -0
- package/dist/spam/providers/turnstile.d.ts +17 -0
- package/dist/spam/providers/turnstile.js +18 -0
- package/dist/spam/providers/turnstile.js.map +1 -0
- package/dist/spam/resolveSpam.js +2 -1
- package/dist/spam/resolveSpam.js.map +1 -1
- package/dist/spam/spamGuard.js +25 -11
- package/dist/spam/spamGuard.js.map +1 -1
- package/dist/spam/types.d.ts +19 -4
- package/dist/submissions/SubmissionAnswers.js +6 -2
- package/dist/submissions/SubmissionAnswers.js.map +1 -1
- package/dist/submissions/SubmissionAnswersClient.js +100 -64
- package/dist/submissions/SubmissionAnswersClient.js.map +1 -1
- package/dist/submissions/coerceBoolean.js +14 -0
- package/dist/submissions/coerceBoolean.js.map +1 -0
- package/dist/submissions/createSubmission.d.ts +36 -0
- package/dist/submissions/createSubmission.js +26 -0
- package/dist/submissions/createSubmission.js.map +1 -0
- package/dist/submissions/formIdOf.js +13 -0
- package/dist/submissions/formIdOf.js.map +1 -0
- package/dist/submissions/resolveVotedSubmission.d.ts +27 -0
- package/dist/submissions/resolveVotedSubmission.js +51 -0
- package/dist/submissions/resolveVotedSubmission.js.map +1 -0
- package/dist/submissions/runSubmission.d.ts +10 -0
- package/dist/submissions/runSubmission.js +104 -54
- package/dist/submissions/runSubmission.js.map +1 -1
- package/dist/submissions/types.d.ts +11 -4
- package/dist/submissions/validateSubmission.js +99 -13
- package/dist/submissions/validateSubmission.js.map +1 -1
- package/dist/submissions/verifyContext.js +35 -0
- package/dist/submissions/verifyContext.js.map +1 -0
- package/dist/submissions/voteChangeEndpoint.js +100 -0
- package/dist/submissions/voteChangeEndpoint.js.map +1 -0
- package/dist/submissions/votedCookie.d.ts +15 -0
- package/dist/submissions/votedCookie.js +74 -0
- package/dist/submissions/votedCookie.js.map +1 -0
- package/dist/translations/clientRuntimeKeys.d.ts +17 -0
- package/dist/translations/clientRuntimeKeys.js +48 -0
- package/dist/translations/clientRuntimeKeys.js.map +1 -0
- package/dist/translations/de.d.ts +12 -0
- package/dist/translations/de.js +379 -0
- package/dist/translations/de.js.map +1 -0
- package/dist/translations/en.js +249 -28
- package/dist/translations/en.js.map +1 -1
- package/dist/translations/index.d.ts +14 -5
- package/dist/translations/index.js +14 -3
- package/dist/translations/index.js.map +1 -1
- package/dist/translations/keys.d.ts +244 -23
- package/dist/translations/keys.js +245 -24
- package/dist/translations/keys.js.map +1 -1
- package/dist/translations/makeTranslate.d.ts +7 -3
- package/dist/translations/makeTranslate.js +12 -3
- package/dist/translations/makeTranslate.js.map +1 -1
- package/dist/translations/server.js +8 -1
- package/dist/translations/server.js.map +1 -1
- package/dist/uploads/captureFileRef.d.ts +10 -3
- package/dist/uploads/captureFileRef.js +18 -9
- package/dist/uploads/captureFileRef.js.map +1 -1
- package/dist/uploads/formatBytes.d.ts +9 -0
- package/dist/uploads/formatBytes.js +25 -0
- package/dist/uploads/formatBytes.js.map +1 -0
- package/dist/uploads/resolveFileRef.js +3 -2
- package/dist/uploads/resolveFileRef.js.map +1 -1
- package/dist/uploads/types.d.ts +1 -2
- package/dist/validation/buildRuleBlocks.js +18 -17
- package/dist/validation/buildRuleBlocks.js.map +1 -1
- package/dist/validation/builtin/email.js +2 -1
- package/dist/validation/builtin/email.js.map +1 -1
- package/dist/validation/builtin/index.d.ts +14 -0
- package/dist/validation/builtin/index.js +14 -1
- package/dist/validation/builtin/index.js.map +1 -1
- package/dist/validation/builtin/integer.js +15 -0
- package/dist/validation/builtin/integer.js.map +1 -0
- package/dist/validation/builtin/matchesField.js +3 -7
- package/dist/validation/builtin/matchesField.js.map +1 -1
- package/dist/validation/builtin/max.js +1 -0
- package/dist/validation/builtin/max.js.map +1 -1
- package/dist/validation/builtin/maxDate.js +24 -0
- package/dist/validation/builtin/maxDate.js.map +1 -0
- package/dist/validation/builtin/maxLength.js +1 -0
- package/dist/validation/builtin/maxLength.js.map +1 -1
- package/dist/validation/builtin/min.js +1 -0
- package/dist/validation/builtin/min.js.map +1 -1
- package/dist/validation/builtin/minDate.js +24 -0
- package/dist/validation/builtin/minDate.js.map +1 -0
- package/dist/validation/builtin/minLength.js +1 -0
- package/dist/validation/builtin/minLength.js.map +1 -1
- package/dist/validation/builtin/notAlreadySubmitted.js +5 -1
- package/dist/validation/builtin/notAlreadySubmitted.js.map +1 -1
- package/dist/validation/builtin/oneOf.js +1 -0
- package/dist/validation/builtin/oneOf.js.map +1 -1
- package/dist/validation/builtin/pattern.js +11 -2
- package/dist/validation/builtin/pattern.js.map +1 -1
- package/dist/validation/builtin/url.js +1 -0
- package/dist/validation/builtin/url.js.map +1 -1
- package/dist/validation/builtin/validateDateBound.js +18 -0
- package/dist/validation/builtin/validateDateBound.js.map +1 -0
- package/dist/validation/builtin/validateRegexParams.js +44 -0
- package/dist/validation/builtin/validateRegexParams.js.map +1 -0
- package/dist/validation/emailPattern.js +10 -0
- package/dist/validation/emailPattern.js.map +1 -0
- package/dist/validation/fieldTargetParam.d.ts +22 -0
- package/dist/validation/fieldTargetParam.js +38 -0
- package/dist/validation/fieldTargetParam.js.map +1 -0
- package/dist/validation/registry.d.ts +2 -1
- package/dist/validation/registry.js +2 -9
- package/dist/validation/registry.js.map +1 -1
- package/dist/validation/runValidation.js +8 -29
- package/dist/validation/runValidation.js.map +1 -1
- package/dist/validation/types.d.ts +5 -11
- package/dist/validation/validateUrl.js +22 -0
- package/dist/validation/validateUrl.js.map +1 -0
- package/package.json +14 -6
- package/styles/form-builder.css +94 -190
- package/dist/collections/uploads.d.ts +0 -30
- package/dist/collections/uploads.js +0 -55
- package/dist/collections/uploads.js.map +0 -1
- package/dist/consent/buildConsentSourceConfig.js +0 -49
- package/dist/consent/buildConsentSourceConfig.js.map +0 -1
- package/dist/consent/builtin/index.d.ts +0 -7
- package/dist/consent/builtin/index.js +0 -11
- package/dist/consent/builtin/index.js.map +0 -1
- package/dist/consent/builtin/pageReference.js +0 -75
- package/dist/consent/builtin/pageReference.js.map +0 -1
- package/dist/consent/builtin/static.js +0 -44
- package/dist/consent/builtin/static.js.map +0 -1
- package/dist/consent/defineConsentSource.d.ts +0 -35
- package/dist/consent/defineConsentSource.js +0 -6
- package/dist/consent/defineConsentSource.js.map +0 -1
- package/dist/consent/registry.d.ts +0 -16
- package/dist/consent/registry.js +0 -16
- package/dist/consent/registry.js.map +0 -1
- package/dist/consent/resolveConsentLinks.d.ts +0 -19
- package/dist/consent/resolveConsentLinks.js +0 -26
- package/dist/consent/resolveConsentLinks.js.map +0 -1
- package/dist/presentations/registry.d.ts +0 -15
- package/dist/presentations/registry.js +0 -15
- package/dist/presentations/registry.js.map +0 -1
- package/dist/react/toFormDocument.d.ts +0 -24
- package/dist/react/toFormDocument.js +0 -22
- package/dist/react/toFormDocument.js.map +0 -1
package/dist/react/state.d.ts
CHANGED
|
@@ -3,13 +3,50 @@ type FieldErrors = Record<string, string[]>;
|
|
|
3
3
|
type FormState = {
|
|
4
4
|
values: Record<string, unknown>;
|
|
5
5
|
errors: FieldErrors;
|
|
6
|
-
warnings: FieldErrors;
|
|
7
6
|
touched: Record<string, boolean>;
|
|
8
7
|
submitting: boolean;
|
|
9
8
|
submitted: boolean;
|
|
10
|
-
|
|
9
|
+
/**
|
|
10
|
+
* The step ids whose validation the user has attempted (a blocked advance, or a submit). A field
|
|
11
|
+
* reveals its error when it is touched or its own step is in this set, never via a single global flag,
|
|
12
|
+
* so a submit attempt cannot pre-reveal errors on a step the visitor has not reached.
|
|
13
|
+
*/
|
|
14
|
+
attemptedSteps: Set<string>;
|
|
11
15
|
submitError?: string;
|
|
12
16
|
};
|
|
17
|
+
type FormAction = {
|
|
18
|
+
type: 'SET_VALUE';
|
|
19
|
+
name: string;
|
|
20
|
+
value: unknown;
|
|
21
|
+
} | {
|
|
22
|
+
type: 'TOUCH';
|
|
23
|
+
name: string;
|
|
24
|
+
} | {
|
|
25
|
+
type: 'SET_FIELD_ISSUES';
|
|
26
|
+
name: string;
|
|
27
|
+
errors: string[];
|
|
28
|
+
} | {
|
|
29
|
+
type: 'SET_ALL_ISSUES';
|
|
30
|
+
errors: FieldErrors;
|
|
31
|
+
steps: string[];
|
|
32
|
+
} | {
|
|
33
|
+
type: 'MARK_STEP_ATTEMPTED';
|
|
34
|
+
stepId: string;
|
|
35
|
+
} | {
|
|
36
|
+
type: 'REMOVE_REPEATER_ROW';
|
|
37
|
+
name: string;
|
|
38
|
+
index: number;
|
|
39
|
+
} | {
|
|
40
|
+
type: 'SUBMIT_START';
|
|
41
|
+
} | {
|
|
42
|
+
type: 'SUBMIT_SUCCESS';
|
|
43
|
+
} | {
|
|
44
|
+
type: 'SUBMIT_ERROR';
|
|
45
|
+
message: string;
|
|
46
|
+
} | {
|
|
47
|
+
type: 'RESET';
|
|
48
|
+
values: Record<string, unknown>;
|
|
49
|
+
};
|
|
13
50
|
//#endregion
|
|
14
|
-
export { FormState };
|
|
51
|
+
export { FieldErrors, FormAction, FormState };
|
|
15
52
|
//# sourceMappingURL=state.d.ts.map
|
package/dist/react/state.js
CHANGED
|
@@ -1,13 +1,65 @@
|
|
|
1
|
+
import { isNamedField } from "../fields/fieldKey.js";
|
|
2
|
+
import { consentDisplayOf } from "../consent/effectiveStatement.js";
|
|
1
3
|
//#region src/react/state.ts
|
|
4
|
+
/**
|
|
5
|
+
* The step a field's error reveal is keyed to when the form has no flow, or the field belongs to no
|
|
6
|
+
* step. A single-step form has exactly this one step, so its reveal collapses to the old global one.
|
|
7
|
+
*/
|
|
8
|
+
const DEFAULT_STEP_ID = "__form__";
|
|
9
|
+
/**
|
|
10
|
+
* Per-field defaults for the reducer's initial state. Nameless (bare) blocks carry no value and
|
|
11
|
+
* are skipped. A repeater with a positive `minRows` starts pre-seeded with that many empty rows,
|
|
12
|
+
* matching the schema's own floor. Computed once, ahead of the reducer, so seeding is never an
|
|
13
|
+
* action: it can't touch a field, trigger validation, or (via `Form`'s dispatch wrapper) be
|
|
14
|
+
* mistaken for the user's first edit and fire `form.started`.
|
|
15
|
+
*/
|
|
16
|
+
const seedFieldValues = (fields) => Object.fromEntries(fields.filter(isNamedField).map((field) => {
|
|
17
|
+
if (field.blockType === "repeater") {
|
|
18
|
+
const minRows = typeof field.minRows === "number" ? field.minRows : 0;
|
|
19
|
+
if (minRows > 0) return [field.name, Array.from({ length: minRows }, () => ({}))];
|
|
20
|
+
}
|
|
21
|
+
if (field.blockType === "consent" && consentDisplayOf(field) === "notice") return [field.name, true];
|
|
22
|
+
return [field.name, void 0];
|
|
23
|
+
}));
|
|
2
24
|
const initialFormState = (values) => ({
|
|
3
25
|
values,
|
|
4
26
|
errors: {},
|
|
5
|
-
warnings: {},
|
|
6
27
|
touched: {},
|
|
7
28
|
submitting: false,
|
|
8
29
|
submitted: false,
|
|
9
|
-
|
|
30
|
+
attemptedSteps: /* @__PURE__ */ new Set()
|
|
10
31
|
});
|
|
32
|
+
/**
|
|
33
|
+
* Re-key composite entries (`name[i].sub`) after repeater row `removed` is deleted: drop the removed
|
|
34
|
+
* index and shift every higher index down by one, so surviving rows keep their own errors/touched
|
|
35
|
+
* flags instead of inheriting a deleted or shifted neighbour's. Matches on the `name[<int>]` prefix,
|
|
36
|
+
* so it is agnostic to the sub-key shape after `]` and needs no sub-field list. Returns the same
|
|
37
|
+
* reference when nothing changed, so an unrelated dispatch does not churn state identity.
|
|
38
|
+
*/
|
|
39
|
+
const reindexRepeaterKeys = (map, name, removed) => {
|
|
40
|
+
const prefix = `${name}[`;
|
|
41
|
+
let changed = false;
|
|
42
|
+
const next = {};
|
|
43
|
+
for (const [key, value] of Object.entries(map)) {
|
|
44
|
+
if (!key.startsWith(prefix)) {
|
|
45
|
+
next[key] = value;
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
const close = key.indexOf("]", prefix.length);
|
|
49
|
+
const idx = close === -1 ? NaN : Number(key.slice(prefix.length, close));
|
|
50
|
+
if (!Number.isInteger(idx) || idx < removed) {
|
|
51
|
+
next[key] = value;
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
if (idx === removed) {
|
|
55
|
+
changed = true;
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
next[`${name}[${idx - 1}]${key.slice(close + 1)}`] = value;
|
|
59
|
+
changed = true;
|
|
60
|
+
}
|
|
61
|
+
return changed ? next : map;
|
|
62
|
+
};
|
|
11
63
|
/** Changing a value clears that field's prior errors (re-validated by the caller). */
|
|
12
64
|
const formReducer = (state, action) => {
|
|
13
65
|
switch (action.type) {
|
|
@@ -34,17 +86,21 @@ const formReducer = (state, action) => {
|
|
|
34
86
|
errors: {
|
|
35
87
|
...state.errors,
|
|
36
88
|
[action.name]: action.errors
|
|
37
|
-
},
|
|
38
|
-
warnings: {
|
|
39
|
-
...state.warnings,
|
|
40
|
-
[action.name]: action.warnings
|
|
41
89
|
}
|
|
42
90
|
};
|
|
43
91
|
case "SET_ALL_ISSUES": return {
|
|
44
92
|
...state,
|
|
45
93
|
errors: action.errors,
|
|
46
|
-
|
|
47
|
-
|
|
94
|
+
attemptedSteps: new Set([...state.attemptedSteps, ...action.steps])
|
|
95
|
+
};
|
|
96
|
+
case "MARK_STEP_ATTEMPTED": return state.attemptedSteps.has(action.stepId) ? state : {
|
|
97
|
+
...state,
|
|
98
|
+
attemptedSteps: new Set([...state.attemptedSteps, action.stepId])
|
|
99
|
+
};
|
|
100
|
+
case "REMOVE_REPEATER_ROW": return {
|
|
101
|
+
...state,
|
|
102
|
+
errors: reindexRepeaterKeys(state.errors, action.name, action.index),
|
|
103
|
+
touched: reindexRepeaterKeys(state.touched, action.name, action.index)
|
|
48
104
|
};
|
|
49
105
|
case "SUBMIT_START": return {
|
|
50
106
|
...state,
|
|
@@ -61,10 +117,11 @@ const formReducer = (state, action) => {
|
|
|
61
117
|
submitting: false,
|
|
62
118
|
submitError: action.message
|
|
63
119
|
};
|
|
120
|
+
case "RESET": return initialFormState(action.values);
|
|
64
121
|
default: return state;
|
|
65
122
|
}
|
|
66
123
|
};
|
|
67
124
|
//#endregion
|
|
68
|
-
export { formReducer, initialFormState };
|
|
125
|
+
export { DEFAULT_STEP_ID, formReducer, initialFormState, seedFieldValues };
|
|
69
126
|
|
|
70
127
|
//# sourceMappingURL=state.js.map
|
package/dist/react/state.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"state.js","names":[],"sources":["../../src/react/state.ts"],"sourcesContent":["
|
|
1
|
+
{"version":3,"file":"state.js","names":[],"sources":["../../src/react/state.ts"],"sourcesContent":["import { consentDisplayOf } from '../consent/effectiveStatement'\nimport { isNamedField } from '../fields/fieldKey'\nimport type { FormFieldInstance } from '../submissions/types'\n\nexport type FieldErrors = Record<string, string[]>\n\n/**\n * The step a field's error reveal is keyed to when the form has no flow, or the field belongs to no\n * step. A single-step form has exactly this one step, so its reveal collapses to the old global one.\n */\nexport const DEFAULT_STEP_ID = '__form__'\n\nexport type FormState = {\n\tvalues: Record<string, unknown>\n\terrors: FieldErrors\n\ttouched: Record<string, boolean>\n\tsubmitting: boolean\n\tsubmitted: boolean\n\t/**\n\t * The step ids whose validation the user has attempted (a blocked advance, or a submit). A field\n\t * reveals its error when it is touched or its own step is in this set, never via a single global flag,\n\t * so a submit attempt cannot pre-reveal errors on a step the visitor has not reached.\n\t */\n\tattemptedSteps: Set<string>\n\tsubmitError?: string\n}\n\nexport type FormAction =\n\t| { type: 'SET_VALUE'; name: string; value: unknown }\n\t| { type: 'TOUCH'; name: string }\n\t| { type: 'SET_FIELD_ISSUES'; name: string; errors: string[] }\n\t| { type: 'SET_ALL_ISSUES'; errors: FieldErrors; steps: string[] }\n\t| { type: 'MARK_STEP_ATTEMPTED'; stepId: string }\n\t| { type: 'REMOVE_REPEATER_ROW'; name: string; index: number }\n\t| { type: 'SUBMIT_START' }\n\t| { type: 'SUBMIT_SUCCESS' }\n\t| { type: 'SUBMIT_ERROR'; message: string }\n\t| { type: 'RESET'; values: Record<string, unknown> }\n\n/**\n * Per-field defaults for the reducer's initial state. Nameless (bare) blocks carry no value and\n * are skipped. A repeater with a positive `minRows` starts pre-seeded with that many empty rows,\n * matching the schema's own floor. Computed once, ahead of the reducer, so seeding is never an\n * action: it can't touch a field, trigger validation, or (via `Form`'s dispatch wrapper) be\n * mistaken for the user's first edit and fire `form.started`.\n */\nexport const seedFieldValues = (fields: FormFieldInstance[]): Record<string, unknown> =>\n\tObject.fromEntries(\n\t\tfields.filter(isNamedField).map((field) => {\n\t\t\tif (field.blockType === 'repeater') {\n\t\t\t\tconst minRows = typeof field.minRows === 'number' ? field.minRows : 0\n\t\t\t\tif (minRows > 0) {\n\t\t\t\t\treturn [field.name, Array.from({ length: minRows }, () => ({}))]\n\t\t\t\t}\n\t\t\t}\n\t\t\t// A notice-display consent has no control and the submit is the agreement, so its value\n\t\t\t// is true from the start; the server coerces the same, keeping dependent conditions and\n\t\t\t// calc in agreement across both engines.\n\t\t\tif (field.blockType === 'consent' && consentDisplayOf(field) === 'notice') {\n\t\t\t\treturn [field.name, true]\n\t\t\t}\n\t\t\treturn [field.name, undefined]\n\t\t})\n\t)\n\nexport const initialFormState = (values: Record<string, unknown>): FormState => ({\n\tvalues,\n\terrors: {},\n\ttouched: {},\n\tsubmitting: false,\n\tsubmitted: false,\n\tattemptedSteps: new Set(),\n})\n\n/**\n * Re-key composite entries (`name[i].sub`) after repeater row `removed` is deleted: drop the removed\n * index and shift every higher index down by one, so surviving rows keep their own errors/touched\n * flags instead of inheriting a deleted or shifted neighbour's. Matches on the `name[<int>]` prefix,\n * so it is agnostic to the sub-key shape after `]` and needs no sub-field list. Returns the same\n * reference when nothing changed, so an unrelated dispatch does not churn state identity.\n */\nconst reindexRepeaterKeys = <T>(\n\tmap: Record<string, T>,\n\tname: string,\n\tremoved: number\n): Record<string, T> => {\n\tconst prefix = `${name}[`\n\tlet changed = false\n\tconst next: Record<string, T> = {}\n\tfor (const [key, value] of Object.entries(map)) {\n\t\tif (!key.startsWith(prefix)) {\n\t\t\tnext[key] = value\n\t\t\tcontinue\n\t\t}\n\t\tconst close = key.indexOf(']', prefix.length)\n\t\tconst idx = close === -1 ? Number.NaN : Number(key.slice(prefix.length, close))\n\t\tif (!Number.isInteger(idx) || idx < removed) {\n\t\t\tnext[key] = value\n\t\t\tcontinue\n\t\t}\n\t\tif (idx === removed) {\n\t\t\tchanged = true\n\t\t\tcontinue\n\t\t}\n\t\tnext[`${name}[${idx - 1}]${key.slice(close + 1)}`] = value\n\t\tchanged = true\n\t}\n\treturn changed ? next : map\n}\n\n/** Changing a value clears that field's prior errors (re-validated by the caller). */\nexport const formReducer = (state: FormState, action: FormAction): FormState => {\n\tswitch (action.type) {\n\t\tcase 'SET_VALUE': {\n\t\t\tconst { [action.name]: _removed, ...restErrors } = state.errors\n\t\t\treturn {\n\t\t\t\t...state,\n\t\t\t\tvalues: { ...state.values, [action.name]: action.value },\n\t\t\t\terrors: restErrors,\n\t\t\t}\n\t\t}\n\t\tcase 'TOUCH':\n\t\t\treturn state.touched[action.name]\n\t\t\t\t? state\n\t\t\t\t: { ...state, touched: { ...state.touched, [action.name]: true } }\n\t\tcase 'SET_FIELD_ISSUES':\n\t\t\treturn {\n\t\t\t\t...state,\n\t\t\t\terrors: { ...state.errors, [action.name]: action.errors },\n\t\t\t}\n\t\tcase 'SET_ALL_ISSUES':\n\t\t\treturn {\n\t\t\t\t...state,\n\t\t\t\terrors: action.errors,\n\t\t\t\tattemptedSteps: new Set([...state.attemptedSteps, ...action.steps]),\n\t\t\t}\n\t\tcase 'MARK_STEP_ATTEMPTED':\n\t\t\treturn state.attemptedSteps.has(action.stepId)\n\t\t\t\t? state\n\t\t\t\t: { ...state, attemptedSteps: new Set([...state.attemptedSteps, action.stepId]) }\n\t\tcase 'REMOVE_REPEATER_ROW':\n\t\t\t// The row value is removed by the field's own SET_VALUE; this shifts the composite issue keys\n\t\t\t// (`name[i].sub`) that a plain value array cannot carry, so a deleted row's errors never strand\n\t\t\t// on a survivor or linger unreachably.\n\t\t\treturn {\n\t\t\t\t...state,\n\t\t\t\terrors: reindexRepeaterKeys(state.errors, action.name, action.index),\n\t\t\t\ttouched: reindexRepeaterKeys(state.touched, action.name, action.index),\n\t\t\t}\n\t\tcase 'SUBMIT_START':\n\t\t\treturn { ...state, submitting: true, submitError: undefined }\n\t\tcase 'SUBMIT_SUCCESS':\n\t\t\treturn { ...state, submitting: false, submitted: true }\n\t\tcase 'SUBMIT_ERROR':\n\t\t\treturn { ...state, submitting: false, submitError: action.message }\n\t\tcase 'RESET':\n\t\t\treturn initialFormState(action.values)\n\t\tdefault:\n\t\t\treturn state\n\t}\n}\n"],"mappings":";;;;;;;AAUA,MAAa,kBAAkB;;;;;;;;AAoC/B,MAAa,mBAAmB,WAC/B,OAAO,YACN,OAAO,OAAO,YAAY,EAAE,KAAK,UAAU;CAC1C,IAAI,MAAM,cAAc,YAAY;EACnC,MAAM,UAAU,OAAO,MAAM,YAAY,WAAW,MAAM,UAAU;EACpE,IAAI,UAAU,GACb,OAAO,CAAC,MAAM,MAAM,MAAM,KAAK,EAAE,QAAQ,QAAQ,UAAU,CAAC,EAAE,CAAC;CAEjE;CAIA,IAAI,MAAM,cAAc,aAAa,iBAAiB,KAAK,MAAM,UAChE,OAAO,CAAC,MAAM,MAAM,IAAI;CAEzB,OAAO,CAAC,MAAM,MAAM,KAAA,CAAS;AAC9B,CAAC,CACF;AAED,MAAa,oBAAoB,YAAgD;CAChF;CACA,QAAQ,CAAC;CACT,SAAS,CAAC;CACV,YAAY;CACZ,WAAW;CACX,gCAAgB,IAAI,IAAI;AACzB;;;;;;;;AASA,MAAM,uBACL,KACA,MACA,YACuB;CACvB,MAAM,SAAS,GAAG,KAAK;CACvB,IAAI,UAAU;CACd,MAAM,OAA0B,CAAC;CACjC,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,GAAG,GAAG;EAC/C,IAAI,CAAC,IAAI,WAAW,MAAM,GAAG;GAC5B,KAAK,OAAO;GACZ;EACD;EACA,MAAM,QAAQ,IAAI,QAAQ,KAAK,OAAO,MAAM;EAC5C,MAAM,MAAM,UAAU,KAAK,MAAa,OAAO,IAAI,MAAM,OAAO,QAAQ,KAAK,CAAC;EAC9E,IAAI,CAAC,OAAO,UAAU,GAAG,KAAK,MAAM,SAAS;GAC5C,KAAK,OAAO;GACZ;EACD;EACA,IAAI,QAAQ,SAAS;GACpB,UAAU;GACV;EACD;EACA,KAAK,GAAG,KAAK,GAAG,MAAM,EAAE,GAAG,IAAI,MAAM,QAAQ,CAAC,OAAO;EACrD,UAAU;CACX;CACA,OAAO,UAAU,OAAO;AACzB;;AAGA,MAAa,eAAe,OAAkB,WAAkC;CAC/E,QAAQ,OAAO,MAAf;EACC,KAAK,aAAa;GACjB,MAAM,GAAG,OAAO,OAAO,UAAU,GAAG,eAAe,MAAM;GACzD,OAAO;IACN,GAAG;IACH,QAAQ;KAAE,GAAG,MAAM;MAAS,OAAO,OAAO,OAAO;IAAM;IACvD,QAAQ;GACT;EACD;EACA,KAAK,SACJ,OAAO,MAAM,QAAQ,OAAO,QACzB,QACA;GAAE,GAAG;GAAO,SAAS;IAAE,GAAG,MAAM;KAAU,OAAO,OAAO;GAAK;EAAE;EACnE,KAAK,oBACJ,OAAO;GACN,GAAG;GACH,QAAQ;IAAE,GAAG,MAAM;KAAS,OAAO,OAAO,OAAO;GAAO;EACzD;EACD,KAAK,kBACJ,OAAO;GACN,GAAG;GACH,QAAQ,OAAO;GACf,gBAAgB,IAAI,IAAI,CAAC,GAAG,MAAM,gBAAgB,GAAG,OAAO,KAAK,CAAC;EACnE;EACD,KAAK,uBACJ,OAAO,MAAM,eAAe,IAAI,OAAO,MAAM,IAC1C,QACA;GAAE,GAAG;GAAO,gBAAgB,IAAI,IAAI,CAAC,GAAG,MAAM,gBAAgB,OAAO,MAAM,CAAC;EAAE;EAClF,KAAK,uBAIJ,OAAO;GACN,GAAG;GACH,QAAQ,oBAAoB,MAAM,QAAQ,OAAO,MAAM,OAAO,KAAK;GACnE,SAAS,oBAAoB,MAAM,SAAS,OAAO,MAAM,OAAO,KAAK;EACtE;EACD,KAAK,gBACJ,OAAO;GAAE,GAAG;GAAO,YAAY;GAAM,aAAa,KAAA;EAAU;EAC7D,KAAK,kBACJ,OAAO;GAAE,GAAG;GAAO,YAAY;GAAO,WAAW;EAAK;EACvD,KAAK,gBACJ,OAAO;GAAE,GAAG;GAAO,YAAY;GAAO,aAAa,OAAO;EAAQ;EACnE,KAAK,SACJ,OAAO,iBAAiB,OAAO,MAAM;EACtC,SACC,OAAO;CACT;AACD"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
//#region src/react/uploadFile.d.ts
|
|
2
2
|
type UploadFileInput = {
|
|
3
|
-
file: File; /** Upload collection slug.
|
|
4
|
-
collection
|
|
3
|
+
file: File; /** Upload collection slug. File fields carry it as the server-stamped `collection` block config. */
|
|
4
|
+
collection: string;
|
|
5
5
|
apiRoute?: string;
|
|
6
6
|
fetchImpl?: typeof fetch;
|
|
7
7
|
};
|
package/dist/react/uploadFile.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* at submit, so the client is never trusted for it. Pure: inject `fetchImpl` in tests.
|
|
6
6
|
*/
|
|
7
7
|
const uploadFile = async (input) => {
|
|
8
|
-
const { file, collection
|
|
8
|
+
const { file, collection, apiRoute = "/api", fetchImpl = fetch } = input;
|
|
9
9
|
const body = new FormData();
|
|
10
10
|
body.append("file", file);
|
|
11
11
|
let response;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"uploadFile.js","names":[],"sources":["../../src/react/uploadFile.ts"],"sourcesContent":["export type UploadFileInput = {\n\tfile: File\n\t/** Upload collection slug.
|
|
1
|
+
{"version":3,"file":"uploadFile.js","names":[],"sources":["../../src/react/uploadFile.ts"],"sourcesContent":["export type UploadFileInput = {\n\tfile: File\n\t/** Upload collection slug. File fields carry it as the server-stamped `collection` block config. */\n\tcollection: string\n\tapiRoute?: string\n\tfetchImpl?: typeof fetch\n}\n\nexport type UploadFileResult = { ok: true; id: string | number } | { ok: false; message?: string }\n\n/**\n * Upload one file to a Payload upload collection (`POST {apiRoute}/{collection}`, multipart) and return its\n * id, which the file field stores as its value. The server re-derives the file metadata from the stored doc\n * at submit, so the client is never trusted for it. Pure: inject `fetchImpl` in tests.\n */\nexport const uploadFile = async (input: UploadFileInput): Promise<UploadFileResult> => {\n\tconst { file, collection, apiRoute = '/api', fetchImpl = fetch } = input\n\tconst body = new FormData()\n\tbody.append('file', file)\n\tlet response: Response\n\ttry {\n\t\tresponse = await fetchImpl(`${apiRoute}/${collection}`, { method: 'POST', body })\n\t} catch (error) {\n\t\treturn { ok: false, message: error instanceof Error ? error.message : 'Network error' }\n\t}\n\tif (!response.ok) {\n\t\treturn { ok: false, message: `Upload failed (${response.status})` }\n\t}\n\tconst data = (await response.json().catch(() => ({}))) as { doc?: { id?: string | number } }\n\tconst id = data.doc?.id\n\treturn id == null ? { ok: false, message: 'No id returned' } : { ok: true, id }\n}\n"],"mappings":";;;;;;AAeA,MAAa,aAAa,OAAO,UAAsD;CACtF,MAAM,EAAE,MAAM,YAAY,WAAW,QAAQ,YAAY,UAAU;CACnE,MAAM,OAAO,IAAI,SAAS;CAC1B,KAAK,OAAO,QAAQ,IAAI;CACxB,IAAI;CACJ,IAAI;EACH,WAAW,MAAM,UAAU,GAAG,SAAS,GAAG,cAAc;GAAE,QAAQ;GAAQ;EAAK,CAAC;CACjF,SAAS,OAAO;EACf,OAAO;GAAE,IAAI;GAAO,SAAS,iBAAiB,QAAQ,MAAM,UAAU;EAAgB;CACvF;CACA,IAAI,CAAC,SAAS,IACb,OAAO;EAAE,IAAI;EAAO,SAAS,kBAAkB,SAAS,OAAO;CAAG;CAGnE,MAAM,MAAK,MADS,SAAS,KAAK,EAAE,aAAa,CAAC,EAAE,GACpC,KAAK;CACrB,OAAO,MAAM,OAAO;EAAE,IAAI;EAAO,SAAS;CAAiB,IAAI;EAAE,IAAI;EAAM;CAAG;AAC/E"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
//#region src/react/useCalcValues.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Live computed calculation values (field name -> number), recomputed as answers change. For
|
|
4
|
+
* composed frontends (custom layouts over `useFormContext`/`FormFields`) that render running
|
|
5
|
+
* totals without re-evaluating expressions themselves.
|
|
6
|
+
*/
|
|
7
|
+
declare const useCalcValues: () => Record<string, number>;
|
|
8
|
+
//#endregion
|
|
9
|
+
export { useCalcValues };
|
|
10
|
+
//# sourceMappingURL=useCalcValues.d.ts.map
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useFormContext } from "./FormContext.js";
|
|
3
|
+
//#region src/react/useCalcValues.ts
|
|
4
|
+
/**
|
|
5
|
+
* Live computed calculation values (field name -> number), recomputed as answers change. For
|
|
6
|
+
* composed frontends (custom layouts over `useFormContext`/`FormFields`) that render running
|
|
7
|
+
* totals without re-evaluating expressions themselves.
|
|
8
|
+
*/
|
|
9
|
+
const useCalcValues = () => useFormContext().calcValues ?? {};
|
|
10
|
+
//#endregion
|
|
11
|
+
export { useCalcValues };
|
|
12
|
+
|
|
13
|
+
//# sourceMappingURL=useCalcValues.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useCalcValues.js","names":[],"sources":["../../src/react/useCalcValues.ts"],"sourcesContent":["'use client'\n\nimport { useFormContext } from './FormContext'\n\n/**\n * Live computed calculation values (field name -> number), recomputed as answers change. For\n * composed frontends (custom layouts over `useFormContext`/`FormFields`) that render running\n * totals without re-evaluating expressions themselves.\n */\nexport const useCalcValues = (): Record<string, number> => useFormContext().calcValues ?? {}\n"],"mappings":";;;;;;;;AASA,MAAa,sBAA8C,eAAe,EAAE,cAAc,CAAC"}
|
package/dist/react/useField.d.ts
CHANGED
package/dist/react/useField.js
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { useFormContext } from "./FormContext.js";
|
|
3
|
+
import "./state.js";
|
|
3
4
|
import { useCallback } from "react";
|
|
4
5
|
//#region src/react/useField.ts
|
|
5
6
|
/** Bind one field by name to the form controller: its value, issues, and change/blur handlers. */
|
|
6
7
|
const useField = (name) => {
|
|
7
|
-
const { state, dispatch, validateField } = useFormContext();
|
|
8
|
+
const { state, dispatch, validateField, stepIdOfField } = useFormContext();
|
|
8
9
|
const touched = state.touched[name] ?? false;
|
|
9
|
-
const
|
|
10
|
+
const stepAttempted = state.attemptedSteps.has(stepIdOfField?.(name) ?? "__form__");
|
|
11
|
+
const showIssues = touched || stepAttempted;
|
|
10
12
|
const value = state.values[name];
|
|
11
13
|
const setValue = useCallback((next) => {
|
|
12
14
|
dispatch({
|
|
@@ -14,12 +16,11 @@ const useField = (name) => {
|
|
|
14
16
|
name,
|
|
15
17
|
value: next
|
|
16
18
|
});
|
|
17
|
-
if (
|
|
19
|
+
if (showIssues) validateField(name, next);
|
|
18
20
|
}, [
|
|
19
21
|
dispatch,
|
|
20
22
|
name,
|
|
21
|
-
|
|
22
|
-
state.submitAttempted,
|
|
23
|
+
showIssues,
|
|
23
24
|
validateField
|
|
24
25
|
]);
|
|
25
26
|
const onBlur = useCallback(() => {
|
|
@@ -37,7 +38,6 @@ const useField = (name) => {
|
|
|
37
38
|
return {
|
|
38
39
|
value,
|
|
39
40
|
errors: showIssues ? state.errors[name] ?? [] : [],
|
|
40
|
-
warnings: showIssues ? state.warnings[name] ?? [] : [],
|
|
41
41
|
touched,
|
|
42
42
|
setValue,
|
|
43
43
|
onBlur
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useField.js","names":[],"sources":["../../src/react/useField.ts"],"sourcesContent":["'use client'\n\nimport { useCallback } from 'react'\nimport { useFormContext } from './FormContext'\n\nexport type UseFieldResult<TValue = unknown> = {\n\tvalue: TValue | undefined\n\terrors: string[]\n\
|
|
1
|
+
{"version":3,"file":"useField.js","names":[],"sources":["../../src/react/useField.ts"],"sourcesContent":["'use client'\n\nimport { useCallback } from 'react'\nimport { useFormContext } from './FormContext'\nimport { DEFAULT_STEP_ID } from './state'\n\nexport type UseFieldResult<TValue = unknown> = {\n\tvalue: TValue | undefined\n\terrors: string[]\n\ttouched: boolean\n\tsetValue: (value: TValue) => void\n\t/** Mark touched and validate now (call on blur). */\n\tonBlur: () => void\n}\n\n/** Bind one field by name to the form controller: its value, issues, and change/blur handlers. */\nexport const useField = <TValue = unknown>(name: string): UseFieldResult<TValue> => {\n\tconst { state, dispatch, validateField, stepIdOfField } = useFormContext()\n\tconst touched = state.touched[name] ?? false\n\t// Reveal is a function of this field's own step, never a single global flag: the field's error shows\n\t// once it is touched, or once the step it belongs to has been attempted (a blocked advance or submit).\n\tconst stepAttempted = state.attemptedSteps.has(stepIdOfField?.(name) ?? DEFAULT_STEP_ID)\n\tconst showIssues = touched || stepAttempted\n\tconst value = state.values[name] as TValue | undefined\n\n\tconst setValue = useCallback(\n\t\t(next: TValue) => {\n\t\t\tdispatch({ type: 'SET_VALUE', name, value: next })\n\t\t\t// Re-validate on change only once the error is already revealed; never reveal an untouched field mid-typing.\n\t\t\tif (showIssues) {\n\t\t\t\tvalidateField(name, next)\n\t\t\t}\n\t\t},\n\t\t[dispatch, name, showIssues, validateField]\n\t)\n\n\tconst onBlur = useCallback(() => {\n\t\tdispatch({ type: 'TOUCH', name })\n\t\tvalidateField(name, value)\n\t}, [dispatch, name, validateField, value])\n\n\treturn {\n\t\tvalue,\n\t\terrors: showIssues ? (state.errors[name] ?? []) : [],\n\t\ttouched,\n\t\tsetValue,\n\t\tonBlur,\n\t}\n}\n"],"mappings":";;;;;;AAgBA,MAAa,YAA8B,SAAyC;CACnF,MAAM,EAAE,OAAO,UAAU,eAAe,kBAAkB,eAAe;CACzE,MAAM,UAAU,MAAM,QAAQ,SAAS;CAGvC,MAAM,gBAAgB,MAAM,eAAe,IAAI,gBAAgB,IAAI,KAAA,UAAoB;CACvF,MAAM,aAAa,WAAW;CAC9B,MAAM,QAAQ,MAAM,OAAO;CAE3B,MAAM,WAAW,aACf,SAAiB;EACjB,SAAS;GAAE,MAAM;GAAa;GAAM,OAAO;EAAK,CAAC;EAEjD,IAAI,YACH,cAAc,MAAM,IAAI;CAE1B,GACA;EAAC;EAAU;EAAM;EAAY;CAAa,CAC3C;CAEA,MAAM,SAAS,kBAAkB;EAChC,SAAS;GAAE,MAAM;GAAS;EAAK,CAAC;EAChC,cAAc,MAAM,KAAK;CAC1B,GAAG;EAAC;EAAU;EAAM;EAAe;CAAK,CAAC;CAEzC,OAAO;EACN;EACA,QAAQ,aAAc,MAAM,OAAO,SAAS,CAAC,IAAK,CAAC;EACnD;EACA;EACA;CACD;AACD"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { FormState } from "./state.js";
|
|
2
2
|
|
|
3
3
|
//#region src/react/useFormState.d.ts
|
|
4
|
-
/** The whole form state (values, errors,
|
|
4
|
+
/** The whole form state (values, errors, touched, submitting, submitted, submitError). */
|
|
5
5
|
declare const useFormState: () => FormState;
|
|
6
6
|
//#endregion
|
|
7
7
|
export { useFormState };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { useFormContext } from "./FormContext.js";
|
|
3
3
|
//#region src/react/useFormState.ts
|
|
4
|
-
/** The whole form state (values, errors,
|
|
4
|
+
/** The whole form state (values, errors, touched, submitting, submitted, submitError). */
|
|
5
5
|
const useFormState = () => useFormContext().state;
|
|
6
6
|
//#endregion
|
|
7
7
|
export { useFormState };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useFormState.js","names":[],"sources":["../../src/react/useFormState.ts"],"sourcesContent":["'use client'\n\nimport { useFormContext } from './FormContext'\nimport type { FormState } from './state'\n\n/** The whole form state (values, errors,
|
|
1
|
+
{"version":3,"file":"useFormState.js","names":[],"sources":["../../src/react/useFormState.ts"],"sourcesContent":["'use client'\n\nimport { useFormContext } from './FormContext'\nimport type { FormState } from './state'\n\n/** The whole form state (values, errors, touched, submitting, submitted, submitError). */\nexport const useFormState = (): FormState => useFormContext().state\n"],"mappings":";;;;AAMA,MAAa,qBAAgC,eAAe,EAAE"}
|
|
@@ -2,11 +2,11 @@ import { runValidation } from "../validation/runValidation.js";
|
|
|
2
2
|
//#region src/react/validateField.ts
|
|
3
3
|
/**
|
|
4
4
|
* Run client-side validation for one field, reusing the shared engine in `mode: 'client'` (server-only
|
|
5
|
-
* rules are skipped, no `req`/`payload`).
|
|
5
|
+
* rules are skipped, no `req`/`payload`). Every returned message is a blocking error.
|
|
6
6
|
*/
|
|
7
7
|
const validateFieldValue = async (input) => {
|
|
8
8
|
const { field, value, registry, ruleRegistry, answers, locale, t } = input;
|
|
9
|
-
const { errors
|
|
9
|
+
const { errors } = await runValidation({
|
|
10
10
|
field,
|
|
11
11
|
fieldDefinition: registry.get(field.blockType),
|
|
12
12
|
value,
|
|
@@ -19,10 +19,7 @@ const validateFieldValue = async (input) => {
|
|
|
19
19
|
event: "onChange",
|
|
20
20
|
mode: "client"
|
|
21
21
|
});
|
|
22
|
-
return {
|
|
23
|
-
errors: issues.filter((issue) => issue.severity === "error").map((issue) => issue.message),
|
|
24
|
-
warnings: issues.filter((issue) => issue.severity === "warning").map((issue) => issue.message)
|
|
25
|
-
};
|
|
22
|
+
return { errors };
|
|
26
23
|
};
|
|
27
24
|
//#endregion
|
|
28
25
|
export { validateFieldValue };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validateField.js","names":[],"sources":["../../src/react/validateField.ts"],"sourcesContent":["import type { FieldTypeRegistry } from '../fields/registry'\nimport type { Translate } from '../fields/types'\nimport type { FormFieldInstance } from '../submissions/types'\nimport type { ValidationRuleRegistry } from '../validation/registry'\nimport { runValidation } from '../validation/runValidation'\n\nexport type ValidateFieldInput = {\n\tfield: FormFieldInstance\n\tvalue: unknown\n\tregistry: FieldTypeRegistry\n\truleRegistry: ValidationRuleRegistry\n\tanswers: Record<string, unknown>\n\tlocale: string\n\tt: Translate\n}\n\nexport type ValidateFieldResult = { errors: string[]
|
|
1
|
+
{"version":3,"file":"validateField.js","names":[],"sources":["../../src/react/validateField.ts"],"sourcesContent":["import type { FieldTypeRegistry } from '../fields/registry'\nimport type { Translate } from '../fields/types'\nimport type { FormFieldInstance } from '../submissions/types'\nimport type { ValidationRuleRegistry } from '../validation/registry'\nimport { runValidation } from '../validation/runValidation'\n\nexport type ValidateFieldInput = {\n\tfield: FormFieldInstance\n\tvalue: unknown\n\tregistry: FieldTypeRegistry\n\truleRegistry: ValidationRuleRegistry\n\tanswers: Record<string, unknown>\n\tlocale: string\n\tt: Translate\n}\n\nexport type ValidateFieldResult = { errors: string[] }\n\n/**\n * Run client-side validation for one field, reusing the shared engine in `mode: 'client'` (server-only\n * rules are skipped, no `req`/`payload`). Every returned message is a blocking error.\n */\nexport const validateFieldValue = async (\n\tinput: ValidateFieldInput\n): Promise<ValidateFieldResult> => {\n\tconst { field, value, registry, ruleRegistry, answers, locale, t } = input\n\tconst { errors } = await runValidation({\n\t\tfield,\n\t\tfieldDefinition: registry.get(field.blockType),\n\t\tvalue,\n\t\tfieldType: field.blockType,\n\t\truleRegistry,\n\t\tanswers,\n\t\tlocale,\n\t\tt,\n\t\toperation: 'create',\n\t\tevent: 'onChange',\n\t\tmode: 'client',\n\t})\n\treturn { errors }\n}\n"],"mappings":";;;;;;AAsBA,MAAa,qBAAqB,OACjC,UACkC;CAClC,MAAM,EAAE,OAAO,OAAO,UAAU,cAAc,SAAS,QAAQ,MAAM;CACrE,MAAM,EAAE,WAAW,MAAM,cAAc;EACtC;EACA,iBAAiB,SAAS,IAAI,MAAM,SAAS;EAC7C;EACA,WAAW,MAAM;EACjB;EACA;EACA;EACA;EACA,WAAW;EACX,OAAO;EACP,MAAM;CACP,CAAC;CACD,OAAO,EAAE,OAAO;AACjB"}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
//#region src/recall/interpolate.d.ts
|
|
2
2
|
/**
|
|
3
|
-
* Replace `{{ name }}
|
|
4
|
-
*
|
|
5
|
-
*
|
|
3
|
+
* Replace `{{ name }}`, `{{ name|fallback }}`, and `{{ name||fallback }}` tokens (single and
|
|
4
|
+
* double pipe are equivalent; the second pipe is just consumed, not part of the fallback text).
|
|
5
|
+
* `resolve` returns the recalled value ('' when absent); the fallback (or '') is substituted when
|
|
6
|
+
* `resolve` yields ''. Token-free input is returned unchanged, so this is a no-op for ordinary text.
|
|
6
7
|
*/
|
|
7
8
|
declare const interpolate: (template: string, resolve: (name: string) => string) => string;
|
|
8
9
|
//#endregion
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
//#region src/recall/interpolate.ts
|
|
2
|
-
const TOKEN = /\{\{\s*([^{}|]+?)\s*(
|
|
2
|
+
const TOKEN = /\{\{\s*([^{}|]+?)\s*(?:\|\|?([^{}]*?))?\}\}/g;
|
|
3
3
|
/**
|
|
4
|
-
* Replace `{{ name }}
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* Replace `{{ name }}`, `{{ name|fallback }}`, and `{{ name||fallback }}` tokens (single and
|
|
5
|
+
* double pipe are equivalent; the second pipe is just consumed, not part of the fallback text).
|
|
6
|
+
* `resolve` returns the recalled value ('' when absent); the fallback (or '') is substituted when
|
|
7
|
+
* `resolve` yields ''. Token-free input is returned unchanged, so this is a no-op for ordinary text.
|
|
7
8
|
*/
|
|
8
9
|
const interpolate = (template, resolve) => template.replace(TOKEN, (_match, rawName, rawFallback) => {
|
|
9
10
|
const value = resolve(rawName.trim());
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"interpolate.js","names":[],"sources":["../../src/recall/interpolate.ts"],"sourcesContent":["const TOKEN = /\\{\\{\\s*([^{}|]+?)\\s*(
|
|
1
|
+
{"version":3,"file":"interpolate.js","names":[],"sources":["../../src/recall/interpolate.ts"],"sourcesContent":["const TOKEN = /\\{\\{\\s*([^{}|]+?)\\s*(?:\\|\\|?([^{}]*?))?\\}\\}/g\n\n/**\n * Replace `{{ name }}`, `{{ name|fallback }}`, and `{{ name||fallback }}` tokens (single and\n * double pipe are equivalent; the second pipe is just consumed, not part of the fallback text).\n * `resolve` returns the recalled value ('' when absent); the fallback (or '') is substituted when\n * `resolve` yields ''. Token-free input is returned unchanged, so this is a no-op for ordinary text.\n */\nexport const interpolate = (template: string, resolve: (name: string) => string): string =>\n\ttemplate.replace(TOKEN, (_match, rawName: string, rawFallback?: string) => {\n\t\tconst value = resolve(rawName.trim())\n\t\tif (value !== '') {\n\t\t\treturn value\n\t\t}\n\t\treturn rawFallback === undefined ? '' : rawFallback.trim()\n\t})\n"],"mappings":";AAAA,MAAM,QAAQ;;;;;;;AAQd,MAAa,eAAe,UAAkB,YAC7C,SAAS,QAAQ,QAAQ,QAAQ,SAAiB,gBAAyB;CAC1E,MAAM,QAAQ,QAAQ,QAAQ,KAAK,CAAC;CACpC,IAAI,UAAU,IACb,OAAO;CAER,OAAO,gBAAgB,KAAA,IAAY,KAAK,YAAY,KAAK;AAC1D,CAAC"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { AnyFormFieldDefinition } from "../fields/types.js";
|
|
2
1
|
import { FormFieldInstance } from "../submissions/types.js";
|
|
2
|
+
import { AnyFormFieldDefinition } from "../fields/types.js";
|
|
3
3
|
|
|
4
4
|
//#region src/recall/resolver.d.ts
|
|
5
5
|
type RecallResolver = (name: string) => string;
|
package/dist/recall/resolver.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
|
+
import { isNamedField } from "../fields/fieldKey.js";
|
|
1
2
|
//#region src/recall/resolver.ts
|
|
2
3
|
/** Derive a value->label map from a select-like field instance's `options`. */
|
|
3
4
|
const optionLabelsFor = (field) => {
|
|
4
5
|
const options = field.options;
|
|
5
6
|
if (!Array.isArray(options)) return;
|
|
6
7
|
const map = {};
|
|
7
|
-
for (const option of options) if (option && typeof option.value === "string") map[option.value] = option.label
|
|
8
|
+
for (const option of options) if (option && typeof option.value === "string") map[option.value] = option.label?.trim() ? option.label : option.value;
|
|
8
9
|
return Object.keys(map).length > 0 ? map : void 0;
|
|
9
10
|
};
|
|
10
11
|
/**
|
|
@@ -13,7 +14,7 @@ const optionLabelsFor = (field) => {
|
|
|
13
14
|
* value -> ''. Pure and isomorphic; the renderer and server templates share it.
|
|
14
15
|
*/
|
|
15
16
|
const buildRecallResolver = (args) => {
|
|
16
|
-
const byName = new Map(args.fields.map((field) => [field.name, field]));
|
|
17
|
+
const byName = new Map(args.fields.filter(isNamedField).map((field) => [field.name, field]));
|
|
17
18
|
return (name) => {
|
|
18
19
|
const field = byName.get(name);
|
|
19
20
|
if (!field) return "";
|
|
@@ -30,7 +31,18 @@ const buildRecallResolver = (args) => {
|
|
|
30
31
|
return Array.isArray(value) ? value.join(", ") : String(value);
|
|
31
32
|
};
|
|
32
33
|
};
|
|
34
|
+
/**
|
|
35
|
+
* Build a submission-shaped descriptor per named field: the client-side counterpart to the
|
|
36
|
+
* per-field descriptors `runSubmission` snapshots server-side. Lets client-rendered templates
|
|
37
|
+
* (the response message) label rows the same way server-rendered ones (email-team) do. `optionLabels`
|
|
38
|
+
* is omitted: pair with values already formatted via `buildRecallResolver`, not raw stored values.
|
|
39
|
+
*/
|
|
40
|
+
const descriptorsFor = (fields) => fields.filter(isNamedField).map((field) => ({
|
|
41
|
+
field: field.name,
|
|
42
|
+
label: field.label ?? field.name,
|
|
43
|
+
fieldType: field.blockType
|
|
44
|
+
}));
|
|
33
45
|
//#endregion
|
|
34
|
-
export { buildRecallResolver, optionLabelsFor };
|
|
46
|
+
export { buildRecallResolver, descriptorsFor, optionLabelsFor };
|
|
35
47
|
|
|
36
48
|
//# sourceMappingURL=resolver.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolver.js","names":[],"sources":["../../src/recall/resolver.ts"],"sourcesContent":["import type { AnyFormFieldDefinition } from '../fields/types'\nimport type { FormFieldInstance } from '../submissions/types'\n\nexport type RecallResolver = (name: string) => string\n\ntype Option = { label?: string; value?: string }\n\n/** Derive a value->label map from a select-like field instance's `options`. */\nexport const optionLabelsFor = (field: FormFieldInstance): Record<string, string> | undefined => {\n\tconst options = field.options\n\tif (!Array.isArray(options)) {\n\t\treturn undefined\n\t}\n\tconst map: Record<string, string> = {}\n\tfor (const option of options as Option[]) {\n\t\tif (option && typeof option.value === 'string') {\n\t\t\tmap[option.value] = option.label
|
|
1
|
+
{"version":3,"file":"resolver.js","names":[],"sources":["../../src/recall/resolver.ts"],"sourcesContent":["import { isNamedField } from '../fields/fieldKey'\nimport type { AnyFormFieldDefinition } from '../fields/types'\nimport type { FormFieldInstance, SubmissionDescriptor } from '../submissions/types'\n\nexport type RecallResolver = (name: string) => string\n\ntype Option = { label?: string; value?: string }\n\n/** Derive a value->label map from a select-like field instance's `options`. */\nexport const optionLabelsFor = (field: FormFieldInstance): Record<string, string> | undefined => {\n\tconst options = field.options\n\tif (!Array.isArray(options)) {\n\t\treturn undefined\n\t}\n\tconst map: Record<string, string> = {}\n\tfor (const option of options as Option[]) {\n\t\tif (option && typeof option.value === 'string') {\n\t\t\tmap[option.value] = option.label?.trim() ? option.label : option.value\n\t\t}\n\t}\n\treturn Object.keys(map).length > 0 ? map : undefined\n}\n\n/**\n * Build a recall resolver: `{{name}}` -> the field's current value, formatted via its type's `format`\n * (so a select shows its option label, a checkbox Yes/No, a date localized). Missing field or empty\n * value -> ''. Pure and isomorphic; the renderer and server templates share it.\n */\nexport const buildRecallResolver = (args: {\n\tfields: FormFieldInstance[]\n\tvalues: Record<string, unknown>\n\tregistry: Map<string, AnyFormFieldDefinition>\n\tlocale: string\n\tt: (key: string) => string\n}): RecallResolver => {\n\tconst byName = new Map(args.fields.filter(isNamedField).map((field) => [field.name, field]))\n\treturn (name) => {\n\t\tconst field = byName.get(name)\n\t\tif (!field) {\n\t\t\treturn ''\n\t\t}\n\t\tconst value = args.values[name]\n\t\tif (value == null || value === '' || (Array.isArray(value) && value.length === 0)) {\n\t\t\treturn ''\n\t\t}\n\t\tconst definition = args.registry.get(field.blockType)\n\t\tif (definition?.format) {\n\t\t\treturn definition.format({\n\t\t\t\tvalue,\n\t\t\t\tconfig: {},\n\t\t\t\toptionLabels: optionLabelsFor(field),\n\t\t\t\tlocale: args.locale,\n\t\t\t\tt: args.t,\n\t\t\t})\n\t\t}\n\t\treturn Array.isArray(value) ? value.join(', ') : String(value)\n\t}\n}\n\n/**\n * Build a submission-shaped descriptor per named field: the client-side counterpart to the\n * per-field descriptors `runSubmission` snapshots server-side. Lets client-rendered templates\n * (the response message) label rows the same way server-rendered ones (email-team) do. `optionLabels`\n * is omitted: pair with values already formatted via `buildRecallResolver`, not raw stored values.\n */\nexport const descriptorsFor = (fields: FormFieldInstance[]): SubmissionDescriptor[] =>\n\tfields.filter(isNamedField).map((field) => ({\n\t\tfield: field.name,\n\t\tlabel: field.label ?? field.name,\n\t\tfieldType: field.blockType,\n\t}))\n"],"mappings":";;;AASA,MAAa,mBAAmB,UAAiE;CAChG,MAAM,UAAU,MAAM;CACtB,IAAI,CAAC,MAAM,QAAQ,OAAO,GACzB;CAED,MAAM,MAA8B,CAAC;CACrC,KAAK,MAAM,UAAU,SACpB,IAAI,UAAU,OAAO,OAAO,UAAU,UACrC,IAAI,OAAO,SAAS,OAAO,OAAO,KAAK,IAAI,OAAO,QAAQ,OAAO;CAGnE,OAAO,OAAO,KAAK,GAAG,EAAE,SAAS,IAAI,MAAM,KAAA;AAC5C;;;;;;AAOA,MAAa,uBAAuB,SAMd;CACrB,MAAM,SAAS,IAAI,IAAI,KAAK,OAAO,OAAO,YAAY,EAAE,KAAK,UAAU,CAAC,MAAM,MAAM,KAAK,CAAC,CAAC;CAC3F,QAAQ,SAAS;EAChB,MAAM,QAAQ,OAAO,IAAI,IAAI;EAC7B,IAAI,CAAC,OACJ,OAAO;EAER,MAAM,QAAQ,KAAK,OAAO;EAC1B,IAAI,SAAS,QAAQ,UAAU,MAAO,MAAM,QAAQ,KAAK,KAAK,MAAM,WAAW,GAC9E,OAAO;EAER,MAAM,aAAa,KAAK,SAAS,IAAI,MAAM,SAAS;EACpD,IAAI,YAAY,QACf,OAAO,WAAW,OAAO;GACxB;GACA,QAAQ,CAAC;GACT,cAAc,gBAAgB,KAAK;GACnC,QAAQ,KAAK;GACb,GAAG,KAAK;EACT,CAAC;EAEF,OAAO,MAAM,QAAQ,KAAK,IAAI,MAAM,KAAK,IAAI,IAAI,OAAO,KAAK;CAC9D;AACD;;;;;;;AAQA,MAAa,kBAAkB,WAC9B,OAAO,OAAO,YAAY,EAAE,KAAK,WAAW;CAC3C,OAAO,MAAM;CACb,OAAO,MAAM,SAAS,MAAM;CAC5B,WAAW,MAAM;AAClB,EAAE"}
|
package/dist/spam/captcha.d.ts
CHANGED
|
@@ -2,9 +2,10 @@ import { CaptchaProvider } from "./types.js";
|
|
|
2
2
|
|
|
3
3
|
//#region src/spam/captcha.d.ts
|
|
4
4
|
/**
|
|
5
|
-
* Identity helper for authoring a captcha provider (mirrors `defineAction`/`
|
|
6
|
-
*
|
|
7
|
-
*
|
|
5
|
+
* Identity helper for authoring a captcha provider (mirrors `defineAction`/`definePollOptionSource`).
|
|
6
|
+
* Bundled adapters (`turnstileProvider`, `recaptchaProvider`, `hcaptchaProvider`) are built with it;
|
|
7
|
+
* use it directly for any other verification service. The submit path verifies a token carried on
|
|
8
|
+
* the submission.
|
|
8
9
|
*/
|
|
9
10
|
declare const defineCaptchaProvider: (provider: CaptchaProvider) => CaptchaProvider;
|
|
10
11
|
//#endregion
|
package/dist/spam/captcha.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
//#region src/spam/captcha.ts
|
|
2
2
|
/**
|
|
3
|
-
* Identity helper for authoring a captcha provider (mirrors `defineAction`/`
|
|
4
|
-
*
|
|
5
|
-
*
|
|
3
|
+
* Identity helper for authoring a captcha provider (mirrors `defineAction`/`definePollOptionSource`).
|
|
4
|
+
* Bundled adapters (`turnstileProvider`, `recaptchaProvider`, `hcaptchaProvider`) are built with it;
|
|
5
|
+
* use it directly for any other verification service. The submit path verifies a token carried on
|
|
6
|
+
* the submission.
|
|
6
7
|
*/
|
|
7
8
|
const defineCaptchaProvider = (provider) => provider;
|
|
8
9
|
//#endregion
|
package/dist/spam/captcha.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"captcha.js","names":[],"sources":["../../src/spam/captcha.ts"],"sourcesContent":["import type { CaptchaProvider } from './types'\n\n/**\n * Identity helper for authoring a captcha provider (mirrors `defineAction`/`
|
|
1
|
+
{"version":3,"file":"captcha.js","names":[],"sources":["../../src/spam/captcha.ts"],"sourcesContent":["import type { CaptchaProvider } from './types'\n\n/**\n * Identity helper for authoring a captcha provider (mirrors `defineAction`/`definePollOptionSource`).\n * Bundled adapters (`turnstileProvider`, `recaptchaProvider`, `hcaptchaProvider`) are built with it;\n * use it directly for any other verification service. The submit path verifies a token carried on\n * the submission.\n */\nexport const defineCaptchaProvider = (provider: CaptchaProvider): CaptchaProvider => provider\n"],"mappings":";;;;;;;AAQA,MAAa,yBAAyB,aAA+C"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
//#region src/spam/clientIp.ts
|
|
2
|
+
/** First hop of a comma-separated proxy header (the client, per X-Forwarded-For convention), or undefined. */
|
|
3
|
+
const firstHop = (headers, header) => {
|
|
4
|
+
return headers?.get(header)?.split(",")[0]?.trim() || void 0;
|
|
5
|
+
};
|
|
6
|
+
//#endregion
|
|
7
|
+
export { firstHop };
|
|
8
|
+
|
|
9
|
+
//# sourceMappingURL=clientIp.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clientIp.js","names":[],"sources":["../../src/spam/clientIp.ts"],"sourcesContent":["/** First hop of a comma-separated proxy header (the client, per X-Forwarded-For convention), or undefined. */\nexport const firstHop = (headers: Headers | undefined, header: string): string | undefined => {\n\tconst first = headers?.get(header)?.split(',')[0]?.trim()\n\treturn first || undefined\n}\n"],"mappings":";;AACA,MAAa,YAAY,SAA8B,WAAuC;CAE7F,OADc,SAAS,IAAI,MAAM,GAAG,MAAM,GAAG,EAAE,IAAI,KAAK,KACxC,KAAA;AACjB"}
|
package/dist/spam/constants.js
CHANGED
|
@@ -7,9 +7,21 @@
|
|
|
7
7
|
const DEFAULT_HONEYPOT_FIELD = "website";
|
|
8
8
|
/** Reserved `values` entry carrying a captcha token from the client. */
|
|
9
9
|
const CAPTCHA_TOKEN_KEY = "__fb_captcha";
|
|
10
|
+
/**
|
|
11
|
+
* Reserved `values` entry carrying a signed form-context token (see `context/formContext.ts`). Rides
|
|
12
|
+
* alongside the answers like the captcha token, but is verified and stored separately: it is never an
|
|
13
|
+
* answer and must not appear in `values`, the answers view, or `{{*}}` body output.
|
|
14
|
+
*/
|
|
15
|
+
const CONTEXT_KEY = "__fb_ctx";
|
|
16
|
+
/**
|
|
17
|
+
* Reserved `values` entry the honeypot decoy is submitted under. The decoy's DOM input keeps a
|
|
18
|
+
* plausible cosmetic name (e.g. `website`), but the submitted value rides this fixed key so a real
|
|
19
|
+
* field sharing that name is never stripped or mistaken for the decoy.
|
|
20
|
+
*/
|
|
21
|
+
const HONEYPOT_VALUE_KEY = "__fb_hp";
|
|
10
22
|
/** `req.context` key under which the spam guard stashes the resolved identity for upload-ownership verification. */
|
|
11
23
|
const IDENTITY_CONTEXT_KEY = "formBuilderSpamIdentity";
|
|
12
24
|
//#endregion
|
|
13
|
-
export { CAPTCHA_TOKEN_KEY, DEFAULT_HONEYPOT_FIELD, IDENTITY_CONTEXT_KEY };
|
|
25
|
+
export { CAPTCHA_TOKEN_KEY, CONTEXT_KEY, DEFAULT_HONEYPOT_FIELD, HONEYPOT_VALUE_KEY, IDENTITY_CONTEXT_KEY };
|
|
14
26
|
|
|
15
27
|
//# sourceMappingURL=constants.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.js","names":[],"sources":["../../src/spam/constants.ts"],"sourcesContent":["/**\n * Default honeypot decoy field name. \"website\" is plausible to bots but doesn't trigger Chrome's\n * email-address autofill (unlike names containing \"email\"). Bots fill every input; real users\n * never see the hidden field.\n */\nexport const DEFAULT_HONEYPOT_FIELD = 'website'\n\n/** Reserved `values` entry carrying a captcha token from the client. */\nexport const CAPTCHA_TOKEN_KEY = '__fb_captcha'\n\n/** `req.context` key under which the spam guard stashes the resolved identity for upload-ownership verification. */\nexport const IDENTITY_CONTEXT_KEY = 'formBuilderSpamIdentity'\n"],"mappings":";;;;;;AAKA,MAAa,yBAAyB;;AAGtC,MAAa,oBAAoB;;
|
|
1
|
+
{"version":3,"file":"constants.js","names":[],"sources":["../../src/spam/constants.ts"],"sourcesContent":["/**\n * Default honeypot decoy field name. \"website\" is plausible to bots but doesn't trigger Chrome's\n * email-address autofill (unlike names containing \"email\"). Bots fill every input; real users\n * never see the hidden field.\n */\nexport const DEFAULT_HONEYPOT_FIELD = 'website'\n\n/** Reserved `values` entry carrying a captcha token from the client. */\nexport const CAPTCHA_TOKEN_KEY = '__fb_captcha'\n\n/**\n * Reserved `values` entry carrying a signed form-context token (see `context/formContext.ts`). Rides\n * alongside the answers like the captcha token, but is verified and stored separately: it is never an\n * answer and must not appear in `values`, the answers view, or `{{*}}` body output.\n */\nexport const CONTEXT_KEY = '__fb_ctx'\n\n/**\n * Reserved `values` entry the honeypot decoy is submitted under. The decoy's DOM input keeps a\n * plausible cosmetic name (e.g. `website`), but the submitted value rides this fixed key so a real\n * field sharing that name is never stripped or mistaken for the decoy.\n */\nexport const HONEYPOT_VALUE_KEY = '__fb_hp'\n\n/** `req.context` key under which the spam guard stashes the resolved identity for upload-ownership verification. */\nexport const IDENTITY_CONTEXT_KEY = 'formBuilderSpamIdentity'\n"],"mappings":";;;;;;AAKA,MAAa,yBAAyB;;AAGtC,MAAa,oBAAoB;;;;;;AAOjC,MAAa,cAAc;;;;;;AAO3B,MAAa,qBAAqB;;AAGlC,MAAa,uBAAuB"}
|
package/dist/spam/identify.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { firstHop } from "./clientIp.js";
|
|
1
2
|
//#region src/spam/identify.ts
|
|
2
3
|
/**
|
|
3
4
|
* Default identity resolution for rate-limiting + upload ownership. Prefers an authenticated user id
|
|
@@ -7,12 +8,8 @@
|
|
|
7
8
|
const defaultIdentify = (ipHeader) => (req) => {
|
|
8
9
|
const userId = req.user?.id;
|
|
9
10
|
if (userId != null) return `user:${String(userId)}`;
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
const first = header.split(",")[0]?.trim();
|
|
13
|
-
if (first) return `ip:${first}`;
|
|
14
|
-
}
|
|
15
|
-
return null;
|
|
11
|
+
const ip = firstHop(req.headers, ipHeader);
|
|
12
|
+
return ip ? `ip:${ip}` : null;
|
|
16
13
|
};
|
|
17
14
|
//#endregion
|
|
18
15
|
export { defaultIdentify };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"identify.js","names":[],"sources":["../../src/spam/identify.ts"],"sourcesContent":["import type { IdentifyFn } from './types'\n\n/**\n * Default identity resolution for rate-limiting + upload ownership. Prefers an authenticated user id\n * (trustworthy); else the first hop of the configured trusted IP header (best-effort, proxy-dependent);\n * else null, in which case the caller fails open (cannot fairly rate-limit an unidentifiable client).\n */\nexport const defaultIdentify =\n\t(ipHeader: string): IdentifyFn =>\n\t(req) => {\n\t\tconst userId = req.user?.id\n\t\tif (userId != null) {\n\t\t\treturn `user:${String(userId)}`\n\t\t}\n\t\tconst
|
|
1
|
+
{"version":3,"file":"identify.js","names":[],"sources":["../../src/spam/identify.ts"],"sourcesContent":["import { firstHop } from './clientIp'\nimport type { IdentifyFn } from './types'\n\n/**\n * Default identity resolution for rate-limiting + upload ownership. Prefers an authenticated user id\n * (trustworthy); else the first hop of the configured trusted IP header (best-effort, proxy-dependent);\n * else null, in which case the caller fails open (cannot fairly rate-limit an unidentifiable client).\n */\nexport const defaultIdentify =\n\t(ipHeader: string): IdentifyFn =>\n\t(req) => {\n\t\tconst userId = req.user?.id\n\t\tif (userId != null) {\n\t\t\treturn `user:${String(userId)}`\n\t\t}\n\t\tconst ip = firstHop(req.headers, ipHeader)\n\t\treturn ip ? `ip:${ip}` : null\n\t}\n"],"mappings":";;;;;;;AAQA,MAAa,mBACX,cACA,QAAQ;CACR,MAAM,SAAS,IAAI,MAAM;CACzB,IAAI,UAAU,MACb,OAAO,QAAQ,OAAO,MAAM;CAE7B,MAAM,KAAK,SAAS,IAAI,SAAS,QAAQ;CACzC,OAAO,KAAK,MAAM,OAAO;AAC1B"}
|