@endora-commerce/platform 0.100.0
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/LICENSE +21 -0
- package/README.md +58 -0
- package/dist/cli/dispatch.d.ts +146 -0
- package/dist/cli/dispatch.d.ts.map +1 -0
- package/dist/cli/dispatch.js +259 -0
- package/dist/cli/dispatch.js.map +1 -0
- package/dist/cli/index.d.ts +58 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +58 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/module-commands.d.ts +118 -0
- package/dist/cli/module-commands.d.ts.map +1 -0
- package/dist/cli/module-commands.js +120 -0
- package/dist/cli/module-commands.js.map +1 -0
- package/dist/commands/actor.d.ts +19 -0
- package/dist/commands/actor.d.ts.map +1 -0
- package/dist/commands/actor.js +45 -0
- package/dist/commands/actor.js.map +1 -0
- package/dist/commands/audit-from-context.d.ts +24 -0
- package/dist/commands/audit-from-context.d.ts.map +1 -0
- package/dist/commands/audit-from-context.js +28 -0
- package/dist/commands/audit-from-context.js.map +1 -0
- package/dist/commands/command-bus.d.ts +40 -0
- package/dist/commands/command-bus.d.ts.map +1 -0
- package/dist/commands/command-bus.js +46 -0
- package/dist/commands/command-bus.js.map +1 -0
- package/dist/commands/command.d.ts +76 -0
- package/dist/commands/command.d.ts.map +1 -0
- package/dist/commands/command.js +2 -0
- package/dist/commands/command.js.map +1 -0
- package/dist/commands/index.d.ts +65 -0
- package/dist/commands/index.d.ts.map +1 -0
- package/dist/commands/index.js +57 -0
- package/dist/commands/index.js.map +1 -0
- package/dist/commands/reversible.d.ts +66 -0
- package/dist/commands/reversible.d.ts.map +1 -0
- package/dist/commands/reversible.js +41 -0
- package/dist/commands/reversible.js.map +1 -0
- package/dist/composition/compose-app.d.ts +305 -0
- package/dist/composition/compose-app.d.ts.map +1 -0
- package/dist/composition/compose-app.js +939 -0
- package/dist/composition/compose-app.js.map +1 -0
- package/dist/composition/index.d.ts +92 -0
- package/dist/composition/index.d.ts.map +1 -0
- package/dist/composition/index.js +175 -0
- package/dist/composition/index.js.map +1 -0
- package/dist/composition/newsletter-token-secret.d.ts +19 -0
- package/dist/composition/newsletter-token-secret.d.ts.map +1 -0
- package/dist/composition/newsletter-token-secret.js +24 -0
- package/dist/composition/newsletter-token-secret.js.map +1 -0
- package/dist/composition/process-runs-workers.d.ts +17 -0
- package/dist/composition/process-runs-workers.d.ts.map +1 -0
- package/dist/composition/process-runs-workers.js +19 -0
- package/dist/composition/process-runs-workers.js.map +1 -0
- package/dist/db/baseline-migration-inventory.d.ts +15 -0
- package/dist/db/baseline-migration-inventory.d.ts.map +1 -0
- package/dist/db/baseline-migration-inventory.js +115 -0
- package/dist/db/baseline-migration-inventory.js.map +1 -0
- package/dist/db/configured-entities.d.ts +74 -0
- package/dist/db/configured-entities.d.ts.map +1 -0
- package/dist/db/configured-entities.js +20 -0
- package/dist/db/configured-entities.js.map +1 -0
- package/dist/db/configured-migrations.d.ts +199 -0
- package/dist/db/configured-migrations.d.ts.map +1 -0
- package/dist/db/configured-migrations.js +181 -0
- package/dist/db/configured-migrations.js.map +1 -0
- package/dist/db/index.d.ts +54 -0
- package/dist/db/index.d.ts.map +1 -0
- package/dist/db/index.js +54 -0
- package/dist/db/index.js.map +1 -0
- package/dist/db/migrate.d.ts +21 -0
- package/dist/db/migrate.d.ts.map +1 -0
- package/dist/db/migrate.js +48 -0
- package/dist/db/migrate.js.map +1 -0
- package/dist/db/migration-order.d.ts +159 -0
- package/dist/db/migration-order.d.ts.map +1 -0
- package/dist/db/migration-order.js +273 -0
- package/dist/db/migration-order.js.map +1 -0
- package/dist/db/mikro-orm.config.d.ts +51 -0
- package/dist/db/mikro-orm.config.d.ts.map +1 -0
- package/dist/db/mikro-orm.config.js +64 -0
- package/dist/db/mikro-orm.config.js.map +1 -0
- package/dist/db/orm.d.ts +40 -0
- package/dist/db/orm.d.ts.map +1 -0
- package/dist/db/orm.js +25 -0
- package/dist/db/orm.js.map +1 -0
- package/dist/db/platform-schema.d.ts +102 -0
- package/dist/db/platform-schema.d.ts.map +1 -0
- package/dist/db/platform-schema.js +79 -0
- package/dist/db/platform-schema.js.map +1 -0
- package/dist/db/pluralizing-naming-strategy.d.ts +16 -0
- package/dist/db/pluralizing-naming-strategy.d.ts.map +1 -0
- package/dist/db/pluralizing-naming-strategy.js +66 -0
- package/dist/db/pluralizing-naming-strategy.js.map +1 -0
- package/dist/demo/guard.d.ts +101 -0
- package/dist/demo/guard.d.ts.map +1 -0
- package/dist/demo/guard.js +168 -0
- package/dist/demo/guard.js.map +1 -0
- package/dist/demo/host-command.d.ts +133 -0
- package/dist/demo/host-command.d.ts.map +1 -0
- package/dist/demo/host-command.js +113 -0
- package/dist/demo/host-command.js.map +1 -0
- package/dist/demo/index.d.ts +82 -0
- package/dist/demo/index.d.ts.map +1 -0
- package/dist/demo/index.js +82 -0
- package/dist/demo/index.js.map +1 -0
- package/dist/demo/packages.d.ts +67 -0
- package/dist/demo/packages.d.ts.map +1 -0
- package/dist/demo/packages.js +132 -0
- package/dist/demo/packages.js.map +1 -0
- package/dist/demo/plan.d.ts +111 -0
- package/dist/demo/plan.d.ts.map +1 -0
- package/dist/demo/plan.js +74 -0
- package/dist/demo/plan.js.map +1 -0
- package/dist/demo/report.d.ts +17 -0
- package/dist/demo/report.d.ts.map +1 -0
- package/dist/demo/report.js +85 -0
- package/dist/demo/report.js.map +1 -0
- package/dist/demo/runner.d.ts +207 -0
- package/dist/demo/runner.d.ts.map +1 -0
- package/dist/demo/runner.js +169 -0
- package/dist/demo/runner.js.map +1 -0
- package/dist/demo/scope.d.ts +44 -0
- package/dist/demo/scope.d.ts.map +1 -0
- package/dist/demo/scope.js +44 -0
- package/dist/demo/scope.js.map +1 -0
- package/dist/env/index.d.ts +68 -0
- package/dist/env/index.d.ts.map +1 -0
- package/dist/env/index.js +427 -0
- package/dist/env/index.js.map +1 -0
- package/dist/events/bus.d.ts +29 -0
- package/dist/events/bus.d.ts.map +1 -0
- package/dist/events/bus.js +67 -0
- package/dist/events/bus.js.map +1 -0
- package/dist/events/index.d.ts +19 -0
- package/dist/events/index.d.ts.map +1 -0
- package/dist/events/index.js +19 -0
- package/dist/events/index.js.map +1 -0
- package/dist/http/cursor.d.ts +10 -0
- package/dist/http/cursor.d.ts.map +1 -0
- package/dist/http/cursor.js +20 -0
- package/dist/http/cursor.js.map +1 -0
- package/dist/http/error-envelope.d.ts +127 -0
- package/dist/http/error-envelope.d.ts.map +1 -0
- package/dist/http/error-envelope.js +402 -0
- package/dist/http/error-envelope.js.map +1 -0
- package/dist/http/health.d.ts +88 -0
- package/dist/http/health.d.ts.map +1 -0
- package/dist/http/health.js +77 -0
- package/dist/http/health.js.map +1 -0
- package/dist/http/index.d.ts +50 -0
- package/dist/http/index.d.ts.map +1 -0
- package/dist/http/index.js +50 -0
- package/dist/http/index.js.map +1 -0
- package/dist/http/interceptors/dispatch.d.ts +14 -0
- package/dist/http/interceptors/dispatch.d.ts.map +1 -0
- package/dist/http/interceptors/dispatch.js +113 -0
- package/dist/http/interceptors/dispatch.js.map +1 -0
- package/dist/http/interceptors/index.d.ts +6 -0
- package/dist/http/interceptors/index.d.ts.map +1 -0
- package/dist/http/interceptors/index.js +5 -0
- package/dist/http/interceptors/index.js.map +1 -0
- package/dist/http/interceptors/registry.d.ts +44 -0
- package/dist/http/interceptors/registry.d.ts.map +1 -0
- package/dist/http/interceptors/registry.js +123 -0
- package/dist/http/interceptors/registry.js.map +1 -0
- package/dist/http/interceptors/route-table.d.ts +33 -0
- package/dist/http/interceptors/route-table.d.ts.map +1 -0
- package/dist/http/interceptors/route-table.js +39 -0
- package/dist/http/interceptors/route-table.js.map +1 -0
- package/dist/http/interceptors/types.d.ts +101 -0
- package/dist/http/interceptors/types.d.ts.map +1 -0
- package/dist/http/interceptors/types.js +2 -0
- package/dist/http/interceptors/types.js.map +1 -0
- package/dist/http/interceptors/validation.d.ts +22 -0
- package/dist/http/interceptors/validation.d.ts.map +1 -0
- package/dist/http/interceptors/validation.js +39 -0
- package/dist/http/interceptors/validation.js.map +1 -0
- package/dist/http/logger.d.ts +9 -0
- package/dist/http/logger.d.ts.map +1 -0
- package/dist/http/logger.js +25 -0
- package/dist/http/logger.js.map +1 -0
- package/dist/http/openapi.d.ts +21 -0
- package/dist/http/openapi.d.ts.map +1 -0
- package/dist/http/openapi.js +114 -0
- package/dist/http/openapi.js.map +1 -0
- package/dist/http/product-audience.d.ts +78 -0
- package/dist/http/product-audience.d.ts.map +1 -0
- package/dist/http/product-audience.js +92 -0
- package/dist/http/product-audience.js.map +1 -0
- package/dist/http/request-actor.d.ts +82 -0
- package/dist/http/request-actor.d.ts.map +1 -0
- package/dist/http/request-actor.js +2 -0
- package/dist/http/request-actor.js.map +1 -0
- package/dist/http/server.d.ts +60 -0
- package/dist/http/server.d.ts.map +1 -0
- package/dist/http/server.js +117 -0
- package/dist/http/server.js.map +1 -0
- package/dist/http/storefront-revalidator.d.ts +29 -0
- package/dist/http/storefront-revalidator.d.ts.map +1 -0
- package/dist/http/storefront-revalidator.js +34 -0
- package/dist/http/storefront-revalidator.js.map +1 -0
- package/dist/http/test-actor-carrier.d.ts +28 -0
- package/dist/http/test-actor-carrier.d.ts.map +1 -0
- package/dist/http/test-actor-carrier.js +10 -0
- package/dist/http/test-actor-carrier.js.map +1 -0
- package/dist/http/trusted-proxy.d.ts +48 -0
- package/dist/http/trusted-proxy.d.ts.map +1 -0
- package/dist/http/trusted-proxy.js +136 -0
- package/dist/http/trusted-proxy.js.map +1 -0
- package/dist/kernel/audit/audit-log-entry.entity.d.ts +33 -0
- package/dist/kernel/audit/audit-log-entry.entity.d.ts.map +1 -0
- package/dist/kernel/audit/audit-log-entry.entity.js +102 -0
- package/dist/kernel/audit/audit-log-entry.entity.js.map +1 -0
- package/dist/kernel/audit/audit-log-service.d.ts +63 -0
- package/dist/kernel/audit/audit-log-service.d.ts.map +1 -0
- package/dist/kernel/audit/audit-log-service.js +107 -0
- package/dist/kernel/audit/audit-log-service.js.map +1 -0
- package/dist/kernel/cache/in-process-cache-registry.d.ts +93 -0
- package/dist/kernel/cache/in-process-cache-registry.d.ts.map +1 -0
- package/dist/kernel/cache/in-process-cache-registry.js +78 -0
- package/dist/kernel/cache/in-process-cache-registry.js.map +1 -0
- package/dist/kernel/cache/shared-drop-marks.d.ts +39 -0
- package/dist/kernel/cache/shared-drop-marks.d.ts.map +1 -0
- package/dist/kernel/cache/shared-drop-marks.js +68 -0
- package/dist/kernel/cache/shared-drop-marks.js.map +1 -0
- package/dist/kernel/compose.d.ts +234 -0
- package/dist/kernel/compose.d.ts.map +1 -0
- package/dist/kernel/compose.js +279 -0
- package/dist/kernel/compose.js.map +1 -0
- package/dist/kernel/container.d.ts +95 -0
- package/dist/kernel/container.d.ts.map +1 -0
- package/dist/kernel/container.js +90 -0
- package/dist/kernel/container.js.map +1 -0
- package/dist/kernel/contribution-sinks.d.ts +106 -0
- package/dist/kernel/contribution-sinks.d.ts.map +1 -0
- package/dist/kernel/contribution-sinks.js +153 -0
- package/dist/kernel/contribution-sinks.js.map +1 -0
- package/dist/kernel/crypto/password-hasher.d.ts +3 -0
- package/dist/kernel/crypto/password-hasher.d.ts.map +1 -0
- package/dist/kernel/crypto/password-hasher.js +44 -0
- package/dist/kernel/crypto/password-hasher.js.map +1 -0
- package/dist/kernel/i18n/error-envelope-options.d.ts +56 -0
- package/dist/kernel/i18n/error-envelope-options.d.ts.map +1 -0
- package/dist/kernel/i18n/error-envelope-options.js +46 -0
- package/dist/kernel/i18n/error-envelope-options.js.map +1 -0
- package/dist/kernel/i18n/error-translation.d.ts +144 -0
- package/dist/kernel/i18n/error-translation.d.ts.map +1 -0
- package/dist/kernel/i18n/error-translation.js +84 -0
- package/dist/kernel/i18n/error-translation.js.map +1 -0
- package/dist/kernel/i18n/request-language.d.ts +80 -0
- package/dist/kernel/i18n/request-language.d.ts.map +1 -0
- package/dist/kernel/i18n/request-language.js +168 -0
- package/dist/kernel/i18n/request-language.js.map +1 -0
- package/dist/kernel/index.d.ts +142 -0
- package/dist/kernel/index.d.ts.map +1 -0
- package/dist/kernel/index.js +160 -0
- package/dist/kernel/index.js.map +1 -0
- package/dist/kernel/lazy-port.d.ts +59 -0
- package/dist/kernel/lazy-port.d.ts.map +1 -0
- package/dist/kernel/lazy-port.js +78 -0
- package/dist/kernel/lazy-port.js.map +1 -0
- package/dist/kernel/lifecycle/activation-resolver.d.ts +63 -0
- package/dist/kernel/lifecycle/activation-resolver.d.ts.map +1 -0
- package/dist/kernel/lifecycle/activation-resolver.js +70 -0
- package/dist/kernel/lifecycle/activation-resolver.js.map +1 -0
- package/dist/kernel/lifecycle/capability-registry.d.ts +145 -0
- package/dist/kernel/lifecycle/capability-registry.d.ts.map +1 -0
- package/dist/kernel/lifecycle/capability-registry.js +170 -0
- package/dist/kernel/lifecycle/capability-registry.js.map +1 -0
- package/dist/kernel/lifecycle/effective-state.d.ts +126 -0
- package/dist/kernel/lifecycle/effective-state.d.ts.map +1 -0
- package/dist/kernel/lifecycle/effective-state.js +111 -0
- package/dist/kernel/lifecycle/effective-state.js.map +1 -0
- package/dist/kernel/lifecycle/module-registration.entity.d.ts +57 -0
- package/dist/kernel/lifecycle/module-registration.entity.d.ts.map +1 -0
- package/dist/kernel/lifecycle/module-registration.entity.js +111 -0
- package/dist/kernel/lifecycle/module-registration.entity.js.map +1 -0
- package/dist/kernel/lifecycle/plugin-helpers.d.ts +165 -0
- package/dist/kernel/lifecycle/plugin-helpers.d.ts.map +1 -0
- package/dist/kernel/lifecycle/plugin-helpers.js +395 -0
- package/dist/kernel/lifecycle/plugin-helpers.js.map +1 -0
- package/dist/kernel/lifecycle/registry-cache.d.ts +318 -0
- package/dist/kernel/lifecycle/registry-cache.d.ts.map +1 -0
- package/dist/kernel/lifecycle/registry-cache.js +509 -0
- package/dist/kernel/lifecycle/registry-cache.js.map +1 -0
- package/dist/kernel/lifecycle/required-modules.d.ts +137 -0
- package/dist/kernel/lifecycle/required-modules.d.ts.map +1 -0
- package/dist/kernel/lifecycle/required-modules.js +80 -0
- package/dist/kernel/lifecycle/required-modules.js.map +1 -0
- package/dist/kernel/lifecycle/unique-module-ids.d.ts +58 -0
- package/dist/kernel/lifecycle/unique-module-ids.d.ts.map +1 -0
- package/dist/kernel/lifecycle/unique-module-ids.js +82 -0
- package/dist/kernel/lifecycle/unique-module-ids.js.map +1 -0
- package/dist/kernel/logging.d.ts +116 -0
- package/dist/kernel/logging.d.ts.map +1 -0
- package/dist/kernel/logging.js +71 -0
- package/dist/kernel/logging.js.map +1 -0
- package/dist/kernel/module-context.d.ts +563 -0
- package/dist/kernel/module-context.d.ts.map +1 -0
- package/dist/kernel/module-context.js +670 -0
- package/dist/kernel/module-context.js.map +1 -0
- package/dist/kernel/ports/audit.d.ts +115 -0
- package/dist/kernel/ports/audit.d.ts.map +1 -0
- package/dist/kernel/ports/audit.js +2 -0
- package/dist/kernel/ports/audit.js.map +1 -0
- package/dist/kernel/ports/organizations.d.ts +56 -0
- package/dist/kernel/ports/organizations.d.ts.map +1 -0
- package/dist/kernel/ports/organizations.js +2 -0
- package/dist/kernel/ports/organizations.js.map +1 -0
- package/dist/kernel/ports/provide.d.ts +14 -0
- package/dist/kernel/ports/provide.d.ts.map +1 -0
- package/dist/kernel/ports/provide.js +50 -0
- package/dist/kernel/ports/provide.js.map +1 -0
- package/dist/kernel/ports/require-admin.d.ts +61 -0
- package/dist/kernel/ports/require-admin.d.ts.map +1 -0
- package/dist/kernel/ports/require-admin.js +2 -0
- package/dist/kernel/ports/require-admin.js.map +1 -0
- package/dist/kernel/ports/require-customer.d.ts +17 -0
- package/dist/kernel/ports/require-customer.d.ts.map +1 -0
- package/dist/kernel/ports/require-customer.js +2 -0
- package/dist/kernel/ports/require-customer.js.map +1 -0
- package/dist/kernel/ports/sales-channel.d.ts +84 -0
- package/dist/kernel/ports/sales-channel.d.ts.map +1 -0
- package/dist/kernel/ports/sales-channel.js +2 -0
- package/dist/kernel/ports/sales-channel.js.map +1 -0
- package/dist/kernel/ports/settings.d.ts +59 -0
- package/dist/kernel/ports/settings.d.ts.map +1 -0
- package/dist/kernel/ports/settings.js +2 -0
- package/dist/kernel/ports/settings.js.map +1 -0
- package/dist/kernel/public-api-base-url.d.ts +98 -0
- package/dist/kernel/public-api-base-url.d.ts.map +1 -0
- package/dist/kernel/public-api-base-url.js +144 -0
- package/dist/kernel/public-api-base-url.js.map +1 -0
- package/dist/kernel/request-scope-hook.d.ts +63 -0
- package/dist/kernel/request-scope-hook.d.ts.map +1 -0
- package/dist/kernel/request-scope-hook.js +67 -0
- package/dist/kernel/request-scope-hook.js.map +1 -0
- package/dist/kernel/sales-channels/channel-bridge-registry.d.ts +109 -0
- package/dist/kernel/sales-channels/channel-bridge-registry.d.ts.map +1 -0
- package/dist/kernel/sales-channels/channel-bridge-registry.js +75 -0
- package/dist/kernel/sales-channels/channel-bridge-registry.js.map +1 -0
- package/dist/kernel/sales-channels/compose.d.ts +69 -0
- package/dist/kernel/sales-channels/compose.d.ts.map +1 -0
- package/dist/kernel/sales-channels/compose.js +43 -0
- package/dist/kernel/sales-channels/compose.js.map +1 -0
- package/dist/kernel/sales-channels/default-channel-reconciler.d.ts +66 -0
- package/dist/kernel/sales-channels/default-channel-reconciler.d.ts.map +1 -0
- package/dist/kernel/sales-channels/default-channel-reconciler.js +91 -0
- package/dist/kernel/sales-channels/default-channel-reconciler.js.map +1 -0
- package/dist/kernel/sales-channels/no-system-default-channel.error.d.ts +28 -0
- package/dist/kernel/sales-channels/no-system-default-channel.error.d.ts.map +1 -0
- package/dist/kernel/sales-channels/no-system-default-channel.error.js +33 -0
- package/dist/kernel/sales-channels/no-system-default-channel.error.js.map +1 -0
- package/dist/kernel/sales-channels/request-channel-assortment.d.ts +72 -0
- package/dist/kernel/sales-channels/request-channel-assortment.d.ts.map +1 -0
- package/dist/kernel/sales-channels/request-channel-assortment.js +83 -0
- package/dist/kernel/sales-channels/request-channel-assortment.js.map +1 -0
- package/dist/kernel/sales-channels/sales-channel-membership.service.d.ts +157 -0
- package/dist/kernel/sales-channels/sales-channel-membership.service.d.ts.map +1 -0
- package/dist/kernel/sales-channels/sales-channel-membership.service.js +302 -0
- package/dist/kernel/sales-channels/sales-channel-membership.service.js.map +1 -0
- package/dist/kernel/sales-channels/sales-channel-resolver.middleware.d.ts +76 -0
- package/dist/kernel/sales-channels/sales-channel-resolver.middleware.d.ts.map +1 -0
- package/dist/kernel/sales-channels/sales-channel-resolver.middleware.js +184 -0
- package/dist/kernel/sales-channels/sales-channel-resolver.middleware.js.map +1 -0
- package/dist/kernel/sales-channels/sales-channel-resolver.service.d.ts +82 -0
- package/dist/kernel/sales-channels/sales-channel-resolver.service.d.ts.map +1 -0
- package/dist/kernel/sales-channels/sales-channel-resolver.service.js +126 -0
- package/dist/kernel/sales-channels/sales-channel-resolver.service.js.map +1 -0
- package/dist/kernel/sales-channels/sales-channel.entity.d.ts +50 -0
- package/dist/kernel/sales-channels/sales-channel.entity.d.ts.map +1 -0
- package/dist/kernel/sales-channels/sales-channel.entity.js +132 -0
- package/dist/kernel/sales-channels/sales-channel.entity.js.map +1 -0
- package/dist/kernel/sales-channels/sales-channels-cache.d.ts +170 -0
- package/dist/kernel/sales-channels/sales-channels-cache.d.ts.map +1 -0
- package/dist/kernel/sales-channels/sales-channels-cache.js +243 -0
- package/dist/kernel/sales-channels/sales-channels-cache.js.map +1 -0
- package/dist/kernel/scope.d.ts +153 -0
- package/dist/kernel/scope.d.ts.map +1 -0
- package/dist/kernel/scope.js +172 -0
- package/dist/kernel/scope.js.map +1 -0
- package/dist/kernel/settings/compose.d.ts +49 -0
- package/dist/kernel/settings/compose.d.ts.map +1 -0
- package/dist/kernel/settings/compose.js +21 -0
- package/dist/kernel/settings/compose.js.map +1 -0
- package/dist/kernel/settings/manifest-reconciler.d.ts +78 -0
- package/dist/kernel/settings/manifest-reconciler.d.ts.map +1 -0
- package/dist/kernel/settings/manifest-reconciler.js +343 -0
- package/dist/kernel/settings/manifest-reconciler.js.map +1 -0
- package/dist/kernel/settings/secret-value-codec.d.ts +52 -0
- package/dist/kernel/settings/secret-value-codec.d.ts.map +1 -0
- package/dist/kernel/settings/secret-value-codec.js +102 -0
- package/dist/kernel/settings/secret-value-codec.js.map +1 -0
- package/dist/kernel/settings/setting-group.entity.d.ts +25 -0
- package/dist/kernel/settings/setting-group.entity.d.ts.map +1 -0
- package/dist/kernel/settings/setting-group.entity.js +79 -0
- package/dist/kernel/settings/setting-group.entity.js.map +1 -0
- package/dist/kernel/settings/setting-value.entity.d.ts +23 -0
- package/dist/kernel/settings/setting-value.entity.d.ts.map +1 -0
- package/dist/kernel/settings/setting-value.entity.js +66 -0
- package/dist/kernel/settings/setting-value.entity.js.map +1 -0
- package/dist/kernel/settings/setting.entity.d.ts +56 -0
- package/dist/kernel/settings/setting.entity.d.ts.map +1 -0
- package/dist/kernel/settings/setting.entity.js +147 -0
- package/dist/kernel/settings/setting.entity.js.map +1 -0
- package/dist/kernel/settings/settings-cache.d.ts +158 -0
- package/dist/kernel/settings/settings-cache.d.ts.map +1 -0
- package/dist/kernel/settings/settings-cache.js +253 -0
- package/dist/kernel/settings/settings-cache.js.map +1 -0
- package/dist/kernel/settings/settings.service.d.ts +142 -0
- package/dist/kernel/settings/settings.service.d.ts.map +1 -0
- package/dist/kernel/settings/settings.service.js +294 -0
- package/dist/kernel/settings/settings.service.js.map +1 -0
- package/dist/lifecycle/backend.d.ts +51 -0
- package/dist/lifecycle/backend.d.ts.map +1 -0
- package/dist/lifecycle/backend.js +40 -0
- package/dist/lifecycle/backend.js.map +1 -0
- package/dist/lifecycle/commands/activation.commands.d.ts +97 -0
- package/dist/lifecycle/commands/activation.commands.d.ts.map +1 -0
- package/dist/lifecycle/commands/activation.commands.js +142 -0
- package/dist/lifecycle/commands/activation.commands.js.map +1 -0
- package/dist/lifecycle/commands/disable.d.ts +3 -0
- package/dist/lifecycle/commands/disable.d.ts.map +1 -0
- package/dist/lifecycle/commands/disable.js +126 -0
- package/dist/lifecycle/commands/disable.js.map +1 -0
- package/dist/lifecycle/commands/enable.d.ts +3 -0
- package/dist/lifecycle/commands/enable.d.ts.map +1 -0
- package/dist/lifecycle/commands/enable.js +102 -0
- package/dist/lifecycle/commands/enable.js.map +1 -0
- package/dist/lifecycle/commands/install.d.ts +3 -0
- package/dist/lifecycle/commands/install.d.ts.map +1 -0
- package/dist/lifecycle/commands/install.js +263 -0
- package/dist/lifecycle/commands/install.js.map +1 -0
- package/dist/lifecycle/commands/operator-entry.d.ts +104 -0
- package/dist/lifecycle/commands/operator-entry.d.ts.map +1 -0
- package/dist/lifecycle/commands/operator-entry.js +127 -0
- package/dist/lifecycle/commands/operator-entry.js.map +1 -0
- package/dist/lifecycle/commands/operator-runtime.d.ts +147 -0
- package/dist/lifecycle/commands/operator-runtime.d.ts.map +1 -0
- package/dist/lifecycle/commands/operator-runtime.js +40 -0
- package/dist/lifecycle/commands/operator-runtime.js.map +1 -0
- package/dist/lifecycle/commands/status.d.ts +3 -0
- package/dist/lifecycle/commands/status.d.ts.map +1 -0
- package/dist/lifecycle/commands/status.js +108 -0
- package/dist/lifecycle/commands/status.js.map +1 -0
- package/dist/lifecycle/commands/uninstall.d.ts +3 -0
- package/dist/lifecycle/commands/uninstall.d.ts.map +1 -0
- package/dist/lifecycle/commands/uninstall.js +223 -0
- package/dist/lifecycle/commands/uninstall.js.map +1 -0
- package/dist/lifecycle/divergence-declaration.d.ts +74 -0
- package/dist/lifecycle/divergence-declaration.d.ts.map +1 -0
- package/dist/lifecycle/divergence-declaration.js +92 -0
- package/dist/lifecycle/divergence-declaration.js.map +1 -0
- package/dist/lifecycle/i18n/en.json +4 -0
- package/dist/lifecycle/i18n/pl.json +4 -0
- package/dist/lifecycle/index.d.ts +110 -0
- package/dist/lifecycle/index.d.ts.map +1 -0
- package/dist/lifecycle/index.js +189 -0
- package/dist/lifecycle/index.js.map +1 -0
- package/dist/lifecycle/manifest-registry.d.ts +244 -0
- package/dist/lifecycle/manifest-registry.d.ts.map +1 -0
- package/dist/lifecycle/manifest-registry.js +223 -0
- package/dist/lifecycle/manifest-registry.js.map +1 -0
- package/dist/lifecycle/manifest.d.ts +166 -0
- package/dist/lifecycle/manifest.d.ts.map +1 -0
- package/dist/lifecycle/manifest.js +121 -0
- package/dist/lifecycle/manifest.js.map +1 -0
- package/dist/lifecycle/plugin.d.ts +56 -0
- package/dist/lifecycle/plugin.d.ts.map +1 -0
- package/dist/lifecycle/plugin.js +59 -0
- package/dist/lifecycle/plugin.js.map +1 -0
- package/dist/lifecycle/resident.d.ts +16 -0
- package/dist/lifecycle/resident.d.ts.map +1 -0
- package/dist/lifecycle/resident.js +59 -0
- package/dist/lifecycle/resident.js.map +1 -0
- package/dist/lifecycle/routes.admin.d.ts +57 -0
- package/dist/lifecycle/routes.admin.d.ts.map +1 -0
- package/dist/lifecycle/routes.admin.js +162 -0
- package/dist/lifecycle/routes.admin.js.map +1 -0
- package/dist/lifecycle/routes.storefront.d.ts +26 -0
- package/dist/lifecycle/routes.storefront.d.ts.map +1 -0
- package/dist/lifecycle/routes.storefront.js +36 -0
- package/dist/lifecycle/routes.storefront.js.map +1 -0
- package/dist/lifecycle/services/deactivation-ledger.d.ts +216 -0
- package/dist/lifecycle/services/deactivation-ledger.d.ts.map +1 -0
- package/dist/lifecycle/services/deactivation-ledger.js +171 -0
- package/dist/lifecycle/services/deactivation-ledger.js.map +1 -0
- package/dist/lifecycle/services/dep-graph.d.ts +119 -0
- package/dist/lifecycle/services/dep-graph.d.ts.map +1 -0
- package/dist/lifecycle/services/dep-graph.js +334 -0
- package/dist/lifecycle/services/dep-graph.js.map +1 -0
- package/dist/lifecycle/services/gating-graph.d.ts +164 -0
- package/dist/lifecycle/services/gating-graph.d.ts.map +1 -0
- package/dist/lifecycle/services/gating-graph.js +203 -0
- package/dist/lifecycle/services/gating-graph.js.map +1 -0
- package/dist/lifecycle/services/lock.d.ts +27 -0
- package/dist/lifecycle/services/lock.d.ts.map +1 -0
- package/dist/lifecycle/services/lock.js +82 -0
- package/dist/lifecycle/services/lock.js.map +1 -0
- package/dist/lifecycle/services/manifest-loader.d.ts +125 -0
- package/dist/lifecycle/services/manifest-loader.d.ts.map +1 -0
- package/dist/lifecycle/services/manifest-loader.js +210 -0
- package/dist/lifecycle/services/manifest-loader.js.map +1 -0
- package/dist/lifecycle/services/migration-ownership.d.ts +36 -0
- package/dist/lifecycle/services/migration-ownership.d.ts.map +1 -0
- package/dist/lifecycle/services/migration-ownership.js +15 -0
- package/dist/lifecycle/services/migration-ownership.js.map +1 -0
- package/dist/lifecycle/services/module-id-claims.d.ts +38 -0
- package/dist/lifecycle/services/module-id-claims.d.ts.map +1 -0
- package/dist/lifecycle/services/module-id-claims.js +123 -0
- package/dist/lifecycle/services/module-id-claims.js.map +1 -0
- package/dist/lifecycle/services/module-origin.d.ts +55 -0
- package/dist/lifecycle/services/module-origin.d.ts.map +1 -0
- package/dist/lifecycle/services/module-origin.js +47 -0
- package/dist/lifecycle/services/module-origin.js.map +1 -0
- package/dist/lifecycle/services/orchestrator.d.ts +235 -0
- package/dist/lifecycle/services/orchestrator.d.ts.map +1 -0
- package/dist/lifecycle/services/orchestrator.js +954 -0
- package/dist/lifecycle/services/orchestrator.js.map +1 -0
- package/dist/lifecycle/services/presence-load.d.ts +281 -0
- package/dist/lifecycle/services/presence-load.d.ts.map +1 -0
- package/dist/lifecycle/services/presence-load.js +437 -0
- package/dist/lifecycle/services/presence-load.js.map +1 -0
- package/dist/lifecycle/services/static-registry.d.ts +47 -0
- package/dist/lifecycle/services/static-registry.d.ts.map +1 -0
- package/dist/lifecycle/services/static-registry.js +41 -0
- package/dist/lifecycle/services/static-registry.js.map +1 -0
- package/dist/migrations/20260424T165847_core_foundation_init.d.ts +25 -0
- package/dist/migrations/20260424T165847_core_foundation_init.d.ts.map +1 -0
- package/dist/migrations/20260424T165847_core_foundation_init.js +238 -0
- package/dist/migrations/20260424T165847_core_foundation_init.js.map +1 -0
- package/dist/migrations/20260425T050720_core_commerce_init.d.ts +19 -0
- package/dist/migrations/20260425T050720_core_commerce_init.d.ts.map +1 -0
- package/dist/migrations/20260425T050720_core_commerce_init.js +200 -0
- package/dist/migrations/20260425T050720_core_commerce_init.js.map +1 -0
- package/dist/migrations/20260430T101450_core_settings_init.d.ts +25 -0
- package/dist/migrations/20260430T101450_core_settings_init.d.ts.map +1 -0
- package/dist/migrations/20260430T101450_core_settings_init.js +113 -0
- package/dist/migrations/20260430T101450_core_settings_init.js.map +1 -0
- package/dist/migrations/20260430T170044_core_sales_channels_promote.d.ts +67 -0
- package/dist/migrations/20260430T170044_core_sales_channels_promote.d.ts.map +1 -0
- package/dist/migrations/20260430T170044_core_sales_channels_promote.js +101 -0
- package/dist/migrations/20260430T170044_core_sales_channels_promote.js.map +1 -0
- package/dist/migrations/20260506T200657_core_module_lifecycle_init.d.ts +21 -0
- package/dist/migrations/20260506T200657_core_module_lifecycle_init.d.ts.map +1 -0
- package/dist/migrations/20260506T200657_core_module_lifecycle_init.js +41 -0
- package/dist/migrations/20260506T200657_core_module_lifecycle_init.js.map +1 -0
- package/dist/migrations/20260514T111329_core_settings_global_value.d.ts +30 -0
- package/dist/migrations/20260514T111329_core_settings_global_value.d.ts.map +1 -0
- package/dist/migrations/20260514T111329_core_settings_global_value.js +34 -0
- package/dist/migrations/20260514T111329_core_settings_global_value.js.map +1 -0
- package/dist/migrations/20260611T140411_core_settings_secret_value_type.d.ts +26 -0
- package/dist/migrations/20260611T140411_core_settings_secret_value_type.d.ts.map +1 -0
- package/dist/migrations/20260611T140411_core_settings_secret_value_type.js +63 -0
- package/dist/migrations/20260611T140411_core_settings_secret_value_type.js.map +1 -0
- package/dist/migrations/20260611T140419_core_settings_enum_options.d.ts +19 -0
- package/dist/migrations/20260611T140419_core_settings_enum_options.d.ts.map +1 -0
- package/dist/migrations/20260611T140419_core_settings_enum_options.js +23 -0
- package/dist/migrations/20260611T140419_core_settings_enum_options.js.map +1 -0
- package/dist/migrations/20260629T090100_core_settings_hidden_flag.d.ts +20 -0
- package/dist/migrations/20260629T090100_core_settings_hidden_flag.d.ts.map +1 -0
- package/dist/migrations/20260629T090100_core_settings_hidden_flag.js +24 -0
- package/dist/migrations/20260629T090100_core_settings_hidden_flag.js.map +1 -0
- package/dist/migrations/20260717T134752_core_tenant_scope_indexes.d.ts +27 -0
- package/dist/migrations/20260717T134752_core_tenant_scope_indexes.d.ts.map +1 -0
- package/dist/migrations/20260717T134752_core_tenant_scope_indexes.js +32 -0
- package/dist/migrations/20260717T134752_core_tenant_scope_indexes.js.map +1 -0
- package/dist/migrations/20260721T011510_core_settings_credential_ref_value_type.d.ts +24 -0
- package/dist/migrations/20260721T011510_core_settings_credential_ref_value_type.d.ts.map +1 -0
- package/dist/migrations/20260721T011510_core_settings_credential_ref_value_type.js +57 -0
- package/dist/migrations/20260721T011510_core_settings_credential_ref_value_type.js.map +1 -0
- package/dist/migrations/20260816T203339_core_retire_core_activation_settings.d.ts +39 -0
- package/dist/migrations/20260816T203339_core_retire_core_activation_settings.d.ts.map +1 -0
- package/dist/migrations/20260816T203339_core_retire_core_activation_settings.js +59 -0
- package/dist/migrations/20260816T203339_core_retire_core_activation_settings.js.map +1 -0
- package/dist/migrations/20260919T101500_core_module_registrations_boot_converged.d.ts +34 -0
- package/dist/migrations/20260919T101500_core_module_registrations_boot_converged.d.ts.map +1 -0
- package/dist/migrations/20260919T101500_core_module_registrations_boot_converged.js +38 -0
- package/dist/migrations/20260919T101500_core_module_registrations_boot_converged.js.map +1 -0
- package/dist/migrations/baseline-migrations.generated.d.ts +2 -0
- package/dist/migrations/baseline-migrations.generated.d.ts.map +1 -0
- package/dist/migrations/baseline-migrations.generated.js +136 -0
- package/dist/migrations/baseline-migrations.generated.js.map +1 -0
- package/dist/migrations/index.d.ts +62 -0
- package/dist/migrations/index.d.ts.map +1 -0
- package/dist/migrations/index.js +75 -0
- package/dist/migrations/index.js.map +1 -0
- package/dist/overlay/deployment-roots.d.ts +37 -0
- package/dist/overlay/deployment-roots.d.ts.map +1 -0
- package/dist/overlay/deployment-roots.js +90 -0
- package/dist/overlay/deployment-roots.js.map +1 -0
- package/dist/overlay/index.d.ts +62 -0
- package/dist/overlay/index.d.ts.map +1 -0
- package/dist/overlay/index.js +62 -0
- package/dist/overlay/index.js.map +1 -0
- package/dist/overlay/overlay-runtime.d.ts +173 -0
- package/dist/overlay/overlay-runtime.d.ts.map +1 -0
- package/dist/overlay/overlay-runtime.js +281 -0
- package/dist/overlay/overlay-runtime.js.map +1 -0
- package/dist/overlay/resolve-overlay.d.ts +41 -0
- package/dist/overlay/resolve-overlay.d.ts.map +1 -0
- package/dist/overlay/resolve-overlay.js +72 -0
- package/dist/overlay/resolve-overlay.js.map +1 -0
- package/dist/packages/index.d.ts +57 -0
- package/dist/packages/index.d.ts.map +1 -0
- package/dist/packages/index.js +57 -0
- package/dist/packages/index.js.map +1 -0
- package/dist/packages/installed-packages.d.ts +79 -0
- package/dist/packages/installed-packages.d.ts.map +1 -0
- package/dist/packages/installed-packages.js +312 -0
- package/dist/packages/installed-packages.js.map +1 -0
- package/dist/packages/package-entity-lookup.d.ts +120 -0
- package/dist/packages/package-entity-lookup.d.ts.map +1 -0
- package/dist/packages/package-entity-lookup.js +17 -0
- package/dist/packages/package-entity-lookup.js.map +1 -0
- package/dist/packages/package-runtime.d.ts +177 -0
- package/dist/packages/package-runtime.d.ts.map +1 -0
- package/dist/packages/package-runtime.js +386 -0
- package/dist/packages/package-runtime.js.map +1 -0
- package/dist/tenancy/derived-scope.d.ts +43 -0
- package/dist/tenancy/derived-scope.d.ts.map +1 -0
- package/dist/tenancy/derived-scope.js +76 -0
- package/dist/tenancy/derived-scope.js.map +1 -0
- package/dist/tenancy/escape-hatch.d.ts +30 -0
- package/dist/tenancy/escape-hatch.d.ts.map +1 -0
- package/dist/tenancy/escape-hatch.js +50 -0
- package/dist/tenancy/escape-hatch.js.map +1 -0
- package/dist/tenancy/filters.d.ts +87 -0
- package/dist/tenancy/filters.d.ts.map +1 -0
- package/dist/tenancy/filters.js +126 -0
- package/dist/tenancy/filters.js.map +1 -0
- package/dist/tenancy/index.d.ts +63 -0
- package/dist/tenancy/index.d.ts.map +1 -0
- package/dist/tenancy/index.js +61 -0
- package/dist/tenancy/index.js.map +1 -0
- package/dist/tenancy/org-scoped.decorator.d.ts +150 -0
- package/dist/tenancy/org-scoped.decorator.d.ts.map +1 -0
- package/dist/tenancy/org-scoped.decorator.js +339 -0
- package/dist/tenancy/org-scoped.decorator.js.map +1 -0
- package/dist/tenancy/org-write-guard.d.ts +106 -0
- package/dist/tenancy/org-write-guard.d.ts.map +1 -0
- package/dist/tenancy/org-write-guard.js +141 -0
- package/dist/tenancy/org-write-guard.js.map +1 -0
- package/dist/tenancy/resolve-tenant-context.d.ts +91 -0
- package/dist/tenancy/resolve-tenant-context.d.ts.map +1 -0
- package/dist/tenancy/resolve-tenant-context.js +85 -0
- package/dist/tenancy/resolve-tenant-context.js.map +1 -0
- package/dist/tenancy/scoped-em.d.ts +10 -0
- package/dist/tenancy/scoped-em.d.ts.map +1 -0
- package/dist/tenancy/scoped-em.js +11 -0
- package/dist/tenancy/scoped-em.js.map +1 -0
- package/dist/tenancy/tenant-context.d.ts +154 -0
- package/dist/tenancy/tenant-context.d.ts.map +1 -0
- package/dist/tenancy/tenant-context.js +109 -0
- package/dist/tenancy/tenant-context.js.map +1 -0
- package/package.json +123 -0
|
@@ -0,0 +1,939 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `composeApp` — the production half of what `composeTestServer` already is
|
|
3
|
+
* (`specs/110-instance-repository/` T118; `contracts/instance-repository.md`
|
|
4
|
+
* R1.4 and R2.4).
|
|
5
|
+
*
|
|
6
|
+
* ## What "the platform's" means here, precisely
|
|
7
|
+
*
|
|
8
|
+
* Everything in a deployment's composition that is true of **any** Endora
|
|
9
|
+
* platform and mentions no module: refuse a boot with no public origin, open the
|
|
10
|
+
* ORM, build the container, register the ORM-derived names and the host values,
|
|
11
|
+
* construct the audit writer, the event bus, the command bus and the two Redis
|
|
12
|
+
* clients, load presence from the database, compose the settings and
|
|
13
|
+
* sales-channel kernels, run `composeModules` once, open the contribution window
|
|
14
|
+
* once, install the request-scope hook, reconcile the settings manifests, run
|
|
15
|
+
* the boot phase once, assemble the error envelope, and give back a handle that
|
|
16
|
+
* can take all of it down again.
|
|
17
|
+
*
|
|
18
|
+
* Everything else — which modules, which ORM configuration, which manifests,
|
|
19
|
+
* which contributions, which actor a request carries — is the caller's, and
|
|
20
|
+
* reaches this function either as {@link AppComposition} or as one of the hooks
|
|
21
|
+
* below.
|
|
22
|
+
*
|
|
23
|
+
* ## The contribution wiring is the point, and it is a callback
|
|
24
|
+
*
|
|
25
|
+
* R1.4 puts *the contribution wiring* in this package; it does **not** put the
|
|
26
|
+
* 61 values `backend/src/composition.ts` contributes here. 41 of them carry a
|
|
27
|
+
* module's type or a value built out of a module's services, which D-52/D-53
|
|
28
|
+
* refuses from inside this package — so what moves is the *slot*, and the values
|
|
29
|
+
* arrive through {@link ComposeAppOptions.contribute}. Twenty do move, and every
|
|
30
|
+
* one of them is a kernel sub-kernel's object, a host value or an environment
|
|
31
|
+
* read; they are contributed **before** the caller's callback, so a deployment
|
|
32
|
+
* can still overwrite one.
|
|
33
|
+
*
|
|
34
|
+
* That is what makes R2.4 true the day this lands rather than after a sweep: an
|
|
35
|
+
* instance supplies no callback, so no file in a client's tree contributes over
|
|
36
|
+
* a name a module defaults, while this repository's `composition.ts` keeps its
|
|
37
|
+
* own as the **reference deployment's** — which is what it is, and not an
|
|
38
|
+
* instance.
|
|
39
|
+
*
|
|
40
|
+
* ## The one ordering rule, and why it is a shape rather than a comment
|
|
41
|
+
*
|
|
42
|
+
* `composeModules` runs once and `runBootHooks` runs once, immediately before
|
|
43
|
+
* this function returns, so a boot hook may resolve anything. A contribution
|
|
44
|
+
* over a name a module defaults goes in the single slot between them — earlier
|
|
45
|
+
* and the module's own registration overwrites it, later and a boot hook has
|
|
46
|
+
* already read the default (D-45). That slot is
|
|
47
|
+
* {@link ComposeAppOptions.contribute}, and both edges are enforced by the
|
|
48
|
+
* platform rather than remembered: the early one because `ComposedModules` does
|
|
49
|
+
* not exist until every module has registered, the late one because `contribute`
|
|
50
|
+
* throws `ContributionWindowClosedError` once `runBootHooks` has started
|
|
51
|
+
* (issue #52).
|
|
52
|
+
*
|
|
53
|
+
* ## Why no module may name this file
|
|
54
|
+
*
|
|
55
|
+
* It is on `./composition`, the host-internal subpath D-160.14 rules: declared
|
|
56
|
+
* by the `exports` map, carried by no published barrel, and answered for a
|
|
57
|
+
* module's reach with `host-internal-subpath`.
|
|
58
|
+
*/
|
|
59
|
+
import { Redis } from 'ioredis';
|
|
60
|
+
import { ERROR_CODES } from '@endora-commerce/contracts';
|
|
61
|
+
import { CommandBus } from '../commands/index.js';
|
|
62
|
+
import { configuredEntitiesFrom } from '../db/configured-entities.js';
|
|
63
|
+
import { discoverConfiguredMigrations } from '../db/configured-migrations.js';
|
|
64
|
+
import { mikroOrmConfigFrom } from '../db/mikro-orm.config.js';
|
|
65
|
+
import { createOrmBootstrap } from '../db/orm.js';
|
|
66
|
+
import { EventBus } from '../events/bus.js';
|
|
67
|
+
import { HttpError } from '../http/error-envelope.js';
|
|
68
|
+
import { healthRoutePlugin } from '../http/health.js';
|
|
69
|
+
import { ApiInterceptorRegistry } from '../http/interceptors/index.js';
|
|
70
|
+
import { StorefrontRevalidator } from '../http/storefront-revalidator.js';
|
|
71
|
+
import { AuditLogService } from '../kernel/audit/audit-log-service.js';
|
|
72
|
+
import { composeModules } from '../kernel/compose.js';
|
|
73
|
+
import { createRootContainer, registerOrm, registerValues, } from '../kernel/container.js';
|
|
74
|
+
import { composeErrorEnvelopeOptions } from '../kernel/i18n/error-envelope-options.js';
|
|
75
|
+
import { buildErrorTranslationTargets, describeErrorCodeCollisions, } from '../kernel/i18n/error-translation.js';
|
|
76
|
+
import { effectiveState } from '../kernel/lifecycle/effective-state.js';
|
|
77
|
+
import { publishStateChanged, registryCache } from '../kernel/lifecycle/registry-cache.js';
|
|
78
|
+
import { requiredModulesFrom } from '../kernel/lifecycle/required-modules.js';
|
|
79
|
+
import { platformLogger } from '../kernel/logging.js';
|
|
80
|
+
import { createRegistrationOwnership } from '../kernel/module-context.js';
|
|
81
|
+
import { assertPublicApiBaseUrlConfigured, resolvePublicApiBaseUrl, } from '../kernel/public-api-base-url.js';
|
|
82
|
+
import { registerRequestScopeHook } from '../kernel/request-scope-hook.js';
|
|
83
|
+
import { composeSalesChannelsKernel, } from '../kernel/sales-channels/compose.js';
|
|
84
|
+
import { DefaultChannelReconciler } from '../kernel/sales-channels/default-channel-reconciler.js';
|
|
85
|
+
import { enterSystemScope } from '../kernel/scope.js';
|
|
86
|
+
import { composeSettingsKernel } from '../kernel/settings/compose.js';
|
|
87
|
+
import { ManifestReconciler } from '../kernel/settings/manifest-reconciler.js';
|
|
88
|
+
import { buildStaticRegistry, deploymentShippedEntries, loadModulePresence, manifest as lifecycleManifest, registerModule as registerLifecycleModule, resolveManifestEntries, } from '../lifecycle/index.js';
|
|
89
|
+
import { activeOverlayModulesRoot } from '../overlay/deployment-roots.js';
|
|
90
|
+
import { overlayModulesUnder } from '../overlay/overlay-runtime.js';
|
|
91
|
+
import { discoverPackageModuleManifests, installedPackageModuleIdClaims, loadPackageModuleEntries, } from '../packages/package-runtime.js';
|
|
92
|
+
import { nodeModulesRootsFor } from '../packages/installed-packages.js';
|
|
93
|
+
import { newsletterTokenSecretFrom } from './newsletter-token-secret.js';
|
|
94
|
+
import { processRunsWorkersFor } from './process-runs-workers.js';
|
|
95
|
+
import { forkScopedEm } from '../tenancy/scoped-em.js';
|
|
96
|
+
import { systemTenantContext } from '../tenancy/resolve-tenant-context.js';
|
|
97
|
+
/**
|
|
98
|
+
* The actor id an audit record carries when its writer could not name an admin
|
|
99
|
+
* (T118b).
|
|
100
|
+
*
|
|
101
|
+
* Three modules' audit contexts owe a non-null `actorAdminUserId` and are
|
|
102
|
+
* reached only behind an admin gate, so this is unreachable by design. It is a
|
|
103
|
+
* sentinel rather than a throw because the alternative is failing the write the
|
|
104
|
+
* record exists to describe, and it was the literal all three spelled inline
|
|
105
|
+
* before the nine moved here.
|
|
106
|
+
*/
|
|
107
|
+
const NON_ADMIN_AUDIT_ACTOR = '00000000-0000-0000-0000-000000000000';
|
|
108
|
+
/**
|
|
109
|
+
* The cookie an anonymous shopper's cart is keyed by.
|
|
110
|
+
*
|
|
111
|
+
* Spelled here because `cartActorResolver` reads it and `@endora-commerce/contracts`
|
|
112
|
+
* publishes no constant for it — unlike the two session cookies, which it does.
|
|
113
|
+
* `carts` owns the name and sets it; `organizations` clears it on sign-out.
|
|
114
|
+
* Deliberately not "fixed" by publishing a fourth cookie constant in the same
|
|
115
|
+
* change: that is a contract addition with three other call sites to convert,
|
|
116
|
+
* and this move is not the place to decide it.
|
|
117
|
+
*/
|
|
118
|
+
const ANONYMOUS_CART_COOKIE = 'b2b_cart_anon';
|
|
119
|
+
/**
|
|
120
|
+
* The default {@link AppComposition} — the compiled-in half empty.
|
|
121
|
+
*
|
|
122
|
+
* An instance ships no generated manifest index and no committed registry, so
|
|
123
|
+
* its modules are its overlay modules plus the packages it installed, its
|
|
124
|
+
* entities are those packages' entities, and its migrations are those packages'
|
|
125
|
+
* migrations. Each is the same platform function the application's own binding
|
|
126
|
+
* calls, with `core` empty, so there is no second derivation of any of them.
|
|
127
|
+
*
|
|
128
|
+
* **Exported for its own test and named by no barrel.** Every other seam that
|
|
129
|
+
* could reach it needs a PostgreSQL, a Redis and an installed module set —
|
|
130
|
+
* `composeApp` opens all three before it composes anything — while the property
|
|
131
|
+
* this function has to hold is decided entirely by what it reads off disk: the
|
|
132
|
+
* modules it composes and the manifests it resolves must be one set.
|
|
133
|
+
* `default-composition-overlay.test.ts` is that assertion and it runs against a
|
|
134
|
+
* fixture deployment root with no service behind it. `./composition` does not
|
|
135
|
+
* carry the name, so nothing outside this package can call it.
|
|
136
|
+
*/
|
|
137
|
+
export async function defaultComposition(deploymentRoot, env) {
|
|
138
|
+
// Both overlay seams off one reader, over one id set
|
|
139
|
+
// (`specs/124-instance-customisation-gap/` FR-001, FR-002). The registration
|
|
140
|
+
// half used to be composed here while the manifest half was passed
|
|
141
|
+
// `async () => []` four lines below, so an instance's overlay module reached
|
|
142
|
+
// the container, the permission gate and the presence projection and never
|
|
143
|
+
// `lifecycleManifestRegistry`: the boot reconcile accounted for one module
|
|
144
|
+
// fewer than the presence projection enumerated, which is A4's own
|
|
145
|
+
// arithmetic, and no operator could switch the module off because there was
|
|
146
|
+
// no manifest to gate it against (Principle XVII).
|
|
147
|
+
const overlayModules = overlayModulesUnder(activeOverlayModulesRoot(deploymentRoot, env), () => installedPackageModuleIdClaims(nodeModulesRootsFor(env)));
|
|
148
|
+
const overlay = await overlayModules.entries();
|
|
149
|
+
const packages = await loadPackageModuleEntries(env);
|
|
150
|
+
const manifests = await resolveManifestEntries({
|
|
151
|
+
core: [],
|
|
152
|
+
overlay: () => overlayModules.manifests(),
|
|
153
|
+
packages: () => discoverPackageModuleManifests(env),
|
|
154
|
+
});
|
|
155
|
+
const bootstrap = createOrmBootstrap(async () => {
|
|
156
|
+
const [entities, migrations] = await Promise.all([
|
|
157
|
+
configuredEntitiesFrom({ coreEntities: [], env }),
|
|
158
|
+
discoverConfiguredMigrations({ coreEntries: [], manifests: [] }, env),
|
|
159
|
+
]);
|
|
160
|
+
return mikroOrmConfigFrom({ entities, migrations });
|
|
161
|
+
});
|
|
162
|
+
return {
|
|
163
|
+
// `_lifecycle` first, and it is the platform's own rather than the
|
|
164
|
+
// instance's (`specs/110-instance-repository/` T141). Its sources are in
|
|
165
|
+
// this package, so the only tree that could compose it is one carrying a
|
|
166
|
+
// generated composition — and an instance carries none, which is what left
|
|
167
|
+
// every instance refusing its own boot with `not-shipped: _lifecycle`,
|
|
168
|
+
// needed by five modules of the default set. `resolveManifestEntries`
|
|
169
|
+
// supplies the manifest half from the same declaration; this is the
|
|
170
|
+
// registration half, which cannot go there because `ModuleEntry` is this
|
|
171
|
+
// directory's and `lifecycle/` may not name it.
|
|
172
|
+
//
|
|
173
|
+
// Nothing is contributed here when the caller supplied its own
|
|
174
|
+
// `composition.modules`: this whole function is the fallback, so a host with
|
|
175
|
+
// a generated composition of its own is untouched.
|
|
176
|
+
modules: [
|
|
177
|
+
{ id: lifecycleManifest.id, version: lifecycleManifest.version, registerModule: registerLifecycleModule },
|
|
178
|
+
...overlay,
|
|
179
|
+
...packages,
|
|
180
|
+
],
|
|
181
|
+
manifests,
|
|
182
|
+
orm: { open: bootstrap.initOrm, close: bootstrap.closeOrm },
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Every environment value below is read as `process.env['NAME']` at its own
|
|
187
|
+
* site, and never through a local alias.
|
|
188
|
+
*
|
|
189
|
+
* That is a rule about `check:env-inputs`, not about style: its walk reconciles
|
|
190
|
+
* `ENVIRONMENT_INPUTS` against the `process.env` reads it can **see**, and an
|
|
191
|
+
* alias hides every read behind it. Measured on the first draft of this file,
|
|
192
|
+
* which bound `const env = process.env` once: the check's site count fell from
|
|
193
|
+
* 67 to 58 and `REDIS_URL` and `REVALIDATE_SECRET` were reported as
|
|
194
|
+
* `unread-input` — an operator asked for two values that appeared to change
|
|
195
|
+
* nothing, on the merge request that made them load-bearing for every
|
|
196
|
+
* deployment at once.
|
|
197
|
+
*/
|
|
198
|
+
export async function composeApp(options) {
|
|
199
|
+
const { deploymentRoot } = options;
|
|
200
|
+
// Issue #218 — before anything is opened, refuse a production boot with no
|
|
201
|
+
// public origin. `PUBLIC_API_BASE_URL` is what every payment-gateway callback
|
|
202
|
+
// URL, public product-feed URL and newsletter confirmation link is built on,
|
|
203
|
+
// and its old `http://localhost:3001` default produced a wrong-but-plausible
|
|
204
|
+
// URL nothing logged and nothing refused. Every deployment entry point goes
|
|
205
|
+
// through this function, so one line covers all of them — and an application's
|
|
206
|
+
// `index.ts` turns a throw from here into a "this is almost always a
|
|
207
|
+
// configuration problem" message plus `exit(1)`.
|
|
208
|
+
assertPublicApiBaseUrlConfigured();
|
|
209
|
+
// Resolved once, and only for the members the caller did not supply: the
|
|
210
|
+
// default builds an ORM bootstrap and scans `node_modules`, and doing that
|
|
211
|
+
// beside a caller that already handed over both would be two answers to one
|
|
212
|
+
// question.
|
|
213
|
+
const supplied = options.composition ?? {};
|
|
214
|
+
const fallback = supplied.modules !== undefined && supplied.manifests !== undefined && supplied.orm !== undefined
|
|
215
|
+
? undefined
|
|
216
|
+
: await defaultComposition(deploymentRoot, process.env);
|
|
217
|
+
const moduleEntries = supplied.modules ?? fallback?.modules ?? [];
|
|
218
|
+
const resolvedRegistry = supplied.manifests ?? fallback?.manifests ?? [];
|
|
219
|
+
const ormLifecycle = supplied.orm ?? fallback?.orm;
|
|
220
|
+
const orm = await ormLifecycle.open();
|
|
221
|
+
// Feature 050 — the single EM-injection seam. `forkScopedEm` is a bare
|
|
222
|
+
// `orm.em.fork()`: it stamps NOTHING, because the tenant filters read the
|
|
223
|
+
// ambient TenantContext from AsyncLocalStorage **when the query is built**
|
|
224
|
+
// (`tenancy/filters.ts`), not when the manager is forked. That is what makes
|
|
225
|
+
// the EntityManager stateless with respect to tenancy, and it is the property
|
|
226
|
+
// the whole request seam rests on.
|
|
227
|
+
const em = () => forkScopedEm(orm);
|
|
228
|
+
// Feature 072 — the kernel container. Modules composed through
|
|
229
|
+
// `composeModules` register into it; the deployment values assembled below
|
|
230
|
+
// are handed to that call and register nothing themselves.
|
|
231
|
+
//
|
|
232
|
+
// It is deliberately **not** installed as the process root
|
|
233
|
+
// (`setRootContainer`). Doing so makes every `enterPlatformScope` branch a
|
|
234
|
+
// child off this graph, and a scope is what lives in an `AsyncLocalStorage`
|
|
235
|
+
// store — so every retained store starts pinning a whole composed
|
|
236
|
+
// application. Phase 4 measured the cost: the suite died with `JavaScript
|
|
237
|
+
// heap out of memory` at file 78 of 930 with the root installed.
|
|
238
|
+
const container = createRootContainer();
|
|
239
|
+
registerOrm(container, orm);
|
|
240
|
+
// One ledger for the whole boot, so two modules composed in different
|
|
241
|
+
// `composeModules` calls still collide loudly on a shared registration name.
|
|
242
|
+
const registrationOwnership = createRegistrationOwnership();
|
|
243
|
+
const redisUrl = process.env['REDIS_URL'] ?? 'redis://localhost:6379';
|
|
244
|
+
const redis = new Redis(redisUrl, { maxRetriesPerRequest: null, lazyConnect: false });
|
|
245
|
+
// Principle X deployment dial. BACKEND_ROLE controls whether this process
|
|
246
|
+
// runs queue consumers (workers):
|
|
247
|
+
// - unset / 'all' → API + co-located workers (default single-VPS)
|
|
248
|
+
// - 'api' → HTTP only; workers run in a separate `pnpm worker`
|
|
249
|
+
// - 'worker' → workers only (set by `worker.ts`; no HTTP listen)
|
|
250
|
+
const runWorkers = processRunsWorkersFor(process.env['BACKEND_ROLE']);
|
|
251
|
+
// Feature 018 — separate ioredis client for the module-state pub/sub
|
|
252
|
+
// channel. ioredis multiplexes commands and subscriptions on different
|
|
253
|
+
// sockets, so we keep them on different clients to avoid the "subscribed
|
|
254
|
+
// mode" command restriction on the main client.
|
|
255
|
+
const redisSubscriber = new Redis(redisUrl, {
|
|
256
|
+
maxRetriesPerRequest: null,
|
|
257
|
+
lazyConnect: false,
|
|
258
|
+
});
|
|
259
|
+
const auditLogService = new AuditLogService(em);
|
|
260
|
+
// Feature 090 Phase 2 — which bundle holds which error code's sentence,
|
|
261
|
+
// derived from the manifests this deployment resolved rather than from a table
|
|
262
|
+
// (`specs/090-module-owned-error-codes/contracts/error-code-declaration.md` §4).
|
|
263
|
+
// Activation is deliberately not consulted: a code owned by a switchable
|
|
264
|
+
// module is raised by other modules too, so a switched-off `carts` must not
|
|
265
|
+
// cost `orders` its checkout sentence.
|
|
266
|
+
//
|
|
267
|
+
// Reported here rather than at the injection site because a collision is a
|
|
268
|
+
// fact about the composition and an operator has to be able to read it before
|
|
269
|
+
// the first request that renders wrong — and it is `warn` rather than a
|
|
270
|
+
// refusal: §3.3's severity gradient reserves a refused boot for the
|
|
271
|
+
// irreversible, and the blast radius of a contested code is one sentence.
|
|
272
|
+
const errorTranslation = buildErrorTranslationTargets(resolvedRegistry);
|
|
273
|
+
if (errorTranslation.collisions.length > 0) {
|
|
274
|
+
platformLogger().warn({ collisions: errorTranslation.collisions.length }, 'error codes are claimed by more than one module and therefore route to none of ' +
|
|
275
|
+
`them:\n${describeErrorCodeCollisions(errorTranslation.collisions)}`);
|
|
276
|
+
}
|
|
277
|
+
// Feature 072 (D-38) — module presence is a **composition input**, so it is
|
|
278
|
+
// loaded here: before the first module registers, and therefore before any
|
|
279
|
+
// boot hook, plugin body or worker registration asks for it. It used to be
|
|
280
|
+
// warmed inside `_lifecycle`'s plugin body, which runs in `buildServer` —
|
|
281
|
+
// after all of them — and the platform stopped booting the moment a boot hook
|
|
282
|
+
// resolved a gated port, because the cache still answered "not installed" for
|
|
283
|
+
// everything.
|
|
284
|
+
//
|
|
285
|
+
// Awaited and fatal, and that costs nothing new: opening the ORM above
|
|
286
|
+
// already makes a reachable PostgreSQL a boot precondition. Arming the Redis
|
|
287
|
+
// pub/sub side is separate (`registryCache.watch()`, from `_lifecycle`'s
|
|
288
|
+
// plugin) and must never fail a boot — a lost notification channel means
|
|
289
|
+
// stale, not off.
|
|
290
|
+
await enterSystemScope('boot: load module presence',
|
|
291
|
+
// The **entries**, not their manifests: `loadModulePresence` narrows the
|
|
292
|
+
// first-boot insert to what this build ships (D-157.6(b)), and `filePath` is
|
|
293
|
+
// what says which entry that is.
|
|
294
|
+
async () => loadModulePresence({
|
|
295
|
+
em,
|
|
296
|
+
entries: resolvedRegistry,
|
|
297
|
+
declaredOmissions: options.declaredOmissions ?? [],
|
|
298
|
+
}), { entryPoint: 'boot' });
|
|
299
|
+
const eventBus = new EventBus();
|
|
300
|
+
// Feature 054 (Principle XIII) — the Command Bus: the single, guaranteed audit
|
|
301
|
+
// writer for sensitive writes. It forks the scoped EM, runs the write + one
|
|
302
|
+
// audit insert co-transactionally, and dispatches the domain event on commit.
|
|
303
|
+
const commandBus = new CommandBus(orm, auditLogService, eventBus);
|
|
304
|
+
// Feature 060 — API interceptor registry. Modules register pre/post
|
|
305
|
+
// interceptors against endpoints owned by other modules; execution is
|
|
306
|
+
// lifecycle-gated per interceptor via the enabled-set cache predicate.
|
|
307
|
+
const apiInterceptors = new ApiInterceptorRegistry({
|
|
308
|
+
isModuleEnabled: (moduleId) => registryCache.isEnabled(moduleId),
|
|
309
|
+
});
|
|
310
|
+
// Feature 072 — the **host values** a composition owns outright. No module
|
|
311
|
+
// registers a default for any of them, so they have no contribution window
|
|
312
|
+
// (D-45's one-slot rule is about overwriting a module's default) and are
|
|
313
|
+
// registered where the value comes into existence rather than after
|
|
314
|
+
// `composeModules`. Everything a module does default is contributed below,
|
|
315
|
+
// between that call and `runBootHooks()`.
|
|
316
|
+
registerValues(container, {
|
|
317
|
+
redis,
|
|
318
|
+
// Feature 072 (T125) — the interceptor registry, so `_lifecycle` can serve
|
|
319
|
+
// the read-only diagnostics screen over it.
|
|
320
|
+
apiInterceptors,
|
|
321
|
+
// Whether this process runs queue consumers: the one module-agnostic
|
|
322
|
+
// answer, read by every module that starts one — at construction and from
|
|
323
|
+
// its `ctx.onBoot` reconcile — so no module reads `BACKEND_ROLE` itself and
|
|
324
|
+
// no module needs a flag of its own here
|
|
325
|
+
// (`specs/134-paid-module-extraction/` research D16, contract W1.1). The six
|
|
326
|
+
// values named after paid modules that stood beside it were removed in
|
|
327
|
+
// T124, and `product_feeds`' own worker flag with them once that module
|
|
328
|
+
// read this instead. Its two values below are D16 §6's free-side
|
|
329
|
+
// remainder, not a pattern to follow.
|
|
330
|
+
processRunsWorkers: runWorkers,
|
|
331
|
+
productFeedsPublicBaseUrl: resolvePublicApiBaseUrl(),
|
|
332
|
+
productFeedsTokenEncryptionKey: process.env['SETTINGS_SECRET_ENCRYPTION_KEY'],
|
|
333
|
+
// The key newsletter confirmation and unsubscribe links are signed with
|
|
334
|
+
// (`specs/117-instance-bring-up/` Phase 6, T6-B1).
|
|
335
|
+
//
|
|
336
|
+
// A **value** rather than a read inside the module, because
|
|
337
|
+
// `NEWSLETTER_TOKEN_SECRET` is declared in this package's own environment
|
|
338
|
+
// declaration. It is a module-named value in a composition root, which
|
|
339
|
+
// `specs/134-paid-module-extraction/` research D16 §2(d) names as the target
|
|
340
|
+
// to converge away from — the module registering it itself, with a default
|
|
341
|
+
// computed from platform-published inputs — and D16 §6 records as a free-side
|
|
342
|
+
// question rather than that feature's. It is not a precedent: the six
|
|
343
|
+
// module-named values that once stood beside it were removed (T124).
|
|
344
|
+
//
|
|
345
|
+
// The fallback chain is the declaration's own sentence: absent, *"newsletter
|
|
346
|
+
// links are signed with the session key instead"* — and an empty value is
|
|
347
|
+
// absent (`./newsletter-token-secret.ts`). The **third** fallback
|
|
348
|
+
// the reference deployment carried — a literal `'newsletter-dev-secret'` —
|
|
349
|
+
// is deliberately not reproduced. It is a shipped default signing key,
|
|
350
|
+
// nothing declares it, and a deployment that reached it signed every
|
|
351
|
+
// confirmation link with a secret that is in this repository.
|
|
352
|
+
newsletterTokenSecret: newsletterTokenSecretFrom(process.env['NEWSLETTER_TOKEN_SECRET'], process.env['SESSION_COOKIE_SECRET']),
|
|
353
|
+
// The one connection ioredis has put into subscriber mode. Shared, because
|
|
354
|
+
// a subscriber connection cannot serve commands: a per-module one would
|
|
355
|
+
// cost a socket per module and buy nothing.
|
|
356
|
+
redisSubscriber,
|
|
357
|
+
// Modules announce on it; `ctx.subscribe` receives on it. A module that
|
|
358
|
+
// publishes needs it as a registration, not just as a composer option.
|
|
359
|
+
eventBus,
|
|
360
|
+
// The audited write path (Principle XIII). A converted module resolves it
|
|
361
|
+
// like any other platform service.
|
|
362
|
+
commandBus,
|
|
363
|
+
// The resolved registry — core manifests plus this deployment's overlay
|
|
364
|
+
// modules plus every installed package. `admin_roles` builds the permission
|
|
365
|
+
// catalogue from it and cannot see it itself: which modules a deployment
|
|
366
|
+
// ships is a composition input, not something a module decides.
|
|
367
|
+
resolvedModuleRegistry: resolvedRegistry,
|
|
368
|
+
auditLogService,
|
|
369
|
+
storefrontBaseUrl: process.env['STOREFRONT_BASE_URL'] ?? 'http://localhost:3000',
|
|
370
|
+
// No verification-token probe outside a harness.
|
|
371
|
+
organizationsExposeTestProbe: false,
|
|
372
|
+
...options.values,
|
|
373
|
+
});
|
|
374
|
+
/**
|
|
375
|
+
* The container reads this function makes, against
|
|
376
|
+
* {@link PlatformContainerReads}.
|
|
377
|
+
*
|
|
378
|
+
* A function rather than a captured object, for the reason every accessor in
|
|
379
|
+
* a composition root is one: a gated name resolves per call, so a switched-off
|
|
380
|
+
* owner answers at the call site instead of through a handle this composition
|
|
381
|
+
* is holding.
|
|
382
|
+
*/
|
|
383
|
+
const reads = () => container.cradle;
|
|
384
|
+
// Where this call sits no longer decides whether a cache is fresh, and that
|
|
385
|
+
// is the point of D-93. Channel *resolution* is kernel infrastructure for the
|
|
386
|
+
// reason T110 gave: every channel-scoped read depends on it (Principle XII),
|
|
387
|
+
// so it must keep working whether or not an operator wants the administration
|
|
388
|
+
// screens. The module owns the admin CRUD service and its routes.
|
|
389
|
+
const salesChannels = composeSalesChannelsKernel({
|
|
390
|
+
emFactory: em,
|
|
391
|
+
eventBus,
|
|
392
|
+
redis,
|
|
393
|
+
auditLogService,
|
|
394
|
+
});
|
|
395
|
+
// Feature 005 / `specs/117-instance-bring-up/` — and the invariant is this
|
|
396
|
+
// root's because the middleware above is.
|
|
397
|
+
//
|
|
398
|
+
// `registerSalesChannelResolverMiddleware` installs a **global `onRequest`
|
|
399
|
+
// hook** that falls back to `resolver.getSystemDefault()` for every
|
|
400
|
+
// `/api/v1/*` path except `/api/v1/_health`, and that call throws
|
|
401
|
+
// `NoSystemDefaultChannel` — an `HttpError(500, INTERNAL)`, which the error
|
|
402
|
+
// envelope answers *without logging*. So a composition that mounts the
|
|
403
|
+
// resolver and does not guarantee the flagged row serves `500 INTERNAL` to
|
|
404
|
+
// every request and writes nothing about any of them.
|
|
405
|
+
//
|
|
406
|
+
// It stood in the reference deployment's contribution callback until
|
|
407
|
+
// 2026-09-13, which made it a step only a root that *supplies* one performed.
|
|
408
|
+
// An instance supplies none (`contracts/instance-repository.md` R2.4), so
|
|
409
|
+
// every scaffolded instance answered 500 on `/api/v1/_openapi.json` — a route
|
|
410
|
+
// that touches no module and no database — from its first served request.
|
|
411
|
+
// `harness-parity.test.ts` could not see it: production and the harness both
|
|
412
|
+
// ran the reconciler, and the root that did not is the one this repository
|
|
413
|
+
// never composes.
|
|
414
|
+
//
|
|
415
|
+
// **Before `composeModules`**, for the reason the reference deployment's own
|
|
416
|
+
// comment gave: a module registration or an `ctx.onBoot` hook may read the
|
|
417
|
+
// system default (`inventory`'s warehouse/channel pairing,
|
|
418
|
+
// `mfaDefaultChannelIdResolver`), and none of them may observe the registry
|
|
419
|
+
// mid-repair.
|
|
420
|
+
//
|
|
421
|
+
// Feature 072 (T036) — boot reconcilers establish their own scope. This one
|
|
422
|
+
// ran with no ambient tenant context for a long time and survived only
|
|
423
|
+
// because the rows it touches carry no automatic filter; that was an accident
|
|
424
|
+
// of entity classification, not a guarantee.
|
|
425
|
+
const defaultChannelReconciliation = await enterSystemScope('boot: reconcile the default sales channel', () => new DefaultChannelReconciler(em, auditLogService).run(), { entryPoint: 'boot' });
|
|
426
|
+
if (defaultChannelReconciliation.action === 'warning' && defaultChannelReconciliation.warning) {
|
|
427
|
+
platformLogger().warn({ action: defaultChannelReconciliation.action }, defaultChannelReconciliation.warning);
|
|
428
|
+
}
|
|
429
|
+
// Feature 072 (T118) — the universal settings *reader* is kernel
|
|
430
|
+
// infrastructure: almost every module calls `SettingsService.get`, so it
|
|
431
|
+
// cannot be gated on whether an operator wants the settings screens.
|
|
432
|
+
const settings = composeSettingsKernel({
|
|
433
|
+
emFactory: em,
|
|
434
|
+
redis,
|
|
435
|
+
...(process.env['SETTINGS_SECRET_ENCRYPTION_KEY']
|
|
436
|
+
? { secretEncryptionKey: process.env['SETTINGS_SECRET_ENCRYPTION_KEY'] }
|
|
437
|
+
: {}),
|
|
438
|
+
});
|
|
439
|
+
// Secret settings (e.g. prompt_actions API keys) are AES-256-GCM encrypted at
|
|
440
|
+
// rest with SETTINGS_SECRET_ENCRYPTION_KEY. The key is read from the
|
|
441
|
+
// environment once at boot, so a value added to `.env` only takes effect
|
|
442
|
+
// after a restart. Warn loudly here so a missing key is obvious instead of
|
|
443
|
+
// surfacing only as a 500 when an operator tries to save a secret.
|
|
444
|
+
if (!process.env['SETTINGS_SECRET_ENCRYPTION_KEY']) {
|
|
445
|
+
// Boot-time logging path; the Fastify logger is not yet available here.
|
|
446
|
+
console.warn('[settings] SETTINGS_SECRET_ENCRYPTION_KEY is not set — secret settings ' +
|
|
447
|
+
'(e.g. prompt_actions API keys) cannot be saved. Set a base64 32-byte key ' +
|
|
448
|
+
'(openssl rand -base64 32) in the deployment environment and restart the backend.');
|
|
449
|
+
}
|
|
450
|
+
// Feature 072 — the module list, composed in one pass (D-45). Registration
|
|
451
|
+
// resolves nothing, so this call has no opinion about the order the caller
|
|
452
|
+
// assembled; the boot hooks it collects run once, at the bottom of this
|
|
453
|
+
// function, after every contribution below.
|
|
454
|
+
const composedModules = composeModules(moduleEntries, {
|
|
455
|
+
container,
|
|
456
|
+
eventBus,
|
|
457
|
+
// Issue #269 — composition runs before `buildServer`, so there is no
|
|
458
|
+
// `app.log` yet. This is late-bound rather than a snapshot: `buildServer`
|
|
459
|
+
// attaches the application's own pino instance the moment it exists.
|
|
460
|
+
log: platformLogger(),
|
|
461
|
+
interceptorRegistry: apiInterceptors,
|
|
462
|
+
ownership: registrationOwnership,
|
|
463
|
+
// Issue #258 — the modules this deployment is required to have, derived
|
|
464
|
+
// from the manifest set it resolved above rather than written down (D-100).
|
|
465
|
+
requiredModules: requiredModulesFrom(resolvedRegistry.map((entry) => entry.manifest)),
|
|
466
|
+
// Feature 107 (FR-040/FR-041) — **checked, never applied.** The composer
|
|
467
|
+
// emits in its own order and drains decorations once; this asserts that the
|
|
468
|
+
// resulting order was the intended one and refuses when the two disagree.
|
|
469
|
+
decorationOrder: options.decorationOrder,
|
|
470
|
+
});
|
|
471
|
+
const composedContext = {
|
|
472
|
+
orm,
|
|
473
|
+
em,
|
|
474
|
+
container,
|
|
475
|
+
eventBus,
|
|
476
|
+
commandBus,
|
|
477
|
+
auditLogService,
|
|
478
|
+
apiInterceptors,
|
|
479
|
+
redis,
|
|
480
|
+
redisSubscriber,
|
|
481
|
+
settings,
|
|
482
|
+
salesChannels,
|
|
483
|
+
resolvedModules: resolvedRegistry,
|
|
484
|
+
composed: composedModules,
|
|
485
|
+
};
|
|
486
|
+
// --- the platform's own contributions ------------------------------------
|
|
487
|
+
//
|
|
488
|
+
// The twenty of `composition.ts`' sixty-one whose value expression names no
|
|
489
|
+
// module: a sub-kernel's object, a host value or an environment read. They
|
|
490
|
+
// are contributed here rather than by a caller because a deployment that had
|
|
491
|
+
// to write them would be writing the platform's own wiring — R1.4 — and an
|
|
492
|
+
// instance that forgot one would compose a platform missing a name eleven
|
|
493
|
+
// modules resolve.
|
|
494
|
+
//
|
|
495
|
+
// They go **before** `options.contribute`, so a deployment that genuinely
|
|
496
|
+
// wants a different answer for one of them can still say so.
|
|
497
|
+
// Feature 072 (T110) — the channel-resolution names. The kernel itself is
|
|
498
|
+
// composed above `composeModules`, for the subscriber ordering; what belongs
|
|
499
|
+
// here is the registration, in the one contribution slot.
|
|
500
|
+
composedModules.contribute({
|
|
501
|
+
salesChannelsCache: salesChannels.cache,
|
|
502
|
+
// Feature 120 (FR-015) — the channel-bridge contribution registry. Each
|
|
503
|
+
// module owning a channel-scoped entity type resolves this name from its
|
|
504
|
+
// own boot hook and declares the one bridge table its migrations create;
|
|
505
|
+
// the platform holds no map of the nine. A member nothing registered
|
|
506
|
+
// refuses at the membership call instead of reaching a relation an
|
|
507
|
+
// instance that omits that module does not have.
|
|
508
|
+
salesChannelBridgeRegistry: salesChannels.bridgeRegistry,
|
|
509
|
+
// The kernel-reserved membership port. `payment_methods` and
|
|
510
|
+
// `delivery_methods` resolve it to auto-bind a new method to the system
|
|
511
|
+
// default channel; both read it when their routes register.
|
|
512
|
+
salesChannelMembershipPort: salesChannels.membershipService,
|
|
513
|
+
// The channel resolver itself. `inventory` has resolved this name since
|
|
514
|
+
// T129 and neither root registered it, so the channel-scoped storefront
|
|
515
|
+
// stock read threw `AwilixResolutionError` on its first call.
|
|
516
|
+
salesChannelResolutionPort: salesChannels.resolver,
|
|
517
|
+
/**
|
|
518
|
+
* The channel a **channel-scoped** settings read resolves against outside a
|
|
519
|
+
* request (worker, boot hook, CLI): the deployment's system-default sales
|
|
520
|
+
* channel.
|
|
521
|
+
*
|
|
522
|
+
* D-48 removed the `?? null` — the resolver cannot fail to find a default,
|
|
523
|
+
* so this cannot answer "none". The return type stays `string | null`
|
|
524
|
+
* because the *seam* still admits one: a composition may register a
|
|
525
|
+
* resolver of its own that has no channel to offer.
|
|
526
|
+
*/
|
|
527
|
+
settingsChannelResolver: async () => (await salesChannels.resolver.getSystemDefault()).id,
|
|
528
|
+
// Feature 072 (wave 2) — the sales-channel code⇄id lookup
|
|
529
|
+
// `google_analytics` resolves. `idByCode` is the kernel resolver's;
|
|
530
|
+
// `codeById` reads the module's own gated `salesChannelsService` port by
|
|
531
|
+
// container name, against the one method it calls.
|
|
532
|
+
salesChannelCodeIdPort: {
|
|
533
|
+
idByCode: async (code) => (await salesChannels.resolver.getByCode(code))?.id ?? null,
|
|
534
|
+
codeById: async (id) => {
|
|
535
|
+
const { items } = await reads().salesChannelsService.list({});
|
|
536
|
+
return items.find((c) => c.id === id)?.code ?? null;
|
|
537
|
+
},
|
|
538
|
+
},
|
|
539
|
+
// Feature 042 / D-96 — the default channel an MFA challenge is scoped to.
|
|
540
|
+
mfaDefaultChannelIdResolver: async () => (await salesChannels.resolver.getSystemDefault()).id,
|
|
541
|
+
});
|
|
542
|
+
// Feature 072 (T118) — the settings names. The kernel itself is composed
|
|
543
|
+
// above `composeModules`, for the subscriber ordering; what belongs here is
|
|
544
|
+
// the registration, in the one contribution slot.
|
|
545
|
+
composedModules.contribute({
|
|
546
|
+
// The kernel's `SettingsService` already implements the read port.
|
|
547
|
+
settingsReadPort: settings.settingsService,
|
|
548
|
+
// The same cache, seen from the writing side (issue #45). The `settings`
|
|
549
|
+
// module owns the one write seam, so it is the one place that can drop the
|
|
550
|
+
// cache *as part of* the write instead of announcing the write and hoping a
|
|
551
|
+
// subscriber gets there first.
|
|
552
|
+
settingsCache: settings.cache,
|
|
553
|
+
settingsSecretEncryptionKey: process.env['SETTINGS_SECRET_ENCRYPTION_KEY'],
|
|
554
|
+
// Feature 073 — the effective-state reader. Registered here rather than
|
|
555
|
+
// imported inside the module so the dependency direction stays declared in
|
|
556
|
+
// a composition: `_lifecycle` reads this module's `Setting` rows, and this
|
|
557
|
+
// module reads nothing of `_lifecycle`'s.
|
|
558
|
+
settingsModulePresence: {
|
|
559
|
+
presenceOf: (moduleId) => effectiveState.presenceOf(moduleId),
|
|
560
|
+
activationControlOwner: (code) => effectiveState.activationControlOwner(code),
|
|
561
|
+
},
|
|
562
|
+
// US2 — the delete-integrity guard reaches settings only through this port
|
|
563
|
+
// (Principle I): `SettingsService.listReferencesToConfiguration`.
|
|
564
|
+
credentialsSettingsPort: settings.settingsService,
|
|
565
|
+
});
|
|
566
|
+
// The lazily built manifest registry the contribution below hands `_i18n`.
|
|
567
|
+
let manifestRegistry;
|
|
568
|
+
composedModules.contribute({
|
|
569
|
+
// Principle X — whether this process runs each module's queue consumers.
|
|
570
|
+
// Only the *flag* was ever a deployment decision; the workers themselves
|
|
571
|
+
// are their modules' own (T143a).
|
|
572
|
+
webhooksRunWorkers: runWorkers,
|
|
573
|
+
pwaRunWorkers: runWorkers,
|
|
574
|
+
catalogRunBulkOperationWorker: runWorkers,
|
|
575
|
+
searchRunWorkers: runWorkers,
|
|
576
|
+
// Feature 072 (T127) — whether a wall-clock status sweeper runs.
|
|
577
|
+
priceListsEnableStatusSweeper: true,
|
|
578
|
+
// Feature 072 (wave 2) — the connection a module may build a BullMQ
|
|
579
|
+
// producer queue on. Deliberately a different name from `redis`: "no queue
|
|
580
|
+
// in this composition" is a statement a composition should be able to make
|
|
581
|
+
// rather than something inferred from a missing option.
|
|
582
|
+
moduleQueueRedis: redis,
|
|
583
|
+
// Blog ships no storefront ports today — the factory defaulted this to `{}`
|
|
584
|
+
// and no composition ever passed one.
|
|
585
|
+
blogStorefrontDeps: undefined,
|
|
586
|
+
// Issue #225 — the reading and its generation, contributed as one value.
|
|
587
|
+
// The palette memoises what the reading produced, so a composition that
|
|
588
|
+
// handed over the reading alone would hand over a cache nothing can drop.
|
|
589
|
+
modulePresenceProbe: {
|
|
590
|
+
// Issue #187 — the platform axis, which the palette used to read by
|
|
591
|
+
// joining `module_registrations` itself. `?? false` where the operator
|
|
592
|
+
// axis defaults `true`, and the asymmetry is the tri-state rather than an
|
|
593
|
+
// oversight.
|
|
594
|
+
isPlatformAvailable: (moduleId) => effectiveState.presence(moduleId)?.platformAvailable ?? false,
|
|
595
|
+
isActivated: (moduleId) => effectiveState.presence(moduleId)?.operatorActivated ?? true,
|
|
596
|
+
version: () => effectiveState.presenceVersion(),
|
|
597
|
+
},
|
|
598
|
+
// The accessor `_i18n` walks to reconcile every module's translation
|
|
599
|
+
// bundles (`specs/110-instance-repository/` T141). It is a **default**:
|
|
600
|
+
// both roots in this repository contribute their own below, through
|
|
601
|
+
// `options.contribute`, and an instance contributes nothing at all — R2.4 —
|
|
602
|
+
// so before this it resolved to nothing and the boot died inside `_i18n`'s
|
|
603
|
+
// reconcile with `Could not resolve 'lifecycleManifestRegistry'`.
|
|
604
|
+
//
|
|
605
|
+
// Built lazily and once: a composition that never reads the name pays for
|
|
606
|
+
// no registry, and `buildStaticRegistry` refuses a duplicate module id,
|
|
607
|
+
// which the resolved set cannot hold.
|
|
608
|
+
lifecycleManifestRegistry: () => (manifestRegistry ??= buildStaticRegistry(resolvedRegistry)),
|
|
609
|
+
// Feature 072 (T125) — how a committed activation flip propagates: the
|
|
610
|
+
// writing process refreshes itself rather than waiting on its own pub/sub
|
|
611
|
+
// round trip, so the very next request it serves sees the new state.
|
|
612
|
+
lifecycleActivationPropagation: {
|
|
613
|
+
commandBus,
|
|
614
|
+
propagation: {
|
|
615
|
+
refreshLocalState: () => registryCache.refreshFromDb(em),
|
|
616
|
+
publishStateChanged: (payload) => publishStateChanged(redis, payload),
|
|
617
|
+
revalidateStorefront: (tags) => new StorefrontRevalidator({
|
|
618
|
+
baseUrl: process.env['STOREFRONT_BASE_URL'],
|
|
619
|
+
secret: process.env['REVALIDATE_SECRET'],
|
|
620
|
+
}).revalidate(tags),
|
|
621
|
+
},
|
|
622
|
+
},
|
|
623
|
+
});
|
|
624
|
+
// --- the actor-shaped ten (T118b, completed by feature 117's Phase 6) -----
|
|
625
|
+
//
|
|
626
|
+
// Nine names that answer one question — *who is asking?* — off `request.actor`
|
|
627
|
+
// and nothing else. They stayed in `backend/src/composition.ts` through T118
|
|
628
|
+
// for a single reason: the `declare module 'fastify'` block that puts `actor`
|
|
629
|
+
// on `FastifyRequest` was `auth`'s, so a platform file reading it would have
|
|
630
|
+
// been a platform file depending on a module (D-52/D-53). T118b moved that
|
|
631
|
+
// declaration to `../http/request-actor.ts` and the shape to
|
|
632
|
+
// `@endora-commerce/contracts`, and the nine came with it. Their value
|
|
633
|
+
// expressions name no module, which is T118's criterion unchanged.
|
|
634
|
+
//
|
|
635
|
+
// **The tenth arrived with `specs/117-instance-bring-up/` Phase 6** and is
|
|
636
|
+
// `customerOrganizationIdResolver`, below. T118b left it in the deployment's
|
|
637
|
+
// `values` saying it stayed because it reads `request.actor` — the very thing
|
|
638
|
+
// T118b moved — so the reason expired in the commit that wrote it, and four
|
|
639
|
+
// modules went on reading a name only two compositions in the world supplied.
|
|
640
|
+
//
|
|
641
|
+
// `ordersAdminScopeResolver` was called the tenth and is not on this list at
|
|
642
|
+
// all: its body decides on `admin_roles.code === 'sales_representative'` over
|
|
643
|
+
// a row it reads from `admin_users`, which is a module's business rule over a
|
|
644
|
+
// module's table. That is a correct reason not to put it here, and the home
|
|
645
|
+
// it points at is `orders`, which registers it since the same phase.
|
|
646
|
+
//
|
|
647
|
+
// **Where a widening appears below it is that site's own.** `request.actor` is
|
|
648
|
+
// decorated by `auth`'s `onRequest` hook; the three audit-context resolvers
|
|
649
|
+
// are called from surfaces a composition can mount without one, and answering
|
|
650
|
+
// the nil-UUID sentinel is what they already did. The five that throw already
|
|
651
|
+
// threw.
|
|
652
|
+
composedModules.contribute({
|
|
653
|
+
// Feature 072 (T143a) — how this platform resolves the acting admin for a
|
|
654
|
+
// module that takes one as an option. `credentials` is the original
|
|
655
|
+
// consumer; the shape is `{ adminUserId }` and the refusal is a 401.
|
|
656
|
+
adminContextResolver: (request) => {
|
|
657
|
+
if (request.actor.kind !== 'admin') {
|
|
658
|
+
throw new HttpError(401, ERROR_CODES.UNAUTHORIZED, 'Admin session required.');
|
|
659
|
+
}
|
|
660
|
+
return { adminUserId: request.actor.adminUserId };
|
|
661
|
+
},
|
|
662
|
+
// Feature 072 (wave 2) — how this platform names the acting admin on an
|
|
663
|
+
// audit record: the admin's id, or `null` for a non-admin caller. Six
|
|
664
|
+
// modules each declared an identically-shaped `resolveAuditContext` option
|
|
665
|
+
// and both roots spelled the same closure once per module.
|
|
666
|
+
adminAuditActorResolver: (request) => ({
|
|
667
|
+
actorAdminUserId: request.actor.kind === 'admin' ? request.actor.adminUserId : null,
|
|
668
|
+
}),
|
|
669
|
+
// Feature 072 (T127) — `price_lists`' audit context. Unlike
|
|
670
|
+
// `adminAuditActorResolver` this one owes a non-null id, so a caller the
|
|
671
|
+
// admin gate should already have refused falls back to the nil UUID rather
|
|
672
|
+
// than to `null`.
|
|
673
|
+
priceListsAdminAuditContext: (request) => {
|
|
674
|
+
const actor = request.actor;
|
|
675
|
+
if (actor?.kind !== 'admin') {
|
|
676
|
+
return { actorAdminUserId: NON_ADMIN_AUDIT_ACTOR };
|
|
677
|
+
}
|
|
678
|
+
return { actorAdminUserId: actor.adminUserId };
|
|
679
|
+
},
|
|
680
|
+
// Feature 072 (T142) — `catalog`'s audit context. Same sentinel, plus the
|
|
681
|
+
// impersonation field that module's record carries.
|
|
682
|
+
catalogAdminAuditContext: (request) => {
|
|
683
|
+
const actor = request.actor;
|
|
684
|
+
if (actor?.kind !== 'admin') {
|
|
685
|
+
// Auditing an anonymous mutation shouldn't happen — the admin gate
|
|
686
|
+
// refuses these — but if it ever does, fall back to a sentinel.
|
|
687
|
+
return { actorAdminUserId: NON_ADMIN_AUDIT_ACTOR };
|
|
688
|
+
}
|
|
689
|
+
return {
|
|
690
|
+
actorAdminUserId: actor.adminUserId,
|
|
691
|
+
impersonatedCustomerAccountId: null,
|
|
692
|
+
};
|
|
693
|
+
},
|
|
694
|
+
// Feature 072 (T129) — `inventory`'s audit context.
|
|
695
|
+
inventoryAdminAuditContext: (request) => {
|
|
696
|
+
const actor = request.actor;
|
|
697
|
+
if (actor?.kind !== 'admin') {
|
|
698
|
+
return { actorAdminUserId: NON_ADMIN_AUDIT_ACTOR };
|
|
699
|
+
}
|
|
700
|
+
return { actorAdminUserId: actor.adminUserId };
|
|
701
|
+
},
|
|
702
|
+
/**
|
|
703
|
+
* Feature 072 (wave 2) — how this platform resolves the calling customer,
|
|
704
|
+
* for the five modules that take one as an option.
|
|
705
|
+
*
|
|
706
|
+
* **The refusal below asserts an invariant; it does not describe a business
|
|
707
|
+
* state** (D-178). It was a 422 `organization_required`, introduced by
|
|
708
|
+
* feature 026 US2 for accounts that were allowed to have no Organization.
|
|
709
|
+
* Every transacting customer has one — `customer_accounts.organization_id`
|
|
710
|
+
* is `NOT NULL` and an individual is backed by a personal organisation — so
|
|
711
|
+
* a caller reaching this branch is a broken invariant, and a 422 telling a
|
|
712
|
+
* buyer to attach an Organization they have no way to attach is a lie with
|
|
713
|
+
* a remedy attached.
|
|
714
|
+
*
|
|
715
|
+
* The guard is **kept** rather than deleted: `Actor`'s `organizationId` is
|
|
716
|
+
* `string | null` at this seam and the consumers' input type is
|
|
717
|
+
* `organizationId: string`, so removing the check would push `undefined`
|
|
718
|
+
* through silently. Routes that work *without* an Organization
|
|
719
|
+
* (cart-add, browsing, profile-read) take `cartActorResolver` or read
|
|
720
|
+
* `request.actor` themselves.
|
|
721
|
+
*/
|
|
722
|
+
customerContextResolver: (request) => {
|
|
723
|
+
if (request.actor.kind !== 'customer') {
|
|
724
|
+
throw new HttpError(401, ERROR_CODES.UNAUTHORIZED, 'Customer session required.');
|
|
725
|
+
}
|
|
726
|
+
if (!request.actor.organizationId) {
|
|
727
|
+
throw new HttpError(500, ERROR_CODES.INTERNAL, 'Invariant violated: a customer account has no Organization (Principle XI).', { code: 'customer_account_organization_missing' });
|
|
728
|
+
}
|
|
729
|
+
return {
|
|
730
|
+
customerAccountId: request.actor.customerAccountId,
|
|
731
|
+
organizationId: request.actor.organizationId,
|
|
732
|
+
impersonatorAdminUserId: request.actor.impersonatorAdminUserId ?? null,
|
|
733
|
+
};
|
|
734
|
+
},
|
|
735
|
+
// Feature 072 (wave 3) — how this platform names the calling customer as an
|
|
736
|
+
// id. Unlike `customerContextResolver` it does not require an Organization:
|
|
737
|
+
// it asserts a customer session and nothing more. The four payment gateways
|
|
738
|
+
// each declared an identically-shaped `resolveCustomerAccountId` option.
|
|
739
|
+
customerAccountIdResolver: (request) => {
|
|
740
|
+
if (request.actor.kind !== 'customer') {
|
|
741
|
+
throw new HttpError(401, ERROR_CODES.UNAUTHORIZED, 'Customer session required.');
|
|
742
|
+
}
|
|
743
|
+
return request.actor.customerAccountId;
|
|
744
|
+
},
|
|
745
|
+
// Feature 072 — `carts`' actor, which is the one that answers for an
|
|
746
|
+
// anonymous shopper too: a signed-in customer, else the anonymous cart
|
|
747
|
+
// cookie, else nothing at all. The empty answer is a cart the caller may
|
|
748
|
+
// still create.
|
|
749
|
+
cartActorResolver: (request) => {
|
|
750
|
+
if (request.actor.kind === 'customer') {
|
|
751
|
+
return {
|
|
752
|
+
customer: {
|
|
753
|
+
customerAccountId: request.actor.customerAccountId,
|
|
754
|
+
organizationId: request.actor.organizationId,
|
|
755
|
+
},
|
|
756
|
+
};
|
|
757
|
+
}
|
|
758
|
+
const cookies = request.cookies;
|
|
759
|
+
const anon = cookies?.[ANONYMOUS_CART_COOKIE];
|
|
760
|
+
if (anon)
|
|
761
|
+
return { anonymousToken: anon };
|
|
762
|
+
return {};
|
|
763
|
+
},
|
|
764
|
+
// Feature 072 (T138) — the actor half of what used to be
|
|
765
|
+
// `buildOrgAllowListResolver`: who is asking, as a bare Organization id.
|
|
766
|
+
//
|
|
767
|
+
// **The tenth actor-shaped name, and it arrived three features late**
|
|
768
|
+
// (`specs/117-instance-bring-up/` Phase 6). It was a `values` entry of
|
|
769
|
+
// `backend/src/composition.ts`, and the comment beside it said why: *"it
|
|
770
|
+
// reads `request.actor`, which is `auth`'s `declare module 'fastify'`
|
|
771
|
+
// block — T118b's subject"*. T118b is the merge request that moved the
|
|
772
|
+
// augmentation to `../http/request-actor.ts` and brought the nine above
|
|
773
|
+
// with it; this one was left behind and its stated blocker expired in the
|
|
774
|
+
// same commit. Its value expression names no module, which is T118's
|
|
775
|
+
// criterion unchanged.
|
|
776
|
+
//
|
|
777
|
+
// Four modules read it — `delivery_methods`, `inventory`, `orders` and
|
|
778
|
+
// `payment_methods` — and nothing defaulted it, so a composition that was
|
|
779
|
+
// not `backend/src/composition.ts` did not have it. That is not an
|
|
780
|
+
// override a client declines; it is a name a scaffolded instance cannot
|
|
781
|
+
// resolve, met as a 500 on the first restriction check rather than at boot.
|
|
782
|
+
//
|
|
783
|
+
// **Soft by contract, and the softness is the reason it is its own name.**
|
|
784
|
+
// It answers `null` for anonymous traffic *and* for a Customer with no
|
|
785
|
+
// Organization, where `customerContextResolver` above throws. It is read on
|
|
786
|
+
// restriction checks, and catching that throw to mean "unrestricted" is how
|
|
787
|
+
// a fail-closed gate becomes fail-open. Do not merge the two.
|
|
788
|
+
customerOrganizationIdResolver: (request) => {
|
|
789
|
+
const actor = request.actor;
|
|
790
|
+
return actor?.kind === 'customer' ? (actor.organizationId ?? null) : null;
|
|
791
|
+
},
|
|
792
|
+
// Feature 072 (T140) — `customers`' own view of the calling customer:
|
|
793
|
+
// the account and its Organization, the second nullable. It is not
|
|
794
|
+
// `customerContextResolver` — self-service profile reads work for an
|
|
795
|
+
// account with no Organization, which is why this one does not assert one.
|
|
796
|
+
customerActorResolver: (request) => {
|
|
797
|
+
if (request.actor.kind !== 'customer') {
|
|
798
|
+
throw new HttpError(401, ERROR_CODES.UNAUTHORIZED, 'Customer session required.');
|
|
799
|
+
}
|
|
800
|
+
return {
|
|
801
|
+
customerAccountId: request.actor.customerAccountId,
|
|
802
|
+
organizationId: request.actor.organizationId ?? null,
|
|
803
|
+
};
|
|
804
|
+
},
|
|
805
|
+
});
|
|
806
|
+
// The caller's own, in the same window and after the platform's.
|
|
807
|
+
await options.contribute?.(composedContext);
|
|
808
|
+
const buildTenantContext = options.buildTenantContext ??
|
|
809
|
+
(async (request) => systemTenantContext(`${request.method} ${request.url}`));
|
|
810
|
+
// Assembled here rather than above the contribution window, and that is a
|
|
811
|
+
// guarantee rather than a placement: a caller adds to `options.plugins` or
|
|
812
|
+
// `options.scopedPlugins` from inside `contribute`, where the value a plugin
|
|
813
|
+
// needs finally exists.
|
|
814
|
+
const modules = [
|
|
815
|
+
// D-229 — the liveness and readiness probe, which is the platform's own
|
|
816
|
+
// surface and not a module's. It is first so that a reader looking for the
|
|
817
|
+
// one route an orchestrator polls finds it without reading the composer,
|
|
818
|
+
// and the position claims nothing about hooks: Fastify assembles a route's
|
|
819
|
+
// hook chain when the application is readied rather than when the route is
|
|
820
|
+
// registered (D-45), so the request-scope and sales-channel hooks below
|
|
821
|
+
// still see it — and both already exempt this path by name.
|
|
822
|
+
//
|
|
823
|
+
// It goes through `modules` rather than through `buildServer` because the
|
|
824
|
+
// probes close over `orm` and `redis`, which exist here and not there, and
|
|
825
|
+
// every composition root already passes `composition.modules` — including
|
|
826
|
+
// the one `endora new instance` writes. Nothing was asked of a root.
|
|
827
|
+
healthRoutePlugin({ orm, redis }),
|
|
828
|
+
// Feature 072 — every module's route contribution, in the composer's order.
|
|
829
|
+
//
|
|
830
|
+
// They sit ahead of the root plugins, and that is not an ordering claim:
|
|
831
|
+
// `buildServer` calls each of these with the root instance, so an
|
|
832
|
+
// `onRequest` hook any of them adds is a root hook, and Fastify assembles a
|
|
833
|
+
// route's hook chain when the application is readied rather than when the
|
|
834
|
+
// route is registered (D-45).
|
|
835
|
+
...composedModules.sink.plugins,
|
|
836
|
+
// Feature 072 (T078) — the auth plugin is `auth`'s own contribution,
|
|
837
|
+
// collected by `ctx.rootPlugin` because it decorates `request.actor` for
|
|
838
|
+
// the whole application rather than contributing routes.
|
|
839
|
+
async (app) => {
|
|
840
|
+
for (const plugin of composedModules.sink.rootPlugins)
|
|
841
|
+
await plugin(app);
|
|
842
|
+
},
|
|
843
|
+
...(options.plugins ?? []),
|
|
844
|
+
// Feature 050 / 072 (T027) — establish the ambient TenantContext for every
|
|
845
|
+
// request from the already-authenticated actor (never from request
|
|
846
|
+
// inputs), and open the request's resolution scope. One hook factory,
|
|
847
|
+
// shared with the test kit, so the two cannot drift.
|
|
848
|
+
async (app) => {
|
|
849
|
+
await registerRequestScopeHook(app, { buildTenantContext });
|
|
850
|
+
},
|
|
851
|
+
// Feature 005 — the sales-channel resolver middleware writes the resolved
|
|
852
|
+
// channel into the open request scope, so it mounts after the hook.
|
|
853
|
+
salesChannels.plugin,
|
|
854
|
+
...(options.scopedPlugins ?? []),
|
|
855
|
+
];
|
|
856
|
+
// Feature 004 / T024 — boot-time manifest reconciliation. Walks every
|
|
857
|
+
// module's settings manifest and inserts any missing groups/settings
|
|
858
|
+
// idempotently before the HTTP layer starts serving requests. NEVER deletes
|
|
859
|
+
// (R-1); destructive uninstall is CLI-only.
|
|
860
|
+
//
|
|
861
|
+
// Feature 080 (T046) — the population is `deploymentShippedEntries`, the same
|
|
862
|
+
// core-plus-overlay split D-157.6(b) ruled for the first-boot presence
|
|
863
|
+
// insert. A **package** is excluded for a reason of its own rather than for
|
|
864
|
+
// symmetry: since D-157.6(b) `install` is its only author, and reconciling a
|
|
865
|
+
// stranger's manifest here would let a `SettingCodeConflict` in something an
|
|
866
|
+
// operator merely `pnpm add`ed abort this boot.
|
|
867
|
+
const settingsManifests = reads()
|
|
868
|
+
.settingsManifestCollectionPort.collect(deploymentShippedEntries(resolvedRegistry));
|
|
869
|
+
const reconciler = new ManifestReconciler(em());
|
|
870
|
+
const reconciliation = await enterSystemScope('boot: reconcile module settings manifests', () => reconciler.apply(settingsManifests), { entryPoint: 'boot' });
|
|
871
|
+
for (const perModule of reconciliation.perModule) {
|
|
872
|
+
if (perModule.orphanSettings.length > 0 || perModule.orphanGroups.length > 0) {
|
|
873
|
+
// Boot-time logging path; the Fastify logger is not yet available here.
|
|
874
|
+
console.warn(`[settings] orphan rows for module "${perModule.moduleCode}": ` +
|
|
875
|
+
`${perModule.orphanSettings.length} settings, ${perModule.orphanGroups.length} groups`);
|
|
876
|
+
}
|
|
877
|
+
eventBus.emit('settings.module_reconciled', {
|
|
878
|
+
eventId: `settings.module_reconciled:${perModule.moduleCode}:${Date.now()}`,
|
|
879
|
+
occurredAt: new Date().toISOString(),
|
|
880
|
+
moduleCode: perModule.moduleCode,
|
|
881
|
+
addedCount: perModule.addedGroups + perModule.addedSettings,
|
|
882
|
+
updatedCount: perModule.updatedGroups + perModule.updatedSettings,
|
|
883
|
+
orphanCount: perModule.orphanGroups.length + perModule.orphanSettings.length,
|
|
884
|
+
});
|
|
885
|
+
}
|
|
886
|
+
// The explicit boot phase (FR-021), run **once**, after every registration
|
|
887
|
+
// and every contribution above and before an entry point calls `buildServer`
|
|
888
|
+
// (D-45). That is what makes the rule statable in one sentence: a boot hook
|
|
889
|
+
// may resolve anything, and a contribution goes between `composeModules` and
|
|
890
|
+
// this line.
|
|
891
|
+
//
|
|
892
|
+
// Why one phase rather than several: a contribution registered *after* a boot
|
|
893
|
+
// hook has already run is invisible to that hook, which reads the owning
|
|
894
|
+
// module's default instead and reports nothing — no error, no warning, a
|
|
895
|
+
// value that is simply the wrong one.
|
|
896
|
+
//
|
|
897
|
+
// Issue #52 — and this line is what closes the slot: every `contribute(…)`
|
|
898
|
+
// below it throws `ContributionWindowClosedError` naming the rule, rather
|
|
899
|
+
// than landing somewhere no hook will read.
|
|
900
|
+
await composedModules.runBootHooks();
|
|
901
|
+
return {
|
|
902
|
+
orm,
|
|
903
|
+
redis,
|
|
904
|
+
modules,
|
|
905
|
+
commandBus,
|
|
906
|
+
apiInterceptors,
|
|
907
|
+
container,
|
|
908
|
+
// Bound to the composed object rather than re-implemented: a second way to
|
|
909
|
+
// build a module's context is a second answer about what that module
|
|
910
|
+
// resolves (T042b).
|
|
911
|
+
contextFor: (moduleId) => composedModules.contextFor(moduleId),
|
|
912
|
+
resolvedModules: resolvedRegistry,
|
|
913
|
+
// The assembly is one function's, and what a composition supplies is the
|
|
914
|
+
// three things only a composition holds: its own resolved routing table and
|
|
915
|
+
// the two gated ports the envelope's callbacks read. The twenty lines that
|
|
916
|
+
// used to stand in each root stood character-for-character in both, which
|
|
917
|
+
// is the drift `harness-parity.test.ts` exists for and which issue #234
|
|
918
|
+
// already paid for once.
|
|
919
|
+
errorEnvelope: composeErrorEnvelopeOptions({
|
|
920
|
+
errorTranslationTargets: errorTranslation.targets,
|
|
921
|
+
adminUserReadPort: () => reads().adminUserReadPort,
|
|
922
|
+
translate: () => reads().adminI18nService,
|
|
923
|
+
}),
|
|
924
|
+
dispose: async () => {
|
|
925
|
+
// Feature 062 — drain the webhook delivery pipeline before dropping the
|
|
926
|
+
// Redis connections (graceful shutdown). Every part of that is the
|
|
927
|
+
// container's job since T143a: `ctx.subscribe` unsubscribes with the
|
|
928
|
+
// module, the queue registration carries its own disposer, and the
|
|
929
|
+
// delivery worker is `webhooks`' own. Disposing the container runs those
|
|
930
|
+
// disposers — for every module, not only one — and it runs *before* the
|
|
931
|
+
// Redis sockets go, which is the ordering the drain needs.
|
|
932
|
+
await container.dispose();
|
|
933
|
+
redis.disconnect();
|
|
934
|
+
redisSubscriber.disconnect();
|
|
935
|
+
await ormLifecycle.close();
|
|
936
|
+
},
|
|
937
|
+
};
|
|
938
|
+
}
|
|
939
|
+
//# sourceMappingURL=compose-app.js.map
|