@openlup/platform 0.17.0 → 0.19.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 (525) hide show
  1. package/CHANGELOG.md +143 -0
  2. package/README.md +299 -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 +21 -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 +173 -0
  22. package/dist/catalog/bundleCatalogReadPort.js +36 -0
  23. package/dist/catalog/bundleCatalogStore.d.ts +5 -0
  24. package/dist/catalog/bundleCatalogStore.js +156 -0
  25. package/dist/catalog/bundlePriceSelection.d.ts +13 -0
  26. package/dist/catalog/bundlePriceSelection.js +26 -0
  27. package/dist/catalog/bundleRuleCodes.d.ts +41 -0
  28. package/dist/catalog/bundleRuleCodes.js +110 -0
  29. package/dist/catalog/bundleRules.d.ts +69 -0
  30. package/dist/catalog/bundleRules.js +102 -0
  31. package/dist/catalog/catalogDraftStore.d.ts +4 -0
  32. package/dist/catalog/catalogDraftStore.js +63 -0
  33. package/dist/catalog/catalogSkuEnvelope.d.ts +7 -0
  34. package/dist/catalog/catalogSkuEnvelope.js +142 -0
  35. package/dist/catalog/catalogSkuEnvelopeMapper.d.ts +38 -0
  36. package/dist/catalog/catalogSkuEnvelopeMapper.js +88 -0
  37. package/dist/catalog/contracts/bundleAdmin.d.ts +143 -0
  38. package/dist/catalog/contracts/bundleAdmin.js +1 -0
  39. package/dist/catalog/contracts/bundleAvailability.d.ts +61 -0
  40. package/dist/catalog/contracts/bundleAvailability.js +1 -0
  41. package/dist/catalog/contracts/bundleRead.d.ts +241 -0
  42. package/dist/catalog/contracts/bundleRead.js +1 -0
  43. package/dist/catalog/contracts/draft.d.ts +79 -0
  44. package/dist/catalog/contracts/draft.js +47 -0
  45. package/dist/catalog/contracts/foundation.d.ts +78 -0
  46. package/dist/catalog/contracts/foundation.js +53 -0
  47. package/dist/catalog/contracts/index.d.ts +14 -0
  48. package/dist/catalog/contracts/index.js +6 -0
  49. package/dist/catalog/contracts/lifecycle.d.ts +77 -0
  50. package/dist/catalog/contracts/lifecycle.js +1 -0
  51. package/dist/catalog/contracts/productMediaContracts.d.ts +77 -0
  52. package/dist/catalog/contracts/productMediaContracts.js +149 -0
  53. package/dist/catalog/contracts/productTypes.d.ts +54 -0
  54. package/dist/catalog/contracts/productTypes.js +16 -0
  55. package/dist/catalog/contracts/resolveProductMedia.d.ts +3 -0
  56. package/dist/catalog/contracts/resolveProductMedia.js +78 -0
  57. package/dist/catalog/contracts/sellable.d.ts +23 -0
  58. package/dist/catalog/contracts/sellable.js +1 -0
  59. package/dist/catalog/draftHandler.d.ts +25 -0
  60. package/dist/catalog/draftHandler.js +118 -0
  61. package/dist/catalog/draftPorts.d.ts +18 -0
  62. package/dist/catalog/draftPorts.js +8 -0
  63. package/dist/catalog/draftSchemas.d.ts +423 -0
  64. package/dist/catalog/draftSchemas.js +89 -0
  65. package/dist/catalog/draftValidation.d.ts +21 -0
  66. package/dist/catalog/draftValidation.js +125 -0
  67. package/dist/catalog/effectiveBundleCatalogQueries.d.ts +8 -0
  68. package/dist/catalog/effectiveBundleCatalogQueries.js +79 -0
  69. package/dist/catalog/effectiveBundleCatalogStore.d.ts +4 -0
  70. package/dist/catalog/effectiveBundleCatalogStore.js +156 -0
  71. package/dist/catalog/foundationSchemas.d.ts +98 -0
  72. package/dist/catalog/foundationSchemas.js +110 -0
  73. package/dist/catalog/index.d.ts +44 -0
  74. package/dist/catalog/index.js +26 -0
  75. package/dist/catalog/mediaSourcePack.d.ts +51 -0
  76. package/dist/catalog/mediaSourcePack.js +247 -0
  77. package/dist/catalog/productTypeSchemas.d.ts +46 -0
  78. package/dist/catalog/productTypeSchemas.js +72 -0
  79. package/dist/catalog/publicationPorts.d.ts +42 -0
  80. package/dist/catalog/publicationPorts.js +1 -0
  81. package/dist/catalog/readPorts.d.ts +51 -0
  82. package/dist/catalog/readPorts.js +1 -0
  83. package/dist/catalog/referenceCatalogHandler.d.ts +7 -0
  84. package/dist/catalog/referenceCatalogHandler.js +27 -0
  85. package/dist/catalog/resolvedSkuProjection.d.ts +88 -0
  86. package/dist/catalog/resolvedSkuProjection.js +60 -0
  87. package/dist/catalog/sellableBundleHandler.d.ts +46 -0
  88. package/dist/catalog/sellableBundleHandler.js +84 -0
  89. package/dist/catalog/sellableSchemas.d.ts +46 -0
  90. package/dist/catalog/sellableSchemas.js +27 -0
  91. package/dist/catalog/sql.d.ts +46 -0
  92. package/dist/catalog/sql.js +13 -0
  93. package/dist/catalog/validation.d.ts +2 -0
  94. package/dist/catalog/validation.js +3 -0
  95. package/dist/communications/contracts/index.d.ts +1 -0
  96. package/dist/communications/contracts/marketingSync.d.ts +194 -0
  97. package/dist/communications/contracts/marketingSync.js +1 -0
  98. package/dist/communications/index.d.ts +1 -0
  99. package/dist/communications/klaviyo/consentPush.d.ts +51 -0
  100. package/dist/communications/klaviyo/consentPush.js +19 -0
  101. package/dist/communications/klaviyo/index.d.ts +110 -0
  102. package/dist/communications/klaviyo/index.js +860 -0
  103. package/dist/communications/newsletterIntegrationContracts.d.ts +3 -3
  104. package/dist/communications/resend/index.d.ts +40 -0
  105. package/dist/communications/resend/index.js +310 -0
  106. package/dist/composition/catalogContribution.d.ts +18 -0
  107. package/dist/composition/catalogContribution.js +21 -0
  108. package/dist/composition/index.d.ts +3 -0
  109. package/dist/composition/index.js +3 -0
  110. package/dist/composition/inventoryContribution.d.ts +16 -0
  111. package/dist/composition/inventoryContribution.js +17 -0
  112. package/dist/composition/shippingContribution.d.ts +16 -0
  113. package/dist/composition/shippingContribution.js +17 -0
  114. package/dist/identity/customerContracts.d.ts +2 -2
  115. package/dist/inventory/adminInventory.d.ts +13 -0
  116. package/dist/inventory/adminInventory.js +214 -0
  117. package/dist/inventory/bindings.d.ts +35 -0
  118. package/dist/inventory/bindings.js +45 -0
  119. package/dist/inventory/contracts/forecast.d.ts +86 -0
  120. package/dist/inventory/contracts/forecast.js +1 -0
  121. package/dist/inventory/contracts/index.d.ts +4 -0
  122. package/dist/inventory/contracts/index.js +1 -0
  123. package/dist/inventory/contracts/inventory.d.ts +157 -0
  124. package/dist/inventory/contracts/inventory.js +1 -0
  125. package/dist/inventory/contracts/newPurchaseStock.d.ts +20 -0
  126. package/dist/inventory/contracts/newPurchaseStock.js +1 -0
  127. package/dist/inventory/contracts/reservation.d.ts +18 -0
  128. package/dist/inventory/contracts/reservation.js +1 -0
  129. package/dist/inventory/forecast.d.ts +24 -0
  130. package/dist/inventory/forecast.js +200 -0
  131. package/dist/inventory/index.d.ts +14 -0
  132. package/dist/inventory/index.js +11 -0
  133. package/dist/inventory/inventoryHandlers.d.ts +53 -0
  134. package/dist/inventory/inventoryHandlers.js +151 -0
  135. package/dist/inventory/newPurchaseStockAvailability.d.ts +47 -0
  136. package/dist/inventory/newPurchaseStockAvailability.js +75 -0
  137. package/dist/inventory/ports.d.ts +21 -0
  138. package/dist/inventory/ports.js +16 -0
  139. package/dist/inventory/renewalReservation.d.ts +27 -0
  140. package/dist/inventory/renewalReservation.js +61 -0
  141. package/dist/inventory/reservationPolicy.d.ts +6 -0
  142. package/dist/inventory/reservationPolicy.js +19 -0
  143. package/dist/inventory/schemas.d.ts +137 -0
  144. package/dist/inventory/schemas.js +112 -0
  145. package/dist/inventory/sql.d.ts +14 -0
  146. package/dist/inventory/sql.js +5 -0
  147. package/dist/inventory/subscriptionForecastCalculation.d.ts +4 -0
  148. package/dist/inventory/subscriptionForecastCalculation.js +133 -0
  149. package/dist/pricing/acquisitionFinancialPolicy.d.ts +26 -0
  150. package/dist/pricing/acquisitionFinancialPolicy.js +1 -0
  151. package/dist/pricing/acquisitionOfferPricing.d.ts +27 -0
  152. package/dist/pricing/acquisitionOfferPricing.js +25 -0
  153. package/dist/pricing/acquisitionOfferPricingHandler.d.ts +20 -0
  154. package/dist/pricing/acquisitionOfferPricingHandler.js +105 -0
  155. package/dist/pricing/acquisitionOfferPricingSchemas.d.ts +31 -0
  156. package/dist/pricing/acquisitionOfferPricingSchemas.js +33 -0
  157. package/dist/pricing/acquisitionQuoteBinding.d.ts +12 -0
  158. package/dist/pricing/acquisitionQuoteBinding.js +12 -0
  159. package/dist/pricing/acquisitionReadiness.d.ts +31 -0
  160. package/dist/pricing/acquisitionReadiness.js +117 -0
  161. package/dist/pricing/acquisitionTerms.d.ts +19 -0
  162. package/dist/pricing/acquisitionTerms.js +126 -0
  163. package/dist/pricing/acquisitionTermsSchemas.d.ts +59 -0
  164. package/dist/pricing/acquisitionTermsSchemas.js +42 -0
  165. package/dist/pricing/catalogFactsProvenance.d.ts +33 -0
  166. package/dist/pricing/catalogFactsProvenance.js +64 -0
  167. package/dist/pricing/catalogFactsSchemas.d.ts +45 -0
  168. package/dist/pricing/catalogFactsSchemas.js +58 -0
  169. package/dist/pricing/commerceOfferPricing.d.ts +25 -0
  170. package/dist/pricing/commerceOfferPricing.js +139 -0
  171. package/dist/pricing/commerceOfferPricingCache.d.ts +10 -0
  172. package/dist/pricing/commerceOfferPricingCache.js +44 -0
  173. package/dist/pricing/commerceOfferPricingHandler.d.ts +21 -0
  174. package/dist/pricing/commerceOfferPricingHandler.js +78 -0
  175. package/dist/pricing/commercePriceAuthority.d.ts +28 -0
  176. package/dist/pricing/commercePriceAuthority.js +140 -0
  177. package/dist/pricing/commercePricingPolicyErrors.d.ts +40 -0
  178. package/dist/pricing/commercePricingPolicyErrors.js +67 -0
  179. package/dist/pricing/commerceQuoteBatchHandler.d.ts +37 -0
  180. package/dist/pricing/commerceQuoteBatchHandler.js +83 -0
  181. package/dist/pricing/commerceQuoteCatalogReadPort.d.ts +27 -0
  182. package/dist/pricing/commerceQuoteCatalogReadPort.js +8 -0
  183. package/dist/pricing/commerceQuoteHandler.d.ts +35 -0
  184. package/dist/pricing/commerceQuoteHandler.js +122 -0
  185. package/dist/pricing/commerceQuoteSnapshotExpect.d.ts +9 -0
  186. package/dist/pricing/commerceQuoteSnapshotExpect.js +22 -0
  187. package/dist/pricing/contracts/acquisitionTerms.d.ts +32 -0
  188. package/dist/pricing/contracts/acquisitionTerms.js +2 -0
  189. package/dist/pricing/contracts/authority.d.ts +27 -0
  190. package/dist/pricing/contracts/authority.js +1 -0
  191. package/dist/pricing/contracts/evidence.d.ts +33 -0
  192. package/dist/pricing/contracts/evidence.js +1 -0
  193. package/dist/pricing/contracts/index.d.ts +17 -0
  194. package/dist/pricing/contracts/index.js +7 -0
  195. package/dist/pricing/contracts/money.d.ts +27 -0
  196. package/dist/pricing/contracts/money.js +1 -0
  197. package/dist/pricing/contracts/offer.d.ts +52 -0
  198. package/dist/pricing/contracts/offer.js +4 -0
  199. package/dist/pricing/contracts/offerPolicy.d.ts +16 -0
  200. package/dist/pricing/contracts/offerPolicy.js +5 -0
  201. package/dist/pricing/contracts/policy.d.ts +22 -0
  202. package/dist/pricing/contracts/policy.js +3 -0
  203. package/dist/pricing/contracts/provenance.d.ts +24 -0
  204. package/dist/pricing/contracts/provenance.js +2 -0
  205. package/dist/pricing/contracts/quote.d.ts +94 -0
  206. package/dist/pricing/contracts/quote.js +1 -0
  207. package/dist/pricing/dbBackedCommerceQuoteHelpers.d.ts +78 -0
  208. package/dist/pricing/dbBackedCommerceQuoteHelpers.js +146 -0
  209. package/dist/pricing/dbBackedCommerceQuotePort.d.ts +74 -0
  210. package/dist/pricing/dbBackedCommerceQuotePort.js +223 -0
  211. package/dist/pricing/dbBackedCommerceQuoteSnapshotVerifier.d.ts +4 -0
  212. package/dist/pricing/dbBackedCommerceQuoteSnapshotVerifier.js +25 -0
  213. package/dist/pricing/index.d.ts +52 -0
  214. package/dist/pricing/index.js +36 -0
  215. package/dist/pricing/offerPolicyReadiness.d.ts +21 -0
  216. package/dist/pricing/offerPolicyReadiness.js +79 -0
  217. package/dist/pricing/offerPolicySchemas.d.ts +25 -0
  218. package/dist/pricing/offerPolicySchemas.js +15 -0
  219. package/dist/pricing/offerPricingSchemas.d.ts +315 -0
  220. package/dist/pricing/offerPricingSchemas.js +65 -0
  221. package/dist/pricing/ports.d.ts +13 -0
  222. package/dist/pricing/ports.js +9 -0
  223. package/dist/pricing/pricingPolicyToken.d.ts +39 -0
  224. package/dist/pricing/pricingPolicyToken.js +84 -0
  225. package/dist/pricing/quoteAcquisitionTerms.d.ts +2 -0
  226. package/dist/pricing/quoteAcquisitionTerms.js +4 -0
  227. package/dist/pricing/quoteCodeRejectionDetails.d.ts +20 -0
  228. package/dist/pricing/quoteCodeRejectionDetails.js +22 -0
  229. package/dist/pricing/quotePorts.d.ts +30 -0
  230. package/dist/pricing/quotePorts.js +20 -0
  231. package/dist/pricing/quotePrimitives.d.ts +13 -0
  232. package/dist/pricing/quotePrimitives.js +18 -0
  233. package/dist/pricing/quotePromotionEvidence.d.ts +39 -0
  234. package/dist/pricing/quotePromotionEvidence.js +73 -0
  235. package/dist/pricing/quoteSchemas.d.ts +1176 -0
  236. package/dist/pricing/quoteSchemas.js +196 -0
  237. package/dist/pricing/quoteShippingPromotions.d.ts +20 -0
  238. package/dist/pricing/quoteShippingPromotions.js +1 -0
  239. package/dist/pricing/subscriptionPricePolicy.d.ts +52 -0
  240. package/dist/pricing/subscriptionPricePolicy.js +96 -0
  241. package/dist/pricing/taxProfileGuard.d.ts +2 -0
  242. package/dist/pricing/taxProfileGuard.js +24 -0
  243. package/dist/pricing/validation.d.ts +2 -0
  244. package/dist/pricing/validation.js +3 -0
  245. package/dist/promotions/adminBindings.d.ts +72 -0
  246. package/dist/promotions/adminBindings.js +1 -0
  247. package/dist/promotions/adminPromotionCodesContracts.d.ts +498 -0
  248. package/dist/promotions/adminPromotionCodesContracts.js +211 -0
  249. package/dist/promotions/adminPromotionCodesDataPort.d.ts +47 -0
  250. package/dist/promotions/adminPromotionCodesDataPort.js +1 -0
  251. package/dist/promotions/adminPromotionCodesHandler.d.ts +14 -0
  252. package/dist/promotions/adminPromotionCodesHandler.js +194 -0
  253. package/dist/promotions/adminPromotionsContracts.d.ts +235 -0
  254. package/dist/promotions/adminPromotionsContracts.js +99 -0
  255. package/dist/promotions/adminPromotionsDataPort.d.ts +42 -0
  256. package/dist/promotions/adminPromotionsDataPort.js +1 -0
  257. package/dist/promotions/adminPromotionsHandler.d.ts +16 -0
  258. package/dist/promotions/adminPromotionsHandler.js +47 -0
  259. package/dist/promotions/commerceQuoteReadPreparation.d.ts +3 -0
  260. package/dist/promotions/commerceQuoteReadPreparation.js +27 -0
  261. package/dist/promotions/contracts/index.d.ts +387 -0
  262. package/dist/promotions/contracts/index.js +1 -0
  263. package/dist/promotions/index.d.ts +25 -0
  264. package/dist/promotions/index.js +22 -0
  265. package/dist/promotions/promoDataPort.d.ts +47 -0
  266. package/dist/promotions/promoDataPort.js +14 -0
  267. package/dist/promotions/promotionAcceptanceTelemetry.d.ts +29 -0
  268. package/dist/promotions/promotionAcceptanceTelemetry.js +45 -0
  269. package/dist/promotions/promotionBenefitDefinition.d.ts +37 -0
  270. package/dist/promotions/promotionBenefitDefinition.js +33 -0
  271. package/dist/promotions/promotionClaimSweepPort.d.ts +14 -0
  272. package/dist/promotions/promotionClaimSweepPort.js +8 -0
  273. package/dist/promotions/promotionClaims.d.ts +5 -0
  274. package/dist/promotions/promotionClaims.js +57 -0
  275. package/dist/promotions/promotionCodePreview.d.ts +11 -0
  276. package/dist/promotions/promotionCodePreview.js +154 -0
  277. package/dist/promotions/promotionCodeQuotePort.d.ts +25 -0
  278. package/dist/promotions/promotionCodeQuotePort.js +1 -0
  279. package/dist/promotions/promotionQuoteAcceptance.d.ts +70 -0
  280. package/dist/promotions/promotionQuoteAcceptance.js +202 -0
  281. package/dist/promotions/promotionQuoteBinding.d.ts +73 -0
  282. package/dist/promotions/promotionQuoteBinding.js +87 -0
  283. package/dist/promotions/quoteAcquisitionBinding.d.ts +6 -0
  284. package/dist/promotions/quoteAcquisitionBinding.js +1 -0
  285. package/dist/promotions/quoteAutomaticPromotions.d.ts +26 -0
  286. package/dist/promotions/quoteAutomaticPromotions.js +60 -0
  287. package/dist/promotions/quotePromoDiscounts.d.ts +36 -0
  288. package/dist/promotions/quotePromoDiscounts.js +146 -0
  289. package/dist/promotions/quotePromotionCodeAdjustments.d.ts +27 -0
  290. package/dist/promotions/quotePromotionCodeAdjustments.js +223 -0
  291. package/dist/promotions/quotePromotionV2.d.ts +30 -0
  292. package/dist/promotions/quotePromotionV2.js +186 -0
  293. package/dist/promotions/quoteShippingPolicy.d.ts +23 -0
  294. package/dist/promotions/quoteShippingPolicy.js +47 -0
  295. package/dist/promotions/sql.d.ts +14 -0
  296. package/dist/promotions/sql.js +5 -0
  297. package/dist/promotions/validation.d.ts +2 -0
  298. package/dist/promotions/validation.js +3 -0
  299. package/dist/shipping/addressCanonLookupHandler.d.ts +7 -0
  300. package/dist/shipping/addressCanonLookupHandler.js +105 -0
  301. package/dist/shipping/addressCanonical.d.ts +2 -0
  302. package/dist/shipping/addressCanonical.js +26 -0
  303. package/dist/shipping/addressPorts.d.ts +39 -0
  304. package/dist/shipping/addressPorts.js +1 -0
  305. package/dist/shipping/addressSchemas.d.ts +30 -0
  306. package/dist/shipping/addressSchemas.js +1 -0
  307. package/dist/shipping/adminShippingRateHandler.d.ts +4 -0
  308. package/dist/shipping/adminShippingRateHandler.js +64 -0
  309. package/dist/shipping/bindings.d.ts +57 -0
  310. package/dist/shipping/bindings.js +46 -0
  311. package/dist/shipping/contracts/address.d.ts +144 -0
  312. package/dist/shipping/contracts/address.js +1 -0
  313. package/dist/shipping/contracts/delivery.d.ts +110 -0
  314. package/dist/shipping/contracts/delivery.js +1 -0
  315. package/dist/shipping/contracts/index.d.ts +4 -0
  316. package/dist/shipping/contracts/index.js +1 -0
  317. package/dist/shipping/contracts/shippingRate.d.ts +11 -0
  318. package/dist/shipping/contracts/shippingRate.js +1 -0
  319. package/dist/shipping/contracts/threshold.d.ts +22 -0
  320. package/dist/shipping/contracts/threshold.js +1 -0
  321. package/dist/shipping/customerAddressesHandler.d.ts +5 -0
  322. package/dist/shipping/customerAddressesHandler.js +80 -0
  323. package/dist/shipping/customerSelfServiceAddressModels.d.ts +27 -0
  324. package/dist/shipping/customerSelfServiceAddressModels.js +101 -0
  325. package/dist/shipping/deliverySelectionHandler.d.ts +10 -0
  326. package/dist/shipping/deliverySelectionHandler.js +77 -0
  327. package/dist/shipping/deliverySelectionPort.d.ts +8 -0
  328. package/dist/shipping/deliverySelectionPort.js +1 -0
  329. package/dist/shipping/deliverySelectionSummary.d.ts +2 -0
  330. package/dist/shipping/deliverySelectionSummary.js +53 -0
  331. package/dist/shipping/handlerSchemas.d.ts +21 -0
  332. package/dist/shipping/handlerSchemas.js +1 -0
  333. package/dist/shipping/index.d.ts +20 -0
  334. package/dist/shipping/index.js +10 -0
  335. package/dist/shipping/pickupPointSearchPort.d.ts +4 -0
  336. package/dist/shipping/pickupPointSearchPort.js +1 -0
  337. package/dist/shipping/readDeliverySelectionEvidence.d.ts +2 -0
  338. package/dist/shipping/readDeliverySelectionEvidence.js +44 -0
  339. package/dist/shipping/shippingRatePorts.d.ts +52 -0
  340. package/dist/shipping/shippingRatePorts.js +1 -0
  341. package/dist/shipping/thresholdPolicy.d.ts +42 -0
  342. package/dist/shipping/thresholdPolicy.js +60 -0
  343. package/package.json +62 -2
  344. package/release-gates.json +263 -53
  345. package/sql/20260807140000_read_parity_catalog.sql +94 -0
  346. package/sql/20260810120000_storefront_catalog_attributes.sql +51 -0
  347. package/sql/20260812140000_sellable_bundle_catalog.sql +124 -0
  348. package/sql/20260812210000_bundle_operator_write_boundary.sql +567 -0
  349. package/sql/20260814000000_fulfillment_stock_evidence.sql +239 -0
  350. package/sql/20260815120000_automatic_subscription_renewal.sql +1083 -0
  351. package/sql/20260817180000_promotion_claim_lifecycle.sql +591 -0
  352. package/sql/20260817180100_promotion_claim_lifecycle_validation.sql +23 -0
  353. package/sql/20260827220000_catalog_document_revision_foundation.sql +226 -0
  354. package/sql/20260827220001_catalog_document_revision_foundation_validate.sql +10 -0
  355. package/sql/20260908100000_catalog_draft_foundation.sql +217 -0
  356. package/src/catalog/activeSkuSelection.ts +20 -0
  357. package/src/catalog/adminBindings.ts +59 -0
  358. package/src/catalog/adminBundleHandler.ts +165 -0
  359. package/src/catalog/adminBundleReadHandler.ts +263 -0
  360. package/src/catalog/adminBundleWritePort.ts +102 -0
  361. package/src/catalog/bundleAvailability.ts +129 -0
  362. package/src/catalog/bundleAvailabilityService.ts +171 -0
  363. package/src/catalog/bundleBindings.ts +29 -0
  364. package/src/catalog/bundleCatalogQueries.ts +98 -0
  365. package/src/catalog/bundleCatalogReadPort.ts +181 -0
  366. package/src/catalog/bundleCatalogStore.ts +274 -0
  367. package/src/catalog/bundlePriceSelection.ts +25 -0
  368. package/src/catalog/bundleRuleCodes.ts +134 -0
  369. package/src/catalog/bundleRules.ts +153 -0
  370. package/src/catalog/catalogDraftStore.ts +71 -0
  371. package/src/catalog/catalogSkuEnvelope.ts +214 -0
  372. package/src/catalog/catalogSkuEnvelopeMapper.ts +160 -0
  373. package/src/catalog/contracts/bundleAdmin.ts +20 -0
  374. package/src/catalog/contracts/bundleAvailability.ts +5 -0
  375. package/src/catalog/contracts/bundleRead.ts +13 -0
  376. package/src/catalog/contracts/draft.ts +69 -0
  377. package/src/catalog/contracts/foundation.ts +104 -0
  378. package/src/catalog/contracts/index.ts +14 -0
  379. package/src/catalog/contracts/lifecycle.ts +74 -0
  380. package/src/catalog/contracts/productMediaContracts.ts +170 -0
  381. package/src/catalog/contracts/productTypes.ts +35 -0
  382. package/src/catalog/contracts/resolveProductMedia.ts +85 -0
  383. package/src/catalog/contracts/sellable.ts +12 -0
  384. package/src/catalog/draftHandler.ts +105 -0
  385. package/src/catalog/draftPorts.ts +18 -0
  386. package/src/catalog/draftSchemas.ts +88 -0
  387. package/src/catalog/draftValidation.ts +100 -0
  388. package/src/catalog/effectiveBundleCatalogQueries.ts +80 -0
  389. package/src/catalog/effectiveBundleCatalogStore.ts +208 -0
  390. package/src/catalog/foundationSchemas.ts +123 -0
  391. package/src/catalog/index.ts +44 -0
  392. package/src/catalog/mediaSourcePack.ts +219 -0
  393. package/src/catalog/productTypeSchemas.ts +70 -0
  394. package/src/catalog/publicationPorts.ts +44 -0
  395. package/src/catalog/readPorts.ts +61 -0
  396. package/src/catalog/referenceCatalogHandler.ts +39 -0
  397. package/src/catalog/resolvedSkuProjection.ts +76 -0
  398. package/src/catalog/sellableBundleHandler.ts +133 -0
  399. package/src/catalog/sellableSchemas.ts +33 -0
  400. package/src/catalog/sql.ts +14 -0
  401. package/src/catalog/validation.ts +3 -0
  402. package/src/communications/contracts/index.ts +1 -0
  403. package/src/communications/contracts/marketingSync.ts +109 -0
  404. package/src/communications/index.ts +1 -0
  405. package/src/communications/klaviyo/consentPush.ts +19 -0
  406. package/src/communications/klaviyo/index.ts +649 -0
  407. package/src/communications/resend/index.ts +350 -0
  408. package/src/composition/catalogContribution.ts +32 -0
  409. package/src/composition/index.ts +3 -0
  410. package/src/composition/inventoryContribution.ts +24 -0
  411. package/src/composition/shippingContribution.ts +24 -0
  412. package/src/inventory/adminInventory.ts +251 -0
  413. package/src/inventory/bindings.ts +61 -0
  414. package/src/inventory/contracts/forecast.ts +96 -0
  415. package/src/inventory/contracts/index.ts +18 -0
  416. package/src/inventory/contracts/inventory.ts +14 -0
  417. package/src/inventory/contracts/newPurchaseStock.ts +23 -0
  418. package/src/inventory/contracts/reservation.ts +20 -0
  419. package/src/inventory/forecast.ts +239 -0
  420. package/src/inventory/index.ts +22 -0
  421. package/src/inventory/inventoryHandlers.ts +215 -0
  422. package/src/inventory/newPurchaseStockAvailability.ts +120 -0
  423. package/src/inventory/ports.ts +46 -0
  424. package/src/inventory/renewalReservation.ts +88 -0
  425. package/src/inventory/reservationPolicy.ts +27 -0
  426. package/src/inventory/schemas.ts +128 -0
  427. package/src/inventory/sql.ts +5 -0
  428. package/src/inventory/subscriptionForecastCalculation.ts +157 -0
  429. package/src/pricing/acquisitionFinancialPolicy.ts +26 -0
  430. package/src/pricing/acquisitionOfferPricing.ts +38 -0
  431. package/src/pricing/acquisitionOfferPricingHandler.ts +157 -0
  432. package/src/pricing/acquisitionOfferPricingSchemas.ts +35 -0
  433. package/src/pricing/acquisitionQuoteBinding.ts +12 -0
  434. package/src/pricing/acquisitionReadiness.ts +148 -0
  435. package/src/pricing/acquisitionTerms.ts +125 -0
  436. package/src/pricing/acquisitionTermsSchemas.ts +52 -0
  437. package/src/pricing/catalogFactsProvenance.ts +102 -0
  438. package/src/pricing/catalogFactsSchemas.ts +69 -0
  439. package/src/pricing/commerceOfferPricing.ts +224 -0
  440. package/src/pricing/commerceOfferPricingCache.ts +53 -0
  441. package/src/pricing/commerceOfferPricingHandler.ts +137 -0
  442. package/src/pricing/commercePriceAuthority.ts +169 -0
  443. package/src/pricing/commercePricingPolicyErrors.ts +88 -0
  444. package/src/pricing/commerceQuoteBatchHandler.ts +129 -0
  445. package/src/pricing/commerceQuoteCatalogReadPort.ts +42 -0
  446. package/src/pricing/commerceQuoteHandler.ts +199 -0
  447. package/src/pricing/commerceQuoteSnapshotExpect.ts +48 -0
  448. package/src/pricing/contracts/acquisitionTerms.ts +26 -0
  449. package/src/pricing/contracts/authority.ts +44 -0
  450. package/src/pricing/contracts/evidence.ts +25 -0
  451. package/src/pricing/contracts/index.ts +17 -0
  452. package/src/pricing/contracts/money.ts +32 -0
  453. package/src/pricing/contracts/offer.ts +42 -0
  454. package/src/pricing/contracts/offerPolicy.ts +17 -0
  455. package/src/pricing/contracts/policy.ts +26 -0
  456. package/src/pricing/contracts/provenance.ts +19 -0
  457. package/src/pricing/contracts/quote.ts +106 -0
  458. package/src/pricing/dbBackedCommerceQuoteHelpers.ts +256 -0
  459. package/src/pricing/dbBackedCommerceQuotePort.ts +280 -0
  460. package/src/pricing/dbBackedCommerceQuoteSnapshotVerifier.ts +49 -0
  461. package/src/pricing/index.ts +53 -0
  462. package/src/pricing/offerPolicyReadiness.ts +110 -0
  463. package/src/pricing/offerPolicySchemas.ts +23 -0
  464. package/src/pricing/offerPricingSchemas.ts +92 -0
  465. package/src/pricing/ports.ts +17 -0
  466. package/src/pricing/pricingPolicyToken.ts +119 -0
  467. package/src/pricing/quoteAcquisitionTerms.ts +10 -0
  468. package/src/pricing/quoteCodeRejectionDetails.ts +23 -0
  469. package/src/pricing/quotePorts.ts +58 -0
  470. package/src/pricing/quotePrimitives.ts +21 -0
  471. package/src/pricing/quotePromotionEvidence.ts +82 -0
  472. package/src/pricing/quoteSchemas.ts +230 -0
  473. package/src/pricing/quoteShippingPromotions.ts +21 -0
  474. package/src/pricing/subscriptionPricePolicy.ts +113 -0
  475. package/src/pricing/taxProfileGuard.ts +33 -0
  476. package/src/pricing/validation.ts +3 -0
  477. package/src/promotions/adminBindings.ts +53 -0
  478. package/src/promotions/adminPromotionCodesContracts.ts +244 -0
  479. package/src/promotions/adminPromotionCodesDataPort.ts +56 -0
  480. package/src/promotions/adminPromotionCodesHandler.ts +254 -0
  481. package/src/promotions/adminPromotionsContracts.ts +121 -0
  482. package/src/promotions/adminPromotionsDataPort.ts +48 -0
  483. package/src/promotions/adminPromotionsHandler.ts +72 -0
  484. package/src/promotions/commerceQuoteReadPreparation.ts +29 -0
  485. package/src/promotions/contracts/index.ts +387 -0
  486. package/src/promotions/index.ts +25 -0
  487. package/src/promotions/promoDataPort.ts +65 -0
  488. package/src/promotions/promotionAcceptanceTelemetry.ts +73 -0
  489. package/src/promotions/promotionBenefitDefinition.ts +48 -0
  490. package/src/promotions/promotionClaimSweepPort.ts +23 -0
  491. package/src/promotions/promotionClaims.ts +70 -0
  492. package/src/promotions/promotionCodePreview.ts +183 -0
  493. package/src/promotions/promotionCodeQuotePort.ts +35 -0
  494. package/src/promotions/promotionQuoteAcceptance.ts +291 -0
  495. package/src/promotions/promotionQuoteBinding.ts +163 -0
  496. package/src/promotions/quoteAcquisitionBinding.ts +7 -0
  497. package/src/promotions/quoteAutomaticPromotions.ts +84 -0
  498. package/src/promotions/quotePromoDiscounts.ts +194 -0
  499. package/src/promotions/quotePromotionCodeAdjustments.ts +277 -0
  500. package/src/promotions/quotePromotionV2.ts +239 -0
  501. package/src/promotions/quoteShippingPolicy.ts +61 -0
  502. package/src/promotions/sql.ts +5 -0
  503. package/src/promotions/validation.ts +3 -0
  504. package/src/shipping/addressCanonLookupHandler.ts +114 -0
  505. package/src/shipping/addressCanonical.ts +31 -0
  506. package/src/shipping/addressPorts.ts +48 -0
  507. package/src/shipping/addressSchemas.ts +28 -0
  508. package/src/shipping/adminShippingRateHandler.ts +72 -0
  509. package/src/shipping/bindings.ts +74 -0
  510. package/src/shipping/contracts/address.ts +71 -0
  511. package/src/shipping/contracts/delivery.ts +114 -0
  512. package/src/shipping/contracts/index.ts +19 -0
  513. package/src/shipping/contracts/shippingRate.ts +7 -0
  514. package/src/shipping/contracts/threshold.ts +22 -0
  515. package/src/shipping/customerAddressesHandler.ts +100 -0
  516. package/src/shipping/customerSelfServiceAddressModels.ts +124 -0
  517. package/src/shipping/deliverySelectionHandler.ts +94 -0
  518. package/src/shipping/deliverySelectionPort.ts +10 -0
  519. package/src/shipping/deliverySelectionSummary.ts +56 -0
  520. package/src/shipping/handlerSchemas.ts +19 -0
  521. package/src/shipping/index.ts +26 -0
  522. package/src/shipping/pickupPointSearchPort.ts +8 -0
  523. package/src/shipping/readDeliverySelectionEvidence.ts +51 -0
  524. package/src/shipping/shippingRatePorts.ts +36 -0
  525. package/src/shipping/thresholdPolicy.ts +65 -0
