@open-mercato/core 0.9.1-develop.7474.1.51db10479d → 0.9.1-develop.7475.1.28ca93ed97

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 (597) hide show
  1. package/.turbo/turbo-build.log +2 -2
  2. package/dist/generated/entities/catalog_price_history_entry/index.js +53 -0
  3. package/dist/generated/entities/catalog_price_history_entry/index.js.map +7 -0
  4. package/dist/generated/entities/customer_group_terms/index.js +2 -0
  5. package/dist/generated/entities/customer_group_terms/index.js.map +2 -2
  6. package/dist/generated/entities/ecommerce_store/index.js +33 -0
  7. package/dist/generated/entities/ecommerce_store/index.js.map +7 -0
  8. package/dist/generated/entities/ecommerce_store_channel_binding/index.js +29 -0
  9. package/dist/generated/entities/ecommerce_store_channel_binding/index.js.map +7 -0
  10. package/dist/generated/entities/ecommerce_store_domain_binding/index.js +23 -0
  11. package/dist/generated/entities/ecommerce_store_domain_binding/index.js.map +7 -0
  12. package/dist/generated/entities.ids.generated.js +8 -1
  13. package/dist/generated/entities.ids.generated.js.map +2 -2
  14. package/dist/generated/entity-fields-registry.js +72 -0
  15. package/dist/generated/entity-fields-registry.js.map +2 -2
  16. package/dist/helpers/integration/customerGroupsFixtures.js.map +2 -2
  17. package/dist/modules/catalog/acl.js +8 -1
  18. package/dist/modules/catalog/acl.js.map +2 -2
  19. package/dist/modules/catalog/api/config/omnibus/route.js +184 -0
  20. package/dist/modules/catalog/api/config/omnibus/route.js.map +7 -0
  21. package/dist/modules/catalog/api/prices/history/route.js +131 -0
  22. package/dist/modules/catalog/api/prices/history/route.js.map +7 -0
  23. package/dist/modules/catalog/api/prices/omnibus-preview/route.js +184 -0
  24. package/dist/modules/catalog/api/prices/omnibus-preview/route.js.map +7 -0
  25. package/dist/modules/catalog/api/products/route.js +54 -245
  26. package/dist/modules/catalog/api/products/route.js.map +3 -3
  27. package/dist/modules/catalog/api/tags/route.js +6 -0
  28. package/dist/modules/catalog/api/tags/route.js.map +2 -2
  29. package/dist/modules/catalog/backend/config/catalog/page.js +3 -1
  30. package/dist/modules/catalog/backend/config/catalog/page.js.map +2 -2
  31. package/dist/modules/catalog/cli.js +80 -2
  32. package/dist/modules/catalog/cli.js.map +2 -2
  33. package/dist/modules/catalog/commands/categories.js +51 -2
  34. package/dist/modules/catalog/commands/categories.js.map +2 -2
  35. package/dist/modules/catalog/commands/prices.js +43 -1
  36. package/dist/modules/catalog/commands/prices.js.map +2 -2
  37. package/dist/modules/catalog/commands/products.js +71 -0
  38. package/dist/modules/catalog/commands/products.js.map +2 -2
  39. package/dist/modules/catalog/commands/variants.js +7 -0
  40. package/dist/modules/catalog/commands/variants.js.map +2 -2
  41. package/dist/modules/catalog/components/OmnibusSettings.js +703 -0
  42. package/dist/modules/catalog/components/OmnibusSettings.js.map +7 -0
  43. package/dist/modules/catalog/components/PriceEditorOmnibusRow.js +152 -0
  44. package/dist/modules/catalog/components/PriceEditorOmnibusRow.js.map +7 -0
  45. package/dist/modules/catalog/components/lookupSources.js +31 -0
  46. package/dist/modules/catalog/components/lookupSources.js.map +7 -0
  47. package/dist/modules/catalog/components/prices/PriceScopeSelectors.js +8 -2
  48. package/dist/modules/catalog/components/prices/PriceScopeSelectors.js.map +2 -2
  49. package/dist/modules/catalog/components/products/VariantBuilder.js +11 -1
  50. package/dist/modules/catalog/components/products/VariantBuilder.js.map +2 -2
  51. package/dist/modules/catalog/data/entities.js +122 -1
  52. package/dist/modules/catalog/data/entities.js.map +2 -2
  53. package/dist/modules/catalog/data/validators.js +78 -0
  54. package/dist/modules/catalog/data/validators.js.map +2 -2
  55. package/dist/modules/catalog/di.js +18 -0
  56. package/dist/modules/catalog/di.js.map +2 -2
  57. package/dist/modules/catalog/lib/omnibus.js +285 -0
  58. package/dist/modules/catalog/lib/omnibus.js.map +7 -0
  59. package/dist/modules/catalog/lib/omnibusBackfill.js +146 -0
  60. package/dist/modules/catalog/lib/omnibusBackfill.js.map +7 -0
  61. package/dist/modules/catalog/lib/omnibusCache.js +89 -0
  62. package/dist/modules/catalog/lib/omnibusCache.js.map +7 -0
  63. package/dist/modules/catalog/lib/omnibusConfig.js +64 -0
  64. package/dist/modules/catalog/lib/omnibusConfig.js.map +7 -0
  65. package/dist/modules/catalog/lib/omnibusHistoryQueries.js +191 -0
  66. package/dist/modules/catalog/lib/omnibusHistoryQueries.js.map +7 -0
  67. package/dist/modules/catalog/lib/omnibusPresentedEntry.js +73 -0
  68. package/dist/modules/catalog/lib/omnibusPresentedEntry.js.map +7 -0
  69. package/dist/modules/catalog/lib/omnibusProductListEnrichment.js +94 -0
  70. package/dist/modules/catalog/lib/omnibusProductListEnrichment.js.map +7 -0
  71. package/dist/modules/catalog/lib/omnibusTypes.js +115 -0
  72. package/dist/modules/catalog/lib/omnibusTypes.js.map +7 -0
  73. package/dist/modules/catalog/lib/optionSchemaTranslations.js +55 -0
  74. package/dist/modules/catalog/lib/optionSchemaTranslations.js.map +7 -0
  75. package/dist/modules/catalog/lib/priceHistoryQuery.js +103 -0
  76. package/dist/modules/catalog/lib/priceHistoryQuery.js.map +7 -0
  77. package/dist/modules/catalog/lib/pricing.js +26 -2
  78. package/dist/modules/catalog/lib/pricing.js.map +2 -2
  79. package/dist/modules/catalog/lib/productFilters.js +273 -0
  80. package/dist/modules/catalog/lib/productFilters.js.map +7 -0
  81. package/dist/modules/catalog/lib/productScopeKeys.js +105 -0
  82. package/dist/modules/catalog/lib/productScopeKeys.js.map +7 -0
  83. package/dist/modules/catalog/lib/productScopeReindex.js +73 -0
  84. package/dist/modules/catalog/lib/productScopeReindex.js.map +7 -0
  85. package/dist/modules/catalog/migrations/Migration20261005105352_catalog.js +39 -0
  86. package/dist/modules/catalog/migrations/Migration20261005105352_catalog.js.map +7 -0
  87. package/dist/modules/catalog/migrations/Migration20261005150824_catalog.js +39 -0
  88. package/dist/modules/catalog/migrations/Migration20261005150824_catalog.js.map +7 -0
  89. package/dist/modules/catalog/services/catalogOmnibusService.js +480 -0
  90. package/dist/modules/catalog/services/catalogOmnibusService.js.map +7 -0
  91. package/dist/modules/catalog/setup.js +3 -1
  92. package/dist/modules/catalog/setup.js.map +2 -2
  93. package/dist/modules/catalog/subscribers/product-scope-keys-category-deleted.js +16 -0
  94. package/dist/modules/catalog/subscribers/product-scope-keys-category-deleted.js.map +7 -0
  95. package/dist/modules/catalog/subscribers/product-scope-keys-category-updated.js +17 -0
  96. package/dist/modules/catalog/subscribers/product-scope-keys-category-updated.js.map +7 -0
  97. package/dist/modules/catalog/translations.js +10 -0
  98. package/dist/modules/catalog/translations.js.map +2 -2
  99. package/dist/modules/configs/lib/upgrade-actions.js +28 -0
  100. package/dist/modules/configs/lib/upgrade-actions.js.map +2 -2
  101. package/dist/modules/customer_groups/api/customer-groups/[id]/terms/route.js +5 -0
  102. package/dist/modules/customer_groups/api/customer-groups/[id]/terms/route.js.map +2 -2
  103. package/dist/modules/customer_groups/components/CustomerGroupTermsSection.js +111 -3
  104. package/dist/modules/customer_groups/components/CustomerGroupTermsSection.js.map +2 -2
  105. package/dist/modules/customer_groups/components/customerGroupAssortmentScope.js +43 -0
  106. package/dist/modules/customer_groups/components/customerGroupAssortmentScope.js.map +7 -0
  107. package/dist/modules/customer_groups/data/entities.js +3 -0
  108. package/dist/modules/customer_groups/data/entities.js.map +2 -2
  109. package/dist/modules/customer_groups/data/validators.js +9 -0
  110. package/dist/modules/customer_groups/data/validators.js.map +2 -2
  111. package/dist/modules/customer_groups/migrations/Migration20261005110250_customer_groups.js +17 -0
  112. package/dist/modules/customer_groups/migrations/Migration20261005110250_customer_groups.js.map +7 -0
  113. package/dist/modules/customer_groups/services/customerGroupsService.js +62 -15
  114. package/dist/modules/customer_groups/services/customerGroupsService.js.map +2 -2
  115. package/dist/modules/ecommerce/acl.js +13 -0
  116. package/dist/modules/ecommerce/acl.js.map +7 -0
  117. package/dist/modules/ecommerce/api/domain-mappings/route.js +72 -0
  118. package/dist/modules/ecommerce/api/domain-mappings/route.js.map +7 -0
  119. package/dist/modules/ecommerce/api/openapi.js +27 -0
  120. package/dist/modules/ecommerce/api/openapi.js.map +7 -0
  121. package/dist/modules/ecommerce/api/store-channel-bindings/[id]/assortment-count/route.js +109 -0
  122. package/dist/modules/ecommerce/api/store-channel-bindings/[id]/assortment-count/route.js.map +7 -0
  123. package/dist/modules/ecommerce/api/store-channel-bindings/crud.js +265 -0
  124. package/dist/modules/ecommerce/api/store-channel-bindings/crud.js.map +7 -0
  125. package/dist/modules/ecommerce/api/store-channel-bindings/route.js +67 -0
  126. package/dist/modules/ecommerce/api/store-channel-bindings/route.js.map +7 -0
  127. package/dist/modules/ecommerce/api/store-domain-bindings/crud.js +296 -0
  128. package/dist/modules/ecommerce/api/store-domain-bindings/crud.js.map +7 -0
  129. package/dist/modules/ecommerce/api/store-domain-bindings/route.js +73 -0
  130. package/dist/modules/ecommerce/api/store-domain-bindings/route.js.map +7 -0
  131. package/dist/modules/ecommerce/api/storefront/categories/[slug]/route.js +87 -0
  132. package/dist/modules/ecommerce/api/storefront/categories/[slug]/route.js.map +7 -0
  133. package/dist/modules/ecommerce/api/storefront/categories/openapiSchemas.js +50 -0
  134. package/dist/modules/ecommerce/api/storefront/categories/openapiSchemas.js.map +7 -0
  135. package/dist/modules/ecommerce/api/storefront/categories/route.js +75 -0
  136. package/dist/modules/ecommerce/api/storefront/categories/route.js.map +7 -0
  137. package/dist/modules/ecommerce/api/storefront/context/route.js +163 -0
  138. package/dist/modules/ecommerce/api/storefront/context/route.js.map +7 -0
  139. package/dist/modules/ecommerce/api/storefront/products/[idOrHandle]/route.js +87 -0
  140. package/dist/modules/ecommerce/api/storefront/products/[idOrHandle]/route.js.map +7 -0
  141. package/dist/modules/ecommerce/api/storefront/products/openapiSchemas.js +177 -0
  142. package/dist/modules/ecommerce/api/storefront/products/openapiSchemas.js.map +7 -0
  143. package/dist/modules/ecommerce/api/storefront/products/route.js +78 -0
  144. package/dist/modules/ecommerce/api/storefront/products/route.js.map +7 -0
  145. package/dist/modules/ecommerce/api/storefront/search/suggest/openapiSchemas.js +25 -0
  146. package/dist/modules/ecommerce/api/storefront/search/suggest/openapiSchemas.js.map +7 -0
  147. package/dist/modules/ecommerce/api/storefront/search/suggest/route.js +75 -0
  148. package/dist/modules/ecommerce/api/storefront/search/suggest/route.js.map +7 -0
  149. package/dist/modules/ecommerce/api/storefront/storefrontRouteSupport.js +58 -0
  150. package/dist/modules/ecommerce/api/storefront/storefrontRouteSupport.js.map +7 -0
  151. package/dist/modules/ecommerce/api/stores/[id]/branding/route.js +183 -0
  152. package/dist/modules/ecommerce/api/stores/[id]/branding/route.js.map +7 -0
  153. package/dist/modules/ecommerce/api/stores/[id]/preview-branding/route.js +92 -0
  154. package/dist/modules/ecommerce/api/stores/[id]/preview-branding/route.js.map +7 -0
  155. package/dist/modules/ecommerce/api/stores/crud.js +401 -0
  156. package/dist/modules/ecommerce/api/stores/crud.js.map +7 -0
  157. package/dist/modules/ecommerce/api/stores/route.js +64 -0
  158. package/dist/modules/ecommerce/api/stores/route.js.map +7 -0
  159. package/dist/modules/ecommerce/backend/config/ecommerce/[id]/page.js +9 -0
  160. package/dist/modules/ecommerce/backend/config/ecommerce/[id]/page.js.map +7 -0
  161. package/dist/modules/ecommerce/backend/config/ecommerce/[id]/page.meta.js +16 -0
  162. package/dist/modules/ecommerce/backend/config/ecommerce/[id]/page.meta.js.map +7 -0
  163. package/dist/modules/ecommerce/backend/config/ecommerce/page.js +9 -0
  164. package/dist/modules/ecommerce/backend/config/ecommerce/page.js.map +7 -0
  165. package/dist/modules/ecommerce/backend/config/ecommerce/page.meta.js +16 -0
  166. package/dist/modules/ecommerce/backend/config/ecommerce/page.meta.js.map +7 -0
  167. package/dist/modules/ecommerce/commands/stores.js +110 -0
  168. package/dist/modules/ecommerce/commands/stores.js.map +7 -0
  169. package/dist/modules/ecommerce/components/ChannelAssortmentCount.js +90 -0
  170. package/dist/modules/ecommerce/components/ChannelAssortmentCount.js.map +7 -0
  171. package/dist/modules/ecommerce/components/ChannelBindingFormSections.js +33 -0
  172. package/dist/modules/ecommerce/components/ChannelBindingFormSections.js.map +7 -0
  173. package/dist/modules/ecommerce/components/ChannelLookupPicker.js +11 -0
  174. package/dist/modules/ecommerce/components/ChannelLookupPicker.js.map +7 -0
  175. package/dist/modules/ecommerce/components/DomainStatusWarning.js +24 -0
  176. package/dist/modules/ecommerce/components/DomainStatusWarning.js.map +7 -0
  177. package/dist/modules/ecommerce/components/StoreAvailabilityDefaultsSection.js +190 -0
  178. package/dist/modules/ecommerce/components/StoreAvailabilityDefaultsSection.js.map +7 -0
  179. package/dist/modules/ecommerce/components/StoreBrandingControls.js +67 -0
  180. package/dist/modules/ecommerce/components/StoreBrandingControls.js.map +7 -0
  181. package/dist/modules/ecommerce/components/StoreBrandingPreview.js +69 -0
  182. package/dist/modules/ecommerce/components/StoreBrandingPreview.js.map +7 -0
  183. package/dist/modules/ecommerce/components/StoreBrandingTab.js +218 -0
  184. package/dist/modules/ecommerce/components/StoreBrandingTab.js.map +7 -0
  185. package/dist/modules/ecommerce/components/StoreChannelBindingDialog.js +270 -0
  186. package/dist/modules/ecommerce/components/StoreChannelBindingDialog.js.map +7 -0
  187. package/dist/modules/ecommerce/components/StoreChannelsTab.js +313 -0
  188. package/dist/modules/ecommerce/components/StoreChannelsTab.js.map +7 -0
  189. package/dist/modules/ecommerce/components/StoreCreateDialog.js +164 -0
  190. package/dist/modules/ecommerce/components/StoreCreateDialog.js.map +7 -0
  191. package/dist/modules/ecommerce/components/StoreDomainBindingDialog.js +162 -0
  192. package/dist/modules/ecommerce/components/StoreDomainBindingDialog.js.map +7 -0
  193. package/dist/modules/ecommerce/components/StoreDomainsTab.js +357 -0
  194. package/dist/modules/ecommerce/components/StoreDomainsTab.js.map +7 -0
  195. package/dist/modules/ecommerce/components/StoreEditPage.js +155 -0
  196. package/dist/modules/ecommerce/components/StoreEditPage.js.map +7 -0
  197. package/dist/modules/ecommerce/components/StoreGeneralTab.js +167 -0
  198. package/dist/modules/ecommerce/components/StoreGeneralTab.js.map +7 -0
  199. package/dist/modules/ecommerce/components/StoreListPage.js +290 -0
  200. package/dist/modules/ecommerce/components/StoreListPage.js.map +7 -0
  201. package/dist/modules/ecommerce/components/StoreSeoTab.js +132 -0
  202. package/dist/modules/ecommerce/components/StoreSeoTab.js.map +7 -0
  203. package/dist/modules/ecommerce/components/StoreStatusBadge.js +20 -0
  204. package/dist/modules/ecommerce/components/StoreStatusBadge.js.map +7 -0
  205. package/dist/modules/ecommerce/components/channelLookups.js +28 -0
  206. package/dist/modules/ecommerce/components/channelLookups.js.map +7 -0
  207. package/dist/modules/ecommerce/components/storeAdmin.js +41 -0
  208. package/dist/modules/ecommerce/components/storeAdmin.js.map +7 -0
  209. package/dist/modules/ecommerce/components/storeBrandingForm.js +197 -0
  210. package/dist/modules/ecommerce/components/storeBrandingForm.js.map +7 -0
  211. package/dist/modules/ecommerce/components/storeChannels.js +140 -0
  212. package/dist/modules/ecommerce/components/storeChannels.js.map +7 -0
  213. package/dist/modules/ecommerce/components/storeDomains.js +167 -0
  214. package/dist/modules/ecommerce/components/storeDomains.js.map +7 -0
  215. package/dist/modules/ecommerce/components/storeEditTabs.js +62 -0
  216. package/dist/modules/ecommerce/components/storeEditTabs.js.map +7 -0
  217. package/dist/modules/ecommerce/components/storeGeneral.js +95 -0
  218. package/dist/modules/ecommerce/components/storeGeneral.js.map +7 -0
  219. package/dist/modules/ecommerce/components/storeSeo.js +69 -0
  220. package/dist/modules/ecommerce/components/storeSeo.js.map +7 -0
  221. package/dist/modules/ecommerce/components/useChannelAssortmentCount.js +45 -0
  222. package/dist/modules/ecommerce/components/useChannelAssortmentCount.js.map +7 -0
  223. package/dist/modules/ecommerce/components/useStoreAccess.js +28 -0
  224. package/dist/modules/ecommerce/components/useStoreAccess.js.map +7 -0
  225. package/dist/modules/ecommerce/data/enrichers.js +157 -0
  226. package/dist/modules/ecommerce/data/enrichers.js.map +7 -0
  227. package/dist/modules/ecommerce/data/entities.js +197 -0
  228. package/dist/modules/ecommerce/data/entities.js.map +7 -0
  229. package/dist/modules/ecommerce/data/validators.js +406 -0
  230. package/dist/modules/ecommerce/data/validators.js.map +7 -0
  231. package/dist/modules/ecommerce/di.js +11 -0
  232. package/dist/modules/ecommerce/di.js.map +7 -0
  233. package/dist/modules/ecommerce/events.js +27 -0
  234. package/dist/modules/ecommerce/events.js.map +7 -0
  235. package/dist/modules/ecommerce/index.js +16 -0
  236. package/dist/modules/ecommerce/index.js.map +7 -0
  237. package/dist/modules/ecommerce/lib/assortmentCount.js +112 -0
  238. package/dist/modules/ecommerce/lib/assortmentCount.js.map +7 -0
  239. package/dist/modules/ecommerce/lib/brandingStyles.js +184 -0
  240. package/dist/modules/ecommerce/lib/brandingStyles.js.map +7 -0
  241. package/dist/modules/ecommerce/lib/buyerContext.js +284 -0
  242. package/dist/modules/ecommerce/lib/buyerContext.js.map +7 -0
  243. package/dist/modules/ecommerce/lib/cacheInvalidation.js +186 -0
  244. package/dist/modules/ecommerce/lib/cacheInvalidation.js.map +7 -0
  245. package/dist/modules/ecommerce/lib/cacheKeys.js +236 -0
  246. package/dist/modules/ecommerce/lib/cacheKeys.js.map +7 -0
  247. package/dist/modules/ecommerce/lib/createConflictRecheck.js +29 -0
  248. package/dist/modules/ecommerce/lib/createConflictRecheck.js.map +7 -0
  249. package/dist/modules/ecommerce/lib/crudEvents.js +94 -0
  250. package/dist/modules/ecommerce/lib/crudEvents.js.map +7 -0
  251. package/dist/modules/ecommerce/lib/crudSupport.js +64 -0
  252. package/dist/modules/ecommerce/lib/crudSupport.js.map +7 -0
  253. package/dist/modules/ecommerce/lib/domainBindingRebind.js +99 -0
  254. package/dist/modules/ecommerce/lib/domainBindingRebind.js.map +7 -0
  255. package/dist/modules/ecommerce/lib/domainMappingSummaries.js +39 -0
  256. package/dist/modules/ecommerce/lib/domainMappingSummaries.js.map +7 -0
  257. package/dist/modules/ecommerce/lib/exclusiveFlag.js +57 -0
  258. package/dist/modules/ecommerce/lib/exclusiveFlag.js.map +7 -0
  259. package/dist/modules/ecommerce/lib/references.js +70 -0
  260. package/dist/modules/ecommerce/lib/references.js.map +7 -0
  261. package/dist/modules/ecommerce/lib/seedDraftStore.js +99 -0
  262. package/dist/modules/ecommerce/lib/seedDraftStore.js.map +7 -0
  263. package/dist/modules/ecommerce/lib/storeBindingCascade.js +109 -0
  264. package/dist/modules/ecommerce/lib/storeBindingCascade.js.map +7 -0
  265. package/dist/modules/ecommerce/lib/storeBranding.js +40 -0
  266. package/dist/modules/ecommerce/lib/storeBranding.js.map +7 -0
  267. package/dist/modules/ecommerce/lib/storeBrandingRoute.js +76 -0
  268. package/dist/modules/ecommerce/lib/storeBrandingRoute.js.map +7 -0
  269. package/dist/modules/ecommerce/lib/storeContext.js +393 -0
  270. package/dist/modules/ecommerce/lib/storeContext.js.map +7 -0
  271. package/dist/modules/ecommerce/lib/storeContextService.js +43 -0
  272. package/dist/modules/ecommerce/lib/storeContextService.js.map +7 -0
  273. package/dist/modules/ecommerce/lib/storeLocale.js +60 -0
  274. package/dist/modules/ecommerce/lib/storeLocale.js.map +7 -0
  275. package/dist/modules/ecommerce/lib/storeNotifications.js +41 -0
  276. package/dist/modules/ecommerce/lib/storeNotifications.js.map +7 -0
  277. package/dist/modules/ecommerce/lib/storefrontCatalogSupport.js +248 -0
  278. package/dist/modules/ecommerce/lib/storefrontCatalogSupport.js.map +7 -0
  279. package/dist/modules/ecommerce/lib/storefrontCategories.js +241 -0
  280. package/dist/modules/ecommerce/lib/storefrontCategories.js.map +7 -0
  281. package/dist/modules/ecommerce/lib/storefrontCategoryCache.js +71 -0
  282. package/dist/modules/ecommerce/lib/storefrontCategoryCache.js.map +7 -0
  283. package/dist/modules/ecommerce/lib/storefrontDetail.js +447 -0
  284. package/dist/modules/ecommerce/lib/storefrontDetail.js.map +7 -0
  285. package/dist/modules/ecommerce/lib/storefrontFacets.js +441 -0
  286. package/dist/modules/ecommerce/lib/storefrontFacets.js.map +7 -0
  287. package/dist/modules/ecommerce/lib/storefrontOptionFilter.js +15 -0
  288. package/dist/modules/ecommerce/lib/storefrontOptionFilter.js.map +7 -0
  289. package/dist/modules/ecommerce/lib/storefrontPricing.js +393 -0
  290. package/dist/modules/ecommerce/lib/storefrontPricing.js.map +7 -0
  291. package/dist/modules/ecommerce/lib/storefrontProductCache.js +90 -0
  292. package/dist/modules/ecommerce/lib/storefrontProductCache.js.map +7 -0
  293. package/dist/modules/ecommerce/lib/storefrontProductScope.js +107 -0
  294. package/dist/modules/ecommerce/lib/storefrontProductScope.js.map +7 -0
  295. package/dist/modules/ecommerce/lib/storefrontProducts.js +670 -0
  296. package/dist/modules/ecommerce/lib/storefrontProducts.js.map +7 -0
  297. package/dist/modules/ecommerce/lib/storefrontQuery.js +156 -0
  298. package/dist/modules/ecommerce/lib/storefrontQuery.js.map +7 -0
  299. package/dist/modules/ecommerce/lib/storefrontRateLimit.js +99 -0
  300. package/dist/modules/ecommerce/lib/storefrontRateLimit.js.map +7 -0
  301. package/dist/modules/ecommerce/lib/storefrontSearch.js +303 -0
  302. package/dist/modules/ecommerce/lib/storefrontSearch.js.map +7 -0
  303. package/dist/modules/ecommerce/lib/storefrontSearchCache.js +35 -0
  304. package/dist/modules/ecommerce/lib/storefrontSearchCache.js.map +7 -0
  305. package/dist/modules/ecommerce/lib/subscriberSupport.js +33 -0
  306. package/dist/modules/ecommerce/lib/subscriberSupport.js.map +7 -0
  307. package/dist/modules/ecommerce/lib/types.js +1 -0
  308. package/dist/modules/ecommerce/lib/types.js.map +7 -0
  309. package/dist/modules/ecommerce/migrations/Migration20261005113233_ecommerce.js +32 -0
  310. package/dist/modules/ecommerce/migrations/Migration20261005113233_ecommerce.js.map +7 -0
  311. package/dist/modules/ecommerce/migrations/Migration20261006112733_ecommerce.js +17 -0
  312. package/dist/modules/ecommerce/migrations/Migration20261006112733_ecommerce.js.map +7 -0
  313. package/dist/modules/ecommerce/notifications.client.js +47 -0
  314. package/dist/modules/ecommerce/notifications.client.js.map +7 -0
  315. package/dist/modules/ecommerce/notifications.js +48 -0
  316. package/dist/modules/ecommerce/notifications.js.map +7 -0
  317. package/dist/modules/ecommerce/search.js +83 -0
  318. package/dist/modules/ecommerce/search.js.map +7 -0
  319. package/dist/modules/ecommerce/setup.js +17 -0
  320. package/dist/modules/ecommerce/setup.js.map +7 -0
  321. package/dist/modules/ecommerce/subscribers/assortment-empty-notifications.js +14 -0
  322. package/dist/modules/ecommerce/subscribers/assortment-empty-notifications.js.map +7 -0
  323. package/dist/modules/ecommerce/subscribers/availability-policy-cache-invalidation.js +14 -0
  324. package/dist/modules/ecommerce/subscribers/availability-policy-cache-invalidation.js.map +7 -0
  325. package/dist/modules/ecommerce/subscribers/catalog-category-cache-invalidation.js +14 -0
  326. package/dist/modules/ecommerce/subscribers/catalog-category-cache-invalidation.js.map +7 -0
  327. package/dist/modules/ecommerce/subscribers/catalog-price-cache-invalidation.js +14 -0
  328. package/dist/modules/ecommerce/subscribers/catalog-price-cache-invalidation.js.map +7 -0
  329. package/dist/modules/ecommerce/subscribers/catalog-product-cache-invalidation.js +14 -0
  330. package/dist/modules/ecommerce/subscribers/catalog-product-cache-invalidation.js.map +7 -0
  331. package/dist/modules/ecommerce/subscribers/catalog-variant-cache-invalidation.js +14 -0
  332. package/dist/modules/ecommerce/subscribers/catalog-variant-cache-invalidation.js.map +7 -0
  333. package/dist/modules/ecommerce/subscribers/customer-group-cache-invalidation.js +14 -0
  334. package/dist/modules/ecommerce/subscribers/customer-group-cache-invalidation.js.map +7 -0
  335. package/dist/modules/ecommerce/subscribers/customer-group-membership-cache-invalidation.js +14 -0
  336. package/dist/modules/ecommerce/subscribers/customer-group-membership-cache-invalidation.js.map +7 -0
  337. package/dist/modules/ecommerce/subscribers/customer-group-terms-cache-invalidation.js +14 -0
  338. package/dist/modules/ecommerce/subscribers/customer-group-terms-cache-invalidation.js.map +7 -0
  339. package/dist/modules/ecommerce/subscribers/customer-user-deleted-cache-invalidation.js +14 -0
  340. package/dist/modules/ecommerce/subscribers/customer-user-deleted-cache-invalidation.js.map +7 -0
  341. package/dist/modules/ecommerce/subscribers/customer-user-updated-cache-invalidation.js +14 -0
  342. package/dist/modules/ecommerce/subscribers/customer-user-updated-cache-invalidation.js.map +7 -0
  343. package/dist/modules/ecommerce/subscribers/domain-binding-rebind.js +16 -0
  344. package/dist/modules/ecommerce/subscribers/domain-binding-rebind.js.map +7 -0
  345. package/dist/modules/ecommerce/subscribers/domain-mapping-cache-invalidation.js +14 -0
  346. package/dist/modules/ecommerce/subscribers/domain-mapping-cache-invalidation.js.map +7 -0
  347. package/dist/modules/ecommerce/subscribers/store-cache-invalidation.js +14 -0
  348. package/dist/modules/ecommerce/subscribers/store-cache-invalidation.js.map +7 -0
  349. package/dist/modules/ecommerce/subscribers/store-channel-binding-cache-invalidation.js +14 -0
  350. package/dist/modules/ecommerce/subscribers/store-channel-binding-cache-invalidation.js.map +7 -0
  351. package/dist/modules/ecommerce/subscribers/store-domain-binding-cache-invalidation.js +14 -0
  352. package/dist/modules/ecommerce/subscribers/store-domain-binding-cache-invalidation.js.map +7 -0
  353. package/dist/modules/ecommerce/subscribers/store-notifications.js +14 -0
  354. package/dist/modules/ecommerce/subscribers/store-notifications.js.map +7 -0
  355. package/dist/modules/query_index/lib/batch.js +23 -9
  356. package/dist/modules/query_index/lib/batch.js.map +2 -2
  357. package/dist/modules/query_index/lib/doc-enrichers.js +212 -0
  358. package/dist/modules/query_index/lib/doc-enrichers.js.map +7 -0
  359. package/dist/modules/query_index/lib/document.js +2 -0
  360. package/dist/modules/query_index/lib/document.js.map +2 -2
  361. package/dist/modules/query_index/lib/engine.js +68 -1
  362. package/dist/modules/query_index/lib/engine.js.map +2 -2
  363. package/dist/modules/query_index/lib/indexer.js +7 -0
  364. package/dist/modules/query_index/lib/indexer.js.map +2 -2
  365. package/dist/modules/query_index/lib/search-tokens.js +2 -0
  366. package/dist/modules/query_index/lib/search-tokens.js.map +2 -2
  367. package/dist/modules/query_index/migrations/Migration20261005201500_query_index.js +17 -0
  368. package/dist/modules/query_index/migrations/Migration20261005201500_query_index.js.map +7 -0
  369. package/dist/modules/translations/components/TranslationManager.js +3 -3
  370. package/dist/modules/translations/components/TranslationManager.js.map +2 -2
  371. package/dist/modules/translations/data/validators.js +1 -1
  372. package/dist/modules/translations/data/validators.js.map +1 -1
  373. package/dist/modules/translations/lib/batch.js +21 -1
  374. package/dist/modules/translations/lib/batch.js.map +2 -2
  375. package/dist/modules/translations/lib/helpers.js +3 -0
  376. package/dist/modules/translations/lib/helpers.js.map +2 -2
  377. package/dist/modules/translations/lib/resolve-field-list.js +14 -2
  378. package/dist/modules/translations/lib/resolve-field-list.js.map +2 -2
  379. package/generated/entities/catalog_price_history_entry/index.ts +25 -0
  380. package/generated/entities/customer_group_terms/index.ts +1 -0
  381. package/generated/entities/ecommerce_store/index.ts +15 -0
  382. package/generated/entities/ecommerce_store_channel_binding/index.ts +13 -0
  383. package/generated/entities/ecommerce_store_domain_binding/index.ts +10 -0
  384. package/generated/entities.ids.generated.ts +8 -1
  385. package/generated/entity-fields-registry.ts +72 -0
  386. package/package.json +7 -7
  387. package/src/helpers/integration/customerGroupsFixtures.ts +2 -0
  388. package/src/modules/auth/i18n/de.json +8 -0
  389. package/src/modules/auth/i18n/en.json +8 -0
  390. package/src/modules/auth/i18n/es.json +8 -0
  391. package/src/modules/auth/i18n/ko.json +8 -0
  392. package/src/modules/auth/i18n/pl.json +8 -0
  393. package/src/modules/catalog/AGENTS.md +5 -2
  394. package/src/modules/catalog/acl.ts +7 -0
  395. package/src/modules/catalog/api/config/omnibus/route.ts +204 -0
  396. package/src/modules/catalog/api/prices/history/route.ts +139 -0
  397. package/src/modules/catalog/api/prices/omnibus-preview/route.ts +202 -0
  398. package/src/modules/catalog/api/products/route.ts +53 -308
  399. package/src/modules/catalog/api/tags/route.ts +6 -0
  400. package/src/modules/catalog/backend/config/catalog/page.tsx +2 -0
  401. package/src/modules/catalog/cli.ts +84 -1
  402. package/src/modules/catalog/commands/categories.ts +54 -2
  403. package/src/modules/catalog/commands/prices.ts +43 -1
  404. package/src/modules/catalog/commands/products.ts +84 -1
  405. package/src/modules/catalog/commands/variants.ts +7 -0
  406. package/src/modules/catalog/components/OmnibusSettings.tsx +832 -0
  407. package/src/modules/catalog/components/PriceEditorOmnibusRow.tsx +219 -0
  408. package/src/modules/catalog/components/lookupSources.ts +29 -0
  409. package/src/modules/catalog/components/prices/PriceScopeSelectors.tsx +9 -0
  410. package/src/modules/catalog/components/products/VariantBuilder.tsx +9 -0
  411. package/src/modules/catalog/data/entities.ts +123 -1
  412. package/src/modules/catalog/data/validators.ts +118 -0
  413. package/src/modules/catalog/di.ts +23 -0
  414. package/src/modules/catalog/i18n/de.json +77 -0
  415. package/src/modules/catalog/i18n/en.json +77 -0
  416. package/src/modules/catalog/i18n/es.json +77 -0
  417. package/src/modules/catalog/i18n/ko.json +77 -0
  418. package/src/modules/catalog/i18n/pl.json +77 -0
  419. package/src/modules/catalog/lib/omnibus.ts +406 -0
  420. package/src/modules/catalog/lib/omnibusBackfill.ts +198 -0
  421. package/src/modules/catalog/lib/omnibusCache.ts +111 -0
  422. package/src/modules/catalog/lib/omnibusConfig.ts +73 -0
  423. package/src/modules/catalog/lib/omnibusHistoryQueries.ts +248 -0
  424. package/src/modules/catalog/lib/omnibusPresentedEntry.ts +76 -0
  425. package/src/modules/catalog/lib/omnibusProductListEnrichment.ts +125 -0
  426. package/src/modules/catalog/lib/omnibusTypes.ts +202 -0
  427. package/src/modules/catalog/lib/optionSchemaTranslations.ts +55 -0
  428. package/src/modules/catalog/lib/priceHistoryQuery.ts +155 -0
  429. package/src/modules/catalog/lib/pricing.ts +42 -4
  430. package/src/modules/catalog/lib/productFilters.ts +349 -0
  431. package/src/modules/catalog/lib/productScopeKeys.ts +162 -0
  432. package/src/modules/catalog/lib/productScopeReindex.ts +139 -0
  433. package/src/modules/catalog/migrations/.snapshot-open-mercato.json +572 -0
  434. package/src/modules/catalog/migrations/Migration20261005105352_catalog.ts +39 -0
  435. package/src/modules/catalog/migrations/Migration20261005150824_catalog.ts +39 -0
  436. package/src/modules/catalog/services/catalogOmnibusService.ts +642 -0
  437. package/src/modules/catalog/setup.ts +2 -0
  438. package/src/modules/catalog/subscribers/product-scope-keys-category-deleted.ts +18 -0
  439. package/src/modules/catalog/subscribers/product-scope-keys-category-updated.ts +19 -0
  440. package/src/modules/catalog/translations.ts +12 -0
  441. package/src/modules/configs/i18n/de.json +5 -1
  442. package/src/modules/configs/i18n/en.json +5 -1
  443. package/src/modules/configs/i18n/es.json +5 -1
  444. package/src/modules/configs/i18n/ko.json +5 -1
  445. package/src/modules/configs/i18n/pl.json +5 -1
  446. package/src/modules/configs/lib/upgrade-actions.ts +35 -0
  447. package/src/modules/customer_groups/api/customer-groups/[id]/terms/route.ts +7 -0
  448. package/src/modules/customer_groups/components/CustomerGroupTermsSection.tsx +124 -2
  449. package/src/modules/customer_groups/components/customerGroupAssortmentScope.ts +46 -0
  450. package/src/modules/customer_groups/data/entities.ts +4 -0
  451. package/src/modules/customer_groups/data/validators.ts +14 -0
  452. package/src/modules/customer_groups/i18n/de.json +12 -0
  453. package/src/modules/customer_groups/i18n/en.json +12 -0
  454. package/src/modules/customer_groups/i18n/es.json +12 -0
  455. package/src/modules/customer_groups/i18n/ko.json +12 -0
  456. package/src/modules/customer_groups/i18n/pl.json +12 -0
  457. package/src/modules/customer_groups/migrations/.snapshot-open-mercato.json +17 -0
  458. package/src/modules/customer_groups/migrations/Migration20261005110250_customer_groups.ts +15 -0
  459. package/src/modules/customer_groups/services/customerGroupsService.ts +74 -23
  460. package/src/modules/ecommerce/acl.ts +9 -0
  461. package/src/modules/ecommerce/api/domain-mappings/route.ts +76 -0
  462. package/src/modules/ecommerce/api/openapi.ts +28 -0
  463. package/src/modules/ecommerce/api/store-channel-bindings/[id]/assortment-count/route.ts +141 -0
  464. package/src/modules/ecommerce/api/store-channel-bindings/crud.ts +283 -0
  465. package/src/modules/ecommerce/api/store-channel-bindings/route.ts +67 -0
  466. package/src/modules/ecommerce/api/store-domain-bindings/crud.ts +324 -0
  467. package/src/modules/ecommerce/api/store-domain-bindings/route.ts +73 -0
  468. package/src/modules/ecommerce/api/storefront/categories/[slug]/route.ts +94 -0
  469. package/src/modules/ecommerce/api/storefront/categories/openapiSchemas.ts +63 -0
  470. package/src/modules/ecommerce/api/storefront/categories/route.ts +78 -0
  471. package/src/modules/ecommerce/api/storefront/context/route.ts +203 -0
  472. package/src/modules/ecommerce/api/storefront/products/[idOrHandle]/route.ts +94 -0
  473. package/src/modules/ecommerce/api/storefront/products/openapiSchemas.ts +193 -0
  474. package/src/modules/ecommerce/api/storefront/products/route.ts +81 -0
  475. package/src/modules/ecommerce/api/storefront/search/suggest/openapiSchemas.ts +25 -0
  476. package/src/modules/ecommerce/api/storefront/search/suggest/route.ts +78 -0
  477. package/src/modules/ecommerce/api/storefront/storefrontRouteSupport.ts +68 -0
  478. package/src/modules/ecommerce/api/stores/[id]/branding/route.ts +205 -0
  479. package/src/modules/ecommerce/api/stores/[id]/preview-branding/route.ts +99 -0
  480. package/src/modules/ecommerce/api/stores/crud.ts +457 -0
  481. package/src/modules/ecommerce/api/stores/route.ts +66 -0
  482. package/src/modules/ecommerce/backend/config/ecommerce/[id]/page.meta.ts +12 -0
  483. package/src/modules/ecommerce/backend/config/ecommerce/[id]/page.tsx +5 -0
  484. package/src/modules/ecommerce/backend/config/ecommerce/page.meta.ts +12 -0
  485. package/src/modules/ecommerce/backend/config/ecommerce/page.tsx +5 -0
  486. package/src/modules/ecommerce/commands/stores.ts +154 -0
  487. package/src/modules/ecommerce/components/ChannelAssortmentCount.tsx +138 -0
  488. package/src/modules/ecommerce/components/ChannelBindingFormSections.tsx +40 -0
  489. package/src/modules/ecommerce/components/ChannelLookupPicker.tsx +5 -0
  490. package/src/modules/ecommerce/components/DomainStatusWarning.tsx +32 -0
  491. package/src/modules/ecommerce/components/StoreAvailabilityDefaultsSection.tsx +219 -0
  492. package/src/modules/ecommerce/components/StoreBrandingControls.tsx +73 -0
  493. package/src/modules/ecommerce/components/StoreBrandingPreview.tsx +77 -0
  494. package/src/modules/ecommerce/components/StoreBrandingTab.tsx +242 -0
  495. package/src/modules/ecommerce/components/StoreChannelBindingDialog.tsx +306 -0
  496. package/src/modules/ecommerce/components/StoreChannelsTab.tsx +375 -0
  497. package/src/modules/ecommerce/components/StoreCreateDialog.tsx +204 -0
  498. package/src/modules/ecommerce/components/StoreDomainBindingDialog.tsx +198 -0
  499. package/src/modules/ecommerce/components/StoreDomainsTab.tsx +426 -0
  500. package/src/modules/ecommerce/components/StoreEditPage.tsx +193 -0
  501. package/src/modules/ecommerce/components/StoreGeneralTab.tsx +189 -0
  502. package/src/modules/ecommerce/components/StoreListPage.tsx +326 -0
  503. package/src/modules/ecommerce/components/StoreSeoTab.tsx +152 -0
  504. package/src/modules/ecommerce/components/StoreStatusBadge.tsx +22 -0
  505. package/src/modules/ecommerce/components/channelLookups.ts +24 -0
  506. package/src/modules/ecommerce/components/storeAdmin.ts +56 -0
  507. package/src/modules/ecommerce/components/storeBrandingForm.ts +230 -0
  508. package/src/modules/ecommerce/components/storeChannels.ts +210 -0
  509. package/src/modules/ecommerce/components/storeDomains.ts +221 -0
  510. package/src/modules/ecommerce/components/storeEditTabs.tsx +76 -0
  511. package/src/modules/ecommerce/components/storeGeneral.ts +155 -0
  512. package/src/modules/ecommerce/components/storeSeo.ts +78 -0
  513. package/src/modules/ecommerce/components/useChannelAssortmentCount.ts +67 -0
  514. package/src/modules/ecommerce/components/useStoreAccess.ts +36 -0
  515. package/src/modules/ecommerce/data/enrichers.ts +213 -0
  516. package/src/modules/ecommerce/data/entities.ts +168 -0
  517. package/src/modules/ecommerce/data/validators.ts +587 -0
  518. package/src/modules/ecommerce/di.ts +9 -0
  519. package/src/modules/ecommerce/events.ts +27 -0
  520. package/src/modules/ecommerce/i18n/de.json +341 -0
  521. package/src/modules/ecommerce/i18n/en.json +341 -0
  522. package/src/modules/ecommerce/i18n/es.json +341 -0
  523. package/src/modules/ecommerce/i18n/ko.json +341 -0
  524. package/src/modules/ecommerce/i18n/pl.json +341 -0
  525. package/src/modules/ecommerce/index.ts +14 -0
  526. package/src/modules/ecommerce/lib/assortmentCount.ts +175 -0
  527. package/src/modules/ecommerce/lib/brandingStyles.ts +215 -0
  528. package/src/modules/ecommerce/lib/buyerContext.ts +401 -0
  529. package/src/modules/ecommerce/lib/cacheInvalidation.ts +302 -0
  530. package/src/modules/ecommerce/lib/cacheKeys.ts +340 -0
  531. package/src/modules/ecommerce/lib/createConflictRecheck.ts +31 -0
  532. package/src/modules/ecommerce/lib/crudEvents.ts +128 -0
  533. package/src/modules/ecommerce/lib/crudSupport.ts +85 -0
  534. package/src/modules/ecommerce/lib/domainBindingRebind.ts +138 -0
  535. package/src/modules/ecommerce/lib/domainMappingSummaries.ts +71 -0
  536. package/src/modules/ecommerce/lib/exclusiveFlag.ts +90 -0
  537. package/src/modules/ecommerce/lib/references.ts +93 -0
  538. package/src/modules/ecommerce/lib/seedDraftStore.ts +125 -0
  539. package/src/modules/ecommerce/lib/storeBindingCascade.ts +138 -0
  540. package/src/modules/ecommerce/lib/storeBranding.ts +48 -0
  541. package/src/modules/ecommerce/lib/storeBrandingRoute.ts +91 -0
  542. package/src/modules/ecommerce/lib/storeContext.ts +669 -0
  543. package/src/modules/ecommerce/lib/storeContextService.ts +71 -0
  544. package/src/modules/ecommerce/lib/storeLocale.ts +88 -0
  545. package/src/modules/ecommerce/lib/storeNotifications.ts +55 -0
  546. package/src/modules/ecommerce/lib/storefrontCatalogSupport.ts +427 -0
  547. package/src/modules/ecommerce/lib/storefrontCategories.ts +419 -0
  548. package/src/modules/ecommerce/lib/storefrontCategoryCache.ts +113 -0
  549. package/src/modules/ecommerce/lib/storefrontDetail.ts +654 -0
  550. package/src/modules/ecommerce/lib/storefrontFacets.ts +697 -0
  551. package/src/modules/ecommerce/lib/storefrontOptionFilter.ts +44 -0
  552. package/src/modules/ecommerce/lib/storefrontPricing.ts +583 -0
  553. package/src/modules/ecommerce/lib/storefrontProductCache.ts +126 -0
  554. package/src/modules/ecommerce/lib/storefrontProductScope.ts +181 -0
  555. package/src/modules/ecommerce/lib/storefrontProducts.ts +963 -0
  556. package/src/modules/ecommerce/lib/storefrontQuery.ts +215 -0
  557. package/src/modules/ecommerce/lib/storefrontRateLimit.ts +126 -0
  558. package/src/modules/ecommerce/lib/storefrontSearch.ts +454 -0
  559. package/src/modules/ecommerce/lib/storefrontSearchCache.ts +49 -0
  560. package/src/modules/ecommerce/lib/subscriberSupport.ts +41 -0
  561. package/src/modules/ecommerce/lib/types.ts +69 -0
  562. package/src/modules/ecommerce/migrations/.snapshot-open-mercato.json +829 -0
  563. package/src/modules/ecommerce/migrations/Migration20261005113233_ecommerce.ts +32 -0
  564. package/src/modules/ecommerce/migrations/Migration20261006112733_ecommerce.ts +15 -0
  565. package/src/modules/ecommerce/notifications.client.ts +46 -0
  566. package/src/modules/ecommerce/notifications.ts +46 -0
  567. package/src/modules/ecommerce/search.ts +93 -0
  568. package/src/modules/ecommerce/setup.ts +15 -0
  569. package/src/modules/ecommerce/subscribers/assortment-empty-notifications.ts +12 -0
  570. package/src/modules/ecommerce/subscribers/availability-policy-cache-invalidation.ts +12 -0
  571. package/src/modules/ecommerce/subscribers/catalog-category-cache-invalidation.ts +12 -0
  572. package/src/modules/ecommerce/subscribers/catalog-price-cache-invalidation.ts +12 -0
  573. package/src/modules/ecommerce/subscribers/catalog-product-cache-invalidation.ts +12 -0
  574. package/src/modules/ecommerce/subscribers/catalog-variant-cache-invalidation.ts +12 -0
  575. package/src/modules/ecommerce/subscribers/customer-group-cache-invalidation.ts +12 -0
  576. package/src/modules/ecommerce/subscribers/customer-group-membership-cache-invalidation.ts +12 -0
  577. package/src/modules/ecommerce/subscribers/customer-group-terms-cache-invalidation.ts +12 -0
  578. package/src/modules/ecommerce/subscribers/customer-user-deleted-cache-invalidation.ts +12 -0
  579. package/src/modules/ecommerce/subscribers/customer-user-updated-cache-invalidation.ts +12 -0
  580. package/src/modules/ecommerce/subscribers/domain-binding-rebind.ts +14 -0
  581. package/src/modules/ecommerce/subscribers/domain-mapping-cache-invalidation.ts +12 -0
  582. package/src/modules/ecommerce/subscribers/store-cache-invalidation.ts +12 -0
  583. package/src/modules/ecommerce/subscribers/store-channel-binding-cache-invalidation.ts +12 -0
  584. package/src/modules/ecommerce/subscribers/store-domain-binding-cache-invalidation.ts +12 -0
  585. package/src/modules/ecommerce/subscribers/store-notifications.ts +12 -0
  586. package/src/modules/query_index/lib/batch.ts +25 -9
  587. package/src/modules/query_index/lib/doc-enrichers.ts +306 -0
  588. package/src/modules/query_index/lib/document.ts +2 -0
  589. package/src/modules/query_index/lib/engine.ts +58 -1
  590. package/src/modules/query_index/lib/indexer.ts +8 -0
  591. package/src/modules/query_index/lib/search-tokens.ts +2 -0
  592. package/src/modules/query_index/migrations/Migration20261005201500_query_index.ts +42 -0
  593. package/src/modules/translations/components/TranslationManager.tsx +3 -3
  594. package/src/modules/translations/data/validators.ts +1 -1
  595. package/src/modules/translations/lib/batch.ts +47 -0
  596. package/src/modules/translations/lib/helpers.ts +4 -0
  597. package/src/modules/translations/lib/resolve-field-list.ts +16 -2
