@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,200 @@
1
+ import { z } from "zod";
2
+ import { INVENTORY_CONTRACT_VERSION, availableNow } from "@openlup/core/inventory";
3
+ import { createInventorySubscriptionForecastResponseSchema } from "./schemas.js";
4
+ const uuidSchema = z.guid();
5
+ const datetimeSchema = z.string().datetime({ offset: true });
6
+ const quantitySchema = z.number().int().nonnegative();
7
+ const positiveQuantitySchema = z.number().int().positive();
8
+ const inventoryForecastShortageSchema = z.object({
9
+ skuId: uuidSchema,
10
+ sku: z.string().trim().min(1),
11
+ dueAt: datetimeSchema,
12
+ demandQuantity: positiveQuantitySchema,
13
+ availableOrExpectedQuantity: quantitySchema,
14
+ missingQuantity: positiveQuantitySchema,
15
+ }).strict();
16
+ const inventoryForecastResponseSchema = z.object({
17
+ contractVersion: z.literal(INVENTORY_CONTRACT_VERSION),
18
+ shortages: z.array(inventoryForecastShortageSchema),
19
+ }).strict();
20
+ const DAY_MS = 24 * 60 * 60 * 1000;
21
+ export function forecastSubscriptionInventoryShortages(input) {
22
+ const demand = input.demand
23
+ .filter((line) => !["skipped", "cancelled"].includes(line.status))
24
+ .sort((a, b) => Date.parse(a.dueAt) - Date.parse(b.dueAt));
25
+ const runningAvailable = input.stock.reduce((available, line) => {
26
+ available[line.skuId] = (available[line.skuId] ?? 0) + availableNow(line);
27
+ return available;
28
+ }, {});
29
+ const plannedSupply = input.supply
30
+ .filter((line) => line.status === "planned")
31
+ .sort((a, b) => Date.parse(a.expectedAt) - Date.parse(b.expectedAt));
32
+ const usedSupplyIndexes = new Set();
33
+ const shortages = demand.flatMap((line) => {
34
+ for (const [index, supply] of plannedSupply.entries()) {
35
+ if (usedSupplyIndexes.has(index))
36
+ continue;
37
+ if (supply.skuId !== line.skuId)
38
+ continue;
39
+ if (Date.parse(supply.expectedAt) > Date.parse(line.dueAt))
40
+ continue;
41
+ runningAvailable[line.skuId] = (runningAvailable[line.skuId] ?? 0) + supply.quantity;
42
+ usedSupplyIndexes.add(index);
43
+ }
44
+ const available = runningAvailable[line.skuId] ?? 0;
45
+ if (available >= line.quantity) {
46
+ runningAvailable[line.skuId] = available - line.quantity;
47
+ return [];
48
+ }
49
+ runningAvailable[line.skuId] = 0;
50
+ return [{
51
+ skuId: line.skuId,
52
+ sku: line.sku,
53
+ dueAt: line.dueAt,
54
+ demandQuantity: line.quantity,
55
+ availableOrExpectedQuantity: available,
56
+ missingQuantity: line.quantity - available,
57
+ }];
58
+ });
59
+ return inventoryForecastResponseSchema.parse({
60
+ contractVersion: INVENTORY_CONTRACT_VERSION,
61
+ shortages,
62
+ });
63
+ }
64
+ export function buildSubscriptionInventoryForecast(input, config) {
65
+ const inventorySubscriptionForecastResponseSchema = createInventorySubscriptionForecastResponseSchema(config.providerSchema);
66
+ const generatedAtMs = Date.parse(input.generatedAt);
67
+ const horizonAtMs = generatedAtMs + input.horizonDays * DAY_MS;
68
+ const protectionAtMs = generatedAtMs + input.protectionDays * DAY_MS;
69
+ const demand = input.demand
70
+ .filter((line) => !["skipped", "cancelled"].includes(line.status))
71
+ .filter((line) => Date.parse(line.dueAt) <= horizonAtMs);
72
+ const plannedSupply = input.supply
73
+ .filter((line) => line.status === "planned")
74
+ .filter((line) => Date.parse(line.expectedAt) <= horizonAtMs);
75
+ const providerBySku = new Map(input.providerCurrent.map((line) => [line.skuId, line]));
76
+ const skuIds = new Set([
77
+ ...input.providerCurrent.map((line) => line.skuId),
78
+ ...input.openHardReservations.map((line) => line.skuId),
79
+ ...input.stock.map((line) => line.skuId),
80
+ ...demand.map((line) => line.skuId),
81
+ ...plannedSupply.map((line) => line.skuId),
82
+ ]);
83
+ const skus = [...skuIds].map((skuId) => {
84
+ const provider = providerBySku.get(skuId) ?? null;
85
+ const stockLines = input.stock.filter((line) => line.skuId === skuId);
86
+ const demandLines = demand.filter((line) => line.skuId === skuId);
87
+ const supplyLines = plannedSupply.filter((line) => line.skuId === skuId);
88
+ const sku = provider?.sku ?? stockLines[0]?.sku ?? demandLines[0]?.sku ?? "unknown";
89
+ const stockStatus = provider === null
90
+ ? "missing"
91
+ : Date.parse(provider.staleAfter) <= generatedAtMs
92
+ ? "stale"
93
+ : "fresh";
94
+ const openHardReservations = sum(input.openHardReservations
95
+ .filter((line) => line.skuId === skuId)
96
+ .map((line) => line.quantity));
97
+ const safetyStock = sum(stockLines
98
+ .filter((line) => line.fulfillable && line.locationStatus === "active")
99
+ .map((line) => line.safetyStock));
100
+ const sellableNow = stockStatus === "fresh" && provider
101
+ ? Math.max(0, provider.forSaleQuantity - openHardReservations - safetyStock)
102
+ : 0;
103
+ const shortage = simulateSubscriptionCoverage({
104
+ generatedAtMs,
105
+ protectionAtMs,
106
+ sellableNow,
107
+ demand: demandLines,
108
+ supply: supplyLines,
109
+ });
110
+ return {
111
+ skuId,
112
+ sku,
113
+ providerCurrentForSale: provider?.forSaleQuantity ?? null,
114
+ providerStockLastSyncedAt: provider?.lastSyncedAt ?? null,
115
+ providerStockStaleAfter: provider?.staleAfter ?? null,
116
+ stockStatus,
117
+ openHardReservations,
118
+ safetyStock,
119
+ sellableNow,
120
+ activeSubscriptionDemand30: demandQuantityWithin(demandLines, generatedAtMs + 30 * DAY_MS),
121
+ activeSubscriptionDemand45: demandQuantityWithin(demandLines, generatedAtMs + 45 * DAY_MS),
122
+ activeSubscriptionDemand60: demandQuantityWithin(demandLines, generatedAtMs + 60 * DAY_MS),
123
+ plannedSupply: sum(supplyLines.map((line) => line.quantity)),
124
+ coverageDays: shortage.shortageDate
125
+ ? Math.max(0, Math.ceil((Date.parse(shortage.shortageDate) - generatedAtMs) / DAY_MS))
126
+ : null,
127
+ shortageDate: shortage.shortageDate,
128
+ horizonMissingQty: shortage.horizonMissingQty,
129
+ protectionMissingQty: shortage.protectionMissingQty,
130
+ missingQty: shortage.protectionMissingQty,
131
+ recommendedProductionQty: shortage.protectionMissingQty,
132
+ };
133
+ }).sort((a, b) => a.sku.localeCompare(b.sku));
134
+ return inventorySubscriptionForecastResponseSchema.parse({
135
+ contractVersion: INVENTORY_CONTRACT_VERSION,
136
+ generatedAt: input.generatedAt,
137
+ stockMasterProvider: config.stockMasterProvider,
138
+ horizonDays: input.horizonDays,
139
+ protectionDays: input.protectionDays,
140
+ skus,
141
+ totals: {
142
+ activeSubscriptionCount: input.activeSubscriptionCount,
143
+ excludedSubscriptionCount: input.excludedSubscriptionCount,
144
+ missingProviderStockSkuCount: skus.filter((line) => line.stockStatus === "missing").length,
145
+ staleProviderStockSkuCount: skus.filter((line) => line.stockStatus === "stale").length,
146
+ horizonShortageSkuCount: skus.filter((line) => line.shortageDate !== null).length,
147
+ protectionShortageSkuCount: skus.filter((line) => line.protectionMissingQty > 0).length,
148
+ shortageSkuCount: skus.filter((line) => line.shortageDate !== null).length,
149
+ recommendedProductionQty: sum(skus.map((line) => line.recommendedProductionQty)),
150
+ },
151
+ });
152
+ }
153
+ function simulateSubscriptionCoverage(input) {
154
+ let available = input.sellableNow;
155
+ let shortageDate = null;
156
+ let horizonMissingQty = 0;
157
+ let protectionMissingQty = 0;
158
+ const events = [
159
+ ...input.supply.map((line) => ({
160
+ type: "supply",
161
+ at: line.expectedAt,
162
+ quantity: line.quantity,
163
+ })),
164
+ ...input.demand.map((line) => ({
165
+ type: "demand",
166
+ at: line.dueAt,
167
+ quantity: line.quantity,
168
+ })),
169
+ ].sort((a, b) => {
170
+ const dateDelta = Date.parse(a.at) - Date.parse(b.at);
171
+ if (dateDelta !== 0)
172
+ return dateDelta;
173
+ return a.type === "supply" && b.type === "demand" ? -1 : 1;
174
+ });
175
+ for (const event of events) {
176
+ if (event.type === "supply") {
177
+ available += event.quantity;
178
+ continue;
179
+ }
180
+ if (available >= event.quantity) {
181
+ available -= event.quantity;
182
+ continue;
183
+ }
184
+ const missing = event.quantity - available;
185
+ available = 0;
186
+ shortageDate ??= event.at;
187
+ horizonMissingQty += missing;
188
+ if (Date.parse(event.at) <= input.protectionAtMs)
189
+ protectionMissingQty += missing;
190
+ }
191
+ return { shortageDate, horizonMissingQty, protectionMissingQty };
192
+ }
193
+ function demandQuantityWithin(lines, dueAtOrBeforeMs) {
194
+ return sum(lines
195
+ .filter((line) => Date.parse(line.dueAt) <= dueAtOrBeforeMs)
196
+ .map((line) => line.quantity));
197
+ }
198
+ function sum(values) {
199
+ return values.reduce((total, value) => total + value, 0);
200
+ }
@@ -0,0 +1,13 @@
1
+ export type { InventoryReadPort, InventoryMutationPort } from "./ports.js";
2
+ export { InventoryPersistenceError, InventoryConflictError } from "./ports.js";
3
+ export { adminInventoryStockRequestSchema, adminInventoryReservationsRequestSchema, adminInventoryStockAdjustmentRequestSchema, adminInventorySubscriptionForecastRequestSchema, inventoryStockListResponseSchema, inventoryReservationsListResponseSchema, createInventorySubscriptionForecastResponseSchema, } from "./schemas.js";
4
+ export { createAdminInventoryStockHandler, createAdminInventoryReservationsHandler, createAdminInventoryAtpCheckHandler, createAdminInventorySubscriptionForecastHandler, createAdminInventoryStockAdjustmentHandler } from "./inventoryHandlers.js";
5
+ export { createPostgresAdminInventoryPort } from "./adminInventory.js";
6
+ export type { NewPurchaseStockRow, NewPurchaseStockMode, NewPurchaseStockAvailabilityOptions } from "./contracts/newPurchaseStock.js";
7
+ export type { NewPurchaseStockReadPort } from "./newPurchaseStockAvailability.js";
8
+ export { createNewPurchaseStockAvailabilityPort } from "./newPurchaseStockAvailability.js";
9
+ export { MIN_CHECKOUT_RESERVATION_TTL_MINUTES, MAX_CHECKOUT_RESERVATION_TTL_MINUTES, DEFAULT_CHECKOUT_RESERVATION_TTL_MINUTES, reservationPolicyFor, normalizedTtlMinutes } from "./reservationPolicy.js";
10
+ export { createPostgresRenewalReservationPort, type AutomaticRenewalInventoryPort } from "./renewalReservation.js";
11
+ export { forecastSubscriptionInventoryShortages, buildSubscriptionInventoryForecast } from "./forecast.js";
12
+ export { calculateSubscriptionForecastSkus, calculateSubscriptionForecastTotals } from "./subscriptionForecastCalculation.js";
13
+ export { INVENTORY_MIGRATIONS } from "./sql.js";
@@ -0,0 +1,10 @@
1
+ export { InventoryPersistenceError, InventoryConflictError } from "./ports.js";
2
+ export { adminInventoryStockRequestSchema, adminInventoryReservationsRequestSchema, adminInventoryStockAdjustmentRequestSchema, adminInventorySubscriptionForecastRequestSchema, inventoryStockListResponseSchema, inventoryReservationsListResponseSchema, createInventorySubscriptionForecastResponseSchema, } from "./schemas.js";
3
+ export { createAdminInventoryStockHandler, createAdminInventoryReservationsHandler, createAdminInventoryAtpCheckHandler, createAdminInventorySubscriptionForecastHandler, createAdminInventoryStockAdjustmentHandler } from "./inventoryHandlers.js";
4
+ export { createPostgresAdminInventoryPort } from "./adminInventory.js";
5
+ export { createNewPurchaseStockAvailabilityPort } from "./newPurchaseStockAvailability.js";
6
+ export { MIN_CHECKOUT_RESERVATION_TTL_MINUTES, MAX_CHECKOUT_RESERVATION_TTL_MINUTES, DEFAULT_CHECKOUT_RESERVATION_TTL_MINUTES, reservationPolicyFor, normalizedTtlMinutes } from "./reservationPolicy.js";
7
+ export { createPostgresRenewalReservationPort } from "./renewalReservation.js";
8
+ export { forecastSubscriptionInventoryShortages, buildSubscriptionInventoryForecast } from "./forecast.js";
9
+ export { calculateSubscriptionForecastSkus, calculateSubscriptionForecastTotals } from "./subscriptionForecastCalculation.js";
10
+ export { INVENTORY_MIGRATIONS } from "./sql.js";
@@ -0,0 +1,53 @@
1
+ import type { IncomingMessage, ServerResponse } from "node:http";
2
+ import type { z } from "zod";
3
+ import { type InventoryMutationPort, type InventoryReadPort } from "./ports.js";
4
+ import type { InventorySubscriptionForecastResponse } from "./contracts/index.js";
5
+ interface HttpRequest extends IncomingMessage {
6
+ query: Record<string, string | string[] | undefined>;
7
+ cookies?: Record<string, string>;
8
+ body?: unknown;
9
+ }
10
+ interface HttpResponse extends ServerResponse {
11
+ status(code: number): this;
12
+ json(body: unknown): this;
13
+ send(body: string | Buffer | object): this;
14
+ redirect(url: string): this;
15
+ redirect(status: number, url: string): this;
16
+ }
17
+ interface ResponseBindings {
18
+ sendBffSuccess(res: HttpResponse, data: unknown): void;
19
+ sendBffError(res: HttpResponse, code: "UNAUTHORIZED" | "FORBIDDEN" | "BAD_REQUEST" | "INVALID_RESPONSE" | "UPSTREAM_UNAVAILABLE" | "CONFLICT", message: string, options?: {
20
+ details?: unknown;
21
+ }): void;
22
+ sendMethodNotAllowed(res: HttpResponse, methods: readonly string[]): void;
23
+ }
24
+ type AdminAuthResult = {
25
+ ok: false;
26
+ code: "UNAUTHORIZED" | "FORBIDDEN";
27
+ message: string;
28
+ } | {
29
+ ok: true;
30
+ userId: string;
31
+ };
32
+ interface BaseDeps extends ResponseBindings {
33
+ authorizeAdmin: (req: HttpRequest) => Promise<AdminAuthResult>;
34
+ }
35
+ export declare function createAdminInventoryStockHandler({ authorizeAdmin, sendBffError, sendBffSuccess, sendMethodNotAllowed, inventoryPort, }: BaseDeps & {
36
+ inventoryPort: Pick<InventoryReadPort, "listStock">;
37
+ }): (req: HttpRequest, res: HttpResponse) => Promise<void>;
38
+ export declare function createAdminInventoryReservationsHandler({ authorizeAdmin, sendBffError, sendBffSuccess, sendMethodNotAllowed, inventoryPort, }: BaseDeps & {
39
+ inventoryPort: Pick<InventoryReadPort, "listReservations">;
40
+ }): (req: HttpRequest, res: HttpResponse) => Promise<void>;
41
+ export declare function createAdminInventoryAtpCheckHandler({ authorizeAdmin, sendBffError, sendBffSuccess, sendMethodNotAllowed, inventoryPort, configuredRegion, }: BaseDeps & {
42
+ inventoryPort: Pick<InventoryReadPort, "checkAtp">;
43
+ configuredRegion?: string;
44
+ }): (req: HttpRequest, res: HttpResponse) => Promise<void>;
45
+ export declare function createAdminInventorySubscriptionForecastHandler({ inventorySubscriptionForecastResponseSchema, authorizeAdmin, sendBffError, sendBffSuccess, sendMethodNotAllowed, inventoryPort, }: BaseDeps & {
46
+ inventoryPort: Pick<InventoryReadPort, "forecastSubscriptions">;
47
+ inventorySubscriptionForecastResponseSchema: z.ZodType<InventorySubscriptionForecastResponse>;
48
+ }): (req: HttpRequest, res: HttpResponse) => Promise<void>;
49
+ export declare function createAdminInventoryStockAdjustmentHandler({ authorizeAdmin, sendBffError, sendBffSuccess, sendMethodNotAllowed, inventoryPort, mutationsEnabled, }: BaseDeps & {
50
+ inventoryPort: Pick<InventoryMutationPort, "adjustStock">;
51
+ mutationsEnabled: () => boolean;
52
+ }): (req: HttpRequest, res: HttpResponse) => Promise<void>;
53
+ export {};
@@ -0,0 +1,151 @@
1
+ import { inventoryAtpRequestSchema, inventoryAtpResultSchema } from "@openlup/core/inventory";
2
+ import { adminInventoryReservationsRequestSchema, adminInventoryStockAdjustmentRequestSchema, adminInventoryStockRequestSchema, adminInventorySubscriptionForecastRequestSchema, inventoryReservationsListResponseSchema, inventoryStockListResponseSchema, } from "./schemas.js";
3
+ import { InventoryConflictError } from "./ports.js";
4
+ export function createAdminInventoryStockHandler({ authorizeAdmin, sendBffError, sendBffSuccess, sendMethodNotAllowed, inventoryPort, }) {
5
+ return async function handler(req, res) {
6
+ if (req.method !== "GET")
7
+ return sendMethodNotAllowed(res, ["GET"]);
8
+ if (!(await authorize(req, res, authorizeAdmin, sendBffError)))
9
+ return;
10
+ const request = adminInventoryStockRequestSchema.safeParse(req.query);
11
+ if (!request.success) {
12
+ sendBffError(res, "BAD_REQUEST", "Invalid admin inventory stock request", {
13
+ details: request.error.flatten(),
14
+ });
15
+ return;
16
+ }
17
+ try {
18
+ const result = await inventoryPort.listStock(request.data);
19
+ const response = inventoryStockListResponseSchema.safeParse(result);
20
+ if (!response.success)
21
+ return sendBffError(res, "INVALID_RESPONSE", "Inventory stock response invalid");
22
+ sendBffSuccess(res, response.data);
23
+ }
24
+ catch {
25
+ sendBffError(res, "UPSTREAM_UNAVAILABLE", "Inventory stock read failed");
26
+ }
27
+ };
28
+ }
29
+ export function createAdminInventoryReservationsHandler({ authorizeAdmin, sendBffError, sendBffSuccess, sendMethodNotAllowed, inventoryPort, }) {
30
+ return async function handler(req, res) {
31
+ if (req.method !== "GET")
32
+ return sendMethodNotAllowed(res, ["GET"]);
33
+ if (!(await authorize(req, res, authorizeAdmin, sendBffError)))
34
+ return;
35
+ const request = adminInventoryReservationsRequestSchema.safeParse(req.query);
36
+ if (!request.success) {
37
+ sendBffError(res, "BAD_REQUEST", "Invalid admin inventory reservations request", {
38
+ details: request.error.flatten(),
39
+ });
40
+ return;
41
+ }
42
+ try {
43
+ const result = await inventoryPort.listReservations(request.data);
44
+ const response = inventoryReservationsListResponseSchema.safeParse(result);
45
+ if (!response.success)
46
+ return sendBffError(res, "INVALID_RESPONSE", "Inventory reservations response invalid");
47
+ sendBffSuccess(res, response.data);
48
+ }
49
+ catch {
50
+ sendBffError(res, "UPSTREAM_UNAVAILABLE", "Inventory reservations read failed");
51
+ }
52
+ };
53
+ }
54
+ export function createAdminInventoryAtpCheckHandler({ authorizeAdmin, sendBffError, sendBffSuccess, sendMethodNotAllowed, inventoryPort, configuredRegion, }) {
55
+ return async function handler(req, res) {
56
+ if (req.method !== "POST")
57
+ return sendMethodNotAllowed(res, ["POST"]);
58
+ if (!(await authorize(req, res, authorizeAdmin, sendBffError)))
59
+ return;
60
+ const request = inventoryAtpRequestSchema.safeParse(req.body ?? {});
61
+ if (!request.success) {
62
+ sendBffError(res, "BAD_REQUEST", "Invalid admin inventory ATP request", {
63
+ details: request.error.flatten(),
64
+ });
65
+ return;
66
+ }
67
+ try {
68
+ const result = await inventoryPort.checkAtp({
69
+ ...request.data,
70
+ region: request.data.region ?? configuredRegion,
71
+ });
72
+ const response = inventoryAtpResultSchema.safeParse(result);
73
+ if (!response.success)
74
+ return sendBffError(res, "INVALID_RESPONSE", "Inventory ATP response invalid");
75
+ sendBffSuccess(res, response.data);
76
+ }
77
+ catch {
78
+ sendBffError(res, "UPSTREAM_UNAVAILABLE", "Inventory ATP check failed");
79
+ }
80
+ };
81
+ }
82
+ export function createAdminInventorySubscriptionForecastHandler({ inventorySubscriptionForecastResponseSchema, authorizeAdmin, sendBffError, sendBffSuccess, sendMethodNotAllowed, inventoryPort, }) {
83
+ return async function handler(req, res) {
84
+ if (req.method !== "GET")
85
+ return sendMethodNotAllowed(res, ["GET"]);
86
+ if (!(await authorize(req, res, authorizeAdmin, sendBffError)))
87
+ return;
88
+ const request = adminInventorySubscriptionForecastRequestSchema.safeParse(req.query);
89
+ if (!request.success) {
90
+ sendBffError(res, "BAD_REQUEST", "Invalid admin inventory subscription forecast request", {
91
+ details: request.error.flatten(),
92
+ });
93
+ return;
94
+ }
95
+ try {
96
+ const result = await inventoryPort.forecastSubscriptions(request.data);
97
+ const response = inventorySubscriptionForecastResponseSchema.safeParse(result);
98
+ if (!response.success) {
99
+ return sendBffError(res, "INVALID_RESPONSE", "Inventory subscription forecast response invalid");
100
+ }
101
+ sendBffSuccess(res, response.data);
102
+ }
103
+ catch {
104
+ sendBffError(res, "UPSTREAM_UNAVAILABLE", "Inventory subscription forecast read failed");
105
+ }
106
+ };
107
+ }
108
+ export function createAdminInventoryStockAdjustmentHandler({ authorizeAdmin, sendBffError, sendBffSuccess, sendMethodNotAllowed, inventoryPort, mutationsEnabled, }) {
109
+ return async function handler(req, res) {
110
+ if (req.method !== "POST")
111
+ return sendMethodNotAllowed(res, ["POST"]);
112
+ const auth = await authorize(req, res, authorizeAdmin, sendBffError);
113
+ if (!auth)
114
+ return;
115
+ if (!mutationsEnabled()) {
116
+ sendBffError(res, "FORBIDDEN", "Inventory mutations are not enabled");
117
+ return;
118
+ }
119
+ const request = adminInventoryStockAdjustmentRequestSchema.safeParse(req.body ?? {});
120
+ if (!request.success) {
121
+ sendBffError(res, "BAD_REQUEST", "Invalid admin inventory stock adjustment request", {
122
+ details: request.error.flatten(),
123
+ });
124
+ return;
125
+ }
126
+ try {
127
+ sendBffSuccess(res, await inventoryPort.adjustStock({ ...request.data, actorUserId: auth.userId }));
128
+ }
129
+ catch (error) {
130
+ if (error instanceof InventoryConflictError) {
131
+ sendBffError(res, "CONFLICT", error.message, { details: error.details });
132
+ return;
133
+ }
134
+ sendBffError(res, "UPSTREAM_UNAVAILABLE", "Inventory stock adjustment failed");
135
+ }
136
+ };
137
+ }
138
+ async function authorize(req, res, authorizeAdmin, sendBffError) {
139
+ try {
140
+ const authorization = await authorizeAdmin(req);
141
+ if (authorization.ok === false) {
142
+ sendBffError(res, authorization.code, authorization.message);
143
+ return null;
144
+ }
145
+ return { userId: authorization.userId };
146
+ }
147
+ catch {
148
+ sendBffError(res, "UPSTREAM_UNAVAILABLE", "Admin authorization failed");
149
+ return null;
150
+ }
151
+ }
@@ -0,0 +1,47 @@
1
+ import type { NewPurchaseStockRow, NewPurchaseStockAvailabilityOptions } from "./contracts/newPurchaseStock.js";
2
+ type BundleStockStatus = "available" | "low_stock" | "out_of_stock" | "unknown";
3
+ interface BundleStockRequestItem {
4
+ sku: string;
5
+ productSlug: string;
6
+ variantId: string;
7
+ requestedQuantity: number;
8
+ checkoutMode: "one_time" | "subscription";
9
+ }
10
+ interface BundleStockAvailability {
11
+ sku: string;
12
+ productSlug: string;
13
+ variantId: string;
14
+ status: BundleStockStatus;
15
+ visibleInConfigurator: boolean;
16
+ sellableNow: number | null;
17
+ reasonCode: string;
18
+ source: string;
19
+ }
20
+ interface BundleStockPort {
21
+ getAvailability(input: {
22
+ items: readonly BundleStockRequestItem[];
23
+ }): Promise<BundleStockAvailability[]>;
24
+ }
25
+ /** Normalized host read. Transport, missing-function recognition and fallback stay with the host. */
26
+ export interface NewPurchaseStockReadPort {
27
+ read(input: {
28
+ skus: readonly string[];
29
+ horizonDays: number;
30
+ excludeOrderId: string | null;
31
+ }): Promise<Map<string, NewPurchaseStockRow>>;
32
+ }
33
+ interface StockBindings {
34
+ readPort: NewPurchaseStockReadPort;
35
+ functionMissingFallback: (() => BundleStockPort) | null;
36
+ functionMissingError: string;
37
+ defaultLowStockThreshold: number;
38
+ defaultHorizonDays: number;
39
+ deriveOfferAvailability(input: BundleStockRequestItem & {
40
+ sellableNow: number | null;
41
+ lowStockThreshold: number;
42
+ source: string;
43
+ }): BundleStockAvailability;
44
+ observe: Pick<Console, "warn">;
45
+ }
46
+ export declare function createNewPurchaseStockAvailabilityPort({ readPort, functionMissingFallback, functionMissingError, defaultLowStockThreshold, defaultHorizonDays, deriveOfferAvailability, observe }: StockBindings, options: NewPurchaseStockAvailabilityOptions): BundleStockPort;
47
+ export {};
@@ -0,0 +1,75 @@
1
+ export function createNewPurchaseStockAvailabilityPort({ readPort, functionMissingFallback, functionMissingError, defaultLowStockThreshold, defaultHorizonDays, deriveOfferAvailability, observe }, options) {
2
+ const lowStockThreshold = options.lowStockThreshold ?? defaultLowStockThreshold;
3
+ const horizonDays = options.horizonDays ?? defaultHorizonDays;
4
+ return {
5
+ async getAvailability({ items }) {
6
+ if (items.length === 0)
7
+ return [];
8
+ let rows;
9
+ try {
10
+ rows = await readPort.read({
11
+ skus: items.map((item) => item.sku),
12
+ horizonDays,
13
+ excludeOrderId: null,
14
+ });
15
+ }
16
+ catch (error) {
17
+ if (functionMissingFallback
18
+ && error instanceof Error
19
+ && error.message === functionMissingError) {
20
+ observe.warn("[new-purchase-stock] function missing; falling back to the core availability read");
21
+ return functionMissingFallback().getAvailability({ items });
22
+ }
23
+ observe.warn("[new-purchase-stock] availability read failed", {
24
+ reason: error instanceof Error ? error.message : String(error),
25
+ });
26
+ return items.map((item) => unknownAvailability(item, "inventory_read_failed"));
27
+ }
28
+ // Same branch rule as the core adapter: once any requested SKU is
29
+ // provider-backed, every SKU must be, and a SKU without a provider row is
30
+ // not sellable rather than silently falling back to local stock.
31
+ const providerBacked = [...rows.values()].some((row) => row.source === "provider");
32
+ return items.map((item) => {
33
+ const row = rows.get(item.sku);
34
+ if (providerBacked) {
35
+ if (row?.source !== "provider")
36
+ return unavailable(item, "provider_stock_missing");
37
+ if (row.stale)
38
+ return unavailable(item, "provider_stock_stale");
39
+ return deriveOfferAvailability({
40
+ ...item,
41
+ sellableNow: sellableFor(row, options.mode),
42
+ lowStockThreshold,
43
+ source: "inventory_provider",
44
+ });
45
+ }
46
+ return deriveOfferAvailability({
47
+ ...item,
48
+ sellableNow: row?.source === "local" ? sellableFor(row, options.mode) : null,
49
+ lowStockThreshold,
50
+ source: "inventory",
51
+ });
52
+ });
53
+ },
54
+ };
55
+ }
56
+ function sellableFor(row, mode) {
57
+ const value = mode === "new_purchase" ? row.availableForNewPurchases : row.available;
58
+ return value == null ? null : Math.max(0, value);
59
+ }
60
+ /** The core adapter's provider-missing / provider-stale answer shape. */
61
+ function unavailable(item, reasonCode) {
62
+ const { sku, productSlug, variantId } = item;
63
+ return {
64
+ sku, productSlug, variantId, status: "out_of_stock", visibleInConfigurator: false, sellableNow: 0,
65
+ reasonCode, source: "inventory_provider",
66
+ };
67
+ }
68
+ /** The core adapter's read-failure answer shape. */
69
+ function unknownAvailability(item, reasonCode) {
70
+ const { sku, productSlug, variantId } = item;
71
+ return {
72
+ sku, productSlug, variantId, status: "unknown", visibleInConfigurator: true, sellableNow: null,
73
+ reasonCode, source: "inventory",
74
+ };
75
+ }
@@ -0,0 +1,21 @@
1
+ import type { InventoryAtpRequest, InventoryAtpResult } from "@openlup/core/inventory";
2
+ import type { AdminInventoryReservationsRequest, AdminInventoryStockAdjustmentRequest, AdminInventoryStockRequest, AdminInventorySubscriptionForecastRequest, InventoryReservationsListResponse, InventoryStockAdjustmentResponse, InventoryStockListResponse, InventorySubscriptionForecastResponse } from "./contracts/index.js";
3
+ export interface InventoryReadPort {
4
+ listStock(request: AdminInventoryStockRequest): Promise<InventoryStockListResponse>;
5
+ listReservations(request: AdminInventoryReservationsRequest): Promise<InventoryReservationsListResponse>;
6
+ checkAtp(request: InventoryAtpRequest): Promise<InventoryAtpResult>;
7
+ forecastSubscriptions(request: AdminInventorySubscriptionForecastRequest): Promise<InventorySubscriptionForecastResponse>;
8
+ }
9
+ export interface InventoryMutationPort {
10
+ adjustStock(request: AdminInventoryStockAdjustmentRequest & {
11
+ actorUserId: string;
12
+ }): Promise<InventoryStockAdjustmentResponse>;
13
+ }
14
+ export declare class InventoryPersistenceError extends Error {
15
+ readonly details: Record<string, unknown>;
16
+ constructor(message?: string, details?: Record<string, unknown>);
17
+ }
18
+ export declare class InventoryConflictError extends Error {
19
+ readonly details: Record<string, unknown>;
20
+ constructor(message?: string, details?: Record<string, unknown>);
21
+ }
@@ -0,0 +1,16 @@
1
+ export class InventoryPersistenceError extends Error {
2
+ details;
3
+ constructor(message = "Inventory persistence failed", details = {}) {
4
+ super(message);
5
+ this.name = "InventoryPersistenceError";
6
+ this.details = details;
7
+ }
8
+ }
9
+ export class InventoryConflictError extends Error {
10
+ details;
11
+ constructor(message = "Inventory conflict", details = {}) {
12
+ super(message);
13
+ this.name = "InventoryConflictError";
14
+ this.details = details;
15
+ }
16
+ }
@@ -0,0 +1,27 @@
1
+ import type { AutomaticRenewalReservationResult } from "./contracts/reservation.js";
2
+ interface PgQueryExecutor {
3
+ query(text: string, values?: unknown[]): Promise<{
4
+ rows: Record<string, unknown>[];
5
+ }>;
6
+ }
7
+ export interface AutomaticRenewalInventoryPort {
8
+ reserve(input: {
9
+ operationId: string;
10
+ claimToken: string;
11
+ holdSeconds?: number;
12
+ now: string;
13
+ }): Promise<AutomaticRenewalReservationResult>;
14
+ releaseReservation(input: {
15
+ operationId: string;
16
+ claimToken: string;
17
+ reason: string;
18
+ now: string;
19
+ }): Promise<Record<string, unknown>>;
20
+ expireReservations(input: {
21
+ now: string;
22
+ limit?: number;
23
+ }): Promise<number>;
24
+ }
25
+ /** ATP/reservation adapter; it can reserve only through the fenced public renewal function. */
26
+ export declare function createPostgresRenewalReservationPort(executor: PgQueryExecutor): AutomaticRenewalInventoryPort;
27
+ export {};