@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,46 @@
1
+ import type { HttpRequest, HttpResponse } from "../http/index.js";
2
+ import type { BffResponder } from "../bff/index.js";
3
+ import type { BundleResponseSchema } from "./adminBindings.js";
4
+ import type { SellableBundle } from "./contracts/bundleAvailability.js";
5
+ import type { BundleAvailability } from "./bundleAvailability.js";
6
+ import type { ActiveBundleComposition } from "./bundleCatalogReadPort.js";
7
+ import type { BundleAvailabilityService } from "./bundleAvailabilityService.js";
8
+ /**
9
+ * The public sellable-bundle feed handler, shaped after the reference catalog
10
+ * handler: GET-only, one
11
+ * port call, validate the body before sending, and never serve an unvalidated
12
+ * shape.
13
+ *
14
+ * It composes rather than computes twice: the availability service already folds
15
+ * one batched stock answer into the live compositions, and the pricing kernel
16
+ * turns the stored target price into per-component money. This module only decides
17
+ * what a storefront is allowed to see.
18
+ *
19
+ * A bundle whose money cannot be derived is DROPPED from the feed, not published
20
+ * with a guessed figure. Three cases reach that door — an unpriced component, an
21
+ * empty composition, and a target price the kernel refuses — and all three mean
22
+ * the same thing to a storefront: this is not sellable today. Publishing it with a
23
+ * partial price would put a number on a shelf that no order line could reproduce.
24
+ */
25
+ export interface SellableBundleHandlerDeps {
26
+ availabilityService: BundleAvailabilityService;
27
+ /** Narrow the feed to one currency; omitted means every currency an operator priced. */
28
+ currency?: string;
29
+ enabled: boolean;
30
+ }
31
+ export declare function createSellableBundleHandlers({ responder, sellableBundleListResponseSchema, SELLABLE_BUNDLE_CONTRACT_VERSION }: {
32
+ responder: BffResponder;
33
+ sellableBundleListResponseSchema: BundleResponseSchema;
34
+ SELLABLE_BUNDLE_CONTRACT_VERSION: "catalog.sellable-bundle.v1";
35
+ }): {
36
+ createSellableBundleHandler: (deps: SellableBundleHandlerDeps) => (req: HttpRequest, res: HttpResponse) => Promise<void>;
37
+ };
38
+ /**
39
+ * Derive the row a storefront sees, or `null` when the money cannot be stated.
40
+ *
41
+ * The allocator emits TWO lines for a quantity whose subtotal does not divide
42
+ * evenly, which is exactly why the feed carries lines rather than a unit price per
43
+ * component: `unitPrice x quantity === lineSubtotal` holds on every line, and the
44
+ * lines sum to the bundle's price with no remainder.
45
+ */
46
+ export declare function toSellableBundle(composition: ActiveBundleComposition, availability: BundleAvailability): SellableBundle | null;
@@ -0,0 +1,84 @@
1
+ import { allocateBundleTargetPrice } from "@openlup/core/pricing";
2
+ export function createSellableBundleHandlers({ responder, sellableBundleListResponseSchema, SELLABLE_BUNDLE_CONTRACT_VERSION }) {
3
+ const { sendBffError, sendBffSuccess, sendMethodNotAllowed } = responder;
4
+ function createSellableBundleHandler(deps) {
5
+ return async function handler(req, res) {
6
+ if (req.method !== "GET") {
7
+ sendMethodNotAllowed(res, ["GET"]);
8
+ return;
9
+ }
10
+ if (!deps.enabled) {
11
+ sendBffError(res, "UPSTREAM_UNAVAILABLE", "Bundle reads are disabled", {
12
+ details: { reason: "feature_flag_disabled", featureFlag: "COMMERCE_BUNDLE_READ_ENABLED" },
13
+ });
14
+ return;
15
+ }
16
+ try {
17
+ const rows = await deps.availabilityService.describeActiveBundles(deps.currency ? { currency: deps.currency } : {});
18
+ const response = sellableBundleListResponseSchema.safeParse({
19
+ contractVersion: SELLABLE_BUNDLE_CONTRACT_VERSION,
20
+ bundles: rows
21
+ .map((row) => toSellableBundle(row.composition, row.availability))
22
+ .filter((bundle) => bundle !== null),
23
+ });
24
+ if (!response.success) {
25
+ sendBffError(res, "INVALID_RESPONSE", "Sellable bundle feed returned an invalid shape");
26
+ return;
27
+ }
28
+ sendBffSuccess(res, response.data, { contractVersion: SELLABLE_BUNDLE_CONTRACT_VERSION }, { cacheControl: "no-store" });
29
+ }
30
+ catch {
31
+ sendBffError(res, "UPSTREAM_UNAVAILABLE", "Sellable bundles are unavailable");
32
+ }
33
+ };
34
+ }
35
+ return { createSellableBundleHandler };
36
+ }
37
+ /**
38
+ * Derive the row a storefront sees, or `null` when the money cannot be stated.
39
+ *
40
+ * The allocator emits TWO lines for a quantity whose subtotal does not divide
41
+ * evenly, which is exactly why the feed carries lines rather than a unit price per
42
+ * component: `unitPrice x quantity === lineSubtotal` holds on every line, and the
43
+ * lines sum to the bundle's price with no remainder.
44
+ */
45
+ export function toSellableBundle(composition, availability) {
46
+ if (composition.components.length === 0)
47
+ return null;
48
+ if (composition.components.some((component) => component.referenceUnitPriceMinor === null)) {
49
+ return null;
50
+ }
51
+ const allocation = allocateBundleTargetPrice({
52
+ components: composition.components.map((component) => ({
53
+ sku: component.sku,
54
+ quantity: component.quantity,
55
+ unitPriceMinor: component.referenceUnitPriceMinor,
56
+ })),
57
+ targetPriceMinor: composition.targetPriceMinor,
58
+ });
59
+ if (!allocation.ok)
60
+ return null;
61
+ // Basis points come from the per-component allocation, so a component split
62
+ // across two lines reports the same discount on both halves rather than two
63
+ // rounded figures that disagree.
64
+ const discountBpsBySku = new Map(allocation.components.map((component) => [component.sku, component.discountBps]));
65
+ return {
66
+ code: composition.code,
67
+ title: composition.title,
68
+ fulfillmentMode: composition.fulfillmentMode,
69
+ price: { amountMinor: composition.targetPriceMinor, currency: composition.currency },
70
+ components: allocation.lines.map((line) => ({
71
+ sku: line.sku,
72
+ quantity: line.quantity,
73
+ effectiveUnitPriceMinor: line.effectiveUnitPriceMinor,
74
+ lineSubtotalMinor: line.lineSubtotalMinor,
75
+ discountBps: discountBpsBySku.get(line.sku) ?? 0,
76
+ })),
77
+ availability: {
78
+ status: availability.status,
79
+ sellableNow: availability.sellableNow,
80
+ limitingSku: availability.limitingSku,
81
+ reasonCode: availability.reasonCode,
82
+ },
83
+ };
84
+ }
@@ -0,0 +1,46 @@
1
+ import { z } from "./validation.js";
2
+ export { SELLABLE_CATALOG_CONTRACT_VERSION } from "./contracts/sellable.js";
3
+ export type { SellableCatalogItem, SellableCatalogProfile, SellableCatalogListResponse } from "./contracts/sellable.js";
4
+ export declare const sellableCatalogItemSchema: z.ZodObject<{
5
+ sku: z.ZodString;
6
+ title: z.ZodString;
7
+ unitPrice: z.ZodObject<{
8
+ amountMinor: z.ZodNumber;
9
+ currency: z.ZodString;
10
+ }, z.core.$strict>;
11
+ permittedPurchaseModes: z.ZodArray<z.ZodEnum<{
12
+ subscription: "subscription";
13
+ one_time: "one_time";
14
+ }>>;
15
+ }, z.core.$strict>;
16
+ export declare const sellableCatalogProfileSchema: z.ZodObject<{
17
+ id: z.ZodString;
18
+ brand: z.ZodString;
19
+ country: z.ZodString;
20
+ currency: z.ZodString;
21
+ locale: z.ZodString;
22
+ timezone: z.ZodString;
23
+ }, z.core.$strict>;
24
+ export declare const sellableCatalogListResponseSchema: z.ZodObject<{
25
+ contractVersion: z.ZodLiteral<"catalog.sellable.v1">;
26
+ profile: z.ZodObject<{
27
+ id: z.ZodString;
28
+ brand: z.ZodString;
29
+ country: z.ZodString;
30
+ currency: z.ZodString;
31
+ locale: z.ZodString;
32
+ timezone: z.ZodString;
33
+ }, z.core.$strict>;
34
+ items: z.ZodArray<z.ZodObject<{
35
+ sku: z.ZodString;
36
+ title: z.ZodString;
37
+ unitPrice: z.ZodObject<{
38
+ amountMinor: z.ZodNumber;
39
+ currency: z.ZodString;
40
+ }, z.core.$strict>;
41
+ permittedPurchaseModes: z.ZodArray<z.ZodEnum<{
42
+ subscription: "subscription";
43
+ one_time: "one_time";
44
+ }>>;
45
+ }, z.core.$strict>>;
46
+ }, z.core.$strict>;
@@ -0,0 +1,27 @@
1
+ import { z } from "./validation.js";
2
+ import { SELLABLE_CATALOG_CONTRACT_VERSION } from "./contracts/sellable.js";
3
+ export { SELLABLE_CATALOG_CONTRACT_VERSION } from "./contracts/sellable.js";
4
+ /** Minimal neutral storefront wire schema. */
5
+ const sellableCatalogMoneySchema = z.object({
6
+ amountMinor: z.number().int().nonnegative(),
7
+ currency: z.string().regex(/^[A-Z]{3}$/),
8
+ }).strict();
9
+ export const sellableCatalogItemSchema = z.object({
10
+ sku: z.string().trim().min(1).max(128).regex(/^[a-zA-Z0-9._:-]+$/),
11
+ title: z.string().trim().min(1).max(160),
12
+ unitPrice: sellableCatalogMoneySchema,
13
+ permittedPurchaseModes: z.array(z.enum(["one_time", "subscription"])).min(1).max(2),
14
+ }).strict();
15
+ export const sellableCatalogProfileSchema = z.object({
16
+ id: z.string().trim().min(1).max(120),
17
+ brand: z.string().trim().min(1).max(160),
18
+ country: z.string().regex(/^[A-Z]{2}$/),
19
+ currency: z.string().regex(/^[A-Z]{3}$/),
20
+ locale: z.string().trim().min(2).max(35),
21
+ timezone: z.string().trim().min(1).max(80),
22
+ }).strict();
23
+ export const sellableCatalogListResponseSchema = z.object({
24
+ contractVersion: z.literal(SELLABLE_CATALOG_CONTRACT_VERSION),
25
+ profile: sellableCatalogProfileSchema,
26
+ items: z.array(sellableCatalogItemSchema).min(1),
27
+ }).strict();
@@ -0,0 +1,46 @@
1
+ /** Sparse projections of canonical units, never an install chain. */
2
+ export declare const BUNDLE_MIGRATIONS: readonly [{
3
+ readonly id: "20260812140000_sellable_bundle_catalog";
4
+ readonly catalogPath: "db/platform/migrations/20260812140000_sellable_bundle_catalog.sql";
5
+ readonly position: 16;
6
+ readonly sha256: "62fbf0910a3a7a2ee47e2d798933fe0a5a273fd1242cae7cc78ff237ba39e394";
7
+ readonly url: URL;
8
+ }, {
9
+ readonly id: "20260812210000_bundle_operator_write_boundary";
10
+ readonly catalogPath: "db/platform/migrations/20260812210000_bundle_operator_write_boundary.sql";
11
+ readonly position: 19;
12
+ readonly sha256: "d0ec6674d7eedf4cd3ce0d8ccd7345ebe2f93da635316a68a6bd178ec55b2679";
13
+ readonly url: URL;
14
+ }];
15
+ /** Catalog foundation projections; install the complete canonical catalogue. */
16
+ export declare const CATALOG_MIGRATIONS: readonly [{
17
+ readonly id: "20260807140000_read_parity_catalog";
18
+ readonly catalogPath: "db/platform/migrations/20260807140000_read_parity_catalog.sql";
19
+ readonly position: 1;
20
+ readonly sha256: "fcf3827028c1651ae42a7c7d7472153825a3121c936d58a3d105befc7dece9ea";
21
+ readonly url: URL;
22
+ }, {
23
+ readonly id: "20260810120000_storefront_catalog_attributes";
24
+ readonly catalogPath: "db/platform/migrations/20260810120000_storefront_catalog_attributes.sql";
25
+ readonly position: 8;
26
+ readonly sha256: "2bf938f5d0076193557bea834f86dbd9bcb7f3e2de00f99fb91cc1229b93a14b";
27
+ readonly url: URL;
28
+ }, {
29
+ readonly id: "20260827220000_catalog_document_revision_foundation";
30
+ readonly catalogPath: "db/platform/migrations/20260827220000_catalog_document_revision_foundation.sql";
31
+ readonly position: 58;
32
+ readonly sha256: "715e74d655b76d35b8a49e0d2a5625594a6c4856863f369cd1eadcd1fb1ae90e";
33
+ readonly url: URL;
34
+ }, {
35
+ readonly id: "20260827220001_catalog_document_revision_foundation_validate";
36
+ readonly catalogPath: "db/platform/migrations/20260827220001_catalog_document_revision_foundation_validate.sql";
37
+ readonly position: 59;
38
+ readonly sha256: "f3cd7fb61dcebac1cf0468cf2d7c1f9dd036817ab0094c72864266e307b269de";
39
+ readonly url: URL;
40
+ }, {
41
+ readonly id: "20260908100000_catalog_draft_foundation";
42
+ readonly catalogPath: "db/platform/migrations/20260908100000_catalog_draft_foundation.sql";
43
+ readonly position: 61;
44
+ readonly sha256: "ac0d614cdb2874df8fbdbbbda4f9455986ef95241fe1334b0b54a1fa6478ab2e";
45
+ readonly url: URL;
46
+ }];
@@ -0,0 +1,13 @@
1
+ /** Sparse projections of canonical units, never an install chain. */
2
+ export const BUNDLE_MIGRATIONS = [
3
+ { id: "20260812140000_sellable_bundle_catalog", catalogPath: "db/platform/migrations/20260812140000_sellable_bundle_catalog.sql", position: 16, sha256: "62fbf0910a3a7a2ee47e2d798933fe0a5a273fd1242cae7cc78ff237ba39e394", url: new URL("../../sql/20260812140000_sellable_bundle_catalog.sql", import.meta.url) },
4
+ { id: "20260812210000_bundle_operator_write_boundary", catalogPath: "db/platform/migrations/20260812210000_bundle_operator_write_boundary.sql", position: 19, sha256: "d0ec6674d7eedf4cd3ce0d8ccd7345ebe2f93da635316a68a6bd178ec55b2679", url: new URL("../../sql/20260812210000_bundle_operator_write_boundary.sql", import.meta.url) },
5
+ ];
6
+ /** Catalog foundation projections; install the complete canonical catalogue. */
7
+ export const CATALOG_MIGRATIONS = [
8
+ { id: "20260807140000_read_parity_catalog", catalogPath: "db/platform/migrations/20260807140000_read_parity_catalog.sql", position: 1, sha256: "fcf3827028c1651ae42a7c7d7472153825a3121c936d58a3d105befc7dece9ea", url: new URL("../../sql/20260807140000_read_parity_catalog.sql", import.meta.url) },
9
+ { id: "20260810120000_storefront_catalog_attributes", catalogPath: "db/platform/migrations/20260810120000_storefront_catalog_attributes.sql", position: 8, sha256: "2bf938f5d0076193557bea834f86dbd9bcb7f3e2de00f99fb91cc1229b93a14b", url: new URL("../../sql/20260810120000_storefront_catalog_attributes.sql", import.meta.url) },
10
+ { id: "20260827220000_catalog_document_revision_foundation", catalogPath: "db/platform/migrations/20260827220000_catalog_document_revision_foundation.sql", position: 58, sha256: "715e74d655b76d35b8a49e0d2a5625594a6c4856863f369cd1eadcd1fb1ae90e", url: new URL("../../sql/20260827220000_catalog_document_revision_foundation.sql", import.meta.url) },
11
+ { id: "20260827220001_catalog_document_revision_foundation_validate", catalogPath: "db/platform/migrations/20260827220001_catalog_document_revision_foundation_validate.sql", position: 59, sha256: "f3cd7fb61dcebac1cf0468cf2d7c1f9dd036817ab0094c72864266e307b269de", url: new URL("../../sql/20260827220001_catalog_document_revision_foundation_validate.sql", import.meta.url) },
12
+ { id: "20260908100000_catalog_draft_foundation", catalogPath: "db/platform/migrations/20260908100000_catalog_draft_foundation.sql", position: 61, sha256: "ac0d614cdb2874df8fbdbbbda4f9455986ef95241fe1334b0b54a1fa6478ab2e", url: new URL("../../sql/20260908100000_catalog_draft_foundation.sql", import.meta.url) },
13
+ ];
@@ -0,0 +1,2 @@
1
+ import { z } from "zod";
2
+ export { z };
@@ -0,0 +1,3 @@
1
+ import { z } from "zod";
2
+ z.config({ jitless: true });
3
+ export { z };
@@ -49,3 +49,4 @@ export * from "./invoiceDocumentContent.js";
49
49
  export * from "./roleNotificationContent.js";
