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,107 @@
|
|
|
1
|
+
import type { Row } from "./types";
|
|
2
|
+
import type { IntrospectedColumn, IntrospectedIndex, IntrospectedForeignKey } from "../Schema/introspection";
|
|
3
|
+
import { parseRenderedCheck } from "../Schema/CheckExpression";
|
|
4
|
+
|
|
5
|
+
export function canonicalPostgresColumn(type: string, defaultExpression: string | null, identity: string): Pick<IntrospectedColumn, "physicalType" | "default" | "generation" | "unsupported"> {
|
|
6
|
+
const physicalType = canonicalPostgresType(type);
|
|
7
|
+
const defaultValue = canonicalPostgresDefault(defaultExpression, physicalType);
|
|
8
|
+
const generation = identity === "d" ? "identityByDefault" as const : defaultValue.kind === "uuidV4" ? "uuidDefault" as const : "none" as const;
|
|
9
|
+
return { physicalType, default: defaultValue.value, generation, unsupported: physicalType === "unknown" || defaultValue.unsupported || (identity !== "" && identity !== "d") };
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function canonicalPostgresType(type: string): "integer" | "real" | "text" | "boolean" | "datetime" | "json" | "uuid" | "unknown" {
|
|
13
|
+
switch (type.trim().toLowerCase()) {
|
|
14
|
+
case "smallint": case "integer": case "bigint": return "integer";
|
|
15
|
+
case "real": case "double precision": case "numeric": return "real";
|
|
16
|
+
case "text": case "character varying": case "character": return "text";
|
|
17
|
+
case "boolean": return "boolean";
|
|
18
|
+
case "timestamp with time zone": return "datetime";
|
|
19
|
+
case "json": case "jsonb": return "json";
|
|
20
|
+
case "uuid": return "uuid";
|
|
21
|
+
default: return "unknown";
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/** Exact admission accepts only the physical spellings rendered by PostgresDialect. */
|
|
26
|
+
export function exactPostgresType(type: string, canonical: IntrospectedColumn["physicalType"]): IntrospectedColumn["physicalType"] {
|
|
27
|
+
const raw = type.trim().toLowerCase();
|
|
28
|
+
switch (raw) {
|
|
29
|
+
case "bigint": case "double precision": case "text": case "boolean": case "timestamp with time zone": case "jsonb": case "uuid": return canonical;
|
|
30
|
+
default: return `${canonical ?? "unknown"}:${raw}`;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function canonicalPostgresDefault(value: string | null, physicalType: string): { readonly value: IntrospectedColumn["default"]; readonly kind: "none" | "uuidV4"; readonly unsupported: boolean } {
|
|
35
|
+
if (value === null) return { value: { kind: "none" }, kind: "none", unsupported: false };
|
|
36
|
+
const raw = normalizePostgresDefault(value);
|
|
37
|
+
if (/^null$/i.test(raw)) return { value: { kind: "null" }, kind: "none", unsupported: false };
|
|
38
|
+
if (/^current_timestamp$/i.test(raw) || /^now\(\)$/i.test(raw)) return { value: { kind: "currentTimestamp" }, kind: "none", unsupported: false };
|
|
39
|
+
if (/^gen_random_uuid\(\)$/i.test(raw)) return { value: { kind: "uuidV4" }, kind: "uuidV4", unsupported: false };
|
|
40
|
+
if (/^(true|false)$/i.test(raw)) return { value: { kind: "boolean", value: /^true$/i.test(raw) }, kind: "none", unsupported: false };
|
|
41
|
+
if (/^-?(?:\d+(?:\.\d*)?|\.\d+)(?:e[+-]?\d+)?$/i.test(raw)) {
|
|
42
|
+
const numeric = Number(raw);
|
|
43
|
+
if (Number.isFinite(numeric)) return { value: { kind: "number", value: numeric }, kind: "none", unsupported: false };
|
|
44
|
+
}
|
|
45
|
+
const string = raw.match(/^'((?:''|[^'])*)'$/);
|
|
46
|
+
if (string) {
|
|
47
|
+
const decoded = string[1]!.replaceAll("''", "'");
|
|
48
|
+
if (physicalType === "datetime") {
|
|
49
|
+
const temporal = canonicalTimestamp(decoded);
|
|
50
|
+
return temporal === undefined ? { value: { kind: "none" }, kind: "none", unsupported: true } : { value: { kind: "string", value: temporal }, kind: "none", unsupported: false };
|
|
51
|
+
}
|
|
52
|
+
if (physicalType === "json") {
|
|
53
|
+
try { const json = JSON.parse(decoded); if (json === null) return { value: { kind: "null" }, kind: "none", unsupported: false }; if (typeof json === "boolean") return { value: { kind: "boolean", value: json }, kind: "none", unsupported: false }; if (typeof json === "number" && Number.isFinite(json)) return { value: { kind: "number", value: json }, kind: "none", unsupported: false }; if (typeof json === "string") return { value: { kind: "string", value: json }, kind: "none", unsupported: false }; } catch { /* fail closed below */ }
|
|
54
|
+
return { value: { kind: "none" }, kind: "none", unsupported: true };
|
|
55
|
+
}
|
|
56
|
+
return { value: { kind: "string", value: decoded }, kind: "none", unsupported: false };
|
|
57
|
+
}
|
|
58
|
+
return { value: { kind: "none" }, kind: "none", unsupported: true };
|
|
59
|
+
}
|
|
60
|
+
function canonicalTimestamp(value: string): string | undefined {
|
|
61
|
+
const match = value.match(/^(\d{4}-\d{2}-\d{2})[ T](\d{2}:\d{2}:\d{2})(?:\.(\d+))?([+-]\d{2}(?::?\d{2})?|Z)$/u);
|
|
62
|
+
if (!match) return undefined;
|
|
63
|
+
let offset = match[4]!;
|
|
64
|
+
if (offset !== "Z" && !offset.includes(":")) offset = offset.length === 3 ? `${offset}:00` : `${offset.slice(0, 3)}:${offset.slice(3)}`;
|
|
65
|
+
const iso = `${match[1]}T${match[2]}${match[3] ? `.${match[3]}` : ""}${offset}`;
|
|
66
|
+
return Number.isNaN(Date.parse(iso)) ? undefined : new Date(iso).toISOString().replace(/\.000Z$/u, "Z");
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function normalizePostgresDefault(value: string): string {
|
|
70
|
+
let current = value.trim();
|
|
71
|
+
for (;;) {
|
|
72
|
+
const next = stripPostgresOuter(stripPostgresCasts(current));
|
|
73
|
+
if (next === current) return next;
|
|
74
|
+
current = next;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
function stripPostgresCasts(value: string): string { return value.replace(/::(?:[A-Za-z_][A-Za-z0-9_]*)(?:\s+[A-Za-z_][A-Za-z0-9_]*)*(?:\[\])?$/u, "").trim(); }
|
|
78
|
+
function stripPostgresOuter(value: string): string { while (value.startsWith("(") && value.endsWith(")")) value = value.slice(1, -1).trim(); return value; }
|
|
79
|
+
|
|
80
|
+
export function collectPostgresIndexes(rows: readonly Row[], exact = false): IntrospectedIndex[] {
|
|
81
|
+
const byName = new Map<string, { unique: boolean; columns: string[]; method: "btree" | undefined; backingConstraint: boolean; unsupported: boolean; predicate?: string }>();
|
|
82
|
+
for (const row of rows) {
|
|
83
|
+
const name = String(row.index_name); let index = byName.get(name);
|
|
84
|
+
if (!index) { index = { unique: row.is_unique === true, columns: [], method: String(row.method) === "btree" ? "btree" : undefined, backingConstraint: row.backing_constraint === true, unsupported: row.is_expression === true || row.is_valid !== true || row.is_ready !== true }; if (row.has_predicate === true) index.predicate = "unsupported"; byName.set(name, index); }
|
|
85
|
+
if (row.column_name == null || (exact && row.is_include === true)) index.unsupported = true; else index.columns.push(String(row.column_name));
|
|
86
|
+
}
|
|
87
|
+
return [...byName.entries()].map(([name, value]) => ({ name, unique: value.unique, columns: value.columns, method: value.method, backingConstraint: value.backingConstraint, predicate: value.predicate, unsupported: value.unsupported }));
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export function collectPostgresForeignKeys(rows: readonly Row[], exact = false): IntrospectedForeignKey[] {
|
|
91
|
+
const byName = new Map<string, { columns: string[]; targetColumns: string[]; targetSchema: string; targetTable: string; onDelete: string; onUpdate: string; deferrable: boolean; unsupported: boolean }>();
|
|
92
|
+
for (const row of rows) {
|
|
93
|
+
const name = String(row.constraint_name); let foreignKey = byName.get(name);
|
|
94
|
+
if (!foreignKey) { const onDelete = postgresAction(String(row.delete_code)); const onUpdate = postgresAction(String(row.update_code)); foreignKey = { columns: [], targetColumns: [], targetSchema: String(row.target_schema), targetTable: String(row.target_table), onDelete: onDelete.value, onUpdate: onUpdate.value, deferrable: row.deferrable === true, unsupported: onDelete.unsupported || onUpdate.unsupported || String(row.match_code) !== "s" || (exact && row.validated !== true) }; byName.set(name, foreignKey); }
|
|
95
|
+
foreignKey.columns.push(String(row.column_name)); foreignKey.targetColumns.push(String(row.target_column));
|
|
96
|
+
}
|
|
97
|
+
return [...byName.entries()].map(([name, value]) => ({ name, ...value, targetSchema: value.targetSchema === "public" ? null : value.targetSchema }));
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function postgresAction(code: string): { readonly value: string; readonly unsupported: boolean } { switch (code) { case "a": return { value: "noAction", unsupported: false }; case "r": return { value: "restrict", unsupported: false }; case "c": return { value: "cascade", unsupported: false }; case "n": return { value: "setNull", unsupported: false }; default: return { value: "unknown", unsupported: true }; } }
|
|
101
|
+
|
|
102
|
+
export function canonicalPostgresCheck(name: string, definition: string): { readonly name: string; readonly expression: unknown; readonly unsupported: boolean } {
|
|
103
|
+
const body = definition.trim().match(/^CHECK\s*\((.*)\)$/isu)?.[1]?.replace(/::(?:[A-Za-z_][A-Za-z0-9_]*(?:\[\])?)/gu, "");
|
|
104
|
+
const expression = body === undefined ? undefined : parseRenderedCheck(body);
|
|
105
|
+
return { name, expression: expression ?? { kind: "unsupported" }, unsupported: expression === undefined };
|
|
106
|
+
}
|
|
107
|
+
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { DatabaseProvider } from "./types";
|
|
2
|
+
|
|
3
|
+
const DEFAULT_MAX_PARAMETERS_PER_COMMAND = 900;
|
|
4
|
+
|
|
5
|
+
export function maxRowsPerInsert(provider: DatabaseProvider, columnsPerRow: number): number {
|
|
6
|
+
const maxParameters = positiveInteger(provider.limits?.maxParametersPerCommand, DEFAULT_MAX_PARAMETERS_PER_COMMAND);
|
|
7
|
+
const safeColumnsPerRow = Math.max(1, Math.floor(columnsPerRow));
|
|
8
|
+
const maxRowsByParams = Math.max(1, Math.floor(maxParameters / safeColumnsPerRow));
|
|
9
|
+
const providerRows = optionalPositiveInteger(provider.limits?.maxRowsPerInsert);
|
|
10
|
+
return providerRows === undefined ? maxRowsByParams : Math.max(1, Math.min(providerRows, maxRowsByParams));
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function maxParametersPerInList(provider: DatabaseProvider): number {
|
|
14
|
+
const maxParameters = positiveInteger(provider.limits?.maxParametersPerCommand, DEFAULT_MAX_PARAMETERS_PER_COMMAND);
|
|
15
|
+
const maxInList = positiveInteger(provider.limits?.maxParametersPerInList, maxParameters);
|
|
16
|
+
return Math.max(1, Math.min(maxInList, maxParameters));
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function positiveInteger(value: number | undefined, fallback: number): number {
|
|
20
|
+
const parsed = optionalPositiveInteger(value);
|
|
21
|
+
return parsed ?? fallback;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function optionalPositiveInteger(value: number | undefined): number | undefined {
|
|
25
|
+
if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) {
|
|
26
|
+
return undefined;
|
|
27
|
+
}
|
|
28
|
+
return Math.floor(value);
|
|
29
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { OrmTransactionScopeError } from "../errors";
|
|
2
|
+
|
|
3
|
+
export function positiveTimeout(value: number | undefined, fallback: number, name: string): number {
|
|
4
|
+
const result = value === undefined ? fallback : value;
|
|
5
|
+
if (!Number.isInteger(result) || result <= 0 || result > 2_147_483_647) throw new TypeError(`${name} must be an integer between 1 and 2147483647.`);
|
|
6
|
+
return result;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
/** One deadline; disposing removes both the timer and the caller's listener. */
|
|
10
|
+
export class OperationDeadline {
|
|
11
|
+
readonly controller = new AbortController();
|
|
12
|
+
readonly signal = this.controller.signal;
|
|
13
|
+
private readonly timer: ReturnType<typeof setTimeout>;
|
|
14
|
+
private readonly onAbort = () => this.controller.abort(new OrmTransactionScopeError("ORM operation was aborted."));
|
|
15
|
+
|
|
16
|
+
constructor(timeoutMs: number, private readonly parent?: AbortSignal) {
|
|
17
|
+
if (parent !== undefined && !(parent instanceof AbortSignal)) throw new TypeError("signal must be an AbortSignal.");
|
|
18
|
+
this.timer = setTimeout(() => this.controller.abort(new OrmTransactionScopeError("ORM operation deadline exceeded.")), timeoutMs);
|
|
19
|
+
if (parent?.aborted) this.onAbort();
|
|
20
|
+
else parent?.addEventListener("abort", this.onAbort, { once: true });
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
wait<T>(work: PromiseLike<T>): Promise<T> { return awaitWithSignal(work, this.signal); }
|
|
24
|
+
|
|
25
|
+
dispose(): void {
|
|
26
|
+
clearTimeout(this.timer);
|
|
27
|
+
this.parent?.removeEventListener("abort", this.onAbort);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** The caller owns termination of work; racing alone never proves cleanup. */
|
|
32
|
+
export function awaitWithSignal<T>(work: PromiseLike<T>, signal: AbortSignal): Promise<T> {
|
|
33
|
+
const pending = Promise.resolve(work);
|
|
34
|
+
if (signal.aborted) { void pending.catch(() => {}); return Promise.reject(signal.reason); }
|
|
35
|
+
return new Promise<T>((resolve, reject) => {
|
|
36
|
+
const abort = () => { signal.removeEventListener("abort", abort); reject(signal.reason); };
|
|
37
|
+
signal.addEventListener("abort", abort, { once: true });
|
|
38
|
+
pending.then(
|
|
39
|
+
(value) => { signal.removeEventListener("abort", abort); resolve(value); },
|
|
40
|
+
(error) => { signal.removeEventListener("abort", abort); reject(error); },
|
|
41
|
+
);
|
|
42
|
+
});
|
|
43
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { DatabaseProvider } from "./types";
|
|
2
|
+
import { knownExecutionStrategyBase } from "../Saving/ExecutionStrategy";
|
|
3
|
+
import { OrmOwnedStoreAdmissionError } from "../errors";
|
|
4
|
+
import type { ExpectedTable } from "../Schema/ExpectedSchema";
|
|
5
|
+
import type { OwnedStoreCatalogSnapshotV1, OwnedStoreRegistrySnapshotV1 } from "../Schema/OwnedStoreCatalog";
|
|
6
|
+
import type { OrmCatalogScopeV1 } from "../Schema/OrmOwnedStore";
|
|
7
|
+
|
|
8
|
+
export interface OwnedStoreSecondaryLockEntryV1 { readonly kind: "store" | "scope"; readonly preimage: Uint8Array; readonly key: bigint; }
|
|
9
|
+
export interface OwnedStoreSecondaryLockPlanV1 { readonly stores: readonly OwnedStoreSecondaryLockEntryV1[]; readonly scopes: readonly OwnedStoreSecondaryLockEntryV1[]; }
|
|
10
|
+
export type OwnedStoreCreateOperationV1 = { readonly kind: "createSchema"; readonly schema: string } | { readonly kind: "createTable"; readonly table: ExpectedTable } | { readonly kind: "addForeignKey"; readonly table: ExpectedTable; readonly foreignKey: ExpectedTable["foreignKeys"][number] } | { readonly kind: "createIndex"; readonly table: ExpectedTable; readonly index: ExpectedTable["indexes"][number] };
|
|
11
|
+
export interface OwnedStoreIdentityInsertV1 { readonly storeKey: string; readonly contract: "bazis.orm-owned-store/v1"; readonly formatVersion: number; readonly ownedSchema: string; readonly tablePrefix: string; readonly ownedScopeHash: `sha256:${string}`; readonly modelHash: `sha256:${string}`; }
|
|
12
|
+
export interface RegistryLockedOwnedStoreSessionV1 { readonly maxIdentifierLength: bigint; inspectRegistry(): Promise<OwnedStoreRegistrySnapshotV1>; lockSecondary(plan: OwnedStoreSecondaryLockPlanV1): Promise<SecondaryLockedOwnedStoreSessionV1>; }
|
|
13
|
+
export interface SecondaryLockedOwnedStoreSessionV1 { inspectCatalog(scopes: readonly OrmCatalogScopeV1[]): Promise<OwnedStoreCatalogSnapshotV1>; createRegistryV1(): Promise<void>; applyCreateOperations(operations: readonly OwnedStoreCreateOperationV1[]): Promise<void>; insertIdentities(rows: readonly OwnedStoreIdentityInsertV1[]): Promise<void>; inspectRegistry(): Promise<OwnedStoreRegistrySnapshotV1>; }
|
|
14
|
+
export interface PostgresOwnedStoreCapability { withOwnedStoreAdmission<T>(signal: AbortSignal | undefined, work: (session: RegistryLockedOwnedStoreSessionV1) => Promise<T>): Promise<T>; }
|
|
15
|
+
const capabilities = new WeakMap<DatabaseProvider, PostgresOwnedStoreCapability>();
|
|
16
|
+
|
|
17
|
+
export function registerPostgresOwnedStoreCapability(provider: DatabaseProvider, capability: PostgresOwnedStoreCapability): void { capabilities.set(provider, capability); }
|
|
18
|
+
export function postgresOwnedStoreCapability(provider: DatabaseProvider): PostgresOwnedStoreCapability | undefined { const base = knownExecutionStrategyBase(provider); return base === undefined ? undefined : capabilities.get(base); }
|
|
19
|
+
export function failure(code: OrmOwnedStoreAdmissionError["code"]): OrmOwnedStoreAdmissionError { return new OrmOwnedStoreAdmissionError(code, code); }
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
2
|
+
import type { DatabaseProvider, DbExecutor, ExecuteResult, Row, SchemaAdmissionScope } from "./types";
|
|
3
|
+
import { knownExecutionStrategyBase } from "../Saving/ExecutionStrategy";
|
|
4
|
+
import type { OrmTransactionScopeOptions, OrmDatabaseTimeV1 } from "../Transactions/OrmTransaction";
|
|
5
|
+
|
|
6
|
+
export type TransactionOperationObserver = <T>(operation: () => Promise<T>) => Promise<T>;
|
|
7
|
+
|
|
8
|
+
function observedExecutor(executor: DbExecutor, observe: TransactionOperationObserver): DbExecutor {
|
|
9
|
+
return {
|
|
10
|
+
query: (sql, params) => observe(() => executor.query(sql, params)),
|
|
11
|
+
execute: (sql, params) => observe(() => executor.execute(sql, params)),
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
export interface CancellableProviderDispatch { cancel(): unknown; readonly settled: Promise<unknown>; }
|
|
15
|
+
export type ProviderDispatchObserver = (dispatch: CancellableProviderDispatch) => void;
|
|
16
|
+
const dispatchObservers = new AsyncLocalStorage<ProviderDispatchObserver>();
|
|
17
|
+
|
|
18
|
+
/** Private ALS bridge used only by provider implementations and the coordinator. */
|
|
19
|
+
export function withProviderDispatchObserver<T>(observer: ProviderDispatchObserver, work: () => T): T {
|
|
20
|
+
return dispatchObservers.run(observer, work);
|
|
21
|
+
}
|
|
22
|
+
export function withoutProviderDispatchObserver<T>(work: () => T): T { return dispatchObservers.exit(work); }
|
|
23
|
+
export function observeProviderDispatch(dispatch: CancellableProviderDispatch): void { dispatchObservers.getStore()?.(dispatch); }
|
|
24
|
+
|
|
25
|
+
const ROOTS = new WeakMap<DatabaseProvider, object>();
|
|
26
|
+
const scopeOptions = new AsyncLocalStorage<OrmTransactionScopeOptions>();
|
|
27
|
+
export function withPostgresScopeOptions<T>(options: OrmTransactionScopeOptions, work: () => T): T { return scopeOptions.run(options, work); }
|
|
28
|
+
export function withoutPostgresScopeOptions<T>(work: () => T): T { return scopeOptions.exit(work); }
|
|
29
|
+
export function currentPostgresScopeOptions(): OrmTransactionScopeOptions | undefined { return scopeOptions.getStore(); }
|
|
30
|
+
|
|
31
|
+
interface PostgresTransactionCapability {
|
|
32
|
+
readonly operationTimeoutMs?: number;
|
|
33
|
+
readonly isOutcomeUncertain?: (error: unknown) => boolean;
|
|
34
|
+
readonly operationSignal?: () => AbortSignal | undefined;
|
|
35
|
+
readonly databaseTime: () => Promise<OrmDatabaseTimeV1>;
|
|
36
|
+
readonly assertScopedClose: () => void | Promise<void>;
|
|
37
|
+
readonly quarantine: () => Promise<void>;
|
|
38
|
+
/** The physical owner settles cancellation and rollback itself; the
|
|
39
|
+
* coordinator must not rely on native Query.cancel or a timed drain. */
|
|
40
|
+
readonly quarantineOnPendingDispatch?: boolean;
|
|
41
|
+
}
|
|
42
|
+
const POSTGRES_CAPABILITIES = new WeakMap<DatabaseProvider, PostgresTransactionCapability>();
|
|
43
|
+
|
|
44
|
+
/** Private registration: PostgreSQL exposes no transaction internals in DatabaseProvider. */
|
|
45
|
+
export function registerPostgresTransactionCapability(provider: DatabaseProvider, capability: PostgresTransactionCapability): void {
|
|
46
|
+
POSTGRES_CAPABILITIES.set(provider, capability);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function postgresTransactionCapability(provider: DatabaseProvider): PostgresTransactionCapability | undefined {
|
|
50
|
+
const base = baseProvider(provider);
|
|
51
|
+
return base ? POSTGRES_CAPABILITIES.get(base) : undefined;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** Private identity is deliberately object identity, never connection settings. */
|
|
55
|
+
export function rootAuthority(provider: DatabaseProvider): object {
|
|
56
|
+
const base = knownExecutionStrategyBase(provider) ?? provider;
|
|
57
|
+
let authority = ROOTS.get(base);
|
|
58
|
+
if (!authority) {
|
|
59
|
+
authority = {};
|
|
60
|
+
ROOTS.set(base, authority);
|
|
61
|
+
}
|
|
62
|
+
return authority;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export function baseProvider(provider: DatabaseProvider): DatabaseProvider | undefined {
|
|
66
|
+
return knownExecutionStrategyBase(provider);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/** Explicit proxy preserves prototype-owned provider methods without object spread. */
|
|
70
|
+
export function createObservedProvider(provider: DatabaseProvider, observe: TransactionOperationObserver, capture?: () => TransactionOperationObserver): DatabaseProvider {
|
|
71
|
+
const schema = provider.schemaAdmissionCapability;
|
|
72
|
+
const fenceSchemaScope = (scope: SchemaAdmissionScope): SchemaAdmissionScope => {
|
|
73
|
+
const scopedObserve = capture?.() ?? observe;
|
|
74
|
+
const executor = observedExecutor(scope, scopedObserve);
|
|
75
|
+
const privateScope = scope as SchemaAdmissionScope & { executeSchemaAdmission?: (sql: string, operation: string) => Promise<ExecuteResult> };
|
|
76
|
+
const result: SchemaAdmissionScope & { executeSchemaAdmission?: (sql: string, operation: string) => Promise<ExecuteResult> } = {
|
|
77
|
+
query: executor.query,
|
|
78
|
+
execute: executor.execute,
|
|
79
|
+
introspectExpected: (expected) => scopedObserve(() => scope.introspectExpected(expected)),
|
|
80
|
+
};
|
|
81
|
+
if (privateScope.executeSchemaAdmission) {
|
|
82
|
+
result.executeSchemaAdmission = (sql, operation) => scopedObserve(() => privateScope.executeSchemaAdmission!(sql, operation));
|
|
83
|
+
}
|
|
84
|
+
return result;
|
|
85
|
+
};
|
|
86
|
+
const result = {
|
|
87
|
+
name: provider.name,
|
|
88
|
+
dialect: provider.dialect,
|
|
89
|
+
limits: provider.limits,
|
|
90
|
+
diagnostics: provider.diagnostics?.bind(provider),
|
|
91
|
+
query: (sql, params): Promise<Row[]> => observe(() => provider.query(sql, params)),
|
|
92
|
+
execute: (sql, params): Promise<ExecuteResult> => observe(() => provider.execute(sql, params)),
|
|
93
|
+
transaction: (work): Promise<unknown> => observe(() => provider.transaction((executor) => work(observedExecutor(executor, capture?.() ?? observe)))),
|
|
94
|
+
transactionScope: provider.transactionScope ? (work): Promise<unknown> => observe(() => provider.transactionScope!((executor) => work(observedExecutor(executor, capture?.() ?? observe)))) : undefined,
|
|
95
|
+
isTransactionActive: provider.isTransactionActive?.bind(provider),
|
|
96
|
+
afterCommit: provider.afterCommit?.bind(provider),
|
|
97
|
+
afterRollback: provider.afterRollback?.bind(provider),
|
|
98
|
+
ping: (signal?: AbortSignal): Promise<boolean> => observe(() => provider.ping(signal)),
|
|
99
|
+
introspect: () => observe(() => provider.introspect()),
|
|
100
|
+
schemaAdmissionCapability: schema ? {
|
|
101
|
+
version: schema.version,
|
|
102
|
+
provider: schema.provider,
|
|
103
|
+
distributedLock: schema.distributedLock,
|
|
104
|
+
transactionalDdl: schema.transactionalDdl,
|
|
105
|
+
exactIntrospection: schema.exactIntrospection,
|
|
106
|
+
withSchemaAdmission: (schemas, work) => observe(() => schema.withSchemaAdmission(schemas, (scope) => work(fenceSchemaScope(scope)))),
|
|
107
|
+
} : undefined,
|
|
108
|
+
withMigrationLock: provider.withMigrationLock ? (work) => observe(() => provider.withMigrationLock!(() => observe(work))) : undefined,
|
|
109
|
+
listen: provider.listen ? (channel, handler) => observe(() => provider.listen!(channel, handler)) : undefined,
|
|
110
|
+
notify: provider.notify ? (channel, payload) => observe(() => provider.notify!(channel, payload)) : undefined,
|
|
111
|
+
// A transaction view must never own, and therefore never close, the root pool.
|
|
112
|
+
close: () => provider.close(),
|
|
113
|
+
} as DatabaseProvider;
|
|
114
|
+
const base = baseProvider(provider);
|
|
115
|
+
if (base) ROOTS.set(result, rootAuthority(base));
|
|
116
|
+
return result;
|
|
117
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { PropertyModel } from "../Metadata/types";
|
|
2
|
+
import type { SqlDialect, SqlParam } from "./types";
|
|
3
|
+
|
|
4
|
+
/** Encodes a property value: converter -> dialect. */
|
|
5
|
+
export function encodeProperty(property: PropertyModel, value: unknown, dialect: SqlDialect): SqlParam {
|
|
6
|
+
const modelValue = property.converter ? property.converter.toProvider(value) : value;
|
|
7
|
+
return dialect.encode(modelValue, property.type);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/** Decodes a column value: dialect -> converter. */
|
|
11
|
+
export function decodeProperty(property: PropertyModel, value: unknown, dialect: SqlDialect): unknown {
|
|
12
|
+
const providerValue = dialect.decode(value, property.type);
|
|
13
|
+
return property.converter ? property.converter.fromProvider(providerValue) : providerValue;
|
|
14
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { ColumnType, EntityModel } from "../Metadata/types";
|
|
2
|
+
import type { ForeignKeyConstraint } from "./types";
|
|
3
|
+
|
|
4
|
+
/** Internal model-backed DDL metadata. Legacy caller-supplied constraints keep
|
|
5
|
+
* their existing columnType and schema.table string contract. */
|
|
6
|
+
interface ResolvedForeignKey {
|
|
7
|
+
readonly target: EntityModel;
|
|
8
|
+
readonly columnTypes: ReadonlyMap<string, ColumnType | "uuid">;
|
|
9
|
+
}
|
|
10
|
+
const resolved = new WeakMap<ForeignKeyConstraint, ResolvedForeignKey>();
|
|
11
|
+
export function bindResolvedForeignKey(constraint: ForeignKeyConstraint, metadata: ResolvedForeignKey): void {
|
|
12
|
+
resolved.set(constraint, metadata);
|
|
13
|
+
}
|
|
14
|
+
export function resolvedForeignKey(constraint: ForeignKeyConstraint): ResolvedForeignKey | undefined {
|
|
15
|
+
return resolved.get(constraint);
|
|
16
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { PostCommitError } from "../errors";
|
|
2
|
+
import type { TransactionCallback } from "./types";
|
|
3
|
+
|
|
4
|
+
const commitFinalizers = new WeakSet<TransactionCallback>();
|
|
5
|
+
|
|
6
|
+
/** Non-barrel tracker cleanup. A confirmed commit releases provisional
|
|
7
|
+
* identities before user callbacks, regardless of registration order. */
|
|
8
|
+
export function registerPostCommitFinalizer(callback: TransactionCallback): void {
|
|
9
|
+
commitFinalizers.add(callback);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export async function runPostCommitCallbacks(callbacks: readonly TransactionCallback[]): Promise<void> {
|
|
13
|
+
const errors = await collectCallbackErrors(callbacks, true);
|
|
14
|
+
errors.push(...await collectCallbackErrors(callbacks, false));
|
|
15
|
+
if (errors.length > 0) {
|
|
16
|
+
throw new PostCommitError(errors);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export async function runRollbackCallbacks(
|
|
21
|
+
callbacks: readonly TransactionCallback[],
|
|
22
|
+
transactionError: unknown,
|
|
23
|
+
): Promise<never> {
|
|
24
|
+
const callbackErrors = await collectCallbackErrors(callbacks);
|
|
25
|
+
if (callbackErrors.length === 0) {
|
|
26
|
+
throw transactionError;
|
|
27
|
+
}
|
|
28
|
+
throw new AggregateError(
|
|
29
|
+
[transactionError, ...callbackErrors],
|
|
30
|
+
"Transaction rolled back, but one or more rollback callbacks also failed.",
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
async function collectCallbackErrors(callbacks: readonly TransactionCallback[], finalizers?: boolean): Promise<unknown[]> {
|
|
35
|
+
const errors: unknown[] = [];
|
|
36
|
+
for (const callback of callbacks) {
|
|
37
|
+
if (finalizers !== undefined && commitFinalizers.has(callback) !== finalizers) continue;
|
|
38
|
+
try {
|
|
39
|
+
await callback();
|
|
40
|
+
} catch (error) {
|
|
41
|
+
errors.push(error);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return errors;
|
|
45
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { DbUpdateError } from "../errors";
|
|
2
|
+
import type { TransactionCallback } from "./types";
|
|
3
|
+
|
|
4
|
+
/** The server's final outcome could not be confirmed after (auto)commit or cancellation. */
|
|
5
|
+
export class TransactionOutcomeUnknownError extends DbUpdateError {
|
|
6
|
+
readonly code = "ORM_TRANSACTION_OUTCOME_UNKNOWN";
|
|
7
|
+
readonly outcome = "unknown";
|
|
8
|
+
constructor(override readonly cause?: unknown, readonly phase: "commit" | "cancellation" = "commit") {
|
|
9
|
+
super(phase === "commit"
|
|
10
|
+
? "Transaction outcome is unknown. Reconcile database state and use a new DbContext before saving again."
|
|
11
|
+
: "Transaction cancellation is unconfirmed. Reconcile database state and use a new DbContext before saving again.");
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function isUnknownTransactionOutcome(error: unknown): boolean {
|
|
16
|
+
const pending = [error];
|
|
17
|
+
const seen = new Set<unknown>();
|
|
18
|
+
while (pending.length) {
|
|
19
|
+
const current = pending.pop();
|
|
20
|
+
if (current === null || (typeof current !== "object" && typeof current !== "function") || seen.has(current)) continue;
|
|
21
|
+
// Excessively wrapped failures are not safe candidates for automatic replay.
|
|
22
|
+
if (seen.size >= 256) return true;
|
|
23
|
+
seen.add(current);
|
|
24
|
+
try {
|
|
25
|
+
const code = Object.getOwnPropertyDescriptor(current, "code");
|
|
26
|
+
if (code && "value" in code && code.value === "ORM_TRANSACTION_OUTCOME_UNKNOWN") return true;
|
|
27
|
+
const cause = Object.getOwnPropertyDescriptor(current, "cause");
|
|
28
|
+
if (cause && "value" in cause) pending.push(cause.value);
|
|
29
|
+
if (current instanceof AggregateError) {
|
|
30
|
+
const errors = Object.getOwnPropertyDescriptor(current, "errors");
|
|
31
|
+
if (errors && "value" in errors && Array.isArray(errors.value)) {
|
|
32
|
+
if (errors.value.length > 256) return true;
|
|
33
|
+
for (let index = 0; index < errors.value.length; index++) {
|
|
34
|
+
const child = Object.getOwnPropertyDescriptor(errors.value, String(index));
|
|
35
|
+
if (child && "value" in child) pending.push(child.value);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
} catch { /* Never replace the original failure while classifying it. */ }
|
|
40
|
+
}
|
|
41
|
+
return false;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** Only an explicit server rollback/constraint rejection proves COMMIT failed.
|
|
45
|
+
* Connection errors (including SQLSTATE 08xxx) never establish that fact. */
|
|
46
|
+
export function isConfirmedCommitRejection(error: unknown): boolean {
|
|
47
|
+
if (error === null || typeof error !== "object") return false;
|
|
48
|
+
try {
|
|
49
|
+
for (const name of ["errno", "code"]) {
|
|
50
|
+
const descriptor = Object.getOwnPropertyDescriptor(error, name);
|
|
51
|
+
const code: unknown = descriptor && "value" in descriptor ? descriptor.value : undefined;
|
|
52
|
+
if (typeof code === "string" && /^(?:40[0-9A-Z]{3}|23[0-9A-Z]{3})$/.test(code) && code !== "40003") return true;
|
|
53
|
+
}
|
|
54
|
+
} catch { return false; }
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/** An explicit statement ErrorResponse proves PostgreSQL rejected this command.
|
|
59
|
+
* Transport loss, shutdown and statement_completion_unknown cannot prove that
|
|
60
|
+
* an autocommit command did not commit before its response was lost. */
|
|
61
|
+
export function isConfirmedStatementRejection(error: unknown): boolean {
|
|
62
|
+
if (error === null || typeof error !== "object") return false;
|
|
63
|
+
try {
|
|
64
|
+
for (const name of ["errno", "code"]) {
|
|
65
|
+
const descriptor = Object.getOwnPropertyDescriptor(error, name);
|
|
66
|
+
const code: unknown = descriptor && "value" in descriptor ? descriptor.value : undefined;
|
|
67
|
+
if (typeof code === "string" && /^[0-9A-Z]{5}$/.test(code)
|
|
68
|
+
&& !/^(?:00|01|02|08)/.test(code) && code !== "40003" && !/^57P0[123]$/.test(code)) return true;
|
|
69
|
+
}
|
|
70
|
+
} catch { return false; }
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// ORM rollback hooks also own provisional tracker state. On an unknown
|
|
75
|
+
// outcome notify only those internal hooks, never user afterRollback callbacks.
|
|
76
|
+
const uncertaintyHooks = new WeakMap<TransactionCallback, () => void>();
|
|
77
|
+
export function registerTransactionUncertainty(callback: TransactionCallback, uncertain: () => void): void {
|
|
78
|
+
uncertaintyHooks.set(callback, uncertain);
|
|
79
|
+
}
|
|
80
|
+
export function notifyTransactionUncertainty(callbacks: readonly TransactionCallback[]): void {
|
|
81
|
+
for (const callback of callbacks) uncertaintyHooks.get(callback)?.();
|
|
82
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { ConcurrentTransactionScopeError } from "../errors";
|
|
2
|
+
import type { AfterCommitCallback, TransactionCallback } from "./types";
|
|
3
|
+
|
|
4
|
+
/** Callback frame owned by one top-level transaction or nested savepoint. */
|
|
5
|
+
export interface TransactionCallbackScope {
|
|
6
|
+
readonly afterCommit: AfterCommitCallback[];
|
|
7
|
+
readonly afterRollback: TransactionCallback[];
|
|
8
|
+
readonly parent?: TransactionCallbackScope;
|
|
9
|
+
activeChild?: symbol;
|
|
10
|
+
rollbackOnly?: unknown;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface ChildTransactionScope {
|
|
14
|
+
readonly callbacks: TransactionCallbackScope;
|
|
15
|
+
readonly ownership: symbol;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function createTransactionCallbackScope(
|
|
19
|
+
parent?: TransactionCallbackScope,
|
|
20
|
+
): TransactionCallbackScope {
|
|
21
|
+
return {
|
|
22
|
+
afterCommit: [],
|
|
23
|
+
afterRollback: [],
|
|
24
|
+
...(parent === undefined ? {} : { parent }),
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Claims the parent's single connection/savepoint stack synchronously. Nested
|
|
30
|
+
* scopes are still allowed because they receive their own callback frame.
|
|
31
|
+
*/
|
|
32
|
+
export function beginChildTransactionScope(parent: TransactionCallbackScope): ChildTransactionScope {
|
|
33
|
+
if (parent.activeChild !== undefined) {
|
|
34
|
+
throw new ConcurrentTransactionScopeError();
|
|
35
|
+
}
|
|
36
|
+
const ownership = Symbol("bazis.transaction-scope");
|
|
37
|
+
parent.activeChild = ownership;
|
|
38
|
+
return { callbacks: createTransactionCallbackScope(parent), ownership };
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function endChildTransactionScope(
|
|
42
|
+
parent: TransactionCallbackScope,
|
|
43
|
+
ownership: symbol,
|
|
44
|
+
): void {
|
|
45
|
+
if (parent.activeChild === ownership) {
|
|
46
|
+
parent.activeChild = undefined;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** Successful savepoint release makes its callbacks part of the parent. */
|
|
51
|
+
export function mergeTransactionScopeCallbacks(
|
|
52
|
+
parent: TransactionCallbackScope,
|
|
53
|
+
child: TransactionCallbackScope,
|
|
54
|
+
): void {
|
|
55
|
+
parent.afterCommit.push(...child.afterCommit);
|
|
56
|
+
parent.afterRollback.push(...child.afterRollback);
|
|
57
|
+
if (child.rollbackOnly !== undefined && parent.rollbackOnly === undefined) {
|
|
58
|
+
parent.rollbackOnly = child.rollbackOnly;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/** A failed savepoint cleanup poisons the whole physical transaction. */
|
|
63
|
+
export function markTransactionRollbackOnly(
|
|
64
|
+
scope: TransactionCallbackScope,
|
|
65
|
+
error: unknown,
|
|
66
|
+
): void {
|
|
67
|
+
let current: TransactionCallbackScope | undefined = scope;
|
|
68
|
+
while (current !== undefined) {
|
|
69
|
+
current.rollbackOnly ??= error;
|
|
70
|
+
current = current.parent;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export function assertTransactionCanCommit(scope: TransactionCallbackScope): void {
|
|
75
|
+
if (scope.rollbackOnly !== undefined) {
|
|
76
|
+
throw scope.rollbackOnly;
|
|
77
|
+
}
|
|
78
|
+
}
|