@open-mercato/core 0.9.1-develop.7473.1.de5b22888f → 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,230 @@
1
+ import { z } from 'zod'
2
+ import { ecommerceStoreBrandingSchema, isSafeAssetUrl } from '../data/validators'
3
+ import {
4
+ ECOMMERCE_BRANDING_COLOR_KEYS,
5
+ ECOMMERCE_BRANDING_DEFAULTS,
6
+ ECOMMERCE_BRANDING_FONT_KEYS,
7
+ findEcommerceBrandingFont,
8
+ isValidBorderRadius,
9
+ normalizeBrandingColor,
10
+ renderBrandingRootRule,
11
+ type EcommerceBrandingColorKey,
12
+ type EcommerceBrandingFontKey,
13
+ } from '../lib/brandingStyles'
14
+ import type { StoreAdminRecord } from './storeAdmin'
15
+
16
+ export const BRANDING_COLOR_KEYS = ECOMMERCE_BRANDING_COLOR_KEYS
17
+ export const BRANDING_FONT_KEYS = ECOMMERCE_BRANDING_FONT_KEYS
18
+ export const BRANDING_ASSET_KEYS = ['logoUrl', 'faviconUrl'] as const
19
+
20
+ export type BrandingAssetKey = (typeof BRANDING_ASSET_KEYS)[number]
21
+ export type StoreBrandingFormKey =
22
+ | EcommerceBrandingColorKey
23
+ | EcommerceBrandingFontKey
24
+ | BrandingAssetKey
25
+ | 'borderRadius'
26
+
27
+ export type StoreBrandingFormValues = Record<StoreBrandingFormKey, string>
28
+
29
+ export type StoreBrandingPayload = Partial<Record<StoreBrandingFormKey, string>>
30
+
31
+ export const BRANDING_FONT_INHERIT = 'inherit'
32
+ export const DEFAULT_BASE_FONT_ID = 'inter'
33
+ export const RADIUS_SLIDER_MIN = 0
34
+ export const RADIUS_SLIDER_MAX = 5
35
+ export const RADIUS_SLIDER_STEP = 0.125
36
+ const PX_PER_REM = 16
37
+
38
+ export const STORE_BRANDING_API_PATH = (storeId: string) => `/api/ecommerce/stores/${encodeURIComponent(storeId)}/branding`
39
+
40
+ const ALL_KEYS: readonly StoreBrandingFormKey[] = [
41
+ ...BRANDING_COLOR_KEYS,
42
+ 'borderRadius',
43
+ ...BRANDING_FONT_KEYS,
44
+ ...BRANDING_ASSET_KEYS,
45
+ ]
46
+
47
+ function readStoredBranding(store: Pick<StoreAdminRecord, 'settings'>): Record<string, unknown> {
48
+ const branding = store.settings?.branding
49
+ return typeof branding === 'object' && branding !== null && !Array.isArray(branding)
50
+ ? (branding as Record<string, unknown>)
51
+ : {}
52
+ }
53
+
54
+ function readStoredString(stored: Record<string, unknown>, key: string): string {
55
+ const value = stored[key]
56
+ return typeof value === 'string' ? value : ''
57
+ }
58
+
59
+ export function buildStoreBrandingInitialValues(store: Pick<StoreAdminRecord, 'settings'>): StoreBrandingFormValues {
60
+ const stored = readStoredBranding(store)
61
+ const values = {} as StoreBrandingFormValues
62
+ for (const key of BRANDING_COLOR_KEYS) {
63
+ values[key] = readStoredString(stored, key) || ECOMMERCE_BRANDING_DEFAULTS[key]
64
+ }
65
+ values.borderRadius = readStoredString(stored, 'borderRadius') || ECOMMERCE_BRANDING_DEFAULTS.borderRadius
66
+ values.fontFamilyBase = readStoredString(stored, 'fontFamilyBase') || DEFAULT_BASE_FONT_ID
67
+ values.fontFamilyHeading = readStoredString(stored, 'fontFamilyHeading') || BRANDING_FONT_INHERIT
68
+ values.logoUrl = readStoredString(stored, 'logoUrl')
69
+ values.faviconUrl = readStoredString(stored, 'faviconUrl')
70
+ return values
71
+ }
72
+
73
+ function readFormString(values: Record<string, unknown>, key: string): string {
74
+ const value = values[key]
75
+ return typeof value === 'string' ? value.trim() : ''
76
+ }
77
+
78
+ function defaultValueFor(key: StoreBrandingFormKey): string | null {
79
+ if (key === 'fontFamilyBase') return DEFAULT_BASE_FONT_ID
80
+ if (key === 'fontFamilyHeading') return BRANDING_FONT_INHERIT
81
+ if (key === 'logoUrl' || key === 'faviconUrl') return null
82
+ return ECOMMERCE_BRANDING_DEFAULTS[key]
83
+ }
84
+
85
+ export function buildStoreBrandingInput(values: Record<string, unknown>): StoreBrandingPayload {
86
+ const input: StoreBrandingPayload = {}
87
+ for (const key of ALL_KEYS) {
88
+ const value = readFormString(values, key)
89
+ if (value === '' || value === BRANDING_FONT_INHERIT) continue
90
+ input[key] = value
91
+ }
92
+ return input
93
+ }
94
+
95
+ export function buildStoreBrandingPayload(
96
+ values: Record<string, unknown>,
97
+ store: Pick<StoreAdminRecord, 'settings'>,
98
+ ): StoreBrandingPayload {
99
+ const stored = readStoredBranding(store)
100
+ const input = buildStoreBrandingInput(values)
101
+ const payload: StoreBrandingPayload = {}
102
+ for (const key of ALL_KEYS) {
103
+ const value = input[key]
104
+ if (value === undefined) continue
105
+ const wasStored = readStoredString(stored, key) !== ''
106
+ if (!wasStored && value === defaultValueFor(key)) continue
107
+ payload[key] = value
108
+ }
109
+ return payload
110
+ }
111
+
112
+ const brandingFormShape = {
113
+ primaryColor: z.string(),
114
+ primaryForeground: z.string(),
115
+ accentColor: z.string(),
116
+ accentForeground: z.string(),
117
+ backgroundColor: z.string(),
118
+ foregroundColor: z.string(),
119
+ borderRadius: z.string(),
120
+ fontFamilyBase: z.string(),
121
+ fontFamilyHeading: z.string(),
122
+ logoUrl: z.string(),
123
+ faviconUrl: z.string(),
124
+ } satisfies Record<StoreBrandingFormKey, z.ZodString>
125
+
126
+ export const storeBrandingFormSchema = z.object(brandingFormShape).superRefine((values, context) => {
127
+ const result = ecommerceStoreBrandingSchema.safeParse(buildStoreBrandingInput(values))
128
+ if (result.success) return
129
+ for (const issue of result.error.issues) {
130
+ context.addIssue({ code: 'custom', path: issue.path, message: issue.message })
131
+ }
132
+ })
133
+
134
+ export function parseRadiusRem(value: string): number {
135
+ const trimmed = value.trim()
136
+ if (trimmed === '0') return 0
137
+ const match = /^(\d+(?:\.\d+)?|\.\d+)(rem|px)$/.exec(trimmed)
138
+ if (!match) return parseRadiusRem(ECOMMERCE_BRANDING_DEFAULTS.borderRadius)
139
+ const amount = Number(match[1])
140
+ const rem = match[2] === 'px' ? amount / PX_PER_REM : amount
141
+ return Math.min(RADIUS_SLIDER_MAX, Math.max(RADIUS_SLIDER_MIN, rem))
142
+ }
143
+
144
+ export function formatRadiusRem(rem: number): string {
145
+ if (rem <= 0) return '0'
146
+ return `${Number(rem.toFixed(3))}rem`
147
+ }
148
+
149
+ export type SanitizedPreviewBranding = Partial<Record<StoreBrandingFormKey, string>>
150
+
151
+ export function sanitizePreviewBranding(values: Record<string, unknown>): SanitizedPreviewBranding {
152
+ const input = buildStoreBrandingInput(values)
153
+ const sanitized: SanitizedPreviewBranding = {}
154
+ for (const key of BRANDING_COLOR_KEYS) {
155
+ const raw = input[key]
156
+ const normalized = raw === undefined ? null : normalizeBrandingColor(raw)
157
+ if (normalized !== null) sanitized[key] = normalized
158
+ }
159
+ const radius = input.borderRadius
160
+ if (radius !== undefined && isValidBorderRadius(radius)) sanitized.borderRadius = radius
161
+ for (const key of BRANDING_FONT_KEYS) {
162
+ const raw = input[key]
163
+ if (raw !== undefined && findEcommerceBrandingFont(raw)) sanitized[key] = raw
164
+ }
165
+ const logo = input.logoUrl
166
+ if (logo !== undefined && isSafeAssetUrl(logo)) sanitized.logoUrl = logo
167
+ return sanitized
168
+ }
169
+
170
+ export type BrandingPreviewLabels = {
171
+ storeName: string
172
+ navShop: string
173
+ navCategories: string
174
+ navCart: string
175
+ heroTitle: string
176
+ heroText: string
177
+ heroButton: string
178
+ productName: string
179
+ productPrice: string
180
+ }
181
+
182
+ const HTML_ESCAPES: Readonly<Record<string, string>> = {
183
+ '&': '&amp;',
184
+ '<': '&lt;',
185
+ '>': '&gt;',
186
+ '"': '&quot;',
187
+ "'": '&#39;',
188
+ }
189
+
190
+ export function escapeHtml(value: string): string {
191
+ return value.replace(/[&<>"']/g, (character) => HTML_ESCAPES[character] ?? character)
192
+ }
193
+
194
+ const PREVIEW_CONTENT_SECURITY_POLICY = "default-src 'none'; style-src 'unsafe-inline'; img-src http: https:"
195
+
196
+ const PREVIEW_STATIC_CSS = [
197
+ '*{box-sizing:border-box}',
198
+ 'body{margin:0;background:var(--background);color:var(--foreground);font-family:var(--font-base);font-size:14px;line-height:1.5}',
199
+ 'h1,.brand{font-family:var(--font-heading)}',
200
+ '.bar{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:12px 20px;border-bottom:1px solid color-mix(in oklch,var(--foreground) 15%,transparent)}',
201
+ '.brand{display:flex;align-items:center;gap:8px;font-size:16px;font-weight:700}',
202
+ '.brand img{max-width:120px;max-height:28px}',
203
+ 'nav{display:flex;gap:16px;opacity:.7}',
204
+ '.hero{padding:28px 20px;background:var(--accent);color:var(--accent-foreground)}',
205
+ '.hero h1{margin:0 0 8px;font-size:24px;line-height:1.2}',
206
+ '.hero p{margin:0 0 16px;max-width:36ch}',
207
+ '.btn{display:inline-block;padding:8px 16px;border-radius:var(--radius);background:var(--primary);color:var(--primary-foreground);font-weight:600}',
208
+ '.grid{display:grid;grid-template-columns:repeat(3,1fr);gap:12px;padding:20px}',
209
+ '.card{overflow:hidden;border:1px solid color-mix(in oklch,var(--foreground) 15%,transparent);border-radius:var(--radius)}',
210
+ '.thumb{height:56px;background:color-mix(in oklch,var(--primary) 20%,var(--background))}',
211
+ '.card-body{padding:10px}',
212
+ '.price{font-weight:600}',
213
+ ].join('')
214
+
215
+ export function buildBrandingPreviewDocument(values: Record<string, unknown>, labels: BrandingPreviewLabels): string {
216
+ const branding = sanitizePreviewBranding(values)
217
+ const rootRule = renderBrandingRootRule(branding)
218
+ const logo = branding.logoUrl ? `<img src="${escapeHtml(branding.logoUrl)}" alt="">` : ''
219
+ const card = `<div class="card"><div class="thumb"></div><div class="card-body"><div>${escapeHtml(labels.productName)}</div><div class="price">${escapeHtml(labels.productPrice)}</div></div></div>`
220
+ return [
221
+ '<!doctype html><html><head><meta charset="utf-8">',
222
+ `<meta http-equiv="Content-Security-Policy" content="${PREVIEW_CONTENT_SECURITY_POLICY}">`,
223
+ `<style>${rootRule}</style><style>${PREVIEW_STATIC_CSS}</style></head><body>`,
224
+ `<header class="bar"><div class="brand">${logo}<span>${escapeHtml(labels.storeName)}</span></div>`,
225
+ `<nav><span>${escapeHtml(labels.navShop)}</span><span>${escapeHtml(labels.navCategories)}</span><span>${escapeHtml(labels.navCart)}</span></nav></header>`,
226
+ `<section class="hero"><h1>${escapeHtml(labels.heroTitle)}</h1><p>${escapeHtml(labels.heroText)}</p><span class="btn">${escapeHtml(labels.heroButton)}</span></section>`,
227
+ `<section class="grid">${card}${card}${card}</section>`,
228
+ '</body></html>',
229
+ ].join('')
230
+ }
@@ -0,0 +1,210 @@
1
+ import { z } from 'zod'
2
+ import type { StatusBadgeVariant } from '@open-mercato/ui/primitives/status-badge'
3
+
4
+ export const CHANNEL_BINDINGS_API_PATH = 'ecommerce/store-channel-bindings'
5
+ export const CHANNEL_BINDINGS_API_URL = `/api/${CHANNEL_BINDINGS_API_PATH}`
6
+ export const CHANNEL_BINDINGS_PAGE_SIZE = 100
7
+ export const ASSORTMENT_COUNT_DEBOUNCE_MS = 400
8
+ export const PRICE_SORT_CAP = 5000
9
+
10
+ export const PRICE_SORT_FALLBACKS = ['approximate', 'unavailable'] as const
11
+
12
+ export type PriceSortFallback = (typeof PRICE_SORT_FALLBACKS)[number]
13
+
14
+ export const DEFAULT_PRICE_SORT_FALLBACK: PriceSortFallback = 'approximate'
15
+
16
+ export const SCOPE_ID_FIELDS = [
17
+ 'categoryIds',
18
+ 'tagIds',
19
+ 'excludeProductIds',
20
+ 'excludeCategoryIds',
21
+ 'excludeTagIds',
22
+ ] as const
23
+
24
+ export type ScopeIdField = (typeof SCOPE_ID_FIELDS)[number]
25
+
26
+ export type ChannelAssortmentScope = Partial<Record<ScopeIdField, string[]>>
27
+
28
+ export type ChannelBindingRecord = {
29
+ id: string
30
+ storeId: string
31
+ salesChannelId: string
32
+ priceKindId: string | null
33
+ assortmentScope: ChannelAssortmentScope | null
34
+ priceSortFallback: PriceSortFallback
35
+ isDefault: boolean
36
+ requireAuthentication: boolean
37
+ createdAt: string | null
38
+ updatedAt: string | null
39
+ }
40
+
41
+ export type ChannelBindingListResponse = {
42
+ items: ChannelBindingRecord[]
43
+ total: number
44
+ totalPages: number
45
+ }
46
+
47
+ export type AssortmentCountResult = {
48
+ count: number
49
+ scopeSource: 'saved' | 'draft'
50
+ requireAuthentication: boolean
51
+ reducedByAuthentication: boolean
52
+ countWithoutAuthentication: number
53
+ unindexedCount: number
54
+ }
55
+
56
+ export type AssortmentCountDraft = {
57
+ scope: ChannelAssortmentScope | null
58
+ requireAuthentication: boolean
59
+ }
60
+
61
+ export type ChannelBindingWritePayload = {
62
+ salesChannelId: string
63
+ priceKindId: string | null
64
+ assortmentScope: ChannelAssortmentScope | null
65
+ priceSortFallback: PriceSortFallback
66
+ requireAuthentication: boolean
67
+ isDefault?: boolean
68
+ }
69
+
70
+ export const PRICE_SORT_FALLBACK_LABELS: Record<PriceSortFallback, { key: string; fallback: string }> = {
71
+ approximate: {
72
+ key: 'ecommerce.backend.store.channels.priceSortFallback.approximate',
73
+ fallback: 'Approximate order from the default price kind',
74
+ },
75
+ unavailable: {
76
+ key: 'ecommerce.backend.store.channels.priceSortFallback.unavailable',
77
+ fallback: 'Withdraw price sorting',
78
+ },
79
+ }
80
+
81
+ export const PRICE_SORT_FALLBACK_VARIANTS: Record<PriceSortFallback, StatusBadgeVariant> = {
82
+ approximate: 'neutral',
83
+ unavailable: 'info',
84
+ }
85
+
86
+ export function isPriceSortFallback(value: unknown): value is PriceSortFallback {
87
+ return typeof value === 'string' && (PRICE_SORT_FALLBACKS as readonly string[]).includes(value)
88
+ }
89
+
90
+ function normalizeIds(value: unknown): string[] {
91
+ if (!Array.isArray(value)) return []
92
+ const seen = new Set<string>()
93
+ const ids: string[] = []
94
+ for (const entry of value) {
95
+ if (typeof entry !== 'string') continue
96
+ const trimmed = entry.trim()
97
+ if (!trimmed || seen.has(trimmed)) continue
98
+ seen.add(trimmed)
99
+ ids.push(trimmed)
100
+ }
101
+ return ids
102
+ }
103
+
104
+ /**
105
+ * Builds the `assortment_scope` sent to the server from the picker values. A cleared picker is
106
+ * omitted rather than sent as `[]`, and a scope with every picker cleared is `null` (no
107
+ * restriction), so clearing never reads as "hide everything" (US-E1).
108
+ */
109
+ export function buildAssortmentScope(values: Partial<Record<ScopeIdField, unknown>>): ChannelAssortmentScope | null {
110
+ const scope: ChannelAssortmentScope = {}
111
+ for (const field of SCOPE_ID_FIELDS) {
112
+ const ids = normalizeIds(values[field])
113
+ if (ids.length > 0) scope[field] = ids
114
+ }
115
+ return Object.keys(scope).length > 0 ? scope : null
116
+ }
117
+
118
+ export function countScopeRules(scope: ChannelAssortmentScope | null | undefined): number {
119
+ if (!scope) return 0
120
+ return SCOPE_ID_FIELDS.reduce((total, field) => total + (scope[field]?.length ?? 0), 0)
121
+ }
122
+
123
+ export function buildChannelBindingInitialValues(
124
+ binding: ChannelBindingRecord | null,
125
+ options: { firstBinding: boolean },
126
+ ): ChannelBindingFormValues {
127
+ const scope = binding?.assortmentScope ?? null
128
+ return {
129
+ salesChannelId: binding?.salesChannelId ?? '',
130
+ priceKindId: binding?.priceKindId ?? '',
131
+ isDefault: binding ? binding.isDefault : options.firstBinding,
132
+ requireAuthentication: binding?.requireAuthentication ?? false,
133
+ priceSortFallback: isPriceSortFallback(binding?.priceSortFallback)
134
+ ? binding.priceSortFallback
135
+ : DEFAULT_PRICE_SORT_FALLBACK,
136
+ categoryIds: normalizeIds(scope?.categoryIds),
137
+ tagIds: normalizeIds(scope?.tagIds),
138
+ excludeProductIds: normalizeIds(scope?.excludeProductIds),
139
+ excludeCategoryIds: normalizeIds(scope?.excludeCategoryIds),
140
+ excludeTagIds: normalizeIds(scope?.excludeTagIds),
141
+ }
142
+ }
143
+
144
+ function buildWritePayload(values: ChannelBindingFormValues): ChannelBindingWritePayload {
145
+ const priceKindId = typeof values.priceKindId === 'string' ? values.priceKindId.trim() : ''
146
+ return {
147
+ salesChannelId: values.salesChannelId.trim(),
148
+ priceKindId: priceKindId.length > 0 ? priceKindId : null,
149
+ assortmentScope: buildAssortmentScope(values),
150
+ priceSortFallback: isPriceSortFallback(values.priceSortFallback) ? values.priceSortFallback : DEFAULT_PRICE_SORT_FALLBACK,
151
+ requireAuthentication: values.requireAuthentication === true,
152
+ }
153
+ }
154
+
155
+ export function buildChannelBindingCreatePayload(
156
+ storeId: string,
157
+ values: ChannelBindingFormValues,
158
+ ): ChannelBindingWritePayload & { storeId: string; isDefault: boolean } {
159
+ return { storeId, ...buildWritePayload(values), isDefault: values.isDefault === true }
160
+ }
161
+
162
+ /**
163
+ * The default mark is only ever promoted from this form: un-ticking it on the current default
164
+ * would leave the store without a default binding (a `503` for every storefront request), so the
165
+ * update omits `isDefault` unless it asks for the promotion.
166
+ */
167
+ export function buildChannelBindingUpdatePayload(
168
+ bindingId: string,
169
+ values: ChannelBindingFormValues,
170
+ ): ChannelBindingWritePayload & { id: string } {
171
+ const payload: ChannelBindingWritePayload & { id: string } = { id: bindingId, ...buildWritePayload(values) }
172
+ if (values.isDefault === true) payload.isDefault = true
173
+ return payload
174
+ }
175
+
176
+ export function buildAssortmentCountDraft(
177
+ values: Partial<Record<ScopeIdField | 'requireAuthentication', unknown>>,
178
+ ): AssortmentCountDraft {
179
+ return {
180
+ scope: buildAssortmentScope(values),
181
+ requireAuthentication: values.requireAuthentication === true,
182
+ }
183
+ }
184
+
185
+ export function buildAssortmentCountUrl(bindingId: string, draft: AssortmentCountDraft | null): string {
186
+ const base = `${CHANNEL_BINDINGS_API_URL}/${encodeURIComponent(bindingId)}/assortment-count`
187
+ if (!draft) return base
188
+ const params = new URLSearchParams({
189
+ draftScope: JSON.stringify(draft.scope),
190
+ draftRequireAuthentication: draft.requireAuthentication ? 'true' : 'false',
191
+ })
192
+ return `${base}?${params.toString()}`
193
+ }
194
+
195
+ const REQUIRED_MESSAGE = 'ui.forms.errors.required'
196
+
197
+ export const channelBindingFormSchema = z.object({
198
+ salesChannelId: z.string().trim().min(1, REQUIRED_MESSAGE),
199
+ priceKindId: z.string().default(''),
200
+ isDefault: z.boolean().default(false),
201
+ requireAuthentication: z.boolean().default(false),
202
+ priceSortFallback: z.enum(PRICE_SORT_FALLBACKS).default(DEFAULT_PRICE_SORT_FALLBACK),
203
+ categoryIds: z.array(z.string()).default([]),
204
+ tagIds: z.array(z.string()).default([]),
205
+ excludeProductIds: z.array(z.string()).default([]),
206
+ excludeCategoryIds: z.array(z.string()).default([]),
207
+ excludeTagIds: z.array(z.string()).default([]),
208
+ })
209
+
210
+ export type ChannelBindingFormValues = z.infer<typeof channelBindingFormSchema>
@@ -0,0 +1,221 @@
1
+ import { z } from 'zod'
2
+ import type { StatusBadgeVariant } from '@open-mercato/ui/primitives/status-badge'
3
+ import type { DomainBindingMappingState } from '../data/enrichers'
4
+ import { ecommerceStoreDomainBindingCreateSchema, normalizePathPrefix } from '../data/validators'
5
+ import { isDomainMappingStatus, type DomainMappingStatus, type DomainMappingSummary } from '../lib/domainMappingSummaries'
6
+
7
+ export const DOMAIN_BINDINGS_API_PATH = 'ecommerce/store-domain-bindings'
8
+ export const DOMAIN_BINDINGS_API_URL = `/api/${DOMAIN_BINDINGS_API_PATH}`
9
+ export const DOMAIN_MAPPINGS_API_URL = '/api/ecommerce/domain-mappings'
10
+ export const DOMAIN_SETTINGS_HREF = '/backend/customer_accounts/settings/domain'
11
+ export const DOMAIN_BINDINGS_PAGE_SIZE = 100
12
+
13
+ export type DomainBindingRecord = {
14
+ id: string
15
+ storeId: string
16
+ domainMappingId: string
17
+ pathPrefix: string | null
18
+ isPrimary: boolean
19
+ createdAt: string | null
20
+ updatedAt: string | null
21
+ _domainMapping?: DomainBindingMappingState
22
+ }
23
+
24
+ export type DomainBindingListResponse = {
25
+ items: DomainBindingRecord[]
26
+ total: number
27
+ totalPages: number
28
+ }
29
+
30
+ export type DomainMappingListResponse = {
31
+ items: DomainMappingSummary[]
32
+ total: number
33
+ }
34
+
35
+ export type DomainBindingFormValues = {
36
+ domainMappingId: string
37
+ pathPrefix: string
38
+ isPrimary: boolean
39
+ }
40
+
41
+ export const DOMAIN_STATUS_VARIANTS: Record<DomainMappingStatus, StatusBadgeVariant> = {
42
+ pending: 'info',
43
+ verified: 'info',
44
+ active: 'success',
45
+ dns_failed: 'error',
46
+ tls_failed: 'warning',
47
+ }
48
+
49
+ export const DOMAIN_STATUS_LABELS: Record<DomainMappingStatus, { key: string; fallback: string }> = {
50
+ pending: { key: 'ecommerce.backend.store.domains.status.pending', fallback: 'Pending' },
51
+ verified: { key: 'ecommerce.backend.store.domains.status.verified', fallback: 'Verified' },
52
+ active: { key: 'ecommerce.backend.store.domains.status.active', fallback: 'Active' },
53
+ dns_failed: { key: 'ecommerce.backend.store.domains.status.dnsFailed', fallback: 'DNS failed' },
54
+ tls_failed: { key: 'ecommerce.backend.store.domains.status.tlsFailed', fallback: 'TLS failed' },
55
+ }
56
+
57
+ export type DomainFailureReasonLabel = { key: string; fallback: string; params: Record<string, string> }
58
+
59
+ type DomainFailureReasonPattern = {
60
+ pattern: RegExp
61
+ key: string
62
+ fallback: string
63
+ params: readonly string[]
64
+ }
65
+
66
+ const DOMAIN_FAILURE_REASON_PATTERNS: readonly DomainFailureReasonPattern[] = [
67
+ {
68
+ pattern: /^HTTP (\d{3})$/,
69
+ key: 'ecommerce.backend.store.domains.failure.httpStatus',
70
+ fallback: 'The TLS health check returned HTTP {status}',
71
+ params: ['status'],
72
+ },
73
+ {
74
+ pattern: /^TLS health check timed out$/,
75
+ key: 'ecommerce.backend.store.domains.failure.tlsTimeout',
76
+ fallback: 'The TLS health check timed out',
77
+ params: [],
78
+ },
79
+ {
80
+ pattern: /^TLS health check failed$/,
81
+ key: 'ecommerce.backend.store.domains.failure.tlsFailed',
82
+ fallback: 'The TLS health check failed',
83
+ params: [],
84
+ },
85
+ {
86
+ pattern: /^DNS lookup error \((CNAME|A)\): /,
87
+ key: 'ecommerce.backend.store.domains.failure.dnsLookup',
88
+ fallback: 'The DNS lookup for the {recordType} record failed',
89
+ params: ['recordType'],
90
+ },
91
+ {
92
+ pattern: /^CNAME points to (.+) instead of (.+)$/,
93
+ key: 'ecommerce.backend.store.domains.failure.cnameMismatch',
94
+ fallback: 'The CNAME record points to {actual} instead of {expected}',
95
+ params: ['actual', 'expected'],
96
+ },
97
+ {
98
+ pattern: /^No CNAME or A record found for /,
99
+ key: 'ecommerce.backend.store.domains.failure.noRecords',
100
+ fallback: 'No CNAME or A record was found',
101
+ params: [],
102
+ },
103
+ {
104
+ pattern: /^A record points to a known proxy IP, but reverse-resolve over HTTPS did not reach our server$/,
105
+ key: 'ecommerce.backend.store.domains.failure.proxyUnreachable',
106
+ fallback: 'The domain is behind a proxy that does not forward traffic to this platform',
107
+ params: [],
108
+ },
109
+ {
110
+ pattern: /^A record points to (.+) instead of (.+)$/,
111
+ key: 'ecommerce.backend.store.domains.failure.aRecordMismatch',
112
+ fallback: 'The A record points to {actual} instead of {expected}',
113
+ params: ['actual', 'expected'],
114
+ },
115
+ {
116
+ pattern: /^A record points to (.+) but apex-domain registration is not enabled on this deployment$/,
117
+ key: 'ecommerce.backend.store.domains.failure.apexNotEnabled',
118
+ fallback: 'The A record points to {actual}, but apex domains are not enabled on this deployment',
119
+ params: ['actual'],
120
+ },
121
+ ]
122
+
123
+ export function describeDomainFailureReason(reason: string): DomainFailureReasonLabel | null {
124
+ for (const entry of DOMAIN_FAILURE_REASON_PATTERNS) {
125
+ const match = entry.pattern.exec(reason)
126
+ if (!match) continue
127
+ const params: Record<string, string> = {}
128
+ entry.params.forEach((name, index) => {
129
+ params[name] = match[index + 1] ?? ''
130
+ })
131
+ return { key: entry.key, fallback: entry.fallback, params }
132
+ }
133
+ return null
134
+ }
135
+
136
+ export function isServingStatus(status: string): boolean {
137
+ return status === 'active'
138
+ }
139
+
140
+ export function describeDomainStatus(status: string): { variant: StatusBadgeVariant; key: string; fallback: string } {
141
+ if (isDomainMappingStatus(status)) {
142
+ return { variant: DOMAIN_STATUS_VARIANTS[status], ...DOMAIN_STATUS_LABELS[status] }
143
+ }
144
+ return { variant: 'neutral', key: '', fallback: status }
145
+ }
146
+
147
+ export function formatBindingAddress(hostname: string, pathPrefix: string | null): string {
148
+ return `${hostname}${pathPrefix ?? ''}`
149
+ }
150
+
151
+ export function normalizeBindingPrefix(value: string | null | undefined): string | null {
152
+ const normalized = normalizePathPrefix(value ?? null)
153
+ return typeof normalized === 'string' && normalized.length > 0 ? normalized : null
154
+ }
155
+
156
+ export function findDuplicateBinding(
157
+ bindings: readonly DomainBindingRecord[],
158
+ candidate: { domainMappingId: string; pathPrefix: string | null },
159
+ ignoreBindingId: string | null,
160
+ ): DomainBindingRecord | null {
161
+ return (
162
+ bindings.find(
163
+ (binding) =>
164
+ binding.id !== ignoreBindingId &&
165
+ binding.domainMappingId === candidate.domainMappingId &&
166
+ (binding.pathPrefix ?? null) === candidate.pathPrefix,
167
+ ) ?? null
168
+ )
169
+ }
170
+
171
+ export function findPreviousPrimary(
172
+ bindings: readonly DomainBindingRecord[],
173
+ nextPrimaryId: string,
174
+ ): DomainBindingRecord | null {
175
+ return bindings.find((binding) => binding.isPrimary && binding.id !== nextPrimaryId) ?? null
176
+ }
177
+
178
+ const REQUIRED_MESSAGE = 'ui.forms.errors.required'
179
+
180
+ export const domainBindingFormSchema = z.object({
181
+ domainMappingId: z.string().trim().min(1, REQUIRED_MESSAGE),
182
+ pathPrefix: z
183
+ .string()
184
+ .superRefine((value, ctx) => {
185
+ const parsed = ecommerceStoreDomainBindingCreateSchema.shape.pathPrefix.safeParse(value)
186
+ if (!parsed.success) ctx.addIssue({ code: 'custom', message: 'ecommerce.validation.pathPrefixInvalid' })
187
+ }),
188
+ isPrimary: z.boolean(),
189
+ })
190
+
191
+ export function buildDomainBindingInitialValues(binding: DomainBindingRecord | null): DomainBindingFormValues {
192
+ return {
193
+ domainMappingId: binding?.domainMappingId ?? '',
194
+ pathPrefix: binding?.pathPrefix ?? '',
195
+ isPrimary: binding?.isPrimary ?? false,
196
+ }
197
+ }
198
+
199
+ export function buildDomainBindingCreatePayload(
200
+ storeId: string,
201
+ values: DomainBindingFormValues,
202
+ ): { storeId: string; domainMappingId: string; pathPrefix: string | null; isPrimary: boolean } {
203
+ return {
204
+ storeId,
205
+ domainMappingId: values.domainMappingId,
206
+ pathPrefix: normalizeBindingPrefix(values.pathPrefix),
207
+ isPrimary: values.isPrimary === true,
208
+ }
209
+ }
210
+
211
+ export function buildDomainBindingUpdatePayload(
212
+ bindingId: string,
213
+ values: DomainBindingFormValues,
214
+ ): { id: string; domainMappingId: string; pathPrefix: string | null; isPrimary: boolean } {
215
+ return {
216
+ id: bindingId,
217
+ domainMappingId: values.domainMappingId,
218
+ pathPrefix: normalizeBindingPrefix(values.pathPrefix),
219
+ isPrimary: values.isPrimary === true,
220
+ }
221
+ }