@openlup/platform 0.17.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.
Files changed (486) hide show
  1. package/CHANGELOG.md +96 -0
  2. package/README.md +284 -6
  3. package/dist/catalog/activeSkuSelection.d.ts +2 -0
  4. package/dist/catalog/activeSkuSelection.js +20 -0
  5. package/dist/catalog/adminBindings.d.ts +72 -0
  6. package/dist/catalog/adminBindings.js +1 -0
  7. package/dist/catalog/adminBundleHandler.d.ts +26 -0
  8. package/dist/catalog/adminBundleHandler.js +111 -0
  9. package/dist/catalog/adminBundleReadHandler.d.ts +20 -0
  10. package/dist/catalog/adminBundleReadHandler.js +185 -0
  11. package/dist/catalog/adminBundleWritePort.d.ts +85 -0
  12. package/dist/catalog/adminBundleWritePort.js +1 -0
  13. package/dist/catalog/bundleAvailability.d.ts +63 -0
  14. package/dist/catalog/bundleAvailability.js +78 -0
  15. package/dist/catalog/bundleAvailabilityService.d.ts +65 -0
  16. package/dist/catalog/bundleAvailabilityService.js +89 -0
  17. package/dist/catalog/bundleBindings.d.ts +33 -0
  18. package/dist/catalog/bundleBindings.js +1 -0
  19. package/dist/catalog/bundleCatalogQueries.d.ts +28 -0
  20. package/dist/catalog/bundleCatalogQueries.js +84 -0
  21. package/dist/catalog/bundleCatalogReadPort.d.ts +166 -0
  22. package/dist/catalog/bundleCatalogReadPort.js +36 -0
  23. package/dist/catalog/bundleCatalogStore.d.ts +3 -0
  24. package/dist/catalog/bundleCatalogStore.js +152 -0
  25. package/dist/catalog/bundleRuleCodes.d.ts +41 -0
  26. package/dist/catalog/bundleRuleCodes.js +110 -0
  27. package/dist/catalog/bundleRules.d.ts +69 -0
  28. package/dist/catalog/bundleRules.js +102 -0
  29. package/dist/catalog/catalogDraftStore.d.ts +4 -0
  30. package/dist/catalog/catalogDraftStore.js +63 -0
  31. package/dist/catalog/catalogSkuEnvelope.d.ts +7 -0
  32. package/dist/catalog/catalogSkuEnvelope.js +142 -0
  33. package/dist/catalog/catalogSkuEnvelopeMapper.d.ts +38 -0
  34. package/dist/catalog/catalogSkuEnvelopeMapper.js +88 -0
  35. package/dist/catalog/contracts/bundleAdmin.d.ts +143 -0
  36. package/dist/catalog/contracts/bundleAdmin.js +1 -0
  37. package/dist/catalog/contracts/bundleAvailability.d.ts +61 -0
  38. package/dist/catalog/contracts/bundleAvailability.js +1 -0
  39. package/dist/catalog/contracts/bundleRead.d.ts +223 -0
  40. package/dist/catalog/contracts/bundleRead.js +1 -0
  41. package/dist/catalog/contracts/draft.d.ts +79 -0
  42. package/dist/catalog/contracts/draft.js +47 -0
  43. package/dist/catalog/contracts/foundation.d.ts +78 -0
  44. package/dist/catalog/contracts/foundation.js +53 -0
  45. package/dist/catalog/contracts/index.d.ts +14 -0
  46. package/dist/catalog/contracts/index.js +6 -0
  47. package/dist/catalog/contracts/lifecycle.d.ts +77 -0
  48. package/dist/catalog/contracts/lifecycle.js +1 -0
  49. package/dist/catalog/contracts/productMediaContracts.d.ts +77 -0
  50. package/dist/catalog/contracts/productMediaContracts.js +149 -0
  51. package/dist/catalog/contracts/productTypes.d.ts +54 -0
  52. package/dist/catalog/contracts/productTypes.js +16 -0
  53. package/dist/catalog/contracts/resolveProductMedia.d.ts +3 -0
  54. package/dist/catalog/contracts/resolveProductMedia.js +78 -0
  55. package/dist/catalog/contracts/sellable.d.ts +23 -0
  56. package/dist/catalog/contracts/sellable.js +1 -0
  57. package/dist/catalog/draftHandler.d.ts +25 -0
  58. package/dist/catalog/draftHandler.js +118 -0
  59. package/dist/catalog/draftPorts.d.ts +18 -0
  60. package/dist/catalog/draftPorts.js +8 -0
  61. package/dist/catalog/draftSchemas.d.ts +423 -0
  62. package/dist/catalog/draftSchemas.js +89 -0
  63. package/dist/catalog/draftValidation.d.ts +21 -0
  64. package/dist/catalog/draftValidation.js +125 -0
  65. package/dist/catalog/foundationSchemas.d.ts +98 -0
  66. package/dist/catalog/foundationSchemas.js +110 -0
  67. package/dist/catalog/index.d.ts +43 -0
  68. package/dist/catalog/index.js +25 -0
  69. package/dist/catalog/mediaSourcePack.d.ts +51 -0
  70. package/dist/catalog/mediaSourcePack.js +247 -0
  71. package/dist/catalog/productTypeSchemas.d.ts +46 -0
  72. package/dist/catalog/productTypeSchemas.js +72 -0
  73. package/dist/catalog/publicationPorts.d.ts +42 -0
  74. package/dist/catalog/publicationPorts.js +1 -0
  75. package/dist/catalog/readPorts.d.ts +51 -0
  76. package/dist/catalog/readPorts.js +1 -0
  77. package/dist/catalog/referenceCatalogHandler.d.ts +7 -0
  78. package/dist/catalog/referenceCatalogHandler.js +27 -0
  79. package/dist/catalog/resolvedSkuProjection.d.ts +88 -0
  80. package/dist/catalog/resolvedSkuProjection.js +60 -0
  81. package/dist/catalog/sellableBundleHandler.d.ts +46 -0
  82. package/dist/catalog/sellableBundleHandler.js +84 -0
  83. package/dist/catalog/sellableSchemas.d.ts +46 -0
  84. package/dist/catalog/sellableSchemas.js +27 -0
  85. package/dist/catalog/sql.d.ts +46 -0
  86. package/dist/catalog/sql.js +13 -0
  87. package/dist/catalog/validation.d.ts +2 -0
  88. package/dist/catalog/validation.js +3 -0
  89. package/dist/communications/contracts/index.d.ts +1 -0
  90. package/dist/communications/contracts/marketingSync.d.ts +194 -0
  91. package/dist/communications/contracts/marketingSync.js +1 -0
  92. package/dist/communications/index.d.ts +1 -0
  93. package/dist/communications/klaviyo/consentPush.d.ts +51 -0
  94. package/dist/communications/klaviyo/consentPush.js +19 -0
  95. package/dist/communications/klaviyo/index.d.ts +110 -0
  96. package/dist/communications/klaviyo/index.js +860 -0
  97. package/dist/communications/newsletterIntegrationContracts.d.ts +3 -3
  98. package/dist/communications/resend/index.d.ts +40 -0
  99. package/dist/communications/resend/index.js +310 -0
  100. package/dist/composition/catalogContribution.d.ts +18 -0
  101. package/dist/composition/catalogContribution.js +21 -0
  102. package/dist/composition/index.d.ts +1 -0
  103. package/dist/composition/index.js +1 -0
  104. package/dist/identity/customerContracts.d.ts +2 -2
  105. package/dist/inventory/adminInventory.d.ts +13 -0
  106. package/dist/inventory/adminInventory.js +214 -0
  107. package/dist/inventory/contracts/forecast.d.ts +86 -0
  108. package/dist/inventory/contracts/forecast.js +1 -0
  109. package/dist/inventory/contracts/index.d.ts +4 -0
  110. package/dist/inventory/contracts/index.js +1 -0
  111. package/dist/inventory/contracts/inventory.d.ts +157 -0
  112. package/dist/inventory/contracts/inventory.js +1 -0
  113. package/dist/inventory/contracts/newPurchaseStock.d.ts +20 -0
  114. package/dist/inventory/contracts/newPurchaseStock.js +1 -0
  115. package/dist/inventory/contracts/reservation.d.ts +18 -0
  116. package/dist/inventory/contracts/reservation.js +1 -0
  117. package/dist/inventory/forecast.d.ts +24 -0
  118. package/dist/inventory/forecast.js +200 -0
  119. package/dist/inventory/index.d.ts +13 -0
  120. package/dist/inventory/index.js +10 -0
  121. package/dist/inventory/inventoryHandlers.d.ts +53 -0
  122. package/dist/inventory/inventoryHandlers.js +151 -0
  123. package/dist/inventory/newPurchaseStockAvailability.d.ts +47 -0
  124. package/dist/inventory/newPurchaseStockAvailability.js +75 -0
  125. package/dist/inventory/ports.d.ts +21 -0
  126. package/dist/inventory/ports.js +16 -0
  127. package/dist/inventory/renewalReservation.d.ts +27 -0
  128. package/dist/inventory/renewalReservation.js +61 -0
  129. package/dist/inventory/reservationPolicy.d.ts +6 -0
  130. package/dist/inventory/reservationPolicy.js +19 -0
  131. package/dist/inventory/schemas.d.ts +137 -0
  132. package/dist/inventory/schemas.js +112 -0
  133. package/dist/inventory/sql.d.ts +14 -0
  134. package/dist/inventory/sql.js +5 -0
  135. package/dist/inventory/subscriptionForecastCalculation.d.ts +4 -0
  136. package/dist/inventory/subscriptionForecastCalculation.js +133 -0
  137. package/dist/pricing/acquisitionFinancialPolicy.d.ts +26 -0
  138. package/dist/pricing/acquisitionFinancialPolicy.js +1 -0
  139. package/dist/pricing/acquisitionOfferPricing.d.ts +27 -0
  140. package/dist/pricing/acquisitionOfferPricing.js +25 -0
  141. package/dist/pricing/acquisitionOfferPricingHandler.d.ts +20 -0
  142. package/dist/pricing/acquisitionOfferPricingHandler.js +105 -0
  143. package/dist/pricing/acquisitionOfferPricingSchemas.d.ts +31 -0
  144. package/dist/pricing/acquisitionOfferPricingSchemas.js +33 -0
  145. package/dist/pricing/acquisitionQuoteBinding.d.ts +12 -0
  146. package/dist/pricing/acquisitionQuoteBinding.js +12 -0
  147. package/dist/pricing/acquisitionReadiness.d.ts +31 -0
  148. package/dist/pricing/acquisitionReadiness.js +117 -0
  149. package/dist/pricing/acquisitionTerms.d.ts +19 -0
  150. package/dist/pricing/acquisitionTerms.js +126 -0
  151. package/dist/pricing/acquisitionTermsSchemas.d.ts +59 -0
  152. package/dist/pricing/acquisitionTermsSchemas.js +42 -0
  153. package/dist/pricing/catalogFactsProvenance.d.ts +33 -0
  154. package/dist/pricing/catalogFactsProvenance.js +64 -0
  155. package/dist/pricing/catalogFactsSchemas.d.ts +45 -0
  156. package/dist/pricing/catalogFactsSchemas.js +58 -0
  157. package/dist/pricing/commerceOfferPricing.d.ts +25 -0
  158. package/dist/pricing/commerceOfferPricing.js +139 -0
  159. package/dist/pricing/commerceOfferPricingCache.d.ts +10 -0
  160. package/dist/pricing/commerceOfferPricingCache.js +44 -0
  161. package/dist/pricing/commerceOfferPricingHandler.d.ts +21 -0
  162. package/dist/pricing/commerceOfferPricingHandler.js +78 -0
  163. package/dist/pricing/commercePriceAuthority.d.ts +26 -0
  164. package/dist/pricing/commercePriceAuthority.js +79 -0
  165. package/dist/pricing/commercePricingPolicyErrors.d.ts +40 -0
  166. package/dist/pricing/commercePricingPolicyErrors.js +67 -0
  167. package/dist/pricing/commerceQuoteBatchHandler.d.ts +37 -0
  168. package/dist/pricing/commerceQuoteBatchHandler.js +83 -0
  169. package/dist/pricing/commerceQuoteCatalogReadPort.d.ts +27 -0
  170. package/dist/pricing/commerceQuoteCatalogReadPort.js +8 -0
  171. package/dist/pricing/commerceQuoteHandler.d.ts +31 -0
  172. package/dist/pricing/commerceQuoteHandler.js +110 -0
  173. package/dist/pricing/commerceQuoteSnapshotExpect.d.ts +9 -0
  174. package/dist/pricing/commerceQuoteSnapshotExpect.js +22 -0
  175. package/dist/pricing/contracts/acquisitionTerms.d.ts +32 -0
  176. package/dist/pricing/contracts/acquisitionTerms.js +2 -0
  177. package/dist/pricing/contracts/authority.d.ts +27 -0
  178. package/dist/pricing/contracts/authority.js +1 -0
  179. package/dist/pricing/contracts/evidence.d.ts +33 -0
  180. package/dist/pricing/contracts/evidence.js +1 -0
  181. package/dist/pricing/contracts/index.d.ts +17 -0
  182. package/dist/pricing/contracts/index.js +7 -0
  183. package/dist/pricing/contracts/money.d.ts +27 -0
  184. package/dist/pricing/contracts/money.js +1 -0
  185. package/dist/pricing/contracts/offer.d.ts +52 -0
  186. package/dist/pricing/contracts/offer.js +4 -0
  187. package/dist/pricing/contracts/offerPolicy.d.ts +16 -0
  188. package/dist/pricing/contracts/offerPolicy.js +5 -0
  189. package/dist/pricing/contracts/policy.d.ts +22 -0
  190. package/dist/pricing/contracts/policy.js +3 -0
  191. package/dist/pricing/contracts/provenance.d.ts +24 -0
  192. package/dist/pricing/contracts/provenance.js +2 -0
  193. package/dist/pricing/contracts/quote.d.ts +94 -0
  194. package/dist/pricing/contracts/quote.js +1 -0
  195. package/dist/pricing/dbBackedCommerceQuoteHelpers.d.ts +78 -0
  196. package/dist/pricing/dbBackedCommerceQuoteHelpers.js +146 -0
  197. package/dist/pricing/dbBackedCommerceQuotePort.d.ts +66 -0
  198. package/dist/pricing/dbBackedCommerceQuotePort.js +206 -0
  199. package/dist/pricing/dbBackedCommerceQuoteSnapshotVerifier.d.ts +4 -0
  200. package/dist/pricing/dbBackedCommerceQuoteSnapshotVerifier.js +25 -0
  201. package/dist/pricing/index.d.ts +51 -0
  202. package/dist/pricing/index.js +36 -0
  203. package/dist/pricing/offerPolicyReadiness.d.ts +21 -0
  204. package/dist/pricing/offerPolicyReadiness.js +79 -0
  205. package/dist/pricing/offerPolicySchemas.d.ts +25 -0
  206. package/dist/pricing/offerPolicySchemas.js +15 -0
  207. package/dist/pricing/offerPricingSchemas.d.ts +315 -0
  208. package/dist/pricing/offerPricingSchemas.js +65 -0
  209. package/dist/pricing/ports.d.ts +13 -0
  210. package/dist/pricing/ports.js +9 -0
  211. package/dist/pricing/pricingPolicyToken.d.ts +39 -0
  212. package/dist/pricing/pricingPolicyToken.js +84 -0
  213. package/dist/pricing/quoteAcquisitionTerms.d.ts +2 -0
  214. package/dist/pricing/quoteAcquisitionTerms.js +4 -0
  215. package/dist/pricing/quoteCodeRejectionDetails.d.ts +20 -0
  216. package/dist/pricing/quoteCodeRejectionDetails.js +22 -0
  217. package/dist/pricing/quotePorts.d.ts +30 -0
  218. package/dist/pricing/quotePorts.js +20 -0
  219. package/dist/pricing/quotePrimitives.d.ts +13 -0
  220. package/dist/pricing/quotePrimitives.js +18 -0
  221. package/dist/pricing/quotePromotionEvidence.d.ts +39 -0
  222. package/dist/pricing/quotePromotionEvidence.js +73 -0
  223. package/dist/pricing/quoteSchemas.d.ts +1176 -0
  224. package/dist/pricing/quoteSchemas.js +196 -0
  225. package/dist/pricing/subscriptionPricePolicy.d.ts +52 -0
  226. package/dist/pricing/subscriptionPricePolicy.js +96 -0
  227. package/dist/pricing/taxProfileGuard.d.ts +2 -0
  228. package/dist/pricing/taxProfileGuard.js +24 -0
  229. package/dist/pricing/validation.d.ts +2 -0
  230. package/dist/pricing/validation.js +3 -0
  231. package/dist/promotions/adminBindings.d.ts +72 -0
  232. package/dist/promotions/adminBindings.js +1 -0
  233. package/dist/promotions/adminPromotionCodesContracts.d.ts +498 -0
  234. package/dist/promotions/adminPromotionCodesContracts.js +211 -0
  235. package/dist/promotions/adminPromotionCodesDataPort.d.ts +47 -0
  236. package/dist/promotions/adminPromotionCodesDataPort.js +1 -0
  237. package/dist/promotions/adminPromotionCodesHandler.d.ts +14 -0
  238. package/dist/promotions/adminPromotionCodesHandler.js +194 -0
  239. package/dist/promotions/adminPromotionsContracts.d.ts +235 -0
  240. package/dist/promotions/adminPromotionsContracts.js +99 -0
  241. package/dist/promotions/adminPromotionsDataPort.d.ts +42 -0
  242. package/dist/promotions/adminPromotionsDataPort.js +1 -0
  243. package/dist/promotions/adminPromotionsHandler.d.ts +16 -0
  244. package/dist/promotions/adminPromotionsHandler.js +47 -0
  245. package/dist/promotions/contracts/index.d.ts +387 -0
  246. package/dist/promotions/contracts/index.js +1 -0
  247. package/dist/promotions/index.d.ts +22 -0
  248. package/dist/promotions/index.js +21 -0
  249. package/dist/promotions/promoDataPort.d.ts +47 -0
  250. package/dist/promotions/promoDataPort.js +14 -0
  251. package/dist/promotions/promotionAcceptanceTelemetry.d.ts +29 -0
  252. package/dist/promotions/promotionAcceptanceTelemetry.js +45 -0
  253. package/dist/promotions/promotionBenefitDefinition.d.ts +37 -0
  254. package/dist/promotions/promotionBenefitDefinition.js +33 -0
  255. package/dist/promotions/promotionClaimSweepPort.d.ts +14 -0
  256. package/dist/promotions/promotionClaimSweepPort.js +8 -0
  257. package/dist/promotions/promotionClaims.d.ts +5 -0
  258. package/dist/promotions/promotionClaims.js +57 -0
  259. package/dist/promotions/promotionCodePreview.d.ts +11 -0
  260. package/dist/promotions/promotionCodePreview.js +154 -0
  261. package/dist/promotions/promotionCodeQuotePort.d.ts +25 -0
  262. package/dist/promotions/promotionCodeQuotePort.js +1 -0
  263. package/dist/promotions/promotionQuoteAcceptance.d.ts +65 -0
  264. package/dist/promotions/promotionQuoteAcceptance.js +202 -0
  265. package/dist/promotions/promotionQuoteBinding.d.ts +71 -0
  266. package/dist/promotions/promotionQuoteBinding.js +85 -0
  267. package/dist/promotions/quoteAutomaticPromotions.d.ts +24 -0
  268. package/dist/promotions/quoteAutomaticPromotions.js +36 -0
  269. package/dist/promotions/quotePromoDiscounts.d.ts +32 -0
  270. package/dist/promotions/quotePromoDiscounts.js +140 -0
  271. package/dist/promotions/quotePromotionCodeAdjustments.d.ts +27 -0
  272. package/dist/promotions/quotePromotionCodeAdjustments.js +223 -0
  273. package/dist/promotions/quotePromotionV2.d.ts +29 -0
  274. package/dist/promotions/quotePromotionV2.js +174 -0
  275. package/dist/promotions/sql.d.ts +14 -0
  276. package/dist/promotions/sql.js +5 -0
  277. package/dist/promotions/validation.d.ts +2 -0
  278. package/dist/promotions/validation.js +3 -0
  279. package/dist/shipping/addressCanonLookupHandler.d.ts +7 -0
  280. package/dist/shipping/addressCanonLookupHandler.js +105 -0
  281. package/dist/shipping/addressCanonical.d.ts +2 -0
  282. package/dist/shipping/addressCanonical.js +26 -0
  283. package/dist/shipping/addressPorts.d.ts +39 -0
  284. package/dist/shipping/addressPorts.js +1 -0
  285. package/dist/shipping/addressSchemas.d.ts +30 -0
  286. package/dist/shipping/addressSchemas.js +1 -0
  287. package/dist/shipping/adminShippingRateHandler.d.ts +4 -0
  288. package/dist/shipping/adminShippingRateHandler.js +64 -0
  289. package/dist/shipping/contracts/address.d.ts +144 -0
  290. package/dist/shipping/contracts/address.js +1 -0
  291. package/dist/shipping/contracts/delivery.d.ts +110 -0
  292. package/dist/shipping/contracts/delivery.js +1 -0
  293. package/dist/shipping/contracts/index.d.ts +3 -0
  294. package/dist/shipping/contracts/index.js +1 -0
  295. package/dist/shipping/contracts/shippingRate.d.ts +11 -0
  296. package/dist/shipping/contracts/shippingRate.js +1 -0
  297. package/dist/shipping/customerAddressesHandler.d.ts +5 -0
  298. package/dist/shipping/customerAddressesHandler.js +80 -0
  299. package/dist/shipping/customerSelfServiceAddressModels.d.ts +27 -0
  300. package/dist/shipping/customerSelfServiceAddressModels.js +101 -0
  301. package/dist/shipping/deliverySelectionHandler.d.ts +10 -0
  302. package/dist/shipping/deliverySelectionHandler.js +77 -0
  303. package/dist/shipping/deliverySelectionPort.d.ts +8 -0
  304. package/dist/shipping/deliverySelectionPort.js +1 -0
  305. package/dist/shipping/deliverySelectionSummary.d.ts +2 -0
  306. package/dist/shipping/deliverySelectionSummary.js +53 -0
  307. package/dist/shipping/handlerSchemas.d.ts +21 -0
  308. package/dist/shipping/handlerSchemas.js +1 -0
  309. package/dist/shipping/index.d.ts +17 -0
  310. package/dist/shipping/index.js +8 -0
  311. package/dist/shipping/pickupPointSearchPort.d.ts +4 -0
  312. package/dist/shipping/pickupPointSearchPort.js +1 -0
  313. package/dist/shipping/readDeliverySelectionEvidence.d.ts +2 -0
  314. package/dist/shipping/readDeliverySelectionEvidence.js +44 -0
  315. package/dist/shipping/shippingRatePorts.d.ts +52 -0
  316. package/dist/shipping/shippingRatePorts.js +1 -0
  317. package/package.json +62 -2
  318. package/release-gates.json +218 -10
  319. package/sql/20260807140000_read_parity_catalog.sql +94 -0
  320. package/sql/20260810120000_storefront_catalog_attributes.sql +51 -0
  321. package/sql/20260812140000_sellable_bundle_catalog.sql +124 -0
  322. package/sql/20260812210000_bundle_operator_write_boundary.sql +567 -0
  323. package/sql/20260814000000_fulfillment_stock_evidence.sql +239 -0
  324. package/sql/20260815120000_automatic_subscription_renewal.sql +1083 -0
  325. package/sql/20260817180000_promotion_claim_lifecycle.sql +591 -0
  326. package/sql/20260817180100_promotion_claim_lifecycle_validation.sql +23 -0
  327. package/sql/20260827220000_catalog_document_revision_foundation.sql +226 -0
  328. package/sql/20260827220001_catalog_document_revision_foundation_validate.sql +10 -0
  329. package/sql/20260908100000_catalog_draft_foundation.sql +217 -0
  330. package/src/catalog/activeSkuSelection.ts +20 -0
  331. package/src/catalog/adminBindings.ts +59 -0
  332. package/src/catalog/adminBundleHandler.ts +165 -0
  333. package/src/catalog/adminBundleReadHandler.ts +261 -0
  334. package/src/catalog/adminBundleWritePort.ts +102 -0
  335. package/src/catalog/bundleAvailability.ts +129 -0
  336. package/src/catalog/bundleAvailabilityService.ts +171 -0
  337. package/src/catalog/bundleBindings.ts +29 -0
  338. package/src/catalog/bundleCatalogQueries.ts +98 -0
  339. package/src/catalog/bundleCatalogReadPort.ts +177 -0
  340. package/src/catalog/bundleCatalogStore.ts +269 -0
  341. package/src/catalog/bundleRuleCodes.ts +134 -0
  342. package/src/catalog/bundleRules.ts +153 -0
  343. package/src/catalog/catalogDraftStore.ts +71 -0
  344. package/src/catalog/catalogSkuEnvelope.ts +214 -0
  345. package/src/catalog/catalogSkuEnvelopeMapper.ts +160 -0
  346. package/src/catalog/contracts/bundleAdmin.ts +20 -0
  347. package/src/catalog/contracts/bundleAvailability.ts +5 -0
  348. package/src/catalog/contracts/bundleRead.ts +13 -0
  349. package/src/catalog/contracts/draft.ts +69 -0
  350. package/src/catalog/contracts/foundation.ts +104 -0
  351. package/src/catalog/contracts/index.ts +14 -0
  352. package/src/catalog/contracts/lifecycle.ts +74 -0
  353. package/src/catalog/contracts/productMediaContracts.ts +170 -0
  354. package/src/catalog/contracts/productTypes.ts +35 -0
  355. package/src/catalog/contracts/resolveProductMedia.ts +85 -0
  356. package/src/catalog/contracts/sellable.ts +12 -0
  357. package/src/catalog/draftHandler.ts +105 -0
  358. package/src/catalog/draftPorts.ts +18 -0
  359. package/src/catalog/draftSchemas.ts +88 -0
  360. package/src/catalog/draftValidation.ts +100 -0
  361. package/src/catalog/foundationSchemas.ts +123 -0
  362. package/src/catalog/index.ts +43 -0
  363. package/src/catalog/mediaSourcePack.ts +219 -0
  364. package/src/catalog/productTypeSchemas.ts +70 -0
  365. package/src/catalog/publicationPorts.ts +44 -0
  366. package/src/catalog/readPorts.ts +61 -0
  367. package/src/catalog/referenceCatalogHandler.ts +39 -0
  368. package/src/catalog/resolvedSkuProjection.ts +76 -0
  369. package/src/catalog/sellableBundleHandler.ts +133 -0
  370. package/src/catalog/sellableSchemas.ts +33 -0
  371. package/src/catalog/sql.ts +14 -0
  372. package/src/catalog/validation.ts +3 -0
  373. package/src/communications/contracts/index.ts +1 -0
  374. package/src/communications/contracts/marketingSync.ts +109 -0
  375. package/src/communications/index.ts +1 -0
  376. package/src/communications/klaviyo/consentPush.ts +19 -0
  377. package/src/communications/klaviyo/index.ts +649 -0
  378. package/src/communications/resend/index.ts +350 -0
  379. package/src/composition/catalogContribution.ts +32 -0
  380. package/src/composition/index.ts +1 -0
  381. package/src/inventory/adminInventory.ts +251 -0
  382. package/src/inventory/contracts/forecast.ts +96 -0
  383. package/src/inventory/contracts/index.ts +18 -0
  384. package/src/inventory/contracts/inventory.ts +14 -0
  385. package/src/inventory/contracts/newPurchaseStock.ts +23 -0
  386. package/src/inventory/contracts/reservation.ts +20 -0
  387. package/src/inventory/forecast.ts +239 -0
  388. package/src/inventory/index.ts +21 -0
  389. package/src/inventory/inventoryHandlers.ts +215 -0
  390. package/src/inventory/newPurchaseStockAvailability.ts +120 -0
  391. package/src/inventory/ports.ts +46 -0
  392. package/src/inventory/renewalReservation.ts +88 -0
  393. package/src/inventory/reservationPolicy.ts +27 -0
  394. package/src/inventory/schemas.ts +128 -0
  395. package/src/inventory/sql.ts +5 -0
  396. package/src/inventory/subscriptionForecastCalculation.ts +157 -0
  397. package/src/pricing/acquisitionFinancialPolicy.ts +26 -0
  398. package/src/pricing/acquisitionOfferPricing.ts +38 -0
  399. package/src/pricing/acquisitionOfferPricingHandler.ts +157 -0
  400. package/src/pricing/acquisitionOfferPricingSchemas.ts +35 -0
  401. package/src/pricing/acquisitionQuoteBinding.ts +12 -0
  402. package/src/pricing/acquisitionReadiness.ts +148 -0
  403. package/src/pricing/acquisitionTerms.ts +125 -0
  404. package/src/pricing/acquisitionTermsSchemas.ts +52 -0
  405. package/src/pricing/catalogFactsProvenance.ts +102 -0
  406. package/src/pricing/catalogFactsSchemas.ts +69 -0
  407. package/src/pricing/commerceOfferPricing.ts +224 -0
  408. package/src/pricing/commerceOfferPricingCache.ts +53 -0
  409. package/src/pricing/commerceOfferPricingHandler.ts +137 -0
  410. package/src/pricing/commercePriceAuthority.ts +104 -0
  411. package/src/pricing/commercePricingPolicyErrors.ts +88 -0
  412. package/src/pricing/commerceQuoteBatchHandler.ts +129 -0
  413. package/src/pricing/commerceQuoteCatalogReadPort.ts +42 -0
  414. package/src/pricing/commerceQuoteHandler.ts +184 -0
  415. package/src/pricing/commerceQuoteSnapshotExpect.ts +48 -0
  416. package/src/pricing/contracts/acquisitionTerms.ts +26 -0
  417. package/src/pricing/contracts/authority.ts +44 -0
  418. package/src/pricing/contracts/evidence.ts +25 -0
  419. package/src/pricing/contracts/index.ts +17 -0
  420. package/src/pricing/contracts/money.ts +32 -0
  421. package/src/pricing/contracts/offer.ts +42 -0
  422. package/src/pricing/contracts/offerPolicy.ts +17 -0
  423. package/src/pricing/contracts/policy.ts +26 -0
  424. package/src/pricing/contracts/provenance.ts +19 -0
  425. package/src/pricing/contracts/quote.ts +106 -0
  426. package/src/pricing/dbBackedCommerceQuoteHelpers.ts +256 -0
  427. package/src/pricing/dbBackedCommerceQuotePort.ts +260 -0
  428. package/src/pricing/dbBackedCommerceQuoteSnapshotVerifier.ts +49 -0
  429. package/src/pricing/index.ts +52 -0
  430. package/src/pricing/offerPolicyReadiness.ts +110 -0
  431. package/src/pricing/offerPolicySchemas.ts +23 -0
  432. package/src/pricing/offerPricingSchemas.ts +92 -0
  433. package/src/pricing/ports.ts +17 -0
  434. package/src/pricing/pricingPolicyToken.ts +119 -0
  435. package/src/pricing/quoteAcquisitionTerms.ts +10 -0
  436. package/src/pricing/quoteCodeRejectionDetails.ts +23 -0
  437. package/src/pricing/quotePorts.ts +58 -0
  438. package/src/pricing/quotePrimitives.ts +21 -0
  439. package/src/pricing/quotePromotionEvidence.ts +82 -0
  440. package/src/pricing/quoteSchemas.ts +230 -0
  441. package/src/pricing/subscriptionPricePolicy.ts +113 -0
  442. package/src/pricing/taxProfileGuard.ts +33 -0
  443. package/src/pricing/validation.ts +3 -0
  444. package/src/promotions/adminBindings.ts +53 -0
  445. package/src/promotions/adminPromotionCodesContracts.ts +244 -0
  446. package/src/promotions/adminPromotionCodesDataPort.ts +56 -0
  447. package/src/promotions/adminPromotionCodesHandler.ts +254 -0
  448. package/src/promotions/adminPromotionsContracts.ts +121 -0
  449. package/src/promotions/adminPromotionsDataPort.ts +48 -0
  450. package/src/promotions/adminPromotionsHandler.ts +72 -0
  451. package/src/promotions/contracts/index.ts +387 -0
  452. package/src/promotions/index.ts +22 -0
  453. package/src/promotions/promoDataPort.ts +65 -0
  454. package/src/promotions/promotionAcceptanceTelemetry.ts +73 -0
  455. package/src/promotions/promotionBenefitDefinition.ts +48 -0
  456. package/src/promotions/promotionClaimSweepPort.ts +23 -0
  457. package/src/promotions/promotionClaims.ts +70 -0
  458. package/src/promotions/promotionCodePreview.ts +183 -0
  459. package/src/promotions/promotionCodeQuotePort.ts +35 -0
  460. package/src/promotions/promotionQuoteAcceptance.ts +284 -0
  461. package/src/promotions/promotionQuoteBinding.ts +158 -0
  462. package/src/promotions/quoteAutomaticPromotions.ts +58 -0
  463. package/src/promotions/quotePromoDiscounts.ts +185 -0
  464. package/src/promotions/quotePromotionCodeAdjustments.ts +277 -0
  465. package/src/promotions/quotePromotionV2.ts +223 -0
  466. package/src/promotions/sql.ts +5 -0
  467. package/src/promotions/validation.ts +3 -0
  468. package/src/shipping/addressCanonLookupHandler.ts +114 -0
  469. package/src/shipping/addressCanonical.ts +31 -0
  470. package/src/shipping/addressPorts.ts +48 -0
  471. package/src/shipping/addressSchemas.ts +28 -0
  472. package/src/shipping/adminShippingRateHandler.ts +72 -0
  473. package/src/shipping/contracts/address.ts +71 -0
  474. package/src/shipping/contracts/delivery.ts +114 -0
  475. package/src/shipping/contracts/index.ts +18 -0
  476. package/src/shipping/contracts/shippingRate.ts +7 -0
  477. package/src/shipping/customerAddressesHandler.ts +100 -0
  478. package/src/shipping/customerSelfServiceAddressModels.ts +124 -0
  479. package/src/shipping/deliverySelectionHandler.ts +94 -0
  480. package/src/shipping/deliverySelectionPort.ts +10 -0
  481. package/src/shipping/deliverySelectionSummary.ts +56 -0
  482. package/src/shipping/handlerSchemas.ts +19 -0
  483. package/src/shipping/index.ts +23 -0
  484. package/src/shipping/pickupPointSearchPort.ts +8 -0
  485. package/src/shipping/readDeliverySelectionEvidence.ts +51 -0
  486. package/src/shipping/shippingRatePorts.ts +36 -0
