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,137 @@
|
|
|
1
|
+
import { OptionsValidationError } from "../errors";
|
|
2
|
+
import type { ServiceCollection } from "../ServiceCollection";
|
|
3
|
+
import { createToken, type InjectionToken } from "../token";
|
|
4
|
+
import type { ServiceResolver } from "../types";
|
|
5
|
+
import { OPTIONS_STARTUP_VALIDATOR, type ValidatedOptionsConfig } from "./options";
|
|
6
|
+
|
|
7
|
+
/** Unsubscribes an {@link OptionsMonitor.onChange} listener. Idempotent. */
|
|
8
|
+
export interface OptionsChangeSubscription {
|
|
9
|
+
dispose(): void;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* .NET `IOptionsMonitor<T>` analog: a singleton holding the always-current value,
|
|
14
|
+
* able to reload it on demand and notify subscribers. Reloads are explicit
|
|
15
|
+
* (`reload()`) — call it from a file watcher, admin endpoint, etc. — which keeps
|
|
16
|
+
* the design free of ambient config-change machinery.
|
|
17
|
+
*/
|
|
18
|
+
export interface OptionsMonitor<T> {
|
|
19
|
+
/** The latest validated value. */
|
|
20
|
+
readonly current: T;
|
|
21
|
+
/** Subscribes to value changes; dispose the result to unsubscribe. */
|
|
22
|
+
onChange(listener: (value: T) => void): OptionsChangeSubscription;
|
|
23
|
+
/**
|
|
24
|
+
* Re-runs `load`/`validate`. On success updates `current` and notifies
|
|
25
|
+
* listeners; on validation failure throws and keeps the last good value.
|
|
26
|
+
*/
|
|
27
|
+
reload(): void;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* .NET `IOptionsSnapshot<T>` analog: scoped, captured once per scope from the
|
|
32
|
+
* monitor's current value. Stable for the lifetime of the scope (e.g. a request)
|
|
33
|
+
* even if the monitor reloads mid-scope.
|
|
34
|
+
*/
|
|
35
|
+
export interface OptionsSnapshot<T> {
|
|
36
|
+
readonly value: T;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function createOptionsMonitorToken<T>(name = "default"): InjectionToken<OptionsMonitor<T>> {
|
|
40
|
+
return createToken<OptionsMonitor<T>>(`IOptionsMonitor<${name}>`);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export function createOptionsSnapshotToken<T>(name = "default"): InjectionToken<OptionsSnapshot<T>> {
|
|
44
|
+
return createToken<OptionsSnapshot<T>>(`IOptionsSnapshot<${name}>`);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** Token pair for a single reloadable options source. */
|
|
48
|
+
export interface ReloadableOptionsTokens<T> {
|
|
49
|
+
readonly monitor: InjectionToken<OptionsMonitor<T>>;
|
|
50
|
+
readonly snapshot: InjectionToken<OptionsSnapshot<T>>;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function createReloadableOptionsTokens<T>(name = "default"): ReloadableOptionsTokens<T> {
|
|
54
|
+
return {
|
|
55
|
+
monitor: createOptionsMonitorToken<T>(name),
|
|
56
|
+
snapshot: createOptionsSnapshotToken<T>(name),
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
class OptionsMonitorImpl<T> implements OptionsMonitor<T> {
|
|
61
|
+
private value: T;
|
|
62
|
+
private readonly listeners = new Set<(value: T) => void>();
|
|
63
|
+
|
|
64
|
+
public constructor(
|
|
65
|
+
private readonly config: ValidatedOptionsConfig<T>,
|
|
66
|
+
private readonly name: string,
|
|
67
|
+
) {
|
|
68
|
+
this.value = this.loadValidated();
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
public get current(): T {
|
|
72
|
+
return this.value;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
public onChange(listener: (value: T) => void): OptionsChangeSubscription {
|
|
76
|
+
this.listeners.add(listener);
|
|
77
|
+
return {
|
|
78
|
+
dispose: (): void => {
|
|
79
|
+
this.listeners.delete(listener);
|
|
80
|
+
},
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
public reload(): void {
|
|
85
|
+
// Validation runs before mutating state, so a bad reload leaves the last
|
|
86
|
+
// good value in place and never fires listeners with invalid data.
|
|
87
|
+
const next = this.loadValidated();
|
|
88
|
+
this.value = next;
|
|
89
|
+
for (const listener of this.listeners) {
|
|
90
|
+
listener(next);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
private loadValidated(): T {
|
|
95
|
+
const value = this.config.load();
|
|
96
|
+
const issues = this.config.validate?.(value) ?? [];
|
|
97
|
+
if (issues.length > 0) {
|
|
98
|
+
throw new OptionsValidationError(issues.map((issue) => `${this.name}: ${issue}`));
|
|
99
|
+
}
|
|
100
|
+
return value;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Registers a reloadable options source: a singleton {@link OptionsMonitor} (the
|
|
106
|
+
* source of truth) and a scoped {@link OptionsSnapshot} read once per scope.
|
|
107
|
+
* Like `addValidatedOptions`, it participates in `validateOptionsOnStart` so a
|
|
108
|
+
* broken config fails fast on boot.
|
|
109
|
+
*/
|
|
110
|
+
export function addReloadableOptions<T>(
|
|
111
|
+
services: ServiceCollection,
|
|
112
|
+
tokens: ReloadableOptionsTokens<T>,
|
|
113
|
+
config: ValidatedOptionsConfig<T>,
|
|
114
|
+
): void {
|
|
115
|
+
services.addSingleton({
|
|
116
|
+
provide: tokens.monitor,
|
|
117
|
+
useFactory: (): OptionsMonitor<T> => new OptionsMonitorImpl(config, tokens.monitor.description),
|
|
118
|
+
deps: [],
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
services.addScoped({
|
|
122
|
+
provide: tokens.snapshot,
|
|
123
|
+
// Captured once per scope from the singleton monitor's current value.
|
|
124
|
+
useFactory: (resolver: ServiceResolver): OptionsSnapshot<T> => ({ value: resolver.resolve(tokens.monitor).current }),
|
|
125
|
+
deps: [],
|
|
126
|
+
withResolver: true,
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
services.addTransient({
|
|
130
|
+
provide: OPTIONS_STARTUP_VALIDATOR,
|
|
131
|
+
useFactory: (resolver: ServiceResolver) => (): void => {
|
|
132
|
+
resolver.resolve(tokens.monitor);
|
|
133
|
+
},
|
|
134
|
+
deps: [],
|
|
135
|
+
withResolver: true,
|
|
136
|
+
});
|
|
137
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { OptionsValidationError } from "../errors";
|
|
2
|
+
import type { ServiceCollection } from "../ServiceCollection";
|
|
3
|
+
import { createToken, type InjectionToken, type Token } from "../token";
|
|
4
|
+
import type { ServiceResolver } from "../types";
|
|
5
|
+
|
|
6
|
+
export interface Options<T> {
|
|
7
|
+
readonly value: T;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function createOptionsToken<T>(name = "default"): InjectionToken<Options<T>> {
|
|
11
|
+
return createToken<Options<T>>(`IOptions<${name}>`);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function addOptions<T>(services: ServiceCollection, token: InjectionToken<Options<T>>, value: T): void {
|
|
15
|
+
services.addSingleton({
|
|
16
|
+
provide: token,
|
|
17
|
+
useValue: { value },
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface ValidatedOptionsConfig<T> {
|
|
22
|
+
/** Loads the raw options value (env vars, config file, constants). */
|
|
23
|
+
readonly load: () => T;
|
|
24
|
+
/** Returns a list of problems; empty list or `undefined` means the value is valid. */
|
|
25
|
+
readonly validate?: (value: T) => readonly string[] | undefined;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Startup validators registered by `addValidatedOptions`. Each one forces its
|
|
30
|
+
* options to load and validate; `validateOptionsOnStart` runs them all and
|
|
31
|
+
* aggregates every problem into a single `OptionsValidationError`.
|
|
32
|
+
*/
|
|
33
|
+
export const OPTIONS_STARTUP_VALIDATOR = createToken<() => void>("OptionsStartupValidator");
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* .NET-style validated options: `load` runs lazily on first resolve, `validate`
|
|
37
|
+
* gates the value. For fail-fast behavior call `validateOptionsOnStart(container)`
|
|
38
|
+
* in your bootstrap (Application.start does it automatically).
|
|
39
|
+
*/
|
|
40
|
+
export function addValidatedOptions<T>(
|
|
41
|
+
services: ServiceCollection,
|
|
42
|
+
token: InjectionToken<Options<T>>,
|
|
43
|
+
config: ValidatedOptionsConfig<T>,
|
|
44
|
+
): void {
|
|
45
|
+
services.addSingleton({
|
|
46
|
+
provide: token,
|
|
47
|
+
useFactory: (): Options<T> => {
|
|
48
|
+
const value = config.load();
|
|
49
|
+
const issues = config.validate?.(value) ?? [];
|
|
50
|
+
if (issues.length > 0) {
|
|
51
|
+
const name = token.description;
|
|
52
|
+
throw new OptionsValidationError(issues.map((issue) => `${name}: ${issue}`));
|
|
53
|
+
}
|
|
54
|
+
return { value };
|
|
55
|
+
},
|
|
56
|
+
deps: [],
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
services.addTransient({
|
|
60
|
+
provide: OPTIONS_STARTUP_VALIDATOR,
|
|
61
|
+
useFactory: (resolver: ServiceResolver) => (): void => {
|
|
62
|
+
resolver.resolve(token);
|
|
63
|
+
},
|
|
64
|
+
deps: [],
|
|
65
|
+
withResolver: true,
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Fail-fast: resolves every validated options registration and throws one
|
|
71
|
+
* `OptionsValidationError` with all collected problems. Non-options errors
|
|
72
|
+
* (e.g. a throwing `load()`) are rethrown as-is.
|
|
73
|
+
*/
|
|
74
|
+
export function validateOptionsOnStart(provider: { resolveAll<T>(token: Token<T>): readonly T[] }): void {
|
|
75
|
+
const validators = provider.resolveAll(OPTIONS_STARTUP_VALIDATOR);
|
|
76
|
+
const issues: string[] = [];
|
|
77
|
+
for (let index = 0; index < validators.length; index += 1) {
|
|
78
|
+
try {
|
|
79
|
+
(validators[index] as () => void)();
|
|
80
|
+
} catch (error) {
|
|
81
|
+
if (error instanceof OptionsValidationError) {
|
|
82
|
+
issues.push(...error.issues);
|
|
83
|
+
} else {
|
|
84
|
+
throw error;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
if (issues.length > 0) {
|
|
89
|
+
throw new OptionsValidationError(issues);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { ServiceProvider } from "../ServiceProvider";
|
|
2
|
+
import { createToken } from "../token";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* The container itself as an injectable service (.NET's IServiceProvider).
|
|
6
|
+
*
|
|
7
|
+
* Registered automatically by `createContainer` as a global provider, so any
|
|
8
|
+
* service can receive the root container — primarily to create per-request
|
|
9
|
+
* scopes (`provider.createScope()`) from infrastructure like the HTTP server.
|
|
10
|
+
*
|
|
11
|
+
* Resolve it sparingly: business services should depend on their actual
|
|
12
|
+
* dependencies, not on the container (service-locator anti-pattern).
|
|
13
|
+
*/
|
|
14
|
+
export const SERVICE_PROVIDER = createToken<ServiceProvider>("IServiceProvider");
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Internal alias for the canonical class token used by generated constructor
|
|
18
|
+
* dependencies. Name-based dependencies resolve this same token, so no
|
|
19
|
+
* second token with the debug name `ServiceProvider` competes with the class.
|
|
20
|
+
*/
|
|
21
|
+
export const SERVICE_PROVIDER_BY_TYPE = ServiceProvider;
|
package/core/di/index.ts
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
export type { BuildServiceProviderOptions, ServiceKey, ServiceResolver } from "./types";
|
|
2
|
+
export { ServiceCollection } from "./ServiceCollection";
|
|
3
|
+
export { ServiceProvider } from "./ServiceProvider";
|
|
4
|
+
export { ServiceScope } from "./ServiceScope";
|
|
5
|
+
export { DiContainer } from "./container";
|
|
6
|
+
export * from "./extensions";
|
|
7
|
+
export {
|
|
8
|
+
AmbiguousNamedDependencyError,
|
|
9
|
+
AsyncResolutionRequiredError,
|
|
10
|
+
CircularDependencyError,
|
|
11
|
+
ClassDependenciesMismatchError,
|
|
12
|
+
DiError,
|
|
13
|
+
InvalidProviderError,
|
|
14
|
+
ModuleEncapsulationError,
|
|
15
|
+
ModuleOwnedProviderConflictError,
|
|
16
|
+
NamedDependencyNotFoundError,
|
|
17
|
+
OptionsValidationError,
|
|
18
|
+
ProviderNotFoundError,
|
|
19
|
+
ScopeDisposedError,
|
|
20
|
+
ScopedServiceFromRootError,
|
|
21
|
+
ServiceValidationError,
|
|
22
|
+
} from "./errors";
|
|
23
|
+
export {
|
|
24
|
+
createContainer,
|
|
25
|
+
collectModuleControllers,
|
|
26
|
+
collectModuleConfigs,
|
|
27
|
+
collectModuleUiProfiles,
|
|
28
|
+
Global,
|
|
29
|
+
markGlobal,
|
|
30
|
+
Module,
|
|
31
|
+
DI,
|
|
32
|
+
registerModuleMetadataExpander,
|
|
33
|
+
registerModuleOwnedContributionValidator,
|
|
34
|
+
registerModuleOwnedProviderContributor,
|
|
35
|
+
expandModuleMetadata,
|
|
36
|
+
createModuleOwnedMetadataChannel,
|
|
37
|
+
createModuleOwnedProviderChannel,
|
|
38
|
+
scoped,
|
|
39
|
+
singleton,
|
|
40
|
+
singletonAsyncFactory,
|
|
41
|
+
singletonAsyncFactoryWithResolver,
|
|
42
|
+
singletonFactory,
|
|
43
|
+
singletonFactoryWithResolver,
|
|
44
|
+
singletonValue,
|
|
45
|
+
transient,
|
|
46
|
+
type DiRegistrar,
|
|
47
|
+
type ModuleConfig,
|
|
48
|
+
type ModuleExport,
|
|
49
|
+
type ModuleMetadataExpander,
|
|
50
|
+
type ModuleOwnedContributionChannel,
|
|
51
|
+
type ModuleOwnedContributionSnapshot,
|
|
52
|
+
type ModuleOwnedValidationSnapshot,
|
|
53
|
+
type ModuleOwnedContributionValidator,
|
|
54
|
+
type ModuleOwnedMetadataChannel,
|
|
55
|
+
type ModuleOwnedMetadataContribution,
|
|
56
|
+
type ModuleOwnedProviderActivation,
|
|
57
|
+
type ModuleOwnedProviderChannel,
|
|
58
|
+
type ModuleOwnedProviderContribution,
|
|
59
|
+
type ModuleOwnedProviderContributionContext,
|
|
60
|
+
type ModuleOwnedProviderContributor,
|
|
61
|
+
type BazisModule,
|
|
62
|
+
type BazisModuleMetadata,
|
|
63
|
+
type BazisModuleRef,
|
|
64
|
+
} from "./module";
|
|
65
|
+
export {
|
|
66
|
+
CLASS_PROVIDER_HOOK,
|
|
67
|
+
type ClassProviderHook,
|
|
68
|
+
type ClassProviderRegistration,
|
|
69
|
+
} from "./module/classProviderHooks";
|
|
70
|
+
export {
|
|
71
|
+
registerNamedDependencyEncapsulationHook,
|
|
72
|
+
type NamedDependencyEncapsulationContext,
|
|
73
|
+
type NamedDependencyEncapsulationHook,
|
|
74
|
+
} from "./module/encapsulationHooks";
|
|
75
|
+
export {
|
|
76
|
+
createOpenGenericTokenFamily,
|
|
77
|
+
createToken,
|
|
78
|
+
type Class,
|
|
79
|
+
type InjectionToken,
|
|
80
|
+
type OpenGenericTokenFamily,
|
|
81
|
+
type Token,
|
|
82
|
+
} from "./token";
|
|
83
|
+
export { ProviderDefinition, keyedDependency, lazyDependency, namedDependency } from "./provider";
|
|
84
|
+
export type {
|
|
85
|
+
AsyncFactoryProvider,
|
|
86
|
+
ClassProvider,
|
|
87
|
+
FactoryProvider,
|
|
88
|
+
KeyedDependency,
|
|
89
|
+
Lazy,
|
|
90
|
+
LazyDependency,
|
|
91
|
+
NamedDependency,
|
|
92
|
+
Provider,
|
|
93
|
+
ProviderDependencyList,
|
|
94
|
+
ProviderLifetime,
|
|
95
|
+
ResolvedDeps,
|
|
96
|
+
ValueProvider,
|
|
97
|
+
} from "./provider";
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { ServiceValidationError } from "../errors";
|
|
2
|
+
import { isLazyDependency } from "../provider";
|
|
3
|
+
import type {
|
|
4
|
+
KeyedDependency,
|
|
5
|
+
NamedDependency,
|
|
6
|
+
Provider,
|
|
7
|
+
ProviderDependencyList,
|
|
8
|
+
ProviderLifetime,
|
|
9
|
+
} from "../provider";
|
|
10
|
+
import { tokenToDebugName, type Token } from "../token";
|
|
11
|
+
import type { ServiceKey } from "../types";
|
|
12
|
+
import type { ServiceRegistration } from "./ServiceRegistration";
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Everything the build-time graph validator needs from the container, exposed as
|
|
16
|
+
* a narrow context so {@link GraphValidator} stays independent of the container's
|
|
17
|
+
* private resolution internals (and unit-testable on its own).
|
|
18
|
+
*/
|
|
19
|
+
export interface GraphValidationContext {
|
|
20
|
+
readonly validateScopes: boolean;
|
|
21
|
+
registrationGroups(): Iterable<readonly ServiceRegistration[]>;
|
|
22
|
+
/** Materializes every open generic against the registered tokens, collecting factory failures. */
|
|
23
|
+
eagerlyMaterializeOpenGenerics(issues: Set<string>): void;
|
|
24
|
+
dependencies(provider: Provider<unknown>): ProviderDependencyList;
|
|
25
|
+
/** Constructor arity vs declared deps for class providers; `undefined` for non-class providers. */
|
|
26
|
+
classShape(provider: Provider<unknown>): { readonly required: number; readonly declared: number } | undefined;
|
|
27
|
+
describeDependency(
|
|
28
|
+
dependency: Token<unknown> | KeyedDependency<unknown> | NamedDependency<unknown>,
|
|
29
|
+
): { readonly token: Token<unknown>; readonly key: ServiceKey | undefined };
|
|
30
|
+
findRegistration(token: Token<unknown>, key: ServiceKey | undefined): ServiceRegistration | undefined;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Static (build-time) graph validation: detects cycles, missing dependencies,
|
|
35
|
+
* captive dependencies (singleton -> scoped) and class arity mismatches, then
|
|
36
|
+
* reports every problem at once via {@link ServiceValidationError}. Runs once on
|
|
37
|
+
* `validateOnBuild`; the resolution hot path never touches this code.
|
|
38
|
+
*/
|
|
39
|
+
export class GraphValidator {
|
|
40
|
+
public constructor(private readonly context: GraphValidationContext) {}
|
|
41
|
+
|
|
42
|
+
public validate(): void {
|
|
43
|
+
const issues = new Set<string>();
|
|
44
|
+
this.context.eagerlyMaterializeOpenGenerics(issues);
|
|
45
|
+
for (const registrations of this.context.registrationGroups()) {
|
|
46
|
+
for (let index = 0; index < registrations.length; index += 1) {
|
|
47
|
+
const registration = registrations[index] as ServiceRegistration;
|
|
48
|
+
this.validateRegistration(registration, registration.lifetime, [], new Set<number>(), issues);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (issues.size > 0) {
|
|
53
|
+
throw new ServiceValidationError([...issues]);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
private validateRegistration(
|
|
58
|
+
registration: ServiceRegistration,
|
|
59
|
+
rootLifetime: ProviderLifetime,
|
|
60
|
+
tokenPath: Token<unknown>[],
|
|
61
|
+
registrationPath: Set<number>,
|
|
62
|
+
issues: Set<string>,
|
|
63
|
+
): void {
|
|
64
|
+
if (registrationPath.has(registration.id)) {
|
|
65
|
+
const cyclePath = [...tokenPath, registration.token].map((token) => tokenToDebugName(token)).join(" -> ");
|
|
66
|
+
issues.add(`Cycle detected: ${cyclePath}`);
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const shape = this.context.classShape(registration.provider);
|
|
71
|
+
if (shape && shape.required > shape.declared) {
|
|
72
|
+
issues.add(
|
|
73
|
+
`Class provider "${tokenToDebugName(registration.token)}" requires at least ${shape.required} constructor deps, but only ${shape.declared} declared.`,
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const deps = this.context.dependencies(registration.provider);
|
|
78
|
+
if (deps.length === 0) {
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
registrationPath.add(registration.id);
|
|
83
|
+
tokenPath.push(registration.token);
|
|
84
|
+
try {
|
|
85
|
+
for (let index = 0; index < deps.length; index += 1) {
|
|
86
|
+
const dependency = deps[index];
|
|
87
|
+
if (dependency === undefined) {
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
const isLazy = isLazyDependency(dependency);
|
|
91
|
+
const descriptor = this.context.describeDependency(isLazy ? dependency.inner : dependency);
|
|
92
|
+
const depRegistration = this.context.findRegistration(descriptor.token, descriptor.key);
|
|
93
|
+
if (!depRegistration) {
|
|
94
|
+
issues.add(
|
|
95
|
+
`Missing dependency "${tokenToDebugName(descriptor.token)}" for "${tokenToDebugName(registration.token)}"`,
|
|
96
|
+
);
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (this.context.validateScopes && rootLifetime === "singleton" && depRegistration.lifetime === "scoped") {
|
|
101
|
+
issues.add(
|
|
102
|
+
`Singleton "${tokenToDebugName(registration.token)}" depends on scoped "${tokenToDebugName(descriptor.token)}"`,
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Lazy edges defer creation to first access, so they cannot deadlock
|
|
107
|
+
// construction: validate existence above, but do not traverse them.
|
|
108
|
+
if (isLazy) {
|
|
109
|
+
continue;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
this.validateRegistration(depRegistration, rootLifetime, tokenPath, registrationPath, issues);
|
|
113
|
+
}
|
|
114
|
+
} finally {
|
|
115
|
+
tokenPath.pop();
|
|
116
|
+
registrationPath.delete(registration.id);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import type { HostedService, HostedServicePlanValidator } from "../extensions/hosted-service";
|
|
2
|
+
|
|
3
|
+
/** Internal bridge: DI knows plan composition, never a particular wrapper class. */
|
|
4
|
+
export interface HostedServicePlanAdmission {
|
|
5
|
+
readonly phase: number;
|
|
6
|
+
replace(candidate: HostedService, signal?: AbortSignal): Promise<void>;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
interface HostedServiceWrapper {
|
|
10
|
+
readonly explicitPhase?: number;
|
|
11
|
+
prepare(): HostedService;
|
|
12
|
+
bind(admission: HostedServicePlanAdmission): void;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const wrappers = new WeakMap<HostedService, HostedServiceWrapper>();
|
|
16
|
+
const owners = new WeakMap<HostedService, HostedServicePlan>();
|
|
17
|
+
|
|
18
|
+
export function registerHostedServiceWrapper(service: HostedService, wrapper: HostedServiceWrapper): void {
|
|
19
|
+
wrappers.set(service, wrapper);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
interface PlanNode {
|
|
23
|
+
readonly service: HostedService;
|
|
24
|
+
readonly phase: number;
|
|
25
|
+
readonly wrapper?: HostedServiceWrapper;
|
|
26
|
+
readonly child?: PlanNode;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function prepareHostedServicePlan(services: readonly HostedService[], signal?: AbortSignal): void | Promise<void> {
|
|
30
|
+
signal?.throwIfAborted();
|
|
31
|
+
if (!services.some(service => wrappers.has(service) || service.planValidator !== undefined)) return;
|
|
32
|
+
return new HostedServicePlan(services, signal).admit(signal);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** One host run owns its concrete identities and serializes whole-plan replacements. */
|
|
36
|
+
class HostedServicePlan {
|
|
37
|
+
private roots: readonly PlanNode[];
|
|
38
|
+
private readonly phases: readonly number[];
|
|
39
|
+
private replacement: Promise<void> = Promise.resolve();
|
|
40
|
+
|
|
41
|
+
constructor(services: readonly HostedService[], signal?: AbortSignal) {
|
|
42
|
+
this.roots = services.map(service => materialize(service, new Set(), signal));
|
|
43
|
+
this.phases = this.roots.map(node => node.phase);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
async admit(signal?: AbortSignal): Promise<void> {
|
|
47
|
+
await this.validate(this.roots, signal);
|
|
48
|
+
signal?.throwIfAborted();
|
|
49
|
+
this.bind();
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
private replace(owner: HostedService, candidate: HostedService, signal?: AbortSignal): Promise<void> {
|
|
53
|
+
const replacing = this.replacement.then(async () => {
|
|
54
|
+
signal?.throwIfAborted();
|
|
55
|
+
this.assertOwner(owner);
|
|
56
|
+
const child = materialize(candidate, new Set([owner]), signal);
|
|
57
|
+
const roots = this.roots.map(node => replaceChild(node, owner, child));
|
|
58
|
+
if (roots.some((node, index) => node.phase !== this.phases[index])) {
|
|
59
|
+
throw new Error("Hosted service retry cannot change the admitted startup phase.");
|
|
60
|
+
}
|
|
61
|
+
await this.validate(roots, signal);
|
|
62
|
+
signal?.throwIfAborted();
|
|
63
|
+
this.assertOwner(owner);
|
|
64
|
+
// No await between the last admission check and publication.
|
|
65
|
+
this.roots = roots;
|
|
66
|
+
this.bind();
|
|
67
|
+
});
|
|
68
|
+
this.replacement = replacing.catch(() => {});
|
|
69
|
+
return replacing;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
private assertOwner(owner: HostedService): void {
|
|
73
|
+
if (owners.get(owner) !== this || !nodesOf(this.roots).some(node => node.service === owner && node.wrapper)) {
|
|
74
|
+
throw new Error("Hosted service retry belongs to an inactive plan wrapper.");
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
private async validate(roots: readonly PlanNode[], signal?: AbortSignal): Promise<void> {
|
|
79
|
+
const nodes = nodesOf(roots);
|
|
80
|
+
const seen = new Set<HostedService>();
|
|
81
|
+
for (const node of nodes) {
|
|
82
|
+
if (seen.has(node.service)) throw new Error("Hosted service plan contains a duplicate service identity.");
|
|
83
|
+
seen.add(node.service);
|
|
84
|
+
}
|
|
85
|
+
const plan = Object.freeze(roots.map(concrete));
|
|
86
|
+
const validators = new Set<HostedServicePlanValidator>();
|
|
87
|
+
for (const service of plan) if (service.planValidator !== undefined) validators.add(service.planValidator);
|
|
88
|
+
if (validators.size > 0) {
|
|
89
|
+
for (const node of nodes) {
|
|
90
|
+
if (node.wrapper && node.phase !== (concrete(node).phase ?? 0)) {
|
|
91
|
+
throw new Error("Supervised hosted phase conflicts with the concrete service phase required by plan validators.");
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
for (const validator of validators) {
|
|
96
|
+
signal?.throwIfAborted();
|
|
97
|
+
await awaitValidation(validator.validate(plan, signal), signal);
|
|
98
|
+
}
|
|
99
|
+
signal?.throwIfAborted();
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
private bind(): void {
|
|
103
|
+
for (const node of nodesOf(this.roots)) {
|
|
104
|
+
if (!node.wrapper) continue;
|
|
105
|
+
owners.set(node.service, this);
|
|
106
|
+
node.wrapper.bind({ phase: node.phase, replace: (candidate, signal) => this.replace(node.service, candidate, signal) });
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function materialize(service: HostedService, ancestors: Set<HostedService>, signal?: AbortSignal): PlanNode {
|
|
112
|
+
signal?.throwIfAborted();
|
|
113
|
+
if (ancestors.has(service)) throw new Error("Hosted service wrapper factory cycle.");
|
|
114
|
+
const wrapper = wrappers.get(service);
|
|
115
|
+
if (!wrapper) return { service, phase: service.phase ?? 0 };
|
|
116
|
+
ancestors.add(service);
|
|
117
|
+
try {
|
|
118
|
+
const child = materialize(wrapper.prepare(), ancestors, signal);
|
|
119
|
+
return { service, wrapper, child, phase: wrapper.explicitPhase ?? child.phase };
|
|
120
|
+
} finally {
|
|
121
|
+
ancestors.delete(service);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function concrete(node: PlanNode): HostedService {
|
|
126
|
+
return node.child ? concrete(node.child) : node.service;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function nodesOf(roots: readonly PlanNode[]): PlanNode[] {
|
|
130
|
+
const nodes: PlanNode[] = [];
|
|
131
|
+
for (const root of roots) {
|
|
132
|
+
for (let node: PlanNode | undefined = root; node !== undefined; node = node.child) nodes.push(node);
|
|
133
|
+
}
|
|
134
|
+
return nodes;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function replaceChild(node: PlanNode, owner: HostedService, replacement: PlanNode): PlanNode {
|
|
138
|
+
if (!node.wrapper || !node.child) return node;
|
|
139
|
+
const child = node.service === owner ? replacement : replaceChild(node.child, owner, replacement);
|
|
140
|
+
return child === node.child ? node : { ...node, child, phase: node.wrapper.explicitPhase ?? child.phase };
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
async function awaitValidation(value: void | Promise<void>, signal?: AbortSignal): Promise<void> {
|
|
144
|
+
if (!signal) return await value;
|
|
145
|
+
let onAbort: (() => void) | undefined;
|
|
146
|
+
try {
|
|
147
|
+
await Promise.race([
|
|
148
|
+
value,
|
|
149
|
+
new Promise<never>((_resolve, reject) => {
|
|
150
|
+
onAbort = () => reject(signal.reason);
|
|
151
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
152
|
+
if (signal.aborted) onAbort();
|
|
153
|
+
}),
|
|
154
|
+
]);
|
|
155
|
+
} finally {
|
|
156
|
+
if (onAbort) signal.removeEventListener("abort", onAbort);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { AmbiguousNamedDependencyError } from "../errors";
|
|
2
|
+
import { tokenToDebugName, type Token } from "../token";
|
|
3
|
+
|
|
4
|
+
const AMBIGUOUS = Symbol("bazis.di.ambiguous-name");
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Maps a token's debug name (`createToken("X")` description or class name) to its
|
|
8
|
+
* token, powering name-based auto deps. Built lazily on first lookup from the
|
|
9
|
+
* full token set; tokens added afterwards (materialized open generics) are
|
|
10
|
+
* indexed incrementally. Distinct tokens sharing a name resolve to an ambiguity
|
|
11
|
+
* marker so a name lookup fails loudly instead of silently picking one.
|
|
12
|
+
*/
|
|
13
|
+
export class NamedTokenIndex {
|
|
14
|
+
private cache: Map<string, Token<unknown> | typeof AMBIGUOUS> | undefined;
|
|
15
|
+
|
|
16
|
+
public constructor(private readonly enumerateTokens: () => Iterable<Token<unknown>>) {}
|
|
17
|
+
|
|
18
|
+
public lookup(name: string): Token<unknown> | undefined {
|
|
19
|
+
if (!this.cache) {
|
|
20
|
+
this.cache = new Map();
|
|
21
|
+
for (const token of this.enumerateTokens()) {
|
|
22
|
+
this.indexInternal(token);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const found = this.cache.get(name);
|
|
27
|
+
if (found === AMBIGUOUS) {
|
|
28
|
+
throw new AmbiguousNamedDependencyError(name);
|
|
29
|
+
}
|
|
30
|
+
return found;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
public index(token: Token<unknown>): void {
|
|
34
|
+
// Before the first lookup the cache is rebuilt from scratch, so eager
|
|
35
|
+
// indexing would be wasted work — defer until the cache exists.
|
|
36
|
+
if (!this.cache) {
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
this.indexInternal(token);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
private indexInternal(token: Token<unknown>): void {
|
|
43
|
+
const cache = this.cache;
|
|
44
|
+
if (!cache) {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
const name = tokenToDebugName(token);
|
|
48
|
+
const existing = cache.get(name);
|
|
49
|
+
if (existing === undefined) {
|
|
50
|
+
cache.set(name, token);
|
|
51
|
+
} else if (existing !== token) {
|
|
52
|
+
cache.set(name, AMBIGUOUS);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Provider, ProviderLifetime } from "../provider";
|
|
2
|
+
import type { OpenGenericTokenFamily, Token } from "../token";
|
|
3
|
+
import type { ServiceKey } from "../types";
|
|
4
|
+
|
|
5
|
+
export type OpenGenericProviderFactory = (argument: Token<unknown>) => Provider<unknown>;
|
|
6
|
+
|
|
7
|
+
export class OpenGenericRegistration {
|
|
8
|
+
public constructor(
|
|
9
|
+
public readonly family: OpenGenericTokenFamily<unknown, unknown>,
|
|
10
|
+
public readonly providerFactory: OpenGenericProviderFactory,
|
|
11
|
+
public readonly lifetime: ProviderLifetime,
|
|
12
|
+
public readonly key?: ServiceKey,
|
|
13
|
+
) {}
|
|
14
|
+
}
|