@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,9 @@
|
|
|
1
|
+
/** Narrow, portable receipt contract for the captured transactional action. */
|
|
2
|
+
|
|
3
|
+
const IDENTIFIER = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,255}$/;
|
|
4
|
+
|
|
5
|
+
/** Bounded opaque identifiers keep commands and persisted evidence content-free. */
|
|
6
|
+
export function isTransactionalDeliveryIdentifier(value: string): boolean {
|
|
7
|
+
return IDENTIFIER.test(value);
|
|
8
|
+
}
|
|
9
|
+
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stateless, signed unsubscribe tokens for marketing emails (RODO one-click
|
|
3
|
+
* opt-out): an HMAC-SHA256 over the recipient email + consent purpose, so the
|
|
4
|
+
* unsubscribe route can suppress the right permission without a lookup table or
|
|
5
|
+
* trusting raw query params. Node marketing senders build the token to embed in
|
|
6
|
+
* the email footer; `api/unsubscribe.ts` verifies it.
|
|
7
|
+
*
|
|
8
|
+
* This module is the only implementation. The former Deno mirror was deleted
|
|
9
|
+
* with the `unsubscribe` Edge function; nothing has to be kept in sync any more.
|
|
10
|
+
*
|
|
11
|
+
* WebCrypto only (global `crypto.subtle`/`btoa`/`atob`, Node 18+).
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
export interface UnsubscribePayload {
|
|
15
|
+
email: string;
|
|
16
|
+
purpose: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* How long a newly minted unsubscribe link stays valid: 548 days, i.e. about
|
|
21
|
+
* eighteen months, expressed in whole days so the value does not depend on which
|
|
22
|
+
* months a token happens to span.
|
|
23
|
+
*
|
|
24
|
+
* Contract, and why this number:
|
|
25
|
+
*
|
|
26
|
+
* - Until this field existed the token carried `{e, p, v}` and the verifier
|
|
27
|
+
* checked only the HMAC, so a link minted in 2026 stayed valid forever. That
|
|
28
|
+
* made "wait for the old links to age out" an unbounded strategy and left a
|
|
29
|
+
* permanently replayable capability sitting in mailboxes.
|
|
30
|
+
* - Eighteen months is longer than a marketing message is realistically acted
|
|
31
|
+
* on and longer than a full annual cycle plus a lapsed re-engagement, so it
|
|
32
|
+
* does not cut short a genuine opt-out; it is short enough that the capability
|
|
33
|
+
* is not effectively perpetual.
|
|
34
|
+
* - ⛔ A token WITHOUT `exp` stays valid. Every link already delivered was
|
|
35
|
+
* minted without one, and refusing them would retro-expire opt-outs the
|
|
36
|
+
* recipient was told would work. Expiry is a forward-only narrowing.
|
|
37
|
+
*
|
|
38
|
+
* ⛔ Do not rename this to anything containing `TOKEN`, `SECRET`, `PASSWORD`,
|
|
39
|
+
* `SERVICE_ROLE` or `API_KEY`. This module is client-reachable `src/` source and
|
|
40
|
+
* `scripts/check-client-secret-boundary.ts` refuses a SCREAMING_SNAKE
|
|
41
|
+
* identifier carrying any of those words there — a TTL is not a credential, so
|
|
42
|
+
* the name avoids the shape rather than the allowlist.
|
|
43
|
+
*/
|
|
44
|
+
export const UNSUBSCRIBE_LINK_TTL_SECONDS = 548 * 24 * 60 * 60;
|
|
45
|
+
|
|
46
|
+
/** Clock seam, so expiry can be proved without waiting eighteen months. */
|
|
47
|
+
export interface UnsubscribeTokenClock {
|
|
48
|
+
now?: Date;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function base64urlEncode(bytes: Uint8Array): string {
|
|
52
|
+
let binary = "";
|
|
53
|
+
for (const b of bytes) binary += String.fromCharCode(b);
|
|
54
|
+
return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function base64urlDecodeToString(value: string): string {
|
|
58
|
+
const padded = value.replace(/-/g, "+").replace(/_/g, "/").padEnd(
|
|
59
|
+
Math.ceil(value.length / 4) * 4,
|
|
60
|
+
"=",
|
|
61
|
+
);
|
|
62
|
+
return atob(padded);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function timingSafeEqual(a: string, b: string): boolean {
|
|
66
|
+
if (a.length !== b.length) return false;
|
|
67
|
+
let diff = 0;
|
|
68
|
+
for (let i = 0; i < a.length; i += 1) diff |= a.charCodeAt(i) ^ b.charCodeAt(i);
|
|
69
|
+
return diff === 0;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
async function hmacBase64url(secret: string, message: string): Promise<string> {
|
|
73
|
+
const key = await crypto.subtle.importKey(
|
|
74
|
+
"raw",
|
|
75
|
+
new TextEncoder().encode(secret),
|
|
76
|
+
{ name: "HMAC", hash: "SHA-256" },
|
|
77
|
+
false,
|
|
78
|
+
["sign"],
|
|
79
|
+
);
|
|
80
|
+
const sig = await crypto.subtle.sign("HMAC", key, new TextEncoder().encode(message));
|
|
81
|
+
return base64urlEncode(new Uint8Array(sig));
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Build a `<base64url(payload)>.<base64url(sig)>` unsubscribe token.
|
|
86
|
+
*
|
|
87
|
+
* Quoted-printable safety: this token rides as `?token=…` inside marketing emails
|
|
88
|
+
* whose Polish diacritics force quoted-printable encoding. A token beginning with
|
|
89
|
+
* two hex digits could be corrupted if a transport leaves the `=` separator raw
|
|
90
|
+
* (`=7d` -> `}`). This token is structurally immune: the payload always serializes
|
|
91
|
+
* as `{"e":…`, so base64url makes the token always begin "ey" (`e` is hex, `y` is
|
|
92
|
+
* not) — `=ey` is never a valid `=<2 hex>` escape. unsubscribeToken.test.ts guards
|
|
93
|
+
* this; do NOT reshape the payload to lead with a field that could base64url into
|
|
94
|
+
* two hex digits without re-checking (and prefixing the token if so). `exp` is
|
|
95
|
+
* appended last for exactly that reason.
|
|
96
|
+
*/
|
|
97
|
+
export async function buildUnsubscribeToken(
|
|
98
|
+
payload: UnsubscribePayload,
|
|
99
|
+
secret: string,
|
|
100
|
+
clock: UnsubscribeTokenClock = {},
|
|
101
|
+
): Promise<string> {
|
|
102
|
+
const issuedAtSeconds = Math.floor((clock.now ?? new Date()).getTime() / 1000);
|
|
103
|
+
const body = base64urlEncode(
|
|
104
|
+
new TextEncoder().encode(JSON.stringify({
|
|
105
|
+
e: payload.email,
|
|
106
|
+
p: payload.purpose,
|
|
107
|
+
v: 1,
|
|
108
|
+
exp: issuedAtSeconds + UNSUBSCRIBE_LINK_TTL_SECONDS,
|
|
109
|
+
})),
|
|
110
|
+
);
|
|
111
|
+
const sig = await hmacBase64url(secret, body);
|
|
112
|
+
return `${body}.${sig}`;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Add the signed query to a resolved unsubscribe endpoint. The adapter that
|
|
117
|
+
* owns deployment/provider configuration must choose and validate that endpoint
|
|
118
|
+
* before it reaches this neutral communications-domain helper.
|
|
119
|
+
*/
|
|
120
|
+
export function buildUnsubscribeUrl(
|
|
121
|
+
unsubscribeEndpointUrl: string,
|
|
122
|
+
token: string,
|
|
123
|
+
locale: "pl" | "en",
|
|
124
|
+
): string {
|
|
125
|
+
const endpoint = parseUnsubscribeEndpointUrl(unsubscribeEndpointUrl);
|
|
126
|
+
const params = new URLSearchParams({ token });
|
|
127
|
+
if (locale === "en") params.set("lang", "en");
|
|
128
|
+
endpoint.search = `?${params.toString()}`;
|
|
129
|
+
return endpoint.toString();
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function parseUnsubscribeEndpointUrl(value: string): URL {
|
|
133
|
+
const endpoint = new URL(value);
|
|
134
|
+
if (
|
|
135
|
+
endpoint.protocol !== "https:" ||
|
|
136
|
+
endpoint.username ||
|
|
137
|
+
endpoint.password ||
|
|
138
|
+
endpoint.search ||
|
|
139
|
+
endpoint.hash ||
|
|
140
|
+
endpoint.hostname.endsWith(".")
|
|
141
|
+
) {
|
|
142
|
+
throw new Error("unsubscribe endpoint URL must be HTTPS without credentials, query, fragment, or a trailing-dot hostname");
|
|
143
|
+
}
|
|
144
|
+
return endpoint;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Verify a token; returns the payload or null on any tampering / bad shape /
|
|
149
|
+
* elapsed expiry.
|
|
150
|
+
*
|
|
151
|
+
* ⛔ An absent `exp` is valid, not a rejection: tokens minted before expiry
|
|
152
|
+
* existed are still in mailboxes, and a recipient who was promised a working
|
|
153
|
+
* opt-out link must keep one. A present `exp` must be a finite number and must
|
|
154
|
+
* still be in the future — it is inside the signed payload, so it cannot be
|
|
155
|
+
* stripped or moved without breaking the HMAC.
|
|
156
|
+
*/
|
|
157
|
+
export async function verifyUnsubscribeToken(
|
|
158
|
+
token: string,
|
|
159
|
+
secret: string,
|
|
160
|
+
clock: UnsubscribeTokenClock = {},
|
|
161
|
+
): Promise<UnsubscribePayload | null> {
|
|
162
|
+
if (!token || !secret) return null;
|
|
163
|
+
const dot = token.indexOf(".");
|
|
164
|
+
if (dot <= 0) return null;
|
|
165
|
+
const body = token.slice(0, dot);
|
|
166
|
+
const sig = token.slice(dot + 1);
|
|
167
|
+
const expected = await hmacBase64url(secret, body);
|
|
168
|
+
if (!timingSafeEqual(sig, expected)) return null;
|
|
169
|
+
try {
|
|
170
|
+
const parsed = JSON.parse(base64urlDecodeToString(body)) as {
|
|
171
|
+
e?: unknown;
|
|
172
|
+
p?: unknown;
|
|
173
|
+
exp?: unknown;
|
|
174
|
+
};
|
|
175
|
+
if (typeof parsed.e !== "string" || typeof parsed.p !== "string") return null;
|
|
176
|
+
if (!parsed.e || !parsed.p) return null;
|
|
177
|
+
if (parsed.exp !== undefined) {
|
|
178
|
+
if (typeof parsed.exp !== "number" || !Number.isFinite(parsed.exp)) return null;
|
|
179
|
+
const nowSeconds = Math.floor((clock.now ?? new Date()).getTime() / 1000);
|
|
180
|
+
if (parsed.exp <= nowSeconds) return null;
|
|
181
|
+
}
|
|
182
|
+
return { email: parsed.e, purpose: parsed.p };
|
|
183
|
+
} catch {
|
|
184
|
+
return null;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { Contribution, RequiredSchema } from "@openlup/core/readiness";
|
|
2
|
+
|
|
3
|
+
/** Actual selected callables, supplied by the host; declarations never activate them. */
|
|
4
|
+
export interface CatalogContributionInput {
|
|
5
|
+
version: string;
|
|
6
|
+
requiredSchema: RequiredSchema;
|
|
7
|
+
catalog: Readonly<Record<string, (...args: never[]) => unknown>>;
|
|
8
|
+
pricing: Readonly<Record<string, (...args: never[]) => unknown>>;
|
|
9
|
+
promotions: Readonly<Record<string, (...args: never[]) => unknown>>;
|
|
10
|
+
routes: Contribution["routes"];
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/** Thin structural declarations under the existing logical module identities. */
|
|
14
|
+
export function createCatalogContribution(input: CatalogContributionInput) {
|
|
15
|
+
const contributions: Contribution[] = [];
|
|
16
|
+
const ports: Record<string, unknown> = {};
|
|
17
|
+
for (const module of ["catalog", "pricing", "promotions"] as const) {
|
|
18
|
+
const selected = input[module];
|
|
19
|
+
for (const [name, callable] of Object.entries(selected)) ports[`@openlup/platform/${module}:${name}`] = callable;
|
|
20
|
+
contributions.push({
|
|
21
|
+
manifest: {
|
|
22
|
+
name: "@openlup/platform", version: input.version, kind: "rail",
|
|
23
|
+
module: { id: module, kind: "capability", provides: [`./${module}`], dependsOn: [] },
|
|
24
|
+
emits: [], handles: [], schedules: [], env: [], requiredPorts: Object.keys(selected),
|
|
25
|
+
routes: module === "catalog" ? input.routes.map(route => route.id) : [],
|
|
26
|
+
...(module === "catalog" ? { requiredSchema: input.requiredSchema } : {}),
|
|
27
|
+
},
|
|
28
|
+
handlers: [], schedules: [], routes: module === "catalog" ? input.routes : [],
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
return { contributions, ports, routes: Object.fromEntries(input.routes.map(route => [`@openlup/platform/catalog:${route.id}`, route.handle])) };
|
|
32
|
+
}
|
package/src/composition/index.ts
CHANGED
package/src/http/index.ts
CHANGED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { createHmac, timingSafeEqual } from "node:crypto";
|
|
2
|
+
import type { HttpRequest } from "./types.js";
|
|
3
|
+
|
|
4
|
+
/** Hard cap on raw webhook body bytes — the payment provider events are well under 256 KiB. */
|
|
5
|
+
export const MAX_WEBHOOK_BODY_BYTES = 1_048_576;
|
|
6
|
+
|
|
7
|
+
/** Thrown by readRawBody when the streamed body exceeds MAX_WEBHOOK_BODY_BYTES. */
|
|
8
|
+
export class WebhookBodyTooLargeError extends Error {
|
|
9
|
+
constructor() {
|
|
10
|
+
super("Webhook body exceeds maximum size");
|
|
11
|
+
this.name = "WebhookBodyTooLargeError";
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Reads the exact raw request body bytes for provider webhook signature
|
|
17
|
+
* verification.
|
|
18
|
+
*
|
|
19
|
+
* `@vercel/node` (v3, the builder for `/api` functions in this Vite project)
|
|
20
|
+
* auto-parses `application/json` request bodies into `req.body` and IGNORES the
|
|
21
|
+
* `export const config = { api: { bodyParser: false } }` opt-out — that opt-out
|
|
22
|
+
* is a Next.js Pages Router convention, not a vanilla `@vercel/node` one
|
|
23
|
+
* (verified empirically against the hidden-preview deploy: a JSON payload posted
|
|
24
|
+
* with `Content-Type: application/json` arrives parsed, the same bytes posted as
|
|
25
|
+
* `text/plain` arrive raw). Re-serializing the parsed object with
|
|
26
|
+
* `JSON.stringify` does NOT reproduce the provider's exact bytes — the payment provider signs
|
|
27
|
+
* pretty-printed JSON, so a compacted re-serialization breaks HMAC verification.
|
|
28
|
+
*
|
|
29
|
+
* Reading the underlying request stream FIRST — before touching `req.body`,
|
|
30
|
+
* whose getter triggers the parse that consumes the stream — preserves the exact
|
|
31
|
+
* bytes when the platform parses lazily. When `req` is not a stream (unit tests
|
|
32
|
+
* pass a plain `{ body }` object) or the stream yields nothing (already
|
|
33
|
+
* consumed), we fall back to `req.body`.
|
|
34
|
+
*/
|
|
35
|
+
export async function readRawBody(req: HttpRequest): Promise<string> {
|
|
36
|
+
if (isAsyncIterable(req)) {
|
|
37
|
+
const chunks: Buffer[] = [];
|
|
38
|
+
let total = 0;
|
|
39
|
+
for await (const chunk of req as unknown as AsyncIterable<Buffer | string>) {
|
|
40
|
+
const buf = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
|
|
41
|
+
total += buf.byteLength;
|
|
42
|
+
// Enforce the cap mid-stream so an oversized body is rejected before it is
|
|
43
|
+
// fully buffered into memory, not after.
|
|
44
|
+
if (total > MAX_WEBHOOK_BODY_BYTES) throw new WebhookBodyTooLargeError();
|
|
45
|
+
chunks.push(buf);
|
|
46
|
+
}
|
|
47
|
+
if (chunks.length > 0) return Buffer.concat(chunks).toString("utf8");
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (typeof req.body === "string") return capBody(req.body);
|
|
51
|
+
if (Buffer.isBuffer(req.body)) return capBody(req.body.toString("utf8"));
|
|
52
|
+
if (req.body && typeof req.body === "object") return capBody(JSON.stringify(req.body));
|
|
53
|
+
return "";
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function capBody(body: string): string {
|
|
57
|
+
if (Buffer.byteLength(body, "utf8") > MAX_WEBHOOK_BODY_BYTES) {
|
|
58
|
+
throw new WebhookBodyTooLargeError();
|
|
59
|
+
}
|
|
60
|
+
return body;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function isAsyncIterable(value: unknown): boolean {
|
|
64
|
+
return (
|
|
65
|
+
value != null &&
|
|
66
|
+
typeof (value as { [Symbol.asyncIterator]?: unknown })[Symbol.asyncIterator] ===
|
|
67
|
+
"function"
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export function verifyHmacSignature(input: {
|
|
72
|
+
rawBody: string;
|
|
73
|
+
signatureHeader: string | undefined;
|
|
74
|
+
secret: string;
|
|
75
|
+
}): boolean {
|
|
76
|
+
if (!input.signatureHeader || !input.secret) return false;
|
|
77
|
+
return timingSafeStringEqual(input.signatureHeader, hmac(input.rawBody, input.secret));
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function hmac(value: string, secret: string): string {
|
|
81
|
+
return createHmac("sha256", secret).update(value).digest("hex");
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Constant-time comparison of two shared-secret strings.
|
|
86
|
+
*
|
|
87
|
+
* Exported because it is not payment-specific: any route holding a shared token has to compare it
|
|
88
|
+
* the same way, and a second hand-rolled copy of a security primitive is how one of them quietly
|
|
89
|
+
* stops being constant-time. The length check comes first because `timingSafeEqual` THROWS on a
|
|
90
|
+
* length mismatch rather than returning false, and the length of a shared token is not the secret.
|
|
91
|
+
*/
|
|
92
|
+
export function timingSafeStringEqual(left: string, right: string): boolean {
|
|
93
|
+
const leftBuffer = Buffer.from(left);
|
|
94
|
+
const rightBuffer = Buffer.from(right);
|
|
95
|
+
return leftBuffer.length === rightBuffer.length && timingSafeEqual(leftBuffer, rightBuffer);
|
|
96
|
+
}
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
|
|
3
|
+
import { calculateInventoryAtp, availableNow, INVENTORY_CONTRACT_VERSION, type InventoryStockLine } from "@openlup/core/inventory";
|
|
4
|
+
import type { z } from "zod";
|
|
5
|
+
import { createInventorySubscriptionForecastResponseSchema } from "./schemas.js";
|
|
6
|
+
import {
|
|
7
|
+
type InventorySubscriptionForecastSku,
|
|
8
|
+
} from "./contracts/index.js";
|
|
9
|
+
import {
|
|
10
|
+
InventoryPersistenceError,
|
|
11
|
+
type InventoryMutationPort,
|
|
12
|
+
type InventoryReadPort,
|
|
13
|
+
} from "./ports.js";
|
|
14
|
+
interface PgQueryExecutor {
|
|
15
|
+
query(text: string, values?: unknown[]): Promise<{ rows: Record<string, unknown>[] }>;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const STOCK_SQL = `SELECT sku.id AS sku_id, sku.sku, stock.source_key,
|
|
19
|
+
stock.for_sale_quantity AS on_hand,
|
|
20
|
+
COALESCE((SELECT sum(line.quantity)::integer
|
|
21
|
+
FROM public.fulfillment_inventory_reservation_lines line
|
|
22
|
+
JOIN public.fulfillment_inventory_reservations reservation ON reservation.id = line.reservation_id
|
|
23
|
+
WHERE line.sku = stock.sku AND reservation.source_key = stock.source_key
|
|
24
|
+
AND reservation.status IN ('held', 'committed')), 0) AS reserved,
|
|
25
|
+
stock.last_synced_at, stock.stale_after,
|
|
26
|
+
count(*) OVER() AS total_count
|
|
27
|
+
FROM public.fulfillment_stock_current stock
|
|
28
|
+
JOIN public.catalog_skus sku ON sku.sku = stock.sku
|
|
29
|
+
WHERE ($1::uuid IS NULL OR sku.id = $1::uuid)
|
|
30
|
+
AND ($2::boolean OR stock.for_sale_quantity > 0)
|
|
31
|
+
ORDER BY stock.updated_at DESC, stock.source_key, stock.sku
|
|
32
|
+
LIMIT $3::integer OFFSET $4::integer`;
|
|
33
|
+
|
|
34
|
+
const RESERVATIONS_SQL = `SELECT reservation.id, order_row.id AS order_id, cycle.id AS cycle_id,
|
|
35
|
+
CASE reservation.status
|
|
36
|
+
WHEN 'held' THEN 'reserved' WHEN 'committed' THEN 'reserved'
|
|
37
|
+
ELSE reservation.status END AS status,
|
|
38
|
+
reservation.expires_at, reservation.created_at,
|
|
39
|
+
operation.identity_key, operation.operation_fingerprint, operation.terminal_outcome,
|
|
40
|
+
count(*) OVER() AS total_count
|
|
41
|
+
FROM public.fulfillment_inventory_reservations reservation
|
|
42
|
+
JOIN public.subscription_renewal_operations operation ON operation.id = reservation.renewal_operation_id
|
|
43
|
+
LEFT JOIN public.subscription_cycles cycle ON cycle.renewal_operation_id = operation.id
|
|
44
|
+
LEFT JOIN public.commerce_orders order_row ON order_row.renewal_operation_id = operation.id
|
|
45
|
+
WHERE ($1::text IS NULL OR CASE reservation.status
|
|
46
|
+
WHEN 'held' THEN 'reserved' WHEN 'committed' THEN 'reserved'
|
|
47
|
+
ELSE reservation.status END = $1::text)
|
|
48
|
+
AND ($2::uuid IS NULL OR order_row.id = $2::uuid)
|
|
49
|
+
ORDER BY reservation.created_at DESC, reservation.id
|
|
50
|
+
LIMIT $3::integer OFFSET $4::integer`;
|
|
51
|
+
|
|
52
|
+
const ATP_SQL = `SELECT sku.id AS sku_id, sku.sku, stock.source_key,
|
|
53
|
+
stock.for_sale_quantity AS on_hand,
|
|
54
|
+
COALESCE((SELECT sum(line.quantity)::integer
|
|
55
|
+
FROM public.fulfillment_inventory_reservation_lines line
|
|
56
|
+
JOIN public.fulfillment_inventory_reservations reservation ON reservation.id = line.reservation_id
|
|
57
|
+
WHERE line.sku = stock.sku AND reservation.source_key = stock.source_key
|
|
58
|
+
AND reservation.status IN ('held', 'committed')), 0) AS reserved,
|
|
59
|
+
stock.last_synced_at, stock.stale_after, 0 AS total_count
|
|
60
|
+
FROM public.fulfillment_stock_current stock
|
|
61
|
+
JOIN public.catalog_skus sku ON sku.sku = stock.sku
|
|
62
|
+
WHERE sku.id = ANY($1::uuid[])
|
|
63
|
+
AND stock.inventory_class = 'sellable'
|
|
64
|
+
AND stock.stale_after > $2::timestamptz
|
|
65
|
+
ORDER BY stock.source_key, stock.sku`;
|
|
66
|
+
|
|
67
|
+
const FORECAST_SQL = `WITH forecast_skus AS (
|
|
68
|
+
SELECT line.sku
|
|
69
|
+
FROM public.subscription_renewal_term_lines line
|
|
70
|
+
JOIN public.subscriptions subscription ON subscription.id = line.subscription_id
|
|
71
|
+
WHERE subscription.status = 'active'
|
|
72
|
+
UNION
|
|
73
|
+
SELECT stock.sku
|
|
74
|
+
FROM public.fulfillment_stock_current stock
|
|
75
|
+
WHERE stock.inventory_class = 'sellable'
|
|
76
|
+
), sellable_stock AS (
|
|
77
|
+
SELECT stock.sku,
|
|
78
|
+
sum(stock.for_sale_quantity)::integer AS for_sale_quantity,
|
|
79
|
+
max(stock.last_synced_at) AS last_synced_at,
|
|
80
|
+
min(stock.stale_after) AS stale_after
|
|
81
|
+
FROM public.fulfillment_stock_current stock
|
|
82
|
+
WHERE stock.inventory_class = 'sellable'
|
|
83
|
+
GROUP BY stock.sku
|
|
84
|
+
)
|
|
85
|
+
SELECT sku.id AS sku_id, sku.sku,
|
|
86
|
+
stock.for_sale_quantity, stock.last_synced_at, stock.stale_after,
|
|
87
|
+
COALESCE(reserved.quantity, 0)::integer AS reserved,
|
|
88
|
+
COALESCE(demand.days_30, 0)::integer AS days_30,
|
|
89
|
+
COALESCE(demand.days_45, 0)::integer AS days_45,
|
|
90
|
+
COALESCE(demand.days_60, 0)::integer AS days_60
|
|
91
|
+
FROM forecast_skus forecast
|
|
92
|
+
JOIN public.catalog_skus sku ON sku.sku = forecast.sku
|
|
93
|
+
LEFT JOIN sellable_stock stock ON stock.sku = forecast.sku
|
|
94
|
+
LEFT JOIN LATERAL (
|
|
95
|
+
SELECT sum(line.quantity)::integer AS quantity
|
|
96
|
+
FROM public.fulfillment_inventory_reservation_lines line
|
|
97
|
+
JOIN public.fulfillment_inventory_reservations reservation ON reservation.id = line.reservation_id
|
|
98
|
+
WHERE line.sku = forecast.sku
|
|
99
|
+
AND reservation.status IN ('held', 'committed')) reserved ON true
|
|
100
|
+
LEFT JOIN LATERAL (
|
|
101
|
+
SELECT
|
|
102
|
+
sum(CASE WHEN subscription.next_cycle_at <= $1::timestamptz + interval '30 days' THEN line.quantity ELSE 0 END)::integer AS days_30,
|
|
103
|
+
sum(CASE WHEN subscription.next_cycle_at <= $1::timestamptz + interval '45 days' THEN line.quantity ELSE 0 END)::integer AS days_45,
|
|
104
|
+
sum(CASE WHEN subscription.next_cycle_at <= $1::timestamptz + interval '60 days' THEN line.quantity ELSE 0 END)::integer AS days_60
|
|
105
|
+
FROM public.subscription_renewal_term_lines line
|
|
106
|
+
JOIN public.subscriptions subscription ON subscription.id = line.subscription_id
|
|
107
|
+
WHERE line.sku = forecast.sku AND subscription.status = 'active'
|
|
108
|
+
AND subscription.next_cycle_at <= $1::timestamptz + ($2::integer * interval '1 day')) demand ON true
|
|
109
|
+
ORDER BY sku.sku`;
|
|
110
|
+
|
|
111
|
+
const ACTIVE_SUBSCRIPTION_COUNT_SQL = `SELECT count(*)::integer AS active_subscription_count
|
|
112
|
+
FROM public.subscriptions WHERE status = 'active'`;
|
|
113
|
+
|
|
114
|
+
/** Operator readback over the same public stock and reservation rail used by renewal. */
|
|
115
|
+
export function createPostgresAdminInventoryPort(
|
|
116
|
+
executor: PgQueryExecutor,
|
|
117
|
+
config: { stockMasterProvider: string; providerSchema: z.ZodType<string> },
|
|
118
|
+
now: () => string = () => new Date().toISOString(),
|
|
119
|
+
): InventoryReadPort & InventoryMutationPort {
|
|
120
|
+
const forecastResponseSchema = createInventorySubscriptionForecastResponseSchema(config.providerSchema);
|
|
121
|
+
return {
|
|
122
|
+
async listStock(request) {
|
|
123
|
+
const offset = (request.page - 1) * request.pageSize;
|
|
124
|
+
const result = await executor.query(STOCK_SQL, [
|
|
125
|
+
request.skuId ?? null, request.includeZero, request.pageSize, offset,
|
|
126
|
+
]);
|
|
127
|
+
const stock = result.rows.map(mapStock);
|
|
128
|
+
return {
|
|
129
|
+
contractVersion: INVENTORY_CONTRACT_VERSION,
|
|
130
|
+
stock: stock.map((line) => ({ ...line, availableNow: availableNow(line) })),
|
|
131
|
+
totalCount: count(result.rows[0]), page: request.page, pageSize: request.pageSize,
|
|
132
|
+
};
|
|
133
|
+
},
|
|
134
|
+
|
|
135
|
+
async listReservations(request) {
|
|
136
|
+
const offset = (request.page - 1) * request.pageSize;
|
|
137
|
+
const result = await executor.query(RESERVATIONS_SQL, [
|
|
138
|
+
request.status ?? null, request.orderId ?? null, request.pageSize, offset,
|
|
139
|
+
]);
|
|
140
|
+
return {
|
|
141
|
+
contractVersion: INVENTORY_CONTRACT_VERSION,
|
|
142
|
+
reservations: result.rows.map((row) => ({
|
|
143
|
+
id: text(row.id), orderId: text(row.order_id),
|
|
144
|
+
subscriptionCycleId: nullableText(row.cycle_id),
|
|
145
|
+
status: text(row.status) as "reserved" | "released" | "consumed" | "expired",
|
|
146
|
+
kind: "subscription_retry_window" as const,
|
|
147
|
+
expiresAt: timestampOrNull(row.expires_at), createdAt: timestamp(row.created_at),
|
|
148
|
+
})),
|
|
149
|
+
totalCount: count(result.rows[0]), page: request.page, pageSize: request.pageSize,
|
|
150
|
+
};
|
|
151
|
+
},
|
|
152
|
+
|
|
153
|
+
async checkAtp(request) {
|
|
154
|
+
const result = await executor.query(ATP_SQL, [
|
|
155
|
+
request.lines.map((line) => line.skuId), request.requestedAt,
|
|
156
|
+
]);
|
|
157
|
+
return calculateInventoryAtp({ request, stock: result.rows.map(mapStock) });
|
|
158
|
+
},
|
|
159
|
+
|
|
160
|
+
async forecastSubscriptions(request) {
|
|
161
|
+
const generatedAt = now();
|
|
162
|
+
const result = await executor.query(FORECAST_SQL, [generatedAt, request.horizonDays]);
|
|
163
|
+
const activeSubscriptionResult = await executor.query(ACTIVE_SUBSCRIPTION_COUNT_SQL);
|
|
164
|
+
const skus = result.rows.map((row) => mapForecast(row, generatedAt, request));
|
|
165
|
+
return forecastResponseSchema.parse({
|
|
166
|
+
contractVersion: INVENTORY_CONTRACT_VERSION,
|
|
167
|
+
generatedAt,
|
|
168
|
+
// Compatibility projection required by the existing admin BFF contract;
|
|
169
|
+
// the public tables themselves keep source_key opaque.
|
|
170
|
+
stockMasterProvider: config.stockMasterProvider,
|
|
171
|
+
horizonDays: request.horizonDays,
|
|
172
|
+
protectionDays: request.protectionDays,
|
|
173
|
+
skus,
|
|
174
|
+
totals: {
|
|
175
|
+
activeSubscriptionCount: integer(
|
|
176
|
+
activeSubscriptionResult.rows[0]?.active_subscription_count,
|
|
177
|
+
),
|
|
178
|
+
excludedSubscriptionCount: 0,
|
|
179
|
+
missingProviderStockSkuCount: skus.filter((sku) => sku.stockStatus === "missing").length,
|
|
180
|
+
staleProviderStockSkuCount: skus.filter((sku) => sku.stockStatus === "stale").length,
|
|
181
|
+
horizonShortageSkuCount: skus.filter((sku) => sku.horizonMissingQty > 0).length,
|
|
182
|
+
protectionShortageSkuCount: skus.filter((sku) => sku.protectionMissingQty > 0).length,
|
|
183
|
+
shortageSkuCount: skus.filter((sku) => sku.missingQty > 0).length,
|
|
184
|
+
recommendedProductionQty: skus.reduce((sum, sku) => sum + sku.recommendedProductionQty, 0),
|
|
185
|
+
},
|
|
186
|
+
});
|
|
187
|
+
},
|
|
188
|
+
|
|
189
|
+
async adjustStock() {
|
|
190
|
+
throw new InventoryPersistenceError(
|
|
191
|
+
"Direct stock is externally observed; use the configured stock-source adapter",
|
|
192
|
+
);
|
|
193
|
+
},
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
function mapStock(row: Record<string, unknown>): InventoryStockLine {
|
|
198
|
+
const source = text(row.source_key);
|
|
199
|
+
return {
|
|
200
|
+
skuId: text(row.sku_id), sku: text(row.sku),
|
|
201
|
+
locationId: stableUuid(source), locationCode: source,
|
|
202
|
+
locationKind: "third_party_logistics", locationStatus: "active", fulfillable: true,
|
|
203
|
+
lotId: null, lotCode: null, lotStatus: null, expiresAt: null,
|
|
204
|
+
onHand: integer(row.on_hand), reserved: integer(row.reserved), unavailable: 0,
|
|
205
|
+
incoming: 0, safetyStock: 0,
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
function mapForecast(
|
|
210
|
+
row: Record<string, unknown>,
|
|
211
|
+
generatedAt: string,
|
|
212
|
+
request: { horizonDays: number; protectionDays: number },
|
|
213
|
+
): InventorySubscriptionForecastSku {
|
|
214
|
+
const sellable = Math.max(0, integer(row.for_sale_quantity) - integer(row.reserved));
|
|
215
|
+
const horizonDemand = request.horizonDays <= 30 ? integer(row.days_30)
|
|
216
|
+
: request.horizonDays <= 45 ? integer(row.days_45) : integer(row.days_60);
|
|
217
|
+
const protectionDemand = request.protectionDays <= 30 ? integer(row.days_30)
|
|
218
|
+
: request.protectionDays <= 45 ? integer(row.days_45) : integer(row.days_60);
|
|
219
|
+
const horizonMissingQty = Math.max(0, horizonDemand - sellable);
|
|
220
|
+
const protectionMissingQty = Math.max(0, protectionDemand - sellable);
|
|
221
|
+
const staleAfter = timestampOrNull(row.stale_after);
|
|
222
|
+
const stockStatus = row.for_sale_quantity === null || row.for_sale_quantity === undefined
|
|
223
|
+
? "missing" as const
|
|
224
|
+
: staleAfter && staleAfter <= generatedAt ? "stale" as const : "fresh" as const;
|
|
225
|
+
return {
|
|
226
|
+
skuId: text(row.sku_id), sku: text(row.sku),
|
|
227
|
+
providerCurrentForSale: nullableInteger(row.for_sale_quantity),
|
|
228
|
+
providerStockLastSyncedAt: timestampOrNull(row.last_synced_at),
|
|
229
|
+
providerStockStaleAfter: staleAfter, stockStatus,
|
|
230
|
+
openHardReservations: integer(row.reserved), safetyStock: 0, sellableNow: sellable,
|
|
231
|
+
activeSubscriptionDemand30: integer(row.days_30),
|
|
232
|
+
activeSubscriptionDemand45: integer(row.days_45),
|
|
233
|
+
activeSubscriptionDemand60: integer(row.days_60), plannedSupply: 0,
|
|
234
|
+
coverageDays: null, shortageDate: null,
|
|
235
|
+
horizonMissingQty, protectionMissingQty,
|
|
236
|
+
missingQty: Math.max(horizonMissingQty, protectionMissingQty),
|
|
237
|
+
recommendedProductionQty: Math.max(horizonMissingQty, protectionMissingQty),
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
function stableUuid(value: string): string {
|
|
242
|
+
const hash = createHash("sha256").update(`inventory-source:${value}`).digest("hex");
|
|
243
|
+
return `${hash.slice(0, 8)}-${hash.slice(8, 12)}-4${hash.slice(13, 16)}-8${hash.slice(17, 20)}-${hash.slice(20, 32)}`;
|
|
244
|
+
}
|
|
245
|
+
function text(value: unknown): string { return typeof value === "string" ? value : String(value ?? ""); }
|
|
246
|
+
function nullableText(value: unknown): string | null { const result = text(value).trim(); return result || null; }
|
|
247
|
+
function integer(value: unknown): number { const result = Number(value); return Number.isSafeInteger(result) && result >= 0 ? result : 0; }
|
|
248
|
+
function nullableInteger(value: unknown): number | null { return value === null || value === undefined ? null : integer(value); }
|
|
249
|
+
function count(row: Record<string, unknown> | undefined): number { return row ? integer(row.total_count) : 0; }
|
|
250
|
+
function timestamp(value: unknown): string { return value instanceof Date ? value.toISOString() : text(value); }
|
|
251
|
+
function timestampOrNull(value: unknown): string | null { return value === null || value === undefined ? null : timestamp(value); }
|