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,100 @@
|
|
|
1
|
+
import { renderCheck } from "./CheckExpression";
|
|
2
|
+
import type { OrmExpectedSchema, ExpectedColumn, ExpectedTable } from "./ExpectedSchema";
|
|
3
|
+
import type { IntrospectedSchema } from "./introspection";
|
|
4
|
+
import type { SchemaDifference, SchemaVerificationResult } from "./ExactSchemaVerifier";
|
|
5
|
+
|
|
6
|
+
export type SafeAdditiveSchemaOperation =
|
|
7
|
+
| { readonly kind: "createSchema"; readonly schema: string }
|
|
8
|
+
| { readonly kind: "createTable"; readonly table: ExpectedTable }
|
|
9
|
+
| { readonly kind: "addColumn"; readonly table: ExpectedTable; readonly column: ExpectedColumn }
|
|
10
|
+
| { readonly kind: "addCheck"; readonly table: ExpectedTable; readonly check: ExpectedTable["checks"][number] }
|
|
11
|
+
| { readonly kind: "addForeignKey"; readonly table: ExpectedTable; readonly foreignKey: ExpectedTable["foreignKeys"][number] }
|
|
12
|
+
| { readonly kind: "createIndex"; readonly table: ExpectedTable; readonly index: ExpectedTable["indexes"][number] };
|
|
13
|
+
|
|
14
|
+
export interface SafeAdditivePreflight { readonly verification: SchemaVerificationResult; readonly hardDifferences: readonly SchemaDifference[]; readonly plan?: readonly SafeAdditiveSchemaOperation[] }
|
|
15
|
+
|
|
16
|
+
/** Classifies a complete catalog snapshot before any DDL is rendered or executed. */
|
|
17
|
+
export function classifySafeAdditive(expected: OrmExpectedSchema, actual: IntrospectedSchema, verification: SchemaVerificationResult): SafeAdditivePreflight {
|
|
18
|
+
const hard = verification.differences.filter((difference) => !isPotentialAddition(difference));
|
|
19
|
+
const plan: SafeAdditiveSchemaOperation[] = [];
|
|
20
|
+
const existingSchemas = new Set(actual.schemas ?? ["public"]);
|
|
21
|
+
for (const table of expected.tables) {
|
|
22
|
+
const found = actual.tables.get(`${table.schema}.${table.table}`);
|
|
23
|
+
if (!found) {
|
|
24
|
+
if (table.schema !== "public" && !existingSchemas.has(table.schema)) { plan.push({ kind: "createSchema", schema: table.schema }); existingSchemas.add(table.schema); }
|
|
25
|
+
plan.push({ kind: "createTable", table });
|
|
26
|
+
for (const foreignKey of table.foreignKeys) plan.push({ kind: "addForeignKey", table, foreignKey });
|
|
27
|
+
for (const index of table.indexes) plan.push({ kind: "createIndex", table, index });
|
|
28
|
+
continue;
|
|
29
|
+
}
|
|
30
|
+
for (const column of table.columns) if (!found.columns.has(column.column)) {
|
|
31
|
+
if (column.generation !== "none" || (!column.nullable && (column.default.kind === "none" || column.default.kind === "null"))) {
|
|
32
|
+
hard.push(...verification.differences.filter((d) => d.schema === table.schema && d.table === table.table && d.code === "column.missing" && d.objectName === column.column));
|
|
33
|
+
} else plan.push({ kind: "addColumn", table, column });
|
|
34
|
+
}
|
|
35
|
+
for (const check of table.checks) if (!(found.checks ?? []).some((item) => item.name === check.name)) plan.push({ kind: "addCheck", table, check });
|
|
36
|
+
for (const foreignKey of table.foreignKeys) if (!(found.foreignKeys ?? []).some((item) => item.name === foreignKey.name)) plan.push({ kind: "addForeignKey", table, foreignKey });
|
|
37
|
+
for (const index of table.indexes) if (!found.indexes.some((item) => !item.backingConstraint && item.name === index.name)) plan.push({ kind: "createIndex", table, index });
|
|
38
|
+
}
|
|
39
|
+
const uniqueHard = deduplicate(hard);
|
|
40
|
+
if (uniqueHard.length) return { verification, hardDifferences: uniqueHard };
|
|
41
|
+
return { verification, hardDifferences: [], plan: Object.freeze(plan.sort(compareOperation)) };
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function isPotentialAddition(difference: SchemaDifference): boolean {
|
|
45
|
+
return difference.code === "table.missing" || difference.code === "column.missing" || difference.code === "index.missing" || difference.code === "foreignKey.missing" || difference.code === "check.missing";
|
|
46
|
+
}
|
|
47
|
+
function deduplicate(differences: readonly SchemaDifference[]): readonly SchemaDifference[] {
|
|
48
|
+
const seen = new Set<string>();
|
|
49
|
+
return differences.filter((value) => { const key = `${value.schema}\0${value.table}\0${value.code}\0${value.objectName ?? ""}`; if (seen.has(key)) return false; seen.add(key); return true; });
|
|
50
|
+
}
|
|
51
|
+
const stage: Record<SafeAdditiveSchemaOperation["kind"], number> = { createSchema: 0, createTable: 1, addColumn: 2, addCheck: 3, addForeignKey: 4, createIndex: 5 };
|
|
52
|
+
function compareOperation(a: SafeAdditiveSchemaOperation, b: SafeAdditiveSchemaOperation): number {
|
|
53
|
+
const stageDifference = stage[a.kind] - stage[b.kind];
|
|
54
|
+
if (stageDifference) return stageDifference;
|
|
55
|
+
return bytes(operationIdentity(a), operationIdentity(b));
|
|
56
|
+
}
|
|
57
|
+
function operationIdentity(operation: SafeAdditiveSchemaOperation): string {
|
|
58
|
+
if (operation.kind === "createSchema") return operation.schema;
|
|
59
|
+
const table = operation.table;
|
|
60
|
+
const name = operation.kind === "createTable" ? table.table : operation.kind === "addColumn" ? operation.column.column : operation.kind === "addCheck" ? operation.check.name : operation.kind === "addForeignKey" ? operation.foreignKey.name : operation.index.name;
|
|
61
|
+
return `${table.schema}\0${table.table}\0${name}`;
|
|
62
|
+
}
|
|
63
|
+
function bytes(a: string, b: string): number { return Buffer.compare(Buffer.from(a, "utf8"), Buffer.from(b, "utf8")); }
|
|
64
|
+
|
|
65
|
+
/** Pure PostgreSQL renderer. Parameters/rows/raw fragments never enter the plan. */
|
|
66
|
+
export function renderSafeAdditivePostgres(operation: SafeAdditiveSchemaOperation): string {
|
|
67
|
+
switch (operation.kind) {
|
|
68
|
+
case "createSchema": return `CREATE SCHEMA ${q(operation.schema)}`;
|
|
69
|
+
case "createTable": return createTable(operation.table);
|
|
70
|
+
case "addColumn": return `ALTER TABLE ${tableName(operation.table)} ADD COLUMN ${column(operation.column)}`;
|
|
71
|
+
case "addCheck": return `ALTER TABLE ${tableName(operation.table)} ADD CONSTRAINT ${q(operation.check.name)} CHECK (${renderCheck(operation.check.expression as never, q)})`;
|
|
72
|
+
case "addForeignKey": return `ALTER TABLE ${tableName(operation.table)} ADD CONSTRAINT ${q(operation.foreignKey.name)} FOREIGN KEY (${operation.foreignKey.columns.map(q).join(", ")}) REFERENCES ${q(operation.foreignKey.target.schema)}.${q(operation.foreignKey.target.table)} (${operation.foreignKey.targetColumns.map(q).join(", ")}) ON DELETE ${action(operation.foreignKey.onDelete)} ON UPDATE ${action(operation.foreignKey.onUpdate)}`;
|
|
73
|
+
case "createIndex": return `CREATE ${operation.index.unique ? "UNIQUE " : ""}INDEX ${q(operation.index.name)} ON ${tableName(operation.table)} (${operation.index.columns.map(q).join(", ")})`;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
function createTable(table: ExpectedTable): string {
|
|
77
|
+
const parts = table.columns.map(column);
|
|
78
|
+
parts.push(`CONSTRAINT ${q(table.primaryKey.name)} PRIMARY KEY (${table.primaryKey.columns.map(q).join(", ")})`);
|
|
79
|
+
for (const check of table.checks) parts.push(`CONSTRAINT ${q(check.name)} CHECK (${renderCheck(check.expression as never, q)})`);
|
|
80
|
+
return `CREATE TABLE ${tableName(table)} (${parts.join(", ")})`;
|
|
81
|
+
}
|
|
82
|
+
function column(value: ExpectedColumn): string {
|
|
83
|
+
const pieces = [q(value.column), type(value.physicalType)];
|
|
84
|
+
if (value.generation === "identityByDefault") pieces.push("GENERATED BY DEFAULT AS IDENTITY");
|
|
85
|
+
if (value.default.kind !== "none") pieces.push(`DEFAULT ${literal(value.default, value.physicalType)}`);
|
|
86
|
+
if (!value.nullable) pieces.push("NOT NULL");
|
|
87
|
+
return pieces.join(" ");
|
|
88
|
+
}
|
|
89
|
+
function literal(value: ExpectedColumn["default"], physicalType: string): string {
|
|
90
|
+
if (physicalType === "json") {
|
|
91
|
+
const json = value.kind === "null" ? "null" : value.kind === "boolean" || value.kind === "number" ? String(value.value) : value.kind === "string" ? JSON.stringify(value.value) : undefined;
|
|
92
|
+
if (json === undefined) throw new Error("Unrenderable PostgreSQL JSON schema default.");
|
|
93
|
+
return `'${json.replaceAll("'", "''")}'::jsonb`;
|
|
94
|
+
}
|
|
95
|
+
switch (value.kind) { case "null": return "NULL"; case "boolean": return value.value ? "TRUE" : "FALSE"; case "number": return String(value.value); case "string": return `'${value.value.replaceAll("'", "''")}'`; case "uuidV4": return "gen_random_uuid()"; default: throw new Error("Unrenderable PostgreSQL schema default."); }
|
|
96
|
+
}
|
|
97
|
+
function type(value: string): string { return value === "integer" ? "bigint" : value === "real" ? "double precision" : value === "datetime" ? "timestamptz" : value === "json" ? "jsonb" : value; }
|
|
98
|
+
function q(value: string): string { return `"${value.replaceAll('"', '""')}"`; }
|
|
99
|
+
function tableName(table: Pick<ExpectedTable, "schema" | "table">): string { return `${q(table.schema)}.${q(table.table)}`; }
|
|
100
|
+
function action(value: string): string { return value === "noAction" ? "NO ACTION" : value === "setNull" ? "SET NULL" : value.toUpperCase(); }
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import type { DatabaseProvider, SchemaAdmissionScope } from "../Providers/types";
|
|
2
|
+
import { SchemaAdmissionError, SchemaMigrationRequiredError, SchemaVerificationError } from "../errors";
|
|
3
|
+
import type { OrmModel } from "../Metadata/OrmModel";
|
|
4
|
+
import { compileExpectedSchema, type OrmExpectedSchema } from "./ExpectedSchema";
|
|
5
|
+
import { ExactSchemaVerifier } from "./ExactSchemaVerifier";
|
|
6
|
+
import { classifySafeAdditive, renderSafeAdditivePostgres } from "./SafeAdditiveSchema";
|
|
7
|
+
|
|
8
|
+
/** PostgreSQL-private trace boundary; deliberately absent from public capability types. */
|
|
9
|
+
type TraceableSchemaAdmissionScope = SchemaAdmissionScope & {
|
|
10
|
+
readonly executeSchemaAdmission?: (sql: string, operation: string) => ReturnType<SchemaAdmissionScope["execute"]>;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
/** PostgreSQL-only create-missing-whole-tables and exact admission. */
|
|
14
|
+
export class SchemaAdmissionEngine {
|
|
15
|
+
constructor(private readonly provider: DatabaseProvider, private readonly models: OrmModel) {}
|
|
16
|
+
async ensureCreated(): Promise<void> {
|
|
17
|
+
let expected: OrmExpectedSchema;
|
|
18
|
+
try {
|
|
19
|
+
expected = compileExpectedSchema(this.models);
|
|
20
|
+
} catch {
|
|
21
|
+
throw new SchemaAdmissionError("ORM_SCHEMA_MODEL_INVALID", "The declared ORM model cannot be admitted.");
|
|
22
|
+
}
|
|
23
|
+
const capability = this.provider.schemaAdmissionCapability;
|
|
24
|
+
if (!capability || this.provider.name !== "postgres" || capability.provider !== "postgres") throw new SchemaAdmissionError("ORM_SCHEMA_PROVIDER_UNSUPPORTED", "PostgreSQL schema admission capability is unavailable.");
|
|
25
|
+
if (capability.version !== 1 || !capability.distributedLock || !capability.transactionalDdl || !capability.exactIntrospection) {
|
|
26
|
+
throw new SchemaAdmissionError("ORM_SCHEMA_ATOMICITY_UNAVAILABLE", "PostgreSQL schema admission cannot guarantee atomic exact verification.");
|
|
27
|
+
}
|
|
28
|
+
try {
|
|
29
|
+
await capability.withSchemaAdmission([...new Set(expected.tables.map((table) => table.schema))], async (scope) => this.admit(scope, expected));
|
|
30
|
+
} catch (error) {
|
|
31
|
+
if (error instanceof SchemaAdmissionError) throw error;
|
|
32
|
+
throw new SchemaAdmissionError("ORM_SCHEMA_ATOMICITY_UNAVAILABLE", "PostgreSQL schema admission could not complete safely.");
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
private async admit(scope: SchemaAdmissionScope, expected: OrmExpectedSchema): Promise<void> {
|
|
36
|
+
const before = await scope.introspectExpected(expected);
|
|
37
|
+
const initial = new ExactSchemaVerifier().verify(expected, before, true);
|
|
38
|
+
const preflight = classifySafeAdditive(expected, before, initial);
|
|
39
|
+
if (preflight.hardDifferences.length) {
|
|
40
|
+
if (preflight.hardDifferences.some((difference) => difference.code === "catalog.unsupported")) throw new SchemaAdmissionError("ORM_SCHEMA_CATALOG_UNSUPPORTED", "PostgreSQL catalog contains a schema form unsupported by exact admission.");
|
|
41
|
+
throw new SchemaMigrationRequiredError(preflight.verification);
|
|
42
|
+
}
|
|
43
|
+
for (const operation of preflight.plan ?? []) {
|
|
44
|
+
try {
|
|
45
|
+
const sql = renderSafeAdditivePostgres(operation);
|
|
46
|
+
const traceable = scope as TraceableSchemaAdmissionScope;
|
|
47
|
+
if (traceable.executeSchemaAdmission) await traceable.executeSchemaAdmission(sql, operation.kind);
|
|
48
|
+
else await scope.execute(sql, []);
|
|
49
|
+
}
|
|
50
|
+
catch (error) { throw this.mapDdlError(operation.kind, error); }
|
|
51
|
+
}
|
|
52
|
+
const final = new ExactSchemaVerifier().verify(expected, await scope.introspectExpected(expected));
|
|
53
|
+
if (!final.compatible) throw new SchemaVerificationError(final);
|
|
54
|
+
}
|
|
55
|
+
private mapDdlError(kind: string, error: unknown): SchemaAdmissionError {
|
|
56
|
+
const sqlState = typeof error === "object" && error !== null
|
|
57
|
+
? String((error as { code?: unknown; sqlState?: unknown; errno?: unknown }).sqlState ?? (error as { errno?: unknown }).errno ?? (error as { code?: unknown }).code ?? "")
|
|
58
|
+
: "";
|
|
59
|
+
if (["23502", "23503", "23505", "23514"].includes(sqlState)) return new SchemaAdmissionError("ORM_SCHEMA_ADDITIVE_DATA_VIOLATION", "Existing PostgreSQL data violates the declared additive schema change.");
|
|
60
|
+
return new SchemaAdmissionError(kind === "createSchema" || kind === "createTable" ? "ORM_SCHEMA_CREATE_FAILED" : "ORM_SCHEMA_ADDITIVE_DDL_FAILED", "PostgreSQL additive schema admission failed.");
|
|
61
|
+
}
|
|
62
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { entityStorageKey } from "./tableKey";
|
|
2
|
+
import type { EntityModel, IndexModel, PropertyModel } from "../Metadata/types";
|
|
3
|
+
import type { IntrospectedSchema, IntrospectedTable } from "./introspection";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Additive schema change operation. Destructive changes (drop/type change) never
|
|
7
|
+
* get here; they are recorded as warnings so no data is lost.
|
|
8
|
+
*/
|
|
9
|
+
export type AdditiveSchemaOperation =
|
|
10
|
+
| { readonly kind: "createTable"; readonly model: EntityModel }
|
|
11
|
+
| { readonly kind: "addColumn"; readonly model: EntityModel; readonly property: PropertyModel }
|
|
12
|
+
| { readonly kind: "createIndex"; readonly model: EntityModel; readonly index: IndexModel };
|
|
13
|
+
|
|
14
|
+
export interface SchemaDiff {
|
|
15
|
+
readonly operations: readonly AdditiveSchemaOperation[];
|
|
16
|
+
/** Destructive differences found, which the auto mode leaves alone. */
|
|
17
|
+
readonly warnings: readonly string[];
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Compares the target model (the context entities) with the actual database
|
|
22
|
+
* schema and returns a list of additive operations. The current state comes
|
|
23
|
+
* from introspection; no separate snapshot file is needed.
|
|
24
|
+
*/
|
|
25
|
+
export class SchemaDiffer {
|
|
26
|
+
diff(targets: readonly EntityModel[], schema: IntrospectedSchema): SchemaDiff {
|
|
27
|
+
const operations: AdditiveSchemaOperation[] = [];
|
|
28
|
+
const warnings: string[] = [];
|
|
29
|
+
|
|
30
|
+
for (const model of targets) {
|
|
31
|
+
const table =
|
|
32
|
+
schema.tables.get(entityStorageKey(model)) ?? schema.tables.get(model.tableName);
|
|
33
|
+
if (!table) {
|
|
34
|
+
// No table: create it whole (with indexes and FKs).
|
|
35
|
+
operations.push({ kind: "createTable", model });
|
|
36
|
+
for (const index of model.indexes) {
|
|
37
|
+
operations.push({ kind: "createIndex", model, index });
|
|
38
|
+
}
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
this.diffColumns(model, table, operations, warnings);
|
|
42
|
+
this.diffIndexes(model, table, operations);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return { operations, warnings };
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
private diffColumns(
|
|
49
|
+
model: EntityModel,
|
|
50
|
+
table: IntrospectedTable,
|
|
51
|
+
operations: AdditiveSchemaOperation[],
|
|
52
|
+
warnings: string[],
|
|
53
|
+
): void {
|
|
54
|
+
for (const property of model.properties) {
|
|
55
|
+
if (!table.columns.has(property.columnName)) {
|
|
56
|
+
operations.push({ kind: "addColumn", model, property });
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
// Destructive: columns exist in the database but not in the model; never dropped automatically.
|
|
60
|
+
const modelColumns = new Set(model.properties.map((property) => property.columnName));
|
|
61
|
+
for (const columnName of table.columns.keys()) {
|
|
62
|
+
if (!modelColumns.has(columnName)) {
|
|
63
|
+
warnings.push(
|
|
64
|
+
`table "${model.tableName}": column "${columnName}" exists in the database but not in the model (left untouched; drop it with an explicit migration).`,
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
private diffIndexes(model: EntityModel, table: IntrospectedTable, operations: AdditiveSchemaOperation[]): void {
|
|
71
|
+
const existing = new Set(table.indexes.map((index) => index.name));
|
|
72
|
+
for (const index of model.indexes) {
|
|
73
|
+
if (!existing.has(index.name)) {
|
|
74
|
+
operations.push({ kind: "createIndex", model, index });
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import type { SafeSchemaDescriptor, SchemaDifference, SchemaDifferenceCode, SchemaVerificationResult } from "./ExactSchemaVerifier";
|
|
2
|
+
|
|
3
|
+
const descriptions: Record<SchemaDifferenceCode, string> = {
|
|
4
|
+
"table.missing": "table is missing",
|
|
5
|
+
"column.missing": "column is missing",
|
|
6
|
+
"column.unexpected": "column exists in the database but is absent from the ORM model",
|
|
7
|
+
"column.type": "column type differs",
|
|
8
|
+
"column.nullability": "column NOT NULL constraint differs",
|
|
9
|
+
"column.default": "column default differs",
|
|
10
|
+
"column.generation": "column generation strategy differs",
|
|
11
|
+
"primaryKey.missing": "primary key is missing",
|
|
12
|
+
"primaryKey.unexpected": "primary key is not declared in the ORM model",
|
|
13
|
+
"primaryKey.name": "primary key name differs",
|
|
14
|
+
"primaryKey.columns": "primary key columns or their order differ",
|
|
15
|
+
"index.missing": "index is missing",
|
|
16
|
+
"index.unexpected": "index is not declared in the ORM model",
|
|
17
|
+
"index.name": "index name differs",
|
|
18
|
+
"index.columns": "index columns or their order differ",
|
|
19
|
+
"index.uniqueness": "index uniqueness differs",
|
|
20
|
+
"index.method": "index method differs",
|
|
21
|
+
"index.unsupportedShape": "index shape is unsupported by exact schema admission",
|
|
22
|
+
"foreignKey.missing": "foreign key is missing",
|
|
23
|
+
"foreignKey.unexpected": "foreign key is not declared in the ORM model",
|
|
24
|
+
"foreignKey.name": "foreign key name differs",
|
|
25
|
+
"foreignKey.columns": "foreign key columns or their order differ",
|
|
26
|
+
"foreignKey.target": "foreign key target differs",
|
|
27
|
+
"foreignKey.actions": "foreign key referential actions differ",
|
|
28
|
+
"foreignKey.deferrable": "foreign key deferrability differs",
|
|
29
|
+
"foreignKey.match": "foreign key match type differs",
|
|
30
|
+
"check.missing": "CHECK constraint is missing",
|
|
31
|
+
"check.unexpected": "CHECK constraint is not declared in the ORM model",
|
|
32
|
+
"check.name": "CHECK constraint name differs",
|
|
33
|
+
"check.expression": "CHECK constraint expression differs",
|
|
34
|
+
"catalog.unsupported": "catalog shape is unsupported by exact schema admission",
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
/** Formats only the verifier's safe descriptors; never SQL, rows or literal defaults. */
|
|
38
|
+
export function formatSchemaDifferences(verification: SchemaVerificationResult): string {
|
|
39
|
+
return verification.differences.map(formatDifference).join("\n");
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function formatDifference(difference: SchemaDifference): string {
|
|
43
|
+
const table = `${JSON.stringify(difference.schema)}.${JSON.stringify(difference.table)}`;
|
|
44
|
+
const object = difference.objectName === undefined ? "" : `, object ${JSON.stringify(difference.objectName)}`;
|
|
45
|
+
return `- Table ${table}${object}: ${descriptions[difference.code]} (${difference.code}); `
|
|
46
|
+
+ `expected (ORM): ${formatDescriptor(difference.expected, difference.code)}; actual (database): ${formatDescriptor(difference.actual, difference.code)}.`;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function formatDescriptor(descriptor: SafeSchemaDescriptor | undefined, code: SchemaDifferenceCode): string {
|
|
50
|
+
if (!descriptor) return "unspecified";
|
|
51
|
+
// These kinds intentionally expose fingerprints, even if a caller supplies a value.
|
|
52
|
+
if (descriptor.kind === "canonicalDefault" || descriptor.kind === "canonicalExpression") {
|
|
53
|
+
return descriptor.hash ? `${descriptor.kind} fingerprint ${JSON.stringify(descriptor.hash)}` : `${descriptor.kind} (value hidden)`;
|
|
54
|
+
}
|
|
55
|
+
if (code === "column.nullability" && descriptor.kind === "present") {
|
|
56
|
+
if (descriptor.value === "true") return "NOT NULL";
|
|
57
|
+
if (descriptor.value === "false") return "NULL allowed";
|
|
58
|
+
}
|
|
59
|
+
if (descriptor.values) return JSON.stringify(descriptor.values);
|
|
60
|
+
if (descriptor.value !== undefined) return JSON.stringify(descriptor.value);
|
|
61
|
+
return descriptor.kind;
|
|
62
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Snapshot of the actual database schema obtained by introspection. The source
|
|
3
|
+
* of the "current" state for the additive auto-migration (the target is the
|
|
4
|
+
* model from the decorators).
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export interface IntrospectedColumn {
|
|
8
|
+
readonly name: string;
|
|
9
|
+
readonly notNull: boolean;
|
|
10
|
+
readonly isPrimaryKey: boolean;
|
|
11
|
+
/** Strict providers report canonical physical details; absent is fail-closed for exact verification. */
|
|
12
|
+
readonly physicalType?: string;
|
|
13
|
+
readonly default?: CanonicalDefault;
|
|
14
|
+
readonly generation?: GenerationStrategy;
|
|
15
|
+
/** Catalog form could not be decoded into the closed strict-v1 domain. */
|
|
16
|
+
readonly unsupported?: boolean;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface IntrospectedIndex {
|
|
20
|
+
readonly name: string;
|
|
21
|
+
readonly columns: readonly string[];
|
|
22
|
+
readonly unique: boolean;
|
|
23
|
+
readonly method?: "btree";
|
|
24
|
+
readonly backingConstraint?: boolean;
|
|
25
|
+
readonly predicate?: string;
|
|
26
|
+
readonly unsupported?: boolean;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export type CanonicalDefault = { readonly kind: "none" | "null" | "currentTimestamp" | "uuidV4" } | { readonly kind: "boolean"; readonly value: boolean } | { readonly kind: "number"; readonly value: number } | { readonly kind: "string"; readonly value: string };
|
|
30
|
+
export type GenerationStrategy = "none" | "identityByDefault" | "uuidDefault";
|
|
31
|
+
export interface IntrospectedPrimaryKey { readonly name: string; readonly columns: readonly string[] }
|
|
32
|
+
export interface IntrospectedForeignKey { readonly name: string; readonly columns: readonly string[]; readonly targetSchema: string | null; readonly targetTable: string; readonly targetColumns: readonly string[]; readonly onDelete: string; readonly onUpdate: string; readonly deferrable?: boolean; readonly unsupported?: boolean }
|
|
33
|
+
export interface IntrospectedCheck { readonly name: string; readonly expression: unknown; readonly unsupported?: boolean }
|
|
34
|
+
|
|
35
|
+
export interface IntrospectedTable {
|
|
36
|
+
readonly name: string;
|
|
37
|
+
/** Columns by name. */
|
|
38
|
+
readonly columns: ReadonlyMap<string, IntrospectedColumn>;
|
|
39
|
+
readonly indexes: readonly IntrospectedIndex[];
|
|
40
|
+
readonly primaryKey?: IntrospectedPrimaryKey;
|
|
41
|
+
readonly foreignKeys?: readonly IntrospectedForeignKey[];
|
|
42
|
+
readonly checks?: readonly IntrospectedCheck[];
|
|
43
|
+
/** The provider observed an unsupported table-level catalog shape. */
|
|
44
|
+
readonly unsupported?: boolean;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export interface IntrospectedSchema {
|
|
48
|
+
/** Tables by name. */
|
|
49
|
+
readonly tables: ReadonlyMap<string, IntrospectedTable>;
|
|
50
|
+
/** Normalized physical schemas observed by the provider for this admission unit. */
|
|
51
|
+
readonly schemas?: ReadonlySet<string>;
|
|
52
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { isUuidKeyGeneration, type ColumnType, type EntityModel, type PropertyModel } from "../Metadata/types";
|
|
2
|
+
|
|
3
|
+
/** Resolve the physical FK contract without changing logical converter types.
|
|
4
|
+
* UUID storage follows referenced keys, including PK/FK chains and cycles. */
|
|
5
|
+
export function physicalColumnTypes(models: readonly EntityModel[]): ReadonlyMap<PropertyModel, ColumnType | "uuid"> {
|
|
6
|
+
const byCtor = new Map(models.map((model) => [model.ctor, model]));
|
|
7
|
+
const result = new Map<PropertyModel, ColumnType | "uuid">();
|
|
8
|
+
const pairs: [PropertyModel, PropertyModel][] = [];
|
|
9
|
+
for (const model of models) {
|
|
10
|
+
for (const property of model.properties) result.set(property, isUuidKeyGeneration(property.generation) ? "uuid" : property.type);
|
|
11
|
+
for (const fk of model.foreignKeys) {
|
|
12
|
+
const target = byCtor.get(fk.target());
|
|
13
|
+
if (!target) throw new Error("ORM_SCHEMA_CROSS_UNIT_FOREIGN_KEY");
|
|
14
|
+
if (fk.properties.length !== target.key.length) throw new Error("ORM_SCHEMA_FOREIGN_KEY_ARITY");
|
|
15
|
+
fk.properties.forEach((name, index) => {
|
|
16
|
+
const local = model.propertyByName(name);
|
|
17
|
+
if (!local) throw new Error("ORM_SCHEMA_FOREIGN_KEY_PROPERTY");
|
|
18
|
+
pairs.push([local, target.key[index]!]);
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
// Monotonic propagation terminates: each text column can become UUID once.
|
|
23
|
+
let changed: boolean;
|
|
24
|
+
do {
|
|
25
|
+
changed = false;
|
|
26
|
+
for (const [local, target] of pairs) {
|
|
27
|
+
if (result.get(target) === "uuid" && result.get(local) === "text" && local.generation === "none") {
|
|
28
|
+
result.set(local, "uuid");
|
|
29
|
+
changed = true;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
} while (changed);
|
|
33
|
+
for (const [local, target] of pairs) {
|
|
34
|
+
if (result.get(local) !== result.get(target)) throw new Error("ORM_SCHEMA_FOREIGN_KEY_TYPE_MISMATCH");
|
|
35
|
+
}
|
|
36
|
+
return result;
|
|
37
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { EntityModel } from "../Metadata/types";
|
|
2
|
+
|
|
3
|
+
interface TableIdentity { readonly schema?: string; readonly table: string }
|
|
4
|
+
const dynamicIdentities = new WeakMap<EntityModel["ctor"], TableIdentity>();
|
|
5
|
+
|
|
6
|
+
/** Legacy dynamic models expose schema.table in tableName. Retain the
|
|
7
|
+
* original components privately so literal dots are never parsed as SQL. */
|
|
8
|
+
export function registerDynamicTableIdentity(ctor: EntityModel["ctor"], identity: TableIdentity): void {
|
|
9
|
+
dynamicIdentities.set(ctor, Object.freeze({ ...identity }));
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function physicalTableIdentity(model: EntityModel): TableIdentity {
|
|
13
|
+
const dynamic = dynamicIdentities.get(model.ctor);
|
|
14
|
+
if (model.schema === undefined && dynamic && model.tableName === (dynamic.schema ? `${dynamic.schema}.${dynamic.table}` : dynamic.table)) return dynamic;
|
|
15
|
+
return { schema: model.schema, table: model.tableName };
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/** Table key in the introspection / diff for an `EntityModel`. */
|
|
19
|
+
export function entityStorageKey(model: EntityModel): string {
|
|
20
|
+
return model.schema !== undefined ? `${model.schema}.${model.tableName}` : model.tableName;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/** Table key from a PostgreSQL introspection row. */
|
|
24
|
+
export function introspectedTableKey(schema: string, table: string): string {
|
|
25
|
+
return schema === "public" ? table : `${schema}.${table}`;
|
|
26
|
+
}
|