@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
@@ -0,0 +1,303 @@
1
+ import { findWithDecryption } from "@open-mercato/shared/lib/encryption/find";
2
+ import { createLogger } from "@open-mercato/shared/lib/logger";
3
+ import { sanitizeSearchTerm } from "@open-mercato/shared/lib/query/sanitizeSearchTerm";
4
+ import { SortDir } from "@open-mercato/shared/lib/query/types";
5
+ import { resolveSearchConfig } from "@open-mercato/shared/lib/search/config";
6
+ import { tokenizeText } from "@open-mercato/shared/lib/search/tokenize";
7
+ import { getTelemetryRuntime } from "@open-mercato/shared/lib/telemetry/runtime";
8
+ import { E } from "../../../generated/entities.ids.generated.js";
9
+ import { CatalogProductVariant } from "@open-mercato/core/modules/catalog/data/entities";
10
+ import { scoreProductSearchRelevance } from "@open-mercato/core/modules/catalog/lib/productFilters";
11
+ import { compareCodeUnits } from "@open-mercato/core/modules/catalog/lib/productScopeKeys";
12
+ import {
13
+ ECOMMERCE_STOREFRONT_SUGGEST_MIN_QUERY_LENGTH
14
+ } from "../data/validators.js";
15
+ import {
16
+ STOREFRONT_CATEGORY_ENTITY_TYPE,
17
+ STOREFRONT_PRODUCT_ENTITY_TYPE,
18
+ loadStorefrontTranslations,
19
+ localeChain,
20
+ localize,
21
+ nonEmptyString,
22
+ referenceId,
23
+ resolvePublicDefaultMediaUrls,
24
+ resolveStorefrontAvailability,
25
+ storefrontAvailabilityKey,
26
+ toStorefrontAvailability,
27
+ tryResolve
28
+ } from "./storefrontCatalogSupport.js";
29
+ import { loadStorefrontVisibleCategories } from "./storefrontCategories.js";
30
+ import { resolveStorefrontPrices } from "./storefrontPricing.js";
31
+ import {
32
+ buildStorefrontProductScope,
33
+ buildStorefrontSearchIndexDocFilter,
34
+ composeStorefrontProductFilters
35
+ } from "./storefrontProductScope.js";
36
+ import { buildStorefrontProductFilterClause } from "./storefrontProducts.js";
37
+ const STOREFRONT_SEARCH_BACKEND_ENV = "OM_ECOMMERCE_STOREFRONT_SEARCH";
38
+ const STOREFRONT_SUGGEST_ILIKE_WINDOW = 100;
39
+ const AUTO_ORDER = ["tokens", "vector"];
40
+ const logger = createLogger("ecommerce").child({ component: "storefront-search" });
41
+ function readStorefrontSearchBackendPreference(value = process.env[STOREFRONT_SEARCH_BACKEND_ENV]) {
42
+ const token = value?.trim().toLowerCase();
43
+ if (token === "ilike" || token === "tokens" || token === "vector") return token;
44
+ return "auto";
45
+ }
46
+ function isStrategyRegistry(value) {
47
+ if (!value || typeof value !== "object") return false;
48
+ const candidate = value;
49
+ return typeof candidate.getStrategy === "function" && typeof candidate.isStrategyAvailable === "function";
50
+ }
51
+ function tokensCanRank(term) {
52
+ const config = resolveSearchConfig();
53
+ return config.enabled && tokenizeText(term, config).hashes.length > 0;
54
+ }
55
+ async function isAvailable(registry, strategyId) {
56
+ try {
57
+ return await registry.isStrategyAvailable(strategyId);
58
+ } catch {
59
+ return false;
60
+ }
61
+ }
62
+ async function selectStorefrontSearchBackend(container, term, preference = readStorefrontSearchBackendPreference()) {
63
+ if (preference === "ilike") return { backend: "ilike" };
64
+ const registry = tryResolve(container, "searchService");
65
+ if (!isStrategyRegistry(registry)) return { backend: "ilike" };
66
+ const order = preference === "auto" ? AUTO_ORDER : [preference];
67
+ for (const backend of order) {
68
+ if (backend === "ilike") continue;
69
+ const strategy = registry.getStrategy(backend);
70
+ if (!strategy || strategy.supportsIndexDocFilter !== true) continue;
71
+ if (backend === "tokens" && !tokensCanRank(term)) continue;
72
+ if (!await isAvailable(registry, backend)) continue;
73
+ return { backend, strategy };
74
+ }
75
+ return { backend: "ilike" };
76
+ }
77
+ function normalizeForMatch(value) {
78
+ return value.normalize("NFKD").replace(/[̀-ͯ]/g, "").toLowerCase();
79
+ }
80
+ function compareOrdered(left, right) {
81
+ return right.score - left.score || left.relevance - right.relevance || left.title.localeCompare(right.title) || compareCodeUnits(left.record.id, right.record.id);
82
+ }
83
+ async function rankWithStrategy(runtime, strategy, term, limit) {
84
+ const { ctx } = runtime;
85
+ const results = await strategy.search(term, {
86
+ tenantId: ctx.tenantId,
87
+ organizationId: ctx.organizationId,
88
+ entityTypes: [E.catalog.catalog_product],
89
+ limit,
90
+ indexDocFilter: buildStorefrontSearchIndexDocFilter(ctx)
91
+ });
92
+ const seen = /* @__PURE__ */ new Set();
93
+ const ranked = [];
94
+ for (const result of results) {
95
+ if (result.entityId !== E.catalog.catalog_product || seen.has(result.recordId)) continue;
96
+ seen.add(result.recordId);
97
+ ranked.push({ id: result.recordId, score: Number.isFinite(result.score) ? result.score : 0 });
98
+ }
99
+ return ranked.slice(0, limit);
100
+ }
101
+ async function rankWithIlike(runtime, term, limit) {
102
+ const { scope } = runtime;
103
+ const clause = await buildStorefrontProductFilterClause(runtime.container, runtime.ctx, { search: term });
104
+ const result = await runtime.queryEngine.query(E.catalog.catalog_product, {
105
+ tenantId: scope.tenantId,
106
+ organizationId: scope.organizationId,
107
+ withDeleted: scope.withDeleted,
108
+ filters: composeStorefrontProductFilters(scope, clause),
109
+ fields: ["id", "title", "sku"],
110
+ sort: [{ field: "title", dir: SortDir.Asc }],
111
+ page: { page: 1, pageSize: STOREFRONT_SUGGEST_ILIKE_WINDOW }
112
+ });
113
+ const needle = term.toLowerCase();
114
+ return result.items.filter((item) => typeof item.id === "string").map((record) => ({
115
+ record,
116
+ score: 0,
117
+ relevance: scoreProductSearchRelevance(needle, record.title, record.sku),
118
+ title: nonEmptyString(record.title) ?? ""
119
+ })).sort(compareOrdered).slice(0, limit).map((entry) => ({ id: entry.record.id, score: 0 }));
120
+ }
121
+ async function rankProducts(runtime, selection, term, limit) {
122
+ if (selection.backend === "ilike") return rankWithIlike(runtime, term, limit);
123
+ try {
124
+ return await rankWithStrategy(runtime, selection.strategy, term, limit);
125
+ } catch (err) {
126
+ logger.error("[internal] ecommerce storefront search backend failed; falling back to ILIKE", {
127
+ backend: selection.backend,
128
+ tenantId: runtime.ctx.tenantId,
129
+ storeId: runtime.ctx.store.id,
130
+ err
131
+ });
132
+ getTelemetryRuntime()?.reportError(err, {
133
+ module: "ecommerce",
134
+ code: "ecommerce.storefront_search_backend_failed",
135
+ attributes: { backend: selection.backend }
136
+ });
137
+ return rankWithIlike(runtime, term, limit);
138
+ }
139
+ }
140
+ async function loadProductsByIds(runtime, ids) {
141
+ if (!ids.length) return [];
142
+ const { scope } = runtime;
143
+ const result = await runtime.queryEngine.query(E.catalog.catalog_product, {
144
+ tenantId: scope.tenantId,
145
+ organizationId: scope.organizationId,
146
+ withDeleted: scope.withDeleted,
147
+ filters: composeStorefrontProductFilters(scope, { id: { $in: ids } }),
148
+ fields: ["id", "title", "sku", "handle", "default_media_id", "default_media_url"],
149
+ page: { page: 1, pageSize: ids.length }
150
+ });
151
+ return result.items.filter((item) => typeof item.id === "string");
152
+ }
153
+ async function loadVariantIds(runtime, productIds) {
154
+ const byProduct = /* @__PURE__ */ new Map();
155
+ if (!productIds.length) return byProduct;
156
+ const { ctx } = runtime;
157
+ const variants = await findWithDecryption(
158
+ runtime.em,
159
+ CatalogProductVariant,
160
+ {
161
+ tenantId: ctx.tenantId,
162
+ organizationId: ctx.organizationId,
163
+ deletedAt: null,
164
+ isActive: true,
165
+ product: { $in: productIds }
166
+ },
167
+ { fields: ["id", "product"] },
168
+ runtime.decryptionScope
169
+ );
170
+ for (const variant of variants) {
171
+ const productId = referenceId(variant.product);
172
+ if (!productId) continue;
173
+ byProduct.set(productId, [...byProduct.get(productId) ?? [], variant.id]);
174
+ }
175
+ return byProduct;
176
+ }
177
+ async function loadPricing(runtime, productIds) {
178
+ if (!productIds.length) return /* @__PURE__ */ new Map();
179
+ const variants = await loadVariantIds(runtime, productIds);
180
+ return resolveStorefrontPrices(
181
+ runtime.container,
182
+ runtime.ctx,
183
+ productIds.map((productId) => ({ productId, variantIds: variants.get(productId) ?? [] })),
184
+ { date: runtime.date }
185
+ );
186
+ }
187
+ async function loadHiddenProductIds(runtime, productIds) {
188
+ const hidden = /* @__PURE__ */ new Set();
189
+ if (!productIds.length) return hidden;
190
+ const targets = productIds.map((productId) => ({ productId, variantId: null }));
191
+ const resolved = await resolveStorefrontAvailability(runtime.container, runtime.ctx, runtime.em, targets);
192
+ for (const target of targets) {
193
+ const entry = resolved.get(storefrontAvailabilityKey(target));
194
+ if (entry?.policy?.hideWhenOutOfStock?.value !== true) continue;
195
+ if (toStorefrontAvailability(entry.result ?? null).state === "out_of_stock") hidden.add(target.productId);
196
+ }
197
+ return hidden;
198
+ }
199
+ function formattedPrice(pricing) {
200
+ return pricing?.price?.formatted ?? pricing?.priceRange?.formattedMin ?? null;
201
+ }
202
+ function matchCategories(categories, translations, locales, term, limit) {
203
+ const needle = normalizeForMatch(term);
204
+ const matches = [];
205
+ for (const row of categories.values()) {
206
+ const name = localize(row.name, translations?.get(row.id), "name", locales) ?? row.name;
207
+ const normalized = normalizeForMatch(name);
208
+ if (!normalized.includes(needle)) continue;
209
+ matches.push({
210
+ category: { id: row.id, name, slug: row.slug },
211
+ relevance: scoreProductSearchRelevance(needle, normalized, null)
212
+ });
213
+ }
214
+ return matches.sort(
215
+ (left, right) => left.relevance - right.relevance || left.category.name.localeCompare(right.category.name) || compareCodeUnits(left.category.id, right.category.id)
216
+ ).slice(0, limit).map((entry) => entry.category);
217
+ }
218
+ function emptyResponse(ctx) {
219
+ return { products: [], categories: [], suggestions: [], effectiveLocale: ctx.effectiveLocale };
220
+ }
221
+ function normalizeStorefrontSuggestTerm(q) {
222
+ const term = sanitizeSearchTerm(q).replace(/\s+/g, " ");
223
+ return Array.from(term).length >= ECOMMERCE_STOREFRONT_SUGGEST_MIN_QUERY_LENGTH ? term : "";
224
+ }
225
+ async function suggestStorefrontSearch(container, ctx, query, options = {}) {
226
+ const term = normalizeStorefrontSuggestTerm(query.q);
227
+ const assortment = ctx.buyer.assortmentScope;
228
+ if (!term || assortment !== null && assortment.length === 0) return emptyResponse(ctx);
229
+ const em = tryResolve(container, "em");
230
+ const queryEngine = tryResolve(container, "queryEngine");
231
+ if (!em || !queryEngine) throw new Error("[internal] ecommerce storefront search requires em and queryEngine");
232
+ const runtime = {
233
+ container,
234
+ ctx,
235
+ em,
236
+ queryEngine,
237
+ scope: buildStorefrontProductScope(ctx),
238
+ decryptionScope: { tenantId: ctx.tenantId, organizationId: ctx.organizationId },
239
+ date: options.date ?? /* @__PURE__ */ new Date()
240
+ };
241
+ const selection = await selectStorefrontSearchBackend(container, term, options.backendPreference);
242
+ const [ranked, categories] = await Promise.all([
243
+ rankProducts(runtime, selection, term, query.limit),
244
+ loadStorefrontVisibleCategories(runtime)
245
+ ]);
246
+ const rankedIds = ranked.map((entry) => entry.id);
247
+ const [records, translations, pricing, hidden] = await Promise.all([
248
+ loadProductsByIds(runtime, rankedIds),
249
+ loadStorefrontTranslations(em, ctx, [
250
+ { entityType: STOREFRONT_PRODUCT_ENTITY_TYPE, ids: rankedIds },
251
+ { entityType: STOREFRONT_CATEGORY_ENTITY_TYPE, ids: Array.from(categories.keys()) }
252
+ ]),
253
+ loadPricing(runtime, rankedIds),
254
+ loadHiddenProductIds(runtime, rankedIds)
255
+ ]);
256
+ const visibleRecords = records.filter((record) => !hidden.has(record.id));
257
+ const mediaUrls = await resolvePublicDefaultMediaUrls(
258
+ em,
259
+ ctx,
260
+ visibleRecords.map((record) => ({
261
+ id: record.id,
262
+ defaultMediaId: record.default_media_id,
263
+ defaultMediaUrl: record.default_media_url
264
+ }))
265
+ );
266
+ const locales = localeChain(ctx);
267
+ const productTranslations = translations.get(STOREFRONT_PRODUCT_ENTITY_TYPE);
268
+ const scores = new Map(ranked.map((entry) => [entry.id, entry.score]));
269
+ const needle = term.toLowerCase();
270
+ const products = visibleRecords.map((record) => ({
271
+ record,
272
+ score: scores.get(record.id) ?? 0,
273
+ relevance: scoreProductSearchRelevance(needle, record.title, record.sku),
274
+ title: nonEmptyString(record.title) ?? ""
275
+ })).sort(compareOrdered).map(({ record }) => ({
276
+ id: record.id,
277
+ handle: nonEmptyString(record.handle),
278
+ title: localize(record.title, productTranslations?.get(record.id), "title", locales) ?? "",
279
+ defaultMediaUrl: mediaUrls.get(record.id) ?? null,
280
+ formattedPrice: formattedPrice(pricing.get(record.id))
281
+ }));
282
+ return {
283
+ products,
284
+ categories: matchCategories(
285
+ categories,
286
+ translations.get(STOREFRONT_CATEGORY_ENTITY_TYPE),
287
+ locales,
288
+ term,
289
+ query.limit
290
+ ),
291
+ suggestions: [],
292
+ effectiveLocale: ctx.effectiveLocale
293
+ };
294
+ }
295
+ export {
296
+ STOREFRONT_SEARCH_BACKEND_ENV,
297
+ STOREFRONT_SUGGEST_ILIKE_WINDOW,
298
+ normalizeStorefrontSuggestTerm,
299
+ readStorefrontSearchBackendPreference,
300
+ selectStorefrontSearchBackend,
301
+ suggestStorefrontSearch
302
+ };
303
+ //# sourceMappingURL=storefrontSearch.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/modules/ecommerce/lib/storefrontSearch.ts"],
4
+ "sourcesContent": ["import type { AwilixContainer } from 'awilix'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport { findWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\nimport { sanitizeSearchTerm } from '@open-mercato/shared/lib/query/sanitizeSearchTerm'\nimport { SortDir, type QueryEngine } from '@open-mercato/shared/lib/query/types'\nimport { resolveSearchConfig } from '@open-mercato/shared/lib/search/config'\nimport { tokenizeText } from '@open-mercato/shared/lib/search/tokenize'\nimport { getTelemetryRuntime } from '@open-mercato/shared/lib/telemetry/runtime'\nimport type { SearchStrategy } from '@open-mercato/shared/modules/search'\nimport { E } from '#generated/entities.ids.generated'\nimport { CatalogProductVariant } from '@open-mercato/core/modules/catalog/data/entities'\nimport { scoreProductSearchRelevance } from '@open-mercato/core/modules/catalog/lib/productFilters'\nimport { compareCodeUnits } from '@open-mercato/core/modules/catalog/lib/productScopeKeys'\nimport {\n ECOMMERCE_STOREFRONT_SUGGEST_MIN_QUERY_LENGTH,\n type EcommerceStorefrontSearchSuggestQuery,\n} from '../data/validators'\nimport {\n STOREFRONT_CATEGORY_ENTITY_TYPE,\n STOREFRONT_PRODUCT_ENTITY_TYPE,\n loadStorefrontTranslations,\n localeChain,\n localize,\n nonEmptyString,\n referenceId,\n resolvePublicDefaultMediaUrls,\n resolveStorefrontAvailability,\n storefrontAvailabilityKey,\n toStorefrontAvailability,\n tryResolve,\n} from './storefrontCatalogSupport'\nimport { loadStorefrontVisibleCategories, type StorefrontVisibleCategory } from './storefrontCategories'\nimport { resolveStorefrontPrices, type StorefrontProductPricing } from './storefrontPricing'\nimport {\n buildStorefrontProductScope,\n buildStorefrontSearchIndexDocFilter,\n composeStorefrontProductFilters,\n type StorefrontProductScope,\n} from './storefrontProductScope'\nimport { buildStorefrontProductFilterClause } from './storefrontProducts'\nimport type { StoreContext } from './types'\n\n/**\n * `GET /search/suggest` (Storefront Public API rev 4 \u00A74.5, \u00A78).\n *\n * Products are ranked by one backend, chosen per request by `selectStorefrontSearchBackend`:\n * the `tokens` strategy or the `vector` strategy on the `pgvector` driver of `@open-mercato/search`\n * (D19), each receiving `buildStorefrontSearchIndexDocFilter` so the assortment scope is evaluated\n * inside the ranking query and a restricted buyer is never starved by out-of-scope hits (\u00A78.2,\n * R14); otherwise the Phase 1 `ILIKE` path (\u00A78.1) over the scoped catalogue. Meilisearch,\n * `chromadb` and `qdrant` cannot evaluate the scope and are never used. Whatever ranked them, the\n * products are re-read through `buildStorefrontProductScope`, priced for the buyer, and hidden when\n * their policy hides out-of-stock products, exactly like the listing page. The payload is the same\n * for every backend (\u00A78.3); facets are never computed.\n *\n * Categories match the localized name of the buyer's visible categories (the `/categories`\n * visibility rule) and are independent of the backend. `suggestions` stays empty in this phase.\n */\n\nexport type StorefrontSearchBackendPreference = 'auto' | 'ilike' | 'tokens' | 'vector'\n\nexport type StorefrontSearchBackend = 'ilike' | 'tokens' | 'vector'\n\nexport type StorefrontSearchBackendSelection =\n | { backend: 'ilike' }\n | { backend: 'tokens' | 'vector'; strategy: SearchStrategy }\n\nexport type StorefrontSearchSuggestProduct = {\n id: string\n handle: string | null\n title: string\n defaultMediaUrl: string | null\n formattedPrice: string | null\n}\n\nexport type StorefrontSearchSuggestCategory = { id: string; name: string; slug: string | null }\n\nexport type StorefrontSearchSuggestResponse = {\n products: StorefrontSearchSuggestProduct[]\n categories: StorefrontSearchSuggestCategory[]\n suggestions: string[]\n effectiveLocale: string\n}\n\nexport type SuggestStorefrontSearchOptions = {\n /** Overrides `OM_ECOMMERCE_STOREFRONT_SEARCH`; intended for tests. */\n backendPreference?: StorefrontSearchBackendPreference\n date?: Date\n}\n\n/** `auto` (default): `tokens`, then `pgvector`, then `ILIKE`; any other value forces that backend or `ILIKE`. */\nexport const STOREFRONT_SEARCH_BACKEND_ENV = 'OM_ECOMMERCE_STOREFRONT_SEARCH'\n\n/** `ILIKE` candidates read (title order) before relevance ranking picks the `limit` best. */\nexport const STOREFRONT_SUGGEST_ILIKE_WINDOW = 100\n\nconst AUTO_ORDER: readonly StorefrontSearchBackend[] = ['tokens', 'vector']\n\nconst logger = createLogger('ecommerce').child({ component: 'storefront-search' })\n\ntype StrategyRegistry = {\n getStrategy(strategyId: string): SearchStrategy | undefined\n isStrategyAvailable(strategyId: string): Promise<boolean>\n}\n\ntype Runtime = {\n container: AwilixContainer\n ctx: StoreContext\n em: EntityManager\n queryEngine: QueryEngine\n scope: StorefrontProductScope\n decryptionScope: { tenantId: string; organizationId: string }\n date: Date\n}\n\ntype RankedProduct = { id: string; score: number }\n\ntype ProductRecord = {\n id: string\n title?: string | null\n sku?: string | null\n handle?: string | null\n default_media_id?: string | null\n default_media_url?: string | null\n}\n\ntype OrderedProduct = { record: ProductRecord; score: number; relevance: number; title: string }\n\nexport function readStorefrontSearchBackendPreference(\n value: string | undefined = process.env[STOREFRONT_SEARCH_BACKEND_ENV],\n): StorefrontSearchBackendPreference {\n const token = value?.trim().toLowerCase()\n if (token === 'ilike' || token === 'tokens' || token === 'vector') return token\n return 'auto'\n}\n\nfunction isStrategyRegistry(value: unknown): value is StrategyRegistry {\n if (!value || typeof value !== 'object') return false\n const candidate = value as Partial<StrategyRegistry>\n return typeof candidate.getStrategy === 'function' && typeof candidate.isStrategyAvailable === 'function'\n}\n\nfunction tokensCanRank(term: string): boolean {\n const config = resolveSearchConfig()\n return config.enabled && tokenizeText(term, config).hashes.length > 0\n}\n\nasync function isAvailable(registry: StrategyRegistry, strategyId: string): Promise<boolean> {\n try {\n return await registry.isStrategyAvailable(strategyId)\n } catch {\n return false\n }\n}\n\n/**\n * The ranking backend for one search term (\u00A78.2, D19). A search strategy qualifies only when it is\n * registered, available and declares `supportsIndexDocFilter` \u2014 the `tokens` strategy, and the\n * `vector` strategy over `pgvector`; `tokens` additionally needs search enabled and a term that\n * tokenizes (shorter than the minimum token length it does not). Anything else is `ILIKE`.\n */\nexport async function selectStorefrontSearchBackend(\n container: AwilixContainer,\n term: string,\n preference: StorefrontSearchBackendPreference = readStorefrontSearchBackendPreference(),\n): Promise<StorefrontSearchBackendSelection> {\n if (preference === 'ilike') return { backend: 'ilike' }\n const registry = tryResolve<unknown>(container, 'searchService')\n if (!isStrategyRegistry(registry)) return { backend: 'ilike' }\n const order = preference === 'auto' ? AUTO_ORDER : [preference]\n for (const backend of order) {\n if (backend === 'ilike') continue\n const strategy = registry.getStrategy(backend)\n if (!strategy || strategy.supportsIndexDocFilter !== true) continue\n if (backend === 'tokens' && !tokensCanRank(term)) continue\n if (!(await isAvailable(registry, backend))) continue\n return { backend, strategy }\n }\n return { backend: 'ilike' }\n}\n\nfunction normalizeForMatch(value: string): string {\n return value.normalize('NFKD').replace(/[\u0300-\u036F]/g, '').toLowerCase()\n}\n\nfunction compareOrdered(left: OrderedProduct, right: OrderedProduct): number {\n return (\n right.score - left.score ||\n left.relevance - right.relevance ||\n left.title.localeCompare(right.title) ||\n compareCodeUnits(left.record.id, right.record.id)\n )\n}\n\nasync function rankWithStrategy(\n runtime: Runtime,\n strategy: SearchStrategy,\n term: string,\n limit: number,\n): Promise<RankedProduct[]> {\n const { ctx } = runtime\n const results = await strategy.search(term, {\n tenantId: ctx.tenantId,\n organizationId: ctx.organizationId,\n entityTypes: [E.catalog.catalog_product],\n limit,\n indexDocFilter: buildStorefrontSearchIndexDocFilter(ctx),\n })\n const seen = new Set<string>()\n const ranked: RankedProduct[] = []\n for (const result of results) {\n if (result.entityId !== E.catalog.catalog_product || seen.has(result.recordId)) continue\n seen.add(result.recordId)\n ranked.push({ id: result.recordId, score: Number.isFinite(result.score) ? result.score : 0 })\n }\n return ranked.slice(0, limit)\n}\n\nasync function rankWithIlike(runtime: Runtime, term: string, limit: number): Promise<RankedProduct[]> {\n const { scope } = runtime\n const clause = await buildStorefrontProductFilterClause(runtime.container, runtime.ctx, { search: term })\n const result = await runtime.queryEngine.query<ProductRecord>(E.catalog.catalog_product, {\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n withDeleted: scope.withDeleted,\n filters: composeStorefrontProductFilters(scope, clause),\n fields: ['id', 'title', 'sku'],\n sort: [{ field: 'title', dir: SortDir.Asc }],\n page: { page: 1, pageSize: STOREFRONT_SUGGEST_ILIKE_WINDOW },\n })\n const needle = term.toLowerCase()\n return result.items\n .filter((item) => typeof item.id === 'string')\n .map((record) => ({\n record,\n score: 0,\n relevance: scoreProductSearchRelevance(needle, record.title, record.sku),\n title: nonEmptyString(record.title) ?? '',\n }))\n .sort(compareOrdered)\n .slice(0, limit)\n .map((entry) => ({ id: entry.record.id, score: 0 }))\n}\n\nasync function rankProducts(\n runtime: Runtime,\n selection: StorefrontSearchBackendSelection,\n term: string,\n limit: number,\n): Promise<RankedProduct[]> {\n if (selection.backend === 'ilike') return rankWithIlike(runtime, term, limit)\n try {\n return await rankWithStrategy(runtime, selection.strategy, term, limit)\n } catch (err) {\n logger.error('[internal] ecommerce storefront search backend failed; falling back to ILIKE', {\n backend: selection.backend,\n tenantId: runtime.ctx.tenantId,\n storeId: runtime.ctx.store.id,\n err,\n })\n getTelemetryRuntime()?.reportError(err, {\n module: 'ecommerce',\n code: 'ecommerce.storefront_search_backend_failed',\n attributes: { backend: selection.backend },\n })\n return rankWithIlike(runtime, term, limit)\n }\n}\n\nasync function loadProductsByIds(runtime: Runtime, ids: string[]): Promise<ProductRecord[]> {\n if (!ids.length) return []\n const { scope } = runtime\n const result = await runtime.queryEngine.query<ProductRecord>(E.catalog.catalog_product, {\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n withDeleted: scope.withDeleted,\n filters: composeStorefrontProductFilters(scope, { id: { $in: ids } }),\n fields: ['id', 'title', 'sku', 'handle', 'default_media_id', 'default_media_url'],\n page: { page: 1, pageSize: ids.length },\n })\n return result.items.filter((item) => typeof item.id === 'string')\n}\n\nasync function loadVariantIds(runtime: Runtime, productIds: string[]): Promise<Map<string, string[]>> {\n const byProduct = new Map<string, string[]>()\n if (!productIds.length) return byProduct\n const { ctx } = runtime\n const variants = await findWithDecryption(\n runtime.em,\n CatalogProductVariant,\n {\n tenantId: ctx.tenantId,\n organizationId: ctx.organizationId,\n deletedAt: null,\n isActive: true,\n product: { $in: productIds },\n },\n { fields: ['id', 'product'] },\n runtime.decryptionScope,\n )\n for (const variant of variants) {\n const productId = referenceId(variant.product)\n if (!productId) continue\n byProduct.set(productId, [...(byProduct.get(productId) ?? []), variant.id])\n }\n return byProduct\n}\n\nasync function loadPricing(runtime: Runtime, productIds: string[]): Promise<Map<string, StorefrontProductPricing>> {\n if (!productIds.length) return new Map()\n const variants = await loadVariantIds(runtime, productIds)\n return resolveStorefrontPrices(\n runtime.container,\n runtime.ctx,\n productIds.map((productId) => ({ productId, variantIds: variants.get(productId) ?? [] })),\n { date: runtime.date },\n )\n}\n\nasync function loadHiddenProductIds(runtime: Runtime, productIds: string[]): Promise<Set<string>> {\n const hidden = new Set<string>()\n if (!productIds.length) return hidden\n const targets = productIds.map((productId) => ({ productId, variantId: null }))\n const resolved = await resolveStorefrontAvailability(runtime.container, runtime.ctx, runtime.em, targets)\n for (const target of targets) {\n const entry = resolved.get(storefrontAvailabilityKey(target))\n if (entry?.policy?.hideWhenOutOfStock?.value !== true) continue\n if (toStorefrontAvailability(entry.result ?? null).state === 'out_of_stock') hidden.add(target.productId)\n }\n return hidden\n}\n\nfunction formattedPrice(pricing: StorefrontProductPricing | undefined): string | null {\n return pricing?.price?.formatted ?? pricing?.priceRange?.formattedMin ?? null\n}\n\nfunction matchCategories(\n categories: Map<string, StorefrontVisibleCategory>,\n translations: Map<string, Record<string, Record<string, unknown>>> | undefined,\n locales: string[],\n term: string,\n limit: number,\n): StorefrontSearchSuggestCategory[] {\n const needle = normalizeForMatch(term)\n const matches: Array<{ category: StorefrontSearchSuggestCategory; relevance: number }> = []\n for (const row of categories.values()) {\n const name = localize(row.name, translations?.get(row.id), 'name', locales) ?? row.name\n const normalized = normalizeForMatch(name)\n if (!normalized.includes(needle)) continue\n matches.push({\n category: { id: row.id, name, slug: row.slug },\n relevance: scoreProductSearchRelevance(needle, normalized, null),\n })\n }\n return matches\n .sort(\n (left, right) =>\n left.relevance - right.relevance ||\n left.category.name.localeCompare(right.category.name) ||\n compareCodeUnits(left.category.id, right.category.id),\n )\n .slice(0, limit)\n .map((entry) => entry.category)\n}\n\nfunction emptyResponse(ctx: StoreContext): StorefrontSearchSuggestResponse {\n return { products: [], categories: [], suggestions: [], effectiveLocale: ctx.effectiveLocale }\n}\n\n/** The normalized term the suggest response is computed and cached for; `''` when shorter than the minimum. */\nexport function normalizeStorefrontSuggestTerm(q: string): string {\n const term = sanitizeSearchTerm(q).replace(/\\s+/g, ' ')\n return Array.from(term).length >= ECOMMERCE_STOREFRONT_SUGGEST_MIN_QUERY_LENGTH ? term : ''\n}\n\nexport async function suggestStorefrontSearch(\n container: AwilixContainer,\n ctx: StoreContext,\n query: Pick<EcommerceStorefrontSearchSuggestQuery, 'q' | 'limit'>,\n options: SuggestStorefrontSearchOptions = {},\n): Promise<StorefrontSearchSuggestResponse> {\n const term = normalizeStorefrontSuggestTerm(query.q)\n const assortment = ctx.buyer.assortmentScope\n if (!term || (assortment !== null && assortment.length === 0)) return emptyResponse(ctx)\n const em = tryResolve<EntityManager>(container, 'em')\n const queryEngine = tryResolve<QueryEngine>(container, 'queryEngine')\n if (!em || !queryEngine) throw new Error('[internal] ecommerce storefront search requires em and queryEngine')\n const runtime: Runtime = {\n container,\n ctx,\n em,\n queryEngine,\n scope: buildStorefrontProductScope(ctx),\n decryptionScope: { tenantId: ctx.tenantId, organizationId: ctx.organizationId },\n date: options.date ?? new Date(),\n }\n const selection = await selectStorefrontSearchBackend(container, term, options.backendPreference)\n const [ranked, categories] = await Promise.all([\n rankProducts(runtime, selection, term, query.limit),\n loadStorefrontVisibleCategories(runtime),\n ])\n const rankedIds = ranked.map((entry) => entry.id)\n const [records, translations, pricing, hidden] = await Promise.all([\n loadProductsByIds(runtime, rankedIds),\n loadStorefrontTranslations(em, ctx, [\n { entityType: STOREFRONT_PRODUCT_ENTITY_TYPE, ids: rankedIds },\n { entityType: STOREFRONT_CATEGORY_ENTITY_TYPE, ids: Array.from(categories.keys()) },\n ]),\n loadPricing(runtime, rankedIds),\n loadHiddenProductIds(runtime, rankedIds),\n ])\n const visibleRecords = records.filter((record) => !hidden.has(record.id))\n const mediaUrls = await resolvePublicDefaultMediaUrls(\n em,\n ctx,\n visibleRecords.map((record) => ({\n id: record.id,\n defaultMediaId: record.default_media_id,\n defaultMediaUrl: record.default_media_url,\n })),\n )\n const locales = localeChain(ctx)\n const productTranslations = translations.get(STOREFRONT_PRODUCT_ENTITY_TYPE)\n const scores = new Map(ranked.map((entry) => [entry.id, entry.score]))\n const needle = term.toLowerCase()\n const products = visibleRecords\n .map((record) => ({\n record,\n score: scores.get(record.id) ?? 0,\n relevance: scoreProductSearchRelevance(needle, record.title, record.sku),\n title: nonEmptyString(record.title) ?? '',\n }))\n .sort(compareOrdered)\n .map(({ record }) => ({\n id: record.id,\n handle: nonEmptyString(record.handle),\n title: localize(record.title, productTranslations?.get(record.id), 'title', locales) ?? '',\n defaultMediaUrl: mediaUrls.get(record.id) ?? null,\n formattedPrice: formattedPrice(pricing.get(record.id)),\n }))\n return {\n products,\n categories: matchCategories(\n categories,\n translations.get(STOREFRONT_CATEGORY_ENTITY_TYPE),\n locales,\n term,\n query.limit,\n ),\n suggestions: [],\n effectiveLocale: ctx.effectiveLocale,\n }\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,35 @@
1
+ import { catalogProductsTag, storefrontAvailabilityTag, storefrontCache, storefrontCacheValueHash } from "./cacheKeys.js";
2
+ import {
3
+ normalizeStorefrontSuggestTerm,
4
+ suggestStorefrontSearch
5
+ } from "./storefrontSearch.js";
6
+ const STOREFRONT_SEARCH_SUGGEST_TTL_MS = 3e4;
7
+ const SUGGEST_CACHE_SEGMENT = "search-suggest";
8
+ function storefrontSearchSuggestCacheParts(term, limit) {
9
+ return [SUGGEST_CACHE_SEGMENT, storefrontCacheValueHash({ term: term.toLowerCase(), limit })];
10
+ }
11
+ function storefrontSearchSuggestCacheTags(ctx) {
12
+ return [catalogProductsTag(ctx.tenantId), storefrontAvailabilityTag(ctx.tenantId)];
13
+ }
14
+ async function cachedSuggestStorefrontSearch(container, ctx, query) {
15
+ const term = normalizeStorefrontSuggestTerm(query.q);
16
+ if (!term) return suggestStorefrontSearch(container, ctx, query);
17
+ const cache = storefrontCache(container, ctx);
18
+ const parts = storefrontSearchSuggestCacheParts(term, query.limit);
19
+ const cached = await cache.get(parts, { scope: "digest" });
20
+ if (cached) return cached;
21
+ const response = await suggestStorefrontSearch(container, ctx, { q: term, limit: query.limit });
22
+ await cache.set(parts, response, {
23
+ scope: "digest",
24
+ ttlMs: STOREFRONT_SEARCH_SUGGEST_TTL_MS,
25
+ tags: storefrontSearchSuggestCacheTags(ctx)
26
+ });
27
+ return response;
28
+ }
29
+ export {
30
+ STOREFRONT_SEARCH_SUGGEST_TTL_MS,
31
+ cachedSuggestStorefrontSearch,
32
+ storefrontSearchSuggestCacheParts,
33
+ storefrontSearchSuggestCacheTags
34
+ };
35
+ //# sourceMappingURL=storefrontSearchCache.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/modules/ecommerce/lib/storefrontSearchCache.ts"],
4
+ "sourcesContent": ["import type { AwilixContainer } from 'awilix'\nimport type { EcommerceStorefrontSearchSuggestQuery } from '../data/validators'\nimport { catalogProductsTag, storefrontAvailabilityTag, storefrontCache, storefrontCacheValueHash } from './cacheKeys'\nimport {\n normalizeStorefrontSuggestTerm,\n suggestStorefrontSearch,\n type StorefrontSearchSuggestResponse,\n} from './storefrontSearch'\nimport type { StoreContext } from './types'\n\n/**\n * Server-side cache for `GET /search/suggest` (Storefront Public API rev 4 \u00A79): `formattedPrice` is\n * buyer-priced, so entries are keyed on the full `digest` plus the normalized term and `limit`.\n * They carry the tenant's `catalog-products` tag (every product, variant, category and price event)\n * and the availability tag (out-of-stock hiding). A term below the minimum length is answered\n * empty without touching the cache.\n */\n\nexport const STOREFRONT_SEARCH_SUGGEST_TTL_MS = 30_000\n\nconst SUGGEST_CACHE_SEGMENT = 'search-suggest'\n\nexport function storefrontSearchSuggestCacheParts(term: string, limit: number): string[] {\n return [SUGGEST_CACHE_SEGMENT, storefrontCacheValueHash({ term: term.toLowerCase(), limit })]\n}\n\nexport function storefrontSearchSuggestCacheTags(ctx: StoreContext): string[] {\n return [catalogProductsTag(ctx.tenantId), storefrontAvailabilityTag(ctx.tenantId)]\n}\n\nexport async function cachedSuggestStorefrontSearch(\n container: AwilixContainer,\n ctx: StoreContext,\n query: Pick<EcommerceStorefrontSearchSuggestQuery, 'q' | 'limit'>,\n): Promise<StorefrontSearchSuggestResponse> {\n const term = normalizeStorefrontSuggestTerm(query.q)\n if (!term) return suggestStorefrontSearch(container, ctx, query)\n const cache = storefrontCache(container, ctx)\n const parts = storefrontSearchSuggestCacheParts(term, query.limit)\n const cached = await cache.get<StorefrontSearchSuggestResponse>(parts, { scope: 'digest' })\n if (cached) return cached\n const response = await suggestStorefrontSearch(container, ctx, { q: term, limit: query.limit })\n await cache.set(parts, response, {\n scope: 'digest',\n ttlMs: STOREFRONT_SEARCH_SUGGEST_TTL_MS,\n tags: storefrontSearchSuggestCacheTags(ctx),\n })\n return response\n}\n"],
5
+ "mappings": "AAEA,SAAS,oBAAoB,2BAA2B,iBAAiB,gCAAgC;AACzG;AAAA,EACE;AAAA,EACA;AAAA,OAEK;AAWA,MAAM,mCAAmC;AAEhD,MAAM,wBAAwB;AAEvB,SAAS,kCAAkC,MAAc,OAAyB;AACvF,SAAO,CAAC,uBAAuB,yBAAyB,EAAE,MAAM,KAAK,YAAY,GAAG,MAAM,CAAC,CAAC;AAC9F;AAEO,SAAS,iCAAiC,KAA6B;AAC5E,SAAO,CAAC,mBAAmB,IAAI,QAAQ,GAAG,0BAA0B,IAAI,QAAQ,CAAC;AACnF;AAEA,eAAsB,8BACpB,WACA,KACA,OAC0C;AAC1C,QAAM,OAAO,+BAA+B,MAAM,CAAC;AACnD,MAAI,CAAC,KAAM,QAAO,wBAAwB,WAAW,KAAK,KAAK;AAC/D,QAAM,QAAQ,gBAAgB,WAAW,GAAG;AAC5C,QAAM,QAAQ,kCAAkC,MAAM,MAAM,KAAK;AACjE,QAAM,SAAS,MAAM,MAAM,IAAqC,OAAO,EAAE,OAAO,SAAS,CAAC;AAC1F,MAAI,OAAQ,QAAO;AACnB,QAAM,WAAW,MAAM,wBAAwB,WAAW,KAAK,EAAE,GAAG,MAAM,OAAO,MAAM,MAAM,CAAC;AAC9F,QAAM,MAAM,IAAI,OAAO,UAAU;AAAA,IAC/B,OAAO;AAAA,IACP,OAAO;AAAA,IACP,MAAM,iCAAiC,GAAG;AAAA,EAC5C,CAAC;AACD,SAAO;AACT;",
6
+ "names": []
7
+ }
@@ -0,0 +1,33 @@
1
+ function asPayloadRecord(payload) {
2
+ return typeof payload === "object" && payload !== null && !Array.isArray(payload) ? payload : {};
3
+ }
4
+ function readPayloadString(payload, key) {
5
+ const value = payload[key];
6
+ return typeof value === "string" && value.length > 0 ? value : null;
7
+ }
8
+ function readEventScope(payload, ctx) {
9
+ return {
10
+ tenantId: ctx.tenantId ?? readPayloadString(payload, "tenantId"),
11
+ organizationId: ctx.organizationId ?? readPayloadString(payload, "organizationId")
12
+ };
13
+ }
14
+ function eventAction(eventName) {
15
+ if (!eventName) return null;
16
+ const segments = eventName.split(".");
17
+ return segments.length > 0 ? segments[segments.length - 1] : null;
18
+ }
19
+ function tryResolveService(ctx, name) {
20
+ try {
21
+ return ctx.resolve(name) ?? null;
22
+ } catch {
23
+ return null;
24
+ }
25
+ }
26
+ export {
27
+ asPayloadRecord,
28
+ eventAction,
29
+ readEventScope,
30
+ readPayloadString,
31
+ tryResolveService
32
+ };
33
+ //# sourceMappingURL=subscriberSupport.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/modules/ecommerce/lib/subscriberSupport.ts"],
4
+ "sourcesContent": ["export type EcommerceSubscriberContext = {\n resolve: <T = unknown>(name: string) => T\n eventName?: string\n tenantId?: string | null\n organizationId?: string | null\n}\n\nexport type EventScope = { tenantId: string | null; organizationId: string | null }\n\nexport function asPayloadRecord(payload: unknown): Record<string, unknown> {\n return typeof payload === 'object' && payload !== null && !Array.isArray(payload)\n ? (payload as Record<string, unknown>)\n : {}\n}\n\nexport function readPayloadString(payload: Record<string, unknown>, key: string): string | null {\n const value = payload[key]\n return typeof value === 'string' && value.length > 0 ? value : null\n}\n\n/** Trusted emitter scope first (events AGENTS.md), payload fields only as a fallback. */\nexport function readEventScope(payload: Record<string, unknown>, ctx: EcommerceSubscriberContext): EventScope {\n return {\n tenantId: ctx.tenantId ?? readPayloadString(payload, 'tenantId'),\n organizationId: ctx.organizationId ?? readPayloadString(payload, 'organizationId'),\n }\n}\n\nexport function eventAction(eventName: string | undefined): string | null {\n if (!eventName) return null\n const segments = eventName.split('.')\n return segments.length > 0 ? segments[segments.length - 1] : null\n}\n\nexport function tryResolveService<T>(ctx: Pick<EcommerceSubscriberContext, 'resolve'>, name: string): T | null {\n try {\n return ctx.resolve<T | null | undefined>(name) ?? null\n } catch {\n return null\n }\n}\n"],
5
+ "mappings": "AASO,SAAS,gBAAgB,SAA2C;AACzE,SAAO,OAAO,YAAY,YAAY,YAAY,QAAQ,CAAC,MAAM,QAAQ,OAAO,IAC3E,UACD,CAAC;AACP;AAEO,SAAS,kBAAkB,SAAkC,KAA4B;AAC9F,QAAM,QAAQ,QAAQ,GAAG;AACzB,SAAO,OAAO,UAAU,YAAY,MAAM,SAAS,IAAI,QAAQ;AACjE;AAGO,SAAS,eAAe,SAAkC,KAA6C;AAC5G,SAAO;AAAA,IACL,UAAU,IAAI,YAAY,kBAAkB,SAAS,UAAU;AAAA,IAC/D,gBAAgB,IAAI,kBAAkB,kBAAkB,SAAS,gBAAgB;AAAA,EACnF;AACF;AAEO,SAAS,YAAY,WAA8C;AACxE,MAAI,CAAC,UAAW,QAAO;AACvB,QAAM,WAAW,UAAU,MAAM,GAAG;AACpC,SAAO,SAAS,SAAS,IAAI,SAAS,SAAS,SAAS,CAAC,IAAI;AAC/D;AAEO,SAAS,kBAAqB,KAAkD,MAAwB;AAC7G,MAAI;AACF,WAAO,IAAI,QAA8B,IAAI,KAAK;AAAA,EACpD,QAAQ;AACN,WAAO;AAAA,EACT;AACF;",
6
+ "names": []
7
+ }
@@ -0,0 +1 @@
1
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": [],
4
+ "sourcesContent": [],
5
+ "mappings": "",
6
+ "names": []
7
+ }
@@ -0,0 +1,32 @@
1
+ import { Migration } from "@mikro-orm/migrations";
2
+ class Migration20261005113233_ecommerce extends Migration {
3
+ constructor() {
4
+ super(...arguments);
5
+ this.name = "Migration20261005113233";
6
+ }
7
+ up() {
8
+ this.addSql(`create table "ecommerce_stores" ("id" uuid not null default gen_random_uuid(), "organization_id" uuid not null, "tenant_id" uuid not null, "code" text not null, "name" text not null, "slug" text not null, "status" text not null default 'draft', "default_locale" text not null, "supported_locales" jsonb not null, "default_currency_code" text not null, "is_primary" boolean not null default false, "settings" jsonb not null, "created_at" timestamptz not null, "updated_at" timestamptz not null, "deleted_at" timestamptz null, primary key ("id"));`);
9
+ this.addSql(`create unique index "ecommerce_stores_org_primary_unique" on "ecommerce_stores" ("organization_id") where "is_primary" and "deleted_at" is null;`);
10
+ this.addSql(`create unique index "ecommerce_stores_tenant_slug_unique" on "ecommerce_stores" ("tenant_id", "slug") where "deleted_at" is null;`);
11
+ this.addSql(`create unique index "ecommerce_stores_tenant_code_unique" on "ecommerce_stores" ("tenant_id", "code") where "deleted_at" is null;`);
12
+ this.addSql(`create index "ecommerce_stores_tenant_org_idx" on "ecommerce_stores" ("tenant_id", "organization_id");`);
13
+ this.addSql(`create table "ecommerce_store_channel_bindings" ("id" uuid not null default gen_random_uuid(), "organization_id" uuid not null, "tenant_id" uuid not null, "store_id" uuid not null, "sales_channel_id" uuid not null, "price_kind_id" uuid null, "assortment_scope" jsonb null, "price_sort_fallback" text not null default 'approximate', "is_default" boolean not null default false, "created_at" timestamptz not null, "updated_at" timestamptz not null, "deleted_at" timestamptz null, primary key ("id"));`);
14
+ this.addSql(`create unique index "ecommerce_store_channel_bindings_store_default_unique" on "ecommerce_store_channel_bindings" ("store_id") where "is_default" and "deleted_at" is null;`);
15
+ this.addSql(`create index "ecommerce_store_channel_bindings_store_idx" on "ecommerce_store_channel_bindings" ("store_id");`);
16
+ this.addSql(`create index "ecommerce_store_channel_bindings_tenant_org_idx" on "ecommerce_store_channel_bindings" ("tenant_id", "organization_id");`);
17
+ this.addSql(`create table "ecommerce_store_domain_bindings" ("id" uuid not null default gen_random_uuid(), "organization_id" uuid not null, "tenant_id" uuid not null, "store_id" uuid not null, "domain_mapping_id" uuid not null, "path_prefix" text null, "is_primary" boolean not null default false, "created_at" timestamptz not null, "updated_at" timestamptz not null, "deleted_at" timestamptz null, primary key ("id"));`);
18
+ this.addSql(`create unique index "ecommerce_store_domain_bindings_store_primary_unique" on "ecommerce_store_domain_bindings" ("store_id") where "is_primary" and "deleted_at" is null;`);
19
+ this.addSql(`create unique index "ecommerce_store_domain_bindings_mapping_prefix_unique" on "ecommerce_store_domain_bindings" ("domain_mapping_id", coalesce("path_prefix", '')) where "deleted_at" is null;`);
20
+ this.addSql(`create index "ecommerce_store_domain_bindings_store_idx" on "ecommerce_store_domain_bindings" ("store_id");`);
21
+ this.addSql(`create index "ecommerce_store_domain_bindings_tenant_org_idx" on "ecommerce_store_domain_bindings" ("tenant_id", "organization_id");`);
22
+ }
23
+ down() {
24
+ this.addSql(`drop table if exists "ecommerce_store_domain_bindings" cascade;`);
25
+ this.addSql(`drop table if exists "ecommerce_store_channel_bindings" cascade;`);
26
+ this.addSql(`drop table if exists "ecommerce_stores" cascade;`);
27
+ }
28
+ }
29
+ export {
30
+ Migration20261005113233_ecommerce
31
+ };
32
+ //# sourceMappingURL=Migration20261005113233_ecommerce.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/modules/ecommerce/migrations/Migration20261005113233_ecommerce.ts"],
4
+ "sourcesContent": ["import { Migration } from '@mikro-orm/migrations';\n\nexport class Migration20261005113233_ecommerce extends Migration {\n\n override name = 'Migration20261005113233';\n\n override up(): void | Promise<void> {\n this.addSql(`create table \"ecommerce_stores\" (\"id\" uuid not null default gen_random_uuid(), \"organization_id\" uuid not null, \"tenant_id\" uuid not null, \"code\" text not null, \"name\" text not null, \"slug\" text not null, \"status\" text not null default 'draft', \"default_locale\" text not null, \"supported_locales\" jsonb not null, \"default_currency_code\" text not null, \"is_primary\" boolean not null default false, \"settings\" jsonb not null, \"created_at\" timestamptz not null, \"updated_at\" timestamptz not null, \"deleted_at\" timestamptz null, primary key (\"id\"));`);\n this.addSql(`create unique index \"ecommerce_stores_org_primary_unique\" on \"ecommerce_stores\" (\"organization_id\") where \"is_primary\" and \"deleted_at\" is null;`);\n this.addSql(`create unique index \"ecommerce_stores_tenant_slug_unique\" on \"ecommerce_stores\" (\"tenant_id\", \"slug\") where \"deleted_at\" is null;`);\n this.addSql(`create unique index \"ecommerce_stores_tenant_code_unique\" on \"ecommerce_stores\" (\"tenant_id\", \"code\") where \"deleted_at\" is null;`);\n this.addSql(`create index \"ecommerce_stores_tenant_org_idx\" on \"ecommerce_stores\" (\"tenant_id\", \"organization_id\");`);\n\n this.addSql(`create table \"ecommerce_store_channel_bindings\" (\"id\" uuid not null default gen_random_uuid(), \"organization_id\" uuid not null, \"tenant_id\" uuid not null, \"store_id\" uuid not null, \"sales_channel_id\" uuid not null, \"price_kind_id\" uuid null, \"assortment_scope\" jsonb null, \"price_sort_fallback\" text not null default 'approximate', \"is_default\" boolean not null default false, \"created_at\" timestamptz not null, \"updated_at\" timestamptz not null, \"deleted_at\" timestamptz null, primary key (\"id\"));`);\n this.addSql(`create unique index \"ecommerce_store_channel_bindings_store_default_unique\" on \"ecommerce_store_channel_bindings\" (\"store_id\") where \"is_default\" and \"deleted_at\" is null;`);\n this.addSql(`create index \"ecommerce_store_channel_bindings_store_idx\" on \"ecommerce_store_channel_bindings\" (\"store_id\");`);\n this.addSql(`create index \"ecommerce_store_channel_bindings_tenant_org_idx\" on \"ecommerce_store_channel_bindings\" (\"tenant_id\", \"organization_id\");`);\n\n this.addSql(`create table \"ecommerce_store_domain_bindings\" (\"id\" uuid not null default gen_random_uuid(), \"organization_id\" uuid not null, \"tenant_id\" uuid not null, \"store_id\" uuid not null, \"domain_mapping_id\" uuid not null, \"path_prefix\" text null, \"is_primary\" boolean not null default false, \"created_at\" timestamptz not null, \"updated_at\" timestamptz not null, \"deleted_at\" timestamptz null, primary key (\"id\"));`);\n this.addSql(`create unique index \"ecommerce_store_domain_bindings_store_primary_unique\" on \"ecommerce_store_domain_bindings\" (\"store_id\") where \"is_primary\" and \"deleted_at\" is null;`);\n this.addSql(`create unique index \"ecommerce_store_domain_bindings_mapping_prefix_unique\" on \"ecommerce_store_domain_bindings\" (\"domain_mapping_id\", coalesce(\"path_prefix\", '')) where \"deleted_at\" is null;`);\n this.addSql(`create index \"ecommerce_store_domain_bindings_store_idx\" on \"ecommerce_store_domain_bindings\" (\"store_id\");`);\n this.addSql(`create index \"ecommerce_store_domain_bindings_tenant_org_idx\" on \"ecommerce_store_domain_bindings\" (\"tenant_id\", \"organization_id\");`);\n }\n\n override down(): void | Promise<void> {\n this.addSql(`drop table if exists \"ecommerce_store_domain_bindings\" cascade;`);\n this.addSql(`drop table if exists \"ecommerce_store_channel_bindings\" cascade;`);\n this.addSql(`drop table if exists \"ecommerce_stores\" cascade;`);\n }\n\n}\n"],
5
+ "mappings": "AAAA,SAAS,iBAAiB;AAEnB,MAAM,0CAA0C,UAAU;AAAA,EAA1D;AAAA;AAEL,SAAS,OAAO;AAAA;AAAA,EAEP,KAA2B;AAClC,SAAK,OAAO,miBAAmiB;AAC/iB,SAAK,OAAO,kJAAkJ;AAC9J,SAAK,OAAO,mIAAmI;AAC/I,SAAK,OAAO,mIAAmI;AAC/I,SAAK,OAAO,wGAAwG;AAEpH,SAAK,OAAO,ofAAof;AAChgB,SAAK,OAAO,6KAA6K;AACzL,SAAK,OAAO,+GAA+G;AAC3H,SAAK,OAAO,wIAAwI;AAEpJ,SAAK,OAAO,wZAAwZ;AACpa,SAAK,OAAO,2KAA2K;AACvL,SAAK,OAAO,iMAAiM;AAC7M,SAAK,OAAO,6GAA6G;AACzH,SAAK,OAAO,sIAAsI;AAAA,EACpJ;AAAA,EAES,OAA6B;AACpC,SAAK,OAAO,iEAAiE;AAC7E,SAAK,OAAO,kEAAkE;AAC9E,SAAK,OAAO,kDAAkD;AAAA,EAChE;AAEF;",
6
+ "names": []
7
+ }
@@ -0,0 +1,17 @@
1
+ import { Migration } from "@mikro-orm/migrations";
2
+ class Migration20261006112733_ecommerce extends Migration {
3
+ constructor() {
4
+ super(...arguments);
5
+ this.name = "Migration20261006112733";
6
+ }
7
+ up() {
8
+ this.addSql(`alter table "ecommerce_store_channel_bindings" add "require_authentication" boolean not null default false;`);
9
+ }
10
+ down() {
11
+ this.addSql(`alter table "ecommerce_store_channel_bindings" drop column "require_authentication";`);
12
+ }
13
+ }
14
+ export {
15
+ Migration20261006112733_ecommerce
16
+ };
17
+ //# sourceMappingURL=Migration20261006112733_ecommerce.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/modules/ecommerce/migrations/Migration20261006112733_ecommerce.ts"],
4
+ "sourcesContent": ["import { Migration } from '@mikro-orm/migrations';\n\nexport class Migration20261006112733_ecommerce extends Migration {\n\n override name = 'Migration20261006112733';\n\n override up(): void | Promise<void> {\n this.addSql(`alter table \"ecommerce_store_channel_bindings\" add \"require_authentication\" boolean not null default false;`);\n }\n\n override down(): void | Promise<void> {\n this.addSql(`alter table \"ecommerce_store_channel_bindings\" drop column \"require_authentication\";`);\n }\n\n}\n"],
5
+ "mappings": "AAAA,SAAS,iBAAiB;AAEnB,MAAM,0CAA0C,UAAU;AAAA,EAA1D;AAAA;AAEL,SAAS,OAAO;AAAA;AAAA,EAEP,KAA2B;AAClC,SAAK,OAAO,6GAA6G;AAAA,EAC3H;AAAA,EAES,OAA6B;AACpC,SAAK,OAAO,sFAAsF;AAAA,EACpG;AAEF;",
6
+ "names": []
7
+ }
@@ -0,0 +1,47 @@
1
+ "use client";
2
+ const ecommerceNotificationTypes = [
3
+ {
4
+ type: "ecommerce.store.channel_binding_missing",
5
+ module: "ecommerce",
6
+ titleKey: "ecommerce.notifications.store.channelBindingMissing.title",
7
+ bodyKey: "ecommerce.notifications.store.channelBindingMissing.body",
8
+ icon: "alert-triangle",
9
+ severity: "warning",
10
+ actions: [
11
+ {
12
+ id: "view",
13
+ labelKey: "common.view",
14
+ variant: "outline",
15
+ href: "/backend/config/ecommerce/{sourceEntityId}",
16
+ icon: "external-link"
17
+ }
18
+ ],
19
+ linkHref: "/backend/config/ecommerce/{sourceEntityId}",
20
+ expiresAfterHours: 168
21
+ },
22
+ {
23
+ type: "ecommerce.store.assortment_empty",
24
+ module: "ecommerce",
25
+ titleKey: "ecommerce.notifications.store.assortmentEmpty.title",
26
+ bodyKey: "ecommerce.notifications.store.assortmentEmpty.body",
27
+ icon: "alert-triangle",
28
+ severity: "warning",
29
+ actions: [
30
+ {
31
+ id: "view",
32
+ labelKey: "common.view",
33
+ variant: "outline",
34
+ href: "/backend/config/ecommerce/{sourceEntityId}",
35
+ icon: "external-link"
36
+ }
37
+ ],
38
+ linkHref: "/backend/config/ecommerce/{sourceEntityId}",
39
+ expiresAfterHours: 168
40
+ }
41
+ ];
42
+ var notifications_client_default = ecommerceNotificationTypes;
43
+ export {
44
+ notifications_client_default as default,
45
+ ecommerceNotificationTypes
46
+ };
47
+ //# sourceMappingURL=notifications.client.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/modules/ecommerce/notifications.client.ts"],
4
+ "sourcesContent": ["'use client'\n\nimport type { NotificationTypeDefinition } from '@open-mercato/shared/modules/notifications/types'\n\nexport const ecommerceNotificationTypes: NotificationTypeDefinition[] = [\n {\n type: 'ecommerce.store.channel_binding_missing',\n module: 'ecommerce',\n titleKey: 'ecommerce.notifications.store.channelBindingMissing.title',\n bodyKey: 'ecommerce.notifications.store.channelBindingMissing.body',\n icon: 'alert-triangle',\n severity: 'warning',\n actions: [\n {\n id: 'view',\n labelKey: 'common.view',\n variant: 'outline',\n href: '/backend/config/ecommerce/{sourceEntityId}',\n icon: 'external-link',\n },\n ],\n linkHref: '/backend/config/ecommerce/{sourceEntityId}',\n expiresAfterHours: 168,\n },\n {\n type: 'ecommerce.store.assortment_empty',\n module: 'ecommerce',\n titleKey: 'ecommerce.notifications.store.assortmentEmpty.title',\n bodyKey: 'ecommerce.notifications.store.assortmentEmpty.body',\n icon: 'alert-triangle',\n severity: 'warning',\n actions: [\n {\n id: 'view',\n labelKey: 'common.view',\n variant: 'outline',\n href: '/backend/config/ecommerce/{sourceEntityId}',\n icon: 'external-link',\n },\n ],\n linkHref: '/backend/config/ecommerce/{sourceEntityId}',\n expiresAfterHours: 168,\n },\n]\n\nexport default ecommerceNotificationTypes\n"],
5
+ "mappings": ";AAIO,MAAM,6BAA2D;AAAA,EACtE;AAAA,IACE,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,UAAU;AAAA,IACV,SAAS;AAAA,IACT,MAAM;AAAA,IACN,UAAU;AAAA,IACV,SAAS;AAAA,MACP;AAAA,QACE,IAAI;AAAA,QACJ,UAAU;AAAA,QACV,SAAS;AAAA,QACT,MAAM;AAAA,QACN,MAAM;AAAA,MACR;AAAA,IACF;AAAA,IACA,UAAU;AAAA,IACV,mBAAmB;AAAA,EACrB;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,UAAU;AAAA,IACV,SAAS;AAAA,IACT,MAAM;AAAA,IACN,UAAU;AAAA,IACV,SAAS;AAAA,MACP;AAAA,QACE,IAAI;AAAA,QACJ,UAAU;AAAA,QACV,SAAS;AAAA,QACT,MAAM;AAAA,QACN,MAAM;AAAA,MACR;AAAA,IACF;AAAA,IACA,UAAU;AAAA,IACV,mBAAmB;AAAA,EACrB;AACF;AAEA,IAAO,+BAAQ;",
6
+ "names": []
7
+ }