bazis 0.96.1
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 +146 -0
- package/cli/build.ts +147 -0
- package/cli/codegen.ts +40 -0
- package/cli/generateModule.ts +187 -0
- package/cli/generateProject.ts +183 -0
- package/cli/main.ts +125 -0
- package/cli/moduleRegistration.ts +127 -0
- package/cli/naming.ts +124 -0
- package/cli/parseCli.ts +151 -0
- package/cli/templates/module.ts +497 -0
- package/cli/templates/pack.ts +76 -0
- package/cli/templates/passport.ts +178 -0
- package/core/agent/AgentContextBuilder.ts +567 -0
- package/core/agent/AgentDataDefinition.ts +8 -0
- package/core/agent/AgentRegistry.ts +539 -0
- package/core/agent/AgentRuntime.ts +47 -0
- package/core/agent/AgentToolExecutor.ts +2130 -0
- package/core/agent/AgentToolHooks.ts +39 -0
- package/core/agent/ModelProvider.ts +21 -0
- package/core/agent/README.md +229 -0
- package/core/agent/Tool.contract.ts +20 -0
- package/core/agent/decorators/Agent.ts +11 -0
- package/core/agent/decorators/Prompt.ts +11 -0
- package/core/agent/decorators/Task.ts +29 -0
- package/core/agent/decorators/Tool.ts +12 -0
- package/core/agent/errors.ts +43 -0
- package/core/agent/generated/catalog.ts +26 -0
- package/core/agent/index.ts +170 -0
- package/core/agent/internal/AgentExecutionDriver.ts +1497 -0
- package/core/agent/internal/AgentExecutionState.ts +775 -0
- package/core/agent/internal/AgentJsonSchema.ts +150 -0
- package/core/agent/internal/AgentModelBinding.ts +57 -0
- package/core/agent/internal/Schema.contract.ts +36 -0
- package/core/agent/internal/ToolAudit.projector.ts +163 -0
- package/core/agent/internal/ToolContract.validator.ts +102 -0
- package/core/agent/metadata.ts +398 -0
- package/core/agent/moduleContributions-v1.ts +113 -0
- package/core/agent/semantic.ts +903 -0
- package/core/agent/session/codec.ts +33 -0
- package/core/agent/session/contracts.ts +96 -0
- package/core/agent/session/entities.ts +84 -0
- package/core/agent/session/protector.ts +92 -0
- package/core/app/index.ts +5 -0
- package/core/app/runApp.ts +293 -0
- package/core/app/ui/index.ts +29 -0
- package/core/app/ui/uiProfileResolver.ts +966 -0
- package/core/app/ui/uiSurfaceHosting.ts +38 -0
- package/core/app/ui/uiSurfaceHttp.ts +476 -0
- package/core/background/BackgroundService.ts +223 -0
- package/core/background/backgroundModule.ts +42 -0
- package/core/background/decorator.ts +43 -0
- package/core/background/delay.ts +27 -0
- package/core/background/index.ts +15 -0
- package/core/cache/COMPATIBILITY.md +13 -0
- package/core/cache/ICache.ts +71 -0
- package/core/cache/MemoryCache.ts +394 -0
- package/core/cache/README.md +83 -0
- package/core/cache/SPEC.md +1355 -0
- package/core/cache/cacheModule.ts +21 -0
- package/core/cache/decorators/Cacheable.ts +38 -0
- package/core/cache/decorators/CacheableRedis.ts +39 -0
- package/core/cache/decorators/OutputCache.ts +33 -0
- package/core/cache/decorators/OutputRedisCache.ts +33 -0
- package/core/cache/decorators/cacheableMetadata.ts +78 -0
- package/core/cache/decorators/cacheableRedisMetadata.ts +81 -0
- package/core/cache/decorators/outputCacheMetadata.ts +71 -0
- package/core/cache/decorators/outputRedisCacheMetadata.ts +77 -0
- package/core/cache/di/classProviderHook.ts +26 -0
- package/core/cache/distributed/CacheCodec.ts +5 -0
- package/core/cache/distributed/DistributedCache.ts +403 -0
- package/core/cache/distributed/DistributedCacheDriver.ts +83 -0
- package/core/cache/distributed/DistributedCacheStores.ts +28 -0
- package/core/cache/distributed/IDistributedCache.ts +40 -0
- package/core/cache/distributed/NamedCacheRegistry.ts +23 -0
- package/core/cache/distributed/codecs.ts +32 -0
- package/core/cache/distributed/index.ts +19 -0
- package/core/cache/errors/CacheError.ts +16 -0
- package/core/cache/http/CachedHttpPayload.ts +213 -0
- package/core/cache/http/applyClientCacheHeaders.ts +61 -0
- package/core/cache/http/buildOutputCacheKey.ts +154 -0
- package/core/cache/http/buildRedisOutputCacheKey.ts +16 -0
- package/core/cache/http/composeOutputCache.ts +130 -0
- package/core/cache/http/outputCacheMiddleware.ts +111 -0
- package/core/cache/http/outputCacheSecurityWarning.ts +58 -0
- package/core/cache/http/outputRedisCacheMiddleware.ts +118 -0
- package/core/cache/index.ts +97 -0
- package/core/cache/internal/AutomaticCacheKey.ts +106 -0
- package/core/cache/internal/CacheKeyGuard.ts +56 -0
- package/core/cache/internal/buildCacheProviders.ts +146 -0
- package/core/cache/internal/normalizeCacheKey.ts +9 -0
- package/core/cache/internal/resolveCachePolicy.ts +32 -0
- package/core/cache/internal/resolveCacheableRedisPolicy.ts +17 -0
- package/core/cache/internal/resolveOutputRedisCachePolicy.ts +17 -0
- package/core/cache/providers/cachedProviders.ts +68 -0
- package/core/cache/services/cacheProxy.ts +243 -0
- package/core/cache/tokens/CACHE_POLICIES.ts +5 -0
- package/core/cache/tokens/DISTRIBUTED_CACHE.ts +30 -0
- package/core/cache/types/CacheEntry.ts +7 -0
- package/core/cache/types/CacheOptions.ts +60 -0
- package/core/cache/types/CachePolicy.ts +74 -0
- package/core/cache/types/CacheableRedisOptions.ts +23 -0
- package/core/cache/types/OutputRedisCacheOptions.ts +25 -0
- package/core/di/README.md +104 -0
- package/core/di/ServiceCollection.ts +185 -0
- package/core/di/ServiceProvider.ts +689 -0
- package/core/di/ServiceScope.ts +61 -0
- package/core/di/container.ts +38 -0
- package/core/di/errors/AmbiguousNamedDependencyError.ts +10 -0
- package/core/di/errors/AsyncResolutionRequiredError.ts +12 -0
- package/core/di/errors/CircularDependencyError.ts +10 -0
- package/core/di/errors/ClassDependenciesMismatchError.ts +15 -0
- package/core/di/errors/DiError.ts +6 -0
- package/core/di/errors/InvalidProviderError.ts +9 -0
- package/core/di/errors/ModuleEncapsulationError.ts +7 -0
- package/core/di/errors/ModuleOwnedProviderConflictError.ts +8 -0
- package/core/di/errors/NamedDependencyNotFoundError.ts +7 -0
- package/core/di/errors/OptionsValidationError.ts +7 -0
- package/core/di/errors/ProviderNotFoundError.ts +10 -0
- package/core/di/errors/ScopeDisposedError.ts +7 -0
- package/core/di/errors/ScopedServiceFromRootError.ts +9 -0
- package/core/di/errors/ServiceValidationError.ts +7 -0
- package/core/di/errors/index.ts +14 -0
- package/core/di/extensions/activator.ts +39 -0
- package/core/di/extensions/application.ts +117 -0
- package/core/di/extensions/hosted-service.ts +124 -0
- package/core/di/extensions/index.ts +23 -0
- package/core/di/extensions/options-reloadable.ts +137 -0
- package/core/di/extensions/options.ts +91 -0
- package/core/di/extensions/service-provider-token.ts +21 -0
- package/core/di/index.ts +97 -0
- package/core/di/internal/GraphValidator.ts +119 -0
- package/core/di/internal/HostedServicePlan.ts +158 -0
- package/core/di/internal/NamedTokenIndex.ts +55 -0
- package/core/di/internal/OpenGenericRegistration.ts +14 -0
- package/core/di/internal/ResolutionPlan.ts +18 -0
- package/core/di/internal/ResolutionScopeState.ts +19 -0
- package/core/di/internal/ResolutionTracker.ts +153 -0
- package/core/di/internal/ScopeLifecycle.ts +159 -0
- package/core/di/internal/ServiceRegistration.ts +14 -0
- package/core/di/internal/ServiceRegistry.ts +252 -0
- package/core/di/internal/classDeps.ts +38 -0
- package/core/di/internal/disposal.ts +58 -0
- package/core/di/internal/providerDeps.ts +26 -0
- package/core/di/module/DI.ts +146 -0
- package/core/di/module/Global.ts +25 -0
- package/core/di/module/Module.ts +44 -0
- package/core/di/module/ModuleRegistrar.ts +69 -0
- package/core/di/module/autoDeps.ts +39 -0
- package/core/di/module/classProviderHooks.ts +66 -0
- package/core/di/module/collectModuleConfigs.ts +57 -0
- package/core/di/module/collectModuleControllers.ts +53 -0
- package/core/di/module/collectModuleUiProfiles.ts +53 -0
- package/core/di/module/createContainer.ts +261 -0
- package/core/di/module/encapsulation.ts +416 -0
- package/core/di/module/encapsulationHooks.ts +36 -0
- package/core/di/module/generatedProviderAttachments.ts +102 -0
- package/core/di/module/index.ts +41 -0
- package/core/di/module/moduleExtensions.ts +35 -0
- package/core/di/module/moduleNameBinding.ts +136 -0
- package/core/di/module/moduleOwnedProviderContributors.ts +409 -0
- package/core/di/module/providerSelection.ts +90 -0
- package/core/di/module/shortcuts.ts +111 -0
- package/core/di/module/types/BazisModule.ts +71 -0
- package/core/di/module/types/DiRegistrar.ts +24 -0
- package/core/di/module/types/index.ts +2 -0
- package/core/di/provider/index.ts +26 -0
- package/core/di/provider/providerGuards.ts +17 -0
- package/core/di/provider/types/AsyncFactoryProvider.ts +15 -0
- package/core/di/provider/types/ClassProvider.ts +18 -0
- package/core/di/provider/types/FactoryProvider.ts +20 -0
- package/core/di/provider/types/KeyedDependency.ts +20 -0
- package/core/di/provider/types/LazyDependency.ts +31 -0
- package/core/di/provider/types/NamedDependency.ts +16 -0
- package/core/di/provider/types/Provider.ts +10 -0
- package/core/di/provider/types/ProviderDefinition.ts +11 -0
- package/core/di/provider/types/ProviderDependencyList.ts +11 -0
- package/core/di/provider/types/ProviderLifetime.ts +1 -0
- package/core/di/provider/types/ProviderOwnership.ts +7 -0
- package/core/di/provider/types/ResolvedDeps.ts +18 -0
- package/core/di/provider/types/ValueProvider.ts +6 -0
- package/core/di/provider/types/index.ts +13 -0
- package/core/di/token.ts +84 -0
- package/core/di/types/BuildServiceProviderOptions.ts +4 -0
- package/core/di/types/ServiceKey.ts +1 -0
- package/core/di/types/ServiceResolver.ts +16 -0
- package/core/di/types/index.ts +3 -0
- package/core/generatedFingerprint.ts +60 -0
- package/core/generatedRuntime.ts +187 -0
- package/core/grpc/Grpc.module.ts +23 -0
- package/core/grpc/GrpcBinding.contract.ts +35 -0
- package/core/grpc/GrpcCall.ts +73 -0
- package/core/grpc/GrpcClient.ts +172 -0
- package/core/grpc/GrpcClientCall.ts +267 -0
- package/core/grpc/GrpcError.ts +19 -0
- package/core/grpc/GrpcRequest.binding.ts +45 -0
- package/core/grpc/GrpcServer.ts +204 -0
- package/core/grpc/GrpcStatus.ts +8 -0
- package/core/grpc/GrpcTransport.ts +174 -0
- package/core/grpc/Metadata.ts +73 -0
- package/core/grpc/ProtoCodec.ts +225 -0
- package/core/grpc/ProtoParser.ts +192 -0
- package/core/grpc/ProtoReader.ts +34 -0
- package/core/grpc/ProtoSchema.ts +52 -0
- package/core/grpc/ServerCredentials.ts +30 -0
- package/core/grpc/clientContracts.ts +39 -0
- package/core/grpc/contracts.ts +45 -0
- package/core/grpc/decorators.ts +82 -0
- package/core/grpc/grpcClientProvider.ts +9 -0
- package/core/grpc/index.ts +17 -0
- package/core/grpc/moduleControllers.ts +38 -0
- package/core/grpc/protobuf.ts +80 -0
- package/core/grpc/serviceDefinition.ts +20 -0
- package/core/http/Authorization/Authorize.ts +52 -0
- package/core/http/Authorization/authorizeComposer.ts +31 -0
- package/core/http/Authorization/metadata.ts +158 -0
- package/core/http/Binding/ParameterBinder.ts +109 -0
- package/core/http/Binding/RequestModel.ts +27 -0
- package/core/http/Binding/autoBindings.ts +125 -0
- package/core/http/Binding/bindings.ts +19 -0
- package/core/http/Binding/convert.ts +48 -0
- package/core/http/Binding/generatedSpec.ts +18 -0
- package/core/http/Binding/listModelRegistry.ts +47 -0
- package/core/http/Binding/modelBinder.ts +345 -0
- package/core/http/Binding/modelValidator.ts +30 -0
- package/core/http/Binding/requestModelRegistry.ts +117 -0
- package/core/http/Decorators/attributes.ts +92 -0
- package/core/http/Decorators/controller.ts +24 -0
- package/core/http/Decorators/metadata.ts +107 -0
- package/core/http/Decorators/routes.ts +131 -0
- package/core/http/Errors/HttpError.ts +92 -0
- package/core/http/HttpContext/HttpContext.ts +148 -0
- package/core/http/HttpContext/ResponseBuilder.ts +37 -0
- package/core/http/HttpContext/inspectableRedirects.ts +47 -0
- package/core/http/HttpContext/principal.ts +24 -0
- package/core/http/HttpContext/responseLifetime.ts +45 -0
- package/core/http/HttpServer.ts +627 -0
- package/core/http/Middleware/accessLog.ts +90 -0
- package/core/http/Middleware/cors.ts +160 -0
- package/core/http/Middleware/errorHandler.ts +100 -0
- package/core/http/Middleware/pipeline.ts +21 -0
- package/core/http/Middleware/rateLimit.ts +104 -0
- package/core/http/Middleware/securityHeaders.ts +118 -0
- package/core/http/Middleware/types.ts +19 -0
- package/core/http/OpenApi/generatedOpenApiRegistry.ts +102 -0
- package/core/http/OpenApi/openApiDocs.ts +75 -0
- package/core/http/OpenApi/openApiDocument.ts +356 -0
- package/core/http/README.md +139 -0
- package/core/http/Results/HttpResult.ts +19 -0
- package/core/http/Results/normalize.ts +93 -0
- package/core/http/Results/results.ts +70 -0
- package/core/http/Routing/Router.ts +201 -0
- package/core/http/Routing/RouterBuilder.ts +184 -0
- package/core/http/Routing/template.ts +112 -0
- package/core/http/SPEC.md +981 -0
- package/core/http/Versioning/VersionReader.ts +20 -0
- package/core/http/WebSocketUpgrade.ts +29 -0
- package/core/http/composeRouteMiddlewareComposers.ts +21 -0
- package/core/http/correlation/createCorrelationIdMiddleware.ts +79 -0
- package/core/http/httpModule.ts +48 -0
- package/core/http/index.ts +140 -0
- package/core/http/middlewareTokens.ts +48 -0
- package/core/http/options.ts +134 -0
- package/core/http-client/index.ts +105 -0
- package/core/infra/Infra.ts +158 -0
- package/core/infra/InfraConnector.ts +86 -0
- package/core/infra/InfraLifecycle.ts +86 -0
- package/core/infra/cache/RedisDistributedCacheBackend.ts +88 -0
- package/core/infra/cache/RedisDistributedCacheDriver.ts +186 -0
- package/core/infra/cache/index.ts +7 -0
- package/core/infra/connectorConfig.ts +29 -0
- package/core/infra/connectorIdentity.ts +39 -0
- package/core/infra/connectors/codex/CodexAppServer.ts +146 -0
- package/core/infra/connectors/codex/CodexAppServerClient.ts +258 -0
- package/core/infra/connectors/codex/CodexPolicy.ts +114 -0
- package/core/infra/connectors/codex/CodexTurn.ts +133 -0
- package/core/infra/connectors/codex/contracts.ts +82 -0
- package/core/infra/connectors/codex.ts +26 -0
- package/core/infra/connectors/llm.ts +78 -0
- package/core/infra/connectors/llmRouter.ts +443 -0
- package/core/infra/connectors/openaiCompatible.ts +590 -0
- package/core/infra/connectors/openaiTextStream.ts +134 -0
- package/core/infra/connectors/opensearch.ts +307 -0
- package/core/infra/connectors/postgres.ts +105 -0
- package/core/infra/connectors/redis.ts +132 -0
- package/core/infra/index.ts +58 -0
- package/core/kernel/ApplicationLifetime.ts +91 -0
- package/core/kernel/Bazis.ts +73 -0
- package/core/kernel/Environment.ts +53 -0
- package/core/kernel/Kernel.ts +391 -0
- package/core/kernel/KernelBuilder.ts +172 -0
- package/core/kernel/LifecycleCoordinator.ts +204 -0
- package/core/kernel/README.md +66 -0
- package/core/kernel/SupervisedHostedService.ts +147 -0
- package/core/kernel/config/ConfigRegistry.ts +48 -0
- package/core/kernel/config/Configuration.ts +110 -0
- package/core/kernel/config/README.md +62 -0
- package/core/kernel/config/Secret.ts +29 -0
- package/core/kernel/config/addConfigOptions.ts +63 -0
- package/core/kernel/config/defineConfig.ts +211 -0
- package/core/kernel/config/sources.ts +123 -0
- package/core/kernel/correlation/requestContext.ts +57 -0
- package/core/kernel/errors/ConfigKeyMissingError.ts +7 -0
- package/core/kernel/errors/KernelError.ts +7 -0
- package/core/kernel/errors/ShutdownTimeoutError.ts +7 -0
- package/core/kernel/errors/StartupAbortedError.ts +7 -0
- package/core/kernel/errors/StartupTimeoutError.ts +7 -0
- package/core/kernel/errors/index.ts +5 -0
- package/core/kernel/events/EventBus.ts +140 -0
- package/core/kernel/events/EventToken.ts +17 -0
- package/core/kernel/events/eventSubscribers.ts +126 -0
- package/core/kernel/events/kernelEvents.ts +16 -0
- package/core/kernel/events/onEvent.ts +32 -0
- package/core/kernel/health/HealthCheckContracts.ts +42 -0
- package/core/kernel/health/HealthService.ts +93 -0
- package/core/kernel/index.ts +96 -0
- package/core/kernel/internal/awaitAbortable.ts +18 -0
- package/core/kernel/internal/awaitShutdown.ts +21 -0
- package/core/kernel/internal/reportDiagnosticFailure.ts +8 -0
- package/core/kernel/internal/validateTimeout.ts +8 -0
- package/core/kernel/lifecycleHooks.ts +18 -0
- package/core/kernel/logging/ConsoleLogger.ts +68 -0
- package/core/kernel/logging/Logger.ts +22 -0
- package/core/kernel/types/ConfigSource.ts +9 -0
- package/core/kernel/types/EnvironmentName.ts +1 -0
- package/core/kernel/types/KernelOptions.ts +23 -0
- package/core/kernel/types/LifecycleHook.ts +18 -0
- package/core/kernel/types/index.ts +4 -0
- package/core/orm/DATABASE_PROVIDER.ts +5 -0
- package/core/orm/OrmHostedPlan.validator.ts +55 -0
- package/core/orm/OrmLifecycle.ts +146 -0
- package/core/orm/OrmOwnedStoreLifecycle.ts +96 -0
- package/core/orm/buildOrmProviders.ts +152 -0
- package/core/orm/databaseConnector.ts +108 -0
- package/core/orm/encapsulationHook.ts +19 -0
- package/core/orm/index.ts +95 -0
- package/core/orm/listQuery.ts +198 -0
- package/core/orm/ormModule.ts +173 -0
- package/core/orm/ownedStoreContributions.ts +195 -0
- package/core/orm/registerRepositories.ts +27 -0
- package/core/orm/repository.ts +45 -0
- package/core/orm/strictSchemaHostedIdentity.ts +17 -0
- package/core/scripts/agent-codegen.ts +1166 -0
- package/core/scripts/di-generate-target.ts +90 -0
- package/core/scripts/di-generate.ts +1837 -0
- package/core/scripts/orm-predicate-codegen.ts +33 -0
- package/core/scripts/request-model-codegen.ts +326 -0
- package/core/websocket/DESIGN.md +297 -0
- package/core/websocket/WsRateLimiter.ts +101 -0
- package/core/websocket/adapter/adapter.interface.ts +45 -0
- package/core/websocket/adapter/in-memory.adapter.ts +190 -0
- package/core/websocket/adapter/redis-delivery-scripts.ts +135 -0
- package/core/websocket/adapter/redis-delivery-store.ts +86 -0
- package/core/websocket/adapter/redis-operations.ts +33 -0
- package/core/websocket/adapter/redis.adapter.ts +218 -0
- package/core/websocket/codec/binary.codec.ts +87 -0
- package/core/websocket/codec/json.codec.ts +34 -0
- package/core/websocket/codec/packet-codec.interface.ts +17 -0
- package/core/websocket/decorators.ts +165 -0
- package/core/websocket/explorer.ts +126 -0
- package/core/websocket/index.ts +78 -0
- package/core/websocket/middleware.ts +146 -0
- package/core/websocket/packet-codec.ts +75 -0
- package/core/websocket/reliable-delivery.ts +56 -0
- package/core/websocket/session-creation.ts +16 -0
- package/core/websocket/session-manager.ts +856 -0
- package/core/websocket/socket-wrapper.ts +314 -0
- package/core/websocket/topic-cache.ts +59 -0
- package/core/websocket/types.ts +122 -0
- package/core/websocket/websocketModule.ts +96 -0
- package/core/websocket/ws-dispatch.ts +123 -0
- package/core/websocket/ws-server.ts +1707 -0
- package/index.ts +281 -0
- package/library/boundary/diagnostics-v1.ts +136 -0
- package/library/boundary/index.ts +73 -0
- package/library/boundary/json/decodeBoundedJsonV1.ts +518 -0
- package/library/boundary/json/limits-v1.ts +46 -0
- package/library/boundary/json/normalizeBoundedJsonV1.ts +256 -0
- package/library/boundary/json/types-v1.ts +11 -0
- package/library/boundary/schema/boundarySchemaHashV1.ts +6 -0
- package/library/boundary/schema/collectBoundaryValueDiagnosticsV1.ts +325 -0
- package/library/boundary/schema/decodeBoundarySchemaV1.ts +646 -0
- package/library/boundary/schema/index.ts +8 -0
- package/library/boundary/schema/types-v1.ts +99 -0
- package/library/boundary/schema/validateBoundaryValueV1.ts +58 -0
- package/library/boundary/serialization/canonicalJsonV1.ts +66 -0
- package/library/http-client/HttpClient.ts +969 -0
- package/library/http-client/HttpClientFactory.ts +45 -0
- package/library/http-client/errors.ts +68 -0
- package/library/http-client/index.ts +43 -0
- package/library/http-client/interceptors.ts +40 -0
- package/library/http-client/progress.ts +62 -0
- package/library/http-client/redirectProtocol.ts +6 -0
- package/library/http-client/serialize.ts +133 -0
- package/library/http-client/types.ts +174 -0
- package/library/jsonapi/ListQueryError.ts +25 -0
- package/library/jsonapi/ListRequest.ts +37 -0
- package/library/jsonapi/decorators.ts +161 -0
- package/library/jsonapi/document.ts +124 -0
- package/library/jsonapi/index.ts +40 -0
- package/library/jsonapi/parseListQuery.ts +291 -0
- package/library/jsonapi/types.ts +125 -0
- package/library/jwt/JwtEncoder.ts +40 -0
- package/library/jwt/JwtKeyRing.ts +164 -0
- package/library/jwt/JwtValidator.ts +210 -0
- package/library/jwt/TokenIssuer.ts +149 -0
- package/library/jwt/TokenService.ts +51 -0
- package/library/jwt/base64url.ts +61 -0
- package/library/jwt/claims.ts +36 -0
- package/library/jwt/errors.ts +44 -0
- package/library/jwt/index.ts +59 -0
- package/library/jwt/limits.ts +8 -0
- package/library/jwt/signing/Hs256Algorithm.ts +62 -0
- package/library/jwt/signing/Rs256Algorithm.ts +133 -0
- package/library/jwt/signing/SigningAlgorithm.ts +18 -0
- package/library/jwt/signing/pem.ts +30 -0
- package/library/openapi/codegen.ts +875 -0
- package/library/openapi/document.ts +326 -0
- package/library/openapi/index.ts +13 -0
- package/library/openapi/types.ts +69 -0
- package/library/openapi/ui.ts +182 -0
- package/library/orm/DatabaseFacade.ts +209 -0
- package/library/orm/DbContext.ts +107 -0
- package/library/orm/DbContextFactory.ts +25 -0
- package/library/orm/DbContextOptions.ts +33 -0
- package/library/orm/Metadata/DynamicModelBuilder.ts +497 -0
- package/library/orm/Metadata/KeyTuple.ts +36 -0
- package/library/orm/Metadata/ModelBuilder.ts +299 -0
- package/library/orm/Metadata/OrmModel.ts +80 -0
- package/library/orm/Metadata/ValueConverter.ts +57 -0
- package/library/orm/Metadata/conventions.ts +54 -0
- package/library/orm/Metadata/decorators.ts +396 -0
- package/library/orm/Metadata/types.ts +140 -0
- package/library/orm/Providers/OwnedStoreCatalog.reader.ts +1802 -0
- package/library/orm/Providers/PostgresDialect.ts +234 -0
- package/library/orm/Providers/PostgresProvider.ts +1494 -0
- package/library/orm/Providers/PostgresSchema.decoder.ts +107 -0
- package/library/orm/Providers/limits.ts +29 -0
- package/library/orm/Providers/operationDeadline.ts +43 -0
- package/library/orm/Providers/ormOwnedStoreRuntime.ts +19 -0
- package/library/orm/Providers/ormTransactionRuntime.ts +117 -0
- package/library/orm/Providers/propertyConversion.ts +14 -0
- package/library/orm/Providers/resolvedForeignKey.ts +16 -0
- package/library/orm/Providers/transactionCallbacks.ts +45 -0
- package/library/orm/Providers/transactionOutcome.ts +82 -0
- package/library/orm/Providers/transactionScopes.ts +78 -0
- package/library/orm/Providers/types.ts +207 -0
- package/library/orm/Query/DbSet.ts +78 -0
- package/library/orm/Query/EntityQuery.ts +247 -0
- package/library/orm/Query/ImmediateMutations.ts +226 -0
- package/library/orm/Query/IncludeLoader.ts +200 -0
- package/library/orm/Query/QueryPlan.ts +55 -0
- package/library/orm/Query/SqlTranslator.ts +195 -0
- package/library/orm/Query/conditions.ts +127 -0
- package/library/orm/Query/materialize.ts +39 -0
- package/library/orm/README.md +256 -0
- package/library/orm/Repository/README.md +684 -0
- package/library/orm/Repository/Repository.ts +68 -0
- package/library/orm/Saving/CommandBuilder.ts +139 -0
- package/library/orm/Saving/ExecutionStrategy.ts +128 -0
- package/library/orm/Saving/SaveExecutor.ts +413 -0
- package/library/orm/Saving/applyConventions.ts +64 -0
- package/library/orm/Schema/CheckExpression.ts +327 -0
- package/library/orm/Schema/ExactSchemaVerifier.ts +168 -0
- package/library/orm/Schema/ExpectedSchema.ts +43 -0
- package/library/orm/Schema/MigrationRunner.ts +146 -0
- package/library/orm/Schema/Migrator.ts +73 -0
- package/library/orm/Schema/OrmOwnedStore.ts +123 -0
- package/library/orm/Schema/OwnedStoreAdmission.ts +752 -0
- package/library/orm/Schema/OwnedStoreCanonical.ts +273 -0
- package/library/orm/Schema/OwnedStoreCatalog.ts +1325 -0
- package/library/orm/Schema/SafeAdditiveSchema.ts +100 -0
- package/library/orm/Schema/SchemaAdmission.ts +62 -0
- package/library/orm/Schema/SchemaDiffer.ts +78 -0
- package/library/orm/Schema/formatSchemaDifferences.ts +62 -0
- package/library/orm/Schema/introspection.ts +52 -0
- package/library/orm/Schema/physicalColumnTypes.ts +37 -0
- package/library/orm/Schema/tableKey.ts +26 -0
- package/library/orm/Tracking/ChangeTracker.ts +448 -0
- package/library/orm/Tracking/EntityState.ts +13 -0
- package/library/orm/Transactions/OrmTransaction.ts +30 -0
- package/library/orm/Transactions/TransactionScopeCoordinator.ts +377 -0
- package/library/orm/errors.ts +190 -0
- package/library/orm/index.ts +162 -0
- package/library/orm/runtime.ts +14 -0
- package/library/redaction/index.ts +166 -0
- package/library/ui/UiProfile.ts +77 -0
- package/library/ui/compiled-v1.ts +131 -0
- package/library/ui/compiler/compileUiSurfaceV1.ts +717 -0
- package/library/ui/compiler/contracts-v1.ts +25 -0
- package/library/ui/compiler/index.ts +12 -0
- package/library/ui/compiler/openApiIndex.ts +246 -0
- package/library/ui/defineUiProfile.ts +340 -0
- package/library/ui/diagnostics-v1.ts +33 -0
- package/library/ui/index.ts +129 -0
- package/library/ui/profile-v1.ts +191 -0
- package/library/ui/serialization.ts +130 -0
- package/library/ui/uiProfileAuthoring.ts +289 -0
- package/library/ui/uiProfileAuthoringMetadata.ts +78 -0
- package/library/validation/MessageRegistry.ts +144 -0
- package/library/validation/README.md +62 -0
- package/library/validation/RuleCompiler.ts +183 -0
- package/library/validation/RuleEngine.ts +401 -0
- package/library/validation/SPEC.md +579 -0
- package/library/validation/ValidationError.ts +37 -0
- package/library/validation/ValidationResult.ts +63 -0
- package/library/validation/Validator.ts +101 -0
- package/library/validation/index.ts +16 -0
- package/library/validation/metadata.ts +69 -0
- package/library/validation/modelValidatorAdapter.ts +119 -0
- package/library/validation/types/ValidationCode.ts +69 -0
- package/library/validation/types/ValidatorOptions.ts +153 -0
- package/package.json +80 -0
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import { DI, Global, Module, collectModuleConfigs, createContainer, type BazisModule, type BazisModuleRef } from "../di";
|
|
2
|
+
import { isBazisModuleClass } from "../di/module/Module";
|
|
3
|
+
import { ApplicationLifetime } from "./ApplicationLifetime";
|
|
4
|
+
import { Configuration, loadConfiguration } from "./config/Configuration";
|
|
5
|
+
import { ConfigRegistry } from "./config/ConfigRegistry";
|
|
6
|
+
import { argsSource, envSource } from "./config/sources";
|
|
7
|
+
import { Environment } from "./Environment";
|
|
8
|
+
import { EventBus } from "./events/EventBus";
|
|
9
|
+
import { HealthService } from "./health/HealthService";
|
|
10
|
+
import { Kernel, type KernelTimings } from "./Kernel";
|
|
11
|
+
import { ConsoleLogger } from "./logging/ConsoleLogger";
|
|
12
|
+
import { LOGGER, type Logger } from "./logging/Logger";
|
|
13
|
+
import type { ConfigSource, EnvironmentName, KernelOptions, UnhandledErrorPolicy } from "./types";
|
|
14
|
+
import { validateTimeout } from "./internal/validateTimeout";
|
|
15
|
+
|
|
16
|
+
/** Root module or a profile factory (Spring profiles, but explicit). */
|
|
17
|
+
export type RootModuleInput = BazisModuleRef | ((environment: Environment) => BazisModuleRef);
|
|
18
|
+
|
|
19
|
+
function resolveUserRoot(rootModule: RootModuleInput, environment: Environment): BazisModuleRef {
|
|
20
|
+
if (typeof rootModule === "function") {
|
|
21
|
+
if (isBazisModuleClass(rootModule)) {
|
|
22
|
+
return rootModule as BazisModule;
|
|
23
|
+
}
|
|
24
|
+
return (rootModule as (environment: Environment) => BazisModuleRef)(environment);
|
|
25
|
+
}
|
|
26
|
+
return rootModule;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const DEFAULT_SHUTDOWN_TIMEOUT_MS = 10_000;
|
|
30
|
+
const DEFAULT_STARTUP_TIMEOUT_MS = 30_000;
|
|
31
|
+
const DEFAULT_SIGNALS: readonly NodeJS.Signals[] = ["SIGINT", "SIGTERM"];
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Mutable configuration phase (.NET HostApplicationBuilder). `build()`
|
|
35
|
+
* produces an immutable Kernel: config is loaded, the DI graph is built and
|
|
36
|
+
* validated, nothing can be registered afterwards.
|
|
37
|
+
*/
|
|
38
|
+
export class KernelBuilder {
|
|
39
|
+
private readonly configSources: ConfigSource[] = [];
|
|
40
|
+
private environmentName?: EnvironmentName;
|
|
41
|
+
private debugFlag?: boolean;
|
|
42
|
+
private shutdownTimeoutMs = DEFAULT_SHUTDOWN_TIMEOUT_MS;
|
|
43
|
+
private startupTimeoutMs = DEFAULT_STARTUP_TIMEOUT_MS;
|
|
44
|
+
private signals: readonly NodeJS.Signals[] = DEFAULT_SIGNALS;
|
|
45
|
+
private unhandledErrorPolicy: UnhandledErrorPolicy = "shutdown";
|
|
46
|
+
private validateOnBuild = true;
|
|
47
|
+
private startupReport?: boolean;
|
|
48
|
+
private logger?: Logger;
|
|
49
|
+
|
|
50
|
+
public constructor(private readonly rootModule: RootModuleInput) {}
|
|
51
|
+
|
|
52
|
+
/** Overrides the default {@link ConsoleLogger} registered under `LOGGER`. */
|
|
53
|
+
public useLogger(logger: Logger): this {
|
|
54
|
+
this.logger = logger;
|
|
55
|
+
return this;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
public useOptions(options: KernelOptions): this {
|
|
59
|
+
if (options.environment !== undefined) this.environmentName = options.environment;
|
|
60
|
+
if (options.debug !== undefined) this.debugFlag = options.debug;
|
|
61
|
+
if (options.shutdownTimeoutMs !== undefined) this.shutdownTimeoutMs = options.shutdownTimeoutMs;
|
|
62
|
+
if (options.startupTimeoutMs !== undefined) this.startupTimeoutMs = options.startupTimeoutMs;
|
|
63
|
+
if (options.signals !== undefined) this.signals = options.signals;
|
|
64
|
+
if (options.unhandledErrorPolicy !== undefined) this.unhandledErrorPolicy = options.unhandledErrorPolicy;
|
|
65
|
+
if (options.validateOnBuild !== undefined) this.validateOnBuild = options.validateOnBuild;
|
|
66
|
+
if (options.startupReport !== undefined) this.startupReport = options.startupReport;
|
|
67
|
+
return this;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
public useEnvironment(name: EnvironmentName, debug?: boolean): this {
|
|
71
|
+
this.environmentName = name;
|
|
72
|
+
if (debug !== undefined) {
|
|
73
|
+
this.debugFlag = debug;
|
|
74
|
+
}
|
|
75
|
+
return this;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
public useShutdownTimeout(timeoutMs: number): this {
|
|
79
|
+
this.shutdownTimeoutMs = timeoutMs;
|
|
80
|
+
return this;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
public useStartupTimeout(timeoutMs: number): this {
|
|
84
|
+
this.startupTimeoutMs = timeoutMs;
|
|
85
|
+
return this;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
public useSignals(signals: readonly NodeJS.Signals[]): this {
|
|
89
|
+
this.signals = signals;
|
|
90
|
+
return this;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
public useUnhandledErrorPolicy(policy: UnhandledErrorPolicy): this {
|
|
94
|
+
this.unhandledErrorPolicy = policy;
|
|
95
|
+
return this;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
public useStartupReport(enabled: boolean): this {
|
|
99
|
+
this.startupReport = enabled;
|
|
100
|
+
return this;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/** Sources are merged in registration order: later sources override earlier ones. */
|
|
104
|
+
public addConfigSource(source: ConfigSource): this {
|
|
105
|
+
this.configSources.push(source);
|
|
106
|
+
return this;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
public async build(): Promise<Kernel> {
|
|
110
|
+
validateTimeout("startupTimeoutMs", this.startupTimeoutMs);
|
|
111
|
+
validateTimeout("shutdownTimeoutMs", this.shutdownTimeoutMs);
|
|
112
|
+
const buildStartedAt = performance.now();
|
|
113
|
+
|
|
114
|
+
const environment =
|
|
115
|
+
this.environmentName !== undefined
|
|
116
|
+
? new Environment(this.environmentName, this.debugFlag ?? this.environmentName !== "production")
|
|
117
|
+
: Environment.fromProcess(this.debugFlag);
|
|
118
|
+
|
|
119
|
+
const configStartedAt = performance.now();
|
|
120
|
+
const configuration = await loadConfiguration(this.configSources.length ? this.configSources : [envSource(), argsSource()]);
|
|
121
|
+
const configMs = performance.now() - configStartedAt;
|
|
122
|
+
|
|
123
|
+
const lifetime = new ApplicationLifetime();
|
|
124
|
+
const logger = this.logger ?? new ConsoleLogger({ minLevel: environment.debug ? "debug" : "info" });
|
|
125
|
+
const userRoot = resolveUserRoot(this.rootModule, environment);
|
|
126
|
+
const configs = collectModuleConfigs([userRoot]);
|
|
127
|
+
const configRegistry = new ConfigRegistry(configs, environment.name, configuration);
|
|
128
|
+
|
|
129
|
+
// Kernel infrastructure is a global module: any user module can depend on
|
|
130
|
+
// Environment / Configuration / ApplicationLifetime / EventBus without
|
|
131
|
+
// importing anything (NestJS @Global semantics).
|
|
132
|
+
@Global()
|
|
133
|
+
@Module({
|
|
134
|
+
providers: [
|
|
135
|
+
DI.singleton(DI.valueProvider(ConfigRegistry, configRegistry)),
|
|
136
|
+
...configRegistry.providers,
|
|
137
|
+
DI.singleton(DI.valueProvider(Environment, environment)),
|
|
138
|
+
DI.singleton(DI.valueProvider(Configuration, configuration)),
|
|
139
|
+
DI.singleton(DI.valueProvider(ApplicationLifetime, lifetime)),
|
|
140
|
+
DI.singleton(DI.valueProvider(LOGGER, logger)),
|
|
141
|
+
DI.singleton(DI.factoryProviderWithResolver(EventBus, [], (resolver) => new EventBus(resolver))),
|
|
142
|
+
DI.singleton(DI.factoryProviderWithResolver(HealthService, [], (resolver) => new HealthService(resolver))),
|
|
143
|
+
],
|
|
144
|
+
})
|
|
145
|
+
class BazisKernelInfraModule {}
|
|
146
|
+
|
|
147
|
+
@Module({
|
|
148
|
+
imports: [BazisKernelInfraModule, userRoot],
|
|
149
|
+
})
|
|
150
|
+
class BazisKernelModule {}
|
|
151
|
+
|
|
152
|
+
const kernelRootModule = BazisKernelModule;
|
|
153
|
+
|
|
154
|
+
const containerStartedAt = performance.now();
|
|
155
|
+
const container = createContainer(kernelRootModule, { validateOnBuild: this.validateOnBuild });
|
|
156
|
+
const containerMs = performance.now() - containerStartedAt;
|
|
157
|
+
|
|
158
|
+
const timings: KernelTimings = {
|
|
159
|
+
configMs,
|
|
160
|
+
containerMs,
|
|
161
|
+
buildStartedAt,
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
return new Kernel(container, environment, configuration, lifetime, timings, {
|
|
165
|
+
startupTimeoutMs: this.startupTimeoutMs,
|
|
166
|
+
shutdownTimeoutMs: this.shutdownTimeoutMs,
|
|
167
|
+
signals: this.signals,
|
|
168
|
+
unhandledErrorPolicy: this.unhandledErrorPolicy,
|
|
169
|
+
startupReport: this.startupReport ?? !environment.isProduction,
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
}
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
import { validateOptionsOnStart, type HostedService } from "../di";
|
|
2
|
+
import type { Token } from "../di";
|
|
3
|
+
import { LIFECYCLE_HOOK } from "./lifecycleHooks";
|
|
4
|
+
import type { LifecycleHook } from "./types";
|
|
5
|
+
import { ShutdownTimeoutError } from "./errors";
|
|
6
|
+
import { awaitAbortable } from "./internal/awaitAbortable";
|
|
7
|
+
import { resolveHostedServices, validateHostedServicePlan } from "../di/extensions/hosted-service";
|
|
8
|
+
import { awaitShutdown } from "./internal/awaitShutdown";
|
|
9
|
+
|
|
10
|
+
interface LifecycleResolver {
|
|
11
|
+
resolveAll<T>(token: Token<T>): readonly T[];
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Orchestrates the boot/shutdown sequence:
|
|
16
|
+
* options fail-fast -> onInit hooks -> hosted services by ascending phase ->
|
|
17
|
+
* onBootstrap hooks; shutdown runs everything in reverse. A failed start rolls
|
|
18
|
+
* back already-started services. The overall shutdown time budget is owned by
|
|
19
|
+
* the {@link Kernel}, which bounds the whole graceful-stop sequence.
|
|
20
|
+
*/
|
|
21
|
+
export class LifecycleCoordinator {
|
|
22
|
+
private hooks: readonly LifecycleHook[] = [];
|
|
23
|
+
/** Hosted services in actual start order (stop iterates in reverse). */
|
|
24
|
+
private readonly started: HostedService[] = [];
|
|
25
|
+
private hostedCount = 0;
|
|
26
|
+
private hookWork?: Promise<void>;
|
|
27
|
+
private rollbackWork?: Promise<void>;
|
|
28
|
+
private rollbackError?: unknown;
|
|
29
|
+
private rollbackStartedAt?: number;
|
|
30
|
+
|
|
31
|
+
public constructor(private readonly resolver: LifecycleResolver) {}
|
|
32
|
+
|
|
33
|
+
public get startedHostedCount(): number {
|
|
34
|
+
return this.hostedCount;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
public get hookCount(): number {
|
|
38
|
+
return this.hooks.length;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** @internal The host must join actual cleanup before disposing hook dependencies. */
|
|
42
|
+
public waitForRollback(): Promise<void> {
|
|
43
|
+
return this.rollbackWork ?? Promise.resolve();
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** @internal Completed rollback failure, distinct from a deadline ending observation. */
|
|
47
|
+
public get rollbackFailure(): unknown {
|
|
48
|
+
return this.rollbackError;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** @internal Container disposal uses the remaining part of the same deadline. */
|
|
52
|
+
public get rollbackElapsedMs(): number {
|
|
53
|
+
return this.rollbackStartedAt === undefined ? 0 : performance.now() - this.rollbackStartedAt;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
public async start(signal?: AbortSignal, rollbackTimeoutMs = 0): Promise<void> {
|
|
57
|
+
signal?.throwIfAborted();
|
|
58
|
+
validateOptionsOnStart(this.resolver);
|
|
59
|
+
const hosted = resolveHostedServices(this.resolver);
|
|
60
|
+
const validation = validateHostedServicePlan(hosted, signal);
|
|
61
|
+
if (validation) await awaitAbortable(validation, signal);
|
|
62
|
+
this.hooks = this.resolver.resolveAll(LIFECYCLE_HOOK);
|
|
63
|
+
|
|
64
|
+
try {
|
|
65
|
+
for (let index = 0; index < this.hooks.length; index += 1) {
|
|
66
|
+
await this.invokeHook(() => (this.hooks[index] as LifecycleHook).onInit?.(), signal);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const phases = groupByPhase(hosted);
|
|
70
|
+
for (let phaseIndex = 0; phaseIndex < phases.length; phaseIndex += 1) {
|
|
71
|
+
const group = phases[phaseIndex] as HostedService[];
|
|
72
|
+
for (let index = 0; index < group.length; index += 1) {
|
|
73
|
+
const service = group[index] as HostedService;
|
|
74
|
+
const starting = Promise.resolve().then(() => {
|
|
75
|
+
signal?.throwIfAborted();
|
|
76
|
+
return service.start(signal);
|
|
77
|
+
});
|
|
78
|
+
try {
|
|
79
|
+
await awaitAbortable(starting, signal);
|
|
80
|
+
} catch (error) {
|
|
81
|
+
if (signal?.aborted) {
|
|
82
|
+
// A legacy service may ignore the signal and finish after startup
|
|
83
|
+
// has already been cancelled. Observe it and stop it immediately
|
|
84
|
+
// so the late listener/connection cannot escape rollback.
|
|
85
|
+
void starting.then(() => service.stop()).catch(() => undefined);
|
|
86
|
+
}
|
|
87
|
+
throw error;
|
|
88
|
+
}
|
|
89
|
+
this.started.push(service);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
this.hostedCount = this.started.length;
|
|
93
|
+
|
|
94
|
+
for (let index = 0; index < this.hooks.length; index += 1) {
|
|
95
|
+
await this.invokeHook(() => (this.hooks[index] as LifecycleHook).onBootstrap?.(), signal);
|
|
96
|
+
}
|
|
97
|
+
} catch (error) {
|
|
98
|
+
try {
|
|
99
|
+
this.rollbackStartedAt = performance.now();
|
|
100
|
+
this.rollbackWork = this.rollbackStart(error);
|
|
101
|
+
await awaitShutdown(this.rollbackWork, rollbackTimeoutMs);
|
|
102
|
+
} catch (cleanupError) {
|
|
103
|
+
if (cleanupError instanceof ShutdownTimeoutError) {
|
|
104
|
+
cleanupError.cause = error;
|
|
105
|
+
throw cleanupError;
|
|
106
|
+
}
|
|
107
|
+
throw new AggregateError([error, cleanupError], "Startup failed and rollback also failed.", { cause: error });
|
|
108
|
+
}
|
|
109
|
+
throw error;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
private invokeHook(callback: () => void | Promise<void>, signal?: AbortSignal): Promise<void> {
|
|
114
|
+
this.hookWork = Promise.resolve().then(() => {
|
|
115
|
+
signal?.throwIfAborted();
|
|
116
|
+
return callback();
|
|
117
|
+
});
|
|
118
|
+
return awaitAbortable(this.hookWork, signal);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Stops hosted services (reverse start order), then runs `onShutdown` and
|
|
123
|
+
* `onDestroy` hooks (reverse). Unbounded by design — the Kernel races the
|
|
124
|
+
* whole shutdown sequence against the configured timeout.
|
|
125
|
+
*/
|
|
126
|
+
public async stopServices(signal?: string): Promise<void> {
|
|
127
|
+
const errors: unknown[] = [];
|
|
128
|
+
|
|
129
|
+
for (let index = this.started.length - 1; index >= 0; index -= 1) {
|
|
130
|
+
try {
|
|
131
|
+
await (this.started[index] as HostedService).stop();
|
|
132
|
+
} catch (error) {
|
|
133
|
+
errors.push(error);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
this.started.length = 0;
|
|
137
|
+
|
|
138
|
+
for (let index = this.hooks.length - 1; index >= 0; index -= 1) {
|
|
139
|
+
try {
|
|
140
|
+
await (this.hooks[index] as LifecycleHook).onShutdown?.(signal);
|
|
141
|
+
} catch (error) {
|
|
142
|
+
errors.push(error);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
for (let index = this.hooks.length - 1; index >= 0; index -= 1) {
|
|
146
|
+
try {
|
|
147
|
+
await (this.hooks[index] as LifecycleHook).onDestroy?.();
|
|
148
|
+
} catch (error) {
|
|
149
|
+
errors.push(error);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
if (errors.length === 1) {
|
|
154
|
+
throw errors[0];
|
|
155
|
+
}
|
|
156
|
+
if (errors.length > 1) {
|
|
157
|
+
throw new AggregateError(errors, "Shutdown finished with errors.");
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// The deadline bounds the caller, not this work. An in-flight hook may still
|
|
162
|
+
// acquire resources and use hosted services: join it before tearing them down.
|
|
163
|
+
private async rollbackStart(startError: unknown): Promise<void> {
|
|
164
|
+
const errors: unknown[] = [];
|
|
165
|
+
try { await this.hookWork; }
|
|
166
|
+
catch (error) { if (error !== startError) errors.push(error); }
|
|
167
|
+
for (let index = this.started.length - 1; index >= 0; index -= 1) {
|
|
168
|
+
try {
|
|
169
|
+
await (this.started[index] as HostedService).stop();
|
|
170
|
+
} catch (error) {
|
|
171
|
+
errors.push(error);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
this.started.length = 0;
|
|
175
|
+
this.hostedCount = 0;
|
|
176
|
+
for (let index = this.hooks.length - 1; index >= 0; index -= 1) {
|
|
177
|
+
try {
|
|
178
|
+
await (this.hooks[index] as LifecycleHook).onDestroy?.();
|
|
179
|
+
} catch (error) {
|
|
180
|
+
errors.push(error);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
if (errors.length > 0) {
|
|
184
|
+
this.rollbackError = new AggregateError(errors, "Startup rollback failed.");
|
|
185
|
+
throw this.rollbackError;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/** Groups by ascending `phase` (default 0), keeping registration order inside a group. */
|
|
191
|
+
function groupByPhase(services: readonly HostedService[]): HostedService[][] {
|
|
192
|
+
const byPhase = new Map<number, HostedService[]>();
|
|
193
|
+
for (let index = 0; index < services.length; index += 1) {
|
|
194
|
+
const service = services[index] as HostedService;
|
|
195
|
+
const phase = service.phase ?? 0;
|
|
196
|
+
const group = byPhase.get(phase);
|
|
197
|
+
if (group) {
|
|
198
|
+
group.push(service);
|
|
199
|
+
} else {
|
|
200
|
+
byPhase.set(phase, [service]);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
return [...byPhase.entries()].sort((a, b) => a[0] - b[0]).map((entry) => entry[1]);
|
|
204
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# Kernel Folder Map
|
|
2
|
+
|
|
3
|
+
The bazis Application/Kernel layer: one application lifecycle on top of DI.
|
|
4
|
+
Borrowed practices: .NET Generic Host (two-phase builder, lifetime, shutdown timeout),
|
|
5
|
+
Spring (startup phases, events, profiles), Symfony (explicit Kernel, module config schema),
|
|
6
|
+
NestJS (granular lifecycle hooks, global modules), all without reflection and AOT-compatible.
|
|
7
|
+
|
|
8
|
+
Contracts of the lifecycle and configuration fixes: [partial passport](MODULE.md).
|
|
9
|
+
|
|
10
|
+
## Entry point
|
|
11
|
+
|
|
12
|
+
- `Bazis.ts`: the facade: the `Bazis.run(AppModule)` one-liner and `Bazis.createBuilder(...)` for fine tuning.
|
|
13
|
+
- `KernelBuilder.ts`: the mutable configuration phase; `build()` returns an immutable `Kernel`.
|
|
14
|
+
- `Kernel.ts`: the kernel: `start()/stop()/run()` with one shared operation for repeated calls, signals, unhandled errors, exit codes, startup report. The startup deadline also covers started callbacks and events.
|
|
15
|
+
|
|
16
|
+
## Lifecycle
|
|
17
|
+
|
|
18
|
+
- `LifecycleCoordinator.ts`: boot/shutdown order: options fail-fast → `onInit` → hosted services by phase → `onBootstrap`; shutdown in reverse order with `shutdownTimeout`; rollback when startup fails.
|
|
19
|
+
- `ApplicationLifetime.ts`: injectable lifetime: `onStarted/onStopping/onStopped` + programmatic `stop(exitCode)`.
|
|
20
|
+
- `lifecycleHooks.ts`: the `LIFECYCLE_HOOK` token (enumerable) + `addLifecycleHook`.
|
|
21
|
+
- `Environment.ts`: the environment (`development|production|test`) from `BAZIS_ENV`/`NODE_ENV`, the `debug` flag.
|
|
22
|
+
- `SupervisedHostedService.ts`: retry with exponential backoff; passes the startup signal and stops retrying on cancellation.
|
|
23
|
+
- `logging/ConsoleLogger.ts`: the standard structured logger; fields are
|
|
24
|
+
redacted through `bazis/library/redaction` by default. Raw fields are
|
|
25
|
+
allowed only with an explicit `redaction: false` for trusted local
|
|
26
|
+
diagnostics.
|
|
27
|
+
|
|
28
|
+
## Configuration (`config/`)
|
|
29
|
+
|
|
30
|
+
- `Configuration.ts`: an own snapshot of the flat config (`db.host` → string), typed getters, `loadConfiguration`.
|
|
31
|
+
- `defineConfig.ts`: an immutable declaration with environment overrides, a separate `resolve(environment?, configuration?)` and the `token` DI token. One declaration is used in several kernels.
|
|
32
|
+
- `ConfigRegistry.ts`: one validated view of a declaration per kernel; `get(definition)` returns the same object as DI by `definition.token`.
|
|
33
|
+
- `sources.ts`: sources: `memorySource`, `envSource` (`BAZIS_DB__HOST` → `db.host`), `argsSource` (`--db.host=x`), `jsonFileSource` (a file next to the binary).
|
|
34
|
+
- `addConfigOptions.ts`: `configOptions(token, { bind, validate })`: validated module options read from `Configuration`; the kernel validates them all at startup with one error.
|
|
35
|
+
- `Secret.ts`: a secret with redaction: `toString/toJSON/inspect` print `***`, the value is available only through `reveal()`.
|
|
36
|
+
|
|
37
|
+
The [per-kernel configuration architecture](../../../../docs/architecture/MODULE_ARCHITECTURE.md#kernel-config-isolation)
|
|
38
|
+
is implemented: the declaration is shared and immutable, while the environment and
|
|
39
|
+
the computed values belong to each kernel. The temporary ban on reusing a declaration
|
|
40
|
+
is lifted. A declaration's direct `get/has` are meant for standalone code; `ensureValid`
|
|
41
|
+
no longer switches their environment. Contracts and checks are in the
|
|
42
|
+
[passport](MODULE.md#config-isolation-decision) and the [config description](config/README.md).
|
|
43
|
+
|
|
44
|
+
## Events (`events/`)
|
|
45
|
+
|
|
46
|
+
- `EventToken.ts`: typed events without reflection (`createEventToken<T>`).
|
|
47
|
+
- `EventBus.ts`: a bus on top of DI (`resolveAllKeyed`); handler errors are aggregated. An optional `signal` stops waiting and stops starting the remaining handlers, including the `isolate` mode. User code that is already running stays responsible for its effects.
|
|
48
|
+
- `onEvent.ts`: subscription from a module (`providers: [onEvent(EVT, handler)]`) or a collection.
|
|
49
|
+
- `kernelEvents.ts`: `APPLICATION_STARTED`, `APPLICATION_STOPPING`.
|
|
50
|
+
|
|
51
|
+
## Health (`health/`)
|
|
52
|
+
|
|
53
|
+
- `HealthCheckContracts.ts`: the `HEALTH_CHECK` token (enumerable), report types.
|
|
54
|
+
- `HealthService.ts`: the aggregator: a failed check is marked unhealthy without failing the report; `kernel.health()`.
|
|
55
|
+
|
|
56
|
+
## Errors (`errors/`)
|
|
57
|
+
|
|
58
|
+
- `KernelError` (base), `StartupAbortedError`, `StartupTimeoutError`, `ShutdownTimeoutError`, `ConfigKeyMissingError`. When cleanup after a failed start times out, `ShutdownTimeoutError.cause` keeps the original error.
|
|
59
|
+
|
|
60
|
+
## Principles
|
|
61
|
+
|
|
62
|
+
- Two-phase: nothing can be registered after `build()`.
|
|
63
|
+
- Kernel infrastructure (`Environment`, `Configuration`, `ApplicationLifetime`, `EventBus`, `HealthService`) is a global module: any module gets it without an import.
|
|
64
|
+
- No reflection and no dynamic import; the config lives outside the binary.
|
|
65
|
+
- The kernel works only at startup/shutdown; there are no runtime hot paths in it.
|
|
66
|
+
- External code imports the kernel through `bazis/core/kernel`.
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import type { HostedService, HostedServicePlanValidator } from "../di";
|
|
2
|
+
import { validateHostedServicePlan, registerHostedServiceWrapper, type HostedServicePlanAdmission } from "../di/extensions/hosted-service";
|
|
3
|
+
import { awaitAbortable } from "./internal/awaitAbortable";
|
|
4
|
+
import { reportDiagnosticFailure } from "./internal/reportDiagnosticFailure";
|
|
5
|
+
|
|
6
|
+
export interface RestartPolicy {
|
|
7
|
+
/** Total start attempts, including the first one. Default: 3. */
|
|
8
|
+
readonly maxAttempts?: number;
|
|
9
|
+
/** Initial pause before a retry; doubles each attempt. Default: 100ms. */
|
|
10
|
+
readonly backoffMs?: number;
|
|
11
|
+
/** Backoff cap. Default: 5000ms. */
|
|
12
|
+
readonly maxBackoffMs?: number;
|
|
13
|
+
/** Startup phase override; defaults to the concrete service's phase. */
|
|
14
|
+
readonly phase?: number;
|
|
15
|
+
/** Diagnostic notification before a retry; throws/returned rejections cannot stop recovery. */
|
|
16
|
+
readonly onRetry?: (attempt: number, error: unknown) => void;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Restart-with-backoff supervisor for hosted service startup: a transient
|
|
21
|
+
* start failure (DB not up yet, port busy) retries with exponential backoff
|
|
22
|
+
* instead of killing the whole application.
|
|
23
|
+
* The factory only constructs a service: hosts call it during plan admission.
|
|
24
|
+
* Validators see the complete plan of real service instances before startup.
|
|
25
|
+
*/
|
|
26
|
+
export class SupervisedHostedService implements HostedService {
|
|
27
|
+
public get phase(): number { return this.admittedPhase ?? this.policy.phase ?? 0; }
|
|
28
|
+
public readonly planValidator: HostedServicePlanValidator = {
|
|
29
|
+
validate: (plan, signal) => validateHostedServicePlan(plan, signal),
|
|
30
|
+
};
|
|
31
|
+
private inner?: HostedService;
|
|
32
|
+
private prepared?: HostedService;
|
|
33
|
+
private admission?: HostedServicePlanAdmission;
|
|
34
|
+
private admittedPhase?: number;
|
|
35
|
+
private starting?: Promise<void>;
|
|
36
|
+
private stopping?: Promise<void>;
|
|
37
|
+
|
|
38
|
+
public constructor(
|
|
39
|
+
private readonly factory: () => HostedService,
|
|
40
|
+
private readonly policy: RestartPolicy = {},
|
|
41
|
+
) {
|
|
42
|
+
registerHostedServiceWrapper(this, {
|
|
43
|
+
explicitPhase: policy.phase,
|
|
44
|
+
prepare: () => this.inner ?? (this.prepared ??= this.factory()),
|
|
45
|
+
bind: admission => { this.admission = admission; this.admittedPhase = admission.phase; },
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
public start(signal?: AbortSignal): Promise<void> {
|
|
50
|
+
if (this.stopping) {
|
|
51
|
+
const stopping = this.stopping;
|
|
52
|
+
return stopping.then(() => {
|
|
53
|
+
if (this.stopping === stopping) this.stopping = undefined;
|
|
54
|
+
return this.start(signal);
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
return this.starting ??= Promise.resolve().then(() => this.startAttempts(signal));
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
private async startAttempts(signal?: AbortSignal): Promise<void> {
|
|
61
|
+
signal?.throwIfAborted();
|
|
62
|
+
if (!this.admission) await validateHostedServicePlan([this], signal);
|
|
63
|
+
signal?.throwIfAborted();
|
|
64
|
+
const maxAttempts = Math.max(1, this.policy.maxAttempts ?? 3);
|
|
65
|
+
const initialBackoff = this.policy.backoffMs ?? 100;
|
|
66
|
+
const maxBackoff = this.policy.maxBackoffMs ?? 5_000;
|
|
67
|
+
|
|
68
|
+
for (let attempt = 1; ; attempt += 1) {
|
|
69
|
+
signal?.throwIfAborted();
|
|
70
|
+
const service = this.prepared!;
|
|
71
|
+
this.prepared = undefined;
|
|
72
|
+
try {
|
|
73
|
+
signal?.throwIfAborted();
|
|
74
|
+
await service.start(signal);
|
|
75
|
+
signal?.throwIfAborted();
|
|
76
|
+
this.inner = service;
|
|
77
|
+
return;
|
|
78
|
+
} catch (error) {
|
|
79
|
+
try {
|
|
80
|
+
await service.stop();
|
|
81
|
+
} catch (cleanupError) {
|
|
82
|
+
this.inner = service;
|
|
83
|
+
throw new SupervisedCleanupError(error, cleanupError);
|
|
84
|
+
}
|
|
85
|
+
signal?.throwIfAborted();
|
|
86
|
+
if (error instanceof SupervisedCleanupError) throw error;
|
|
87
|
+
if (attempt >= maxAttempts) {
|
|
88
|
+
throw error;
|
|
89
|
+
}
|
|
90
|
+
this.notifyRetry(attempt, error);
|
|
91
|
+
const backoff = Math.min(initialBackoff * 2 ** (attempt - 1), maxBackoff);
|
|
92
|
+
await waitForRetry(backoff, signal);
|
|
93
|
+
signal?.throwIfAborted();
|
|
94
|
+
// Construction and admission errors are configuration failures, not
|
|
95
|
+
// another started attempt. Never retry an unvalidated replacement.
|
|
96
|
+
const candidate = this.factory();
|
|
97
|
+
await this.admission!.replace(candidate, signal);
|
|
98
|
+
signal?.throwIfAborted();
|
|
99
|
+
this.prepared = candidate;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
private notifyRetry(attempt: number, error: unknown): void {
|
|
105
|
+
try {
|
|
106
|
+
void Promise.resolve(this.policy.onRetry?.(attempt, error))
|
|
107
|
+
.catch(() => reportDiagnosticFailure("supervised.onRetry"));
|
|
108
|
+
} catch {
|
|
109
|
+
reportDiagnosticFailure("supervised.onRetry");
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
public stop(): Promise<void> {
|
|
114
|
+
return this.stopping ??= this.stopInner();
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
private async stopInner(): Promise<void> {
|
|
118
|
+
await this.starting?.catch(() => {});
|
|
119
|
+
if (this.inner) {
|
|
120
|
+
await this.inner.stop();
|
|
121
|
+
this.inner = undefined;
|
|
122
|
+
}
|
|
123
|
+
this.prepared = undefined;
|
|
124
|
+
this.admission = undefined;
|
|
125
|
+
this.starting = undefined;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
class SupervisedCleanupError extends AggregateError {
|
|
130
|
+
public constructor(startError: unknown, cleanupError: unknown) {
|
|
131
|
+
super([startError, cleanupError], "Supervised service startup and cleanup failed; retry is unsafe.", { cause: startError });
|
|
132
|
+
this.name = "SupervisedCleanupError";
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
async function waitForRetry(backoffMs: number, signal?: AbortSignal): Promise<void> {
|
|
137
|
+
signal?.throwIfAborted();
|
|
138
|
+
let timer: ReturnType<typeof setTimeout> | undefined;
|
|
139
|
+
try {
|
|
140
|
+
await awaitAbortable(new Promise<void>(resolve => { timer = setTimeout(resolve, backoffMs); }), signal);
|
|
141
|
+
} finally { if (timer !== undefined) clearTimeout(timer); }
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/** Sugar for `addHostedService(services, supervised(() => new Worker(), { ... }))`. */
|
|
145
|
+
export function supervised(factory: () => HostedService, policy?: RestartPolicy): () => HostedService {
|
|
146
|
+
return () => new SupervisedHostedService(factory, policy);
|
|
147
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { DI, type ProviderDefinition } from "../../di";
|
|
2
|
+
import { KernelError } from "../errors";
|
|
3
|
+
import type { EnvironmentName } from "../types";
|
|
4
|
+
import type { Configuration } from "./Configuration";
|
|
5
|
+
import { isConfigDefinition, type AppConfig, type ConfigDefinition, type ConfigInspection, type ConfigView, type ValidatableConfig } from "./defineConfig";
|
|
6
|
+
|
|
7
|
+
/** One immutable set of resolved module configurations per kernel. */
|
|
8
|
+
export class ConfigRegistry {
|
|
9
|
+
private readonly views = new Map<ValidatableConfig, AppConfig<object>>();
|
|
10
|
+
public readonly providers: readonly ProviderDefinition[];
|
|
11
|
+
|
|
12
|
+
public constructor(configs: readonly ValidatableConfig[], environment: EnvironmentName, source: Configuration) {
|
|
13
|
+
const providers: ProviderDefinition[] = [];
|
|
14
|
+
const issues: string[] = [];
|
|
15
|
+
const errors: unknown[] = [];
|
|
16
|
+
for (const config of new Set(configs)) {
|
|
17
|
+
try {
|
|
18
|
+
if (isConfigDefinition(config)) {
|
|
19
|
+
const view = config.resolve(environment, source);
|
|
20
|
+
this.views.set(config, view);
|
|
21
|
+
providers.push(DI.singleton(DI.valueProvider(config.token, view)));
|
|
22
|
+
} else {
|
|
23
|
+
const view = config.resolve?.(environment, source) ?? config;
|
|
24
|
+
view.ensureValid(environment);
|
|
25
|
+
this.views.set(config, view as AppConfig<object>);
|
|
26
|
+
}
|
|
27
|
+
} catch (error) {
|
|
28
|
+
errors.push(error);
|
|
29
|
+
issues.push(error instanceof Error ? error.message : "Configuration validation failed.");
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
if (errors.length === 1) throw errors[0];
|
|
33
|
+
if (errors.length > 1) throw new AggregateError(errors, `Configuration validation failed:\n${issues.join("\n")}`);
|
|
34
|
+
this.providers = Object.freeze(providers);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
public get<T extends object>(config: ConfigDefinition<T>): ConfigView<T>;
|
|
38
|
+
public get<T extends object>(config: AppConfig<T>): AppConfig<T>;
|
|
39
|
+
public get<T extends object>(config: AppConfig<T>): AppConfig<T> {
|
|
40
|
+
const view = this.views.get(config);
|
|
41
|
+
if (view === undefined) throw new KernelError("Configuration was not declared in this kernel's module graph.");
|
|
42
|
+
return view as AppConfig<T>;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
public inspect(): readonly ConfigInspection[] {
|
|
46
|
+
return Object.freeze([...this.views.values()].flatMap(view => "inspect" in view ? (view as ConfigView<object>).inspect() : []));
|
|
47
|
+
}
|
|
48
|
+
}
|