@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,89 @@
1
+ import { z } from "./validation.js";
2
+ import { CATALOG_DRAFT_MAX_PAGE, canonicalCatalogDraftJson } from "./contracts/draft.js";
3
+ export { CATALOG_DRAFT_MAX_BYTES, CATALOG_DRAFT_MAX_PAGE, canonicalCatalogDraftJson } from "./contracts/draft.js";
4
+ import { catalogDocumentRevisionRefSchema } from "./foundationSchemas.js";
5
+ import { catalogDimensionKeySchema, catalogNamespacedKeySchema, catalogOptionValueSchema, catalogProductTypeRefSchema, catalogQuantitySchema, } from "./productTypeSchemas.js";
6
+ const id = z.guid().refine((value) => value === value.toLowerCase(), "UUID must be lowercase");
7
+ const reference = z.string().min(1).max(240).refine((value) => value.trim() === value);
8
+ const code = z.string().min(1).max(160).regex(/^[A-Za-z0-9._:-]+$/u);
9
+ const revision = z.number().int().min(0).max(2_147_483_646);
10
+ const persistedRevision = z.number().int().positive().max(2_147_483_647);
11
+ const commandKey = reference;
12
+ const jsonContent = z.unknown().refine((value) => value !== undefined, "content must be JSON");
13
+ export const catalogDraftPayloadSchema = z.object({
14
+ schemaVersion: z.literal(1),
15
+ product: z.object({
16
+ id, type: catalogProductTypeRefSchema, slug: code.optional(), primarySkuId: id.optional(),
17
+ dimensions: z.array(catalogDimensionKeySchema).max(16),
18
+ sharedContent: jsonContent.optional(), documentRevision: catalogDocumentRevisionRefSchema.optional(),
19
+ }).strict(),
20
+ skus: z.array(z.object({
21
+ id, productId: id, code: code.optional(),
22
+ options: z.record(catalogDimensionKeySchema, catalogOptionValueSchema),
23
+ netContent: catalogQuantitySchema.optional(),
24
+ identifiers: z.array(z.object({
25
+ scheme: catalogNamespacedKeySchema, issuer: reference, value: z.string().min(1).max(128),
26
+ packagingLevel: z.enum(["unit", "case"]), quantity: z.number().int().min(1).max(2_147_483_647).optional(),
27
+ }).strict()).max(32).optional(),
28
+ assetRefs: z.array(reference).max(32).optional(), grossMass: catalogQuantitySchema.optional(),
29
+ priceRef: reference.optional(), logisticsRef: reference.optional(),
30
+ }).strict()).max(10_000),
31
+ }).strict().superRefine((payload, context) => {
32
+ try {
33
+ canonicalCatalogDraftJson(payload);
34
+ }
35
+ catch {
36
+ context.addIssue({ code: "custom", message: "payload must be bounded safe JSON" });
37
+ }
38
+ if (payload.product.documentRevision && payload.product.documentRevision.productId !== payload.product.id) {
39
+ context.addIssue({ code: "custom", path: ["product", "documentRevision", "productId"], message: "document must belong to product" });
40
+ }
41
+ if (payload.product.primarySkuId && !payload.skus.some((sku) => sku.id === payload.product.primarySkuId)) {
42
+ context.addIssue({ code: "custom", path: ["product", "primarySkuId"], message: "primary must belong to product" });
43
+ }
44
+ payload.skus.forEach((sku, index) => {
45
+ if (sku.productId !== payload.product.id)
46
+ context.addIssue({ code: "custom", path: ["skus", index, "productId"], message: "SKU must belong to product" });
47
+ });
48
+ });
49
+ export const catalogDraftCommandSchema = z.object({
50
+ schemaVersion: z.literal(1), action: z.enum(["create", "revise", "abandon"]),
51
+ draftId: id, commandKey, expectedRevision: revision, payload: catalogDraftPayloadSchema.optional(),
52
+ }).strict().superRefine((command, context) => {
53
+ if ((command.action === "abandon") === (command.payload !== undefined)) {
54
+ context.addIssue({ code: "custom", path: ["payload"], message: "payload is required only for create and revise" });
55
+ }
56
+ if ((command.action === "create") !== (command.expectedRevision === 0)) {
57
+ context.addIssue({ code: "custom", path: ["expectedRevision"], message: "create starts at revision zero; other commands require a persisted revision" });
58
+ }
59
+ });
60
+ export const catalogDraftGetQuerySchema = z.object({
61
+ draftId: id, revision: persistedRevision.optional(), commandKey: commandKey.optional(),
62
+ }).strict().refine((query) => query.revision === undefined || query.commandKey === undefined, "selectors are mutually exclusive");
63
+ export const catalogDraftListQuerySchema = z.object({
64
+ afterDraftId: id.optional(), limit: z.number().int().min(1).max(CATALOG_DRAFT_MAX_PAGE),
65
+ }).strict();
66
+ export const catalogDraftSummarySchema = z.object({
67
+ draftId: id, productId: id, revision: persistedRevision, status: z.enum(["open", "abandoned"]),
68
+ commandKey, fingerprint: z.string().regex(/^[a-f0-9]{64}$/u), actorId: reference,
69
+ createdAt: z.string().datetime({ offset: true }),
70
+ }).strict();
71
+ export const catalogDraftRecordSchema = catalogDraftSummarySchema.extend({ payload: catalogDraftPayloadSchema }).strict()
72
+ .refine((record) => record.productId === record.payload.product.id, "record product must own payload");
73
+ export const catalogDraftPageSchema = z.object({
74
+ items: z.array(catalogDraftSummarySchema).max(CATALOG_DRAFT_MAX_PAGE), nextCursor: id.nullable(),
75
+ }).strict().superRefine((page, context) => {
76
+ const ids = page.items.map((item) => item.draftId);
77
+ if (ids.some((value, index) => index > 0 && value <= ids[index - 1])
78
+ || (page.nextCursor !== null && page.nextCursor !== ids[ids.length - 1])) {
79
+ context.addIssue({ code: "custom", message: "page must have ordered unique heads and a matching cursor" });
80
+ }
81
+ });
82
+ export const catalogDraftRefusalSchema = z.object({
83
+ outcome: z.enum(["conflict", "validation_issue", "unauthorized", "dependency_unavailable"]),
84
+ reason: z.string().min(1).max(160).regex(/^[a-z][a-z0-9_]*$/u), currentRevision: z.number().int().min(0).max(2_147_483_647).optional(),
85
+ }).strict();
86
+ export const catalogDraftApplyResultSchema = z.union([
87
+ z.object({ outcome: z.enum(["committed", "replayed"]), record: catalogDraftRecordSchema }).strict(),
88
+ catalogDraftRefusalSchema,
89
+ ]);
@@ -0,0 +1,21 @@
1
+ import type { CatalogDraftPayload } from "./draftSchemas.js";
2
+ import { type CatalogDraftIssue, type CatalogProductTypeRegistry } from "./productTypeSchemas.js";
3
+ export interface CatalogDraftReadiness {
4
+ publication: {
5
+ status: "incomplete" | "not_assessed";
6
+ issues: CatalogDraftIssue[];
7
+ };
8
+ commercial: {
9
+ status: "inactive";
10
+ issues: CatalogDraftIssue[];
11
+ };
12
+ }
13
+ export type CatalogDraftValidation = {
14
+ valid: false;
15
+ issues: CatalogDraftIssue[];
16
+ } | {
17
+ valid: true;
18
+ readiness: CatalogDraftReadiness;
19
+ };
20
+ /** Supplied facts must be true; absent publish-time facts remain draft readiness issues. */
21
+ export declare function validateCatalogDraft(payload: CatalogDraftPayload, registry: CatalogProductTypeRegistry): CatalogDraftValidation;
@@ -0,0 +1,125 @@
1
+ import { isValidGtin } from "./foundationSchemas.js";
2
+ import { canonicalCatalogOption, validateCatalogQuantity, } from "./productTypeSchemas.js";
3
+ /** Supplied facts must be true; absent publish-time facts remain draft readiness issues. */
4
+ export function validateCatalogDraft(payload, registry) {
5
+ const issues = [];
6
+ const publication = [];
7
+ const commercial = [];
8
+ const add = (path, code) => issues.push({ path, code });
9
+ const missing = (path, code) => publication.push({ path, code });
10
+ const { product, skus } = payload;
11
+ const definition = registry.resolve(product.type);
12
+ if (!definition)
13
+ return { valid: false, issues: [{ path: "product.type", code: "type_not_installed" }] };
14
+ const dimensions = new Map(definition.dimensions.map((dimension) => [dimension.key, dimension]));
15
+ const netContentKey = definition.dimensions.find((dimension) => dimension.kind === "quantity" && dimension.role === "net_content")?.key;
16
+ if (new Set(product.dimensions).size !== product.dimensions.length)
17
+ add("product.dimensions", "duplicate_dimension");
18
+ product.dimensions.forEach((key) => { if (!dimensions.has(key))
19
+ add(`product.dimensions.${key}`, "dimension_not_installed"); });
20
+ if (product.sharedContent !== undefined) {
21
+ issues.push(...definition.validateContent(product.sharedContent).map((issue) => ({ ...issue, path: `product.sharedContent${issue.path ? `.${issue.path}` : ""}` })));
22
+ }
23
+ else if (!product.documentRevision)
24
+ missing("product.sharedContent", "content_missing");
25
+ if (product.documentRevision && product.documentRevision.productId !== product.id)
26
+ add("product.documentRevision.productId", "foreign_product_reference");
27
+ if (product.primarySkuId && !skus.some((sku) => sku.id === product.primarySkuId))
28
+ add("product.primarySkuId", "primary_sku_not_in_product");
29
+ if (!product.primarySkuId)
30
+ missing("product.primarySkuId", "primary_sku_missing");
31
+ if (!product.slug)
32
+ missing("product.slug", "slug_missing");
33
+ if (!skus.length)
34
+ missing("skus", "sku_missing");
35
+ const skuIds = new Set();
36
+ const skuCodes = new Set();
37
+ const combinations = new Set();
38
+ const identifiers = new Set();
39
+ skus.forEach((sku, index) => {
40
+ const path = `skus.${index}`;
41
+ if (sku.productId !== product.id)
42
+ add(`${path}.productId`, "foreign_product_reference");
43
+ if (skuIds.has(sku.id))
44
+ add(`${path}.id`, "duplicate_sku_id");
45
+ skuIds.add(sku.id);
46
+ if (sku.code) {
47
+ if (skuCodes.has(sku.code))
48
+ add(`${path}.code`, "duplicate_sku_code");
49
+ skuCodes.add(sku.code);
50
+ }
51
+ else
52
+ missing(`${path}.code`, "sku_code_missing");
53
+ const optionKeys = Object.keys(sku.options);
54
+ for (const key of optionKeys) {
55
+ const option = sku.options[key];
56
+ const dimension = dimensions.get(key);
57
+ if (!product.dimensions.includes(key) || !dimension) {
58
+ add(`${path}.options.${key}`, "dimension_not_declared");
59
+ continue;
60
+ }
61
+ if (dimension.kind !== option.kind) {
62
+ add(`${path}.options.${key}`, "option_type_invalid");
63
+ continue;
64
+ }
65
+ if (dimension.kind === "choice" && option.kind === "choice" && !dimension.values.includes(option.value))
66
+ add(`${path}.options.${key}`, "option_value_invalid");
67
+ if (dimension.kind === "quantity" && option.kind === "quantity"
68
+ && (option.value.dimension !== dimension.dimension || !dimension.units.includes(option.value.unit)
69
+ || !validateCatalogQuantity(option.value, definition)))
70
+ add(`${path}.options.${key}`, "option_quantity_invalid");
71
+ }
72
+ const absent = product.dimensions.filter((key) => !Object.prototype.hasOwnProperty.call(sku.options, key));
73
+ absent.forEach((key) => missing(`${path}.options.${key}`, "option_missing"));
74
+ if (!absent.length && optionKeys.length === product.dimensions.length) {
75
+ const combination = JSON.stringify([...product.dimensions].sort().map((key) => [key, canonicalCatalogOption(sku.options[key])]));
76
+ if (combinations.has(combination))
77
+ add(`${path}.options`, "duplicate_option_combination");
78
+ combinations.add(combination);
79
+ }
80
+ if (sku.netContent) {
81
+ if (!validateCatalogQuantity(sku.netContent, definition) || !definition.netContentUnits.includes(sku.netContent.unit))
82
+ add(`${path}.netContent`, "net_content_invalid");
83
+ }
84
+ else
85
+ missing(`${path}.netContent`, "net_content_missing");
86
+ const netContentOption = netContentKey === undefined ? undefined : sku.options[netContentKey];
87
+ if (netContentOption?.kind === "quantity" && sku.netContent
88
+ && canonicalCatalogOption(netContentOption) !== canonicalCatalogOption({ kind: "quantity", value: sku.netContent }))
89
+ add(`${path}.options.${netContentKey}`, "net_content_option_mismatch");
90
+ if (sku.grossMass && (sku.grossMass.dimension !== "mass" || !validateCatalogQuantity(sku.grossMass, definition)))
91
+ add(`${path}.grossMass`, "gross_mass_invalid");
92
+ (sku.identifiers ?? []).forEach((identifier, identifierIndex) => {
93
+ const at = `${path}.identifiers.${identifierIndex}`;
94
+ // One GTIN is one identity in any 8-, 12-, 13- or 14-digit spelling, whatever its issuer text.
95
+ const gtin = identifier.scheme === "gs1:gtin" && isValidGtin(identifier.value) ? identifier.value.padStart(14, "0") : null;
96
+ const identity = JSON.stringify(gtin === null ? [identifier.scheme, identifier.issuer, identifier.value] : [identifier.scheme, gtin]);
97
+ if (identifiers.has(identity))
98
+ add(at, "duplicate_trade_identifier");
99
+ identifiers.add(identity);
100
+ if (identifier.scheme === "gs1:gtin" && gtin === null)
101
+ add(at, "trade_identifier_invalid");
102
+ if (identifier.scheme !== "gs1:gtin" && identifier.scheme.startsWith("gs1:"))
103
+ add(at, "trade_identifier_scheme_unsupported");
104
+ // Checked here, not in the wire schema, so a stored revision without a quantity stays readable.
105
+ if (identifier.packagingLevel === "case" ? (identifier.quantity ?? 0) < 2 : (identifier.quantity ?? 1) !== 1)
106
+ add(`${at}.quantity`, "trade_identifier_quantity_invalid");
107
+ });
108
+ if (!sku.identifiers?.length)
109
+ commercial.push({ path: `${path}.identifiers`, code: "channel_identity_not_assessed" });
110
+ if (!sku.identifiers?.some((identifier) => identifier.scheme === "gs1:gtin" && identifier.packagingLevel === "unit"))
111
+ commercial.push({ path: `${path}.identifiers`, code: "unit_trade_identifier_missing" });
112
+ if (!sku.priceRef)
113
+ commercial.push({ path: `${path}.priceRef`, code: "price_reference_missing" });
114
+ if (!sku.logisticsRef)
115
+ commercial.push({ path: `${path}.logisticsRef`, code: "logistics_reference_missing" });
116
+ });
117
+ if (issues.length)
118
+ return { valid: false, issues };
119
+ // Opaque references are not current pricing, stock, logistics or publication proof.
120
+ commercial.push({ path: "skus", code: "commercial_activation_not_assessed" });
121
+ return { valid: true, readiness: {
122
+ publication: { status: publication.length ? "incomplete" : "not_assessed", issues: publication },
123
+ commercial: { status: "inactive", issues: commercial },
124
+ } };
125
+ }
@@ -0,0 +1,8 @@
1
+ export declare const COMPONENT_SQL: string;
2
+ export declare const FEED_COMPONENT_SQL: string;
3
+ export declare const PRICE_SQL = "\n SELECT p.mode, p.price_list_id, p.target_price_minor, list.currency, p.amount_kind, p.active, p.valid_from, p.valid_to\n FROM public.catalog_bundle_prices p JOIN public.price_lists list ON list.id = p.price_list_id\n WHERE p.bundle_id = $1::uuid ORDER BY p.valid_from DESC";
4
+ export declare const OWN_LIST_SQL = "\n SELECT list.id, list.currency, list.region_code, p.mode\n FROM public.catalog_bundle_prices p JOIN public.price_lists list ON list.id = p.price_list_id\n WHERE p.bundle_id = $1::uuid AND p.active AND p.amount_kind = 'gross'\n AND (p.mode = $2::text OR p.mode = 'any') AND list.status = 'active'\n AND p.valid_from <= $3::timestamptz AND (p.valid_to IS NULL OR p.valid_to > $3::timestamptz)\n AND list.valid_from <= $3::timestamptz AND (list.valid_to IS NULL OR list.valid_to > $3::timestamptz)\n ORDER BY p.valid_from DESC";
5
+ export declare const CURRENCY_LIST_SQL = "\n SELECT id, currency, region_code FROM public.price_lists\n WHERE currency = $1::text AND status = 'active' AND ($2::text IS NULL OR region_code = $2::text)\n AND valid_from <= $3::timestamptz AND (valid_to IS NULL OR valid_to > $3::timestamptz)";
6
+ export declare const FEED_SQL = "\n SELECT b.id, b.code, b.title, b.fulfillment_mode, p.mode, p.target_price_minor, p.price_list_id, list.currency, list.region_code\n FROM public.catalog_bundles b\n JOIN public.catalog_bundle_prices p ON p.bundle_id = b.id AND p.active\n JOIN public.price_lists list ON list.id = p.price_list_id\n WHERE b.status = 'active' AND p.amount_kind = 'gross' AND p.target_price_minor > 0\n AND list.status = 'active' AND ($1::text IS NULL OR list.currency = $1::text)\n AND ($2::text IS NULL OR list.region_code = $2::text) AND (p.mode = $4::text OR p.mode = 'any')\n AND p.valid_from <= $3::timestamptz AND (p.valid_to IS NULL OR p.valid_to > $3::timestamptz)\n AND list.valid_from <= $3::timestamptz AND (list.valid_to IS NULL OR list.valid_to > $3::timestamptz)\n ORDER BY b.code, p.valid_from DESC";
7
+ export declare const DETAIL_SQL = "SELECT b.id, b.code, b.title, b.status, b.fulfillment_mode, b.updated_at,\n b.composition_constraint, b.metadata,\n (SELECT count(*) FROM public.catalog_bundle_components c WHERE c.bundle_id = b.id) AS component_count,\n EXISTS (SELECT 1 FROM public.catalog_bundle_prices p JOIN public.price_lists list ON list.id = p.price_list_id\n WHERE p.bundle_id = b.id AND p.active AND p.amount_kind = 'gross' AND p.target_price_minor > 0\n AND p.mode IN ('one_time', 'any') AND list.status = 'active'\n AND p.valid_from <= CURRENT_TIMESTAMP AND (p.valid_to IS NULL OR p.valid_to > CURRENT_TIMESTAMP)\n AND list.valid_from <= CURRENT_TIMESTAMP AND (list.valid_to IS NULL OR list.valid_to > CURRENT_TIMESTAMP)) AS has_active_target_price FROM public.catalog_bundles b WHERE b.code = $1";
8
+ export declare const LIST_SQL = "SELECT b.id, b.code, b.title, b.status, b.fulfillment_mode, b.updated_at,\n b.composition_constraint, b.metadata,\n (SELECT count(*) FROM public.catalog_bundle_components c WHERE c.bundle_id = b.id) AS component_count,\n EXISTS (SELECT 1 FROM public.catalog_bundle_prices p JOIN public.price_lists list ON list.id = p.price_list_id\n WHERE p.bundle_id = b.id AND p.active AND p.amount_kind = 'gross' AND p.target_price_minor > 0\n AND p.mode IN ('one_time', 'any') AND list.status = 'active'\n AND p.valid_from <= CURRENT_TIMESTAMP AND (p.valid_to IS NULL OR p.valid_to > CURRENT_TIMESTAMP)\n AND list.valid_from <= CURRENT_TIMESTAMP AND (list.valid_to IS NULL OR list.valid_to > CURRENT_TIMESTAMP)) AS has_active_target_price FROM public.catalog_bundles b\n WHERE ($1::text = 'all' OR b.status = $1::text)\n AND ($2::text IS NULL OR b.code ILIKE '%' || $2 || '%' OR b.title ILIKE '%' || $2 || '%')\n ORDER BY b.code LIMIT $3 OFFSET $4";
@@ -0,0 +1,79 @@
1
+ /** Effective-authority SQL is isolated from the incumbent exported statements. */
2
+ const ANCHORS = `SELECT pe.unit_price_minor FROM public.price_entries pe
3
+ WHERE pe.variant_id = s.id AND pe.price_list_id = %LIST% AND pe.active
4
+ AND pe.min_qty = 1 AND pe.amount_kind = 'gross'
5
+ AND pe.valid_from <= $3::timestamptz AND (pe.valid_to IS NULL OR pe.valid_to > $3::timestamptz)
6
+ AND (pe.mode = $4::text OR (pe.mode = 'any' AND NOT EXISTS (
7
+ SELECT 1 FROM public.price_entries exact WHERE exact.variant_id = s.id
8
+ AND exact.price_list_id = pe.price_list_id AND exact.active AND exact.min_qty = 1
9
+ AND exact.amount_kind = 'gross' AND exact.mode = $4::text
10
+ AND exact.valid_from <= $3::timestamptz AND (exact.valid_to IS NULL OR exact.valid_to > $3::timestamptz))))`;
11
+ const FACTS = `s.status AS sku_status, s.sellable_standalone, s.sellable_in_subscription,
12
+ s.net_weight_g, pr.status AS product_status,
13
+ (pr.primary_sku_id IS NOT NULL AND revision.id IS NOT NULL) AS document_ready,
14
+ COALESCE((SELECT jsonb_agg(jsonb_build_object('issuer', identifier.issuer, 'normalizedValue', identifier.normalized_value,
15
+ 'kind', identifier.identifier_kind, 'packKind', identifier.pack_kind, 'packQuantity', identifier.quantity, 'isPrimary', identifier.is_primary))
16
+ FROM public.catalog_sku_identifiers identifier WHERE identifier.catalog_sku_id = s.id), '[]'::jsonb) AS identifiers`;
17
+ const REFERENCE = `(SELECT (array_agg(candidate.unit_price_minor))[1] FROM (${ANCHORS}) candidate)`;
18
+ const COUNT = `(SELECT count(*) FROM (${ANCHORS}) candidate)`;
19
+ export const COMPONENT_SQL = `
20
+ SELECT c.bundle_id, s.sku, s.title, pr.slug AS product_slug, s.id AS variant_id,
21
+ c.quantity, c.is_addon, c.sort_order, ${FACTS},
22
+ ${REFERENCE.replace("%LIST%", "$2::uuid")} AS reference_unit_price_minor,
23
+ ${COUNT.replace("%LIST%", "$2::uuid")} AS reference_price_count
24
+ FROM public.catalog_bundle_components c
25
+ JOIN public.catalog_skus s ON s.id = c.catalog_sku_id
26
+ JOIN public.catalog_products pr ON pr.id = s.product_id
27
+ LEFT JOIN public.catalog_product_document_revisions revision ON revision.id = pr.current_document_revision_id AND revision.product_id = pr.id
28
+ WHERE c.bundle_id = $1::uuid ORDER BY c.sort_order, s.sku`;
29
+ export const FEED_COMPONENT_SQL = `
30
+ SELECT c.bundle_id, s.sku, s.title, pr.slug AS product_slug, s.id AS variant_id,
31
+ c.quantity, c.is_addon, c.sort_order, ${FACTS},
32
+ ${REFERENCE.replace("%LIST%", "selected.price_list_id")} AS reference_unit_price_minor,
33
+ ${COUNT.replace("%LIST%", "selected.price_list_id")} AS reference_price_count
34
+ FROM unnest($1::uuid[], $2::uuid[]) AS selected(bundle_id, price_list_id)
35
+ JOIN public.catalog_bundle_components c ON c.bundle_id = selected.bundle_id
36
+ JOIN public.catalog_skus s ON s.id = c.catalog_sku_id
37
+ JOIN public.catalog_products pr ON pr.id = s.product_id
38
+ LEFT JOIN public.catalog_product_document_revisions revision ON revision.id = pr.current_document_revision_id AND revision.product_id = pr.id
39
+ ORDER BY c.bundle_id, c.sort_order, s.sku`;
40
+ export const PRICE_SQL = `
41
+ SELECT p.mode, p.price_list_id, p.target_price_minor, list.currency, p.amount_kind, p.active, p.valid_from, p.valid_to
42
+ FROM public.catalog_bundle_prices p JOIN public.price_lists list ON list.id = p.price_list_id
43
+ WHERE p.bundle_id = $1::uuid ORDER BY p.valid_from DESC`;
44
+ export const OWN_LIST_SQL = `
45
+ SELECT list.id, list.currency, list.region_code, p.mode
46
+ FROM public.catalog_bundle_prices p JOIN public.price_lists list ON list.id = p.price_list_id
47
+ WHERE p.bundle_id = $1::uuid AND p.active AND p.amount_kind = 'gross'
48
+ AND (p.mode = $2::text OR p.mode = 'any') AND list.status = 'active'
49
+ AND p.valid_from <= $3::timestamptz AND (p.valid_to IS NULL OR p.valid_to > $3::timestamptz)
50
+ AND list.valid_from <= $3::timestamptz AND (list.valid_to IS NULL OR list.valid_to > $3::timestamptz)
51
+ ORDER BY p.valid_from DESC`;
52
+ export const CURRENCY_LIST_SQL = `
53
+ SELECT id, currency, region_code FROM public.price_lists
54
+ WHERE currency = $1::text AND status = 'active' AND ($2::text IS NULL OR region_code = $2::text)
55
+ AND valid_from <= $3::timestamptz AND (valid_to IS NULL OR valid_to > $3::timestamptz)`;
56
+ export const FEED_SQL = `
57
+ SELECT b.id, b.code, b.title, b.fulfillment_mode, p.mode, p.target_price_minor, p.price_list_id, list.currency, list.region_code
58
+ FROM public.catalog_bundles b
59
+ JOIN public.catalog_bundle_prices p ON p.bundle_id = b.id AND p.active
60
+ JOIN public.price_lists list ON list.id = p.price_list_id
61
+ WHERE b.status = 'active' AND p.amount_kind = 'gross' AND p.target_price_minor > 0
62
+ AND list.status = 'active' AND ($1::text IS NULL OR list.currency = $1::text)
63
+ AND ($2::text IS NULL OR list.region_code = $2::text) AND (p.mode = $4::text OR p.mode = 'any')
64
+ AND p.valid_from <= $3::timestamptz AND (p.valid_to IS NULL OR p.valid_to > $3::timestamptz)
65
+ AND list.valid_from <= $3::timestamptz AND (list.valid_to IS NULL OR list.valid_to > $3::timestamptz)
66
+ ORDER BY b.code, p.valid_from DESC`;
67
+ const SUMMARY_COLUMNS = `b.id, b.code, b.title, b.status, b.fulfillment_mode, b.updated_at,
68
+ b.composition_constraint, b.metadata,
69
+ (SELECT count(*) FROM public.catalog_bundle_components c WHERE c.bundle_id = b.id) AS component_count,
70
+ EXISTS (SELECT 1 FROM public.catalog_bundle_prices p JOIN public.price_lists list ON list.id = p.price_list_id
71
+ WHERE p.bundle_id = b.id AND p.active AND p.amount_kind = 'gross' AND p.target_price_minor > 0
72
+ AND p.mode IN ('one_time', 'any') AND list.status = 'active'
73
+ AND p.valid_from <= CURRENT_TIMESTAMP AND (p.valid_to IS NULL OR p.valid_to > CURRENT_TIMESTAMP)
74
+ AND list.valid_from <= CURRENT_TIMESTAMP AND (list.valid_to IS NULL OR list.valid_to > CURRENT_TIMESTAMP)) AS has_active_target_price`;
75
+ export const DETAIL_SQL = `SELECT ${SUMMARY_COLUMNS} FROM public.catalog_bundles b WHERE b.code = $1`;
76
+ export const LIST_SQL = `SELECT ${SUMMARY_COLUMNS} FROM public.catalog_bundles b
77
+ WHERE ($1::text = 'all' OR b.status = $1::text)
78
+ AND ($2::text IS NULL OR b.code ILIKE '%' || $2 || '%' OR b.title ILIKE '%' || $2 || '%')
79
+ ORDER BY b.code LIMIT $3 OFFSET $4`;
@@ -0,0 +1,4 @@
1
+ import type { PgQueryExecutor } from "../data/index.js";
2
+ import { type BundleCatalogReadPort } from "./bundleCatalogReadPort.js";
3
+ /** Selected only by the explicit effective-authority option. */
4
+ export declare function createEffectiveBundleCatalogStore(executor: PgQueryExecutor, incumbent: BundleCatalogReadPort): BundleCatalogReadPort;
@@ -0,0 +1,156 @@
1
+ import { assertPrimaryUnitGtinAuthority } from "./contracts/foundation.js";
2
+ import { BundleCatalogReadError } from "./bundleCatalogReadPort.js";
3
+ import { uniqueBundlePrice, selectEffectiveBundleTargetPrice } from "./bundlePriceSelection.js";
4
+ import { COUNT_SQL } from "./bundleCatalogQueries.js";
5
+ import { LIST_SQL, DETAIL_SQL, COMPONENT_SQL, FEED_COMPONENT_SQL, PRICE_SQL, OWN_LIST_SQL, CURRENCY_LIST_SQL, FEED_SQL } from "./effectiveBundleCatalogQueries.js";
6
+ /** Selected only by the explicit effective-authority option. */
7
+ export function createEffectiveBundleCatalogStore(executor, incumbent) {
8
+ async function rows(sql, values) {
9
+ const result = await executor.query(sql, values).catch((error) => {
10
+ throw new BundleCatalogReadError(error instanceof Error ? error.message : String(error));
11
+ });
12
+ return (result.rows ?? []);
13
+ }
14
+ async function selectPriceList(bundleId, input) {
15
+ const atTime = input.atTime ?? new Date().toISOString(), mode = input.mode ?? "one_time";
16
+ const own = input.currency ? [] : await rows(OWN_LIST_SQL, [bundleId, mode, atTime]);
17
+ const chosenPrice = uniqueBundlePrice(own, mode), chosen = chosenPrice ? [chosenPrice] : [];
18
+ const currency = input.currency ?? chosen[0]?.currency;
19
+ if (!currency)
20
+ return null;
21
+ const candidates = await rows(CURRENCY_LIST_SQL, [currency, input.regionCode ?? chosen[0]?.region_code ?? null, atTime]);
22
+ if (candidates.length > 1)
23
+ throw new BundleCatalogReadError("bundle_price_list_ambiguous");
24
+ if (chosen[0] && candidates[0] && chosen[0].id !== candidates[0].id)
25
+ throw new BundleCatalogReadError("bundle_price_list_changed");
26
+ return candidates[0] ?? null;
27
+ }
28
+ return {
29
+ ...incumbent,
30
+ async listBundles(input) {
31
+ const filter = [input.status, input.query ?? null];
32
+ const [page, counted] = await Promise.all([
33
+ rows(LIST_SQL, [...filter, input.limit, input.offset]),
34
+ rows(COUNT_SQL, filter),
35
+ ]);
36
+ return { bundles: page.map(toSummary), total: Number(counted[0]?.total ?? page.length) };
37
+ },
38
+ async getBundle(input) {
39
+ const bundle = (await rows(DETAIL_SQL, [input.code]))[0];
40
+ if (!bundle)
41
+ return null;
42
+ const atTime = input.atTime ?? new Date().toISOString();
43
+ const list = await selectPriceList(bundle.id, { ...input, atTime });
44
+ const [componentRows, priceRows] = await Promise.all([
45
+ rows(COMPONENT_SQL, [bundle.id, list?.id ?? null, atTime, input.mode ?? "one_time"]).then(rows => rows.map(toComponent)),
46
+ rows(PRICE_SQL, [bundle.id]),
47
+ ]);
48
+ return {
49
+ ...toSummary(bundle), compositionConstraint: toConstraint(bundle.composition_constraint), metadata: bundle.metadata ?? {},
50
+ components: componentRows, prices: priceRows.map(toPrice),
51
+ resolvedTargetPrice: selectEffectiveBundleTargetPrice(priceRows.map(row => ({ price: toPrice(row), priceListId: row.price_list_id })), { priceListId: list?.id ?? null, currency: list?.currency ?? null, mode: input.mode ?? "one_time", atTime }),
52
+ resolvedCurrency: list?.currency ?? null, resolvedPriceListId: list?.id ?? null,
53
+ };
54
+ },
55
+ async listActiveBundleCompositions(input = {}) {
56
+ const atTime = input.atTime ?? new Date().toISOString(), mode = input.mode ?? "one_time";
57
+ const feed = await rows(FEED_SQL, [input.currency ?? null, input.regionCode ?? null, atTime, mode]);
58
+ const selected = new Map();
59
+ const listReads = new Map();
60
+ for (const row of feed) {
61
+ const same = feed.filter(candidate => candidate.id === row.id);
62
+ const candidate = uniqueBundlePrice(same, mode);
63
+ const key = `${row.currency}:${row.region_code}`;
64
+ if (!listReads.has(key))
65
+ listReads.set(key, rows(CURRENCY_LIST_SQL, [row.currency, row.region_code ?? null, atTime]));
66
+ const lists = await listReads.get(key);
67
+ if (lists.length > 1)
68
+ throw new BundleCatalogReadError("bundle_price_list_ambiguous");
69
+ if (lists[0]?.id !== row.price_list_id)
70
+ throw new BundleCatalogReadError("bundle_price_list_changed");
71
+ selected.set(row.id, candidate);
72
+ }
73
+ if (!selected.size)
74
+ return [];
75
+ const chosen = [...selected.values()];
76
+ const source = await rows(FEED_COMPONENT_SQL, [chosen.map(row => row.id), chosen.map(row => row.price_list_id), atTime, mode]);
77
+ const byBundle = groupComponents(source);
78
+ const sellable = chosen.filter(row => {
79
+ const components = source.filter(component => component.bundle_id === row.id);
80
+ return components.length > 0 && components.every(component => componentReady(component, mode));
81
+ });
82
+ return sellable.map(row => ({ code: row.code, title: row.title, fulfillmentMode: row.fulfillment_mode,
83
+ currency: row.currency, targetPriceMinor: row.target_price_minor, mode: row.mode, components: byBundle.get(row.id) ?? [] }));
84
+ },
85
+ };
86
+ }
87
+ function groupComponents(rows) {
88
+ const grouped = new Map();
89
+ for (const row of rows) {
90
+ const bucket = grouped.get(row.bundle_id) ?? [];
91
+ bucket.push(toComponent(row));
92
+ grouped.set(row.bundle_id, bucket);
93
+ }
94
+ return grouped;
95
+ }
96
+ function toComponent(row) {
97
+ if (Number(row.reference_price_count) > 1)
98
+ throw new BundleCatalogReadError("bundle_price_ambiguous");
99
+ return {
100
+ sku: row.sku,
101
+ title: row.title ?? null,
102
+ productSlug: row.product_slug,
103
+ variantId: row.variant_id,
104
+ quantity: Number(row.quantity),
105
+ isAddon: row.is_addon === true,
106
+ sortOrder: Number(row.sort_order),
107
+ referenceUnitPriceMinor: row.reference_unit_price_minor === null || row.reference_unit_price_minor === undefined
108
+ ? null
109
+ : Number(row.reference_unit_price_minor),
110
+ };
111
+ }
112
+ function toSummary(row) {
113
+ return {
114
+ code: row.code,
115
+ title: row.title,
116
+ status: row.status,
117
+ fulfillmentMode: row.fulfillment_mode,
118
+ componentCount: Number(row.component_count ?? 0),
119
+ hasActiveTargetPrice: row.has_active_target_price === true,
120
+ updatedAt: row.updated_at,
121
+ };
122
+ }
123
+ function toPrice(row) {
124
+ return {
125
+ mode: row.mode,
126
+ targetPriceMinor: Number(row.target_price_minor),
127
+ currency: row.currency,
128
+ amountKind: row.amount_kind,
129
+ active: row.active === true,
130
+ validFrom: row.valid_from,
131
+ validTo: row.valid_to ?? null,
132
+ };
133
+ }
134
+ /** An empty envelope is stored as `{}`; that is "unconstrained", not a constraint. */
135
+ function toConstraint(value) {
136
+ if (!value || typeof value.kind !== "string" || value.kind.trim() === "")
137
+ return null;
138
+ return {
139
+ kind: value.kind,
140
+ version: typeof value.version === "number" ? value.version : 0,
141
+ data: (value.data ?? {}),
142
+ };
143
+ }
144
+ function componentReady(row, mode) {
145
+ try {
146
+ assertPrimaryUnitGtinAuthority(row.identifiers);
147
+ }
148
+ catch {
149
+ return false;
150
+ }
151
+ return row.sku_status === "active" && row.product_status === "active" && row.document_ready === true
152
+ && Number.isSafeInteger(row.net_weight_g) && row.net_weight_g > 0
153
+ && (mode === "subscription" ? row.sellable_in_subscription : row.sellable_standalone)
154
+ && row.reference_unit_price_minor !== null && Number.isSafeInteger(Number(row.reference_unit_price_minor))
155
+ && Number(row.reference_unit_price_minor) > 0;
156
+ }
@@ -0,0 +1,98 @@
1
+ import { z } from "./validation.js";
2
+ export { CATALOG_FOUNDATION_CONTRACT_VERSION, CatalogSkuAuthorityError, isValidGtin, assertPrimaryUnitGtinAuthority, requireCurrentCatalogDocumentAuthority } from "./contracts/foundation.js";
3
+ export type { CatalogDocumentRevisionRef, CatalogSkuIdentifier, CatalogSkuEnvelopeSelector, NeutralSkuEnvelopeV1, CatalogPriceContext, CatalogSkuAuthorityRefusal } from "./contracts/foundation.js";
4
+ export declare const catalogFixedPointSchema: z.ZodObject<{
5
+ unscaled: z.ZodNumber;
6
+ scale: z.ZodNumber;
7
+ unit: z.ZodString;
8
+ }, z.core.$strict>;
9
+ export declare const catalogDocumentRevisionRefSchema: z.ZodObject<{
10
+ id: z.ZodGUID;
11
+ productId: z.ZodGUID;
12
+ revisionNo: z.ZodNumber;
13
+ schemaId: z.ZodString;
14
+ documentRef: z.ZodString;
15
+ sourceRef: z.ZodString;
16
+ digest: z.ZodString;
17
+ }, z.core.$strict>;
18
+ export declare const catalogSkuIdentifierSchema: z.ZodObject<{
19
+ issuer: z.ZodString;
20
+ normalizedValue: z.ZodString;
21
+ kind: z.ZodEnum<{
22
+ gtin: "gtin";
23
+ other: "other";
24
+ }>;
25
+ packKind: z.ZodEnum<{
26
+ unit: "unit";
27
+ collective: "collective";
28
+ }>;
29
+ packQuantity: z.ZodNumber;
30
+ isPrimary: z.ZodBoolean;
31
+ }, z.core.$strict>;
32
+ /** Stable, payload-free detail selectors shared by both catalog adapters. */
33
+ export declare const catalogSkuEnvelopeSelectorSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
34
+ kind: z.ZodLiteral<"sku_code">;
35
+ skuCode: z.ZodString;
36
+ }, z.core.$strict>, z.ZodObject<{
37
+ kind: z.ZodLiteral<"primary_product_slug">;
38
+ productSlug: z.ZodString;
39
+ }, z.core.$strict>], "kind">;
40
+ export declare const neutralSkuEnvelopeV1Schema: z.ZodObject<{
41
+ contractVersion: z.ZodLiteral<"catalog.foundation.v1">;
42
+ product: z.ZodObject<{
43
+ id: z.ZodGUID;
44
+ slug: z.ZodString;
45
+ primarySkuId: z.ZodGUID;
46
+ }, z.core.$strict>;
47
+ sku: z.ZodObject<{
48
+ id: z.ZodGUID;
49
+ productId: z.ZodGUID;
50
+ code: z.ZodString;
51
+ netContent: z.ZodObject<{
52
+ unscaled: z.ZodNumber;
53
+ scale: z.ZodNumber;
54
+ unit: z.ZodString;
55
+ }, z.core.$strict>;
56
+ sellability: z.ZodObject<{
57
+ status: z.ZodEnum<{
58
+ draft: "draft";
59
+ active: "active";
60
+ archived: "archived";
61
+ }>;
62
+ oneTime: z.ZodBoolean;
63
+ subscription: z.ZodBoolean;
64
+ }, z.core.$strict>;
65
+ isAddon: z.ZodBoolean;
66
+ assetRef: z.ZodNullable<z.ZodString>;
67
+ }, z.core.$strict>;
68
+ documentRevision: z.ZodObject<{
69
+ id: z.ZodGUID;
70
+ productId: z.ZodGUID;
71
+ revisionNo: z.ZodNumber;
72
+ schemaId: z.ZodString;
73
+ documentRef: z.ZodString;
74
+ sourceRef: z.ZodString;
75
+ digest: z.ZodString;
76
+ }, z.core.$strict>;
77
+ identifiers: z.ZodArray<z.ZodObject<{
78
+ issuer: z.ZodString;
79
+ normalizedValue: z.ZodString;
80
+ kind: z.ZodEnum<{
81
+ gtin: "gtin";
82
+ other: "other";
83
+ }>;
84
+ packKind: z.ZodEnum<{
85
+ unit: "unit";
86
+ collective: "collective";
87
+ }>;
88
+ packQuantity: z.ZodNumber;
89
+ isPrimary: z.ZodBoolean;
90
+ }, z.core.$strict>>;
91
+ }, z.core.$strict>;
92
+ export declare const catalogPriceContextSchema: z.ZodObject<{
93
+ priceListId: z.ZodGUID;
94
+ regionCode: z.ZodString;
95
+ currency: z.ZodString;
96
+ channel: z.ZodString;
97
+ atTime: z.ZodString;
98
+ }, z.core.$strict>;