@10x-media/form-builder 0.1.0-beta.2 → 0.1.0-beta.21
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 +360 -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 +17 -5
- package/dist/actions/defineAction.js.map +1 -1
- package/dist/actions/dispatch.js +51 -6
- package/dist/actions/dispatch.js.map +1 -1
- package/dist/actions/dispatchContext.js +13 -0
- package/dist/actions/dispatchContext.js.map +1 -0
- 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 +5 -7
- 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 +47 -16
- 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 +114 -28
- 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 +46 -3
- package/dist/react/state.js +73 -10
- package/dist/react/state.js.map +1 -1
- package/dist/react/submitForm.js +1 -1
- package/dist/react/submitForm.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 +7 -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 +105 -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 +380 -0
- package/dist/translations/de.js.map +1 -0
- package/dist/translations/en.js +250 -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 +245 -23
- package/dist/translations/keys.js +246 -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
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"emailAction.js","names":[],"sources":["../../../src/actions/builtin/emailAction.ts"],"sourcesContent":["import type { Field, RichTextField } from 'payload'\nimport type { DepartmentEmailsResolver } from '../../email/departments'\nimport { localizedIf } from '../../fields/localizedIf'\nimport { interpolate } from '../../recall/interpolate'\nimport { keys } from '../../translations/keys'\nimport { labelFor } from '../../translations/server'\nimport { resolverFor } from '../body/serializeBody'\nimport { type ActionDefinition, defineAction } from '../defineAction'\nimport {\n\tbuildRecipientField,\n\ttype RecipientsConfig,\n\tresolveRecipientEntries,\n} from '../emailRecipients'\nimport {\n\tbuildFromField,\n\ttype FromAddressesResolver,\n\ttype FromAddressSourceRegistry,\n\tresolveSendFrom,\n} from '../fromAddresses'\nimport {\n\ttype RecipientResolveArgs,\n\ttype RecipientSource,\n\ttype RecipientSourceRegistry,\n\tsourcesByValue,\n} from '../recipientSources'\n\n/** The plugin-derived options every built-in email action is built from (was five positional args). */\nexport type EmailActionOptions = {\n\tlocalize: boolean\n\teditor?: RichTextField['editor']\n\tfromAddresses?: FromAddressesResolver\n\t/** Send-time-resolved senders offered in the from select (plugin option `email.fromSources`). */\n\tfromSources?: FromAddressSourceRegistry\n\tdepartments?: DepartmentEmailsResolver\n\trecipients?: RecipientsConfig\n\t/** Server-resolved recipient sources offered in every recipient list (plugin option `email.recipientSources`). */\n\trecipientSources?: RecipientSourceRegistry\n}\n\n/** The config fields shared by every built-in email action (each action adds its own `to` target). */\nexport type EmailActionConfig = {\n\tfrom?: string\n\tcc?: string[]\n\tbcc?: string[]\n\treplyTo?: string[]\n\tsubject?: string\n\tbody?: unknown\n}\n\n/** Builds a recipient-list field (`to`/`cc`/`bcc`/`replyTo`) with the shared width, endpoint, and options. */\ntype RecipientFieldBuilder = (name: string, labelKey: string) => Field\n\ntype Resolver = ReturnType<typeof resolverFor>\n\n/** What `resolveTo` needs to compute the primary target, including server-resolved sources. */\ntype ResolveToArgs<TConfig extends EmailActionConfig> = {\n\tconfig: TConfig\n\tresolve: Resolver\n\tsources: Map<string, RecipientSource>\n\tsourceArgs: RecipientResolveArgs\n}\n\n/** What distinguishes one email action from another: identity, its primary target, and how it resolves/guards that target. */\ntype EmailActionSpec<TConfig extends EmailActionConfig> = {\n\ttype: string\n\tlabel: string\n\t/** The first cell of the opening row (paired with `replyTo`): a recipient list, or an email-field select. */\n\ttarget: (recip: RecipientFieldBuilder) => Field\n\t/** Resolve the primary `to` to a comma-joined address string, or `''` when nothing resolves. */\n\tresolveTo: (args: ResolveToArgs<TConfig>) => Promise<string> | string\n\t/**\n\t * Whether the author configured any target at all. A configured target that resolves empty (e.g. a\n\t * source returned `[]`) is a normal skip; only a target the author never set is a misconfiguration.\n\t */\n\thasTarget: (config: TConfig) => boolean\n\t/** With no target authored, `emailTeam` treats it as a misconfiguration (`throw`), `confirmation` as a silent skip. */\n\tonMissingTo: 'throw' | 'skip'\n}\n\n/**\n * The shared skeleton of the built-in email actions (`emailTeam`, `confirmation`): an identical\n * config (a first row pairing the action's target with `replyTo`, an optional `from` select, a\n * cc/bcc row, a subject, and a rich text body, content and recipient fields carrying `localized`\n * when `localize`) and an identical send (interpolate the subject, render the body, resolve\n * cc/bcc/replyTo, and hand a single comma-joined string per list to `payload.sendEmail`). Only the\n * primary `to` target and its missing-value behavior differ, threaded through `spec`.\n */\nexport const buildEmailAction = <TConfig extends EmailActionConfig>(\n\toptions: EmailActionOptions,\n\tspec: EmailActionSpec<TConfig>\n): ActionDefinition<TConfig> => {\n\tconst {\n\t\tlocalize,\n\t\teditor,\n\t\tfromAddresses,\n\t\tfromSources,\n\t\tdepartments,\n\t\trecipients,\n\t\trecipientSources,\n\t} = options\n\tconst fromSourcesByValue = sourcesByValue(fromSources)\n\tconst endpoint = departments ? 'departments' : undefined\n\tconst recip: RecipientFieldBuilder = (name, labelKey) =>\n\t\tbuildRecipientField(name, labelKey, localize, {\n\t\t\tendpoint,\n\t\t\trecipients,\n\t\t\twidth: '50%',\n\t\t\tdepartments,\n\t\t\tsources: recipientSources,\n\t\t})\n\treturn defineAction<TConfig>({\n\t\ttype: spec.type,\n\t\tlabel: spec.label,\n\t\tconfig: [\n\t\t\t{\n\t\t\t\ttype: 'row',\n\t\t\t\tfields: [spec.target(recip), recip('replyTo', keys.actionConfigReplyTo)],\n\t\t\t},\n\t\t\t...(fromAddresses || fromSources ? [buildFromField(fromAddresses, fromSources)] : []),\n\t\t\t{\n\t\t\t\ttype: 'row',\n\t\t\t\tfields: [recip('cc', keys.actionConfigCc), recip('bcc', keys.actionConfigBcc)],\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: 'subject',\n\t\t\t\ttype: 'text',\n\t\t\t\tlabel: labelFor(keys.actionConfigSubject),\n\t\t\t\t...localizedIf(localize),\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: 'body',\n\t\t\t\ttype: 'richText',\n\t\t\t\tlabel: labelFor(keys.actionConfigBody),\n\t\t\t\tadmin: { description: labelFor(keys.actionConfigBodyDescription) },\n\t\t\t\t...localizedIf(localize),\n\t\t\t\t...(editor ? { editor } : {}),\n\t\t\t},\n\t\t],\n\t\trun: async (args) => {\n\t\t\tconst { config, values } = args\n\t\t\tconst resolve = resolverFor(values)\n\t\t\tconst sources = sourcesByValue(recipientSources)\n\t\t\tconst sourceArgs: RecipientResolveArgs = {\n\t\t\t\tcontext: args.context,\n\t\t\t\tvalues,\n\t\t\t\tdescriptors: args.descriptors,\n\t\t\t\tform: args.form,\n\t\t\t\tsubmissionId: args.submissionId,\n\t\t\t\tpayload: args.payload,\n\t\t\t\treq: args.req,\n\t\t\t\tlocale: args.locale,\n\t\t\t}\n\t\t\tconst to = await spec.resolveTo({ config, resolve, sources, sourceArgs })\n\t\t\tif (!to) {\n\t\t\t\t// Nothing to send to. A target the author never configured is a misconfiguration (emailTeam\n\t\t\t\t// throws); a configured target that resolved empty (e.g. a source returned []) is a normal skip.\n\t\t\t\tif (!spec.hasTarget(config) && spec.onMissingTo === 'throw') {\n\t\t\t\t\tthrow new Error(`${spec.type}: missing \"to\" address`)\n\t\t\t\t}\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif (typeof args.payload.sendEmail !== 'function') {\n\t\t\t\tthrow new Error(`${spec.type}: no email adapter configured`)\n\t\t\t}\n\n\t\t\tconst subject = interpolate(config.subject ?? '', resolve)\n\t\t\tconst html = await args.renderBody(config.body)\n\t\t\tconst cc = (await resolveRecipientEntries(config.cc, { resolve, sources, sourceArgs })).join(\n\t\t\t\t', '\n\t\t\t)\n\t\t\tconst bcc = (\n\t\t\t\tawait resolveRecipientEntries(config.bcc, { resolve, sources, sourceArgs })\n\t\t\t).join(', ')\n\t\t\tconst replyTo = (\n\t\t\t\tawait resolveRecipientEntries(config.replyTo, { resolve, sources, sourceArgs })\n\t\t\t).join(', ')\n\n\t\t\t// A literal `from` was validated at save time against `fromAddresses(req)`; not re-checked\n\t\t\t// here (the job's `req` may differ from the authoring admin's, and the config is\n\t\t\t// admin-authored, not visitor-controlled), so it is forwarded verbatim. A stored source\n\t\t\t// value instead resolves freshly on every send, so the sender follows the host (e.g. a\n\t\t\t// tenant that changed its address) rather than freezing at authoring time.\n\t\t\tconst from = await resolveSendFrom({\n\t\t\t\tconfigured: config.from,\n\t\t\t\tsources: fromSourcesByValue,\n\t\t\t\tsourceArgs,\n\t\t\t})\n\t\t\tawait args.payload.sendEmail({\n\t\t\t\tto,\n\t\t\t\tsubject,\n\t\t\t\thtml,\n\t\t\t\t...(from ? { from } : {}),\n\t\t\t\t...(cc ? { cc } : {}),\n\t\t\t\t...(bcc ? { bcc } : {}),\n\t\t\t\t...(replyTo ? { replyTo } : {}),\n\t\t\t})\n\t\t},\n\t})\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAuFA,MAAa,oBACZ,SACA,SAC+B;CAC/B,MAAM,EACL,UACA,QACA,eACA,aACA,aACA,YACA,qBACG;CACJ,MAAM,qBAAqB,eAAe,WAAW;CACrD,MAAM,WAAW,cAAc,gBAAgB,KAAA;CAC/C,MAAM,SAAgC,MAAM,aAC3C,oBAAoB,MAAM,UAAU,UAAU;EAC7C;EACA;EACA,OAAO;EACP;EACA,SAAS;CACV,CAAC;CACF,OAAO,aAAsB;EAC5B,MAAM,KAAK;EACX,OAAO,KAAK;EACZ,QAAQ;GACP;IACC,MAAM;IACN,QAAQ,CAAC,KAAK,OAAO,KAAK,GAAG,MAAM,WAAW,KAAK,mBAAmB,CAAC;GACxE;GACA,GAAI,iBAAiB,cAAc,CAAC,eAAe,eAAe,WAAW,CAAC,IAAI,CAAC;GACnF;IACC,MAAM;IACN,QAAQ,CAAC,MAAM,MAAM,KAAK,cAAc,GAAG,MAAM,OAAO,KAAK,eAAe,CAAC;GAC9E;GACA;IACC,MAAM;IACN,MAAM;IACN,OAAO,SAAS,KAAK,mBAAmB;IACxC,GAAG,YAAY,QAAQ;GACxB;GACA;IACC,MAAM;IACN,MAAM;IACN,OAAO,SAAS,KAAK,gBAAgB;IACrC,OAAO,EAAE,aAAa,SAAS,KAAK,2BAA2B,EAAE;IACjE,GAAG,YAAY,QAAQ;IACvB,GAAI,SAAS,EAAE,OAAO,IAAI,CAAC;GAC5B;EACD;EACA,KAAK,OAAO,SAAS;GACpB,MAAM,EAAE,QAAQ,WAAW;GAC3B,MAAM,UAAU,YAAY,MAAM;GAClC,MAAM,UAAU,eAAe,gBAAgB;GAC/C,MAAM,aAAmC;IACxC,SAAS,KAAK;IACd;IACA,aAAa,KAAK;IAClB,MAAM,KAAK;IACX,cAAc,KAAK;IACnB,SAAS,KAAK;IACd,KAAK,KAAK;IACV,QAAQ,KAAK;GACd;GACA,MAAM,KAAK,MAAM,KAAK,UAAU;IAAE;IAAQ;IAAS;IAAS;GAAW,CAAC;GACxE,IAAI,CAAC,IAAI;IAGR,IAAI,CAAC,KAAK,UAAU,MAAM,KAAK,KAAK,gBAAgB,SACnD,MAAM,IAAI,MAAM,GAAG,KAAK,KAAK,uBAAuB;IAErD;GACD;GACA,IAAI,OAAO,KAAK,QAAQ,cAAc,YACrC,MAAM,IAAI,MAAM,GAAG,KAAK,KAAK,8BAA8B;GAG5D,MAAM,UAAU,YAAY,OAAO,WAAW,IAAI,OAAO;GACzD,MAAM,OAAO,MAAM,KAAK,WAAW,OAAO,IAAI;GAC9C,MAAM,MAAM,MAAM,wBAAwB,OAAO,IAAI;IAAE;IAAS;IAAS;GAAW,CAAC,GAAG,KACvF,IACD;GACA,MAAM,OACL,MAAM,wBAAwB,OAAO,KAAK;IAAE;IAAS;IAAS;GAAW,CAAC,GACzE,KAAK,IAAI;GACX,MAAM,WACL,MAAM,wBAAwB,OAAO,SAAS;IAAE;IAAS;IAAS;GAAW,CAAC,GAC7E,KAAK,IAAI;GAOX,MAAM,OAAO,MAAM,gBAAgB;IAClC,YAAY,OAAO;IACnB,SAAS;IACT;GACD,CAAC;GACD,MAAM,KAAK,QAAQ,UAAU;IAC5B;IACA;IACA;IACA,GAAI,OAAO,EAAE,KAAK,IAAI,CAAC;IACvB,GAAI,KAAK,EAAE,GAAG,IAAI,CAAC;IACnB,GAAI,MAAM,EAAE,IAAI,IAAI,CAAC;IACrB,GAAI,UAAU,EAAE,QAAQ,IAAI,CAAC;GAC9B,CAAC;EACF;CACD,CAAC;AACF"}
|
|
@@ -1,46 +1,28 @@
|
|
|
1
|
-
import { interpolate } from "../../recall/interpolate.js";
|
|
2
1
|
import { keys } from "../../translations/keys.js";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
2
|
+
import { resolveRecipientEntries } from "../emailRecipients.js";
|
|
3
|
+
import { buildEmailAction } from "./emailAction.js";
|
|
5
4
|
//#region src/actions/builtin/emailTeam.ts
|
|
6
|
-
|
|
5
|
+
/**
|
|
6
|
+
* The `emailTeam` action: its target is a `to` recipient list (`RecipientsSelect`, `string[]`) of
|
|
7
|
+
* literal emails, picked department addresses, `{{field}}` tokens, or registered recipient sources,
|
|
8
|
+
* resolved at send. A `to` the author never configured is a misconfiguration and throws; a configured
|
|
9
|
+
* `to` that resolves empty (e.g. every source returned nothing) skips the send. Everything else
|
|
10
|
+
* (from/cc/bcc/replyTo, subject, body, localization) is the shared email-action skeleton.
|
|
11
|
+
*/
|
|
12
|
+
const buildEmailTeam = (options) => buildEmailAction(options, {
|
|
7
13
|
type: "emailTeam",
|
|
8
14
|
label: keys.actionEmailTeam,
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
type: "text",
|
|
18
|
-
label: labelFor(keys.actionConfigSubject)
|
|
19
|
-
},
|
|
20
|
-
{
|
|
21
|
-
name: "body",
|
|
22
|
-
type: "textarea",
|
|
23
|
-
label: labelFor(keys.actionConfigBody)
|
|
24
|
-
}
|
|
25
|
-
],
|
|
26
|
-
run: async (args) => {
|
|
27
|
-
const { config, values, payload } = args;
|
|
28
|
-
if (!config.to) throw new Error("emailTeam: missing \"to\" address");
|
|
29
|
-
if (typeof payload.sendEmail !== "function") throw new Error("emailTeam: no email adapter configured");
|
|
30
|
-
const resolve = (name) => {
|
|
31
|
-
const entry = values.find((v) => v.field === name);
|
|
32
|
-
return entry == null ? "" : String(entry.value ?? "");
|
|
33
|
-
};
|
|
34
|
-
const subject = interpolate(config.subject ?? "", resolve);
|
|
35
|
-
const html = interpolate(config.body ?? "", resolve);
|
|
36
|
-
await payload.sendEmail({
|
|
37
|
-
to: config.to,
|
|
38
|
-
subject,
|
|
39
|
-
html
|
|
40
|
-
});
|
|
41
|
-
}
|
|
15
|
+
target: (recip) => recip("to", keys.actionConfigTo),
|
|
16
|
+
resolveTo: async ({ config, resolve, sources, sourceArgs }) => (await resolveRecipientEntries(config.to, {
|
|
17
|
+
resolve,
|
|
18
|
+
sources,
|
|
19
|
+
sourceArgs
|
|
20
|
+
})).join(", "),
|
|
21
|
+
hasTarget: (config) => Array.isArray(config.to) ? config.to.length > 0 : Boolean(config.to),
|
|
22
|
+
onMissingTo: "throw"
|
|
42
23
|
});
|
|
24
|
+
buildEmailTeam({ localize: true });
|
|
43
25
|
//#endregion
|
|
44
|
-
export {
|
|
26
|
+
export { buildEmailTeam };
|
|
45
27
|
|
|
46
28
|
//# sourceMappingURL=emailTeam.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"emailTeam.js","names":[],"sources":["../../../src/actions/builtin/emailTeam.ts"],"sourcesContent":["import {
|
|
1
|
+
{"version":3,"file":"emailTeam.js","names":[],"sources":["../../../src/actions/builtin/emailTeam.ts"],"sourcesContent":["import { keys } from '../../translations/keys'\nimport { resolveRecipientEntries } from '../emailRecipients'\nimport { buildEmailAction, type EmailActionConfig, type EmailActionOptions } from './emailAction'\n\ntype EmailTeamConfig = EmailActionConfig & { to?: string[] }\n\n/**\n * The `emailTeam` action: its target is a `to` recipient list (`RecipientsSelect`, `string[]`) of\n * literal emails, picked department addresses, `{{field}}` tokens, or registered recipient sources,\n * resolved at send. A `to` the author never configured is a misconfiguration and throws; a configured\n * `to` that resolves empty (e.g. every source returned nothing) skips the send. Everything else\n * (from/cc/bcc/replyTo, subject, body, localization) is the shared email-action skeleton.\n */\nexport const buildEmailTeam = (options: EmailActionOptions) =>\n\tbuildEmailAction<EmailTeamConfig>(options, {\n\t\ttype: 'emailTeam',\n\t\tlabel: keys.actionEmailTeam,\n\t\ttarget: (recip) => recip('to', keys.actionConfigTo),\n\t\tresolveTo: async ({ config, resolve, sources, sourceArgs }) =>\n\t\t\t(await resolveRecipientEntries(config.to, { resolve, sources, sourceArgs })).join(', '),\n\t\thasTarget: (config) => (Array.isArray(config.to) ? config.to.length > 0 : Boolean(config.to)),\n\t\tonMissingTo: 'throw',\n\t})\n\nexport const emailTeam = buildEmailTeam({ localize: true })\n"],"mappings":";;;;;;;;;;;AAaA,MAAa,kBAAkB,YAC9B,iBAAkC,SAAS;CAC1C,MAAM;CACN,OAAO,KAAK;CACZ,SAAS,UAAU,MAAM,MAAM,KAAK,cAAc;CAClD,WAAW,OAAO,EAAE,QAAQ,SAAS,SAAS,kBAC5C,MAAM,wBAAwB,OAAO,IAAI;EAAE;EAAS;EAAS;CAAW,CAAC,GAAG,KAAK,IAAI;CACvF,YAAY,WAAY,MAAM,QAAQ,OAAO,EAAE,IAAI,OAAO,GAAG,SAAS,IAAI,QAAQ,OAAO,EAAE;CAC3F,aAAa;AACd,CAAC;AAEuB,eAAe,EAAE,UAAU,KAAK,CAAC"}
|
|
@@ -1,7 +1,22 @@
|
|
|
1
1
|
import { AnyActionDefinition } from "../defineAction.js";
|
|
2
|
+
import { EmailActionOptions } from "./emailAction.js";
|
|
2
3
|
|
|
3
4
|
//#region src/actions/builtin/index.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* Built-in action definitions with content-bearing config fields (email subjects and rich text
|
|
7
|
+
* bodies) carrying `localized: true` when `options.localize` is true. `options.editor`, when given,
|
|
8
|
+
* overrides the Lexical/richText editor on both action bodies (the plugin passes
|
|
9
|
+
* `richText.bodyEditor ?? richText.editor`). `options.fromAddresses` (the plugin's
|
|
10
|
+
* `email.fromAddresses` option) adds a `from` select to both email actions. `options.departments`
|
|
11
|
+
* (the plugin's `email.departments` option) turns the recipient selects into pickers over the host's
|
|
12
|
+
* resolved departments. `signedWebhook` has no content fields and is shared static.
|
|
13
|
+
*/
|
|
14
|
+
declare const buildDefaultActionDefinitions: (options: EmailActionOptions) => Record<string, AnyActionDefinition>;
|
|
15
|
+
/**
|
|
16
|
+
* Prebuilt with content localization on; with `localizeContent: false`, derive overrides from
|
|
17
|
+
* `buildDefaultActionDefinitions({ localize: false })` instead so a spread does not reintroduce `localized`.
|
|
18
|
+
*/
|
|
4
19
|
declare const defaultActionDefinitions: Record<string, AnyActionDefinition>;
|
|
5
20
|
//#endregion
|
|
6
|
-
export { defaultActionDefinitions };
|
|
21
|
+
export { buildDefaultActionDefinitions, defaultActionDefinitions };
|
|
7
22
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1,13 +1,27 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { buildConfirmation } from "./confirmation.js";
|
|
2
|
+
import { buildEmailTeam } from "./emailTeam.js";
|
|
3
3
|
import { signedWebhook } from "./signedWebhook.js";
|
|
4
4
|
//#region src/actions/builtin/index.ts
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
/**
|
|
6
|
+
* Built-in action definitions with content-bearing config fields (email subjects and rich text
|
|
7
|
+
* bodies) carrying `localized: true` when `options.localize` is true. `options.editor`, when given,
|
|
8
|
+
* overrides the Lexical/richText editor on both action bodies (the plugin passes
|
|
9
|
+
* `richText.bodyEditor ?? richText.editor`). `options.fromAddresses` (the plugin's
|
|
10
|
+
* `email.fromAddresses` option) adds a `from` select to both email actions. `options.departments`
|
|
11
|
+
* (the plugin's `email.departments` option) turns the recipient selects into pickers over the host's
|
|
12
|
+
* resolved departments. `signedWebhook` has no content fields and is shared static.
|
|
13
|
+
*/
|
|
14
|
+
const buildDefaultActionDefinitions = (options) => ({
|
|
15
|
+
emailTeam: buildEmailTeam(options),
|
|
16
|
+
confirmation: buildConfirmation(options),
|
|
8
17
|
signedWebhook
|
|
9
|
-
};
|
|
18
|
+
});
|
|
19
|
+
/**
|
|
20
|
+
* Prebuilt with content localization on; with `localizeContent: false`, derive overrides from
|
|
21
|
+
* `buildDefaultActionDefinitions({ localize: false })` instead so a spread does not reintroduce `localized`.
|
|
22
|
+
*/
|
|
23
|
+
const defaultActionDefinitions = buildDefaultActionDefinitions({ localize: true });
|
|
10
24
|
//#endregion
|
|
11
|
-
export { defaultActionDefinitions };
|
|
25
|
+
export { buildDefaultActionDefinitions, defaultActionDefinitions };
|
|
12
26
|
|
|
13
27
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../../src/actions/builtin/index.ts"],"sourcesContent":["import type { AnyActionDefinition } from '../defineAction'\nimport {
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../../src/actions/builtin/index.ts"],"sourcesContent":["import type { AnyActionDefinition } from '../defineAction'\nimport { buildConfirmation } from './confirmation'\nimport type { EmailActionOptions } from './emailAction'\nimport { buildEmailTeam } from './emailTeam'\nimport { signedWebhook } from './signedWebhook'\n\n/**\n * Built-in action definitions with content-bearing config fields (email subjects and rich text\n * bodies) carrying `localized: true` when `options.localize` is true. `options.editor`, when given,\n * overrides the Lexical/richText editor on both action bodies (the plugin passes\n * `richText.bodyEditor ?? richText.editor`). `options.fromAddresses` (the plugin's\n * `email.fromAddresses` option) adds a `from` select to both email actions. `options.departments`\n * (the plugin's `email.departments` option) turns the recipient selects into pickers over the host's\n * resolved departments. `signedWebhook` has no content fields and is shared static.\n */\nexport const buildDefaultActionDefinitions = (\n\toptions: EmailActionOptions\n): Record<string, AnyActionDefinition> => ({\n\temailTeam: buildEmailTeam(options) as AnyActionDefinition,\n\tconfirmation: buildConfirmation(options) as AnyActionDefinition,\n\tsignedWebhook: signedWebhook as AnyActionDefinition,\n})\n\n/**\n * Prebuilt with content localization on; with `localizeContent: false`, derive overrides from\n * `buildDefaultActionDefinitions({ localize: false })` instead so a spread does not reintroduce `localized`.\n */\nexport const defaultActionDefinitions: Record<string, AnyActionDefinition> =\n\tbuildDefaultActionDefinitions({ localize: true })\n"],"mappings":";;;;;;;;;;;;;AAeA,MAAa,iCACZ,aAC0C;CAC1C,WAAW,eAAe,OAAO;CACjC,cAAc,kBAAkB,OAAO;CACxB;AAChB;;;;;AAMA,MAAa,2BACZ,8BAA8B,EAAE,UAAU,KAAK,CAAC"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { keys } from "../../translations/keys.js";
|
|
2
2
|
import { labelFor } from "../../translations/server.js";
|
|
3
3
|
import { defineAction } from "../defineAction.js";
|
|
4
|
+
import { validateUrl } from "../../validation/validateUrl.js";
|
|
4
5
|
import { SIGNATURE_HEADER, signPayload } from "../sign.js";
|
|
5
6
|
//#region src/actions/builtin/signedWebhook.ts
|
|
6
7
|
const signedWebhook = defineAction({
|
|
@@ -9,11 +10,14 @@ const signedWebhook = defineAction({
|
|
|
9
10
|
config: [{
|
|
10
11
|
name: "url",
|
|
11
12
|
type: "text",
|
|
12
|
-
label: labelFor(keys.actionConfigUrl)
|
|
13
|
+
label: labelFor(keys.actionConfigUrl),
|
|
14
|
+
admin: { description: labelFor(keys.actionConfigUrlDescription) },
|
|
15
|
+
validate: validateUrl
|
|
13
16
|
}, {
|
|
14
17
|
name: "secret",
|
|
15
18
|
type: "text",
|
|
16
|
-
label: labelFor(keys.actionConfigSecret)
|
|
19
|
+
label: labelFor(keys.actionConfigSecret),
|
|
20
|
+
admin: { description: labelFor(keys.actionConfigSecretDescription) }
|
|
17
21
|
}],
|
|
18
22
|
run: async (args) => {
|
|
19
23
|
const { config, form, submissionId, values } = args;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"signedWebhook.js","names":[],"sources":["../../../src/actions/builtin/signedWebhook.ts"],"sourcesContent":["import { keys } from '../../translations/keys'\nimport { labelFor } from '../../translations/server'\nimport { defineAction } from '../defineAction'\nimport { SIGNATURE_HEADER, signPayload } from '../sign'\n\ntype SignedWebhookConfig = { url?: string; secret?: string }\n\nexport const signedWebhook = defineAction<SignedWebhookConfig>({\n\ttype: 'signedWebhook',\n\tlabel: keys.actionSignedWebhook,\n\tconfig: [\n\t\t{
|
|
1
|
+
{"version":3,"file":"signedWebhook.js","names":[],"sources":["../../../src/actions/builtin/signedWebhook.ts"],"sourcesContent":["import { keys } from '../../translations/keys'\nimport { labelFor } from '../../translations/server'\nimport { validateUrl } from '../../validation/validateUrl'\nimport { defineAction } from '../defineAction'\nimport { SIGNATURE_HEADER, signPayload } from '../sign'\n\nexport { validateUrl } from '../../validation/validateUrl'\n\ntype SignedWebhookConfig = { url?: string; secret?: string }\n\nexport const signedWebhook = defineAction<SignedWebhookConfig>({\n\ttype: 'signedWebhook',\n\tlabel: keys.actionSignedWebhook,\n\tconfig: [\n\t\t{\n\t\t\tname: 'url',\n\t\t\ttype: 'text',\n\t\t\tlabel: labelFor(keys.actionConfigUrl),\n\t\t\tadmin: { description: labelFor(keys.actionConfigUrlDescription) },\n\t\t\tvalidate: validateUrl,\n\t\t},\n\t\t{\n\t\t\tname: 'secret',\n\t\t\ttype: 'text',\n\t\t\tlabel: labelFor(keys.actionConfigSecret),\n\t\t\tadmin: { description: labelFor(keys.actionConfigSecretDescription) },\n\t\t},\n\t],\n\trun: async (args) => {\n\t\tconst { config, form, submissionId, values } = args\n\n\t\tif (!config.url) {\n\t\t\tthrow new Error('signedWebhook: missing \"url\"')\n\t\t}\n\t\tif (!config.secret) {\n\t\t\tthrow new Error('signedWebhook: missing \"secret\"')\n\t\t}\n\n\t\tconst body = JSON.stringify({ formId: form.id, submissionId, values })\n\t\tconst controller = new AbortController()\n\t\tconst timer = setTimeout(() => controller.abort(), 10_000)\n\n\t\tlet response: Response\n\t\ttry {\n\t\t\tresponse = await fetch(config.url, {\n\t\t\t\tmethod: 'POST',\n\t\t\t\theaders: {\n\t\t\t\t\t'Content-Type': 'application/json',\n\t\t\t\t\t[SIGNATURE_HEADER]: signPayload(body, config.secret),\n\t\t\t\t},\n\t\t\t\tbody,\n\t\t\t\tsignal: controller.signal,\n\t\t\t})\n\t\t} finally {\n\t\t\tclearTimeout(timer)\n\t\t}\n\n\t\tif (!response.ok) {\n\t\t\tthrow new Error(`signedWebhook: server responded ${response.status}`)\n\t\t}\n\t},\n})\n"],"mappings":";;;;;;AAUA,MAAa,gBAAgB,aAAkC;CAC9D,MAAM;CACN,OAAO,KAAK;CACZ,QAAQ,CACP;EACC,MAAM;EACN,MAAM;EACN,OAAO,SAAS,KAAK,eAAe;EACpC,OAAO,EAAE,aAAa,SAAS,KAAK,0BAA0B,EAAE;EAChE,UAAU;CACX,GACA;EACC,MAAM;EACN,MAAM;EACN,OAAO,SAAS,KAAK,kBAAkB;EACvC,OAAO,EAAE,aAAa,SAAS,KAAK,6BAA6B,EAAE;CACpE,CACD;CACA,KAAK,OAAO,SAAS;EACpB,MAAM,EAAE,QAAQ,MAAM,cAAc,WAAW;EAE/C,IAAI,CAAC,OAAO,KACX,MAAM,IAAI,MAAM,gCAA8B;EAE/C,IAAI,CAAC,OAAO,QACX,MAAM,IAAI,MAAM,mCAAiC;EAGlD,MAAM,OAAO,KAAK,UAAU;GAAE,QAAQ,KAAK;GAAI;GAAc;EAAO,CAAC;EACrE,MAAM,aAAa,IAAI,gBAAgB;EACvC,MAAM,QAAQ,iBAAiB,WAAW,MAAM,GAAG,GAAM;EAEzD,IAAI;EACJ,IAAI;GACH,WAAW,MAAM,MAAM,OAAO,KAAK;IAClC,QAAQ;IACR,SAAS;KACR,gBAAgB;MACf,mBAAmB,YAAY,MAAM,OAAO,MAAM;IACpD;IACA;IACA,QAAQ,WAAW;GACpB,CAAC;EACF,UAAU;GACT,aAAa,KAAK;EACnB;EAEA,IAAI,CAAC,SAAS,IACb,MAAM,IAAI,MAAM,mCAAmC,SAAS,QAAQ;CAEtE;AACD,CAAC"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { Translate } from "../fields/types.js";
|
|
2
1
|
import { SubmissionDescriptor, SubmissionValue } from "../submissions/types.js";
|
|
2
|
+
import { Translate } from "../fields/types.js";
|
|
3
|
+
import { FormContextReference } from "../context/formContext.js";
|
|
3
4
|
import { Field, Payload, PayloadRequest } from "payload";
|
|
4
5
|
|
|
5
6
|
//#region src/actions/defineAction.d.ts
|
|
@@ -11,21 +12,32 @@ type ActionRunArgs<TConfig extends Record<string, unknown> = Record<string, unkn
|
|
|
11
12
|
};
|
|
12
13
|
submissionId: number | string;
|
|
13
14
|
values: SubmissionValue[];
|
|
14
|
-
descriptors: SubmissionDescriptor[];
|
|
15
|
+
descriptors: SubmissionDescriptor[]; /** The verified form-context reference the submission was made through, or null when it had none. */
|
|
16
|
+
context: FormContextReference | null;
|
|
15
17
|
config: TConfig;
|
|
16
18
|
payload: Payload;
|
|
17
19
|
req?: PayloadRequest;
|
|
18
20
|
locale: string;
|
|
19
|
-
t: Translate;
|
|
21
|
+
t: Translate; /** Serialize a rich text (or legacy string) body config into channel-ready HTML. */
|
|
22
|
+
renderBody: (body: unknown) => Promise<string>;
|
|
20
23
|
};
|
|
21
24
|
/**
|
|
22
25
|
* A post-submit action type, authored once: `config` is the admin `Field[]` for authoring;
|
|
23
26
|
* `run` executes when a submission completes. Built-ins use this same primitive.
|
|
24
27
|
*/
|
|
25
28
|
type ActionDefinition<TConfig extends Record<string, unknown> = Record<string, unknown>> = {
|
|
26
|
-
type: string;
|
|
27
|
-
label: string
|
|
29
|
+
type: string; /** i18n-key or literal (resolved like a field label), or a per-locale record. */
|
|
30
|
+
label: string | Record<string, string>;
|
|
28
31
|
config?: Field[];
|
|
32
|
+
/**
|
|
33
|
+
* This action's failure is the submission's failure: it runs inline before the response (never
|
|
34
|
+
* queued, bounded by the dispatch deadline), a throw or timeout turns the submit into an error
|
|
35
|
+
* the visitor sees, the remaining actions are skipped, and the submission is kept even on a
|
|
36
|
+
* `persistSubmissions: false` form so what the visitor sent is never lost. For an action that
|
|
37
|
+
* IS the point of the submission (a signup provider that is the system of record); leave unset
|
|
38
|
+
* for notifications and other fire-and-forget work.
|
|
39
|
+
*/
|
|
40
|
+
essential?: boolean;
|
|
29
41
|
run: (args: ActionRunArgs<TConfig>) => Promise<void> | void;
|
|
30
42
|
};
|
|
31
43
|
/** Erased shape stored in the registry; config re-narrows per matched type at execution. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"defineAction.js","names":[],"sources":["../../src/actions/defineAction.ts"],"sourcesContent":["import type { Field, Payload, PayloadRequest } from 'payload'\nimport type { Translate } from '../fields/types'\nimport type { SubmissionDescriptor, SubmissionValue } from '../submissions/types'\n\n/** Context passed to an action's `run` when a submission completes. */\nexport type ActionRunArgs<TConfig extends Record<string, unknown> = Record<string, unknown>> = {\n\tform: { id: number | string; title?: string }\n\tsubmissionId: number | string\n\tvalues: SubmissionValue[]\n\tdescriptors: SubmissionDescriptor[]\n\tconfig: TConfig\n\tpayload: Payload\n\treq?: PayloadRequest\n\tlocale: string\n\tt: Translate\n}\n\n/**\n * A post-submit action type, authored once: `config` is the admin `Field[]` for authoring;\n * `run` executes when a submission completes. Built-ins use this same primitive.\n */\nexport type ActionDefinition<TConfig extends Record<string, unknown> = Record<string, unknown>> = {\n\ttype: string\n\tlabel: string
|
|
1
|
+
{"version":3,"file":"defineAction.js","names":[],"sources":["../../src/actions/defineAction.ts"],"sourcesContent":["import type { Field, Payload, PayloadRequest } from 'payload'\nimport type { FormContextReference } from '../context/formContext'\nimport type { Translate } from '../fields/types'\nimport type { SubmissionDescriptor, SubmissionValue } from '../submissions/types'\n\n/** Context passed to an action's `run` when a submission completes. */\nexport type ActionRunArgs<TConfig extends Record<string, unknown> = Record<string, unknown>> = {\n\tform: { id: number | string; title?: string }\n\tsubmissionId: number | string\n\tvalues: SubmissionValue[]\n\tdescriptors: SubmissionDescriptor[]\n\t/** The verified form-context reference the submission was made through, or null when it had none. */\n\tcontext: FormContextReference | null\n\tconfig: TConfig\n\tpayload: Payload\n\treq?: PayloadRequest\n\tlocale: string\n\tt: Translate\n\t/** Serialize a rich text (or legacy string) body config into channel-ready HTML. */\n\trenderBody: (body: unknown) => Promise<string>\n}\n\n/**\n * A post-submit action type, authored once: `config` is the admin `Field[]` for authoring;\n * `run` executes when a submission completes. Built-ins use this same primitive.\n */\nexport type ActionDefinition<TConfig extends Record<string, unknown> = Record<string, unknown>> = {\n\ttype: string\n\t/** i18n-key or literal (resolved like a field label), or a per-locale record. */\n\tlabel: string | Record<string, string>\n\tconfig?: Field[]\n\t/**\n\t * This action's failure is the submission's failure: it runs inline before the response (never\n\t * queued, bounded by the dispatch deadline), a throw or timeout turns the submit into an error\n\t * the visitor sees, the remaining actions are skipped, and the submission is kept even on a\n\t * `persistSubmissions: false` form so what the visitor sent is never lost. For an action that\n\t * IS the point of the submission (a signup provider that is the system of record); leave unset\n\t * for notifications and other fire-and-forget work.\n\t */\n\tessential?: boolean\n\trun: (args: ActionRunArgs<TConfig>) => Promise<void> | void\n}\n\n/** Erased shape stored in the registry; config re-narrows per matched type at execution. */\nexport type AnyActionDefinition = ActionDefinition<Record<string, unknown>>\n\nexport const defineAction = <TConfig extends Record<string, unknown> = Record<string, unknown>>(\n\tdefinition: ActionDefinition<TConfig>\n): ActionDefinition<TConfig> => definition\n"],"mappings":";AA8CA,MAAa,gBACZ,eAC+B"}
|
package/dist/actions/dispatch.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { isEssentialAction } from "./registry.js";
|
|
2
|
+
import { ESSENTIAL_ACTION_FAILED_CONTEXT_KEY } from "./dispatchContext.js";
|
|
1
3
|
import { ACTIONS_TASK_SLUG, runActionsForSubmission } from "./task.js";
|
|
2
4
|
const canQueue = (payload) => typeof payload.jobs?.queue === "function";
|
|
3
5
|
const deadline = (ms) => new Promise((resolve) => {
|
|
@@ -8,39 +10,82 @@ const deadline = (ms) => new Promise((resolve) => {
|
|
|
8
10
|
* action work. With no actions, returns immediately. When a job runner is present, enqueues the native
|
|
9
11
|
* `form-builder-actions` task and returns (action work happens out of band). Otherwise runs the actions
|
|
10
12
|
* inline but bounded by a deadline so a missing worker still delivers without hanging the request; any
|
|
11
|
-
* error is swallowed (logged via `payload.logger`). Never rejects
|
|
13
|
+
* error is swallowed (logged via `payload.logger`). Never rejects; the return reports whether an
|
|
14
|
+
* essential pass failed, so the caller can withhold success signals (the created event, the 201).
|
|
12
15
|
*/
|
|
13
16
|
const dispatchActions = async (args) => {
|
|
14
17
|
const { payload, registry, req, formId, submissionId } = args;
|
|
15
|
-
|
|
18
|
+
const actions = args.actions ?? [];
|
|
19
|
+
const hasEssential = actions.some((instance) => isEssentialAction(registry, instance));
|
|
20
|
+
if (hasEssential) {
|
|
21
|
+
const ms = args.deadlineMs ?? 5e3;
|
|
22
|
+
const work = runActionsForSubmission({
|
|
23
|
+
input: {
|
|
24
|
+
formId,
|
|
25
|
+
submissionId,
|
|
26
|
+
subset: "essential"
|
|
27
|
+
},
|
|
28
|
+
registry,
|
|
29
|
+
payload,
|
|
30
|
+
req,
|
|
31
|
+
richText: args.richText
|
|
32
|
+
}).then((results) => ({
|
|
33
|
+
timedOut: false,
|
|
34
|
+
failed: results.some((result) => !result.ok)
|
|
35
|
+
}), (error) => {
|
|
36
|
+
payload.logger?.error(`@10x-media/form-builder: essential action pass for submission ${String(submissionId)} threw: ${error instanceof Error ? error.message : String(error)}`);
|
|
37
|
+
return {
|
|
38
|
+
timedOut: false,
|
|
39
|
+
failed: true
|
|
40
|
+
};
|
|
41
|
+
});
|
|
42
|
+
const outcome = await Promise.race([work, deadline(ms).then(() => ({
|
|
43
|
+
timedOut: true,
|
|
44
|
+
failed: true
|
|
45
|
+
}))]);
|
|
46
|
+
if (outcome.failed) {
|
|
47
|
+
if (outcome.timedOut) payload.logger?.error(`@10x-media/form-builder: essential action pass for submission ${String(submissionId)} outlived its ${ms}ms deadline; treating the submission as failed (the work may still complete)`);
|
|
48
|
+
if (req) req.context = {
|
|
49
|
+
...req.context ?? {},
|
|
50
|
+
[ESSENTIAL_ACTION_FAILED_CONTEXT_KEY]: true
|
|
51
|
+
};
|
|
52
|
+
return { essentialFailed: true };
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
if ((hasEssential ? actions.filter((instance) => !isEssentialAction(registry, instance)) : actions).length === 0 && args.persistSubmissions !== false) return { essentialFailed: false };
|
|
56
|
+
const subset = hasEssential ? { subset: "rest" } : {};
|
|
16
57
|
if (args.hasRunner && canQueue(payload)) {
|
|
17
58
|
try {
|
|
18
59
|
await payload.jobs.queue({
|
|
19
60
|
task: ACTIONS_TASK_SLUG,
|
|
20
61
|
input: {
|
|
21
62
|
formId: String(formId),
|
|
22
|
-
submissionId: String(submissionId)
|
|
63
|
+
submissionId: String(submissionId),
|
|
64
|
+
...subset
|
|
23
65
|
},
|
|
24
66
|
req
|
|
25
67
|
});
|
|
26
68
|
} catch (error) {
|
|
27
69
|
payload.logger?.error(`@10x-media/form-builder: failed to enqueue actions for submission ${String(submissionId)}: ${error instanceof Error ? error.message : String(error)}`);
|
|
28
70
|
}
|
|
29
|
-
return;
|
|
71
|
+
return { essentialFailed: false };
|
|
30
72
|
}
|
|
31
73
|
const ms = args.deadlineMs ?? 5e3;
|
|
32
74
|
const work = runActionsForSubmission({
|
|
33
75
|
input: {
|
|
34
76
|
formId,
|
|
35
|
-
submissionId
|
|
77
|
+
submissionId,
|
|
78
|
+
...subset
|
|
36
79
|
},
|
|
37
80
|
registry,
|
|
38
81
|
payload,
|
|
39
|
-
req
|
|
82
|
+
req,
|
|
83
|
+
richText: args.richText
|
|
40
84
|
}).catch((error) => {
|
|
41
85
|
payload.logger?.error(`@10x-media/form-builder: inline action dispatch for submission ${String(submissionId)} threw: ${error instanceof Error ? error.message : String(error)}`);
|
|
42
86
|
});
|
|
43
87
|
await Promise.race([work, deadline(ms)]);
|
|
88
|
+
return { essentialFailed: false };
|
|
44
89
|
};
|
|
45
90
|
//#endregion
|
|
46
91
|
export { dispatchActions };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dispatch.js","names":[],"sources":["../../src/actions/dispatch.ts"],"sourcesContent":["import type { Payload, PayloadRequest } from 'payload'\nimport type { ActionRegistry } from './registry'\nimport type { ActionInstance } from './runActions'\nimport { ACTIONS_TASK_SLUG, runActionsForSubmission } from './task'\n\n/** Default cap on inline action work so a missing worker never hangs the submission response. */\nexport const INLINE_DISPATCH_DEADLINE_MS = 5_000\n\nexport type DispatchActionsArgs = {\n\tactions: ActionInstance[] | null | undefined\n\tformId: number | string\n\tsubmissionId: number | string\n\tregistry: ActionRegistry\n\tpayload: Payload\n\treq?: PayloadRequest\n\t/** Whether a job runner is likely present (queued path); otherwise the bounded-inline fallback runs. */\n\thasRunner: boolean\n\tdeadlineMs?: number\n}\n\nconst canQueue = (payload: Payload): boolean => typeof payload.jobs?.queue === 'function'\n\nconst deadline = (ms: number): Promise<void> =>\n\tnew Promise((resolve) => {\n\t\tconst timer = setTimeout(resolve, ms)\n\t\ttimer.unref?.()\n\t})\n\n/**\n * Dispatch a submission's post-submit actions without throwing and without blocking the response on slow\n * action work. With no actions, returns immediately. When a job runner is present, enqueues the native\n * `form-builder-actions` task and returns (action work happens out of band). Otherwise runs the actions\n * inline but bounded by a deadline so a missing worker still delivers without hanging the request; any\n * error is swallowed (logged via `payload.logger`). Never rejects.\n */\nexport const dispatchActions = async (
|
|
1
|
+
{"version":3,"file":"dispatch.js","names":[],"sources":["../../src/actions/dispatch.ts"],"sourcesContent":["import type { Payload, PayloadRequest } from 'payload'\nimport type { RichTextBodyOption } from './body/serializeBody'\nimport { ESSENTIAL_ACTION_FAILED_CONTEXT_KEY } from './dispatchContext'\nimport { type ActionRegistry, isEssentialAction } from './registry'\nimport type { ActionInstance } from './runActions'\nimport { ACTIONS_TASK_SLUG, runActionsForSubmission } from './task'\n\nexport { ESSENTIAL_ACTION_FAILED_CONTEXT_KEY }\n\n/** Default cap on inline action work so a missing worker never hangs the submission response. */\nexport const INLINE_DISPATCH_DEADLINE_MS = 5_000\n\nexport type DispatchActionsArgs = {\n\tactions: ActionInstance[] | null | undefined\n\tformId: number | string\n\tsubmissionId: number | string\n\tregistry: ActionRegistry\n\tpayload: Payload\n\treq?: PayloadRequest\n\t/** Whether a job runner is likely present (queued path); otherwise the bounded-inline fallback runs. */\n\thasRunner: boolean\n\t/** The owning form's `persistSubmissions`; when explicitly `false`, run the completion even with no actions so the row is pruned. */\n\tpersistSubmissions?: boolean\n\tdeadlineMs?: number\n\trichText?: RichTextBodyOption\n}\n\nconst canQueue = (payload: Payload): boolean => typeof payload.jobs?.queue === 'function'\n\nconst deadline = (ms: number): Promise<void> =>\n\tnew Promise((resolve) => {\n\t\tconst timer = setTimeout(resolve, ms)\n\t\ttimer.unref?.()\n\t})\n\n/**\n * Dispatch a submission's post-submit actions without throwing and without blocking the response on slow\n * action work. With no actions, returns immediately. When a job runner is present, enqueues the native\n * `form-builder-actions` task and returns (action work happens out of band). Otherwise runs the actions\n * inline but bounded by a deadline so a missing worker still delivers without hanging the request; any\n * error is swallowed (logged via `payload.logger`). Never rejects; the return reports whether an\n * essential pass failed, so the caller can withhold success signals (the created event, the 201).\n */\nexport const dispatchActions = async (\n\targs: DispatchActionsArgs\n): Promise<{ essentialFailed: boolean }> => {\n\tconst { payload, registry, req, formId, submissionId } = args\n\tconst actions = args.actions ?? []\n\tconst hasEssential = actions.some((instance) => isEssentialAction(registry, instance))\n\n\t// Essential actions run first, inline and awaited, never queued: their failure is the\n\t// submission's failure, which the submit endpoint turns into an error response via the context\n\t// flag. On failure the remaining actions are skipped and so is the pruning completion, so a\n\t// `persistSubmissions: false` form keeps the row: the provider never received it, and the\n\t// stored copy is the only record of what the visitor sent.\n\tif (hasEssential) {\n\t\tconst ms = args.deadlineMs ?? INLINE_DISPATCH_DEADLINE_MS\n\t\tconst work = runActionsForSubmission({\n\t\t\tinput: { formId, submissionId, subset: 'essential' },\n\t\t\tregistry,\n\t\t\tpayload,\n\t\t\treq,\n\t\t\trichText: args.richText,\n\t\t}).then(\n\t\t\t(results) => ({ timedOut: false, failed: results.some((result) => !result.ok) }),\n\t\t\t(error) => {\n\t\t\t\tpayload.logger?.error(\n\t\t\t\t\t`@10x-media/form-builder: essential action pass for submission ${String(submissionId)} threw: ${\n\t\t\t\t\t\terror instanceof Error ? error.message : String(error)\n\t\t\t\t\t}`\n\t\t\t\t)\n\t\t\t\treturn { timedOut: false, failed: true }\n\t\t\t}\n\t\t)\n\t\tconst outcome = await Promise.race([\n\t\t\twork,\n\t\t\tdeadline(ms).then(() => ({ timedOut: true, failed: true })),\n\t\t])\n\t\tif (outcome.failed) {\n\t\t\tif (outcome.timedOut) {\n\t\t\t\tpayload.logger?.error(\n\t\t\t\t\t`@10x-media/form-builder: essential action pass for submission ${String(submissionId)} outlived its ${ms}ms deadline; treating the submission as failed (the work may still complete)`\n\t\t\t\t)\n\t\t\t}\n\t\t\tif (req) {\n\t\t\t\treq.context = { ...(req.context ?? {}), [ESSENTIAL_ACTION_FAILED_CONTEXT_KEY]: true }\n\t\t\t}\n\t\t\treturn { essentialFailed: true }\n\t\t}\n\t}\n\n\t// Nothing to run and nothing to prune: skip. An action-less form that opted out of persistence still\n\t// runs the completion below, so `runActionsForSubmission` can delete the row out of band.\n\tconst rest = hasEssential\n\t\t? actions.filter((instance) => !isEssentialAction(registry, instance))\n\t\t: actions\n\tif (rest.length === 0 && args.persistSubmissions !== false) {\n\t\treturn { essentialFailed: false }\n\t}\n\n\t// With an essential pass already run, the closing pass covers only the rest (subset threading\n\t// keeps the queued task from re-running the essential actions).\n\tconst subset = hasEssential ? ({ subset: 'rest' } as const) : {}\n\n\tif (args.hasRunner && canQueue(payload)) {\n\t\ttry {\n\t\t\tawait payload.jobs.queue({\n\t\t\t\ttask: ACTIONS_TASK_SLUG,\n\t\t\t\tinput: { formId: String(formId), submissionId: String(submissionId), ...subset },\n\t\t\t\treq,\n\t\t\t})\n\t\t} catch (error) {\n\t\t\tpayload.logger?.error(\n\t\t\t\t`@10x-media/form-builder: failed to enqueue actions for submission ${String(submissionId)}: ${\n\t\t\t\t\terror instanceof Error ? error.message : String(error)\n\t\t\t\t}`\n\t\t\t)\n\t\t}\n\t\treturn { essentialFailed: false }\n\t}\n\n\tconst ms = args.deadlineMs ?? INLINE_DISPATCH_DEADLINE_MS\n\t// Guard the action arm itself (not just the race) so a rejection AFTER the deadline wins is never an unhandled rejection.\n\tconst work = runActionsForSubmission({\n\t\tinput: { formId, submissionId, ...subset },\n\t\tregistry,\n\t\tpayload,\n\t\treq,\n\t\trichText: args.richText,\n\t}).catch((error) => {\n\t\tpayload.logger?.error(\n\t\t\t`@10x-media/form-builder: inline action dispatch for submission ${String(submissionId)} threw: ${\n\t\t\t\terror instanceof Error ? error.message : String(error)\n\t\t\t}`\n\t\t)\n\t})\n\tawait Promise.race([work, deadline(ms)])\n\treturn { essentialFailed: false }\n}\n"],"mappings":";;;AA2BA,MAAM,YAAY,YAA8B,OAAO,QAAQ,MAAM,UAAU;AAE/E,MAAM,YAAY,OACjB,IAAI,SAAS,YAAY;CAExB,WADyB,SAAS,EAC9B,EAAE,QAAQ;AACf,CAAC;;;;;;;;;AAUF,MAAa,kBAAkB,OAC9B,SAC2C;CAC3C,MAAM,EAAE,SAAS,UAAU,KAAK,QAAQ,iBAAiB;CACzD,MAAM,UAAU,KAAK,WAAW,CAAC;CACjC,MAAM,eAAe,QAAQ,MAAM,aAAa,kBAAkB,UAAU,QAAQ,CAAC;CAOrF,IAAI,cAAc;EACjB,MAAM,KAAK,KAAK,cAAA;EAChB,MAAM,OAAO,wBAAwB;GACpC,OAAO;IAAE;IAAQ;IAAc,QAAQ;GAAY;GACnD;GACA;GACA;GACA,UAAU,KAAK;EAChB,CAAC,EAAE,MACD,aAAa;GAAE,UAAU;GAAO,QAAQ,QAAQ,MAAM,WAAW,CAAC,OAAO,EAAE;EAAE,KAC7E,UAAU;GACV,QAAQ,QAAQ,MACf,iEAAiE,OAAO,YAAY,EAAE,UACrF,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,GAEvD;GACA,OAAO;IAAE,UAAU;IAAO,QAAQ;GAAK;EACxC,CACD;EACA,MAAM,UAAU,MAAM,QAAQ,KAAK,CAClC,MACA,SAAS,EAAE,EAAE,YAAY;GAAE,UAAU;GAAM,QAAQ;EAAK,EAAE,CAC3D,CAAC;EACD,IAAI,QAAQ,QAAQ;GACnB,IAAI,QAAQ,UACX,QAAQ,QAAQ,MACf,iEAAiE,OAAO,YAAY,EAAE,gBAAgB,GAAG,6EAC1G;GAED,IAAI,KACH,IAAI,UAAU;IAAE,GAAI,IAAI,WAAW,CAAC;KAAK,sCAAsC;GAAK;GAErF,OAAO,EAAE,iBAAiB,KAAK;EAChC;CACD;CAOA,KAHa,eACV,QAAQ,QAAQ,aAAa,CAAC,kBAAkB,UAAU,QAAQ,CAAC,IACnE,SACM,WAAW,KAAK,KAAK,uBAAuB,OACpD,OAAO,EAAE,iBAAiB,MAAM;CAKjC,MAAM,SAAS,eAAgB,EAAE,QAAQ,OAAO,IAAc,CAAC;CAE/D,IAAI,KAAK,aAAa,SAAS,OAAO,GAAG;EACxC,IAAI;GACH,MAAM,QAAQ,KAAK,MAAM;IACxB,MAAM;IACN,OAAO;KAAE,QAAQ,OAAO,MAAM;KAAG,cAAc,OAAO,YAAY;KAAG,GAAG;IAAO;IAC/E;GACD,CAAC;EACF,SAAS,OAAO;GACf,QAAQ,QAAQ,MACf,qEAAqE,OAAO,YAAY,EAAE,IACzF,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,GAEvD;EACD;EACA,OAAO,EAAE,iBAAiB,MAAM;CACjC;CAEA,MAAM,KAAK,KAAK,cAAA;CAEhB,MAAM,OAAO,wBAAwB;EACpC,OAAO;GAAE;GAAQ;GAAc,GAAG;EAAO;EACzC;EACA;EACA;EACA,UAAU,KAAK;CAChB,CAAC,EAAE,OAAO,UAAU;EACnB,QAAQ,QAAQ,MACf,kEAAkE,OAAO,YAAY,EAAE,UACtF,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,GAEvD;CACD,CAAC;CACD,MAAM,QAAQ,KAAK,CAAC,MAAM,SAAS,EAAE,CAAC,CAAC;CACvC,OAAO,EAAE,iBAAiB,MAAM;AACjC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
//#region src/actions/dispatchContext.ts
|
|
2
|
+
/**
|
|
3
|
+
* `req.context` key the dispatcher sets to `true` when an essential action failed (or outlived its
|
|
4
|
+
* deadline) for the submission this request created. The submit endpoint reads it to turn the 201
|
|
5
|
+
* into an error response; the submission itself stays stored, prune included, so a failed handoff
|
|
6
|
+
* to a provider never deletes the only copy of what the visitor sent. A leaf module (no imports)
|
|
7
|
+
* because both the dispatcher and the submit endpoint need it across an import cycle.
|
|
8
|
+
*/
|
|
9
|
+
const ESSENTIAL_ACTION_FAILED_CONTEXT_KEY = "formBuilderEssentialActionFailed";
|
|
10
|
+
//#endregion
|
|
11
|
+
export { ESSENTIAL_ACTION_FAILED_CONTEXT_KEY };
|
|
12
|
+
|
|
13
|
+
//# sourceMappingURL=dispatchContext.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dispatchContext.js","names":[],"sources":["../../src/actions/dispatchContext.ts"],"sourcesContent":["/**\n * `req.context` key the dispatcher sets to `true` when an essential action failed (or outlived its\n * deadline) for the submission this request created. The submit endpoint reads it to turn the 201\n * into an error response; the submission itself stays stored, prune included, so a failed handoff\n * to a provider never deletes the only copy of what the visitor sent. A leaf module (no imports)\n * because both the dispatcher and the submit endpoint need it across an import cycle.\n */\nexport const ESSENTIAL_ACTION_FAILED_CONTEXT_KEY = 'formBuilderEssentialActionFailed'\n"],"mappings":";;;;;;;;AAOA,MAAa,sCAAsC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { PayloadRequest } from "payload";
|
|
2
|
+
|
|
3
|
+
//#region src/actions/emailRecipients.d.ts
|
|
4
|
+
/** Host-configurable behavior for the recipient fields (plugin option `email.recipients`). */
|
|
5
|
+
type RecipientsConfig = {
|
|
6
|
+
/** Allow free-typed emails (default true). */allowCustom?: boolean; /** Offer the form's own fields as recipient tokens (default true). */
|
|
7
|
+
fieldTokens?: boolean; /** Field types eligible as tokens (default `['email']`). */
|
|
8
|
+
tokenFieldTypes?: string[];
|
|
9
|
+
};
|
|
10
|
+
//#endregion
|
|
11
|
+
export { RecipientsConfig };
|
|
12
|
+
//# sourceMappingURL=emailRecipients.d.ts.map
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { fieldNames, fieldNamesOfType } from "../fields/fieldNamesOfType.js";
|
|
2
|
+
import { keys } from "../translations/keys.js";
|
|
3
|
+
import { asTranslate, labelFor } from "../translations/server.js";
|
|
4
|
+
import { localizedIf } from "../fields/localizedIf.js";
|
|
5
|
+
import { interpolate } from "../recall/interpolate.js";
|
|
6
|
+
//#region src/actions/emailRecipients.ts
|
|
7
|
+
const EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
8
|
+
const TOKEN_RE = /^\{\{\s*([\w.-]+)\s*\}\}$/;
|
|
9
|
+
/** A plausible email address (a permissive shape check, not full RFC validation). */
|
|
10
|
+
const isPlausibleEmail = (value) => EMAIL_RE.test(value.trim());
|
|
11
|
+
/** The field name inside a `{{name}}` recipient token, or undefined when the string is not a token. */
|
|
12
|
+
const parseFieldToken = (value) => {
|
|
13
|
+
const match = TOKEN_RE.exec(value.trim());
|
|
14
|
+
return match ? match[1] : void 0;
|
|
15
|
+
};
|
|
16
|
+
const toList = (value) => Array.isArray(value) ? value.filter((entry) => typeof entry === "string") : typeof value === "string" && value.length > 0 ? [value] : [];
|
|
17
|
+
/**
|
|
18
|
+
* The first plausible email in a resolved value, or empty. A recipient entry names a single address,
|
|
19
|
+
* so this drops anything past a separator or CR/LF that a `{{field}}` token might interpolate from
|
|
20
|
+
* visitor input, closing SMTP header injection and extra-recipient injection.
|
|
21
|
+
*/
|
|
22
|
+
const firstAddress = (value) => value.split(/[,;\n\r]+/).map((part) => part.trim()).find(isPlausibleEmail) ?? "";
|
|
23
|
+
/**
|
|
24
|
+
* Async recipient resolution for the email actions, extending `resolveRecipients` with server-resolved
|
|
25
|
+
* sources. A registered source value calls its `resolve` (each returned address reduced to one by
|
|
26
|
+
* `firstAddress`, so a source cannot inject headers or extra recipients either); a `{{token}}`/plain
|
|
27
|
+
* email resolves exactly as before. Returns a clean address list (`[]` when nothing resolves) so the
|
|
28
|
+
* caller can skip an empty send. A thrown resolver propagates, failing the action loudly rather than
|
|
29
|
+
* sending to a shortened list.
|
|
30
|
+
*/
|
|
31
|
+
const resolveRecipientEntries = async (value, opts) => {
|
|
32
|
+
const out = [];
|
|
33
|
+
for (const entry of toList(value)) {
|
|
34
|
+
const source = opts.sources?.get(entry);
|
|
35
|
+
if (source) {
|
|
36
|
+
const resolved = opts.sourceArgs ? await source.resolve(opts.sourceArgs) : [];
|
|
37
|
+
for (const address of resolved) {
|
|
38
|
+
const clean = firstAddress(address);
|
|
39
|
+
if (clean) out.push(clean);
|
|
40
|
+
}
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
const clean = firstAddress(interpolate(entry, opts.resolve));
|
|
44
|
+
if (clean) out.push(clean);
|
|
45
|
+
}
|
|
46
|
+
return out;
|
|
47
|
+
};
|
|
48
|
+
/**
|
|
49
|
+
* Field `validate` for a recipient list: unset is fine; otherwise every entry must be a valid email
|
|
50
|
+
* or a `{{field}}` token naming an existing field of an allowed token type. When `allowCustom` is
|
|
51
|
+
* false, a non-token entry must additionally be a member of the resolved options (`resolveAllowed`,
|
|
52
|
+
* e.g. the department addresses), matching the client constraint on the server. Fails closed if the
|
|
53
|
+
* options resolver throws (mirroring the `from` field). Reads the form's `fields` off `data`. Like
|
|
54
|
+
* `from`, Payload runs this on every save, so the resolver is consulted each save under
|
|
55
|
+
* `allowCustom: false`; `buildRecipientField` memoizes it per request so all recipient fields share one call.
|
|
56
|
+
*/
|
|
57
|
+
const validateRecipients = (opts) => async (value, { data, req }) => {
|
|
58
|
+
const list = toList(value);
|
|
59
|
+
if (list.length === 0) return true;
|
|
60
|
+
const fields = data && typeof data === "object" ? data.fields : void 0;
|
|
61
|
+
const { tokenFieldTypes, allowCustom, fieldTokens, resolveAllowed } = opts;
|
|
62
|
+
const allowedFields = new Set(tokenFieldTypes && tokenFieldTypes.length > 0 ? fieldNamesOfType(fields, tokenFieldTypes) : fieldNames(fields));
|
|
63
|
+
let allowedValues;
|
|
64
|
+
if (allowCustom === false) if (resolveAllowed) try {
|
|
65
|
+
allowedValues = await resolveAllowed(req);
|
|
66
|
+
} catch {
|
|
67
|
+
return asTranslate(req.t)(keys.validationRecipientOptionsUnavailable);
|
|
68
|
+
}
|
|
69
|
+
else allowedValues = /* @__PURE__ */ new Set();
|
|
70
|
+
for (const entry of list) {
|
|
71
|
+
if (opts.sourceValues?.has(entry)) continue;
|
|
72
|
+
const token = parseFieldToken(entry);
|
|
73
|
+
if (token) {
|
|
74
|
+
if (fieldTokens === false) return asTranslate(req.t)(keys.validationRecipientNotAllowed);
|
|
75
|
+
if (!allowedFields.has(token)) return asTranslate(req.t)(keys.validationRecipientUnknownField);
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
if (!isPlausibleEmail(entry)) return asTranslate(req.t)(keys.validationRecipientInvalid);
|
|
79
|
+
if (allowCustom === false && !allowedValues?.has(entry.trim().toLowerCase())) return asTranslate(req.t)(keys.validationRecipientNotAllowed);
|
|
80
|
+
}
|
|
81
|
+
return true;
|
|
82
|
+
};
|
|
83
|
+
const RECIPIENTS_FIELD_REF = "@10x-media/form-builder/client#RecipientsSelect";
|
|
84
|
+
const DEPARTMENT_ALLOWED_CACHE = "formBuilderDepartmentAllowedSet";
|
|
85
|
+
/**
|
|
86
|
+
* The department option values as a lowercased Set, memoized on `req.context` so every recipient
|
|
87
|
+
* field validated in one save shares a single `departments` call. Payload validates the fields
|
|
88
|
+
* concurrently, so the in-flight promise is cached synchronously (not the resolved value) to avoid a
|
|
89
|
+
* resolve-per-field race. Lowercased because email delivery ignores case, matching the client dedupe.
|
|
90
|
+
*/
|
|
91
|
+
const resolveDepartmentAllowed = (req, departments) => {
|
|
92
|
+
const cached = req.context?.[DEPARTMENT_ALLOWED_CACHE];
|
|
93
|
+
if (cached instanceof Promise) return cached;
|
|
94
|
+
const promise = Promise.resolve().then(() => departments({ req })).then((options) => new Set(options.map((option) => option.value.trim().toLowerCase())));
|
|
95
|
+
if (req.context) req.context[DEPARTMENT_ALLOWED_CACHE] = promise;
|
|
96
|
+
return promise;
|
|
97
|
+
};
|
|
98
|
+
/**
|
|
99
|
+
* A `text hasMany` field rendered by `RecipientsSelect`, used for every email address list. `endpoint`
|
|
100
|
+
* (when set) supplies preset options (e.g. the host's departments); `recipients` narrows the field's
|
|
101
|
+
* behavior; `width` sets `admin.width` so a pair can share a row; `departments` (when set) backs
|
|
102
|
+
* server-side `allowCustom: false` enforcement with the resolved option values.
|
|
103
|
+
*/
|
|
104
|
+
const buildRecipientField = (name, labelKey, localize, opts = {}) => {
|
|
105
|
+
const { departments } = opts;
|
|
106
|
+
const resolveAllowed = departments ? (req) => resolveDepartmentAllowed(req, departments) : void 0;
|
|
107
|
+
const sourceList = Object.values(opts.sources ?? {});
|
|
108
|
+
const sourceValues = sourceList.length > 0 ? new Set(sourceList.map((s) => s.value)) : void 0;
|
|
109
|
+
return {
|
|
110
|
+
name,
|
|
111
|
+
type: "text",
|
|
112
|
+
hasMany: true,
|
|
113
|
+
label: labelFor(labelKey),
|
|
114
|
+
validate: validateRecipients({
|
|
115
|
+
tokenFieldTypes: opts.recipients?.tokenFieldTypes ?? ["email"],
|
|
116
|
+
allowCustom: opts.recipients?.allowCustom,
|
|
117
|
+
fieldTokens: opts.recipients?.fieldTokens,
|
|
118
|
+
resolveAllowed,
|
|
119
|
+
sourceValues
|
|
120
|
+
}),
|
|
121
|
+
...localizedIf(localize),
|
|
122
|
+
admin: {
|
|
123
|
+
...opts.width ? { width: opts.width } : {},
|
|
124
|
+
components: { Field: {
|
|
125
|
+
path: RECIPIENTS_FIELD_REF,
|
|
126
|
+
clientProps: {
|
|
127
|
+
...opts.endpoint ? {
|
|
128
|
+
endpoint: opts.endpoint,
|
|
129
|
+
scope: "request"
|
|
130
|
+
} : {},
|
|
131
|
+
...opts.recipients?.allowCustom === false ? { allowCustom: false } : {},
|
|
132
|
+
...opts.recipients?.fieldTokens === false ? { fieldTokens: false } : {},
|
|
133
|
+
...opts.recipients?.tokenFieldTypes ? { tokenFieldTypes: opts.recipients.tokenFieldTypes } : {},
|
|
134
|
+
...sourceList.length > 0 ? { sources: sourceList.map((s) => ({
|
|
135
|
+
value: s.value,
|
|
136
|
+
label: s.label
|
|
137
|
+
})) } : {}
|
|
138
|
+
}
|
|
139
|
+
} }
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
};
|
|
143
|
+
//#endregion
|
|
144
|
+
export { buildRecipientField, firstAddress, isPlausibleEmail, resolveRecipientEntries };
|
|
145
|
+
|
|
146
|
+
//# sourceMappingURL=emailRecipients.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"emailRecipients.js","names":[],"sources":["../../src/actions/emailRecipients.ts"],"sourcesContent":["import type { PayloadRequest, TextField } from 'payload'\nimport type { DepartmentEmailsResolver } from '../email/departments'\nimport { fieldNames, fieldNamesOfType } from '../fields/fieldNamesOfType'\nimport { localizedIf } from '../fields/localizedIf'\nimport { interpolate } from '../recall/interpolate'\nimport { keys } from '../translations/keys'\nimport { asTranslate, labelFor } from '../translations/server'\nimport type {\n\tRecipientResolveArgs,\n\tRecipientSource,\n\tRecipientSourceRegistry,\n} from './recipientSources'\n\nconst EMAIL_RE = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/\nconst TOKEN_RE = /^\\{\\{\\s*([\\w.-]+)\\s*\\}\\}$/\n\n/** A plausible email address (a permissive shape check, not full RFC validation). */\nexport const isPlausibleEmail = (value: string): boolean => EMAIL_RE.test(value.trim())\n\n/** The field name inside a `{{name}}` recipient token, or undefined when the string is not a token. */\nexport const parseFieldToken = (value: string): string | undefined => {\n\tconst match = TOKEN_RE.exec(value.trim())\n\treturn match ? match[1] : undefined\n}\n\nexport const isFieldToken = (value: string): boolean => parseFieldToken(value) !== undefined\n\nconst toList = (value: unknown): string[] =>\n\tArray.isArray(value)\n\t\t? value.filter((entry): entry is string => typeof entry === 'string')\n\t\t: typeof value === 'string' && value.length > 0\n\t\t\t? [value]\n\t\t\t: []\n\n/**\n * The first plausible email in a resolved value, or empty. A recipient entry names a single address,\n * so this drops anything past a separator or CR/LF that a `{{field}}` token might interpolate from\n * visitor input, closing SMTP header injection and extra-recipient injection.\n */\nexport const firstAddress = (value: string): string =>\n\tvalue\n\t\t.split(/[,;\\n\\r]+/)\n\t\t.map((part) => part.trim())\n\t\t.find(isPlausibleEmail) ?? ''\n\n/**\n * Resolve a stored recipient value (a `string[]`, or a legacy single string) to the comma-separated\n * list `payload.sendEmail` accepts: each entry is interpolated (a `{{field}}` token resolves from the\n * submission, a plain email passes through), sanitized to a single address, empties dropped, joined.\n */\nexport const resolveRecipients = (value: unknown, resolve: (name: string) => string): string =>\n\ttoList(value)\n\t\t.map((entry) => firstAddress(interpolate(entry, resolve)))\n\t\t.filter((entry) => entry.length > 0)\n\t\t.join(', ')\n\n/**\n * Async recipient resolution for the email actions, extending `resolveRecipients` with server-resolved\n * sources. A registered source value calls its `resolve` (each returned address reduced to one by\n * `firstAddress`, so a source cannot inject headers or extra recipients either); a `{{token}}`/plain\n * email resolves exactly as before. Returns a clean address list (`[]` when nothing resolves) so the\n * caller can skip an empty send. A thrown resolver propagates, failing the action loudly rather than\n * sending to a shortened list.\n */\nexport const resolveRecipientEntries = async (\n\tvalue: unknown,\n\topts: {\n\t\tresolve: (name: string) => string\n\t\tsources?: Map<string, RecipientSource>\n\t\tsourceArgs?: RecipientResolveArgs\n\t}\n): Promise<string[]> => {\n\tconst out: string[] = []\n\tfor (const entry of toList(value)) {\n\t\tconst source = opts.sources?.get(entry)\n\t\tif (source) {\n\t\t\t// A source only resolves with the run-time args; there are none at authoring/validation time.\n\t\t\tconst resolved = opts.sourceArgs ? await source.resolve(opts.sourceArgs) : []\n\t\t\tfor (const address of resolved) {\n\t\t\t\tconst clean = firstAddress(address)\n\t\t\t\tif (clean) {\n\t\t\t\t\tout.push(clean)\n\t\t\t\t}\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\t\tconst clean = firstAddress(interpolate(entry, opts.resolve))\n\t\tif (clean) {\n\t\t\tout.push(clean)\n\t\t}\n\t}\n\treturn out\n}\n\n/**\n * Field `validate` for a recipient list: unset is fine; otherwise every entry must be a valid email\n * or a `{{field}}` token naming an existing field of an allowed token type. When `allowCustom` is\n * false, a non-token entry must additionally be a member of the resolved options (`resolveAllowed`,\n * e.g. the department addresses), matching the client constraint on the server. Fails closed if the\n * options resolver throws (mirroring the `from` field). Reads the form's `fields` off `data`. Like\n * `from`, Payload runs this on every save, so the resolver is consulted each save under\n * `allowCustom: false`; `buildRecipientField` memoizes it per request so all recipient fields share one call.\n */\nexport const validateRecipients =\n\t(opts: {\n\t\ttokenFieldTypes?: string[]\n\t\tallowCustom?: boolean\n\t\tfieldTokens?: boolean\n\t\tresolveAllowed?: (req: PayloadRequest) => Set<string> | Promise<Set<string>>\n\t\t/** Stored values of registered recipient sources; a member is a valid recipient by itself. */\n\t\tsourceValues?: Set<string>\n\t}) =>\n\tasync (\n\t\tvalue: unknown,\n\t\t{ data, req }: { data?: unknown; req: PayloadRequest }\n\t): Promise<string | true> => {\n\t\tconst list = toList(value)\n\t\tif (list.length === 0) {\n\t\t\treturn true\n\t\t}\n\t\tconst fields =\n\t\t\tdata && typeof data === 'object' ? (data as Record<string, unknown>).fields : undefined\n\t\tconst { tokenFieldTypes, allowCustom, fieldTokens, resolveAllowed } = opts\n\t\tconst allowedFields = new Set(\n\t\t\ttokenFieldTypes && tokenFieldTypes.length > 0\n\t\t\t\t? fieldNamesOfType(fields, tokenFieldTypes)\n\t\t\t\t: fieldNames(fields)\n\t\t)\n\t\t// Only resolve the membership set when it is actually enforced (allowCustom explicitly false),\n\t\t// so the default (free-typed) path pays no resolver cost. Compare case-insensitively, matching\n\t\t// the client's dedupe, since email delivery ignores case.\n\t\tlet allowedValues: Set<string> | undefined\n\t\tif (allowCustom === false) {\n\t\t\tif (resolveAllowed) {\n\t\t\t\ttry {\n\t\t\t\t\tallowedValues = await resolveAllowed(req)\n\t\t\t\t} catch {\n\t\t\t\t\treturn asTranslate(req.t)(keys.validationRecipientOptionsUnavailable)\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tallowedValues = new Set()\n\t\t\t}\n\t\t}\n\t\tfor (const entry of list) {\n\t\t\t// A registered source value is a valid recipient on its own: checked first, so a same-named form\n\t\t\t// field cannot shadow it and `allowCustom: false` cannot block it (it is not a custom address).\n\t\t\tif (opts.sourceValues?.has(entry)) {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tconst token = parseFieldToken(entry)\n\t\t\tif (token) {\n\t\t\t\t// `fieldTokens: false` disables recipient tokens; enforce it on the server, not just the client.\n\t\t\t\tif (fieldTokens === false) {\n\t\t\t\t\treturn asTranslate(req.t)(keys.validationRecipientNotAllowed)\n\t\t\t\t}\n\t\t\t\tif (!allowedFields.has(token)) {\n\t\t\t\t\treturn asTranslate(req.t)(keys.validationRecipientUnknownField)\n\t\t\t\t}\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif (!isPlausibleEmail(entry)) {\n\t\t\t\treturn asTranslate(req.t)(keys.validationRecipientInvalid)\n\t\t\t}\n\t\t\tif (allowCustom === false && !allowedValues?.has(entry.trim().toLowerCase())) {\n\t\t\t\treturn asTranslate(req.t)(keys.validationRecipientNotAllowed)\n\t\t\t}\n\t\t}\n\t\treturn true\n\t}\n\n/** Host-configurable behavior for the recipient fields (plugin option `email.recipients`). */\nexport type RecipientsConfig = {\n\t/** Allow free-typed emails (default true). */\n\tallowCustom?: boolean\n\t/** Offer the form's own fields as recipient tokens (default true). */\n\tfieldTokens?: boolean\n\t/** Field types eligible as tokens (default `['email']`). */\n\ttokenFieldTypes?: string[]\n}\n\nconst RECIPIENTS_FIELD_REF = '@10x-media/form-builder/client#RecipientsSelect'\n\nconst DEPARTMENT_ALLOWED_CACHE = 'formBuilderDepartmentAllowedSet'\n\n/**\n * The department option values as a lowercased Set, memoized on `req.context` so every recipient\n * field validated in one save shares a single `departments` call. Payload validates the fields\n * concurrently, so the in-flight promise is cached synchronously (not the resolved value) to avoid a\n * resolve-per-field race. Lowercased because email delivery ignores case, matching the client dedupe.\n */\nconst resolveDepartmentAllowed = (\n\treq: PayloadRequest,\n\tdepartments: DepartmentEmailsResolver\n): Promise<Set<string>> => {\n\tconst cached = req.context?.[DEPARTMENT_ALLOWED_CACHE]\n\tif (cached instanceof Promise) {\n\t\treturn cached as Promise<Set<string>>\n\t}\n\tconst promise = Promise.resolve()\n\t\t.then(() => departments({ req }))\n\t\t.then((options) => new Set(options.map((option) => option.value.trim().toLowerCase())))\n\tif (req.context) {\n\t\treq.context[DEPARTMENT_ALLOWED_CACHE] = promise\n\t}\n\treturn promise\n}\n\n/**\n * A `text hasMany` field rendered by `RecipientsSelect`, used for every email address list. `endpoint`\n * (when set) supplies preset options (e.g. the host's departments); `recipients` narrows the field's\n * behavior; `width` sets `admin.width` so a pair can share a row; `departments` (when set) backs\n * server-side `allowCustom: false` enforcement with the resolved option values.\n */\n// biome-ignore lint/complexity/useMaxParams: the field identity (name, label, localize) plus its grouped options is the minimal surface\nexport const buildRecipientField = (\n\tname: string,\n\tlabelKey: string,\n\tlocalize: boolean,\n\topts: {\n\t\tendpoint?: string\n\t\trecipients?: RecipientsConfig\n\t\twidth?: string\n\t\tdepartments?: DepartmentEmailsResolver\n\t\tsources?: RecipientSourceRegistry\n\t} = {}\n): TextField => {\n\tconst { departments } = opts\n\tconst resolveAllowed = departments\n\t\t? (req: PayloadRequest) => resolveDepartmentAllowed(req, departments)\n\t\t: undefined\n\tconst sourceList = Object.values(opts.sources ?? {})\n\tconst sourceValues = sourceList.length > 0 ? new Set(sourceList.map((s) => s.value)) : undefined\n\treturn {\n\t\tname,\n\t\ttype: 'text',\n\t\thasMany: true,\n\t\tlabel: labelFor(labelKey),\n\t\tvalidate: validateRecipients({\n\t\t\ttokenFieldTypes: opts.recipients?.tokenFieldTypes ?? ['email'],\n\t\t\tallowCustom: opts.recipients?.allowCustom,\n\t\t\tfieldTokens: opts.recipients?.fieldTokens,\n\t\t\tresolveAllowed,\n\t\t\tsourceValues,\n\t\t}),\n\t\t...localizedIf(localize),\n\t\tadmin: {\n\t\t\t...(opts.width ? { width: opts.width } : {}),\n\t\t\tcomponents: {\n\t\t\t\tField: {\n\t\t\t\t\tpath: RECIPIENTS_FIELD_REF,\n\t\t\t\t\tclientProps: {\n\t\t\t\t\t\t// The departments option set is request-scoped, so it loads before the first save.\n\t\t\t\t\t\t...(opts.endpoint ? { endpoint: opts.endpoint, scope: 'request' } : {}),\n\t\t\t\t\t\t...(opts.recipients?.allowCustom === false ? { allowCustom: false } : {}),\n\t\t\t\t\t\t...(opts.recipients?.fieldTokens === false ? { fieldTokens: false } : {}),\n\t\t\t\t\t\t...(opts.recipients?.tokenFieldTypes\n\t\t\t\t\t\t\t? { tokenFieldTypes: opts.recipients.tokenFieldTypes }\n\t\t\t\t\t\t\t: {}),\n\t\t\t\t\t\t...(sourceList.length > 0\n\t\t\t\t\t\t\t? { sources: sourceList.map((s) => ({ value: s.value, label: s.label })) }\n\t\t\t\t\t\t\t: {}),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n}\n"],"mappings":";;;;;;AAaA,MAAM,WAAW;AACjB,MAAM,WAAW;;AAGjB,MAAa,oBAAoB,UAA2B,SAAS,KAAK,MAAM,KAAK,CAAC;;AAGtF,MAAa,mBAAmB,UAAsC;CACrE,MAAM,QAAQ,SAAS,KAAK,MAAM,KAAK,CAAC;CACxC,OAAO,QAAQ,MAAM,KAAK,KAAA;AAC3B;AAIA,MAAM,UAAU,UACf,MAAM,QAAQ,KAAK,IAChB,MAAM,QAAQ,UAA2B,OAAO,UAAU,QAAQ,IAClE,OAAO,UAAU,YAAY,MAAM,SAAS,IAC3C,CAAC,KAAK,IACN,CAAC;;;;;;AAON,MAAa,gBAAgB,UAC5B,MACE,MAAM,WAAW,EACjB,KAAK,SAAS,KAAK,KAAK,CAAC,EACzB,KAAK,gBAAgB,KAAK;;;;;;;;;AAqB7B,MAAa,0BAA0B,OACtC,OACA,SAKuB;CACvB,MAAM,MAAgB,CAAC;CACvB,KAAK,MAAM,SAAS,OAAO,KAAK,GAAG;EAClC,MAAM,SAAS,KAAK,SAAS,IAAI,KAAK;EACtC,IAAI,QAAQ;GAEX,MAAM,WAAW,KAAK,aAAa,MAAM,OAAO,QAAQ,KAAK,UAAU,IAAI,CAAC;GAC5E,KAAK,MAAM,WAAW,UAAU;IAC/B,MAAM,QAAQ,aAAa,OAAO;IAClC,IAAI,OACH,IAAI,KAAK,KAAK;GAEhB;GACA;EACD;EACA,MAAM,QAAQ,aAAa,YAAY,OAAO,KAAK,OAAO,CAAC;EAC3D,IAAI,OACH,IAAI,KAAK,KAAK;CAEhB;CACA,OAAO;AACR;;;;;;;;;;AAWA,MAAa,sBACX,SAQD,OACC,OACA,EAAE,MAAM,UACoB;CAC5B,MAAM,OAAO,OAAO,KAAK;CACzB,IAAI,KAAK,WAAW,GACnB,OAAO;CAER,MAAM,SACL,QAAQ,OAAO,SAAS,WAAY,KAAiC,SAAS,KAAA;CAC/E,MAAM,EAAE,iBAAiB,aAAa,aAAa,mBAAmB;CACtE,MAAM,gBAAgB,IAAI,IACzB,mBAAmB,gBAAgB,SAAS,IACzC,iBAAiB,QAAQ,eAAe,IACxC,WAAW,MAAM,CACrB;CAIA,IAAI;CACJ,IAAI,gBAAgB,OACnB,IAAI,gBACH,IAAI;EACH,gBAAgB,MAAM,eAAe,GAAG;CACzC,QAAQ;EACP,OAAO,YAAY,IAAI,CAAC,EAAE,KAAK,qCAAqC;CACrE;MAEA,gCAAgB,IAAI,IAAI;CAG1B,KAAK,MAAM,SAAS,MAAM;EAGzB,IAAI,KAAK,cAAc,IAAI,KAAK,GAC/B;EAED,MAAM,QAAQ,gBAAgB,KAAK;EACnC,IAAI,OAAO;GAEV,IAAI,gBAAgB,OACnB,OAAO,YAAY,IAAI,CAAC,EAAE,KAAK,6BAA6B;GAE7D,IAAI,CAAC,cAAc,IAAI,KAAK,GAC3B,OAAO,YAAY,IAAI,CAAC,EAAE,KAAK,+BAA+B;GAE/D;EACD;EACA,IAAI,CAAC,iBAAiB,KAAK,GAC1B,OAAO,YAAY,IAAI,CAAC,EAAE,KAAK,0BAA0B;EAE1D,IAAI,gBAAgB,SAAS,CAAC,eAAe,IAAI,MAAM,KAAK,EAAE,YAAY,CAAC,GAC1E,OAAO,YAAY,IAAI,CAAC,EAAE,KAAK,6BAA6B;CAE9D;CACA,OAAO;AACR;AAYD,MAAM,uBAAuB;AAE7B,MAAM,2BAA2B;;;;;;;AAQjC,MAAM,4BACL,KACA,gBAC0B;CAC1B,MAAM,SAAS,IAAI,UAAU;CAC7B,IAAI,kBAAkB,SACrB,OAAO;CAER,MAAM,UAAU,QAAQ,QAAQ,EAC9B,WAAW,YAAY,EAAE,IAAI,CAAC,CAAC,EAC/B,MAAM,YAAY,IAAI,IAAI,QAAQ,KAAK,WAAW,OAAO,MAAM,KAAK,EAAE,YAAY,CAAC,CAAC,CAAC;CACvF,IAAI,IAAI,SACP,IAAI,QAAQ,4BAA4B;CAEzC,OAAO;AACR;;;;;;;AASA,MAAa,uBACZ,MACA,UACA,UACA,OAMI,CAAC,MACU;CACf,MAAM,EAAE,gBAAgB;CACxB,MAAM,iBAAiB,eACnB,QAAwB,yBAAyB,KAAK,WAAW,IAClE,KAAA;CACH,MAAM,aAAa,OAAO,OAAO,KAAK,WAAW,CAAC,CAAC;CACnD,MAAM,eAAe,WAAW,SAAS,IAAI,IAAI,IAAI,WAAW,KAAK,MAAM,EAAE,KAAK,CAAC,IAAI,KAAA;CACvF,OAAO;EACN;EACA,MAAM;EACN,SAAS;EACT,OAAO,SAAS,QAAQ;EACxB,UAAU,mBAAmB;GAC5B,iBAAiB,KAAK,YAAY,mBAAmB,CAAC,OAAO;GAC7D,aAAa,KAAK,YAAY;GAC9B,aAAa,KAAK,YAAY;GAC9B;GACA;EACD,CAAC;EACD,GAAG,YAAY,QAAQ;EACvB,OAAO;GACN,GAAI,KAAK,QAAQ,EAAE,OAAO,KAAK,MAAM,IAAI,CAAC;GAC1C,YAAY,EACX,OAAO;IACN,MAAM;IACN,aAAa;KAEZ,GAAI,KAAK,WAAW;MAAE,UAAU,KAAK;MAAU,OAAO;KAAU,IAAI,CAAC;KACrE,GAAI,KAAK,YAAY,gBAAgB,QAAQ,EAAE,aAAa,MAAM,IAAI,CAAC;KACvE,GAAI,KAAK,YAAY,gBAAgB,QAAQ,EAAE,aAAa,MAAM,IAAI,CAAC;KACvE,GAAI,KAAK,YAAY,kBAClB,EAAE,iBAAiB,KAAK,WAAW,gBAAgB,IACnD,CAAC;KACJ,GAAI,WAAW,SAAS,IACrB,EAAE,SAAS,WAAW,KAAK,OAAO;MAAE,OAAO,EAAE;MAAO,OAAO,EAAE;KAAM,EAAE,EAAE,IACvE,CAAC;IACL;GACD,EACD;EACD;CACD;AACD"}
|