@@ -1,11 +1,29 @@
1
1
  import { asFunction, asValue } from "awilix";
2
+ import { registerIndexDocEnricher } from "@open-mercato/core/modules/query_index/lib/doc-enrichers";
2
3
  import { DefaultCatalogPricingService } from "./services/catalogPricingService.js";
4
+ import { DefaultCatalogOmnibusService } from "./services/catalogOmnibusService.js";
3
5
  import { CatalogProduct, CatalogProductPrice, CatalogProductVariant } from "./data/entities.js";
6
+ import { catalogProductScopeKeysEnricher } from "./lib/productScopeKeys.js";
7
+ function softCradle(cradle, name) {
8
+ try {
9
+ const value = cradle[name];
10
+ return value === void 0 || value === null ? null : value;
11
+ } catch {
12
+ return null;
13
+ }
14
+ }
4
15
  function register(container) {
16
+ registerIndexDocEnricher(catalogProductScopeKeysEnricher);
5
17
  container.register({
6
18
  catalogPricingService: asFunction(({ eventBus }) => {
7
19
  return new DefaultCatalogPricingService(eventBus ?? null);
8
20
  }).singleton().proxy(),
21
+ catalogOmnibusService: asFunction((cradle) => {
22
+ return new DefaultCatalogOmnibusService(
23
+ softCradle(cradle, "moduleConfigService"),
24
+ softCradle(cradle, "cache")
25
+ );
26
+ }).scoped().proxy(),
9
27
  CatalogProduct: asValue(CatalogProduct),
10
28
  CatalogProductPrice: asValue(CatalogProductPrice),
11
29
  CatalogProductVariant: asValue(CatalogProductVariant)
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/modules/catalog/di.ts"],
4
- "sourcesContent": ["import { asFunction, asValue } from 'awilix'\nimport type { EventBus } from '@open-mercato/events'\nimport type { AppContainer } from '@open-mercato/shared/lib/di/container'\nimport { DefaultCatalogPricingService } from './services/catalogPricingService'\nimport { CatalogProduct, CatalogProductPrice, CatalogProductVariant } from './data/entities'\n\ntype AppCradle = AppContainer['cradle'] & {\n eventBus?: EventBus | null\n}\n\nexport function register(container: AppContainer) {\n container.register({\n catalogPricingService: asFunction(({ eventBus }: AppCradle) => {\n return new DefaultCatalogPricingService(eventBus ?? null)\n })\n .singleton()\n .proxy(),\n CatalogProduct: asValue(CatalogProduct),\n CatalogProductPrice: asValue(CatalogProductPrice),\n CatalogProductVariant: asValue(CatalogProductVariant),\n })\n}\n"],
5
- "mappings": "AAAA,SAAS,YAAY,eAAe;AAGpC,SAAS,oCAAoC;AAC7C,SAAS,gBAAgB,qBAAqB,6BAA6B;AAMpE,SAAS,SAAS,WAAyB;AAChD,YAAU,SAAS;AAAA,IACjB,uBAAuB,WAAW,CAAC,EAAE,SAAS,MAAiB;AAC7D,aAAO,IAAI,6BAA6B,YAAY,IAAI;AAAA,IAC1D,CAAC,EACE,UAAU,EACV,MAAM;AAAA,IACT,gBAAgB,QAAQ,cAAc;AAAA,IACtC,qBAAqB,QAAQ,mBAAmB;AAAA,IAChD,uBAAuB,QAAQ,qBAAqB;AAAA,EACtD,CAAC;AACH;",
4
+ "sourcesContent": ["import { asFunction, asValue } from 'awilix'\nimport type { CacheStrategy } from '@open-mercato/cache'\nimport type { EventBus } from '@open-mercato/events'\nimport type { AppContainer } from '@open-mercato/shared/lib/di/container'\nimport type { ModuleConfigService } from '@open-mercato/core/modules/configs/lib/module-config-service'\nimport { registerIndexDocEnricher } from '@open-mercato/core/modules/query_index/lib/doc-enrichers'\nimport { DefaultCatalogPricingService } from './services/catalogPricingService'\nimport { DefaultCatalogOmnibusService } from './services/catalogOmnibusService'\nimport { CatalogProduct, CatalogProductPrice, CatalogProductVariant } from './data/entities'\nimport { catalogProductScopeKeysEnricher } from './lib/productScopeKeys'\n\ntype AppCradle = AppContainer['cradle'] & {\n eventBus?: EventBus | null\n}\n\nfunction softCradle<T>(cradle: AppCradle, name: string): T | null {\n try {\n const value = (cradle as Record<string, unknown>)[name]\n return value === undefined || value === null ? null : (value as T)\n } catch {\n return null\n }\n}\n\nexport function register(container: AppContainer) {\n registerIndexDocEnricher(catalogProductScopeKeysEnricher)\n container.register({\n catalogPricingService: asFunction(({ eventBus }: AppCradle) => {\n return new DefaultCatalogPricingService(eventBus ?? null)\n })\n .singleton()\n .proxy(),\n catalogOmnibusService: asFunction((cradle: AppCradle) => {\n return new DefaultCatalogOmnibusService(\n softCradle<ModuleConfigService>(cradle, 'moduleConfigService'),\n softCradle<CacheStrategy>(cradle, 'cache'),\n )\n })\n .scoped()\n .proxy(),\n CatalogProduct: asValue(CatalogProduct),\n CatalogProductPrice: asValue(CatalogProductPrice),\n CatalogProductVariant: asValue(CatalogProductVariant),\n })\n}\n"],
5
+ "mappings": "AAAA,SAAS,YAAY,eAAe;AAKpC,SAAS,gCAAgC;AACzC,SAAS,oCAAoC;AAC7C,SAAS,oCAAoC;AAC7C,SAAS,gBAAgB,qBAAqB,6BAA6B;AAC3E,SAAS,uCAAuC;AAMhD,SAAS,WAAc,QAAmB,MAAwB;AAChE,MAAI;AACF,UAAM,QAAS,OAAmC,IAAI;AACtD,WAAO,UAAU,UAAa,UAAU,OAAO,OAAQ;AAAA,EACzD,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEO,SAAS,SAAS,WAAyB;AAChD,2BAAyB,+BAA+B;AACxD,YAAU,SAAS;AAAA,IACjB,uBAAuB,WAAW,CAAC,EAAE,SAAS,MAAiB;AAC7D,aAAO,IAAI,6BAA6B,YAAY,IAAI;AAAA,IAC1D,CAAC,EACE,UAAU,EACV,MAAM;AAAA,IACT,uBAAuB,WAAW,CAAC,WAAsB;AACvD,aAAO,IAAI;AAAA,QACT,WAAgC,QAAQ,qBAAqB;AAAA,QAC7D,WAA0B,QAAQ,OAAO;AAAA,MAC3C;AAAA,IACF,CAAC,EACE,OAAO,EACP,MAAM;AAAA,IACT,gBAAgB,QAAQ,cAAc;AAAA,IACtC,qBAAqB,QAAQ,mBAAmB;AAAA,IAChD,uBAAuB,QAAQ,qBAAqB;AAAA,EACtD,CAAC;AACH;",
6
6
  "names": []
7
7
  }
@@ -0,0 +1,285 @@
1
+ import { createHash } from "node:crypto";
2
+ import { isUniqueViolation } from "@open-mercato/shared/lib/crud/errors";
3
+ import { createLogger } from "@open-mercato/shared/lib/logger";
4
+ import { getTelemetryRuntime } from "@open-mercato/shared/lib/telemetry/runtime";
5
+ import { CatalogPriceHistoryEntry } from "../data/entities.js";
6
+ import { invalidateOmnibusCache } from "./omnibusCache.js";
7
+ const PRICE_HISTORY_IDEMPOTENCY_CONSTRAINT = "catalog_price_history_idempotency_uq";
8
+ const logger = createLogger("catalog");
9
+ async function invalidateOmnibusCacheForPrices(cache, prices) {
10
+ if (!cache) return;
11
+ const present = prices.filter((price) => Boolean(price));
12
+ if (!present.length) return;
13
+ await invalidateOmnibusCache(
14
+ cache,
15
+ present.map((price) => ({
16
+ tenantId: price.tenantId,
17
+ organizationId: price.organizationId,
18
+ productId: price.productId,
19
+ variantId: price.variantId,
20
+ offerId: price.offerId
21
+ }))
22
+ );
23
+ }
24
+ function isOmnibusTrackedPrice(price) {
25
+ return !price.customerId && !price.customerGroupId && !price.userId && !price.userGroupId && (price.minQuantity ?? 1) <= 1;
26
+ }
27
+ function normalizeDecimal(value) {
28
+ if (value === null || value === void 0) return null;
29
+ if (typeof value === "number") return value;
30
+ const trimmed = value.trim();
31
+ if (!trimmed.length) return null;
32
+ const numeric = Number(trimmed);
33
+ return Number.isNaN(numeric) ? trimmed : numeric;
34
+ }
35
+ function normalizeTimestamp(value) {
36
+ if (value === null || value === void 0) return null;
37
+ const date = value instanceof Date ? value : new Date(value);
38
+ const time = date.getTime();
39
+ return Number.isNaN(time) ? String(value) : time;
40
+ }
41
+ const PRICE_HISTORY_IDENTITY_FIELDS = [
42
+ "productId",
43
+ "variantId",
44
+ "offerId",
45
+ "channelId",
46
+ "priceKindId",
47
+ "currencyCode"
48
+ ];
49
+ const PRICE_HISTORY_DECIMAL_FIELDS = [
50
+ "unitPriceNet",
51
+ "unitPriceGross",
52
+ "taxRate",
53
+ "taxAmount",
54
+ "minQuantity",
55
+ "maxQuantity"
56
+ ];
57
+ const PRICE_HISTORY_TIMESTAMP_FIELDS = ["startsAt", "endsAt"];
58
+ function hasPriceHistoryRelevantChange(before, after) {
59
+ for (const field of PRICE_HISTORY_IDENTITY_FIELDS) {
60
+ if ((before[field] ?? null) !== (after[field] ?? null)) return true;
61
+ }
62
+ for (const field of PRICE_HISTORY_DECIMAL_FIELDS) {
63
+ if (normalizeDecimal(before[field]) !== normalizeDecimal(after[field])) return true;
64
+ }
65
+ for (const field of PRICE_HISTORY_TIMESTAMP_FIELDS) {
66
+ if (normalizeTimestamp(before[field]) !== normalizeTimestamp(after[field])) return true;
67
+ }
68
+ return isOmnibusTrackedPrice(before) !== isOmnibusTrackedPrice(after);
69
+ }
70
+ function buildPriceHistoryIdempotencyKey(priceId, changeType, recordedAt) {
71
+ return createHash("sha256").update(`${priceId}|${changeType}|${recordedAt.toISOString()}`).digest("hex");
72
+ }
73
+ function resolvePriceHistoryAnnounced(price, announce) {
74
+ return Boolean(price.startsAt) || Boolean(price.offerId) || announce === true;
75
+ }
76
+ function toDateOrNull(value) {
77
+ if (value === null || value === void 0) return null;
78
+ const date = value instanceof Date ? new Date(value.getTime()) : new Date(value);
79
+ if (Number.isNaN(date.getTime())) {
80
+ throw new Error(`[internal] Invalid price history date value: ${String(value)}`);
81
+ }
82
+ return date;
83
+ }
84
+ function buildHistoryEntry(price, changeType, options = {}) {
85
+ if (!price.productId) {
86
+ throw new Error("[internal] Price history entry requires a product id");
87
+ }
88
+ if (!price.priceKindId) {
89
+ throw new Error("[internal] Price history entry requires a price kind id");
90
+ }
91
+ const recordedAt = options.recordedAt ? new Date(options.recordedAt.getTime()) : /* @__PURE__ */ new Date();
92
+ const source = options.source ?? "api";
93
+ return {
94
+ tenantId: price.tenantId,
95
+ organizationId: price.organizationId,
96
+ priceId: price.id,
97
+ productId: price.productId,
98
+ variantId: price.variantId ?? null,
99
+ offerId: price.offerId ?? null,
100
+ channelId: price.channelId ?? null,
101
+ priceKindId: price.priceKindId,
102
+ priceKindCode: price.priceKindCode ?? "",
103
+ currencyCode: price.currencyCode,
104
+ unitPriceNet: price.unitPriceNet ?? null,
105
+ unitPriceGross: price.unitPriceGross ?? null,
106
+ taxRate: price.taxRate ?? null,
107
+ taxAmount: price.taxAmount ?? null,
108
+ minQuantity: price.minQuantity ?? null,
109
+ maxQuantity: price.maxQuantity ?? null,
110
+ startsAt: toDateOrNull(price.startsAt),
111
+ endsAt: toDateOrNull(price.endsAt),
112
+ recordedAt,
113
+ changeType,
114
+ source,
115
+ isAnnounced: resolvePriceHistoryAnnounced(price, options.announce),
116
+ idempotencyKey: source === "system" ? null : buildPriceHistoryIdempotencyKey(price.id, changeType, recordedAt),
117
+ metadata: options.metadata ?? null
118
+ };
119
+ }
120
+ function refId(ref) {
121
+ if (!ref) return null;
122
+ return typeof ref === "string" ? ref : ref.id ?? null;
123
+ }
124
+ function nestedProductId(ref) {
125
+ if (!ref || typeof ref !== "object") return null;
126
+ return refId(ref.product);
127
+ }
128
+ function priceHistoryInputFromRecord(record) {
129
+ const priceKind = record.priceKind;
130
+ const priceKindCode = priceKind && typeof priceKind === "object" && priceKind.code ? priceKind.code : record.kind;
131
+ return {
132
+ id: record.id,
133
+ tenantId: record.tenantId,
134
+ organizationId: record.organizationId,
135
+ productId: refId(record.product) ?? nestedProductId(record.variant) ?? nestedProductId(record.offer),
136
+ variantId: refId(record.variant),
137
+ offerId: refId(record.offer),
138
+ channelId: record.channelId ?? null,
139
+ priceKindId: refId(priceKind),
140
+ priceKindCode: priceKindCode ?? null,
141
+ currencyCode: record.currencyCode,
142
+ unitPriceNet: record.unitPriceNet ?? null,
143
+ unitPriceGross: record.unitPriceGross ?? null,
144
+ taxRate: record.taxRate ?? null,
145
+ taxAmount: record.taxAmount ?? null,
146
+ minQuantity: record.minQuantity ?? null,
147
+ maxQuantity: record.maxQuantity ?? null,
148
+ startsAt: record.startsAt ?? null,
149
+ endsAt: record.endsAt ?? null,
150
+ customerId: record.customerId ?? null,
151
+ customerGroupId: record.customerGroupId ?? null,
152
+ userId: record.userId ?? null,
153
+ userGroupId: record.userGroupId ?? null
154
+ };
155
+ }
156
+ async function recordPriceHistoryEntry(em, price, changeType, options = {}) {
157
+ const entry = buildHistoryEntry(price, changeType, options);
158
+ const historyEm = em.fork();
159
+ const row = historyEm.create(CatalogPriceHistoryEntry, entry);
160
+ historyEm.persist(row);
161
+ try {
162
+ await historyEm.flush();
163
+ } catch (err) {
164
+ if (entry.idempotencyKey && isUniqueViolation(err, PRICE_HISTORY_IDEMPOTENCY_CONSTRAINT)) {
165
+ return "duplicate";
166
+ }
167
+ throw err;
168
+ }
169
+ return "recorded";
170
+ }
171
+ async function closeUntrackedPriceHistory(em, previous, changeType, options) {
172
+ if (!previous || !isOmnibusTrackedPrice(previous)) return null;
173
+ return recordPriceHistoryEntry(em, previous, "delete", {
174
+ recordedAt: options.recordedAt,
175
+ source: options.source,
176
+ metadata: { ...options.metadata ?? {}, closedBy: changeType, reason: "untracked" }
177
+ });
178
+ }
179
+ async function capturePriceHistoryEntry(em, price, changeType, options = {}) {
180
+ if (!price) return null;
181
+ try {
182
+ const result = isOmnibusTrackedPrice(price) ? await recordPriceHistoryEntry(em, price, changeType, options) : await closeUntrackedPriceHistory(em, options.previous, changeType, options);
183
+ await invalidateOmnibusCacheForPrices(options.cache, [price, ...options.invalidatePrices ?? []]);
184
+ return result;
185
+ } catch (err) {
186
+ logger.error("[internal] catalog price history capture failed", {
187
+ priceId: price.id,
188
+ changeType,
189
+ tenantId: price.tenantId,
190
+ organizationId: price.organizationId,
191
+ err
192
+ });
193
+ getTelemetryRuntime()?.reportError(err, {
194
+ module: "catalog",
195
+ code: "catalog.price_history_capture_failed",
196
+ attributes: { priceId: price.id, changeType }
197
+ });
198
+ return null;
199
+ }
200
+ }
201
+ function uniquePricesById(prices) {
202
+ const seen = /* @__PURE__ */ new Set();
203
+ const unique = [];
204
+ for (const price of prices) {
205
+ if (seen.has(price.id)) continue;
206
+ seen.add(price.id);
207
+ unique.push(price);
208
+ }
209
+ return unique;
210
+ }
211
+ function isCompletePriceHistoryInput(price) {
212
+ return Boolean(price.productId && price.priceKindId);
213
+ }
214
+ async function recordPriceHistoryEntries(em, prices, changeType, options = {}) {
215
+ const tracked = uniquePricesById(prices.filter(isOmnibusTrackedPrice));
216
+ const unique = tracked.filter(isCompletePriceHistoryInput);
217
+ if (unique.length < tracked.length) {
218
+ const skipped = tracked.filter((price) => !isCompletePriceHistoryInput(price));
219
+ logger.warn("[internal] catalog price history skipped prices without a product or price kind", {
220
+ priceIds: skipped.map((price) => price.id),
221
+ changeType,
222
+ tenantId: skipped[0].tenantId,
223
+ organizationId: skipped[0].organizationId
224
+ });
225
+ }
226
+ if (!unique.length) return { recorded: 0, duplicates: 0 };
227
+ const batchOptions = { ...options, recordedAt: options.recordedAt ?? /* @__PURE__ */ new Date() };
228
+ const entries = unique.map((price) => buildHistoryEntry(price, changeType, batchOptions));
229
+ const historyEm = em.fork();
230
+ for (const entry of entries) {
231
+ historyEm.persist(historyEm.create(CatalogPriceHistoryEntry, entry));
232
+ }
233
+ try {
234
+ await historyEm.flush();
235
+ } catch (err) {
236
+ if (!isUniqueViolation(err, PRICE_HISTORY_IDEMPOTENCY_CONSTRAINT)) throw err;
237
+ let recorded = 0;
238
+ let duplicates = 0;
239
+ for (const price of unique) {
240
+ const result = await recordPriceHistoryEntry(em, price, changeType, batchOptions);
241
+ if (result === "duplicate") duplicates += 1;
242
+ else recorded += 1;
243
+ }
244
+ return { recorded, duplicates };
245
+ }
246
+ return { recorded: entries.length, duplicates: 0 };
247
+ }
248
+ async function capturePriceHistoryEntries(em, prices, changeType, options = {}) {
249
+ if (!prices || !prices.length) return null;
250
+ try {
251
+ const result = await recordPriceHistoryEntries(em, prices, changeType, options);
252
+ await invalidateOmnibusCacheForPrices(options.cache, [...prices, ...options.invalidatePrices ?? []]);
253
+ return result;
254
+ } catch (err) {
255
+ logger.error("[internal] catalog price history batch capture failed", {
256
+ priceIds: prices.map((price) => price.id),
257
+ changeType,
258
+ tenantId: prices[0].tenantId,
259
+ organizationId: prices[0].organizationId,
260
+ err
261
+ });
262
+ getTelemetryRuntime()?.reportError(err, {
263
+ module: "catalog",
264
+ code: "catalog.price_history_capture_failed",
265
+ attributes: { priceCount: prices.length, changeType }
266
+ });
267
+ return null;
268
+ }
269
+ }
270
+ export {
271
+ PRICE_HISTORY_IDEMPOTENCY_CONSTRAINT,
272
+ buildHistoryEntry,
273
+ buildPriceHistoryIdempotencyKey,
274
+ capturePriceHistoryEntries,
275
+ capturePriceHistoryEntry,
276
+ hasPriceHistoryRelevantChange,
277
+ invalidateOmnibusCacheForPrices,
278
+ isCompletePriceHistoryInput,
279
+ isOmnibusTrackedPrice,
280
+ priceHistoryInputFromRecord,
281
+ recordPriceHistoryEntries,
282
+ recordPriceHistoryEntry,
283
+ resolvePriceHistoryAnnounced
284
+ };
285
+ //# sourceMappingURL=omnibus.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/modules/catalog/lib/omnibus.ts"],
4
+ "sourcesContent": ["import { createHash } from 'node:crypto'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport type { CacheStrategy } from '@open-mercato/cache'\nimport { isUniqueViolation } from '@open-mercato/shared/lib/crud/errors'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\nimport { getTelemetryRuntime } from '@open-mercato/shared/lib/telemetry/runtime'\nimport { CatalogPriceHistoryEntry } from '../data/entities'\nimport type { CatalogPriceKind, CatalogProductPrice } from '../data/entities'\nimport type { PriceHistoryChangeType, PriceHistoryEntryInput, PriceHistorySource } from './omnibusTypes'\nimport { invalidateOmnibusCache } from './omnibusCache'\n\nexport const PRICE_HISTORY_IDEMPOTENCY_CONSTRAINT = 'catalog_price_history_idempotency_uq'\n\nconst logger = createLogger('catalog')\n\nexport type PriceHistoryPriceInput = {\n id: string\n tenantId: string\n organizationId: string\n productId: string | null\n variantId: string | null\n offerId: string | null\n channelId: string | null\n priceKindId: string | null\n priceKindCode: string | null\n currencyCode: string\n unitPriceNet: string | null\n unitPriceGross: string | null\n taxRate: string | null\n taxAmount: string | null\n minQuantity: number | null\n maxQuantity: number | null\n startsAt: Date | string | null\n endsAt: Date | string | null\n customerId?: string | null\n customerGroupId?: string | null\n userId?: string | null\n userGroupId?: string | null\n}\n\nexport type BuildHistoryEntryOptions = {\n recordedAt?: Date\n source?: PriceHistorySource\n announce?: boolean\n metadata?: Record<string, unknown> | null\n}\n\nexport type CapturePriceHistoryOptions = BuildHistoryEntryOptions & {\n cache?: CacheStrategy | null\n invalidatePrices?: Array<PriceHistoryPriceInput | null | undefined>\n previous?: PriceHistoryPriceInput | null\n}\n\nexport type RecordPriceHistoryResult = 'recorded' | 'duplicate'\n\n/**\n * Drops cached Omnibus references for every product/variant/offer scope the given prices touch.\n * Pass both the before- and after-state of a moved price so the old scope is not left stale.\n */\nexport async function invalidateOmnibusCacheForPrices(\n cache: CacheStrategy | null | undefined,\n prices: Array<PriceHistoryPriceInput | null | undefined>,\n): Promise<void> {\n if (!cache) return\n const present = prices.filter((price): price is PriceHistoryPriceInput => Boolean(price))\n if (!present.length) return\n await invalidateOmnibusCache(\n cache,\n present.map((price) => ({\n tenantId: price.tenantId,\n organizationId: price.organizationId,\n productId: price.productId,\n variantId: price.variantId,\n offerId: price.offerId,\n })),\n )\n}\n\n/**\n * A price feeds the public Omnibus reference only when it is addressed to the general public:\n * no customer, customer group, user, or user group individualization and no quantity tier above 1.\n */\nexport function isOmnibusTrackedPrice(\n price: Pick<PriceHistoryPriceInput, 'customerId' | 'customerGroupId' | 'userId' | 'userGroupId' | 'minQuantity'>,\n): boolean {\n return (\n !price.customerId &&\n !price.customerGroupId &&\n !price.userId &&\n !price.userGroupId &&\n (price.minQuantity ?? 1) <= 1\n )\n}\n\nfunction normalizeDecimal(value: string | number | null | undefined): string | number | null {\n if (value === null || value === undefined) return null\n if (typeof value === 'number') return value\n const trimmed = value.trim()\n if (!trimmed.length) return null\n const numeric = Number(trimmed)\n return Number.isNaN(numeric) ? trimmed : numeric\n}\n\nfunction normalizeTimestamp(value: Date | string | null | undefined): number | string | null {\n if (value === null || value === undefined) return null\n const date = value instanceof Date ? value : new Date(value)\n const time = date.getTime()\n return Number.isNaN(time) ? String(value) : time\n}\n\nconst PRICE_HISTORY_IDENTITY_FIELDS = [\n 'productId',\n 'variantId',\n 'offerId',\n 'channelId',\n 'priceKindId',\n 'currencyCode',\n] as const satisfies ReadonlyArray<keyof PriceHistoryPriceInput>\n\nconst PRICE_HISTORY_DECIMAL_FIELDS = [\n 'unitPriceNet',\n 'unitPriceGross',\n 'taxRate',\n 'taxAmount',\n 'minQuantity',\n 'maxQuantity',\n] as const satisfies ReadonlyArray<keyof PriceHistoryPriceInput>\n\nconst PRICE_HISTORY_TIMESTAMP_FIELDS = ['startsAt', 'endsAt'] as const satisfies ReadonlyArray<\n keyof PriceHistoryPriceInput\n>\n\n/**\n * True when an update changed anything the Omnibus history observes (scope, amounts, tiers, schedule\n * or tracked-ness). Decimals compare numerically and dates by instant, so re-saving an unchanged price\n * does not produce a fresh history row.\n */\nexport function hasPriceHistoryRelevantChange(before: PriceHistoryPriceInput, after: PriceHistoryPriceInput): boolean {\n for (const field of PRICE_HISTORY_IDENTITY_FIELDS) {\n if ((before[field] ?? null) !== (after[field] ?? null)) return true\n }\n for (const field of PRICE_HISTORY_DECIMAL_FIELDS) {\n if (normalizeDecimal(before[field]) !== normalizeDecimal(after[field])) return true\n }\n for (const field of PRICE_HISTORY_TIMESTAMP_FIELDS) {\n if (normalizeTimestamp(before[field]) !== normalizeTimestamp(after[field])) return true\n }\n return isOmnibusTrackedPrice(before) !== isOmnibusTrackedPrice(after)\n}\n\nexport function buildPriceHistoryIdempotencyKey(\n priceId: string,\n changeType: PriceHistoryChangeType,\n recordedAt: Date,\n): string {\n return createHash('sha256').update(`${priceId}|${changeType}|${recordedAt.toISOString()}`).digest('hex')\n}\n\nexport function resolvePriceHistoryAnnounced(\n price: Pick<PriceHistoryPriceInput, 'startsAt' | 'offerId'>,\n announce?: boolean,\n): boolean {\n return Boolean(price.startsAt) || Boolean(price.offerId) || announce === true\n}\n\nfunction toDateOrNull(value: Date | string | null | undefined): Date | null {\n if (value === null || value === undefined) return null\n const date = value instanceof Date ? new Date(value.getTime()) : new Date(value)\n if (Number.isNaN(date.getTime())) {\n throw new Error(`[internal] Invalid price history date value: ${String(value)}`)\n }\n return date\n}\n\nexport function buildHistoryEntry(\n price: PriceHistoryPriceInput,\n changeType: PriceHistoryChangeType,\n options: BuildHistoryEntryOptions = {},\n): PriceHistoryEntryInput {\n if (!price.productId) {\n throw new Error('[internal] Price history entry requires a product id')\n }\n if (!price.priceKindId) {\n throw new Error('[internal] Price history entry requires a price kind id')\n }\n const recordedAt = options.recordedAt ? new Date(options.recordedAt.getTime()) : new Date()\n const source: PriceHistorySource = options.source ?? 'api'\n return {\n tenantId: price.tenantId,\n organizationId: price.organizationId,\n priceId: price.id,\n productId: price.productId,\n variantId: price.variantId ?? null,\n offerId: price.offerId ?? null,\n channelId: price.channelId ?? null,\n priceKindId: price.priceKindId,\n priceKindCode: price.priceKindCode ?? '',\n currencyCode: price.currencyCode,\n unitPriceNet: price.unitPriceNet ?? null,\n unitPriceGross: price.unitPriceGross ?? null,\n taxRate: price.taxRate ?? null,\n taxAmount: price.taxAmount ?? null,\n minQuantity: price.minQuantity ?? null,\n maxQuantity: price.maxQuantity ?? null,\n startsAt: toDateOrNull(price.startsAt),\n endsAt: toDateOrNull(price.endsAt),\n recordedAt,\n changeType,\n source,\n isAnnounced: resolvePriceHistoryAnnounced(price, options.announce),\n idempotencyKey: source === 'system' ? null : buildPriceHistoryIdempotencyKey(price.id, changeType, recordedAt),\n metadata: options.metadata ?? null,\n }\n}\n\ntype EntityRef = string | { id: string } | null | undefined\n\nfunction refId(ref: EntityRef): string | null {\n if (!ref) return null\n return typeof ref === 'string' ? ref : ref.id ?? null\n}\n\nfunction nestedProductId(ref: unknown): string | null {\n if (!ref || typeof ref !== 'object') return null\n return refId((ref as { product?: EntityRef }).product)\n}\n\nexport function priceHistoryInputFromRecord(record: CatalogProductPrice): PriceHistoryPriceInput {\n const priceKind = record.priceKind as unknown as string | CatalogPriceKind | null | undefined\n const priceKindCode = priceKind && typeof priceKind === 'object' && priceKind.code ? priceKind.code : record.kind\n return {\n id: record.id,\n tenantId: record.tenantId,\n organizationId: record.organizationId,\n productId:\n refId(record.product as EntityRef) ?? nestedProductId(record.variant) ?? nestedProductId(record.offer),\n variantId: refId(record.variant as EntityRef),\n offerId: refId(record.offer as EntityRef),\n channelId: record.channelId ?? null,\n priceKindId: refId(priceKind),\n priceKindCode: priceKindCode ?? null,\n currencyCode: record.currencyCode,\n unitPriceNet: record.unitPriceNet ?? null,\n unitPriceGross: record.unitPriceGross ?? null,\n taxRate: record.taxRate ?? null,\n taxAmount: record.taxAmount ?? null,\n minQuantity: record.minQuantity ?? null,\n maxQuantity: record.maxQuantity ?? null,\n startsAt: record.startsAt ?? null,\n endsAt: record.endsAt ?? null,\n customerId: record.customerId ?? null,\n customerGroupId: record.customerGroupId ?? null,\n userId: record.userId ?? null,\n userGroupId: record.userGroupId ?? null,\n }\n}\n\nexport async function recordPriceHistoryEntry(\n em: EntityManager,\n price: PriceHistoryPriceInput,\n changeType: PriceHistoryChangeType,\n options: BuildHistoryEntryOptions = {},\n): Promise<RecordPriceHistoryResult> {\n const entry = buildHistoryEntry(price, changeType, options)\n const historyEm = em.fork()\n const row = historyEm.create(CatalogPriceHistoryEntry, entry)\n historyEm.persist(row)\n try {\n await historyEm.flush()\n } catch (err) {\n if (entry.idempotencyKey && isUniqueViolation(err, PRICE_HISTORY_IDEMPOTENCY_CONSTRAINT)) {\n return 'duplicate'\n }\n throw err\n }\n return 'recorded'\n}\n\nasync function closeUntrackedPriceHistory(\n em: EntityManager,\n previous: PriceHistoryPriceInput | null | undefined,\n changeType: PriceHistoryChangeType,\n options: BuildHistoryEntryOptions,\n): Promise<RecordPriceHistoryResult | null> {\n if (!previous || !isOmnibusTrackedPrice(previous)) return null\n return recordPriceHistoryEntry(em, previous, 'delete', {\n recordedAt: options.recordedAt,\n source: options.source,\n metadata: { ...(options.metadata ?? {}), closedBy: changeType, reason: 'untracked' },\n })\n}\n\nexport async function capturePriceHistoryEntry(\n em: EntityManager,\n price: PriceHistoryPriceInput | null | undefined,\n changeType: PriceHistoryChangeType,\n options: CapturePriceHistoryOptions = {},\n): Promise<RecordPriceHistoryResult | null> {\n if (!price) return null\n try {\n const result = isOmnibusTrackedPrice(price)\n ? await recordPriceHistoryEntry(em, price, changeType, options)\n : await closeUntrackedPriceHistory(em, options.previous, changeType, options)\n await invalidateOmnibusCacheForPrices(options.cache, [price, ...(options.invalidatePrices ?? [])])\n return result\n } catch (err) {\n logger.error('[internal] catalog price history capture failed', {\n priceId: price.id,\n changeType,\n tenantId: price.tenantId,\n organizationId: price.organizationId,\n err,\n })\n getTelemetryRuntime()?.reportError(err, {\n module: 'catalog',\n code: 'catalog.price_history_capture_failed',\n attributes: { priceId: price.id, changeType },\n })\n return null\n }\n}\n\nexport type RecordPriceHistoryBatchResult = { recorded: number; duplicates: number }\n\nfunction uniquePricesById(prices: PriceHistoryPriceInput[]): PriceHistoryPriceInput[] {\n const seen = new Set<string>()\n const unique: PriceHistoryPriceInput[] = []\n for (const price of prices) {\n if (seen.has(price.id)) continue\n seen.add(price.id)\n unique.push(price)\n }\n return unique\n}\n\nexport function isCompletePriceHistoryInput(price: PriceHistoryPriceInput): boolean {\n return Boolean(price.productId && price.priceKindId)\n}\n\nexport async function recordPriceHistoryEntries(\n em: EntityManager,\n prices: PriceHistoryPriceInput[],\n changeType: PriceHistoryChangeType,\n options: BuildHistoryEntryOptions = {},\n): Promise<RecordPriceHistoryBatchResult> {\n const tracked = uniquePricesById(prices.filter(isOmnibusTrackedPrice))\n const unique = tracked.filter(isCompletePriceHistoryInput)\n if (unique.length < tracked.length) {\n const skipped = tracked.filter((price) => !isCompletePriceHistoryInput(price))\n logger.warn('[internal] catalog price history skipped prices without a product or price kind', {\n priceIds: skipped.map((price) => price.id),\n changeType,\n tenantId: skipped[0].tenantId,\n organizationId: skipped[0].organizationId,\n })\n }\n if (!unique.length) return { recorded: 0, duplicates: 0 }\n const batchOptions: BuildHistoryEntryOptions = { ...options, recordedAt: options.recordedAt ?? new Date() }\n const entries = unique.map((price) => buildHistoryEntry(price, changeType, batchOptions))\n const historyEm = em.fork()\n for (const entry of entries) {\n historyEm.persist(historyEm.create(CatalogPriceHistoryEntry, entry))\n }\n try {\n await historyEm.flush()\n } catch (err) {\n if (!isUniqueViolation(err, PRICE_HISTORY_IDEMPOTENCY_CONSTRAINT)) throw err\n let recorded = 0\n let duplicates = 0\n for (const price of unique) {\n const result = await recordPriceHistoryEntry(em, price, changeType, batchOptions)\n if (result === 'duplicate') duplicates += 1\n else recorded += 1\n }\n return { recorded, duplicates }\n }\n return { recorded: entries.length, duplicates: 0 }\n}\n\nexport async function capturePriceHistoryEntries(\n em: EntityManager,\n prices: PriceHistoryPriceInput[] | null | undefined,\n changeType: PriceHistoryChangeType,\n options: CapturePriceHistoryOptions = {},\n): Promise<RecordPriceHistoryBatchResult | null> {\n if (!prices || !prices.length) return null\n try {\n const result = await recordPriceHistoryEntries(em, prices, changeType, options)\n await invalidateOmnibusCacheForPrices(options.cache, [...prices, ...(options.invalidatePrices ?? [])])\n return result\n } catch (err) {\n logger.error('[internal] catalog price history batch capture failed', {\n priceIds: prices.map((price) => price.id),\n changeType,\n tenantId: prices[0].tenantId,\n organizationId: prices[0].organizationId,\n err,\n })\n getTelemetryRuntime()?.reportError(err, {\n module: 'catalog',\n code: 'catalog.price_history_capture_failed',\n attributes: { priceCount: prices.length, changeType },\n })\n return null\n }\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,146 @@
1
+ import { findWithDecryption } from "@open-mercato/shared/lib/encryption/find";
2
+ import { CatalogPriceHistoryEntry, CatalogProductPrice } from "../data/entities.js";
3
+ import { omnibusBackfillOptionsSchema } from "../data/validators.js";
4
+ import {
5
+ isCompletePriceHistoryInput,
6
+ isOmnibusTrackedPrice,
7
+ priceHistoryInputFromRecord,
8
+ recordPriceHistoryEntries
9
+ } from "./omnibus.js";
10
+ import { invalidateOmnibusTenantCache } from "./omnibusCache.js";
11
+ import { listInScopeOmnibusChannels } from "./omnibusConfig.js";
12
+ import {
13
+ OMNIBUS_CONFIG_MODULE_ID,
14
+ OMNIBUS_CONFIG_NAME,
15
+ omnibusConfigSchema
16
+ } from "./omnibusTypes.js";
17
+ const DAY_MS = 24 * 60 * 60 * 1e3;
18
+ const OMNIBUS_UNSCOPED_COVERAGE_KEY = "";
19
+ async function readOmnibusConfig(service, tenantId) {
20
+ const raw = await service.getValue(OMNIBUS_CONFIG_MODULE_ID, OMNIBUS_CONFIG_NAME, { scope: { tenantId } });
21
+ if (raw === null || raw === void 0) return null;
22
+ const parsed = omnibusConfigSchema.safeParse(raw);
23
+ if (!parsed.success) {
24
+ throw new Error("[internal] Stored catalog omnibus config is invalid; fix it before running the backfill");
25
+ }
26
+ return parsed.data;
27
+ }
28
+ function resolveOmnibusBackfillTargets(config, options) {
29
+ if (options.channelId) {
30
+ const lookbackDays = config.channels[options.channelId]?.lookbackDays ?? config.lookbackDays;
31
+ return [{ coverageKey: options.channelId, channelId: options.channelId, lookbackDays }];
32
+ }
33
+ const channelTargets = listInScopeOmnibusChannels(config).map((channelId) => ({
34
+ coverageKey: channelId,
35
+ channelId,
36
+ lookbackDays: config.channels[channelId]?.lookbackDays ?? config.lookbackDays
37
+ }));
38
+ const unscopedLookbackDays = Math.max(config.lookbackDays, ...channelTargets.map((target) => target.lookbackDays));
39
+ const unscopedTarget = {
40
+ coverageKey: OMNIBUS_UNSCOPED_COVERAGE_KEY,
41
+ channelId: null,
42
+ lookbackDays: unscopedLookbackDays
43
+ };
44
+ if (options.unscoped) return [unscopedTarget];
45
+ return [...channelTargets, unscopedTarget];
46
+ }
47
+ async function backfillTarget(deps, scope, target, options) {
48
+ const windowStart = new Date(options.now.getTime() - target.lookbackDays * DAY_MS);
49
+ const recordedAt = new Date(windowStart.getTime() - 1);
50
+ const result = {
51
+ ...target,
52
+ recordedAt: recordedAt.toISOString(),
53
+ scanned: 0,
54
+ alreadyCovered: 0,
55
+ missing: 0,
56
+ created: 0,
57
+ skippedIncomplete: 0,
58
+ skippedUntracked: 0
59
+ };
60
+ const decryptionScope = { tenantId: scope.tenantId, organizationId: scope.organizationId };
61
+ const orgFilter = scope.organizationId ? { organizationId: scope.organizationId } : {};
62
+ let cursor = null;
63
+ for (; ; ) {
64
+ const batchEm = deps.em.fork();
65
+ const prices = await findWithDecryption(
66
+ batchEm,
67
+ CatalogProductPrice,
68
+ {
69
+ tenantId: scope.tenantId,
70
+ ...orgFilter,
71
+ channelId: target.channelId,
72
+ ...cursor ? { id: { $gt: cursor } } : {}
73
+ },
74
+ { populate: ["priceKind", "variant", "offer"], orderBy: { id: "asc" }, limit: options.batchSize },
75
+ decryptionScope
76
+ );
77
+ if (!prices.length) break;
78
+ cursor = prices[prices.length - 1].id;
79
+ result.scanned += prices.length;
80
+ const existing = await findWithDecryption(
81
+ batchEm,
82
+ CatalogPriceHistoryEntry,
83
+ { tenantId: scope.tenantId, ...orgFilter, priceId: { $in: prices.map((price) => price.id) } },
84
+ { fields: ["id", "priceId"] },
85
+ decryptionScope
86
+ );
87
+ const covered = new Set(existing.map((entry) => entry.priceId));
88
+ const uncovered = prices.filter((price) => !covered.has(price.id));
89
+ result.alreadyCovered += prices.length - uncovered.length;
90
+ const inputs = uncovered.map(priceHistoryInputFromRecord);
91
+ const tracked = inputs.filter(isOmnibusTrackedPrice);
92
+ result.skippedUntracked += inputs.length - tracked.length;
93
+ const complete = tracked.filter(isCompletePriceHistoryInput);
94
+ result.skippedIncomplete += tracked.length - complete.length;
95
+ result.missing += complete.length;
96
+ if (!options.dryRun && complete.length) {
97
+ const written = await recordPriceHistoryEntries(batchEm, complete, "create", { recordedAt, source: "system" });
98
+ result.created += written.recorded;
99
+ }
100
+ if (prices.length < options.batchSize) break;
101
+ }
102
+ return result;
103
+ }
104
+ async function recordBackfillCoverage(service, tenantId, targets, completedAt) {
105
+ const latest = await readOmnibusConfig(service, tenantId);
106
+ const coverage = { ...latest?.backfillCoverage ?? {} };
107
+ for (const target of targets) {
108
+ coverage[target.coverageKey] = { completedAt: completedAt.toISOString(), lookbackDays: target.lookbackDays };
109
+ }
110
+ const next = omnibusConfigSchema.parse({ ...latest ?? {}, backfillCoverage: coverage });
111
+ await service.setValue(OMNIBUS_CONFIG_MODULE_ID, OMNIBUS_CONFIG_NAME, next, { tenantId });
112
+ }
113
+ async function runOmnibusBackfill(deps, input) {
114
+ const options = omnibusBackfillOptionsSchema.parse(input);
115
+ const now = deps.now ?? /* @__PURE__ */ new Date();
116
+ const scope = { tenantId: options.tenantId, organizationId: options.organizationId ?? null };
117
+ const config = await readOmnibusConfig(deps.moduleConfigService, options.tenantId) ?? omnibusConfigSchema.parse({});
118
+ const targets = resolveOmnibusBackfillTargets(config, { channelId: options.channelId, unscoped: options.unscoped });
119
+ const results = [];
120
+ for (const target of targets) {
121
+ results.push(
122
+ await backfillTarget(deps, scope, target, { batchSize: options.batchSize, dryRun: options.dryRun, now })
123
+ );
124
+ }
125
+ if (options.dryRun) {
126
+ return { dryRun: true, tenantId: scope.tenantId, organizationId: scope.organizationId, targets: results, coverageRecorded: [] };
127
+ }
128
+ const recordsCoverage = scope.organizationId === null;
129
+ if (recordsCoverage) {
130
+ await recordBackfillCoverage(deps.moduleConfigService, options.tenantId, results, deps.now ?? /* @__PURE__ */ new Date());
131
+ }
132
+ await invalidateOmnibusTenantCache(deps.cache ?? null, options.tenantId);
133
+ return {
134
+ dryRun: false,
135
+ tenantId: scope.tenantId,
136
+ organizationId: scope.organizationId,
137
+ targets: results,
138
+ coverageRecorded: recordsCoverage ? results.map((target) => target.coverageKey) : []
139
+ };
140
+ }
141
+ export {
142
+ OMNIBUS_UNSCOPED_COVERAGE_KEY,
143
+ resolveOmnibusBackfillTargets,
144
+ runOmnibusBackfill
145
+ };
146
+ //# sourceMappingURL=omnibusBackfill.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/modules/catalog/lib/omnibusBackfill.ts"],
4
+ "sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport type { CacheStrategy } from '@open-mercato/cache'\nimport { findWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport type { ModuleConfigService } from '@open-mercato/core/modules/configs/lib/module-config-service'\nimport { CatalogPriceHistoryEntry, CatalogProductPrice } from '../data/entities'\nimport { omnibusBackfillOptionsSchema, type OmnibusBackfillOptionsInput } from '../data/validators'\nimport {\n isCompletePriceHistoryInput,\n isOmnibusTrackedPrice,\n priceHistoryInputFromRecord,\n recordPriceHistoryEntries,\n} from './omnibus'\nimport { invalidateOmnibusTenantCache } from './omnibusCache'\nimport { listInScopeOmnibusChannels } from './omnibusConfig'\nimport {\n OMNIBUS_CONFIG_MODULE_ID,\n OMNIBUS_CONFIG_NAME,\n omnibusConfigSchema,\n type OmnibusConfig,\n} from './omnibusTypes'\n\nconst DAY_MS = 24 * 60 * 60 * 1000\n\nexport const OMNIBUS_UNSCOPED_COVERAGE_KEY = ''\n\nexport type OmnibusBackfillDeps = {\n em: EntityManager\n moduleConfigService: ModuleConfigService\n cache?: CacheStrategy | null\n now?: Date\n}\n\nexport type OmnibusBackfillTarget = {\n coverageKey: string\n channelId: string | null\n lookbackDays: number\n}\n\nexport type OmnibusBackfillTargetResult = OmnibusBackfillTarget & {\n recordedAt: string\n scanned: number\n alreadyCovered: number\n missing: number\n created: number\n skippedIncomplete: number\n skippedUntracked: number\n}\n\nexport type OmnibusBackfillResult = {\n dryRun: boolean\n tenantId: string\n organizationId: string | null\n targets: OmnibusBackfillTargetResult[]\n coverageRecorded: string[]\n}\n\nasync function readOmnibusConfig(service: ModuleConfigService, tenantId: string): Promise<OmnibusConfig | null> {\n const raw = await service.getValue<unknown>(OMNIBUS_CONFIG_MODULE_ID, OMNIBUS_CONFIG_NAME, { scope: { tenantId } })\n if (raw === null || raw === undefined) return null\n const parsed = omnibusConfigSchema.safeParse(raw)\n if (!parsed.success) {\n throw new Error('[internal] Stored catalog omnibus config is invalid; fix it before running the backfill')\n }\n return parsed.data\n}\n\nexport function resolveOmnibusBackfillTargets(\n config: OmnibusConfig,\n options: { channelId?: string | null; unscoped?: boolean },\n): OmnibusBackfillTarget[] {\n if (options.channelId) {\n const lookbackDays = config.channels[options.channelId]?.lookbackDays ?? config.lookbackDays\n return [{ coverageKey: options.channelId, channelId: options.channelId, lookbackDays }]\n }\n const channelTargets = listInScopeOmnibusChannels(config).map((channelId) => ({\n coverageKey: channelId,\n channelId,\n lookbackDays: config.channels[channelId]?.lookbackDays ?? config.lookbackDays,\n }))\n const unscopedLookbackDays = Math.max(config.lookbackDays, ...channelTargets.map((target) => target.lookbackDays))\n const unscopedTarget: OmnibusBackfillTarget = {\n coverageKey: OMNIBUS_UNSCOPED_COVERAGE_KEY,\n channelId: null,\n lookbackDays: unscopedLookbackDays,\n }\n if (options.unscoped) return [unscopedTarget]\n return [...channelTargets, unscopedTarget]\n}\n\nasync function backfillTarget(\n deps: OmnibusBackfillDeps,\n scope: { tenantId: string; organizationId: string | null },\n target: OmnibusBackfillTarget,\n options: { batchSize: number; dryRun: boolean; now: Date },\n): Promise<OmnibusBackfillTargetResult> {\n const windowStart = new Date(options.now.getTime() - target.lookbackDays * DAY_MS)\n const recordedAt = new Date(windowStart.getTime() - 1)\n const result: OmnibusBackfillTargetResult = {\n ...target,\n recordedAt: recordedAt.toISOString(),\n scanned: 0,\n alreadyCovered: 0,\n missing: 0,\n created: 0,\n skippedIncomplete: 0,\n skippedUntracked: 0,\n }\n const decryptionScope = { tenantId: scope.tenantId, organizationId: scope.organizationId }\n const orgFilter = scope.organizationId ? { organizationId: scope.organizationId } : {}\n let cursor: string | null = null\n for (;;) {\n const batchEm = deps.em.fork()\n const prices: CatalogProductPrice[] = await findWithDecryption<CatalogProductPrice>(\n batchEm,\n CatalogProductPrice,\n {\n tenantId: scope.tenantId,\n ...orgFilter,\n channelId: target.channelId,\n ...(cursor ? { id: { $gt: cursor } } : {}),\n },\n { populate: ['priceKind', 'variant', 'offer'], orderBy: { id: 'asc' }, limit: options.batchSize },\n decryptionScope,\n )\n if (!prices.length) break\n cursor = prices[prices.length - 1].id\n result.scanned += prices.length\n const existing = await findWithDecryption<CatalogPriceHistoryEntry>(\n batchEm,\n CatalogPriceHistoryEntry,\n { tenantId: scope.tenantId, ...orgFilter, priceId: { $in: prices.map((price) => price.id) } },\n { fields: ['id', 'priceId'] },\n decryptionScope,\n )\n const covered = new Set(existing.map((entry) => entry.priceId))\n const uncovered = prices.filter((price) => !covered.has(price.id))\n result.alreadyCovered += prices.length - uncovered.length\n const inputs = uncovered.map(priceHistoryInputFromRecord)\n const tracked = inputs.filter(isOmnibusTrackedPrice)\n result.skippedUntracked += inputs.length - tracked.length\n const complete = tracked.filter(isCompletePriceHistoryInput)\n result.skippedIncomplete += tracked.length - complete.length\n result.missing += complete.length\n if (!options.dryRun && complete.length) {\n const written = await recordPriceHistoryEntries(batchEm, complete, 'create', { recordedAt, source: 'system' })\n result.created += written.recorded\n }\n if (prices.length < options.batchSize) break\n }\n return result\n}\n\nasync function recordBackfillCoverage(\n service: ModuleConfigService,\n tenantId: string,\n targets: OmnibusBackfillTargetResult[],\n completedAt: Date,\n): Promise<void> {\n const latest = await readOmnibusConfig(service, tenantId)\n const coverage = { ...(latest?.backfillCoverage ?? {}) }\n for (const target of targets) {\n coverage[target.coverageKey] = { completedAt: completedAt.toISOString(), lookbackDays: target.lookbackDays }\n }\n const next = omnibusConfigSchema.parse({ ...(latest ?? {}), backfillCoverage: coverage })\n await service.setValue(OMNIBUS_CONFIG_MODULE_ID, OMNIBUS_CONFIG_NAME, next, { tenantId })\n}\n\nexport async function runOmnibusBackfill(\n deps: OmnibusBackfillDeps,\n input: OmnibusBackfillOptionsInput,\n): Promise<OmnibusBackfillResult> {\n const options = omnibusBackfillOptionsSchema.parse(input)\n const now = deps.now ?? new Date()\n const scope = { tenantId: options.tenantId, organizationId: options.organizationId ?? null }\n const config = (await readOmnibusConfig(deps.moduleConfigService, options.tenantId)) ?? omnibusConfigSchema.parse({})\n const targets = resolveOmnibusBackfillTargets(config, { channelId: options.channelId, unscoped: options.unscoped })\n const results: OmnibusBackfillTargetResult[] = []\n for (const target of targets) {\n results.push(\n await backfillTarget(deps, scope, target, { batchSize: options.batchSize, dryRun: options.dryRun, now }),\n )\n }\n if (options.dryRun) {\n return { dryRun: true, tenantId: scope.tenantId, organizationId: scope.organizationId, targets: results, coverageRecorded: [] }\n }\n const recordsCoverage = scope.organizationId === null\n if (recordsCoverage) {\n await recordBackfillCoverage(deps.moduleConfigService, options.tenantId, results, deps.now ?? new Date())\n }\n await invalidateOmnibusTenantCache(deps.cache ?? null, options.tenantId)\n return {\n dryRun: false,\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n targets: results,\n coverageRecorded: recordsCoverage ? results.map((target) => target.coverageKey) : [],\n }\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,89 @@
1
+ import { runWithCacheTenant } from "@open-mercato/cache";
2
+ import { createLogger } from "@open-mercato/shared/lib/logger";
3
+ const OMNIBUS_CACHE_TTL_MS = 5 * 60 * 1e3;
4
+ const OMNIBUS_CACHE_PREFIX = "catalog:omnibus";
5
+ const logger = createLogger("catalog");
6
+ function resolveOmnibusCache(container) {
7
+ if (!container) return null;
8
+ try {
9
+ return container.resolve("cache") ?? null;
10
+ } catch {
11
+ return null;
12
+ }
13
+ }
14
+ function omnibusTenantWideTag(tenantId) {
15
+ return `${OMNIBUS_CACHE_PREFIX}:${tenantId}`;
16
+ }
17
+ function omnibusTenantTag(scope) {
18
+ return `${OMNIBUS_CACHE_PREFIX}:${scope.tenantId}:${scope.organizationId}`;
19
+ }
20
+ function omnibusTargetTags(scope, targets) {
21
+ const base = omnibusTenantTag(scope);
22
+ const tags = [];
23
+ if (targets.productId) tags.push(`${base}:product:${targets.productId}`);
24
+ if (targets.variantId) tags.push(`${base}:variant:${targets.variantId}`);
25
+ if (targets.offerId) tags.push(`${base}:offer:${targets.offerId}`);
26
+ return tags;
27
+ }
28
+ function buildOmnibusCacheTags(scope, targets) {
29
+ return [omnibusTenantWideTag(scope.tenantId), omnibusTenantTag(scope), ...omnibusTargetTags(scope, targets)];
30
+ }
31
+ function buildOmnibusCacheKey(kind, parts) {
32
+ return [OMNIBUS_CACHE_PREFIX, "v1", kind, ...parts.map((part) => part === null || part === void 0 ? "-" : String(part))].join(":");
33
+ }
34
+ async function readOmnibusCache(cache, tenantId, key) {
35
+ if (!cache) return null;
36
+ try {
37
+ const value = await runWithCacheTenant(tenantId, () => cache.get(key));
38
+ return value === null || value === void 0 ? null : value;
39
+ } catch {
40
+ return null;
41
+ }
42
+ }
43
+ async function writeOmnibusCache(cache, tenantId, key, value, tags) {
44
+ if (!cache) return;
45
+ try {
46
+ await runWithCacheTenant(tenantId, () => cache.set(key, value, { ttl: OMNIBUS_CACHE_TTL_MS, tags }));
47
+ } catch {
48
+ }
49
+ }
50
+ async function invalidateOmnibusCache(cache, targets) {
51
+ if (!cache || !targets.length) return;
52
+ const tagsByTenant = /* @__PURE__ */ new Map();
53
+ for (const target of targets) {
54
+ const tags = omnibusTargetTags(target, target);
55
+ if (!tags.length) continue;
56
+ const bucket = tagsByTenant.get(target.tenantId) ?? /* @__PURE__ */ new Set();
57
+ for (const tag of tags) bucket.add(tag);
58
+ tagsByTenant.set(target.tenantId, bucket);
59
+ }
60
+ for (const [tenantId, tags] of tagsByTenant) {
61
+ try {
62
+ await runWithCacheTenant(tenantId, () => cache.deleteByTags(Array.from(tags)));
63
+ } catch (err) {
64
+ logger.warn("[internal] catalog omnibus cache invalidation failed", { tenantId, err });
65
+ }
66
+ }
67
+ }
68
+ async function invalidateOmnibusTenantCache(cache, tenantId) {
69
+ if (!cache) return;
70
+ try {
71
+ await runWithCacheTenant(tenantId, () => cache.deleteByTags([omnibusTenantWideTag(tenantId)]));
72
+ } catch (err) {
73
+ logger.warn("[internal] catalog omnibus tenant cache invalidation failed", { tenantId, err });
74
+ }
75
+ }
76
+ export {
77
+ OMNIBUS_CACHE_TTL_MS,
78
+ buildOmnibusCacheKey,
79
+ buildOmnibusCacheTags,
80
+ invalidateOmnibusCache,
81
+ invalidateOmnibusTenantCache,
82
+ omnibusTargetTags,
83
+ omnibusTenantTag,
84
+ omnibusTenantWideTag,
85
+ readOmnibusCache,
86
+ resolveOmnibusCache,
87
+ writeOmnibusCache
88
+ };
89
+ //# sourceMappingURL=omnibusCache.js.map