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,82 @@
|
|
|
1
|
+
import type { ServiceDefinition } from "./serviceDefinition";
|
|
2
|
+
import type { Class } from "../di";
|
|
3
|
+
import type { GrpcControllerDefinition } from "./contracts";
|
|
4
|
+
import type { RequestModelClass } from "../http/Binding/requestModelRegistry";
|
|
5
|
+
|
|
6
|
+
(Symbol as { metadata?: symbol }).metadata ??= Symbol.for("Symbol.metadata");
|
|
7
|
+
const GRPC_META = Symbol("bazis:grpc:controller");
|
|
8
|
+
|
|
9
|
+
interface ControllerMetadata {
|
|
10
|
+
service?: ServiceDefinition;
|
|
11
|
+
methods: Map<string | symbol, string>;
|
|
12
|
+
requestModels: Map<string | symbol, RequestModelClass>;
|
|
13
|
+
}
|
|
14
|
+
interface Carrier { [GRPC_META]?: ControllerMetadata }
|
|
15
|
+
|
|
16
|
+
function ownMetadata(metadata: object): ControllerMetadata {
|
|
17
|
+
const carrier = metadata as Carrier;
|
|
18
|
+
if (!Object.hasOwn(carrier, GRPC_META)) {
|
|
19
|
+
const parent = carrier[GRPC_META];
|
|
20
|
+
carrier[GRPC_META] = { service: parent?.service, methods: new Map(parent?.methods), requestModels: new Map(parent?.requestModels) };
|
|
21
|
+
}
|
|
22
|
+
return carrier[GRPC_META]!;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/** Bind a controller to a generated codec definition or grpcService(). */
|
|
26
|
+
export function GrpcController(service: ServiceDefinition) {
|
|
27
|
+
return (_value: Class<object>, context: ClassDecoratorContext): void => {
|
|
28
|
+
if (!service || typeof service !== "object" || Object.keys(service).length === 0) {
|
|
29
|
+
throw new TypeError("@GrpcController requires a non-empty gRPC service definition.");
|
|
30
|
+
}
|
|
31
|
+
const snapshot: Record<string, ServiceDefinition[string]> = Object.create(null);
|
|
32
|
+
for (const [name, method] of Object.entries(service)) {
|
|
33
|
+
if (!method || typeof method.path !== "string" || !/^\/[^/]+\/[^/]+$/.test(method.path)
|
|
34
|
+
|| typeof method.requestStream !== "boolean" || typeof method.responseStream !== "boolean"
|
|
35
|
+
|| typeof method.requestDeserialize !== "function" || typeof method.responseSerialize !== "function") {
|
|
36
|
+
throw new TypeError(`Invalid gRPC service method: ${name}.`);
|
|
37
|
+
}
|
|
38
|
+
snapshot[name] = Object.freeze({ ...method });
|
|
39
|
+
}
|
|
40
|
+
ownMetadata(context.metadata).service = Object.freeze(snapshot);
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** Request/response values for unary; AsyncIterable values for streaming sides. */
|
|
45
|
+
export function GrpcMethod(rpcName?: string, requestModel?: RequestModelClass) {
|
|
46
|
+
if (requestModel !== undefined && (typeof requestModel !== "function" || !requestModel.prototype)) {
|
|
47
|
+
throw new TypeError("gRPC requestModel must be a DTO class.");
|
|
48
|
+
}
|
|
49
|
+
return (_value: unknown, context: ClassMethodDecoratorContext): void => {
|
|
50
|
+
if (context.static || context.private) throw new TypeError("@GrpcMethod requires a public instance method.");
|
|
51
|
+
const name = rpcName ?? (typeof context.name === "string" ? context.name : "");
|
|
52
|
+
if (typeof name !== "string" || name.trim().length === 0) throw new TypeError("gRPC method name must not be empty.");
|
|
53
|
+
const meta = ownMetadata(context.metadata);
|
|
54
|
+
meta.methods.set(context.name, name);
|
|
55
|
+
// A redecorated override must not silently retain the base method's DTO.
|
|
56
|
+
if (requestModel === undefined) meta.requestModels.delete(context.name);
|
|
57
|
+
else meta.requestModels.set(context.name, requestModel);
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/** @internal Resolve aliases and reject contract mismatches before opening a port. */
|
|
62
|
+
export function grpcControllerDefinition(controller: Class<object>): GrpcControllerDefinition {
|
|
63
|
+
const carrier = (controller as unknown as { [Symbol.metadata]?: Carrier })[Symbol.metadata];
|
|
64
|
+
const meta = carrier?.[GRPC_META];
|
|
65
|
+
if (!meta?.service) throw new TypeError(`${controller.name} must use @GrpcController().`);
|
|
66
|
+
const methods = new Map<string, string | symbol>();
|
|
67
|
+
for (const [methodName, rpcName] of meta.methods) {
|
|
68
|
+
const keys = Object.keys(meta.service).filter((key) => {
|
|
69
|
+
const rpc = meta.service![key]!;
|
|
70
|
+
return key === rpcName || rpc.originalName === rpcName || rpc.path.split("/").at(-1) === rpcName;
|
|
71
|
+
});
|
|
72
|
+
if (keys.length !== 1) throw new TypeError(`${controller.name}.${String(methodName)}: unknown or ambiguous RPC ${rpcName}.`);
|
|
73
|
+
const key = keys[0]!;
|
|
74
|
+
if (methods.has(key)) throw new TypeError(`${controller.name}: duplicate RPC ${rpcName}.`);
|
|
75
|
+
if (typeof controller.prototype[methodName] !== "function") throw new TypeError(`Missing RPC handler ${String(methodName)}.`);
|
|
76
|
+
methods.set(key, methodName);
|
|
77
|
+
}
|
|
78
|
+
for (const key of Object.keys(meta.service)) {
|
|
79
|
+
if (!methods.has(key)) throw new TypeError(`${controller.name}: RPC ${key} is missing @GrpcMethod().`);
|
|
80
|
+
}
|
|
81
|
+
return Object.freeze({ controller, service: meta.service, methods, requestModels: new Map(meta.requestModels) });
|
|
82
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { singletonFactory, type ProviderDefinition, type Token } from "../di";
|
|
2
|
+
import { GrpcClient } from "./GrpcClient";
|
|
3
|
+
import type { GrpcClientOptions } from "./clientContracts";
|
|
4
|
+
import type { ServiceDefinition } from "./serviceDefinition";
|
|
5
|
+
|
|
6
|
+
/** Container-owned singleton: lazy network connection and automatic dispose(). */
|
|
7
|
+
export function grpcClientProvider(service: ServiceDefinition, options: GrpcClientOptions, token: Token<GrpcClient> = GrpcClient): ProviderDefinition<GrpcClient> {
|
|
8
|
+
return singletonFactory(token, [], () => new GrpcClient(service, options));
|
|
9
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export { GrpcController, GrpcMethod } from "./decorators";
|
|
2
|
+
export { GrpcError } from "./GrpcError";
|
|
3
|
+
export { grpcModule } from "./Grpc.module";
|
|
4
|
+
export { GrpcServer } from "./GrpcServer";
|
|
5
|
+
export { GrpcClient } from "./GrpcClient";
|
|
6
|
+
export { grpcClientProvider } from "./grpcClientProvider";
|
|
7
|
+
export type { GrpcClientOptions, GrpcClientTlsOptions, GrpcCallOptions, GrpcResponse, GrpcResponseStream } from "./clientContracts";
|
|
8
|
+
export { grpcService, loadGrpcPackage } from "./protobuf";
|
|
9
|
+
export type { GrpcContext, GrpcModuleOptions } from "./contracts";
|
|
10
|
+
export { Metadata, type MetadataValue } from "./Metadata";
|
|
11
|
+
export { ServerCredentials } from "./ServerCredentials";
|
|
12
|
+
export { GrpcStatus } from "./GrpcStatus";
|
|
13
|
+
export type { MethodDefinition, ServiceDefinition, PackageDefinition, ServerOptions } from "./serviceDefinition";
|
|
14
|
+
export type { ProtoLoaderOptions } from "./ProtoSchema";
|
|
15
|
+
/** @internal Codegen attachment channel, not an application registration API. */
|
|
16
|
+
export { GRPC_REQUEST_BINDINGS } from "./GrpcBinding.contract";
|
|
17
|
+
export type { ModelValidator, ModelValidationIssue } from "../http/Binding/modelValidator";
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createModuleOwnedProviderChannel, registerModuleOwnedProviderContributor, scoped,
|
|
3
|
+
type Class, type BazisModuleRef,
|
|
4
|
+
} from "../di";
|
|
5
|
+
import type { GrpcControllerDefinition } from "./contracts";
|
|
6
|
+
import { grpcControllerDefinition } from "./decorators";
|
|
7
|
+
|
|
8
|
+
declare module "../di/module/types/BazisModule" {
|
|
9
|
+
interface BazisModuleMetadata {
|
|
10
|
+
/** gRPC controllers, automatically scoped to one RPC by core/grpc. */
|
|
11
|
+
readonly grpcControllers?: readonly Class<object>[];
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export const GRPC_CONTROLLERS = createModuleOwnedProviderChannel<GrpcControllerDefinition, object>("gRPC controllers");
|
|
16
|
+
|
|
17
|
+
registerModuleOwnedProviderContributor((metadata, context) => {
|
|
18
|
+
const seen = new Set<Class<object>>();
|
|
19
|
+
for (const controller of metadata.grpcControllers ?? []) {
|
|
20
|
+
if (seen.has(controller)) continue;
|
|
21
|
+
seen.add(controller);
|
|
22
|
+
context.addScoped(GRPC_CONTROLLERS, scoped(controller), grpcControllerDefinition(controller));
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
/** @internal Discover only the feature tree published by this transport. */
|
|
27
|
+
export function collectGrpcControllers(roots: readonly BazisModuleRef[], extra: readonly Class<object>[] = []): Set<Class<object>> {
|
|
28
|
+
const result = new Set(extra);
|
|
29
|
+
const visited = new Set<BazisModuleRef>();
|
|
30
|
+
const visit = (module: BazisModuleRef): void => {
|
|
31
|
+
if (visited.has(module)) return;
|
|
32
|
+
visited.add(module);
|
|
33
|
+
for (const child of module.imports ?? []) visit(child);
|
|
34
|
+
for (const controller of module.grpcControllers ?? []) result.add(controller);
|
|
35
|
+
};
|
|
36
|
+
for (const root of roots) visit(root);
|
|
37
|
+
return result;
|
|
38
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import type { ServiceDefinition, PackageDefinition } from "./serviceDefinition";
|
|
4
|
+
import { ProtoParser } from "./ProtoParser";
|
|
5
|
+
import { ProtoCodec } from "./ProtoCodec";
|
|
6
|
+
import { resolveProtoType, type ProtoSchema, type ProtoLoaderOptions } from "./ProtoSchema";
|
|
7
|
+
|
|
8
|
+
/** Select a service by its fully qualified protobuf name. */
|
|
9
|
+
export function grpcService(definition: PackageDefinition, serviceName: string): ServiceDefinition {
|
|
10
|
+
const service = definition[serviceName];
|
|
11
|
+
if (!service || "format" in service || Object.keys(service).length === 0) {
|
|
12
|
+
throw new TypeError(`Protobuf service not found: ${serviceName}.`);
|
|
13
|
+
}
|
|
14
|
+
return service as ServiceDefinition;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/** Load proto3 contracts without a package dependency or external compiler. */
|
|
18
|
+
export function loadGrpcPackage(filename: string | readonly string[], options: ProtoLoaderOptions = {}): PackageDefinition {
|
|
19
|
+
validateOptions(options);
|
|
20
|
+
options = Object.freeze({ ...options, includeDirs: options.includeDirs && Object.freeze([...options.includeDirs]) });
|
|
21
|
+
const roots = typeof filename === "string" ? [filename] : filename;
|
|
22
|
+
if (!Array.isArray(roots) || roots.length === 0 || roots.some((file) => typeof file !== "string" || !file)) throw new TypeError("Expected protobuf filename(s).");
|
|
23
|
+
const schema: ProtoSchema = { messages: new Map(), enums: new Map(), services: new Map() };
|
|
24
|
+
const loaded = new Set<string>();
|
|
25
|
+
let schemaBytes = 0;
|
|
26
|
+
const load = (file: string, depth: number): void => {
|
|
27
|
+
file = path.resolve(file);
|
|
28
|
+
if (loaded.has(file)) return;
|
|
29
|
+
if (depth > 64 || loaded.size >= 256) throw new TypeError("Protobuf import graph exceeds limit.");
|
|
30
|
+
loaded.add(file);
|
|
31
|
+
const source = readFileSync(file, "utf8");
|
|
32
|
+
if ((schemaBytes += Buffer.byteLength(source)) > 16 * 1024 * 1024) throw new TypeError("Protobuf schema graph exceeds 16 MiB.");
|
|
33
|
+
const parser = new ProtoParser(source, schema, file);
|
|
34
|
+
parser.parse();
|
|
35
|
+
for (const imported of parser.imports) {
|
|
36
|
+
const candidates = [path.resolve(path.dirname(file), imported), ...(options.includeDirs ?? []).map((dir) => path.resolve(dir, imported))];
|
|
37
|
+
const resolved = candidates.find((candidate) => existsSync(candidate));
|
|
38
|
+
if (!resolved) throw new TypeError("Protobuf import not found: " + imported);
|
|
39
|
+
load(resolved, depth + 1);
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
for (const root of roots) load(root, 0);
|
|
43
|
+
const codec = new ProtoCodec(schema, options);
|
|
44
|
+
const definition: PackageDefinition = Object.create(null);
|
|
45
|
+
for (const name of schema.messages.keys()) definition[name] = { format: "Bazis proto3 message" };
|
|
46
|
+
for (const name of schema.enums.keys()) definition[name] = { format: "Bazis proto3 enum" };
|
|
47
|
+
for (const [name, methods] of schema.services) {
|
|
48
|
+
const service: ServiceDefinition = Object.create(null);
|
|
49
|
+
for (const method of methods) {
|
|
50
|
+
const input = resolveProtoType(schema, method.input, name);
|
|
51
|
+
const output = resolveProtoType(schema, method.output, name);
|
|
52
|
+
if (!schema.messages.has(input) || !schema.messages.has(output)) throw new TypeError("RPC input/output must be protobuf messages.");
|
|
53
|
+
service[method.name] = {
|
|
54
|
+
path: "/" + name + "/" + method.name,
|
|
55
|
+
originalName: method.name[0]!.toLowerCase() + method.name.slice(1),
|
|
56
|
+
requestStream: method.requestStream, responseStream: method.responseStream,
|
|
57
|
+
requestSerialize: (value) => codec.encode(input, value),
|
|
58
|
+
requestDeserialize: (buffer) => codec.decode(input, buffer),
|
|
59
|
+
responseSerialize: (value) => codec.encode(output, value),
|
|
60
|
+
responseDeserialize: (buffer) => codec.decode(output, buffer),
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
definition[name] = service;
|
|
64
|
+
}
|
|
65
|
+
return definition;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function validateOptions(options: ProtoLoaderOptions): void {
|
|
69
|
+
if (!options || typeof options !== "object" || Array.isArray(options)) throw new TypeError("Invalid protobuf options.");
|
|
70
|
+
const booleans = new Set(["keepCase", "defaults", "arrays", "objects", "oneofs"]);
|
|
71
|
+
const known = new Set([...booleans, "longs", "enums", "bytes", "includeDirs"]);
|
|
72
|
+
for (const [key, value] of Object.entries(options)) {
|
|
73
|
+
if (!known.has(key)) throw new TypeError("Unsupported protobuf option: " + key);
|
|
74
|
+
if (booleans.has(key) && typeof value !== "boolean") throw new TypeError("Invalid protobuf option: " + key);
|
|
75
|
+
}
|
|
76
|
+
if (options.longs !== undefined && ![String, Number, BigInt].includes(options.longs)) throw new TypeError("Invalid protobuf longs option.");
|
|
77
|
+
if (options.enums !== undefined && ![String, Number].includes(options.enums)) throw new TypeError("Invalid protobuf enums option.");
|
|
78
|
+
if (options.bytes !== undefined && ![String, Array, Buffer].includes(options.bytes)) throw new TypeError("Invalid protobuf bytes option.");
|
|
79
|
+
if (options.includeDirs !== undefined && (!Array.isArray(options.includeDirs) || options.includeDirs.some((dir) => typeof dir !== "string" || !dir))) throw new TypeError("Invalid protobuf includeDirs.");
|
|
80
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/** A codec contract, compatible structurally with generated protobuf services. */
|
|
2
|
+
export interface MethodDefinition<Request = any, Response = any> {
|
|
3
|
+
readonly path: string;
|
|
4
|
+
readonly requestStream: boolean;
|
|
5
|
+
readonly responseStream: boolean;
|
|
6
|
+
readonly requestSerialize: (value: Request) => Buffer;
|
|
7
|
+
readonly requestDeserialize: (buffer: Buffer) => Request;
|
|
8
|
+
readonly responseSerialize: (value: Response) => Buffer;
|
|
9
|
+
readonly responseDeserialize: (buffer: Buffer) => Response;
|
|
10
|
+
readonly originalName?: string;
|
|
11
|
+
}
|
|
12
|
+
export type ServiceDefinition = Record<string, MethodDefinition>;
|
|
13
|
+
export type PackageDefinition = Record<string, ServiceDefinition | { readonly format: string }>;
|
|
14
|
+
|
|
15
|
+
/** Supported transport controls. Unknown controls fail before opening a port. */
|
|
16
|
+
export interface ServerOptions {
|
|
17
|
+
readonly "grpc.max_receive_message_length"?: number;
|
|
18
|
+
readonly "grpc.max_send_message_length"?: number;
|
|
19
|
+
readonly "grpc.max_concurrent_streams"?: number;
|
|
20
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import {
|
|
2
|
+
setActionAllowAnonymous,
|
|
3
|
+
setActionAuthorize,
|
|
4
|
+
setControllerAllowAnonymous,
|
|
5
|
+
setControllerAuthorize,
|
|
6
|
+
type AuthorizeCheck,
|
|
7
|
+
} from "./metadata";
|
|
8
|
+
|
|
9
|
+
type AnyClass = abstract new (...args: never[]) => unknown;
|
|
10
|
+
type AnyMethod = (...args: never[]) => unknown;
|
|
11
|
+
type ClassOrMethodDecorator = (
|
|
12
|
+
value: AnyClass | AnyMethod,
|
|
13
|
+
context: ClassDecoratorContext | ClassMethodDecoratorContext,
|
|
14
|
+
) => void;
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Protects a controller or a single action: the route gets the
|
|
18
|
+
* {@link AuthorizeCheck} function. The HTTP kernel does not know *what* it
|
|
19
|
+
* checks: JWT, login/password, Telegram sign-in and so on. Several checks
|
|
20
|
+
* can be passed; all of them must pass.
|
|
21
|
+
*
|
|
22
|
+
* ```ts
|
|
23
|
+
* @Authorize(requireTokenKind(TokenKind.Admin)) // access token kind
|
|
24
|
+
* @Authorize(loginMatches) // login/password matched
|
|
25
|
+
* @Authorize(telegramVerified) // Telegram sign-in
|
|
26
|
+
* ```
|
|
27
|
+
*
|
|
28
|
+
* Check result semantics, see {@link AuthorizeCheck}: `false` → 403,
|
|
29
|
+
* `throw` → the status of the thrown `HttpError`.
|
|
30
|
+
*/
|
|
31
|
+
export function Authorize(check: AuthorizeCheck, ...rest: AuthorizeCheck[]): ClassOrMethodDecorator {
|
|
32
|
+
const checks = [check, ...rest];
|
|
33
|
+
|
|
34
|
+
return (_value, context) => {
|
|
35
|
+
if (context.kind === "class") {
|
|
36
|
+
setControllerAuthorize(context.metadata, { checks });
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
setActionAuthorize(context.metadata, context.name, { checks });
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** Public route: overrides `@Authorize` declared on the controller. */
|
|
44
|
+
export function AllowAnonymous(): ClassOrMethodDecorator {
|
|
45
|
+
return (_value, context) => {
|
|
46
|
+
if (context.kind === "class") {
|
|
47
|
+
setControllerAllowAnonymous(context.metadata);
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
setActionAllowAnonymous(context.metadata, context.name);
|
|
51
|
+
};
|
|
52
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { ForbiddenError } from "../Errors/HttpError";
|
|
2
|
+
import type { HttpMiddleware } from "../Middleware/types";
|
|
3
|
+
import type { RouteMiddlewareComposer } from "../options";
|
|
4
|
+
import { resolveAuthorizeMeta } from "./metadata";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Built-in composer for `@Authorize`. The HTTP server puts it first among
|
|
8
|
+
* the per-route composers. For routes that require authorization it returns
|
|
9
|
+
* middleware that runs all checks in order: any that returns `false` → `403`;
|
|
10
|
+
* a check may throw an `HttpError` itself (for example
|
|
11
|
+
* `UnauthorizedError` → `401`).
|
|
12
|
+
*/
|
|
13
|
+
export function createAuthorizeComposer(): RouteMiddlewareComposer {
|
|
14
|
+
return (controllerClass, methodName) => {
|
|
15
|
+
const meta = resolveAuthorizeMeta(controllerClass, methodName);
|
|
16
|
+
if (meta.allowAnonymous || meta.authorize === undefined) {
|
|
17
|
+
return [];
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const { checks } = meta.authorize;
|
|
21
|
+
const middleware: HttpMiddleware = async (ctx, next) => {
|
|
22
|
+
for (const check of checks) {
|
|
23
|
+
if (!(await check(ctx))) {
|
|
24
|
+
throw new ForbiddenError();
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
await next();
|
|
28
|
+
};
|
|
29
|
+
return [middleware];
|
|
30
|
+
};
|
|
31
|
+
}
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import type { HttpContext } from "../HttpContext/HttpContext";
|
|
2
|
+
|
|
3
|
+
// Same one-line polyfill as the rest of the HTTP module: Bun executes TC39
|
|
4
|
+
// decorators natively, but Symbol.metadata may be missing in the runtime.
|
|
5
|
+
(Symbol as { metadata?: symbol }).metadata ??= Symbol.for("Symbol.metadata");
|
|
6
|
+
|
|
7
|
+
const AUTHORIZE_META = Symbol.for("bazis:http:authorize");
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Access check for `@Authorize`. Receives the request context and decides
|
|
11
|
+
* whether to let it through. The HTTP kernel does not know *what* is checked
|
|
12
|
+
* (JWT kind, login/password, a successful Telegram sign-in and so on): that
|
|
13
|
+
* is entirely inside the function.
|
|
14
|
+
*
|
|
15
|
+
* - `true`: access granted;
|
|
16
|
+
* - `false`: access denied (the kernel answers `403 Forbidden`);
|
|
17
|
+
* - `throw`: the function defines the response itself by throwing an `HttpError`
|
|
18
|
+
* (for example `UnauthorizedError` → `401` when there are no credentials at all).
|
|
19
|
+
*
|
|
20
|
+
* Dependencies (services, DB) come from `ctx.services` (the request scope).
|
|
21
|
+
*/
|
|
22
|
+
export type AuthorizeCheck = (ctx: HttpContext) => boolean | Promise<boolean>;
|
|
23
|
+
|
|
24
|
+
/** Authorization requirement: one or more checks (all must pass). */
|
|
25
|
+
export interface AuthorizeOptions {
|
|
26
|
+
readonly checks: readonly AuthorizeCheck[];
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
interface AuthActionMeta {
|
|
30
|
+
authorize?: AuthorizeOptions;
|
|
31
|
+
allowAnonymous?: boolean;
|
|
32
|
+
/** Declaration made on this exact class/method metadata object. */
|
|
33
|
+
declaration?: "authorize" | "anonymous";
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
interface AuthControllerMeta {
|
|
37
|
+
authorize?: AuthorizeOptions;
|
|
38
|
+
allowAnonymous?: boolean;
|
|
39
|
+
/** Declaration made on this exact class metadata object. */
|
|
40
|
+
declaration?: "authorize" | "anonymous";
|
|
41
|
+
actions: Map<string | symbol, AuthActionMeta>;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
interface AuthMetadataCarrier {
|
|
45
|
+
[AUTHORIZE_META]?: AuthControllerMeta;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function emptyMeta(): AuthControllerMeta {
|
|
49
|
+
return { actions: new Map() };
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function cloneMeta(source: AuthControllerMeta): AuthControllerMeta {
|
|
53
|
+
const actions = new Map<string | symbol, AuthActionMeta>();
|
|
54
|
+
for (const [name, action] of source.actions) {
|
|
55
|
+
// Values inherit, declaration markers do not: the first decorator on a
|
|
56
|
+
// subclass must override its base rather than accidentally accumulate it.
|
|
57
|
+
actions.set(name, {
|
|
58
|
+
authorize: action.authorize,
|
|
59
|
+
allowAnonymous: action.allowAnonymous,
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
return {
|
|
63
|
+
authorize: source.authorize,
|
|
64
|
+
allowAnonymous: source.allowAnonymous,
|
|
65
|
+
actions,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Own (copy-on-write) authorization metadata of the decorated class. TC39
|
|
71
|
+
* metadata is inherited prototypically from the parent: the first write in a
|
|
72
|
+
* subclass clones the inherited state.
|
|
73
|
+
*/
|
|
74
|
+
function ownMeta(metadata: object): AuthControllerMeta {
|
|
75
|
+
const carrier = metadata as AuthMetadataCarrier;
|
|
76
|
+
if (!Object.prototype.hasOwnProperty.call(carrier, AUTHORIZE_META)) {
|
|
77
|
+
const inherited = carrier[AUTHORIZE_META];
|
|
78
|
+
carrier[AUTHORIZE_META] = inherited ? cloneMeta(inherited) : emptyMeta();
|
|
79
|
+
}
|
|
80
|
+
return carrier[AUTHORIZE_META]!;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function ownActionMeta(metadata: object, methodName: string | symbol): AuthActionMeta {
|
|
84
|
+
const meta = ownMeta(metadata);
|
|
85
|
+
let action = meta.actions.get(methodName);
|
|
86
|
+
if (!action) {
|
|
87
|
+
action = {};
|
|
88
|
+
meta.actions.set(methodName, action);
|
|
89
|
+
}
|
|
90
|
+
return action;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export function setControllerAuthorize(metadata: object, options: AuthorizeOptions): void {
|
|
94
|
+
const meta = ownMeta(metadata);
|
|
95
|
+
meta.authorize = meta.declaration === "authorize" && meta.authorize
|
|
96
|
+
? { checks: [...options.checks, ...meta.authorize.checks] }
|
|
97
|
+
: options;
|
|
98
|
+
meta.declaration = "authorize";
|
|
99
|
+
delete meta.allowAnonymous;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export function setControllerAllowAnonymous(metadata: object): void {
|
|
103
|
+
const meta = ownMeta(metadata);
|
|
104
|
+
meta.allowAnonymous = true;
|
|
105
|
+
meta.declaration = "anonymous";
|
|
106
|
+
delete meta.authorize;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export function setActionAuthorize(metadata: object, methodName: string | symbol, options: AuthorizeOptions): void {
|
|
110
|
+
const action = ownActionMeta(metadata, methodName);
|
|
111
|
+
action.authorize = action.declaration === "authorize" && action.authorize
|
|
112
|
+
? { checks: [...options.checks, ...action.authorize.checks] }
|
|
113
|
+
: options;
|
|
114
|
+
action.declaration = "authorize";
|
|
115
|
+
delete action.allowAnonymous;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export function setActionAllowAnonymous(metadata: object, methodName: string | symbol): void {
|
|
119
|
+
const action = ownActionMeta(metadata, methodName);
|
|
120
|
+
action.allowAnonymous = true;
|
|
121
|
+
action.declaration = "anonymous";
|
|
122
|
+
delete action.authorize;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/** Effective route requirement (the method overrides the controller). */
|
|
126
|
+
export interface ResolvedAuthorizeMeta {
|
|
127
|
+
readonly allowAnonymous: boolean;
|
|
128
|
+
readonly authorize?: AuthorizeOptions;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Resolves the authorization requirement of a specific action. Precedence:
|
|
133
|
+
* `@AllowAnonymous`/`@Authorize` on the method override those declared on the class.
|
|
134
|
+
*/
|
|
135
|
+
export function resolveAuthorizeMeta(ctor: object, methodName: string | symbol): ResolvedAuthorizeMeta {
|
|
136
|
+
const metadata = (ctor as { [key: symbol]: unknown })[Symbol.metadata as unknown as symbol] as
|
|
137
|
+
| AuthMetadataCarrier
|
|
138
|
+
| undefined;
|
|
139
|
+
const meta = metadata?.[AUTHORIZE_META];
|
|
140
|
+
if (!meta) {
|
|
141
|
+
return { allowAnonymous: false };
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const action = meta.actions.get(methodName);
|
|
145
|
+
if (action?.allowAnonymous) {
|
|
146
|
+
return { allowAnonymous: true };
|
|
147
|
+
}
|
|
148
|
+
if (action?.authorize) {
|
|
149
|
+
return { allowAnonymous: false, authorize: action.authorize };
|
|
150
|
+
}
|
|
151
|
+
if (meta.allowAnonymous) {
|
|
152
|
+
return { allowAnonymous: true };
|
|
153
|
+
}
|
|
154
|
+
if (meta.authorize) {
|
|
155
|
+
return { allowAnonymous: false, authorize: meta.authorize };
|
|
156
|
+
}
|
|
157
|
+
return { allowAnonymous: false };
|
|
158
|
+
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { ListQueryError, parseListQuery } from "../../../library/jsonapi";
|
|
2
|
+
import { BadRequestError, UnsupportedMediaTypeError } from "../Errors/HttpError";
|
|
3
|
+
import type { HttpContext } from "../HttpContext/HttpContext";
|
|
4
|
+
import type { ParameterBinding } from "./bindings";
|
|
5
|
+
import { convertOr400 } from "./convert";
|
|
6
|
+
import { bindModel } from "./modelBinder";
|
|
7
|
+
|
|
8
|
+
/** Per-action constraints affecting binding (from decorators). */
|
|
9
|
+
export interface BindingDefaults {
|
|
10
|
+
/** `@Consumes(...)`: required request Content-Type for body access. */
|
|
11
|
+
consumes?: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function bindValue(binding: ParameterBinding, raw: string | undefined, kind: string): unknown {
|
|
15
|
+
if (raw === undefined) {
|
|
16
|
+
if (binding.defaultValue !== undefined) {
|
|
17
|
+
return binding.defaultValue;
|
|
18
|
+
}
|
|
19
|
+
if (binding.optional) {
|
|
20
|
+
return undefined;
|
|
21
|
+
}
|
|
22
|
+
throw new BadRequestError(`Missing required ${kind} parameter "${binding.name}"`);
|
|
23
|
+
}
|
|
24
|
+
return binding.type && binding.type !== "string" ? convertOr400(raw, binding.type, binding.name ?? "?") : raw;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Resolves generated binding descriptors into the action's argument list.
|
|
29
|
+
* All conversions fail with 400 (never 500); body parse errors and model
|
|
30
|
+
* validation are handled by the body branch.
|
|
31
|
+
*/
|
|
32
|
+
export async function bindArguments(
|
|
33
|
+
bindings: readonly ParameterBinding[],
|
|
34
|
+
ctx: HttpContext,
|
|
35
|
+
defaults: BindingDefaults,
|
|
36
|
+
): Promise<unknown[]> {
|
|
37
|
+
const args: unknown[] = new Array(bindings.length);
|
|
38
|
+
for (let index = 0; index < bindings.length; index += 1) {
|
|
39
|
+
const binding = bindings[index]!;
|
|
40
|
+
switch (binding.source) {
|
|
41
|
+
case "route": {
|
|
42
|
+
const value = binding.name !== undefined ? ctx.params[binding.name] : undefined;
|
|
43
|
+
// Route params are already constraint-converted; re-convert only when
|
|
44
|
+
// the binding asks for a different primitive type.
|
|
45
|
+
if (value === undefined) {
|
|
46
|
+
args[index] = bindValue(binding, undefined, "route");
|
|
47
|
+
} else if (binding.type && binding.type !== "string" && typeof value === "string") {
|
|
48
|
+
args[index] = convertOr400(value, binding.type, binding.name ?? "?");
|
|
49
|
+
} else {
|
|
50
|
+
args[index] = value;
|
|
51
|
+
}
|
|
52
|
+
break;
|
|
53
|
+
}
|
|
54
|
+
case "query":
|
|
55
|
+
args[index] = bindValue(binding, ctx.query(binding.name ?? ""), "query");
|
|
56
|
+
break;
|
|
57
|
+
case "body": {
|
|
58
|
+
const contentType = ctx.header("content-type") ?? "";
|
|
59
|
+
if (defaults.consumes) {
|
|
60
|
+
if (!contentType.toLowerCase().startsWith(defaults.consumes.toLowerCase())) {
|
|
61
|
+
throw new UnsupportedMediaTypeError(defaults.consumes);
|
|
62
|
+
}
|
|
63
|
+
} else if (!isJsonMediaType(contentType)) {
|
|
64
|
+
// Convention-based body-model binding is a JSON boundary. Requiring
|
|
65
|
+
// a non-simple media type also prevents cross-origin text/plain POSTs
|
|
66
|
+
// from bypassing the browser's CORS preflight.
|
|
67
|
+
throw new UnsupportedMediaTypeError("application/json");
|
|
68
|
+
}
|
|
69
|
+
const data = await ctx.json();
|
|
70
|
+
args[index] = binding.model ? bindModel(binding.model, data, ctx.modelValidator, { primitiveTypes: true }) : data;
|
|
71
|
+
break;
|
|
72
|
+
}
|
|
73
|
+
case "request":
|
|
74
|
+
args[index] = ctx.request;
|
|
75
|
+
break;
|
|
76
|
+
case "response":
|
|
77
|
+
args[index] = ctx.res;
|
|
78
|
+
break;
|
|
79
|
+
case "context":
|
|
80
|
+
args[index] = ctx;
|
|
81
|
+
break;
|
|
82
|
+
case "list": {
|
|
83
|
+
let parsed;
|
|
84
|
+
try {
|
|
85
|
+
parsed = parseListQuery(ctx.url.searchParams, binding.listOptions);
|
|
86
|
+
} catch (error) {
|
|
87
|
+
if (error instanceof ListQueryError) {
|
|
88
|
+
throw new BadRequestError("Invalid list query", error.problems);
|
|
89
|
+
}
|
|
90
|
+
throw error;
|
|
91
|
+
}
|
|
92
|
+
if (binding.model) {
|
|
93
|
+
// Class-based list request (extends ListRequest): instantiate and
|
|
94
|
+
// populate the parsed sort/filters/page so the action gets a typed object.
|
|
95
|
+
args[index] = Object.assign(new (binding.model as new () => object)(), parsed);
|
|
96
|
+
} else {
|
|
97
|
+
args[index] = parsed;
|
|
98
|
+
}
|
|
99
|
+
break;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
return args;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function isJsonMediaType(contentType: string): boolean {
|
|
107
|
+
const mediaType = contentType.split(";", 1)[0]?.trim().toLowerCase() ?? "";
|
|
108
|
+
return mediaType === "application/json" || mediaType.endsWith("+json");
|
|
109
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { registerRequestModelClass, type RequestModelClass } from "./requestModelRegistry";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Marks a class as a request model (DTO) addressable by name.
|
|
5
|
+
*
|
|
6
|
+
* Needed only for DTOs declared outside the scanned sources (for example in
|
|
7
|
+
* another package). Codegen registers all other DTOs from method signatures:
|
|
8
|
+
*
|
|
9
|
+
* ```ts
|
|
10
|
+
* @RequestModel()
|
|
11
|
+
* class CreateUserDto {
|
|
12
|
+
* @Validator({ required: true, minLength: 3 })
|
|
13
|
+
* name!: string;
|
|
14
|
+
* }
|
|
15
|
+
*
|
|
16
|
+
* // In the controller the parameter type is enough:
|
|
17
|
+
* @Post()
|
|
18
|
+
* create(dto: CreateUserDto) { ... }
|
|
19
|
+
* ```
|
|
20
|
+
*
|
|
21
|
+
* DTOs in the application sources do not need the decorator.
|
|
22
|
+
*/
|
|
23
|
+
export function RequestModel() {
|
|
24
|
+
return (value: RequestModelClass, _context: ClassDecoratorContext): void => {
|
|
25
|
+
registerRequestModelClass(value);
|
|
26
|
+
};
|
|
27
|
+
}
|