@hartl-services/medusa-base 0.3.0 → 1.0.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/.medusa/server/src/admin/index.js +2164 -29
- package/.medusa/server/src/admin/index.mjs +2166 -31
- package/.medusa/server/src/api/admin/email/messages/[id]/resends/route.js +24 -0
- package/.medusa/server/src/api/admin/email/messages/[id]/route.js +12 -0
- package/.medusa/server/src/api/admin/email/messages/route.js +12 -0
- package/.medusa/server/src/api/admin/email/terms-versions/[id]/download/route.js +16 -0
- package/.medusa/server/src/api/admin/email/terms-versions/route.js +47 -0
- package/.medusa/server/src/api/admin/orders/[id]/documents/[document_id]/download/route.js +21 -0
- package/.medusa/server/src/api/admin/orders/[id]/documents/[document_id]/regenerate/route.js +38 -0
- package/.medusa/server/src/api/admin/orders/[id]/documents/regenerate/route.js +32 -0
- package/.medusa/server/src/api/admin/orders/[id]/documents/route.js +36 -0
- package/.medusa/server/src/api/admin/orders/[id]/packing-lists/[fulfillment_id]/download/route.js +24 -0
- package/.medusa/server/src/api/admin/orders/[id]/packing-lists/[fulfillment_id]/retry/route.js +44 -0
- package/.medusa/server/src/api/admin/orders/[id]/packing-lists/route.js +82 -0
- package/.medusa/server/src/api/admin/plugin-features/[plugin_key]/actions/[action_key]/route.js +31 -0
- package/.medusa/server/src/api/admin/plugin-features/[plugin_key]/actions/[action_key]/runs/route.js +16 -0
- package/.medusa/server/src/api/admin/plugin-features/[plugin_key]/route.js +14 -0
- package/.medusa/server/src/api/admin/plugin-features/[plugin_key]/settings/route.js +22 -0
- package/.medusa/server/src/api/admin/plugin-features/route.js +6 -4
- package/.medusa/server/src/api/document-download-response.js +16 -0
- package/.medusa/server/src/api/document-response.js +23 -0
- package/.medusa/server/src/api/files/[asset]/route.js +24 -0
- package/.medusa/server/src/api/files/file-response.js +43 -0
- package/.medusa/server/src/api/files/gateway-options.js +31 -0
- package/.medusa/server/src/api/files/private/[token]/route.js +29 -0
- package/.medusa/server/src/api/files/upload/[token]/route.js +66 -0
- package/.medusa/server/src/api/middlewares.js +186 -5
- package/.medusa/server/src/api/packing-list-response.js +22 -0
- package/.medusa/server/src/api/plugin-actions.js +221 -0
- package/.medusa/server/src/api/plugin-features-http.js +67 -8
- package/.medusa/server/src/api/route.js +27 -0
- package/.medusa/server/src/api/store/documents/[id]/download/route.js +21 -0
- package/.medusa/server/src/api/store/documents/[id]/route.js +15 -0
- package/.medusa/server/src/api/store/documents/route.js +11 -0
- package/.medusa/server/src/api/terms-download-response.js +12 -0
- package/.medusa/server/src/documents/config/index.js +18 -0
- package/.medusa/server/src/documents/paths/documents.js +6 -0
- package/.medusa/server/src/documents/paths/index.js +18 -0
- package/.medusa/server/src/documents/plugin-features.js +24 -0
- package/.medusa/server/src/documents/schemas/documents.js +18 -0
- package/.medusa/server/src/documents/schemas/index.js +18 -0
- package/.medusa/server/src/documents/scripts/verify-documents-file-storage.js +55 -0
- package/.medusa/server/src/documents/templates/financial-document.js +142 -0
- package/.medusa/server/src/documents/templates/format.js +31 -0
- package/.medusa/server/src/documents/templates/html-factory.js +40 -0
- package/.medusa/server/src/documents/templates/html-utils.js +13 -0
- package/.medusa/server/src/documents/templates/layout.js +97 -0
- package/.medusa/server/src/documents/templates/packing-list.js +50 -0
- package/.medusa/server/src/documents/types/admin-api.js +3 -0
- package/.medusa/server/src/documents/types/document-summary.js +3 -0
- package/.medusa/server/src/documents/types/documents.js +3 -0
- package/.medusa/server/src/documents/types/html-factory.js +6 -0
- package/.medusa/server/src/documents/types/index.js +22 -0
- package/.medusa/server/src/documents/types/store-api.js +3 -0
- package/.medusa/server/src/documents/utils/document-merchant.js +22 -0
- package/.medusa/server/src/documents/utils/html-to-pdf.js +61 -0
- package/.medusa/server/src/documents/utils/private-file-storage.js +64 -0
- package/.medusa/server/src/documents/utils/resolve-services.js +7 -0
- package/.medusa/server/src/email/application/handle-invite-event.js +312 -0
- package/.medusa/server/src/email/application/handle-password-reset-event.js +354 -0
- package/.medusa/server/src/email/config/index.js +84 -0
- package/.medusa/server/src/email/config/notification-module.js +20 -0
- package/.medusa/server/src/email/domain/business-keys.js +50 -0
- package/.medusa/server/src/email/domain/documents-fact-fingerprint.js +7 -0
- package/.medusa/server/src/email/domain/event-schemas.js +36 -0
- package/.medusa/server/src/email/domain/failure-classification.js +53 -0
- package/.medusa/server/src/email/plugin-features.js +31 -0
- package/.medusa/server/src/email/rendering/default-templates.js +91 -0
- package/.medusa/server/src/email/rendering/render-email.js +37 -0
- package/.medusa/server/src/email/rendering/resolve-shop-configuration.js +48 -0
- package/.medusa/server/src/email/types/email-kinds.js +18 -0
- package/.medusa/server/src/email/types/index.js +21 -0
- package/.medusa/server/src/email/types/shop-configuration.js +3 -0
- package/.medusa/server/src/email/types/smtp-configuration.js +3 -0
- package/.medusa/server/src/email/types/template-data.js +79 -0
- package/.medusa/server/src/files/config/index.js +256 -0
- package/.medusa/server/src/files/gateway/index.js +115 -0
- package/.medusa/server/src/files/types/index.js +6 -0
- package/.medusa/server/src/files/types/public.js +6 -0
- package/.medusa/server/src/jobs/document-fact-publication-reconciliation.js +18 -0
- package/.medusa/server/src/jobs/document-resolution-reconciliation.js +20 -0
- package/.medusa/server/src/jobs/packing-list-reconciliation.js +49 -0
- package/.medusa/server/src/jobs/reconcile-email-attempts.js +63 -0
- package/.medusa/server/src/jobs/reconcile-pending-email-messages.js +41 -0
- package/.medusa/server/src/jobs/retry-email-messages.js +27 -0
- package/.medusa/server/src/migration-scripts/dismiss-orphaned-cart-promotion-links.js +26 -0
- package/.medusa/server/src/modules/documents/domain/cancellation-snapshot.js +97 -0
- package/.medusa/server/src/modules/documents/domain/document-number.js +36 -0
- package/.medusa/server/src/modules/documents/domain/document-resolution.js +24 -0
- package/.medusa/server/src/modules/documents/domain/issuance-rules.js +37 -0
- package/.medusa/server/src/modules/documents/domain/merchant.js +86 -0
- package/.medusa/server/src/modules/documents/domain/options.js +40 -0
- package/.medusa/server/src/modules/documents/domain/packing-list.js +90 -0
- package/.medusa/server/src/modules/documents/domain/snapshot-normalization.js +17 -0
- package/.medusa/server/src/modules/documents/domain/tax-breakdown.js +66 -0
- package/.medusa/server/src/modules/documents/index.js +15 -0
- package/.medusa/server/src/modules/documents/loaders/assert-private-file-storage.js +20 -0
- package/.medusa/server/src/modules/documents/migrations/Migration20260827061749.js +75 -0
- package/.medusa/server/src/modules/documents/migrations/Migration20260830111207.js +28 -0
- package/.medusa/server/src/modules/documents/models/document-artifact.js +25 -0
- package/.medusa/server/src/modules/documents/models/document-number-sequence.js +29 -0
- package/.medusa/server/src/modules/documents/models/document.js +82 -0
- package/.medusa/server/src/modules/documents/models/order-cancellation-resolution.js +51 -0
- package/.medusa/server/src/modules/documents/models/packing-list-revision.js +36 -0
- package/.medusa/server/src/modules/documents/models/packing-list.js +27 -0
- package/.medusa/server/src/modules/documents/models/refund-document-resolution.js +66 -0
- package/.medusa/server/src/modules/documents/models/shipment-invoice-assignment.js +51 -0
- package/.medusa/server/src/modules/documents/models/shipment-invoice-coordinator.js +44 -0
- package/.medusa/server/src/modules/documents/service.js +1701 -0
- package/.medusa/server/src/modules/email/domain/attachment.js +25 -0
- package/.medusa/server/src/modules/email/domain/message-state.js +69 -0
- package/.medusa/server/src/modules/email/index.js +13 -0
- package/.medusa/server/src/modules/email/migrations/Migration20260826173422.js +32 -0
- package/.medusa/server/src/modules/email/migrations/Migration20260827172945.js +16 -0
- package/.medusa/server/src/modules/email/migrations/Migration20260827194804.js +22 -0
- package/.medusa/server/src/modules/email/migrations/Migration20260906195205.js +16 -0
- package/.medusa/server/src/modules/email/models/email-attempt.js +56 -0
- package/.medusa/server/src/modules/email/models/email-message.js +71 -0
- package/.medusa/server/src/modules/email/models/email-terms-version.js +37 -0
- package/.medusa/server/src/modules/email/service.js +1285 -0
- package/.medusa/server/src/modules/plugin-features/domain/plugin-action-runs.js +92 -0
- package/.medusa/server/src/modules/plugin-features/domain/plugin-settings.js +213 -0
- package/.medusa/server/src/modules/plugin-features/domain/secret-box.js +56 -0
- package/.medusa/server/src/modules/plugin-features/migrations/Migration20260928205031.js +16 -0
- package/.medusa/server/src/modules/plugin-features/migrations/Migration20260928215428.js +17 -0
- package/.medusa/server/src/modules/plugin-features/models/plugin-action-run.js +43 -0
- package/.medusa/server/src/modules/plugin-features/models/plugin-setting-state.js +32 -0
- package/.medusa/server/src/modules/plugin-features/service.js +419 -17
- package/.medusa/server/src/providers/s3-cache/cache/atomic-write.js +25 -0
- package/.medusa/server/src/providers/s3-cache/cache/cache-manager.js +115 -0
- package/.medusa/server/src/providers/s3-cache/cache/keyed-lock.js +28 -0
- package/.medusa/server/src/providers/s3-cache/index.js +8 -0
- package/.medusa/server/src/providers/s3-cache/object-key.js +53 -0
- package/.medusa/server/src/providers/s3-cache/s3-cache-file.js +229 -0
- package/.medusa/server/src/providers/s3-cache/s3-object-store.js +86 -0
- package/.medusa/server/src/providers/smtp/index.js +8 -0
- package/.medusa/server/src/providers/smtp/service.js +236 -0
- package/.medusa/server/src/providers/smtp/types.js +11 -0
- package/.medusa/server/src/public/action-progress.js +67 -0
- package/.medusa/server/src/public/config.js +186 -0
- package/.medusa/server/src/public/descriptor.js +199 -2
- package/.medusa/server/src/public/effective-features.js +9 -5
- package/.medusa/server/src/public/enforcement.js +18 -8
- package/.medusa/server/src/public/gateway.js +19 -0
- package/.medusa/server/src/public/index.js +10 -2
- package/.medusa/server/src/public/instrumentation.js +56 -0
- package/.medusa/server/src/public/module-access.js +14 -0
- package/.medusa/server/src/public/settings.js +17 -0
- package/.medusa/server/src/public/shop-config.js +12 -0
- package/.medusa/server/src/public/shop-master-data.js +95 -0
- package/.medusa/server/src/public/shop-types.js +24 -0
- package/.medusa/server/src/shop-config/build-food-shop-config.js +248 -0
- package/.medusa/server/src/shop-config/options.js +71 -0
- package/.medusa/server/src/subscribers/affiliate-consignment-reminder-due.js +26 -0
- package/.medusa/server/src/subscribers/documents-order-canceled.js +24 -0
- package/.medusa/server/src/subscribers/documents-order-cancellation-ready.js +26 -0
- package/.medusa/server/src/subscribers/documents-refund-ready.js +24 -0
- package/.medusa/server/src/subscribers/documents-shipment-created.js +36 -0
- package/.medusa/server/src/subscribers/documents-shipment-invoice-assignment-decided.js +26 -0
- package/.medusa/server/src/subscribers/email-order-canceled.js +28 -0
- package/.medusa/server/src/subscribers/email-shipment-created.js +32 -0
- package/.medusa/server/src/subscribers/order-placed.js +27 -0
- package/.medusa/server/src/subscribers/packing-list-allocation-revised.js +32 -0
- package/.medusa/server/src/subscribers/packing-list-fulfillment-canceled.js +54 -0
- package/.medusa/server/src/subscribers/packing-list-fulfillment-created.js +31 -0
- package/.medusa/server/src/subscribers/password-reset.js +23 -0
- package/.medusa/server/src/subscribers/payment-refunded.js +38 -0
- package/.medusa/server/src/subscribers/return-received.js +27 -0
- package/.medusa/server/src/subscribers/return-requested.js +27 -0
- package/.medusa/server/src/subscribers/user-invite.js +23 -0
- package/.medusa/server/src/utils/cart-promotion-links.js +101 -0
- package/.medusa/server/src/utils/discover-complete-cart-participants.js +9 -2
- package/.medusa/server/src/utils/discover-plugin-features.js +47 -9
- package/.medusa/server/src/workflows/documents/issue-cancellation-after-refund.js +246 -0
- package/.medusa/server/src/workflows/documents/issue-document.js +163 -0
- package/.medusa/server/src/workflows/documents/issue-invoice-after-shipment.js +521 -0
- package/.medusa/server/src/workflows/documents/issue-packing-list.js +384 -0
- package/.medusa/server/src/workflows/documents/publish-document-facts.js +53 -0
- package/.medusa/server/src/workflows/documents/reconcile-document-resolutions.js +48 -0
- package/.medusa/server/src/workflows/documents/reconcile-order-cancellation.js +92 -0
- package/.medusa/server/src/workflows/documents/regenerate-issued-document.js +61 -0
- package/.medusa/server/src/workflows/email/dispatch-email-message.js +299 -0
- package/.medusa/server/src/workflows/email/documents-required-facts.js +30 -0
- package/.medusa/server/src/workflows/email/prepare-affiliate-reminder-email.js +58 -0
- package/.medusa/server/src/workflows/email/prepare-order-canceled-email.js +64 -0
- package/.medusa/server/src/workflows/email/prepare-order-received-email.js +56 -0
- package/.medusa/server/src/workflows/email/prepare-refund-email.js +47 -0
- package/.medusa/server/src/workflows/email/prepare-return-email.js +75 -0
- package/.medusa/server/src/workflows/email/prepare-shipment-email.js +82 -0
- package/.medusa/server/src/workflows/email/retry-email-messages.js +31 -0
- package/.medusa/server/src/workflows/hooks/complete-cart-participants.js +28 -16
- package/.medusa/server/src/workflows/hooks/dismiss-deleted-promotion-cart-links.js +23 -0
- package/README.md +2004 -11
- package/dist/admin-components/features/plugin-features/components/PluginActionsSection.d.ts +6 -0
- package/dist/admin-components/features/plugin-features/components/PluginActionsSection.js +66 -0
- package/dist/admin-components/features/plugin-features/components/PluginDetailPage.d.ts +2 -0
- package/dist/admin-components/features/plugin-features/components/PluginDetailPage.js +9 -0
- package/dist/admin-components/features/plugin-features/components/PluginFeatureGate.d.ts +22 -0
- package/dist/admin-components/features/plugin-features/components/PluginFeatureGate.js +18 -0
- package/dist/admin-components/features/plugin-features/components/PluginFeatureSections.d.ts +11 -0
- package/dist/admin-components/features/plugin-features/components/PluginFeatureSections.js +19 -0
- package/dist/admin-components/features/plugin-features/components/PluginFeaturesCard.d.ts +12 -0
- package/dist/admin-components/features/plugin-features/components/PluginFeaturesCard.js +34 -0
- package/dist/admin-components/features/plugin-features/components/PluginFeaturesSettingsPage.d.ts +5 -0
- package/dist/admin-components/features/plugin-features/components/PluginFeaturesSettingsPage.js +16 -0
- package/dist/admin-components/features/plugin-features/components/PluginHubCard.d.ts +7 -0
- package/dist/admin-components/features/plugin-features/components/PluginHubCard.js +21 -0
- package/dist/admin-components/features/plugin-features/components/PluginPageShell.d.ts +13 -0
- package/dist/admin-components/features/plugin-features/components/PluginPageShell.js +20 -0
- package/dist/admin-components/features/plugin-features/components/PluginSettingsForm.d.ts +7 -0
- package/dist/admin-components/features/plugin-features/components/PluginSettingsForm.js +39 -0
- package/dist/admin-components/features/plugin-features/components/PluginStatusChips.d.ts +5 -0
- package/dist/admin-components/features/plugin-features/components/PluginStatusChips.js +8 -0
- package/dist/admin-components/features/plugin-features/hooks/usePluginFeatureEnabled.d.ts +114 -0
- package/dist/admin-components/features/plugin-features/hooks/usePluginFeatureEnabled.js +40 -0
- package/dist/admin-components/features/plugin-features/hooks/usePluginFeatures.d.ts +392 -0
- package/dist/admin-components/features/plugin-features/hooks/usePluginFeatures.js +128 -0
- package/dist/admin-components/features/plugin-features/hooks/usePluginSettingsForm.d.ts +93 -0
- package/dist/admin-components/features/plugin-features/hooks/usePluginSettingsForm.js +44 -0
- package/dist/admin-components/features/plugin-features/lib/action-runs.d.ts +19 -0
- package/dist/admin-components/features/plugin-features/lib/action-runs.js +74 -0
- package/dist/admin-components/features/plugin-features/lib/plugin-features-admin-client.d.ts +363 -0
- package/dist/admin-components/features/plugin-features/lib/plugin-features-admin-client.js +9 -0
- package/dist/admin-components/features/plugin-features/lib/plugin-paths.d.ts +4 -0
- package/dist/admin-components/features/plugin-features/lib/plugin-paths.js +4 -0
- package/dist/admin-components/features/plugin-features/lib/settings-draft.d.ts +28 -0
- package/dist/admin-components/features/plugin-features/lib/settings-draft.js +86 -0
- package/dist/admin-components/features/plugin-features/queries/pluginFeatureKeys.d.ts +7 -0
- package/dist/admin-components/features/plugin-features/queries/pluginFeatureKeys.js +7 -0
- package/dist/admin-components/i18n/texts.d.ts +90 -0
- package/dist/admin-components/i18n/texts.js +90 -0
- package/dist/admin-components/index.d.ts +14 -0
- package/dist/admin-components/index.js +14 -0
- package/dist/admin-components/lib/errors.d.ts +6 -0
- package/dist/admin-components/lib/errors.js +27 -0
- package/dist/admin-components/lib/sdk.d.ts +2 -0
- package/dist/admin-components/lib/sdk.js +13 -0
- package/dist/documents/config/index.d.ts +11 -0
- package/dist/documents/config/index.js +17 -0
- package/dist/documents/templates/financial-document.d.ts +3 -0
- package/dist/documents/templates/financial-document.js +141 -0
- package/dist/documents/templates/format.d.ts +16 -0
- package/dist/documents/templates/format.js +30 -0
- package/dist/documents/templates/html-factory.d.ts +11 -0
- package/dist/documents/templates/html-factory.js +39 -0
- package/dist/documents/templates/html-utils.d.ts +2 -0
- package/dist/documents/templates/html-utils.js +12 -0
- package/dist/documents/templates/layout.d.ts +17 -0
- package/dist/documents/templates/layout.js +96 -0
- package/dist/documents/templates/packing-list.d.ts +3 -0
- package/dist/documents/templates/packing-list.js +49 -0
- package/dist/documents/types/admin-api.d.ts +1 -0
- package/dist/documents/types/admin-api.js +2 -0
- package/dist/documents/types/document-summary.d.ts +1 -0
- package/dist/documents/types/document-summary.js +2 -0
- package/dist/documents/types/documents.d.ts +174 -0
- package/dist/documents/types/documents.js +2 -0
- package/dist/documents/types/html-factory.d.ts +7 -0
- package/dist/documents/types/html-factory.js +5 -0
- package/dist/documents/types/index.d.ts +5 -0
- package/dist/documents/types/index.js +21 -0
- package/dist/documents/types/store-api.d.ts +1 -0
- package/dist/documents/types/store-api.js +2 -0
- package/dist/email/config/index.d.ts +17 -0
- package/dist/email/config/index.js +83 -0
- package/dist/email/config/notification-module.d.ts +22 -0
- package/dist/email/config/notification-module.js +19 -0
- package/dist/email/types/email-kinds.d.ts +15 -0
- package/dist/email/types/email-kinds.js +17 -0
- package/dist/email/types/index.d.ts +4 -0
- package/dist/email/types/index.js +20 -0
- package/dist/email/types/shop-configuration.d.ts +43 -0
- package/dist/email/types/shop-configuration.js +2 -0
- package/dist/email/types/smtp-configuration.d.ts +9 -0
- package/dist/email/types/smtp-configuration.js +2 -0
- package/dist/email/types/template-data.d.ts +100 -0
- package/dist/email/types/template-data.js +78 -0
- package/dist/files/config/index.d.ts +32 -0
- package/dist/files/config/index.js +255 -0
- package/dist/files/gateway/index.d.ts +30 -0
- package/dist/files/gateway/index.js +114 -0
- package/dist/files/types/index.d.ts +2 -0
- package/dist/files/types/index.js +5 -0
- package/dist/files/types/public.d.ts +90 -0
- package/dist/files/types/public.js +5 -0
- package/dist/modules/documents/domain/merchant.d.ts +22 -0
- package/dist/modules/documents/domain/merchant.js +85 -0
- package/dist/modules/documents/domain/options.d.ts +34 -0
- package/dist/modules/documents/domain/options.js +39 -0
- package/dist/public/action-progress.d.ts +25 -0
- package/dist/public/action-progress.js +66 -0
- package/dist/public/config.d.ts +59 -0
- package/dist/public/config.js +185 -0
- package/dist/public/descriptor.d.ts +3 -2
- package/dist/public/descriptor.js +198 -1
- package/dist/public/effective-features.d.ts +2 -1
- package/dist/public/effective-features.js +8 -4
- package/dist/public/enforcement.d.ts +7 -0
- package/dist/public/enforcement.js +17 -7
- package/dist/public/gateway.d.ts +2 -0
- package/dist/public/gateway.js +18 -0
- package/dist/public/index.d.ts +5 -2
- package/dist/public/index.js +9 -1
- package/dist/public/instrumentation.d.ts +12 -0
- package/dist/public/instrumentation.js +55 -0
- package/dist/public/module-access.d.ts +3 -0
- package/dist/public/module-access.js +13 -0
- package/dist/public/settings.d.ts +11 -0
- package/dist/public/settings.js +16 -0
- package/dist/public/shop-config.d.ts +8 -0
- package/dist/public/shop-config.js +11 -0
- package/dist/public/shop-master-data.d.ts +25 -0
- package/dist/public/shop-master-data.js +94 -0
- package/dist/public/shop-types.d.ts +7 -0
- package/dist/public/shop-types.js +23 -0
- package/dist/public/types.d.ts +113 -1
- package/dist/shop-config/build-food-shop-config.d.ts +44 -0
- package/dist/shop-config/build-food-shop-config.js +247 -0
- package/dist/shop-config/options.d.ts +41 -0
- package/dist/shop-config/options.js +70 -0
- package/dist/utils/discover-plugin-features.d.ts +28 -0
- package/dist/utils/discover-plugin-features.js +96 -0
- package/package.json +53 -6
|
@@ -0,0 +1,1285 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
11
|
+
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
12
|
+
return function (target, key) { decorator(target, key, paramIndex); }
|
|
13
|
+
};
|
|
14
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
15
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
16
|
+
};
|
|
17
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
|
+
exports.EMAIL_ATTEMPT_LEASE_MS = void 0;
|
|
19
|
+
const node_crypto_1 = require("node:crypto");
|
|
20
|
+
const utils_1 = require("@medusajs/framework/utils");
|
|
21
|
+
const zod_1 = require("@medusajs/framework/zod");
|
|
22
|
+
const documents_1 = require("@hartl-services/medusa-food-supplements-contracts/events/documents");
|
|
23
|
+
const email_1 = require("@hartl-services/medusa-food-supplements-contracts/schemas/email");
|
|
24
|
+
const types_1 = require("../../email/types");
|
|
25
|
+
const business_keys_1 = require("../../email/domain/business-keys");
|
|
26
|
+
const plugin_features_1 = require("../../email/plugin-features");
|
|
27
|
+
const resolve_shop_configuration_1 = require("../../email/rendering/resolve-shop-configuration");
|
|
28
|
+
const failure_classification_1 = require("../../email/domain/failure-classification");
|
|
29
|
+
const attachment_1 = require("./domain/attachment");
|
|
30
|
+
const message_state_1 = require("./domain/message-state");
|
|
31
|
+
const email_attempt_1 = __importDefault(require("./models/email-attempt"));
|
|
32
|
+
const email_message_1 = __importDefault(require("./models/email-message"));
|
|
33
|
+
const email_terms_version_1 = __importDefault(require("./models/email-terms-version"));
|
|
34
|
+
exports.EMAIL_ATTEMPT_LEASE_MS = 2 * 60 * 1000;
|
|
35
|
+
const EmailModuleServiceBase = (0, utils_1.MedusaService)({
|
|
36
|
+
EmailMessage: email_message_1.default,
|
|
37
|
+
EmailAttempt: email_attempt_1.default,
|
|
38
|
+
EmailTermsVersion: email_terms_version_1.default,
|
|
39
|
+
});
|
|
40
|
+
const asNonEmptyString = (value, field) => {
|
|
41
|
+
if (typeof value !== "string" || !value.trim()) {
|
|
42
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, `${field} must be a non-empty string.`);
|
|
43
|
+
}
|
|
44
|
+
return value.trim();
|
|
45
|
+
};
|
|
46
|
+
const asNullableString = (value) => typeof value === "string" ? value : null;
|
|
47
|
+
const asDate = (value, field) => {
|
|
48
|
+
const date = value instanceof Date ? value : new Date(String(value ?? ""));
|
|
49
|
+
if (Number.isNaN(date.getTime())) {
|
|
50
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.UNEXPECTED_STATE, `${field} is not a valid date.`);
|
|
51
|
+
}
|
|
52
|
+
return date;
|
|
53
|
+
};
|
|
54
|
+
const asNullableDate = (value) => value === null || value === undefined ? null : asDate(value, "date");
|
|
55
|
+
const asSafeStatusCode = (value, field) => {
|
|
56
|
+
if (!(0, message_state_1.isEmailSafeStatusCode)(value)) {
|
|
57
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, `${field} must be an allowlisted email status code.`);
|
|
58
|
+
}
|
|
59
|
+
return value;
|
|
60
|
+
};
|
|
61
|
+
const equalJson = (left, right) => JSON.stringify(left) === JSON.stringify(right);
|
|
62
|
+
const UuidSchema = zod_1.z.string().uuid();
|
|
63
|
+
const TermsPdfFilenameSchema = zod_1.z
|
|
64
|
+
.string()
|
|
65
|
+
.min(5)
|
|
66
|
+
.max(255)
|
|
67
|
+
.regex(/^(?!.*\.\.)[A-Za-z0-9](?:[A-Za-z0-9._ -]*[A-Za-z0-9_-])?\.pdf$/i);
|
|
68
|
+
const Sha256Schema = zod_1.z.string().regex(/^[0-9a-f]{64}$/);
|
|
69
|
+
const asUuid = (value, field) => {
|
|
70
|
+
const normalized = asNonEmptyString(value, field);
|
|
71
|
+
if (!UuidSchema.safeParse(normalized).success) {
|
|
72
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, `${field} must be a UUID.`);
|
|
73
|
+
}
|
|
74
|
+
return normalized.toLowerCase();
|
|
75
|
+
};
|
|
76
|
+
class EmailModuleService extends EmailModuleServiceBase {
|
|
77
|
+
/**
|
|
78
|
+
* Medusa passes the plugin options of the base plugin to every module; this
|
|
79
|
+
* service reads only its own `email` namespace.
|
|
80
|
+
*/
|
|
81
|
+
constructor(container, options) {
|
|
82
|
+
super(container);
|
|
83
|
+
/** Discovered by @hartl-services/medusa-base for the feature toggles. */
|
|
84
|
+
this.pluginFeatures = plugin_features_1.emailPluginFeatures;
|
|
85
|
+
const email = options?.email;
|
|
86
|
+
this.dispatchConfiguration_ = email?.shop
|
|
87
|
+
? (0, resolve_shop_configuration_1.resolveShopEmailConfiguration)(email.shop)
|
|
88
|
+
: null;
|
|
89
|
+
this.jwtSecret_ = email?.jwtSecret?.trim() || null;
|
|
90
|
+
}
|
|
91
|
+
getDispatchConfiguration() {
|
|
92
|
+
if (!this.dispatchConfiguration_) {
|
|
93
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.UNEXPECTED_STATE, "Email dispatch configuration is unavailable.");
|
|
94
|
+
}
|
|
95
|
+
return this.dispatchConfiguration_;
|
|
96
|
+
}
|
|
97
|
+
getJwtSecret() {
|
|
98
|
+
if (!this.jwtSecret_) {
|
|
99
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.UNEXPECTED_STATE, "Email JWT configuration is unavailable.");
|
|
100
|
+
}
|
|
101
|
+
return this.jwtSecret_;
|
|
102
|
+
}
|
|
103
|
+
async findMessageByBusinessKey(businessKey, sharedContext = {}) {
|
|
104
|
+
const rows = await this.requireManager(sharedContext).execute(`select * from "email_message"
|
|
105
|
+
where "business_key" = ? and "deleted_at" is null
|
|
106
|
+
limit 1`, [asNonEmptyString(businessKey, "business_key")], "all");
|
|
107
|
+
return rows[0] ? this.toMessageRecord(rows[0]) : null;
|
|
108
|
+
}
|
|
109
|
+
async upsertMessageFact(input, sharedContext = {}) {
|
|
110
|
+
const normalized = this.normalizeFactInput(input);
|
|
111
|
+
const manager = this.requireManager(sharedContext);
|
|
112
|
+
await manager.execute("select pg_advisory_xact_lock(hashtext(?))", [
|
|
113
|
+
`email:message:${normalized.business_key}`,
|
|
114
|
+
]);
|
|
115
|
+
const rows = await manager.execute(`select * from "email_message" where "business_key" = ? for update`, [normalized.business_key], "all");
|
|
116
|
+
const existing = rows[0] ? this.toMessageRecord(rows[0]) : null;
|
|
117
|
+
if (!existing) {
|
|
118
|
+
const attachments = [...normalized.attachments];
|
|
119
|
+
if (normalized.terms_effective_at) {
|
|
120
|
+
const termsAttachment = await this.findTermsAttachmentAt(normalized.terms_effective_at, sharedContext);
|
|
121
|
+
if (termsAttachment) {
|
|
122
|
+
attachments.push(termsAttachment);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
const initialState = normalized.suppression_code
|
|
126
|
+
? {
|
|
127
|
+
status: "suppressed",
|
|
128
|
+
terminal_code: normalized.suppression_code,
|
|
129
|
+
}
|
|
130
|
+
: await this.resolvePendingState(normalized.required_facts, [normalized.fact], normalized.predecessor_message_id, sharedContext);
|
|
131
|
+
const created = (await this.createEmailMessages({
|
|
132
|
+
kind: normalized.kind,
|
|
133
|
+
business_key: normalized.business_key,
|
|
134
|
+
resource_type: normalized.resource_type,
|
|
135
|
+
resource_id: normalized.resource_id,
|
|
136
|
+
recipient: normalized.recipient,
|
|
137
|
+
template_data: normalized.template_data,
|
|
138
|
+
attachments,
|
|
139
|
+
status: initialState.status,
|
|
140
|
+
required_facts: normalized.required_facts,
|
|
141
|
+
received_facts: [normalized.fact],
|
|
142
|
+
predecessor_message_id: normalized.predecessor_message_id,
|
|
143
|
+
trigger: normalized.trigger,
|
|
144
|
+
request_id: normalized.request_id,
|
|
145
|
+
requested_by_admin_id: normalized.requested_by_admin_id,
|
|
146
|
+
original_message_id: normalized.original_message_id,
|
|
147
|
+
next_attempt_at: null,
|
|
148
|
+
sent_at: null,
|
|
149
|
+
failed_at: initialState.status === "failed" ? new Date() : null,
|
|
150
|
+
payload_expires_at: normalized.payload_expires_at,
|
|
151
|
+
terminal_code: initialState.terminal_code,
|
|
152
|
+
}, sharedContext));
|
|
153
|
+
return this.toMessageRecord(created);
|
|
154
|
+
}
|
|
155
|
+
if (existing.deleted_at) {
|
|
156
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.CONFLICT, "The email business key was already consumed.");
|
|
157
|
+
}
|
|
158
|
+
this.assertSameMessageIdentity(existing, normalized);
|
|
159
|
+
const receivedFacts = (0, message_state_1.canonicalizeFacts)([
|
|
160
|
+
...existing.received_facts,
|
|
161
|
+
normalized.fact,
|
|
162
|
+
]);
|
|
163
|
+
const templateData = this.mergeTemplateData(existing.kind, existing.template_data, normalized.template_data);
|
|
164
|
+
const attachments = this.mergeAttachments(existing.attachments, normalized.attachments);
|
|
165
|
+
const state = existing.status !== "pending" && existing.status !== "ready"
|
|
166
|
+
? { status: existing.status, terminal_code: existing.terminal_code }
|
|
167
|
+
: normalized.suppression_code
|
|
168
|
+
? {
|
|
169
|
+
status: "suppressed",
|
|
170
|
+
terminal_code: normalized.suppression_code,
|
|
171
|
+
}
|
|
172
|
+
: await this.resolvePendingState(existing.required_facts, receivedFacts, existing.predecessor_message_id, sharedContext);
|
|
173
|
+
const updated = (await this.updateEmailMessages({
|
|
174
|
+
id: existing.id,
|
|
175
|
+
recipient: existing.recipient ?? normalized.recipient,
|
|
176
|
+
template_data: templateData,
|
|
177
|
+
attachments,
|
|
178
|
+
received_facts: receivedFacts,
|
|
179
|
+
status: state.status,
|
|
180
|
+
terminal_code: state.terminal_code,
|
|
181
|
+
failed_at: state.status === "failed"
|
|
182
|
+
? (existing.failed_at ?? new Date())
|
|
183
|
+
: existing.failed_at,
|
|
184
|
+
}, sharedContext));
|
|
185
|
+
const message = this.toMessageRecord(updated);
|
|
186
|
+
if (message.status === "failed" || message.status === "suppressed") {
|
|
187
|
+
await this.reevaluateDependentMessages(message, new Date(), sharedContext);
|
|
188
|
+
}
|
|
189
|
+
return message;
|
|
190
|
+
}
|
|
191
|
+
async createEmailTermsVersion(input, persistPrivatePdf, deletePrivatePdf, sharedContext = {}) {
|
|
192
|
+
const normalized = this.normalizeTermsVersionInput(input);
|
|
193
|
+
const manager = this.requireManager(sharedContext);
|
|
194
|
+
await manager.execute("select pg_advisory_xact_lock(hashtext(?))", [
|
|
195
|
+
`email:terms-version:${normalized.request_id}`,
|
|
196
|
+
]);
|
|
197
|
+
const rows = await manager.execute(`select * from "email_terms_version" where "request_id" = ? for update`, [normalized.request_id], "all");
|
|
198
|
+
if (rows[0]) {
|
|
199
|
+
const existing = this.toTermsVersionRecord(rows[0]);
|
|
200
|
+
if (existing.deleted_at) {
|
|
201
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.CONFLICT, "The terms upload request was already consumed.");
|
|
202
|
+
}
|
|
203
|
+
if (existing.filename !== normalized.filename ||
|
|
204
|
+
existing.effective_at.getTime() !== normalized.effective_at.getTime() ||
|
|
205
|
+
existing.byte_size !== normalized.byte_size ||
|
|
206
|
+
existing.sha256 !== normalized.sha256) {
|
|
207
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.CONFLICT, "The terms upload request was reused with different PDF data.");
|
|
208
|
+
}
|
|
209
|
+
return {
|
|
210
|
+
created: false,
|
|
211
|
+
terms_version: this.toSafeAdminTermsVersion(existing),
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
let fileId = null;
|
|
215
|
+
try {
|
|
216
|
+
fileId = asNonEmptyString(await persistPrivatePdf(), "file_id");
|
|
217
|
+
await this.createEmailTermsVersions({ ...normalized, file_id: fileId }, sharedContext);
|
|
218
|
+
await manager.flush?.();
|
|
219
|
+
const createdRows = await manager.execute(`select * from "email_terms_version" where "request_id" = ? limit 1`, [normalized.request_id], "all");
|
|
220
|
+
if (!createdRows[0]) {
|
|
221
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.UNEXPECTED_STATE, "The terms version was not persisted.");
|
|
222
|
+
}
|
|
223
|
+
return {
|
|
224
|
+
created: true,
|
|
225
|
+
terms_version: this.toSafeAdminTermsVersion(this.toTermsVersionRecord(createdRows[0])),
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
catch (error) {
|
|
229
|
+
if (fileId) {
|
|
230
|
+
try {
|
|
231
|
+
await deletePrivatePdf(fileId);
|
|
232
|
+
}
|
|
233
|
+
catch {
|
|
234
|
+
// Preserve the original persistence failure; cleanup is best effort.
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
throw error;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
async listAdminEmailTermsVersions(input, sharedContext = {}) {
|
|
241
|
+
const limit = this.positiveLimit(input.limit);
|
|
242
|
+
const offset = this.safeOffset(input.offset);
|
|
243
|
+
const manager = this.requireManager(sharedContext);
|
|
244
|
+
const [rows, countRows] = await Promise.all([
|
|
245
|
+
manager.execute(`select * from "email_terms_version"
|
|
246
|
+
where "deleted_at" is null
|
|
247
|
+
order by "effective_at" desc, "created_at" desc, "id" desc
|
|
248
|
+
limit ? offset ?`, [limit, offset], "all"),
|
|
249
|
+
manager.execute(`select count(*) as "count" from "email_terms_version"
|
|
250
|
+
where "deleted_at" is null`, [], "all"),
|
|
251
|
+
]);
|
|
252
|
+
return {
|
|
253
|
+
terms_versions: rows.map((row) => this.toSafeAdminTermsVersion(this.toTermsVersionRecord(row))),
|
|
254
|
+
count: Number(countRows[0]?.count ?? 0),
|
|
255
|
+
limit,
|
|
256
|
+
offset,
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
async getEmailTermsVersionFile(termsVersionId, sharedContext = {}) {
|
|
260
|
+
const rows = await this.requireManager(sharedContext).execute(`select "file_id", "filename" from "email_terms_version"
|
|
261
|
+
where "id" = ? and "deleted_at" is null limit 1`, [asNonEmptyString(termsVersionId, "terms_version_id")], "all");
|
|
262
|
+
if (!rows[0]) {
|
|
263
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.NOT_FOUND, "The terms version was not found.");
|
|
264
|
+
}
|
|
265
|
+
return {
|
|
266
|
+
file_id: asNonEmptyString(rows[0].file_id, "file_id"),
|
|
267
|
+
filename: asNonEmptyString(rows[0].filename, "filename"),
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
async createAffiliateReminderMessage(input, resolveRecipient, sharedContext = {}) {
|
|
271
|
+
const factInput = {
|
|
272
|
+
kind: "affiliate.consignment_report_due",
|
|
273
|
+
business_key: input.business_key,
|
|
274
|
+
resource_type: "affiliate",
|
|
275
|
+
resource_id: input.resource_id,
|
|
276
|
+
template_data: input.template_data,
|
|
277
|
+
required_facts: ["reminder_due"],
|
|
278
|
+
fact: "reminder_due",
|
|
279
|
+
trigger: input.trigger,
|
|
280
|
+
};
|
|
281
|
+
const normalized = this.normalizeFactInput(factInput);
|
|
282
|
+
const manager = this.requireManager(sharedContext);
|
|
283
|
+
await manager.execute("select pg_advisory_xact_lock(hashtext(?))", [
|
|
284
|
+
`email:message:${normalized.business_key}`,
|
|
285
|
+
]);
|
|
286
|
+
const rows = await manager.execute(`select * from "email_message" where "business_key" = ? for update`, [normalized.business_key], "all");
|
|
287
|
+
if (rows[0]) {
|
|
288
|
+
const existing = this.toMessageRecord(rows[0]);
|
|
289
|
+
if (existing.deleted_at) {
|
|
290
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.CONFLICT, "The email business key was already consumed.");
|
|
291
|
+
}
|
|
292
|
+
if (existing.kind !== normalized.kind ||
|
|
293
|
+
existing.resource_type !== normalized.resource_type ||
|
|
294
|
+
existing.resource_id !== normalized.resource_id) {
|
|
295
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.CONFLICT, "The email business key was reused for another resource.");
|
|
296
|
+
}
|
|
297
|
+
return existing;
|
|
298
|
+
}
|
|
299
|
+
const snapshot = this.normalizeFactInput({
|
|
300
|
+
...factInput,
|
|
301
|
+
recipient: await resolveRecipient(),
|
|
302
|
+
});
|
|
303
|
+
return this.toMessageRecord((await this.createEmailMessages({
|
|
304
|
+
kind: snapshot.kind,
|
|
305
|
+
business_key: snapshot.business_key,
|
|
306
|
+
resource_type: snapshot.resource_type,
|
|
307
|
+
resource_id: snapshot.resource_id,
|
|
308
|
+
recipient: snapshot.recipient,
|
|
309
|
+
template_data: snapshot.template_data,
|
|
310
|
+
attachments: [],
|
|
311
|
+
status: "ready",
|
|
312
|
+
required_facts: snapshot.required_facts,
|
|
313
|
+
received_facts: [snapshot.fact],
|
|
314
|
+
predecessor_message_id: null,
|
|
315
|
+
trigger: snapshot.trigger,
|
|
316
|
+
request_id: null,
|
|
317
|
+
requested_by_admin_id: null,
|
|
318
|
+
original_message_id: null,
|
|
319
|
+
next_attempt_at: null,
|
|
320
|
+
sent_at: null,
|
|
321
|
+
failed_at: null,
|
|
322
|
+
payload_expires_at: null,
|
|
323
|
+
terminal_code: null,
|
|
324
|
+
}, sharedContext)));
|
|
325
|
+
}
|
|
326
|
+
async createAdminResend(input, sharedContext = {}) {
|
|
327
|
+
const sourceMessageId = asNonEmptyString(input.source_message_id, "source_message_id");
|
|
328
|
+
const requestId = asUuid(input.request_id, "request_id");
|
|
329
|
+
const requestedByAdminId = asNonEmptyString(input.requested_by_admin_id, "requested_by_admin_id");
|
|
330
|
+
const businessKey = (0, business_keys_1.adminResendBusinessKey)(sourceMessageId, requestId);
|
|
331
|
+
const manager = this.requireManager(sharedContext);
|
|
332
|
+
await manager.execute("select pg_advisory_xact_lock(hashtext(?))", [
|
|
333
|
+
`email:message:${businessKey}`,
|
|
334
|
+
]);
|
|
335
|
+
const replayRows = await manager.execute(`select * from "email_message" where "business_key" = ? for update`, [businessKey], "all");
|
|
336
|
+
if (replayRows[0]) {
|
|
337
|
+
const replay = this.toMessageRecord(replayRows[0]);
|
|
338
|
+
if (replay.deleted_at) {
|
|
339
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.CONFLICT, "The email resend request was already consumed.");
|
|
340
|
+
}
|
|
341
|
+
if (replay.original_message_id !== sourceMessageId ||
|
|
342
|
+
replay.request_id !== requestId ||
|
|
343
|
+
replay.trigger !== "admin_resend") {
|
|
344
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.CONFLICT, "The email resend key was reused with conflicting identity.");
|
|
345
|
+
}
|
|
346
|
+
return replay;
|
|
347
|
+
}
|
|
348
|
+
const sourceRows = await manager.execute(`select * from "email_message"
|
|
349
|
+
where "id" = ? and "deleted_at" is null for update`, [sourceMessageId], "all");
|
|
350
|
+
if (!sourceRows[0]) {
|
|
351
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.NOT_FOUND, "The source email message was not found.");
|
|
352
|
+
}
|
|
353
|
+
const source = this.toMessageRecord(sourceRows[0]);
|
|
354
|
+
if (source.kind === "auth.password_reset") {
|
|
355
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.NOT_ALLOWED, "Password reset messages cannot be resent.");
|
|
356
|
+
}
|
|
357
|
+
if (source.status !== "sent" &&
|
|
358
|
+
source.status !== "unknown" &&
|
|
359
|
+
source.status !== "failed") {
|
|
360
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.CONFLICT, "The source email message is not eligible for resend.");
|
|
361
|
+
}
|
|
362
|
+
return this.toMessageRecord((await this.createEmailMessages({
|
|
363
|
+
kind: source.kind,
|
|
364
|
+
business_key: businessKey,
|
|
365
|
+
resource_type: source.resource_type,
|
|
366
|
+
resource_id: source.resource_id,
|
|
367
|
+
recipient: source.recipient,
|
|
368
|
+
template_data: source.template_data,
|
|
369
|
+
attachments: source.attachments,
|
|
370
|
+
status: "ready",
|
|
371
|
+
required_facts: ["admin_resend"],
|
|
372
|
+
received_facts: ["admin_resend"],
|
|
373
|
+
predecessor_message_id: null,
|
|
374
|
+
trigger: "admin_resend",
|
|
375
|
+
request_id: requestId,
|
|
376
|
+
requested_by_admin_id: requestedByAdminId,
|
|
377
|
+
original_message_id: source.id,
|
|
378
|
+
next_attempt_at: null,
|
|
379
|
+
sent_at: null,
|
|
380
|
+
failed_at: null,
|
|
381
|
+
payload_expires_at: null,
|
|
382
|
+
terminal_code: null,
|
|
383
|
+
}, sharedContext)));
|
|
384
|
+
}
|
|
385
|
+
async listAdminEmailMessages(input, sharedContext = {}) {
|
|
386
|
+
const limit = this.positiveLimit(input.limit);
|
|
387
|
+
const offset = this.safeOffset(input.offset);
|
|
388
|
+
const conditions = ['m."deleted_at" is null'];
|
|
389
|
+
const params = [];
|
|
390
|
+
if (input.kind !== undefined) {
|
|
391
|
+
conditions.push('m."kind" = ?');
|
|
392
|
+
params.push(types_1.EmailKindSchema.parse(input.kind));
|
|
393
|
+
}
|
|
394
|
+
if (input.status !== undefined) {
|
|
395
|
+
if (!message_state_1.EMAIL_MESSAGE_STATUSES.includes(input.status)) {
|
|
396
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "status must be an email message status.");
|
|
397
|
+
}
|
|
398
|
+
conditions.push('m."status" = ?');
|
|
399
|
+
params.push(input.status);
|
|
400
|
+
}
|
|
401
|
+
if (input.trigger !== undefined) {
|
|
402
|
+
const trigger = asNonEmptyString(input.trigger, "trigger");
|
|
403
|
+
if (trigger.length > 100) {
|
|
404
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "trigger must not exceed 100 characters.");
|
|
405
|
+
}
|
|
406
|
+
conditions.push('m."trigger" = ?');
|
|
407
|
+
params.push(trigger);
|
|
408
|
+
}
|
|
409
|
+
for (const [column, value] of [
|
|
410
|
+
["resource_type", input.resource_type],
|
|
411
|
+
["resource_id", input.resource_id],
|
|
412
|
+
]) {
|
|
413
|
+
if (value !== undefined) {
|
|
414
|
+
const normalized = asNonEmptyString(value, column);
|
|
415
|
+
if (normalized.length > 255) {
|
|
416
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, `${column} must not exceed 255 characters.`);
|
|
417
|
+
}
|
|
418
|
+
conditions.push(`m."${column}" = ?`);
|
|
419
|
+
params.push(normalized);
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
const where = conditions.join(" and ");
|
|
423
|
+
const manager = this.requireManager(sharedContext);
|
|
424
|
+
const [rows, countRows] = await Promise.all([
|
|
425
|
+
manager.execute(`select m.*,
|
|
426
|
+
(select count(*)::integer from "email_attempt" a
|
|
427
|
+
where a."message_id" = m."id" and a."deleted_at" is null)
|
|
428
|
+
as "attempt_count"
|
|
429
|
+
from "email_message" m
|
|
430
|
+
where ${where}
|
|
431
|
+
order by m."created_at" desc, m."id" desc
|
|
432
|
+
limit ? offset ?`, [...params, limit, offset], "all"),
|
|
433
|
+
manager.execute(`select count(*) as "count" from "email_message" m where ${where}`, params, "all"),
|
|
434
|
+
]);
|
|
435
|
+
return {
|
|
436
|
+
messages: rows.map((row) => this.toSafeAdminMessage(row)),
|
|
437
|
+
count: Number(countRows[0]?.count ?? 0),
|
|
438
|
+
limit,
|
|
439
|
+
offset,
|
|
440
|
+
};
|
|
441
|
+
}
|
|
442
|
+
async getAdminEmailMessage(messageId, sharedContext = {}) {
|
|
443
|
+
const manager = this.requireManager(sharedContext);
|
|
444
|
+
const rows = await manager.execute(`select m.*,
|
|
445
|
+
(select count(*)::integer from "email_attempt" a
|
|
446
|
+
where a."message_id" = m."id" and a."deleted_at" is null)
|
|
447
|
+
as "attempt_count"
|
|
448
|
+
from "email_message" m
|
|
449
|
+
where m."id" = ? and m."deleted_at" is null
|
|
450
|
+
limit 1`, [asNonEmptyString(messageId, "message_id")], "all");
|
|
451
|
+
if (!rows[0]) {
|
|
452
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.NOT_FOUND, "The email message was not found.");
|
|
453
|
+
}
|
|
454
|
+
const attempts = await manager.execute(`select "id", "attempt_number", "status", "failure_code",
|
|
455
|
+
"started_at", "finished_at", "created_at", "updated_at"
|
|
456
|
+
from "email_attempt"
|
|
457
|
+
where "message_id" = ? and "deleted_at" is null
|
|
458
|
+
order by "attempt_number" asc, "id" asc`, [messageId], "all");
|
|
459
|
+
return {
|
|
460
|
+
message: this.toSafeAdminMessage(rows[0]),
|
|
461
|
+
attempts: attempts.map((attempt) => this.toSafeAdminAttempt(attempt)),
|
|
462
|
+
};
|
|
463
|
+
}
|
|
464
|
+
async suppressMessage(input, sharedContext = {}) {
|
|
465
|
+
const message = await this.lockMessage(input.message_id, sharedContext);
|
|
466
|
+
if (message.status === "suppressed") {
|
|
467
|
+
await this.reevaluateDependentMessages(message, new Date(), sharedContext);
|
|
468
|
+
return message;
|
|
469
|
+
}
|
|
470
|
+
if (message.status !== "pending" && message.status !== "ready") {
|
|
471
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.CONFLICT, "Only pending or ready email messages can be suppressed.");
|
|
472
|
+
}
|
|
473
|
+
const manager = this.requireManager(sharedContext);
|
|
474
|
+
const attempts = await manager.execute(`select count(*)::text as "count" from "email_attempt"
|
|
475
|
+
where "message_id" = ? and "deleted_at" is null`, [message.id], "all");
|
|
476
|
+
if (Number(attempts[0]?.count ?? 0) !== 0) {
|
|
477
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.CONFLICT, "An email message with transport attempts cannot be suppressed.");
|
|
478
|
+
}
|
|
479
|
+
const updated = (await this.updateEmailMessages({
|
|
480
|
+
id: message.id,
|
|
481
|
+
status: "suppressed",
|
|
482
|
+
terminal_code: asSafeStatusCode(input.terminal_code, "terminal_code"),
|
|
483
|
+
}, sharedContext));
|
|
484
|
+
const suppressed = this.toMessageRecord(updated);
|
|
485
|
+
await this.reevaluateDependentMessages(suppressed, new Date(), sharedContext);
|
|
486
|
+
return suppressed;
|
|
487
|
+
}
|
|
488
|
+
async claimReadyMessage(input, sharedContext = {}) {
|
|
489
|
+
return await this.claimReadyMessageInTransaction(input, sharedContext);
|
|
490
|
+
}
|
|
491
|
+
async claimReadyMessageForAutomaticDispatch(input, sharedContext = {}) {
|
|
492
|
+
return await this.claimReadyMessageInTransaction({ ...input, allow_password_reset: false }, sharedContext);
|
|
493
|
+
}
|
|
494
|
+
async claimDueRetries(input, sharedContext = {}) {
|
|
495
|
+
const now = asDate(input.now, "now");
|
|
496
|
+
const limit = this.positiveLimit(input.limit);
|
|
497
|
+
const manager = this.requireManager(sharedContext);
|
|
498
|
+
const rows = await manager.execute(`select "id" from "email_message"
|
|
499
|
+
where "status" = 'retry_pending'
|
|
500
|
+
and "next_attempt_at" <= ?
|
|
501
|
+
and "kind" <> 'auth.password_reset'
|
|
502
|
+
and "deleted_at" is null
|
|
503
|
+
order by "next_attempt_at" asc, "id" asc
|
|
504
|
+
limit ?
|
|
505
|
+
for update skip locked`, [now, limit], "all");
|
|
506
|
+
const claims = [];
|
|
507
|
+
for (const row of rows) {
|
|
508
|
+
const claim = await this.claimReadyMessageInTransaction({ message_id: row.id, now }, sharedContext);
|
|
509
|
+
if (claim) {
|
|
510
|
+
claims.push(claim);
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
return claims;
|
|
514
|
+
}
|
|
515
|
+
async markAttemptSent(input) {
|
|
516
|
+
return await this.completeAttempt({
|
|
517
|
+
...input,
|
|
518
|
+
attempt_status: "sent",
|
|
519
|
+
message_status: "sent",
|
|
520
|
+
failure_code: null,
|
|
521
|
+
next_attempt_at: null,
|
|
522
|
+
});
|
|
523
|
+
}
|
|
524
|
+
async markAttemptRetryable(input) {
|
|
525
|
+
return await this.completeAttempt({
|
|
526
|
+
...input,
|
|
527
|
+
notification_id: input.notification_id ?? null,
|
|
528
|
+
attempt_status: "failed",
|
|
529
|
+
message_status: "retry_pending",
|
|
530
|
+
});
|
|
531
|
+
}
|
|
532
|
+
async markAttemptFailed(input) {
|
|
533
|
+
return await this.completeAttempt({
|
|
534
|
+
...input,
|
|
535
|
+
notification_id: input.notification_id ?? null,
|
|
536
|
+
attempt_status: "failed",
|
|
537
|
+
message_status: "failed",
|
|
538
|
+
next_attempt_at: null,
|
|
539
|
+
});
|
|
540
|
+
}
|
|
541
|
+
async markAttemptUnknown(input) {
|
|
542
|
+
return await this.completeAttempt({
|
|
543
|
+
...input,
|
|
544
|
+
notification_id: input.notification_id ?? null,
|
|
545
|
+
attempt_status: "unknown",
|
|
546
|
+
message_status: "unknown",
|
|
547
|
+
next_attempt_at: null,
|
|
548
|
+
});
|
|
549
|
+
}
|
|
550
|
+
async renewAttemptLease(input, sharedContext = {}) {
|
|
551
|
+
const now = asDate(input.now ?? new Date(), "now");
|
|
552
|
+
const leaseDuration = input.lease_duration_ms ?? exports.EMAIL_ATTEMPT_LEASE_MS;
|
|
553
|
+
if (!Number.isInteger(leaseDuration) || leaseDuration <= 0) {
|
|
554
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "lease_duration_ms must be a positive integer.");
|
|
555
|
+
}
|
|
556
|
+
const rows = await this.requireManager(sharedContext).execute(`update "email_attempt" a
|
|
557
|
+
set "lease_started_at" = ?, "lease_expires_at" = ?, "updated_at" = now()
|
|
558
|
+
where a."id" = ? and a."status" = 'processing'
|
|
559
|
+
and a."attempt_token" = ? and a."deleted_at" is null
|
|
560
|
+
and exists (
|
|
561
|
+
select 1 from "email_message" m
|
|
562
|
+
where m."id" = a."message_id" and m."status" = 'sending'
|
|
563
|
+
and m."deleted_at" is null
|
|
564
|
+
)
|
|
565
|
+
returning a.*`, [
|
|
566
|
+
now,
|
|
567
|
+
new Date(now.getTime() + leaseDuration),
|
|
568
|
+
asNonEmptyString(input.attempt_id, "attempt_id"),
|
|
569
|
+
asNonEmptyString(input.attempt_token, "attempt_token"),
|
|
570
|
+
], "all");
|
|
571
|
+
if (!rows[0]) {
|
|
572
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.CONFLICT, "The email attempt lease is no longer owned by this token.");
|
|
573
|
+
}
|
|
574
|
+
return this.toAttemptRecord(rows[0]);
|
|
575
|
+
}
|
|
576
|
+
async completeStaleAttempt(input) {
|
|
577
|
+
if (input.outcome === "sent") {
|
|
578
|
+
return await this.completeAttempt({
|
|
579
|
+
attempt_id: input.attempt_id,
|
|
580
|
+
attempt_status: "sent",
|
|
581
|
+
attempt_token: input.attempt_token,
|
|
582
|
+
failure_code: null,
|
|
583
|
+
finished_at: input.now,
|
|
584
|
+
message_status: "sent",
|
|
585
|
+
next_attempt_at: null,
|
|
586
|
+
notification_id: input.notification_id,
|
|
587
|
+
require_lease_expired_at: input.now,
|
|
588
|
+
});
|
|
589
|
+
}
|
|
590
|
+
return await this.completeAttempt({
|
|
591
|
+
attempt_id: input.attempt_id,
|
|
592
|
+
attempt_status: "unknown",
|
|
593
|
+
attempt_token: input.attempt_token,
|
|
594
|
+
failure_code: "lease_expired",
|
|
595
|
+
finished_at: input.now,
|
|
596
|
+
message_status: "unknown",
|
|
597
|
+
next_attempt_at: null,
|
|
598
|
+
notification_id: input.notification_id ?? null,
|
|
599
|
+
require_lease_expired_at: input.now,
|
|
600
|
+
});
|
|
601
|
+
}
|
|
602
|
+
async listStaleAttemptCandidates(input, sharedContext = {}) {
|
|
603
|
+
const manager = this.requireManager(sharedContext);
|
|
604
|
+
const rows = await manager.execute(`select a."id" as "attempt_id", a."attempt_token", a."message_id", m."kind"
|
|
605
|
+
from "email_attempt" a
|
|
606
|
+
join "email_message" m on m."id" = a."message_id"
|
|
607
|
+
where a."status" = 'processing' and a."lease_expires_at" <= ?
|
|
608
|
+
and a."attempt_token" is not null and a."deleted_at" is null
|
|
609
|
+
and m."status" = 'sending' and m."deleted_at" is null
|
|
610
|
+
order by a."lease_expires_at" asc, a."id" asc
|
|
611
|
+
limit ?`, [asDate(input.now, "now"), this.positiveLimit(input.limit)], "all");
|
|
612
|
+
return rows.map((row) => ({
|
|
613
|
+
attempt_id: asNonEmptyString(row.attempt_id, "attempt_id"),
|
|
614
|
+
attempt_token: asNonEmptyString(row.attempt_token, "attempt_token"),
|
|
615
|
+
kind: types_1.EmailKindSchema.parse(row.kind),
|
|
616
|
+
message_id: asNonEmptyString(row.message_id, "message_id"),
|
|
617
|
+
notification_idempotency_key: (0, failure_classification_1.emailAttemptNotificationKey)(row.attempt_id),
|
|
618
|
+
}));
|
|
619
|
+
}
|
|
620
|
+
async reconcilePendingMessageDependencies(input, sharedContext = {}) {
|
|
621
|
+
const now = asDate(input.now, "now");
|
|
622
|
+
const manager = this.requireManager(sharedContext);
|
|
623
|
+
const rows = await manager.execute(`select m.* from "email_message" m
|
|
624
|
+
left join "email_message" p on p."id" = m."predecessor_message_id"
|
|
625
|
+
and p."deleted_at" is null
|
|
626
|
+
where m."status" = 'pending' and m."deleted_at" is null
|
|
627
|
+
and (
|
|
628
|
+
(m."predecessor_message_id" is null
|
|
629
|
+
and m."received_facts" @> m."required_facts")
|
|
630
|
+
or p."status" in ('failed', 'unknown', 'suppressed')
|
|
631
|
+
or (p."status" = 'sent'
|
|
632
|
+
and m."received_facts" @> m."required_facts")
|
|
633
|
+
)
|
|
634
|
+
order by m."updated_at" asc, m."id" asc
|
|
635
|
+
limit ?
|
|
636
|
+
for update of m skip locked`, [this.positiveLimit(input.limit)], "all");
|
|
637
|
+
let transitioned = 0;
|
|
638
|
+
for (const row of rows) {
|
|
639
|
+
const message = this.toMessageRecord(row);
|
|
640
|
+
const state = await this.resolvePendingState(message.required_facts, message.received_facts, message.predecessor_message_id, sharedContext);
|
|
641
|
+
if (state.status === message.status &&
|
|
642
|
+
state.terminal_code === message.terminal_code) {
|
|
643
|
+
continue;
|
|
644
|
+
}
|
|
645
|
+
const updated = this.toMessageRecord((await this.updateEmailMessages({
|
|
646
|
+
id: message.id,
|
|
647
|
+
status: state.status,
|
|
648
|
+
terminal_code: state.terminal_code,
|
|
649
|
+
failed_at: state.status === "failed" ? now : message.failed_at,
|
|
650
|
+
}, sharedContext)));
|
|
651
|
+
transitioned += 1;
|
|
652
|
+
if (updated.status === "failed" || updated.status === "suppressed") {
|
|
653
|
+
await this.reevaluateDependentMessages(updated, now, sharedContext);
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
return transitioned;
|
|
657
|
+
}
|
|
658
|
+
async listReadyMessageIds(input, sharedContext = {}) {
|
|
659
|
+
const rows = await this.requireManager(sharedContext).execute(`select "id" from "email_message"
|
|
660
|
+
where "status" = 'ready' and "kind" <> 'auth.password_reset'
|
|
661
|
+
and "deleted_at" is null
|
|
662
|
+
order by "updated_at" asc, "id" asc
|
|
663
|
+
limit ?`, [this.positiveLimit(input.limit)], "all");
|
|
664
|
+
return rows.map((row) => asNonEmptyString(row.id, "id"));
|
|
665
|
+
}
|
|
666
|
+
async completeAttempt(input, sharedContext = {}) {
|
|
667
|
+
const manager = this.requireManager(sharedContext);
|
|
668
|
+
const finishedAt = asDate(input.finished_at ?? new Date(), "finished_at");
|
|
669
|
+
const nextAttemptAt = input.next_attempt_at === null
|
|
670
|
+
? null
|
|
671
|
+
: asDate(input.next_attempt_at, "next_attempt_at");
|
|
672
|
+
if (nextAttemptAt && nextAttemptAt.getTime() <= finishedAt.getTime()) {
|
|
673
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "next_attempt_at must be later than finished_at.");
|
|
674
|
+
}
|
|
675
|
+
const failureCode = input.failure_code === null
|
|
676
|
+
? null
|
|
677
|
+
: asSafeStatusCode(input.failure_code, "failure_code");
|
|
678
|
+
const notificationId = input.notification_id === null
|
|
679
|
+
? null
|
|
680
|
+
: asNonEmptyString(input.notification_id, "notification_id");
|
|
681
|
+
if (input.attempt_status === "sent" && !notificationId) {
|
|
682
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "A sent email attempt requires notification_id.");
|
|
683
|
+
}
|
|
684
|
+
const requiredLeaseExpiry = input.require_lease_expired_at
|
|
685
|
+
? asDate(input.require_lease_expired_at, "require_lease_expired_at")
|
|
686
|
+
: null;
|
|
687
|
+
const attempts = await manager.execute(`update "email_attempt"
|
|
688
|
+
set "status" = ?, "attempt_token" = null, "notification_id" = ?,
|
|
689
|
+
"failure_code" = ?, "finished_at" = ?, "updated_at" = now()
|
|
690
|
+
where "id" = ? and "status" = 'processing' and "attempt_token" = ?
|
|
691
|
+
and "deleted_at" is null
|
|
692
|
+
${requiredLeaseExpiry ? 'and "lease_expires_at" <= ?' : ""}
|
|
693
|
+
returning *`, [
|
|
694
|
+
input.attempt_status,
|
|
695
|
+
notificationId,
|
|
696
|
+
failureCode,
|
|
697
|
+
finishedAt,
|
|
698
|
+
asNonEmptyString(input.attempt_id, "attempt_id"),
|
|
699
|
+
asNonEmptyString(input.attempt_token, "attempt_token"),
|
|
700
|
+
...(requiredLeaseExpiry ? [requiredLeaseExpiry] : []),
|
|
701
|
+
], "all");
|
|
702
|
+
if (!attempts[0]) {
|
|
703
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.CONFLICT, "The email attempt is no longer owned by this token.");
|
|
704
|
+
}
|
|
705
|
+
const attempt = this.toAttemptRecord(attempts[0]);
|
|
706
|
+
const messages = await manager.execute(`update "email_message"
|
|
707
|
+
set "status" = ?, "next_attempt_at" = ?,
|
|
708
|
+
"sent_at" = case when ? = 'sent' then ? else "sent_at" end,
|
|
709
|
+
"failed_at" = case when ? = 'failed' then ? else "failed_at" end,
|
|
710
|
+
"terminal_code" = case when ? in ('failed', 'unknown') then ? else null end,
|
|
711
|
+
"updated_at" = now()
|
|
712
|
+
where "id" = ? and "status" = 'sending' and "deleted_at" is null
|
|
713
|
+
returning *`, [
|
|
714
|
+
input.message_status,
|
|
715
|
+
nextAttemptAt,
|
|
716
|
+
input.message_status,
|
|
717
|
+
finishedAt,
|
|
718
|
+
input.message_status,
|
|
719
|
+
finishedAt,
|
|
720
|
+
input.message_status,
|
|
721
|
+
failureCode,
|
|
722
|
+
attempt.message_id,
|
|
723
|
+
], "all");
|
|
724
|
+
if (!messages[0]) {
|
|
725
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.CONFLICT, "The email attempt no longer owns its message.");
|
|
726
|
+
}
|
|
727
|
+
const message = this.toMessageRecord(messages[0]);
|
|
728
|
+
if (message.status === "sent" ||
|
|
729
|
+
message.status === "failed" ||
|
|
730
|
+
message.status === "unknown") {
|
|
731
|
+
await this.reevaluateDependentMessages(message, finishedAt, sharedContext);
|
|
732
|
+
}
|
|
733
|
+
return {
|
|
734
|
+
attempt,
|
|
735
|
+
message,
|
|
736
|
+
};
|
|
737
|
+
}
|
|
738
|
+
async claimReadyMessageInTransaction(input, sharedContext) {
|
|
739
|
+
const now = asDate(input.now ?? new Date(), "now");
|
|
740
|
+
const leaseDuration = input.lease_duration_ms ?? exports.EMAIL_ATTEMPT_LEASE_MS;
|
|
741
|
+
if (!Number.isInteger(leaseDuration) || leaseDuration <= 0) {
|
|
742
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "lease_duration_ms must be a positive integer.");
|
|
743
|
+
}
|
|
744
|
+
const message = await this.lockMessage(input.message_id, sharedContext);
|
|
745
|
+
if (input.allow_password_reset === false &&
|
|
746
|
+
message.kind === "auth.password_reset") {
|
|
747
|
+
return null;
|
|
748
|
+
}
|
|
749
|
+
const eligible = message.status === "ready" ||
|
|
750
|
+
(message.status === "retry_pending" &&
|
|
751
|
+
message.next_attempt_at !== null &&
|
|
752
|
+
message.next_attempt_at.getTime() <= now.getTime());
|
|
753
|
+
if (!eligible) {
|
|
754
|
+
return null;
|
|
755
|
+
}
|
|
756
|
+
if (message.payload_expires_at &&
|
|
757
|
+
message.payload_expires_at.getTime() <= now.getTime()) {
|
|
758
|
+
const expired = this.toMessageRecord((await this.updateEmailMessages({
|
|
759
|
+
id: message.id,
|
|
760
|
+
status: "failed",
|
|
761
|
+
failed_at: now,
|
|
762
|
+
terminal_code: "payload_expired",
|
|
763
|
+
next_attempt_at: null,
|
|
764
|
+
}, sharedContext)));
|
|
765
|
+
await this.reevaluateDependentMessages(expired, now, sharedContext);
|
|
766
|
+
return null;
|
|
767
|
+
}
|
|
768
|
+
const state = await this.resolvePendingState(message.required_facts, message.received_facts, message.predecessor_message_id, sharedContext);
|
|
769
|
+
if (state.status !== "ready") {
|
|
770
|
+
const updated = this.toMessageRecord((await this.updateEmailMessages({
|
|
771
|
+
id: message.id,
|
|
772
|
+
status: state.status,
|
|
773
|
+
terminal_code: state.terminal_code,
|
|
774
|
+
failed_at: state.status === "failed" ? now : message.failed_at,
|
|
775
|
+
}, sharedContext)));
|
|
776
|
+
if (updated.status === "failed" || updated.status === "suppressed") {
|
|
777
|
+
await this.reevaluateDependentMessages(updated, now, sharedContext);
|
|
778
|
+
}
|
|
779
|
+
return null;
|
|
780
|
+
}
|
|
781
|
+
const manager = this.requireManager(sharedContext);
|
|
782
|
+
const numberRows = await manager.execute(`select coalesce(max("attempt_number"), 0)::integer + 1 as "next_number"
|
|
783
|
+
from "email_attempt" where "message_id" = ?`, [message.id], "all");
|
|
784
|
+
let previousRows = await manager.execute(`select "notification_id" from "email_attempt"
|
|
785
|
+
where "message_id" = ? and "notification_id" is not null
|
|
786
|
+
and "deleted_at" is null
|
|
787
|
+
order by "attempt_number" desc
|
|
788
|
+
limit 1`, [message.id], "all");
|
|
789
|
+
if (!previousRows[0] && message.original_message_id) {
|
|
790
|
+
previousRows = await manager.execute(`select "notification_id" from "email_attempt"
|
|
791
|
+
where "message_id" = ? and "notification_id" is not null
|
|
792
|
+
and "deleted_at" is null
|
|
793
|
+
order by "attempt_number" desc
|
|
794
|
+
limit 1`, [message.original_message_id], "all");
|
|
795
|
+
}
|
|
796
|
+
const attemptToken = (0, node_crypto_1.randomUUID)();
|
|
797
|
+
const leaseExpiresAt = new Date(now.getTime() + leaseDuration);
|
|
798
|
+
const created = (await this.createEmailAttempts({
|
|
799
|
+
message_id: message.id,
|
|
800
|
+
attempt_number: numberRows[0]?.next_number ?? 1,
|
|
801
|
+
status: "processing",
|
|
802
|
+
attempt_token: attemptToken,
|
|
803
|
+
lease_started_at: now,
|
|
804
|
+
lease_expires_at: leaseExpiresAt,
|
|
805
|
+
notification_id: null,
|
|
806
|
+
failure_code: null,
|
|
807
|
+
started_at: now,
|
|
808
|
+
finished_at: null,
|
|
809
|
+
}, sharedContext));
|
|
810
|
+
const updated = (await this.updateEmailMessages({
|
|
811
|
+
id: message.id,
|
|
812
|
+
status: "sending",
|
|
813
|
+
next_attempt_at: null,
|
|
814
|
+
terminal_code: null,
|
|
815
|
+
}, sharedContext));
|
|
816
|
+
return {
|
|
817
|
+
message: this.toMessageRecord(updated),
|
|
818
|
+
attempt: this.toAttemptRecord(created),
|
|
819
|
+
attempt_token: attemptToken,
|
|
820
|
+
previous_notification_id: asNullableString(previousRows[0]?.notification_id),
|
|
821
|
+
};
|
|
822
|
+
}
|
|
823
|
+
normalizeFactInput(input) {
|
|
824
|
+
const kind = types_1.EmailKindSchema.parse(input.kind);
|
|
825
|
+
const requiredFacts = (0, message_state_1.canonicalizeFacts)(input.required_facts);
|
|
826
|
+
const fact = asNonEmptyString(input.fact, "fact");
|
|
827
|
+
if (!requiredFacts.length || !requiredFacts.includes(fact)) {
|
|
828
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "required_facts must include the received fact.");
|
|
829
|
+
}
|
|
830
|
+
const templateData = input.template_data === undefined || input.template_data === null
|
|
831
|
+
? null
|
|
832
|
+
: types_1.EmailPersistedDataSchemas[kind].parse(input.template_data);
|
|
833
|
+
const attachments = documents_1.DocumentsEmailArtifactSchema.array().parse(input.attachments ?? []);
|
|
834
|
+
const termsEffectiveAt = input.terms_effective_at
|
|
835
|
+
? asDate(input.terms_effective_at, "terms_effective_at")
|
|
836
|
+
: null;
|
|
837
|
+
if (termsEffectiveAt && kind !== "order.received") {
|
|
838
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "terms_effective_at is only valid for customer order confirmations.");
|
|
839
|
+
}
|
|
840
|
+
const suppressionCode = input.suppression_code ?? null;
|
|
841
|
+
if (suppressionCode && !(0, message_state_1.isEmailSafeStatusCode)(suppressionCode)) {
|
|
842
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "suppression_code must be allowlisted.");
|
|
843
|
+
}
|
|
844
|
+
return {
|
|
845
|
+
kind,
|
|
846
|
+
business_key: asNonEmptyString(input.business_key, "business_key"),
|
|
847
|
+
resource_type: asNonEmptyString(input.resource_type, "resource_type"),
|
|
848
|
+
resource_id: input.resource_id
|
|
849
|
+
? asNonEmptyString(input.resource_id, "resource_id")
|
|
850
|
+
: null,
|
|
851
|
+
recipient: input.recipient
|
|
852
|
+
? asNonEmptyString(input.recipient, "recipient")
|
|
853
|
+
: null,
|
|
854
|
+
template_data: templateData,
|
|
855
|
+
attachments,
|
|
856
|
+
required_facts: requiredFacts,
|
|
857
|
+
fact,
|
|
858
|
+
predecessor_message_id: input.predecessor_message_id
|
|
859
|
+
? asNonEmptyString(input.predecessor_message_id, "predecessor_message_id")
|
|
860
|
+
: null,
|
|
861
|
+
trigger: input.trigger
|
|
862
|
+
? asNonEmptyString(input.trigger, "trigger")
|
|
863
|
+
: "automatic",
|
|
864
|
+
request_id: input.request_id ?? null,
|
|
865
|
+
requested_by_admin_id: input.requested_by_admin_id ?? null,
|
|
866
|
+
original_message_id: input.original_message_id ?? null,
|
|
867
|
+
payload_expires_at: input.payload_expires_at
|
|
868
|
+
? asDate(input.payload_expires_at, "payload_expires_at")
|
|
869
|
+
: null,
|
|
870
|
+
suppression_code: suppressionCode,
|
|
871
|
+
terms_effective_at: termsEffectiveAt,
|
|
872
|
+
};
|
|
873
|
+
}
|
|
874
|
+
assertSameMessageIdentity(existing, input) {
|
|
875
|
+
const conflicts = existing.kind !== input.kind ||
|
|
876
|
+
existing.resource_type !== input.resource_type ||
|
|
877
|
+
existing.resource_id !== input.resource_id ||
|
|
878
|
+
existing.trigger !== input.trigger ||
|
|
879
|
+
!equalJson(existing.required_facts, input.required_facts) ||
|
|
880
|
+
(existing.predecessor_message_id !== null &&
|
|
881
|
+
existing.predecessor_message_id !== input.predecessor_message_id) ||
|
|
882
|
+
(existing.recipient !== null &&
|
|
883
|
+
input.recipient !== null &&
|
|
884
|
+
existing.recipient !== input.recipient) ||
|
|
885
|
+
(existing.payload_expires_at !== null &&
|
|
886
|
+
input.payload_expires_at !== null &&
|
|
887
|
+
existing.payload_expires_at.getTime() !==
|
|
888
|
+
input.payload_expires_at.getTime());
|
|
889
|
+
if (conflicts) {
|
|
890
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.CONFLICT, "The email business key was reused with conflicting facts.");
|
|
891
|
+
}
|
|
892
|
+
}
|
|
893
|
+
mergeTemplateData(kind, existing, incoming) {
|
|
894
|
+
if (!existing) {
|
|
895
|
+
return incoming;
|
|
896
|
+
}
|
|
897
|
+
if (!incoming) {
|
|
898
|
+
return existing;
|
|
899
|
+
}
|
|
900
|
+
const merged = { ...existing };
|
|
901
|
+
for (const [key, value] of Object.entries(incoming)) {
|
|
902
|
+
if (key in merged && !equalJson(merged[key], value)) {
|
|
903
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.CONFLICT, "The email business key was reused with conflicting template data.");
|
|
904
|
+
}
|
|
905
|
+
merged[key] = value;
|
|
906
|
+
}
|
|
907
|
+
return types_1.EmailPersistedDataSchemas[kind].parse(merged);
|
|
908
|
+
}
|
|
909
|
+
mergeAttachments(existing, incoming) {
|
|
910
|
+
const byId = new Map(existing.map((attachment) => [(0, attachment_1.emailAttachmentId)(attachment), attachment]));
|
|
911
|
+
for (const artifact of incoming) {
|
|
912
|
+
const id = (0, attachment_1.emailAttachmentId)(artifact);
|
|
913
|
+
const prior = byId.get(id);
|
|
914
|
+
if (prior && !equalJson(prior, artifact)) {
|
|
915
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.CONFLICT, "The email business key was reused with conflicting attachments.");
|
|
916
|
+
}
|
|
917
|
+
byId.set(id, artifact);
|
|
918
|
+
}
|
|
919
|
+
return [...byId.values()];
|
|
920
|
+
}
|
|
921
|
+
async findTermsAttachmentAt(effectiveAt, sharedContext) {
|
|
922
|
+
const rows = await this.requireManager(sharedContext).execute(`select * from "email_terms_version"
|
|
923
|
+
where "effective_at" <= ? and "deleted_at" is null
|
|
924
|
+
order by "effective_at" desc, "created_at" desc, "id" desc
|
|
925
|
+
limit 1`, [effectiveAt], "all");
|
|
926
|
+
if (!rows[0]) {
|
|
927
|
+
return null;
|
|
928
|
+
}
|
|
929
|
+
const version = this.toTermsVersionRecord(rows[0]);
|
|
930
|
+
return {
|
|
931
|
+
source: "terms",
|
|
932
|
+
terms_version_id: version.id,
|
|
933
|
+
file_id: version.file_id,
|
|
934
|
+
filename: version.filename,
|
|
935
|
+
content_type: "application/pdf",
|
|
936
|
+
byte_size: version.byte_size,
|
|
937
|
+
sha256: version.sha256,
|
|
938
|
+
};
|
|
939
|
+
}
|
|
940
|
+
async resolvePendingState(requiredFacts, receivedFacts, predecessorMessageId, sharedContext) {
|
|
941
|
+
if (!predecessorMessageId) {
|
|
942
|
+
return (0, message_state_1.hasRequiredFacts)(requiredFacts, receivedFacts)
|
|
943
|
+
? (0, message_state_1.statusAfterPredecessor)(null)
|
|
944
|
+
: { status: "pending", terminal_code: null };
|
|
945
|
+
}
|
|
946
|
+
const rows = await this.requireManager(sharedContext).execute(`select * from "email_message"
|
|
947
|
+
where "id" = ? and "deleted_at" is null`, [asNonEmptyString(predecessorMessageId, "predecessor_message_id")], "all");
|
|
948
|
+
if (!rows[0]) {
|
|
949
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.NOT_FOUND, "The predecessor email message was not found.");
|
|
950
|
+
}
|
|
951
|
+
return this.resolveStateWithPredecessor(requiredFacts, receivedFacts, this.toMessageRecord(rows[0]).status);
|
|
952
|
+
}
|
|
953
|
+
resolveStateWithPredecessor(requiredFacts, receivedFacts, predecessorStatus) {
|
|
954
|
+
const predecessorState = (0, message_state_1.statusAfterPredecessor)(predecessorStatus);
|
|
955
|
+
if (predecessorState.status === "failed" ||
|
|
956
|
+
predecessorState.status === "suppressed") {
|
|
957
|
+
return predecessorState;
|
|
958
|
+
}
|
|
959
|
+
return (0, message_state_1.hasRequiredFacts)(requiredFacts, receivedFacts)
|
|
960
|
+
? predecessorState
|
|
961
|
+
: { status: "pending", terminal_code: null };
|
|
962
|
+
}
|
|
963
|
+
async reevaluateDependentMessages(predecessor, now, sharedContext, visited = new Set()) {
|
|
964
|
+
if (visited.has(predecessor.id)) {
|
|
965
|
+
return;
|
|
966
|
+
}
|
|
967
|
+
visited.add(predecessor.id);
|
|
968
|
+
const manager = this.requireManager(sharedContext);
|
|
969
|
+
const rows = await manager.execute(`select * from "email_message"
|
|
970
|
+
where "predecessor_message_id" = ? and "status" = 'pending'
|
|
971
|
+
and "deleted_at" is null
|
|
972
|
+
order by "id" asc
|
|
973
|
+
for update skip locked`, [predecessor.id], "all");
|
|
974
|
+
for (const row of rows) {
|
|
975
|
+
const dependent = this.toMessageRecord(row);
|
|
976
|
+
const state = this.resolveStateWithPredecessor(dependent.required_facts, dependent.received_facts, predecessor.status);
|
|
977
|
+
if (state.status === "pending") {
|
|
978
|
+
continue;
|
|
979
|
+
}
|
|
980
|
+
const updated = this.toMessageRecord((await this.updateEmailMessages({
|
|
981
|
+
id: dependent.id,
|
|
982
|
+
status: state.status,
|
|
983
|
+
terminal_code: state.terminal_code,
|
|
984
|
+
failed_at: state.status === "failed" ? now : dependent.failed_at,
|
|
985
|
+
}, sharedContext)));
|
|
986
|
+
if (updated.status === "failed" || updated.status === "suppressed") {
|
|
987
|
+
await this.reevaluateDependentMessages(updated, now, sharedContext, visited);
|
|
988
|
+
}
|
|
989
|
+
}
|
|
990
|
+
}
|
|
991
|
+
async lockMessage(messageId, sharedContext) {
|
|
992
|
+
const manager = this.requireManager(sharedContext);
|
|
993
|
+
const rows = await manager.execute(`select * from "email_message"
|
|
994
|
+
where "id" = ? and "deleted_at" is null for update`, [asNonEmptyString(messageId, "message_id")], "all");
|
|
995
|
+
if (!rows[0]) {
|
|
996
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.NOT_FOUND, "The email message was not found.");
|
|
997
|
+
}
|
|
998
|
+
return this.toMessageRecord(rows[0]);
|
|
999
|
+
}
|
|
1000
|
+
toMessageRecord(value) {
|
|
1001
|
+
const kind = types_1.EmailKindSchema.parse(value.kind);
|
|
1002
|
+
const templateData = value.template_data === null || value.template_data === undefined
|
|
1003
|
+
? null
|
|
1004
|
+
: types_1.EmailPersistedDataSchemas[kind].parse(value.template_data);
|
|
1005
|
+
return {
|
|
1006
|
+
id: asNonEmptyString(value.id, "id"),
|
|
1007
|
+
kind,
|
|
1008
|
+
business_key: asNonEmptyString(value.business_key, "business_key"),
|
|
1009
|
+
resource_type: asNonEmptyString(value.resource_type, "resource_type"),
|
|
1010
|
+
resource_id: asNullableString(value.resource_id),
|
|
1011
|
+
recipient: asNullableString(value.recipient),
|
|
1012
|
+
template_data: templateData,
|
|
1013
|
+
attachments: attachment_1.EmailAttachmentSchema.array().parse(value.attachments ?? []),
|
|
1014
|
+
status: value.status,
|
|
1015
|
+
required_facts: (0, message_state_1.canonicalizeFacts)(Array.isArray(value.required_facts)
|
|
1016
|
+
? value.required_facts
|
|
1017
|
+
: []),
|
|
1018
|
+
received_facts: (0, message_state_1.canonicalizeFacts)(Array.isArray(value.received_facts)
|
|
1019
|
+
? value.received_facts
|
|
1020
|
+
: []),
|
|
1021
|
+
predecessor_message_id: asNullableString(value.predecessor_message_id),
|
|
1022
|
+
trigger: asNonEmptyString(value.trigger, "trigger"),
|
|
1023
|
+
request_id: asNullableString(value.request_id),
|
|
1024
|
+
requested_by_admin_id: asNullableString(value.requested_by_admin_id),
|
|
1025
|
+
original_message_id: asNullableString(value.original_message_id),
|
|
1026
|
+
next_attempt_at: asNullableDate(value.next_attempt_at),
|
|
1027
|
+
sent_at: asNullableDate(value.sent_at),
|
|
1028
|
+
failed_at: asNullableDate(value.failed_at),
|
|
1029
|
+
payload_expires_at: asNullableDate(value.payload_expires_at),
|
|
1030
|
+
terminal_code: asNullableString(value.terminal_code),
|
|
1031
|
+
created_at: asNullableDate(value.created_at) ?? new Date(0),
|
|
1032
|
+
updated_at: asNullableDate(value.updated_at) ?? new Date(0),
|
|
1033
|
+
deleted_at: asNullableDate(value.deleted_at),
|
|
1034
|
+
};
|
|
1035
|
+
}
|
|
1036
|
+
toAttemptRecord(value) {
|
|
1037
|
+
return {
|
|
1038
|
+
id: asNonEmptyString(value.id, "id"),
|
|
1039
|
+
message_id: asNonEmptyString(value.message_id, "message_id"),
|
|
1040
|
+
attempt_number: Number(value.attempt_number),
|
|
1041
|
+
status: value.status,
|
|
1042
|
+
attempt_token: asNullableString(value.attempt_token),
|
|
1043
|
+
lease_started_at: asNullableDate(value.lease_started_at),
|
|
1044
|
+
lease_expires_at: asNullableDate(value.lease_expires_at),
|
|
1045
|
+
notification_id: asNullableString(value.notification_id),
|
|
1046
|
+
failure_code: asNullableString(value.failure_code),
|
|
1047
|
+
started_at: asDate(value.started_at, "started_at"),
|
|
1048
|
+
finished_at: asNullableDate(value.finished_at),
|
|
1049
|
+
created_at: asNullableDate(value.created_at) ?? new Date(0),
|
|
1050
|
+
updated_at: asNullableDate(value.updated_at) ?? new Date(0),
|
|
1051
|
+
deleted_at: asNullableDate(value.deleted_at),
|
|
1052
|
+
};
|
|
1053
|
+
}
|
|
1054
|
+
toSafeAdminMessage(value) {
|
|
1055
|
+
const message = this.toMessageRecord(value);
|
|
1056
|
+
return {
|
|
1057
|
+
id: message.id,
|
|
1058
|
+
kind: message.kind,
|
|
1059
|
+
status: message.status,
|
|
1060
|
+
resource_type: message.resource_type,
|
|
1061
|
+
resource_id: message.resource_id,
|
|
1062
|
+
trigger: message.trigger,
|
|
1063
|
+
request_id: message.request_id,
|
|
1064
|
+
requested_by_admin_id: message.requested_by_admin_id,
|
|
1065
|
+
original_message_id: message.original_message_id,
|
|
1066
|
+
attempt_count: Number(value.attempt_count ?? 0),
|
|
1067
|
+
next_attempt_at: message.next_attempt_at?.toISOString() ?? null,
|
|
1068
|
+
sent_at: message.sent_at?.toISOString() ?? null,
|
|
1069
|
+
failed_at: message.failed_at?.toISOString() ?? null,
|
|
1070
|
+
terminal_code: message.terminal_code === null
|
|
1071
|
+
? null
|
|
1072
|
+
: asSafeStatusCode(message.terminal_code, "terminal_code"),
|
|
1073
|
+
created_at: message.created_at.toISOString(),
|
|
1074
|
+
updated_at: message.updated_at.toISOString(),
|
|
1075
|
+
};
|
|
1076
|
+
}
|
|
1077
|
+
toSafeAdminAttempt(value) {
|
|
1078
|
+
return {
|
|
1079
|
+
id: asNonEmptyString(value.id, "id"),
|
|
1080
|
+
attempt_number: Number(value.attempt_number),
|
|
1081
|
+
status: value.status,
|
|
1082
|
+
failure_code: value.failure_code === null || value.failure_code === undefined
|
|
1083
|
+
? null
|
|
1084
|
+
: asSafeStatusCode(value.failure_code, "failure_code"),
|
|
1085
|
+
started_at: asDate(value.started_at, "started_at").toISOString(),
|
|
1086
|
+
finished_at: asNullableDate(value.finished_at)?.toISOString() ?? null,
|
|
1087
|
+
created_at: asDate(value.created_at, "created_at").toISOString(),
|
|
1088
|
+
updated_at: asDate(value.updated_at, "updated_at").toISOString(),
|
|
1089
|
+
};
|
|
1090
|
+
}
|
|
1091
|
+
normalizeTermsVersionInput(input) {
|
|
1092
|
+
const byteSize = Number(input.byte_size);
|
|
1093
|
+
if (!Number.isInteger(byteSize) ||
|
|
1094
|
+
byteSize < 1 ||
|
|
1095
|
+
byteSize > email_1.EMAIL_TERMS_MAX_PDF_BYTES) {
|
|
1096
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, `byte_size must be from 1 to ${email_1.EMAIL_TERMS_MAX_PDF_BYTES}.`);
|
|
1097
|
+
}
|
|
1098
|
+
const filename = TermsPdfFilenameSchema.safeParse(input.filename);
|
|
1099
|
+
if (!filename.success) {
|
|
1100
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "filename must be a safe PDF filename.");
|
|
1101
|
+
}
|
|
1102
|
+
const sha256 = Sha256Schema.safeParse(input.sha256);
|
|
1103
|
+
if (!sha256.success) {
|
|
1104
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "sha256 must be a lowercase SHA-256 digest.");
|
|
1105
|
+
}
|
|
1106
|
+
return {
|
|
1107
|
+
request_id: asUuid(input.request_id, "request_id"),
|
|
1108
|
+
filename: filename.data,
|
|
1109
|
+
effective_at: asDate(input.effective_at, "effective_at"),
|
|
1110
|
+
byte_size: byteSize,
|
|
1111
|
+
sha256: sha256.data,
|
|
1112
|
+
};
|
|
1113
|
+
}
|
|
1114
|
+
toTermsVersionRecord(value) {
|
|
1115
|
+
return {
|
|
1116
|
+
id: asNonEmptyString(value.id, "id"),
|
|
1117
|
+
request_id: asUuid(value.request_id, "request_id"),
|
|
1118
|
+
filename: asNonEmptyString(value.filename, "filename"),
|
|
1119
|
+
file_id: asNonEmptyString(value.file_id, "file_id"),
|
|
1120
|
+
effective_at: asDate(value.effective_at, "effective_at"),
|
|
1121
|
+
byte_size: Number(value.byte_size),
|
|
1122
|
+
sha256: asNonEmptyString(value.sha256, "sha256"),
|
|
1123
|
+
created_at: asDate(value.created_at, "created_at"),
|
|
1124
|
+
updated_at: asDate(value.updated_at, "updated_at"),
|
|
1125
|
+
deleted_at: asNullableDate(value.deleted_at),
|
|
1126
|
+
};
|
|
1127
|
+
}
|
|
1128
|
+
toSafeAdminTermsVersion(value) {
|
|
1129
|
+
return {
|
|
1130
|
+
id: value.id,
|
|
1131
|
+
filename: value.filename,
|
|
1132
|
+
effective_at: value.effective_at.toISOString(),
|
|
1133
|
+
byte_size: value.byte_size,
|
|
1134
|
+
sha256: value.sha256,
|
|
1135
|
+
created_at: value.created_at.toISOString(),
|
|
1136
|
+
};
|
|
1137
|
+
}
|
|
1138
|
+
positiveLimit(value) {
|
|
1139
|
+
if (!Number.isInteger(value) || value < 1 || value > 100) {
|
|
1140
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "limit must be an integer from 1 to 100.");
|
|
1141
|
+
}
|
|
1142
|
+
return value;
|
|
1143
|
+
}
|
|
1144
|
+
safeOffset(value) {
|
|
1145
|
+
if (!Number.isInteger(value) || value < 0 || value > 10_000) {
|
|
1146
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "offset must be an integer from 0 to 10000.");
|
|
1147
|
+
}
|
|
1148
|
+
return value;
|
|
1149
|
+
}
|
|
1150
|
+
requireManager(sharedContext) {
|
|
1151
|
+
const manager = sharedContext.transactionManager;
|
|
1152
|
+
if (!manager) {
|
|
1153
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.UNEXPECTED_STATE, "Email persistence requires a database transaction manager.");
|
|
1154
|
+
}
|
|
1155
|
+
return manager;
|
|
1156
|
+
}
|
|
1157
|
+
}
|
|
1158
|
+
__decorate([
|
|
1159
|
+
(0, utils_1.InjectTransactionManager)(),
|
|
1160
|
+
__param(1, (0, utils_1.MedusaContext)()),
|
|
1161
|
+
__metadata("design:type", Function),
|
|
1162
|
+
__metadata("design:paramtypes", [String, Object]),
|
|
1163
|
+
__metadata("design:returntype", Promise)
|
|
1164
|
+
], EmailModuleService.prototype, "findMessageByBusinessKey", null);
|
|
1165
|
+
__decorate([
|
|
1166
|
+
(0, utils_1.InjectTransactionManager)(),
|
|
1167
|
+
__param(1, (0, utils_1.MedusaContext)()),
|
|
1168
|
+
__metadata("design:type", Function),
|
|
1169
|
+
__metadata("design:paramtypes", [Object, Object]),
|
|
1170
|
+
__metadata("design:returntype", Promise)
|
|
1171
|
+
], EmailModuleService.prototype, "upsertMessageFact", null);
|
|
1172
|
+
__decorate([
|
|
1173
|
+
(0, utils_1.InjectTransactionManager)(),
|
|
1174
|
+
__param(3, (0, utils_1.MedusaContext)()),
|
|
1175
|
+
__metadata("design:type", Function),
|
|
1176
|
+
__metadata("design:paramtypes", [Object, Function, Function, Object]),
|
|
1177
|
+
__metadata("design:returntype", Promise)
|
|
1178
|
+
], EmailModuleService.prototype, "createEmailTermsVersion", null);
|
|
1179
|
+
__decorate([
|
|
1180
|
+
(0, utils_1.InjectTransactionManager)(),
|
|
1181
|
+
__param(1, (0, utils_1.MedusaContext)()),
|
|
1182
|
+
__metadata("design:type", Function),
|
|
1183
|
+
__metadata("design:paramtypes", [Object, Object]),
|
|
1184
|
+
__metadata("design:returntype", Promise)
|
|
1185
|
+
], EmailModuleService.prototype, "listAdminEmailTermsVersions", null);
|
|
1186
|
+
__decorate([
|
|
1187
|
+
(0, utils_1.InjectTransactionManager)(),
|
|
1188
|
+
__param(1, (0, utils_1.MedusaContext)()),
|
|
1189
|
+
__metadata("design:type", Function),
|
|
1190
|
+
__metadata("design:paramtypes", [String, Object]),
|
|
1191
|
+
__metadata("design:returntype", Promise)
|
|
1192
|
+
], EmailModuleService.prototype, "getEmailTermsVersionFile", null);
|
|
1193
|
+
__decorate([
|
|
1194
|
+
(0, utils_1.InjectTransactionManager)(),
|
|
1195
|
+
__param(2, (0, utils_1.MedusaContext)()),
|
|
1196
|
+
__metadata("design:type", Function),
|
|
1197
|
+
__metadata("design:paramtypes", [Object, Function, Object]),
|
|
1198
|
+
__metadata("design:returntype", Promise)
|
|
1199
|
+
], EmailModuleService.prototype, "createAffiliateReminderMessage", null);
|
|
1200
|
+
__decorate([
|
|
1201
|
+
(0, utils_1.InjectTransactionManager)(),
|
|
1202
|
+
__param(1, (0, utils_1.MedusaContext)()),
|
|
1203
|
+
__metadata("design:type", Function),
|
|
1204
|
+
__metadata("design:paramtypes", [Object, Object]),
|
|
1205
|
+
__metadata("design:returntype", Promise)
|
|
1206
|
+
], EmailModuleService.prototype, "createAdminResend", null);
|
|
1207
|
+
__decorate([
|
|
1208
|
+
(0, utils_1.InjectTransactionManager)(),
|
|
1209
|
+
__param(1, (0, utils_1.MedusaContext)()),
|
|
1210
|
+
__metadata("design:type", Function),
|
|
1211
|
+
__metadata("design:paramtypes", [Object, Object]),
|
|
1212
|
+
__metadata("design:returntype", Promise)
|
|
1213
|
+
], EmailModuleService.prototype, "listAdminEmailMessages", null);
|
|
1214
|
+
__decorate([
|
|
1215
|
+
(0, utils_1.InjectTransactionManager)(),
|
|
1216
|
+
__param(1, (0, utils_1.MedusaContext)()),
|
|
1217
|
+
__metadata("design:type", Function),
|
|
1218
|
+
__metadata("design:paramtypes", [String, Object]),
|
|
1219
|
+
__metadata("design:returntype", Promise)
|
|
1220
|
+
], EmailModuleService.prototype, "getAdminEmailMessage", null);
|
|
1221
|
+
__decorate([
|
|
1222
|
+
(0, utils_1.InjectTransactionManager)(),
|
|
1223
|
+
__param(1, (0, utils_1.MedusaContext)()),
|
|
1224
|
+
__metadata("design:type", Function),
|
|
1225
|
+
__metadata("design:paramtypes", [Object, Object]),
|
|
1226
|
+
__metadata("design:returntype", Promise)
|
|
1227
|
+
], EmailModuleService.prototype, "suppressMessage", null);
|
|
1228
|
+
__decorate([
|
|
1229
|
+
(0, utils_1.InjectTransactionManager)(),
|
|
1230
|
+
__param(1, (0, utils_1.MedusaContext)()),
|
|
1231
|
+
__metadata("design:type", Function),
|
|
1232
|
+
__metadata("design:paramtypes", [Object, Object]),
|
|
1233
|
+
__metadata("design:returntype", Promise)
|
|
1234
|
+
], EmailModuleService.prototype, "claimReadyMessage", null);
|
|
1235
|
+
__decorate([
|
|
1236
|
+
(0, utils_1.InjectTransactionManager)(),
|
|
1237
|
+
__param(1, (0, utils_1.MedusaContext)()),
|
|
1238
|
+
__metadata("design:type", Function),
|
|
1239
|
+
__metadata("design:paramtypes", [Object, Object]),
|
|
1240
|
+
__metadata("design:returntype", Promise)
|
|
1241
|
+
], EmailModuleService.prototype, "claimReadyMessageForAutomaticDispatch", null);
|
|
1242
|
+
__decorate([
|
|
1243
|
+
(0, utils_1.InjectTransactionManager)(),
|
|
1244
|
+
__param(1, (0, utils_1.MedusaContext)()),
|
|
1245
|
+
__metadata("design:type", Function),
|
|
1246
|
+
__metadata("design:paramtypes", [Object, Object]),
|
|
1247
|
+
__metadata("design:returntype", Promise)
|
|
1248
|
+
], EmailModuleService.prototype, "claimDueRetries", null);
|
|
1249
|
+
__decorate([
|
|
1250
|
+
(0, utils_1.InjectTransactionManager)(),
|
|
1251
|
+
__param(1, (0, utils_1.MedusaContext)()),
|
|
1252
|
+
__metadata("design:type", Function),
|
|
1253
|
+
__metadata("design:paramtypes", [Object, Object]),
|
|
1254
|
+
__metadata("design:returntype", Promise)
|
|
1255
|
+
], EmailModuleService.prototype, "renewAttemptLease", null);
|
|
1256
|
+
__decorate([
|
|
1257
|
+
(0, utils_1.InjectTransactionManager)(),
|
|
1258
|
+
__param(1, (0, utils_1.MedusaContext)()),
|
|
1259
|
+
__metadata("design:type", Function),
|
|
1260
|
+
__metadata("design:paramtypes", [Object, Object]),
|
|
1261
|
+
__metadata("design:returntype", Promise)
|
|
1262
|
+
], EmailModuleService.prototype, "listStaleAttemptCandidates", null);
|
|
1263
|
+
__decorate([
|
|
1264
|
+
(0, utils_1.InjectTransactionManager)(),
|
|
1265
|
+
__param(1, (0, utils_1.MedusaContext)()),
|
|
1266
|
+
__metadata("design:type", Function),
|
|
1267
|
+
__metadata("design:paramtypes", [Object, Object]),
|
|
1268
|
+
__metadata("design:returntype", Promise)
|
|
1269
|
+
], EmailModuleService.prototype, "reconcilePendingMessageDependencies", null);
|
|
1270
|
+
__decorate([
|
|
1271
|
+
(0, utils_1.InjectTransactionManager)(),
|
|
1272
|
+
__param(1, (0, utils_1.MedusaContext)()),
|
|
1273
|
+
__metadata("design:type", Function),
|
|
1274
|
+
__metadata("design:paramtypes", [Object, Object]),
|
|
1275
|
+
__metadata("design:returntype", Promise)
|
|
1276
|
+
], EmailModuleService.prototype, "listReadyMessageIds", null);
|
|
1277
|
+
__decorate([
|
|
1278
|
+
(0, utils_1.InjectTransactionManager)(),
|
|
1279
|
+
__param(1, (0, utils_1.MedusaContext)()),
|
|
1280
|
+
__metadata("design:type", Function),
|
|
1281
|
+
__metadata("design:paramtypes", [Object, Object]),
|
|
1282
|
+
__metadata("design:returntype", Promise)
|
|
1283
|
+
], EmailModuleService.prototype, "completeAttempt", null);
|
|
1284
|
+
exports.default = EmailModuleService;
|
|
1285
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VydmljZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3NyYy9tb2R1bGVzL2VtYWlsL3NlcnZpY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBQUEsNkNBQXlDO0FBR3pDLHFEQUttQztBQUNuQyxpREFBNEM7QUFDNUMsa0dBRzRFO0FBQzVFLDJGQUE0RztBQUU1Ryw2Q0FNMkI7QUFFM0Isb0VBQTBFO0FBQzFFLGlFQUFrRTtBQUNsRSxpR0FBaUc7QUFDakcsc0ZBQXdGO0FBQ3hGLG9EQUs2QjtBQUM3QiwwREFTZ0M7QUFDaEMsMkVBQWtEO0FBQ2xELDJFQUFrRDtBQUNsRCx1RkFBNkQ7QUFFaEQsUUFBQSxzQkFBc0IsR0FBRyxDQUFDLEdBQUcsRUFBRSxHQUFHLElBQUksQ0FBQztBQTJMcEQsTUFBTSxzQkFBc0IsR0FBRyxJQUFBLHFCQUFhLEVBQUM7SUFDM0MsWUFBWSxFQUFaLHVCQUFZO0lBQ1osWUFBWSxFQUFaLHVCQUFZO0lBQ1osaUJBQWlCLEVBQWpCLDZCQUFpQjtDQUNsQixDQUFDLENBQUM7QUFFSCxNQUFNLGdCQUFnQixHQUFHLENBQUMsS0FBYyxFQUFFLEtBQWEsRUFBVSxFQUFFO0lBQ2pFLElBQUksT0FBTyxLQUFLLEtBQUssUUFBUSxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksRUFBRSxFQUFFLENBQUM7UUFDL0MsTUFBTSxJQUFJLG1CQUFXLENBQ25CLG1CQUFXLENBQUMsS0FBSyxDQUFDLFlBQVksRUFDOUIsR0FBRyxLQUFLLDhCQUE4QixDQUN2QyxDQUFDO0lBQ0osQ0FBQztJQUNELE9BQU8sS0FBSyxDQUFDLElBQUksRUFBRSxDQUFDO0FBQ3RCLENBQUMsQ0FBQztBQUVGLE1BQU0sZ0JBQWdCLEdBQUcsQ0FBQyxLQUFjLEVBQWlCLEVBQUUsQ0FDekQsT0FBTyxLQUFLLEtBQUssUUFBUSxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLElBQUks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
|