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,68 @@
|
|
|
1
|
+
import { redactSensitive, type SensitiveRedactionOptions } from "../../../library/redaction";
|
|
2
|
+
import type { LogFields, LogLevel, Logger } from "./Logger";
|
|
3
|
+
|
|
4
|
+
const LEVEL_ORDER: Record<LogLevel, number> = { debug: 0, info: 1, warn: 2, error: 3 };
|
|
5
|
+
|
|
6
|
+
const LEVEL_SINK: Record<LogLevel, (message: string) => void> = {
|
|
7
|
+
debug: (m) => console.debug(m),
|
|
8
|
+
info: (m) => console.info(m),
|
|
9
|
+
warn: (m) => console.warn(m),
|
|
10
|
+
error: (m) => console.error(m),
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export interface ConsoleLoggerOptions {
|
|
14
|
+
/** Minimum level emitted. Default: "info". */
|
|
15
|
+
readonly minLevel?: LogLevel;
|
|
16
|
+
/** Prefix tag, e.g. the app name. */
|
|
17
|
+
readonly name?: string;
|
|
18
|
+
/** Structured fields are redacted by default; pass false only for trusted local debugging. */
|
|
19
|
+
readonly redaction?: SensitiveRedactionOptions | false;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function formatFields(fields: LogFields | undefined, redaction: SensitiveRedactionOptions | false): string {
|
|
23
|
+
if (!fields) {
|
|
24
|
+
return "";
|
|
25
|
+
}
|
|
26
|
+
try {
|
|
27
|
+
if (Object.keys(fields).length === 0) return "";
|
|
28
|
+
return ` ${JSON.stringify(redaction === false ? fields : redactSensitive(fields, redaction))}`;
|
|
29
|
+
} catch {
|
|
30
|
+
return " [Unserializable log fields]";
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** Default {@link Logger}: single-line, level-filtered output to the console. */
|
|
35
|
+
export class ConsoleLogger implements Logger {
|
|
36
|
+
private readonly threshold: number;
|
|
37
|
+
private readonly prefix: string;
|
|
38
|
+
private readonly redaction: SensitiveRedactionOptions | false;
|
|
39
|
+
|
|
40
|
+
public constructor(options: ConsoleLoggerOptions = {}) {
|
|
41
|
+
this.threshold = LEVEL_ORDER[options.minLevel ?? "info"];
|
|
42
|
+
this.prefix = options.name ? `[${options.name}] ` : "";
|
|
43
|
+
this.redaction = options.redaction ?? {};
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
public debug(message: string, fields?: LogFields): void {
|
|
47
|
+
this.write("debug", message, fields);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
public info(message: string, fields?: LogFields): void {
|
|
51
|
+
this.write("info", message, fields);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
public warn(message: string, fields?: LogFields): void {
|
|
55
|
+
this.write("warn", message, fields);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
public error(message: string, fields?: LogFields): void {
|
|
59
|
+
this.write("error", message, fields);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
private write(level: LogLevel, message: string, fields?: LogFields): void {
|
|
63
|
+
if (LEVEL_ORDER[level] < this.threshold) {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
LEVEL_SINK[level](`${this.prefix}${level}: ${message}${formatFields(fields, this.redaction)}`);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { createToken } from "../../di";
|
|
2
|
+
|
|
3
|
+
export type LogLevel = "debug" | "info" | "warn" | "error";
|
|
4
|
+
|
|
5
|
+
/** Structured context attached to a log line. */
|
|
6
|
+
export interface LogFields {
|
|
7
|
+
readonly [key: string]: unknown;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Minimal structured logging port. Inject via {@link LOGGER}; the kernel
|
|
12
|
+
* registers a {@link ConsoleLogger} by default (override with
|
|
13
|
+
* `Bazis.createBuilder(...).useLogger(...)`).
|
|
14
|
+
*/
|
|
15
|
+
export interface Logger {
|
|
16
|
+
debug(message: string, fields?: LogFields): void;
|
|
17
|
+
info(message: string, fields?: LogFields): void;
|
|
18
|
+
warn(message: string, fields?: LogFields): void;
|
|
19
|
+
error(message: string, fields?: LogFields): void;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export const LOGGER = createToken<Logger>("Logger");
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A configuration source produces a flat map of dot-separated keys to string
|
|
3
|
+
* values (e.g. "db.host" -> "localhost"). Later sources override earlier ones.
|
|
4
|
+
*/
|
|
5
|
+
export interface ConfigSource {
|
|
6
|
+
/** Shown in diagnostics and error messages. */
|
|
7
|
+
readonly description: string;
|
|
8
|
+
load(): Record<string, string> | Promise<Record<string, string>>;
|
|
9
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export type EnvironmentName = "development" | "production" | "test";
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { EnvironmentName } from "./EnvironmentName";
|
|
2
|
+
|
|
3
|
+
/** What the kernel does with unhandledRejection / uncaughtException. */
|
|
4
|
+
export type UnhandledErrorPolicy = "shutdown" | "none";
|
|
5
|
+
|
|
6
|
+
export interface KernelOptions {
|
|
7
|
+
/** Overrides BAZIS_ENV / NODE_ENV detection. */
|
|
8
|
+
readonly environment?: EnvironmentName;
|
|
9
|
+
/** Overrides the debug flag (default: true everywhere except production). */
|
|
10
|
+
readonly debug?: boolean;
|
|
11
|
+
/** Graceful shutdown budget: integer 0..2147483647ms. Default: 10000ms; 0 disables the limit. */
|
|
12
|
+
readonly shutdownTimeoutMs?: number;
|
|
13
|
+
/** Whole startup budget, including notifications: integer 0..2147483647ms. Default: 30000ms; 0 disables the limit. */
|
|
14
|
+
readonly startupTimeoutMs?: number;
|
|
15
|
+
/** Signals that trigger graceful shutdown. Default: SIGINT, SIGTERM. The built kernel snapshots unique values. */
|
|
16
|
+
readonly signals?: readonly NodeJS.Signals[];
|
|
17
|
+
/** Default: "shutdown" — an unhandled error triggers graceful stop with exit code 1. */
|
|
18
|
+
readonly unhandledErrorPolicy?: UnhandledErrorPolicy;
|
|
19
|
+
/** Default: true — the DI graph is fully validated at build. */
|
|
20
|
+
readonly validateOnBuild?: boolean;
|
|
21
|
+
/** Startup report in the console. Default: only outside production. */
|
|
22
|
+
readonly startupReport?: boolean;
|
|
23
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Granular lifecycle hooks (NestJS-style), discovered without reflection:
|
|
3
|
+
* register implementations under the LIFECYCLE_HOOK token (enumerable).
|
|
4
|
+
*
|
|
5
|
+
* Order: hooks run in module registration order (imports are loaded before
|
|
6
|
+
* the importing module, so the order is topological by the import graph).
|
|
7
|
+
* Shutdown hooks run in reverse.
|
|
8
|
+
*/
|
|
9
|
+
export interface LifecycleHook {
|
|
10
|
+
/** Before hosted services start (resources, caches, migrations). */
|
|
11
|
+
onInit?(): void | Promise<void>;
|
|
12
|
+
/** After every hosted service has started. */
|
|
13
|
+
onBootstrap?(): void | Promise<void>;
|
|
14
|
+
/** Graceful shutdown began; hosted services are already stopped. */
|
|
15
|
+
onShutdown?(signal?: string): void | Promise<void>;
|
|
16
|
+
/** Final cleanup right before the container is disposed. */
|
|
17
|
+
onDestroy?(): void | Promise<void>;
|
|
18
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { createToken } from "../di";
|
|
2
|
+
import type { DatabaseProvider } from "../../library/orm";
|
|
3
|
+
|
|
4
|
+
/** Shared database connection published by the connection mode of `ormModule({ provider })`. */
|
|
5
|
+
export const DATABASE_PROVIDER = createToken<DatabaseProvider>("DatabaseProvider");
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import type { HostedService, HostedServicePlanValidator } from "../di";
|
|
2
|
+
import { SchemaAdmissionError } from "../../library/orm";
|
|
3
|
+
import { isOrmProviderLifecycle, isStrictSchemaPrerequisiteLifecycle } from "./strictSchemaHostedIdentity";
|
|
4
|
+
|
|
5
|
+
/** Stateless strategy shared by ORM lifecycles; it owns no connection or application state. */
|
|
6
|
+
export const ormHostedPlanValidator: HostedServicePlanValidator = Object.freeze({ validate: validateOrmHostedPlan });
|
|
7
|
+
|
|
8
|
+
/** ORM-owned admission rules. Runs before any hosted service starts. */
|
|
9
|
+
function validateOrmHostedPlan(services: readonly HostedService[]): void {
|
|
10
|
+
const owned = services.filter((service) => (service as { __bazisOrmOwnedStoreAdmission?: unknown }).__bazisOrmOwnedStoreAdmission === true);
|
|
11
|
+
for (const service of owned) {
|
|
12
|
+
if ((service.phase ?? 0) !== -105) throw new SchemaAdmissionError("ORM_SCHEMA_HOSTED_PHASE_CONFLICT", "ORM owned-store admission has an invalid hosted phase.");
|
|
13
|
+
if (!services.some((candidate) => isOrmProviderLifecycle(candidate) && (candidate.phase ?? 0) === -110)) throw new SchemaAdmissionError("ORM_SCHEMA_HOSTED_PHASE_CONFLICT", "ORM owned-store admission requires a provider lifecycle at phase -110.");
|
|
14
|
+
}
|
|
15
|
+
if (owned.length !== 0) {
|
|
16
|
+
for (const service of services) {
|
|
17
|
+
const framework = isOrmProviderLifecycle(service)
|
|
18
|
+
|| (service as { __bazisOrmOwnedStoreAdmission?: unknown }).__bazisOrmOwnedStoreAdmission === true
|
|
19
|
+
|| (service as { __bazisOrmLegacyLifecycle?: unknown }).__bazisOrmLegacyLifecycle === true
|
|
20
|
+
|| isStrictSchemaPrerequisiteLifecycle(service);
|
|
21
|
+
if (!framework && (service.phase ?? 0) < 0) throw new SchemaAdmissionError("ORM_SCHEMA_HOSTED_PHASE_CONFLICT", "Application hosted services must use phase 0 or later with ORM owned-store admission.");
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
const strict = services.filter((service): service is HostedService & { readonly __bazisSchemaAdmission: { readonly unit: readonly string[]; readonly tables: readonly string[]; readonly foreignKeys: readonly { readonly source: string; readonly target: string }[] } } =>
|
|
25
|
+
(service as { __bazisSchemaAdmission?: unknown }).__bazisSchemaAdmission !== undefined,
|
|
26
|
+
);
|
|
27
|
+
if (strict.length === 0) return;
|
|
28
|
+
const owners = new Set<string>();
|
|
29
|
+
for (const service of strict) {
|
|
30
|
+
if ((service.phase ?? 0) !== -105) throw new SchemaAdmissionError("ORM_SCHEMA_HOSTED_PHASE_CONFLICT", "Schema admission has an invalid hosted phase.");
|
|
31
|
+
for (const table of service.__bazisSchemaAdmission.tables) { if (owners.has(table)) throw new SchemaAdmissionError("ORM_SCHEMA_OWNERSHIP_CONFLICT", "Schema admission table ownership conflicts."); owners.add(table); }
|
|
32
|
+
const unit = new Set(service.__bazisSchemaAdmission.unit);
|
|
33
|
+
for (const foreignKey of service.__bazisSchemaAdmission.foreignKeys) {
|
|
34
|
+
if (!unit.has(foreignKey.source) || !unit.has(foreignKey.target)) {
|
|
35
|
+
throw new SchemaAdmissionError("ORM_SCHEMA_OWNERSHIP_CONFLICT", "Schema admission foreign keys must target the same explicit unit.");
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
if (!services.some((service) => isOrmProviderLifecycle(service) && (service.phase ?? 0) === -110)) {
|
|
40
|
+
throw new SchemaAdmissionError("ORM_SCHEMA_HOSTED_PHASE_CONFLICT", "Schema admission requires a provider lifecycle at phase -110.");
|
|
41
|
+
}
|
|
42
|
+
for (const service of services) {
|
|
43
|
+
if ((service as { __bazisLegacySchemaAuthority?: unknown }).__bazisLegacySchemaAuthority === true) {
|
|
44
|
+
throw new SchemaAdmissionError("ORM_SCHEMA_HOSTED_PHASE_CONFLICT", "Schema admission and legacy ORM schema authority cannot be composed together.");
|
|
45
|
+
}
|
|
46
|
+
const framework = isOrmProviderLifecycle(service)
|
|
47
|
+
|| isStrictSchemaPrerequisiteLifecycle(service)
|
|
48
|
+
|| (service as { __bazisOrmLegacyLifecycle?: unknown }).__bazisOrmLegacyLifecycle === true
|
|
49
|
+
|| (service as { __bazisSchemaAdmission?: unknown }).__bazisSchemaAdmission !== undefined
|
|
50
|
+
|| (service as { __bazisOrmOwnedStoreAdmission?: unknown }).__bazisOrmOwnedStoreAdmission === true;
|
|
51
|
+
if (!framework && (service.phase ?? 0) < 0) {
|
|
52
|
+
throw new SchemaAdmissionError("ORM_SCHEMA_HOSTED_PHASE_CONFLICT", "Application hosted services must use phase 0 or later with schema admission.");
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { ormHostedPlanValidator } from "./OrmHostedPlan.validator";
|
|
2
|
+
import type { HostedService } from "../di";
|
|
3
|
+
import { DatabaseFacade, type DbContextOptions, type Migration } from "../../library/orm";
|
|
4
|
+
import { compileExpectedSchema } from "../../library/orm/Schema/ExpectedSchema";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* ORM lifecycle hosted service: at start it (optionally) creates the schema or
|
|
8
|
+
* runs the auto-migration; at shutdown it closes the connection/pool.
|
|
9
|
+
* Starts early (negative phase) so the database is ready before the servers.
|
|
10
|
+
*/
|
|
11
|
+
export class OrmLifecycle implements HostedService {
|
|
12
|
+
readonly planValidator = ormHostedPlanValidator;
|
|
13
|
+
readonly phase: number;
|
|
14
|
+
/** Internal hosted-plan marker; public hosted services never receive it. */
|
|
15
|
+
readonly __bazisOrmLegacyLifecycle = true;
|
|
16
|
+
/**
|
|
17
|
+
* Internal hosted-plan marker: this lifecycle changes the schema at phase -100
|
|
18
|
+
* without exact admission (`ensureCreated` on a non-PostgreSQL provider,
|
|
19
|
+
* `migrateOnStart` or startup migrations). The hosted-plan validator rejects
|
|
20
|
+
* it in a container that also uses exact schema admission.
|
|
21
|
+
*/
|
|
22
|
+
readonly __bazisLegacySchemaAuthority: boolean;
|
|
23
|
+
/** Internal hosted-plan marker: tables and foreign keys of the phase -105 exact `ensureCreated` admission on PostgreSQL. */
|
|
24
|
+
readonly __bazisSchemaAdmission?: {
|
|
25
|
+
readonly unit: readonly string[];
|
|
26
|
+
readonly tables: readonly string[];
|
|
27
|
+
readonly foreignKeys: readonly { readonly source: string; readonly target: string }[];
|
|
28
|
+
};
|
|
29
|
+
private connectionClosed = false;
|
|
30
|
+
private closePromise?: Promise<void>;
|
|
31
|
+
|
|
32
|
+
constructor(
|
|
33
|
+
private readonly options: DbContextOptions,
|
|
34
|
+
private readonly ensureCreated: boolean,
|
|
35
|
+
private readonly migrateOnStart: boolean,
|
|
36
|
+
private readonly migrations: readonly Migration[] = [],
|
|
37
|
+
private readonly runMigrationsOnStart: boolean = false,
|
|
38
|
+
/**
|
|
39
|
+
* Whether this lifecycle owns the connection. `false` for the feature mode on
|
|
40
|
+
* top of the shared {@link DATABASE_PROVIDER}: the infrastructure owns the
|
|
41
|
+
* connection (the connection module / `@Infra` connector), and the feature
|
|
42
|
+
* must not close it at shutdown, or the shared pool would be closed twice.
|
|
43
|
+
*/
|
|
44
|
+
private readonly ownsConnection: boolean = true,
|
|
45
|
+
) {
|
|
46
|
+
this.phase = ensureCreated && options.provider.name === "postgres" ? -105 : -100;
|
|
47
|
+
this.__bazisLegacySchemaAuthority = this.phase === -100 && (ensureCreated || migrateOnStart || (runMigrationsOnStart && migrations.length > 0));
|
|
48
|
+
if (this.phase === -105) {
|
|
49
|
+
const expected = compileExpectedSchema(options.model);
|
|
50
|
+
const tables = Object.freeze(expected.tables.map((table) => `${table.schema}.${table.table}`));
|
|
51
|
+
this.__bazisSchemaAdmission = Object.freeze({
|
|
52
|
+
unit: tables,
|
|
53
|
+
tables,
|
|
54
|
+
foreignKeys: Object.freeze(expected.tables.flatMap((table) =>
|
|
55
|
+
table.foreignKeys.map((foreignKey) => Object.freeze({
|
|
56
|
+
source: `${table.schema}.${table.table}`,
|
|
57
|
+
target: `${foreignKey.target.schema}.${foreignKey.target.table}`,
|
|
58
|
+
})),
|
|
59
|
+
)),
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
async start(): Promise<void> {
|
|
65
|
+
const database = new DatabaseFacade(this.options.provider, this.options.model);
|
|
66
|
+
try {
|
|
67
|
+
if (this.ensureCreated) {
|
|
68
|
+
await database.ensureCreated();
|
|
69
|
+
}
|
|
70
|
+
if (this.migrateOnStart) {
|
|
71
|
+
const result = await database.migrate();
|
|
72
|
+
if (result.applied > 0) {
|
|
73
|
+
console.info(`[orm:migrate] applied ${result.applied} operation(s): ${result.operations.join(", ")}`);
|
|
74
|
+
}
|
|
75
|
+
for (const warning of result.warnings) {
|
|
76
|
+
console.warn(`[orm:migrate] ${warning}`);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
if (this.runMigrationsOnStart && this.migrations.length > 0) {
|
|
80
|
+
const result = await database.migrateVersioned(this.migrations);
|
|
81
|
+
if (result.applied.length > 0) {
|
|
82
|
+
console.info(`[orm:migrations] applied: ${result.applied.join(", ")}`);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
} catch (error) {
|
|
86
|
+
if (!this.ownsConnection) {
|
|
87
|
+
throw error;
|
|
88
|
+
}
|
|
89
|
+
try {
|
|
90
|
+
await this.closeOwnedConnection();
|
|
91
|
+
} catch (cleanupError) {
|
|
92
|
+
throw new AggregateError([error, cleanupError], "ORM startup failed and connection rollback also failed.");
|
|
93
|
+
}
|
|
94
|
+
throw error;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
async stop(): Promise<void> {
|
|
99
|
+
if (this.ownsConnection) {
|
|
100
|
+
await this.closeOwnedConnection();
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
private async closeOwnedConnection(): Promise<void> {
|
|
105
|
+
if (this.connectionClosed) {
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
this.closePromise ??= this.options.provider.close().then(() => {
|
|
109
|
+
this.connectionClosed = true;
|
|
110
|
+
});
|
|
111
|
+
await this.closePromise;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Occupies the phase -110 provider slot that exact schema admission requires:
|
|
117
|
+
* it runs before the phase -105 admissions and the phase -100 ORM lifecycle,
|
|
118
|
+
* without taking connection ownership.
|
|
119
|
+
*/
|
|
120
|
+
export class OrmProviderReadyLifecycle implements HostedService {
|
|
121
|
+
readonly planValidator = ormHostedPlanValidator;
|
|
122
|
+
public readonly phase = -110;
|
|
123
|
+
readonly __bazisOrmProviderReady = true;
|
|
124
|
+
start(): void {}
|
|
125
|
+
stop(): void {}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/** Owns a provider published by connection-only `ormModule({ provider })`. */
|
|
129
|
+
export class OrmConnectionLifecycle implements HostedService {
|
|
130
|
+
readonly planValidator = ormHostedPlanValidator;
|
|
131
|
+
public readonly phase = -110;
|
|
132
|
+
readonly __bazisOrmProviderReady = true;
|
|
133
|
+
private stopPromise?: Promise<void>;
|
|
134
|
+
|
|
135
|
+
public constructor(private readonly provider: DbContextOptions["provider"]) {}
|
|
136
|
+
|
|
137
|
+
public start(): void {
|
|
138
|
+
// DatabaseProvider has no separate connect contract; providers initialize
|
|
139
|
+
// lazily on first operation. This lifecycle exists to establish ownership.
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
public stop(): Promise<void> {
|
|
143
|
+
this.stopPromise ??= this.provider.close();
|
|
144
|
+
return this.stopPromise;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { ormHostedPlanValidator } from "./OrmHostedPlan.validator";
|
|
2
|
+
import type { HostedService } from "../di";
|
|
3
|
+
import type { DatabaseProvider } from "../../library/orm";
|
|
4
|
+
import { admitOwnedStoresV1, discardOwnedStoreAdmissionV1, publishOwnedStoreAdmissionV1, type OwnedStoreLeaseV1 } from "../../library/orm/Schema/OwnedStoreAdmission";
|
|
5
|
+
import { OrmOwnedStoreAdmissionError } from "../../library/orm";
|
|
6
|
+
import type { OwnedStoreRegistration } from "./ownedStoreContributions";
|
|
7
|
+
import { preparedOwnedStoreRegistration } from "./ownedStoreContributions";
|
|
8
|
+
|
|
9
|
+
const plans = new WeakMap<object, OrmOwnedStoreLifecycle>();
|
|
10
|
+
|
|
11
|
+
export interface OwnedStorePlanHealth { check(): Promise<{ healthy: boolean; details?: string }>; }
|
|
12
|
+
|
|
13
|
+
/** Container-local owner of the receipt and leases. It never owns the provider. */
|
|
14
|
+
export class OrmOwnedStoreLifecycle implements HostedService {
|
|
15
|
+
readonly planValidator = ormHostedPlanValidator;
|
|
16
|
+
public readonly phase = -105;
|
|
17
|
+
public readonly __bazisOrmOwnedStoreAdmission = true;
|
|
18
|
+
private state: "idle" | "starting" | "ready" | "failed" | "closing" | "stopped" = "idle";
|
|
19
|
+
private startPromise?: Promise<void>;
|
|
20
|
+
private readonly controller = new AbortController();
|
|
21
|
+
private leases: readonly OwnedStoreLeaseV1[] = Object.freeze([]);
|
|
22
|
+
|
|
23
|
+
public constructor(private readonly provider: DatabaseProvider, private readonly registrations: readonly OwnedStoreRegistration[]) {}
|
|
24
|
+
|
|
25
|
+
public async start(signal?: AbortSignal): Promise<void> {
|
|
26
|
+
if (this.state === "ready") return;
|
|
27
|
+
if (this.state === "stopped" || this.state === "closing") throw new OrmOwnedStoreAdmissionError("ORM_OWNED_STORE_LOCK_UNAVAILABLE", "ORM_OWNED_STORE_LOCK_UNAVAILABLE");
|
|
28
|
+
this.startPromise ??= this.admit(signal);
|
|
29
|
+
return this.startPromise;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
public async stop(): Promise<void> {
|
|
33
|
+
if (this.state === "idle" || this.state === "stopped") return;
|
|
34
|
+
this.state = "closing";
|
|
35
|
+
this.controller.abort();
|
|
36
|
+
try { await this.startPromise; } catch { /* a failed admission owns no lease */ }
|
|
37
|
+
for (const lease of this.leases) lease.revoke();
|
|
38
|
+
this.leases = Object.freeze([]);
|
|
39
|
+
this.state = "stopped";
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
public readonly health: OwnedStorePlanHealth = Object.freeze({
|
|
43
|
+
check: async () => this.state === "ready" && this.leases.length === this.registrations.length && this.leases.every((lease) => lease.active)
|
|
44
|
+
? { healthy: true }
|
|
45
|
+
: { healthy: false, details: "ORM_OWNED_STORE_NOT_READY" },
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
private async admit(external: AbortSignal | undefined): Promise<void> {
|
|
49
|
+
this.state = "starting";
|
|
50
|
+
const signal = combineSignals(this.controller.signal, external);
|
|
51
|
+
try {
|
|
52
|
+
if (signal.aborted) throw unavailable();
|
|
53
|
+
const receipt = await admitOwnedStoresV1(this.provider, { stores: this.registrations.map(preparedOwnedStoreRegistration), signal });
|
|
54
|
+
if (signal.aborted || this.controller.signal.aborted) {
|
|
55
|
+
discardOwnedStoreAdmissionV1(receipt);
|
|
56
|
+
throw unavailable();
|
|
57
|
+
}
|
|
58
|
+
// Publication and ready are deliberately adjacent: no await can leave a
|
|
59
|
+
// committed receipt visible to an aborted graph.
|
|
60
|
+
const leases = publishOwnedStoreAdmissionV1(this.provider, receipt);
|
|
61
|
+
if (signal.aborted || this.controller.signal.aborted) {
|
|
62
|
+
for (const lease of leases) lease.revoke();
|
|
63
|
+
throw unavailable();
|
|
64
|
+
}
|
|
65
|
+
this.leases = leases;
|
|
66
|
+
this.state = "ready";
|
|
67
|
+
} catch (error) {
|
|
68
|
+
if (!this.controller.signal.aborted) this.state = "failed";
|
|
69
|
+
throw error;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/** One container owns one whole-graph admission plan, regardless of module count. */
|
|
75
|
+
export function ownedStoreLifecycleFor(container: object, provider: DatabaseProvider, registrations: readonly OwnedStoreRegistration[]): OrmOwnedStoreLifecycle {
|
|
76
|
+
let plan = plans.get(container);
|
|
77
|
+
if (!plan) { plan = new OrmOwnedStoreLifecycle(provider, registrations); plans.set(container, plan); }
|
|
78
|
+
return plan;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/** Health must not activate a provider merely to observe a plan that has not started. */
|
|
82
|
+
export function ownedStoreLifecycleHealthFor(container: object): OwnedStorePlanHealth | undefined {
|
|
83
|
+
return plans.get(container)?.health;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function unavailable(): OrmOwnedStoreAdmissionError { return new OrmOwnedStoreAdmissionError("ORM_OWNED_STORE_LOCK_UNAVAILABLE", "ORM_OWNED_STORE_LOCK_UNAVAILABLE"); }
|
|
87
|
+
|
|
88
|
+
function combineSignals(local: AbortSignal, external: AbortSignal | undefined): AbortSignal {
|
|
89
|
+
if (!external) return local;
|
|
90
|
+
if (local.aborted || external.aborted) { const controller = new AbortController(); controller.abort(); return controller.signal; }
|
|
91
|
+
const controller = new AbortController();
|
|
92
|
+
const abort = (): void => controller.abort();
|
|
93
|
+
local.addEventListener("abort", abort, { once: true });
|
|
94
|
+
external.addEventListener("abort", abort, { once: true });
|
|
95
|
+
return controller.signal;
|
|
96
|
+
}
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import { DI, HOSTED_SERVICE, type InjectionToken, type ModuleOwnedContributionSnapshot, type ProviderDefinition } from "../di";
|
|
2
|
+
import { HEALTH_CHECK } from "../kernel";
|
|
3
|
+
import { DbContextOptions, type DatabaseProvider, type DbContext } from "../../library/orm";
|
|
4
|
+
import { OrmLifecycle } from "./OrmLifecycle";
|
|
5
|
+
import { ownedStoreLifecycleFor, ownedStoreLifecycleHealthFor } from "./OrmOwnedStoreLifecycle";
|
|
6
|
+
import { effectiveOrmModuleConfig, ownedStoreRegistrations } from "./ownedStoreContributions";
|
|
7
|
+
import { SERVICE_PROVIDER } from "../di";
|
|
8
|
+
import { DATABASE_PROVIDER } from "./DATABASE_PROVIDER";
|
|
9
|
+
import type { OrmModuleConfig } from "./ormModule";
|
|
10
|
+
|
|
11
|
+
type EntityClass = new () => object;
|
|
12
|
+
type ContextClass<TContext extends DbContext> = new (options: DbContextOptions) => TContext;
|
|
13
|
+
|
|
14
|
+
type OrmBuildConfig<TContext extends DbContext> = OrmModuleConfig<TContext> & {
|
|
15
|
+
readonly context: ContextClass<TContext>;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
function createContextOptions<TContext extends DbContext>(
|
|
19
|
+
config: OrmBuildConfig<TContext>,
|
|
20
|
+
provider: DatabaseProvider,
|
|
21
|
+
): DbContextOptions {
|
|
22
|
+
return new DbContextOptions({
|
|
23
|
+
provider,
|
|
24
|
+
entities: config.entities ?? [],
|
|
25
|
+
validateOnSave: config.validateOnSave,
|
|
26
|
+
executionStrategy: config.executionStrategy,
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function createOrmLifecycle<TContext extends DbContext>(
|
|
31
|
+
config: OrmBuildConfig<TContext>,
|
|
32
|
+
options: DbContextOptions,
|
|
33
|
+
ownsConnection: boolean,
|
|
34
|
+
): OrmLifecycle {
|
|
35
|
+
return new OrmLifecycle(
|
|
36
|
+
options,
|
|
37
|
+
config.ensureCreated === true,
|
|
38
|
+
config.migrateOnStart === true,
|
|
39
|
+
config.migrations ?? [],
|
|
40
|
+
config.runMigrationsOnStart === true,
|
|
41
|
+
ownsConnection,
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
function isInjectionToken(value: unknown): value is InjectionToken<DatabaseProvider> {
|
|
47
|
+
return typeof value === "object" && value !== null && "id" in value && "description" in value;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function effectiveConfigFor<TContext extends DbContext>(
|
|
51
|
+
serviceProvider: unknown,
|
|
52
|
+
registrationIdentity: object | undefined,
|
|
53
|
+
fallback: OrmBuildConfig<TContext>,
|
|
54
|
+
): OrmBuildConfig<TContext> {
|
|
55
|
+
const container = serviceProvider as import("../di").DiContainer;
|
|
56
|
+
const snapshot = {
|
|
57
|
+
getProviderContributions: container.getModuleOwnedProviderContributions.bind(container),
|
|
58
|
+
getMetadataContributions: container.getModuleOwnedMetadataContributions.bind(container),
|
|
59
|
+
} as unknown as ModuleOwnedContributionSnapshot;
|
|
60
|
+
ownedStoreRegistrations(snapshot);
|
|
61
|
+
return effectiveOrmModuleConfig(snapshot, registrationIdentity, fallback);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export function buildOrmModuleProviders<TContext extends DbContext>(
|
|
65
|
+
config: OrmBuildConfig<TContext>,
|
|
66
|
+
providerOrToken: DatabaseProvider | InjectionToken<DatabaseProvider>,
|
|
67
|
+
registrationIdentity?: object,
|
|
68
|
+
optionsAtModuleCall?: DbContextOptions,
|
|
69
|
+
): ProviderDefinition[] {
|
|
70
|
+
if (isInjectionToken(providerOrToken)) {
|
|
71
|
+
const token = providerOrToken;
|
|
72
|
+
const providers: ProviderDefinition[] = [
|
|
73
|
+
DI.scoped(
|
|
74
|
+
DI.factoryProvider(config.context, [token, SERVICE_PROVIDER] as const, (provider: DatabaseProvider, serviceProvider) => {
|
|
75
|
+
const current = effectiveConfigFor(serviceProvider, registrationIdentity, config);
|
|
76
|
+
return new current.context(createContextOptions(current, provider));
|
|
77
|
+
}),
|
|
78
|
+
),
|
|
79
|
+
DI.singleton(
|
|
80
|
+
DI.factoryProvider(HOSTED_SERVICE, [token, SERVICE_PROVIDER] as const, (provider: DatabaseProvider, serviceProvider) => {
|
|
81
|
+
const current = effectiveConfigFor(serviceProvider, registrationIdentity, config);
|
|
82
|
+
// Feature mode: the connection is shared (DATABASE_PROVIDER) and owned by
|
|
83
|
+
// the infrastructure; only ensureCreated/migrations here, no close.
|
|
84
|
+
if (current.ownedStore !== undefined) {
|
|
85
|
+
const container = serviceProvider as import("../di").DiContainer;
|
|
86
|
+
const records = ownedStoreRegistrations({
|
|
87
|
+
getProviderContributions: (channel) => container.getModuleOwnedProviderContributions(channel),
|
|
88
|
+
getMetadataContributions: (channel) => container.getModuleOwnedMetadataContributions(channel),
|
|
89
|
+
});
|
|
90
|
+
return ownedStoreLifecycleFor(container, provider, records);
|
|
91
|
+
}
|
|
92
|
+
return createOrmLifecycle(current, createContextOptions(current, provider), false);
|
|
93
|
+
}),
|
|
94
|
+
),
|
|
95
|
+
];
|
|
96
|
+
if (config.ownedStore !== undefined) {
|
|
97
|
+
providers.push(DI.singleton(DI.factoryProvider(HEALTH_CHECK, [SERVICE_PROVIDER], (serviceProvider) => {
|
|
98
|
+
const container = serviceProvider as unknown as import("../di").DiContainer;
|
|
99
|
+
return { name: `orm-owned-store:${config.ownedStore!.storeKey}`, check: () => ownedStoreLifecycleHealthFor(container)?.check() ?? Promise.resolve({ healthy: false, details: "ORM_OWNED_STORE_NOT_READY" }) };
|
|
100
|
+
})));
|
|
101
|
+
}
|
|
102
|
+
return providers;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const provider = providerOrToken;
|
|
106
|
+
const providers: ProviderDefinition[] = [
|
|
107
|
+
DI.scoped(DI.factoryProvider(config.context, [SERVICE_PROVIDER], (serviceProvider) => {
|
|
108
|
+
const current = effectiveConfigFor(serviceProvider, registrationIdentity, config);
|
|
109
|
+
const context = current === config ? config.context : current.context;
|
|
110
|
+
return new context(current === config && optionsAtModuleCall !== undefined ? optionsAtModuleCall : createContextOptions(current, provider));
|
|
111
|
+
})),
|
|
112
|
+
// Standalone mode: the context owns its provider and closes it.
|
|
113
|
+
DI.singleton(DI.factoryProvider(HOSTED_SERVICE, [SERVICE_PROVIDER], (serviceProvider) => {
|
|
114
|
+
const current = effectiveConfigFor(serviceProvider, registrationIdentity, config);
|
|
115
|
+
return createOrmLifecycle(current, current === config && optionsAtModuleCall !== undefined ? optionsAtModuleCall : createContextOptions(current, provider), true);
|
|
116
|
+
})),
|
|
117
|
+
];
|
|
118
|
+
return providers;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/** Connection health check for a concrete provider value. */
|
|
122
|
+
export function buildOrmHealthCheck(provider: DatabaseProvider): ProviderDefinition {
|
|
123
|
+
return DI.singleton(
|
|
124
|
+
DI.factoryProvider(HEALTH_CHECK, [], () => ({
|
|
125
|
+
name: `database:${provider.name}`,
|
|
126
|
+
check: () => checkProviderHealth(provider),
|
|
127
|
+
})),
|
|
128
|
+
);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/** Connection health check through the shared {@link DATABASE_PROVIDER} (feature mode). */
|
|
132
|
+
export function buildOrmHealthCheckFromToken(token: InjectionToken<DatabaseProvider>): ProviderDefinition {
|
|
133
|
+
return DI.singleton(
|
|
134
|
+
DI.factoryProvider(HEALTH_CHECK, [token], (provider: DatabaseProvider) => ({
|
|
135
|
+
name: `database:${provider.name}`,
|
|
136
|
+
check: () => checkProviderHealth(provider),
|
|
137
|
+
})),
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
async function checkProviderHealth(provider: DatabaseProvider): Promise<{ healthy: boolean; details?: string }> {
|
|
142
|
+
const connected = await provider.ping();
|
|
143
|
+
const diagnostics = provider.diagnostics?.() ?? [];
|
|
144
|
+
const hasError = diagnostics.some((diagnostic) => diagnostic.severity === "error");
|
|
145
|
+
const details = diagnostics.map((diagnostic) => `${diagnostic.severity}:${diagnostic.code}: ${diagnostic.message}`);
|
|
146
|
+
return {
|
|
147
|
+
healthy: connected && !hasError,
|
|
148
|
+
...(details.length === 0 ? {} : { details: details.join("; ") }),
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
export type { ContextClass, EntityClass, OrmBuildConfig };
|