@@ -0,0 +1,111 @@
1
+ import { evaluateBundleComposition, evaluateBundleCompositionConstraint, evaluateBundleFulfillmentMode } from "./bundleRules.js";
2
+ export function createAdminBundleHandlers({ bundleSpec, BundleRpcError, COMMERCE_CONTRACT_VERSION, createAdminMutationHandler }) {
3
+ /**
4
+ * Bundle write handlers — each is the generic kit factory
5
+ * `createAdminMutationHandler` driven by one operation of `bundleSpec`. The
6
+ * factory owns the shared spine (POST-only, flag gate, admin authz, DB-derived
7
+ * actor-kind gate, contract parse, error map, success envelope); this module only
8
+ * injects the request-scoped port call, the envelope shape and the two pure rule
9
+ * passes that are decidable before the write.
10
+ */
11
+ const BUNDLE_DISABLED = "Bundle writes are disabled";
12
+ const BUNDLE_INVALID = "Invalid bundle write request";
13
+ const BUNDLE_FAILURE = "Bundle write failed";
14
+ /** Bundle success envelope; only the fields the operation actually produced. */
15
+ function bundleResponse(result) {
16
+ return {
17
+ contractVersion: COMMERCE_CONTRACT_VERSION,
18
+ dryRun: result.dryRun,
19
+ idempotent: result.idempotent,
20
+ ...(result.code ? { code: result.code } : {}),
21
+ ...(result.bundleId ? { bundleId: result.bundleId } : {}),
22
+ ...(result.componentCount === undefined ? {} : { componentCount: result.componentCount }),
23
+ };
24
+ }
25
+ /** A request-layer rule refusal, mapped onto the same envelope the boundary uses. */
26
+ function ruleRefusal(violations) {
27
+ return new BundleRpcError("P0001", violations.join(","));
28
+ }
29
+ function buildBundleHandler(deps, mutationKey, invoke) {
30
+ const mutation = bundleSpec.mutations[mutationKey];
31
+ const isActivation = mutation.gate === "activation";
32
+ return createAdminMutationHandler({
33
+ mutation,
34
+ flagName: isActivation ? bundleSpec.activationFlag : bundleSpec.mutationFlag,
35
+ enabled: isActivation ? deps.activationEnabled : deps.mutationsEnabled,
36
+ authorizeAdmin: deps.authorizeAdmin,
37
+ invoke: (actorId, input) => invoke(deps.writePort, actorId, input),
38
+ toResponse: bundleResponse,
39
+ disabledMessage: BUNDLE_DISABLED,
40
+ invalidRequestMessage: BUNDLE_INVALID,
41
+ failureMessage: BUNDLE_FAILURE,
42
+ });
43
+ }
44
+ function createAdminBundleCreateDraftHandler(deps) {
45
+ return buildBundleHandler(deps, "create", (port, actorId, input) => {
46
+ const mode = evaluateBundleFulfillmentMode(input.bundle.fulfillmentMode);
47
+ if (!mode.ok)
48
+ return Promise.reject(ruleRefusal(mode.violations));
49
+ return port.upsertDraft(actorId, input);
50
+ });
51
+ }
52
+ function createAdminBundleUpdateDraftHandler(deps) {
53
+ return buildBundleHandler(deps, "update", (port, actorId, input) => {
54
+ const requested = input.updates.fulfillmentMode;
55
+ if (requested !== undefined) {
56
+ const mode = evaluateBundleFulfillmentMode(requested);
57
+ if (!mode.ok)
58
+ return Promise.reject(ruleRefusal(mode.violations));
59
+ }
60
+ return port.updateDraft(actorId, input);
61
+ });
62
+ }
63
+ /**
64
+ * Whole-set composition replace. Two pure passes run before the write: the set
65
+ * rules that are decidable from the request alone (at least one component, at
66
+ * least one non-add-on, no unit twice), and — when the bundle carries a non-empty
67
+ * constraint envelope — the adopter's own `CompositionRulesPort`. The write
68
+ * boundary re-derives everything it can see and refuses independently.
69
+ */
70
+ function createAdminBundleSetCompositionHandler(deps) {
71
+ return buildBundleHandler(deps, "setComposition", async (port, actorId, input) => {
72
+ const composition = evaluateBundleComposition(input.components);
73
+ if (!composition.ok)
74
+ throw ruleRefusal(composition.violations);
75
+ const constraint = await evaluateBundleCompositionConstraint(deps.compositionRules, {
76
+ components: input.components,
77
+ constraint: await port.loadCompositionConstraint(input.code),
78
+ });
79
+ if (!constraint.ok)
80
+ throw ruleRefusal(constraint.violations);
81
+ return port.setComposition(actorId, input);
82
+ });
83
+ }
84
+ function createAdminBundleSetTargetPriceHandler(deps) {
85
+ return buildBundleHandler(deps, "setTargetPrice", (port, actorId, input) => port.setTargetPrice(actorId, input));
86
+ }
87
+ function createAdminBundleArchiveHandler(deps) {
88
+ return buildBundleHandler(deps, "archive", (port, actorId, input) => port.archive(actorId, input));
89
+ }
90
+ function createAdminBundleRestoreHandler(deps) {
91
+ return buildBundleHandler(deps, "restore", (port, actorId, input) => port.restore(actorId, input));
92
+ }
93
+ function createAdminBundleCloneDraftHandler(deps) {
94
+ return buildBundleHandler(deps, "cloneDraft", (port, actorId, input) => port.cloneDraft(actorId, input));
95
+ }
96
+ /**
97
+ * Activate (publish) — HUMAN-ONLY. The mutation's gate is `activation`, so the
98
+ * factory wires it to the activation flag and refuses a machine actor (403) from
99
+ * `allowedActorKinds` before the write is ever reached. The managed write routine
100
+ * also RAISEs 42501 as a second layer; the native routine has no independent
101
+ * actor-kind gate and relies on this handler gate.
102
+ */
103
+ function createAdminBundleActivateHandler(deps) {
104
+ return buildBundleHandler(deps, "activate", (port, actorId, input) => port.activate(actorId, input));
105
+ }
106
+ /** Deactivate (unpublish) — HUMAN-ONLY, gated identically to activate. */
107
+ function createAdminBundleDeactivateHandler(deps) {
108
+ return buildBundleHandler(deps, "deactivate", (port, actorId, input) => port.deactivate(actorId, input));
109
+ }
110
+ return { createAdminBundleCreateDraftHandler, createAdminBundleUpdateDraftHandler, createAdminBundleSetCompositionHandler, createAdminBundleSetTargetPriceHandler, createAdminBundleArchiveHandler, createAdminBundleRestoreHandler, createAdminBundleCloneDraftHandler, createAdminBundleActivateHandler, createAdminBundleDeactivateHandler };
111
+ }
@@ -0,0 +1,21 @@
1
+ import type { BundleAdminBindings, AuthorizeAdmin } from "./adminBindings.js";
2
+ import type { BundleAvailabilityService } from "./bundleAvailabilityService.js";
3
+ import type { BundleCatalogReadPort, BundleDetail, BundleTargetPriceRow } from "./bundleCatalogReadPort.js";
4
+ export interface AdminBundleReadHandlerDeps {
5
+ effectiveTarget?: (bundle: BundleDetail) => BundleTargetPriceRow | null;
6
+ readPort: BundleCatalogReadPort;
7
+ authorizeAdmin: AuthorizeAdmin;
8
+ readsEnabled: boolean;
9
+ /**
10
+ * Derived stock for the detail response. OPTIONAL, and absence is reported as a null
11
+ * `availability` rather than as an omitted field or a zero: a deployment with no stock rail has
12
+ * not counted anything, and saying so is different from saying nothing can ship.
13
+ */
14
+ availabilityService?: BundleAvailabilityService;
15
+ }
16
+ export declare function createAdminBundleReadHandlers({ bundleSpec, BundleRpcError, COMMERCE_CONTRACT_VERSION, createAdminParameterizedReadHandler, bundleHistoryResponseSchema, getBundleResponseSchema, listBundlesResponseSchema, previewBundlePriceResponseSchema }: Pick<BundleAdminBindings, "bundleSpec" | "BundleRpcError" | "COMMERCE_CONTRACT_VERSION" | "createAdminParameterizedReadHandler" | "bundleHistoryResponseSchema" | "getBundleResponseSchema" | "listBundlesResponseSchema" | "previewBundlePriceResponseSchema">): {
17
+ createAdminBundleListHandler: (deps: AdminBundleReadHandlerDeps) => (req: import("../http/types.js").HttpRequest, res: import("../http/types.js").HttpResponse) => Promise<void>;
18
+ createAdminBundleGetHandler: (deps: AdminBundleReadHandlerDeps) => (req: import("../http/types.js").HttpRequest, res: import("../http/types.js").HttpResponse) => Promise<void>;
19
+ createAdminBundleHistoryHandler: (deps: AdminBundleReadHandlerDeps) => (req: import("../http/types.js").HttpRequest, res: import("../http/types.js").HttpResponse) => Promise<void>;
20
+ createAdminBundlePreviewPriceHandler: (deps: AdminBundleReadHandlerDeps) => (req: import("../http/types.js").HttpRequest, res: import("../http/types.js").HttpResponse) => Promise<void>;
21
+ };
@@ -0,0 +1,185 @@
1
+ import { allocateBundleTargetPrice } from "@openlup/core/pricing";
2
+ export function createAdminBundleReadHandlers({ bundleSpec, BundleRpcError, COMMERCE_CONTRACT_VERSION, createAdminParameterizedReadHandler, bundleHistoryResponseSchema, getBundleResponseSchema, listBundlesResponseSchema, previewBundlePriceResponseSchema }) {
3
+ /**
4
+ * Bundle READ handlers — each is the generic kit factory
5
+ * `createAdminParameterizedReadHandler` driven by one query of `bundleSpec`. The
6
+ * factory owns the shared spine (GET-only, flag gate, admin authz, DB-derived
7
+ * actor-kind gate, query parse, error map, response validation, success
8
+ * envelope); this module only injects the read-port call and the response shape.
9
+ * It mirrors `adminBundleHandler.ts`, and the catalog reference
10
+ * (`server/domains/commerce/adminCatalogReadHandler.ts`) is the shape both follow.
11
+ *
12
+ * The price preview is the one read that computes: it runs the SAME pricing kernel
13
+ * the write boundary refuses against (`allocateBundleTargetPrice`) over TODAY's
14
+ * component prices, so an operator can see the money before committing to it. Its
15
+ * three refusal codes are mapped onto the same envelope a refused write produces,
16
+ * because they are the same three decisions.
17
+ */
18
+ const BUNDLE_READ_DISABLED = "Bundle reads are disabled";
19
+ const BUNDLE_READ_INVALID = "Invalid bundle read request";
20
+ const BUNDLE_READ_FAILURE = "Bundle read failed";
21
+ function query(key) {
22
+ const spec = bundleSpec.queries?.[key];
23
+ if (!spec)
24
+ throw new Error(`bundleSpec.queries.${key} is not defined`);
25
+ return spec;
26
+ }
27
+ function gate(deps, key, load, toResponse, responseSchema, invalidResponseMessage) {
28
+ return createAdminParameterizedReadHandler({
29
+ query: query(key),
30
+ flagName: bundleSpec.readFlag,
31
+ enabled: deps.readsEnabled,
32
+ authorizeAdmin: deps.authorizeAdmin,
33
+ load: (_actorId, input) => load(deps.readPort, input),
34
+ toResponse,
35
+ responseSchema,
36
+ disabledMessage: BUNDLE_READ_DISABLED,
37
+ invalidRequestMessage: BUNDLE_READ_INVALID,
38
+ invalidResponseMessage,
39
+ failureMessage: BUNDLE_READ_FAILURE,
40
+ });
41
+ }
42
+ function createAdminBundleListHandler(deps) {
43
+ return gate(deps, "list", (port, input) => port.listBundles(input), (data) => ({
44
+ contractVersion: COMMERCE_CONTRACT_VERSION,
45
+ bundles: data.bundles,
46
+ total: data.total,
47
+ }), listBundlesResponseSchema, "Invalid bundle list response");
48
+ }
49
+ function createAdminBundleGetHandler(deps) {
50
+ return gate(deps, "get", async (port, input) => {
51
+ const bundle = await port.getBundle(input);
52
+ // Absent is NOT an empty detail: the same P0002 the write boundary raises,
53
+ // so a missing bundle answers 404 through one map rather than two.
54
+ if (!bundle)
55
+ throw new BundleRpcError("P0002", "bundle_not_found");
56
+ return { bundle, stock: await describeStock(deps, bundle) };
57
+ }, ({ bundle, stock }) => ({
58
+ contractVersion: COMMERCE_CONTRACT_VERSION,
59
+ bundle: toDetailView(bundle, stock),
60
+ }), getBundleResponseSchema, "Invalid bundle detail response");
61
+ }
62
+ /**
63
+ * Fold stock into ONE bundle, through the same service the public feed uses.
64
+ *
65
+ * The service takes compositions and this is a detail, but the two carry the identical component
66
+ * row type, so the adaptation is a rename rather than a translation — and routing this read through
67
+ * the shared service is the point: `deriveBundleAvailability` stays the single place that folds
68
+ * units into bundles, so an operator's detail page and a shopper's feed can never disagree about
69
+ * the same bundle.
70
+ *
71
+ * A bundle whose status is not live is NOT skipped here. That is the whole gain over the feed: the
72
+ * feed is live-only by construction, so a draft had no derived stock anywhere, and an operator
73
+ * about to activate one could not see whether it would ship.
74
+ */
75
+ async function describeStock(deps, bundle) {
76
+ if (!deps.availabilityService)
77
+ return null;
78
+ const [row] = await deps.availabilityService.describeCompositions([
79
+ {
80
+ code: bundle.code,
81
+ title: bundle.title,
82
+ fulfillmentMode: bundle.fulfillmentMode,
83
+ // Stated from what the detail resolved. Neither reaches the stock question — the service
84
+ // asks the availability port for units, never for money — but the shape is the contract and
85
+ // inventing a currency here would be a lie in a field somebody may later read.
86
+ currency: bundle.resolvedCurrency ?? "",
87
+ targetPriceMinor: 0,
88
+ mode: "any",
89
+ components: bundle.components,
90
+ },
91
+ ]);
92
+ return row ?? null;
93
+ }
94
+ function createAdminBundleHistoryHandler(deps) {
95
+ return gate(deps, "history", (port, input) => port.listBundleHistory(input), (data) => ({
96
+ contractVersion: COMMERCE_CONTRACT_VERSION,
97
+ events: data.events,
98
+ total: data.total,
99
+ }), bundleHistoryResponseSchema, "Invalid bundle history response");
100
+ }
101
+ function createAdminBundlePreviewPriceHandler(deps) {
102
+ return gate(deps, "previewPrice", async (port, input) => {
103
+ const bundle = await port.getBundle({
104
+ code: input.code,
105
+ currency: input.currency,
106
+ mode: input.mode,
107
+ });
108
+ if (!bundle)
109
+ throw new BundleRpcError("P0002", "bundle_not_found");
110
+ return previewBundlePrice(bundle, input, deps.effectiveTarget);
111
+ }, (preview) => ({ contractVersion: COMMERCE_CONTRACT_VERSION, preview }), previewBundlePriceResponseSchema, "Invalid bundle price preview response");
112
+ }
113
+ /** The detail the transport carries: the port's internal variant id stays server-side. */
114
+ function toDetailView(bundle, stock) {
115
+ const { components, resolvedPriceListId: _priceListId, ...rest } = bundle;
116
+ return {
117
+ ...rest,
118
+ components: components.map(({ variantId: _variantId, ...component }) => component),
119
+ availability: stock
120
+ ? {
121
+ sellableNow: stock.availability.sellableNow,
122
+ status: stock.availability.status,
123
+ reasonCode: stock.availability.reasonCode,
124
+ limitingSku: stock.availability.limitingSku,
125
+ components: stock.components.map((component) => ({
126
+ sku: component.sku,
127
+ quantity: component.quantity,
128
+ isAddon: component.isAddon,
129
+ sellableNow: component.sellableNow,
130
+ })),
131
+ }
132
+ : null,
133
+ };
134
+ }
135
+ /**
136
+ * Run the pricing kernel over the bundle's live component prices.
137
+ *
138
+ * Every refusal is stated as the same rule violation a write would produce, so an
139
+ * operator previewing a price and an operator setting it are told the same thing:
140
+ * no priced list (P0002), an unpriced component or an empty set (P0001), and the
141
+ * kernel's own three failure codes (P0001).
142
+ */
143
+ function previewBundlePrice(bundle, input, effectiveTarget) {
144
+ if (!bundle.resolvedPriceListId || !bundle.resolvedCurrency) {
145
+ throw new BundleRpcError("P0002", "no_active_price_list");
146
+ }
147
+ const counted = bundle.components;
148
+ if (counted.length === 0)
149
+ throw new BundleRpcError("P0001", "min_components");
150
+ const unpriced = counted.filter((component) => component.referenceUnitPriceMinor === null);
151
+ if (unpriced.length > 0) {
152
+ throw new BundleRpcError("P0001", `component_unpriced:${unpriced[0].sku}`);
153
+ }
154
+ const activePrice = effectiveTarget ? effectiveTarget(bundle) : bundle.prices.find((price) => price.active && (!input.mode || price.mode === input.mode));
155
+ const targetPriceMinor = input.targetPriceMinor ?? activePrice?.targetPriceMinor;
156
+ if (targetPriceMinor === undefined)
157
+ throw new BundleRpcError("P0002", "no_active_target_price");
158
+ const allocation = allocateBundleTargetPrice({
159
+ components: counted.map((component) => ({
160
+ sku: component.sku,
161
+ quantity: component.quantity,
162
+ unitPriceMinor: component.referenceUnitPriceMinor,
163
+ })),
164
+ targetPriceMinor,
165
+ });
166
+ // The narrowing is written out rather than relied upon: the Node tsconfig runs
167
+ // without strictNullChecks, where a discriminated union does not narrow on `ok`.
168
+ if (!allocation.ok)
169
+ throw new BundleRpcError("P0001", allocation.code);
170
+ return {
171
+ bundleCode: bundle.code,
172
+ priceListId: bundle.resolvedPriceListId,
173
+ mode: input.mode ?? activePrice?.mode ?? (effectiveTarget ? "one_time" : "any"),
174
+ currency: bundle.resolvedCurrency,
175
+ referenceTotalMinor: allocation.referenceTotalMinor,
176
+ targetPriceMinor: allocation.targetPriceMinor,
177
+ discountTotalMinor: allocation.discountTotalMinor,
178
+ discountBps: allocation.discountBps,
179
+ floorApplied: allocation.floorApplied,
180
+ componentTargets: allocation.components,
181
+ allocatedLines: allocation.lines,
182
+ };
183
+ }
184
+ return { createAdminBundleListHandler, createAdminBundleGetHandler, createAdminBundleHistoryHandler, createAdminBundlePreviewPriceHandler };
185
+ }
@@ -0,0 +1,85 @@
1
+ import type { CreateBundleDraftRequest, SetBundleCompositionRequest, SetBundleTargetPriceRequest, UpdateBundleDraftRequest } from "./contracts/bundleAdmin.js";
2
+ import type { ActivateBundleRequest, ArchiveBundleRequest, CloneBundleDraftRequest, DeactivateBundleRequest, RestoreBundleRequest } from "./contracts/bundleAdmin.js";
3
+ /**
4
+ * The semantic write port for the admin/agent bundle surface.
5
+ *
6
+ * This file names the CAPABILITY, never the storage. Both shipped write adapters
7
+ * implement exactly this interface and are proved against ONE shared scenario table, so a caller cannot
8
+ * tell them apart and neither can a rule. No data-client type, table name or
9
+ * routine name appears here; the domain layer opens no database handle of its own.
10
+ *
11
+ * Each method is one atomic operation on the security boundary: the boundary takes
12
+ * the actor explicitly; the managed chain re-derives actor kind, while native
13
+ * relies on the handler human-only gate. Each boundary writes its ledger row in the same transaction, short-circuits a replayed
14
+ * idempotency key, and validates a dry run without durable writes.
15
+ */
16
+ /** Shape every bundle write returns. */
17
+ export interface BundleWriteResult {
18
+ idempotent: boolean;
19
+ dryRun: boolean;
20
+ code?: string;
21
+ bundleId?: string;
22
+ componentCount?: number;
23
+ }
24
+ /** The opaque rules envelope a bundle carries, as the boundary hands it back. */
25
+ export interface BundleCompositionConstraintEnvelope {
26
+ kind: string;
27
+ version: number;
28
+ data: Record<string, unknown>;
29
+ }
30
+ export interface AdminBundleWritePort {
31
+ /**
32
+ * Read the bundle's stored composition constraint. This is a WRITE-path read: the
33
+ * whole-set replace must be validated against the envelope the bundle already
34
+ * carries before anything is written, and the adopter's `CompositionRulesPort` is
35
+ * the only thing that can decide it. Returns `null` for an unconstrained bundle.
36
+ * Raises P0002 when the bundle does not exist.
37
+ */
38
+ loadCompositionConstraint(code: string): Promise<BundleCompositionConstraintEnvelope | null>;
39
+ /** Create or edit a DRAFT bundle from a full structural payload. */
40
+ upsertDraft(actorId: string, input: CreateBundleDraftRequest): Promise<BundleWriteResult>;
41
+ /**
42
+ * Partial structural edit of a DRAFT bundle. The upsert is full-payload, so this
43
+ * reads the current bundle, overlays the supplied fields and replays the merged
44
+ * payload through the same boundary. Raises NOT_FOUND (P0002) when the bundle
45
+ * does not exist.
46
+ */
47
+ updateDraft(actorId: string, input: UpdateBundleDraftRequest): Promise<BundleWriteResult>;
48
+ /**
49
+ * Replace the bill of materials as a WHOLE SET, atomically. Raises P0002 when the
50
+ * bundle or a named unit is missing, and P0001 when a unit is not sellable on its
51
+ * own or is priced in another currency.
52
+ */
53
+ setComposition(actorId: string, input: SetBundleCompositionRequest): Promise<BundleWriteResult>;
54
+ /**
55
+ * Append a new active target price and close the previous one. Never mutates an
56
+ * existing row. Raises P0001 when the target sits above the sum of the parts or
57
+ * below the floor every component must clear.
58
+ */
59
+ setTargetPrice(actorId: string, input: SetBundleTargetPriceRequest): Promise<BundleWriteResult>;
60
+ /** Remove a bundle from sale (status flip, never a hard delete). P0002 when missing. */
61
+ archive(actorId: string, input: ArchiveBundleRequest): Promise<BundleWriteResult>;
62
+ /**
63
+ * Restore an archived bundle to draft. Raises P0002 when missing and P0001
64
+ * (`restore_requires_archived`) when the bundle is not archived.
65
+ */
66
+ restore(actorId: string, input: RestoreBundleRequest): Promise<BundleWriteResult>;
67
+ /**
68
+ * Clone any bundle into a NEW draft under a new code, including its composition.
69
+ * Raises P0002 (`clone_source_not_found`) when the source is missing and P0001
70
+ * when the target code is already taken.
71
+ */
72
+ cloneDraft(actorId: string, input: CloneBundleDraftRequest): Promise<BundleWriteResult>;
73
+ /**
74
+ * Publish (draft -> active). HUMAN-ONLY: the managed chain raises 42501
75
+ * (`publish_requires_human`) for machine actors; native relies on the handler gate. Raises P0001 when the bundle has
76
+ * no composition or no active target price.
77
+ */
78
+ activate(actorId: string, input: ActivateBundleRequest): Promise<BundleWriteResult>;
79
+ /**
80
+ * Unpublish (active -> draft). HUMAN-ONLY: the managed chain uses the same
81
+ * 42501 refusal; native relies on the handler gate. Raises P0001
82
+ * (`deactivate_requires_active`) when the bundle is not live.
83
+ */
84
+ deactivate(actorId: string, input: DeactivateBundleRequest): Promise<BundleWriteResult>;
85
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,63 @@
1
+ import type { BundleRuleBindings, BundleStockStatus as CommerceOfferAvailabilityStatus } from "./bundleBindings.js";
2
+ /**
3
+ * Derived stock for a composed bundle — the pure kernel that folds many component
4
+ * stock figures into ONE answer about the bundle.
5
+ *
6
+ * A bundle is only as sellable as its scarcest counted part: with a bill of
7
+ * materials of `quantity` units per component, the number of whole bundles that
8
+ * can ship is `min(floor(component.sellableNow / component.quantity))`. That
9
+ * component is named (`limitingSku`) so an operator learns WHICH part is the
10
+ * constraint instead of only that there is one.
11
+ *
12
+ * FAIL TO UNKNOWN, NEVER GUESS. If any counted component's stock is itself
13
+ * unknown, the bundle's stock is unknown — not the minimum of the parts that did
14
+ * answer. Treating a missing figure as unlimited oversells; treating it as zero
15
+ * hides a sellable bundle. Both are decisions this module refuses to make, so it
16
+ * reports `unknown` and names the component whose figure is missing.
17
+ *
18
+ * The status ladder and the reason-code vocabulary are IMPORTED from the commerce
19
+ * domain's PUBLIC port seam rather than restated, so a bundle and a single unit
20
+ * can never disagree about what `low_stock` means.
21
+ *
22
+ * Pure: integer arithmetic, no clock, no randomness, no I/O.
23
+ */
24
+ /**
25
+ * Threshold below which a bundle reads as `low_stock`. Deliberately far under the
26
+ * single-unit default: a bundle consumes several units per sale, so the same raw
27
+ * stock represents far fewer bundles and a unit-scale threshold would report
28
+ * nearly every bundle as low.
29
+ */
30
+ export declare const DEFAULT_BUNDLE_LOW_STOCK_THRESHOLD = 3;
31
+ /** A counted component answered with no figure at all. */
32
+ export declare const BUNDLE_COMPONENT_STOCK_UNKNOWN = "component_stock_unknown";
33
+ /** Nothing was counted — no non-add-on component to derive an answer from. */
34
+ export declare const BUNDLE_COMPOSITION_EMPTY = "bundle_composition_empty";
35
+ export interface BundleAvailabilityComponent {
36
+ sku: string;
37
+ /** Units of this component consumed by ONE bundle; always positive. */
38
+ quantity: number;
39
+ isAddon: boolean;
40
+ /** Sellable units of the component, or `null` when the figure is unknown. */
41
+ sellableNow: number | null;
42
+ }
43
+ export interface BundleAvailability {
44
+ /** Whole bundles that can ship now, or `null` when any counted part is unknown. */
45
+ sellableNow: number | null;
46
+ status: CommerceOfferAvailabilityStatus;
47
+ reasonCode: string;
48
+ /** The component that decided the answer; `null` only when nothing was counted. */
49
+ limitingSku: string | null;
50
+ }
51
+ export interface DeriveBundleAvailabilityInput {
52
+ components: readonly BundleAvailabilityComponent[];
53
+ lowStockThreshold?: number;
54
+ /**
55
+ * Add-ons are excluded by default: an add-on is priced into the bundle but
56
+ * optional in composition, so its stock must not make the bundle unsellable.
57
+ * An operator who sells the add-on as mandatory opts in here.
58
+ */
59
+ includeAddonsInStock?: boolean;
60
+ }
61
+ export declare function createBundleAvailability({ offerAvailabilityReasonCode, offerAvailabilityStatusFor }: Pick<BundleRuleBindings, "offerAvailabilityReasonCode" | "offerAvailabilityStatusFor">): {
62
+ deriveBundleAvailability: (input: DeriveBundleAvailabilityInput) => BundleAvailability;
63
+ };
@@ -0,0 +1,78 @@
1
+ /**
2
+ * Derived stock for a composed bundle — the pure kernel that folds many component
3
+ * stock figures into ONE answer about the bundle.
4
+ *
5
+ * A bundle is only as sellable as its scarcest counted part: with a bill of
6
+ * materials of `quantity` units per component, the number of whole bundles that
7
+ * can ship is `min(floor(component.sellableNow / component.quantity))`. That
8
+ * component is named (`limitingSku`) so an operator learns WHICH part is the
9
+ * constraint instead of only that there is one.
10
+ *
11
+ * FAIL TO UNKNOWN, NEVER GUESS. If any counted component's stock is itself
12
+ * unknown, the bundle's stock is unknown — not the minimum of the parts that did
13
+ * answer. Treating a missing figure as unlimited oversells; treating it as zero
14
+ * hides a sellable bundle. Both are decisions this module refuses to make, so it
15
+ * reports `unknown` and names the component whose figure is missing.
16
+ *
17
+ * The status ladder and the reason-code vocabulary are IMPORTED from the commerce
18
+ * domain's PUBLIC port seam rather than restated, so a bundle and a single unit
19
+ * can never disagree about what `low_stock` means.
20
+ *
21
+ * Pure: integer arithmetic, no clock, no randomness, no I/O.
22
+ */
23
+ /**
24
+ * Threshold below which a bundle reads as `low_stock`. Deliberately far under the
25
+ * single-unit default: a bundle consumes several units per sale, so the same raw
26
+ * stock represents far fewer bundles and a unit-scale threshold would report
27
+ * nearly every bundle as low.
28
+ */
29
+ export const DEFAULT_BUNDLE_LOW_STOCK_THRESHOLD = 3;
30
+ /** A counted component answered with no figure at all. */
31
+ export const BUNDLE_COMPONENT_STOCK_UNKNOWN = "component_stock_unknown";
32
+ /** Nothing was counted — no non-add-on component to derive an answer from. */
33
+ export const BUNDLE_COMPOSITION_EMPTY = "bundle_composition_empty";
34
+ export function createBundleAvailability({ offerAvailabilityReasonCode, offerAvailabilityStatusFor }) {
35
+ function deriveBundleAvailability(input) {
36
+ const counted = input.components.filter((component) => input.includeAddonsInStock === true || !component.isAddon);
37
+ if (counted.length === 0) {
38
+ return {
39
+ sellableNow: null,
40
+ status: "unknown",
41
+ reasonCode: BUNDLE_COMPOSITION_EMPTY,
42
+ limitingSku: null,
43
+ };
44
+ }
45
+ // Unknown wins over every figure that did answer, and the named component is the
46
+ // lowest sku among the unknown ones, so the same set always names the same part.
47
+ const unknown = counted.filter((component) => component.sellableNow === null);
48
+ if (unknown.length > 0) {
49
+ return {
50
+ sellableNow: null,
51
+ status: "unknown",
52
+ reasonCode: BUNDLE_COMPONENT_STOCK_UNKNOWN,
53
+ limitingSku: lowestSku(unknown),
54
+ };
55
+ }
56
+ let limiting = counted[0];
57
+ let sellableNow = wholeBundles(counted[0]);
58
+ for (const component of counted.slice(1)) {
59
+ const candidate = wholeBundles(component);
60
+ // Strictly lower wins; an exact tie is broken by ascending sku code units, so
61
+ // the named component never depends on the order the composition was read in.
62
+ if (candidate < sellableNow || (candidate === sellableNow && component.sku < limiting.sku)) {
63
+ limiting = component;
64
+ sellableNow = candidate;
65
+ }
66
+ }
67
+ const status = offerAvailabilityStatusFor(sellableNow, input.lowStockThreshold ?? DEFAULT_BUNDLE_LOW_STOCK_THRESHOLD);
68
+ return { sellableNow, status, reasonCode: offerAvailabilityReasonCode(status), limitingSku: limiting.sku };
69
+ }
70
+ return { deriveBundleAvailability };
71
+ }
72
+ /** Whole bundles this component alone can carry. */
73
+ function wholeBundles(component) {
74
+ return Math.floor((component.sellableNow ?? 0) / component.quantity);
75
+ }
76
+ function lowestSku(components) {
77
+ return components.reduce((lowest, component) => (component.sku < lowest ? component.sku : lowest), components[0].sku);
78
+ }
@@ -0,0 +1,65 @@
1
+ import type { BundleAvailability, BundleAvailabilityComponent } from "./bundleAvailability.js";
2
+ import type { BundleStockPort as CommerceOfferAvailabilityPort } from "./bundleBindings.js";
3
+ import type { ActiveBundleComposition, BundleCatalogReadPort } from "./bundleCatalogReadPort.js";
4
+ /**
5
+ * Derived bundle stock, composed from the two ports that already know the halves:
6
+ * the bundle read port knows the bill of materials, the EXISTING commerce offer
7
+ * availability port knows what a unit's stock is. Nothing here re-derives stock and
8
+ * nothing here opens a database handle.
9
+ *
10
+ * ONE BATCHED CALL, ALWAYS. Every component of every bundle in the request is
11
+ * asked for in a single `getAvailability`, deduplicated by sku, because the
12
+ * underlying port answers a set in three queries — asking per bundle would turn a
13
+ * catalogue listing into a query storm and would let two bundles sharing a unit
14
+ * disagree about its stock inside one response.
15
+ *
16
+ * A sku the availability port does not answer for is a MISSING figure, not zero:
17
+ * it is folded in as `sellableNow: null`, so the pure kernel reports the bundle as
18
+ * unknown and names the component rather than quietly overselling or hiding it.
19
+ */
20
+ export interface BundleAvailabilityServiceDeps {
21
+ bundleCatalogReadPort: BundleCatalogReadPort;
22
+ offerAvailabilityPort: CommerceOfferAvailabilityPort;
23
+ /** Threshold handed to the pure kernel; its own default applies when omitted. */
24
+ lowStockThreshold?: number;
25
+ includeAddonsInStock?: boolean;
26
+ }
27
+ export interface BundleAvailabilityRow {
28
+ composition: ActiveBundleComposition;
29
+ availability: BundleAvailability;
30
+ /**
31
+ * The EXACT rows the kernel was given, carried out again rather than recomputed.
32
+ *
33
+ * The bundle-level answer names one limiting component; an operator staring at a bundle that
34
+ * cannot ship needs to know how far off every OTHER component is too, so they can tell "order one
35
+ * more of this" from "this bundle is months away". These rows are the only place that figure
36
+ * exists — the kernel folds them into a single number and the sellable feed's components carry
37
+ * price, never stock. Returning them costs nothing here and is the alternative to a second stock
38
+ * derivation somewhere that can disagree with this one.
39
+ */
40
+ components: readonly BundleAvailabilityComponent[];
41
+ }
42
+ export interface BundleAvailabilityService {
43
+ /** Fold stock into a set of compositions the caller already holds. */
44
+ describeCompositions(compositions: readonly ActiveBundleComposition[]): Promise<BundleAvailabilityRow[]>;
45
+ /** Read the live sellable set and fold stock into it. */
46
+ describeActiveBundles(input?: {
47
+ currency?: string;
48
+ }): Promise<BundleAvailabilityRow[]>;
49
+ }
50
+ export declare function createBundleAvailabilityServices({ deriveBundleAvailability }: {
51
+ deriveBundleAvailability: (input: import("./bundleAvailability.js").DeriveBundleAvailabilityInput) => BundleAvailability;
52
+ }): {
53
+ createBundleAvailabilityService: (deps: BundleAvailabilityServiceDeps) => BundleAvailabilityService;
54
+ };
55
+ /**
56
+ * The port to use where no stock source is bound at all.
57
+ *
58
+ * It answers every item with `sellableNow: null`, which the kernel reads as
59
+ * unknown — so a deployment without an inventory rail publishes bundles whose
60
+ * price is exact and whose stock is honestly unstated. The alternative, omitting
61
+ * the availability block, would have made "we do not know" indistinguishable from
62
+ * "we did not ask", and the alternative to THAT — defaulting to available —
63
+ * oversells on a deployment that never counted anything.
64
+ */
65
+ export declare function createUnknownOfferAvailabilityPort(): CommerceOfferAvailabilityPort;