@teleporthq/teleport-plugin-next-workflows 0.44.11 → 0.45.0
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/__tests__/_helpers/fake-fetch.ts +75 -0
- package/__tests__/_helpers/gui-place-order-statements.ts +17 -0
- package/__tests__/_helpers/inserted-lines.ts +22 -0
- package/__tests__/_helpers/invoice-store.ts +10 -1
- package/__tests__/_helpers/load-security-runtime.ts +45 -0
- package/__tests__/_helpers/load-server-runtime.ts +26 -3
- package/__tests__/_helpers/run-account-delete-route.ts +3 -1
- package/__tests__/_helpers/run-generated-middleware.ts +7 -2
- package/__tests__/account-delete-owned-rows.test.ts +3 -1
- package/__tests__/adopted-element-trigger-code.test.ts +128 -0
- package/__tests__/analytics-track-outcome.test.ts +145 -0
- package/__tests__/auth-password-change-ends-sessions.test.ts +8 -1
- package/__tests__/auth-password-security.test.ts +2275 -0
- package/__tests__/auth-session-cost.test.ts +31 -0
- package/__tests__/auth-signup-route.test.ts +960 -0
- package/__tests__/authored-code-every-path.test.ts +247 -0
- package/__tests__/automations-bus.test.ts +3820 -0
- package/__tests__/automations-catalog-drift.test.ts +97 -0
- package/__tests__/booking-calendar-feed-route.test.ts +20 -3
- package/__tests__/cart-price-order.test.ts +336 -1
- package/__tests__/code-lookup-rate-limit-route.test.ts +189 -0
- package/__tests__/cost-bearing-node-types.test.ts +119 -0
- package/__tests__/credential-columns-reply.test.ts +9 -0
- package/__tests__/credential-result-reply.test.ts +19 -5
- package/__tests__/cron-route-loop-templateparams.test.ts +6 -3
- package/__tests__/custom-js-authored-code.test.ts +304 -0
- package/__tests__/custom-node-custom-code-gate.test.ts +136 -0
- package/__tests__/custom-node-step-handlers.test.ts +251 -0
- package/__tests__/custom-node-step-reach.test.ts +63 -0
- package/__tests__/data-api-anon-user-id-fallback.test.ts +7 -2
- package/__tests__/data-api-browser-reads.test.ts +7 -0
- package/__tests__/data-api-business-events.test.ts +403 -0
- package/__tests__/data-api-invalid-body.test.ts +7 -0
- package/__tests__/data-api-low-stock-autofire.test.ts +30 -4
- package/__tests__/data-api-optional-feature-columns.test.ts +44 -0
- package/__tests__/data-api-owner-scope-credentials.test.ts +1324 -0
- package/__tests__/data-api-protected-tables.test.ts +48 -15
- package/__tests__/data-api-retired-table-and-account-fields.test.ts +208 -0
- package/__tests__/email-locale-senders.test.ts +5 -3
- package/__tests__/expression-injection.test.ts +343 -0
- package/__tests__/fixtures/admin-file-workflows.json +242 -0
- package/__tests__/form-confirmation-email-template.test.ts +44 -0
- package/__tests__/internal-request-headers.test.ts +25 -0
- package/__tests__/invoice-pdf-service-project-header.test.ts +120 -0
- package/__tests__/invoice-self-call-origin.test.ts +57 -1
- package/__tests__/legacy-webhook-self-calls.test.ts +86 -1
- package/__tests__/middleware-home-route-protection.test.ts +3 -1
- package/__tests__/middleware-subscriber-access.test.ts +1 -1
- package/__tests__/newsletter-admin-route.test.ts +649 -0
- package/__tests__/newsletter-plugin.test.ts +1248 -0
- package/__tests__/outbound-nodes-security.test.ts +1929 -0
- package/__tests__/page-access-guard.test.ts +217 -0
- package/__tests__/page-access-route-table.test.ts +231 -0
- package/__tests__/payment-drivers-module.test.ts +23 -0
- package/__tests__/payment-legacy-webhook-routes.test.ts +100 -5
- package/__tests__/payment-webhook-route.test.ts +4 -1
- package/__tests__/paypal-webhook-signature-verification.test.ts +44 -0
- package/__tests__/place-order-guards.test.ts +506 -0
- package/__tests__/public-step-guards.test.ts +310 -0
- package/__tests__/publish-refusals.test.ts +505 -0
- package/__tests__/realtime-identity-routes.test.ts +492 -0
- package/__tests__/record-event-writer-server-only.test.ts +975 -0
- package/__tests__/resolve-config-template-params.test.ts +3 -3
- package/__tests__/runtime-storage-upload-access.test.ts +280 -17
- package/__tests__/security-integration-env-names.test.ts +74 -0
- package/__tests__/security-lists-parity.test.ts +245 -0
- package/__tests__/security-runtime-shadow.test.ts +224 -1
- package/__tests__/security-runtime.test.ts +893 -0
- package/__tests__/segment-rate-limit-error-branch.test.ts +284 -0
- package/__tests__/segment-route-abuse-gate.test.ts +309 -0
- package/__tests__/server-job-hops-real-data-api.test.ts +669 -0
- package/__tests__/server-session-identity.test.ts +522 -0
- package/__tests__/server-step-chain.test.ts +222 -0
- package/__tests__/server-step-signing.test.ts +107 -2
- package/__tests__/session-cookie-resolver.test.ts +62 -106
- package/__tests__/signup-event.test.ts +649 -0
- package/__tests__/signup-reply-identical.test.ts +144 -0
- package/__tests__/slack-message-escaping.test.ts +123 -0
- package/__tests__/visitor-step-limits.test.ts +318 -0
- package/__tests__/webhook-delivery-lease.test.ts +4 -1
- package/__tests__/webpack-safe-handlers.test.ts +57 -8
- package/__tests__/workflow-auth-guard.test.ts +9 -1
- package/dist/cjs/account-delete-route-generator.d.ts +1 -0
- package/dist/cjs/account-delete-route-generator.d.ts.map +1 -1
- package/dist/cjs/account-delete-route-generator.js +18 -3
- package/dist/cjs/account-delete-route-generator.js.map +1 -1
- package/dist/cjs/api-route-generator.d.ts +52 -3
- package/dist/cjs/api-route-generator.d.ts.map +1 -1
- package/dist/cjs/api-route-generator.js +600 -145
- package/dist/cjs/api-route-generator.js.map +1 -1
- package/dist/cjs/auth-generator.d.ts +126 -3
- package/dist/cjs/auth-generator.d.ts.map +1 -1
- package/dist/cjs/auth-generator.js +1353 -139
- package/dist/cjs/auth-generator.js.map +1 -1
- package/dist/cjs/automations/activity-kicks.d.ts +12 -0
- package/dist/cjs/automations/activity-kicks.d.ts.map +1 -0
- package/dist/cjs/automations/activity-kicks.js +123 -0
- package/dist/cjs/automations/activity-kicks.js.map +1 -0
- package/dist/cjs/automations/app-events-source.d.ts +33 -0
- package/dist/cjs/automations/app-events-source.d.ts.map +1 -0
- package/dist/cjs/automations/app-events-source.js +109 -0
- package/dist/cjs/automations/app-events-source.js.map +1 -0
- package/dist/cjs/automations/automations-project-plugin.d.ts +21 -0
- package/dist/cjs/automations/automations-project-plugin.d.ts.map +1 -0
- package/dist/cjs/automations/automations-project-plugin.js +102 -0
- package/dist/cjs/automations/automations-project-plugin.js.map +1 -0
- package/dist/cjs/automations/automations-scope.d.ts +104 -0
- package/dist/cjs/automations/automations-scope.d.ts.map +1 -0
- package/dist/cjs/automations/automations-scope.js +176 -0
- package/dist/cjs/automations/automations-scope.js.map +1 -0
- package/dist/cjs/automations/dispatcher-source.d.ts +72 -0
- package/dist/cjs/automations/dispatcher-source.d.ts.map +1 -0
- package/dist/cjs/automations/dispatcher-source.js +1008 -0
- package/dist/cjs/automations/dispatcher-source.js.map +1 -0
- package/dist/cjs/automations/event-bus-source.d.ts +44 -0
- package/dist/cjs/automations/event-bus-source.d.ts.map +1 -0
- package/dist/cjs/automations/event-bus-source.js +427 -0
- package/dist/cjs/automations/event-bus-source.js.map +1 -0
- package/dist/cjs/automations/handler-module-generator.d.ts +25 -0
- package/dist/cjs/automations/handler-module-generator.d.ts.map +1 -0
- package/dist/cjs/automations/handler-module-generator.js +78 -0
- package/dist/cjs/automations/handler-module-generator.js.map +1 -0
- package/dist/cjs/automations/hydrators-source.d.ts +33 -0
- package/dist/cjs/automations/hydrators-source.d.ts.map +1 -0
- package/dist/cjs/automations/hydrators-source.js +571 -0
- package/dist/cjs/automations/hydrators-source.js.map +1 -0
- package/dist/cjs/booking-calendar-feed-route-generator.d.ts.map +1 -1
- package/dist/cjs/booking-calendar-feed-route-generator.js +8 -0
- package/dist/cjs/booking-calendar-feed-route-generator.js.map +1 -1
- package/dist/cjs/configured-nextauth-url.d.ts +17 -0
- package/dist/cjs/configured-nextauth-url.d.ts.map +1 -0
- package/dist/cjs/configured-nextauth-url.js +20 -0
- package/dist/cjs/configured-nextauth-url.js.map +1 -0
- package/dist/cjs/cron-request-verification.d.ts +22 -1
- package/dist/cjs/cron-request-verification.d.ts.map +1 -1
- package/dist/cjs/cron-request-verification.js +50 -6
- package/dist/cjs/cron-request-verification.js.map +1 -1
- package/dist/cjs/data-api-route-generator.d.ts +19 -0
- package/dist/cjs/data-api-route-generator.d.ts.map +1 -1
- package/dist/cjs/data-api-route-generator.js +711 -43
- package/dist/cjs/data-api-route-generator.js.map +1 -1
- package/dist/cjs/ecommerce/parameterized-stock-chain.d.ts +3 -1
- package/dist/cjs/ecommerce/parameterized-stock-chain.d.ts.map +1 -1
- package/dist/cjs/ecommerce/parameterized-stock-chain.js +45 -5
- package/dist/cjs/ecommerce/parameterized-stock-chain.js.map +1 -1
- package/dist/cjs/ecommerce/place-order-guards.d.ts +126 -0
- package/dist/cjs/ecommerce/place-order-guards.d.ts.map +1 -0
- package/dist/cjs/ecommerce/place-order-guards.js +670 -0
- package/dist/cjs/ecommerce/place-order-guards.js.map +1 -0
- package/dist/cjs/ecommerce-customhandler-rewriter.d.ts +2 -0
- package/dist/cjs/ecommerce-customhandler-rewriter.d.ts.map +1 -1
- package/dist/cjs/ecommerce-customhandler-rewriter.js +38 -2
- package/dist/cjs/ecommerce-customhandler-rewriter.js.map +1 -1
- package/dist/cjs/executor-generator.d.ts.map +1 -1
- package/dist/cjs/executor-generator.js +368 -60
- package/dist/cjs/executor-generator.js.map +1 -1
- package/dist/cjs/graph-utils.d.ts +9 -0
- package/dist/cjs/graph-utils.d.ts.map +1 -1
- package/dist/cjs/graph-utils.js +32 -1
- package/dist/cjs/graph-utils.js.map +1 -1
- package/dist/cjs/index.d.ts +20 -1
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js +72 -2
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/invoice/api-routes-code.d.ts +9 -3
- package/dist/cjs/invoice/api-routes-code.d.ts.map +1 -1
- package/dist/cjs/invoice/api-routes-code.js +9 -7
- package/dist/cjs/invoice/api-routes-code.js.map +1 -1
- package/dist/cjs/invoice/index.d.ts.map +1 -1
- package/dist/cjs/invoice/index.js +12 -7
- package/dist/cjs/invoice/index.js.map +1 -1
- package/dist/cjs/invoice/invoice-assembly-code.d.ts.map +1 -1
- package/dist/cjs/invoice/invoice-assembly-code.js +8 -3
- package/dist/cjs/invoice/invoice-assembly-code.js.map +1 -1
- package/dist/cjs/invoice/pdf-generator-code.d.ts.map +1 -1
- package/dist/cjs/invoice/pdf-generator-code.js +2 -1
- package/dist/cjs/invoice/pdf-generator-code.js.map +1 -1
- package/dist/cjs/invoice/pdf-service-client-code.d.ts.map +1 -1
- package/dist/cjs/invoice/pdf-service-client-code.js +15 -7
- package/dist/cjs/invoice/pdf-service-client-code.js.map +1 -1
- package/dist/cjs/newsletter/admin-route-code.d.ts +60 -0
- package/dist/cjs/newsletter/admin-route-code.d.ts.map +1 -0
- package/dist/cjs/newsletter/admin-route-code.js +300 -0
- package/dist/cjs/newsletter/admin-route-code.js.map +1 -0
- package/dist/cjs/newsletter/helper-code.d.ts +109 -0
- package/dist/cjs/newsletter/helper-code.d.ts.map +1 -0
- package/dist/cjs/newsletter/helper-code.js +662 -0
- package/dist/cjs/newsletter/helper-code.js.map +1 -0
- package/dist/cjs/newsletter/newsletter-scope.d.ts +65 -0
- package/dist/cjs/newsletter/newsletter-scope.d.ts.map +1 -0
- package/dist/cjs/newsletter/newsletter-scope.js +103 -0
- package/dist/cjs/newsletter/newsletter-scope.js.map +1 -0
- package/dist/cjs/newsletter/project-plugin.d.ts +18 -0
- package/dist/cjs/newsletter/project-plugin.d.ts.map +1 -0
- package/dist/cjs/newsletter/project-plugin.js +97 -0
- package/dist/cjs/newsletter/project-plugin.js.map +1 -0
- package/dist/cjs/newsletter/routes-code.d.ts +6 -0
- package/dist/cjs/newsletter/routes-code.d.ts.map +1 -0
- package/dist/cjs/newsletter/routes-code.js +181 -0
- package/dist/cjs/newsletter/routes-code.js.map +1 -0
- package/dist/cjs/nodes/account/account-compare-passwords.d.ts.map +1 -1
- package/dist/cjs/nodes/account/account-compare-passwords.js +16 -6
- package/dist/cjs/nodes/account/account-compare-passwords.js.map +1 -1
- package/dist/cjs/nodes/account/account-delete-current.js +1 -1
- package/dist/cjs/nodes/account/account-get-current.js +1 -1
- package/dist/cjs/nodes/account/account-hash-password.d.ts.map +1 -1
- package/dist/cjs/nodes/account/account-hash-password.js +15 -3
- package/dist/cjs/nodes/account/account-hash-password.js.map +1 -1
- package/dist/cjs/nodes/account/account-login.d.ts.map +1 -1
- package/dist/cjs/nodes/account/account-login.js +23 -6
- package/dist/cjs/nodes/account/account-login.js.map +1 -1
- package/dist/cjs/nodes/account/account-logout.js +1 -1
- package/dist/cjs/nodes/account/account-refresh-session.js +1 -1
- package/dist/cjs/nodes/account/account-request-password-reset.d.ts +3 -0
- package/dist/cjs/nodes/account/account-request-password-reset.d.ts.map +1 -0
- package/dist/cjs/nodes/account/account-request-password-reset.js +46 -0
- package/dist/cjs/nodes/account/account-request-password-reset.js.map +1 -0
- package/dist/cjs/nodes/account/account-reset-password.d.ts +3 -0
- package/dist/cjs/nodes/account/account-reset-password.d.ts.map +1 -0
- package/dist/cjs/nodes/account/account-reset-password.js +44 -0
- package/dist/cjs/nodes/account/account-reset-password.js.map +1 -0
- package/dist/cjs/nodes/account/account-signup.d.ts.map +1 -1
- package/dist/cjs/nodes/account/account-signup.js +82 -19
- package/dist/cjs/nodes/account/account-signup.js.map +1 -1
- package/dist/cjs/nodes/account/account-social-login.js +1 -1
- package/dist/cjs/nodes/ai/ai-custom-prompt.d.ts.map +1 -1
- package/dist/cjs/nodes/ai/ai-custom-prompt.js +20 -5
- package/dist/cjs/nodes/ai/ai-custom-prompt.js.map +1 -1
- package/dist/cjs/nodes/ai/ai-detect-language.d.ts.map +1 -1
- package/dist/cjs/nodes/ai/ai-detect-language.js +20 -5
- package/dist/cjs/nodes/ai/ai-detect-language.js.map +1 -1
- package/dist/cjs/nodes/ai/ai-generate-text-embedding.d.ts.map +1 -1
- package/dist/cjs/nodes/ai/ai-generate-text-embedding.js +10 -2
- package/dist/cjs/nodes/ai/ai-generate-text-embedding.js.map +1 -1
- package/dist/cjs/nodes/ai/ai-provider-utils-sources.generated.js +2 -2
- package/dist/cjs/nodes/ai/ai-provider-utils-sources.generated.js.map +1 -1
- package/dist/cjs/nodes/ai/ai-provider-utils.d.ts +31 -2
- package/dist/cjs/nodes/ai/ai-provider-utils.d.ts.map +1 -1
- package/dist/cjs/nodes/ai/ai-provider-utils.js +125 -11
- package/dist/cjs/nodes/ai/ai-provider-utils.js.map +1 -1
- package/dist/cjs/nodes/ai/ai-select-database-data.d.ts.map +1 -1
- package/dist/cjs/nodes/ai/ai-select-database-data.js +6 -2
- package/dist/cjs/nodes/ai/ai-select-database-data.js.map +1 -1
- package/dist/cjs/nodes/ai/ai-sentiment-analysis.d.ts.map +1 -1
- package/dist/cjs/nodes/ai/ai-sentiment-analysis.js +20 -5
- package/dist/cjs/nodes/ai/ai-sentiment-analysis.js.map +1 -1
- package/dist/cjs/nodes/ai/ai-summarization.d.ts.map +1 -1
- package/dist/cjs/nodes/ai/ai-summarization.js +20 -5
- package/dist/cjs/nodes/ai/ai-summarization.js.map +1 -1
- package/dist/cjs/nodes/ai/ai-text-classifier.d.ts.map +1 -1
- package/dist/cjs/nodes/ai/ai-text-classifier.js +20 -5
- package/dist/cjs/nodes/ai/ai-text-classifier.js.map +1 -1
- package/dist/cjs/nodes/ai/ai-text-transform.d.ts.map +1 -1
- package/dist/cjs/nodes/ai/ai-text-transform.js +20 -5
- package/dist/cjs/nodes/ai/ai-text-transform.js.map +1 -1
- package/dist/cjs/nodes/analytics/analytics-track-outcome.d.ts +3 -0
- package/dist/cjs/nodes/analytics/analytics-track-outcome.d.ts.map +1 -0
- package/dist/cjs/nodes/analytics/analytics-track-outcome.js +110 -0
- package/dist/cjs/nodes/analytics/analytics-track-outcome.js.map +1 -0
- package/dist/cjs/nodes/cart/cart-price-order.d.ts.map +1 -1
- package/dist/cjs/nodes/cart/cart-price-order.js +161 -2
- package/dist/cjs/nodes/cart/cart-price-order.js.map +1 -1
- package/dist/cjs/nodes/cost-bearing-node-types.d.ts +4 -0
- package/dist/cjs/nodes/cost-bearing-node-types.d.ts.map +1 -0
- package/dist/cjs/nodes/cost-bearing-node-types.js +43 -0
- package/dist/cjs/nodes/cost-bearing-node-types.js.map +1 -0
- package/dist/cjs/nodes/data/data-select.d.ts.map +1 -1
- package/dist/cjs/nodes/data/data-select.js +12 -2
- package/dist/cjs/nodes/data/data-select.js.map +1 -1
- package/dist/cjs/nodes/email/email-mailersend.d.ts.map +1 -1
- package/dist/cjs/nodes/email/email-mailersend.js +15 -11
- package/dist/cjs/nodes/email/email-mailersend.js.map +1 -1
- package/dist/cjs/nodes/email/email-mailgun.d.ts.map +1 -1
- package/dist/cjs/nodes/email/email-mailgun.js +15 -15
- package/dist/cjs/nodes/email/email-mailgun.js.map +1 -1
- package/dist/cjs/nodes/email/email-postmark.d.ts.map +1 -1
- package/dist/cjs/nodes/email/email-postmark.js +15 -15
- package/dist/cjs/nodes/email/email-postmark.js.map +1 -1
- package/dist/cjs/nodes/email/email-resend.d.ts.map +1 -1
- package/dist/cjs/nodes/email/email-resend.js +15 -15
- package/dist/cjs/nodes/email/email-resend.js.map +1 -1
- package/dist/cjs/nodes/email/email-sendgrid.d.ts.map +1 -1
- package/dist/cjs/nodes/email/email-sendgrid.js +15 -15
- package/dist/cjs/nodes/email/email-sendgrid.js.map +1 -1
- package/dist/cjs/nodes/email/html-escape-code.d.ts +3 -0
- package/dist/cjs/nodes/email/html-escape-code.d.ts.map +1 -0
- package/dist/cjs/nodes/email/html-escape-code.js +23 -0
- package/dist/cjs/nodes/email/html-escape-code.js.map +1 -0
- package/dist/cjs/nodes/email/message-trust.d.ts +40 -0
- package/dist/cjs/nodes/email/message-trust.d.ts.map +1 -0
- package/dist/cjs/nodes/email/message-trust.js +167 -0
- package/dist/cjs/nodes/email/message-trust.js.map +1 -0
- package/dist/cjs/nodes/email/outbound-message-guard.d.ts +113 -0
- package/dist/cjs/nodes/email/outbound-message-guard.d.ts.map +1 -0
- package/dist/cjs/nodes/email/outbound-message-guard.js +460 -0
- package/dist/cjs/nodes/email/outbound-message-guard.js.map +1 -0
- package/dist/cjs/nodes/email/trusted-html-code.d.ts +22 -0
- package/dist/cjs/nodes/email/trusted-html-code.d.ts.map +1 -0
- package/dist/cjs/nodes/email/trusted-html-code.js +52 -0
- package/dist/cjs/nodes/email/trusted-html-code.js.map +1 -0
- package/dist/cjs/nodes/general/general-custom-js.d.ts.map +1 -1
- package/dist/cjs/nodes/general/general-custom-js.js +44 -7
- package/dist/cjs/nodes/general/general-custom-js.js.map +1 -1
- package/dist/cjs/nodes/general/general-http-request.d.ts.map +1 -1
- package/dist/cjs/nodes/general/general-http-request.js +431 -45
- package/dist/cjs/nodes/general/general-http-request.js.map +1 -1
- package/dist/cjs/nodes/general/general-rate-limiter.d.ts.map +1 -1
- package/dist/cjs/nodes/general/general-rate-limiter.js +46 -78
- package/dist/cjs/nodes/general/general-rate-limiter.js.map +1 -1
- package/dist/cjs/nodes/general/general-wait.d.ts +3 -0
- package/dist/cjs/nodes/general/general-wait.d.ts.map +1 -0
- package/dist/cjs/nodes/general/general-wait.js +81 -0
- package/dist/cjs/nodes/general/general-wait.js.map +1 -0
- package/dist/cjs/nodes/general/visitor-request.d.ts +44 -0
- package/dist/cjs/nodes/general/visitor-request.d.ts.map +1 -0
- package/dist/cjs/nodes/general/visitor-request.js +72 -0
- package/dist/cjs/nodes/general/visitor-request.js.map +1 -0
- package/dist/cjs/nodes/index.d.ts.map +1 -1
- package/dist/cjs/nodes/index.js +7 -1
- package/dist/cjs/nodes/index.js.map +1 -1
- package/dist/cjs/nodes/integrations/integration-slack.d.ts.map +1 -1
- package/dist/cjs/nodes/integrations/integration-slack.js +17 -6
- package/dist/cjs/nodes/integrations/integration-slack.js.map +1 -1
- package/dist/cjs/nodes/newsletter/newsletter-confirm.d.ts +3 -0
- package/dist/cjs/nodes/newsletter/newsletter-confirm.d.ts.map +1 -0
- package/dist/cjs/nodes/newsletter/newsletter-confirm.js +41 -0
- package/dist/cjs/nodes/newsletter/newsletter-confirm.js.map +1 -0
- package/dist/cjs/nodes/newsletter/newsletter-subscribe.d.ts +7 -0
- package/dist/cjs/nodes/newsletter/newsletter-subscribe.d.ts.map +1 -0
- package/dist/cjs/nodes/newsletter/newsletter-subscribe.js +69 -0
- package/dist/cjs/nodes/newsletter/newsletter-subscribe.js.map +1 -0
- package/dist/cjs/nodes/newsletter/newsletter-unsubscribe.d.ts +3 -0
- package/dist/cjs/nodes/newsletter/newsletter-unsubscribe.d.ts.map +1 -0
- package/dist/cjs/nodes/newsletter/newsletter-unsubscribe.js +42 -0
- package/dist/cjs/nodes/newsletter/newsletter-unsubscribe.js.map +1 -0
- package/dist/cjs/nodes/realtime/realtime-join-channel.d.ts.map +1 -1
- package/dist/cjs/nodes/realtime/realtime-join-channel.js +5 -4
- package/dist/cjs/nodes/realtime/realtime-join-channel.js.map +1 -1
- package/dist/cjs/nodes/realtime/realtime-send-channel-event.d.ts.map +1 -1
- package/dist/cjs/nodes/realtime/realtime-send-channel-event.js +11 -2
- package/dist/cjs/nodes/realtime/realtime-send-channel-event.js.map +1 -1
- package/dist/cjs/nodes/realtime/realtime-send-channel-message.d.ts.map +1 -1
- package/dist/cjs/nodes/realtime/realtime-send-channel-message.js +11 -2
- package/dist/cjs/nodes/realtime/realtime-send-channel-message.js.map +1 -1
- package/dist/cjs/nodes/sms/sms-infobip.d.ts.map +1 -1
- package/dist/cjs/nodes/sms/sms-infobip.js +11 -8
- package/dist/cjs/nodes/sms/sms-infobip.js.map +1 -1
- package/dist/cjs/nodes/sms/sms-smsapi.d.ts.map +1 -1
- package/dist/cjs/nodes/sms/sms-smsapi.js +11 -8
- package/dist/cjs/nodes/sms/sms-smsapi.js.map +1 -1
- package/dist/cjs/nodes/sms/sms-textmagic.d.ts.map +1 -1
- package/dist/cjs/nodes/sms/sms-textmagic.js +11 -8
- package/dist/cjs/nodes/sms/sms-textmagic.js.map +1 -1
- package/dist/cjs/nodes/sms/sms-twilio.d.ts.map +1 -1
- package/dist/cjs/nodes/sms/sms-twilio.js +12 -10
- package/dist/cjs/nodes/sms/sms-twilio.js.map +1 -1
- package/dist/cjs/nodes/types.d.ts +8 -1
- package/dist/cjs/nodes/types.d.ts.map +1 -1
- package/dist/cjs/nodes/utility/utility-similarity-scoring.d.ts.map +1 -1
- package/dist/cjs/nodes/utility/utility-similarity-scoring.js +29 -10
- package/dist/cjs/nodes/utility/utility-similarity-scoring.js.map +1 -1
- package/dist/cjs/page-access-guard-generator.d.ts +23 -0
- package/dist/cjs/page-access-guard-generator.d.ts.map +1 -0
- package/dist/cjs/page-access-guard-generator.js +135 -0
- package/dist/cjs/page-access-guard-generator.js.map +1 -0
- package/dist/cjs/password-reset-route-generator.d.ts +119 -0
- package/dist/cjs/password-reset-route-generator.d.ts.map +1 -0
- package/dist/cjs/password-reset-route-generator.js +460 -0
- package/dist/cjs/password-reset-route-generator.js.map +1 -0
- package/dist/cjs/payments/payment-core-code.d.ts.map +1 -1
- package/dist/cjs/payments/payment-core-code.js +12 -7
- package/dist/cjs/payments/payment-core-code.js.map +1 -1
- package/dist/cjs/project-code-scanner.d.ts +11 -0
- package/dist/cjs/project-code-scanner.d.ts.map +1 -0
- package/dist/cjs/project-code-scanner.js +80 -0
- package/dist/cjs/project-code-scanner.js.map +1 -0
- package/dist/cjs/public-step-guards.d.ts +122 -0
- package/dist/cjs/public-step-guards.d.ts.map +1 -0
- package/dist/cjs/public-step-guards.js +288 -0
- package/dist/cjs/public-step-guards.js.map +1 -0
- package/dist/cjs/publish-refusals.d.ts +66 -0
- package/dist/cjs/publish-refusals.d.ts.map +1 -0
- package/dist/cjs/publish-refusals.js +278 -0
- package/dist/cjs/publish-refusals.js.map +1 -0
- package/dist/cjs/realtime-generator.d.ts +63 -1
- package/dist/cjs/realtime-generator.d.ts.map +1 -1
- package/dist/cjs/realtime-generator.js +404 -230
- package/dist/cjs/realtime-generator.js.map +1 -1
- package/dist/cjs/runtime-storage-generator.d.ts +32 -1
- package/dist/cjs/runtime-storage-generator.d.ts.map +1 -1
- package/dist/cjs/runtime-storage-generator.js +265 -12
- package/dist/cjs/runtime-storage-generator.js.map +1 -1
- package/dist/cjs/security-runtime/index.d.ts +14 -0
- package/dist/cjs/security-runtime/index.d.ts.map +1 -0
- package/dist/cjs/security-runtime/index.js +48 -0
- package/dist/cjs/security-runtime/index.js.map +1 -0
- package/dist/cjs/security-runtime/security-runtime-code.d.ts +53 -0
- package/dist/cjs/security-runtime/security-runtime-code.d.ts.map +1 -0
- package/dist/cjs/security-runtime/security-runtime-code.js +580 -0
- package/dist/cjs/security-runtime/security-runtime-code.js.map +1 -0
- package/dist/cjs/security-scanner.d.ts +72 -3
- package/dist/cjs/security-scanner.d.ts.map +1 -1
- package/dist/cjs/security-scanner.js +220 -8
- package/dist/cjs/security-scanner.js.map +1 -1
- package/dist/cjs/segment-splitter.d.ts.map +1 -1
- package/dist/cjs/segment-splitter.js +10 -2
- package/dist/cjs/segment-splitter.js.map +1 -1
- package/dist/cjs/segment-trust.d.ts +36 -0
- package/dist/cjs/segment-trust.d.ts.map +1 -1
- package/dist/cjs/segment-trust.js +147 -3
- package/dist/cjs/segment-trust.js.map +1 -1
- package/dist/cjs/self-call-headers.d.ts +31 -0
- package/dist/cjs/self-call-headers.d.ts.map +1 -0
- package/dist/cjs/self-call-headers.js +48 -0
- package/dist/cjs/self-call-headers.js.map +1 -0
- package/dist/cjs/sent-email-log/index.d.ts +7 -0
- package/dist/cjs/sent-email-log/index.d.ts.map +1 -1
- package/dist/cjs/sent-email-log/index.js +17 -1
- package/dist/cjs/sent-email-log/index.js.map +1 -1
- package/dist/cjs/sent-email-log/sent-email-log-code.d.ts +7 -0
- package/dist/cjs/sent-email-log/sent-email-log-code.d.ts.map +1 -1
- package/dist/cjs/sent-email-log/sent-email-log-code.js +17 -3
- package/dist/cjs/sent-email-log/sent-email-log-code.js.map +1 -1
- package/dist/cjs/server-custom-node-call.d.ts +79 -0
- package/dist/cjs/server-custom-node-call.d.ts.map +1 -0
- package/dist/cjs/server-custom-node-call.js +285 -0
- package/dist/cjs/server-custom-node-call.js.map +1 -0
- package/dist/cjs/server-runtime-code.d.ts +39 -12
- package/dist/cjs/server-runtime-code.d.ts.map +1 -1
- package/dist/cjs/server-runtime-code.js +484 -41
- package/dist/cjs/server-runtime-code.js.map +1 -1
- package/dist/cjs/session-cookie-resolver.d.ts +3 -1
- package/dist/cjs/session-cookie-resolver.d.ts.map +1 -1
- package/dist/cjs/session-revocation-generator.d.ts +39 -0
- package/dist/cjs/session-revocation-generator.d.ts.map +1 -0
- package/dist/cjs/session-revocation-generator.js +177 -0
- package/dist/cjs/session-revocation-generator.js.map +1 -0
- package/dist/cjs/slack-message-values.d.ts +6 -0
- package/dist/cjs/slack-message-values.d.ts.map +1 -0
- package/dist/cjs/slack-message-values.js +73 -0
- package/dist/cjs/slack-message-values.js.map +1 -0
- package/dist/cjs/transactional-email-code.d.ts +11 -0
- package/dist/cjs/transactional-email-code.d.ts.map +1 -1
- package/dist/cjs/transactional-email-code.js +29 -5
- package/dist/cjs/transactional-email-code.js.map +1 -1
- package/dist/cjs/trigger-generator.d.ts +2 -0
- package/dist/cjs/trigger-generator.d.ts.map +1 -1
- package/dist/cjs/trigger-generator.js +17 -4
- package/dist/cjs/trigger-generator.js.map +1 -1
- package/dist/cjs/tsconfig.tsbuildinfo +1 -1
- package/dist/cjs/visitor-step-limits.d.ts +66 -0
- package/dist/cjs/visitor-step-limits.d.ts.map +1 -0
- package/dist/cjs/visitor-step-limits.js +187 -0
- package/dist/cjs/visitor-step-limits.js.map +1 -0
- package/dist/cjs/webhook-generator.d.ts.map +1 -1
- package/dist/cjs/webhook-generator.js +93 -15
- package/dist/cjs/webhook-generator.js.map +1 -1
- package/dist/cjs/webhook-signature-verification.d.ts.map +1 -1
- package/dist/cjs/webhook-signature-verification.js +13 -3
- package/dist/cjs/webhook-signature-verification.js.map +1 -1
- package/dist/cjs/workflow-auth-generator.d.ts +4 -1
- package/dist/cjs/workflow-auth-generator.d.ts.map +1 -1
- package/dist/cjs/workflow-auth-generator.js +8 -3
- package/dist/cjs/workflow-auth-generator.js.map +1 -1
- package/dist/cjs/workflow-component-plugin.js +11 -3
- package/dist/cjs/workflow-component-plugin.js.map +1 -1
- package/dist/cjs/workflow-project-plugin.d.ts.map +1 -1
- package/dist/cjs/workflow-project-plugin.js +302 -56
- package/dist/cjs/workflow-project-plugin.js.map +1 -1
- package/dist/cjs/workflow-scope.d.ts.map +1 -1
- package/dist/cjs/workflow-scope.js +5 -0
- package/dist/cjs/workflow-scope.js.map +1 -1
- package/dist/esm/account-delete-route-generator.d.ts +1 -0
- package/dist/esm/account-delete-route-generator.d.ts.map +1 -1
- package/dist/esm/account-delete-route-generator.js +18 -3
- package/dist/esm/account-delete-route-generator.js.map +1 -1
- package/dist/esm/api-route-generator.d.ts +52 -3
- package/dist/esm/api-route-generator.d.ts.map +1 -1
- package/dist/esm/api-route-generator.js +595 -142
- package/dist/esm/api-route-generator.js.map +1 -1
- package/dist/esm/auth-generator.d.ts +126 -3
- package/dist/esm/auth-generator.d.ts.map +1 -1
- package/dist/esm/auth-generator.js +1350 -140
- package/dist/esm/auth-generator.js.map +1 -1
- package/dist/esm/automations/activity-kicks.d.ts +12 -0
- package/dist/esm/automations/activity-kicks.d.ts.map +1 -0
- package/dist/esm/automations/activity-kicks.js +118 -0
- package/dist/esm/automations/activity-kicks.js.map +1 -0
- package/dist/esm/automations/app-events-source.d.ts +33 -0
- package/dist/esm/automations/app-events-source.d.ts.map +1 -0
- package/dist/esm/automations/app-events-source.js +104 -0
- package/dist/esm/automations/app-events-source.js.map +1 -0
- package/dist/esm/automations/automations-project-plugin.d.ts +21 -0
- package/dist/esm/automations/automations-project-plugin.d.ts.map +1 -0
- package/dist/esm/automations/automations-project-plugin.js +98 -0
- package/dist/esm/automations/automations-project-plugin.js.map +1 -0
- package/dist/esm/automations/automations-scope.d.ts +104 -0
- package/dist/esm/automations/automations-scope.d.ts.map +1 -0
- package/dist/esm/automations/automations-scope.js +165 -0
- package/dist/esm/automations/automations-scope.js.map +1 -0
- package/dist/esm/automations/dispatcher-source.d.ts +72 -0
- package/dist/esm/automations/dispatcher-source.d.ts.map +1 -0
- package/dist/esm/automations/dispatcher-source.js +999 -0
- package/dist/esm/automations/dispatcher-source.js.map +1 -0
- package/dist/esm/automations/event-bus-source.d.ts +44 -0
- package/dist/esm/automations/event-bus-source.d.ts.map +1 -0
- package/dist/esm/automations/event-bus-source.js +421 -0
- package/dist/esm/automations/event-bus-source.js.map +1 -0
- package/dist/esm/automations/handler-module-generator.d.ts +25 -0
- package/dist/esm/automations/handler-module-generator.d.ts.map +1 -0
- package/dist/esm/automations/handler-module-generator.js +71 -0
- package/dist/esm/automations/handler-module-generator.js.map +1 -0
- package/dist/esm/automations/hydrators-source.d.ts +33 -0
- package/dist/esm/automations/hydrators-source.d.ts.map +1 -0
- package/dist/esm/automations/hydrators-source.js +567 -0
- package/dist/esm/automations/hydrators-source.js.map +1 -0
- package/dist/esm/booking-calendar-feed-route-generator.d.ts.map +1 -1
- package/dist/esm/booking-calendar-feed-route-generator.js +8 -0
- package/dist/esm/booking-calendar-feed-route-generator.js.map +1 -1
- package/dist/esm/configured-nextauth-url.d.ts +17 -0
- package/dist/esm/configured-nextauth-url.d.ts.map +1 -0
- package/dist/esm/configured-nextauth-url.js +17 -0
- package/dist/esm/configured-nextauth-url.js.map +1 -0
- package/dist/esm/cron-request-verification.d.ts +22 -1
- package/dist/esm/cron-request-verification.d.ts.map +1 -1
- package/dist/esm/cron-request-verification.js +48 -5
- package/dist/esm/cron-request-verification.js.map +1 -1
- package/dist/esm/data-api-route-generator.d.ts +19 -0
- package/dist/esm/data-api-route-generator.d.ts.map +1 -1
- package/dist/esm/data-api-route-generator.js +710 -43
- package/dist/esm/data-api-route-generator.js.map +1 -1
- package/dist/esm/ecommerce/parameterized-stock-chain.d.ts +3 -1
- package/dist/esm/ecommerce/parameterized-stock-chain.d.ts.map +1 -1
- package/dist/esm/ecommerce/parameterized-stock-chain.js +43 -4
- package/dist/esm/ecommerce/parameterized-stock-chain.js.map +1 -1
- package/dist/esm/ecommerce/place-order-guards.d.ts +126 -0
- package/dist/esm/ecommerce/place-order-guards.d.ts.map +1 -0
- package/dist/esm/ecommerce/place-order-guards.js +655 -0
- package/dist/esm/ecommerce/place-order-guards.js.map +1 -0
- package/dist/esm/ecommerce-customhandler-rewriter.d.ts +2 -0
- package/dist/esm/ecommerce-customhandler-rewriter.d.ts.map +1 -1
- package/dist/esm/ecommerce-customhandler-rewriter.js +38 -2
- package/dist/esm/ecommerce-customhandler-rewriter.js.map +1 -1
- package/dist/esm/executor-generator.d.ts.map +1 -1
- package/dist/esm/executor-generator.js +368 -60
- package/dist/esm/executor-generator.js.map +1 -1
- package/dist/esm/graph-utils.d.ts +9 -0
- package/dist/esm/graph-utils.d.ts.map +1 -1
- package/dist/esm/graph-utils.js +30 -0
- package/dist/esm/graph-utils.js.map +1 -1
- package/dist/esm/index.d.ts +20 -1
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +27 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/invoice/api-routes-code.d.ts +9 -3
- package/dist/esm/invoice/api-routes-code.d.ts.map +1 -1
- package/dist/esm/invoice/api-routes-code.js +9 -7
- package/dist/esm/invoice/api-routes-code.js.map +1 -1
- package/dist/esm/invoice/index.d.ts.map +1 -1
- package/dist/esm/invoice/index.js +12 -7
- package/dist/esm/invoice/index.js.map +1 -1
- package/dist/esm/invoice/invoice-assembly-code.d.ts.map +1 -1
- package/dist/esm/invoice/invoice-assembly-code.js +8 -3
- package/dist/esm/invoice/invoice-assembly-code.js.map +1 -1
- package/dist/esm/invoice/pdf-generator-code.d.ts.map +1 -1
- package/dist/esm/invoice/pdf-generator-code.js +2 -1
- package/dist/esm/invoice/pdf-generator-code.js.map +1 -1
- package/dist/esm/invoice/pdf-service-client-code.d.ts.map +1 -1
- package/dist/esm/invoice/pdf-service-client-code.js +15 -7
- package/dist/esm/invoice/pdf-service-client-code.js.map +1 -1
- package/dist/esm/newsletter/admin-route-code.d.ts +60 -0
- package/dist/esm/newsletter/admin-route-code.d.ts.map +1 -0
- package/dist/esm/newsletter/admin-route-code.js +295 -0
- package/dist/esm/newsletter/admin-route-code.js.map +1 -0
- package/dist/esm/newsletter/helper-code.d.ts +109 -0
- package/dist/esm/newsletter/helper-code.d.ts.map +1 -0
- package/dist/esm/newsletter/helper-code.js +656 -0
- package/dist/esm/newsletter/helper-code.js.map +1 -0
- package/dist/esm/newsletter/newsletter-scope.d.ts +65 -0
- package/dist/esm/newsletter/newsletter-scope.d.ts.map +1 -0
- package/dist/esm/newsletter/newsletter-scope.js +97 -0
- package/dist/esm/newsletter/newsletter-scope.js.map +1 -0
- package/dist/esm/newsletter/project-plugin.d.ts +18 -0
- package/dist/esm/newsletter/project-plugin.d.ts.map +1 -0
- package/dist/esm/newsletter/project-plugin.js +93 -0
- package/dist/esm/newsletter/project-plugin.js.map +1 -0
- package/dist/esm/newsletter/routes-code.d.ts +6 -0
- package/dist/esm/newsletter/routes-code.d.ts.map +1 -0
- package/dist/esm/newsletter/routes-code.js +175 -0
- package/dist/esm/newsletter/routes-code.js.map +1 -0
- package/dist/esm/nodes/account/account-compare-passwords.d.ts.map +1 -1
- package/dist/esm/nodes/account/account-compare-passwords.js +16 -6
- package/dist/esm/nodes/account/account-compare-passwords.js.map +1 -1
- package/dist/esm/nodes/account/account-delete-current.js +1 -1
- package/dist/esm/nodes/account/account-get-current.js +1 -1
- package/dist/esm/nodes/account/account-hash-password.d.ts.map +1 -1
- package/dist/esm/nodes/account/account-hash-password.js +15 -3
- package/dist/esm/nodes/account/account-hash-password.js.map +1 -1
- package/dist/esm/nodes/account/account-login.d.ts.map +1 -1
- package/dist/esm/nodes/account/account-login.js +23 -6
- package/dist/esm/nodes/account/account-login.js.map +1 -1
- package/dist/esm/nodes/account/account-logout.js +1 -1
- package/dist/esm/nodes/account/account-refresh-session.js +1 -1
- package/dist/esm/nodes/account/account-request-password-reset.d.ts +3 -0
- package/dist/esm/nodes/account/account-request-password-reset.d.ts.map +1 -0
- package/dist/esm/nodes/account/account-request-password-reset.js +43 -0
- package/dist/esm/nodes/account/account-request-password-reset.js.map +1 -0
- package/dist/esm/nodes/account/account-reset-password.d.ts +3 -0
- package/dist/esm/nodes/account/account-reset-password.d.ts.map +1 -0
- package/dist/esm/nodes/account/account-reset-password.js +41 -0
- package/dist/esm/nodes/account/account-reset-password.js.map +1 -0
- package/dist/esm/nodes/account/account-signup.d.ts.map +1 -1
- package/dist/esm/nodes/account/account-signup.js +82 -19
- package/dist/esm/nodes/account/account-signup.js.map +1 -1
- package/dist/esm/nodes/account/account-social-login.js +1 -1
- package/dist/esm/nodes/ai/ai-custom-prompt.d.ts.map +1 -1
- package/dist/esm/nodes/ai/ai-custom-prompt.js +20 -5
- package/dist/esm/nodes/ai/ai-custom-prompt.js.map +1 -1
- package/dist/esm/nodes/ai/ai-detect-language.d.ts.map +1 -1
- package/dist/esm/nodes/ai/ai-detect-language.js +20 -5
- package/dist/esm/nodes/ai/ai-detect-language.js.map +1 -1
- package/dist/esm/nodes/ai/ai-generate-text-embedding.d.ts.map +1 -1
- package/dist/esm/nodes/ai/ai-generate-text-embedding.js +10 -2
- package/dist/esm/nodes/ai/ai-generate-text-embedding.js.map +1 -1
- package/dist/esm/nodes/ai/ai-provider-utils-sources.generated.js +2 -2
- package/dist/esm/nodes/ai/ai-provider-utils-sources.generated.js.map +1 -1
- package/dist/esm/nodes/ai/ai-provider-utils.d.ts +31 -2
- package/dist/esm/nodes/ai/ai-provider-utils.d.ts.map +1 -1
- package/dist/esm/nodes/ai/ai-provider-utils.js +124 -10
- package/dist/esm/nodes/ai/ai-provider-utils.js.map +1 -1
- package/dist/esm/nodes/ai/ai-select-database-data.d.ts.map +1 -1
- package/dist/esm/nodes/ai/ai-select-database-data.js +6 -2
- package/dist/esm/nodes/ai/ai-select-database-data.js.map +1 -1
- package/dist/esm/nodes/ai/ai-sentiment-analysis.d.ts.map +1 -1
- package/dist/esm/nodes/ai/ai-sentiment-analysis.js +20 -5
- package/dist/esm/nodes/ai/ai-sentiment-analysis.js.map +1 -1
- package/dist/esm/nodes/ai/ai-summarization.d.ts.map +1 -1
- package/dist/esm/nodes/ai/ai-summarization.js +20 -5
- package/dist/esm/nodes/ai/ai-summarization.js.map +1 -1
- package/dist/esm/nodes/ai/ai-text-classifier.d.ts.map +1 -1
- package/dist/esm/nodes/ai/ai-text-classifier.js +20 -5
- package/dist/esm/nodes/ai/ai-text-classifier.js.map +1 -1
- package/dist/esm/nodes/ai/ai-text-transform.d.ts.map +1 -1
- package/dist/esm/nodes/ai/ai-text-transform.js +20 -5
- package/dist/esm/nodes/ai/ai-text-transform.js.map +1 -1
- package/dist/esm/nodes/analytics/analytics-track-outcome.d.ts +3 -0
- package/dist/esm/nodes/analytics/analytics-track-outcome.d.ts.map +1 -0
- package/dist/esm/nodes/analytics/analytics-track-outcome.js +107 -0
- package/dist/esm/nodes/analytics/analytics-track-outcome.js.map +1 -0
- package/dist/esm/nodes/cart/cart-price-order.d.ts.map +1 -1
- package/dist/esm/nodes/cart/cart-price-order.js +161 -2
- package/dist/esm/nodes/cart/cart-price-order.js.map +1 -1
- package/dist/esm/nodes/cost-bearing-node-types.d.ts +4 -0
- package/dist/esm/nodes/cost-bearing-node-types.d.ts.map +1 -0
- package/dist/esm/nodes/cost-bearing-node-types.js +39 -0
- package/dist/esm/nodes/cost-bearing-node-types.js.map +1 -0
- package/dist/esm/nodes/data/data-select.d.ts.map +1 -1
- package/dist/esm/nodes/data/data-select.js +12 -2
- package/dist/esm/nodes/data/data-select.js.map +1 -1
- package/dist/esm/nodes/email/email-mailersend.d.ts.map +1 -1
- package/dist/esm/nodes/email/email-mailersend.js +15 -11
- package/dist/esm/nodes/email/email-mailersend.js.map +1 -1
- package/dist/esm/nodes/email/email-mailgun.d.ts.map +1 -1
- package/dist/esm/nodes/email/email-mailgun.js +15 -15
- package/dist/esm/nodes/email/email-mailgun.js.map +1 -1
- package/dist/esm/nodes/email/email-postmark.d.ts.map +1 -1
- package/dist/esm/nodes/email/email-postmark.js +15 -15
- package/dist/esm/nodes/email/email-postmark.js.map +1 -1
- package/dist/esm/nodes/email/email-resend.d.ts.map +1 -1
- package/dist/esm/nodes/email/email-resend.js +15 -15
- package/dist/esm/nodes/email/email-resend.js.map +1 -1
- package/dist/esm/nodes/email/email-sendgrid.d.ts.map +1 -1
- package/dist/esm/nodes/email/email-sendgrid.js +15 -15
- package/dist/esm/nodes/email/email-sendgrid.js.map +1 -1
- package/dist/esm/nodes/email/html-escape-code.d.ts +3 -0
- package/dist/esm/nodes/email/html-escape-code.d.ts.map +1 -0
- package/dist/esm/nodes/email/html-escape-code.js +18 -0
- package/dist/esm/nodes/email/html-escape-code.js.map +1 -0
- package/dist/esm/nodes/email/message-trust.d.ts +40 -0
- package/dist/esm/nodes/email/message-trust.d.ts.map +1 -0
- package/dist/esm/nodes/email/message-trust.js +161 -0
- package/dist/esm/nodes/email/message-trust.js.map +1 -0
- package/dist/esm/nodes/email/outbound-message-guard.d.ts +113 -0
- package/dist/esm/nodes/email/outbound-message-guard.d.ts.map +1 -0
- package/dist/esm/nodes/email/outbound-message-guard.js +452 -0
- package/dist/esm/nodes/email/outbound-message-guard.js.map +1 -0
- package/dist/esm/nodes/email/trusted-html-code.d.ts +22 -0
- package/dist/esm/nodes/email/trusted-html-code.d.ts.map +1 -0
- package/dist/esm/nodes/email/trusted-html-code.js +49 -0
- package/dist/esm/nodes/email/trusted-html-code.js.map +1 -0
- package/dist/esm/nodes/general/general-custom-js.d.ts.map +1 -1
- package/dist/esm/nodes/general/general-custom-js.js +44 -7
- package/dist/esm/nodes/general/general-custom-js.js.map +1 -1
- package/dist/esm/nodes/general/general-http-request.d.ts.map +1 -1
- package/dist/esm/nodes/general/general-http-request.js +431 -45
- package/dist/esm/nodes/general/general-http-request.js.map +1 -1
- package/dist/esm/nodes/general/general-rate-limiter.d.ts.map +1 -1
- package/dist/esm/nodes/general/general-rate-limiter.js +46 -78
- package/dist/esm/nodes/general/general-rate-limiter.js.map +1 -1
- package/dist/esm/nodes/general/general-wait.d.ts +3 -0
- package/dist/esm/nodes/general/general-wait.d.ts.map +1 -0
- package/dist/esm/nodes/general/general-wait.js +78 -0
- package/dist/esm/nodes/general/general-wait.js.map +1 -0
- package/dist/esm/nodes/general/visitor-request.d.ts +44 -0
- package/dist/esm/nodes/general/visitor-request.d.ts.map +1 -0
- package/dist/esm/nodes/general/visitor-request.js +65 -0
- package/dist/esm/nodes/general/visitor-request.js.map +1 -0
- package/dist/esm/nodes/index.d.ts.map +1 -1
- package/dist/esm/nodes/index.js +7 -1
- package/dist/esm/nodes/index.js.map +1 -1
- package/dist/esm/nodes/integrations/integration-slack.d.ts.map +1 -1
- package/dist/esm/nodes/integrations/integration-slack.js +17 -6
- package/dist/esm/nodes/integrations/integration-slack.js.map +1 -1
- package/dist/esm/nodes/newsletter/newsletter-confirm.d.ts +3 -0
- package/dist/esm/nodes/newsletter/newsletter-confirm.d.ts.map +1 -0
- package/dist/esm/nodes/newsletter/newsletter-confirm.js +38 -0
- package/dist/esm/nodes/newsletter/newsletter-confirm.js.map +1 -0
- package/dist/esm/nodes/newsletter/newsletter-subscribe.d.ts +7 -0
- package/dist/esm/nodes/newsletter/newsletter-subscribe.d.ts.map +1 -0
- package/dist/esm/nodes/newsletter/newsletter-subscribe.js +66 -0
- package/dist/esm/nodes/newsletter/newsletter-subscribe.js.map +1 -0
- package/dist/esm/nodes/newsletter/newsletter-unsubscribe.d.ts +3 -0
- package/dist/esm/nodes/newsletter/newsletter-unsubscribe.d.ts.map +1 -0
- package/dist/esm/nodes/newsletter/newsletter-unsubscribe.js +39 -0
- package/dist/esm/nodes/newsletter/newsletter-unsubscribe.js.map +1 -0
- package/dist/esm/nodes/realtime/realtime-join-channel.d.ts.map +1 -1
- package/dist/esm/nodes/realtime/realtime-join-channel.js +5 -4
- package/dist/esm/nodes/realtime/realtime-join-channel.js.map +1 -1
- package/dist/esm/nodes/realtime/realtime-send-channel-event.d.ts.map +1 -1
- package/dist/esm/nodes/realtime/realtime-send-channel-event.js +11 -2
- package/dist/esm/nodes/realtime/realtime-send-channel-event.js.map +1 -1
- package/dist/esm/nodes/realtime/realtime-send-channel-message.d.ts.map +1 -1
- package/dist/esm/nodes/realtime/realtime-send-channel-message.js +11 -2
- package/dist/esm/nodes/realtime/realtime-send-channel-message.js.map +1 -1
- package/dist/esm/nodes/sms/sms-infobip.d.ts.map +1 -1
- package/dist/esm/nodes/sms/sms-infobip.js +11 -8
- package/dist/esm/nodes/sms/sms-infobip.js.map +1 -1
- package/dist/esm/nodes/sms/sms-smsapi.d.ts.map +1 -1
- package/dist/esm/nodes/sms/sms-smsapi.js +11 -8
- package/dist/esm/nodes/sms/sms-smsapi.js.map +1 -1
- package/dist/esm/nodes/sms/sms-textmagic.d.ts.map +1 -1
- package/dist/esm/nodes/sms/sms-textmagic.js +11 -8
- package/dist/esm/nodes/sms/sms-textmagic.js.map +1 -1
- package/dist/esm/nodes/sms/sms-twilio.d.ts.map +1 -1
- package/dist/esm/nodes/sms/sms-twilio.js +12 -10
- package/dist/esm/nodes/sms/sms-twilio.js.map +1 -1
- package/dist/esm/nodes/types.d.ts +8 -1
- package/dist/esm/nodes/types.d.ts.map +1 -1
- package/dist/esm/nodes/utility/utility-similarity-scoring.d.ts.map +1 -1
- package/dist/esm/nodes/utility/utility-similarity-scoring.js +29 -10
- package/dist/esm/nodes/utility/utility-similarity-scoring.js.map +1 -1
- package/dist/esm/page-access-guard-generator.d.ts +23 -0
- package/dist/esm/page-access-guard-generator.d.ts.map +1 -0
- package/dist/esm/page-access-guard-generator.js +131 -0
- package/dist/esm/page-access-guard-generator.js.map +1 -0
- package/dist/esm/password-reset-route-generator.d.ts +119 -0
- package/dist/esm/password-reset-route-generator.d.ts.map +1 -0
- package/dist/esm/password-reset-route-generator.js +448 -0
- package/dist/esm/password-reset-route-generator.js.map +1 -0
- package/dist/esm/payments/payment-core-code.d.ts.map +1 -1
- package/dist/esm/payments/payment-core-code.js +12 -7
- package/dist/esm/payments/payment-core-code.js.map +1 -1
- package/dist/esm/project-code-scanner.d.ts +11 -0
- package/dist/esm/project-code-scanner.d.ts.map +1 -0
- package/dist/esm/project-code-scanner.js +75 -0
- package/dist/esm/project-code-scanner.js.map +1 -0
- package/dist/esm/public-step-guards.d.ts +122 -0
- package/dist/esm/public-step-guards.d.ts.map +1 -0
- package/dist/esm/public-step-guards.js +280 -0
- package/dist/esm/public-step-guards.js.map +1 -0
- package/dist/esm/publish-refusals.d.ts +66 -0
- package/dist/esm/publish-refusals.d.ts.map +1 -0
- package/dist/esm/publish-refusals.js +271 -0
- package/dist/esm/publish-refusals.js.map +1 -0
- package/dist/esm/realtime-generator.d.ts +63 -1
- package/dist/esm/realtime-generator.d.ts.map +1 -1
- package/dist/esm/realtime-generator.js +401 -229
- package/dist/esm/realtime-generator.js.map +1 -1
- package/dist/esm/runtime-storage-generator.d.ts +32 -1
- package/dist/esm/runtime-storage-generator.d.ts.map +1 -1
- package/dist/esm/runtime-storage-generator.js +264 -11
- package/dist/esm/runtime-storage-generator.js.map +1 -1
- package/dist/esm/security-runtime/index.d.ts +14 -0
- package/dist/esm/security-runtime/index.d.ts.map +1 -0
- package/dist/esm/security-runtime/index.js +37 -0
- package/dist/esm/security-runtime/index.js.map +1 -0
- package/dist/esm/security-runtime/security-runtime-code.d.ts +53 -0
- package/dist/esm/security-runtime/security-runtime-code.d.ts.map +1 -0
- package/dist/esm/security-runtime/security-runtime-code.js +575 -0
- package/dist/esm/security-runtime/security-runtime-code.js.map +1 -0
- package/dist/esm/security-scanner.d.ts +72 -3
- package/dist/esm/security-scanner.d.ts.map +1 -1
- package/dist/esm/security-scanner.js +217 -8
- package/dist/esm/security-scanner.js.map +1 -1
- package/dist/esm/segment-splitter.d.ts.map +1 -1
- package/dist/esm/segment-splitter.js +10 -2
- package/dist/esm/segment-splitter.js.map +1 -1
- package/dist/esm/segment-trust.d.ts +36 -0
- package/dist/esm/segment-trust.d.ts.map +1 -1
- package/dist/esm/segment-trust.js +146 -2
- package/dist/esm/segment-trust.js.map +1 -1
- package/dist/esm/self-call-headers.d.ts +31 -0
- package/dist/esm/self-call-headers.d.ts.map +1 -0
- package/dist/esm/self-call-headers.js +43 -0
- package/dist/esm/self-call-headers.js.map +1 -0
- package/dist/esm/sent-email-log/index.d.ts +7 -0
- package/dist/esm/sent-email-log/index.d.ts.map +1 -1
- package/dist/esm/sent-email-log/index.js +15 -0
- package/dist/esm/sent-email-log/index.js.map +1 -1
- package/dist/esm/sent-email-log/sent-email-log-code.d.ts +7 -0
- package/dist/esm/sent-email-log/sent-email-log-code.d.ts.map +1 -1
- package/dist/esm/sent-email-log/sent-email-log-code.js +17 -3
- package/dist/esm/sent-email-log/sent-email-log-code.js.map +1 -1
- package/dist/esm/server-custom-node-call.d.ts +79 -0
- package/dist/esm/server-custom-node-call.d.ts.map +1 -0
- package/dist/esm/server-custom-node-call.js +278 -0
- package/dist/esm/server-custom-node-call.js.map +1 -0
- package/dist/esm/server-runtime-code.d.ts +39 -12
- package/dist/esm/server-runtime-code.d.ts.map +1 -1
- package/dist/esm/server-runtime-code.js +483 -40
- package/dist/esm/server-runtime-code.js.map +1 -1
- package/dist/esm/session-cookie-resolver.d.ts +3 -1
- package/dist/esm/session-cookie-resolver.d.ts.map +1 -1
- package/dist/esm/session-revocation-generator.d.ts +39 -0
- package/dist/esm/session-revocation-generator.d.ts.map +1 -0
- package/dist/esm/session-revocation-generator.js +172 -0
- package/dist/esm/session-revocation-generator.js.map +1 -0
- package/dist/esm/slack-message-values.d.ts +6 -0
- package/dist/esm/slack-message-values.d.ts.map +1 -0
- package/dist/esm/slack-message-values.js +68 -0
- package/dist/esm/slack-message-values.js.map +1 -0
- package/dist/esm/transactional-email-code.d.ts +11 -0
- package/dist/esm/transactional-email-code.d.ts.map +1 -1
- package/dist/esm/transactional-email-code.js +28 -4
- package/dist/esm/transactional-email-code.js.map +1 -1
- package/dist/esm/trigger-generator.d.ts +2 -0
- package/dist/esm/trigger-generator.d.ts.map +1 -1
- package/dist/esm/trigger-generator.js +15 -3
- package/dist/esm/trigger-generator.js.map +1 -1
- package/dist/esm/tsconfig.tsbuildinfo +1 -1
- package/dist/esm/visitor-step-limits.d.ts +66 -0
- package/dist/esm/visitor-step-limits.d.ts.map +1 -0
- package/dist/esm/visitor-step-limits.js +181 -0
- package/dist/esm/visitor-step-limits.js.map +1 -0
- package/dist/esm/webhook-generator.d.ts.map +1 -1
- package/dist/esm/webhook-generator.js +93 -15
- package/dist/esm/webhook-generator.js.map +1 -1
- package/dist/esm/webhook-signature-verification.d.ts.map +1 -1
- package/dist/esm/webhook-signature-verification.js +13 -3
- package/dist/esm/webhook-signature-verification.js.map +1 -1
- package/dist/esm/workflow-auth-generator.d.ts +4 -1
- package/dist/esm/workflow-auth-generator.d.ts.map +1 -1
- package/dist/esm/workflow-auth-generator.js +8 -3
- package/dist/esm/workflow-auth-generator.js.map +1 -1
- package/dist/esm/workflow-component-plugin.js +12 -4
- package/dist/esm/workflow-component-plugin.js.map +1 -1
- package/dist/esm/workflow-project-plugin.d.ts.map +1 -1
- package/dist/esm/workflow-project-plugin.js +306 -60
- package/dist/esm/workflow-project-plugin.js.map +1 -1
- package/dist/esm/workflow-scope.d.ts.map +1 -1
- package/dist/esm/workflow-scope.js +5 -0
- package/dist/esm/workflow-scope.js.map +1 -1
- package/package.json +4 -4
- package/src/account-delete-route-generator.ts +28 -4
- package/src/api-route-generator.ts +712 -134
- package/src/auth-generator.ts +1471 -142
- package/src/automations/activity-kicks.ts +139 -0
- package/src/automations/app-events-source.ts +117 -0
- package/src/automations/automations-project-plugin.ts +202 -0
- package/src/automations/automations-scope.ts +196 -0
- package/src/automations/dispatcher-source.ts +1072 -0
- package/src/automations/event-bus-source.ts +428 -0
- package/src/automations/handler-module-generator.ts +107 -0
- package/src/automations/hydrators-source.ts +647 -0
- package/src/booking-calendar-feed-route-generator.ts +8 -0
- package/src/configured-nextauth-url.ts +17 -0
- package/src/cron-request-verification.ts +55 -5
- package/src/data-api-route-generator.ts +780 -43
- package/src/ecommerce/parameterized-stock-chain.ts +52 -5
- package/src/ecommerce/place-order-guards.ts +785 -0
- package/src/ecommerce-customhandler-rewriter.ts +55 -2
- package/src/executor-generator.ts +372 -60
- package/src/graph-utils.ts +33 -0
- package/src/index.ts +70 -0
- package/src/invoice/api-routes-code.ts +20 -7
- package/src/invoice/index.ts +11 -6
- package/src/invoice/invoice-assembly-code.ts +8 -3
- package/src/invoice/pdf-generator-code.ts +2 -1
- package/src/invoice/pdf-service-client-code.ts +15 -7
- package/src/newsletter/admin-route-code.ts +319 -0
- package/src/newsletter/helper-code.ts +748 -0
- package/src/newsletter/newsletter-scope.ts +116 -0
- package/src/newsletter/project-plugin.ts +119 -0
- package/src/newsletter/routes-code.ts +186 -0
- package/src/nodes/account/account-compare-passwords.ts +17 -6
- package/src/nodes/account/account-delete-current.ts +1 -1
- package/src/nodes/account/account-get-current.ts +1 -1
- package/src/nodes/account/account-hash-password.ts +19 -3
- package/src/nodes/account/account-login.ts +24 -7
- package/src/nodes/account/account-logout.ts +1 -1
- package/src/nodes/account/account-refresh-session.ts +1 -1
- package/src/nodes/account/account-request-password-reset.ts +47 -0
- package/src/nodes/account/account-reset-password.ts +45 -0
- package/src/nodes/account/account-signup.ts +86 -20
- package/src/nodes/account/account-social-login.ts +1 -1
- package/src/nodes/ai/ai-custom-prompt.ts +25 -6
- package/src/nodes/ai/ai-detect-language.ts +25 -6
- package/src/nodes/ai/ai-generate-text-embedding.ts +16 -3
- package/src/nodes/ai/ai-provider-utils-sources.generated.ts +2 -2
- package/src/nodes/ai/ai-provider-utils.ts +135 -10
- package/src/nodes/ai/ai-select-database-data.ts +8 -3
- package/src/nodes/ai/ai-sentiment-analysis.ts +25 -6
- package/src/nodes/ai/ai-summarization.ts +25 -6
- package/src/nodes/ai/ai-text-classifier.ts +25 -6
- package/src/nodes/ai/ai-text-transform.ts +25 -6
- package/src/nodes/analytics/analytics-track-outcome.ts +111 -0
- package/src/nodes/cart/cart-price-order.ts +200 -2
- package/src/nodes/cost-bearing-node-types.ts +45 -0
- package/src/nodes/data/data-select.ts +11 -2
- package/src/nodes/email/email-mailersend.ts +16 -8
- package/src/nodes/email/email-mailgun.ts +17 -12
- package/src/nodes/email/email-postmark.ts +17 -12
- package/src/nodes/email/email-resend.ts +17 -12
- package/src/nodes/email/email-sendgrid.ts +17 -12
- package/src/nodes/email/html-escape-code.ts +21 -0
- package/src/nodes/email/message-trust.ts +198 -0
- package/src/nodes/email/outbound-message-guard.ts +572 -0
- package/src/nodes/email/trusted-html-code.ts +49 -0
- package/src/nodes/general/general-custom-js.ts +46 -7
- package/src/nodes/general/general-http-request.ts +449 -46
- package/src/nodes/general/general-rate-limiter.ts +54 -81
- package/src/nodes/general/general-wait.ts +80 -0
- package/src/nodes/general/visitor-request.ts +79 -0
- package/src/nodes/index.ts +12 -0
- package/src/nodes/integrations/integration-slack.ts +21 -6
- package/src/nodes/newsletter/newsletter-confirm.ts +44 -0
- package/src/nodes/newsletter/newsletter-subscribe.ts +78 -0
- package/src/nodes/newsletter/newsletter-unsubscribe.ts +43 -0
- package/src/nodes/realtime/realtime-join-channel.ts +5 -4
- package/src/nodes/realtime/realtime-send-channel-event.ts +13 -2
- package/src/nodes/realtime/realtime-send-channel-message.ts +13 -2
- package/src/nodes/sms/sms-infobip.ts +14 -4
- package/src/nodes/sms/sms-smsapi.ts +14 -4
- package/src/nodes/sms/sms-textmagic.ts +14 -4
- package/src/nodes/sms/sms-twilio.ts +14 -4
- package/src/nodes/types.ts +9 -1
- package/src/nodes/utility/utility-similarity-scoring.ts +33 -12
- package/src/page-access-guard-generator.ts +154 -0
- package/src/password-reset-route-generator.ts +531 -0
- package/src/payments/payment-core-code.ts +12 -7
- package/src/project-code-scanner.ts +98 -0
- package/src/public-step-guards.ts +448 -0
- package/src/publish-refusals.ts +459 -0
- package/src/realtime-generator.ts +457 -234
- package/src/runtime-storage-generator.ts +270 -11
- package/src/security-runtime/index.ts +53 -0
- package/src/security-runtime/security-runtime-code.ts +579 -0
- package/src/security-scanner.ts +253 -10
- package/src/segment-splitter.ts +10 -2
- package/src/segment-trust.ts +205 -2
- package/src/self-call-headers.ts +46 -0
- package/src/sent-email-log/index.ts +16 -0
- package/src/sent-email-log/sent-email-log-code.ts +30 -4
- package/src/server-custom-node-call.ts +331 -0
- package/src/server-runtime-code.ts +488 -40
- package/src/session-revocation-generator.ts +177 -0
- package/src/slack-message-values.ts +84 -0
- package/src/transactional-email-code.ts +30 -4
- package/src/trigger-generator.ts +19 -3
- package/src/visitor-step-limits.ts +228 -0
- package/src/webhook-generator.ts +94 -14
- package/src/webhook-signature-verification.ts +13 -3
- package/src/workflow-auth-generator.ts +9 -4
- package/src/workflow-component-plugin.ts +14 -4
- package/src/workflow-project-plugin.ts +374 -61
- package/src/workflow-scope.ts +6 -0
|
@@ -0,0 +1,748 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `utils/newsletter/newsletter.js`: the one place the generated app changes a
|
|
3
|
+
* person's newsletter state. The public sign-up route, the `newsletter-subscribe`
|
|
4
|
+
* node, the sign-up route's consent box and the confirm / unsubscribe routes all
|
|
5
|
+
* go through it, so the policy is written once:
|
|
6
|
+
*
|
|
7
|
+
* - nobody is subscribed without their own action: a submit (single opt-in),
|
|
8
|
+
* or the emailed confirmation link (double opt-in);
|
|
9
|
+
* - a form never undoes an opt-out: anyone can type anyone's address, so an
|
|
10
|
+
* unsubscribed address is only ever sent a confirmation link;
|
|
11
|
+
* - every sign-up answers the same (`{ ok: true, pending }`, `pending` decided
|
|
12
|
+
* by the settings alone), so the answer never tells whether an address is
|
|
13
|
+
* known;
|
|
14
|
+
* - the links are stateless HMAC tokens keyed by the app secret
|
|
15
|
+
* (`newsletterTokenSpec`), which the services worker reproduces for the
|
|
16
|
+
* unsubscribe links of the newsletters it sends.
|
|
17
|
+
*
|
|
18
|
+
* CommonJS, server-only. The TeleportHQ database (`TELEPORT_DB_*`), through the
|
|
19
|
+
* same Postgres client the account routes open.
|
|
20
|
+
*/
|
|
21
|
+
import type { UIDLNewsletterSettings } from '@teleporthq/teleport-types'
|
|
22
|
+
import {
|
|
23
|
+
SUPPORTED_EMAIL_PROVIDERS,
|
|
24
|
+
generateEmailLocaleRequire,
|
|
25
|
+
generateFillTemplateFn,
|
|
26
|
+
generateProviderSendFunction,
|
|
27
|
+
} from '../transactional-email-code'
|
|
28
|
+
import { generateLazyPgClientCode } from '../pg-client-code'
|
|
29
|
+
import { securityRuntimeSpecifier } from '../security-runtime/security-runtime-code'
|
|
30
|
+
import { TRUSTED_ORIGIN_CODE } from '../password-reset-route-generator'
|
|
31
|
+
import { AUTOMATIONS_PATH } from '../automations/automations-scope'
|
|
32
|
+
import {
|
|
33
|
+
DEFAULT_NEWSLETTER_CONFIRM_PATH,
|
|
34
|
+
DEFAULT_NEWSLETTER_UNSUBSCRIBE_PATH,
|
|
35
|
+
NEWSLETTER_ADDRESS_LIMIT,
|
|
36
|
+
NEWSLETTER_MIN_RESPONSE_MS,
|
|
37
|
+
NEWSLETTER_OPTED_OUT_CONFIRMATIONS_PER_DAY,
|
|
38
|
+
NEWSLETTER_SOURCES,
|
|
39
|
+
NEWSLETTER_UNSUBSCRIBE_URL,
|
|
40
|
+
NEWSLETTER_USERS_TABLE,
|
|
41
|
+
PUBLIC_ROUTE_SIGN_UP_POINTS,
|
|
42
|
+
VISITOR_SIGN_UP_POINTS,
|
|
43
|
+
} from './newsletter-scope'
|
|
44
|
+
|
|
45
|
+
/** From `utils/newsletter/` to the project root. */
|
|
46
|
+
const RELATIVE_PREFIX = '../..'
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* The confirmation and unsubscribe links' token, exactly, so the services
|
|
50
|
+
* worker (the unsubscribe links in the newsletters it sends, R-N7) mints the
|
|
51
|
+
* same bytes as the site:
|
|
52
|
+
*
|
|
53
|
+
* key = HMAC-SHA256(key: NEXTAUTH_SECRET (UTF-8), message: 'teleport-newsletter:v1') → 32 bytes
|
|
54
|
+
* payload = UTF-8 of `${email}|${purpose}|${issuedAt}`
|
|
55
|
+
* email: trimmed, lower-cased; purpose: 'confirm' | 'unsubscribe';
|
|
56
|
+
* issuedAt: whole seconds since the Unix epoch, in decimal
|
|
57
|
+
* token = base64url(payload) + '.' + base64url(HMAC-SHA256(key, payload))
|
|
58
|
+
* base64url = RFC 4648 §5, no '=' padding
|
|
59
|
+
*
|
|
60
|
+
* Verification: exactly one '.'; both parts base64url; a 32-byte MAC compared
|
|
61
|
+
* in constant time; the payload split at its LAST two '|'; the purpose the
|
|
62
|
+
* caller expects; issuedAt at most `futureSkewSeconds` ahead of now; a
|
|
63
|
+
* `confirm` token at most `confirmMaxAgeSeconds` old; an `unsubscribe` token
|
|
64
|
+
* never expires. No app secret: nothing is signed and nothing verifies. The
|
|
65
|
+
* links carry the token in the `t` query parameter of the site's confirm and
|
|
66
|
+
* unsubscribe pages.
|
|
67
|
+
*/
|
|
68
|
+
export const newsletterTokenSpec = {
|
|
69
|
+
keyLabel: 'teleport-newsletter:v1',
|
|
70
|
+
keySecretEnv: 'NEXTAUTH_SECRET',
|
|
71
|
+
separator: '|',
|
|
72
|
+
purposes: ['confirm', 'unsubscribe'] as const,
|
|
73
|
+
confirmMaxAgeSeconds: 7 * 24 * 3600,
|
|
74
|
+
futureSkewSeconds: 300,
|
|
75
|
+
unsubscribeExpires: false,
|
|
76
|
+
maxTokenLength: 1024,
|
|
77
|
+
queryParameter: 't',
|
|
78
|
+
/** One token, for a byte-for-byte check of any other implementation. */
|
|
79
|
+
testVector: {
|
|
80
|
+
secret: 'newsletter-test-vector-secret',
|
|
81
|
+
email: 'reader@example.com',
|
|
82
|
+
purpose: 'unsubscribe' as const,
|
|
83
|
+
issuedAt: 1790000000,
|
|
84
|
+
token:
|
|
85
|
+
'cmVhZGVyQGV4YW1wbGUuY29tfHVuc3Vic2NyaWJlfDE3OTAwMDAwMDA.9xqxAQkmupu1AK9wbvBzMEbua-rdFAsjJHmRS6xrUwk',
|
|
86
|
+
},
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/** The person columns every statement answers. */
|
|
90
|
+
const PERSON_COLUMNS =
|
|
91
|
+
'id, email, source, email_unsubscribed, newsletter_status, newsletter_source, newsletter_unsubscribed_at'
|
|
92
|
+
const USERS = NEWSLETTER_USERS_TABLE
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Every statement the helper runs. Each change of state is guarded in its own
|
|
96
|
+
* WHERE, so two requests at once can never take a row anywhere the policy
|
|
97
|
+
* does not allow (an unsubscribed person subscribed by a form, an event
|
|
98
|
+
* recorded twice). Consent is always written explicitly: a `users` table made
|
|
99
|
+
* before 2026-10-26 still defaults `marketing_consent` to TRUE.
|
|
100
|
+
*/
|
|
101
|
+
export const NEWSLETTER_SQL = {
|
|
102
|
+
/** `$1`: the address, lower-cased. The exact spelling first, else any case. */
|
|
103
|
+
findPerson: `SELECT ${PERSON_COLUMNS} FROM ${USERS} WHERE LOWER(email) = $1 ORDER BY CASE WHEN email = $1 THEN 0 ELSE 1 END LIMIT 1`,
|
|
104
|
+
/** `$1` address, `$2` `users.source`, `$3` `newsletter_source`. */
|
|
105
|
+
insertPending: `INSERT INTO ${USERS} (email, source, marketing_consent, newsletter_status, newsletter_source) VALUES ($1, $2, FALSE, 'pending', $3) ON CONFLICT DO NOTHING RETURNING ${PERSON_COLUMNS}`,
|
|
106
|
+
insertSubscribed: `INSERT INTO ${USERS} (email, source, marketing_consent, email_unsubscribed, newsletter_status, newsletter_source, newsletter_subscribed_at) VALUES ($1, $2, TRUE, FALSE, 'subscribed', $3, CURRENT_TIMESTAMP) ON CONFLICT DO NOTHING RETURNING ${PERSON_COLUMNS}`,
|
|
107
|
+
/**
|
|
108
|
+
* `$1` id, `$2` `newsletter_source`: only a person never on the list, or
|
|
109
|
+
* still pending, and not opted out of email (an opt-out is undone only by
|
|
110
|
+
* the person's own confirmation click).
|
|
111
|
+
*/
|
|
112
|
+
markPending: `UPDATE ${USERS} SET newsletter_status = 'pending', newsletter_source = $2 WHERE id = $1 AND (newsletter_status IS NULL OR newsletter_status = 'pending') AND email_unsubscribed IS NOT TRUE RETURNING ${PERSON_COLUMNS}`,
|
|
113
|
+
markSubscribed: `UPDATE ${USERS} SET newsletter_status = 'subscribed', newsletter_subscribed_at = CURRENT_TIMESTAMP, newsletter_source = $2, marketing_consent = TRUE, email_unsubscribed = FALSE WHERE id = $1 AND (newsletter_status IS NULL OR newsletter_status = 'pending') AND email_unsubscribed IS NOT TRUE RETURNING ${PERSON_COLUMNS}`,
|
|
114
|
+
/** `$1` id: the confirmation link, the person's own click. */
|
|
115
|
+
confirm: `UPDATE ${USERS} SET newsletter_status = 'subscribed', newsletter_subscribed_at = CURRENT_TIMESTAMP, marketing_consent = TRUE, email_unsubscribed = FALSE WHERE id = $1 AND newsletter_status IS DISTINCT FROM 'subscribed' RETURNING ${PERSON_COLUMNS}`,
|
|
116
|
+
unsubscribe: `UPDATE ${USERS} SET newsletter_status = 'unsubscribed', newsletter_unsubscribed_at = CURRENT_TIMESTAMP, marketing_consent = FALSE, email_unsubscribed = TRUE WHERE id = $1 AND newsletter_status IS DISTINCT FROM 'unsubscribed' RETURNING ${PERSON_COLUMNS}`,
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/** What the confirmation email says when the project's template has no body. */
|
|
120
|
+
export const DEFAULT_NEWSLETTER_CONFIRMATION_EMAIL = {
|
|
121
|
+
subject: 'Confirm you want our newsletter',
|
|
122
|
+
body:
|
|
123
|
+
'<p>Please confirm that you want to receive the {{site_name}} newsletter at {{email}}.</p>' +
|
|
124
|
+
'<p><a href="{{confirm_url}}">Yes, send me the newsletter</a></p>' +
|
|
125
|
+
'<p>The link works for 7 days. Did not sign up? Ignore this email: you will not be subscribed unless you click the link.</p>',
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export interface NewsletterHelperOptions {
|
|
129
|
+
settings: UIDLNewsletterSettings
|
|
130
|
+
/** The `{{site_name}}` of the emails; the request's host when empty. */
|
|
131
|
+
siteName?: string
|
|
132
|
+
/** The project has the in-app event bus (`hasAutomationsBus`). */
|
|
133
|
+
withAutomations?: boolean
|
|
134
|
+
/**
|
|
135
|
+
* The sign-up route sends the account's own welcome email: a person who
|
|
136
|
+
* joins through the sign-up form's box is not sent the newsletter's too.
|
|
137
|
+
*/
|
|
138
|
+
signupSendsAccountWelcome?: boolean
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/** A same-site path without a query or fragment, else `fallback`. */
|
|
142
|
+
export const resolveNewsletterPagePath = (value: unknown, fallback: string): string => {
|
|
143
|
+
const path = typeof value === 'string' ? value.trim() : ''
|
|
144
|
+
if (
|
|
145
|
+
!path.startsWith('/') ||
|
|
146
|
+
path.startsWith('//') ||
|
|
147
|
+
/[\\?#\s"'<>]/.test(path) ||
|
|
148
|
+
path.indexOf('..') !== -1
|
|
149
|
+
) {
|
|
150
|
+
return fallback
|
|
151
|
+
}
|
|
152
|
+
return path.length > 1 ? path.replace(/\/+$/, '') : path
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const envNameOf = (value: unknown): string =>
|
|
156
|
+
typeof value === 'string' && /^[A-Za-z_][A-Za-z0-9_]*$/.test(value) ? value : ''
|
|
157
|
+
|
|
158
|
+
interface EmailCopy {
|
|
159
|
+
subject: string
|
|
160
|
+
body: string
|
|
161
|
+
localized: Record<string, { subject: string; body: string }>
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
const copyOf = (value: unknown): EmailCopy => {
|
|
165
|
+
const template = (value && typeof value === 'object' ? value : {}) as Record<string, unknown>
|
|
166
|
+
const localized: Record<string, { subject: string; body: string }> = {}
|
|
167
|
+
const copies =
|
|
168
|
+
template.localized && typeof template.localized === 'object'
|
|
169
|
+
? (template.localized as Record<string, unknown>)
|
|
170
|
+
: {}
|
|
171
|
+
for (const [locale, copy] of Object.entries(copies)) {
|
|
172
|
+
const entry = (copy && typeof copy === 'object' ? copy : {}) as Record<string, unknown>
|
|
173
|
+
if (typeof entry.body === 'string' && entry.body) {
|
|
174
|
+
localized[locale] = {
|
|
175
|
+
subject: typeof entry.subject === 'string' ? entry.subject : '',
|
|
176
|
+
body: entry.body,
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
return {
|
|
181
|
+
subject: typeof template.subject === 'string' ? template.subject : '',
|
|
182
|
+
body: typeof template.body === 'string' ? template.body : '',
|
|
183
|
+
localized,
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/** What a welcome email whose body has no `{{unsubscribe_url}}` gets, before `</body>`. */
|
|
188
|
+
export const NEWSLETTER_UNSUBSCRIBE_FOOTER =
|
|
189
|
+
'<p style="font-size:12px;color:#6b7280;margin-top:24px">You receive this email because you subscribed to the {{site_name}} newsletter. <a href="{{unsubscribe_url}}">Unsubscribe</a></p>'
|
|
190
|
+
|
|
191
|
+
/** A newsletter email body that always carries its unsubscribe link. */
|
|
192
|
+
export const withUnsubscribeLink = (body: string): string => {
|
|
193
|
+
if (!body || body.indexOf('{{unsubscribe_url}}') !== -1) {
|
|
194
|
+
return body
|
|
195
|
+
}
|
|
196
|
+
const close = body.search(/<\/body>/i)
|
|
197
|
+
return close === -1
|
|
198
|
+
? body + NEWSLETTER_UNSUBSCRIBE_FOOTER
|
|
199
|
+
: body.slice(0, close) + NEWSLETTER_UNSUBSCRIBE_FOOTER + body.slice(close)
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
const MAILGUN_DOMAIN_READ = "var domain = process.env.MAILGUN_DOMAIN || '';"
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Each provider's send call, and the same call with the message's own headers
|
|
206
|
+
* (`msg.headers`, the welcome email's `List-Unsubscribe`). MailerSend sets
|
|
207
|
+
* custom headers only on some plans: its emails carry the footer link alone.
|
|
208
|
+
*/
|
|
209
|
+
const PROVIDER_HEADER_CALLS: Record<string, [string, string]> = {
|
|
210
|
+
resend: [
|
|
211
|
+
'resend.emails.send({ from: sender.header, to: [msg.to], subject: msg.subject, html: msg.html })',
|
|
212
|
+
'resend.emails.send({ from: sender.header, to: [msg.to], subject: msg.subject, html: msg.html, headers: msg.headers || undefined })',
|
|
213
|
+
],
|
|
214
|
+
sendgrid: [
|
|
215
|
+
'sgMail.send({ to: msg.to, from: from, subject: msg.subject, html: msg.html })',
|
|
216
|
+
'sgMail.send({ to: msg.to, from: from, subject: msg.subject, html: msg.html, headers: msg.headers || undefined })',
|
|
217
|
+
],
|
|
218
|
+
postmark: [
|
|
219
|
+
'client.sendEmail({ From: sender.header, To: msg.to, Subject: msg.subject, HtmlBody: msg.html })',
|
|
220
|
+
'client.sendEmail({ From: sender.header, To: msg.to, Subject: msg.subject, HtmlBody: msg.html, Headers: msg.headers ? Object.keys(msg.headers).map(function (name) { return { Name: name, Value: msg.headers[name] }; }) : undefined })',
|
|
221
|
+
],
|
|
222
|
+
mailgun: [
|
|
223
|
+
'mg.messages.create(domain, { from: sender.header, to: [msg.to], subject: msg.subject, html: msg.html })',
|
|
224
|
+
"mg.messages.create(domain, Object.keys(msg.headers || {}).reduce(function (message, name) { message['h:' + name] = msg.headers[name]; return message; }, { from: sender.header, to: [msg.to], subject: msg.subject, html: msg.html }))",
|
|
225
|
+
],
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* The provider send, with the message's headers, and Mailgun's domain read
|
|
230
|
+
* from the env var the settings name. Fails the generation when the shared
|
|
231
|
+
* send no longer reads as expected, so a change there cannot drop them.
|
|
232
|
+
*/
|
|
233
|
+
const providerSendCode = (provider: string | null): string => {
|
|
234
|
+
let code = generateProviderSendFunction(provider)
|
|
235
|
+
const call = provider ? PROVIDER_HEADER_CALLS[provider] : undefined
|
|
236
|
+
if (call) {
|
|
237
|
+
if (code.indexOf(call[0]) === -1) {
|
|
238
|
+
throw new Error(`The ${provider} send no longer reads as the newsletter expects`)
|
|
239
|
+
}
|
|
240
|
+
code = code.replace(call[0], call[1])
|
|
241
|
+
}
|
|
242
|
+
if (provider !== 'mailgun') {
|
|
243
|
+
return code
|
|
244
|
+
}
|
|
245
|
+
if (code.indexOf(MAILGUN_DOMAIN_READ) === -1) {
|
|
246
|
+
throw new Error('The Mailgun send no longer reads MAILGUN_DOMAIN as the newsletter expects')
|
|
247
|
+
}
|
|
248
|
+
return code.replace(
|
|
249
|
+
MAILGUN_DOMAIN_READ,
|
|
250
|
+
"var domain = (EMAIL_DOMAIN_ENV_NAME ? process.env[EMAIL_DOMAIN_ENV_NAME] : process.env.MAILGUN_DOMAIN) || '';"
|
|
251
|
+
)
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
const eventRecorderCode = (withAutomations: boolean): string =>
|
|
255
|
+
withAutomations
|
|
256
|
+
? `// The project has automations: joining and leaving wake them. Best effort:
|
|
257
|
+
// recording can never fail the request. One event per person per minute
|
|
258
|
+
// (the dedupe key's minute), so a later re-subscribe is an event of its own.
|
|
259
|
+
async function recordNewsletterEvent(type, row, req) {
|
|
260
|
+
try {
|
|
261
|
+
var id = row && row.id != null ? String(row.id) : '';
|
|
262
|
+
if (!id) { return; }
|
|
263
|
+
var email = row.email ? String(row.email) : '';
|
|
264
|
+
var bus = require('${RELATIVE_PREFIX}/${AUTOMATIONS_PATH.join('/')}/event-bus');
|
|
265
|
+
await bus.emitBusinessEvent({
|
|
266
|
+
type: type,
|
|
267
|
+
entityType: 'subscriber',
|
|
268
|
+
entityId: id,
|
|
269
|
+
payload: {
|
|
270
|
+
subscriber: {
|
|
271
|
+
email: email,
|
|
272
|
+
source: row.source ? String(row.source) : null,
|
|
273
|
+
consent: type === 'newsletter-subscribed',
|
|
274
|
+
},
|
|
275
|
+
},
|
|
276
|
+
actor: email,
|
|
277
|
+
actorType: 'customer',
|
|
278
|
+
dedupeKey: type + ':' + id + ':' + Math.floor(Date.now() / 60000),
|
|
279
|
+
}, req);
|
|
280
|
+
} catch (eventErr) {
|
|
281
|
+
console.error('[newsletter] could not record the ' + type + ' event:', eventErr && eventErr.message ? eventErr.message : eventErr);
|
|
282
|
+
}
|
|
283
|
+
}`
|
|
284
|
+
: `// The project has no automations: nothing listens for newsletter events.
|
|
285
|
+
async function recordNewsletterEvent() {}`
|
|
286
|
+
|
|
287
|
+
export const generateNewsletterHelperCode = (options: NewsletterHelperOptions): string => {
|
|
288
|
+
const { settings } = options
|
|
289
|
+
const email = settings.email || ({} as UIDLNewsletterSettings['email'])
|
|
290
|
+
const provider =
|
|
291
|
+
email.provider && SUPPORTED_EMAIL_PROVIDERS.has(email.provider) ? email.provider : null
|
|
292
|
+
const confirmation = copyOf(settings.templates && settings.templates.confirmation)
|
|
293
|
+
if (!confirmation.body) {
|
|
294
|
+
confirmation.subject = confirmation.subject || DEFAULT_NEWSLETTER_CONFIRMATION_EMAIL.subject
|
|
295
|
+
confirmation.body = DEFAULT_NEWSLETTER_CONFIRMATION_EMAIL.body
|
|
296
|
+
}
|
|
297
|
+
const welcome = copyOf(settings.templates && settings.templates.welcome)
|
|
298
|
+
// A newsletter email always carries its way out.
|
|
299
|
+
welcome.body = withUnsubscribeLink(welcome.body)
|
|
300
|
+
for (const locale of Object.keys(welcome.localized)) {
|
|
301
|
+
welcome.localized[locale].body = withUnsubscribeLink(welcome.localized[locale].body)
|
|
302
|
+
}
|
|
303
|
+
const sender = settings.sender || { name: '', email: '' }
|
|
304
|
+
const pages = settings.pages || ({} as UIDLNewsletterSettings['pages'])
|
|
305
|
+
|
|
306
|
+
return `'use strict';
|
|
307
|
+
/**
|
|
308
|
+
* The newsletter (generated): how a person joins it and leaves it. Every
|
|
309
|
+
* writer of the newsletter state goes through this module.
|
|
310
|
+
*/
|
|
311
|
+
var crypto = require('crypto');
|
|
312
|
+
var __security = require('${securityRuntimeSpecifier(RELATIVE_PREFIX)}');
|
|
313
|
+
${generateEmailLocaleRequire(RELATIVE_PREFIX)}
|
|
314
|
+
${
|
|
315
|
+
provider
|
|
316
|
+
? `var __sentEmailLog = require('${RELATIVE_PREFIX}/utils/email/sent-email-log');`
|
|
317
|
+
: 'var __sentEmailLog = null;'
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
${generateLazyPgClientCode()}
|
|
321
|
+
|
|
322
|
+
var CONFIRMATION_REQUIRED = ${settings.confirmation === true};
|
|
323
|
+
var WELCOME_ENABLED = ${settings.welcome === true && !!welcome.body};
|
|
324
|
+
var SIGNUP_SENDS_ACCOUNT_WELCOME = ${options.signupSendsAccountWelcome === true};
|
|
325
|
+
var SITE_NAME = ${JSON.stringify(options.siteName || '')};
|
|
326
|
+
var SENDER_NAME = ${JSON.stringify(typeof sender.name === 'string' ? sender.name : '')};
|
|
327
|
+
var SENDER_EMAIL = ${JSON.stringify(typeof sender.email === 'string' ? sender.email : '')};
|
|
328
|
+
var EMAIL_PROVIDER = ${JSON.stringify(provider)};
|
|
329
|
+
var EMAIL_SECRET_ENV_NAME = ${JSON.stringify(envNameOf(email.apiKeyEnv))};
|
|
330
|
+
var EMAIL_DOMAIN_ENV_NAME = ${JSON.stringify(envNameOf(email.domainEnv))};
|
|
331
|
+
var CONFIRMATION_EMAIL = ${JSON.stringify({
|
|
332
|
+
subject: confirmation.subject,
|
|
333
|
+
body: confirmation.body,
|
|
334
|
+
})};
|
|
335
|
+
var CONFIRMATION_EMAIL_LOCALIZED = ${JSON.stringify(confirmation.localized)};
|
|
336
|
+
var WELCOME_EMAIL = ${JSON.stringify({ subject: welcome.subject, body: welcome.body })};
|
|
337
|
+
var WELCOME_EMAIL_LOCALIZED = ${JSON.stringify(welcome.localized)};
|
|
338
|
+
var CONFIRM_PAGE_PATH = ${JSON.stringify(
|
|
339
|
+
resolveNewsletterPagePath(pages.confirm, DEFAULT_NEWSLETTER_CONFIRM_PATH)
|
|
340
|
+
)};
|
|
341
|
+
var UNSUBSCRIBE_PAGE_PATH = ${JSON.stringify(
|
|
342
|
+
resolveNewsletterPagePath(pages.unsubscribe, DEFAULT_NEWSLETTER_UNSUBSCRIBE_PATH)
|
|
343
|
+
)};
|
|
344
|
+
var UNSUBSCRIBE_ROUTE = ${JSON.stringify(NEWSLETTER_UNSUBSCRIBE_URL)};
|
|
345
|
+
|
|
346
|
+
// Every sign-up answers after at least this long, whatever happened.
|
|
347
|
+
var NEWSLETTER_MIN_RESPONSE_MS = ${NEWSLETTER_MIN_RESPONSE_MS};
|
|
348
|
+
// Sign-ups one address may make per hour (counted for every address).
|
|
349
|
+
var ADDRESS_LIMIT = ${NEWSLETTER_ADDRESS_LIMIT};
|
|
350
|
+
var NEWSLETTER_SOURCES = ${JSON.stringify(NEWSLETTER_SOURCES)};
|
|
351
|
+
var VISITOR_SIGN_UP_POINTS = ${JSON.stringify(VISITOR_SIGN_UP_POINTS)};
|
|
352
|
+
// The sign-up points of the site's pages: all the public sign-up route takes.
|
|
353
|
+
var PUBLIC_ROUTE_SIGN_UP_POINTS = ${JSON.stringify(PUBLIC_ROUTE_SIGN_UP_POINTS)};
|
|
354
|
+
// An address that opted out is sent at most this many confirmation links a day.
|
|
355
|
+
var OPTED_OUT_CONFIRMATIONS_PER_DAY = ${NEWSLETTER_OPTED_OUT_CONFIRMATIONS_PER_DAY};
|
|
356
|
+
// Where a row the newsletter adds came from (users.source); 'newsletter' for
|
|
357
|
+
// the newsletter's own sign-up points.
|
|
358
|
+
var ACCOUNT_SOURCE_OF_POINT = { signup: 'signup', checkout: 'checkout', booking: 'booking', form: 'form', import: 'import', manual: 'manual' };
|
|
359
|
+
|
|
360
|
+
var TOKEN_KEY_LABEL = ${JSON.stringify(newsletterTokenSpec.keyLabel)};
|
|
361
|
+
var TOKEN_PURPOSES = ${JSON.stringify(newsletterTokenSpec.purposes)};
|
|
362
|
+
var CONFIRM_TOKEN_MAX_AGE_SECONDS = ${newsletterTokenSpec.confirmMaxAgeSeconds};
|
|
363
|
+
var TOKEN_FUTURE_SKEW_SECONDS = ${newsletterTokenSpec.futureSkewSeconds};
|
|
364
|
+
var TOKEN_MAX_LENGTH = ${newsletterTokenSpec.maxTokenLength};
|
|
365
|
+
|
|
366
|
+
var SQL = ${JSON.stringify(NEWSLETTER_SQL, null, 2)};
|
|
367
|
+
|
|
368
|
+
/** The address as the newsletter keeps it (trimmed, lower-cased), or '' when it is not one. */
|
|
369
|
+
function normalizeEmail(value) {
|
|
370
|
+
var email = typeof value === 'string' ? value.trim().toLowerCase() : '';
|
|
371
|
+
if (email.length < 3 || email.length > 254 || !/^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(email)) { return ''; }
|
|
372
|
+
return email;
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
/** A sign-up point a visitor's request names; 'block' for anything else. */
|
|
376
|
+
function visitorSignUpPoint(value) {
|
|
377
|
+
return VISITOR_SIGN_UP_POINTS.indexOf(value) !== -1 ? value : 'block';
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
/** The sign-up point the public route takes from its body: a page's own, else 'block'. */
|
|
381
|
+
function publicRouteSignUpPoint(value) {
|
|
382
|
+
return PUBLIC_ROUTE_SIGN_UP_POINTS.indexOf(value) !== -1 ? value : 'block';
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
/**
|
|
386
|
+
* What a log line may keep of an error: its code and message, never a
|
|
387
|
+
* database row (pg's \`detail\`) or anything else it carries.
|
|
388
|
+
*/
|
|
389
|
+
function safeError(err) {
|
|
390
|
+
return {
|
|
391
|
+
code: err && err.code ? String(err.code) : null,
|
|
392
|
+
message: err && err.message ? String(err.message) : String(err),
|
|
393
|
+
};
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
function signUpPointOf(value) {
|
|
397
|
+
return NEWSLETTER_SOURCES.indexOf(value) !== -1 ? value : 'block';
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
/**
|
|
401
|
+
* What every sign-up answers: the same for a new address, a known one, an
|
|
402
|
+
* unsubscribed one, a limited one and a bot. \`pending\` is the settings' (a
|
|
403
|
+
* confirmation email is on its way when double opt-in is on), never the
|
|
404
|
+
* address's.
|
|
405
|
+
*/
|
|
406
|
+
function publicSubscribeAnswer() {
|
|
407
|
+
return { ok: true, pending: CONFIRMATION_REQUIRED };
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
function waitUntilElapsed(startedAt, ms) {
|
|
411
|
+
var left = ms - (Date.now() - startedAt);
|
|
412
|
+
return left > 0 ? new Promise(function (resolve) { setTimeout(resolve, left); }) : Promise.resolve();
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
/** Runs \`fn(db)\` on one connection to the site's database, closed afterwards. */
|
|
416
|
+
async function withNewsletterDb(fn) {
|
|
417
|
+
var client = getClient();
|
|
418
|
+
if (typeof client.on === 'function') { client.on('error', function () {}); }
|
|
419
|
+
await client.connect();
|
|
420
|
+
try {
|
|
421
|
+
return await fn(client);
|
|
422
|
+
} finally {
|
|
423
|
+
try { await client.end(); } catch (_e) {}
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
function rowOf(result) {
|
|
428
|
+
return result && result.rows && result.rows[0] ? result.rows[0] : null;
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
// ---------------------------------------------------------------------------
|
|
432
|
+
// The links' tokens (see newsletterTokenSpec in the code generator)
|
|
433
|
+
// ---------------------------------------------------------------------------
|
|
434
|
+
|
|
435
|
+
var __tokenKeyCache = { secret: null, key: null };
|
|
436
|
+
|
|
437
|
+
function newsletterTokenKey() {
|
|
438
|
+
var secret = process.env.NEXTAUTH_SECRET || '';
|
|
439
|
+
if (!secret) { return null; }
|
|
440
|
+
if (__tokenKeyCache.secret !== secret) {
|
|
441
|
+
__tokenKeyCache = { secret: secret, key: crypto.createHmac('sha256', secret).update(TOKEN_KEY_LABEL).digest() };
|
|
442
|
+
}
|
|
443
|
+
return __tokenKeyCache.key;
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
function toBase64Url(buffer) {
|
|
447
|
+
return buffer.toString('base64').replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/, '');
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
function fromBase64Url(text) {
|
|
451
|
+
if (typeof text !== 'string' || !text || !/^[A-Za-z0-9_-]+$/.test(text)) { return null; }
|
|
452
|
+
var base64 = text.replace(/-/g, '+').replace(/_/g, '/');
|
|
453
|
+
while (base64.length % 4) { base64 += '='; }
|
|
454
|
+
return Buffer.from(base64, 'base64');
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
function nowSeconds() {
|
|
458
|
+
return Math.floor(Date.now() / 1000);
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
/** The token of a confirm or unsubscribe link for \`email\`; null without the app secret. */
|
|
462
|
+
function signNewsletterToken(email, purpose, issuedAt) {
|
|
463
|
+
var key = newsletterTokenKey();
|
|
464
|
+
var address = normalizeEmail(email);
|
|
465
|
+
if (!key || !address || TOKEN_PURPOSES.indexOf(purpose) === -1) { return null; }
|
|
466
|
+
var at = issuedAt === undefined ? nowSeconds() : Math.floor(Number(issuedAt));
|
|
467
|
+
if (!isFinite(at) || at < 0) { return null; }
|
|
468
|
+
var payload = Buffer.from(address + '|' + purpose + '|' + at, 'utf8');
|
|
469
|
+
return toBase64Url(payload) + '.' + toBase64Url(crypto.createHmac('sha256', key).update(payload).digest());
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
/** \`{ email, purpose, issuedAt }\` for a live token of \`purpose\`, else null. */
|
|
473
|
+
function verifyNewsletterToken(token, purpose) {
|
|
474
|
+
var key = newsletterTokenKey();
|
|
475
|
+
if (!key || typeof token !== 'string' || token.length > TOKEN_MAX_LENGTH || TOKEN_PURPOSES.indexOf(purpose) === -1) { return null; }
|
|
476
|
+
var parts = token.trim().split('.');
|
|
477
|
+
if (parts.length !== 2) { return null; }
|
|
478
|
+
var payload = fromBase64Url(parts[0]);
|
|
479
|
+
var mac = fromBase64Url(parts[1]);
|
|
480
|
+
if (!payload || !mac || mac.length !== 32) { return null; }
|
|
481
|
+
var expected = crypto.createHmac('sha256', key).update(payload).digest();
|
|
482
|
+
if (!crypto.timingSafeEqual(mac, expected)) { return null; }
|
|
483
|
+
var text = payload.toString('utf8');
|
|
484
|
+
var last = text.lastIndexOf('|');
|
|
485
|
+
var middle = last > 0 ? text.lastIndexOf('|', last - 1) : -1;
|
|
486
|
+
if (middle <= 0) { return null; }
|
|
487
|
+
var email = text.slice(0, middle);
|
|
488
|
+
var issued = text.slice(last + 1);
|
|
489
|
+
if (text.slice(middle + 1, last) !== purpose || !/^[0-9]{1,12}$/.test(issued) || normalizeEmail(email) !== email) { return null; }
|
|
490
|
+
var issuedAt = Number(issued);
|
|
491
|
+
var now = nowSeconds();
|
|
492
|
+
if (issuedAt > now + TOKEN_FUTURE_SKEW_SECONDS) { return null; }
|
|
493
|
+
if (purpose === 'confirm' && now - issuedAt > CONFIRM_TOKEN_MAX_AGE_SECONDS) { return null; }
|
|
494
|
+
return { email: email, purpose: purpose, issuedAt: issuedAt };
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
// ---------------------------------------------------------------------------
|
|
498
|
+
// Emails
|
|
499
|
+
// ---------------------------------------------------------------------------
|
|
500
|
+
|
|
501
|
+
${TRUSTED_ORIGIN_CODE}
|
|
502
|
+
|
|
503
|
+
${generateFillTemplateFn()}
|
|
504
|
+
|
|
505
|
+
${providerSendCode(provider)}
|
|
506
|
+
|
|
507
|
+
function siteNameOf(req) {
|
|
508
|
+
if (SITE_NAME) { return SITE_NAME; }
|
|
509
|
+
var host = req && req.headers && req.headers.host ? String(req.headers.host) : '';
|
|
510
|
+
return host.replace(/^www\\./, '').split(':')[0];
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
function senderAddress() {
|
|
514
|
+
var email = String(SENDER_EMAIL || process.env.EMAIL_FROM || '').trim();
|
|
515
|
+
if (!email) { return ''; }
|
|
516
|
+
var name = String(SENDER_NAME || '').replace(/[\\r\\n<>"]/g, '').trim();
|
|
517
|
+
return name && email.indexOf('<') === -1 ? name + ' <' + email + '>' : email;
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
function emailCredential() {
|
|
521
|
+
var apiKey = EMAIL_SECRET_ENV_NAME ? process.env[EMAIL_SECRET_ENV_NAME] : '';
|
|
522
|
+
if (apiKey && String(apiKey).indexOf('teleporthq.secrets.') === 0) { apiKey = ''; }
|
|
523
|
+
return apiKey ? String(apiKey) : '';
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
/** Whether the site can mail a newsletter email at all (a provider, its credential, a sender). */
|
|
527
|
+
function canSendNewsletterEmail() {
|
|
528
|
+
return !!EMAIL_PROVIDER && !!emailCredential() && !!senderAddress();
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
// A link to one of the site's pages carries the token in its fragment: a
|
|
532
|
+
// fragment never reaches a server, a CDN log or a Referer (the page's first
|
|
533
|
+
// head script keeps it). The site's own unsubscribe route reads it on the
|
|
534
|
+
// server, so a link to it carries it in the query.
|
|
535
|
+
function pageLink(path, token) {
|
|
536
|
+
return path + (path.indexOf('/api/') === 0 ? '?t=' : '#t=') + encodeURIComponent(token);
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
// The token, wherever it appears, for what the sent-email log keeps: whoever
|
|
540
|
+
// reads the log cannot confirm or unsubscribe someone else with it.
|
|
541
|
+
function hideToken(text, token) {
|
|
542
|
+
return String(text == null ? '' : text).split(token).join('[hidden]');
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
/**
|
|
546
|
+
* Mails the \`confirmation\` (its link confirms the subscription) or the
|
|
547
|
+
* \`welcome\` (its link unsubscribes) email to \`toEmail\`, in \`locale\`'s copy,
|
|
548
|
+
* with links to this site's pages. Recorded in the sent-email log, the
|
|
549
|
+
* token hidden. Resolves whether it was sent; never throws.
|
|
550
|
+
*/
|
|
551
|
+
async function sendNewsletterEmail(kind, toEmail, locale, req, userId) {
|
|
552
|
+
var to = normalizeEmail(toEmail);
|
|
553
|
+
var template = kind === 'confirmation' ? CONFIRMATION_EMAIL : kind === 'welcome' ? WELCOME_EMAIL : null;
|
|
554
|
+
if (!template || !to) { return false; }
|
|
555
|
+
if (!EMAIL_PROVIDER) { console.warn('[newsletter] ' + kind + ' email not sent: no email provider is configured'); return false; }
|
|
556
|
+
var apiKey = emailCredential();
|
|
557
|
+
if (!apiKey) { console.warn('[newsletter] ' + kind + ' email not sent: the email credential is not set'); return false; }
|
|
558
|
+
var from = senderAddress();
|
|
559
|
+
if (!from) { console.warn('[newsletter] ' + kind + ' email not sent: no sender is configured'); return false; }
|
|
560
|
+
var purpose = kind === 'confirmation' ? 'confirm' : 'unsubscribe';
|
|
561
|
+
var token = signNewsletterToken(to, purpose);
|
|
562
|
+
if (!token) { console.warn('[newsletter] ' + kind + ' email not sent: the app secret is not set'); return false; }
|
|
563
|
+
var link = trustedOrigin(req) + pageLink(kind === 'confirmation' ? CONFIRM_PAGE_PATH : UNSUBSCRIBE_PAGE_PATH, token);
|
|
564
|
+
var values = kind === 'confirmation'
|
|
565
|
+
? { confirm_url: link, site_name: siteNameOf(req), email: to }
|
|
566
|
+
: { unsubscribe_url: link, site_name: siteNameOf(req), email: to };
|
|
567
|
+
var copy = __emailLocale.pickLocalizedTemplate(template, kind === 'confirmation' ? CONFIRMATION_EMAIL_LOCALIZED : WELCOME_EMAIL_LOCALIZED, locale);
|
|
568
|
+
if (!copy.body) { return false; }
|
|
569
|
+
var subject = fillSubjectTemplate(copy.subject, values);
|
|
570
|
+
var html = fillTemplate(copy.body, values);
|
|
571
|
+
// The welcome is a newsletter message: mail clients offer its way out too,
|
|
572
|
+
// through the route that reads the token on the server and asks first.
|
|
573
|
+
var headers = kind === 'welcome' ? { 'List-Unsubscribe': '<' + trustedOrigin(req) + UNSUBSCRIBE_ROUTE + '?t=' + encodeURIComponent(token) + '>' } : undefined;
|
|
574
|
+
var failure = null;
|
|
575
|
+
try {
|
|
576
|
+
await __sendProviderEmail({ from: from, to: to, subject: subject, html: html, apiKey: apiKey, headers: headers });
|
|
577
|
+
} catch (err) {
|
|
578
|
+
failure = err;
|
|
579
|
+
}
|
|
580
|
+
if (__sentEmailLog) {
|
|
581
|
+
__sentEmailLog.recordSentEmail({
|
|
582
|
+
emailType: 'newsletter-' + kind,
|
|
583
|
+
audience: 'customer',
|
|
584
|
+
to: to,
|
|
585
|
+
from: from,
|
|
586
|
+
subject: hideToken(subject, token),
|
|
587
|
+
html: hideToken(html, token),
|
|
588
|
+
payload: { recipientEmail: to },
|
|
589
|
+
provider: EMAIL_PROVIDER,
|
|
590
|
+
status: failure ? 'failed' : 'sent',
|
|
591
|
+
error: failure ? (failure.message || String(failure)) : null,
|
|
592
|
+
source: 'newsletter',
|
|
593
|
+
sourceRef: 'utils/newsletter',
|
|
594
|
+
userId: userId != null ? userId : null,
|
|
595
|
+
});
|
|
596
|
+
await __sentEmailLog.settleSentEmailLog();
|
|
597
|
+
}
|
|
598
|
+
if (failure) {
|
|
599
|
+
// A provider may echo the recipient: the log never keeps it.
|
|
600
|
+
console.error('[newsletter] the ' + kind + ' email could not be sent:', String(failure.message || failure).split(to).join('[address]'));
|
|
601
|
+
return false;
|
|
602
|
+
}
|
|
603
|
+
return true;
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
// ---------------------------------------------------------------------------
|
|
607
|
+
// Events
|
|
608
|
+
// ---------------------------------------------------------------------------
|
|
609
|
+
|
|
610
|
+
${eventRecorderCode(options.withAutomations === true)}
|
|
611
|
+
|
|
612
|
+
// ---------------------------------------------------------------------------
|
|
613
|
+
// Joining and leaving
|
|
614
|
+
// ---------------------------------------------------------------------------
|
|
615
|
+
|
|
616
|
+
async function findPerson(db, email) {
|
|
617
|
+
return rowOf(await db.query(SQL.findPerson, [email]));
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
// The person is on the list now: the automations hear of it, and they are
|
|
621
|
+
// welcomed (not when they joined through the sign-up form whose route sends
|
|
622
|
+
// the account's own welcome; an \`account\` sign-up, the account page's
|
|
623
|
+
// switch, is welcomed like any other).
|
|
624
|
+
async function joinedNewsletter(row, point, locale, req) {
|
|
625
|
+
await recordNewsletterEvent('newsletter-subscribed', row, req);
|
|
626
|
+
if (WELCOME_ENABLED && !(point === 'signup' && SIGNUP_SENDS_ACCOUNT_WELCOME)) {
|
|
627
|
+
await sendNewsletterEmail('welcome', row.email, locale, req, row.id);
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
/**
|
|
632
|
+
* Adds \`email\` to the newsletter from \`signUpPoint\` (a \`newsletter_source\`).
|
|
633
|
+
* The caller handled the honeypot and answers \`publicSubscribeAnswer()\`
|
|
634
|
+
* whatever this resolves: \`{ outcome }\`, one of
|
|
635
|
+
* 'invalid' not an address;
|
|
636
|
+
* 'limited' this address signed up ${NEWSLETTER_ADDRESS_LIMIT} times this hour, or an
|
|
637
|
+
* opted-out address was already sent its confirmation today;
|
|
638
|
+
* 'already' already subscribed: nothing changes, nothing is sent;
|
|
639
|
+
* 'confirm-sent' a confirmation link was mailed (double opt-in, or an
|
|
640
|
+
* address that unsubscribed or opted out of email: nothing
|
|
641
|
+
* is written);
|
|
642
|
+
* 'pending' double opt-in, but no confirmation email could go out;
|
|
643
|
+
* 'noop' an unsubscribed address and no way to mail it;
|
|
644
|
+
* 'subscribed' single opt-in: on the list now (event, welcome email).
|
|
645
|
+
*/
|
|
646
|
+
async function subscribeNewsletterPerson(input) {
|
|
647
|
+
var o = input || {};
|
|
648
|
+
var db = o.db;
|
|
649
|
+
var req = o.req;
|
|
650
|
+
var email = normalizeEmail(o.email);
|
|
651
|
+
if (!email) { return { outcome: 'invalid' }; }
|
|
652
|
+
var point = signUpPointOf(o.signUpPoint);
|
|
653
|
+
var limit = await __security.rateLimit({ key: 'newsletter:' + email, limit: ADDRESS_LIMIT, windowSeconds: 3600 });
|
|
654
|
+
if (!limit.allowed) { return { outcome: 'limited' }; }
|
|
655
|
+
var locale = __emailLocale.resolveRequestLocale(req);
|
|
656
|
+
var accountSource = ACCOUNT_SOURCE_OF_POINT[point] || 'newsletter';
|
|
657
|
+
// Twice at most: a row that changed between the read and the write is read again.
|
|
658
|
+
for (var attempt = 0; attempt < 2; attempt++) {
|
|
659
|
+
var person = await findPerson(db, email);
|
|
660
|
+
if (person && person.newsletter_status === 'subscribed') { return { outcome: 'already' }; }
|
|
661
|
+
if (person && (person.newsletter_status === 'unsubscribed' || person.email_unsubscribed === true)) {
|
|
662
|
+
// Anyone can type anyone's address: a form never undoes an opt-out (off
|
|
663
|
+
// the newsletter, or off every marketing email). The address's owner is
|
|
664
|
+
// asked to confirm instead, at most once a day, and nothing is written.
|
|
665
|
+
if (!canSendNewsletterEmail()) { return { outcome: 'noop' }; }
|
|
666
|
+
var daily = await __security.rateLimit({ key: 'newsletter-resubscribe:' + email, limit: OPTED_OUT_CONFIRMATIONS_PER_DAY, windowSeconds: 86400 });
|
|
667
|
+
if (!daily.allowed) { return { outcome: 'limited' }; }
|
|
668
|
+
var resent = await sendNewsletterEmail('confirmation', email, locale, req, person.id);
|
|
669
|
+
return { outcome: resent ? 'confirm-sent' : 'noop' };
|
|
670
|
+
}
|
|
671
|
+
if (CONFIRMATION_REQUIRED) {
|
|
672
|
+
var pending = rowOf(person
|
|
673
|
+
? await db.query(SQL.markPending, [person.id, point])
|
|
674
|
+
: await db.query(SQL.insertPending, [email, accountSource, point]));
|
|
675
|
+
if (!pending) { continue; }
|
|
676
|
+
var sent = await sendNewsletterEmail('confirmation', email, locale, req, pending.id);
|
|
677
|
+
return { outcome: sent ? 'confirm-sent' : 'pending' };
|
|
678
|
+
}
|
|
679
|
+
var joined = rowOf(person
|
|
680
|
+
? await db.query(SQL.markSubscribed, [person.id, point])
|
|
681
|
+
: await db.query(SQL.insertSubscribed, [email, accountSource, point]));
|
|
682
|
+
if (!joined) { continue; }
|
|
683
|
+
await joinedNewsletter(joined, point, locale, req);
|
|
684
|
+
return { outcome: 'subscribed' };
|
|
685
|
+
}
|
|
686
|
+
return { outcome: 'noop' };
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
/**
|
|
690
|
+
* The confirmation link: \`{ ok: true, email }\` once the person is subscribed
|
|
691
|
+
* (opening it again answers the same), \`{ ok: false }\` for a link that is
|
|
692
|
+
* not one, expired (${
|
|
693
|
+
newsletterTokenSpec.confirmMaxAgeSeconds / 86400
|
|
694
|
+
} days), or mailed before the person last unsubscribed.
|
|
695
|
+
*/
|
|
696
|
+
async function confirmNewsletter(input) {
|
|
697
|
+
var o = input || {};
|
|
698
|
+
var claim = verifyNewsletterToken(o.token, 'confirm');
|
|
699
|
+
if (!claim) { return { ok: false }; }
|
|
700
|
+
var person = await findPerson(o.db, claim.email);
|
|
701
|
+
if (!person) { return { ok: false }; }
|
|
702
|
+
if (person.newsletter_status === 'subscribed') { return { ok: true, email: claim.email }; }
|
|
703
|
+
var leftAt = person.newsletter_unsubscribed_at ? new Date(person.newsletter_unsubscribed_at).getTime() : NaN;
|
|
704
|
+
if (isFinite(leftAt) && claim.issuedAt < Math.floor(leftAt / 1000)) { return { ok: false }; }
|
|
705
|
+
var confirmed = rowOf(await o.db.query(SQL.confirm, [person.id]));
|
|
706
|
+
if (confirmed) {
|
|
707
|
+
await joinedNewsletter(confirmed, confirmed.newsletter_source, __emailLocale.resolveRequestLocale(o.req), o.req);
|
|
708
|
+
}
|
|
709
|
+
return { ok: true, email: claim.email };
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
/**
|
|
713
|
+
* The unsubscribe link: \`{ ok: true, email }\` once the person is off the list
|
|
714
|
+
* (idempotent: the event is recorded once, when a subscriber leaves),
|
|
715
|
+
* \`{ ok: false }\` for a link that is not one.
|
|
716
|
+
*/
|
|
717
|
+
async function unsubscribeNewsletter(input) {
|
|
718
|
+
var o = input || {};
|
|
719
|
+
var claim = verifyNewsletterToken(o.token, 'unsubscribe');
|
|
720
|
+
if (!claim) { return { ok: false }; }
|
|
721
|
+
var person = await findPerson(o.db, claim.email);
|
|
722
|
+
if (!person || person.newsletter_status === 'unsubscribed') { return { ok: true, email: claim.email }; }
|
|
723
|
+
var left = rowOf(await o.db.query(SQL.unsubscribe, [person.id]));
|
|
724
|
+
if (left && person.newsletter_status === 'subscribed') {
|
|
725
|
+
await recordNewsletterEvent('newsletter-unsubscribed', left, o.req);
|
|
726
|
+
}
|
|
727
|
+
return { ok: true, email: claim.email };
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
module.exports = {
|
|
731
|
+
NEWSLETTER_MIN_RESPONSE_MS: NEWSLETTER_MIN_RESPONSE_MS,
|
|
732
|
+
normalizeEmail: normalizeEmail,
|
|
733
|
+
visitorSignUpPoint: visitorSignUpPoint,
|
|
734
|
+
publicRouteSignUpPoint: publicRouteSignUpPoint,
|
|
735
|
+
safeError: safeError,
|
|
736
|
+
publicSubscribeAnswer: publicSubscribeAnswer,
|
|
737
|
+
waitUntilElapsed: waitUntilElapsed,
|
|
738
|
+
withNewsletterDb: withNewsletterDb,
|
|
739
|
+
subscribeNewsletterPerson: subscribeNewsletterPerson,
|
|
740
|
+
confirmNewsletter: confirmNewsletter,
|
|
741
|
+
unsubscribeNewsletter: unsubscribeNewsletter,
|
|
742
|
+
signNewsletterToken: signNewsletterToken,
|
|
743
|
+
verifyNewsletterToken: verifyNewsletterToken,
|
|
744
|
+
sendNewsletterEmail: sendNewsletterEmail,
|
|
745
|
+
recordNewsletterEvent: recordNewsletterEvent,
|
|
746
|
+
};
|
|
747
|
+
`
|
|
748
|
+
}
|