50
50
  export * from "./inquiryContent.js";
51
51
  export * from "./optOutContent.js";
52
+ export type * from "./marketingSync.js";
@@ -0,0 +1,194 @@
1
+ declare const subjectBrand: unique symbol, feedbackBrand: unique symbol, receiptBrand: unique symbol, readBrand: unique symbol;
2
+ type Operation = "profile.sync" | "consent.read" | "erasure.request" | "erasure.read";
3
+ type Mutation = "profile.sync" | "erasure.request";
4
+ type SubjectReference = string & {
5
+ readonly [subjectBrand]: "opaque-subject";
6
+ };
7
+ export type SyncBinding = Readonly<{
8
+ account: string;
9
+ environment: string;
10
+ namespace: string;
11
+ mappingVersion: string;
12
+ }>;
13
+ export type SyncAudience = Readonly<{
14
+ kind: "account-wide";
15
+ } | {
16
+ kind: "audience";
17
+ reference: string;
18
+ }>;
19
+ export type ProfileProjection = Readonly<{
20
+ email: string;
21
+ externalReference: string;
22
+ fields: Readonly<Partial<Record<"givenName" | "familyName" | "locale", string>>>;
23
+ properties: Readonly<Record<string, string | number | boolean>>;
24
+ }>;
25
+ type Payload = {
26
+ "profile.sync": {
27
+ projection: ProfileProjection;
28
+ consentEvidenceReference: string;
29
+ };
30
+ "consent.read": Readonly<Record<string, never>>;
31
+ "erasure.request": {
32
+ caseReference: string;
33
+ authorityReference: string;
34
+ };
35
+ "erasure.read": {
36
+ receipt: SyncReceipt<"erasure.request">;
37
+ };
38
+ };
39
+ export type SyncRequest<O extends Operation = Operation> = {
40
+ [K in O]: Readonly<{
41
+ binding: SyncBinding;
42
+ audience: SyncAudience;
43
+ subjectReference: SubjectReference;
44
+ requestId: string;
45
+ generation: number;
46
+ deadlineMs: number;
47
+ authorizationReference: string;
48
+ operation: K;
49
+ payload: Readonly<Payload[K]>;
50
+ }>;
51
+ }[O];
52
+ export type NegativeFeedback = Readonly<{
53
+ [feedbackBrand]: "provider-negative";
54
+ sourceReference: string;
55
+ occurredAtMs: number | null;
56
+ audience: SyncAudience;
57
+ }> & Readonly<{
58
+ kind: "unsubscribe" | "complaint" | "manual_block";
59
+ outcome: "deny_permission";
60
+ } | {
61
+ kind: "hard_bounce" | "invalid_address";
62
+ outcome: "deny_delivery";
63
+ }>;
64
+ export type ConsentReadback = Readonly<{
65
+ audience: SyncAudience;
66
+ observedAtMs: number;
67
+ remoteConsent: "subscribed" | "unsubscribed" | "pending" | "never_subscribed" | "unknown";
68
+ feedback: readonly NegativeFeedback[];
69
+ coverage: "complete" | "partial" | "unsupported";
70
+ }>;
71
+ export type SyncFailure<O extends Operation = Operation> = {
72
+ kind: "refused";
73
+ reason: "invalid_request" | "binding" | "provenance" | "stale" | "deadline" | "unsupported" | "verification_pending" | "restricted" | "identity_conflict" | "provider_refusal";
74
+ } | {
75
+ kind: "retryable";
76
+ reason: "cooling" | "host" | "provider";
77
+ afterSeconds: number;
78
+ } | ({
79
+ kind: "unknown";
80
+ reason: "dispatch_unresolved" | "acceptance_ambiguous" | "record_failed";
81
+ } & (O extends Mutation ? {
82
+ receipt?: SyncReceipt<O>;
83
+ } : {
84
+ receipt?: never;
85
+ }));
86
+ export type SyncReceipt<O extends Mutation> = Readonly<{
87
+ [receiptBrand]: O;
88
+ operation: O;
89
+ request: SyncRequest<O>;
90
+ }>;
91
+ type MutationSuccess<O extends Mutation> = {
92
+ kind: "accepted" | "acknowledged";
93
+ receipt: SyncReceipt<O>;
94
+ journal: "confirmed" | "unknown";
95
+ };
96
+ type Success = {
97
+ "profile.sync": MutationSuccess<"profile.sync">;
98
+ "consent.read": {
99
+ kind: "completed";
100
+ value: ConsentReadback;
101
+ journal: "confirmed" | "unknown";
102
+ };
103
+ "erasure.request": MutationSuccess<"erasure.request">;
104
+ "erasure.read": MutationSuccess<"erasure.request"> | {
105
+ kind: "completed";
106
+ receipt: SyncReceipt<"erasure.request">;
107
+ journal: "confirmed" | "unknown";
108
+ evidence: Readonly<{
109
+ [readBrand]: "provider-read";
110
+ readRequestId: string;
111
+ observedAtMs: number;
112
+ evidenceReference: string;
113
+ assurance: "provider_record_deleted" | "provider_erasure_confirmed";
114
+ }>;
115
+ };
116
+ };
117
+ export type SyncResult<O extends Operation = Operation> = {
118
+ [K in O]: Readonly<Pick<SyncRequest<K>, "binding" | "operation" | "subjectReference" | "requestId" | "generation">> & Readonly<Success[K] | SyncFailure<K>>;
119
+ }[O];
120
+ export type SyncCapabilities = Readonly<{
121
+ binding: SyncBinding;
122
+ audience: SyncAudience;
123
+ operations: Readonly<Record<Operation, {
124
+ state: "supported";
125
+ evidenceReference: string;
126
+ maxRequestBytes: number;
127
+ maxFeedbackItems: number;
128
+ } | {
129
+ state: "unsupported" | "verification_pending";
130
+ }>>;
131
+ }>;
132
+ export interface ProfileSyncPort {
133
+ sync(request: SyncRequest<"profile.sync">): Promise<SyncResult<"profile.sync">>;
134
+ }
135
+ export interface ConsentReadPort {
136
+ read(request: SyncRequest<"consent.read">): Promise<SyncResult<"consent.read">>;
137
+ }
138
+ export interface ErasurePort {
139
+ request(request: SyncRequest<"erasure.request">): Promise<SyncResult<"erasure.request">>;
140
+ read(request: SyncRequest<"erasure.read">): Promise<SyncResult<"erasure.read">>;
141
+ }
142
+ export interface MarketingSyncProvider {
143
+ readonly capabilities: SyncCapabilities;
144
+ readonly profiles: ProfileSyncPort;
145
+ readonly consent: ConsentReadPort;
146
+ readonly erasure: ErasurePort;
147
+ }
148
+ export type ConsentPushRequest = Readonly<Omit<SyncRequest<"profile.sync">, "operation" | "audience" | "payload"> & {
149
+ operation: "consent.push";
150
+ } & ({
151
+ audience: Extract<SyncAudience, {
152
+ kind: "audience";
153
+ }>;
154
+ payload: Readonly<{
155
+ action: "grant";
156
+ consentEvidenceReference: string;
157
+ }>;
158
+ } | {
159
+ audience: SyncAudience;
160
+ payload: Readonly<{
161
+ action: "withdraw";
162
+ consentEvidenceReference: string;
163
+ }>;
164
+ })>;
165
+ declare const pushReceiptBrand: unique symbol;
166
+ type PushReceipt = Readonly<{
167
+ [pushReceiptBrand]: "consent.push";
168
+ operation: "consent.push";
169
+ request: ConsentPushRequest;
170
+ }>;
171
+ type PushFailure = Exclude<SyncFailure, {
172
+ kind: "unknown";
173
+ }> | (Omit<Extract<SyncFailure, {
174
+ kind: "unknown";
175
+ }>, "receipt"> & {
176
+ receipt?: PushReceipt;
177
+ });
178
+ export type ConsentPushResult = Readonly<Pick<ConsentPushRequest, "binding" | "operation" | "subjectReference" | "requestId" | "generation">> & Readonly<{
179
+ kind: "accepted" | "acknowledged";
180
+ receipt: PushReceipt;
181
+ journal: "confirmed" | "unknown";
182
+ reconcileRequired: boolean;
183
+ } | PushFailure>;
184
+ export interface ConsentPushPort {
185
+ readonly capabilities: SyncCapabilities & Readonly<{
186
+ operations: SyncCapabilities["operations"] & Readonly<{
187
+ "consent.push": SyncCapabilities["operations"]["profile.sync"] & Readonly<{
188
+ grantEffect: "audience" | "account-wide";
189
+ }>;
190
+ }>;
191
+ }>;
192
+ push(request: ConsentPushRequest): Promise<ConsentPushResult>;
193
+ }
194
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -44,3 +44,4 @@ export * from "./postgresDeliveryReconciliation.js";
44
44
  export * from "./postgresCommunicationSync.js";
