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,299 @@
|
|
|
1
|
+
import { ModelBuildError } from "../errors";
|
|
2
|
+
import { readRawEntity, type RawProperty } from "./decorators";
|
|
3
|
+
import { defaultTableName, isConventionalKey, resolveColumnType } from "./conventions";
|
|
4
|
+
import { validateCheckAst } from "../Schema/CheckExpression";
|
|
5
|
+
import type {
|
|
6
|
+
EntityModel,
|
|
7
|
+
ForeignKeyModel,
|
|
8
|
+
IndexModel,
|
|
9
|
+
CheckModel,
|
|
10
|
+
KeyGeneration,
|
|
11
|
+
PropertyModel,
|
|
12
|
+
RelationModel,
|
|
13
|
+
} from "./types";
|
|
14
|
+
import type { CanonicalDefault } from "../Schema/introspection";
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Turns raw class metadata (decorators) into a compiled `EntityModel`,
|
|
18
|
+
* applying conventions where there are no explicit settings.
|
|
19
|
+
* Any configuration error is a `ModelBuildError` at startup (fail fast).
|
|
20
|
+
*/
|
|
21
|
+
export class ModelBuilder {
|
|
22
|
+
static build(ctor: new () => object): EntityModel {
|
|
23
|
+
return ModelBuilder.buildGraph(ctor, new Map());
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
private static buildGraph(ctor: new () => object, graph: Map<new () => object, EntityModel>): EntityModel {
|
|
27
|
+
const cached = graph.get(ctor);
|
|
28
|
+
if (cached) return cached;
|
|
29
|
+
const raw = readRawEntity(ctor);
|
|
30
|
+
if (!raw) {
|
|
31
|
+
throw new ModelBuildError(`Class "${ctor.name}" is not an entity. Add the @Entity() decorator.`);
|
|
32
|
+
}
|
|
33
|
+
if (raw.properties.size === 0) {
|
|
34
|
+
throw new ModelBuildError(`Entity "${ctor.name}" has no mapped properties. Annotate fields with @Column()/@Key().`);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const properties: PropertyModel[] = [];
|
|
38
|
+
const indexes: IndexModel[] = [];
|
|
39
|
+
const foreignKeys: ForeignKeyModel[] = [];
|
|
40
|
+
let explicitKey: PropertyModel | undefined;
|
|
41
|
+
|
|
42
|
+
for (const rawProp of raw.properties.values()) {
|
|
43
|
+
const property = ModelBuilder.buildProperty(ctor.name, rawProp);
|
|
44
|
+
properties.push(property);
|
|
45
|
+
if (property.isKey) {
|
|
46
|
+
if (explicitKey) {
|
|
47
|
+
throw new ModelBuildError(
|
|
48
|
+
`Entity "${ctor.name}" declares multiple scalar keys.`,
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
explicitKey = property;
|
|
52
|
+
}
|
|
53
|
+
if (rawProp.index) {
|
|
54
|
+
indexes.push({
|
|
55
|
+
name: rawProp.index.name ?? `ix_${defaultTableName(ctor.name).toLowerCase()}_${property.columnName}`,
|
|
56
|
+
columns: [property.columnName],
|
|
57
|
+
unique: rawProp.index.unique,
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
if (rawProp.fkTarget) {
|
|
61
|
+
foreignKeys.push({ property: property.propertyName, properties: [property.propertyName], target: rawProp.fkTarget, onDelete: "noAction", onUpdate: "noAction" });
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const relations: RelationModel[] = raw.relations.map((relation) => ({
|
|
66
|
+
navigationName: relation.navigationName,
|
|
67
|
+
kind: relation.kind,
|
|
68
|
+
target: relation.target,
|
|
69
|
+
foreignKey: relation.foreignKey,
|
|
70
|
+
}));
|
|
71
|
+
// Reference relations implicitly declare a foreign key for DDL.
|
|
72
|
+
for (const relation of relations) {
|
|
73
|
+
const names = Array.isArray(relation.foreignKey) ? relation.foreignKey : [relation.foreignKey];
|
|
74
|
+
if (relation.kind === "reference" && !foreignKeys.some((fk) => fk.properties.join("\0") === names.join("\0"))) {
|
|
75
|
+
foreignKeys.push({ property: names[0]!, properties: names, target: relation.target, onDelete: "noAction", onUpdate: "noAction" });
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (!explicitKey && !raw.keyDeclaration) {
|
|
80
|
+
const inferredIndex = properties.findIndex((property) => isConventionalKey(property.propertyName, ctor.name));
|
|
81
|
+
if (inferredIndex < 0) {
|
|
82
|
+
throw new ModelBuildError(
|
|
83
|
+
`Entity "${ctor.name}" has no primary key. Mark a property with @Key() or name one "id" / "${ctor.name}Id".`,
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
const base = properties[inferredIndex]!;
|
|
87
|
+
explicitKey = {
|
|
88
|
+
...base,
|
|
89
|
+
isKey: true,
|
|
90
|
+
generation: base.type === "integer" ? "identity" : "none",
|
|
91
|
+
required: true,
|
|
92
|
+
};
|
|
93
|
+
properties[inferredIndex] = explicitKey;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const byName = new Map<string, PropertyModel>();
|
|
97
|
+
for (const property of properties) {
|
|
98
|
+
byName.set(property.propertyName, property);
|
|
99
|
+
}
|
|
100
|
+
const relationByName = new Map<string, RelationModel>();
|
|
101
|
+
const checks: CheckModel[] = (raw.checks ?? []).map((check) => {
|
|
102
|
+
if (raw.checks!.filter((candidate) => candidate.name === check.name).length > 1) throw new ModelBuildError(`Entity "${ctor.name}": duplicate CHECK name "${check.name}".`);
|
|
103
|
+
return check;
|
|
104
|
+
});
|
|
105
|
+
for (const relation of relations) {
|
|
106
|
+
if (byName.has(relation.navigationName)) {
|
|
107
|
+
throw new ModelBuildError(
|
|
108
|
+
`Entity "${ctor.name}": "${relation.navigationName}" is both a column and a navigation. Use distinct names.`,
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
relationByName.set(relation.navigationName, relation);
|
|
112
|
+
}
|
|
113
|
+
// The FK of a reference relation must exist as a mapped column.
|
|
114
|
+
for (const relation of relations) {
|
|
115
|
+
const relationForeignKeys = Array.isArray(relation.foreignKey) ? relation.foreignKey : [relation.foreignKey];
|
|
116
|
+
if (relation.kind === "reference" && relationForeignKeys.some((name) => !byName.has(name))) {
|
|
117
|
+
throw new ModelBuildError(
|
|
118
|
+
`Entity "${ctor.name}": navigation "${relation.navigationName}" references an unmapped foreign key property.`,
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const primaryKey = ModelBuilder.primaryKeyFor(ctor, raw, properties, byName, explicitKey);
|
|
124
|
+
for (const primary of primaryKey) {
|
|
125
|
+
const index = properties.findIndex((property) => property.propertyName === primary.propertyName);
|
|
126
|
+
properties[index] = primary;
|
|
127
|
+
byName.set(primary.propertyName, primary);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const tableName = raw.table ?? defaultTableName(ctor.name);
|
|
131
|
+
const model: EntityModel = {
|
|
132
|
+
ctor,
|
|
133
|
+
name: ctor.name,
|
|
134
|
+
tableName,
|
|
135
|
+
schema: raw.schema,
|
|
136
|
+
properties,
|
|
137
|
+
key: primaryKey,
|
|
138
|
+
keyName: raw.keyDeclaration?.name,
|
|
139
|
+
indexes,
|
|
140
|
+
checks,
|
|
141
|
+
relations,
|
|
142
|
+
foreignKeys,
|
|
143
|
+
queryFilters: raw.queryFilters ?? [],
|
|
144
|
+
softDeleteProperty: raw.softDeleteProperty,
|
|
145
|
+
propertyByName: (name: string) => byName.get(name),
|
|
146
|
+
relationByName: (name: string) => relationByName.get(name),
|
|
147
|
+
};
|
|
148
|
+
graph.set(ctor, model);
|
|
149
|
+
|
|
150
|
+
for (const declared of raw.foreignKeys ?? []) {
|
|
151
|
+
if (new Set(declared.properties).size !== declared.properties.length) throw new ModelBuildError(`Entity "${ctor.name}": foreign key contains duplicate properties.`);
|
|
152
|
+
for (const name of declared.properties) if (!byName.has(name)) throw new ModelBuildError(`Entity "${ctor.name}": foreign key references unknown property "${name}".`);
|
|
153
|
+
const targetKey = ModelBuilder.buildGraph(declared.target(), graph).key;
|
|
154
|
+
if (targetKey.length !== declared.properties.length) throw new ModelBuildError(`Entity "${ctor.name}": foreign key must target the complete primary key.`);
|
|
155
|
+
const locals = declared.properties.map((name) => byName.get(name)!);
|
|
156
|
+
for (let index = 0; index < locals.length; index += 1) if (locals[index]!.type !== targetKey[index]!.type) throw new ModelBuildError(`Entity "${ctor.name}": foreign key component types/order do not match target primary key.`);
|
|
157
|
+
const nullable = locals.map((property) => !property.required);
|
|
158
|
+
if (nullable.some(Boolean) && !nullable.every(Boolean)) throw new ModelBuildError(`Entity "${ctor.name}": nullable composite foreign key must be all nullable or all required.`);
|
|
159
|
+
if ((declared.onDelete === "setNull" || declared.onUpdate === "setNull") && !nullable.every(Boolean)) throw new ModelBuildError(`Entity "${ctor.name}": setNull requires nullable foreign key components.`);
|
|
160
|
+
foreignKeys.push({ property: declared.properties[0]!, properties: declared.properties, name: declared.name ?? `fk_${(raw.table ?? defaultTableName(ctor.name)).toLowerCase()}_${declared.properties.join("_")}`, target: declared.target, onDelete: declared.onDelete ?? "noAction", onUpdate: declared.onUpdate ?? "noAction" });
|
|
161
|
+
if (nullable.every(Boolean) && locals.length > 1) {
|
|
162
|
+
let allNull: CheckModel["expression"] = { kind: "null", left: locals[0]!.propertyName, not: false };
|
|
163
|
+
let allPresent: CheckModel["expression"] = { kind: "null", left: locals[0]!.propertyName, not: true };
|
|
164
|
+
for (const property of locals.slice(1)) { allNull = { kind: "and", left: allNull, right: { kind: "null", left: property.propertyName, not: false } }; allPresent = { kind: "and", left: allPresent, right: { kind: "null", left: property.propertyName, not: true } }; }
|
|
165
|
+
checks.push({ name: `ck_${(raw.table ?? defaultTableName(ctor.name)).toLowerCase()}_${declared.properties.join("_")}_tuple`, expression: { kind: "or", left: allNull, right: allPresent } });
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
for (const check of checks) validateCheckAst(check.expression, properties);
|
|
170
|
+
for (const declared of raw.indexes ?? []) {
|
|
171
|
+
const columns = declared.properties.map((name) => {
|
|
172
|
+
const property = byName.get(name);
|
|
173
|
+
if (!property) throw new ModelBuildError(`Entity "${ctor.name}": index references unknown property "${name}".`);
|
|
174
|
+
return property.columnName;
|
|
175
|
+
});
|
|
176
|
+
if (new Set(columns).size !== columns.length) throw new ModelBuildError(`Entity "${ctor.name}": index contains duplicate properties.`);
|
|
177
|
+
indexes.push({ name: declared.name ?? `ix_${(raw.table ?? defaultTableName(ctor.name)).toLowerCase()}_${columns.join("_")}`, columns, unique: declared.unique });
|
|
178
|
+
}
|
|
179
|
+
const indexNames = new Set<string>();
|
|
180
|
+
for (const index of indexes) {
|
|
181
|
+
if (indexNames.has(index.name)) throw new ModelBuildError(`Entity "${ctor.name}": duplicate index name "${index.name}".`);
|
|
182
|
+
indexNames.add(index.name);
|
|
183
|
+
}
|
|
184
|
+
return model;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
private static buildProperty(entityName: string, raw: RawProperty): PropertyModel {
|
|
188
|
+
const isKey = raw.isKey === true;
|
|
189
|
+
const resolved = resolveColumnType(raw.type, isKey);
|
|
190
|
+
const storageType = resolved.storageType;
|
|
191
|
+
let convention = raw.convention ?? resolved.convention;
|
|
192
|
+
let generated: KeyGeneration = "none";
|
|
193
|
+
if (isKey) {
|
|
194
|
+
if (convention === "uuid" || raw.type === "uuid") {
|
|
195
|
+
generated = raw.uuidVersion === "v7" ? "uuidV7" : "uuid";
|
|
196
|
+
convention = undefined;
|
|
197
|
+
} else if (raw.keyGenerated ?? storageType === "integer") {
|
|
198
|
+
generated = "identity";
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
if (raw.keyGenerated === true && generated !== "identity") {
|
|
202
|
+
throw new ModelBuildError(
|
|
203
|
+
`Entity "${entityName}": key "${raw.propertyName}" has keyGenerated=true but is not an integer identity key.`,
|
|
204
|
+
);
|
|
205
|
+
}
|
|
206
|
+
// The key and semantic timestamp fields are always NOT NULL.
|
|
207
|
+
const required =
|
|
208
|
+
isKey ||
|
|
209
|
+
raw.required === true ||
|
|
210
|
+
raw.nullable === false ||
|
|
211
|
+
resolved.impliedRequired === true;
|
|
212
|
+
const databaseDefault = ModelBuilder.defaultFor(entityName, raw, storageType, isKey, generated, convention, required);
|
|
213
|
+
return {
|
|
214
|
+
propertyName: raw.propertyName,
|
|
215
|
+
columnName: raw.columnName ?? raw.propertyName,
|
|
216
|
+
type: storageType,
|
|
217
|
+
isKey,
|
|
218
|
+
generation: generated,
|
|
219
|
+
required,
|
|
220
|
+
converter: raw.converter,
|
|
221
|
+
convention,
|
|
222
|
+
uuidVersion: raw.uuidVersion,
|
|
223
|
+
databaseDefault,
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
private static primaryKeyFor(
|
|
228
|
+
ctor: new () => object,
|
|
229
|
+
raw: NonNullable<ReturnType<typeof readRawEntity>>,
|
|
230
|
+
properties: PropertyModel[],
|
|
231
|
+
byName: ReadonlyMap<string, PropertyModel>,
|
|
232
|
+
initialKey: PropertyModel | undefined,
|
|
233
|
+
): [PropertyModel, ...PropertyModel[]] {
|
|
234
|
+
let explicitKey = initialKey;
|
|
235
|
+
if (!explicitKey && !raw.keyDeclaration) {
|
|
236
|
+
const inferredIndex = properties.findIndex((property) => isConventionalKey(property.propertyName, ctor.name));
|
|
237
|
+
if (inferredIndex < 0) throw new ModelBuildError(`Entity "${ctor.name}" has no primary key. Mark a property with @Key() or name one "id" / "${ctor.name}Id".`);
|
|
238
|
+
const base = properties[inferredIndex]!;
|
|
239
|
+
explicitKey = { ...base, isKey: true, generation: base.type === "integer" ? "identity" : "none", required: true };
|
|
240
|
+
properties[inferredIndex] = explicitKey;
|
|
241
|
+
}
|
|
242
|
+
const primaryKey = raw.keyDeclaration
|
|
243
|
+
? raw.keyDeclaration.properties.map((name) => {
|
|
244
|
+
const property = byName.get(name);
|
|
245
|
+
if (!property) throw new ModelBuildError(`Entity "${ctor.name}": primary key references unknown property "${name}".`);
|
|
246
|
+
return { ...property, isKey: true, required: true, generation: raw.keyDeclaration!.composite ? "none" : property.generation };
|
|
247
|
+
})
|
|
248
|
+
: [explicitKey!];
|
|
249
|
+
if (new Set(primaryKey.map((property) => property.propertyName)).size !== primaryKey.length) throw new ModelBuildError(`Entity "${ctor.name}": primary key contains duplicate properties.`);
|
|
250
|
+
if (raw.keyDeclaration?.composite && (!raw.keyDeclaration.properties.includes(raw.keyDeclaration.anchor) || raw.keyDeclaration.properties.length < 2)) throw new ModelBuildError(`Entity "${ctor.name}": composite @Key must contain its anchor and at least two properties.`);
|
|
251
|
+
if (primaryKey.length > 1 && primaryKey.some((property) => property.generation !== "none")) throw new ModelBuildError(`Entity "${ctor.name}": generated composite primary-key components are not supported.`);
|
|
252
|
+
if (primaryKey.some((property) => property.generation === "none" && property.databaseDefault.kind !== "none")) throw new ModelBuildError(`Entity "${ctor.name}": primary-key components cannot declare database defaults.`);
|
|
253
|
+
return primaryKey as [PropertyModel, ...PropertyModel[]];
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
private static defaultFor(entityName: string, raw: RawProperty, type: PropertyModel["type"], isKey: boolean, generation: KeyGeneration, convention: PropertyModel["convention"], required: boolean): CanonicalDefault {
|
|
257
|
+
if (raw.default === undefined) return generation === "uuid" ? { kind: "uuidV4" } : { kind: "none" };
|
|
258
|
+
if (isKey || generation !== "none" || convention !== undefined || raw.converter !== undefined) throw new ModelBuildError(`Entity "${entityName}": database default is not allowed on key/generated/converter/convention property "${raw.propertyName}".`);
|
|
259
|
+
const value = raw.default;
|
|
260
|
+
if (value === null) {
|
|
261
|
+
if (required) throw new ModelBuildError(`Entity "${entityName}": NULL database default requires a nullable property "${raw.propertyName}".`);
|
|
262
|
+
return { kind: "null" };
|
|
263
|
+
}
|
|
264
|
+
if (typeof value === "boolean") {
|
|
265
|
+
if (type !== "boolean" && type !== "json") throw new ModelBuildError(`Entity "${entityName}": boolean database default does not match "${raw.propertyName}".`);
|
|
266
|
+
return { kind: "boolean", value };
|
|
267
|
+
}
|
|
268
|
+
if (typeof value === "number") {
|
|
269
|
+
if (!Number.isFinite(value) || (type === "integer" && (!Number.isSafeInteger(value))) || (type !== "integer" && type !== "real" && type !== "json")) throw new ModelBuildError(`Entity "${entityName}": numeric database default is invalid for "${raw.propertyName}".`);
|
|
270
|
+
return { kind: "number", value };
|
|
271
|
+
}
|
|
272
|
+
if (typeof value === "string") {
|
|
273
|
+
if (value.length > 1024) throw new ModelBuildError(`Entity "${entityName}": database default string exceeds 1024 code units.`);
|
|
274
|
+
if (type === "datetime" && !isCanonicalRfc3339(value)) throw new ModelBuildError(`Entity "${entityName}": datetime database default must be canonical RFC3339 with timezone.`);
|
|
275
|
+
if (type !== "text" && type !== "datetime" && type !== "json") throw new ModelBuildError(`Entity "${entityName}": string database default does not match "${raw.propertyName}".`);
|
|
276
|
+
return { kind: "string", value };
|
|
277
|
+
}
|
|
278
|
+
throw new ModelBuildError(`Entity "${entityName}": database default is not a supported literal for "${raw.propertyName}".`);
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
function isCanonicalRfc3339(value: string): boolean {
|
|
283
|
+
const match = value.match(/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(?:\.\d+)?(Z|[+-]\d{2}:\d{2})$/u);
|
|
284
|
+
if (!match) return false;
|
|
285
|
+
const [, year, month, day, hour, minute, second, zone] = match;
|
|
286
|
+
if (year === undefined || month === undefined || day === undefined || hour === undefined || minute === undefined || second === undefined || zone === undefined) return false;
|
|
287
|
+
const numeric: readonly [number, number, number, number, number, number] = [Number(year), Number(month), Number(day), Number(hour), Number(minute), Number(second)];
|
|
288
|
+
if (numeric[1] < 1 || numeric[1] > 12 || numeric[2] < 1 || numeric[3] > 23 || numeric[4] > 59 || numeric[5] > 59) return false;
|
|
289
|
+
const days = new Date(Date.UTC(numeric[0], numeric[1], 0)).getUTCDate();
|
|
290
|
+
if (numeric[2] > days) return false;
|
|
291
|
+
if (zone !== "Z") {
|
|
292
|
+
const [offsetHourText, offsetMinuteText] = zone.slice(1).split(":");
|
|
293
|
+
if (offsetHourText === undefined || offsetMinuteText === undefined) return false;
|
|
294
|
+
const offsetHour = Number(offsetHourText);
|
|
295
|
+
const offsetMinute = Number(offsetMinuteText);
|
|
296
|
+
if (offsetHour > 23 || offsetMinute > 59) return false;
|
|
297
|
+
}
|
|
298
|
+
return true;
|
|
299
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { EntityNotMappedError } from "../errors";
|
|
2
|
+
import { ModelBuilder } from "./ModelBuilder";
|
|
3
|
+
import type { EntityModel } from "./types";
|
|
4
|
+
|
|
5
|
+
type EntityClass = new () => object;
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Registry of the compiled entity models of a context. Built once at startup
|
|
9
|
+
* from the `entities` list (deterministically, without global side effects or
|
|
10
|
+
* reflection, which keeps it binary-friendly).
|
|
11
|
+
*/
|
|
12
|
+
export class OrmModel {
|
|
13
|
+
private readonly byCtor = new Map<EntityClass, EntityModel>();
|
|
14
|
+
private readonly byName = new Map<string, EntityModel>();
|
|
15
|
+
|
|
16
|
+
constructor(entities: readonly EntityClass[]) {
|
|
17
|
+
for (const ctor of entities) {
|
|
18
|
+
const model = ModelBuilder.build(ctor);
|
|
19
|
+
this.byCtor.set(ctor, model);
|
|
20
|
+
this.byName.set(model.name, model);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
get entities(): readonly EntityModel[] {
|
|
25
|
+
return [...this.byCtor.values()];
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Registers an already built `EntityModel` at runtime (for example one built
|
|
30
|
+
* by `DynamicModelBuilder` from a metadata catalog). Registration is idempotent
|
|
31
|
+
* for the same model; registering again under the same name replaces the previous one.
|
|
32
|
+
*
|
|
33
|
+
* This is the only mutating point of the registry; it is used by controlled
|
|
34
|
+
* scenarios (dynamic tables), not by arbitrary code.
|
|
35
|
+
*/
|
|
36
|
+
registerModel(model: EntityModel): void {
|
|
37
|
+
const previous = this.byName.get(model.name);
|
|
38
|
+
if (previous && previous.ctor !== model.ctor) {
|
|
39
|
+
this.byCtor.delete(previous.ctor);
|
|
40
|
+
}
|
|
41
|
+
this.byCtor.set(model.ctor, model);
|
|
42
|
+
this.byName.set(model.name, model);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** Unregisters a dynamic model by name (table archive/drop). */
|
|
46
|
+
unregister(name: string): void {
|
|
47
|
+
const model = this.byName.get(name);
|
|
48
|
+
if (model) {
|
|
49
|
+
this.byCtor.delete(model.ctor);
|
|
50
|
+
this.byName.delete(name);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
tryByCtor(ctor: EntityClass): EntityModel | undefined {
|
|
55
|
+
return this.byCtor.get(ctor);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/** Model by entity/table name (for access to dynamic sets). */
|
|
59
|
+
tryByName(name: string): EntityModel | undefined {
|
|
60
|
+
return this.byName.get(name);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
requireByCtor(ctor: EntityClass): EntityModel {
|
|
64
|
+
const model = this.byCtor.get(ctor);
|
|
65
|
+
if (!model) {
|
|
66
|
+
throw new EntityNotMappedError(ctor.name);
|
|
67
|
+
}
|
|
68
|
+
return model;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** Model for an instance, by its constructor. */
|
|
72
|
+
requireForInstance(entity: object): EntityModel {
|
|
73
|
+
return this.requireByCtor(entity.constructor as EntityClass);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/** Resolves the lazy navigation target thunk into a model. */
|
|
77
|
+
targetModel(target: () => EntityClass): EntityModel {
|
|
78
|
+
return this.requireByCtor(target());
|
|
79
|
+
}
|
|
80
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { createCipheriv, createDecipheriv, createHash, randomBytes } from "node:crypto";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Value converter between the model (a class property) and the provider (an SQL
|
|
5
|
+
* parameter / column value). Applied before/after the dialect's type encode/decode.
|
|
6
|
+
*/
|
|
7
|
+
export interface ValueConverter<TModel = unknown, TProvider = unknown> {
|
|
8
|
+
toProvider(value: TModel): TProvider;
|
|
9
|
+
fromProvider(value: TProvider): TModel;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/** Built-in converters (no external dependencies: Node/Bun `crypto`). */
|
|
13
|
+
export const ValueConverters = {
|
|
14
|
+
/**
|
|
15
|
+
* AES-256-GCM at-rest string encryption. The database stores base64(nonce|ciphertext|tag).
|
|
16
|
+
* `secret` is the application password/key (derived through SHA-256).
|
|
17
|
+
*/
|
|
18
|
+
encrypted(secret: string): ValueConverter<string, string> {
|
|
19
|
+
const key = createHash("sha256").update(secret).digest();
|
|
20
|
+
return {
|
|
21
|
+
toProvider(plaintext: string): string {
|
|
22
|
+
if (plaintext === "") {
|
|
23
|
+
return "";
|
|
24
|
+
}
|
|
25
|
+
const iv = randomBytes(12);
|
|
26
|
+
const cipher = createCipheriv("aes-256-gcm", key, iv);
|
|
27
|
+
const encrypted = Buffer.concat([cipher.update(plaintext, "utf8"), cipher.final()]);
|
|
28
|
+
const tag = cipher.getAuthTag();
|
|
29
|
+
return Buffer.concat([iv, encrypted, tag]).toString("base64");
|
|
30
|
+
},
|
|
31
|
+
fromProvider(stored: string): string {
|
|
32
|
+
if (stored === "") {
|
|
33
|
+
return "";
|
|
34
|
+
}
|
|
35
|
+
const buf = Buffer.from(stored, "base64");
|
|
36
|
+
const iv = buf.subarray(0, 12);
|
|
37
|
+
const tag = buf.subarray(buf.length - 16);
|
|
38
|
+
const ciphertext = buf.subarray(12, buf.length - 16);
|
|
39
|
+
const decipher = createDecipheriv("aes-256-gcm", key, iv);
|
|
40
|
+
decipher.setAuthTag(tag);
|
|
41
|
+
return Buffer.concat([decipher.update(ciphertext), decipher.final()]).toString("utf8");
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
},
|
|
45
|
+
|
|
46
|
+
/** JSON <-> string through serialization (for custom structures on top of a text column). */
|
|
47
|
+
json<T>(): ValueConverter<T, string> {
|
|
48
|
+
return {
|
|
49
|
+
toProvider(value: T): string {
|
|
50
|
+
return JSON.stringify(value ?? null);
|
|
51
|
+
},
|
|
52
|
+
fromProvider(stored: string): T {
|
|
53
|
+
return JSON.parse(stored) as T;
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
},
|
|
57
|
+
};
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Default conventions. Applied in `ModelBuilder`; explicit decorator settings
|
|
3
|
+
* always override what a convention infers.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { ColumnOptionsType, ColumnType, PropertyConvention } from "./types";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Plural form for a table name (simplified English rules).
|
|
10
|
+
* Case is preserved: `User` -> `Users`, `Category` -> `Categories`.
|
|
11
|
+
*/
|
|
12
|
+
export function pluralize(name: string): string {
|
|
13
|
+
if (name.length === 0) {
|
|
14
|
+
return name;
|
|
15
|
+
}
|
|
16
|
+
if (/[^aeiou]y$/i.test(name)) {
|
|
17
|
+
return `${name.slice(0, -1)}ies`;
|
|
18
|
+
}
|
|
19
|
+
if (/(s|x|z|ch|sh)$/i.test(name)) {
|
|
20
|
+
return `${name}es`;
|
|
21
|
+
}
|
|
22
|
+
return `${name}s`;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/** Default table name. */
|
|
26
|
+
export function defaultTableName(className: string): string {
|
|
27
|
+
return pluralize(className);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Whether the property is the primary key by convention: `id` or
|
|
32
|
+
* `<ClassName>Id` (case-insensitive).
|
|
33
|
+
*/
|
|
34
|
+
export function isConventionalKey(propertyName: string, className: string): boolean {
|
|
35
|
+
const lower = propertyName.toLowerCase();
|
|
36
|
+
return lower === "id" || lower === `${className.toLowerCase()}id`;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** Splits a semantic `@Column({ type })` into a physical type and a convention. */
|
|
40
|
+
export function resolveColumnType(
|
|
41
|
+
optionsType: ColumnOptionsType | undefined,
|
|
42
|
+
isKey: boolean,
|
|
43
|
+
): { storageType: ColumnType; convention?: PropertyConvention; impliedRequired?: boolean } {
|
|
44
|
+
switch (optionsType) {
|
|
45
|
+
case "uuid":
|
|
46
|
+
return { storageType: "text", convention: "uuid", impliedRequired: isKey };
|
|
47
|
+
case "createdAt":
|
|
48
|
+
return { storageType: "datetime", convention: "createdAt", impliedRequired: true };
|
|
49
|
+
case "updatedAt":
|
|
50
|
+
return { storageType: "datetime", convention: "updatedAt", impliedRequired: true };
|
|
51
|
+
default:
|
|
52
|
+
return { storageType: optionsType ?? (isKey ? "integer" : "text") };
|
|
53
|
+
}
|
|
54
|
+
}
|