@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,247 @@
1
+ /** Local, bounded source-resource transfer. Uploading bytes never activates associations. */
2
+ import { constants, promises as fs } from "node:fs";
3
+ import { createHash } from "node:crypto";
4
+ import { isAbsolute, resolve, sep } from "node:path";
5
+ import { resolveProductMedia } from "./contracts/resolveProductMedia.js";
6
+ import { validateProductMediaManifest, PRODUCT_MEDIA_LIMITS, } from "./contracts/productMediaContracts.js";
7
+ export const SOURCE_PACK_LIMITS = PRODUCT_MEDIA_LIMITS;
8
+ export class CatalogMediaSourcePackError extends Error {
9
+ code;
10
+ reference;
11
+ constructor(code, reference) {
12
+ super(reference ? `${code}:${reference}` : code);
13
+ this.code = code;
14
+ this.reference = reference;
15
+ this.name = "CatalogMediaSourcePackError";
16
+ }
17
+ }
18
+ const refuse = (code, reference) => {
19
+ throw new CatalogMediaSourcePackError(code, reference);
20
+ };
21
+ const digest = (bytes) => createHash("sha256").update(bytes).digest("hex");
22
+ const extensions = { "image/png": "png", "image/jpeg": "jpg", "image/webp": "webp" };
23
+ const keyFor = (asset) => `assets/${asset.sha256}.${extensions[asset.contentType]}`;
24
+ function normalized(manifest) {
25
+ return {
26
+ schemaVersion: manifest.schemaVersion,
27
+ products: manifest.products.map(({ productId, variantIds, primaryVariantId }) => ({ productId, variantIds: [...variantIds], primaryVariantId })),
28
+ assets: manifest.assets.map(({ assetRef, source, contentType, byteLength, sha256, artworkLocale }) => ({ assetRef, source, contentType, byteLength, sha256, artworkLocale })),
29
+ associations: manifest.associations.map(({ itemId, assetRef, productId, scope, variantId, locale, role, viewKey, order, label }) => ({
30
+ itemId, assetRef, productId, scope, ...(variantId === undefined ? {} : { variantId }),
31
+ locale, role, ...(viewKey === undefined ? {} : { viewKey }), order, label,
32
+ })),
33
+ };
34
+ }
35
+ function checkedManifest(value) {
36
+ const manifest = normalized(validateProductMediaManifest(value));
37
+ const envelope = { schemaVersion: "catalog.media-source-pack.v1", manifest: {
38
+ ...manifest, assets: manifest.assets.map((asset) => ({ ...asset, source: keyFor(asset) })),
39
+ } };
40
+ if (Buffer.byteLength(JSON.stringify(manifest)) > SOURCE_PACK_LIMITS.manifestBytes ||
41
+ Buffer.byteLength(JSON.stringify(envelope, null, 2) + "\n") > SOURCE_PACK_LIMITS.manifestBytes)
42
+ refuse("pack_limit_exceeded");
43
+ const checks = manifest.products.map((product) => {
44
+ const items = manifest.associations.filter((item) => item.productId === product.productId);
45
+ const locales = new Set(items.flatMap((item) => item.locale === null ? [] : [item.locale]));
46
+ let neutralIndex = 0;
47
+ while (locales.has(`source-pack-neutral-${neutralIndex}`))
48
+ neutralIndex++;
49
+ locales.add(`source-pack-neutral-${neutralIndex}`);
50
+ return { product, locales };
51
+ });
52
+ // Bound processing before any full resolver pass, resource read or upload.
53
+ const expandedChecks = checks.reduce((total, { product, locales }) => total + product.variantIds.length * locales.size, 0);
54
+ if (expandedChecks > SOURCE_PACK_LIMITS.associations)
55
+ refuse("pack_limit_exceeded");
56
+ const urls = Object.fromEntries(manifest.assets.map((asset) => [asset.assetRef, asset.source]));
57
+ for (const { product, locales } of checks) {
58
+ for (const variantId of product.variantIds)
59
+ for (const locale of locales) {
60
+ resolveProductMedia(manifest, { productId: product.productId, variantId, locale }, urls);
61
+ }
62
+ }
63
+ return manifest;
64
+ }
65
+ async function contained(root, key, reference) {
66
+ if (!key || isAbsolute(key) || key.includes("\\") || key.includes(":") || key.includes("%") ||
67
+ key.split("/").some((part) => !part || part === "." || part === ".."))
68
+ refuse("unsafe_path", reference);
69
+ try {
70
+ const canonicalRoot = await fs.realpath(root);
71
+ const target = await fs.realpath(resolve(canonicalRoot, key));
72
+ if (!target.startsWith(canonicalRoot + sep))
73
+ refuse("unsafe_path", reference);
74
+ return target;
75
+ }
76
+ catch (error) {
77
+ if (error instanceof CatalogMediaSourcePackError)
78
+ throw error;
79
+ return refuse("missing_resource", reference);
80
+ }
81
+ }
82
+ /** Open only contained regular files, allocate a fixed bound and read at most limit + 1. */
83
+ async function boundedRead(path, limit, reference) {
84
+ const handle = await fs.open(path, constants.O_RDONLY | constants.O_NOFOLLOW).catch(() => refuse("missing_resource", reference));
85
+ try {
86
+ const stat = await handle.stat();
87
+ if (!stat.isFile())
88
+ refuse("unsafe_path", reference);
89
+ if (stat.size > limit)
90
+ refuse("pack_limit_exceeded", reference);
91
+ const bytes = Buffer.alloc(limit + 1);
92
+ let length = 0;
93
+ while (length < bytes.length) {
94
+ const { bytesRead } = await handle.read(bytes, length, bytes.length - length, null);
95
+ if (!bytesRead)
96
+ break;
97
+ length += bytesRead;
98
+ }
99
+ if (length > limit)
100
+ refuse("pack_limit_exceeded", reference);
101
+ return bytes.subarray(0, length);
102
+ }
103
+ finally {
104
+ await handle.close();
105
+ }
106
+ }
107
+ function matchesMime(bytes, mime) {
108
+ if (mime === "image/png")
109
+ return bytes.subarray(0, 8).equals(Buffer.from([137, 80, 78, 71, 13, 10, 26, 10]));
110
+ if (mime === "image/jpeg")
111
+ return bytes[0] === 255 && bytes[1] === 216 && bytes[2] === 255;
112
+ return bytes.length >= 16 && bytes.toString("ascii", 0, 4) === "RIFF" &&
113
+ bytes.toString("ascii", 8, 12) === "WEBP" && bytes.readUInt32LE(4) + 8 === bytes.length &&
114
+ ["VP8 ", "VP8L", "VP8X"].includes(bytes.toString("ascii", 12, 16));
115
+ }
116
+ async function loadResources(manifest, root) {
117
+ const paths = new Map();
118
+ // Stat every resource before reading any payload; declared and actual totals are bounded.
119
+ for (const asset of manifest.assets) {
120
+ const path = await contained(root, asset.source, asset.assetRef);
121
+ const stat = await fs.stat(path);
122
+ if (!stat.isFile())
123
+ refuse("unsafe_path", asset.assetRef);
124
+ if (stat.size > SOURCE_PACK_LIMITS.imageBytes)
125
+ refuse("pack_limit_exceeded", asset.assetRef);
126
+ if (stat.size !== asset.byteLength)
127
+ refuse("size_mismatch", asset.assetRef);
128
+ paths.set(asset.assetRef, path);
129
+ }
130
+ const resources = new Map();
131
+ for (const asset of manifest.assets) {
132
+ const bytes = await boundedRead(paths.get(asset.assetRef), asset.byteLength, asset.assetRef);
133
+ if (bytes.length !== asset.byteLength)
134
+ refuse("size_mismatch", asset.assetRef);
135
+ if (!matchesMime(bytes, asset.contentType))
136
+ refuse("mime_mismatch", asset.assetRef);
137
+ if (digest(bytes) !== asset.sha256)
138
+ refuse("digest_mismatch", asset.assetRef);
139
+ resources.set(asset.assetRef, bytes);
140
+ }
141
+ return resources;
142
+ }
143
+ export async function readCatalogMediaSourceManifest(path) {
144
+ const bytes = await boundedRead(path, SOURCE_PACK_LIMITS.manifestBytes);
145
+ try {
146
+ return JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(bytes));
147
+ }
148
+ catch {
149
+ return refuse("invalid_schema");
150
+ }
151
+ }
152
+ async function checkInventory(root, manifest) {
153
+ const expected = new Set(manifest.assets.map((asset) => keyFor(asset).slice(7)));
154
+ const rootEntries = await fs.opendir(root);
155
+ let rootCount = 0;
156
+ for await (const entry of rootEntries) {
157
+ if (++rootCount > 2 || !["assets", "manifest.json"].includes(entry.name))
158
+ refuse("reference_mismatch");
159
+ }
160
+ const assetRoot = await contained(root, "assets");
161
+ const entries = await fs.opendir(assetRoot);
162
+ let count = 0;
163
+ for await (const entry of entries) {
164
+ if (++count > SOURCE_PACK_LIMITS.assets)
165
+ refuse("pack_limit_exceeded");
166
+ if (!expected.delete(entry.name))
167
+ refuse("reference_mismatch");
168
+ }
169
+ if (expected.size)
170
+ refuse("missing_resource");
171
+ }
172
+ export async function validateCatalogMediaSourcePack(root) {
173
+ const input = await readCatalogMediaSourceManifest(await contained(root, "manifest.json"));
174
+ if (!input || typeof input !== "object" || input.schemaVersion !== "catalog.media-source-pack.v1")
175
+ return refuse("invalid_schema");
176
+ if (Object.keys(input).some((key) => !["schemaVersion", "manifest"].includes(key)))
177
+ refuse("invalid_schema");
178
+ const manifest = checkedManifest(input.manifest);
179
+ for (const asset of manifest.assets)
180
+ if (asset.source !== keyFor(asset))
181
+ refuse("unsafe_path", asset.assetRef);
182
+ await checkInventory(root, manifest);
183
+ const resources = await loadResources(manifest, root);
184
+ return { pack: { schemaVersion: "catalog.media-source-pack.v1", manifest }, resources };
185
+ }
186
+ async function writeNewPack(pack, resources, targetRoot) {
187
+ const encoded = JSON.stringify(pack, null, 2) + "\n";
188
+ if (Buffer.byteLength(encoded) > SOURCE_PACK_LIMITS.manifestBytes)
189
+ refuse("pack_limit_exceeded");
190
+ // mkdir without recursive is the atomic no-overwrite boundary.
191
+ await fs.mkdir(targetRoot).catch((error) => {
192
+ if (error.code === "EEXIST")
193
+ refuse("target_exists");
194
+ refuse("dependency_unavailable");
195
+ });
196
+ const root = await fs.realpath(targetRoot);
197
+ await fs.mkdir(resolve(root, "assets"));
198
+ const written = new Set();
199
+ for (const asset of pack.manifest.assets) {
200
+ if (written.has(asset.source))
201
+ continue;
202
+ await fs.writeFile(resolve(root, asset.source), resources.get(asset.assetRef), { flag: "wx" });
203
+ written.add(asset.source);
204
+ }
205
+ await fs.writeFile(resolve(root, "manifest.json"), encoded, { flag: "wx" });
206
+ return pack;
207
+ }
208
+ export async function exportCatalogMediaSourcePack(options) {
209
+ const manifest = checkedManifest(options.manifest);
210
+ const resources = await loadResources(manifest, options.sourceRoot);
211
+ const portable = { ...manifest, assets: manifest.assets.map((asset) => ({ ...asset, source: keyFor(asset) })) };
212
+ return writeNewPack({ schemaVersion: "catalog.media-source-pack.v1", manifest: portable }, resources, options.targetRoot);
213
+ }
214
+ export async function restoreCatalogMediaSourcePack(packRoot, targetRoot) {
215
+ const { pack, resources } = await validateCatalogMediaSourcePack(packRoot);
216
+ return writeNewPack(pack, resources, targetRoot);
217
+ }
218
+ export async function importCatalogMediaSourcePack(root, storage) {
219
+ let validated;
220
+ try {
221
+ validated = await validateCatalogMediaSourcePack(root);
222
+ }
223
+ catch (error) {
224
+ const refusal = error;
225
+ return { status: "validation_refusal", code: refusal.code ?? "invalid_schema", ...(refusal.reference ? { reference: refusal.reference } : {}) };
226
+ }
227
+ const successfulKeys = [];
228
+ const assets = [];
229
+ const urlsByKey = new Map();
230
+ for (const asset of validated.pack.manifest.assets) {
231
+ const key = keyFor(asset);
232
+ try {
233
+ if (!urlsByKey.has(key)) {
234
+ const result = await storage.upload(key, validated.resources.get(asset.assetRef), { contentType: asset.contentType });
235
+ if (result.pathname !== key)
236
+ refuse("storage_path_mismatch", asset.assetRef);
237
+ successfulKeys.push(key);
238
+ urlsByKey.set(key, storage.urlFor(key));
239
+ }
240
+ assets.push({ assetRef: asset.assetRef, key, url: urlsByKey.get(key) });
241
+ }
242
+ catch {
243
+ return { status: successfulKeys.length ? "partial_upload" : "dependency_unavailable", successfulKeys, failedAssetRef: asset.assetRef, failedKey: key };
244
+ }
245
+ }
246
+ return { status: "complete", successfulKeys, assets };
247
+ }
@@ -0,0 +1,46 @@
1
+ import { z } from "./validation.js";
2
+ import type { CatalogProductTypeDefinition, CatalogProductTypeRegistry } from "./contracts/productTypes.js";
3
+ export { canonicalCatalogOption, validateCatalogQuantity } from "./contracts/productTypes.js";
4
+ export type { CatalogQuantity, CatalogOptionValue, CatalogDraftIssue, CatalogProductTypeDefinition, CatalogProductTypeRegistry } from "./contracts/productTypes.js";
5
+ export declare const catalogNamespacedKeySchema: z.ZodString;
6
+ export declare const catalogDimensionKeySchema: z.ZodString;
7
+ export declare const catalogQuantityDimensionSchema: z.ZodEnum<{
8
+ count: "count";
9
+ mass: "mass";
10
+ volume: "volume";
11
+ }>;
12
+ export declare const catalogQuantitySchema: z.ZodObject<{
13
+ dimension: z.ZodEnum<{
14
+ count: "count";
15
+ mass: "mass";
16
+ volume: "volume";
17
+ }>;
18
+ unscaled: z.ZodString;
19
+ scale: z.ZodNumber;
20
+ unit: z.ZodString;
21
+ }, z.core.$strict>;
22
+ export declare const catalogOptionValueSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
23
+ kind: z.ZodLiteral<"choice">;
24
+ value: z.ZodString;
25
+ }, z.core.$strict>, z.ZodObject<{
26
+ kind: z.ZodLiteral<"quantity">;
27
+ value: z.ZodObject<{
28
+ dimension: z.ZodEnum<{
29
+ count: "count";
30
+ mass: "mass";
31
+ volume: "volume";
32
+ }>;
33
+ unscaled: z.ZodString;
34
+ scale: z.ZodNumber;
35
+ unit: z.ZodString;
36
+ }, z.core.$strict>;
37
+ }, z.core.$strict>, z.ZodObject<{
38
+ kind: z.ZodLiteral<"boolean">;
39
+ value: z.ZodBoolean;
40
+ }, z.core.$strict>], "kind">;
41
+ export declare const catalogProductTypeRefSchema: z.ZodObject<{
42
+ key: z.ZodString;
43
+ version: z.ZodNumber;
44
+ }, z.core.$strict>;
45
+ /** Definitions are installed by composition, never supplied as executable draft data. */
46
+ export declare function createCatalogProductTypeRegistry(definitions: readonly CatalogProductTypeDefinition[]): CatalogProductTypeRegistry;
@@ -0,0 +1,72 @@
1
+ import { z } from "./validation.js";
2
+ export { canonicalCatalogOption, validateCatalogQuantity } from "./contracts/productTypes.js";
3
+ export const catalogNamespacedKeySchema = z.string().max(120).regex(/^[a-z][a-z0-9.-]*:[a-z][a-z0-9._-]*$/u);
4
+ export const catalogDimensionKeySchema = z.string().max(64).regex(/^[a-z][a-z0-9_-]*$/u)
5
+ .refine((key) => !["__proto__", "constructor", "prototype"].includes(key));
6
+ export const catalogQuantityDimensionSchema = z.enum(["mass", "volume", "count"]);
7
+ export const catalogQuantitySchema = z.object({
8
+ dimension: catalogQuantityDimensionSchema,
9
+ unscaled: z.string().regex(/^[1-9][0-9]{0,39}$/u),
10
+ scale: z.number().int().min(0).max(12),
11
+ unit: catalogNamespacedKeySchema,
12
+ }).strict();
13
+ export const catalogOptionValueSchema = z.discriminatedUnion("kind", [
14
+ z.object({ kind: z.literal("choice"), value: z.string().min(1).max(120) }).strict(),
15
+ z.object({ kind: z.literal("quantity"), value: catalogQuantitySchema }).strict(),
16
+ z.object({ kind: z.literal("boolean"), value: z.boolean() }).strict(),
17
+ ]);
18
+ export const catalogProductTypeRefSchema = z.object({
19
+ key: catalogNamespacedKeySchema,
20
+ version: z.number().int().positive().max(2_147_483_647),
21
+ }).strict();
22
+ const unitSchema = z.object({
23
+ code: catalogNamespacedKeySchema,
24
+ dimension: catalogQuantityDimensionSchema,
25
+ integral: z.boolean(),
26
+ }).strict();
27
+ const dimensionSchema = z.discriminatedUnion("kind", [
28
+ z.object({ key: catalogDimensionKeySchema, kind: z.literal("choice"), values: z.array(z.string().min(1).max(120)).min(1).max(1000) }).strict(),
29
+ z.object({ key: catalogDimensionKeySchema, kind: z.literal("quantity"), dimension: catalogQuantityDimensionSchema,
30
+ units: z.array(catalogNamespacedKeySchema).min(1).max(32), role: z.literal("net_content").optional() }).strict(),
31
+ z.object({ key: catalogDimensionKeySchema, kind: z.literal("boolean") }).strict(),
32
+ ]);
33
+ const definitionSchema = catalogProductTypeRefSchema.extend({
34
+ units: z.array(unitSchema).max(64),
35
+ netContentUnits: z.array(catalogNamespacedKeySchema).min(1).max(64),
36
+ dimensions: z.array(dimensionSchema).max(16),
37
+ }).strict();
38
+ /** Definitions are installed by composition, never supplied as executable draft data. */
39
+ export function createCatalogProductTypeRegistry(definitions) {
40
+ const installed = new Map();
41
+ for (const definition of definitions) {
42
+ const { validateContent, ...metadata } = definition;
43
+ const parsed = definitionSchema.parse(metadata);
44
+ const units = new Map(parsed.units.map((unit) => [unit.code, unit]));
45
+ const identity = `${parsed.key}@${parsed.version}`;
46
+ if (typeof validateContent !== "function" || installed.has(identity)
47
+ || units.size !== parsed.units.length
48
+ || new Set(parsed.dimensions.map(({ key }) => key)).size !== parsed.dimensions.length
49
+ || new Set(parsed.netContentUnits).size !== parsed.netContentUnits.length
50
+ || parsed.netContentUnits.some((code) => !units.has(code)))
51
+ throw new Error("invalid_catalog_type_definition");
52
+ for (const dimension of parsed.dimensions) {
53
+ if (dimension.kind === "choice" && new Set(dimension.values).size !== dimension.values.length)
54
+ throw new Error("invalid_catalog_type_definition");
55
+ if (dimension.kind === "quantity" && (new Set(dimension.units).size !== dimension.units.length
56
+ || dimension.units.some((code) => units.get(code)?.dimension !== dimension.dimension)
57
+ || (dimension.role === "net_content" && dimension.units.some((code) => !parsed.netContentUnits.includes(code)))))
58
+ throw new Error("invalid_catalog_type_definition");
59
+ }
60
+ if (parsed.dimensions.filter((dimension) => dimension.kind === "quantity" && dimension.role === "net_content").length > 1)
61
+ throw new Error("invalid_catalog_type_definition");
62
+ function freeze(value) {
63
+ for (const child of Object.values(value))
64
+ if (child && typeof child === "object")
65
+ freeze(child);
66
+ Object.freeze(value);
67
+ }
68
+ freeze(parsed);
69
+ installed.set(identity, Object.freeze({ ...parsed, validateContent }));
70
+ }
71
+ return Object.freeze({ resolve: (ref) => installed.get(`${ref.key}@${ref.version}`) });
72
+ }
@@ -0,0 +1,42 @@
1
+ import type { CatalogHeadRef, CatalogHistoryResult, CatalogPublicationReadResult, CatalogPublicationReceipt, CatalogPublicationReceiptResult, CatalogPublicationRefusal, CatalogPublishCommand } from "./contracts/lifecycle.js";
2
+ declare const verifiedCatalogPublisher: unique symbol;
3
+ /** Server authorization result. P1 exposes no constructor or actor-string conversion. */
4
+ export interface VerifiedCatalogPublisher {
5
+ readonly [verifiedCatalogPublisher]: true;
6
+ }
7
+ export interface CatalogValidationPort {
8
+ validate(candidateRef: string): Promise<{
9
+ candidateDigest: string;
10
+ issues: readonly {
11
+ code: string;
12
+ path: string;
13
+ }[];
14
+ }>;
15
+ }
16
+ /** No default binding: missing authority is unsupported; configured outage is dependency_unavailable. */
17
+ export interface CatalogPublicationReadPort {
18
+ current(productId: string): Promise<CatalogPublicationReadResult>;
19
+ readback(head: CatalogHeadRef): Promise<CatalogPublicationReadResult>;
20
+ receipt(scope: {
21
+ productId: string;
22
+ commandKey: string;
23
+ }): Promise<CatalogPublicationReceiptResult>;
24
+ /** Null starts a bounded history page; cursors retain the authority's stable ordering. */
25
+ history(productId: string, cursor: string | null): Promise<CatalogHistoryResult>;
26
+ }
27
+ /** Types only: proposal submission does not implement publication or lifecycle writes. */
28
+ export interface CatalogPublicationPort {
29
+ publish(command: CatalogPublishCommand, actor: VerifiedCatalogPublisher): Promise<{
30
+ outcome: "committed" | "replayed";
31
+ receipt: CatalogPublicationReceipt;
32
+ } | CatalogPublicationRefusal>;
33
+ }
34
+ /** Describes a host's actual support; exporting ports supplies no capabilities. */
35
+ export interface CatalogCapabilityDescriptor {
36
+ read: boolean;
37
+ draft: boolean;
38
+ publicationRead: boolean;
39
+ publish: boolean;
40
+ lifecycleWrite: boolean;
41
+ }
42
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,51 @@
1
+ import type { SellableCatalogItem, SellableCatalogProfile, CatalogSkuEnvelopeSelector, NeutralSkuEnvelopeV1 } from "./contracts/index.js";
2
+ /**
3
+ * Minimal neutral catalog seam used by the local reference storefront. It is
4
+ * independent of richer application catalog read ports.
5
+ */
6
+ export interface SellableCatalogPort {
7
+ getStorefrontProfile(): Promise<SellableCatalogProfile>;
8
+ listSellableItems(): Promise<SellableCatalogItem[]>;
9
+ }
10
+ /**
11
+ * Dark W2a read seam. Its row-safe return value deliberately contains document
12
+ * references, never a document payload or a SKU-level document override.
13
+ */
14
+ export interface CatalogSkuEnvelopeReadPort {
15
+ listSkuEnvelopes(query: CatalogSkuEnvelopeListQuery): Promise<CatalogSkuEnvelopePage>;
16
+ /**
17
+ * Page only active trade items that are sellable in at least one commerce
18
+ * channel. This is intentionally distinct from the neutral inventory-style
19
+ * listing above: consumers such as compatibility must not discover dormant
20
+ * SKUs and then try to filter them with a second authority.
21
+ */
22
+ listActiveSkuEnvelopes(query: CatalogActiveSkuEnvelopeListQuery): Promise<CatalogSkuEnvelopePage>;
23
+ getSkuEnvelope(selector: CatalogSkuEnvelopeSelector): Promise<NeutralSkuEnvelopeV1 | null>;
24
+ /** Compatibility lookup for callers that already persist the neutral SKU UUID. */
25
+ getSkuEnvelopeById(skuId: string): Promise<NeutralSkuEnvelopeV1 | null>;
26
+ }
27
+ /**
28
+ * Additive discovery capability. Existing commerce consumers remain typed to
29
+ * {@link CatalogSkuEnvelopeReadPort} and therefore cannot accidentally use it.
30
+ */
31
+ export interface PublicCatalogSkuEnvelopeReadPort extends CatalogSkuEnvelopeReadPort {
32
+ /**
33
+ * Public discovery's active-only page. Unlike the commerce method above it
34
+ * intentionally includes temporarily unsellable active variants.
35
+ */
36
+ listPublicActiveSkuEnvelopes(query: CatalogSkuEnvelopeListQuery): Promise<CatalogSkuEnvelopePage>;
37
+ /** Active-only cursor page restricted to one already-authoritative product. */
38
+ listPublicActiveProductSkuEnvelopes(productId: string, query: CatalogSkuEnvelopeListQuery): Promise<CatalogSkuEnvelopePage>;
39
+ }
40
+ export interface CatalogSkuEnvelopeListQuery {
41
+ cursor: string | null;
42
+ limit: number;
43
+ }
44
+ export interface CatalogActiveSkuEnvelopeListQuery extends CatalogSkuEnvelopeListQuery {
45
+ /** Optional server-selected scope; supplied selections contain 1–100 unique SKU codes. */
46
+ skuCodes?: readonly string[];
47
+ }
48
+ export interface CatalogSkuEnvelopePage {
49
+ items: NeutralSkuEnvelopeV1[];
50
+ nextCursor: string | null;
51
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,7 @@
1
+ import type { HttpRequest, HttpResponse } from "../http/index.js";
2
+ import type { BffResponder } from "../bff/index.js";
3
+ import type { SellableCatalogPort } from "./readPorts.js";
4
+ export declare function createReferenceCatalogItemsHandler({ catalogPort, responder, }: {
5
+ catalogPort: SellableCatalogPort;
6
+ responder: BffResponder;
7
+ }): (req: HttpRequest, res: HttpResponse) => Promise<void>;
@@ -0,0 +1,27 @@
1
+ import { SELLABLE_CATALOG_CONTRACT_VERSION, sellableCatalogListResponseSchema, } from "./sellableSchemas.js";
2
+ export function createReferenceCatalogItemsHandler({ catalogPort, responder, }) {
3
+ const { sendBffError, sendBffSuccess, sendMethodNotAllowed } = responder;
4
+ return async function handler(req, res) {
5
+ if (req.method !== "GET") {
6
+ sendMethodNotAllowed(res, ["GET"]);
7
+ return;
8
+ }
9
+ try {
10
+ const response = sellableCatalogListResponseSchema.safeParse({
11
+ contractVersion: SELLABLE_CATALOG_CONTRACT_VERSION,
12
+ profile: await catalogPort.getStorefrontProfile(),
13
+ items: await catalogPort.listSellableItems(),
14
+ });
15
+ if (!response.success) {
16
+ sendBffError(res, "INVALID_RESPONSE", "Reference catalog returned invalid items");
17
+ return;
18
+ }
19
+ sendBffSuccess(res, response.data, { contractVersion: SELLABLE_CATALOG_CONTRACT_VERSION }, {
20
+ cacheControl: "no-store",
21
+ });
22
+ }
23
+ catch {
24
+ sendBffError(res, "UPSTREAM_UNAVAILABLE", "Reference catalog is unavailable");
25
+ }
26
+ };
27
+ }
@@ -0,0 +1,88 @@
1
+ import { z } from "./validation.js";
2
+ import { type NeutralSkuEnvelopeV1 } from "./foundationSchemas.js";
3
+ /**
4
+ * Server-only, read-safe projection. It intentionally composes opaque document
5
+ * references with resolved prices and never selects or exposes document payload.
6
+ */
7
+ export declare const RESOLVED_SKU_PROJECTION_VERSION = "catalog.resolved-sku.v1";
8
+ export declare const resolvedSkuProjectionSchema: z.ZodObject<{
9
+ contractVersion: z.ZodLiteral<"catalog.resolved-sku.v1">;
10
+ envelope: z.ZodObject<{
11
+ contractVersion: z.ZodLiteral<"catalog.foundation.v1">;
12
+ product: z.ZodObject<{
13
+ id: z.ZodGUID;
14
+ slug: z.ZodString;
15
+ primarySkuId: z.ZodGUID;
16
+ }, z.core.$strict>;
17
+ sku: z.ZodObject<{
18
+ id: z.ZodGUID;
19
+ productId: z.ZodGUID;
20
+ code: z.ZodString;
21
+ netContent: z.ZodObject<{
22
+ unscaled: z.ZodNumber;
23
+ scale: z.ZodNumber;
24
+ unit: z.ZodString;
25
+ }, z.core.$strict>;
26
+ sellability: z.ZodObject<{
27
+ status: z.ZodEnum<{
28
+ draft: "draft";
29
+ active: "active";
30
+ archived: "archived";
31
+ }>;
32
+ oneTime: z.ZodBoolean;
33
+ subscription: z.ZodBoolean;
34
+ }, z.core.$strict>;
35
+ isAddon: z.ZodBoolean;
36
+ assetRef: z.ZodNullable<z.ZodString>;
37
+ }, z.core.$strict>;
38
+ documentRevision: z.ZodObject<{
39
+ id: z.ZodGUID;
40
+ productId: z.ZodGUID;
41
+ revisionNo: z.ZodNumber;
42
+ schemaId: z.ZodString;
43
+ documentRef: z.ZodString;
44
+ sourceRef: z.ZodString;
45
+ digest: z.ZodString;
46
+ }, z.core.$strict>;
47
+ identifiers: z.ZodArray<z.ZodObject<{
48
+ issuer: z.ZodString;
49
+ normalizedValue: z.ZodString;
50
+ kind: z.ZodEnum<{
51
+ gtin: "gtin";
52
+ other: "other";
53
+ }>;
54
+ packKind: z.ZodEnum<{
55
+ unit: "unit";
56
+ collective: "collective";
57
+ }>;
58
+ packQuantity: z.ZodNumber;
59
+ isPrimary: z.ZodBoolean;
60
+ }, z.core.$strict>>;
61
+ }, z.core.$strict>;
62
+ priceContext: z.ZodObject<{
63
+ priceListId: z.ZodGUID;
64
+ regionCode: z.ZodString;
65
+ currency: z.ZodString;
66
+ channel: z.ZodString;
67
+ atTime: z.ZodString;
68
+ }, z.core.$strict>;
69
+ pricing: z.ZodObject<{
70
+ base: z.ZodObject<{
71
+ priceEntryId: z.ZodGUID;
72
+ amountMinor: z.ZodNumber;
73
+ }, z.core.$strict>;
74
+ subscription: z.ZodNullable<z.ZodObject<{
75
+ policyRevisionId: z.ZodGUID;
76
+ policyDigest: z.ZodString;
77
+ amountMinor: z.ZodNumber;
78
+ }, z.core.$strict>>;
79
+ }, z.core.$strict>;
80
+ }, z.core.$strict>;
81
+ export type ResolvedSkuProjection = z.infer<typeof resolvedSkuProjectionSchema>;
82
+ /** Row-safe constructor boundary for adapters; it accepts no raw document row/payload. */
83
+ export interface ResolvedSkuProjectionInput {
84
+ envelope: NeutralSkuEnvelopeV1;
85
+ priceContext: ResolvedSkuProjection["priceContext"];
86
+ pricing: ResolvedSkuProjection["pricing"];
87
+ }
88
+ export declare function buildResolvedSkuProjection(input: ResolvedSkuProjectionInput): ResolvedSkuProjection;
@@ -0,0 +1,60 @@
1
+ import { z } from "./validation.js";
2
+ import { CatalogSkuAuthorityError, assertPrimaryUnitGtinAuthority, neutralSkuEnvelopeV1Schema, } from "./foundationSchemas.js";
3
+ const uuidSchema = z.guid();
4
+ const digestSchema = z.string().regex(/^[a-f0-9]{64}$/u);
5
+ const currencySchema = z.string().regex(/^[A-Z]{3}$/u);
6
+ const moneyMinorSchema = z.number().int().nonnegative();
7
+ /**
8
+ * Server-only, read-safe projection. It intentionally composes opaque document
9
+ * references with resolved prices and never selects or exposes document payload.
10
+ */
11
+ export const RESOLVED_SKU_PROJECTION_VERSION = "catalog.resolved-sku.v1";
12
+ export const resolvedSkuProjectionSchema = z.object({
13
+ contractVersion: z.literal(RESOLVED_SKU_PROJECTION_VERSION),
14
+ envelope: neutralSkuEnvelopeV1Schema,
15
+ priceContext: z.object({
16
+ priceListId: uuidSchema,
17
+ regionCode: z.string().regex(/^[A-Z]{2,3}$/u),
18
+ currency: currencySchema,
19
+ channel: z.string().trim().min(1).max(64),
20
+ atTime: z.string().datetime({ offset: true }),
21
+ }).strict(),
22
+ pricing: z.object({
23
+ base: z.object({
24
+ priceEntryId: uuidSchema,
25
+ amountMinor: moneyMinorSchema,
26
+ }).strict(),
27
+ subscription: z.object({
28
+ policyRevisionId: uuidSchema,
29
+ policyDigest: digestSchema,
30
+ amountMinor: moneyMinorSchema,
31
+ }).strict().nullable(),
32
+ }).strict(),
33
+ }).strict().superRefine((projection, context) => {
34
+ try {
35
+ assertPrimaryUnitGtinAuthority(projection.envelope.identifiers);
36
+ }
37
+ catch (error) {
38
+ if (!(error instanceof CatalogSkuAuthorityError))
39
+ throw error;
40
+ context.addIssue({
41
+ code: z.ZodIssueCode.custom,
42
+ path: ["envelope", "identifiers"],
43
+ message: error.code,
44
+ });
45
+ }
46
+ const subscriptionSellable = projection.envelope.sku.sellability.subscription;
47
+ if (subscriptionSellable && projection.pricing.subscription === null) {
48
+ context.addIssue({ code: z.ZodIssueCode.custom, path: ["pricing", "subscription"], message: "subscription-sellable SKUs require a subscription price" });
49
+ }
50
+ if (!subscriptionSellable && projection.pricing.subscription !== null) {
51
+ context.addIssue({ code: z.ZodIssueCode.custom, path: ["pricing", "subscription"], message: "one-time-only SKUs must not carry a subscription price" });
52
+ }
53
+ });
54
+ export function buildResolvedSkuProjection(input) {
55
+ assertPrimaryUnitGtinAuthority(input.envelope.identifiers);
56
+ return resolvedSkuProjectionSchema.parse({
57
+ contractVersion: RESOLVED_SKU_PROJECTION_VERSION,
58
+ ...input,
59
+ });
60
+ }