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,326 @@
|
|
|
1
|
+
import type { OpenApiCatalogOperation, OpenApiDocumentBuildInput, OpenApiParameter, OpenApiSchema } from "./types";
|
|
2
|
+
|
|
3
|
+
type OpenApiOperation = {
|
|
4
|
+
tags: string[];
|
|
5
|
+
operationId: string;
|
|
6
|
+
summary: string;
|
|
7
|
+
parameters?: OpenApiParameter[];
|
|
8
|
+
requestBody?: OpenApiSchema;
|
|
9
|
+
responses: Record<string, OpenApiSchema>;
|
|
10
|
+
security?: readonly OpenApiSchema[];
|
|
11
|
+
[extension: `x-${string}`]: unknown;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
const HTTP_METHODS = new Set(["GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS", "HEAD"]);
|
|
15
|
+
const HTTP_METHOD_KEYS = new Set([...HTTP_METHODS].map((method) => method.toLowerCase()));
|
|
16
|
+
|
|
17
|
+
export function buildOpenApiDocument(input: OpenApiDocumentBuildInput): OpenApiSchema {
|
|
18
|
+
const paths: Record<string, Record<string, unknown>> = {};
|
|
19
|
+
let hasSecurity = false;
|
|
20
|
+
|
|
21
|
+
for (const item of input.operations) {
|
|
22
|
+
const operation = operationFromCatalog(item);
|
|
23
|
+
if (operation.security !== undefined) {
|
|
24
|
+
hasSecurity = true;
|
|
25
|
+
}
|
|
26
|
+
addOperation(paths, item.path, item.httpMethod, operation);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const components: Record<string, unknown> = { schemas: schemasForPaths(input.schemas, paths) };
|
|
30
|
+
if (hasSecurity) {
|
|
31
|
+
components.securitySchemes = {
|
|
32
|
+
bearerAuth: {
|
|
33
|
+
type: "http",
|
|
34
|
+
scheme: "bearer",
|
|
35
|
+
bearerFormat: "JWT",
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return {
|
|
41
|
+
openapi: "3.1.0",
|
|
42
|
+
info: {
|
|
43
|
+
title: input.title,
|
|
44
|
+
version: input.version,
|
|
45
|
+
...(input.generatedBy !== undefined ? { "x-generated-by": input.generatedBy } : {}),
|
|
46
|
+
},
|
|
47
|
+
paths,
|
|
48
|
+
components,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Creates the least-privilege OpenAPI view for an effective UI surface.
|
|
54
|
+
* Only explicitly allowed operations and the schemas reachable from them are
|
|
55
|
+
* retained. A missing operation is a server configuration error, never a
|
|
56
|
+
* reason to silently publish a broader document.
|
|
57
|
+
*/
|
|
58
|
+
export function projectOpenApiByOperationIds(
|
|
59
|
+
document: OpenApiSchema,
|
|
60
|
+
operationIds: ReadonlySet<string> | readonly string[],
|
|
61
|
+
): OpenApiSchema {
|
|
62
|
+
const requested = operationIds instanceof Set ? operationIds : new Set(operationIds);
|
|
63
|
+
const found = new Set<string>();
|
|
64
|
+
const projectedPaths: Record<string, Record<string, unknown>> = {};
|
|
65
|
+
const sourcePaths = isRecord(document.paths) ? document.paths : {};
|
|
66
|
+
|
|
67
|
+
for (const [path, sourceItem] of Object.entries(sourcePaths)) {
|
|
68
|
+
if (!isRecord(sourceItem)) {
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
const projectedItem: Record<string, unknown> = {};
|
|
72
|
+
let hasOperation = false;
|
|
73
|
+
for (const [key, value] of Object.entries(sourceItem)) {
|
|
74
|
+
if (HTTP_METHOD_KEYS.has(key)) {
|
|
75
|
+
if (isRequestedOperation(value, requested, found)) {
|
|
76
|
+
projectedItem[key] = value;
|
|
77
|
+
hasOperation = true;
|
|
78
|
+
}
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
if (key === "x-bazis-any-method") {
|
|
82
|
+
const projected = requestedAnyMethodOperations(value, requested, found);
|
|
83
|
+
if (projected !== undefined) {
|
|
84
|
+
projectedItem[key] = projected;
|
|
85
|
+
hasOperation = true;
|
|
86
|
+
}
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
projectedItem[key] = value;
|
|
90
|
+
}
|
|
91
|
+
if (hasOperation) {
|
|
92
|
+
projectedPaths[path] = projectedItem;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const missing = [...requested].filter((operationId) => !found.has(operationId)).sort();
|
|
97
|
+
if (missing.length > 0) {
|
|
98
|
+
throw new TypeError(`OpenAPI operations not found: ${missing.join(", ")}.`);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const sourceComponents = isRecord(document.components) ? document.components : {};
|
|
102
|
+
const sourceSchemas = isRecord(sourceComponents.schemas)
|
|
103
|
+
? sourceComponents.schemas as Readonly<Record<string, OpenApiSchema>>
|
|
104
|
+
: {};
|
|
105
|
+
const components: Record<string, unknown> = {
|
|
106
|
+
schemas: schemasForPaths(sourceSchemas, projectedPaths),
|
|
107
|
+
};
|
|
108
|
+
if (sourceComponents.securitySchemes !== undefined) {
|
|
109
|
+
components.securitySchemes = sourceComponents.securitySchemes;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return {
|
|
113
|
+
...(document.openapi !== undefined ? { openapi: document.openapi } : {}),
|
|
114
|
+
...(document.info !== undefined ? { info: document.info } : {}),
|
|
115
|
+
...(document.jsonSchemaDialect !== undefined ? { jsonSchemaDialect: document.jsonSchemaDialect } : {}),
|
|
116
|
+
...(document.servers !== undefined ? { servers: document.servers } : {}),
|
|
117
|
+
...(document.security !== undefined ? { security: document.security } : {}),
|
|
118
|
+
...(document.externalDocs !== undefined ? { externalDocs: document.externalDocs } : {}),
|
|
119
|
+
paths: projectedPaths,
|
|
120
|
+
components,
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function isRequestedOperation(
|
|
125
|
+
value: unknown,
|
|
126
|
+
requested: ReadonlySet<string>,
|
|
127
|
+
found: Set<string>,
|
|
128
|
+
): boolean {
|
|
129
|
+
if (!isRecord(value) || typeof value.operationId !== "string" || !requested.has(value.operationId)) {
|
|
130
|
+
return false;
|
|
131
|
+
}
|
|
132
|
+
found.add(value.operationId);
|
|
133
|
+
return true;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function requestedAnyMethodOperations(
|
|
137
|
+
value: unknown,
|
|
138
|
+
requested: ReadonlySet<string>,
|
|
139
|
+
found: Set<string>,
|
|
140
|
+
): unknown {
|
|
141
|
+
if (Array.isArray(value)) {
|
|
142
|
+
const operations = value.filter((item) => isRequestedOperation(item, requested, found));
|
|
143
|
+
return operations.length === 0 ? undefined : operations;
|
|
144
|
+
}
|
|
145
|
+
return isRequestedOperation(value, requested, found) ? value : undefined;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function operationFromCatalog(item: OpenApiCatalogOperation): OpenApiOperation {
|
|
149
|
+
const operation: OpenApiOperation = {
|
|
150
|
+
tags: [item.tag],
|
|
151
|
+
operationId: item.operationId,
|
|
152
|
+
summary: item.summary ?? `${normalizedMethod(item.httpMethod)} ${item.path}`,
|
|
153
|
+
responses: { ...item.responses },
|
|
154
|
+
};
|
|
155
|
+
const parameters = mergeParameters(item.parameters ?? []);
|
|
156
|
+
if (parameters.length > 0) {
|
|
157
|
+
operation.parameters = parameters;
|
|
158
|
+
}
|
|
159
|
+
if (item.requestBody !== undefined) {
|
|
160
|
+
operation.requestBody = item.requestBody;
|
|
161
|
+
}
|
|
162
|
+
if (item.authorized === true) {
|
|
163
|
+
operation.security = [{ bearerAuth: [] }];
|
|
164
|
+
}
|
|
165
|
+
if (item.versions !== undefined && item.versions.length > 0) {
|
|
166
|
+
operation["x-bazis-versions"] = uniqueStrings(item.versions);
|
|
167
|
+
}
|
|
168
|
+
return operation;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function addOperation(
|
|
172
|
+
paths: Record<string, Record<string, unknown>>,
|
|
173
|
+
path: string,
|
|
174
|
+
httpMethod: string,
|
|
175
|
+
operation: OpenApiOperation,
|
|
176
|
+
): void {
|
|
177
|
+
const item = (paths[path] ??= {});
|
|
178
|
+
if (httpMethod === "*") {
|
|
179
|
+
const existing = item["x-bazis-any-method"];
|
|
180
|
+
item["x-bazis-any-method"] = mergeAnyMethod(existing, operation);
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
if (!HTTP_METHODS.has(httpMethod)) {
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
const key = httpMethod.toLowerCase();
|
|
187
|
+
const existing = item[key];
|
|
188
|
+
item[key] = existing && isRecord(existing) ? mergeOperations(existing, operation) : operation;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
function mergeAnyMethod(existing: unknown, operation: OpenApiOperation): OpenApiOperation | OpenApiOperation[] {
|
|
192
|
+
if (existing === undefined) {
|
|
193
|
+
return operation;
|
|
194
|
+
}
|
|
195
|
+
return Array.isArray(existing) ? [...existing, operation] : [existing as OpenApiOperation, operation];
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
function mergeOperations(existing: Record<string, unknown>, next: OpenApiOperation): OpenApiOperation {
|
|
199
|
+
const existingOperationId = String(existing.operationId ?? next.operationId);
|
|
200
|
+
const versions = uniqueStrings([
|
|
201
|
+
...readStringArray(existing["x-bazis-versions"]),
|
|
202
|
+
...readStringArray(next["x-bazis-versions"]),
|
|
203
|
+
]);
|
|
204
|
+
const parameters = mergeParameters([
|
|
205
|
+
...readParameters(existing.parameters),
|
|
206
|
+
...(next.parameters ?? []),
|
|
207
|
+
]);
|
|
208
|
+
return {
|
|
209
|
+
...next,
|
|
210
|
+
operationId: existingOperationId === next.operationId
|
|
211
|
+
? existingOperationId
|
|
212
|
+
: `${existingOperationId}_${next.operationId}`,
|
|
213
|
+
parameters: parameters.length > 0 ? parameters : undefined,
|
|
214
|
+
responses: { ...(existing.responses as Record<string, OpenApiSchema> | undefined), ...next.responses },
|
|
215
|
+
...(versions.length > 0 ? { "x-bazis-versions": versions } : {}),
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
function mergeParameters(parameters: readonly OpenApiParameter[]): OpenApiParameter[] {
|
|
220
|
+
const out: OpenApiParameter[] = [];
|
|
221
|
+
for (const parameter of parameters) {
|
|
222
|
+
const existingIndex = out.findIndex((item) => item.in === parameter.in && item.name === parameter.name);
|
|
223
|
+
if (existingIndex < 0) {
|
|
224
|
+
out.push({ ...parameter });
|
|
225
|
+
continue;
|
|
226
|
+
}
|
|
227
|
+
const existing = out[existingIndex] as OpenApiParameter;
|
|
228
|
+
out[existingIndex] = {
|
|
229
|
+
...existing,
|
|
230
|
+
required: existing.required === true || parameter.required === true,
|
|
231
|
+
schema: mergeParameterSchema(existing.schema, parameter.schema),
|
|
232
|
+
// One projected operation may cover multiple query/header versions.
|
|
233
|
+
// Only their common fields are safe to offer without selecting a version.
|
|
234
|
+
...(existing["x-bazis-sort-fields"] !== undefined || parameter["x-bazis-sort-fields"] !== undefined
|
|
235
|
+
? { "x-bazis-sort-fields": (existing["x-bazis-sort-fields"] ?? []).filter(
|
|
236
|
+
(field) => parameter["x-bazis-sort-fields"]?.includes(field),
|
|
237
|
+
) }
|
|
238
|
+
: {}),
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
return out;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
function mergeParameterSchema(left: OpenApiSchema | undefined, right: OpenApiSchema | undefined): OpenApiSchema | undefined {
|
|
245
|
+
if (!left) {
|
|
246
|
+
return right;
|
|
247
|
+
}
|
|
248
|
+
if (!right) {
|
|
249
|
+
return left;
|
|
250
|
+
}
|
|
251
|
+
const leftEnum = readStringArray(left.enum);
|
|
252
|
+
const rightEnum = readStringArray(right.enum);
|
|
253
|
+
if (leftEnum.length === 0 && rightEnum.length === 0) {
|
|
254
|
+
return left;
|
|
255
|
+
}
|
|
256
|
+
return { ...left, enum: uniqueStrings([...leftEnum, ...rightEnum]) };
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
function schemasForPaths(
|
|
260
|
+
schemas: Readonly<Record<string, OpenApiSchema>>,
|
|
261
|
+
paths: Record<string, Record<string, unknown>>,
|
|
262
|
+
): Record<string, OpenApiSchema> {
|
|
263
|
+
const out: Record<string, OpenApiSchema> = {};
|
|
264
|
+
const seen = new Set<string>();
|
|
265
|
+
const queue: string[] = [];
|
|
266
|
+
const add = (name: string): void => {
|
|
267
|
+
if (seen.has(name) || schemas[name] === undefined) {
|
|
268
|
+
return;
|
|
269
|
+
}
|
|
270
|
+
seen.add(name);
|
|
271
|
+
queue.push(name);
|
|
272
|
+
};
|
|
273
|
+
collectRefs(paths, add);
|
|
274
|
+
for (let index = 0; index < queue.length; index += 1) {
|
|
275
|
+
const name = queue[index] as string;
|
|
276
|
+
const schema = schemas[name] as OpenApiSchema;
|
|
277
|
+
out[name] = schema;
|
|
278
|
+
collectRefs(schema, add);
|
|
279
|
+
}
|
|
280
|
+
return out;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
function collectRefs(value: unknown, add: (name: string) => void): void {
|
|
284
|
+
if (Array.isArray(value)) {
|
|
285
|
+
for (const item of value) {
|
|
286
|
+
collectRefs(item, add);
|
|
287
|
+
}
|
|
288
|
+
return;
|
|
289
|
+
}
|
|
290
|
+
if (!isRecord(value)) {
|
|
291
|
+
return;
|
|
292
|
+
}
|
|
293
|
+
if (typeof value.$ref === "string") {
|
|
294
|
+
const prefix = "#/components/schemas/";
|
|
295
|
+
if (value.$ref.startsWith(prefix)) {
|
|
296
|
+
add(value.$ref.slice(prefix.length));
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
for (const item of Object.values(value)) {
|
|
300
|
+
collectRefs(item, add);
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
function normalizedMethod(method: string): string {
|
|
305
|
+
return method === "*" ? "ANY" : method;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
309
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
function readStringArray(value: unknown): string[] {
|
|
313
|
+
return Array.isArray(value) ? value.filter((item): item is string => typeof item === "string") : [];
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
function readParameters(value: unknown): OpenApiParameter[] {
|
|
317
|
+
return Array.isArray(value) ? value.filter(isOpenApiParameter) : [];
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
function isOpenApiParameter(value: unknown): value is OpenApiParameter {
|
|
321
|
+
return isRecord(value) && typeof value.name === "string" && (value.in === "path" || value.in === "query" || value.in === "header");
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
function uniqueStrings(values: readonly string[]): string[] {
|
|
325
|
+
return [...new Set(values)].sort((a, b) => a.localeCompare(b));
|
|
326
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export { buildOpenApiDocument, projectOpenApiByOperationIds } from "./document";
|
|
2
|
+
export { openApiDocsHeaders, renderOpenApiHtml, serveOpenApiDocs } from "./ui";
|
|
3
|
+
export type {
|
|
4
|
+
GeneratedOpenApiMetadata,
|
|
5
|
+
GeneratedOpenApiOperationMetadata,
|
|
6
|
+
OpenApiCatalogOperation,
|
|
7
|
+
OpenApiDocsOptions,
|
|
8
|
+
OpenApiDocumentBuildInput,
|
|
9
|
+
OpenApiParameter,
|
|
10
|
+
OpenApiParameterLocation,
|
|
11
|
+
OpenApiSchema,
|
|
12
|
+
PreparedOpenApiDocs,
|
|
13
|
+
} from "./types";
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
export type OpenApiSchema = Readonly<Record<string, unknown>>;
|
|
2
|
+
|
|
3
|
+
export interface GeneratedOpenApiOperationMetadata {
|
|
4
|
+
readonly response?: OpenApiSchema;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export interface GeneratedOpenApiMetadata {
|
|
8
|
+
readonly schemas: Readonly<Record<string, OpenApiSchema>>;
|
|
9
|
+
readonly operations: Readonly<Record<string, Readonly<Record<string, GeneratedOpenApiOperationMetadata>>>>;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface OpenApiDocsOptions {
|
|
13
|
+
/**
|
|
14
|
+
* Enables or disables built-in API docs. When omitted, docs are available in
|
|
15
|
+
* debug environments and disabled in production.
|
|
16
|
+
*/
|
|
17
|
+
readonly enabled?: boolean;
|
|
18
|
+
/** Absolute path of the HTML UI. Default: "/docs". */
|
|
19
|
+
readonly path?: string;
|
|
20
|
+
/** Absolute path of the OpenAPI JSON document. Default: "<path>/openapi.json". */
|
|
21
|
+
readonly specPath?: string;
|
|
22
|
+
/** OpenAPI info.title. Default: "Bazis API". */
|
|
23
|
+
readonly title?: string;
|
|
24
|
+
/** OpenAPI info.version. Default: "1.0.0". */
|
|
25
|
+
readonly version?: string;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface PreparedOpenApiDocs {
|
|
29
|
+
readonly uiPath: string;
|
|
30
|
+
readonly specPath: string;
|
|
31
|
+
readonly document: OpenApiSchema;
|
|
32
|
+
readonly json: string;
|
|
33
|
+
readonly html: string;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export type OpenApiParameterLocation = "path" | "query" | "header";
|
|
37
|
+
|
|
38
|
+
export interface OpenApiParameter {
|
|
39
|
+
readonly name: string;
|
|
40
|
+
readonly in: OpenApiParameterLocation;
|
|
41
|
+
readonly required?: boolean;
|
|
42
|
+
readonly schema?: OpenApiSchema;
|
|
43
|
+
readonly description?: string;
|
|
44
|
+
readonly style?: string;
|
|
45
|
+
readonly explode?: boolean;
|
|
46
|
+
/** Allowed sort field names, without direction prefixes. An empty list forbids sorting. */
|
|
47
|
+
readonly "x-bazis-sort-fields"?: readonly string[];
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export interface OpenApiCatalogOperation {
|
|
51
|
+
readonly path: string;
|
|
52
|
+
readonly httpMethod: string;
|
|
53
|
+
readonly tag: string;
|
|
54
|
+
readonly operationId: string;
|
|
55
|
+
readonly summary?: string;
|
|
56
|
+
readonly parameters?: readonly OpenApiParameter[];
|
|
57
|
+
readonly requestBody?: OpenApiSchema;
|
|
58
|
+
readonly responses: Readonly<Record<string, OpenApiSchema>>;
|
|
59
|
+
readonly authorized?: boolean;
|
|
60
|
+
readonly versions?: readonly string[];
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export interface OpenApiDocumentBuildInput {
|
|
64
|
+
readonly title: string;
|
|
65
|
+
readonly version: string;
|
|
66
|
+
readonly operations: readonly OpenApiCatalogOperation[];
|
|
67
|
+
readonly schemas: Readonly<Record<string, OpenApiSchema>>;
|
|
68
|
+
readonly generatedBy?: string;
|
|
69
|
+
}
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
export function serveOpenApiDocs(
|
|
2
|
+
docs: { readonly uiPath: string; readonly specPath: string; readonly json: string; readonly html: string },
|
|
3
|
+
pathname: string,
|
|
4
|
+
method: string,
|
|
5
|
+
): Response | undefined {
|
|
6
|
+
if (pathname !== docs.uiPath && pathname !== `${docs.uiPath}/` && pathname !== docs.specPath) {
|
|
7
|
+
return undefined;
|
|
8
|
+
}
|
|
9
|
+
if (method !== "GET" && method !== "HEAD") {
|
|
10
|
+
return new Response(JSON.stringify({ error: "Method Not Allowed" }), {
|
|
11
|
+
status: 405,
|
|
12
|
+
headers: {
|
|
13
|
+
allow: "GET, HEAD",
|
|
14
|
+
"content-type": "application/json; charset=utf-8",
|
|
15
|
+
},
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
if (pathname === docs.specPath) {
|
|
19
|
+
return new Response(docs.json, {
|
|
20
|
+
headers: openApiDocsHeaders("application/json; charset=utf-8"),
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
return new Response(docs.html, {
|
|
24
|
+
headers: openApiDocsHeaders("text/html; charset=utf-8"),
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function openApiDocsHeaders(contentType: string): Record<string, string> {
|
|
29
|
+
return {
|
|
30
|
+
"content-type": contentType,
|
|
31
|
+
"cache-control": "no-store",
|
|
32
|
+
"x-content-type-options": "nosniff",
|
|
33
|
+
"referrer-policy": "no-referrer",
|
|
34
|
+
"content-security-policy": "default-src 'none'; connect-src 'self'; style-src 'unsafe-inline'; script-src 'unsafe-inline';",
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function renderOpenApiHtml(title: string, specPath: string): string {
|
|
39
|
+
const titleJson = JSON.stringify(title);
|
|
40
|
+
const specPathJson = JSON.stringify(specPath);
|
|
41
|
+
return `<!doctype html>
|
|
42
|
+
<html lang="en">
|
|
43
|
+
<head>
|
|
44
|
+
<meta charset="utf-8">
|
|
45
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
46
|
+
<title>${escapeHtml(title)} Docs</title>
|
|
47
|
+
<style>
|
|
48
|
+
:root { color-scheme: light dark; font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; }
|
|
49
|
+
* { box-sizing: border-box; }
|
|
50
|
+
body { margin: 0; background: Canvas; color: CanvasText; }
|
|
51
|
+
header { position: sticky; top: 0; z-index: 2; display: grid; grid-template-columns: 1fr minmax(180px, 320px) auto; gap: 12px; align-items: center; padding: 16px 20px; border-bottom: 1px solid color-mix(in srgb, CanvasText 14%, transparent); background: color-mix(in srgb, Canvas 94%, CanvasText 6%); }
|
|
52
|
+
h1 { margin: 0; font-size: 18px; line-height: 1.2; letter-spacing: 0; }
|
|
53
|
+
main { display: grid; grid-template-columns: minmax(0, 1fr) 360px; min-height: calc(100vh - 69px); }
|
|
54
|
+
#operations { padding: 18px 20px 40px; }
|
|
55
|
+
#raw { padding: 18px; border-left: 1px solid color-mix(in srgb, CanvasText 12%, transparent); background: color-mix(in srgb, CanvasText 4%, Canvas); overflow: auto; }
|
|
56
|
+
input { width: 100%; min-height: 36px; border: 1px solid color-mix(in srgb, CanvasText 22%, transparent); border-radius: 6px; padding: 8px 10px; background: Canvas; color: CanvasText; font: inherit; }
|
|
57
|
+
a, button { color: inherit; }
|
|
58
|
+
.spec-link { white-space: nowrap; font-size: 13px; text-decoration: none; border: 1px solid color-mix(in srgb, CanvasText 22%, transparent); border-radius: 6px; padding: 8px 10px; }
|
|
59
|
+
.path { margin: 0 0 18px; border: 1px solid color-mix(in srgb, CanvasText 13%, transparent); border-radius: 8px; overflow: hidden; background: Canvas; }
|
|
60
|
+
.path h2 { margin: 0; padding: 12px 14px; font-size: 14px; font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; background: color-mix(in srgb, CanvasText 5%, Canvas); overflow-wrap: anywhere; letter-spacing: 0; }
|
|
61
|
+
.operation { border-top: 1px solid color-mix(in srgb, CanvasText 10%, transparent); padding: 12px 14px; }
|
|
62
|
+
.line { display: flex; gap: 10px; align-items: center; min-width: 0; }
|
|
63
|
+
.method { width: 68px; flex: 0 0 68px; text-align: center; border-radius: 5px; padding: 5px 7px; font-weight: 700; font-size: 12px; color: white; background: #64748b; }
|
|
64
|
+
.GET { background: #087f5b; } .POST { background: #1c64b7; } .PUT { background: #9a5b00; } .PATCH { background: #7c3aed; } .DELETE { background: #b42318; }
|
|
65
|
+
.summary { min-width: 0; overflow-wrap: anywhere; font-size: 14px; }
|
|
66
|
+
.meta { display: flex; flex-wrap: wrap; gap: 6px; margin: 10px 0 0 78px; }
|
|
67
|
+
.pill { border: 1px solid color-mix(in srgb, CanvasText 16%, transparent); border-radius: 999px; padding: 3px 7px; font-size: 12px; color: color-mix(in srgb, CanvasText 72%, Canvas); }
|
|
68
|
+
pre { margin: 0; font-size: 12px; line-height: 1.5; white-space: pre-wrap; overflow-wrap: anywhere; }
|
|
69
|
+
.empty { color: color-mix(in srgb, CanvasText 60%, Canvas); }
|
|
70
|
+
@media (max-width: 900px) {
|
|
71
|
+
header { grid-template-columns: 1fr; }
|
|
72
|
+
main { grid-template-columns: 1fr; }
|
|
73
|
+
#raw { border-left: 0; border-top: 1px solid color-mix(in srgb, CanvasText 12%, transparent); max-height: 45vh; }
|
|
74
|
+
}
|
|
75
|
+
</style>
|
|
76
|
+
</head>
|
|
77
|
+
<body>
|
|
78
|
+
<header>
|
|
79
|
+
<h1></h1>
|
|
80
|
+
<input id="filter" type="search" placeholder="Filter operations">
|
|
81
|
+
<a class="spec-link" href="">Open JSON</a>
|
|
82
|
+
</header>
|
|
83
|
+
<main>
|
|
84
|
+
<section id="operations"></section>
|
|
85
|
+
<aside id="raw"><pre></pre></aside>
|
|
86
|
+
</main>
|
|
87
|
+
<script>
|
|
88
|
+
const docsTitle = ${titleJson};
|
|
89
|
+
const specPath = ${specPathJson};
|
|
90
|
+
const state = { spec: null, rows: [] };
|
|
91
|
+
document.querySelector("h1").textContent = docsTitle;
|
|
92
|
+
document.querySelector(".spec-link").href = specPath;
|
|
93
|
+
fetch(specPath)
|
|
94
|
+
.then((response) => response.json())
|
|
95
|
+
.then((spec) => {
|
|
96
|
+
state.spec = spec;
|
|
97
|
+
state.rows = flatten(spec);
|
|
98
|
+
document.querySelector("#raw pre").textContent = JSON.stringify(spec, null, 2);
|
|
99
|
+
render();
|
|
100
|
+
})
|
|
101
|
+
.catch((error) => {
|
|
102
|
+
document.querySelector("#operations").innerHTML = '<p class="empty">Unable to load OpenAPI document.</p>';
|
|
103
|
+
document.querySelector("#raw pre").textContent = String(error);
|
|
104
|
+
});
|
|
105
|
+
document.querySelector("#filter").addEventListener("input", render);
|
|
106
|
+
function flatten(spec) {
|
|
107
|
+
const methods = ["get", "post", "put", "patch", "delete", "options", "head"];
|
|
108
|
+
const rows = [];
|
|
109
|
+
for (const [path, item] of Object.entries(spec.paths || {})) {
|
|
110
|
+
for (const method of methods) {
|
|
111
|
+
if (item && item[method]) rows.push({ path, method: method.toUpperCase(), operation: item[method] });
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
return rows;
|
|
115
|
+
}
|
|
116
|
+
function render() {
|
|
117
|
+
const filter = document.querySelector("#filter").value.trim().toLowerCase();
|
|
118
|
+
const grouped = new Map();
|
|
119
|
+
for (const row of state.rows) {
|
|
120
|
+
const haystack = [row.method, row.path, row.operation.summary, row.operation.operationId, ...(row.operation.tags || [])].join(" ").toLowerCase();
|
|
121
|
+
if (filter && !haystack.includes(filter)) continue;
|
|
122
|
+
if (!grouped.has(row.path)) grouped.set(row.path, []);
|
|
123
|
+
grouped.get(row.path).push(row);
|
|
124
|
+
}
|
|
125
|
+
const root = document.querySelector("#operations");
|
|
126
|
+
if (grouped.size === 0) {
|
|
127
|
+
root.innerHTML = '<p class="empty">No operations found.</p>';
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
root.innerHTML = "";
|
|
131
|
+
for (const [path, rows] of grouped) {
|
|
132
|
+
const block = document.createElement("article");
|
|
133
|
+
block.className = "path";
|
|
134
|
+
const heading = document.createElement("h2");
|
|
135
|
+
heading.textContent = path;
|
|
136
|
+
block.appendChild(heading);
|
|
137
|
+
for (const row of rows) block.appendChild(operationNode(row));
|
|
138
|
+
root.appendChild(block);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
function operationNode(row) {
|
|
142
|
+
const node = document.createElement("section");
|
|
143
|
+
node.className = "operation";
|
|
144
|
+
const line = document.createElement("div");
|
|
145
|
+
line.className = "line";
|
|
146
|
+
const method = document.createElement("span");
|
|
147
|
+
method.className = "method " + row.method;
|
|
148
|
+
method.textContent = row.method;
|
|
149
|
+
const summary = document.createElement("span");
|
|
150
|
+
summary.className = "summary";
|
|
151
|
+
summary.textContent = row.operation.operationId || row.operation.summary || "";
|
|
152
|
+
line.append(method, summary);
|
|
153
|
+
node.appendChild(line);
|
|
154
|
+
const meta = document.createElement("div");
|
|
155
|
+
meta.className = "meta";
|
|
156
|
+
for (const parameter of row.operation.parameters || []) {
|
|
157
|
+
meta.appendChild(pill(parameter.in + ":" + parameter.name + (parameter.required ? " required" : "")));
|
|
158
|
+
}
|
|
159
|
+
if (row.operation.requestBody) meta.appendChild(pill("body"));
|
|
160
|
+
if (row.operation.security) meta.appendChild(pill("auth"));
|
|
161
|
+
for (const status of Object.keys(row.operation.responses || {})) meta.appendChild(pill(status));
|
|
162
|
+
if (meta.children.length > 0) node.appendChild(meta);
|
|
163
|
+
return node;
|
|
164
|
+
}
|
|
165
|
+
function pill(text) {
|
|
166
|
+
const item = document.createElement("span");
|
|
167
|
+
item.className = "pill";
|
|
168
|
+
item.textContent = text;
|
|
169
|
+
return item;
|
|
170
|
+
}
|
|
171
|
+
</script>
|
|
172
|
+
</body>
|
|
173
|
+
</html>`;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
function escapeHtml(value: string): string {
|
|
177
|
+
return value
|
|
178
|
+
.replaceAll("&", "&")
|
|
179
|
+
.replaceAll("<", "<")
|
|
180
|
+
.replaceAll(">", ">")
|
|
181
|
+
.replaceAll('"', """);
|
|
182
|
+
}
|