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,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* "Class name -> class" registry for request models (`@RequestModel()`).
|
|
3
|
+
*
|
|
4
|
+
* Generated binding conventions refer to the request body class by name (the
|
|
5
|
+
* generated file is plain data without imports of user modules). The generated
|
|
6
|
+
* target resolves its own DTOs; this registry is the fallback for classes it
|
|
7
|
+
* does not know, such as external DTOs marked with `@RequestModel()`.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/** Marker: several different classes are registered under one name. */
|
|
11
|
+
export const AMBIGUOUS_REQUEST_MODEL: unique symbol = Symbol("ambiguous-request-model");
|
|
12
|
+
|
|
13
|
+
export type RequestModelClass = new () => object;
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Runtime hydration metadata emitted by `bun run di:generate` for a class-
|
|
17
|
+
* typed request-model field. Standard TC39 decorators deliberately do not
|
|
18
|
+
* expose design types, so this tiny registry is the dependency-free bridge
|
|
19
|
+
* from TypeScript source types to the HTTP binder.
|
|
20
|
+
*/
|
|
21
|
+
interface RequestModelFieldShapeBase {
|
|
22
|
+
readonly array?: boolean;
|
|
23
|
+
/** `null` is part of the declared property type. */
|
|
24
|
+
readonly nullable?: boolean;
|
|
25
|
+
/** `null` is part of an array element type. */
|
|
26
|
+
readonly elementNullable?: boolean;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/** A field typed as a request-model class (or an array of them). */
|
|
30
|
+
export interface RequestModelNestedFieldShape extends RequestModelFieldShapeBase {
|
|
31
|
+
readonly model: RequestModelClass;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** A field declared exactly as `string`, `number` or `boolean` (or an array of one). */
|
|
35
|
+
export interface RequestModelPrimitiveFieldShape extends RequestModelFieldShapeBase {
|
|
36
|
+
readonly primitive: RequestModelPrimitive;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export type RequestModelPrimitive = "string" | "number" | "boolean";
|
|
40
|
+
export type RequestModelFieldShape = RequestModelNestedFieldShape | RequestModelPrimitiveFieldShape;
|
|
41
|
+
const PRIMITIVES: ReadonlySet<unknown> = new Set<RequestModelPrimitive>(["string", "number", "boolean"]);
|
|
42
|
+
|
|
43
|
+
export type RequestModelShape = Readonly<Record<string, RequestModelFieldShape>>;
|
|
44
|
+
|
|
45
|
+
let registry = new Map<string, RequestModelClass | typeof AMBIGUOUS_REQUEST_MODEL>();
|
|
46
|
+
// Runtime model constructors are process-owned; Map permits exact generated
|
|
47
|
+
// target rollback without changing the public lookup contract.
|
|
48
|
+
let shapes = new Map<RequestModelClass, RequestModelShape>();
|
|
49
|
+
const FORBIDDEN_SHAPE_KEYS = new Set(["__proto__", "constructor", "prototype"]);
|
|
50
|
+
|
|
51
|
+
/** Registers a request-model class (called by the `@RequestModel()` decorator). */
|
|
52
|
+
export function registerRequestModelClass(ctor: RequestModelClass): void {
|
|
53
|
+
const name = ctor.name;
|
|
54
|
+
if (!name) {
|
|
55
|
+
return; // an anonymous class cannot be addressed by name
|
|
56
|
+
}
|
|
57
|
+
const existing = registry.get(name);
|
|
58
|
+
if (existing === undefined) {
|
|
59
|
+
registry.set(name, ctor);
|
|
60
|
+
} else if (existing !== ctor) {
|
|
61
|
+
registry.set(name, AMBIGUOUS_REQUEST_MODEL);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Class by name: `undefined` if not registered (no `@RequestModel()`),
|
|
67
|
+
* `AMBIGUOUS_REQUEST_MODEL` if the name is ambiguous (two different classes).
|
|
68
|
+
*/
|
|
69
|
+
export function findRequestModelByName(
|
|
70
|
+
name: string,
|
|
71
|
+
): RequestModelClass | typeof AMBIGUOUS_REQUEST_MODEL | undefined {
|
|
72
|
+
return registry.get(name);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/** Registers generated hydration metadata (nested models, primitive types) for one DTO class. */
|
|
76
|
+
export function registerRequestModelShape(ctor: RequestModelClass, shape: RequestModelShape): void {
|
|
77
|
+
const snapshot: Record<string, RequestModelFieldShape> = Object.create(null) as Record<string, RequestModelFieldShape>;
|
|
78
|
+
for (const key of Object.keys(shape)) {
|
|
79
|
+
if (
|
|
80
|
+
FORBIDDEN_SHAPE_KEYS.has(key) ||
|
|
81
|
+
!Object.prototype.hasOwnProperty.call(shape, key)
|
|
82
|
+
) {
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
const field = shape[key] as Partial<RequestModelNestedFieldShape & RequestModelPrimitiveFieldShape> | undefined;
|
|
86
|
+
const nested = typeof field?.model === "function";
|
|
87
|
+
const primitive = PRIMITIVES.has(field?.primitive);
|
|
88
|
+
if (field === undefined || nested === primitive) {
|
|
89
|
+
throw new TypeError(`Invalid request-model shape for ${ctor.name}.${key}`);
|
|
90
|
+
}
|
|
91
|
+
const flags = {
|
|
92
|
+
array: field.array === true || undefined,
|
|
93
|
+
nullable: field.nullable === true || undefined,
|
|
94
|
+
elementNullable: field.elementNullable === true || undefined,
|
|
95
|
+
};
|
|
96
|
+
snapshot[key] = Object.freeze(nested
|
|
97
|
+
? { model: field.model as RequestModelClass, ...flags }
|
|
98
|
+
: { primitive: field.primitive as RequestModelPrimitive, ...flags });
|
|
99
|
+
}
|
|
100
|
+
shapes.set(ctor, Object.freeze(snapshot));
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/** Generated hydration shape for a DTO constructor, if one was registered. */
|
|
104
|
+
export function findRequestModelShape(ctor: RequestModelClass): RequestModelShape | undefined {
|
|
105
|
+
return shapes.get(ctor);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/** Internal generated-runtime transaction support. */
|
|
109
|
+
export function snapshotRequestModelRegistry(): { readonly registry: typeof registry; readonly shapes: typeof shapes } {
|
|
110
|
+
return { registry: new Map(registry), shapes: new Map(shapes) };
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/** Internal generated-runtime transaction support. */
|
|
114
|
+
export function restoreRequestModelRegistry(snapshot: ReturnType<typeof snapshotRequestModelRegistry>): void {
|
|
115
|
+
registry = snapshot.registry;
|
|
116
|
+
shapes = snapshot.shapes;
|
|
117
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import type { Class } from "../../di";
|
|
2
|
+
import type { ActionFilterHooks, HttpMiddleware } from "../Middleware/types";
|
|
3
|
+
import { ownActionMeta, ownMeta } from "./metadata";
|
|
4
|
+
|
|
5
|
+
type AnyClass = abstract new (...args: never[]) => unknown;
|
|
6
|
+
type AnyMethod = (...args: never[]) => unknown;
|
|
7
|
+
type MethodDecorator = (value: AnyMethod, context: ClassMethodDecoratorContext) => void;
|
|
8
|
+
type ClassOrMethodDecorator = (value: AnyClass | AnyMethod, context: ClassDecoratorContext | ClassMethodDecoratorContext) => void;
|
|
9
|
+
|
|
10
|
+
/** Default success status code for the action (`@HttpCode(201)`). */
|
|
11
|
+
export function HttpCode(code: number): MethodDecorator {
|
|
12
|
+
return (_value, context) => {
|
|
13
|
+
ownActionMeta(context.metadata, context.name).httpCode = code;
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/** Response Content-Type for plain-value returns (`@Produces("text/csv")`). */
|
|
18
|
+
export function Produces(contentType: string): MethodDecorator {
|
|
19
|
+
return (_value, context) => {
|
|
20
|
+
ownActionMeta(context.metadata, context.name).produces = contentType;
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/** Required request Content-Type for body bindings; mismatch -> 415. */
|
|
25
|
+
export function Consumes(contentType: string): MethodDecorator {
|
|
26
|
+
return (_value, context) => {
|
|
27
|
+
ownActionMeta(context.metadata, context.name).consumes = contentType;
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Attaches middleware to a controller (class) or a single route (method).
|
|
33
|
+
* Execution order: global -> controller -> route -> action.
|
|
34
|
+
*/
|
|
35
|
+
export function Middleware(...middleware: HttpMiddleware[]): ClassOrMethodDecorator {
|
|
36
|
+
return (_value, context) => {
|
|
37
|
+
if (context.kind === "class") {
|
|
38
|
+
ownMeta(context.metadata).middleware.push(...middleware);
|
|
39
|
+
} else {
|
|
40
|
+
ownActionMeta(context.metadata, context.name).middleware.push(...middleware);
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Action filters (.NET style): `before` runs after binding, `after` may
|
|
47
|
+
* replace the result. Class-level filters wrap method-level ones.
|
|
48
|
+
*/
|
|
49
|
+
export function ActionFilter(filter: ActionFilterHooks): ClassOrMethodDecorator {
|
|
50
|
+
return (_value, context) => {
|
|
51
|
+
if (context.kind === "class") {
|
|
52
|
+
ownMeta(context.metadata).filters.push(filter);
|
|
53
|
+
} else {
|
|
54
|
+
ownActionMeta(context.metadata, context.name).filters.push(filter);
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* API version of a controller (or a single action). Routes of versioned
|
|
61
|
+
* controllers are matched according to `httpModule({ versioning })`:
|
|
62
|
+
* URL segment (`/v1.0/...`), query parameter or header.
|
|
63
|
+
*/
|
|
64
|
+
export function ApiVersion(version: string): ClassOrMethodDecorator {
|
|
65
|
+
return (_value, context) => {
|
|
66
|
+
if (context.kind === "class") {
|
|
67
|
+
ownMeta(context.metadata).version = version;
|
|
68
|
+
} else {
|
|
69
|
+
ownActionMeta(context.metadata, context.name).version = version;
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Declares a controller method as an error handler for the given error type
|
|
76
|
+
* (instanceof match; omit the type to catch everything). The handler receives
|
|
77
|
+
* `(error, ctx)` and returns a result like a regular action:
|
|
78
|
+
*
|
|
79
|
+
* ```ts
|
|
80
|
+
* @Catch(EntityNotFoundError)
|
|
81
|
+
* onMissing(error: EntityNotFoundError) {
|
|
82
|
+
* return NotFound({ error: error.message });
|
|
83
|
+
* }
|
|
84
|
+
* ```
|
|
85
|
+
*
|
|
86
|
+
* Unmatched (or re-thrown) errors fall through to the global error handler.
|
|
87
|
+
*/
|
|
88
|
+
export function Catch(errorType?: Class<Error>): MethodDecorator {
|
|
89
|
+
return (_value, context) => {
|
|
90
|
+
ownMeta(context.metadata).catches.push({ errorType, methodName: context.name });
|
|
91
|
+
};
|
|
92
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { ownMeta } from "./metadata";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Marks a class as an HTTP controller with an optional base path:
|
|
5
|
+
*
|
|
6
|
+
* ```ts
|
|
7
|
+
* @Controller("users")
|
|
8
|
+
* class UsersController {
|
|
9
|
+
* @Get(":id(int)")
|
|
10
|
+
* getUser(id: number) { ... }
|
|
11
|
+
* }
|
|
12
|
+
* ```
|
|
13
|
+
*
|
|
14
|
+
* The controller is a regular DI service: register it in a module
|
|
15
|
+
* (`controllers: [...]` on `BazisModule`, or `httpModule({ controllers: [...] })`)
|
|
16
|
+
* with scoped lifetime and declare constructor dependencies as usual — auto deps work.
|
|
17
|
+
*/
|
|
18
|
+
export function Controller(prefix = "") {
|
|
19
|
+
return (_value: abstract new (...args: never[]) => unknown, context: ClassDecoratorContext): void => {
|
|
20
|
+
const meta = ownMeta(context.metadata);
|
|
21
|
+
meta.isController = true;
|
|
22
|
+
meta.prefix = prefix;
|
|
23
|
+
};
|
|
24
|
+
}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import type { Class } from "../../di";
|
|
2
|
+
import type { ActionFilterHooks, HttpMiddleware } from "../Middleware/types";
|
|
3
|
+
|
|
4
|
+
// Same one-line polyfill as the validation module: Bun executes TC39
|
|
5
|
+
// decorators natively, Symbol.metadata may be missing in the runtime.
|
|
6
|
+
(Symbol as { metadata?: symbol }).metadata ??= Symbol.for("Symbol.metadata");
|
|
7
|
+
|
|
8
|
+
const HTTP_META = Symbol.for("bazis:http:meta");
|
|
9
|
+
|
|
10
|
+
/** One route declared by a method decorator (@Get/@Post/...). */
|
|
11
|
+
export interface RouteDeclaration {
|
|
12
|
+
/** HTTP verb, "*" for @All. */
|
|
13
|
+
readonly httpMethod: string;
|
|
14
|
+
/** Path template relative to the controller prefix (":id(int)", "*rest"). */
|
|
15
|
+
readonly template: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/** Error handler declared with @Catch on a controller method. */
|
|
19
|
+
export interface CatchDeclaration {
|
|
20
|
+
/** Error class to match (instanceof); undefined matches any error. */
|
|
21
|
+
errorType?: Class<Error>;
|
|
22
|
+
methodName: string | symbol;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/** Metadata of a single action (method). */
|
|
26
|
+
export interface ActionMeta {
|
|
27
|
+
routes: RouteDeclaration[];
|
|
28
|
+
httpCode?: number;
|
|
29
|
+
produces?: string;
|
|
30
|
+
consumes?: string;
|
|
31
|
+
version?: string;
|
|
32
|
+
maxBodyBytes?: number;
|
|
33
|
+
middleware: HttpMiddleware[];
|
|
34
|
+
filters: ActionFilterHooks[];
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** Metadata of a controller class (own + inherited via copy-on-write). */
|
|
38
|
+
export interface ControllerMeta {
|
|
39
|
+
/** Set by @Controller. */
|
|
40
|
+
prefix?: string;
|
|
41
|
+
isController: boolean;
|
|
42
|
+
version?: string;
|
|
43
|
+
middleware: HttpMiddleware[];
|
|
44
|
+
filters: ActionFilterHooks[];
|
|
45
|
+
catches: CatchDeclaration[];
|
|
46
|
+
actions: Map<string | symbol, ActionMeta>;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
interface HttpMetadataCarrier {
|
|
50
|
+
[HTTP_META]?: ControllerMeta;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function emptyMeta(): ControllerMeta {
|
|
54
|
+
return { isController: false, middleware: [], filters: [], catches: [], actions: new Map() };
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function cloneMeta(source: ControllerMeta): ControllerMeta {
|
|
58
|
+
const actions = new Map<string | symbol, ActionMeta>();
|
|
59
|
+
for (const [name, action] of source.actions) {
|
|
60
|
+
actions.set(name, {
|
|
61
|
+
...action,
|
|
62
|
+
routes: [...action.routes],
|
|
63
|
+
middleware: [...action.middleware],
|
|
64
|
+
filters: [...action.filters],
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
return {
|
|
68
|
+
...source,
|
|
69
|
+
middleware: [...source.middleware],
|
|
70
|
+
filters: [...source.filters],
|
|
71
|
+
catches: [...source.catches],
|
|
72
|
+
actions,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Own (copy-on-write) controller metadata for the class being decorated.
|
|
78
|
+
* TC39 metadata objects inherit prototypically from the parent class — the
|
|
79
|
+
* first write into a subclass clones the inherited state.
|
|
80
|
+
*/
|
|
81
|
+
export function ownMeta(metadata: object): ControllerMeta {
|
|
82
|
+
const carrier = metadata as HttpMetadataCarrier;
|
|
83
|
+
if (!Object.prototype.hasOwnProperty.call(carrier, HTTP_META)) {
|
|
84
|
+
const inherited = carrier[HTTP_META];
|
|
85
|
+
carrier[HTTP_META] = inherited ? cloneMeta(inherited) : emptyMeta();
|
|
86
|
+
}
|
|
87
|
+
return carrier[HTTP_META]!;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/** Action metadata bucket for a method decorator. */
|
|
91
|
+
export function ownActionMeta(metadata: object, methodName: string | symbol): ActionMeta {
|
|
92
|
+
const meta = ownMeta(metadata);
|
|
93
|
+
let action = meta.actions.get(methodName);
|
|
94
|
+
if (!action) {
|
|
95
|
+
action = { routes: [], middleware: [], filters: [] };
|
|
96
|
+
meta.actions.set(methodName, action);
|
|
97
|
+
}
|
|
98
|
+
return action;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/** Reads controller metadata from a class (undefined if not decorated). */
|
|
102
|
+
export function controllerMetaOf(ctor: object): ControllerMeta | undefined {
|
|
103
|
+
const metadata = (ctor as { [key: symbol]: unknown })[Symbol.metadata as unknown as symbol] as
|
|
104
|
+
| HttpMetadataCarrier
|
|
105
|
+
| undefined;
|
|
106
|
+
return metadata?.[HTTP_META];
|
|
107
|
+
}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import type { HttpMiddleware } from "../Middleware/types";
|
|
2
|
+
import { HttpSetupError } from "../Errors/HttpError";
|
|
3
|
+
import { ownActionMeta } from "./metadata";
|
|
4
|
+
|
|
5
|
+
type MethodDecorator = (value: (...args: never[]) => unknown, context: ClassMethodDecoratorContext) => void;
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Inline action options: the equivalent of separate attribute decorators
|
|
9
|
+
* gathered into one object (the `@Validator({...})` style):
|
|
10
|
+
*
|
|
11
|
+
* ```ts
|
|
12
|
+
* @Post(":id(int)", { code: 201, produces: "application/json" })
|
|
13
|
+
* update(id: number) { ... }
|
|
14
|
+
*
|
|
15
|
+
* @Post({ code: 202 }) // empty path: options as the first argument
|
|
16
|
+
* enqueue() { ... }
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
export interface RouteOptions {
|
|
20
|
+
/** Status of a successful response (= `@HttpCode`). */
|
|
21
|
+
readonly code?: number;
|
|
22
|
+
/** Response Content-Type for plain results (= `@Produces`). */
|
|
23
|
+
readonly produces?: string;
|
|
24
|
+
/** Required request Content-Type for body bindings (= `@Consumes`). */
|
|
25
|
+
readonly consumes?: string;
|
|
26
|
+
/** API version of the action (= `@ApiVersion` on the method). */
|
|
27
|
+
readonly version?: string;
|
|
28
|
+
/** Route middleware (= `@Middleware` on the method). */
|
|
29
|
+
readonly middleware?: readonly HttpMiddleware[];
|
|
30
|
+
/** Maximum body size: an integer and a binary unit together, for example `4mb`. */
|
|
31
|
+
readonly maxBodySize?: `${bigint}${"b" | "kb" | "mb" | "gb"}`;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function route(httpMethod: string, templateOrOptions?: string | RouteOptions, maybeOptions?: RouteOptions): MethodDecorator {
|
|
35
|
+
const template = typeof templateOrOptions === "string" ? templateOrOptions : "";
|
|
36
|
+
const options = typeof templateOrOptions === "object" ? templateOrOptions : maybeOptions;
|
|
37
|
+
return (_value, context) => {
|
|
38
|
+
if (context.static || context.private) {
|
|
39
|
+
throw new Error(`HTTP route decorators support public instance methods only ("${String(context.name)}").`);
|
|
40
|
+
}
|
|
41
|
+
const action = ownActionMeta(context.metadata, context.name);
|
|
42
|
+
action.routes.push({ httpMethod, template });
|
|
43
|
+
if (options) {
|
|
44
|
+
// Options apply to the whole action (like attribute decorators); with
|
|
45
|
+
// several route decorators scalar fields are overwritten and
|
|
46
|
+
// middleware accumulates.
|
|
47
|
+
if (options.code !== undefined) {
|
|
48
|
+
action.httpCode = options.code;
|
|
49
|
+
}
|
|
50
|
+
if (options.produces !== undefined) {
|
|
51
|
+
action.produces = options.produces;
|
|
52
|
+
}
|
|
53
|
+
if (options.consumes !== undefined) {
|
|
54
|
+
action.consumes = options.consumes;
|
|
55
|
+
}
|
|
56
|
+
if (options.version !== undefined) {
|
|
57
|
+
action.version = options.version;
|
|
58
|
+
}
|
|
59
|
+
if (options.middleware !== undefined) {
|
|
60
|
+
action.middleware.push(...options.middleware);
|
|
61
|
+
}
|
|
62
|
+
if (options.maxBodySize !== undefined) {
|
|
63
|
+
const maxBodyBytes = parseRouteMaxBodySize(options.maxBodySize);
|
|
64
|
+
if (action.maxBodyBytes !== undefined && action.maxBodyBytes !== maxBodyBytes) {
|
|
65
|
+
throw new HttpSetupError(
|
|
66
|
+
"HTTP route decorators on one action must resolve maxBodySize to the same byte limit.",
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
action.maxBodyBytes = maxBodyBytes;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function parseRouteMaxBodySize(input: unknown): number {
|
|
76
|
+
const formatError = () => new HttpSetupError(
|
|
77
|
+
"HTTP route maxBodySize must match '<positive integer><b|kb|mb|gb>' (e.g. '4mb').",
|
|
78
|
+
);
|
|
79
|
+
if (typeof input !== "string" || input.length > 18) {
|
|
80
|
+
throw formatError();
|
|
81
|
+
}
|
|
82
|
+
const match = /^([1-9][0-9]{0,15})(b|kb|mb|gb)$/.exec(input);
|
|
83
|
+
if (match === null || match[0] !== input) {
|
|
84
|
+
throw formatError();
|
|
85
|
+
}
|
|
86
|
+
const multiplier = match[2] === "gb"
|
|
87
|
+
? 1_073_741_824n
|
|
88
|
+
: match[2] === "mb"
|
|
89
|
+
? 1_048_576n
|
|
90
|
+
: match[2] === "kb"
|
|
91
|
+
? 1_024n
|
|
92
|
+
: 1n;
|
|
93
|
+
const bytes = BigInt(match[1]!) * multiplier;
|
|
94
|
+
if (bytes > BigInt(Number.MAX_SAFE_INTEGER)) {
|
|
95
|
+
throw new HttpSetupError("HTTP route maxBodySize exceeds Number.MAX_SAFE_INTEGER bytes.");
|
|
96
|
+
}
|
|
97
|
+
return Number(bytes);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
type RouteFactory = {
|
|
101
|
+
(template?: string, options?: RouteOptions): MethodDecorator;
|
|
102
|
+
(options: RouteOptions): MethodDecorator;
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
function createRouteFactory(httpMethod: string): RouteFactory {
|
|
106
|
+
return ((templateOrOptions?: string | RouteOptions, maybeOptions?: RouteOptions) =>
|
|
107
|
+
route(httpMethod, templateOrOptions, maybeOptions)) as RouteFactory;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Route decorators. The template is relative to the controller prefix and
|
|
112
|
+
* supports constrained parameters and a trailing wildcard:
|
|
113
|
+
*
|
|
114
|
+
* - `":id"`: a string parameter;
|
|
115
|
+
* - `":id(int)"`, `":n(number)"`, `":f(bool)"`, `":u(uuid)"`, `":a(alpha)"`:
|
|
116
|
+
* a constrained parameter with auto-conversion (a mismatch -> the route does not match);
|
|
117
|
+
* - `"*rest"`: catch-all, captures the rest of the path (last segment only).
|
|
118
|
+
*
|
|
119
|
+
* The second argument (or the first, if the path is empty) takes inline action
|
|
120
|
+
* options, see {@link RouteOptions}. A method may have several route
|
|
121
|
+
* decorators; the action is reachable through all of them.
|
|
122
|
+
*/
|
|
123
|
+
export const Get = createRouteFactory("GET");
|
|
124
|
+
export const Post = createRouteFactory("POST");
|
|
125
|
+
export const Put = createRouteFactory("PUT");
|
|
126
|
+
export const Patch = createRouteFactory("PATCH");
|
|
127
|
+
export const Delete = createRouteFactory("DELETE");
|
|
128
|
+
export const Options = createRouteFactory("OPTIONS");
|
|
129
|
+
export const Head = createRouteFactory("HEAD");
|
|
130
|
+
/** Matches any HTTP method (lowest priority when choosing). */
|
|
131
|
+
export const All = createRouteFactory("*");
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import type { ModelValidationIssue } from "../Binding/modelValidator";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Base class for errors that map directly to an HTTP response.
|
|
5
|
+
* The global error handler turns any thrown HttpError into
|
|
6
|
+
* `{ error: message, details? }` with the given status code.
|
|
7
|
+
*/
|
|
8
|
+
export class HttpError extends Error {
|
|
9
|
+
constructor(
|
|
10
|
+
readonly status: number,
|
|
11
|
+
message: string,
|
|
12
|
+
readonly details?: unknown,
|
|
13
|
+
) {
|
|
14
|
+
super(message);
|
|
15
|
+
this.name = new.target.name;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export class BadRequestError extends HttpError {
|
|
20
|
+
constructor(message = "Bad Request", details?: unknown) {
|
|
21
|
+
super(400, message, details);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export class UnauthorizedError extends HttpError {
|
|
26
|
+
readonly challenge = "Bearer";
|
|
27
|
+
|
|
28
|
+
constructor(message = "Unauthorized", details?: unknown) {
|
|
29
|
+
super(401, message, details);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export class ForbiddenError extends HttpError {
|
|
34
|
+
constructor(message = "Forbidden", details?: unknown) {
|
|
35
|
+
super(403, message, details);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export class NotFoundError extends HttpError {
|
|
40
|
+
constructor(message = "Not Found", details?: unknown) {
|
|
41
|
+
super(404, message, details);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export class MethodNotAllowedError extends HttpError {
|
|
46
|
+
constructor(readonly allow: readonly string[]) {
|
|
47
|
+
super(405, "Method Not Allowed");
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export class UnsupportedMediaTypeError extends HttpError {
|
|
52
|
+
constructor(expected: string) {
|
|
53
|
+
super(415, `Unsupported Media Type: expected ${expected}`);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export class PayloadTooLargeError extends HttpError {
|
|
58
|
+
constructor(maxBytes: number) {
|
|
59
|
+
super(413, "Payload Too Large", { maxBytes });
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export class TooManyRequestsError extends HttpError {
|
|
64
|
+
constructor(readonly retryAfterSeconds: number) {
|
|
65
|
+
super(429, "Too Many Requests");
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Request body failed model validation (generated DTO binding + `@Validator`
|
|
71
|
+
* rules on the DTO). The error handler renders it as 400 with the full list
|
|
72
|
+
* of validation problems.
|
|
73
|
+
*/
|
|
74
|
+
export class ModelValidationError extends BadRequestError {
|
|
75
|
+
constructor(readonly errors: readonly ModelValidationIssue[]) {
|
|
76
|
+
super(
|
|
77
|
+
"Validation failed",
|
|
78
|
+
errors.map((error) => ({ property: error.property, message: error.message, code: error.code })),
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Misconfigured routes/controllers (duplicate route, bad template, missing
|
|
85
|
+
* @Controller). Thrown at startup, never at request time — fail fast.
|
|
86
|
+
*/
|
|
87
|
+
export class HttpSetupError extends Error {
|
|
88
|
+
constructor(message: string) {
|
|
89
|
+
super(message);
|
|
90
|
+
this.name = "HttpSetupError";
|
|
91
|
+
}
|
|
92
|
+
}
|