@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,56 @@
1
+ import type {
2
+ PromotionCodeCreateRequest,
3
+ PromotionCodeSummary,
4
+ PromotionCodesListRequest,
5
+ PromotionCodeUpdateRequest,
6
+ } from "./contracts/index.js";
7
+
8
+ export interface PromotionCodesListResult {
9
+ codes: PromotionCodeSummary[];
10
+ nextCursor: string | null;
11
+ legacyCompatibility: {
12
+ ready: boolean;
13
+ unprojectedCount: number;
14
+ collisionGroupCount: number;
15
+ };
16
+ }
17
+
18
+ export interface PromotionCodeCreateResult {
19
+ id: string;
20
+ code: string;
21
+ status: "draft" | "active" | "paused" | "archived";
22
+ idempotent: boolean;
23
+ revision: number;
24
+ }
25
+
26
+ export interface PromotionCodeUpdateResult {
27
+ id: string;
28
+ status: "draft" | "active" | "paused" | "archived";
29
+ idempotent: boolean;
30
+ revision: number;
31
+ }
32
+
33
+ export interface AdminPromotionCodesDataPort {
34
+ list(actorId: string, input: PromotionCodesListRequest): Promise<PromotionCodesListResult>;
35
+ definition(actorId: string, id: string): Promise<{
36
+ benefits: PromotionCodeSummary["benefits"];
37
+ scopes: PromotionCodeCreateRequest["scopes"];
38
+ minimumReferenceMinor: number;
39
+ revision: number;
40
+ status: "draft" | "active" | "paused" | "archived";
41
+ validFrom: string;
42
+ validTo: string | null;
43
+ promotionEngineVersion: "promotion-engine.v1" | "promotion-engine.v2";
44
+ }>;
45
+ create(input: {
46
+ actorId: string;
47
+ request: PromotionCodeCreateRequest;
48
+ resolvedCode: string;
49
+ requestFingerprint: string;
50
+ }): Promise<PromotionCodeCreateResult>;
51
+ update(input: {
52
+ actorId: string;
53
+ request: PromotionCodeUpdateRequest;
54
+ requestFingerprint: string;
55
+ }): Promise<PromotionCodeUpdateResult>;
56
+ }
@@ -0,0 +1,254 @@
1
+ import { createHash } from "node:crypto";
2
+ import {
3
+ promotionCodeCreateRequestSchema,
4
+ promotionCodeCreateResponseSchema,
5
+ promotionCodePreviewRequestSchema,
6
+ promotionCodePreviewResponseSchema,
7
+ promotionCodesListRequestSchema,
8
+ promotionCodesListResponseSchema,
9
+ promotionCodeUpdateRequestSchema,
10
+ promotionCodeUpdateResponseSchema,
11
+ type PromotionCodeCreateRequest,
12
+ type PromotionCodePreviewRequest,
13
+ type PromotionCodesListRequest,
14
+ type PromotionCodeUpdateRequest,
15
+ } from "./adminPromotionCodesContracts.js";
16
+ import { COMMERCE_CONTRACT_VERSION } from "../pricing/index.js";
17
+ import type {
18
+ AgentDomainMutationSpec,
19
+ AgentDomainQuerySpec,
20
+ } from "./adminBindings.js";
21
+ import type { AuthorizeAdmin, PromotionAdminBindings } from "./adminBindings.js";
22
+ import type { HttpRequest as VercelRequest, HttpResponse as VercelResponse } from "../http/index.js";
23
+ import type { AdminPromotionCodesDataPort } from "./adminPromotionCodesDataPort.js";
24
+ export interface AdminPromotionCodesHandlerDeps {
25
+ dataPort: AdminPromotionCodesDataPort;
26
+ authorizeAdmin: AuthorizeAdmin;
27
+ previewSecret: string;
28
+ }
29
+
30
+ export function createAdminPromotionCodesHandlers({ createAdminMutationHandler, createAdminParameterizedReadHandler, mapRpcError, DomainRpcError, resolveAdmin, sendBffError, sendBffSuccess, sendMethodNotAllowed, generatePromotionCode, normalizePromotionCode, previewPromotionCode, verifyPromotionPreviewProof }: Omit<PromotionAdminBindings, "createAdminReadHandler">) {
31
+ /**
32
+ * The Promotion Code Center is a permanent part of the service, so these handlers are unconditional: the
33
+ * `enabled` / `flagName` / `disabledMessage` options of the admin-domain kit are
34
+ * omitted, which the kit reads as "always run the handler". The human-actor gate
35
+ * on create/update below is a security control, not rollout gating, and stays.
36
+ */
37
+ const listSpec: AgentDomainQuerySpec<PromotionCodesListRequest> = {
38
+ key: "list",
39
+ requestSchema: promotionCodesListRequestSchema,
40
+ gate: "read",
41
+ allowedActorKinds: ["human", "machine"],
42
+ };
43
+
44
+ const createSpec: AgentDomainMutationSpec<PromotionCodeCreateRequest> = {
45
+ key: "create",
46
+ requestSchema: promotionCodeCreateRequestSchema,
47
+ gate: "mutation",
48
+ allowedActorKinds: ["human"],
49
+ lifecycleMarkers: [],
50
+ };
51
+
52
+ const updateSpec: AgentDomainMutationSpec<PromotionCodeUpdateRequest> = {
53
+ key: "update",
54
+ requestSchema: promotionCodeUpdateRequestSchema,
55
+ gate: "mutation",
56
+ allowedActorKinds: ["human"],
57
+ lifecycleMarkers: [],
58
+ };
59
+
60
+ function createAdminPromotionCodesListHandler(deps: AdminPromotionCodesHandlerDeps) {
61
+ return createAdminParameterizedReadHandler({
62
+ query: listSpec,
63
+ authorizeAdmin: deps.authorizeAdmin,
64
+ load: (actorId, input) => deps.dataPort.list(actorId, input),
65
+ toResponse: (result) => ({
66
+ contractVersion: COMMERCE_CONTRACT_VERSION,
67
+ ...result,
68
+ // Kept on the wire (constant `true`) so a browser bundle built before the
69
+ // rollout flags were retired still parses this response unchanged.
70
+ capabilities: { mutationsEnabled: true },
71
+ }),
72
+ responseSchema: promotionCodesListResponseSchema,
73
+ invalidRequestMessage: "Invalid promotion code list request",
74
+ invalidResponseMessage: "Invalid promotion code list response",
75
+ failureMessage: "Promotion code list failed",
76
+ mapError: mapPromotionCodeError,
77
+ });
78
+ }
79
+
80
+ function createAdminPromotionCodePreviewHandler(
81
+ deps: Pick<AdminPromotionCodesHandlerDeps, "authorizeAdmin" | "previewSecret">,
82
+ ) {
83
+ return async (req: VercelRequest, res: VercelResponse): Promise<void> => {
84
+ if (req.method !== "POST") return sendMethodNotAllowed(res, ["POST"]);
85
+ if (!(await resolveAdmin(deps.authorizeAdmin, res))) return;
86
+ const parsed = promotionCodePreviewRequestSchema.safeParse(req.body);
87
+ if (!parsed.success) {
88
+ sendBffError(res, "BAD_REQUEST", "Invalid promotion code preview request", {
89
+ details: parsed.error.flatten(),
90
+ });
91
+ return;
92
+ }
93
+ try {
94
+ const result = promotionCodePreviewResponseSchema.parse(
95
+ previewPromotionCode(parsed.data, deps.previewSecret),
96
+ );
97
+ sendBffSuccess(res, result);
98
+ } catch (error) {
99
+ mapPromotionCodeError(res, error, "Promotion code preview failed");
100
+ }
101
+ };
102
+ }
103
+
104
+ function createAdminPromotionCodeCreateHandler(deps: AdminPromotionCodesHandlerDeps) {
105
+ return createAdminMutationHandler({
106
+ mutation: createSpec,
107
+ authorizeAdmin: deps.authorizeAdmin,
108
+ invoke: async (actorId, request) => {
109
+ verifyActivationPreview(request, deps.previewSecret);
110
+ const resolvedCode = normalizePromotionCode(
111
+ request.code.kind === "automatic" ? generatePromotionCode() : request.code.value,
112
+ );
113
+ return deps.dataPort.create({
114
+ actorId,
115
+ request,
116
+ resolvedCode,
117
+ requestFingerprint: mutationFingerprint(request),
118
+ });
119
+ },
120
+ toResponse: (result) => ({ contractVersion: COMMERCE_CONTRACT_VERSION, ...result }),
121
+ responseSchema: promotionCodeCreateResponseSchema,
122
+ invalidRequestMessage: "Invalid promotion code create request",
123
+ invalidResponseMessage: "Invalid promotion code create response",
124
+ failureMessage: "Promotion code create failed",
125
+ mapError: mapPromotionCodeError,
126
+ });
127
+ }
128
+
129
+ function createAdminPromotionCodeUpdateHandler(deps: AdminPromotionCodesHandlerDeps) {
130
+ return createAdminMutationHandler({
131
+ mutation: updateSpec,
132
+ authorizeAdmin: deps.authorizeAdmin,
133
+ invoke: async (actorId, request) => {
134
+ await verifyUpdateLifecycle(deps.dataPort, actorId, request, deps.previewSecret);
135
+ return deps.dataPort.update({
136
+ actorId,
137
+ request,
138
+ requestFingerprint: mutationFingerprint(request),
139
+ });
140
+ },
141
+ toResponse: (result) => ({ contractVersion: COMMERCE_CONTRACT_VERSION, ...result }),
142
+ responseSchema: promotionCodeUpdateResponseSchema,
143
+ invalidRequestMessage: "Invalid promotion code update request",
144
+ invalidResponseMessage: "Invalid promotion code update response",
145
+ failureMessage: "Promotion code update failed",
146
+ mapError: mapPromotionCodeError,
147
+ });
148
+ }
149
+
150
+ function verifyActivationPreview(request: PromotionCodeCreateRequest, secret: string): void {
151
+ if (request.status !== "active") return;
152
+ if (!request.previewContext || !request.previewProof) {
153
+ throw new DomainRpcError("22023", "promotion_preview_required");
154
+ }
155
+ const previewInput: PromotionCodePreviewRequest = {
156
+ benefits: request.benefits,
157
+ scopes: request.scopes,
158
+ promotionEngineVersion: "promotion-engine.v2",
159
+ minimumReferenceMinor: request.minimumReferenceMinor,
160
+ context: request.previewContext,
161
+ };
162
+ previewPromotionCode(previewInput, secret);
163
+ if (!verifyPromotionPreviewProof(previewInput, request.previewProof, secret)) {
164
+ throw new DomainRpcError("22023", "promotion_preview_proof_mismatch");
165
+ }
166
+ }
167
+
168
+ async function verifyUpdateLifecycle(
169
+ dataPort: AdminPromotionCodesDataPort,
170
+ actorId: string,
171
+ request: PromotionCodeUpdateRequest,
172
+ secret: string,
173
+ ): Promise<void> {
174
+ const definition = await dataPort.definition(actorId, request.id);
175
+ if (definition.revision !== request.expectedRevision) {
176
+ // Let the transactional RPC decide between an idempotent replay (whose
177
+ // original revision is now stale by definition) and a genuine 409.
178
+ return;
179
+ }
180
+ const resultingValidFrom = request.updates.validFrom ?? definition.validFrom;
181
+ const resultingValidTo = request.updates.validTo === undefined
182
+ ? definition.validTo
183
+ : request.updates.validTo;
184
+ if (resultingValidTo !== null && Date.parse(resultingValidTo) <= Date.parse(resultingValidFrom)) {
185
+ throw new DomainRpcError("22023", "promotion_code_invalid_validity_window");
186
+ }
187
+ const beforeEffective = isEffectivelyActive(
188
+ definition.status,
189
+ definition.validFrom,
190
+ definition.validTo,
191
+ );
192
+ const afterEffective = isEffectivelyActive(
193
+ request.updates.status ?? definition.status,
194
+ resultingValidFrom,
195
+ resultingValidTo,
196
+ );
197
+ const transitionsToActiveStatus = definition.status !== "active"
198
+ && (request.updates.status ?? definition.status) === "active";
199
+ if (!transitionsToActiveStatus && (beforeEffective || !afterEffective)) return;
200
+ if (!request.previewContext || !request.previewProof) {
201
+ throw new DomainRpcError("22023", "promotion_preview_required");
202
+ }
203
+ const actualPreview = {
204
+ benefits: definition.benefits,
205
+ scopes: definition.scopes,
206
+ promotionEngineVersion: definition.promotionEngineVersion,
207
+ minimumReferenceMinor: definition.minimumReferenceMinor,
208
+ context: request.previewContext,
209
+ };
210
+ previewPromotionCode(actualPreview, secret);
211
+ if (!verifyPromotionPreviewProof(actualPreview, request.previewProof, secret)) {
212
+ throw new DomainRpcError("22023", "promotion_preview_proof_mismatch");
213
+ }
214
+ }
215
+
216
+ function isEffectivelyActive(
217
+ status: "draft" | "active" | "paused" | "archived",
218
+ validFrom: string,
219
+ validTo: string | null,
220
+ now = Date.now(),
221
+ ): boolean {
222
+ return status === "active"
223
+ && Date.parse(validFrom) <= now
224
+ && (validTo === null || Date.parse(validTo) > now);
225
+ }
226
+
227
+ function mapPromotionCodeError(
228
+ res: VercelResponse,
229
+ error: unknown,
230
+ failureMessage: string,
231
+ ): void {
232
+ if (error instanceof DomainRpcError && error.sqlstate === "22023") {
233
+ sendBffError(res, "BAD_REQUEST", error.pgMessage, {
234
+ details: { reason: error.pgMessage },
235
+ });
236
+ return;
237
+ }
238
+ if (error instanceof RangeError) {
239
+ sendBffError(res, "BAD_REQUEST", error.message, {
240
+ details: { reason: error.message },
241
+ });
242
+ return;
243
+ }
244
+ mapRpcError(res, error, failureMessage);
245
+ }
246
+
247
+ function mutationFingerprint(request: PromotionCodeCreateRequest | PromotionCodeUpdateRequest): string {
248
+ const sanitized = "code" in request && request.code.kind === "automatic"
249
+ ? { ...request, code: { kind: "automatic" } }
250
+ : request;
251
+ return createHash("sha256").update(JSON.stringify(sanitized)).digest("hex");
252
+ }
253
+ return { createAdminPromotionCodesListHandler, createAdminPromotionCodePreviewHandler, createAdminPromotionCodeCreateHandler, createAdminPromotionCodeUpdateHandler };
254
+ }
@@ -0,0 +1,121 @@
1
+
2
+ import { z } from "./validation.js";
3
+
4
+ import {
5
+ PROMOTION_APPLIES_TO_KINDS,
6
+ PROMOTION_DISCOUNT_TYPES,
7
+ PROMOTION_STACKING_RULES,
8
+ PROMOTION_TRIGGER_TYPES,
9
+ } from "@openlup/core/promo";
10
+
11
+ import { COMMERCE_CONTRACT_VERSION } from "../pricing/index.js";
12
+
13
+ /** Admin promotion schemas; raw adapter rows never cross this boundary. */
14
+
15
+
16
+ export function createAdminPromotionSchemas({ currencySchema: platformCurrencySchema }: { currencySchema: z.ZodType<string> }) {
17
+ const PROMOTION_STATUSES = ["draft", "active", "paused", "archived"] as const;
18
+
19
+ const jsonObjectSchema = z.record(z.string(), z.unknown());
20
+
21
+ const adminPromotionUnitTargetSchema = z.object({
22
+ variantId: z.string().min(1),
23
+ sku: z.string().nullable(),
24
+ referenceMinor: z.number().int().positive(),
25
+ targetMinor: z.number().int().nonnegative(),
26
+ currency: platformCurrencySchema,
27
+ });
28
+
29
+ const adminPromotionSemanticBenefitSchema = z.discriminatedUnion("kind", [
30
+ z.object({
31
+ kind: z.literal("target_percentage"),
32
+ valueBps: z.number().int().min(1).max(9_999),
33
+ reference: z.literal("catalog_list_price"),
34
+ unitTargets: z.array(adminPromotionUnitTargetSchema),
35
+ }),
36
+ z.object({
37
+ kind: z.literal("percentage"),
38
+ valuePercent: z.number().nonnegative(),
39
+ }),
40
+ z.object({
41
+ kind: z.literal("fixed_amount"),
42
+ valueMinor: z.number().nonnegative(),
43
+ currency: platformCurrencySchema,
44
+ }),
45
+ z.object({ kind: z.literal("free_shipping") }),
46
+ z.object({
47
+ kind: z.literal("unavailable"),
48
+ reason: z.literal("system_managed_metadata_incomplete"),
49
+ }),
50
+ ]);
51
+
52
+ /**
53
+ * Engine-v2 mirror paired to a system-managed legacy row. Exposes only what the
54
+ * deliberate human-operator activation/pause control needs; mirror semantics stay read-only.
55
+ */
56
+ const adminPromotionV2MirrorSchema = z.object({
57
+ id: z.string().min(1),
58
+ status: z.enum(PROMOTION_STATUSES),
59
+ });
60
+
61
+ /** One promotion as shown in the admin editor. */
62
+ const adminPromotionSchema = z.object({
63
+ id: z.string().min(1),
64
+ code: z.string().nullable(),
65
+ name: z.string(),
66
+ triggerType: z.enum(PROMOTION_TRIGGER_TYPES),
67
+ discountType: z.enum(PROMOTION_DISCOUNT_TYPES),
68
+ semanticBenefit: adminPromotionSemanticBenefitSchema,
69
+ systemManaged: z.boolean(),
70
+ readOnly: z.boolean(),
71
+ v2Mirror: adminPromotionV2MirrorSchema.nullable(),
72
+ appliesToKind: z.enum(PROMOTION_APPLIES_TO_KINDS),
73
+ stackingRule: z.enum(PROMOTION_STACKING_RULES),
74
+ eligibility: jsonObjectSchema,
75
+ validFrom: z.string(),
76
+ validTo: z.string().nullable(),
77
+ status: z.enum(PROMOTION_STATUSES),
78
+ regionAvailability: z.array(z.string()),
79
+ redemptionLimitGlobal: z.number().nullable(),
80
+ redemptionLimitPerCustomer: z.number().nullable(),
81
+ });
82
+
83
+ const adminPromotionsListResponseSchema = z.object({
84
+ contractVersion: z.literal(COMMERCE_CONTRACT_VERSION),
85
+ promotions: z.array(adminPromotionSchema),
86
+ });
87
+
88
+ /** Editable fields. Trigger/discount type and code are fixed in v1 (edit, not recreate). */
89
+ const adminPromotionUpdatePayloadSchema = z
90
+ .object({
91
+ name: z.string().trim().min(1).optional(),
92
+ discountValue: z.number().min(0).optional(),
93
+ stackingRule: z.enum(PROMOTION_STACKING_RULES).optional(),
94
+ status: z.enum(PROMOTION_STATUSES).optional(),
95
+ eligibility: jsonObjectSchema.optional(),
96
+ validFrom: z.string().optional(),
97
+ validTo: z.string().nullable().optional(),
98
+ redemptionLimitGlobal: z.number().int().positive().nullable().optional(),
99
+ redemptionLimitPerCustomer: z.number().int().positive().nullable().optional(),
100
+ })
101
+ .strict()
102
+ .refine((updates) => Object.values(updates).some((value) => value !== undefined), {
103
+ message: "At least one promotion field is required",
104
+ });
105
+
106
+ const adminPromotionUpdateRequestSchema = z
107
+ .object({
108
+ id: z.string().trim().min(1),
109
+ updates: adminPromotionUpdatePayloadSchema,
110
+ })
111
+ .strict();
112
+
113
+ const adminPromotionUpdateResponseSchema = z.object({
114
+ contractVersion: z.literal(COMMERCE_CONTRACT_VERSION),
115
+ updated: z.literal(true),
116
+ id: z.string().min(1),
117
+ });
118
+
119
+
120
+ return { PROMOTION_STATUSES, adminPromotionSemanticBenefitSchema, adminPromotionV2MirrorSchema, adminPromotionSchema, adminPromotionsListResponseSchema, adminPromotionUpdatePayloadSchema, adminPromotionUpdateRequestSchema, adminPromotionUpdateResponseSchema };
121
+ }
@@ -0,0 +1,48 @@
1
+ import type {
2
+ AdminPromotion,
3
+ AdminPromotionUpdatePayload,
4
+ AdminSubscriptionBandEntry,
5
+ } from "./contracts/index.js";
6
+
7
+ /**
8
+ * @agent-domain-anti-reference
9
+ * NOT THE REFERENCE — Promotions back-compat harness port (see
10
+ * `adminPromotionsHandler.ts`); copy the catalog `@agent-domain-reference` port.
11
+ *
12
+ * Server-side data access for the admin discounts editor. The
13
+ * host must provide promotion updates and atomic subscription-band writes.
14
+ * Promotion-edit audit recording is required: an audit failure must surface
15
+ * rather than silently turn into a successful unaudited edit.
16
+ */
17
+
18
+ export interface AdminPromotionsAuditEntry {
19
+ actorId: string;
20
+ actorEmail: string | null;
21
+ action: "promo_update" | "promo_status_change" | "shipping_rate_change";
22
+ promotionId: string;
23
+ newValue: Record<string, unknown>;
24
+ }
25
+
26
+ export interface AdminPromotionsDataPort {
27
+ listPromotions(): Promise<AdminPromotion[]>;
28
+ updatePromotion(id: string, updates: AdminPromotionUpdatePayload): Promise<void>;
29
+ listSubscriptionBand(): Promise<AdminSubscriptionBandEntry[]>;
30
+ setSubscriptionBandPercent(
31
+ percent: number,
32
+ ): Promise<{ updatedSkuCount: number; appliedPercent: number }>;
33
+ /** Flat shipping rate (gross minor units) from host settings; 0 when unset. */
34
+ getShippingFlatMinor(): Promise<number>;
35
+ /** Upsert the flat shipping rate (gross minor units). */
36
+ setShippingFlatMinor(minor: number): Promise<void>;
37
+ /**
38
+ * Set a SKU's one-time (list) price across the active price list via the
39
+ * host's append-only atomic writer. Subscription prices are untouched
40
+ * (re-apply the band to recompute them). The writer records its own audit row.
41
+ */
42
+ setCatalogPrice(input: {
43
+ actorId: string;
44
+ sku: string;
45
+ unitPriceMinor: number;
46
+ }): Promise<void>;
47
+ recordPromotionAudit(entry: AdminPromotionsAuditEntry): Promise<void>;
48
+ }
@@ -0,0 +1,72 @@
1
+ /** @agent-domain-anti-reference Promotion compatibility harness; use the catalog reference for new admin domains. */
2
+ import { COMMERCE_CONTRACT_VERSION } from "../pricing/index.js";
3
+ import type { createAdminPromotionSchemas } from "./adminPromotionsContracts.js";
4
+ import type { AdminPromotionUpdateRequest } from "./contracts/index.js";
5
+ import type { AgentDomainMutationSpec } from "./adminBindings.js";
6
+ import type { AuthorizeAdmin, PromotionAdminBindings } from "./adminBindings.js";
7
+ import type { AdminPromotionsDataPort } from "./adminPromotionsDataPort.js";
8
+ /** Human-admin promotion edits retain the required audit and the existing non-atomic update boundary. */
9
+
10
+ export interface AdminPromotionsListHandlerDeps {
11
+ dataPort: AdminPromotionsDataPort;
12
+ authorizeAdmin: AuthorizeAdmin;
13
+ }
14
+ export interface AdminPromotionUpdateHandlerDeps {
15
+ dataPort: AdminPromotionsDataPort;
16
+ authorizeAdmin: AuthorizeAdmin;
17
+ }
18
+
19
+ export function createAdminPromotionsHandlers({ createAdminMutationHandler, createAdminReadHandler, mapRpcError }: Pick<PromotionAdminBindings, "createAdminMutationHandler" | "createAdminReadHandler" | "mapRpcError">, { adminPromotionUpdateRequestSchema, adminPromotionUpdateResponseSchema, adminPromotionsListResponseSchema }: Pick<ReturnType<typeof createAdminPromotionSchemas>, "adminPromotionUpdateRequestSchema" | "adminPromotionUpdateResponseSchema" | "adminPromotionsListResponseSchema">) {
20
+ function createAdminPromotionsListHandler({
21
+ dataPort,
22
+ authorizeAdmin,
23
+ }: AdminPromotionsListHandlerDeps) {
24
+ return createAdminReadHandler({
25
+ authorizeAdmin,
26
+ load: () => dataPort.listPromotions(),
27
+ toResponse: (promotions) => ({ contractVersion: COMMERCE_CONTRACT_VERSION, promotions }),
28
+ responseSchema: adminPromotionsListResponseSchema,
29
+ invalidResponseMessage: "Admin promotions list returned invalid response",
30
+ failureMessage: "Admin promotions list failed",
31
+ });
32
+ }
33
+
34
+ const promotionUpdateMutation: AgentDomainMutationSpec<AdminPromotionUpdateRequest> = {
35
+ key: "update",
36
+ requestSchema: adminPromotionUpdateRequestSchema,
37
+ gate: "mutation",
38
+ allowedActorKinds: ["human"],
39
+ lifecycleMarkers: [],
40
+ };
41
+
42
+ function createAdminPromotionUpdateHandler({
43
+ dataPort,
44
+ authorizeAdmin,
45
+ }: AdminPromotionUpdateHandlerDeps) {
46
+ return createAdminMutationHandler<AdminPromotionUpdateRequest, { id: string }>({
47
+ mutation: promotionUpdateMutation,
48
+ authorizeAdmin,
49
+ invoke: async (actorId, input) => {
50
+ await dataPort.updatePromotion(input.id, input.updates);
51
+ const action =
52
+ input.updates.status !== undefined ? "promo_status_change" : "promo_update";
53
+ // Required, non-repudiable audit via the fn — no longer best-effort/swallowed.
54
+ await dataPort.recordPromotionAudit({
55
+ actorId,
56
+ actorEmail: null,
57
+ action,
58
+ promotionId: input.id,
59
+ newValue: input.updates as Record<string, unknown>,
60
+ });
61
+ return { id: input.id };
62
+ },
63
+ toResponse: ({ id }) => ({ contractVersion: COMMERCE_CONTRACT_VERSION, updated: true, id }),
64
+ responseSchema: adminPromotionUpdateResponseSchema,
65
+ invalidResponseMessage: "Admin promotion update returned invalid response",
66
+ invalidRequestMessage: "Invalid promotion update request",
67
+ failureMessage: "Admin promotion update failed",
68
+ mapError: mapRpcError,
69
+ });
70
+ }
71
+ return { createAdminPromotionsListHandler, createAdminPromotionUpdateHandler };
72
+ }