@openlup/platform 0.16.0 → 0.18.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/CHANGELOG.md +180 -0
- package/README.md +564 -6
- package/dist/catalog/activeSkuSelection.d.ts +2 -0
- package/dist/catalog/activeSkuSelection.js +20 -0
- package/dist/catalog/adminBindings.d.ts +72 -0
- package/dist/catalog/adminBindings.js +1 -0
- package/dist/catalog/adminBundleHandler.d.ts +26 -0
- package/dist/catalog/adminBundleHandler.js +111 -0
- package/dist/catalog/adminBundleReadHandler.d.ts +20 -0
- package/dist/catalog/adminBundleReadHandler.js +185 -0
- package/dist/catalog/adminBundleWritePort.d.ts +85 -0
- package/dist/catalog/adminBundleWritePort.js +1 -0
- package/dist/catalog/bundleAvailability.d.ts +63 -0
- package/dist/catalog/bundleAvailability.js +78 -0
- package/dist/catalog/bundleAvailabilityService.d.ts +65 -0
- package/dist/catalog/bundleAvailabilityService.js +89 -0
- package/dist/catalog/bundleBindings.d.ts +33 -0
- package/dist/catalog/bundleBindings.js +1 -0
- package/dist/catalog/bundleCatalogQueries.d.ts +28 -0
- package/dist/catalog/bundleCatalogQueries.js +84 -0
- package/dist/catalog/bundleCatalogReadPort.d.ts +166 -0
- package/dist/catalog/bundleCatalogReadPort.js +36 -0
- package/dist/catalog/bundleCatalogStore.d.ts +3 -0
- package/dist/catalog/bundleCatalogStore.js +152 -0
- package/dist/catalog/bundleRuleCodes.d.ts +41 -0
- package/dist/catalog/bundleRuleCodes.js +110 -0
- package/dist/catalog/bundleRules.d.ts +69 -0
- package/dist/catalog/bundleRules.js +102 -0
- package/dist/catalog/catalogDraftStore.d.ts +4 -0
- package/dist/catalog/catalogDraftStore.js +63 -0
- package/dist/catalog/catalogSkuEnvelope.d.ts +7 -0
- package/dist/catalog/catalogSkuEnvelope.js +142 -0
- package/dist/catalog/catalogSkuEnvelopeMapper.d.ts +38 -0
- package/dist/catalog/catalogSkuEnvelopeMapper.js +88 -0
- package/dist/catalog/contracts/bundleAdmin.d.ts +143 -0
- package/dist/catalog/contracts/bundleAdmin.js +1 -0
- package/dist/catalog/contracts/bundleAvailability.d.ts +61 -0
- package/dist/catalog/contracts/bundleAvailability.js +1 -0
- package/dist/catalog/contracts/bundleRead.d.ts +223 -0
- package/dist/catalog/contracts/bundleRead.js +1 -0
- package/dist/catalog/contracts/draft.d.ts +79 -0
- package/dist/catalog/contracts/draft.js +47 -0
- package/dist/catalog/contracts/foundation.d.ts +78 -0
- package/dist/catalog/contracts/foundation.js +53 -0
- package/dist/catalog/contracts/index.d.ts +14 -0
- package/dist/catalog/contracts/index.js +6 -0
- package/dist/catalog/contracts/lifecycle.d.ts +77 -0
- package/dist/catalog/contracts/lifecycle.js +1 -0
- package/dist/catalog/contracts/productMediaContracts.d.ts +77 -0
- package/dist/catalog/contracts/productMediaContracts.js +149 -0
- package/dist/catalog/contracts/productTypes.d.ts +54 -0
- package/dist/catalog/contracts/productTypes.js +16 -0
- package/dist/catalog/contracts/resolveProductMedia.d.ts +3 -0
- package/dist/catalog/contracts/resolveProductMedia.js +78 -0
- package/dist/catalog/contracts/sellable.d.ts +23 -0
- package/dist/catalog/contracts/sellable.js +1 -0
- package/dist/catalog/draftHandler.d.ts +25 -0
- package/dist/catalog/draftHandler.js +118 -0
- package/dist/catalog/draftPorts.d.ts +18 -0
- package/dist/catalog/draftPorts.js +8 -0
- package/dist/catalog/draftSchemas.d.ts +423 -0
- package/dist/catalog/draftSchemas.js +89 -0
- package/dist/catalog/draftValidation.d.ts +21 -0
- package/dist/catalog/draftValidation.js +125 -0
- package/dist/catalog/foundationSchemas.d.ts +98 -0
- package/dist/catalog/foundationSchemas.js +110 -0
- package/dist/catalog/index.d.ts +43 -0
- package/dist/catalog/index.js +25 -0
- package/dist/catalog/mediaSourcePack.d.ts +51 -0
- package/dist/catalog/mediaSourcePack.js +247 -0
- package/dist/catalog/productTypeSchemas.d.ts +46 -0
- package/dist/catalog/productTypeSchemas.js +72 -0
- package/dist/catalog/publicationPorts.d.ts +42 -0
- package/dist/catalog/publicationPorts.js +1 -0
- package/dist/catalog/readPorts.d.ts +51 -0
- package/dist/catalog/readPorts.js +1 -0
- package/dist/catalog/referenceCatalogHandler.d.ts +7 -0
- package/dist/catalog/referenceCatalogHandler.js +27 -0
- package/dist/catalog/resolvedSkuProjection.d.ts +88 -0
- package/dist/catalog/resolvedSkuProjection.js +60 -0
- package/dist/catalog/sellableBundleHandler.d.ts +46 -0
- package/dist/catalog/sellableBundleHandler.js +84 -0
- package/dist/catalog/sellableSchemas.d.ts +46 -0
- package/dist/catalog/sellableSchemas.js +27 -0
- package/dist/catalog/sql.d.ts +46 -0
- package/dist/catalog/sql.js +13 -0
- package/dist/catalog/validation.d.ts +2 -0
- package/dist/catalog/validation.js +3 -0
- package/dist/communications/accountingDocumentDelivery.d.ts +35 -0
- package/dist/communications/accountingDocumentDelivery.js +33 -0
- package/dist/communications/authEmailError.d.ts +5 -0
- package/dist/communications/authEmailError.js +8 -0
- package/dist/communications/authEmailPorts.d.ts +2 -0
- package/dist/communications/authEmailPorts.js +1 -0
- package/dist/communications/authSendEmailHook.d.ts +35 -0
- package/dist/communications/authSendEmailHook.js +250 -0
- package/dist/communications/capturedTransactionalDelivery.d.ts +13 -0
- package/dist/communications/capturedTransactionalDelivery.js +14 -0
- package/dist/communications/communicationSync.d.ts +11 -0
- package/dist/communications/communicationSync.js +79 -0
- package/dist/communications/communicationSyncWorker.d.ts +68 -0
- package/dist/communications/communicationSyncWorker.js +218 -0
- package/dist/communications/consentPolicy.d.ts +19 -0
- package/dist/communications/consentPolicy.js +43 -0
- package/dist/communications/consentPurposeRegistry.d.ts +4 -0
- package/dist/communications/consentPurposeRegistry.js +24 -0
- package/dist/communications/contracts/abandonedCart.d.ts +27 -0
- package/dist/communications/contracts/abandonedCart.js +25 -0
- package/dist/communications/contracts/authEmail.d.ts +62 -0
- package/dist/communications/contracts/authEmail.js +1 -0
- package/dist/communications/contracts/backInStock.d.ts +28 -0
- package/dist/communications/contracts/backInStock.js +28 -0
- package/dist/communications/contracts/blocks.d.ts +24 -0
- package/dist/communications/contracts/blocks.js +23 -0
- package/dist/communications/contracts/checkoutExpired.d.ts +22 -0
- package/dist/communications/contracts/checkoutExpired.js +25 -0
- package/dist/communications/contracts/checkoutRecovery.d.ts +26 -0
- package/dist/communications/contracts/checkoutRecovery.js +37 -0
- package/dist/communications/contracts/commerceEmailContent.d.ts +176 -0
- package/dist/communications/contracts/commerceEmailContent.js +1 -0
- package/dist/communications/contracts/commerceEngagementEmailContent.d.ts +95 -0
- package/dist/communications/contracts/commerceEngagementEmailContent.js +1 -0
- package/dist/communications/contracts/consent.d.ts +12 -0
- package/dist/communications/contracts/consent.js +1 -0
- package/dist/communications/contracts/email.d.ts +182 -0
- package/dist/communications/contracts/email.js +1 -0
- package/dist/communications/contracts/guideCard.d.ts +3 -0
- package/dist/communications/contracts/guideCard.js +26 -0
- package/dist/communications/contracts/index.d.ts +52 -0
- package/dist/communications/contracts/index.js +42 -0
- package/dist/communications/contracts/inquiryContent.d.ts +32 -0
- package/dist/communications/contracts/inquiryContent.js +33 -0
- package/dist/communications/contracts/invoiceDocumentContent.d.ts +26 -0
- package/dist/communications/contracts/invoiceDocumentContent.js +36 -0
- package/dist/communications/contracts/marketingAutomation.d.ts +52 -0
- package/dist/communications/contracts/marketingAutomation.js +1 -0
- package/dist/communications/contracts/marketingSync.d.ts +194 -0
- package/dist/communications/contracts/marketingSync.js +1 -0
- package/dist/communications/contracts/newsletter.d.ts +63 -0
- package/dist/communications/contracts/newsletter.js +1 -0
- package/dist/communications/contracts/newsletterWebhook.d.ts +26 -0
- package/dist/communications/contracts/newsletterWebhook.js +1 -0
- package/dist/communications/contracts/optOutContent.d.ts +11 -0
- package/dist/communications/contracts/optOutContent.js +17 -0
- package/dist/communications/contracts/orderCanceled.d.ts +25 -0
- package/dist/communications/contracts/orderCanceled.js +27 -0
- package/dist/communications/contracts/orderDraft.d.ts +46 -0
- package/dist/communications/contracts/orderDraft.js +46 -0
- package/dist/communications/contracts/orderPaid.d.ts +53 -0
- package/dist/communications/contracts/orderPaid.js +71 -0
- package/dist/communications/contracts/orderRefunded.d.ts +24 -0
- package/dist/communications/contracts/orderRefunded.js +27 -0
- package/dist/communications/contracts/paymentFailed.d.ts +24 -0
- package/dist/communications/contracts/paymentFailed.js +24 -0
- package/dist/communications/contracts/publicIntake.d.ts +49 -0
- package/dist/communications/contracts/publicIntake.js +1 -0
- package/dist/communications/contracts/render.d.ts +2 -0
- package/dist/communications/contracts/render.js +229 -0
- package/dist/communications/contracts/reorderReminder.d.ts +24 -0
- package/dist/communications/contracts/reorderReminder.js +24 -0
- package/dist/communications/contracts/returnEmails.d.ts +25 -0
- package/dist/communications/contracts/returnEmails.js +62 -0
- package/dist/communications/contracts/reviewEffects.d.ts +26 -0
- package/dist/communications/contracts/reviewEffects.js +25 -0
- package/dist/communications/contracts/reviewRequest.d.ts +26 -0
- package/dist/communications/contracts/reviewRequest.js +24 -0
- package/dist/communications/contracts/roleNotificationContent.d.ts +25 -0
- package/dist/communications/contracts/roleNotificationContent.js +46 -0
- package/dist/communications/contracts/shipmentDelivered.d.ts +23 -0
- package/dist/communications/contracts/shipmentDelivered.js +24 -0
- package/dist/communications/contracts/shipmentDispatched.d.ts +27 -0
- package/dist/communications/contracts/shipmentDispatched.js +35 -0
- package/dist/communications/contracts/shipmentException.d.ts +21 -0
- package/dist/communications/contracts/shipmentException.js +26 -0
- package/dist/communications/contracts/subscriptionActivationActionRequired.d.ts +17 -0
- package/dist/communications/contracts/subscriptionActivationActionRequired.js +22 -0
- package/dist/communications/contracts/subscriptionAddressChanged.d.ts +19 -0
- package/dist/communications/contracts/subscriptionAddressChanged.js +25 -0
- package/dist/communications/contracts/subscriptionCancelled.d.ts +19 -0
- package/dist/communications/contracts/subscriptionCancelled.js +25 -0
- package/dist/communications/contracts/subscriptionCycleSkipped.d.ts +25 -0
- package/dist/communications/contracts/subscriptionCycleSkipped.js +40 -0
- package/dist/communications/contracts/subscriptionDeliveryRescheduled.d.ts +25 -0
- package/dist/communications/contracts/subscriptionDeliveryRescheduled.js +39 -0
- package/dist/communications/contracts/subscriptionEmailContent.d.ts +145 -0
- package/dist/communications/contracts/subscriptionEmailContent.js +1 -0
- package/dist/communications/contracts/subscriptionPackageChanged.d.ts +20 -0
- package/dist/communications/contracts/subscriptionPackageChanged.js +26 -0
- package/dist/communications/contracts/subscriptionPauseReminder.d.ts +23 -0
- package/dist/communications/contracts/subscriptionPauseReminder.js +29 -0
- package/dist/communications/contracts/subscriptionPaused.d.ts +21 -0
- package/dist/communications/contracts/subscriptionPaused.js +25 -0
- package/dist/communications/contracts/subscriptionPaymentExpired.d.ts +34 -0
- package/dist/communications/contracts/subscriptionPaymentExpired.js +37 -0
- package/dist/communications/contracts/subscriptionPaymentFailed.d.ts +49 -0
- package/dist/communications/contracts/subscriptionPaymentFailed.js +56 -0
- package/dist/communications/contracts/subscriptionPaymentRecovered.d.ts +19 -0
- package/dist/communications/contracts/subscriptionPaymentRecovered.js +22 -0
- package/dist/communications/contracts/subscriptionRenewalAtRisk.d.ts +36 -0
- package/dist/communications/contracts/subscriptionRenewalAtRisk.js +36 -0
- package/dist/communications/contracts/subscriptionRenewalUpcoming.d.ts +49 -0
- package/dist/communications/contracts/subscriptionRenewalUpcoming.js +43 -0
- package/dist/communications/contracts/subscriptionResumed.d.ts +23 -0
- package/dist/communications/contracts/subscriptionResumed.js +25 -0
- package/dist/communications/contracts/subscriptionWelcome.d.ts +44 -0
- package/dist/communications/contracts/subscriptionWelcome.js +45 -0
- package/dist/communications/contracts/subscriptionWinback.d.ts +21 -0
- package/dist/communications/contracts/subscriptionWinback.js +28 -0
- package/dist/communications/contracts/transactionalDelivery.d.ts +42 -0
- package/dist/communications/contracts/transactionalDelivery.js +1 -0
- package/dist/communications/contracts/types.d.ts +46 -0
- package/dist/communications/contracts/types.js +1 -0
- package/dist/communications/contribution.d.ts +10 -0
- package/dist/communications/contribution.js +24 -0
- package/dist/communications/deliveryReconciliation.d.ts +64 -0
- package/dist/communications/deliveryReconciliation.js +60 -0
- package/dist/communications/emailEgress.d.ts +38 -0
- package/dist/communications/emailEgress.js +100 -0
- package/dist/communications/emailHealthAssessment.d.ts +39 -0
- package/dist/communications/emailHealthAssessment.js +59 -0
- package/dist/communications/emailHealthMetricsPort.d.ts +17 -0
- package/dist/communications/emailHealthMetricsPort.js +1 -0
- package/dist/communications/emailNotificationControl.d.ts +27 -0
- package/dist/communications/emailNotificationControl.js +10 -0
- package/dist/communications/emailObservation.d.ts +28 -0
- package/dist/communications/emailObservation.js +23 -0
- package/dist/communications/emailTransport.d.ts +82 -0
- package/dist/communications/emailTransport.js +95 -0
- package/dist/communications/errors.d.ts +15 -0
- package/dist/communications/errors.js +30 -0
- package/dist/communications/index.d.ts +47 -0
- package/dist/communications/index.js +38 -0
- package/dist/communications/integrationEventSignature.d.ts +15 -0
- package/dist/communications/integrationEventSignature.js +37 -0
- package/dist/communications/klaviyo/consentPush.d.ts +51 -0
- package/dist/communications/klaviyo/consentPush.js +19 -0
- package/dist/communications/klaviyo/index.d.ts +110 -0
- package/dist/communications/klaviyo/index.js +860 -0
- package/dist/communications/managedTransactionalDeliveryStore.d.ts +12 -0
- package/dist/communications/managedTransactionalDeliveryStore.js +49 -0
- package/dist/communications/nativeOperations.d.ts +79 -0
- package/dist/communications/nativeOperations.js +3 -0
- package/dist/communications/newsletterIntegrationContracts.d.ts +130 -0
- package/dist/communications/newsletterIntegrationContracts.js +128 -0
- package/dist/communications/newsletterWebhookPort.d.ts +11 -0
- package/dist/communications/newsletterWebhookPort.js +84 -0
- package/dist/communications/newsletterWebhookProcessing.d.ts +17 -0
- package/dist/communications/newsletterWebhookProcessing.js +71 -0
- package/dist/communications/originPolicy.d.ts +40 -0
- package/dist/communications/originPolicy.js +100 -0
- package/dist/communications/postgresCommunicationSync.d.ts +79 -0
- package/dist/communications/postgresCommunicationSync.js +111 -0
- package/dist/communications/postgresConsentEvaluator.d.ts +19 -0
- package/dist/communications/postgresConsentEvaluator.js +43 -0
- package/dist/communications/postgresDeliveryReconciliation.d.ts +3 -0
- package/dist/communications/postgresDeliveryReconciliation.js +113 -0
- package/dist/communications/postgresNativeOperations.d.ts +13 -0
- package/dist/communications/postgresNativeOperations.js +63 -0
- package/dist/communications/postgresNotificationRecipients.d.ts +37 -0
- package/dist/communications/postgresNotificationRecipients.js +60 -0
- package/dist/communications/postgresTransactionalDeliveryStore.d.ts +7 -0
- package/dist/communications/postgresTransactionalDeliveryStore.js +55 -0
- package/dist/communications/preferencesToken.d.ts +10 -0
- package/dist/communications/preferencesToken.js +40 -0
- package/dist/communications/publicPreferenceToken.d.ts +24 -0
- package/dist/communications/publicPreferenceToken.js +53 -0
- package/dist/communications/resend/index.d.ts +40 -0
- package/dist/communications/resend/index.js +310 -0
- package/dist/communications/shipmentNotifications.d.ts +34 -0
- package/dist/communications/shipmentNotifications.js +61 -0
- package/dist/communications/sql.d.ts +26 -0
- package/dist/communications/sql.js +7 -0
- package/dist/communications/standardWebhooks.d.ts +14 -0
- package/dist/communications/standardWebhooks.js +73 -0
- package/dist/communications/status.d.ts +11 -0
- package/dist/communications/status.js +36 -0
- package/dist/communications/transactionalDelivery.d.ts +19 -0
- package/dist/communications/transactionalDelivery.js +96 -0
- package/dist/communications/transactionalDeliveryIdentifier.d.ts +3 -0
- package/dist/communications/transactionalDeliveryIdentifier.js +6 -0
- package/dist/communications/unsubscribeToken.d.ts +77 -0
- package/dist/communications/unsubscribeToken.js +150 -0
- package/dist/communications/validation.d.ts +2 -0
- package/dist/communications/validation.js +3 -0
- package/dist/composition/catalogContribution.d.ts +18 -0
- package/dist/composition/catalogContribution.js +21 -0
- package/dist/composition/index.d.ts +1 -0
- package/dist/composition/index.js +1 -0
- package/dist/http/index.d.ts +1 -0
- package/dist/http/index.js +1 -0
- package/dist/http/webhookSignature.d.ts +42 -0
- package/dist/http/webhookSignature.js +86 -0
- package/dist/identity/customerContracts.d.ts +2 -2
- package/dist/inventory/adminInventory.d.ts +13 -0
- package/dist/inventory/adminInventory.js +214 -0
- package/dist/inventory/contracts/forecast.d.ts +86 -0
- package/dist/inventory/contracts/forecast.js +1 -0
- package/dist/inventory/contracts/index.d.ts +4 -0
- package/dist/inventory/contracts/index.js +1 -0
- package/dist/inventory/contracts/inventory.d.ts +157 -0
- package/dist/inventory/contracts/inventory.js +1 -0
- package/dist/inventory/contracts/newPurchaseStock.d.ts +20 -0
- package/dist/inventory/contracts/newPurchaseStock.js +1 -0
- package/dist/inventory/contracts/reservation.d.ts +18 -0
- package/dist/inventory/contracts/reservation.js +1 -0
- package/dist/inventory/forecast.d.ts +24 -0
- package/dist/inventory/forecast.js +200 -0
- package/dist/inventory/index.d.ts +13 -0
- package/dist/inventory/index.js +10 -0
- package/dist/inventory/inventoryHandlers.d.ts +53 -0
- package/dist/inventory/inventoryHandlers.js +151 -0
- package/dist/inventory/newPurchaseStockAvailability.d.ts +47 -0
- package/dist/inventory/newPurchaseStockAvailability.js +75 -0
- package/dist/inventory/ports.d.ts +21 -0
- package/dist/inventory/ports.js +16 -0
- package/dist/inventory/renewalReservation.d.ts +27 -0
- package/dist/inventory/renewalReservation.js +61 -0
- package/dist/inventory/reservationPolicy.d.ts +6 -0
- package/dist/inventory/reservationPolicy.js +19 -0
- package/dist/inventory/schemas.d.ts +137 -0
- package/dist/inventory/schemas.js +112 -0
- package/dist/inventory/sql.d.ts +14 -0
- package/dist/inventory/sql.js +5 -0
- package/dist/inventory/subscriptionForecastCalculation.d.ts +4 -0
- package/dist/inventory/subscriptionForecastCalculation.js +133 -0
- package/dist/pricing/acquisitionFinancialPolicy.d.ts +26 -0
- package/dist/pricing/acquisitionFinancialPolicy.js +1 -0
- package/dist/pricing/acquisitionOfferPricing.d.ts +27 -0
- package/dist/pricing/acquisitionOfferPricing.js +25 -0
- package/dist/pricing/acquisitionOfferPricingHandler.d.ts +20 -0
- package/dist/pricing/acquisitionOfferPricingHandler.js +105 -0
- package/dist/pricing/acquisitionOfferPricingSchemas.d.ts +31 -0
- package/dist/pricing/acquisitionOfferPricingSchemas.js +33 -0
- package/dist/pricing/acquisitionQuoteBinding.d.ts +12 -0
- package/dist/pricing/acquisitionQuoteBinding.js +12 -0
- package/dist/pricing/acquisitionReadiness.d.ts +31 -0
- package/dist/pricing/acquisitionReadiness.js +117 -0
- package/dist/pricing/acquisitionTerms.d.ts +19 -0
- package/dist/pricing/acquisitionTerms.js +126 -0
- package/dist/pricing/acquisitionTermsSchemas.d.ts +59 -0
- package/dist/pricing/acquisitionTermsSchemas.js +42 -0
- package/dist/pricing/catalogFactsProvenance.d.ts +33 -0
- package/dist/pricing/catalogFactsProvenance.js +64 -0
- package/dist/pricing/catalogFactsSchemas.d.ts +45 -0
- package/dist/pricing/catalogFactsSchemas.js +58 -0
- package/dist/pricing/commerceOfferPricing.d.ts +25 -0
- package/dist/pricing/commerceOfferPricing.js +139 -0
- package/dist/pricing/commerceOfferPricingCache.d.ts +10 -0
- package/dist/pricing/commerceOfferPricingCache.js +44 -0
- package/dist/pricing/commerceOfferPricingHandler.d.ts +21 -0
- package/dist/pricing/commerceOfferPricingHandler.js +78 -0
- package/dist/pricing/commercePriceAuthority.d.ts +26 -0
- package/dist/pricing/commercePriceAuthority.js +79 -0
- package/dist/pricing/commercePricingPolicyErrors.d.ts +40 -0
- package/dist/pricing/commercePricingPolicyErrors.js +67 -0
- package/dist/pricing/commerceQuoteBatchHandler.d.ts +37 -0
- package/dist/pricing/commerceQuoteBatchHandler.js +83 -0
- package/dist/pricing/commerceQuoteCatalogReadPort.d.ts +27 -0
- package/dist/pricing/commerceQuoteCatalogReadPort.js +8 -0
- package/dist/pricing/commerceQuoteHandler.d.ts +31 -0
- package/dist/pricing/commerceQuoteHandler.js +110 -0
- package/dist/pricing/commerceQuoteSnapshotExpect.d.ts +9 -0
- package/dist/pricing/commerceQuoteSnapshotExpect.js +22 -0
- package/dist/pricing/contracts/acquisitionTerms.d.ts +32 -0
- package/dist/pricing/contracts/acquisitionTerms.js +2 -0
- package/dist/pricing/contracts/authority.d.ts +27 -0
- package/dist/pricing/contracts/authority.js +1 -0
- package/dist/pricing/contracts/evidence.d.ts +33 -0
- package/dist/pricing/contracts/evidence.js +1 -0
- package/dist/pricing/contracts/index.d.ts +17 -0
- package/dist/pricing/contracts/index.js +7 -0
- package/dist/pricing/contracts/money.d.ts +27 -0
- package/dist/pricing/contracts/money.js +1 -0
- package/dist/pricing/contracts/offer.d.ts +52 -0
- package/dist/pricing/contracts/offer.js +4 -0
- package/dist/pricing/contracts/offerPolicy.d.ts +16 -0
- package/dist/pricing/contracts/offerPolicy.js +5 -0
- package/dist/pricing/contracts/policy.d.ts +22 -0
- package/dist/pricing/contracts/policy.js +3 -0
- package/dist/pricing/contracts/provenance.d.ts +24 -0
- package/dist/pricing/contracts/provenance.js +2 -0
- package/dist/pricing/contracts/quote.d.ts +94 -0
- package/dist/pricing/contracts/quote.js +1 -0
- package/dist/pricing/dbBackedCommerceQuoteHelpers.d.ts +78 -0
- package/dist/pricing/dbBackedCommerceQuoteHelpers.js +146 -0
- package/dist/pricing/dbBackedCommerceQuotePort.d.ts +66 -0
- package/dist/pricing/dbBackedCommerceQuotePort.js +206 -0
- package/dist/pricing/dbBackedCommerceQuoteSnapshotVerifier.d.ts +4 -0
- package/dist/pricing/dbBackedCommerceQuoteSnapshotVerifier.js +25 -0
- package/dist/pricing/index.d.ts +51 -0
- package/dist/pricing/index.js +36 -0
- package/dist/pricing/offerPolicyReadiness.d.ts +21 -0
- package/dist/pricing/offerPolicyReadiness.js +79 -0
- package/dist/pricing/offerPolicySchemas.d.ts +25 -0
- package/dist/pricing/offerPolicySchemas.js +15 -0
- package/dist/pricing/offerPricingSchemas.d.ts +315 -0
- package/dist/pricing/offerPricingSchemas.js +65 -0
- package/dist/pricing/ports.d.ts +13 -0
- package/dist/pricing/ports.js +9 -0
- package/dist/pricing/pricingPolicyToken.d.ts +39 -0
- package/dist/pricing/pricingPolicyToken.js +84 -0
- package/dist/pricing/quoteAcquisitionTerms.d.ts +2 -0
- package/dist/pricing/quoteAcquisitionTerms.js +4 -0
- package/dist/pricing/quoteCodeRejectionDetails.d.ts +20 -0
- package/dist/pricing/quoteCodeRejectionDetails.js +22 -0
- package/dist/pricing/quotePorts.d.ts +30 -0
- package/dist/pricing/quotePorts.js +20 -0
- package/dist/pricing/quotePrimitives.d.ts +13 -0
- package/dist/pricing/quotePrimitives.js +18 -0
- package/dist/pricing/quotePromotionEvidence.d.ts +39 -0
- package/dist/pricing/quotePromotionEvidence.js +73 -0
- package/dist/pricing/quoteSchemas.d.ts +1176 -0
- package/dist/pricing/quoteSchemas.js +196 -0
- package/dist/pricing/subscriptionPricePolicy.d.ts +52 -0
- package/dist/pricing/subscriptionPricePolicy.js +96 -0
- package/dist/pricing/taxProfileGuard.d.ts +2 -0
- package/dist/pricing/taxProfileGuard.js +24 -0
- package/dist/pricing/validation.d.ts +2 -0
- package/dist/pricing/validation.js +3 -0
- package/dist/promotions/adminBindings.d.ts +72 -0
- package/dist/promotions/adminBindings.js +1 -0
- package/dist/promotions/adminPromotionCodesContracts.d.ts +498 -0
- package/dist/promotions/adminPromotionCodesContracts.js +211 -0
- package/dist/promotions/adminPromotionCodesDataPort.d.ts +47 -0
- package/dist/promotions/adminPromotionCodesDataPort.js +1 -0
- package/dist/promotions/adminPromotionCodesHandler.d.ts +14 -0
- package/dist/promotions/adminPromotionCodesHandler.js +194 -0
- package/dist/promotions/adminPromotionsContracts.d.ts +235 -0
- package/dist/promotions/adminPromotionsContracts.js +99 -0
- package/dist/promotions/adminPromotionsDataPort.d.ts +42 -0
- package/dist/promotions/adminPromotionsDataPort.js +1 -0
- package/dist/promotions/adminPromotionsHandler.d.ts +16 -0
- package/dist/promotions/adminPromotionsHandler.js +47 -0
- package/dist/promotions/contracts/index.d.ts +387 -0
- package/dist/promotions/contracts/index.js +1 -0
- package/dist/promotions/index.d.ts +22 -0
- package/dist/promotions/index.js +21 -0
- package/dist/promotions/promoDataPort.d.ts +47 -0
- package/dist/promotions/promoDataPort.js +14 -0
- package/dist/promotions/promotionAcceptanceTelemetry.d.ts +29 -0
- package/dist/promotions/promotionAcceptanceTelemetry.js +45 -0
- package/dist/promotions/promotionBenefitDefinition.d.ts +37 -0
- package/dist/promotions/promotionBenefitDefinition.js +33 -0
- package/dist/promotions/promotionClaimSweepPort.d.ts +14 -0
- package/dist/promotions/promotionClaimSweepPort.js +8 -0
- package/dist/promotions/promotionClaims.d.ts +5 -0
- package/dist/promotions/promotionClaims.js +57 -0
- package/dist/promotions/promotionCodePreview.d.ts +11 -0
- package/dist/promotions/promotionCodePreview.js +154 -0
- package/dist/promotions/promotionCodeQuotePort.d.ts +25 -0
- package/dist/promotions/promotionCodeQuotePort.js +1 -0
- package/dist/promotions/promotionQuoteAcceptance.d.ts +65 -0
- package/dist/promotions/promotionQuoteAcceptance.js +202 -0
- package/dist/promotions/promotionQuoteBinding.d.ts +71 -0
- package/dist/promotions/promotionQuoteBinding.js +85 -0
- package/dist/promotions/quoteAutomaticPromotions.d.ts +24 -0
- package/dist/promotions/quoteAutomaticPromotions.js +36 -0
- package/dist/promotions/quotePromoDiscounts.d.ts +32 -0
- package/dist/promotions/quotePromoDiscounts.js +140 -0
- package/dist/promotions/quotePromotionCodeAdjustments.d.ts +27 -0
- package/dist/promotions/quotePromotionCodeAdjustments.js +223 -0
- package/dist/promotions/quotePromotionV2.d.ts +29 -0
- package/dist/promotions/quotePromotionV2.js +174 -0
- package/dist/promotions/sql.d.ts +14 -0
- package/dist/promotions/sql.js +5 -0
- package/dist/promotions/validation.d.ts +2 -0
- package/dist/promotions/validation.js +3 -0
- package/dist/shipping/addressCanonLookupHandler.d.ts +7 -0
- package/dist/shipping/addressCanonLookupHandler.js +105 -0
- package/dist/shipping/addressCanonical.d.ts +2 -0
- package/dist/shipping/addressCanonical.js +26 -0
- package/dist/shipping/addressPorts.d.ts +39 -0
- package/dist/shipping/addressPorts.js +1 -0
- package/dist/shipping/addressSchemas.d.ts +30 -0
- package/dist/shipping/addressSchemas.js +1 -0
- package/dist/shipping/adminShippingRateHandler.d.ts +4 -0
- package/dist/shipping/adminShippingRateHandler.js +64 -0
- package/dist/shipping/contracts/address.d.ts +144 -0
- package/dist/shipping/contracts/address.js +1 -0
- package/dist/shipping/contracts/delivery.d.ts +110 -0
- package/dist/shipping/contracts/delivery.js +1 -0
- package/dist/shipping/contracts/index.d.ts +3 -0
- package/dist/shipping/contracts/index.js +1 -0
- package/dist/shipping/contracts/shippingRate.d.ts +11 -0
- package/dist/shipping/contracts/shippingRate.js +1 -0
- package/dist/shipping/customerAddressesHandler.d.ts +5 -0
- package/dist/shipping/customerAddressesHandler.js +80 -0
- package/dist/shipping/customerSelfServiceAddressModels.d.ts +27 -0
- package/dist/shipping/customerSelfServiceAddressModels.js +101 -0
- package/dist/shipping/deliverySelectionHandler.d.ts +10 -0
- package/dist/shipping/deliverySelectionHandler.js +77 -0
- package/dist/shipping/deliverySelectionPort.d.ts +8 -0
- package/dist/shipping/deliverySelectionPort.js +1 -0
- package/dist/shipping/deliverySelectionSummary.d.ts +2 -0
- package/dist/shipping/deliverySelectionSummary.js +53 -0
- package/dist/shipping/handlerSchemas.d.ts +21 -0
- package/dist/shipping/handlerSchemas.js +1 -0
- package/dist/shipping/index.d.ts +17 -0
- package/dist/shipping/index.js +8 -0
- package/dist/shipping/pickupPointSearchPort.d.ts +4 -0
- package/dist/shipping/pickupPointSearchPort.js +1 -0
- package/dist/shipping/readDeliverySelectionEvidence.d.ts +2 -0
- package/dist/shipping/readDeliverySelectionEvidence.js +44 -0
- package/dist/shipping/shippingRatePorts.d.ts +52 -0
- package/dist/shipping/shippingRatePorts.js +1 -0
- package/package.json +72 -2
- package/release-gates.json +249 -8
- package/sql/20260807140000_read_parity_catalog.sql +94 -0
- package/sql/20260807190000_comms_outbox_rail.sql +329 -0
- package/sql/20260810120000_storefront_catalog_attributes.sql +51 -0
- package/sql/20260810120001_transactional_delivery_receipts.sql +209 -0
- package/sql/20260812140000_sellable_bundle_catalog.sql +124 -0
- package/sql/20260812210000_bundle_operator_write_boundary.sql +567 -0
- package/sql/20260813120000_communications_control_plane.sql +568 -0
- package/sql/20260814000000_fulfillment_stock_evidence.sql +239 -0
- package/sql/20260815120000_automatic_subscription_renewal.sql +1083 -0
- package/sql/20260817180000_promotion_claim_lifecycle.sql +591 -0
- package/sql/20260817180100_promotion_claim_lifecycle_validation.sql +23 -0
- package/sql/20260827220000_catalog_document_revision_foundation.sql +226 -0
- package/sql/20260827220001_catalog_document_revision_foundation_validate.sql +10 -0
- package/sql/20260908100000_catalog_draft_foundation.sql +217 -0
- package/sql/20261019200000_communications_native_operations.sql +68 -0
- package/src/catalog/activeSkuSelection.ts +20 -0
- package/src/catalog/adminBindings.ts +59 -0
- package/src/catalog/adminBundleHandler.ts +165 -0
- package/src/catalog/adminBundleReadHandler.ts +261 -0
- package/src/catalog/adminBundleWritePort.ts +102 -0
- package/src/catalog/bundleAvailability.ts +129 -0
- package/src/catalog/bundleAvailabilityService.ts +171 -0
- package/src/catalog/bundleBindings.ts +29 -0
- package/src/catalog/bundleCatalogQueries.ts +98 -0
- package/src/catalog/bundleCatalogReadPort.ts +177 -0
- package/src/catalog/bundleCatalogStore.ts +269 -0
- package/src/catalog/bundleRuleCodes.ts +134 -0
- package/src/catalog/bundleRules.ts +153 -0
- package/src/catalog/catalogDraftStore.ts +71 -0
- package/src/catalog/catalogSkuEnvelope.ts +214 -0
- package/src/catalog/catalogSkuEnvelopeMapper.ts +160 -0
- package/src/catalog/contracts/bundleAdmin.ts +20 -0
- package/src/catalog/contracts/bundleAvailability.ts +5 -0
- package/src/catalog/contracts/bundleRead.ts +13 -0
- package/src/catalog/contracts/draft.ts +69 -0
- package/src/catalog/contracts/foundation.ts +104 -0
- package/src/catalog/contracts/index.ts +14 -0
- package/src/catalog/contracts/lifecycle.ts +74 -0
- package/src/catalog/contracts/productMediaContracts.ts +170 -0
- package/src/catalog/contracts/productTypes.ts +35 -0
- package/src/catalog/contracts/resolveProductMedia.ts +85 -0
- package/src/catalog/contracts/sellable.ts +12 -0
- package/src/catalog/draftHandler.ts +105 -0
- package/src/catalog/draftPorts.ts +18 -0
- package/src/catalog/draftSchemas.ts +88 -0
- package/src/catalog/draftValidation.ts +100 -0
- package/src/catalog/foundationSchemas.ts +123 -0
- package/src/catalog/index.ts +43 -0
- package/src/catalog/mediaSourcePack.ts +219 -0
- package/src/catalog/productTypeSchemas.ts +70 -0
- package/src/catalog/publicationPorts.ts +44 -0
- package/src/catalog/readPorts.ts +61 -0
- package/src/catalog/referenceCatalogHandler.ts +39 -0
- package/src/catalog/resolvedSkuProjection.ts +76 -0
- package/src/catalog/sellableBundleHandler.ts +133 -0
- package/src/catalog/sellableSchemas.ts +33 -0
- package/src/catalog/sql.ts +14 -0
- package/src/catalog/validation.ts +3 -0
- package/src/communications/accountingDocumentDelivery.ts +63 -0
- package/src/communications/authEmailError.ts +10 -0
- package/src/communications/authEmailPorts.ts +2 -0
- package/src/communications/authSendEmailHook.ts +310 -0
- package/src/communications/capturedTransactionalDelivery.ts +29 -0
- package/src/communications/communicationSync.ts +96 -0
- package/src/communications/communicationSyncWorker.ts +302 -0
- package/src/communications/consentPolicy.ts +82 -0
- package/src/communications/consentPurposeRegistry.ts +31 -0
- package/src/communications/contracts/abandonedCart.ts +64 -0
- package/src/communications/contracts/authEmail.ts +73 -0
- package/src/communications/contracts/backInStock.ts +69 -0
- package/src/communications/contracts/blocks.ts +47 -0
- package/src/communications/contracts/checkoutExpired.ts +62 -0
- package/src/communications/contracts/checkoutRecovery.ts +68 -0
- package/src/communications/contracts/commerceEmailContent.ts +189 -0
- package/src/communications/contracts/commerceEngagementEmailContent.ts +106 -0
- package/src/communications/contracts/consent.ts +13 -0
- package/src/communications/contracts/email.ts +210 -0
- package/src/communications/contracts/guideCard.ts +34 -0
- package/src/communications/contracts/index.ts +52 -0
- package/src/communications/contracts/inquiryContent.ts +53 -0
- package/src/communications/contracts/invoiceDocumentContent.ts +57 -0
- package/src/communications/contracts/marketingAutomation.ts +45 -0
- package/src/communications/contracts/marketingSync.ts +109 -0
- package/src/communications/contracts/newsletter.ts +78 -0
- package/src/communications/contracts/newsletterWebhook.ts +23 -0
- package/src/communications/contracts/optOutContent.ts +23 -0
- package/src/communications/contracts/orderCanceled.ts +64 -0
- package/src/communications/contracts/orderDraft.ts +112 -0
- package/src/communications/contracts/orderPaid.ts +147 -0
- package/src/communications/contracts/orderRefunded.ts +63 -0
- package/src/communications/contracts/paymentFailed.ts +59 -0
- package/src/communications/contracts/publicIntake.ts +53 -0
- package/src/communications/contracts/render.ts +271 -0
- package/src/communications/contracts/reorderReminder.ts +59 -0
- package/src/communications/contracts/returnEmails.ts +113 -0
- package/src/communications/contracts/reviewEffects.ts +60 -0
- package/src/communications/contracts/reviewRequest.ts +59 -0
- package/src/communications/contracts/roleNotificationContent.ts +65 -0
- package/src/communications/contracts/shipmentDelivered.ts +59 -0
- package/src/communications/contracts/shipmentDispatched.ts +77 -0
- package/src/communications/contracts/shipmentException.ts +62 -0
- package/src/communications/contracts/subscriptionActivationActionRequired.ts +37 -0
- package/src/communications/contracts/subscriptionAddressChanged.ts +56 -0
- package/src/communications/contracts/subscriptionCancelled.ts +57 -0
- package/src/communications/contracts/subscriptionCycleSkipped.ts +80 -0
- package/src/communications/contracts/subscriptionDeliveryRescheduled.ts +79 -0
- package/src/communications/contracts/subscriptionEmailContent.ts +163 -0
- package/src/communications/contracts/subscriptionPackageChanged.ts +59 -0
- package/src/communications/contracts/subscriptionPauseReminder.ts +63 -0
- package/src/communications/contracts/subscriptionPaused.ts +58 -0
- package/src/communications/contracts/subscriptionPaymentExpired.ts +83 -0
- package/src/communications/contracts/subscriptionPaymentFailed.ts +117 -0
- package/src/communications/contracts/subscriptionPaymentRecovered.ts +50 -0
- package/src/communications/contracts/subscriptionRenewalAtRisk.ts +85 -0
- package/src/communications/contracts/subscriptionRenewalUpcoming.ts +103 -0
- package/src/communications/contracts/subscriptionResumed.ts +60 -0
- package/src/communications/contracts/subscriptionWelcome.ts +102 -0
- package/src/communications/contracts/subscriptionWinback.ts +62 -0
- package/src/communications/contracts/transactionalDelivery.ts +43 -0
- package/src/communications/contracts/types.ts +58 -0
- package/src/communications/contribution.ts +33 -0
- package/src/communications/deliveryReconciliation.ts +108 -0
- package/src/communications/emailEgress.ts +111 -0
- package/src/communications/emailHealthAssessment.ts +106 -0
- package/src/communications/emailHealthMetricsPort.ts +17 -0
- package/src/communications/emailNotificationControl.ts +28 -0
- package/src/communications/emailObservation.ts +43 -0
- package/src/communications/emailTransport.ts +167 -0
- package/src/communications/errors.ts +34 -0
- package/src/communications/index.ts +47 -0
- package/src/communications/integrationEventSignature.ts +49 -0
- package/src/communications/klaviyo/consentPush.ts +19 -0
- package/src/communications/klaviyo/index.ts +649 -0
- package/src/communications/managedTransactionalDeliveryStore.ts +59 -0
- package/src/communications/nativeOperations.ts +40 -0
- package/src/communications/newsletterIntegrationContracts.ts +154 -0
- package/src/communications/newsletterWebhookPort.ts +104 -0
- package/src/communications/newsletterWebhookProcessing.ts +102 -0
- package/src/communications/originPolicy.ts +151 -0
- package/src/communications/postgresCommunicationSync.ts +127 -0
- package/src/communications/postgresConsentEvaluator.ts +49 -0
- package/src/communications/postgresDeliveryReconciliation.ts +101 -0
- package/src/communications/postgresNativeOperations.ts +55 -0
- package/src/communications/postgresNotificationRecipients.ts +57 -0
- package/src/communications/postgresTransactionalDeliveryStore.ts +79 -0
- package/src/communications/preferencesToken.ts +62 -0
- package/src/communications/publicPreferenceToken.ts +68 -0
- package/src/communications/resend/index.ts +350 -0
- package/src/communications/shipmentNotifications.ts +78 -0
- package/src/communications/sql.ts +7 -0
- package/src/communications/standardWebhooks.ts +84 -0
- package/src/communications/status.ts +51 -0
- package/src/communications/transactionalDelivery.ts +114 -0
- package/src/communications/transactionalDeliveryIdentifier.ts +9 -0
- package/src/communications/unsubscribeToken.ts +186 -0
- package/src/communications/validation.ts +3 -0
- package/src/composition/catalogContribution.ts +32 -0
- package/src/composition/index.ts +1 -0
- package/src/http/index.ts +1 -0
- package/src/http/webhookSignature.ts +96 -0
- package/src/inventory/adminInventory.ts +251 -0
- package/src/inventory/contracts/forecast.ts +96 -0
- package/src/inventory/contracts/index.ts +18 -0
- package/src/inventory/contracts/inventory.ts +14 -0
- package/src/inventory/contracts/newPurchaseStock.ts +23 -0
- package/src/inventory/contracts/reservation.ts +20 -0
- package/src/inventory/forecast.ts +239 -0
- package/src/inventory/index.ts +21 -0
- package/src/inventory/inventoryHandlers.ts +215 -0
- package/src/inventory/newPurchaseStockAvailability.ts +120 -0
- package/src/inventory/ports.ts +46 -0
- package/src/inventory/renewalReservation.ts +88 -0
- package/src/inventory/reservationPolicy.ts +27 -0
- package/src/inventory/schemas.ts +128 -0
- package/src/inventory/sql.ts +5 -0
- package/src/inventory/subscriptionForecastCalculation.ts +157 -0
- package/src/pricing/acquisitionFinancialPolicy.ts +26 -0
- package/src/pricing/acquisitionOfferPricing.ts +38 -0
- package/src/pricing/acquisitionOfferPricingHandler.ts +157 -0
- package/src/pricing/acquisitionOfferPricingSchemas.ts +35 -0
- package/src/pricing/acquisitionQuoteBinding.ts +12 -0
- package/src/pricing/acquisitionReadiness.ts +148 -0
- package/src/pricing/acquisitionTerms.ts +125 -0
- package/src/pricing/acquisitionTermsSchemas.ts +52 -0
- package/src/pricing/catalogFactsProvenance.ts +102 -0
- package/src/pricing/catalogFactsSchemas.ts +69 -0
- package/src/pricing/commerceOfferPricing.ts +224 -0
- package/src/pricing/commerceOfferPricingCache.ts +53 -0
- package/src/pricing/commerceOfferPricingHandler.ts +137 -0
- package/src/pricing/commercePriceAuthority.ts +104 -0
- package/src/pricing/commercePricingPolicyErrors.ts +88 -0
- package/src/pricing/commerceQuoteBatchHandler.ts +129 -0
- package/src/pricing/commerceQuoteCatalogReadPort.ts +42 -0
- package/src/pricing/commerceQuoteHandler.ts +184 -0
- package/src/pricing/commerceQuoteSnapshotExpect.ts +48 -0
- package/src/pricing/contracts/acquisitionTerms.ts +26 -0
- package/src/pricing/contracts/authority.ts +44 -0
- package/src/pricing/contracts/evidence.ts +25 -0
- package/src/pricing/contracts/index.ts +17 -0
- package/src/pricing/contracts/money.ts +32 -0
- package/src/pricing/contracts/offer.ts +42 -0
- package/src/pricing/contracts/offerPolicy.ts +17 -0
- package/src/pricing/contracts/policy.ts +26 -0
- package/src/pricing/contracts/provenance.ts +19 -0
- package/src/pricing/contracts/quote.ts +106 -0
- package/src/pricing/dbBackedCommerceQuoteHelpers.ts +256 -0
- package/src/pricing/dbBackedCommerceQuotePort.ts +260 -0
- package/src/pricing/dbBackedCommerceQuoteSnapshotVerifier.ts +49 -0
- package/src/pricing/index.ts +52 -0
- package/src/pricing/offerPolicyReadiness.ts +110 -0
- package/src/pricing/offerPolicySchemas.ts +23 -0
- package/src/pricing/offerPricingSchemas.ts +92 -0
- package/src/pricing/ports.ts +17 -0
- package/src/pricing/pricingPolicyToken.ts +119 -0
- package/src/pricing/quoteAcquisitionTerms.ts +10 -0
- package/src/pricing/quoteCodeRejectionDetails.ts +23 -0
- package/src/pricing/quotePorts.ts +58 -0
- package/src/pricing/quotePrimitives.ts +21 -0
- package/src/pricing/quotePromotionEvidence.ts +82 -0
- package/src/pricing/quoteSchemas.ts +230 -0
- package/src/pricing/subscriptionPricePolicy.ts +113 -0
- package/src/pricing/taxProfileGuard.ts +33 -0
- package/src/pricing/validation.ts +3 -0
- package/src/promotions/adminBindings.ts +53 -0
- package/src/promotions/adminPromotionCodesContracts.ts +244 -0
- package/src/promotions/adminPromotionCodesDataPort.ts +56 -0
- package/src/promotions/adminPromotionCodesHandler.ts +254 -0
- package/src/promotions/adminPromotionsContracts.ts +121 -0
- package/src/promotions/adminPromotionsDataPort.ts +48 -0
- package/src/promotions/adminPromotionsHandler.ts +72 -0
- package/src/promotions/contracts/index.ts +387 -0
- package/src/promotions/index.ts +22 -0
- package/src/promotions/promoDataPort.ts +65 -0
- package/src/promotions/promotionAcceptanceTelemetry.ts +73 -0
- package/src/promotions/promotionBenefitDefinition.ts +48 -0
- package/src/promotions/promotionClaimSweepPort.ts +23 -0
- package/src/promotions/promotionClaims.ts +70 -0
- package/src/promotions/promotionCodePreview.ts +183 -0
- package/src/promotions/promotionCodeQuotePort.ts +35 -0
- package/src/promotions/promotionQuoteAcceptance.ts +284 -0
- package/src/promotions/promotionQuoteBinding.ts +158 -0
- package/src/promotions/quoteAutomaticPromotions.ts +58 -0
- package/src/promotions/quotePromoDiscounts.ts +185 -0
- package/src/promotions/quotePromotionCodeAdjustments.ts +277 -0
- package/src/promotions/quotePromotionV2.ts +223 -0
- package/src/promotions/sql.ts +5 -0
- package/src/promotions/validation.ts +3 -0
- package/src/shipping/addressCanonLookupHandler.ts +114 -0
- package/src/shipping/addressCanonical.ts +31 -0
- package/src/shipping/addressPorts.ts +48 -0
- package/src/shipping/addressSchemas.ts +28 -0
- package/src/shipping/adminShippingRateHandler.ts +72 -0
- package/src/shipping/contracts/address.ts +71 -0
- package/src/shipping/contracts/delivery.ts +114 -0
- package/src/shipping/contracts/index.ts +18 -0
- package/src/shipping/contracts/shippingRate.ts +7 -0
- package/src/shipping/customerAddressesHandler.ts +100 -0
- package/src/shipping/customerSelfServiceAddressModels.ts +124 -0
- package/src/shipping/deliverySelectionHandler.ts +94 -0
- package/src/shipping/deliverySelectionPort.ts +10 -0
- package/src/shipping/deliverySelectionSummary.ts +56 -0
- package/src/shipping/handlerSchemas.ts +19 -0
- package/src/shipping/index.ts +23 -0
- package/src/shipping/pickupPointSearchPort.ts +8 -0
- package/src/shipping/readDeliverySelectionEvidence.ts +51 -0
- package/src/shipping/shippingRatePorts.ts +36 -0
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { HttpRequest, HttpResponse } from "../http/index.js";
|
|
2
|
+
import type { BffResponder } from "../bff/index.js";
|
|
3
|
+
import type { BundleResponseSchema } from "./adminBindings.js";
|
|
4
|
+
import type { SellableBundle } from "./contracts/bundleAvailability.js";
|
|
5
|
+
import type { BundleAvailability } from "./bundleAvailability.js";
|
|
6
|
+
import type { ActiveBundleComposition } from "./bundleCatalogReadPort.js";
|
|
7
|
+
import type { BundleAvailabilityService } from "./bundleAvailabilityService.js";
|
|
8
|
+
/**
|
|
9
|
+
* The public sellable-bundle feed handler, shaped after the reference catalog
|
|
10
|
+
* handler: GET-only, one
|
|
11
|
+
* port call, validate the body before sending, and never serve an unvalidated
|
|
12
|
+
* shape.
|
|
13
|
+
*
|
|
14
|
+
* It composes rather than computes twice: the availability service already folds
|
|
15
|
+
* one batched stock answer into the live compositions, and the pricing kernel
|
|
16
|
+
* turns the stored target price into per-component money. This module only decides
|
|
17
|
+
* what a storefront is allowed to see.
|
|
18
|
+
*
|
|
19
|
+
* A bundle whose money cannot be derived is DROPPED from the feed, not published
|
|
20
|
+
* with a guessed figure. Three cases reach that door — an unpriced component, an
|
|
21
|
+
* empty composition, and a target price the kernel refuses — and all three mean
|
|
22
|
+
* the same thing to a storefront: this is not sellable today. Publishing it with a
|
|
23
|
+
* partial price would put a number on a shelf that no order line could reproduce.
|
|
24
|
+
*/
|
|
25
|
+
export interface SellableBundleHandlerDeps {
|
|
26
|
+
availabilityService: BundleAvailabilityService;
|
|
27
|
+
/** Narrow the feed to one currency; omitted means every currency an operator priced. */
|
|
28
|
+
currency?: string;
|
|
29
|
+
enabled: boolean;
|
|
30
|
+
}
|
|
31
|
+
export declare function createSellableBundleHandlers({ responder, sellableBundleListResponseSchema, SELLABLE_BUNDLE_CONTRACT_VERSION }: {
|
|
32
|
+
responder: BffResponder;
|
|
33
|
+
sellableBundleListResponseSchema: BundleResponseSchema;
|
|
34
|
+
SELLABLE_BUNDLE_CONTRACT_VERSION: "catalog.sellable-bundle.v1";
|
|
35
|
+
}): {
|
|
36
|
+
createSellableBundleHandler: (deps: SellableBundleHandlerDeps) => (req: HttpRequest, res: HttpResponse) => Promise<void>;
|
|
37
|
+
};
|
|
38
|
+
/**
|
|
39
|
+
* Derive the row a storefront sees, or `null` when the money cannot be stated.
|
|
40
|
+
*
|
|
41
|
+
* The allocator emits TWO lines for a quantity whose subtotal does not divide
|
|
42
|
+
* evenly, which is exactly why the feed carries lines rather than a unit price per
|
|
43
|
+
* component: `unitPrice x quantity === lineSubtotal` holds on every line, and the
|
|
44
|
+
* lines sum to the bundle's price with no remainder.
|
|
45
|
+
*/
|
|
46
|
+
export declare function toSellableBundle(composition: ActiveBundleComposition, availability: BundleAvailability): SellableBundle | null;
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { allocateBundleTargetPrice } from "@openlup/core/pricing";
|
|
2
|
+
export function createSellableBundleHandlers({ responder, sellableBundleListResponseSchema, SELLABLE_BUNDLE_CONTRACT_VERSION }) {
|
|
3
|
+
const { sendBffError, sendBffSuccess, sendMethodNotAllowed } = responder;
|
|
4
|
+
function createSellableBundleHandler(deps) {
|
|
5
|
+
return async function handler(req, res) {
|
|
6
|
+
if (req.method !== "GET") {
|
|
7
|
+
sendMethodNotAllowed(res, ["GET"]);
|
|
8
|
+
return;
|
|
9
|
+
}
|
|
10
|
+
if (!deps.enabled) {
|
|
11
|
+
sendBffError(res, "UPSTREAM_UNAVAILABLE", "Bundle reads are disabled", {
|
|
12
|
+
details: { reason: "feature_flag_disabled", featureFlag: "COMMERCE_BUNDLE_READ_ENABLED" },
|
|
13
|
+
});
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
try {
|
|
17
|
+
const rows = await deps.availabilityService.describeActiveBundles(deps.currency ? { currency: deps.currency } : {});
|
|
18
|
+
const response = sellableBundleListResponseSchema.safeParse({
|
|
19
|
+
contractVersion: SELLABLE_BUNDLE_CONTRACT_VERSION,
|
|
20
|
+
bundles: rows
|
|
21
|
+
.map((row) => toSellableBundle(row.composition, row.availability))
|
|
22
|
+
.filter((bundle) => bundle !== null),
|
|
23
|
+
});
|
|
24
|
+
if (!response.success) {
|
|
25
|
+
sendBffError(res, "INVALID_RESPONSE", "Sellable bundle feed returned an invalid shape");
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
sendBffSuccess(res, response.data, { contractVersion: SELLABLE_BUNDLE_CONTRACT_VERSION }, { cacheControl: "no-store" });
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
sendBffError(res, "UPSTREAM_UNAVAILABLE", "Sellable bundles are unavailable");
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
return { createSellableBundleHandler };
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Derive the row a storefront sees, or `null` when the money cannot be stated.
|
|
39
|
+
*
|
|
40
|
+
* The allocator emits TWO lines for a quantity whose subtotal does not divide
|
|
41
|
+
* evenly, which is exactly why the feed carries lines rather than a unit price per
|
|
42
|
+
* component: `unitPrice x quantity === lineSubtotal` holds on every line, and the
|
|
43
|
+
* lines sum to the bundle's price with no remainder.
|
|
44
|
+
*/
|
|
45
|
+
export function toSellableBundle(composition, availability) {
|
|
46
|
+
if (composition.components.length === 0)
|
|
47
|
+
return null;
|
|
48
|
+
if (composition.components.some((component) => component.referenceUnitPriceMinor === null)) {
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
const allocation = allocateBundleTargetPrice({
|
|
52
|
+
components: composition.components.map((component) => ({
|
|
53
|
+
sku: component.sku,
|
|
54
|
+
quantity: component.quantity,
|
|
55
|
+
unitPriceMinor: component.referenceUnitPriceMinor,
|
|
56
|
+
})),
|
|
57
|
+
targetPriceMinor: composition.targetPriceMinor,
|
|
58
|
+
});
|
|
59
|
+
if (!allocation.ok)
|
|
60
|
+
return null;
|
|
61
|
+
// Basis points come from the per-component allocation, so a component split
|
|
62
|
+
// across two lines reports the same discount on both halves rather than two
|
|
63
|
+
// rounded figures that disagree.
|
|
64
|
+
const discountBpsBySku = new Map(allocation.components.map((component) => [component.sku, component.discountBps]));
|
|
65
|
+
return {
|
|
66
|
+
code: composition.code,
|
|
67
|
+
title: composition.title,
|
|
68
|
+
fulfillmentMode: composition.fulfillmentMode,
|
|
69
|
+
price: { amountMinor: composition.targetPriceMinor, currency: composition.currency },
|
|
70
|
+
components: allocation.lines.map((line) => ({
|
|
71
|
+
sku: line.sku,
|
|
72
|
+
quantity: line.quantity,
|
|
73
|
+
effectiveUnitPriceMinor: line.effectiveUnitPriceMinor,
|
|
74
|
+
lineSubtotalMinor: line.lineSubtotalMinor,
|
|
75
|
+
discountBps: discountBpsBySku.get(line.sku) ?? 0,
|
|
76
|
+
})),
|
|
77
|
+
availability: {
|
|
78
|
+
status: availability.status,
|
|
79
|
+
sellableNow: availability.sellableNow,
|
|
80
|
+
limitingSku: availability.limitingSku,
|
|
81
|
+
reasonCode: availability.reasonCode,
|
|
82
|
+
},
|
|
83
|
+
};
|
|
84
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { z } from "./validation.js";
|
|
2
|
+
export { SELLABLE_CATALOG_CONTRACT_VERSION } from "./contracts/sellable.js";
|
|
3
|
+
export type { SellableCatalogItem, SellableCatalogProfile, SellableCatalogListResponse } from "./contracts/sellable.js";
|
|
4
|
+
export declare const sellableCatalogItemSchema: z.ZodObject<{
|
|
5
|
+
sku: z.ZodString;
|
|
6
|
+
title: z.ZodString;
|
|
7
|
+
unitPrice: z.ZodObject<{
|
|
8
|
+
amountMinor: z.ZodNumber;
|
|
9
|
+
currency: z.ZodString;
|
|
10
|
+
}, z.core.$strict>;
|
|
11
|
+
permittedPurchaseModes: z.ZodArray<z.ZodEnum<{
|
|
12
|
+
subscription: "subscription";
|
|
13
|
+
one_time: "one_time";
|
|
14
|
+
}>>;
|
|
15
|
+
}, z.core.$strict>;
|
|
16
|
+
export declare const sellableCatalogProfileSchema: z.ZodObject<{
|
|
17
|
+
id: z.ZodString;
|
|
18
|
+
brand: z.ZodString;
|
|
19
|
+
country: z.ZodString;
|
|
20
|
+
currency: z.ZodString;
|
|
21
|
+
locale: z.ZodString;
|
|
22
|
+
timezone: z.ZodString;
|
|
23
|
+
}, z.core.$strict>;
|
|
24
|
+
export declare const sellableCatalogListResponseSchema: z.ZodObject<{
|
|
25
|
+
contractVersion: z.ZodLiteral<"catalog.sellable.v1">;
|
|
26
|
+
profile: z.ZodObject<{
|
|
27
|
+
id: z.ZodString;
|
|
28
|
+
brand: z.ZodString;
|
|
29
|
+
country: z.ZodString;
|
|
30
|
+
currency: z.ZodString;
|
|
31
|
+
locale: z.ZodString;
|
|
32
|
+
timezone: z.ZodString;
|
|
33
|
+
}, z.core.$strict>;
|
|
34
|
+
items: z.ZodArray<z.ZodObject<{
|
|
35
|
+
sku: z.ZodString;
|
|
36
|
+
title: z.ZodString;
|
|
37
|
+
unitPrice: z.ZodObject<{
|
|
38
|
+
amountMinor: z.ZodNumber;
|
|
39
|
+
currency: z.ZodString;
|
|
40
|
+
}, z.core.$strict>;
|
|
41
|
+
permittedPurchaseModes: z.ZodArray<z.ZodEnum<{
|
|
42
|
+
subscription: "subscription";
|
|
43
|
+
one_time: "one_time";
|
|
44
|
+
}>>;
|
|
45
|
+
}, z.core.$strict>>;
|
|
46
|
+
}, z.core.$strict>;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { z } from "./validation.js";
|
|
2
|
+
import { SELLABLE_CATALOG_CONTRACT_VERSION } from "./contracts/sellable.js";
|
|
3
|
+
export { SELLABLE_CATALOG_CONTRACT_VERSION } from "./contracts/sellable.js";
|
|
4
|
+
/** Minimal neutral storefront wire schema. */
|
|
5
|
+
const sellableCatalogMoneySchema = z.object({
|
|
6
|
+
amountMinor: z.number().int().nonnegative(),
|
|
7
|
+
currency: z.string().regex(/^[A-Z]{3}$/),
|
|
8
|
+
}).strict();
|
|
9
|
+
export const sellableCatalogItemSchema = z.object({
|
|
10
|
+
sku: z.string().trim().min(1).max(128).regex(/^[a-zA-Z0-9._:-]+$/),
|
|
11
|
+
title: z.string().trim().min(1).max(160),
|
|
12
|
+
unitPrice: sellableCatalogMoneySchema,
|
|
13
|
+
permittedPurchaseModes: z.array(z.enum(["one_time", "subscription"])).min(1).max(2),
|
|
14
|
+
}).strict();
|
|
15
|
+
export const sellableCatalogProfileSchema = z.object({
|
|
16
|
+
id: z.string().trim().min(1).max(120),
|
|
17
|
+
brand: z.string().trim().min(1).max(160),
|
|
18
|
+
country: z.string().regex(/^[A-Z]{2}$/),
|
|
19
|
+
currency: z.string().regex(/^[A-Z]{3}$/),
|
|
20
|
+
locale: z.string().trim().min(2).max(35),
|
|
21
|
+
timezone: z.string().trim().min(1).max(80),
|
|
22
|
+
}).strict();
|
|
23
|
+
export const sellableCatalogListResponseSchema = z.object({
|
|
24
|
+
contractVersion: z.literal(SELLABLE_CATALOG_CONTRACT_VERSION),
|
|
25
|
+
profile: sellableCatalogProfileSchema,
|
|
26
|
+
items: z.array(sellableCatalogItemSchema).min(1),
|
|
27
|
+
}).strict();
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/** Sparse projections of canonical units, never an install chain. */
|
|
2
|
+
export declare const BUNDLE_MIGRATIONS: readonly [{
|
|
3
|
+
readonly id: "20260812140000_sellable_bundle_catalog";
|
|
4
|
+
readonly catalogPath: "db/platform/migrations/20260812140000_sellable_bundle_catalog.sql";
|
|
5
|
+
readonly position: 16;
|
|
6
|
+
readonly sha256: "62fbf0910a3a7a2ee47e2d798933fe0a5a273fd1242cae7cc78ff237ba39e394";
|
|
7
|
+
readonly url: URL;
|
|
8
|
+
}, {
|
|
9
|
+
readonly id: "20260812210000_bundle_operator_write_boundary";
|
|
10
|
+
readonly catalogPath: "db/platform/migrations/20260812210000_bundle_operator_write_boundary.sql";
|
|
11
|
+
readonly position: 19;
|
|
12
|
+
readonly sha256: "d0ec6674d7eedf4cd3ce0d8ccd7345ebe2f93da635316a68a6bd178ec55b2679";
|
|
13
|
+
readonly url: URL;
|
|
14
|
+
}];
|
|
15
|
+
/** Catalog foundation projections; install the complete canonical catalogue. */
|
|
16
|
+
export declare const CATALOG_MIGRATIONS: readonly [{
|
|
17
|
+
readonly id: "20260807140000_read_parity_catalog";
|
|
18
|
+
readonly catalogPath: "db/platform/migrations/20260807140000_read_parity_catalog.sql";
|
|
19
|
+
readonly position: 1;
|
|
20
|
+
readonly sha256: "fcf3827028c1651ae42a7c7d7472153825a3121c936d58a3d105befc7dece9ea";
|
|
21
|
+
readonly url: URL;
|
|
22
|
+
}, {
|
|
23
|
+
readonly id: "20260810120000_storefront_catalog_attributes";
|
|
24
|
+
readonly catalogPath: "db/platform/migrations/20260810120000_storefront_catalog_attributes.sql";
|
|
25
|
+
readonly position: 8;
|
|
26
|
+
readonly sha256: "2bf938f5d0076193557bea834f86dbd9bcb7f3e2de00f99fb91cc1229b93a14b";
|
|
27
|
+
readonly url: URL;
|
|
28
|
+
}, {
|
|
29
|
+
readonly id: "20260827220000_catalog_document_revision_foundation";
|
|
30
|
+
readonly catalogPath: "db/platform/migrations/20260827220000_catalog_document_revision_foundation.sql";
|
|
31
|
+
readonly position: 58;
|
|
32
|
+
readonly sha256: "715e74d655b76d35b8a49e0d2a5625594a6c4856863f369cd1eadcd1fb1ae90e";
|
|
33
|
+
readonly url: URL;
|
|
34
|
+
}, {
|
|
35
|
+
readonly id: "20260827220001_catalog_document_revision_foundation_validate";
|
|
36
|
+
readonly catalogPath: "db/platform/migrations/20260827220001_catalog_document_revision_foundation_validate.sql";
|
|
37
|
+
readonly position: 59;
|
|
38
|
+
readonly sha256: "f3cd7fb61dcebac1cf0468cf2d7c1f9dd036817ab0094c72864266e307b269de";
|
|
39
|
+
readonly url: URL;
|
|
40
|
+
}, {
|
|
41
|
+
readonly id: "20260908100000_catalog_draft_foundation";
|
|
42
|
+
readonly catalogPath: "db/platform/migrations/20260908100000_catalog_draft_foundation.sql";
|
|
43
|
+
readonly position: 61;
|
|
44
|
+
readonly sha256: "ac0d614cdb2874df8fbdbbbda4f9455986ef95241fe1334b0b54a1fa6478ab2e";
|
|
45
|
+
readonly url: URL;
|
|
46
|
+
}];
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/** Sparse projections of canonical units, never an install chain. */
|
|
2
|
+
export const BUNDLE_MIGRATIONS = [
|
|
3
|
+
{ id: "20260812140000_sellable_bundle_catalog", catalogPath: "db/platform/migrations/20260812140000_sellable_bundle_catalog.sql", position: 16, sha256: "62fbf0910a3a7a2ee47e2d798933fe0a5a273fd1242cae7cc78ff237ba39e394", url: new URL("../../sql/20260812140000_sellable_bundle_catalog.sql", import.meta.url) },
|
|
4
|
+
{ id: "20260812210000_bundle_operator_write_boundary", catalogPath: "db/platform/migrations/20260812210000_bundle_operator_write_boundary.sql", position: 19, sha256: "d0ec6674d7eedf4cd3ce0d8ccd7345ebe2f93da635316a68a6bd178ec55b2679", url: new URL("../../sql/20260812210000_bundle_operator_write_boundary.sql", import.meta.url) },
|
|
5
|
+
];
|
|
6
|
+
/** Catalog foundation projections; install the complete canonical catalogue. */
|
|
7
|
+
export const CATALOG_MIGRATIONS = [
|
|
8
|
+
{ id: "20260807140000_read_parity_catalog", catalogPath: "db/platform/migrations/20260807140000_read_parity_catalog.sql", position: 1, sha256: "fcf3827028c1651ae42a7c7d7472153825a3121c936d58a3d105befc7dece9ea", url: new URL("../../sql/20260807140000_read_parity_catalog.sql", import.meta.url) },
|
|
9
|
+
{ id: "20260810120000_storefront_catalog_attributes", catalogPath: "db/platform/migrations/20260810120000_storefront_catalog_attributes.sql", position: 8, sha256: "2bf938f5d0076193557bea834f86dbd9bcb7f3e2de00f99fb91cc1229b93a14b", url: new URL("../../sql/20260810120000_storefront_catalog_attributes.sql", import.meta.url) },
|
|
10
|
+
{ id: "20260827220000_catalog_document_revision_foundation", catalogPath: "db/platform/migrations/20260827220000_catalog_document_revision_foundation.sql", position: 58, sha256: "715e74d655b76d35b8a49e0d2a5625594a6c4856863f369cd1eadcd1fb1ae90e", url: new URL("../../sql/20260827220000_catalog_document_revision_foundation.sql", import.meta.url) },
|
|
11
|
+
{ id: "20260827220001_catalog_document_revision_foundation_validate", catalogPath: "db/platform/migrations/20260827220001_catalog_document_revision_foundation_validate.sql", position: 59, sha256: "f3cd7fb61dcebac1cf0468cf2d7c1f9dd036817ab0094c72864266e307b269de", url: new URL("../../sql/20260827220001_catalog_document_revision_foundation_validate.sql", import.meta.url) },
|
|
12
|
+
{ id: "20260908100000_catalog_draft_foundation", catalogPath: "db/platform/migrations/20260908100000_catalog_draft_foundation.sql", position: 61, sha256: "ac0d614cdb2874df8fbdbbbda4f9455986ef95241fe1334b0b54a1fa6478ab2e", url: new URL("../../sql/20260908100000_catalog_draft_foundation.sql", import.meta.url) },
|
|
13
|
+
];
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The sealed transport boundary for handing an accounting document to its recipient.
|
|
3
|
+
*
|
|
4
|
+
* The kernel exercises the whole capability up to this line: a document is owed, registered with
|
|
5
|
+
* whatever authority the market has, queued, claimed and settled against a receipt. What crosses
|
|
6
|
+
* the line is one opaque hand-off, and this adapter is the deliberately inert implementation of
|
|
7
|
+
* it -- deterministic, and leaving the installation by no route at all.
|
|
8
|
+
*
|
|
9
|
+
* It is FAIL CLOSED, and that is the whole design. An installation that has declared no delivery
|
|
10
|
+
* channel gets a refusal, never a silent success: a boundary whose default answer is "fine" is
|
|
11
|
+
* how a deployment discovers months later that nothing was ever handed to anyone.
|
|
12
|
+
*/
|
|
13
|
+
export type CapturedDocumentDeliveryCommand = {
|
|
14
|
+
readonly deliveryId: string;
|
|
15
|
+
readonly recipientReference: string;
|
|
16
|
+
};
|
|
17
|
+
export type CapturedDocumentDeliveryPort = {
|
|
18
|
+
deliver(command: CapturedDocumentDeliveryCommand): Promise<{
|
|
19
|
+
readonly receiptReference: string;
|
|
20
|
+
}>;
|
|
21
|
+
};
|
|
22
|
+
export type CapturedDocumentDeliveryResolution = {
|
|
23
|
+
readonly port: CapturedDocumentDeliveryPort;
|
|
24
|
+
readonly refused?: undefined;
|
|
25
|
+
} | {
|
|
26
|
+
readonly port?: undefined;
|
|
27
|
+
readonly refused: string;
|
|
28
|
+
};
|
|
29
|
+
/** The one marker that opens the boundary. Anything else, including its absence, is a refusal. */
|
|
30
|
+
export declare const CAPTURED_DOCUMENT_DELIVERY_CHANNEL = "captured";
|
|
31
|
+
/**
|
|
32
|
+
* Resolve the boundary for one installation. The environment is the only input, and every path
|
|
33
|
+
* that is not an explicit declaration of the captured channel ends in a named refusal.
|
|
34
|
+
*/
|
|
35
|
+
export declare function resolveCapturedDocumentDelivery(env: Record<string, string | undefined>): CapturedDocumentDeliveryResolution;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
/** The one marker that opens the boundary. Anything else, including its absence, is a refusal. */
|
|
3
|
+
export const CAPTURED_DOCUMENT_DELIVERY_CHANNEL = "captured";
|
|
4
|
+
const CHANNEL_KEY = "PLATFORM_DOCUMENT_DELIVERY_CHANNEL";
|
|
5
|
+
const reference = (command) => `captured:${createHash("sha256")
|
|
6
|
+
.update(`${command.deliveryId}::${command.recipientReference}`)
|
|
7
|
+
.digest("hex")
|
|
8
|
+
.slice(0, 32)}`;
|
|
9
|
+
/**
|
|
10
|
+
* Resolve the boundary for one installation. The environment is the only input, and every path
|
|
11
|
+
* that is not an explicit declaration of the captured channel ends in a named refusal.
|
|
12
|
+
*/
|
|
13
|
+
export function resolveCapturedDocumentDelivery(env) {
|
|
14
|
+
const declared = env[CHANNEL_KEY]?.trim().toLowerCase() ?? "";
|
|
15
|
+
if (declared === "")
|
|
16
|
+
return { refused: "document_delivery_channel_undeclared" };
|
|
17
|
+
if (declared !== CAPTURED_DOCUMENT_DELIVERY_CHANNEL) {
|
|
18
|
+
return { refused: "document_delivery_channel_unsupported" };
|
|
19
|
+
}
|
|
20
|
+
return {
|
|
21
|
+
port: {
|
|
22
|
+
async deliver(command) {
|
|
23
|
+
if (typeof command.deliveryId !== "string" || command.deliveryId.trim() === "") {
|
|
24
|
+
throw new Error("document_delivery_command_invalid");
|
|
25
|
+
}
|
|
26
|
+
if (typeof command.recipientReference !== "string" || command.recipientReference.trim() === "") {
|
|
27
|
+
throw new Error("document_delivery_recipient_missing");
|
|
28
|
+
}
|
|
29
|
+
return { receiptReference: reference(command) };
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/** Typed refusal used by public/default composition when product copy is absent. */
|
|
2
|
+
export class AuthEmailContentUnavailableError extends Error {
|
|
3
|
+
code = "auth_email_content_unavailable";
|
|
4
|
+
constructor() {
|
|
5
|
+
super("Auth email content unavailable");
|
|
6
|
+
this.name = "AuthEmailContentUnavailableError";
|
|
7
|
+
}
|
|
8
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { AuthEmailContentUnavailableError } from "./authEmailError.js";
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Auth Send Email hook. Live, not a candidate.
|
|
3
|
+
*
|
|
4
|
+
* Supabase Auth targets `/api/auth-send-email` in staging and production - the
|
|
5
|
+
* hooks were repointed here on 2026-09-04 and the hosted Edge Functions were
|
|
6
|
+
* undeployed the same day, so this owns the raw-stream, signature, render/send
|
|
7
|
+
* and ledger contract for every magic link, recovery and confirmation the
|
|
8
|
+
* product sends. Rotating its signing secret is a human-only control-plane act.
|
|
9
|
+
*/
|
|
10
|
+
import type { HttpRequest as VercelRequest, HttpResponse as VercelResponse } from "../http/index.js";
|
|
11
|
+
import type { EmailBrand, EmailRenderer } from "./contracts/email.js";
|
|
12
|
+
import { type AuthEmailContentPort, type AuthEmailPersistencePort, type AuthEmailTransportPort } from "./authEmailPorts.js";
|
|
13
|
+
export interface AuthSendEmailHookDeps {
|
|
14
|
+
transport: AuthEmailTransportPort;
|
|
15
|
+
persistence: AuthEmailPersistencePort;
|
|
16
|
+
content: AuthEmailContentPort;
|
|
17
|
+
fromEmail: string;
|
|
18
|
+
hookSecret: string;
|
|
19
|
+
authServiceUrl: string;
|
|
20
|
+
/** App-layer defaults injected at composition; no brand/env ownership lives here. */
|
|
21
|
+
defaultOrigin: string;
|
|
22
|
+
productionEmailHosts: string[];
|
|
23
|
+
legacyBaseUrl?: string | null;
|
|
24
|
+
emailBrandForOrigin: (origin: string) => EmailBrand;
|
|
25
|
+
defaultSandboxRecipient: string;
|
|
26
|
+
defaultRedirectTo?: string;
|
|
27
|
+
env: Record<string, string | undefined>;
|
|
28
|
+
now?: () => number;
|
|
29
|
+
}
|
|
30
|
+
export interface AuthEmailHookHost {
|
|
31
|
+
renderEmail: EmailRenderer;
|
|
32
|
+
readObservedEnvironment: (env: Record<string, string | undefined>) => string;
|
|
33
|
+
readHiddenPreviewEnabled: (env: Record<string, string | undefined>) => boolean;
|
|
34
|
+
}
|
|
35
|
+
export declare function createAuthSendEmailHookCandidate(deps: AuthSendEmailHookDeps, host: AuthEmailHookHost): (req: VercelRequest, res: VercelResponse) => Promise<void>;
|
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
import { readEmailOriginConfiguration, resolveEmailOrigin } from "./originPolicy.js";
|
|
2
|
+
import { buildAuthVerifyUrl } from "../identity/index.js";
|
|
3
|
+
import { AuthEmailContentUnavailableError, } from "./authEmailPorts.js";
|
|
4
|
+
import { guardAuthEmailTransport } from "./emailEgress.js";
|
|
5
|
+
import { verifyStandardWebhookSignature } from "./standardWebhooks.js";
|
|
6
|
+
const CORS_HEADERS = {
|
|
7
|
+
"access-control-allow-origin": "*",
|
|
8
|
+
"access-control-allow-headers": "authorization, x-client-info, apikey, content-type",
|
|
9
|
+
};
|
|
10
|
+
const KNOWN_ACTION_TYPES = new Set([
|
|
11
|
+
"magiclink", "signup", "recovery", "invite", "email_change",
|
|
12
|
+
"email_change_current", "email_change_new", "email",
|
|
13
|
+
]);
|
|
14
|
+
function json(res, status, body) {
|
|
15
|
+
for (const [key, value] of Object.entries(CORS_HEADERS))
|
|
16
|
+
res.setHeader(key, value);
|
|
17
|
+
res.status(status).json(body);
|
|
18
|
+
}
|
|
19
|
+
function hookError(res, httpCode, message) {
|
|
20
|
+
json(res, httpCode, { error: { http_code: httpCode, message } });
|
|
21
|
+
}
|
|
22
|
+
async function readRawBody(req) {
|
|
23
|
+
const chunks = [];
|
|
24
|
+
for await (const chunk of req)
|
|
25
|
+
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
|
|
26
|
+
return Buffer.concat(chunks).toString("utf8");
|
|
27
|
+
}
|
|
28
|
+
function resolveRedirectTarget(data, defaultRedirectTo) {
|
|
29
|
+
if (data?.redirect_to?.trim())
|
|
30
|
+
return { redirectTo: data.redirect_to, source: "redirect_to" };
|
|
31
|
+
if (data?.site_url?.trim())
|
|
32
|
+
return { redirectTo: data.site_url, source: "site_url" };
|
|
33
|
+
return { redirectTo: defaultRedirectTo ?? "", source: "default_redirect" };
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* An email carries no base URL, so a relative action link is not a degraded
|
|
37
|
+
* link - it is an unclickable one. The Edge runtime supplied this origin for
|
|
38
|
+
* free; a Node deployment must be configured with it, and one that is not must
|
|
39
|
+
* refuse rather than send mail whose only working path is the OTP fallback.
|
|
40
|
+
*/
|
|
41
|
+
function absoluteAuthServiceUrl(value) {
|
|
42
|
+
try {
|
|
43
|
+
const url = new URL(value);
|
|
44
|
+
return url.protocol === "https:" || url.protocol === "http:";
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
function uuidOrNull(value) {
|
|
51
|
+
return value && /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(value)
|
|
52
|
+
? value
|
|
53
|
+
: null;
|
|
54
|
+
}
|
|
55
|
+
function deliveryMode(result, env, recipient, defaultSandboxRecipient) {
|
|
56
|
+
// Preserve the existing Auth-hook audit vocabulary even though the Node
|
|
57
|
+
// transport's lower-level egress seam uses a richer set of route names.
|
|
58
|
+
if (result.outcome.egressMode === "production")
|
|
59
|
+
return "standard";
|
|
60
|
+
if ((env.EMAIL_DELIVERY_PROFILE ?? "").trim().toLowerCase() !== "production_like")
|
|
61
|
+
return "standard";
|
|
62
|
+
const sandboxRecipients = parseEmailList(env.EMAIL_SANDBOX_RECIPIENTS ?? env.COMMS_SANDBOX_SINK_ADDRESS ?? defaultSandboxRecipient);
|
|
63
|
+
return result.outcome.egressMode === "sandbox_sink"
|
|
64
|
+
|| (result.outcome.adminDisabled === true && sandboxRecipients.has(recipient.trim().toLowerCase()))
|
|
65
|
+
? "sandbox_recipient"
|
|
66
|
+
: "production_like_real";
|
|
67
|
+
}
|
|
68
|
+
function parseEmailList(value) {
|
|
69
|
+
return new Set((value ?? "")
|
|
70
|
+
.split(/[,\s;]+/)
|
|
71
|
+
.map((item) => item.trim().toLowerCase())
|
|
72
|
+
.filter(Boolean));
|
|
73
|
+
}
|
|
74
|
+
function selectFromEmail(deps, recipient) {
|
|
75
|
+
const env = deps.env;
|
|
76
|
+
if ((env.EMAIL_DELIVERY_PROFILE ?? "").trim().toLowerCase() !== "production_like")
|
|
77
|
+
return deps.fromEmail;
|
|
78
|
+
const sandboxRecipients = parseEmailList(env.EMAIL_SANDBOX_RECIPIENTS ?? env.COMMS_SANDBOX_SINK_ADDRESS ?? deps.defaultSandboxRecipient);
|
|
79
|
+
if (sandboxRecipients.has(recipient.trim().toLowerCase()))
|
|
80
|
+
return deps.fromEmail;
|
|
81
|
+
return env.EMAIL_REAL_DELIVERY_FROM_EMAIL?.trim()
|
|
82
|
+
|| env.AUTH_EMAIL_REAL_DELIVERY_FROM_EMAIL?.trim()
|
|
83
|
+
|| deps.fromEmail;
|
|
84
|
+
}
|
|
85
|
+
function validateAuthEmailRedirectOrigin(deps, redirectTo, host) {
|
|
86
|
+
const env = deps.env;
|
|
87
|
+
const originConfiguration = readEmailOriginConfiguration(env, {
|
|
88
|
+
defaultOrigin: deps.defaultOrigin,
|
|
89
|
+
productionEmailHosts: deps.productionEmailHosts,
|
|
90
|
+
});
|
|
91
|
+
const environment = env.EMAIL_ENVIRONMENT ?? host.readObservedEnvironment(env);
|
|
92
|
+
const configured = resolveEmailOrigin({
|
|
93
|
+
...originConfiguration,
|
|
94
|
+
explicitBaseUrl: env.APP_BASE_URL?.trim() || deps.legacyBaseUrl,
|
|
95
|
+
customerAuthRedirectOrigin: env.CUSTOMER_AUTH_REDIRECT_ORIGIN,
|
|
96
|
+
siteUrl: env.SITE_URL,
|
|
97
|
+
hiddenPreviewEnabled: host.readHiddenPreviewEnabled(env),
|
|
98
|
+
environment,
|
|
99
|
+
});
|
|
100
|
+
if (configured.ok === false)
|
|
101
|
+
return { ok: false, error: configured.error };
|
|
102
|
+
const redirect = resolveEmailOrigin({
|
|
103
|
+
...originConfiguration,
|
|
104
|
+
explicitBaseUrl: redirectTo,
|
|
105
|
+
hiddenPreviewEnabled: host.readHiddenPreviewEnabled(env),
|
|
106
|
+
environment,
|
|
107
|
+
});
|
|
108
|
+
if (redirect.ok === false)
|
|
109
|
+
return { ok: false, error: redirect.error };
|
|
110
|
+
return {
|
|
111
|
+
ok: true,
|
|
112
|
+
environment: configured.resolved.environment,
|
|
113
|
+
origin: redirect.origin,
|
|
114
|
+
production: configured.resolved.production,
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
function persistenceOutcome(result) {
|
|
118
|
+
return {
|
|
119
|
+
ok: result.outcome.ok,
|
|
120
|
+
messageId: result.outcome.messageId,
|
|
121
|
+
providerError: result.outcome.providerError,
|
|
122
|
+
aborted: result.outcome.aborted,
|
|
123
|
+
skipReason: result.outcome.adminDisabled === true
|
|
124
|
+
? "admin_disabled"
|
|
125
|
+
: result.outcome.suppressed === "drop" ? "egress_suppressed" : null,
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
export function createAuthSendEmailHookCandidate(deps, host) {
|
|
129
|
+
return async function authSendEmailHookCandidate(req, res) {
|
|
130
|
+
if (req.method === "OPTIONS") {
|
|
131
|
+
for (const [key, value] of Object.entries(CORS_HEADERS))
|
|
132
|
+
res.setHeader(key, value);
|
|
133
|
+
res.status(200).send("ok");
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
if (req.method !== "POST")
|
|
137
|
+
return hookError(res, 405, "Method not allowed");
|
|
138
|
+
if (!deps.hookSecret) {
|
|
139
|
+
console.error("[auth-send-email] SEND_EMAIL_HOOK_SECRET not configured");
|
|
140
|
+
return hookError(res, 500, "Hook secret not configured");
|
|
141
|
+
}
|
|
142
|
+
if (!absoluteAuthServiceUrl(deps.authServiceUrl)) {
|
|
143
|
+
console.error("[auth-send-email] auth service URL not configured");
|
|
144
|
+
return hookError(res, 500, "Auth service URL not configured");
|
|
145
|
+
}
|
|
146
|
+
let rawBody;
|
|
147
|
+
try {
|
|
148
|
+
rawBody = await readRawBody(req);
|
|
149
|
+
}
|
|
150
|
+
catch {
|
|
151
|
+
return hookError(res, 400, "Invalid JSON payload");
|
|
152
|
+
}
|
|
153
|
+
const valid = await verifyStandardWebhookSignature({
|
|
154
|
+
headers: {
|
|
155
|
+
id: typeof req.headers["webhook-id"] === "string" ? req.headers["webhook-id"] : null,
|
|
156
|
+
timestamp: typeof req.headers["webhook-timestamp"] === "string" ? req.headers["webhook-timestamp"] : null,
|
|
157
|
+
signature: typeof req.headers["webhook-signature"] === "string" ? req.headers["webhook-signature"] : null,
|
|
158
|
+
},
|
|
159
|
+
rawBody,
|
|
160
|
+
secret: deps.hookSecret,
|
|
161
|
+
now: deps.now,
|
|
162
|
+
});
|
|
163
|
+
if (!valid)
|
|
164
|
+
return hookError(res, 401, "Invalid signature");
|
|
165
|
+
let payload;
|
|
166
|
+
try {
|
|
167
|
+
payload = JSON.parse(rawBody);
|
|
168
|
+
}
|
|
169
|
+
catch {
|
|
170
|
+
return hookError(res, 400, "Invalid JSON payload");
|
|
171
|
+
}
|
|
172
|
+
const email = payload.user?.email;
|
|
173
|
+
const data = payload.email_data;
|
|
174
|
+
const actionType = data?.email_action_type;
|
|
175
|
+
const tokenHash = data?.token_hash;
|
|
176
|
+
const redirect = resolveRedirectTarget(data, deps.defaultRedirectTo);
|
|
177
|
+
if (!email || !actionType || !tokenHash)
|
|
178
|
+
return hookError(res, 400, "Missing user email or email_data");
|
|
179
|
+
const redirectPolicy = validateAuthEmailRedirectOrigin(deps, redirect.redirectTo, host);
|
|
180
|
+
if (redirectPolicy.ok === false)
|
|
181
|
+
return hookError(res, 500, `Email origin policy failed: ${redirectPolicy.error}`);
|
|
182
|
+
if (!KNOWN_ACTION_TYPES.has(actionType))
|
|
183
|
+
console.warn("[auth-send-email] unknown email_action_type:", actionType);
|
|
184
|
+
let content;
|
|
185
|
+
try {
|
|
186
|
+
content = deps.content.buildAuthEmailContent({
|
|
187
|
+
actionType, userMetadata: payload.user?.user_metadata, redirectTo: redirect.redirectTo,
|
|
188
|
+
actionLink: buildAuthVerifyUrl(deps.authServiceUrl, actionType, tokenHash, redirect.redirectTo),
|
|
189
|
+
otp: data?.token ?? null,
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
catch (error) {
|
|
193
|
+
if (error instanceof AuthEmailContentUnavailableError)
|
|
194
|
+
return hookError(res, 503, error.message);
|
|
195
|
+
throw error;
|
|
196
|
+
}
|
|
197
|
+
const rendered = host.renderEmail({
|
|
198
|
+
brand: deps.emailBrandForOrigin(redirectPolicy.origin), locale: content.locale,
|
|
199
|
+
subject: content.subject, preheader: content.preheader, blocks: content.blocks,
|
|
200
|
+
});
|
|
201
|
+
const sendAttemptId = crypto.randomUUID();
|
|
202
|
+
const authUserId = uuidOrNull(payload.user?.id);
|
|
203
|
+
const aggregateId = authUserId ?? crypto.randomUUID();
|
|
204
|
+
// Match the hosted hook's ordering: persistence/control failure is a
|
|
205
|
+
// retryable refusal before any email side effect, never a post-send false 5xx.
|
|
206
|
+
const templateSlug = `auth-${actionType}`;
|
|
207
|
+
const enabled = await deps.persistence.isTemplateEnabled(templateSlug, new AbortController().signal);
|
|
208
|
+
const sendResult = enabled
|
|
209
|
+
? await guardAuthEmailTransport(deps.transport).send({
|
|
210
|
+
sender: selectFromEmail(deps, email), recipient: email,
|
|
211
|
+
subject: rendered.subject, html: rendered.html, text: rendered.text,
|
|
212
|
+
})
|
|
213
|
+
: {
|
|
214
|
+
outcome: { ok: true, messageId: null, providerError: null, aborted: false, adminDisabled: true },
|
|
215
|
+
providerResponse: { skipped: "admin_disabled" },
|
|
216
|
+
};
|
|
217
|
+
const mode = deliveryMode(sendResult, deps.env, email, deps.defaultSandboxRecipient);
|
|
218
|
+
const originMetadata = {
|
|
219
|
+
emailBaseUrl: redirectPolicy.origin,
|
|
220
|
+
emailOriginSource: redirect.source,
|
|
221
|
+
emailEnvironment: redirectPolicy.environment,
|
|
222
|
+
};
|
|
223
|
+
await deps.persistence.recordSend({
|
|
224
|
+
templateSlug,
|
|
225
|
+
recipientEmail: email,
|
|
226
|
+
authUserId,
|
|
227
|
+
aggregateId,
|
|
228
|
+
dedupeKey: `auth-send-email:${actionType}:${sendAttemptId}`,
|
|
229
|
+
providerKind: deps.transport.providerKind,
|
|
230
|
+
outcome: persistenceOutcome(sendResult),
|
|
231
|
+
providerResponse: sendResult.providerResponse,
|
|
232
|
+
metadata: {
|
|
233
|
+
...originMetadata,
|
|
234
|
+
authEmailDeliveryMode: mode,
|
|
235
|
+
deliveryMode: mode,
|
|
236
|
+
triggerSource: "auth-send-email",
|
|
237
|
+
triggerReason: actionType,
|
|
238
|
+
providerKind: deps.transport.providerKind,
|
|
239
|
+
sendAttemptId,
|
|
240
|
+
aggregateType: "auth_user",
|
|
241
|
+
aggregateId,
|
|
242
|
+
},
|
|
243
|
+
});
|
|
244
|
+
if (!sendResult.outcome.ok) {
|
|
245
|
+
console.error("[auth-send-email] transport send failed:", sendResult.outcome.providerError);
|
|
246
|
+
return hookError(res, 502, "Email delivery failed");
|
|
247
|
+
}
|
|
248
|
+
json(res, 200, {});
|
|
249
|
+
};
|
|
250
|
+
}
|