@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.
- package/.turbo/turbo-build.log +2 -2
- package/dist/generated/entities/catalog_price_history_entry/index.js +53 -0
- package/dist/generated/entities/catalog_price_history_entry/index.js.map +7 -0
- package/dist/generated/entities/customer_group_terms/index.js +2 -0
- package/dist/generated/entities/customer_group_terms/index.js.map +2 -2
- package/dist/generated/entities/ecommerce_store/index.js +33 -0
- package/dist/generated/entities/ecommerce_store/index.js.map +7 -0
- package/dist/generated/entities/ecommerce_store_channel_binding/index.js +29 -0
- package/dist/generated/entities/ecommerce_store_channel_binding/index.js.map +7 -0
- package/dist/generated/entities/ecommerce_store_domain_binding/index.js +23 -0
- package/dist/generated/entities/ecommerce_store_domain_binding/index.js.map +7 -0
- package/dist/generated/entities.ids.generated.js +8 -1
- package/dist/generated/entities.ids.generated.js.map +2 -2
- package/dist/generated/entity-fields-registry.js +72 -0
- package/dist/generated/entity-fields-registry.js.map +2 -2
- package/dist/helpers/integration/customerGroupsFixtures.js.map +2 -2
- package/dist/modules/catalog/acl.js +8 -1
- package/dist/modules/catalog/acl.js.map +2 -2
- package/dist/modules/catalog/api/config/omnibus/route.js +184 -0
- package/dist/modules/catalog/api/config/omnibus/route.js.map +7 -0
- package/dist/modules/catalog/api/prices/history/route.js +131 -0
- package/dist/modules/catalog/api/prices/history/route.js.map +7 -0
- package/dist/modules/catalog/api/prices/omnibus-preview/route.js +184 -0
- package/dist/modules/catalog/api/prices/omnibus-preview/route.js.map +7 -0
- package/dist/modules/catalog/api/products/route.js +54 -245
- package/dist/modules/catalog/api/products/route.js.map +3 -3
- package/dist/modules/catalog/api/tags/route.js +6 -0
- package/dist/modules/catalog/api/tags/route.js.map +2 -2
- package/dist/modules/catalog/backend/config/catalog/page.js +3 -1
- package/dist/modules/catalog/backend/config/catalog/page.js.map +2 -2
- package/dist/modules/catalog/cli.js +80 -2
- package/dist/modules/catalog/cli.js.map +2 -2
- package/dist/modules/catalog/commands/categories.js +51 -2
- package/dist/modules/catalog/commands/categories.js.map +2 -2
- package/dist/modules/catalog/commands/prices.js +43 -1
- package/dist/modules/catalog/commands/prices.js.map +2 -2
- package/dist/modules/catalog/commands/products.js +71 -0
- package/dist/modules/catalog/commands/products.js.map +2 -2
- package/dist/modules/catalog/commands/variants.js +7 -0
- package/dist/modules/catalog/commands/variants.js.map +2 -2
- package/dist/modules/catalog/components/OmnibusSettings.js +703 -0
- package/dist/modules/catalog/components/OmnibusSettings.js.map +7 -0
- package/dist/modules/catalog/components/PriceEditorOmnibusRow.js +152 -0
- package/dist/modules/catalog/components/PriceEditorOmnibusRow.js.map +7 -0
- package/dist/modules/catalog/components/lookupSources.js +31 -0
- package/dist/modules/catalog/components/lookupSources.js.map +7 -0
- package/dist/modules/catalog/components/prices/PriceScopeSelectors.js +8 -2
- package/dist/modules/catalog/components/prices/PriceScopeSelectors.js.map +2 -2
- package/dist/modules/catalog/components/products/VariantBuilder.js +11 -1
- package/dist/modules/catalog/components/products/VariantBuilder.js.map +2 -2
- package/dist/modules/catalog/data/entities.js +122 -1
- package/dist/modules/catalog/data/entities.js.map +2 -2
- package/dist/modules/catalog/data/validators.js +78 -0
- package/dist/modules/catalog/data/validators.js.map +2 -2
- package/dist/modules/catalog/di.js +18 -0
- package/dist/modules/catalog/di.js.map +2 -2
- package/dist/modules/catalog/lib/omnibus.js +285 -0
- package/dist/modules/catalog/lib/omnibus.js.map +7 -0
- package/dist/modules/catalog/lib/omnibusBackfill.js +146 -0
- package/dist/modules/catalog/lib/omnibusBackfill.js.map +7 -0
- package/dist/modules/catalog/lib/omnibusCache.js +89 -0
- package/dist/modules/catalog/lib/omnibusCache.js.map +7 -0
- package/dist/modules/catalog/lib/omnibusConfig.js +64 -0
- package/dist/modules/catalog/lib/omnibusConfig.js.map +7 -0
- package/dist/modules/catalog/lib/omnibusHistoryQueries.js +191 -0
- package/dist/modules/catalog/lib/omnibusHistoryQueries.js.map +7 -0
- package/dist/modules/catalog/lib/omnibusPresentedEntry.js +73 -0
- package/dist/modules/catalog/lib/omnibusPresentedEntry.js.map +7 -0
- package/dist/modules/catalog/lib/omnibusProductListEnrichment.js +94 -0
- package/dist/modules/catalog/lib/omnibusProductListEnrichment.js.map +7 -0
- package/dist/modules/catalog/lib/omnibusTypes.js +115 -0
- package/dist/modules/catalog/lib/omnibusTypes.js.map +7 -0
- package/dist/modules/catalog/lib/optionSchemaTranslations.js +55 -0
- package/dist/modules/catalog/lib/optionSchemaTranslations.js.map +7 -0
- package/dist/modules/catalog/lib/priceHistoryQuery.js +103 -0
- package/dist/modules/catalog/lib/priceHistoryQuery.js.map +7 -0
- package/dist/modules/catalog/lib/pricing.js +26 -2
- package/dist/modules/catalog/lib/pricing.js.map +2 -2
- package/dist/modules/catalog/lib/productFilters.js +273 -0
- package/dist/modules/catalog/lib/productFilters.js.map +7 -0
- package/dist/modules/catalog/lib/productScopeKeys.js +105 -0
- package/dist/modules/catalog/lib/productScopeKeys.js.map +7 -0
- package/dist/modules/catalog/lib/productScopeReindex.js +73 -0
- package/dist/modules/catalog/lib/productScopeReindex.js.map +7 -0
- package/dist/modules/catalog/migrations/Migration20261005105352_catalog.js +39 -0
- package/dist/modules/catalog/migrations/Migration20261005105352_catalog.js.map +7 -0
- package/dist/modules/catalog/migrations/Migration20261005150824_catalog.js +39 -0
- package/dist/modules/catalog/migrations/Migration20261005150824_catalog.js.map +7 -0
- package/dist/modules/catalog/services/catalogOmnibusService.js +480 -0
- package/dist/modules/catalog/services/catalogOmnibusService.js.map +7 -0
- package/dist/modules/catalog/setup.js +3 -1
- package/dist/modules/catalog/setup.js.map +2 -2
- package/dist/modules/catalog/subscribers/product-scope-keys-category-deleted.js +16 -0
- package/dist/modules/catalog/subscribers/product-scope-keys-category-deleted.js.map +7 -0
- package/dist/modules/catalog/subscribers/product-scope-keys-category-updated.js +17 -0
- package/dist/modules/catalog/subscribers/product-scope-keys-category-updated.js.map +7 -0
- package/dist/modules/catalog/translations.js +10 -0
- package/dist/modules/catalog/translations.js.map +2 -2
- package/dist/modules/configs/lib/upgrade-actions.js +28 -0
- package/dist/modules/configs/lib/upgrade-actions.js.map +2 -2
- package/dist/modules/customer_groups/api/customer-groups/[id]/terms/route.js +5 -0
- package/dist/modules/customer_groups/api/customer-groups/[id]/terms/route.js.map +2 -2
- package/dist/modules/customer_groups/components/CustomerGroupTermsSection.js +111 -3
- package/dist/modules/customer_groups/components/CustomerGroupTermsSection.js.map +2 -2
- package/dist/modules/customer_groups/components/customerGroupAssortmentScope.js +43 -0
- package/dist/modules/customer_groups/components/customerGroupAssortmentScope.js.map +7 -0
- package/dist/modules/customer_groups/data/entities.js +3 -0
- package/dist/modules/customer_groups/data/entities.js.map +2 -2
- package/dist/modules/customer_groups/data/validators.js +9 -0
- package/dist/modules/customer_groups/data/validators.js.map +2 -2
- package/dist/modules/customer_groups/migrations/Migration20261005110250_customer_groups.js +17 -0
- package/dist/modules/customer_groups/migrations/Migration20261005110250_customer_groups.js.map +7 -0
- package/dist/modules/customer_groups/services/customerGroupsService.js +62 -15
- package/dist/modules/customer_groups/services/customerGroupsService.js.map +2 -2
- package/dist/modules/ecommerce/acl.js +13 -0
- package/dist/modules/ecommerce/acl.js.map +7 -0
- package/dist/modules/ecommerce/api/domain-mappings/route.js +72 -0
- package/dist/modules/ecommerce/api/domain-mappings/route.js.map +7 -0
- package/dist/modules/ecommerce/api/openapi.js +27 -0
- package/dist/modules/ecommerce/api/openapi.js.map +7 -0
- package/dist/modules/ecommerce/api/store-channel-bindings/[id]/assortment-count/route.js +109 -0
- package/dist/modules/ecommerce/api/store-channel-bindings/[id]/assortment-count/route.js.map +7 -0
- package/dist/modules/ecommerce/api/store-channel-bindings/crud.js +265 -0
- package/dist/modules/ecommerce/api/store-channel-bindings/crud.js.map +7 -0
- package/dist/modules/ecommerce/api/store-channel-bindings/route.js +67 -0
- package/dist/modules/ecommerce/api/store-channel-bindings/route.js.map +7 -0
- package/dist/modules/ecommerce/api/store-domain-bindings/crud.js +296 -0
- package/dist/modules/ecommerce/api/store-domain-bindings/crud.js.map +7 -0
- package/dist/modules/ecommerce/api/store-domain-bindings/route.js +73 -0
- package/dist/modules/ecommerce/api/store-domain-bindings/route.js.map +7 -0
- package/dist/modules/ecommerce/api/storefront/categories/[slug]/route.js +87 -0
- package/dist/modules/ecommerce/api/storefront/categories/[slug]/route.js.map +7 -0
- package/dist/modules/ecommerce/api/storefront/categories/openapiSchemas.js +50 -0
- package/dist/modules/ecommerce/api/storefront/categories/openapiSchemas.js.map +7 -0
- package/dist/modules/ecommerce/api/storefront/categories/route.js +75 -0
- package/dist/modules/ecommerce/api/storefront/categories/route.js.map +7 -0
- package/dist/modules/ecommerce/api/storefront/context/route.js +163 -0
- package/dist/modules/ecommerce/api/storefront/context/route.js.map +7 -0
- package/dist/modules/ecommerce/api/storefront/products/[idOrHandle]/route.js +87 -0
- package/dist/modules/ecommerce/api/storefront/products/[idOrHandle]/route.js.map +7 -0
- package/dist/modules/ecommerce/api/storefront/products/openapiSchemas.js +177 -0
- package/dist/modules/ecommerce/api/storefront/products/openapiSchemas.js.map +7 -0
- package/dist/modules/ecommerce/api/storefront/products/route.js +78 -0
- package/dist/modules/ecommerce/api/storefront/products/route.js.map +7 -0
- package/dist/modules/ecommerce/api/storefront/search/suggest/openapiSchemas.js +25 -0
- package/dist/modules/ecommerce/api/storefront/search/suggest/openapiSchemas.js.map +7 -0
- package/dist/modules/ecommerce/api/storefront/search/suggest/route.js +75 -0
- package/dist/modules/ecommerce/api/storefront/search/suggest/route.js.map +7 -0
- package/dist/modules/ecommerce/api/storefront/storefrontRouteSupport.js +58 -0
- package/dist/modules/ecommerce/api/storefront/storefrontRouteSupport.js.map +7 -0
- package/dist/modules/ecommerce/api/stores/[id]/branding/route.js +183 -0
- package/dist/modules/ecommerce/api/stores/[id]/branding/route.js.map +7 -0
- package/dist/modules/ecommerce/api/stores/[id]/preview-branding/route.js +92 -0
- package/dist/modules/ecommerce/api/stores/[id]/preview-branding/route.js.map +7 -0
- package/dist/modules/ecommerce/api/stores/crud.js +401 -0
- package/dist/modules/ecommerce/api/stores/crud.js.map +7 -0
- package/dist/modules/ecommerce/api/stores/route.js +64 -0
- package/dist/modules/ecommerce/api/stores/route.js.map +7 -0
- package/dist/modules/ecommerce/backend/config/ecommerce/[id]/page.js +9 -0
- package/dist/modules/ecommerce/backend/config/ecommerce/[id]/page.js.map +7 -0
- package/dist/modules/ecommerce/backend/config/ecommerce/[id]/page.meta.js +16 -0
- package/dist/modules/ecommerce/backend/config/ecommerce/[id]/page.meta.js.map +7 -0
- package/dist/modules/ecommerce/backend/config/ecommerce/page.js +9 -0
- package/dist/modules/ecommerce/backend/config/ecommerce/page.js.map +7 -0
- package/dist/modules/ecommerce/backend/config/ecommerce/page.meta.js +16 -0
- package/dist/modules/ecommerce/backend/config/ecommerce/page.meta.js.map +7 -0
- package/dist/modules/ecommerce/commands/stores.js +110 -0
- package/dist/modules/ecommerce/commands/stores.js.map +7 -0
- package/dist/modules/ecommerce/components/ChannelAssortmentCount.js +90 -0
- package/dist/modules/ecommerce/components/ChannelAssortmentCount.js.map +7 -0
- package/dist/modules/ecommerce/components/ChannelBindingFormSections.js +33 -0
- package/dist/modules/ecommerce/components/ChannelBindingFormSections.js.map +7 -0
- package/dist/modules/ecommerce/components/ChannelLookupPicker.js +11 -0
- package/dist/modules/ecommerce/components/ChannelLookupPicker.js.map +7 -0
- package/dist/modules/ecommerce/components/DomainStatusWarning.js +24 -0
- package/dist/modules/ecommerce/components/DomainStatusWarning.js.map +7 -0
- package/dist/modules/ecommerce/components/StoreAvailabilityDefaultsSection.js +190 -0
- package/dist/modules/ecommerce/components/StoreAvailabilityDefaultsSection.js.map +7 -0
- package/dist/modules/ecommerce/components/StoreBrandingControls.js +67 -0
- package/dist/modules/ecommerce/components/StoreBrandingControls.js.map +7 -0
- package/dist/modules/ecommerce/components/StoreBrandingPreview.js +69 -0
- package/dist/modules/ecommerce/components/StoreBrandingPreview.js.map +7 -0
- package/dist/modules/ecommerce/components/StoreBrandingTab.js +218 -0
- package/dist/modules/ecommerce/components/StoreBrandingTab.js.map +7 -0
- package/dist/modules/ecommerce/components/StoreChannelBindingDialog.js +270 -0
- package/dist/modules/ecommerce/components/StoreChannelBindingDialog.js.map +7 -0
- package/dist/modules/ecommerce/components/StoreChannelsTab.js +313 -0
- package/dist/modules/ecommerce/components/StoreChannelsTab.js.map +7 -0
- package/dist/modules/ecommerce/components/StoreCreateDialog.js +164 -0
- package/dist/modules/ecommerce/components/StoreCreateDialog.js.map +7 -0
- package/dist/modules/ecommerce/components/StoreDomainBindingDialog.js +162 -0
- package/dist/modules/ecommerce/components/StoreDomainBindingDialog.js.map +7 -0
- package/dist/modules/ecommerce/components/StoreDomainsTab.js +357 -0
- package/dist/modules/ecommerce/components/StoreDomainsTab.js.map +7 -0
- package/dist/modules/ecommerce/components/StoreEditPage.js +155 -0
- package/dist/modules/ecommerce/components/StoreEditPage.js.map +7 -0
- package/dist/modules/ecommerce/components/StoreGeneralTab.js +167 -0
- package/dist/modules/ecommerce/components/StoreGeneralTab.js.map +7 -0
- package/dist/modules/ecommerce/components/StoreListPage.js +290 -0
- package/dist/modules/ecommerce/components/StoreListPage.js.map +7 -0
- package/dist/modules/ecommerce/components/StoreSeoTab.js +132 -0
- package/dist/modules/ecommerce/components/StoreSeoTab.js.map +7 -0
- package/dist/modules/ecommerce/components/StoreStatusBadge.js +20 -0
- package/dist/modules/ecommerce/components/StoreStatusBadge.js.map +7 -0
- package/dist/modules/ecommerce/components/channelLookups.js +28 -0
- package/dist/modules/ecommerce/components/channelLookups.js.map +7 -0
- package/dist/modules/ecommerce/components/storeAdmin.js +41 -0
- package/dist/modules/ecommerce/components/storeAdmin.js.map +7 -0
- package/dist/modules/ecommerce/components/storeBrandingForm.js +197 -0
- package/dist/modules/ecommerce/components/storeBrandingForm.js.map +7 -0
- package/dist/modules/ecommerce/components/storeChannels.js +140 -0
- package/dist/modules/ecommerce/components/storeChannels.js.map +7 -0
- package/dist/modules/ecommerce/components/storeDomains.js +167 -0
- package/dist/modules/ecommerce/components/storeDomains.js.map +7 -0
- package/dist/modules/ecommerce/components/storeEditTabs.js +62 -0
- package/dist/modules/ecommerce/components/storeEditTabs.js.map +7 -0
- package/dist/modules/ecommerce/components/storeGeneral.js +95 -0
- package/dist/modules/ecommerce/components/storeGeneral.js.map +7 -0
- package/dist/modules/ecommerce/components/storeSeo.js +69 -0
- package/dist/modules/ecommerce/components/storeSeo.js.map +7 -0
- package/dist/modules/ecommerce/components/useChannelAssortmentCount.js +45 -0
- package/dist/modules/ecommerce/components/useChannelAssortmentCount.js.map +7 -0
- package/dist/modules/ecommerce/components/useStoreAccess.js +28 -0
- package/dist/modules/ecommerce/components/useStoreAccess.js.map +7 -0
- package/dist/modules/ecommerce/data/enrichers.js +157 -0
- package/dist/modules/ecommerce/data/enrichers.js.map +7 -0
- package/dist/modules/ecommerce/data/entities.js +197 -0
- package/dist/modules/ecommerce/data/entities.js.map +7 -0
- package/dist/modules/ecommerce/data/validators.js +406 -0
- package/dist/modules/ecommerce/data/validators.js.map +7 -0
- package/dist/modules/ecommerce/di.js +11 -0
- package/dist/modules/ecommerce/di.js.map +7 -0
- package/dist/modules/ecommerce/events.js +27 -0
- package/dist/modules/ecommerce/events.js.map +7 -0
- package/dist/modules/ecommerce/index.js +16 -0
- package/dist/modules/ecommerce/index.js.map +7 -0
- package/dist/modules/ecommerce/lib/assortmentCount.js +112 -0
- package/dist/modules/ecommerce/lib/assortmentCount.js.map +7 -0
- package/dist/modules/ecommerce/lib/brandingStyles.js +184 -0
- package/dist/modules/ecommerce/lib/brandingStyles.js.map +7 -0
- package/dist/modules/ecommerce/lib/buyerContext.js +284 -0
- package/dist/modules/ecommerce/lib/buyerContext.js.map +7 -0
- package/dist/modules/ecommerce/lib/cacheInvalidation.js +186 -0
- package/dist/modules/ecommerce/lib/cacheInvalidation.js.map +7 -0
- package/dist/modules/ecommerce/lib/cacheKeys.js +236 -0
- package/dist/modules/ecommerce/lib/cacheKeys.js.map +7 -0
- package/dist/modules/ecommerce/lib/createConflictRecheck.js +29 -0
- package/dist/modules/ecommerce/lib/createConflictRecheck.js.map +7 -0
- package/dist/modules/ecommerce/lib/crudEvents.js +94 -0
- package/dist/modules/ecommerce/lib/crudEvents.js.map +7 -0
- package/dist/modules/ecommerce/lib/crudSupport.js +64 -0
- package/dist/modules/ecommerce/lib/crudSupport.js.map +7 -0
- package/dist/modules/ecommerce/lib/domainBindingRebind.js +99 -0
- package/dist/modules/ecommerce/lib/domainBindingRebind.js.map +7 -0
- package/dist/modules/ecommerce/lib/domainMappingSummaries.js +39 -0
- package/dist/modules/ecommerce/lib/domainMappingSummaries.js.map +7 -0
- package/dist/modules/ecommerce/lib/exclusiveFlag.js +57 -0
- package/dist/modules/ecommerce/lib/exclusiveFlag.js.map +7 -0
- package/dist/modules/ecommerce/lib/references.js +70 -0
- package/dist/modules/ecommerce/lib/references.js.map +7 -0
- package/dist/modules/ecommerce/lib/seedDraftStore.js +99 -0
- package/dist/modules/ecommerce/lib/seedDraftStore.js.map +7 -0
- package/dist/modules/ecommerce/lib/storeBindingCascade.js +109 -0
- package/dist/modules/ecommerce/lib/storeBindingCascade.js.map +7 -0
- package/dist/modules/ecommerce/lib/storeBranding.js +40 -0
- package/dist/modules/ecommerce/lib/storeBranding.js.map +7 -0
- package/dist/modules/ecommerce/lib/storeBrandingRoute.js +76 -0
- package/dist/modules/ecommerce/lib/storeBrandingRoute.js.map +7 -0
- package/dist/modules/ecommerce/lib/storeContext.js +393 -0
- package/dist/modules/ecommerce/lib/storeContext.js.map +7 -0
- package/dist/modules/ecommerce/lib/storeContextService.js +43 -0
- package/dist/modules/ecommerce/lib/storeContextService.js.map +7 -0
- package/dist/modules/ecommerce/lib/storeLocale.js +60 -0
- package/dist/modules/ecommerce/lib/storeLocale.js.map +7 -0
- package/dist/modules/ecommerce/lib/storeNotifications.js +41 -0
- package/dist/modules/ecommerce/lib/storeNotifications.js.map +7 -0
- package/dist/modules/ecommerce/lib/storefrontCatalogSupport.js +248 -0
- package/dist/modules/ecommerce/lib/storefrontCatalogSupport.js.map +7 -0
- package/dist/modules/ecommerce/lib/storefrontCategories.js +241 -0
- package/dist/modules/ecommerce/lib/storefrontCategories.js.map +7 -0
- package/dist/modules/ecommerce/lib/storefrontCategoryCache.js +71 -0
- package/dist/modules/ecommerce/lib/storefrontCategoryCache.js.map +7 -0
- package/dist/modules/ecommerce/lib/storefrontDetail.js +447 -0
- package/dist/modules/ecommerce/lib/storefrontDetail.js.map +7 -0
- package/dist/modules/ecommerce/lib/storefrontFacets.js +441 -0
- package/dist/modules/ecommerce/lib/storefrontFacets.js.map +7 -0
- package/dist/modules/ecommerce/lib/storefrontOptionFilter.js +15 -0
- package/dist/modules/ecommerce/lib/storefrontOptionFilter.js.map +7 -0
- package/dist/modules/ecommerce/lib/storefrontPricing.js +393 -0
- package/dist/modules/ecommerce/lib/storefrontPricing.js.map +7 -0
- package/dist/modules/ecommerce/lib/storefrontProductCache.js +90 -0
- package/dist/modules/ecommerce/lib/storefrontProductCache.js.map +7 -0
- package/dist/modules/ecommerce/lib/storefrontProductScope.js +107 -0
- package/dist/modules/ecommerce/lib/storefrontProductScope.js.map +7 -0
- package/dist/modules/ecommerce/lib/storefrontProducts.js +670 -0
- package/dist/modules/ecommerce/lib/storefrontProducts.js.map +7 -0
- package/dist/modules/ecommerce/lib/storefrontQuery.js +156 -0
- package/dist/modules/ecommerce/lib/storefrontQuery.js.map +7 -0
- package/dist/modules/ecommerce/lib/storefrontRateLimit.js +99 -0
- package/dist/modules/ecommerce/lib/storefrontRateLimit.js.map +7 -0
- package/dist/modules/ecommerce/lib/storefrontSearch.js +303 -0
- package/dist/modules/ecommerce/lib/storefrontSearch.js.map +7 -0
- package/dist/modules/ecommerce/lib/storefrontSearchCache.js +35 -0
- package/dist/modules/ecommerce/lib/storefrontSearchCache.js.map +7 -0
- package/dist/modules/ecommerce/lib/subscriberSupport.js +33 -0
- package/dist/modules/ecommerce/lib/subscriberSupport.js.map +7 -0
- package/dist/modules/ecommerce/lib/types.js +1 -0
- package/dist/modules/ecommerce/lib/types.js.map +7 -0
- package/dist/modules/ecommerce/migrations/Migration20261005113233_ecommerce.js +32 -0
- package/dist/modules/ecommerce/migrations/Migration20261005113233_ecommerce.js.map +7 -0
- package/dist/modules/ecommerce/migrations/Migration20261006112733_ecommerce.js +17 -0
- package/dist/modules/ecommerce/migrations/Migration20261006112733_ecommerce.js.map +7 -0
- package/dist/modules/ecommerce/notifications.client.js +47 -0
- package/dist/modules/ecommerce/notifications.client.js.map +7 -0
- package/dist/modules/ecommerce/notifications.js +48 -0
- package/dist/modules/ecommerce/notifications.js.map +7 -0
- package/dist/modules/ecommerce/search.js +83 -0
- package/dist/modules/ecommerce/search.js.map +7 -0
- package/dist/modules/ecommerce/setup.js +17 -0
- package/dist/modules/ecommerce/setup.js.map +7 -0
- package/dist/modules/ecommerce/subscribers/assortment-empty-notifications.js +14 -0
- package/dist/modules/ecommerce/subscribers/assortment-empty-notifications.js.map +7 -0
- package/dist/modules/ecommerce/subscribers/availability-policy-cache-invalidation.js +14 -0
- package/dist/modules/ecommerce/subscribers/availability-policy-cache-invalidation.js.map +7 -0
- package/dist/modules/ecommerce/subscribers/catalog-category-cache-invalidation.js +14 -0
- package/dist/modules/ecommerce/subscribers/catalog-category-cache-invalidation.js.map +7 -0
- package/dist/modules/ecommerce/subscribers/catalog-price-cache-invalidation.js +14 -0
- package/dist/modules/ecommerce/subscribers/catalog-price-cache-invalidation.js.map +7 -0
- package/dist/modules/ecommerce/subscribers/catalog-product-cache-invalidation.js +14 -0
- package/dist/modules/ecommerce/subscribers/catalog-product-cache-invalidation.js.map +7 -0
- package/dist/modules/ecommerce/subscribers/catalog-variant-cache-invalidation.js +14 -0
- package/dist/modules/ecommerce/subscribers/catalog-variant-cache-invalidation.js.map +7 -0
- package/dist/modules/ecommerce/subscribers/customer-group-cache-invalidation.js +14 -0
- package/dist/modules/ecommerce/subscribers/customer-group-cache-invalidation.js.map +7 -0
- package/dist/modules/ecommerce/subscribers/customer-group-membership-cache-invalidation.js +14 -0
- package/dist/modules/ecommerce/subscribers/customer-group-membership-cache-invalidation.js.map +7 -0
- package/dist/modules/ecommerce/subscribers/customer-group-terms-cache-invalidation.js +14 -0
- package/dist/modules/ecommerce/subscribers/customer-group-terms-cache-invalidation.js.map +7 -0
- package/dist/modules/ecommerce/subscribers/customer-user-deleted-cache-invalidation.js +14 -0
- package/dist/modules/ecommerce/subscribers/customer-user-deleted-cache-invalidation.js.map +7 -0
- package/dist/modules/ecommerce/subscribers/customer-user-updated-cache-invalidation.js +14 -0
- package/dist/modules/ecommerce/subscribers/customer-user-updated-cache-invalidation.js.map +7 -0
- package/dist/modules/ecommerce/subscribers/domain-binding-rebind.js +16 -0
- package/dist/modules/ecommerce/subscribers/domain-binding-rebind.js.map +7 -0
- package/dist/modules/ecommerce/subscribers/domain-mapping-cache-invalidation.js +14 -0
- package/dist/modules/ecommerce/subscribers/domain-mapping-cache-invalidation.js.map +7 -0
- package/dist/modules/ecommerce/subscribers/store-cache-invalidation.js +14 -0
- package/dist/modules/ecommerce/subscribers/store-cache-invalidation.js.map +7 -0
- package/dist/modules/ecommerce/subscribers/store-channel-binding-cache-invalidation.js +14 -0
- package/dist/modules/ecommerce/subscribers/store-channel-binding-cache-invalidation.js.map +7 -0
- package/dist/modules/ecommerce/subscribers/store-domain-binding-cache-invalidation.js +14 -0
- package/dist/modules/ecommerce/subscribers/store-domain-binding-cache-invalidation.js.map +7 -0
- package/dist/modules/ecommerce/subscribers/store-notifications.js +14 -0
- package/dist/modules/ecommerce/subscribers/store-notifications.js.map +7 -0
- package/dist/modules/query_index/lib/batch.js +23 -9
- package/dist/modules/query_index/lib/batch.js.map +2 -2
- package/dist/modules/query_index/lib/doc-enrichers.js +212 -0
- package/dist/modules/query_index/lib/doc-enrichers.js.map +7 -0
- package/dist/modules/query_index/lib/document.js +2 -0
- package/dist/modules/query_index/lib/document.js.map +2 -2
- package/dist/modules/query_index/lib/engine.js +68 -1
- package/dist/modules/query_index/lib/engine.js.map +2 -2
- package/dist/modules/query_index/lib/indexer.js +7 -0
- package/dist/modules/query_index/lib/indexer.js.map +2 -2
- package/dist/modules/query_index/lib/search-tokens.js +2 -0
- package/dist/modules/query_index/lib/search-tokens.js.map +2 -2
- package/dist/modules/query_index/migrations/Migration20261005201500_query_index.js +17 -0
- package/dist/modules/query_index/migrations/Migration20261005201500_query_index.js.map +7 -0
- package/dist/modules/translations/components/TranslationManager.js +3 -3
- package/dist/modules/translations/components/TranslationManager.js.map +2 -2
- package/dist/modules/translations/data/validators.js +1 -1
- package/dist/modules/translations/data/validators.js.map +1 -1
- package/dist/modules/translations/lib/batch.js +21 -1
- package/dist/modules/translations/lib/batch.js.map +2 -2
- package/dist/modules/translations/lib/helpers.js +3 -0
- package/dist/modules/translations/lib/helpers.js.map +2 -2
- package/dist/modules/translations/lib/resolve-field-list.js +14 -2
- package/dist/modules/translations/lib/resolve-field-list.js.map +2 -2
- package/generated/entities/catalog_price_history_entry/index.ts +25 -0
- package/generated/entities/customer_group_terms/index.ts +1 -0
- package/generated/entities/ecommerce_store/index.ts +15 -0
- package/generated/entities/ecommerce_store_channel_binding/index.ts +13 -0
- package/generated/entities/ecommerce_store_domain_binding/index.ts +10 -0
- package/generated/entities.ids.generated.ts +8 -1
- package/generated/entity-fields-registry.ts +72 -0
- package/package.json +7 -7
- package/src/helpers/integration/customerGroupsFixtures.ts +2 -0
- package/src/modules/auth/i18n/de.json +8 -0
- package/src/modules/auth/i18n/en.json +8 -0
- package/src/modules/auth/i18n/es.json +8 -0
- package/src/modules/auth/i18n/ko.json +8 -0
- package/src/modules/auth/i18n/pl.json +8 -0
- package/src/modules/catalog/AGENTS.md +5 -2
- package/src/modules/catalog/acl.ts +7 -0
- package/src/modules/catalog/api/config/omnibus/route.ts +204 -0
- package/src/modules/catalog/api/prices/history/route.ts +139 -0
- package/src/modules/catalog/api/prices/omnibus-preview/route.ts +202 -0
- package/src/modules/catalog/api/products/route.ts +53 -308
- package/src/modules/catalog/api/tags/route.ts +6 -0
- package/src/modules/catalog/backend/config/catalog/page.tsx +2 -0
- package/src/modules/catalog/cli.ts +84 -1
- package/src/modules/catalog/commands/categories.ts +54 -2
- package/src/modules/catalog/commands/prices.ts +43 -1
- package/src/modules/catalog/commands/products.ts +84 -1
- package/src/modules/catalog/commands/variants.ts +7 -0
- package/src/modules/catalog/components/OmnibusSettings.tsx +832 -0
- package/src/modules/catalog/components/PriceEditorOmnibusRow.tsx +219 -0
- package/src/modules/catalog/components/lookupSources.ts +29 -0
- package/src/modules/catalog/components/prices/PriceScopeSelectors.tsx +9 -0
- package/src/modules/catalog/components/products/VariantBuilder.tsx +9 -0
- package/src/modules/catalog/data/entities.ts +123 -1
- package/src/modules/catalog/data/validators.ts +118 -0
- package/src/modules/catalog/di.ts +23 -0
- package/src/modules/catalog/i18n/de.json +77 -0
- package/src/modules/catalog/i18n/en.json +77 -0
- package/src/modules/catalog/i18n/es.json +77 -0
- package/src/modules/catalog/i18n/ko.json +77 -0
- package/src/modules/catalog/i18n/pl.json +77 -0
- package/src/modules/catalog/lib/omnibus.ts +406 -0
- package/src/modules/catalog/lib/omnibusBackfill.ts +198 -0
- package/src/modules/catalog/lib/omnibusCache.ts +111 -0
- package/src/modules/catalog/lib/omnibusConfig.ts +73 -0
- package/src/modules/catalog/lib/omnibusHistoryQueries.ts +248 -0
- package/src/modules/catalog/lib/omnibusPresentedEntry.ts +76 -0
- package/src/modules/catalog/lib/omnibusProductListEnrichment.ts +125 -0
- package/src/modules/catalog/lib/omnibusTypes.ts +202 -0
- package/src/modules/catalog/lib/optionSchemaTranslations.ts +55 -0
- package/src/modules/catalog/lib/priceHistoryQuery.ts +155 -0
- package/src/modules/catalog/lib/pricing.ts +42 -4
- package/src/modules/catalog/lib/productFilters.ts +349 -0
- package/src/modules/catalog/lib/productScopeKeys.ts +162 -0
- package/src/modules/catalog/lib/productScopeReindex.ts +139 -0
- package/src/modules/catalog/migrations/.snapshot-open-mercato.json +572 -0
- package/src/modules/catalog/migrations/Migration20261005105352_catalog.ts +39 -0
- package/src/modules/catalog/migrations/Migration20261005150824_catalog.ts +39 -0
- package/src/modules/catalog/services/catalogOmnibusService.ts +642 -0
- package/src/modules/catalog/setup.ts +2 -0
- package/src/modules/catalog/subscribers/product-scope-keys-category-deleted.ts +18 -0
- package/src/modules/catalog/subscribers/product-scope-keys-category-updated.ts +19 -0
- package/src/modules/catalog/translations.ts +12 -0
- package/src/modules/configs/i18n/de.json +5 -1
- package/src/modules/configs/i18n/en.json +5 -1
- package/src/modules/configs/i18n/es.json +5 -1
- package/src/modules/configs/i18n/ko.json +5 -1
- package/src/modules/configs/i18n/pl.json +5 -1
- package/src/modules/configs/lib/upgrade-actions.ts +35 -0
- package/src/modules/customer_groups/api/customer-groups/[id]/terms/route.ts +7 -0
- package/src/modules/customer_groups/components/CustomerGroupTermsSection.tsx +124 -2
- package/src/modules/customer_groups/components/customerGroupAssortmentScope.ts +46 -0
- package/src/modules/customer_groups/data/entities.ts +4 -0
- package/src/modules/customer_groups/data/validators.ts +14 -0
- package/src/modules/customer_groups/i18n/de.json +12 -0
- package/src/modules/customer_groups/i18n/en.json +12 -0
- package/src/modules/customer_groups/i18n/es.json +12 -0
- package/src/modules/customer_groups/i18n/ko.json +12 -0
- package/src/modules/customer_groups/i18n/pl.json +12 -0
- package/src/modules/customer_groups/migrations/.snapshot-open-mercato.json +17 -0
- package/src/modules/customer_groups/migrations/Migration20261005110250_customer_groups.ts +15 -0
- package/src/modules/customer_groups/services/customerGroupsService.ts +74 -23
- package/src/modules/ecommerce/acl.ts +9 -0
- package/src/modules/ecommerce/api/domain-mappings/route.ts +76 -0
- package/src/modules/ecommerce/api/openapi.ts +28 -0
- package/src/modules/ecommerce/api/store-channel-bindings/[id]/assortment-count/route.ts +141 -0
- package/src/modules/ecommerce/api/store-channel-bindings/crud.ts +283 -0
- package/src/modules/ecommerce/api/store-channel-bindings/route.ts +67 -0
- package/src/modules/ecommerce/api/store-domain-bindings/crud.ts +324 -0
- package/src/modules/ecommerce/api/store-domain-bindings/route.ts +73 -0
- package/src/modules/ecommerce/api/storefront/categories/[slug]/route.ts +94 -0
- package/src/modules/ecommerce/api/storefront/categories/openapiSchemas.ts +63 -0
- package/src/modules/ecommerce/api/storefront/categories/route.ts +78 -0
- package/src/modules/ecommerce/api/storefront/context/route.ts +203 -0
- package/src/modules/ecommerce/api/storefront/products/[idOrHandle]/route.ts +94 -0
- package/src/modules/ecommerce/api/storefront/products/openapiSchemas.ts +193 -0
- package/src/modules/ecommerce/api/storefront/products/route.ts +81 -0
- package/src/modules/ecommerce/api/storefront/search/suggest/openapiSchemas.ts +25 -0
- package/src/modules/ecommerce/api/storefront/search/suggest/route.ts +78 -0
- package/src/modules/ecommerce/api/storefront/storefrontRouteSupport.ts +68 -0
- package/src/modules/ecommerce/api/stores/[id]/branding/route.ts +205 -0
- package/src/modules/ecommerce/api/stores/[id]/preview-branding/route.ts +99 -0
- package/src/modules/ecommerce/api/stores/crud.ts +457 -0
- package/src/modules/ecommerce/api/stores/route.ts +66 -0
- package/src/modules/ecommerce/backend/config/ecommerce/[id]/page.meta.ts +12 -0
- package/src/modules/ecommerce/backend/config/ecommerce/[id]/page.tsx +5 -0
- package/src/modules/ecommerce/backend/config/ecommerce/page.meta.ts +12 -0
- package/src/modules/ecommerce/backend/config/ecommerce/page.tsx +5 -0
- package/src/modules/ecommerce/commands/stores.ts +154 -0
- package/src/modules/ecommerce/components/ChannelAssortmentCount.tsx +138 -0
- package/src/modules/ecommerce/components/ChannelBindingFormSections.tsx +40 -0
- package/src/modules/ecommerce/components/ChannelLookupPicker.tsx +5 -0
- package/src/modules/ecommerce/components/DomainStatusWarning.tsx +32 -0
- package/src/modules/ecommerce/components/StoreAvailabilityDefaultsSection.tsx +219 -0
- package/src/modules/ecommerce/components/StoreBrandingControls.tsx +73 -0
- package/src/modules/ecommerce/components/StoreBrandingPreview.tsx +77 -0
- package/src/modules/ecommerce/components/StoreBrandingTab.tsx +242 -0
- package/src/modules/ecommerce/components/StoreChannelBindingDialog.tsx +306 -0
- package/src/modules/ecommerce/components/StoreChannelsTab.tsx +375 -0
- package/src/modules/ecommerce/components/StoreCreateDialog.tsx +204 -0
- package/src/modules/ecommerce/components/StoreDomainBindingDialog.tsx +198 -0
- package/src/modules/ecommerce/components/StoreDomainsTab.tsx +426 -0
- package/src/modules/ecommerce/components/StoreEditPage.tsx +193 -0
- package/src/modules/ecommerce/components/StoreGeneralTab.tsx +189 -0
- package/src/modules/ecommerce/components/StoreListPage.tsx +326 -0
- package/src/modules/ecommerce/components/StoreSeoTab.tsx +152 -0
- package/src/modules/ecommerce/components/StoreStatusBadge.tsx +22 -0
- package/src/modules/ecommerce/components/channelLookups.ts +24 -0
- package/src/modules/ecommerce/components/storeAdmin.ts +56 -0
- package/src/modules/ecommerce/components/storeBrandingForm.ts +230 -0
- package/src/modules/ecommerce/components/storeChannels.ts +210 -0
- package/src/modules/ecommerce/components/storeDomains.ts +221 -0
- package/src/modules/ecommerce/components/storeEditTabs.tsx +76 -0
- package/src/modules/ecommerce/components/storeGeneral.ts +155 -0
- package/src/modules/ecommerce/components/storeSeo.ts +78 -0
- package/src/modules/ecommerce/components/useChannelAssortmentCount.ts +67 -0
- package/src/modules/ecommerce/components/useStoreAccess.ts +36 -0
- package/src/modules/ecommerce/data/enrichers.ts +213 -0
- package/src/modules/ecommerce/data/entities.ts +168 -0
- package/src/modules/ecommerce/data/validators.ts +587 -0
- package/src/modules/ecommerce/di.ts +9 -0
- package/src/modules/ecommerce/events.ts +27 -0
- package/src/modules/ecommerce/i18n/de.json +341 -0
- package/src/modules/ecommerce/i18n/en.json +341 -0
- package/src/modules/ecommerce/i18n/es.json +341 -0
- package/src/modules/ecommerce/i18n/ko.json +341 -0
- package/src/modules/ecommerce/i18n/pl.json +341 -0
- package/src/modules/ecommerce/index.ts +14 -0
- package/src/modules/ecommerce/lib/assortmentCount.ts +175 -0
- package/src/modules/ecommerce/lib/brandingStyles.ts +215 -0
- package/src/modules/ecommerce/lib/buyerContext.ts +401 -0
- package/src/modules/ecommerce/lib/cacheInvalidation.ts +302 -0
- package/src/modules/ecommerce/lib/cacheKeys.ts +340 -0
- package/src/modules/ecommerce/lib/createConflictRecheck.ts +31 -0
- package/src/modules/ecommerce/lib/crudEvents.ts +128 -0
- package/src/modules/ecommerce/lib/crudSupport.ts +85 -0
- package/src/modules/ecommerce/lib/domainBindingRebind.ts +138 -0
- package/src/modules/ecommerce/lib/domainMappingSummaries.ts +71 -0
- package/src/modules/ecommerce/lib/exclusiveFlag.ts +90 -0
- package/src/modules/ecommerce/lib/references.ts +93 -0
- package/src/modules/ecommerce/lib/seedDraftStore.ts +125 -0
- package/src/modules/ecommerce/lib/storeBindingCascade.ts +138 -0
- package/src/modules/ecommerce/lib/storeBranding.ts +48 -0
- package/src/modules/ecommerce/lib/storeBrandingRoute.ts +91 -0
- package/src/modules/ecommerce/lib/storeContext.ts +669 -0
- package/src/modules/ecommerce/lib/storeContextService.ts +71 -0
- package/src/modules/ecommerce/lib/storeLocale.ts +88 -0
- package/src/modules/ecommerce/lib/storeNotifications.ts +55 -0
- package/src/modules/ecommerce/lib/storefrontCatalogSupport.ts +427 -0
- package/src/modules/ecommerce/lib/storefrontCategories.ts +419 -0
- package/src/modules/ecommerce/lib/storefrontCategoryCache.ts +113 -0
- package/src/modules/ecommerce/lib/storefrontDetail.ts +654 -0
- package/src/modules/ecommerce/lib/storefrontFacets.ts +697 -0
- package/src/modules/ecommerce/lib/storefrontOptionFilter.ts +44 -0
- package/src/modules/ecommerce/lib/storefrontPricing.ts +583 -0
- package/src/modules/ecommerce/lib/storefrontProductCache.ts +126 -0
- package/src/modules/ecommerce/lib/storefrontProductScope.ts +181 -0
- package/src/modules/ecommerce/lib/storefrontProducts.ts +963 -0
- package/src/modules/ecommerce/lib/storefrontQuery.ts +215 -0
- package/src/modules/ecommerce/lib/storefrontRateLimit.ts +126 -0
- package/src/modules/ecommerce/lib/storefrontSearch.ts +454 -0
- package/src/modules/ecommerce/lib/storefrontSearchCache.ts +49 -0
- package/src/modules/ecommerce/lib/subscriberSupport.ts +41 -0
- package/src/modules/ecommerce/lib/types.ts +69 -0
- package/src/modules/ecommerce/migrations/.snapshot-open-mercato.json +829 -0
- package/src/modules/ecommerce/migrations/Migration20261005113233_ecommerce.ts +32 -0
- package/src/modules/ecommerce/migrations/Migration20261006112733_ecommerce.ts +15 -0
- package/src/modules/ecommerce/notifications.client.ts +46 -0
- package/src/modules/ecommerce/notifications.ts +46 -0
- package/src/modules/ecommerce/search.ts +93 -0
- package/src/modules/ecommerce/setup.ts +15 -0
- package/src/modules/ecommerce/subscribers/assortment-empty-notifications.ts +12 -0
- package/src/modules/ecommerce/subscribers/availability-policy-cache-invalidation.ts +12 -0
- package/src/modules/ecommerce/subscribers/catalog-category-cache-invalidation.ts +12 -0
- package/src/modules/ecommerce/subscribers/catalog-price-cache-invalidation.ts +12 -0
- package/src/modules/ecommerce/subscribers/catalog-product-cache-invalidation.ts +12 -0
- package/src/modules/ecommerce/subscribers/catalog-variant-cache-invalidation.ts +12 -0
- package/src/modules/ecommerce/subscribers/customer-group-cache-invalidation.ts +12 -0
- package/src/modules/ecommerce/subscribers/customer-group-membership-cache-invalidation.ts +12 -0
- package/src/modules/ecommerce/subscribers/customer-group-terms-cache-invalidation.ts +12 -0
- package/src/modules/ecommerce/subscribers/customer-user-deleted-cache-invalidation.ts +12 -0
- package/src/modules/ecommerce/subscribers/customer-user-updated-cache-invalidation.ts +12 -0
- package/src/modules/ecommerce/subscribers/domain-binding-rebind.ts +14 -0
- package/src/modules/ecommerce/subscribers/domain-mapping-cache-invalidation.ts +12 -0
- package/src/modules/ecommerce/subscribers/store-cache-invalidation.ts +12 -0
- package/src/modules/ecommerce/subscribers/store-channel-binding-cache-invalidation.ts +12 -0
- package/src/modules/ecommerce/subscribers/store-domain-binding-cache-invalidation.ts +12 -0
- package/src/modules/ecommerce/subscribers/store-notifications.ts +12 -0
- package/src/modules/query_index/lib/batch.ts +25 -9
- package/src/modules/query_index/lib/doc-enrichers.ts +306 -0
- package/src/modules/query_index/lib/document.ts +2 -0
- package/src/modules/query_index/lib/engine.ts +58 -1
- package/src/modules/query_index/lib/indexer.ts +8 -0
- package/src/modules/query_index/lib/search-tokens.ts +2 -0
- package/src/modules/query_index/migrations/Migration20261005201500_query_index.ts +42 -0
- package/src/modules/translations/components/TranslationManager.tsx +3 -3
- package/src/modules/translations/data/validators.ts +1 -1
- package/src/modules/translations/lib/batch.ts +47 -0
- package/src/modules/translations/lib/helpers.ts +4 -0
- package/src/modules/translations/lib/resolve-field-list.ts +16 -2
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { NextResponse } from "next/server";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { isCrudHttpError } from "@open-mercato/shared/lib/crud/errors";
|
|
4
|
+
import { createLogger } from "@open-mercato/shared/lib/logger";
|
|
5
|
+
import { loadOrganizationDomainMappings } from "../../lib/domainMappingSummaries.js";
|
|
6
|
+
import { resolveBrandingRouteContext } from "../../lib/storeBrandingRoute.js";
|
|
7
|
+
import { ecommerceInternalErrorBody, translateEcommerceError } from "../../lib/crudSupport.js";
|
|
8
|
+
const metadata = {
|
|
9
|
+
GET: { requireAuth: true, requireFeatures: ["ecommerce.stores.view"] }
|
|
10
|
+
};
|
|
11
|
+
const logger = createLogger("ecommerce").child({ component: "domain-mappings-route" });
|
|
12
|
+
async function GET(req) {
|
|
13
|
+
try {
|
|
14
|
+
const context = await resolveBrandingRouteContext(req);
|
|
15
|
+
const mappings = await loadOrganizationDomainMappings(context.container, {
|
|
16
|
+
organizationId: context.organizationId,
|
|
17
|
+
tenantId: context.tenantId
|
|
18
|
+
});
|
|
19
|
+
if (!mappings) {
|
|
20
|
+
const error = await translateEcommerceError(
|
|
21
|
+
"ecommerce.errors.domainMappingsUnavailable",
|
|
22
|
+
"Domains are unavailable right now. Try again later."
|
|
23
|
+
);
|
|
24
|
+
return NextResponse.json({ error }, { status: 503 });
|
|
25
|
+
}
|
|
26
|
+
const items = [...mappings].sort((left, right) => left.hostname.localeCompare(right.hostname));
|
|
27
|
+
return NextResponse.json({ items, total: items.length }, { headers: { "Cache-Control": "no-store" } });
|
|
28
|
+
} catch (err) {
|
|
29
|
+
if (isCrudHttpError(err)) return NextResponse.json(err.body, { status: err.status });
|
|
30
|
+
logger.error("ecommerce.domain-mappings.GET failed", { err });
|
|
31
|
+
return NextResponse.json(await ecommerceInternalErrorBody(), { status: 500 });
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
const domainMappingItemSchema = z.object({
|
|
35
|
+
id: z.string().uuid(),
|
|
36
|
+
hostname: z.string(),
|
|
37
|
+
status: z.string().describe("customer_accounts domain status: pending, verified, active, dns_failed or tls_failed. Only active serves."),
|
|
38
|
+
lastDnsCheckAt: z.string().nullable(),
|
|
39
|
+
dnsFailureReason: z.string().nullable(),
|
|
40
|
+
tlsFailureReason: z.string().nullable()
|
|
41
|
+
});
|
|
42
|
+
const errorSchema = z.object({ error: z.string() }).passthrough();
|
|
43
|
+
const openApi = {
|
|
44
|
+
tag: "Ecommerce",
|
|
45
|
+
summary: "Domain mappings available to store bindings",
|
|
46
|
+
methods: {
|
|
47
|
+
GET: {
|
|
48
|
+
summary: "List the domain mappings of the selected organization",
|
|
49
|
+
description: "Read-only list of the customer_accounts domain mappings (any status) of the selected organization, read through domainMappingService. Backs the domain picker of the store Domains tab, so that managing store bindings does not require the customer_accounts domain permission. Requires ecommerce.stores.view.",
|
|
50
|
+
tags: ["Ecommerce"],
|
|
51
|
+
responses: [
|
|
52
|
+
{
|
|
53
|
+
status: 200,
|
|
54
|
+
description: "Domain mappings of the selected organization",
|
|
55
|
+
schema: z.object({ items: z.array(domainMappingItemSchema), total: z.number().int() })
|
|
56
|
+
}
|
|
57
|
+
],
|
|
58
|
+
errors: [
|
|
59
|
+
{ status: 400, description: "No organization is selected", schema: errorSchema },
|
|
60
|
+
{ status: 401, description: "Unauthorized", schema: errorSchema },
|
|
61
|
+
{ status: 403, description: "Missing ecommerce.stores.view", schema: errorSchema },
|
|
62
|
+
{ status: 503, description: "The domain mapping service is not available", schema: errorSchema }
|
|
63
|
+
]
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
export {
|
|
68
|
+
GET,
|
|
69
|
+
metadata,
|
|
70
|
+
openApi
|
|
71
|
+
};
|
|
72
|
+
//# sourceMappingURL=route.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../../src/modules/ecommerce/api/domain-mappings/route.ts"],
|
|
4
|
+
"sourcesContent": ["import { NextResponse } from 'next/server'\nimport { z } from 'zod'\nimport { isCrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\nimport type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'\nimport { loadOrganizationDomainMappings } from '../../lib/domainMappingSummaries'\nimport { resolveBrandingRouteContext } from '../../lib/storeBrandingRoute'\nimport { ecommerceInternalErrorBody, translateEcommerceError } from '../../lib/crudSupport'\n\nexport const metadata = {\n GET: { requireAuth: true, requireFeatures: ['ecommerce.stores.view'] },\n}\n\nconst logger = createLogger('ecommerce').child({ component: 'domain-mappings-route' })\n\nexport async function GET(req: Request) {\n try {\n const context = await resolveBrandingRouteContext(req)\n const mappings = await loadOrganizationDomainMappings(context.container, {\n organizationId: context.organizationId,\n tenantId: context.tenantId,\n })\n if (!mappings) {\n const error = await translateEcommerceError(\n 'ecommerce.errors.domainMappingsUnavailable',\n 'Domains are unavailable right now. Try again later.',\n )\n return NextResponse.json({ error }, { status: 503 })\n }\n const items = [...mappings].sort((left, right) => left.hostname.localeCompare(right.hostname))\n return NextResponse.json({ items, total: items.length }, { headers: { 'Cache-Control': 'no-store' } })\n } catch (err) {\n if (isCrudHttpError(err)) return NextResponse.json(err.body, { status: err.status })\n logger.error('ecommerce.domain-mappings.GET failed', { err })\n return NextResponse.json(await ecommerceInternalErrorBody(), { status: 500 })\n }\n}\n\nconst domainMappingItemSchema = z.object({\n id: z.string().uuid(),\n hostname: z.string(),\n status: z\n .string()\n .describe('customer_accounts domain status: pending, verified, active, dns_failed or tls_failed. Only active serves.'),\n lastDnsCheckAt: z.string().nullable(),\n dnsFailureReason: z.string().nullable(),\n tlsFailureReason: z.string().nullable(),\n})\n\nconst errorSchema = z.object({ error: z.string() }).passthrough()\n\nexport const openApi: OpenApiRouteDoc = {\n tag: 'Ecommerce',\n summary: 'Domain mappings available to store bindings',\n methods: {\n GET: {\n summary: 'List the domain mappings of the selected organization',\n description:\n 'Read-only list of the customer_accounts domain mappings (any status) of the selected organization, read through domainMappingService. Backs the domain picker of the store Domains tab, so that managing store bindings does not require the customer_accounts domain permission. Requires ecommerce.stores.view.',\n tags: ['Ecommerce'],\n responses: [\n {\n status: 200,\n description: 'Domain mappings of the selected organization',\n schema: z.object({ items: z.array(domainMappingItemSchema), total: z.number().int() }),\n },\n ],\n errors: [\n { status: 400, description: 'No organization is selected', schema: errorSchema },\n { status: 401, description: 'Unauthorized', schema: errorSchema },\n { status: 403, description: 'Missing ecommerce.stores.view', schema: errorSchema },\n { status: 503, description: 'The domain mapping service is not available', schema: errorSchema },\n ],\n },\n },\n}\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,oBAAoB;AAC7B,SAAS,SAAS;AAClB,SAAS,uBAAuB;AAChC,SAAS,oBAAoB;AAE7B,SAAS,sCAAsC;AAC/C,SAAS,mCAAmC;AAC5C,SAAS,4BAA4B,+BAA+B;AAE7D,MAAM,WAAW;AAAA,EACtB,KAAK,EAAE,aAAa,MAAM,iBAAiB,CAAC,uBAAuB,EAAE;AACvE;AAEA,MAAM,SAAS,aAAa,WAAW,EAAE,MAAM,EAAE,WAAW,wBAAwB,CAAC;AAErF,eAAsB,IAAI,KAAc;AACtC,MAAI;AACF,UAAM,UAAU,MAAM,4BAA4B,GAAG;AACrD,UAAM,WAAW,MAAM,+BAA+B,QAAQ,WAAW;AAAA,MACvE,gBAAgB,QAAQ;AAAA,MACxB,UAAU,QAAQ;AAAA,IACpB,CAAC;AACD,QAAI,CAAC,UAAU;AACb,YAAM,QAAQ,MAAM;AAAA,QAClB;AAAA,QACA;AAAA,MACF;AACA,aAAO,aAAa,KAAK,EAAE,MAAM,GAAG,EAAE,QAAQ,IAAI,CAAC;AAAA,IACrD;AACA,UAAM,QAAQ,CAAC,GAAG,QAAQ,EAAE,KAAK,CAAC,MAAM,UAAU,KAAK,SAAS,cAAc,MAAM,QAAQ,CAAC;AAC7F,WAAO,aAAa,KAAK,EAAE,OAAO,OAAO,MAAM,OAAO,GAAG,EAAE,SAAS,EAAE,iBAAiB,WAAW,EAAE,CAAC;AAAA,EACvG,SAAS,KAAK;AACZ,QAAI,gBAAgB,GAAG,EAAG,QAAO,aAAa,KAAK,IAAI,MAAM,EAAE,QAAQ,IAAI,OAAO,CAAC;AACnF,WAAO,MAAM,wCAAwC,EAAE,IAAI,CAAC;AAC5D,WAAO,aAAa,KAAK,MAAM,2BAA2B,GAAG,EAAE,QAAQ,IAAI,CAAC;AAAA,EAC9E;AACF;AAEA,MAAM,0BAA0B,EAAE,OAAO;AAAA,EACvC,IAAI,EAAE,OAAO,EAAE,KAAK;AAAA,EACpB,UAAU,EAAE,OAAO;AAAA,EACnB,QAAQ,EACL,OAAO,EACP,SAAS,2GAA2G;AAAA,EACvH,gBAAgB,EAAE,OAAO,EAAE,SAAS;AAAA,EACpC,kBAAkB,EAAE,OAAO,EAAE,SAAS;AAAA,EACtC,kBAAkB,EAAE,OAAO,EAAE,SAAS;AACxC,CAAC;AAED,MAAM,cAAc,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,YAAY;AAEzD,MAAM,UAA2B;AAAA,EACtC,KAAK;AAAA,EACL,SAAS;AAAA,EACT,SAAS;AAAA,IACP,KAAK;AAAA,MACH,SAAS;AAAA,MACT,aACE;AAAA,MACF,MAAM,CAAC,WAAW;AAAA,MAClB,WAAW;AAAA,QACT;AAAA,UACE,QAAQ;AAAA,UACR,aAAa;AAAA,UACb,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAuB,GAAG,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;AAAA,QACvF;AAAA,MACF;AAAA,MACA,QAAQ;AAAA,QACN,EAAE,QAAQ,KAAK,aAAa,+BAA+B,QAAQ,YAAY;AAAA,QAC/E,EAAE,QAAQ,KAAK,aAAa,gBAAgB,QAAQ,YAAY;AAAA,QAChE,EAAE,QAAQ,KAAK,aAAa,iCAAiC,QAAQ,YAAY;AAAA,QACjF,EAAE,QAAQ,KAAK,aAAa,+CAA+C,QAAQ,YAAY;AAAA,MACjG;AAAA,IACF;AAAA,EACF;AACF;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createCrudOpenApiFactory,
|
|
3
|
+
createPagedListResponseSchema as createSharedPagedListResponseSchema,
|
|
4
|
+
defaultCreateResponseSchema as sharedDefaultCreateResponseSchema,
|
|
5
|
+
defaultOkResponseSchema as sharedDefaultOkResponseSchema
|
|
6
|
+
} from "@open-mercato/shared/lib/openapi/crud";
|
|
7
|
+
const defaultCreateResponseSchema = sharedDefaultCreateResponseSchema;
|
|
8
|
+
const defaultOkResponseSchema = sharedDefaultOkResponseSchema;
|
|
9
|
+
function createPagedListResponseSchema(itemSchema) {
|
|
10
|
+
return createSharedPagedListResponseSchema(itemSchema, { paginationMetaOptional: true });
|
|
11
|
+
}
|
|
12
|
+
const buildEcommerceCrudOpenApi = createCrudOpenApiFactory({
|
|
13
|
+
defaultTag: "Ecommerce",
|
|
14
|
+
defaultCreateResponseSchema,
|
|
15
|
+
defaultOkResponseSchema,
|
|
16
|
+
makeListDescription: ({ pluralLower }) => `Returns a paginated collection of ${pluralLower} scoped to the authenticated tenant and organization.`
|
|
17
|
+
});
|
|
18
|
+
function createEcommerceCrudOpenApi(options) {
|
|
19
|
+
return buildEcommerceCrudOpenApi(options);
|
|
20
|
+
}
|
|
21
|
+
export {
|
|
22
|
+
createEcommerceCrudOpenApi,
|
|
23
|
+
createPagedListResponseSchema,
|
|
24
|
+
defaultCreateResponseSchema,
|
|
25
|
+
defaultOkResponseSchema
|
|
26
|
+
};
|
|
27
|
+
//# sourceMappingURL=openapi.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/modules/ecommerce/api/openapi.ts"],
|
|
4
|
+
"sourcesContent": ["import { type ZodTypeAny } from 'zod'\nimport type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'\nimport {\n createCrudOpenApiFactory,\n createPagedListResponseSchema as createSharedPagedListResponseSchema,\n defaultCreateResponseSchema as sharedDefaultCreateResponseSchema,\n defaultOkResponseSchema as sharedDefaultOkResponseSchema,\n type CrudOpenApiOptions,\n} from '@open-mercato/shared/lib/openapi/crud'\n\nexport const defaultCreateResponseSchema = sharedDefaultCreateResponseSchema\nexport const defaultOkResponseSchema = sharedDefaultOkResponseSchema\n\nexport function createPagedListResponseSchema(itemSchema: ZodTypeAny) {\n return createSharedPagedListResponseSchema(itemSchema, { paginationMetaOptional: true })\n}\n\nconst buildEcommerceCrudOpenApi = createCrudOpenApiFactory({\n defaultTag: 'Ecommerce',\n defaultCreateResponseSchema,\n defaultOkResponseSchema,\n makeListDescription: ({ pluralLower }) =>\n `Returns a paginated collection of ${pluralLower} scoped to the authenticated tenant and organization.`,\n})\n\nexport function createEcommerceCrudOpenApi(options: CrudOpenApiOptions): OpenApiRouteDoc {\n return buildEcommerceCrudOpenApi(options)\n}\n"],
|
|
5
|
+
"mappings": "AAEA;AAAA,EACE;AAAA,EACA,iCAAiC;AAAA,EACjC,+BAA+B;AAAA,EAC/B,2BAA2B;AAAA,OAEtB;AAEA,MAAM,8BAA8B;AACpC,MAAM,0BAA0B;AAEhC,SAAS,8BAA8B,YAAwB;AACpE,SAAO,oCAAoC,YAAY,EAAE,wBAAwB,KAAK,CAAC;AACzF;AAEA,MAAM,4BAA4B,yBAAyB;AAAA,EACzD,YAAY;AAAA,EACZ;AAAA,EACA;AAAA,EACA,qBAAqB,CAAC,EAAE,YAAY,MAClC,qCAAqC,WAAW;AACpD,CAAC;AAEM,SAAS,2BAA2B,SAA8C;AACvF,SAAO,0BAA0B,OAAO;AAC1C;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { NextResponse } from "next/server";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { isCrudHttpError } from "@open-mercato/shared/lib/crud/errors";
|
|
4
|
+
import { findOneWithDecryption } from "@open-mercato/shared/lib/encryption/find";
|
|
5
|
+
import { resolveTranslations } from "@open-mercato/shared/lib/i18n/server";
|
|
6
|
+
import { createLogger } from "@open-mercato/shared/lib/logger";
|
|
7
|
+
import { EcommerceStoreChannelBinding } from "../../../../data/entities.js";
|
|
8
|
+
import {
|
|
9
|
+
countChannelAssortment,
|
|
10
|
+
DRAFT_REQUIRE_AUTHENTICATION_PARAM,
|
|
11
|
+
DRAFT_SCOPE_PARAM,
|
|
12
|
+
parseAssortmentCountDraft
|
|
13
|
+
} from "../../../../lib/assortmentCount.js";
|
|
14
|
+
import { resolveBrandingRouteContext, storeIdParamSchema } from "../../../../lib/storeBrandingRoute.js";
|
|
15
|
+
import { ecommerceInternalErrorBody } from "../../../../lib/crudSupport.js";
|
|
16
|
+
const metadata = {
|
|
17
|
+
GET: { requireAuth: true, requireFeatures: ["ecommerce.stores.view"] }
|
|
18
|
+
};
|
|
19
|
+
const logger = createLogger("ecommerce").child({ component: "assortment-count-route" });
|
|
20
|
+
async function GET(req, ctx) {
|
|
21
|
+
try {
|
|
22
|
+
const context = await resolveBrandingRouteContext(req);
|
|
23
|
+
const { translate } = await resolveTranslations();
|
|
24
|
+
const notFound = () => NextResponse.json(
|
|
25
|
+
{
|
|
26
|
+
error: translate(
|
|
27
|
+
"ecommerce.errors.channelBindingNotFound",
|
|
28
|
+
"The selected channel binding does not exist in this organization."
|
|
29
|
+
)
|
|
30
|
+
},
|
|
31
|
+
{ status: 404 }
|
|
32
|
+
);
|
|
33
|
+
const params = await ctx.params;
|
|
34
|
+
const bindingId = storeIdParamSchema.safeParse(params?.id);
|
|
35
|
+
if (!bindingId.success) return notFound();
|
|
36
|
+
const em = context.container.resolve("em").fork();
|
|
37
|
+
const binding = await findOneWithDecryption(
|
|
38
|
+
em,
|
|
39
|
+
EcommerceStoreChannelBinding,
|
|
40
|
+
{ id: bindingId.data, tenantId: context.tenantId, organizationId: context.organizationId, deletedAt: null },
|
|
41
|
+
void 0,
|
|
42
|
+
{ tenantId: context.tenantId, organizationId: context.organizationId }
|
|
43
|
+
);
|
|
44
|
+
if (!binding) return notFound();
|
|
45
|
+
const parsed = parseAssortmentCountDraft(new URL(req.url).searchParams, translate);
|
|
46
|
+
if (!parsed.ok) {
|
|
47
|
+
const [message] = Object.values(parsed.fieldErrors);
|
|
48
|
+
return NextResponse.json({ error: message, fieldErrors: parsed.fieldErrors }, { status: 400 });
|
|
49
|
+
}
|
|
50
|
+
const { draft } = parsed;
|
|
51
|
+
const response = await countChannelAssortment(context.container, {
|
|
52
|
+
tenantId: binding.tenantId,
|
|
53
|
+
organizationId: binding.organizationId,
|
|
54
|
+
channelAssortmentScope: draft.scope !== void 0 ? draft.scope : binding.assortmentScope ?? null,
|
|
55
|
+
requireAuthentication: draft.requireAuthentication ?? binding.requireAuthentication,
|
|
56
|
+
scopeSource: draft.scope !== void 0 ? "draft" : "saved"
|
|
57
|
+
});
|
|
58
|
+
return NextResponse.json(response, { headers: { "Cache-Control": "no-store" } });
|
|
59
|
+
} catch (err) {
|
|
60
|
+
if (isCrudHttpError(err)) return NextResponse.json(err.body, { status: err.status });
|
|
61
|
+
logger.error("ecommerce.store-channel-bindings.assortment-count.GET failed", { err });
|
|
62
|
+
return NextResponse.json(await ecommerceInternalErrorBody(), { status: 500 });
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
const countResponseSchema = z.object({
|
|
66
|
+
count: z.number().int().describe("Products an anonymous buyer sees on this channel. 0 while require_authentication is on."),
|
|
67
|
+
scopeSource: z.enum(["saved", "draft"]).describe("draft when the count used the draftScope query parameter, saved when it used the stored assortment_scope."),
|
|
68
|
+
requireAuthentication: z.boolean().describe("The require_authentication value the count used: draftRequireAuthentication when sent, otherwise the stored value."),
|
|
69
|
+
reducedByAuthentication: z.boolean().describe("True when require_authentication brings the count to 0 although the scope matches products for a signed-in buyer."),
|
|
70
|
+
countWithoutAuthentication: z.number().int().describe("The count the same scope would give an anonymous buyer with require_authentication off."),
|
|
71
|
+
unindexedCount: z.number().int().describe("Active products with no scope index yet. They fail closed under a restricted scope, so they are excluded from count.")
|
|
72
|
+
});
|
|
73
|
+
const errorSchema = z.object({ error: z.string() }).passthrough();
|
|
74
|
+
const fieldErrorsSchema = z.object({
|
|
75
|
+
error: z.string(),
|
|
76
|
+
fieldErrors: z.record(z.string(), z.string())
|
|
77
|
+
});
|
|
78
|
+
const countQuerySchema = z.object({
|
|
79
|
+
[DRAFT_SCOPE_PARAM]: z.string().optional().describe(
|
|
80
|
+
"JSON-encoded assortment_scope for unsaved form state, validated like the channel binding write (allOf is rejected); null means unrestricted."
|
|
81
|
+
),
|
|
82
|
+
[DRAFT_REQUIRE_AUTHENTICATION_PARAM]: z.string().optional().describe("true or false: the unsaved require_authentication switch. Defaults to the stored value.")
|
|
83
|
+
});
|
|
84
|
+
const openApi = {
|
|
85
|
+
tag: "Ecommerce",
|
|
86
|
+
summary: "Channel binding assortment count",
|
|
87
|
+
pathParams: z.object({ id: z.string().uuid() }),
|
|
88
|
+
methods: {
|
|
89
|
+
GET: {
|
|
90
|
+
summary: "Count the products a channel binding shows an anonymous buyer",
|
|
91
|
+
description: "Backs the live product count of the Channels tab. Counts the products the storefront would list for an anonymous buyer on this channel binding, using the stored assortment_scope or, when draftScope is given, the unsaved one. The effective assortment is the channel scope intersected with the default customer group scope and counted through the same scope query as the storefront listing. A binding that requires authentication counts 0 and reports reducedByAuthentication. Requires ecommerce.stores.view.",
|
|
92
|
+
tags: ["Ecommerce"],
|
|
93
|
+
query: countQuerySchema,
|
|
94
|
+
responses: [{ status: 200, description: "Product count", schema: countResponseSchema }],
|
|
95
|
+
errors: [
|
|
96
|
+
{ status: 400, description: "draftScope is not valid JSON or not a valid assortment scope, or draftRequireAuthentication is not a boolean", schema: fieldErrorsSchema },
|
|
97
|
+
{ status: 401, description: "Unauthorized", schema: errorSchema },
|
|
98
|
+
{ status: 403, description: "Missing ecommerce.stores.view", schema: errorSchema },
|
|
99
|
+
{ status: 404, description: "The channel binding does not exist in the selected organization", schema: errorSchema }
|
|
100
|
+
]
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
export {
|
|
105
|
+
GET,
|
|
106
|
+
metadata,
|
|
107
|
+
openApi
|
|
108
|
+
};
|
|
109
|
+
//# sourceMappingURL=route.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../../../../src/modules/ecommerce/api/store-channel-bindings/%5Bid%5D/assortment-count/route.ts"],
|
|
4
|
+
"sourcesContent": ["import { NextResponse } from 'next/server'\nimport { z } from 'zod'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport { isCrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport { findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\nimport type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'\nimport { EcommerceStoreChannelBinding } from '../../../../data/entities'\nimport {\n countChannelAssortment,\n DRAFT_REQUIRE_AUTHENTICATION_PARAM,\n DRAFT_SCOPE_PARAM,\n parseAssortmentCountDraft,\n} from '../../../../lib/assortmentCount'\nimport { resolveBrandingRouteContext, storeIdParamSchema } from '../../../../lib/storeBrandingRoute'\nimport { ecommerceInternalErrorBody } from '../../../../lib/crudSupport'\n\nexport const metadata = {\n GET: { requireAuth: true, requireFeatures: ['ecommerce.stores.view'] },\n}\n\nconst logger = createLogger('ecommerce').child({ component: 'assortment-count-route' })\n\ntype RouteParams = { params?: { id?: string } | Promise<{ id?: string }> }\n\nexport async function GET(req: Request, ctx: RouteParams) {\n try {\n const context = await resolveBrandingRouteContext(req)\n const { translate } = await resolveTranslations()\n const notFound = () =>\n NextResponse.json(\n {\n error: translate(\n 'ecommerce.errors.channelBindingNotFound',\n 'The selected channel binding does not exist in this organization.',\n ),\n },\n { status: 404 },\n )\n const params = await ctx.params\n const bindingId = storeIdParamSchema.safeParse(params?.id)\n if (!bindingId.success) return notFound()\n\n const em = (context.container.resolve('em') as EntityManager).fork()\n const binding = await findOneWithDecryption(\n em,\n EcommerceStoreChannelBinding,\n { id: bindingId.data, tenantId: context.tenantId, organizationId: context.organizationId, deletedAt: null },\n undefined,\n { tenantId: context.tenantId, organizationId: context.organizationId },\n )\n if (!binding) return notFound()\n\n const parsed = parseAssortmentCountDraft(new URL(req.url).searchParams, translate)\n if (!parsed.ok) {\n const [message] = Object.values(parsed.fieldErrors)\n return NextResponse.json({ error: message, fieldErrors: parsed.fieldErrors }, { status: 400 })\n }\n const { draft } = parsed\n\n const response = await countChannelAssortment(context.container, {\n tenantId: binding.tenantId,\n organizationId: binding.organizationId,\n channelAssortmentScope: draft.scope !== undefined ? draft.scope : (binding.assortmentScope ?? null),\n requireAuthentication: draft.requireAuthentication ?? binding.requireAuthentication,\n scopeSource: draft.scope !== undefined ? 'draft' : 'saved',\n })\n return NextResponse.json(response, { headers: { 'Cache-Control': 'no-store' } })\n } catch (err) {\n if (isCrudHttpError(err)) return NextResponse.json(err.body, { status: err.status })\n logger.error('ecommerce.store-channel-bindings.assortment-count.GET failed', { err })\n return NextResponse.json(await ecommerceInternalErrorBody(), { status: 500 })\n }\n}\n\nconst countResponseSchema = z.object({\n count: z\n .number()\n .int()\n .describe('Products an anonymous buyer sees on this channel. 0 while require_authentication is on.'),\n scopeSource: z\n .enum(['saved', 'draft'])\n .describe('draft when the count used the draftScope query parameter, saved when it used the stored assortment_scope.'),\n requireAuthentication: z\n .boolean()\n .describe('The require_authentication value the count used: draftRequireAuthentication when sent, otherwise the stored value.'),\n reducedByAuthentication: z\n .boolean()\n .describe('True when require_authentication brings the count to 0 although the scope matches products for a signed-in buyer.'),\n countWithoutAuthentication: z\n .number()\n .int()\n .describe('The count the same scope would give an anonymous buyer with require_authentication off.'),\n unindexedCount: z\n .number()\n .int()\n .describe('Active products with no scope index yet. They fail closed under a restricted scope, so they are excluded from count.'),\n})\n\nconst errorSchema = z.object({ error: z.string() }).passthrough()\n\nconst fieldErrorsSchema = z.object({\n error: z.string(),\n fieldErrors: z.record(z.string(), z.string()),\n})\n\nconst countQuerySchema = z.object({\n [DRAFT_SCOPE_PARAM]: z\n .string()\n .optional()\n .describe(\n 'JSON-encoded assortment_scope for unsaved form state, validated like the channel binding write (allOf is rejected); null means unrestricted.',\n ),\n [DRAFT_REQUIRE_AUTHENTICATION_PARAM]: z\n .string()\n .optional()\n .describe('true or false: the unsaved require_authentication switch. Defaults to the stored value.'),\n})\n\nexport const openApi: OpenApiRouteDoc = {\n tag: 'Ecommerce',\n summary: 'Channel binding assortment count',\n pathParams: z.object({ id: z.string().uuid() }),\n methods: {\n GET: {\n summary: 'Count the products a channel binding shows an anonymous buyer',\n description:\n 'Backs the live product count of the Channels tab. Counts the products the storefront would list for an anonymous buyer on this channel binding, using the stored assortment_scope or, when draftScope is given, the unsaved one. The effective assortment is the channel scope intersected with the default customer group scope and counted through the same scope query as the storefront listing. A binding that requires authentication counts 0 and reports reducedByAuthentication. Requires ecommerce.stores.view.',\n tags: ['Ecommerce'],\n query: countQuerySchema,\n responses: [{ status: 200, description: 'Product count', schema: countResponseSchema }],\n errors: [\n { status: 400, description: 'draftScope is not valid JSON or not a valid assortment scope, or draftRequireAuthentication is not a boolean', schema: fieldErrorsSchema },\n { status: 401, description: 'Unauthorized', schema: errorSchema },\n { status: 403, description: 'Missing ecommerce.stores.view', schema: errorSchema },\n { status: 404, description: 'The channel binding does not exist in the selected organization', schema: errorSchema },\n ],\n },\n },\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { makeCrudRoute } from "@open-mercato/shared/lib/crud/factory";
|
|
3
|
+
import { isUniqueViolation } from "@open-mercato/shared/lib/crud/errors";
|
|
4
|
+
import { parseBooleanToken } from "@open-mercato/shared/lib/boolean";
|
|
5
|
+
import { resolveTranslations } from "@open-mercato/shared/lib/i18n/server";
|
|
6
|
+
import { E } from "../../../../generated/entities.ids.generated.js";
|
|
7
|
+
import * as F from "../../../../generated/entities/ecommerce_store_channel_binding/index.js";
|
|
8
|
+
import { EcommerceStoreChannelBinding } from "../../data/entities.js";
|
|
9
|
+
import {
|
|
10
|
+
ecommerceStoreChannelBindingCreateSchema,
|
|
11
|
+
ecommerceStoreChannelBindingUpdateSchema
|
|
12
|
+
} from "../../data/validators.js";
|
|
13
|
+
import {
|
|
14
|
+
assertRecordInWriteScope,
|
|
15
|
+
fieldError,
|
|
16
|
+
hasOwn,
|
|
17
|
+
resolveScopeOrganizationId,
|
|
18
|
+
resolveWriteScope
|
|
19
|
+
} from "../../lib/crudSupport.js";
|
|
20
|
+
import { assignExclusiveFlag, promoteExclusiveFlag } from "../../lib/exclusiveFlag.js";
|
|
21
|
+
import { assertPriceKindInScope, assertSalesChannelInScope, assertStoreInScope } from "../../lib/references.js";
|
|
22
|
+
import {
|
|
23
|
+
announceStoreChannelBindingsUpdated,
|
|
24
|
+
buildStoreChannelBindingEventPayload,
|
|
25
|
+
ECOMMERCE_EVENTS_MODULE,
|
|
26
|
+
rememberChannelBindingStore,
|
|
27
|
+
STORE_CHANNEL_BINDING_EVENT_ENTITY
|
|
28
|
+
} from "../../lib/crudEvents.js";
|
|
29
|
+
const rawBodySchema = z.object({}).passthrough();
|
|
30
|
+
const channelBindingListQuerySchema = z.object({
|
|
31
|
+
page: z.coerce.number().min(1).default(1),
|
|
32
|
+
pageSize: z.coerce.number().min(1).max(100).default(50),
|
|
33
|
+
id: z.string().uuid().optional(),
|
|
34
|
+
storeId: z.string().uuid().optional(),
|
|
35
|
+
salesChannelId: z.string().uuid().optional(),
|
|
36
|
+
isDefault: z.string().optional(),
|
|
37
|
+
sortField: z.string().optional(),
|
|
38
|
+
sortDir: z.enum(["asc", "desc"]).optional()
|
|
39
|
+
}).passthrough();
|
|
40
|
+
const channelBindingRouteMetadata = {
|
|
41
|
+
GET: { requireAuth: true, requireFeatures: ["ecommerce.stores.view"] },
|
|
42
|
+
POST: { requireAuth: true, requireFeatures: ["ecommerce.channels.manage"] },
|
|
43
|
+
PUT: { requireAuth: true, requireFeatures: ["ecommerce.channels.manage"] },
|
|
44
|
+
DELETE: { requireAuth: true, requireFeatures: ["ecommerce.channels.manage"] }
|
|
45
|
+
};
|
|
46
|
+
const CHANNEL_BINDING_DEFAULT_UNIQUE_CONSTRAINT = "ecommerce_store_channel_bindings_store_default_unique";
|
|
47
|
+
const channelBindingDefaultFlag = {
|
|
48
|
+
entity: EcommerceStoreChannelBinding,
|
|
49
|
+
flag: "isDefault",
|
|
50
|
+
constraint: CHANNEL_BINDING_DEFAULT_UNIQUE_CONSTRAINT
|
|
51
|
+
};
|
|
52
|
+
function defaultBindingConflict(translate) {
|
|
53
|
+
return fieldError(409, {
|
|
54
|
+
isDefault: translate(
|
|
55
|
+
"ecommerce.errors.defaultChannelConflict",
|
|
56
|
+
"Another channel binding of this store was made the default at the same time. Reload and try again."
|
|
57
|
+
)
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
function toChannelBindingUniqueConflict(err, translate) {
|
|
61
|
+
if (isUniqueViolation(err, CHANNEL_BINDING_DEFAULT_UNIQUE_CONSTRAINT)) return defaultBindingConflict(translate);
|
|
62
|
+
return err;
|
|
63
|
+
}
|
|
64
|
+
function parseCreateInput(input, ctx) {
|
|
65
|
+
return ecommerceStoreChannelBindingCreateSchema.parse({ ...input, ...resolveWriteScope(ctx) });
|
|
66
|
+
}
|
|
67
|
+
function parseUpdateInput(input, ctx) {
|
|
68
|
+
return ecommerceStoreChannelBindingUpdateSchema.parse({ ...input, ...resolveWriteScope(ctx) });
|
|
69
|
+
}
|
|
70
|
+
function bindingScope(binding) {
|
|
71
|
+
return { tenantId: binding.tenantId, organizationId: binding.organizationId };
|
|
72
|
+
}
|
|
73
|
+
const clearedDefaultByUpdate = /* @__PURE__ */ new WeakMap();
|
|
74
|
+
function toChannelBindingListItem(row) {
|
|
75
|
+
return {
|
|
76
|
+
id: row[F.id],
|
|
77
|
+
organizationId: row[F.organization_id] ?? null,
|
|
78
|
+
tenantId: row[F.tenant_id] ?? null,
|
|
79
|
+
storeId: row[F.store_id],
|
|
80
|
+
salesChannelId: row[F.sales_channel_id],
|
|
81
|
+
priceKindId: row[F.price_kind_id] ?? null,
|
|
82
|
+
assortmentScope: row[F.assortment_scope] ?? null,
|
|
83
|
+
priceSortFallback: row[F.price_sort_fallback] ?? "approximate",
|
|
84
|
+
isDefault: row[F.is_default] === true,
|
|
85
|
+
requireAuthentication: row[F.require_authentication] === true,
|
|
86
|
+
createdAt: row[F.created_at] ?? null,
|
|
87
|
+
updatedAt: row[F.updated_at] ?? null
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
const NOT_FOUND = { key: "ecommerce.errors.channelBindingNotFound", fallback: "The selected channel binding does not exist in this organization." };
|
|
91
|
+
const channelBindingCrud = makeCrudRoute({
|
|
92
|
+
metadata: channelBindingRouteMetadata,
|
|
93
|
+
orm: {
|
|
94
|
+
entity: EcommerceStoreChannelBinding,
|
|
95
|
+
idField: "id",
|
|
96
|
+
orgField: "organizationId",
|
|
97
|
+
tenantField: "tenantId",
|
|
98
|
+
softDeleteField: "deletedAt"
|
|
99
|
+
},
|
|
100
|
+
indexer: { entityType: E.ecommerce.ecommerce_store_channel_binding },
|
|
101
|
+
list: {
|
|
102
|
+
schema: channelBindingListQuerySchema,
|
|
103
|
+
entityId: E.ecommerce.ecommerce_store_channel_binding,
|
|
104
|
+
fields: [
|
|
105
|
+
F.id,
|
|
106
|
+
F.organization_id,
|
|
107
|
+
F.tenant_id,
|
|
108
|
+
F.store_id,
|
|
109
|
+
F.sales_channel_id,
|
|
110
|
+
F.price_kind_id,
|
|
111
|
+
F.assortment_scope,
|
|
112
|
+
F.price_sort_fallback,
|
|
113
|
+
F.is_default,
|
|
114
|
+
F.require_authentication,
|
|
115
|
+
F.created_at,
|
|
116
|
+
F.updated_at
|
|
117
|
+
],
|
|
118
|
+
sortFieldMap: {
|
|
119
|
+
isDefault: F.is_default,
|
|
120
|
+
createdAt: F.created_at,
|
|
121
|
+
updatedAt: F.updated_at
|
|
122
|
+
},
|
|
123
|
+
defaultSort: { field: "createdAt", dir: "asc" },
|
|
124
|
+
tiebreakSortField: F.id,
|
|
125
|
+
buildFilters: async (query, ctx) => {
|
|
126
|
+
const filters = {};
|
|
127
|
+
const scopeOrganizationId = resolveScopeOrganizationId(ctx);
|
|
128
|
+
if (scopeOrganizationId) filters[F.organization_id] = { $eq: scopeOrganizationId };
|
|
129
|
+
if (query.id) filters[F.id] = { $eq: query.id };
|
|
130
|
+
if (query.storeId) filters[F.store_id] = { $eq: query.storeId };
|
|
131
|
+
if (query.salesChannelId) filters[F.sales_channel_id] = { $eq: query.salesChannelId };
|
|
132
|
+
const isDefault = parseBooleanToken(query.isDefault);
|
|
133
|
+
if (isDefault !== null) filters[F.is_default] = { $eq: isDefault };
|
|
134
|
+
return filters;
|
|
135
|
+
},
|
|
136
|
+
transformItem: (item) => toChannelBindingListItem(item)
|
|
137
|
+
},
|
|
138
|
+
events: {
|
|
139
|
+
module: ECOMMERCE_EVENTS_MODULE,
|
|
140
|
+
entity: STORE_CHANNEL_BINDING_EVENT_ENTITY,
|
|
141
|
+
persistent: true,
|
|
142
|
+
buildPayload: (emitCtx) => buildStoreChannelBindingEventPayload(emitCtx.entity)
|
|
143
|
+
},
|
|
144
|
+
create: {
|
|
145
|
+
schema: rawBodySchema,
|
|
146
|
+
mapToEntity: (input, ctx) => {
|
|
147
|
+
const parsed = parseCreateInput(input, ctx);
|
|
148
|
+
return {
|
|
149
|
+
organizationId: parsed.organizationId,
|
|
150
|
+
tenantId: parsed.tenantId,
|
|
151
|
+
storeId: parsed.storeId,
|
|
152
|
+
salesChannelId: parsed.salesChannelId,
|
|
153
|
+
priceKindId: parsed.priceKindId ?? null,
|
|
154
|
+
assortmentScope: parsed.assortmentScope ?? null,
|
|
155
|
+
priceSortFallback: parsed.priceSortFallback,
|
|
156
|
+
isDefault: false,
|
|
157
|
+
requireAuthentication: parsed.requireAuthentication
|
|
158
|
+
};
|
|
159
|
+
},
|
|
160
|
+
response: (entity) => {
|
|
161
|
+
const binding = entity;
|
|
162
|
+
return { id: binding.id, isDefault: binding.isDefault };
|
|
163
|
+
}
|
|
164
|
+
},
|
|
165
|
+
update: {
|
|
166
|
+
schema: rawBodySchema,
|
|
167
|
+
getId: (input) => typeof input.id === "string" ? input.id : "",
|
|
168
|
+
applyToEntity: async (entity, input, ctx) => {
|
|
169
|
+
const binding = entity;
|
|
170
|
+
rememberChannelBindingStore(binding);
|
|
171
|
+
const parsed = parseUpdateInput(input, ctx);
|
|
172
|
+
const em = ctx.container.resolve("em");
|
|
173
|
+
const { translate } = await resolveTranslations();
|
|
174
|
+
const scope = bindingScope(binding);
|
|
175
|
+
const nextStoreId = parsed.storeId ?? binding.storeId;
|
|
176
|
+
const storeChanged = nextStoreId !== binding.storeId;
|
|
177
|
+
if (storeChanged) await assertStoreInScope(em, nextStoreId, scope, translate);
|
|
178
|
+
if (parsed.salesChannelId !== void 0 && parsed.salesChannelId !== binding.salesChannelId) {
|
|
179
|
+
await assertSalesChannelInScope(em, parsed.salesChannelId, scope, translate);
|
|
180
|
+
}
|
|
181
|
+
const nextPriceKindId = hasOwn(parsed, "priceKindId") ? parsed.priceKindId ?? null : binding.priceKindId ?? null;
|
|
182
|
+
if (nextPriceKindId && nextPriceKindId !== (binding.priceKindId ?? null)) {
|
|
183
|
+
await assertPriceKindInScope(em, nextPriceKindId, scope, translate);
|
|
184
|
+
}
|
|
185
|
+
const nextDefault = parsed.isDefault ?? binding.isDefault;
|
|
186
|
+
if (nextDefault && (!binding.isDefault || storeChanged)) {
|
|
187
|
+
clearedDefaultByUpdate.set(
|
|
188
|
+
binding,
|
|
189
|
+
await assignExclusiveFlag(
|
|
190
|
+
em,
|
|
191
|
+
channelBindingDefaultFlag,
|
|
192
|
+
{ ...scope, storeId: nextStoreId },
|
|
193
|
+
binding.id,
|
|
194
|
+
() => defaultBindingConflict(translate)
|
|
195
|
+
)
|
|
196
|
+
);
|
|
197
|
+
}
|
|
198
|
+
binding.storeId = nextStoreId;
|
|
199
|
+
if (parsed.salesChannelId !== void 0) binding.salesChannelId = parsed.salesChannelId;
|
|
200
|
+
binding.priceKindId = nextPriceKindId;
|
|
201
|
+
if (hasOwn(parsed, "assortmentScope")) binding.assortmentScope = parsed.assortmentScope ?? null;
|
|
202
|
+
if (parsed.priceSortFallback !== void 0) binding.priceSortFallback = parsed.priceSortFallback;
|
|
203
|
+
if (parsed.requireAuthentication !== void 0) binding.requireAuthentication = parsed.requireAuthentication;
|
|
204
|
+
binding.isDefault = nextDefault;
|
|
205
|
+
try {
|
|
206
|
+
await em.flush();
|
|
207
|
+
} catch (err) {
|
|
208
|
+
throw toChannelBindingUniqueConflict(err, translate);
|
|
209
|
+
}
|
|
210
|
+
},
|
|
211
|
+
response: () => ({ ok: true })
|
|
212
|
+
},
|
|
213
|
+
del: { idFrom: "query", softDelete: true, response: () => ({ ok: true }) },
|
|
214
|
+
hooks: {
|
|
215
|
+
beforeUpdate: async (input, ctx) => {
|
|
216
|
+
await assertRecordInWriteScope(ctx, EcommerceStoreChannelBinding, input.id, NOT_FOUND);
|
|
217
|
+
},
|
|
218
|
+
beforeDelete: async (id, ctx) => {
|
|
219
|
+
await assertRecordInWriteScope(ctx, EcommerceStoreChannelBinding, id, NOT_FOUND);
|
|
220
|
+
},
|
|
221
|
+
beforeCreate: async (input, ctx) => {
|
|
222
|
+
const result = ecommerceStoreChannelBindingCreateSchema.safeParse({ ...input, ...resolveWriteScope(ctx) });
|
|
223
|
+
if (!result.success) return;
|
|
224
|
+
const { translate } = await resolveTranslations();
|
|
225
|
+
const em = ctx.container.resolve("em").fork();
|
|
226
|
+
const scope = { tenantId: result.data.tenantId, organizationId: result.data.organizationId };
|
|
227
|
+
await assertStoreInScope(em, result.data.storeId, scope, translate);
|
|
228
|
+
await assertSalesChannelInScope(em, result.data.salesChannelId, scope, translate);
|
|
229
|
+
if (result.data.priceKindId) await assertPriceKindInScope(em, result.data.priceKindId, scope, translate);
|
|
230
|
+
},
|
|
231
|
+
afterCreate: async (entity, ctx) => {
|
|
232
|
+
const binding = entity;
|
|
233
|
+
if (parseCreateInput(ctx.input, ctx).isDefault !== true) return;
|
|
234
|
+
const now = /* @__PURE__ */ new Date();
|
|
235
|
+
const em = ctx.container.resolve("em");
|
|
236
|
+
const { promoted, cleared } = await promoteExclusiveFlag(
|
|
237
|
+
em,
|
|
238
|
+
channelBindingDefaultFlag,
|
|
239
|
+
{ ...bindingScope(binding), storeId: binding.storeId },
|
|
240
|
+
binding.id,
|
|
241
|
+
now
|
|
242
|
+
);
|
|
243
|
+
if (!promoted) return;
|
|
244
|
+
binding.isDefault = true;
|
|
245
|
+
binding.updatedAt = now;
|
|
246
|
+
await announceStoreChannelBindingsUpdated(ctx.container, cleared);
|
|
247
|
+
},
|
|
248
|
+
afterUpdate: async (entity, ctx) => {
|
|
249
|
+
const binding = entity;
|
|
250
|
+
const cleared = clearedDefaultByUpdate.get(binding);
|
|
251
|
+
if (!cleared) return;
|
|
252
|
+
clearedDefaultByUpdate.delete(binding);
|
|
253
|
+
await announceStoreChannelBindingsUpdated(ctx.container, cleared);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
});
|
|
257
|
+
export {
|
|
258
|
+
CHANNEL_BINDING_DEFAULT_UNIQUE_CONSTRAINT,
|
|
259
|
+
channelBindingCrud,
|
|
260
|
+
channelBindingListQuerySchema,
|
|
261
|
+
channelBindingRouteMetadata,
|
|
262
|
+
toChannelBindingListItem,
|
|
263
|
+
toChannelBindingUniqueConflict
|
|
264
|
+
};
|
|
265
|
+
//# sourceMappingURL=crud.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../../src/modules/ecommerce/api/store-channel-bindings/crud.ts"],
|
|
4
|
+
"sourcesContent": ["import { z } from 'zod'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport type { CrudCtx } from '@open-mercato/shared/lib/crud/factory'\nimport { makeCrudRoute } from '@open-mercato/shared/lib/crud/factory'\nimport { isUniqueViolation } from '@open-mercato/shared/lib/crud/errors'\nimport { parseBooleanToken } from '@open-mercato/shared/lib/boolean'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport { E } from '#generated/entities.ids.generated'\nimport * as F from '#generated/entities/ecommerce_store_channel_binding'\nimport { EcommerceStoreChannelBinding } from '../../data/entities'\nimport {\n ecommerceStoreChannelBindingCreateSchema,\n ecommerceStoreChannelBindingUpdateSchema,\n type EcommerceStoreChannelBindingCreateInput,\n type EcommerceStoreChannelBindingUpdateInput,\n} from '../../data/validators'\nimport {\n assertRecordInWriteScope,\n fieldError,\n hasOwn,\n resolveScopeOrganizationId,\n resolveWriteScope,\n type EcommerceWriteScope,\n type Translate,\n} from '../../lib/crudSupport'\nimport { assignExclusiveFlag, promoteExclusiveFlag, type ExclusiveFlagConfig } from '../../lib/exclusiveFlag'\nimport { assertPriceKindInScope, assertSalesChannelInScope, assertStoreInScope } from '../../lib/references'\nimport {\n announceStoreChannelBindingsUpdated,\n buildStoreChannelBindingEventPayload,\n ECOMMERCE_EVENTS_MODULE,\n rememberChannelBindingStore,\n STORE_CHANNEL_BINDING_EVENT_ENTITY,\n} from '../../lib/crudEvents'\n\nconst rawBodySchema = z.object({}).passthrough()\ntype RawChannelBindingInput = z.infer<typeof rawBodySchema>\n\nexport const channelBindingListQuerySchema = z\n .object({\n page: z.coerce.number().min(1).default(1),\n pageSize: z.coerce.number().min(1).max(100).default(50),\n id: z.string().uuid().optional(),\n storeId: z.string().uuid().optional(),\n salesChannelId: z.string().uuid().optional(),\n isDefault: z.string().optional(),\n sortField: z.string().optional(),\n sortDir: z.enum(['asc', 'desc']).optional(),\n })\n .passthrough()\n\nexport type ChannelBindingListQuery = z.infer<typeof channelBindingListQuerySchema>\n\nexport const channelBindingRouteMetadata = {\n GET: { requireAuth: true, requireFeatures: ['ecommerce.stores.view'] },\n POST: { requireAuth: true, requireFeatures: ['ecommerce.channels.manage'] },\n PUT: { requireAuth: true, requireFeatures: ['ecommerce.channels.manage'] },\n DELETE: { requireAuth: true, requireFeatures: ['ecommerce.channels.manage'] },\n}\n\nexport const CHANNEL_BINDING_DEFAULT_UNIQUE_CONSTRAINT = 'ecommerce_store_channel_bindings_store_default_unique'\n\nconst channelBindingDefaultFlag: ExclusiveFlagConfig<EcommerceStoreChannelBinding> = {\n entity: EcommerceStoreChannelBinding,\n flag: 'isDefault',\n constraint: CHANNEL_BINDING_DEFAULT_UNIQUE_CONSTRAINT,\n}\n\nfunction defaultBindingConflict(translate: Translate) {\n return fieldError(409, {\n isDefault: translate(\n 'ecommerce.errors.defaultChannelConflict',\n 'Another channel binding of this store was made the default at the same time. Reload and try again.',\n ),\n })\n}\n\nexport function toChannelBindingUniqueConflict(err: unknown, translate: Translate): unknown {\n if (isUniqueViolation(err, CHANNEL_BINDING_DEFAULT_UNIQUE_CONSTRAINT)) return defaultBindingConflict(translate)\n return err\n}\n\nfunction parseCreateInput(input: RawChannelBindingInput, ctx: CrudCtx): EcommerceStoreChannelBindingCreateInput {\n return ecommerceStoreChannelBindingCreateSchema.parse({ ...input, ...resolveWriteScope(ctx) })\n}\n\nfunction parseUpdateInput(input: RawChannelBindingInput, ctx: CrudCtx): EcommerceStoreChannelBindingUpdateInput {\n return ecommerceStoreChannelBindingUpdateSchema.parse({ ...input, ...resolveWriteScope(ctx) })\n}\n\nfunction bindingScope(binding: Pick<EcommerceStoreChannelBinding, 'tenantId' | 'organizationId'>): EcommerceWriteScope {\n return { tenantId: binding.tenantId, organizationId: binding.organizationId }\n}\n\nconst clearedDefaultByUpdate = new WeakMap<EcommerceStoreChannelBinding, EcommerceStoreChannelBinding[]>()\n\ntype ChannelBindingListRow = Record<string, unknown>\n\nexport function toChannelBindingListItem(row: ChannelBindingListRow): Record<string, unknown> {\n return {\n id: row[F.id],\n organizationId: row[F.organization_id] ?? null,\n tenantId: row[F.tenant_id] ?? null,\n storeId: row[F.store_id],\n salesChannelId: row[F.sales_channel_id],\n priceKindId: row[F.price_kind_id] ?? null,\n assortmentScope: row[F.assortment_scope] ?? null,\n priceSortFallback: row[F.price_sort_fallback] ?? 'approximate',\n isDefault: row[F.is_default] === true,\n requireAuthentication: row[F.require_authentication] === true,\n createdAt: row[F.created_at] ?? null,\n updatedAt: row[F.updated_at] ?? null,\n }\n}\n\nconst NOT_FOUND = { key: 'ecommerce.errors.channelBindingNotFound', fallback: 'The selected channel binding does not exist in this organization.' }\n\nexport const channelBindingCrud = makeCrudRoute<RawChannelBindingInput, RawChannelBindingInput, ChannelBindingListQuery>({\n metadata: channelBindingRouteMetadata,\n orm: {\n entity: EcommerceStoreChannelBinding,\n idField: 'id',\n orgField: 'organizationId',\n tenantField: 'tenantId',\n softDeleteField: 'deletedAt',\n },\n indexer: { entityType: E.ecommerce.ecommerce_store_channel_binding },\n list: {\n schema: channelBindingListQuerySchema,\n entityId: E.ecommerce.ecommerce_store_channel_binding,\n fields: [\n F.id,\n F.organization_id,\n F.tenant_id,\n F.store_id,\n F.sales_channel_id,\n F.price_kind_id,\n F.assortment_scope,\n F.price_sort_fallback,\n F.is_default,\n F.require_authentication,\n F.created_at,\n F.updated_at,\n ],\n sortFieldMap: {\n isDefault: F.is_default,\n createdAt: F.created_at,\n updatedAt: F.updated_at,\n },\n defaultSort: { field: 'createdAt', dir: 'asc' },\n tiebreakSortField: F.id,\n buildFilters: async (query, ctx) => {\n const filters: Record<string, unknown> = {}\n const scopeOrganizationId = resolveScopeOrganizationId(ctx)\n if (scopeOrganizationId) filters[F.organization_id] = { $eq: scopeOrganizationId }\n if (query.id) filters[F.id] = { $eq: query.id }\n if (query.storeId) filters[F.store_id] = { $eq: query.storeId }\n if (query.salesChannelId) filters[F.sales_channel_id] = { $eq: query.salesChannelId }\n const isDefault = parseBooleanToken(query.isDefault)\n if (isDefault !== null) filters[F.is_default] = { $eq: isDefault }\n return filters\n },\n transformItem: (item: ChannelBindingListRow) => toChannelBindingListItem(item),\n },\n events: {\n module: ECOMMERCE_EVENTS_MODULE,\n entity: STORE_CHANNEL_BINDING_EVENT_ENTITY,\n persistent: true,\n buildPayload: (emitCtx) => buildStoreChannelBindingEventPayload(emitCtx.entity as EcommerceStoreChannelBinding),\n },\n create: {\n schema: rawBodySchema,\n mapToEntity: (input, ctx) => {\n const parsed = parseCreateInput(input, ctx)\n return {\n organizationId: parsed.organizationId,\n tenantId: parsed.tenantId,\n storeId: parsed.storeId,\n salesChannelId: parsed.salesChannelId,\n priceKindId: parsed.priceKindId ?? null,\n assortmentScope: parsed.assortmentScope ?? null,\n priceSortFallback: parsed.priceSortFallback,\n isDefault: false,\n requireAuthentication: parsed.requireAuthentication,\n }\n },\n response: (entity) => {\n const binding = entity as EcommerceStoreChannelBinding\n return { id: binding.id, isDefault: binding.isDefault }\n },\n },\n update: {\n schema: rawBodySchema,\n getId: (input) => (typeof input.id === 'string' ? input.id : ''),\n applyToEntity: async (entity, input, ctx) => {\n const binding = entity as EcommerceStoreChannelBinding\n rememberChannelBindingStore(binding)\n const parsed = parseUpdateInput(input, ctx)\n const em = ctx.container.resolve('em') as EntityManager\n const { translate } = await resolveTranslations()\n const scope = bindingScope(binding)\n const nextStoreId = parsed.storeId ?? binding.storeId\n const storeChanged = nextStoreId !== binding.storeId\n if (storeChanged) await assertStoreInScope(em, nextStoreId, scope, translate)\n if (parsed.salesChannelId !== undefined && parsed.salesChannelId !== binding.salesChannelId) {\n await assertSalesChannelInScope(em, parsed.salesChannelId, scope, translate)\n }\n const nextPriceKindId = hasOwn(parsed, 'priceKindId') ? parsed.priceKindId ?? null : binding.priceKindId ?? null\n if (nextPriceKindId && nextPriceKindId !== (binding.priceKindId ?? null)) {\n await assertPriceKindInScope(em, nextPriceKindId, scope, translate)\n }\n const nextDefault = parsed.isDefault ?? binding.isDefault\n if (nextDefault && (!binding.isDefault || storeChanged)) {\n clearedDefaultByUpdate.set(\n binding,\n await assignExclusiveFlag(\n em,\n channelBindingDefaultFlag,\n { ...scope, storeId: nextStoreId },\n binding.id,\n () => defaultBindingConflict(translate),\n ),\n )\n }\n binding.storeId = nextStoreId\n if (parsed.salesChannelId !== undefined) binding.salesChannelId = parsed.salesChannelId\n binding.priceKindId = nextPriceKindId\n if (hasOwn(parsed, 'assortmentScope')) binding.assortmentScope = parsed.assortmentScope ?? null\n if (parsed.priceSortFallback !== undefined) binding.priceSortFallback = parsed.priceSortFallback\n if (parsed.requireAuthentication !== undefined) binding.requireAuthentication = parsed.requireAuthentication\n binding.isDefault = nextDefault\n try {\n await em.flush()\n } catch (err) {\n throw toChannelBindingUniqueConflict(err, translate)\n }\n },\n response: () => ({ ok: true }),\n },\n del: { idFrom: 'query', softDelete: true, response: () => ({ ok: true }) },\n hooks: {\n beforeUpdate: async (input, ctx) => {\n await assertRecordInWriteScope(ctx, EcommerceStoreChannelBinding, (input as { id?: unknown }).id, NOT_FOUND)\n },\n beforeDelete: async (id, ctx) => {\n await assertRecordInWriteScope(ctx, EcommerceStoreChannelBinding, id, NOT_FOUND)\n },\n beforeCreate: async (input, ctx) => {\n const result = ecommerceStoreChannelBindingCreateSchema.safeParse({ ...input, ...resolveWriteScope(ctx) })\n if (!result.success) return\n const { translate } = await resolveTranslations()\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const scope: EcommerceWriteScope = { tenantId: result.data.tenantId, organizationId: result.data.organizationId }\n await assertStoreInScope(em, result.data.storeId, scope, translate)\n await assertSalesChannelInScope(em, result.data.salesChannelId, scope, translate)\n if (result.data.priceKindId) await assertPriceKindInScope(em, result.data.priceKindId, scope, translate)\n },\n afterCreate: async (entity, ctx) => {\n const binding = entity as EcommerceStoreChannelBinding\n if (parseCreateInput(ctx.input, ctx).isDefault !== true) return\n const now = new Date()\n const em = ctx.container.resolve('em') as EntityManager\n const { promoted, cleared } = await promoteExclusiveFlag(\n em,\n channelBindingDefaultFlag,\n { ...bindingScope(binding), storeId: binding.storeId },\n binding.id,\n now,\n )\n if (!promoted) return\n binding.isDefault = true\n binding.updatedAt = now\n await announceStoreChannelBindingsUpdated(ctx.container, cleared)\n },\n afterUpdate: async (entity, ctx) => {\n const binding = entity as EcommerceStoreChannelBinding\n const cleared = clearedDefaultByUpdate.get(binding)\n if (!cleared) return\n clearedDefaultByUpdate.delete(binding)\n await announceStoreChannelBindingsUpdated(ctx.container, cleared)\n },\n },\n})\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,SAAS;AAGlB,SAAS,qBAAqB;AAC9B,SAAS,yBAAyB;AAClC,SAAS,yBAAyB;AAClC,SAAS,2BAA2B;AACpC,SAAS,SAAS;AAClB,YAAY,OAAO;AACnB,SAAS,oCAAoC;AAC7C;AAAA,EACE;AAAA,EACA;AAAA,OAGK;AACP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAGK;AACP,SAAS,qBAAqB,4BAAsD;AACpF,SAAS,wBAAwB,2BAA2B,0BAA0B;AACtF;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAEP,MAAM,gBAAgB,EAAE,OAAO,CAAC,CAAC,EAAE,YAAY;AAGxC,MAAM,gCAAgC,EAC1C,OAAO;AAAA,EACN,MAAM,EAAE,OAAO,OAAO,EAAE,IAAI,CAAC,EAAE,QAAQ,CAAC;AAAA,EACxC,UAAU,EAAE,OAAO,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,GAAG,EAAE,QAAQ,EAAE;AAAA,EACtD,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS;AAAA,EAC/B,SAAS,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS;AAAA,EACpC,gBAAgB,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS;AAAA,EAC3C,WAAW,EAAE,OAAO,EAAE,SAAS;AAAA,EAC/B,WAAW,EAAE,OAAO,EAAE,SAAS;AAAA,EAC/B,SAAS,EAAE,KAAK,CAAC,OAAO,MAAM,CAAC,EAAE,SAAS;AAC5C,CAAC,EACA,YAAY;AAIR,MAAM,8BAA8B;AAAA,EACzC,KAAK,EAAE,aAAa,MAAM,iBAAiB,CAAC,uBAAuB,EAAE;AAAA,EACrE,MAAM,EAAE,aAAa,MAAM,iBAAiB,CAAC,2BAA2B,EAAE;AAAA,EAC1E,KAAK,EAAE,aAAa,MAAM,iBAAiB,CAAC,2BAA2B,EAAE;AAAA,EACzE,QAAQ,EAAE,aAAa,MAAM,iBAAiB,CAAC,2BAA2B,EAAE;AAC9E;AAEO,MAAM,4CAA4C;AAEzD,MAAM,4BAA+E;AAAA,EACnF,QAAQ;AAAA,EACR,MAAM;AAAA,EACN,YAAY;AACd;AAEA,SAAS,uBAAuB,WAAsB;AACpD,SAAO,WAAW,KAAK;AAAA,IACrB,WAAW;AAAA,MACT;AAAA,MACA;AAAA,IACF;AAAA,EACF,CAAC;AACH;AAEO,SAAS,+BAA+B,KAAc,WAA+B;AAC1F,MAAI,kBAAkB,KAAK,yCAAyC,EAAG,QAAO,uBAAuB,SAAS;AAC9G,SAAO;AACT;AAEA,SAAS,iBAAiB,OAA+B,KAAuD;AAC9G,SAAO,yCAAyC,MAAM,EAAE,GAAG,OAAO,GAAG,kBAAkB,GAAG,EAAE,CAAC;AAC/F;AAEA,SAAS,iBAAiB,OAA+B,KAAuD;AAC9G,SAAO,yCAAyC,MAAM,EAAE,GAAG,OAAO,GAAG,kBAAkB,GAAG,EAAE,CAAC;AAC/F;AAEA,SAAS,aAAa,SAAiG;AACrH,SAAO,EAAE,UAAU,QAAQ,UAAU,gBAAgB,QAAQ,eAAe;AAC9E;AAEA,MAAM,yBAAyB,oBAAI,QAAsE;AAIlG,SAAS,yBAAyB,KAAqD;AAC5F,SAAO;AAAA,IACL,IAAI,IAAI,EAAE,EAAE;AAAA,IACZ,gBAAgB,IAAI,EAAE,eAAe,KAAK;AAAA,IAC1C,UAAU,IAAI,EAAE,SAAS,KAAK;AAAA,IAC9B,SAAS,IAAI,EAAE,QAAQ;AAAA,IACvB,gBAAgB,IAAI,EAAE,gBAAgB;AAAA,IACtC,aAAa,IAAI,EAAE,aAAa,KAAK;AAAA,IACrC,iBAAiB,IAAI,EAAE,gBAAgB,KAAK;AAAA,IAC5C,mBAAmB,IAAI,EAAE,mBAAmB,KAAK;AAAA,IACjD,WAAW,IAAI,EAAE,UAAU,MAAM;AAAA,IACjC,uBAAuB,IAAI,EAAE,sBAAsB,MAAM;AAAA,IACzD,WAAW,IAAI,EAAE,UAAU,KAAK;AAAA,IAChC,WAAW,IAAI,EAAE,UAAU,KAAK;AAAA,EAClC;AACF;AAEA,MAAM,YAAY,EAAE,KAAK,2CAA2C,UAAU,oEAAoE;AAE3I,MAAM,qBAAqB,cAAuF;AAAA,EACvH,UAAU;AAAA,EACV,KAAK;AAAA,IACH,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,UAAU;AAAA,IACV,aAAa;AAAA,IACb,iBAAiB;AAAA,EACnB;AAAA,EACA,SAAS,EAAE,YAAY,EAAE,UAAU,gCAAgC;AAAA,EACnE,MAAM;AAAA,IACJ,QAAQ;AAAA,IACR,UAAU,EAAE,UAAU;AAAA,IACtB,QAAQ;AAAA,MACN,EAAE;AAAA,MACF,EAAE;AAAA,MACF,EAAE;AAAA,MACF,EAAE;AAAA,MACF,EAAE;AAAA,MACF,EAAE;AAAA,MACF,EAAE;AAAA,MACF,EAAE;AAAA,MACF,EAAE;AAAA,MACF,EAAE;AAAA,MACF,EAAE;AAAA,MACF,EAAE;AAAA,IACJ;AAAA,IACA,cAAc;AAAA,MACZ,WAAW,EAAE;AAAA,MACb,WAAW,EAAE;AAAA,MACb,WAAW,EAAE;AAAA,IACf;AAAA,IACA,aAAa,EAAE,OAAO,aAAa,KAAK,MAAM;AAAA,IAC9C,mBAAmB,EAAE;AAAA,IACrB,cAAc,OAAO,OAAO,QAAQ;AAClC,YAAM,UAAmC,CAAC;AAC1C,YAAM,sBAAsB,2BAA2B,GAAG;AAC1D,UAAI,oBAAqB,SAAQ,EAAE,eAAe,IAAI,EAAE,KAAK,oBAAoB;AACjF,UAAI,MAAM,GAAI,SAAQ,EAAE,EAAE,IAAI,EAAE,KAAK,MAAM,GAAG;AAC9C,UAAI,MAAM,QAAS,SAAQ,EAAE,QAAQ,IAAI,EAAE,KAAK,MAAM,QAAQ;AAC9D,UAAI,MAAM,eAAgB,SAAQ,EAAE,gBAAgB,IAAI,EAAE,KAAK,MAAM,eAAe;AACpF,YAAM,YAAY,kBAAkB,MAAM,SAAS;AACnD,UAAI,cAAc,KAAM,SAAQ,EAAE,UAAU,IAAI,EAAE,KAAK,UAAU;AACjE,aAAO;AAAA,IACT;AAAA,IACA,eAAe,CAAC,SAAgC,yBAAyB,IAAI;AAAA,EAC/E;AAAA,EACA,QAAQ;AAAA,IACN,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,cAAc,CAAC,YAAY,qCAAqC,QAAQ,MAAsC;AAAA,EAChH;AAAA,EACA,QAAQ;AAAA,IACN,QAAQ;AAAA,IACR,aAAa,CAAC,OAAO,QAAQ;AAC3B,YAAM,SAAS,iBAAiB,OAAO,GAAG;AAC1C,aAAO;AAAA,QACL,gBAAgB,OAAO;AAAA,QACvB,UAAU,OAAO;AAAA,QACjB,SAAS,OAAO;AAAA,QAChB,gBAAgB,OAAO;AAAA,QACvB,aAAa,OAAO,eAAe;AAAA,QACnC,iBAAiB,OAAO,mBAAmB;AAAA,QAC3C,mBAAmB,OAAO;AAAA,QAC1B,WAAW;AAAA,QACX,uBAAuB,OAAO;AAAA,MAChC;AAAA,IACF;AAAA,IACA,UAAU,CAAC,WAAW;AACpB,YAAM,UAAU;AAChB,aAAO,EAAE,IAAI,QAAQ,IAAI,WAAW,QAAQ,UAAU;AAAA,IACxD;AAAA,EACF;AAAA,EACA,QAAQ;AAAA,IACN,QAAQ;AAAA,IACR,OAAO,CAAC,UAAW,OAAO,MAAM,OAAO,WAAW,MAAM,KAAK;AAAA,IAC7D,eAAe,OAAO,QAAQ,OAAO,QAAQ;AAC3C,YAAM,UAAU;AAChB,kCAA4B,OAAO;AACnC,YAAM,SAAS,iBAAiB,OAAO,GAAG;AAC1C,YAAM,KAAK,IAAI,UAAU,QAAQ,IAAI;AACrC,YAAM,EAAE,UAAU,IAAI,MAAM,oBAAoB;AAChD,YAAM,QAAQ,aAAa,OAAO;AAClC,YAAM,cAAc,OAAO,WAAW,QAAQ;AAC9C,YAAM,eAAe,gBAAgB,QAAQ;AAC7C,UAAI,aAAc,OAAM,mBAAmB,IAAI,aAAa,OAAO,SAAS;AAC5E,UAAI,OAAO,mBAAmB,UAAa,OAAO,mBAAmB,QAAQ,gBAAgB;AAC3F,cAAM,0BAA0B,IAAI,OAAO,gBAAgB,OAAO,SAAS;AAAA,MAC7E;AACA,YAAM,kBAAkB,OAAO,QAAQ,aAAa,IAAI,OAAO,eAAe,OAAO,QAAQ,eAAe;AAC5G,UAAI,mBAAmB,qBAAqB,QAAQ,eAAe,OAAO;AACxE,cAAM,uBAAuB,IAAI,iBAAiB,OAAO,SAAS;AAAA,MACpE;AACA,YAAM,cAAc,OAAO,aAAa,QAAQ;AAChD,UAAI,gBAAgB,CAAC,QAAQ,aAAa,eAAe;AACvD,+BAAuB;AAAA,UACrB;AAAA,UACA,MAAM;AAAA,YACJ;AAAA,YACA;AAAA,YACA,EAAE,GAAG,OAAO,SAAS,YAAY;AAAA,YACjC,QAAQ;AAAA,YACR,MAAM,uBAAuB,SAAS;AAAA,UACxC;AAAA,QACF;AAAA,MACF;AACA,cAAQ,UAAU;AAClB,UAAI,OAAO,mBAAmB,OAAW,SAAQ,iBAAiB,OAAO;AACzE,cAAQ,cAAc;AACtB,UAAI,OAAO,QAAQ,iBAAiB,EAAG,SAAQ,kBAAkB,OAAO,mBAAmB;AAC3F,UAAI,OAAO,sBAAsB,OAAW,SAAQ,oBAAoB,OAAO;AAC/E,UAAI,OAAO,0BAA0B,OAAW,SAAQ,wBAAwB,OAAO;AACvF,cAAQ,YAAY;AACpB,UAAI;AACF,cAAM,GAAG,MAAM;AAAA,MACjB,SAAS,KAAK;AACZ,cAAM,+BAA+B,KAAK,SAAS;AAAA,MACrD;AAAA,IACF;AAAA,IACA,UAAU,OAAO,EAAE,IAAI,KAAK;AAAA,EAC9B;AAAA,EACA,KAAK,EAAE,QAAQ,SAAS,YAAY,MAAM,UAAU,OAAO,EAAE,IAAI,KAAK,GAAG;AAAA,EACzE,OAAO;AAAA,IACL,cAAc,OAAO,OAAO,QAAQ;AAClC,YAAM,yBAAyB,KAAK,8BAA+B,MAA2B,IAAI,SAAS;AAAA,IAC7G;AAAA,IACA,cAAc,OAAO,IAAI,QAAQ;AAC/B,YAAM,yBAAyB,KAAK,8BAA8B,IAAI,SAAS;AAAA,IACjF;AAAA,IACA,cAAc,OAAO,OAAO,QAAQ;AAClC,YAAM,SAAS,yCAAyC,UAAU,EAAE,GAAG,OAAO,GAAG,kBAAkB,GAAG,EAAE,CAAC;AACzG,UAAI,CAAC,OAAO,QAAS;AACrB,YAAM,EAAE,UAAU,IAAI,MAAM,oBAAoB;AAChD,YAAM,KAAM,IAAI,UAAU,QAAQ,IAAI,EAAoB,KAAK;AAC/D,YAAM,QAA6B,EAAE,UAAU,OAAO,KAAK,UAAU,gBAAgB,OAAO,KAAK,eAAe;AAChH,YAAM,mBAAmB,IAAI,OAAO,KAAK,SAAS,OAAO,SAAS;AAClE,YAAM,0BAA0B,IAAI,OAAO,KAAK,gBAAgB,OAAO,SAAS;AAChF,UAAI,OAAO,KAAK,YAAa,OAAM,uBAAuB,IAAI,OAAO,KAAK,aAAa,OAAO,SAAS;AAAA,IACzG;AAAA,IACA,aAAa,OAAO,QAAQ,QAAQ;AAClC,YAAM,UAAU;AAChB,UAAI,iBAAiB,IAAI,OAAO,GAAG,EAAE,cAAc,KAAM;AACzD,YAAM,MAAM,oBAAI,KAAK;AACrB,YAAM,KAAK,IAAI,UAAU,QAAQ,IAAI;AACrC,YAAM,EAAE,UAAU,QAAQ,IAAI,MAAM;AAAA,QAClC;AAAA,QACA;AAAA,QACA,EAAE,GAAG,aAAa,OAAO,GAAG,SAAS,QAAQ,QAAQ;AAAA,QACrD,QAAQ;AAAA,QACR;AAAA,MACF;AACA,UAAI,CAAC,SAAU;AACf,cAAQ,YAAY;AACpB,cAAQ,YAAY;AACpB,YAAM,oCAAoC,IAAI,WAAW,OAAO;AAAA,IAClE;AAAA,IACA,aAAa,OAAO,QAAQ,QAAQ;AAClC,YAAM,UAAU;AAChB,YAAM,UAAU,uBAAuB,IAAI,OAAO;AAClD,UAAI,CAAC,QAAS;AACd,6BAAuB,OAAO,OAAO;AACrC,YAAM,oCAAoC,IAAI,WAAW,OAAO;AAAA,IAClE;AAAA,EACF;AACF,CAAC;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { channelBindingCrud, channelBindingListQuerySchema, channelBindingRouteMetadata } from "./crud.js";
|
|
3
|
+
import {
|
|
4
|
+
ecommerceStoreChannelBindingCreateSchema,
|
|
5
|
+
ecommerceStoreChannelBindingUpdateSchema
|
|
6
|
+
} from "../../data/validators.js";
|
|
7
|
+
import { createEcommerceCrudOpenApi, createPagedListResponseSchema, defaultOkResponseSchema } from "../openapi.js";
|
|
8
|
+
const metadata = channelBindingRouteMetadata;
|
|
9
|
+
const GET = channelBindingCrud.GET;
|
|
10
|
+
const POST = channelBindingCrud.POST;
|
|
11
|
+
const PUT = channelBindingCrud.PUT;
|
|
12
|
+
const DELETE = channelBindingCrud.DELETE;
|
|
13
|
+
const assortmentScopeSchema = z.object({
|
|
14
|
+
categoryIds: z.array(z.string().uuid()).optional(),
|
|
15
|
+
tagIds: z.array(z.string().uuid()).optional(),
|
|
16
|
+
excludeProductIds: z.array(z.string().uuid()).optional(),
|
|
17
|
+
excludeCategoryIds: z.array(z.string().uuid()).optional(),
|
|
18
|
+
excludeTagIds: z.array(z.string().uuid()).optional()
|
|
19
|
+
}).nullable();
|
|
20
|
+
const channelBindingListItemSchema = z.object({
|
|
21
|
+
id: z.string().uuid(),
|
|
22
|
+
organizationId: z.string().uuid().nullable(),
|
|
23
|
+
tenantId: z.string().uuid().nullable(),
|
|
24
|
+
storeId: z.string().uuid(),
|
|
25
|
+
salesChannelId: z.string().uuid(),
|
|
26
|
+
priceKindId: z.string().uuid().nullable(),
|
|
27
|
+
assortmentScope: assortmentScopeSchema,
|
|
28
|
+
priceSortFallback: z.enum(["approximate", "unavailable"]),
|
|
29
|
+
isDefault: z.boolean(),
|
|
30
|
+
requireAuthentication: z.boolean().describe("When true, anonymous buyers resolve to an empty assortment on this channel binding."),
|
|
31
|
+
createdAt: z.string().nullable(),
|
|
32
|
+
updatedAt: z.string().nullable()
|
|
33
|
+
});
|
|
34
|
+
const openApi = createEcommerceCrudOpenApi({
|
|
35
|
+
resourceName: "StoreChannelBinding",
|
|
36
|
+
pluralName: "StoreChannelBindings",
|
|
37
|
+
querySchema: channelBindingListQuerySchema,
|
|
38
|
+
listResponseSchema: createPagedListResponseSchema(channelBindingListItemSchema),
|
|
39
|
+
create: {
|
|
40
|
+
schema: ecommerceStoreChannelBindingCreateSchema,
|
|
41
|
+
responseSchema: z.object({
|
|
42
|
+
id: z.string().uuid().nullable(),
|
|
43
|
+
isDefault: z.boolean().describe("Whether the created binding is the default binding of its store. False when a concurrent request won the promotion.")
|
|
44
|
+
}),
|
|
45
|
+
description: "Binds a sales channel of the same organization to a store, with an optional price kind, assortment scope and require-authentication gate. Requesting isDefault clears the previous default binding of the store."
|
|
46
|
+
},
|
|
47
|
+
update: {
|
|
48
|
+
schema: ecommerceStoreChannelBindingUpdateSchema,
|
|
49
|
+
responseSchema: defaultOkResponseSchema,
|
|
50
|
+
description: "Updates a store channel binding by id (id in the body). Setting isDefault clears the previous default binding of the store."
|
|
51
|
+
},
|
|
52
|
+
del: {
|
|
53
|
+
schema: z.object({ id: z.string().uuid() }),
|
|
54
|
+
responseSchema: defaultOkResponseSchema,
|
|
55
|
+
description: "Soft-deletes a store channel binding by id (?id= query parameter)."
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
export {
|
|
59
|
+
DELETE,
|
|
60
|
+
GET,
|
|
61
|
+
POST,
|
|
62
|
+
PUT,
|
|
63
|
+
channelBindingListItemSchema,
|
|
64
|
+
metadata,
|
|
65
|
+
openApi
|
|
66
|
+
};
|
|
67
|
+
//# sourceMappingURL=route.js.map
|