45
45
  export * from "./postgresNotificationRecipients.js";
46
46
  export * from "./postgresConsentEvaluator.js";
47
+ export type * from "./contracts/marketingSync.js";
@@ -0,0 +1,51 @@
1
+ import type { ConsentPushRequest } from "../contracts/marketingSync.js";
2
+ /** Private singleton translation. Local evidence is deliberately absent from wire attributes. */
3
+ export declare function consentCommand(request: ConsentPushRequest, target: {
4
+ id: string;
5
+ email: string;
6
+ }, listId: string | undefined): {
7
+ method: string;
8
+ path: string;
9
+ expected: number[];
10
+ body: {
11
+ data: {
12
+ type: string;
13
+ id: string;
14
+ }[];
15
+ };
16
+ } | {
17
+ method: string;
18
+ path: string;
19
+ expected: number[];
20
+ body: {
21
+ data: {
22
+ relationships?: {
23
+ list: {
24
+ data: {
25
+ type: string;
26
+ id: string | undefined;
27
+ };
28
+ };
29
+ } | undefined;
30
+ type: string;
31
+ attributes: {
32
+ profiles: {
33
+ data: {
34
+ attributes: {
35
+ email: string;
36
+ subscriptions: {
37
+ email: {
38
+ marketing: {
39
+ consent: string;
40
+ };
41
+ };
42
+ };
43
+ };
44
+ id?: string | undefined;
45
+ type: string;
46
+ }[];
47
+ };
48
+ };
49
+ };
50
+ };
51
+ };
@@ -0,0 +1,19 @@
1
+ /** Private singleton translation. Local evidence is deliberately absent from wire attributes. */
2
+ export function consentCommand(request, target, listId) {
3
+ if (request.payload.action === "withdraw" && request.audience.kind === "audience") {
4
+ if (!listId)
5
+ throw new Error("scope");
6
+ return { method: "DELETE", path: `/api/lists/${listId}/relationships/profiles`, expected: [204],
7
+ body: { data: [{ type: "profile", id: target.id }] } };
8
+ }
9
+ const grant = request.payload.action === "grant";
10
+ const type = grant ? "profile-subscription-bulk-create-job" : "profile-subscription-bulk-delete-job";
11
+ if (grant && !listId)
12
+ throw new Error("scope");
13
+ return { method: "POST", path: `/api/${type}s`, expected: [202], body: { data: { type,
14
+ attributes: { profiles: { data: [{ type: "profile", ...(grant ? { id: target.id } : {}), attributes: {
15
+ email: target.email, subscriptions: { email: { marketing: { consent: grant ? "SUBSCRIBED" : "UNSUBSCRIBED" } } },
16
+ } }] } },
17
+ ...(grant ? { relationships: { list: { data: { type: "list", id: listId } } } } : {}),
18
+ } } };
19
+ }
@@ -0,0 +1,110 @@
1
+ import type { ConsentPushPort, ConsentPushRequest, MarketingSyncProvider, ProfileProjection, SyncAudience, SyncBinding, SyncRequest } from "../contracts/marketingSync.js";
2
+ import type { MarketingAutomationClaim, MarketingAutomationProviderPort, MarketingAutomationScope } from "../contracts/marketingAutomation.js";
3
+ import type { NewsletterSyncProviderPort } from "../contracts/newsletter.js";
4
+ type Request = SyncRequest | ConsentPushRequest;
5
+ type Operation = Request["operation"];
6
+ type Subject = {
7
+ binding: SyncBinding;
8
+ subjectReference: string;
9
+ generation: number;
10
+ erased: boolean;
11
+ id?: string;
12
+ email: string;
13
+ externalReference: string;
14
+ ownedFields: readonly (keyof ProfileProjection["fields"])[];
15
+ ownedProperties: readonly string[];
16
+ };
17
+ type LocalEvidence = {
18
+ binding: SyncBinding;
19
+ subjectReference: string;
20
+ audience: SyncAudience;
21
+ purpose: string;
22
+ action: "profile" | "grant" | "withdraw" | "erase";
23
+ current: boolean;
24
+ projection?: ProfileProjection;
25
+ caseReference?: string;
26
+ authorityReference?: string;
27
+ allPurposes?: boolean;
28
+ };
29
+ type Authorization = {
30
+ binding: SyncBinding;
31
+ subjectReference: string;
32
+ audience: SyncAudience;
33
+ operation: Operation;
34
+ expiresAtMs: number;
35
+ };
36
+ type Verification = {
37
+ binding: SyncBinding;
38
+ audience: SyncAudience;
39
+ evidenceReference: string;
40
+ revision: string;
41
+ operations: readonly Exclude<Operation, "erasure.read">[];
42
+ scopes: readonly string[];
43
+ noTrigger: {
44
+ profile: boolean;
45
+ accountWideGrant: boolean;
46
+ doi: boolean;
47
+ };
48
+ safeCreate: boolean;
49
+ safeListRemoval: boolean;
50
+ suppressionSafeAtEffect: boolean;
51
+ negativeSourcesComplete: boolean;
52
+ listMappings: Readonly<Record<string, SyncAudience>>;
53
+ };
54
+ type Storage = {
55
+ /** Shared plain mutable record for this account/environment, independent of CAS failure.
56
+ * Start quarantined after host restart; only explicit host reconciliation clears it.
57
+ * Every adapter namespace/instance uses the same record. Never reset it at construction. */
58
+ availability: {
59
+ account: string;
60
+ environment: string;
61
+ busy: boolean;
62
+ quarantined: boolean;
63
+ };
64
+ /** Shared across every adapter for the account. false proves no commit; throws may have committed. */
65
+ get(key: string): Promise<string | null>;
66
+ compareAndSwap(key: string, expected: string | null, value: string): Promise<boolean>;
67
+ };
68
+ type Configuration = {
69
+ binding: SyncBinding;
70
+ audience: SyncAudience;
71
+ /** Synchronous current host registry lookup; never parses an opaque subject reference. */
72
+ subjectMapper(subjectReference: string): Subject | undefined;
73
+ resolveCredential(): {
74
+ binding: SyncBinding;
75
+ key: string;
76
+ } | undefined;
77
+ authorizations: ReadonlyMap<string, Authorization>;
78
+ localEvidence: ReadonlyMap<string, LocalEvidence>;
79
+ storage: Storage;
80
+ verification?: Verification;
81
+ /** Private authenticated settlement facts from the host's existing reconciliation journal. */
82
+ grantSettlements?: ReadonlyMap<string, {
83
+ binding: SyncBinding;
84
+ subjectReference: string;
85
+ requestId: string;
86
+ source: "provider-read";
87
+ evidenceReference: string;
88
+ settledAtMs: number;
89
+ }>;
90
+ fetch?: typeof fetch;
91
+ now?: () => number;
92
+ maxRequestBytes?: number;
93
+ maxResponseBytes?: number;
94
+ maxFeedbackItems?: number;
95
+ timeoutMs?: number;
96
+ rateIntervalMs?: number;
97
+ legacy?: {
98
+ scope: MarketingAutomationScope;
99
+ claims: ReadonlyMap<string, {
100
+ claim: MarketingAutomationClaim;
101
+ request: Request;
102
+ }>;
103
+ };
104
+ };
105
+ /** Opt-in Node adapter; owner TEST evidence is required before any bound operation is enabled. */
106
+ export declare function createKlaviyoMarketingAdapter(input: Configuration): MarketingSyncProvider & MarketingAutomationProviderPort & {
107
+ readonly consentPush: ConsentPushPort;
108
+ readonly newsletter: NewsletterSyncProviderPort;
109
+ };
110
+ export {};