From a35953d90f17c48fb97137e7231905df3b07c7cc Mon Sep 17 00:00:00 2001 From: sdarbinyan Date: Fri, 21 Aug 2026 15:59:11 +0400 Subject: [PATCH] refactor(di): keep mock gateways out of production builds (FH-E.6) 21 DI tokens selected their implementation like this: factory: () => (environment.useMockData ? inject(XLocal) : inject(XApi)) That reads as a toggle and is not one. Naming both classes in the factory keeps both reachable, so every mock shipped regardless of the flag - and `useMockData` is false in both environment files, so none of them were ever the selected implementation in the first place. Verified: a fixture string from partner-hierarchy-local.gateway.ts was present in a production bundle. Token factories now inject the API gateway unconditionally. Mock overrides move to src/app/mock-gateway.providers.ts, swapped for a production copy that imports nothing, via the same fileReplacements mechanism mock-data.interceptor.production.ts already uses. Dev behaviour is unchanged - flip useMockData in environment.ts exactly as before. useExisting rather than useClass: the local gateways are already providedIn: 'root' singletons, and an app-level provider for the token wins over its tree-shakable default. scan-bundle.sh gains two patterns so this cannot come back: any *LocalGateway class name, and known fixture literals. Verified in both directions - clean against the real dist, exit 1 against a planted OfferLocalGateway. Result: zero LocalGateway classes and zero fixtures in the production bundle, down from 21 classes and 75 kB of source. Initial bundle is unchanged at 1.55 MB because these all sat in lazy chunks; the win is that production can no longer serve seeded fixtures as real data, not bytes off the critical path. Not addressed here: MediaRepository is still bound to MockMediaRepository unconditionally in app.config.ts. That one cannot be deleted - no real implementation exists yet - so it is a missing API gateway, not dead weight. Tracked separately. 256 tests pass. Build green, boundaries and cycles green. Co-Authored-By: Claude Opus 5 --- angular.json | 4 + scripts/ci/scan-bundle.sh | 13 ++- src/app/app.config.ts | 6 +- .../services/analytics-gateway.token.ts | 4 +- .../services/server-cart-gateway.token.ts | 4 +- .../services/mall-content-gateway.token.ts | 4 +- .../finance/services/finance-gateway.token.ts | 4 +- .../services/social-identity-gateway.token.ts | 4 +- .../services/connector-gateway.token.ts | 4 +- .../services/marketplace-gateway.token.ts | 4 +- .../marketplace-revision-gateway.token.ts | 4 +- .../offers/services/offer-gateway.token.ts | 4 +- .../partner-hierarchy-gateway.token.ts | 4 +- .../services/permission-gateway.token.ts | 4 +- .../services/fx-quote-gateway.token.ts | 4 +- .../sellers/services/seller-gateway.token.ts | 4 +- .../admin-dashboard-metrics-gateway.token.ts | 4 +- .../admin-moderation-gateway.token.ts | 4 +- .../admin-monitoring-gateway.token.ts | 4 +- .../admin-notifications-gateway.token.ts | 4 +- .../services/admin-orders-gateway.token.ts | 4 +- .../services/admin-products-gateway.token.ts | 4 +- .../admin-transactions-gateway.token.ts | 4 +- .../services/admin-users-gateway.token.ts | 4 +- src/app/mock-gateway.providers.production.ts | 9 ++ src/app/mock-gateway.providers.ts | 91 +++++++++++++++++++ 26 files changed, 142 insertions(+), 65 deletions(-) create mode 100644 src/app/mock-gateway.providers.production.ts create mode 100644 src/app/mock-gateway.providers.ts diff --git a/angular.json b/angular.json index 72cbb99..7e17eb3 100644 --- a/angular.json +++ b/angular.json @@ -49,6 +49,10 @@ { "replace": "src/app/interceptors/mock-data.interceptor.ts", "with": "src/app/interceptors/mock-data.interceptor.production.ts" + }, + { + "replace": "src/app/mock-gateway.providers.ts", + "with": "src/app/mock-gateway.providers.production.ts" } ], "styles": [ diff --git a/scripts/ci/scan-bundle.sh b/scripts/ci/scan-bundle.sh index 2379405..bdb7403 100644 --- a/scripts/ci/scan-bundle.sh +++ b/scripts/ci/scan-bundle.sh @@ -2,6 +2,13 @@ # Fails the build if a production bundle contains anything that should only # ever exist server-side. # +# It also fails on mock gateway code, for the same reason in a different +# register: a production build that can reach a *LocalGateway is a production +# build that can serve seeded fixtures as if they were real data. Those used to +# ship - a fixture string from partner-hierarchy-local.gateway.ts was present in +# a production bundle on 2026-08-21 - because naming both classes in a token +# factory kept both reachable no matter what the flag said. +# # Why this exists: the storefront used to send provider payment credentials # from the browser - an `authorization-key` header, a `userid-value` header, # and a hardcoded partner ID literal compiled into the bundle. That code is @@ -30,6 +37,8 @@ PATTERNS=( "private key block|BEGIN (RSA |EC |OPENSSH )?PRIVATE KEY" "aws access key|AKIA[0-9A-Z]{16}" "telegram bot token|[0-9]{8,10}:AA[0-9A-Za-z_-]{33}" + "mock gateway class|[A-Za-z]+LocalGateway" + "mock gateway fixture|ptr_local|customer_vk_mock" ) failed=0 @@ -49,7 +58,9 @@ done if [[ $failed -ne 0 ]]; then echo >&2 - echo "A credential reached the browser bundle. Move it behind the API." >&2 + echo "Something reached the browser bundle that should not have." >&2 + echo "Credentials belong behind the API; mock gateways belong in dev-only" >&2 + echo "providers swapped out by angular.json fileReplacements." >&2 exit 1 fi diff --git a/src/app/app.config.ts b/src/app/app.config.ts index 98534c8..5cdbe2f 100644 --- a/src/app/app.config.ts +++ b/src/app/app.config.ts @@ -16,6 +16,7 @@ import { MockMediaRepository } from './core/media/mock-media-repository.service' import { ApiConfigService } from './core/config/api-config.service'; import { TenantResolverService } from './core/config/tenant-resolver.service'; import { environment } from '../environments/environment'; +import { MOCK_GATEWAY_PROVIDERS } from './mock-gateway.providers'; export const appConfig: ApplicationConfig = { providers: [ @@ -72,6 +73,9 @@ export const appConfig: ApplicationConfig = { provideServiceWorker('ngsw-worker.js', { enabled: !isDevMode(), registrationStrategy: 'registerWhenStable:30000' - }) + }), + // Empty in production - the file is swapped at build time so no mock + // gateway is even importable there. See mock-gateway.providers.ts. + ...MOCK_GATEWAY_PROVIDERS ] }; diff --git a/src/app/core/analytics/services/analytics-gateway.token.ts b/src/app/core/analytics/services/analytics-gateway.token.ts index af1b2d2..8bb6e9e 100644 --- a/src/app/core/analytics/services/analytics-gateway.token.ts +++ b/src/app/core/analytics/services/analytics-gateway.token.ts @@ -1,11 +1,9 @@ import { InjectionToken, inject } from '@angular/core'; -import { environment } from '../../../../environments/environment'; import { AnalyticsGateway } from './analytics-gateway.interface'; -import { AnalyticsLocalGateway } from './analytics-local.gateway'; import { AnalyticsApiGateway } from './analytics-api.gateway'; /** Swap point for docs/backend/TRACK-A-ANALYTICS-CONTRACT.md §1. */ export const ANALYTICS_GATEWAY = new InjectionToken('ANALYTICS_GATEWAY', { providedIn: 'root', - factory: () => (environment.useMockData ? inject(AnalyticsLocalGateway) : inject(AnalyticsApiGateway)), + factory: () => inject(AnalyticsApiGateway), }); diff --git a/src/app/core/cart/services/server-cart-gateway.token.ts b/src/app/core/cart/services/server-cart-gateway.token.ts index b622b45..a690884 100644 --- a/src/app/core/cart/services/server-cart-gateway.token.ts +++ b/src/app/core/cart/services/server-cart-gateway.token.ts @@ -1,11 +1,9 @@ import { InjectionToken, inject } from '@angular/core'; -import { environment } from '../../../../environments/environment'; import { ServerCartGateway } from './server-cart-gateway.interface'; -import { ServerCartLocalGateway } from './server-cart-local.gateway'; import { ServerCartApiGateway } from './server-cart-api.gateway'; /** Swap point for docs/backend/PHASE-6-CART-CHECKOUT-CONTRACT.md §3, §5. */ export const SERVER_CART_GATEWAY = new InjectionToken('SERVER_CART_GATEWAY', { providedIn: 'root', - factory: () => (environment.useMockData ? inject(ServerCartLocalGateway) : inject(ServerCartApiGateway)), + factory: () => inject(ServerCartApiGateway), }); diff --git a/src/app/core/content-modules/services/mall-content-gateway.token.ts b/src/app/core/content-modules/services/mall-content-gateway.token.ts index 18ca97e..0b7b314 100644 --- a/src/app/core/content-modules/services/mall-content-gateway.token.ts +++ b/src/app/core/content-modules/services/mall-content-gateway.token.ts @@ -1,11 +1,9 @@ import { InjectionToken, inject } from '@angular/core'; -import { environment } from '../../../../environments/environment'; import { MallContentGateway } from './mall-content-gateway.interface'; -import { MallContentLocalGateway } from './mall-content-local.gateway'; import { MallContentApiGateway } from './mall-content-api.gateway'; /** Swap point for docs/backend/PHASE-10-CONTENT-MODULES-CONTRACT.md. */ export const MALL_CONTENT_GATEWAY = new InjectionToken('MALL_CONTENT_GATEWAY', { providedIn: 'root', - factory: () => (environment.useMockData ? inject(MallContentLocalGateway) : inject(MallContentApiGateway)), + factory: () => inject(MallContentApiGateway), }); diff --git a/src/app/core/finance/services/finance-gateway.token.ts b/src/app/core/finance/services/finance-gateway.token.ts index a51d8ce..d7dd8c8 100644 --- a/src/app/core/finance/services/finance-gateway.token.ts +++ b/src/app/core/finance/services/finance-gateway.token.ts @@ -1,11 +1,9 @@ import { InjectionToken, inject } from '@angular/core'; -import { environment } from '../../../../environments/environment'; import { FinanceGateway } from './finance-gateway.interface'; -import { FinanceLocalGateway } from './finance-local.gateway'; import { FinanceApiGateway } from './finance-api.gateway'; /** Swap point for docs/backend/PHASE-7-PAYMENTS-RECONCILIATION-CONTRACT.md. */ export const FINANCE_GATEWAY = new InjectionToken('FINANCE_GATEWAY', { providedIn: 'root', - factory: () => (environment.useMockData ? inject(FinanceLocalGateway) : inject(FinanceApiGateway)), + factory: () => inject(FinanceApiGateway), }); diff --git a/src/app/core/identity/services/social-identity-gateway.token.ts b/src/app/core/identity/services/social-identity-gateway.token.ts index ced18ec..e7fbe9d 100644 --- a/src/app/core/identity/services/social-identity-gateway.token.ts +++ b/src/app/core/identity/services/social-identity-gateway.token.ts @@ -1,11 +1,9 @@ import { InjectionToken, inject } from '@angular/core'; -import { environment } from '../../../../environments/environment'; import { SocialIdentityGateway } from './social-identity-gateway.interface'; -import { SocialIdentityLocalGateway } from './social-identity-local.gateway'; import { SocialIdentityApiGateway } from './social-identity-api.gateway'; /** Swap point for docs/backend/PHASE-8-IDENTITY-MESSAGING-CONTRACT.md §2. */ export const SOCIAL_IDENTITY_GATEWAY = new InjectionToken('SOCIAL_IDENTITY_GATEWAY', { providedIn: 'root', - factory: () => (environment.useMockData ? inject(SocialIdentityLocalGateway) : inject(SocialIdentityApiGateway)), + factory: () => inject(SocialIdentityApiGateway), }); diff --git a/src/app/core/integrations/services/connector-gateway.token.ts b/src/app/core/integrations/services/connector-gateway.token.ts index f416cdf..290c518 100644 --- a/src/app/core/integrations/services/connector-gateway.token.ts +++ b/src/app/core/integrations/services/connector-gateway.token.ts @@ -1,11 +1,9 @@ import { InjectionToken, inject } from '@angular/core'; -import { environment } from '../../../../environments/environment'; import { ConnectorGateway } from './connector-gateway.interface'; -import { ConnectorLocalGateway } from './connector-local.gateway'; import { ConnectorApiGateway } from './connector-api.gateway'; /** Swap point for docs/backend/PHASE-4-CONNECTOR-FRAMEWORK-CONTRACT.md §7. */ export const CONNECTOR_GATEWAY = new InjectionToken('CONNECTOR_GATEWAY', { providedIn: 'root', - factory: () => (environment.useMockData ? inject(ConnectorLocalGateway) : inject(ConnectorApiGateway)), + factory: () => inject(ConnectorApiGateway), }); diff --git a/src/app/core/marketplace-registry/services/marketplace-gateway.token.ts b/src/app/core/marketplace-registry/services/marketplace-gateway.token.ts index f1c492b..c8ea6c0 100644 --- a/src/app/core/marketplace-registry/services/marketplace-gateway.token.ts +++ b/src/app/core/marketplace-registry/services/marketplace-gateway.token.ts @@ -1,11 +1,9 @@ import { InjectionToken, inject } from '@angular/core'; -import { environment } from '../../../../environments/environment'; import { MarketplaceGateway } from './marketplace-gateway.interface'; -import { MarketplaceLocalGateway } from './marketplace-local.gateway'; import { MarketplaceApiGateway } from './marketplace-api.gateway'; /** Swap point for docs/backend/PHASE-9-TENANT-REGISTRY-DOMAINS-CONTRACT.md. */ export const MARKETPLACE_GATEWAY = new InjectionToken('MARKETPLACE_GATEWAY', { providedIn: 'root', - factory: () => (environment.useMockData ? inject(MarketplaceLocalGateway) : inject(MarketplaceApiGateway)), + factory: () => inject(MarketplaceApiGateway), }); diff --git a/src/app/core/marketplace-registry/services/marketplace-revision-gateway.token.ts b/src/app/core/marketplace-registry/services/marketplace-revision-gateway.token.ts index e18cdf9..da6c99b 100644 --- a/src/app/core/marketplace-registry/services/marketplace-revision-gateway.token.ts +++ b/src/app/core/marketplace-registry/services/marketplace-revision-gateway.token.ts @@ -1,11 +1,9 @@ import { InjectionToken, inject } from '@angular/core'; -import { environment } from '../../../../environments/environment'; import { MarketplaceRevisionGateway } from './marketplace-revision-gateway.interface'; -import { MarketplaceRevisionLocalGateway } from './marketplace-revision-local.gateway'; import { MarketplaceRevisionApiGateway } from './marketplace-revision-api.gateway'; /** Swap point for docs/backend/PHASE-9-TENANT-REGISTRY-DOMAINS-CONTRACT.md §5. */ export const MARKETPLACE_REVISION_GATEWAY = new InjectionToken('MARKETPLACE_REVISION_GATEWAY', { providedIn: 'root', - factory: () => (environment.useMockData ? inject(MarketplaceRevisionLocalGateway) : inject(MarketplaceRevisionApiGateway)), + factory: () => inject(MarketplaceRevisionApiGateway), }); diff --git a/src/app/core/offers/services/offer-gateway.token.ts b/src/app/core/offers/services/offer-gateway.token.ts index a237433..c5f4acb 100644 --- a/src/app/core/offers/services/offer-gateway.token.ts +++ b/src/app/core/offers/services/offer-gateway.token.ts @@ -1,11 +1,9 @@ import { InjectionToken, inject } from '@angular/core'; -import { environment } from '../../../../environments/environment'; import { OfferGateway } from './offer-gateway.interface'; -import { OfferLocalGateway } from './offer-local.gateway'; import { OfferApiGateway } from './offer-api.gateway'; /** Swap point for docs/backend/PHASE-3-CATALOG-OFFER-FULFILLMENT-CONTRACT.md §7. */ export const OFFER_GATEWAY = new InjectionToken('OFFER_GATEWAY', { providedIn: 'root', - factory: () => (environment.useMockData ? inject(OfferLocalGateway) : inject(OfferApiGateway)), + factory: () => inject(OfferApiGateway), }); diff --git a/src/app/core/partner-hierarchy/services/partner-hierarchy-gateway.token.ts b/src/app/core/partner-hierarchy/services/partner-hierarchy-gateway.token.ts index e82017c..74b84c6 100644 --- a/src/app/core/partner-hierarchy/services/partner-hierarchy-gateway.token.ts +++ b/src/app/core/partner-hierarchy/services/partner-hierarchy-gateway.token.ts @@ -1,11 +1,9 @@ import { InjectionToken, inject } from '@angular/core'; -import { environment } from '../../../../environments/environment'; import { PartnerHierarchyGateway } from './partner-hierarchy-gateway.interface'; -import { PartnerHierarchyLocalGateway } from './partner-hierarchy-local.gateway'; import { PartnerHierarchyApiGateway } from './partner-hierarchy-api.gateway'; /** Swap point for docs/backend/PARTNER-PROVISIONING-API-CONTRACT.md §4, §6. */ export const PARTNER_HIERARCHY_GATEWAY = new InjectionToken('PARTNER_HIERARCHY_GATEWAY', { providedIn: 'root', - factory: () => (environment.useMockData ? inject(PartnerHierarchyLocalGateway) : inject(PartnerHierarchyApiGateway)), + factory: () => inject(PartnerHierarchyApiGateway), }); diff --git a/src/app/core/permissions/services/permission-gateway.token.ts b/src/app/core/permissions/services/permission-gateway.token.ts index c11bdb8..5a074b2 100644 --- a/src/app/core/permissions/services/permission-gateway.token.ts +++ b/src/app/core/permissions/services/permission-gateway.token.ts @@ -1,11 +1,9 @@ import { InjectionToken, inject } from '@angular/core'; -import { environment } from '../../../../environments/environment'; import { PermissionGateway } from './permission-gateway.interface'; -import { PermissionLocalGateway } from './permission-local.gateway'; import { PermissionApiGateway } from './permission-api.gateway'; /** Swap point for docs/backend/TRACK-S-SECURITY-RBAC-CONTRACT.md §2-3. */ export const PERMISSION_GATEWAY = new InjectionToken('PERMISSION_GATEWAY', { providedIn: 'root', - factory: () => (environment.useMockData ? inject(PermissionLocalGateway) : inject(PermissionApiGateway)), + factory: () => inject(PermissionApiGateway), }); diff --git a/src/app/core/pricing/services/fx-quote-gateway.token.ts b/src/app/core/pricing/services/fx-quote-gateway.token.ts index 6336fc9..2a54e53 100644 --- a/src/app/core/pricing/services/fx-quote-gateway.token.ts +++ b/src/app/core/pricing/services/fx-quote-gateway.token.ts @@ -1,11 +1,9 @@ import { InjectionToken, inject } from '@angular/core'; -import { environment } from '../../../../environments/environment'; import { FxQuoteGateway } from './fx-quote-gateway.interface'; -import { FxQuoteLocalGateway } from './fx-quote-local.gateway'; import { FxQuoteApiGateway } from './fx-quote-api.gateway'; /** Swap point for docs/backend/PHASE-1-MONEY-FX-PAYMENTS-CONTRACT.md §3.1. */ export const FX_QUOTE_GATEWAY = new InjectionToken('FX_QUOTE_GATEWAY', { providedIn: 'root', - factory: () => (environment.useMockData ? inject(FxQuoteLocalGateway) : inject(FxQuoteApiGateway)), + factory: () => inject(FxQuoteApiGateway), }); diff --git a/src/app/core/sellers/services/seller-gateway.token.ts b/src/app/core/sellers/services/seller-gateway.token.ts index c1972e7..d4444c1 100644 --- a/src/app/core/sellers/services/seller-gateway.token.ts +++ b/src/app/core/sellers/services/seller-gateway.token.ts @@ -1,11 +1,9 @@ import { InjectionToken, inject } from '@angular/core'; -import { environment } from '../../../../environments/environment'; import { SellerGateway } from './seller-gateway.interface'; -import { SellerLocalGateway } from './seller-local.gateway'; import { SellerApiGateway } from './seller-api.gateway'; /** Swap point for docs/backend/PHASE-5-SELLER-PORTAL-CONTRACT.md §3. */ export const SELLER_GATEWAY = new InjectionToken('SELLER_GATEWAY', { providedIn: 'root', - factory: () => (environment.useMockData ? inject(SellerLocalGateway) : inject(SellerApiGateway)), + factory: () => inject(SellerApiGateway), }); diff --git a/src/app/features/admin/dashboard/services/admin-dashboard-metrics-gateway.token.ts b/src/app/features/admin/dashboard/services/admin-dashboard-metrics-gateway.token.ts index 2ab37b2..7ff99e0 100644 --- a/src/app/features/admin/dashboard/services/admin-dashboard-metrics-gateway.token.ts +++ b/src/app/features/admin/dashboard/services/admin-dashboard-metrics-gateway.token.ts @@ -1,11 +1,9 @@ import { InjectionToken, inject } from '@angular/core'; -import { environment } from '../../../../../environments/environment'; import { AdminDashboardMetricsGateway } from './admin-dashboard-metrics.gateway.interface'; -import { AdminDashboardMetricsLocalGateway } from './admin-dashboard-metrics.local.gateway'; import { AdminDashboardMetricsApiGateway } from './admin-dashboard-metrics-api.gateway'; /** Swap point. */ export const ADMIN_DASHBOARD_METRICS_GATEWAY = new InjectionToken('ADMIN_DASHBOARD_METRICS_GATEWAY', { providedIn: 'root', - factory: () => (environment.useMockData ? inject(AdminDashboardMetricsLocalGateway) : inject(AdminDashboardMetricsApiGateway)), + factory: () => inject(AdminDashboardMetricsApiGateway), }); diff --git a/src/app/features/admin/moderation/services/admin-moderation-gateway.token.ts b/src/app/features/admin/moderation/services/admin-moderation-gateway.token.ts index b860008..e847c65 100644 --- a/src/app/features/admin/moderation/services/admin-moderation-gateway.token.ts +++ b/src/app/features/admin/moderation/services/admin-moderation-gateway.token.ts @@ -1,11 +1,9 @@ import { InjectionToken, inject } from '@angular/core'; -import { environment } from '../../../../../environments/environment'; import { AdminModerationGateway } from './admin-moderation-gateway.interface'; -import { AdminModerationLocalGateway } from './admin-moderation-local.gateway'; import { AdminModerationApiGateway } from './admin-moderation-api.gateway'; /** Swap point. */ export const ADMIN_MODERATION_GATEWAY = new InjectionToken('ADMIN_MODERATION_GATEWAY', { providedIn: 'root', - factory: () => (environment.useMockData ? inject(AdminModerationLocalGateway) : inject(AdminModerationApiGateway)), + factory: () => inject(AdminModerationApiGateway), }); diff --git a/src/app/features/admin/monitoring/services/admin-monitoring-gateway.token.ts b/src/app/features/admin/monitoring/services/admin-monitoring-gateway.token.ts index e95daf0..1858645 100644 --- a/src/app/features/admin/monitoring/services/admin-monitoring-gateway.token.ts +++ b/src/app/features/admin/monitoring/services/admin-monitoring-gateway.token.ts @@ -1,11 +1,9 @@ import { InjectionToken, inject } from '@angular/core'; -import { environment } from '../../../../../environments/environment'; import { AdminMonitoringGateway } from './admin-monitoring-gateway.interface'; -import { AdminMonitoringLocalGateway } from './admin-monitoring-local.gateway'; import { AdminMonitoringApiGateway } from './admin-monitoring-api.gateway'; /** Swap point. */ export const ADMIN_MONITORING_GATEWAY = new InjectionToken('ADMIN_MONITORING_GATEWAY', { providedIn: 'root', - factory: () => (environment.useMockData ? inject(AdminMonitoringLocalGateway) : inject(AdminMonitoringApiGateway)), + factory: () => inject(AdminMonitoringApiGateway), }); diff --git a/src/app/features/admin/notifications/services/admin-notifications-gateway.token.ts b/src/app/features/admin/notifications/services/admin-notifications-gateway.token.ts index 91e313e..91b3b6e 100644 --- a/src/app/features/admin/notifications/services/admin-notifications-gateway.token.ts +++ b/src/app/features/admin/notifications/services/admin-notifications-gateway.token.ts @@ -1,11 +1,9 @@ import { InjectionToken, inject } from '@angular/core'; -import { environment } from '../../../../../environments/environment'; import { AdminNotificationsGateway } from './admin-notifications-gateway.interface'; -import { AdminNotificationsLocalGateway } from './admin-notifications-local.gateway'; import { AdminNotificationsApiGateway } from './admin-notifications-api.gateway'; /** Swap point for docs/backend/PHASE-2-ORDERS-NOTIFICATIONS-CONTRACT.md §7. */ export const ADMIN_NOTIFICATIONS_GATEWAY = new InjectionToken('ADMIN_NOTIFICATIONS_GATEWAY', { providedIn: 'root', - factory: () => (environment.useMockData ? inject(AdminNotificationsLocalGateway) : inject(AdminNotificationsApiGateway)), + factory: () => inject(AdminNotificationsApiGateway), }); diff --git a/src/app/features/admin/orders/services/admin-orders-gateway.token.ts b/src/app/features/admin/orders/services/admin-orders-gateway.token.ts index 42dd680..2852195 100644 --- a/src/app/features/admin/orders/services/admin-orders-gateway.token.ts +++ b/src/app/features/admin/orders/services/admin-orders-gateway.token.ts @@ -1,11 +1,9 @@ import { InjectionToken, inject } from '@angular/core'; -import { environment } from '../../../../../environments/environment'; import { AdminOrdersGateway } from './admin-orders-gateway.interface'; -import { AdminOrdersLocalGateway } from './admin-orders-local.gateway'; import { AdminOrdersApiGateway } from './admin-orders-api.gateway'; /** Swap point for docs/backend/PHASE-2-ORDERS-NOTIFICATIONS-CONTRACT.md. */ export const ADMIN_ORDERS_GATEWAY = new InjectionToken('ADMIN_ORDERS_GATEWAY', { providedIn: 'root', - factory: () => (environment.useMockData ? inject(AdminOrdersLocalGateway) : inject(AdminOrdersApiGateway)), + factory: () => inject(AdminOrdersApiGateway), }); diff --git a/src/app/features/admin/products/services/admin-products-gateway.token.ts b/src/app/features/admin/products/services/admin-products-gateway.token.ts index 5e414c2..a04b2c5 100644 --- a/src/app/features/admin/products/services/admin-products-gateway.token.ts +++ b/src/app/features/admin/products/services/admin-products-gateway.token.ts @@ -1,11 +1,9 @@ import { InjectionToken, inject } from '@angular/core'; -import { environment } from '../../../../../environments/environment'; import { AdminProductsGateway } from './admin-products-gateway.interface'; -import { AdminProductsLocalGateway } from './admin-products-local.gateway'; import { AdminProductsApiGateway } from './admin-products-api.gateway'; /** Swap point for docs/backend/PHASE-3-CATALOG-OFFER-FULFILLMENT-CONTRACT.md §7. */ export const ADMIN_PRODUCTS_GATEWAY = new InjectionToken('ADMIN_PRODUCTS_GATEWAY', { providedIn: 'root', - factory: () => (environment.useMockData ? inject(AdminProductsLocalGateway) : inject(AdminProductsApiGateway)), + factory: () => inject(AdminProductsApiGateway), }); diff --git a/src/app/features/admin/transactions/services/admin-transactions-gateway.token.ts b/src/app/features/admin/transactions/services/admin-transactions-gateway.token.ts index 972a892..86c0fc4 100644 --- a/src/app/features/admin/transactions/services/admin-transactions-gateway.token.ts +++ b/src/app/features/admin/transactions/services/admin-transactions-gateway.token.ts @@ -1,11 +1,9 @@ import { InjectionToken, inject } from '@angular/core'; -import { environment } from '../../../../../environments/environment'; import { AdminTransactionsGateway } from './admin-transactions-gateway.interface'; -import { AdminTransactionsLocalGateway } from './admin-transactions-local.gateway'; import { AdminTransactionsApiGateway } from './admin-transactions-api.gateway'; /** Swap point for docs/backend/PHASE-1-MONEY-FX-PAYMENTS-CONTRACT.md §6. */ export const ADMIN_TRANSACTIONS_GATEWAY = new InjectionToken('ADMIN_TRANSACTIONS_GATEWAY', { providedIn: 'root', - factory: () => (environment.useMockData ? inject(AdminTransactionsLocalGateway) : inject(AdminTransactionsApiGateway)), + factory: () => inject(AdminTransactionsApiGateway), }); diff --git a/src/app/features/admin/users/services/admin-users-gateway.token.ts b/src/app/features/admin/users/services/admin-users-gateway.token.ts index d144e46..22e9009 100644 --- a/src/app/features/admin/users/services/admin-users-gateway.token.ts +++ b/src/app/features/admin/users/services/admin-users-gateway.token.ts @@ -1,11 +1,9 @@ import { InjectionToken, inject } from '@angular/core'; -import { environment } from '../../../../../environments/environment'; import { AdminUsersGateway } from './admin-users-gateway.interface'; -import { AdminUsersLocalGateway } from './admin-users-local.gateway'; import { AdminUsersApiGateway } from './admin-users-api.gateway'; /** Swap point for docs/backend/TRACK-S-SECURITY-RBAC-CONTRACT.md §8. */ export const ADMIN_USERS_GATEWAY = new InjectionToken('ADMIN_USERS_GATEWAY', { providedIn: 'root', - factory: () => (environment.useMockData ? inject(AdminUsersLocalGateway) : inject(AdminUsersApiGateway)), + factory: () => inject(AdminUsersApiGateway), }); diff --git a/src/app/mock-gateway.providers.production.ts b/src/app/mock-gateway.providers.production.ts new file mode 100644 index 0000000..3d92efd --- /dev/null +++ b/src/app/mock-gateway.providers.production.ts @@ -0,0 +1,9 @@ +import { Provider } from '@angular/core'; + +/** + * Production replacement for mock-gateway.providers.ts (angular.json + * fileReplacements). Imports nothing on purpose: this file existing is what + * guarantees no *LocalGateway or its fixtures can be reached from a + * production build. + */ +export const MOCK_GATEWAY_PROVIDERS: Provider[] = []; diff --git a/src/app/mock-gateway.providers.ts b/src/app/mock-gateway.providers.ts new file mode 100644 index 0000000..2fe4c09 --- /dev/null +++ b/src/app/mock-gateway.providers.ts @@ -0,0 +1,91 @@ +import { Provider } from '@angular/core'; +import { environment } from '../environments/environment'; + +import { ADMIN_DASHBOARD_METRICS_GATEWAY } from './features/admin/dashboard/services/admin-dashboard-metrics-gateway.token'; +import { AdminDashboardMetricsLocalGateway } from './features/admin/dashboard/services/admin-dashboard-metrics.local.gateway'; +import { ADMIN_MODERATION_GATEWAY } from './features/admin/moderation/services/admin-moderation-gateway.token'; +import { AdminModerationLocalGateway } from './features/admin/moderation/services/admin-moderation-local.gateway'; +import { ADMIN_MONITORING_GATEWAY } from './features/admin/monitoring/services/admin-monitoring-gateway.token'; +import { AdminMonitoringLocalGateway } from './features/admin/monitoring/services/admin-monitoring-local.gateway'; +import { ADMIN_NOTIFICATIONS_GATEWAY } from './features/admin/notifications/services/admin-notifications-gateway.token'; +import { AdminNotificationsLocalGateway } from './features/admin/notifications/services/admin-notifications-local.gateway'; +import { ADMIN_ORDERS_GATEWAY } from './features/admin/orders/services/admin-orders-gateway.token'; +import { AdminOrdersLocalGateway } from './features/admin/orders/services/admin-orders-local.gateway'; +import { ADMIN_PRODUCTS_GATEWAY } from './features/admin/products/services/admin-products-gateway.token'; +import { AdminProductsLocalGateway } from './features/admin/products/services/admin-products-local.gateway'; +import { ADMIN_TRANSACTIONS_GATEWAY } from './features/admin/transactions/services/admin-transactions-gateway.token'; +import { AdminTransactionsLocalGateway } from './features/admin/transactions/services/admin-transactions-local.gateway'; +import { ADMIN_USERS_GATEWAY } from './features/admin/users/services/admin-users-gateway.token'; +import { AdminUsersLocalGateway } from './features/admin/users/services/admin-users-local.gateway'; +import { ANALYTICS_GATEWAY } from './core/analytics/services/analytics-gateway.token'; +import { AnalyticsLocalGateway } from './core/analytics/services/analytics-local.gateway'; +import { CONNECTOR_GATEWAY } from './core/integrations/services/connector-gateway.token'; +import { ConnectorLocalGateway } from './core/integrations/services/connector-local.gateway'; +import { FINANCE_GATEWAY } from './core/finance/services/finance-gateway.token'; +import { FinanceLocalGateway } from './core/finance/services/finance-local.gateway'; +import { FX_QUOTE_GATEWAY } from './core/pricing/services/fx-quote-gateway.token'; +import { FxQuoteLocalGateway } from './core/pricing/services/fx-quote-local.gateway'; +import { MALL_CONTENT_GATEWAY } from './core/content-modules/services/mall-content-gateway.token'; +import { MallContentLocalGateway } from './core/content-modules/services/mall-content-local.gateway'; +import { MARKETPLACE_GATEWAY } from './core/marketplace-registry/services/marketplace-gateway.token'; +import { MarketplaceLocalGateway } from './core/marketplace-registry/services/marketplace-local.gateway'; +import { MARKETPLACE_REVISION_GATEWAY } from './core/marketplace-registry/services/marketplace-revision-gateway.token'; +import { MarketplaceRevisionLocalGateway } from './core/marketplace-registry/services/marketplace-revision-local.gateway'; +import { OFFER_GATEWAY } from './core/offers/services/offer-gateway.token'; +import { OfferLocalGateway } from './core/offers/services/offer-local.gateway'; +import { PARTNER_HIERARCHY_GATEWAY } from './core/partner-hierarchy/services/partner-hierarchy-gateway.token'; +import { PartnerHierarchyLocalGateway } from './core/partner-hierarchy/services/partner-hierarchy-local.gateway'; +import { PERMISSION_GATEWAY } from './core/permissions/services/permission-gateway.token'; +import { PermissionLocalGateway } from './core/permissions/services/permission-local.gateway'; +import { SELLER_GATEWAY } from './core/sellers/services/seller-gateway.token'; +import { SellerLocalGateway } from './core/sellers/services/seller-local.gateway'; +import { SERVER_CART_GATEWAY } from './core/cart/services/server-cart-gateway.token'; +import { ServerCartLocalGateway } from './core/cart/services/server-cart-local.gateway'; +import { SOCIAL_IDENTITY_GATEWAY } from './core/identity/services/social-identity-gateway.token'; +import { SocialIdentityLocalGateway } from './core/identity/services/social-identity-local.gateway'; + +/** + * Development-only gateway overrides. + * + * This file is swapped for mock-gateway.providers.production.ts at build time + * (see angular.json fileReplacements), the same mechanism + * mock-data.interceptor.production.ts already uses. The production copy + * imports nothing, so no *LocalGateway class - and none of its seeded + * fixtures - can reach a production bundle. + * + * It used to live inside each token factory as + * factory: () => (environment.useMockData ? inject(XLocal) : inject(XApi)) + * which reads as a toggle but is not one: naming both classes in the factory + * keeps both reachable, so every mock shipped regardless of the flag. A + * fixture string from partner-hierarchy-local.gateway.ts was verifiably + * present in a production build on 2026-08-21. + * + * useExisting rather than useClass: the local gateways are already + * providedIn: 'root' singletons, and an app-level provider for the token + * wins over its tree-shakable default. + */ +export const MOCK_GATEWAY_PROVIDERS: Provider[] = environment.useMockData + ? [ + { provide: ADMIN_DASHBOARD_METRICS_GATEWAY, useExisting: AdminDashboardMetricsLocalGateway }, + { provide: ADMIN_MODERATION_GATEWAY, useExisting: AdminModerationLocalGateway }, + { provide: ADMIN_MONITORING_GATEWAY, useExisting: AdminMonitoringLocalGateway }, + { provide: ADMIN_NOTIFICATIONS_GATEWAY, useExisting: AdminNotificationsLocalGateway }, + { provide: ADMIN_ORDERS_GATEWAY, useExisting: AdminOrdersLocalGateway }, + { provide: ADMIN_PRODUCTS_GATEWAY, useExisting: AdminProductsLocalGateway }, + { provide: ADMIN_TRANSACTIONS_GATEWAY, useExisting: AdminTransactionsLocalGateway }, + { provide: ADMIN_USERS_GATEWAY, useExisting: AdminUsersLocalGateway }, + { provide: ANALYTICS_GATEWAY, useExisting: AnalyticsLocalGateway }, + { provide: CONNECTOR_GATEWAY, useExisting: ConnectorLocalGateway }, + { provide: FINANCE_GATEWAY, useExisting: FinanceLocalGateway }, + { provide: FX_QUOTE_GATEWAY, useExisting: FxQuoteLocalGateway }, + { provide: MALL_CONTENT_GATEWAY, useExisting: MallContentLocalGateway }, + { provide: MARKETPLACE_GATEWAY, useExisting: MarketplaceLocalGateway }, + { provide: MARKETPLACE_REVISION_GATEWAY, useExisting: MarketplaceRevisionLocalGateway }, + { provide: OFFER_GATEWAY, useExisting: OfferLocalGateway }, + { provide: PARTNER_HIERARCHY_GATEWAY, useExisting: PartnerHierarchyLocalGateway }, + { provide: PERMISSION_GATEWAY, useExisting: PermissionLocalGateway }, + { provide: SELLER_GATEWAY, useExisting: SellerLocalGateway }, + { provide: SERVER_CART_GATEWAY, useExisting: ServerCartLocalGateway }, + { provide: SOCIAL_IDENTITY_GATEWAY, useExisting: SocialIdentityLocalGateway }, + ] + : [];