@@ -0,0 +1,129 @@
1
+ import type { ResolvedAcquisitionTerms } from "./contracts/acquisitionTerms.js";
2
+ import { mapAcquisitionTermsFailure } from "./acquisitionQuoteBinding.js";
3
+ import type { HttpRequest, HttpResponse } from "../http/index.js";
4
+ import type { BffResponder } from "../bff/index.js";
5
+ import type { z } from "zod";
6
+ import {
7
+ type CreateQuoteRequest, type CreateQuoteResponse,
8
+ } from "./contracts/quote.js";
9
+ import { COMMERCE_CONTRACT_VERSION } from "./contracts/index.js";
10
+ import {
11
+ CommerceQuoteError,
12
+ type CommerceQuotePort,
13
+ } from "./quotePorts.js";
14
+ import { CommerceQuoteCatalogReadError } from "./commerceQuoteCatalogReadPort.js";
15
+ import { mapPricingPolicyFailure } from "./commercePricingPolicyErrors.js";
16
+ import type { PricingPolicySnapshot } from "./contracts/offerPolicy.js";
17
+
18
+ export interface CommerceQuoteBatchHandlerDeps<Request extends CreateQuoteRequest = CreateQuoteRequest, Response extends CreateQuoteResponse = CreateQuoteResponse> {
19
+ responder: BffResponder;
20
+ acquisition?: { terms(quote: Response["quote"]): ResolvedAcquisitionTerms | undefined };
21
+ createQuoteBatchRequestSchema: z.ZodType<{ quotes: Request[] }>;
22
+ publicCreateQuoteBatchResponseSchema: z.ZodType<{ contractVersion: typeof COMMERCE_CONTRACT_VERSION; quotes: Response["quote"][] }>;
23
+
24
+ quotePort: CommerceQuotePort<Request, Response>;
25
+ resolveCustomerEligibility?: (
26
+ request: Request,
27
+ ) => Promise<{ clientId: string | null; source: "anonymous" | "resolved_client" }>;
28
+ resolvePricingPolicy?: (
29
+ request: Request,
30
+ ) => PricingPolicySnapshot | undefined | Promise<PricingPolicySnapshot | undefined>;
31
+ }
32
+
33
+ /**
34
+ * Batch quote BFF handler: prices N independent quotes in one request so the
35
+ * configurator stops fanning out one HTTP call per length tile. The injected
36
+ * `quotePort` is expected to share its catalog + active price-list reads across
37
+ * the batch (single `atTime` + memoized catalog), so this is one DB warm-up, not
38
+ * N. Output is identical to calling the single-quote endpoint N times, and order
39
+ * is preserved (`quotes[i]` ⇔ the i-th request). A failure in any quote fails
40
+ * the whole batch, mirroring the single-endpoint error mapping.
41
+ */
42
+ export function createCommerceQuoteBatchHandler<Request extends CreateQuoteRequest, Response extends CreateQuoteResponse>({
43
+ responder, createQuoteBatchRequestSchema, publicCreateQuoteBatchResponseSchema,
44
+ quotePort,
45
+ acquisition,
46
+ resolveCustomerEligibility,
47
+ resolvePricingPolicy,
48
+ }: CommerceQuoteBatchHandlerDeps<Request, Response>) {
49
+ const { sendBffError, sendBffSuccess, sendMethodNotAllowed } = responder;
50
+ return async function handler(req: HttpRequest, res: HttpResponse): Promise<void> {
51
+ if (req.method !== "POST") {
52
+ sendMethodNotAllowed(res, ["POST"]);
53
+ return;
54
+ }
55
+
56
+ const request = createQuoteBatchRequestSchema.safeParse(req.body);
57
+ if (!request.success) {
58
+ sendBffError(res, "BAD_REQUEST", "Invalid commerce quote batch request", {
59
+ details: request.error.flatten(),
60
+ });
61
+ return;
62
+ }
63
+
64
+ try {
65
+ const results = await Promise.all(
66
+ request.data.quotes.map(async (quote) => {
67
+ const eligibility = resolveCustomerEligibility
68
+ ? await resolveCustomerEligibility(quote)
69
+ : { clientId: null, source: "anonymous" as const };
70
+ const pricingPolicy = await resolvePricingPolicy?.(quote);
71
+ return quotePort.createQuote(quote, {
72
+ clientId: eligibility.clientId,
73
+ ...(pricingPolicy ? { pricingPolicy } : {}),
74
+ });
75
+ }),
76
+ );
77
+ const payload = {
78
+ contractVersion: COMMERCE_CONTRACT_VERSION,
79
+ quotes: results.map((result) => result.quote),
80
+ };
81
+ const response = publicCreateQuoteBatchResponseSchema.safeParse(payload);
82
+ if (!response.success) {
83
+ sendBffError(res, "INVALID_RESPONSE", "Commerce quote batch returned invalid response");
84
+ return;
85
+ }
86
+
87
+ sendBffSuccess(res, response.data, {
88
+ contractVersion: COMMERCE_CONTRACT_VERSION,
89
+ });
90
+ } catch (error) {
91
+ const acquisitionFailure = acquisition ? mapAcquisitionTermsFailure(error) : null;
92
+ if (acquisitionFailure) {
93
+ sendBffError(res, acquisitionFailure.code, "Acquisition terms unavailable", { details: acquisitionFailure.details });
94
+ return;
95
+ }
96
+ if (error instanceof CommerceQuoteCatalogReadError) {
97
+ sendBffError(res, "UPSTREAM_UNAVAILABLE", "Commerce catalog is unavailable", {
98
+ details: { reason: "catalog_unavailable", refusalCode: error.code },
99
+ });
100
+ return;
101
+ }
102
+ if (error instanceof CommerceQuoteError) {
103
+ sendBffError(
104
+ res,
105
+ error.code === "UNKNOWN_SKU" ? "BAD_REQUEST" : "CONFLICT",
106
+ error.message,
107
+ { details: error.details },
108
+ );
109
+ return;
110
+ }
111
+ // Without this the batch route answered every pricing-policy refusal with
112
+ // a detail-free 503, so the one route the configurator actually fans out
113
+ // to said the least about why it refused.
114
+ const policyFailure = mapPricingPolicyFailure(error);
115
+ if (policyFailure) {
116
+ console.error(
117
+ "[commerce-quote-batch] pricing policy refused:",
118
+ JSON.stringify(policyFailure.details),
119
+ );
120
+ sendBffError(res, policyFailure.code, policyFailure.code === "BAD_REQUEST"
121
+ ? "Commerce quote batch request is missing offer policy context"
122
+ : "Commerce quote batch failed", { details: policyFailure.details });
123
+ return;
124
+ }
125
+
126
+ sendBffError(res, "UPSTREAM_UNAVAILABLE", "Commerce quote batch failed");
127
+ }
128
+ };
129
+ }
@@ -0,0 +1,42 @@
1
+ /** Quote-only facts: no copy, route, price, or inventory authority. */
2
+ export interface CommerceQuoteCatalogItem {
3
+ skuId: string;
4
+ skuCode: string;
5
+ variantId: string;
6
+ productSlug: string;
7
+ netWeightG: number;
8
+ /** Identifies the product primary SKU for offer selection; secondary SKUs are excluded. */
9
+ isPrimarySku?: boolean;
10
+ isAddon: boolean;
11
+ sellability: {
12
+ oneTime: boolean;
13
+ subscription: boolean;
14
+ };
15
+ documentRevision: {
16
+ id: string | null;
17
+ digest: string | null;
18
+ };
19
+ }
20
+
21
+ export interface CommerceQuoteCatalogReadPort {
22
+ listQuoteCatalogItems(): Promise<CommerceQuoteCatalogItem[]>;
23
+ }
24
+
25
+ export type CommerceQuoteCatalogReadRefusalCode =
26
+ | "catalog_read_not_configured"
27
+ | "catalog_authority_unavailable"
28
+ | "catalog_authority_changed"
29
+ | "catalog_revision_invalid"
30
+ | "catalog_document_schema_invalid"
31
+ | "catalog_document_digest_mismatch"
32
+ | "catalog_primary_trade_item_invalid"
33
+ | "catalog_cursor_invalid"
34
+ | "catalog_cardinality_exceeded";
35
+
36
+ export class CommerceQuoteCatalogReadError extends Error {
37
+ constructor(readonly code: CommerceQuoteCatalogReadRefusalCode) {
38
+ super(code);
39
+ this.name = "CommerceQuoteCatalogReadError";
40
+ }
41
+ }
42
+
@@ -0,0 +1,184 @@
1
+ import type { ResolvedAcquisitionTerms } from "./contracts/acquisitionTerms.js";
2
+ import { mapAcquisitionTermsFailure } from "./acquisitionQuoteBinding.js";
3
+ import type { HttpRequest, HttpResponse } from "../http/index.js";
4
+ import type { BffResponder } from "../bff/index.js";
5
+ import type { z } from "zod";
6
+ import {
7
+ type CreateQuoteRequest, type CreateQuoteResponse,
8
+ } from "./contracts/quote.js";
9
+ import { COMMERCE_CONTRACT_VERSION } from "./contracts/index.js";
10
+ import {
11
+ CommerceQuoteError,
12
+ type CommerceQuotePort,
13
+ } from "./quotePorts.js";
14
+ import type { PricingPolicySnapshot } from "./contracts/offerPolicy.js";
15
+ import { mapPricingPolicyFailure } from "./commercePricingPolicyErrors.js";
16
+ import { CommerceQuoteCatalogReadError } from "./commerceQuoteCatalogReadPort.js";
17
+
18
+ type CommerceQuoteFailureStage =
19
+ | "customer_eligibility"
20
+ | "pricing_policy"
21
+ | "quote_evaluation"
22
+ | "promotion_acceptance"
23
+ | "promotion_fallback";
24
+
25
+ function commerceQuoteFailureDetails(stage: CommerceQuoteFailureStage) {
26
+ return { reason: "quote_dependency_failed" as const, stage };
27
+ }
28
+
29
+ export interface CommerceQuoteHandlerDeps<Request extends CreateQuoteRequest = CreateQuoteRequest, Response extends CreateQuoteResponse = CreateQuoteResponse> {
30
+ responder: BffResponder;
31
+ acquisition?: { terms(quote: Response["quote"]): ResolvedAcquisitionTerms | undefined };
32
+ createQuoteRequestSchema: z.ZodType<Request>;
33
+ createQuoteResponseSchema: z.ZodType<Response>;
34
+ publicCreateQuoteRequestSchema: z.ZodType<Request & { promotionAcceptanceToken?: string }>;
35
+ publicCreateQuoteResponseSchema: z.ZodType<Response & { promotionAcceptanceToken?: string }>;
36
+
37
+ quotePort: CommerceQuotePort<Request, Response>;
38
+ fallbackQuotePort?: CommerceQuotePort<Request, Response>;
39
+ resolveCustomerEligibility?: (
40
+ request: Request,
41
+ ) => Promise<{ clientId: string | null; source: "anonymous" | "resolved_client" }>;
42
+ resolvePricingPolicy?: (
43
+ request: Request,
44
+ ) => PricingPolicySnapshot | undefined | Promise<PricingPolicySnapshot | undefined>;
45
+ createPromotionAcceptance?: (
46
+ request: Request,
47
+ quote: Awaited<ReturnType<CommerceQuotePort<Request, Response>["createQuote"]>>["quote"],
48
+ acquisitionTerms?: ResolvedAcquisitionTerms,
49
+ ) => string | null;
50
+ honorPromotionAcceptance?: (
51
+ token: string,
52
+ request: Request,
53
+ quote: Awaited<ReturnType<CommerceQuotePort<Request, Response>["createQuote"]>>["quote"],
54
+ acquisitionTerms?: ResolvedAcquisitionTerms,
55
+ ) => boolean;
56
+ }
57
+
58
+ export function createCommerceQuoteHandler<Request extends CreateQuoteRequest, Response extends CreateQuoteResponse>({
59
+ responder, createQuoteRequestSchema, createQuoteResponseSchema, publicCreateQuoteRequestSchema, publicCreateQuoteResponseSchema,
60
+ quotePort,
61
+ acquisition,
62
+ fallbackQuotePort,
63
+ resolveCustomerEligibility,
64
+ resolvePricingPolicy,
65
+ createPromotionAcceptance,
66
+ honorPromotionAcceptance,
67
+ }: CommerceQuoteHandlerDeps<Request, Response>) {
68
+ const { sendBffError, sendBffSuccess, sendMethodNotAllowed } = responder;
69
+ return async function handler(req: HttpRequest, res: HttpResponse): Promise<void> {
70
+ if (req.method !== "POST") {
71
+ sendMethodNotAllowed(res, ["POST"]);
72
+ return;
73
+ }
74
+
75
+ const publicRequest = publicCreateQuoteRequestSchema.safeParse(req.body);
76
+ if (!publicRequest.success) {
77
+ sendBffError(res, "BAD_REQUEST", "Invalid commerce quote request", {
78
+ details: publicRequest.error.flatten(),
79
+ });
80
+ return;
81
+ }
82
+ const { promotionAcceptanceToken, ...canonicalInput } = publicRequest.data;
83
+ const request = createQuoteRequestSchema.safeParse(canonicalInput);
84
+ if (!request.success) {
85
+ sendBffError(res, "BAD_REQUEST", "Invalid commerce quote request");
86
+ return;
87
+ }
88
+
89
+ let stage: CommerceQuoteFailureStage = "customer_eligibility";
90
+ try {
91
+ const eligibility = resolveCustomerEligibility
92
+ ? await resolveCustomerEligibility(request.data)
93
+ : { clientId: null, source: "anonymous" as const };
94
+ console.info(
95
+ "commerce_quote_promo_eligibility_context",
96
+ JSON.stringify({ promoEligibilityContext: eligibility.source }),
97
+ );
98
+ stage = "pricing_policy";
99
+ const pricingPolicy = await resolvePricingPolicy?.(request.data);
100
+ stage = "quote_evaluation";
101
+ const rawQuote = await quotePort.createQuote(request.data, {
102
+ clientId: eligibility.clientId,
103
+ ...(pricingPolicy ? { pricingPolicy } : {}),
104
+ });
105
+ const canonicalQuote = createQuoteResponseSchema.safeParse(rawQuote);
106
+ if (!canonicalQuote.success) {
107
+ sendBffError(res, "INVALID_RESPONSE", "Commerce quote returned invalid response");
108
+ return;
109
+ }
110
+ let quote = canonicalQuote.data;
111
+ stage = "promotion_acceptance";
112
+ const acquisitionTerms = acquisition?.terms(quote.quote);
113
+ const honoredToken = promotionAcceptanceToken && honorPromotionAcceptance?.(
114
+ promotionAcceptanceToken, request.data, quote.quote, acquisitionTerms,
115
+ ) ? promotionAcceptanceToken : undefined;
116
+ const issuedToken = honoredToken ?? createPromotionAcceptance?.(request.data, quote.quote, acquisitionTerms) ?? undefined;
117
+ const containsV2Promotion = quote.quote.discounts.some((discount) =>
118
+ discount.promotionEngineVersion === "promotion-engine.v2");
119
+ if ((containsV2Promotion || acquisitionTerms) && !issuedToken) {
120
+ stage = "promotion_fallback";
121
+ const fallback = fallbackQuotePort
122
+ ? createQuoteResponseSchema.safeParse(await fallbackQuotePort.createQuote(request.data, {
123
+ clientId: eligibility.clientId,
124
+ ...(pricingPolicy ? { pricingPolicy } : {}),
125
+ }))
126
+ : null;
127
+ if (!fallback?.success || acquisition?.terms(fallback.data.quote) || fallback.data.quote.discounts.some((discount) =>
128
+ discount.promotionEngineVersion === "promotion-engine.v2")) {
129
+ sendBffError(res, "CONFLICT", "Promotion quote must be refreshed", {
130
+ details: { feature: "quote", reason: "promotion_acceptance_refresh_required" },
131
+ });
132
+ return;
133
+ }
134
+ quote = fallback.data;
135
+ }
136
+ const response = publicCreateQuoteResponseSchema.safeParse({
137
+ ...quote,
138
+ promotionAcceptanceToken: quote === canonicalQuote.data ? issuedToken : undefined,
139
+ });
140
+ if (!response.success) {
141
+ sendBffError(res, "INVALID_RESPONSE", "Commerce quote returned invalid response");
142
+ return;
143
+ }
144
+
145
+ sendBffSuccess(res, response.data, {
146
+ contractVersion: COMMERCE_CONTRACT_VERSION,
147
+ });
148
+ } catch (error) {
149
+ const acquisitionFailure = acquisition ? mapAcquisitionTermsFailure(error) : null;
150
+ if (acquisitionFailure) {
151
+ sendBffError(res, acquisitionFailure.code, "Acquisition terms unavailable", { details: acquisitionFailure.details });
152
+ return;
153
+ }
154
+ if (error instanceof CommerceQuoteCatalogReadError) {
155
+ sendBffError(res, "UPSTREAM_UNAVAILABLE", "Commerce catalog is unavailable", {
156
+ details: { reason: "catalog_unavailable", refusalCode: error.code },
157
+ });
158
+ return;
159
+ }
160
+ if (error instanceof CommerceQuoteError) {
161
+ sendBffError(
162
+ res,
163
+ error.code === "UNKNOWN_SKU" ? "BAD_REQUEST" : "CONFLICT",
164
+ error.message,
165
+ { details: error.details },
166
+ );
167
+ return;
168
+ }
169
+
170
+ const policyFailure = stage === "pricing_policy" ? mapPricingPolicyFailure(error) : null;
171
+ if (policyFailure) {
172
+ console.error("[commerce-quote] pricing policy refused:", JSON.stringify(policyFailure.details));
173
+ sendBffError(res, policyFailure.code, policyFailure.code === "BAD_REQUEST"
174
+ ? "Commerce quote request is missing offer policy context"
175
+ : "Commerce quote failed", { details: policyFailure.details });
176
+ return;
177
+ }
178
+
179
+ const details = commerceQuoteFailureDetails(stage);
180
+ console.error("[commerce-quote] dependency failed:", JSON.stringify(details));
181
+ sendBffError(res, "UPSTREAM_UNAVAILABLE", "Commerce quote failed", { details });
182
+ }
183
+ };
184
+ }
@@ -0,0 +1,48 @@
1
+ import type { z } from "zod";
2
+ import {
3
+ CommerceQuoteError,
4
+ CommerceQuoteSnapshotError,
5
+ type CommerceQuotePort,
6
+ } from "./quotePorts.js";
7
+
8
+ // Shared by the static and DB-backed quote snapshot verifiers. The verify body
9
+ // and request builder differ per verifier; only this re-quote-and-wrap tail is
10
+ // identical apart from two human-facing message strings, which are passed in so
11
+ // each verifier keeps its exact wording (asserted by their tests).
12
+ export interface QuoteSnapshotExpectMessages {
13
+ /** Thrown when the re-quoted response fails schema validation. */
14
+ invalidResponseMessage: string;
15
+ /** Thrown when re-quoting raises a CommerceQuoteError (pricing changed). */
16
+ catalogMismatchMessage: string;
17
+ }
18
+
19
+ export async function createExpectedQuote<Request, Response>(
20
+ quotePort: CommerceQuotePort<Request, Response>,
21
+ request: Request,
22
+ messages: QuoteSnapshotExpectMessages,
23
+ createQuoteResponseSchema: z.ZodType<Response>,
24
+ ): Promise<Response> {
25
+ try {
26
+ const expected = await quotePort.createQuote(request);
27
+ const parsed = createQuoteResponseSchema.safeParse(expected);
28
+ if (!parsed.success) {
29
+ throw new CommerceQuoteSnapshotError(
30
+ "QUOTE_SNAPSHOT_MISMATCH",
31
+ messages.invalidResponseMessage,
32
+ { reason: "invalid_expected_quote" },
33
+ );
34
+ }
35
+
36
+ return parsed.data;
37
+ } catch (error) {
38
+ if (error instanceof CommerceQuoteSnapshotError) throw error;
39
+ if (error instanceof CommerceQuoteError) {
40
+ throw new CommerceQuoteSnapshotError("QUOTE_SNAPSHOT_MISMATCH", messages.catalogMismatchMessage, {
41
+ reason: error.code,
42
+ ...error.details,
43
+ });
44
+ }
45
+
46
+ throw error;
47
+ }
48
+ }
@@ -0,0 +1,26 @@
1
+ /** Opt-in protocol identity; financial schedules belong to the injected policy. */
2
+ export const ACQUISITION_TERMS_CAPABILITY = "subscription-acquisition.v1" as const;
3
+ export type AcquisitionCapability = typeof ACQUISITION_TERMS_CAPABILITY;
4
+ export interface AcquisitionTermsMetadata {
5
+ schemaVersion: AcquisitionCapability;
6
+ revision: string;
7
+ delivery2DiscountBps: number;
8
+ }
9
+ export interface AcquisitionTerms extends AcquisitionTermsMetadata {
10
+ initialDiscountBps: number;
11
+ effectiveFrom: string;
12
+ effectiveTo: string | null;
13
+ }
14
+ export interface ResolvedAcquisitionTerms extends AcquisitionTerms { sourcePromotionId: string }
15
+ export interface AcquisitionTermsExpectation { revision: string; delivery2DiscountBps: number }
16
+
17
+ import type { CreateQuoteRequest, CommerceQuoteContext, CommerceQuote } from "./quote.js";
18
+ /** Separate opt-in DTOs; incumbent request/response admission is unchanged. */
19
+ export interface AcquisitionQuoteRequest extends CreateQuoteRequest {
20
+ acquisitionCapability?: AcquisitionCapability;
21
+ }
22
+ export interface AcquisitionQuoteContext extends CommerceQuoteContext {
23
+ acquisitionCapability?: AcquisitionCapability;
24
+ atTime?: string;
25
+ }
26
+ export interface AcquisitionQuote extends CommerceQuote { acquisitionTerms?: ResolvedAcquisitionTerms }
@@ -0,0 +1,44 @@
1
+ import type { ResolvedPrice } from "@openlup/core/pricing";
2
+ import type { SubscriptionPricePolicyRevision } from "./policy.js";
3
+
4
+ /** Exact settlement context for a current quote price; tiers and open-mode fallbacks are excluded. */
5
+ export interface CommercePriceAuthorityQuery {
6
+ variantId: string;
7
+ mode: "one_time" | "subscription";
8
+ regionCode: string;
9
+ currency: string;
10
+ channel: string;
11
+ atTime?: string;
12
+ }
13
+
14
+ export interface CommerceBasePriceObservation {
15
+ /** The sole active/effective `one_time`, `min_qty=1` entry. */
16
+ base: ResolvedPrice;
17
+ unitPriceMinor: number;
18
+ }
19
+
20
+ export type CommercePriceAuthorityResult =
21
+ | (CommerceBasePriceObservation & { kind: "one_time" })
22
+ | (CommerceBasePriceObservation & {
23
+ kind: "subscription_policy";
24
+ policy: SubscriptionPricePolicyRevision;
25
+ })
26
+ | (CommerceBasePriceObservation & {
27
+ /** Explicit compatibility observation allowed only before this context has policy history. */
28
+ kind: "subscription_legacy";
29
+ legacyResolved: ResolvedPrice;
30
+ });
31
+
32
+ export type CommercePriceAuthorityRefusal =
33
+ | "active_price_list_not_found"
34
+ | "active_price_list_ambiguous"
35
+ | "base_price_not_found"
36
+ | "base_price_ambiguous"
37
+ | "base_price_amount_kind_invalid"
38
+ | "legacy_subscription_price_not_found"
39
+ | "legacy_subscription_price_ambiguous"
40
+ | "subscription_price_policy_not_effective"
41
+ | "subscription_price_policy_ambiguous"
42
+ | "subscription_price_policy_invalid"
43
+ | "subscription_price_policy_digest_mismatch";
44
+
@@ -0,0 +1,25 @@
1
+ /** UI-safe, additive explanation for a frozen `codeRejections` item. */
2
+ export type CommerceCodeRejectionDetail =
3
+ | { code: string; reason: "scope_not_applicable"; allowedScopes: Array<"one_time" | "subscription_initial"> }
4
+ | { code: string; reason: "minimum_not_met"; minimumReferenceMinor: number }
5
+ | { code: string; reason: "not_yet_active"; validFrom: string }
6
+ | { code: string; reason: "global_limit_reached" };
7
+
8
+
9
+ export interface QuotePromotionEvidence {
10
+ promotionId: string;
11
+ code?: string | null;
12
+ reasonCode: string;
13
+ promotionEngineVersion?: "promotion-engine.v2";
14
+ promotionCodeId?: string;
15
+ promotionCodeRevision?: number;
16
+ promotionDefinitionFingerprint?: string;
17
+ promotionCodeScopes?: Array<"one_time" | "subscription_initial">;
18
+ promotionMinimumReferenceMinor?: number;
19
+ promotionCodeValidTo?: string | null;
20
+ promotionBenefitKind?: "target_percentage" | "percentage" | "fixed_amount" | "free_shipping";
21
+ promotionBenefitValueBps?: number;
22
+ promotionBenefitValueMinor?: number;
23
+ floorApplied?: boolean;
24
+ }
25
+
@@ -0,0 +1,17 @@
1
+ export type { CommercePriceAuthorityQuery, CommerceBasePriceObservation, CommercePriceAuthorityResult, CommercePriceAuthorityRefusal } from "./authority.js";
2
+ export { SUBSCRIPTION_PRICE_POLICY_SCHEMA_VERSION, SUBSCRIPTION_PRICE_POLICY_DEFAULT_DISCOUNT_BPS, SUBSCRIPTION_PRICE_POLICY_DEFAULT_QUANTUM_MINOR } from "./policy.js";
3
+ export type { SubscriptionPricePolicySemantics, SubscriptionPricePolicyCanonicalInput, SubscriptionPricePolicyRevision, SubscriptionPricePolicyDigestRefusal } from "./policy.js";
4
+ export { OFFER_POLICY_V1, OFFER_POLICY_V2, PROMOTION_ENGINE_V1, PROMOTION_ENGINE_V2, OFFER_POLICY_V2_CAPABILITY } from "./offerPolicy.js";
5
+ export type { OfferPolicyVersion, PromotionEngineVersion, PricingPolicyRequest, PricingPolicySnapshot } from "./offerPolicy.js";
6
+ export type { CommerceCurrency, CommerceTaxCountry, CommerceTaxCategory, CommerceTaxLegalBasis, CommerceMoney, CartLineInput, CommerceTaxProfile, CommerceTaxBreakdown } from "./money.js";
7
+ export { COMMERCE_CONTRACT_VERSION } from "./quote.js";
8
+ export type { CommerceQuotePricingComponent, CommerceQuoteContext, CommerceQuoteLine, CommercePromotionCustomerSemantic, CommerceQuoteDiscount, CommerceCodeRejectionReason, CommerceCodeRejection, CommerceQuote, CreateQuoteRequest, CreateQuoteResponse } from "./quote.js";
9
+ export type { QuotePromotionEvidence, CommerceCodeRejectionDetail } from "./evidence.js";
10
+ export { CATALOG_FACTS_PROVENANCE_VERSION, CATALOG_FACTS_POLICY_PROVENANCE_VERSION } from "./provenance.js";
11
+ export type { CatalogFactsProvenance } from "./provenance.js";
12
+ export { COMMERCE_OFFER_PRICING_CONTRACT_VERSION, COMMERCE_OFFER_PRICING_V2_CONTRACT_VERSION } from "./offer.js";
13
+ export type { CommerceOfferPrice, CommerceProductOfferPricing, CommerceOfferPricingResponse } from "./offer.js";
14
+ export { ACQUISITION_TERMS_CAPABILITY } from "./acquisitionTerms.js";
15
+ export type { AcquisitionQuoteRequest, AcquisitionQuoteContext, AcquisitionQuote, AcquisitionCapability, AcquisitionTermsMetadata, AcquisitionTerms, ResolvedAcquisitionTerms, AcquisitionTermsExpectation } from "./acquisitionTerms.js";
16
+ export { COMMERCE_OFFER_PRICING_V3_CONTRACT_VERSION } from "./offer.js";
17
+ export type { AcquisitionOfferPricingResponse } from "./offer.js";
@@ -0,0 +1,32 @@
1
+ export type CommerceCurrency = string;
2
+ export type CommerceTaxCountry = string;
3
+ export type CommerceTaxCategory = string;
4
+ export type CommerceTaxLegalBasis = string;
5
+
6
+ export interface CommerceMoney {
7
+ amountMinor: number;
8
+ currency: CommerceCurrency;
9
+ }
10
+
11
+ export interface CartLineInput {
12
+ sku: string;
13
+ quantity: number;
14
+ variantId?: string;
15
+ modeAtLine?: "one_time" | "subscription";
16
+ isAddon?: boolean;
17
+ }
18
+
19
+ export interface CommerceTaxProfile {
20
+ included: true;
21
+ country: CommerceTaxCountry;
22
+ category: CommerceTaxCategory;
23
+ vatRateBps: number;
24
+ legalBasis: CommerceTaxLegalBasis;
25
+ }
26
+
27
+ export interface CommerceTaxBreakdown extends CommerceTaxProfile {
28
+ netAmount: CommerceMoney;
29
+ vatAmount: CommerceMoney;
30
+ grossAmount: CommerceMoney;
31
+ }
32
+
@@ -0,0 +1,42 @@
1
+ import type { CommerceMoney } from "./money.js";
2
+ import type { PricingPolicySnapshot } from "./offerPolicy.js";
3
+ export const COMMERCE_OFFER_PRICING_CONTRACT_VERSION = "commerce.offer-pricing.v1" as const;
4
+ export const COMMERCE_OFFER_PRICING_V2_CONTRACT_VERSION = "commerce.offer-pricing.v2" as const;
5
+ export interface CommerceOfferPrice {
6
+ packageGross: CommerceMoney;
7
+ unitGross: CommerceMoney;
8
+ }
9
+ export interface CommerceProductOfferPricing {
10
+ productSlug: string;
11
+ unitCount: number;
12
+ oneTime: CommerceOfferPrice;
13
+ subscriptionInitial: CommerceOfferPrice;
14
+ subscriptionRecurring: CommerceOfferPrice;
15
+ catalogAnchorUnitGross: CommerceMoney;
16
+ initialDiscountPercent: number;
17
+ recurringDiscountPercent: number;
18
+ }
19
+ export type CommerceOfferPricingResponse<ScopeV1 extends string = string, ScopeV2 extends string = string> = {
20
+ contractVersion: typeof COMMERCE_OFFER_PRICING_CONTRACT_VERSION;
21
+ scope: ScopeV1;
22
+ products: CommerceProductOfferPricing[];
23
+ minimum: { oneTime: CommerceProductOfferPricing; subscription: CommerceProductOfferPricing };
24
+ } | {
25
+ contractVersion: typeof COMMERCE_OFFER_PRICING_V2_CONTRACT_VERSION;
26
+ scope: ScopeV2;
27
+ products: CommerceProductOfferPricing[];
28
+ minimum: { oneTime: CommerceProductOfferPricing; subscription: CommerceProductOfferPricing };
29
+ pricingPolicy: PricingPolicySnapshot;
30
+ shipping: { gross: CommerceMoney; discountGross: CommerceMoney; payable: CommerceMoney };
31
+ minimumProductPayable: CommerceMoney;
32
+ };
33
+
34
+ /** Complete opt-in v3 response; the incumbent v1/v2 union stays unchanged. */
35
+ export const COMMERCE_OFFER_PRICING_V3_CONTRACT_VERSION = "commerce.offer-pricing.v3" as const;
36
+ export type AcquisitionOfferPricingResponse<ScopeV2 extends string = string> =
37
+ Omit<Extract<CommerceOfferPricingResponse<string, ScopeV2>, { contractVersion: typeof COMMERCE_OFFER_PRICING_V2_CONTRACT_VERSION }>, "contractVersion"> & {
38
+ contractVersion: typeof COMMERCE_OFFER_PRICING_V3_CONTRACT_VERSION;
39
+ acquisitionTerms: import("./acquisitionTerms.js").AcquisitionTerms;
40
+ observedAt: string;
41
+ validUntil: string;
42
+ };
@@ -0,0 +1,17 @@
1
+ export const OFFER_POLICY_V1 = "commerce.offer-policy.v1" as const;
2
+ export const OFFER_POLICY_V2 = "commerce.offer-policy.v2" as const;
3
+ export const PROMOTION_ENGINE_V1 = "promotion-engine.v1" as const;
4
+ export const PROMOTION_ENGINE_V2 = "promotion-engine.v2" as const;
5
+ export const OFFER_POLICY_V2_CAPABILITY = OFFER_POLICY_V2;
6
+
7
+ export type OfferPolicyVersion = typeof OFFER_POLICY_V1 | typeof OFFER_POLICY_V2;
8
+ export type PromotionEngineVersion = typeof PROMOTION_ENGINE_V1 | typeof PROMOTION_ENGINE_V2;
9
+ export interface PricingPolicyRequest {
10
+ capability?: typeof OFFER_POLICY_V2_CAPABILITY;
11
+ token?: string;
12
+ }
13
+ export interface PricingPolicySnapshot {
14
+ offerPolicyVersion: OfferPolicyVersion;
15
+ promotionEngineVersion: PromotionEngineVersion;
16
+ pricingPolicyToken?: string;
17
+ }
@@ -0,0 +1,26 @@
1
+ export const SUBSCRIPTION_PRICE_POLICY_SCHEMA_VERSION = "subscription-price-policy.v1";
2
+ export const SUBSCRIPTION_PRICE_POLICY_DEFAULT_DISCOUNT_BPS = 1_000;
3
+ export const SUBSCRIPTION_PRICE_POLICY_DEFAULT_QUANTUM_MINOR = 10;
4
+
5
+ export interface SubscriptionPricePolicySemantics {
6
+ discountBps: number;
7
+ roundingQuantumMinor: number;
8
+ roundingRule: "FLOOR_TO_QUANTUM";
9
+ }
10
+
11
+ export interface SubscriptionPricePolicyCanonicalInput extends SubscriptionPricePolicySemantics {
12
+ id: string;
13
+ revisionNo: number;
14
+ priceListId: string;
15
+ regionCode: string;
16
+ currency: string;
17
+ channel: string;
18
+ effectiveFrom: string;
19
+ effectiveTo: string | null;
20
+ }
21
+
22
+ export interface SubscriptionPricePolicyRevision extends SubscriptionPricePolicyCanonicalInput {
23
+ digest: string;
24
+ }
25
+
26
+ export type SubscriptionPricePolicyDigestRefusal = "subscription_price_policy_digest_mismatch";
@@ -0,0 +1,19 @@
1
+ export const CATALOG_FACTS_PROVENANCE_VERSION = "catalog_facts_v1" as const;
2
+ export const CATALOG_FACTS_POLICY_PROVENANCE_VERSION = "catalog_facts_v2" as const;
3
+
4
+ interface CatalogFactsFields {
5
+ skuId: string;
6
+ documentRevisionId: string;
7
+ documentDigest: string;
8
+ basePriceEntryId: string;
9
+ atTime: string;
10
+ currency: string;
11
+ resolvedUnitAmountMinor: number;
12
+ resolvedLineAmountMinor: number;
13
+ baseUnitAmountMinor: number;
14
+ }
15
+
16
+ export type CatalogFactsProvenance = CatalogFactsFields & (
17
+ | { version: typeof CATALOG_FACTS_PROVENANCE_VERSION; resolvedPriceEntryId: string; mode: "one_time" | "subscription" }
18
+ | { version: typeof CATALOG_FACTS_POLICY_PROVENANCE_VERSION; policyRevisionId: string; policyDigest: string; mode: "subscription" }
19
+ );