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.
Files changed (513) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +146 -0
  3. package/cli/build.ts +147 -0
  4. package/cli/codegen.ts +40 -0
  5. package/cli/generateModule.ts +187 -0
  6. package/cli/generateProject.ts +183 -0
  7. package/cli/main.ts +125 -0
  8. package/cli/moduleRegistration.ts +127 -0
  9. package/cli/naming.ts +124 -0
  10. package/cli/parseCli.ts +151 -0
  11. package/cli/templates/module.ts +497 -0
  12. package/cli/templates/pack.ts +76 -0
  13. package/cli/templates/passport.ts +178 -0
  14. package/core/agent/AgentContextBuilder.ts +567 -0
  15. package/core/agent/AgentDataDefinition.ts +8 -0
  16. package/core/agent/AgentRegistry.ts +539 -0
  17. package/core/agent/AgentRuntime.ts +47 -0
  18. package/core/agent/AgentToolExecutor.ts +2130 -0
  19. package/core/agent/AgentToolHooks.ts +39 -0
  20. package/core/agent/ModelProvider.ts +21 -0
  21. package/core/agent/README.md +229 -0
  22. package/core/agent/Tool.contract.ts +20 -0
  23. package/core/agent/decorators/Agent.ts +11 -0
  24. package/core/agent/decorators/Prompt.ts +11 -0
  25. package/core/agent/decorators/Task.ts +29 -0
  26. package/core/agent/decorators/Tool.ts +12 -0
  27. package/core/agent/errors.ts +43 -0
  28. package/core/agent/generated/catalog.ts +26 -0
  29. package/core/agent/index.ts +170 -0
  30. package/core/agent/internal/AgentExecutionDriver.ts +1497 -0
  31. package/core/agent/internal/AgentExecutionState.ts +775 -0
  32. package/core/agent/internal/AgentJsonSchema.ts +150 -0
  33. package/core/agent/internal/AgentModelBinding.ts +57 -0
  34. package/core/agent/internal/Schema.contract.ts +36 -0
  35. package/core/agent/internal/ToolAudit.projector.ts +163 -0
  36. package/core/agent/internal/ToolContract.validator.ts +102 -0
  37. package/core/agent/metadata.ts +398 -0
  38. package/core/agent/moduleContributions-v1.ts +113 -0
  39. package/core/agent/semantic.ts +903 -0
  40. package/core/agent/session/codec.ts +33 -0
  41. package/core/agent/session/contracts.ts +96 -0
  42. package/core/agent/session/entities.ts +84 -0
  43. package/core/agent/session/protector.ts +92 -0
  44. package/core/app/index.ts +5 -0
  45. package/core/app/runApp.ts +293 -0
  46. package/core/app/ui/index.ts +29 -0
  47. package/core/app/ui/uiProfileResolver.ts +966 -0
  48. package/core/app/ui/uiSurfaceHosting.ts +38 -0
  49. package/core/app/ui/uiSurfaceHttp.ts +476 -0
  50. package/core/background/BackgroundService.ts +223 -0
  51. package/core/background/backgroundModule.ts +42 -0
  52. package/core/background/decorator.ts +43 -0
  53. package/core/background/delay.ts +27 -0
  54. package/core/background/index.ts +15 -0
  55. package/core/cache/COMPATIBILITY.md +13 -0
  56. package/core/cache/ICache.ts +71 -0
  57. package/core/cache/MemoryCache.ts +394 -0
  58. package/core/cache/README.md +83 -0
  59. package/core/cache/SPEC.md +1355 -0
  60. package/core/cache/cacheModule.ts +21 -0
  61. package/core/cache/decorators/Cacheable.ts +38 -0
  62. package/core/cache/decorators/CacheableRedis.ts +39 -0
  63. package/core/cache/decorators/OutputCache.ts +33 -0
  64. package/core/cache/decorators/OutputRedisCache.ts +33 -0
  65. package/core/cache/decorators/cacheableMetadata.ts +78 -0
  66. package/core/cache/decorators/cacheableRedisMetadata.ts +81 -0
  67. package/core/cache/decorators/outputCacheMetadata.ts +71 -0
  68. package/core/cache/decorators/outputRedisCacheMetadata.ts +77 -0
  69. package/core/cache/di/classProviderHook.ts +26 -0
  70. package/core/cache/distributed/CacheCodec.ts +5 -0
  71. package/core/cache/distributed/DistributedCache.ts +403 -0
  72. package/core/cache/distributed/DistributedCacheDriver.ts +83 -0
  73. package/core/cache/distributed/DistributedCacheStores.ts +28 -0
  74. package/core/cache/distributed/IDistributedCache.ts +40 -0
  75. package/core/cache/distributed/NamedCacheRegistry.ts +23 -0
  76. package/core/cache/distributed/codecs.ts +32 -0
  77. package/core/cache/distributed/index.ts +19 -0
  78. package/core/cache/errors/CacheError.ts +16 -0
  79. package/core/cache/http/CachedHttpPayload.ts +213 -0
  80. package/core/cache/http/applyClientCacheHeaders.ts +61 -0
  81. package/core/cache/http/buildOutputCacheKey.ts +154 -0
  82. package/core/cache/http/buildRedisOutputCacheKey.ts +16 -0
  83. package/core/cache/http/composeOutputCache.ts +130 -0
  84. package/core/cache/http/outputCacheMiddleware.ts +111 -0
  85. package/core/cache/http/outputCacheSecurityWarning.ts +58 -0
  86. package/core/cache/http/outputRedisCacheMiddleware.ts +118 -0
  87. package/core/cache/index.ts +97 -0
  88. package/core/cache/internal/AutomaticCacheKey.ts +106 -0
  89. package/core/cache/internal/CacheKeyGuard.ts +56 -0
  90. package/core/cache/internal/buildCacheProviders.ts +146 -0
  91. package/core/cache/internal/normalizeCacheKey.ts +9 -0
  92. package/core/cache/internal/resolveCachePolicy.ts +32 -0
  93. package/core/cache/internal/resolveCacheableRedisPolicy.ts +17 -0
  94. package/core/cache/internal/resolveOutputRedisCachePolicy.ts +17 -0
  95. package/core/cache/providers/cachedProviders.ts +68 -0
  96. package/core/cache/services/cacheProxy.ts +243 -0
  97. package/core/cache/tokens/CACHE_POLICIES.ts +5 -0
  98. package/core/cache/tokens/DISTRIBUTED_CACHE.ts +30 -0
  99. package/core/cache/types/CacheEntry.ts +7 -0
  100. package/core/cache/types/CacheOptions.ts +60 -0
  101. package/core/cache/types/CachePolicy.ts +74 -0
  102. package/core/cache/types/CacheableRedisOptions.ts +23 -0
  103. package/core/cache/types/OutputRedisCacheOptions.ts +25 -0
  104. package/core/di/README.md +104 -0
  105. package/core/di/ServiceCollection.ts +185 -0
  106. package/core/di/ServiceProvider.ts +689 -0
  107. package/core/di/ServiceScope.ts +61 -0
  108. package/core/di/container.ts +38 -0
  109. package/core/di/errors/AmbiguousNamedDependencyError.ts +10 -0
  110. package/core/di/errors/AsyncResolutionRequiredError.ts +12 -0
  111. package/core/di/errors/CircularDependencyError.ts +10 -0
  112. package/core/di/errors/ClassDependenciesMismatchError.ts +15 -0
  113. package/core/di/errors/DiError.ts +6 -0
  114. package/core/di/errors/InvalidProviderError.ts +9 -0
  115. package/core/di/errors/ModuleEncapsulationError.ts +7 -0
  116. package/core/di/errors/ModuleOwnedProviderConflictError.ts +8 -0
  117. package/core/di/errors/NamedDependencyNotFoundError.ts +7 -0
  118. package/core/di/errors/OptionsValidationError.ts +7 -0
  119. package/core/di/errors/ProviderNotFoundError.ts +10 -0
  120. package/core/di/errors/ScopeDisposedError.ts +7 -0
  121. package/core/di/errors/ScopedServiceFromRootError.ts +9 -0
  122. package/core/di/errors/ServiceValidationError.ts +7 -0
  123. package/core/di/errors/index.ts +14 -0
  124. package/core/di/extensions/activator.ts +39 -0
  125. package/core/di/extensions/application.ts +117 -0
  126. package/core/di/extensions/hosted-service.ts +124 -0
  127. package/core/di/extensions/index.ts +23 -0
  128. package/core/di/extensions/options-reloadable.ts +137 -0
  129. package/core/di/extensions/options.ts +91 -0
  130. package/core/di/extensions/service-provider-token.ts +21 -0
  131. package/core/di/index.ts +97 -0
  132. package/core/di/internal/GraphValidator.ts +119 -0
  133. package/core/di/internal/HostedServicePlan.ts +158 -0
  134. package/core/di/internal/NamedTokenIndex.ts +55 -0
  135. package/core/di/internal/OpenGenericRegistration.ts +14 -0
  136. package/core/di/internal/ResolutionPlan.ts +18 -0
  137. package/core/di/internal/ResolutionScopeState.ts +19 -0
  138. package/core/di/internal/ResolutionTracker.ts +153 -0
  139. package/core/di/internal/ScopeLifecycle.ts +159 -0
  140. package/core/di/internal/ServiceRegistration.ts +14 -0
  141. package/core/di/internal/ServiceRegistry.ts +252 -0
  142. package/core/di/internal/classDeps.ts +38 -0
  143. package/core/di/internal/disposal.ts +58 -0
  144. package/core/di/internal/providerDeps.ts +26 -0
  145. package/core/di/module/DI.ts +146 -0
  146. package/core/di/module/Global.ts +25 -0
  147. package/core/di/module/Module.ts +44 -0
  148. package/core/di/module/ModuleRegistrar.ts +69 -0
  149. package/core/di/module/autoDeps.ts +39 -0
  150. package/core/di/module/classProviderHooks.ts +66 -0
  151. package/core/di/module/collectModuleConfigs.ts +57 -0
  152. package/core/di/module/collectModuleControllers.ts +53 -0
  153. package/core/di/module/collectModuleUiProfiles.ts +53 -0
  154. package/core/di/module/createContainer.ts +261 -0
  155. package/core/di/module/encapsulation.ts +416 -0
  156. package/core/di/module/encapsulationHooks.ts +36 -0
  157. package/core/di/module/generatedProviderAttachments.ts +102 -0
  158. package/core/di/module/index.ts +41 -0
  159. package/core/di/module/moduleExtensions.ts +35 -0
  160. package/core/di/module/moduleNameBinding.ts +136 -0
  161. package/core/di/module/moduleOwnedProviderContributors.ts +409 -0
  162. package/core/di/module/providerSelection.ts +90 -0
  163. package/core/di/module/shortcuts.ts +111 -0
  164. package/core/di/module/types/BazisModule.ts +71 -0
  165. package/core/di/module/types/DiRegistrar.ts +24 -0
  166. package/core/di/module/types/index.ts +2 -0
  167. package/core/di/provider/index.ts +26 -0
  168. package/core/di/provider/providerGuards.ts +17 -0
  169. package/core/di/provider/types/AsyncFactoryProvider.ts +15 -0
  170. package/core/di/provider/types/ClassProvider.ts +18 -0
  171. package/core/di/provider/types/FactoryProvider.ts +20 -0
  172. package/core/di/provider/types/KeyedDependency.ts +20 -0
  173. package/core/di/provider/types/LazyDependency.ts +31 -0
  174. package/core/di/provider/types/NamedDependency.ts +16 -0
  175. package/core/di/provider/types/Provider.ts +10 -0
  176. package/core/di/provider/types/ProviderDefinition.ts +11 -0
  177. package/core/di/provider/types/ProviderDependencyList.ts +11 -0
  178. package/core/di/provider/types/ProviderLifetime.ts +1 -0
  179. package/core/di/provider/types/ProviderOwnership.ts +7 -0
  180. package/core/di/provider/types/ResolvedDeps.ts +18 -0
  181. package/core/di/provider/types/ValueProvider.ts +6 -0
  182. package/core/di/provider/types/index.ts +13 -0
  183. package/core/di/token.ts +84 -0
  184. package/core/di/types/BuildServiceProviderOptions.ts +4 -0
  185. package/core/di/types/ServiceKey.ts +1 -0
  186. package/core/di/types/ServiceResolver.ts +16 -0
  187. package/core/di/types/index.ts +3 -0
  188. package/core/generatedFingerprint.ts +60 -0
  189. package/core/generatedRuntime.ts +187 -0
  190. package/core/grpc/Grpc.module.ts +23 -0
  191. package/core/grpc/GrpcBinding.contract.ts +35 -0
  192. package/core/grpc/GrpcCall.ts +73 -0
  193. package/core/grpc/GrpcClient.ts +172 -0
  194. package/core/grpc/GrpcClientCall.ts +267 -0
  195. package/core/grpc/GrpcError.ts +19 -0
  196. package/core/grpc/GrpcRequest.binding.ts +45 -0
  197. package/core/grpc/GrpcServer.ts +204 -0
  198. package/core/grpc/GrpcStatus.ts +8 -0
  199. package/core/grpc/GrpcTransport.ts +174 -0
  200. package/core/grpc/Metadata.ts +73 -0
  201. package/core/grpc/ProtoCodec.ts +225 -0
  202. package/core/grpc/ProtoParser.ts +192 -0
  203. package/core/grpc/ProtoReader.ts +34 -0
  204. package/core/grpc/ProtoSchema.ts +52 -0
  205. package/core/grpc/ServerCredentials.ts +30 -0
  206. package/core/grpc/clientContracts.ts +39 -0
  207. package/core/grpc/contracts.ts +45 -0
  208. package/core/grpc/decorators.ts +82 -0
  209. package/core/grpc/grpcClientProvider.ts +9 -0
  210. package/core/grpc/index.ts +17 -0
  211. package/core/grpc/moduleControllers.ts +38 -0
  212. package/core/grpc/protobuf.ts +80 -0
  213. package/core/grpc/serviceDefinition.ts +20 -0
  214. package/core/http/Authorization/Authorize.ts +52 -0
  215. package/core/http/Authorization/authorizeComposer.ts +31 -0
  216. package/core/http/Authorization/metadata.ts +158 -0
  217. package/core/http/Binding/ParameterBinder.ts +109 -0
  218. package/core/http/Binding/RequestModel.ts +27 -0
  219. package/core/http/Binding/autoBindings.ts +125 -0
  220. package/core/http/Binding/bindings.ts +19 -0
  221. package/core/http/Binding/convert.ts +48 -0
  222. package/core/http/Binding/generatedSpec.ts +18 -0
  223. package/core/http/Binding/listModelRegistry.ts +47 -0
  224. package/core/http/Binding/modelBinder.ts +345 -0
  225. package/core/http/Binding/modelValidator.ts +30 -0
  226. package/core/http/Binding/requestModelRegistry.ts +117 -0
  227. package/core/http/Decorators/attributes.ts +92 -0
  228. package/core/http/Decorators/controller.ts +24 -0
  229. package/core/http/Decorators/metadata.ts +107 -0
  230. package/core/http/Decorators/routes.ts +131 -0
  231. package/core/http/Errors/HttpError.ts +92 -0
  232. package/core/http/HttpContext/HttpContext.ts +148 -0
  233. package/core/http/HttpContext/ResponseBuilder.ts +37 -0
  234. package/core/http/HttpContext/inspectableRedirects.ts +47 -0
  235. package/core/http/HttpContext/principal.ts +24 -0
  236. package/core/http/HttpContext/responseLifetime.ts +45 -0
  237. package/core/http/HttpServer.ts +627 -0
  238. package/core/http/Middleware/accessLog.ts +90 -0
  239. package/core/http/Middleware/cors.ts +160 -0
  240. package/core/http/Middleware/errorHandler.ts +100 -0
  241. package/core/http/Middleware/pipeline.ts +21 -0
  242. package/core/http/Middleware/rateLimit.ts +104 -0
  243. package/core/http/Middleware/securityHeaders.ts +118 -0
  244. package/core/http/Middleware/types.ts +19 -0
  245. package/core/http/OpenApi/generatedOpenApiRegistry.ts +102 -0
  246. package/core/http/OpenApi/openApiDocs.ts +75 -0
  247. package/core/http/OpenApi/openApiDocument.ts +356 -0
  248. package/core/http/README.md +139 -0
  249. package/core/http/Results/HttpResult.ts +19 -0
  250. package/core/http/Results/normalize.ts +93 -0
  251. package/core/http/Results/results.ts +70 -0
  252. package/core/http/Routing/Router.ts +201 -0
  253. package/core/http/Routing/RouterBuilder.ts +184 -0
  254. package/core/http/Routing/template.ts +112 -0
  255. package/core/http/SPEC.md +981 -0
  256. package/core/http/Versioning/VersionReader.ts +20 -0
  257. package/core/http/WebSocketUpgrade.ts +29 -0
  258. package/core/http/composeRouteMiddlewareComposers.ts +21 -0
  259. package/core/http/correlation/createCorrelationIdMiddleware.ts +79 -0
  260. package/core/http/httpModule.ts +48 -0
  261. package/core/http/index.ts +140 -0
  262. package/core/http/middlewareTokens.ts +48 -0
  263. package/core/http/options.ts +134 -0
  264. package/core/http-client/index.ts +105 -0
  265. package/core/infra/Infra.ts +158 -0
  266. package/core/infra/InfraConnector.ts +86 -0
  267. package/core/infra/InfraLifecycle.ts +86 -0
  268. package/core/infra/cache/RedisDistributedCacheBackend.ts +88 -0
  269. package/core/infra/cache/RedisDistributedCacheDriver.ts +186 -0
  270. package/core/infra/cache/index.ts +7 -0
  271. package/core/infra/connectorConfig.ts +29 -0
  272. package/core/infra/connectorIdentity.ts +39 -0
  273. package/core/infra/connectors/codex/CodexAppServer.ts +146 -0
  274. package/core/infra/connectors/codex/CodexAppServerClient.ts +258 -0
  275. package/core/infra/connectors/codex/CodexPolicy.ts +114 -0
  276. package/core/infra/connectors/codex/CodexTurn.ts +133 -0
  277. package/core/infra/connectors/codex/contracts.ts +82 -0
  278. package/core/infra/connectors/codex.ts +26 -0
  279. package/core/infra/connectors/llm.ts +78 -0
  280. package/core/infra/connectors/llmRouter.ts +443 -0
  281. package/core/infra/connectors/openaiCompatible.ts +590 -0
  282. package/core/infra/connectors/openaiTextStream.ts +134 -0
  283. package/core/infra/connectors/opensearch.ts +307 -0
  284. package/core/infra/connectors/postgres.ts +105 -0
  285. package/core/infra/connectors/redis.ts +132 -0
  286. package/core/infra/index.ts +58 -0
  287. package/core/kernel/ApplicationLifetime.ts +91 -0
  288. package/core/kernel/Bazis.ts +73 -0
  289. package/core/kernel/Environment.ts +53 -0
  290. package/core/kernel/Kernel.ts +391 -0
  291. package/core/kernel/KernelBuilder.ts +172 -0
  292. package/core/kernel/LifecycleCoordinator.ts +204 -0
  293. package/core/kernel/README.md +66 -0
  294. package/core/kernel/SupervisedHostedService.ts +147 -0
  295. package/core/kernel/config/ConfigRegistry.ts +48 -0
  296. package/core/kernel/config/Configuration.ts +110 -0
  297. package/core/kernel/config/README.md +62 -0
  298. package/core/kernel/config/Secret.ts +29 -0
  299. package/core/kernel/config/addConfigOptions.ts +63 -0
  300. package/core/kernel/config/defineConfig.ts +211 -0
  301. package/core/kernel/config/sources.ts +123 -0
  302. package/core/kernel/correlation/requestContext.ts +57 -0
  303. package/core/kernel/errors/ConfigKeyMissingError.ts +7 -0
  304. package/core/kernel/errors/KernelError.ts +7 -0
  305. package/core/kernel/errors/ShutdownTimeoutError.ts +7 -0
  306. package/core/kernel/errors/StartupAbortedError.ts +7 -0
  307. package/core/kernel/errors/StartupTimeoutError.ts +7 -0
  308. package/core/kernel/errors/index.ts +5 -0
  309. package/core/kernel/events/EventBus.ts +140 -0
  310. package/core/kernel/events/EventToken.ts +17 -0
  311. package/core/kernel/events/eventSubscribers.ts +126 -0
  312. package/core/kernel/events/kernelEvents.ts +16 -0
  313. package/core/kernel/events/onEvent.ts +32 -0
  314. package/core/kernel/health/HealthCheckContracts.ts +42 -0
  315. package/core/kernel/health/HealthService.ts +93 -0
  316. package/core/kernel/index.ts +96 -0
  317. package/core/kernel/internal/awaitAbortable.ts +18 -0
  318. package/core/kernel/internal/awaitShutdown.ts +21 -0
  319. package/core/kernel/internal/reportDiagnosticFailure.ts +8 -0
  320. package/core/kernel/internal/validateTimeout.ts +8 -0
  321. package/core/kernel/lifecycleHooks.ts +18 -0
  322. package/core/kernel/logging/ConsoleLogger.ts +68 -0
  323. package/core/kernel/logging/Logger.ts +22 -0
  324. package/core/kernel/types/ConfigSource.ts +9 -0
  325. package/core/kernel/types/EnvironmentName.ts +1 -0
  326. package/core/kernel/types/KernelOptions.ts +23 -0
  327. package/core/kernel/types/LifecycleHook.ts +18 -0
  328. package/core/kernel/types/index.ts +4 -0
  329. package/core/orm/DATABASE_PROVIDER.ts +5 -0
  330. package/core/orm/OrmHostedPlan.validator.ts +55 -0
  331. package/core/orm/OrmLifecycle.ts +146 -0
  332. package/core/orm/OrmOwnedStoreLifecycle.ts +96 -0
  333. package/core/orm/buildOrmProviders.ts +152 -0
  334. package/core/orm/databaseConnector.ts +108 -0
  335. package/core/orm/encapsulationHook.ts +19 -0
  336. package/core/orm/index.ts +95 -0
  337. package/core/orm/listQuery.ts +198 -0
  338. package/core/orm/ormModule.ts +173 -0
  339. package/core/orm/ownedStoreContributions.ts +195 -0
  340. package/core/orm/registerRepositories.ts +27 -0
  341. package/core/orm/repository.ts +45 -0
  342. package/core/orm/strictSchemaHostedIdentity.ts +17 -0
  343. package/core/scripts/agent-codegen.ts +1166 -0
  344. package/core/scripts/di-generate-target.ts +90 -0
  345. package/core/scripts/di-generate.ts +1837 -0
  346. package/core/scripts/orm-predicate-codegen.ts +33 -0
  347. package/core/scripts/request-model-codegen.ts +326 -0
  348. package/core/websocket/DESIGN.md +297 -0
  349. package/core/websocket/WsRateLimiter.ts +101 -0
  350. package/core/websocket/adapter/adapter.interface.ts +45 -0
  351. package/core/websocket/adapter/in-memory.adapter.ts +190 -0
  352. package/core/websocket/adapter/redis-delivery-scripts.ts +135 -0
  353. package/core/websocket/adapter/redis-delivery-store.ts +86 -0
  354. package/core/websocket/adapter/redis-operations.ts +33 -0
  355. package/core/websocket/adapter/redis.adapter.ts +218 -0
  356. package/core/websocket/codec/binary.codec.ts +87 -0
  357. package/core/websocket/codec/json.codec.ts +34 -0
  358. package/core/websocket/codec/packet-codec.interface.ts +17 -0
  359. package/core/websocket/decorators.ts +165 -0
  360. package/core/websocket/explorer.ts +126 -0
  361. package/core/websocket/index.ts +78 -0
  362. package/core/websocket/middleware.ts +146 -0
  363. package/core/websocket/packet-codec.ts +75 -0
  364. package/core/websocket/reliable-delivery.ts +56 -0
  365. package/core/websocket/session-creation.ts +16 -0
  366. package/core/websocket/session-manager.ts +856 -0
  367. package/core/websocket/socket-wrapper.ts +314 -0
  368. package/core/websocket/topic-cache.ts +59 -0
  369. package/core/websocket/types.ts +122 -0
  370. package/core/websocket/websocketModule.ts +96 -0
  371. package/core/websocket/ws-dispatch.ts +123 -0
  372. package/core/websocket/ws-server.ts +1707 -0
  373. package/index.ts +281 -0
  374. package/library/boundary/diagnostics-v1.ts +136 -0
  375. package/library/boundary/index.ts +73 -0
  376. package/library/boundary/json/decodeBoundedJsonV1.ts +518 -0
  377. package/library/boundary/json/limits-v1.ts +46 -0
  378. package/library/boundary/json/normalizeBoundedJsonV1.ts +256 -0
  379. package/library/boundary/json/types-v1.ts +11 -0
  380. package/library/boundary/schema/boundarySchemaHashV1.ts +6 -0
  381. package/library/boundary/schema/collectBoundaryValueDiagnosticsV1.ts +325 -0
  382. package/library/boundary/schema/decodeBoundarySchemaV1.ts +646 -0
  383. package/library/boundary/schema/index.ts +8 -0
  384. package/library/boundary/schema/types-v1.ts +99 -0
  385. package/library/boundary/schema/validateBoundaryValueV1.ts +58 -0
  386. package/library/boundary/serialization/canonicalJsonV1.ts +66 -0
  387. package/library/http-client/HttpClient.ts +969 -0
  388. package/library/http-client/HttpClientFactory.ts +45 -0
  389. package/library/http-client/errors.ts +68 -0
  390. package/library/http-client/index.ts +43 -0
  391. package/library/http-client/interceptors.ts +40 -0
  392. package/library/http-client/progress.ts +62 -0
  393. package/library/http-client/redirectProtocol.ts +6 -0
  394. package/library/http-client/serialize.ts +133 -0
  395. package/library/http-client/types.ts +174 -0
  396. package/library/jsonapi/ListQueryError.ts +25 -0
  397. package/library/jsonapi/ListRequest.ts +37 -0
  398. package/library/jsonapi/decorators.ts +161 -0
  399. package/library/jsonapi/document.ts +124 -0
  400. package/library/jsonapi/index.ts +40 -0
  401. package/library/jsonapi/parseListQuery.ts +291 -0
  402. package/library/jsonapi/types.ts +125 -0
  403. package/library/jwt/JwtEncoder.ts +40 -0
  404. package/library/jwt/JwtKeyRing.ts +164 -0
  405. package/library/jwt/JwtValidator.ts +210 -0
  406. package/library/jwt/TokenIssuer.ts +149 -0
  407. package/library/jwt/TokenService.ts +51 -0
  408. package/library/jwt/base64url.ts +61 -0
  409. package/library/jwt/claims.ts +36 -0
  410. package/library/jwt/errors.ts +44 -0
  411. package/library/jwt/index.ts +59 -0
  412. package/library/jwt/limits.ts +8 -0
  413. package/library/jwt/signing/Hs256Algorithm.ts +62 -0
  414. package/library/jwt/signing/Rs256Algorithm.ts +133 -0
  415. package/library/jwt/signing/SigningAlgorithm.ts +18 -0
  416. package/library/jwt/signing/pem.ts +30 -0
  417. package/library/openapi/codegen.ts +875 -0
  418. package/library/openapi/document.ts +326 -0
  419. package/library/openapi/index.ts +13 -0
  420. package/library/openapi/types.ts +69 -0
  421. package/library/openapi/ui.ts +182 -0
  422. package/library/orm/DatabaseFacade.ts +209 -0
  423. package/library/orm/DbContext.ts +107 -0
  424. package/library/orm/DbContextFactory.ts +25 -0
  425. package/library/orm/DbContextOptions.ts +33 -0
  426. package/library/orm/Metadata/DynamicModelBuilder.ts +497 -0
  427. package/library/orm/Metadata/KeyTuple.ts +36 -0
  428. package/library/orm/Metadata/ModelBuilder.ts +299 -0
  429. package/library/orm/Metadata/OrmModel.ts +80 -0
  430. package/library/orm/Metadata/ValueConverter.ts +57 -0
  431. package/library/orm/Metadata/conventions.ts +54 -0
  432. package/library/orm/Metadata/decorators.ts +396 -0
  433. package/library/orm/Metadata/types.ts +140 -0
  434. package/library/orm/Providers/OwnedStoreCatalog.reader.ts +1802 -0
  435. package/library/orm/Providers/PostgresDialect.ts +234 -0
  436. package/library/orm/Providers/PostgresProvider.ts +1494 -0
  437. package/library/orm/Providers/PostgresSchema.decoder.ts +107 -0
  438. package/library/orm/Providers/limits.ts +29 -0
  439. package/library/orm/Providers/operationDeadline.ts +43 -0
  440. package/library/orm/Providers/ormOwnedStoreRuntime.ts +19 -0
  441. package/library/orm/Providers/ormTransactionRuntime.ts +117 -0
  442. package/library/orm/Providers/propertyConversion.ts +14 -0
  443. package/library/orm/Providers/resolvedForeignKey.ts +16 -0
  444. package/library/orm/Providers/transactionCallbacks.ts +45 -0
  445. package/library/orm/Providers/transactionOutcome.ts +82 -0
  446. package/library/orm/Providers/transactionScopes.ts +78 -0
  447. package/library/orm/Providers/types.ts +207 -0
  448. package/library/orm/Query/DbSet.ts +78 -0
  449. package/library/orm/Query/EntityQuery.ts +247 -0
  450. package/library/orm/Query/ImmediateMutations.ts +226 -0
  451. package/library/orm/Query/IncludeLoader.ts +200 -0
  452. package/library/orm/Query/QueryPlan.ts +55 -0
  453. package/library/orm/Query/SqlTranslator.ts +195 -0
  454. package/library/orm/Query/conditions.ts +127 -0
  455. package/library/orm/Query/materialize.ts +39 -0
  456. package/library/orm/README.md +256 -0
  457. package/library/orm/Repository/README.md +684 -0
  458. package/library/orm/Repository/Repository.ts +68 -0
  459. package/library/orm/Saving/CommandBuilder.ts +139 -0
  460. package/library/orm/Saving/ExecutionStrategy.ts +128 -0
  461. package/library/orm/Saving/SaveExecutor.ts +413 -0
  462. package/library/orm/Saving/applyConventions.ts +64 -0
  463. package/library/orm/Schema/CheckExpression.ts +327 -0
  464. package/library/orm/Schema/ExactSchemaVerifier.ts +168 -0
  465. package/library/orm/Schema/ExpectedSchema.ts +43 -0
  466. package/library/orm/Schema/MigrationRunner.ts +146 -0
  467. package/library/orm/Schema/Migrator.ts +73 -0
  468. package/library/orm/Schema/OrmOwnedStore.ts +123 -0
  469. package/library/orm/Schema/OwnedStoreAdmission.ts +752 -0
  470. package/library/orm/Schema/OwnedStoreCanonical.ts +273 -0
  471. package/library/orm/Schema/OwnedStoreCatalog.ts +1325 -0
  472. package/library/orm/Schema/SafeAdditiveSchema.ts +100 -0
  473. package/library/orm/Schema/SchemaAdmission.ts +62 -0
  474. package/library/orm/Schema/SchemaDiffer.ts +78 -0
  475. package/library/orm/Schema/formatSchemaDifferences.ts +62 -0
  476. package/library/orm/Schema/introspection.ts +52 -0
  477. package/library/orm/Schema/physicalColumnTypes.ts +37 -0
  478. package/library/orm/Schema/tableKey.ts +26 -0
  479. package/library/orm/Tracking/ChangeTracker.ts +448 -0
  480. package/library/orm/Tracking/EntityState.ts +13 -0
  481. package/library/orm/Transactions/OrmTransaction.ts +30 -0
  482. package/library/orm/Transactions/TransactionScopeCoordinator.ts +377 -0
  483. package/library/orm/errors.ts +190 -0
  484. package/library/orm/index.ts +162 -0
  485. package/library/orm/runtime.ts +14 -0
  486. package/library/redaction/index.ts +166 -0
  487. package/library/ui/UiProfile.ts +77 -0
  488. package/library/ui/compiled-v1.ts +131 -0
  489. package/library/ui/compiler/compileUiSurfaceV1.ts +717 -0
  490. package/library/ui/compiler/contracts-v1.ts +25 -0
  491. package/library/ui/compiler/index.ts +12 -0
  492. package/library/ui/compiler/openApiIndex.ts +246 -0
  493. package/library/ui/defineUiProfile.ts +340 -0
  494. package/library/ui/diagnostics-v1.ts +33 -0
  495. package/library/ui/index.ts +129 -0
  496. package/library/ui/profile-v1.ts +191 -0
  497. package/library/ui/serialization.ts +130 -0
  498. package/library/ui/uiProfileAuthoring.ts +289 -0
  499. package/library/ui/uiProfileAuthoringMetadata.ts +78 -0
  500. package/library/validation/MessageRegistry.ts +144 -0
  501. package/library/validation/README.md +62 -0
  502. package/library/validation/RuleCompiler.ts +183 -0
  503. package/library/validation/RuleEngine.ts +401 -0
  504. package/library/validation/SPEC.md +579 -0
  505. package/library/validation/ValidationError.ts +37 -0
  506. package/library/validation/ValidationResult.ts +63 -0
  507. package/library/validation/Validator.ts +101 -0
  508. package/library/validation/index.ts +16 -0
  509. package/library/validation/metadata.ts +69 -0
  510. package/library/validation/modelValidatorAdapter.ts +119 -0
  511. package/library/validation/types/ValidationCode.ts +69 -0
  512. package/library/validation/types/ValidatorOptions.ts +153 -0
  513. package/package.json +80 -0
@@ -0,0 +1,102 @@
1
+ import type { GeneratedOpenApiMetadata, GeneratedOpenApiOperationMetadata, OpenApiSchema } from "../../../library/openapi";
2
+
3
+ export type GeneratedOpenApiSchemaModel = abstract new (...args: never[]) => object;
4
+
5
+ const EMPTY_GENERATED_OPENAPI_METADATA: GeneratedOpenApiMetadata = Object.freeze({
6
+ schemas: Object.freeze({}),
7
+ operations: Object.freeze({}),
8
+ });
9
+
10
+ interface GeneratedOpenApiTargetSlice {
11
+ readonly metadata: GeneratedOpenApiMetadata;
12
+ readonly controllers?: ReadonlySet<abstract new (...args: never[]) => object>;
13
+ }
14
+
15
+ let registered: GeneratedOpenApiTargetSlice[] = [];
16
+ let schemaNamesByModel = new Map<GeneratedOpenApiSchemaModel, string>();
17
+
18
+ export function registerGeneratedOpenApiMetadata(
19
+ metadata: GeneratedOpenApiMetadata,
20
+ controllers?: readonly (abstract new (...args: never[]) => object)[],
21
+ ): void {
22
+ if (metadata === EMPTY_GENERATED_OPENAPI_METADATA || registered.some((entry) => entry.metadata === metadata)) {
23
+ return;
24
+ }
25
+ registered.push({ metadata, ...(controllers === undefined ? {} : { controllers: new Set(controllers) }) });
26
+ }
27
+
28
+ /**
29
+ * Binds a real runtime model constructor to the exact generated component
30
+ * schema. This is the nominal bridge used by code-first consumers such as
31
+ * @UiProfile; they must not rediscover schemas through `ctor.name`.
32
+ */
33
+ export function registerGeneratedOpenApiSchemaModel(
34
+ model: GeneratedOpenApiSchemaModel,
35
+ schemaName: string,
36
+ ): void {
37
+ const normalized = schemaName.trim();
38
+ if (normalized.length === 0) {
39
+ throw new TypeError("Generated OpenAPI schema model name must not be empty.");
40
+ }
41
+ const existing = schemaNamesByModel.get(model);
42
+ if (existing !== undefined && existing !== normalized) {
43
+ throw new TypeError(
44
+ `OpenAPI model ${model.name || "<anonymous>"} is already bound to schema ${existing}; ` +
45
+ `cannot also bind it to ${normalized}.`,
46
+ );
47
+ }
48
+ schemaNamesByModel.set(model, normalized);
49
+ }
50
+
51
+ /** Exact generated component schema name for a runtime model constructor. */
52
+ export function getGeneratedOpenApiSchemaName(
53
+ model: GeneratedOpenApiSchemaModel,
54
+ ): string | undefined {
55
+ return schemaNamesByModel.get(model);
56
+ }
57
+
58
+ export function getGeneratedOpenApiMetadata(controllers?: readonly (abstract new (...args: never[]) => object)[]): GeneratedOpenApiMetadata {
59
+ const requested = controllers === undefined ? undefined : new Set(controllers);
60
+ const selected = requested === undefined
61
+ ? registered
62
+ : registered.filter((entry) => entry.controllers === undefined || [...requested].some((controller) => entry.controllers?.has(controller) === true));
63
+ if (selected.length === 0) {
64
+ return EMPTY_GENERATED_OPENAPI_METADATA;
65
+ }
66
+
67
+ const schemas: Record<string, OpenApiSchema> = {};
68
+ const operations: Record<string, Record<string, GeneratedOpenApiOperationMetadata>> = {};
69
+ for (let index = 0; index < selected.length; index += 1) {
70
+ const metadata = selected[index]!.metadata;
71
+ Object.assign(schemas, metadata.schemas);
72
+ for (const [controllerName, methods] of Object.entries(metadata.operations)) {
73
+ operations[controllerName] ??= {};
74
+ Object.assign(operations[controllerName], methods);
75
+ }
76
+ }
77
+
78
+ return Object.freeze({
79
+ schemas: Object.freeze(schemas),
80
+ operations: Object.freeze(operations),
81
+ });
82
+ }
83
+
84
+ /** Internal generated-runtime transaction support. */
85
+ export function snapshotGeneratedOpenApiRegistry(): { readonly registered: readonly GeneratedOpenApiTargetSlice[]; readonly schemaNamesByModel: typeof schemaNamesByModel } {
86
+ return {
87
+ registered: registered.map((entry) => ({
88
+ metadata: entry.metadata,
89
+ ...(entry.controllers === undefined ? {} : { controllers: new Set(entry.controllers) }),
90
+ })),
91
+ schemaNamesByModel: new Map(schemaNamesByModel),
92
+ };
93
+ }
94
+
95
+ /** Internal generated-runtime transaction support. */
96
+ export function restoreGeneratedOpenApiRegistry(snapshot: ReturnType<typeof snapshotGeneratedOpenApiRegistry>): void {
97
+ registered = snapshot.registered.map((entry) => ({
98
+ metadata: entry.metadata,
99
+ ...(entry.controllers === undefined ? {} : { controllers: new Set(entry.controllers) }),
100
+ }));
101
+ schemaNamesByModel = snapshot.schemaNamesByModel;
102
+ }
@@ -0,0 +1,75 @@
1
+ import type { Class } from "../../di";
2
+ import { Environment } from "../../kernel";
3
+ import {
4
+ renderOpenApiHtml,
5
+ serveOpenApiDocs,
6
+ type OpenApiDocsOptions,
7
+ type PreparedOpenApiDocs,
8
+ } from "../../../library/openapi";
9
+ import { buildHttpOpenApiDocument } from "./openApiDocument";
10
+ import type { ApiVersioningOptions } from "../options";
11
+
12
+ interface PrepareOpenApiDocsInput {
13
+ readonly option?: OpenApiDocsOptions | boolean;
14
+ readonly controllers: readonly Class<object>[];
15
+ readonly globalPrefix?: string;
16
+ readonly versioning?: ApiVersioningOptions;
17
+ readonly environment?: Environment;
18
+ }
19
+
20
+ const DEFAULT_UI_PATH = "/docs";
21
+ const DEFAULT_TITLE = "Bazis API";
22
+ const DEFAULT_VERSION = "1.0.0";
23
+
24
+ export { serveOpenApiDocs };
25
+
26
+ export function prepareOpenApiDocs(input: PrepareOpenApiDocsInput): PreparedOpenApiDocs | undefined {
27
+ if (!isEnabled(input.option, input.environment)) {
28
+ return undefined;
29
+ }
30
+ const options = normalizeOptions(input.option);
31
+ const uiPath = normalizeAbsolutePath(options.path ?? DEFAULT_UI_PATH);
32
+ const specPath = normalizeAbsolutePath(options.specPath ?? joinDocsPath(uiPath, "openapi.json"));
33
+ const title = options.title ?? DEFAULT_TITLE;
34
+ const version = options.version ?? DEFAULT_VERSION;
35
+ const document = buildHttpOpenApiDocument({
36
+ controllers: input.controllers,
37
+ globalPrefix: input.globalPrefix,
38
+ versioning: input.versioning,
39
+ title,
40
+ version,
41
+ });
42
+ const json = JSON.stringify(document, null, 2);
43
+ return {
44
+ uiPath,
45
+ specPath,
46
+ document,
47
+ json,
48
+ html: renderOpenApiHtml(title, specPath),
49
+ };
50
+ }
51
+
52
+ function isEnabled(option: OpenApiDocsOptions | boolean | undefined, environment: Environment | undefined): boolean {
53
+ if (typeof option === "boolean") {
54
+ return option;
55
+ }
56
+ if (option !== undefined) {
57
+ return option.enabled ?? true;
58
+ }
59
+ return environment?.debug ?? false;
60
+ }
61
+
62
+ function normalizeOptions(option: OpenApiDocsOptions | boolean | undefined): OpenApiDocsOptions {
63
+ return typeof option === "object" && option !== null ? option : {};
64
+ }
65
+
66
+ function normalizeAbsolutePath(path: string): string {
67
+ const trimmed = path.trim();
68
+ const prefixed = trimmed.startsWith("/") ? trimmed : `/${trimmed}`;
69
+ const parts = prefixed.split("/").filter((part) => part.length > 0);
70
+ return `/${parts.join("/")}`;
71
+ }
72
+
73
+ function joinDocsPath(base: string, child: string): string {
74
+ return `${base.replace(/\/+$/, "")}/${child.replace(/^\/+/, "")}`;
75
+ }
@@ -0,0 +1,356 @@
1
+ import type { Class } from "../../di";
2
+ import { createHash } from "node:crypto";
3
+ import {
4
+ buildOpenApiDocument,
5
+ type OpenApiCatalogOperation,
6
+ type OpenApiDocumentBuildInput as LibraryOpenApiDocumentBuildInput,
7
+ type OpenApiParameter,
8
+ type OpenApiSchema,
9
+ } from "../../../library/openapi";
10
+ import { optionsFromSchema } from "../../../library/jsonapi";
11
+ import { resolveAuthorizeMeta } from "../Authorization/metadata";
12
+ import type { ParameterBinding } from "../Binding/bindings";
13
+ import { resolveGeneratedBindings } from "../Binding/autoBindings";
14
+ import { controllerMetaOf, type ActionMeta, type ControllerMeta } from "../Decorators/metadata";
15
+ import { joinPaths } from "../Routing/template";
16
+ import { getGeneratedOpenApiMetadata } from "./generatedOpenApiRegistry";
17
+ import type { ApiVersioningOptions } from "../options";
18
+ import type { GeneratedOpenApiMetadata } from "../../../library/openapi";
19
+
20
+ export interface HttpOpenApiDocumentBuildInput {
21
+ readonly controllers: readonly Class<object>[];
22
+ readonly globalPrefix?: string;
23
+ readonly versioning?: ApiVersioningOptions;
24
+ readonly title: string;
25
+ readonly version: string;
26
+ }
27
+
28
+ export function buildHttpOpenApiDocument(input: HttpOpenApiDocumentBuildInput): OpenApiSchema {
29
+ const generated = getGeneratedOpenApiMetadata(input.controllers);
30
+ const documentInput: LibraryOpenApiDocumentBuildInput = {
31
+ title: input.title,
32
+ version: input.version,
33
+ schemas: generated.schemas,
34
+ operations: collectOpenApiOperations(input, generated),
35
+ generatedBy: "bazis:di-generate",
36
+ };
37
+ return buildOpenApiDocument(documentInput);
38
+ }
39
+
40
+ function collectOpenApiOperations(
41
+ input: HttpOpenApiDocumentBuildInput,
42
+ generated: GeneratedOpenApiMetadata,
43
+ ): OpenApiCatalogOperation[] {
44
+ const operations: OpenApiCatalogOperation[] = [];
45
+ for (const controllerClass of input.controllers) {
46
+ const meta = controllerMetaOf(controllerClass);
47
+ if (!meta?.isController) {
48
+ continue;
49
+ }
50
+ for (const [methodName, action] of meta.actions) {
51
+ if (action.routes.length === 0) {
52
+ continue;
53
+ }
54
+ const bindings = resolveGeneratedBindings(controllerClass, methodName) ?? [];
55
+ for (const route of action.routes) {
56
+ operations.push(createOperation({
57
+ controllerClass,
58
+ methodName,
59
+ meta,
60
+ action,
61
+ bindings,
62
+ httpMethod: route.httpMethod,
63
+ path: fullOpenApiPath(input.globalPrefix, input.versioning?.source, meta, action, route.template),
64
+ routeTemplate: joinPaths(meta.prefix, route.template),
65
+ versioning: input.versioning,
66
+ generated,
67
+ }));
68
+ }
69
+ }
70
+ }
71
+ return operations;
72
+ }
73
+
74
+ interface CreateOperationInput {
75
+ readonly controllerClass: Class<object>;
76
+ readonly methodName: string | symbol;
77
+ readonly meta: ControllerMeta;
78
+ readonly action: ActionMeta;
79
+ readonly bindings: readonly ParameterBinding[];
80
+ readonly httpMethod: string;
81
+ readonly path: string;
82
+ readonly routeTemplate: string;
83
+ readonly versioning?: ApiVersioningOptions;
84
+ readonly generated: GeneratedOpenApiMetadata;
85
+ }
86
+
87
+ function createOperation(input: CreateOperationInput): OpenApiCatalogOperation {
88
+ const methodName = String(input.methodName);
89
+ const version = input.action.version ?? input.meta.version;
90
+ const auth = resolveAuthorizeMeta(input.controllerClass, input.methodName);
91
+ const generatedOperation = input.generated.operations[input.controllerClass.name]?.[methodName];
92
+ const status = String(successStatus(input.httpMethod, input.action));
93
+ const responseSchema = generatedOperation?.response;
94
+ const contentType = input.action.produces ?? "application/json";
95
+
96
+ return {
97
+ path: input.path,
98
+ httpMethod: input.httpMethod,
99
+ tag: tagName(input.meta, input.controllerClass),
100
+ operationId: stableHttpOperationId(input.httpMethod, input.path),
101
+ summary: `${normalizedMethod(input.httpMethod)} ${input.path}`,
102
+ parameters: collectParameters(
103
+ input.bindings,
104
+ input.versioning,
105
+ version,
106
+ routeParamSchemas(input.routeTemplate),
107
+ ),
108
+ requestBody: createRequestBody(input.bindings, input.action, input.generated),
109
+ responses: {
110
+ [status]: responseSchema && status !== "204"
111
+ ? {
112
+ description: "Success",
113
+ content: {
114
+ [contentType]: {
115
+ schema: responseSchema,
116
+ },
117
+ },
118
+ }
119
+ : { description: "Success" },
120
+ },
121
+ authorized: !auth.allowAnonymous && auth.authorize !== undefined,
122
+ ...(version !== undefined ? { versions: [version] } : {}),
123
+ };
124
+ }
125
+
126
+ /**
127
+ * Stable transport identity owned by HTTP/OpenAPI. Controller and handler
128
+ * names are intentionally excluded: renaming implementation symbols must not
129
+ * invalidate compiled UI references or generated clients.
130
+ */
131
+ function stableHttpOperationId(httpMethod: string, canonicalPath: string): string {
132
+ const method = normalizedMethod(httpMethod).toLowerCase();
133
+ const slug = readableOperationPath(canonicalPath);
134
+ const digest = createHash("sha256")
135
+ .update(JSON.stringify([method, canonicalPath]))
136
+ .digest("hex")
137
+ .slice(0, 32);
138
+ return `http_${method}_${slug}__${digest}`;
139
+ }
140
+
141
+ function readableOperationPath(path: string): string {
142
+ const slug = path
143
+ .replace(/\{([^{}]+)\}/g, " by $1 ")
144
+ .toLowerCase()
145
+ .replace(/[^a-z0-9]+/g, "_")
146
+ .replace(/^_+|_+$/g, "")
147
+ .slice(0, 80)
148
+ .replace(/_+$/g, "");
149
+ return slug.length > 0 ? slug : "root";
150
+ }
151
+
152
+ function collectParameters(
153
+ bindings: readonly ParameterBinding[],
154
+ versioning: ApiVersioningOptions | undefined,
155
+ version: string | undefined,
156
+ routeSchemas: Readonly<Record<string, OpenApiSchema>>,
157
+ ): OpenApiParameter[] {
158
+ const parameters: OpenApiParameter[] = [];
159
+ for (const binding of bindings) {
160
+ switch (binding.source) {
161
+ case "route":
162
+ if (binding.name) {
163
+ parameters.push({
164
+ name: binding.name,
165
+ in: "path",
166
+ required: true,
167
+ schema: routeSchemas[binding.name] ?? schemaForValueType(binding.type),
168
+ });
169
+ }
170
+ break;
171
+ case "query":
172
+ if (binding.name) {
173
+ parameters.push({
174
+ name: binding.name,
175
+ in: "query",
176
+ required: binding.optional !== true && binding.defaultValue === undefined,
177
+ schema: schemaForValueType(binding.type),
178
+ });
179
+ }
180
+ break;
181
+ case "list":
182
+ parameters.push(...listParameters(binding));
183
+ break;
184
+ default:
185
+ break;
186
+ }
187
+ }
188
+ if (version !== undefined && versioning !== undefined && versioning.source !== "url") {
189
+ const name = versioning.source === "query" ? (versioning.parameterName ?? "api-version") : (versioning.headerName ?? "x-api-version");
190
+ parameters.push({
191
+ name,
192
+ in: versioning.source,
193
+ required: versioning.defaultVersion === undefined,
194
+ schema: { type: "string", enum: [version] },
195
+ });
196
+ }
197
+ return parameters;
198
+ }
199
+
200
+ function listParameters(binding: ParameterBinding): OpenApiParameter[] {
201
+ const options = binding.listOptions ?? (binding.model ? optionsFromSchema(binding.model) : {});
202
+ const parameters: OpenApiParameter[] = [
203
+ {
204
+ name: "sort", in: "query", required: false, schema: { type: "string" },
205
+ "x-bazis-sort-fields": [...(options.sort ?? [])],
206
+ },
207
+ { name: "page[number]", in: "query", required: false, schema: { type: "integer", minimum: 1 } },
208
+ {
209
+ name: "page[size]",
210
+ in: "query",
211
+ required: false,
212
+ schema: pageSizeSchema(options.page?.maxSize),
213
+ },
214
+ ];
215
+ if (options.include && options.include.length > 0) {
216
+ parameters.push({ name: "include", in: "query", required: false, schema: { type: "string", enum: options.include } });
217
+ }
218
+ for (const [field, operators] of Object.entries(options.filter ?? {})) {
219
+ for (const operator of operators) {
220
+ parameters.push({
221
+ name: `filter[${field}][${operator}]`,
222
+ in: "query",
223
+ required: false,
224
+ schema: { type: "string" },
225
+ });
226
+ }
227
+ }
228
+ return parameters;
229
+ }
230
+
231
+ function pageSizeSchema(maximum: number | undefined): OpenApiSchema {
232
+ return maximum === undefined ? { type: "integer", minimum: 1 } : { type: "integer", minimum: 1, maximum };
233
+ }
234
+
235
+ function createRequestBody(
236
+ bindings: readonly ParameterBinding[],
237
+ action: ActionMeta,
238
+ generated: GeneratedOpenApiMetadata,
239
+ ): OpenApiSchema | undefined {
240
+ const body = bindings.find((binding) => binding.source === "body");
241
+ if (!body) {
242
+ return undefined;
243
+ }
244
+ const schema = body.model ? schemaForModel(body.model.name, generated) : { type: "object" };
245
+ return {
246
+ required: body.optional !== true,
247
+ content: {
248
+ [action.consumes ?? "application/json"]: {
249
+ schema,
250
+ },
251
+ },
252
+ };
253
+ }
254
+
255
+ function schemaForModel(name: string, generated: GeneratedOpenApiMetadata): OpenApiSchema {
256
+ return generated.schemas[name] !== undefined
257
+ ? { $ref: `#/components/schemas/${name}` }
258
+ : { type: "object", "x-bazis-model": name };
259
+ }
260
+
261
+ function schemaForValueType(type: ParameterBinding["type"]): OpenApiSchema {
262
+ switch (type) {
263
+ case "int":
264
+ return { type: "integer" };
265
+ case "number":
266
+ return { type: "number" };
267
+ case "bool":
268
+ return { type: "boolean" };
269
+ case "string":
270
+ case undefined:
271
+ return { type: "string" };
272
+ }
273
+ }
274
+
275
+ function routeParamSchemas(template: string): Record<string, OpenApiSchema> {
276
+ const schemas: Record<string, OpenApiSchema> = {};
277
+ for (const segment of template.split("/")) {
278
+ const param = /^:([A-Za-z_][A-Za-z0-9_]*)(?:\(([a-z]+)\))?$/.exec(segment);
279
+ if (param) {
280
+ schemas[param[1] as string] = schemaForConstraint(param[2]);
281
+ continue;
282
+ }
283
+ const wildcard = /^\*([A-Za-z_][A-Za-z0-9_]*)?$/.exec(segment);
284
+ if (wildcard) {
285
+ schemas[(wildcard[1] as string | undefined) ?? "rest"] = { type: "string" };
286
+ }
287
+ }
288
+ return schemas;
289
+ }
290
+
291
+ function schemaForConstraint(constraint: string | undefined): OpenApiSchema {
292
+ switch (constraint) {
293
+ case "int":
294
+ return { type: "integer" };
295
+ case "number":
296
+ return { type: "number" };
297
+ case "bool":
298
+ return { type: "boolean" };
299
+ case "uuid":
300
+ return { type: "string", format: "uuid" };
301
+ case "alpha":
302
+ return { type: "string", pattern: "^[A-Za-z]+$" };
303
+ default:
304
+ return { type: "string" };
305
+ }
306
+ }
307
+
308
+ function successStatus(method: string, action: ActionMeta): number {
309
+ if (action.httpCode !== undefined) {
310
+ return action.httpCode;
311
+ }
312
+ return method === "DELETE" ? 204 : 200;
313
+ }
314
+
315
+ function tagName(meta: ControllerMeta, controllerClass: Class<object>): string {
316
+ const firstPrefix = meta.prefix?.split("/").find((part) => part.length > 0);
317
+ return firstPrefix ?? controllerClass.name.replace(/Controller$/, "");
318
+ }
319
+
320
+ function fullOpenApiPath(
321
+ globalPrefix: string | undefined,
322
+ versionSource: "url" | "query" | "header" | undefined,
323
+ meta: ControllerMeta,
324
+ action: ActionMeta,
325
+ template: string,
326
+ ): string {
327
+ const version = action.version ?? meta.version;
328
+ const versionSegment = (versionSource === undefined || versionSource === "url") && version !== undefined ? `v${version}` : undefined;
329
+ const joined = joinPaths(globalPrefix, versionSegment, meta.prefix, template);
330
+ return `/${templateToOpenApiPath(joined)}`;
331
+ }
332
+
333
+ function templateToOpenApiPath(template: string): string {
334
+ if (template === "") {
335
+ return "";
336
+ }
337
+ return template
338
+ .split("/")
339
+ .filter((segment) => segment.length > 0)
340
+ .map((segment) => {
341
+ if (segment.startsWith(":")) {
342
+ const match = /^:([A-Za-z_][A-Za-z0-9_]*)/.exec(segment);
343
+ return match ? `{${match[1]}}` : segment;
344
+ }
345
+ if (segment.startsWith("*")) {
346
+ const name = segment.length > 1 ? segment.slice(1) : "rest";
347
+ return `{${name}}`;
348
+ }
349
+ return segment;
350
+ })
351
+ .join("/");
352
+ }
353
+
354
+ function normalizedMethod(method: string): string {
355
+ return method === "*" ? "ANY" : method;
356
+ }
@@ -0,0 +1,139 @@
1
+ # src/bazis/core/http: HTTP module (in the spirit of ASP.NET Core)
2
+
3
+ Controllers are classes with standard TC39 decorators; routes are compiled into a
4
+ radix tree at startup; each request lives in its own DI scope.
5
+ No external dependencies, no reflection, compatible with `bun build --compile`
6
+ (checked by the shared `bun run build:bin`).
7
+
8
+ The full specification of middleware and `@Middleware`: [SPEC.md](./SPEC.md).
9
+
10
+ ## Quick start
11
+
12
+ First create an application by the [guide](../../../../docs/QUICKSTART.md), then
13
+ the module `bunx bazis g module Echo --empty`. To try it without a database, replace
14
+ the content of the generated `Echo.module.ts` with this code and fill in its `MODULE.md`:
15
+
16
+ ```ts
17
+ import { Module } from "bazis/core/di";
18
+ import { Controller, Get, Post, RequestModel } from "bazis/core/http";
19
+ import { Validator } from "bazis/library/validation";
20
+
21
+ @RequestModel()
22
+ export class EchoRequest {
23
+ @Validator({ required: true, type: "string", minLength: 3, maxLength: 100 })
24
+ text!: string;
25
+ }
26
+
27
+ @Controller("echo")
28
+ export class EchoController {
29
+ @Get(":id(int)")
30
+ getById(id: number) { return { id }; }
31
+
32
+ @Post()
33
+ send(body: EchoRequest) { return { text: body.text }; }
34
+ }
35
+
36
+ @Module({ controllers: [EchoController], exports: [] })
37
+ export class EchoModule {}
38
+ ```
39
+
40
+ `bun run dev` runs codegen before the application. GET `/echo/42` returns
41
+ `{"id":42}`; POST `/echo` with `{"text":"hello"}` returns `{"text":"hello"}`.
42
+ An invalid body gets HTTP 400. If the host sets a prefix, add it to the path.
43
+ Parameter bindings are inferred from the signature before the run; TypeScript is
44
+ not analyzed on each request. For service dependencies a constructor and
45
+ `scoped(IService, Service)` are enough: the same codegen infers the usual `deps`.
46
+
47
+ ## Binding conventions (instead of parameter decorators)
48
+
49
+ **Parameter** decorators (`getUser(@Param("id") id)`) do not exist in the TC39
50
+ standard, and `experimentalDecorators` would break the other framework modules.
51
+ Instead there are ASP.NET-style conventions that codegen infers from the signature:
52
+
53
+ | Method parameter | Binding |
54
+ |---|---|
55
+ | the name matches the route `:name` | the route value (converted by the constraint/type) |
56
+ | a DTO class from the application sources | the request body + `@Validator` validation (errors -> 400) |
57
+ | `HttpContext` / `Request` / `ResponseBuilder` | context / raw request / response builder |
58
+ | a primitive (`string`/`number`/`boolean` or inferred from the default) | a query parameter; `?` and a default -> optional |
59
+
60
+ If no convention can be inferred (for example a union of string literals, no
61
+ annotation or two body classes), `di:generate` fails with
62
+ `BAZIS_HTTP_BINDING_UNRESOLVED`, the method name and the reason. The previous
63
+ generated files are not replaced. Use a supported type; for headers and raw
64
+ bodies take `ctx: HttpContext`, and inject services into the constructor.
65
+ Checking allowed values belongs to the Validator or the service.
66
+
67
+ A `ctx: HttpContext` parameter stays a regular supported input. For older manual
68
+ HTTP assembly without generated metadata there is a runtime fallback with one
69
+ HttpContext; it does not replace codegen for typed actions.
70
+
71
+ ### Nested request DTOs
72
+
73
+ `di:generate` also reads the field types of a request model and registers the shape
74
+ for recursive hydration without `reflect-metadata`. So the usual DX works for
75
+ objects and arrays too:
76
+
77
+ ```ts
78
+ export class AddressRequest {
79
+ @Validator({ required: true })
80
+ city!: string;
81
+ }
82
+
83
+ export class CreateUserRequest {
84
+ @Validator({ required: true, nested: true })
85
+ address!: AddressRequest;
86
+
87
+ @Validator({ nested: true })
88
+ previousAddresses!: AddressRequest[];
89
+ }
90
+ ```
91
+
92
+ Both classes must be named top-level exports. The binder creates real instances
93
+ of nested DTOs, removes unknown and prototype-polluting fields at every level,
94
+ then runs validation with paths like `address.city` and
95
+ `previousAddresses[0].city`. An ambiguous type with `nested: true` (for example a
96
+ union of two classes) stops codegen; with missing or stale generated metadata the
97
+ standard validator rejects a plain object fail-closed.
98
+
99
+ A request body field declared exactly as `string`, `number` or `boolean`
100
+ (also `| null`, optional or an array of such values) is checked against the
101
+ JSON type without `@Validator`: `{"done":"yes"}` for `done?: boolean` gives 400
102
+ with the code `type`. Codegen takes the type from the sources; literal unions, enums,
103
+ `Date` and mixed unions are not checked; they need `@Validator`.
104
+ Required-ness is still set with `required: true`. The check applies only at the
105
+ HTTP boundary: gRPC and Agent use the same binder without it.
106
+
107
+ Open JSON fields (`Record<string, unknown>`, `{}`, `unknown[]`) keep regular user
108
+ keys, but the binder clones them recursively and removes `__proto__`,
109
+ `constructor`, `prototype` at any depth. Cycles, nesting deeper than 64 containers
110
+ and overly complex graphs are rejected with 400 before reaching the action.
111
+
112
+ ## Folder map
113
+
114
+ | Folder/file | Purpose |
115
+ |---|---|
116
+ | `Decorators/` | `@Controller`, `@Get`/`@Post`/... (+ inline options `{ code, produces, consumes, version, middleware }`), `@HttpCode`, `@Produces`, `@Consumes`, `@Middleware`, `@ApiVersion`, `@Catch`, `@ActionFilter`; metadata stored through `Symbol.metadata` |
117
+ | `Routing/` | template parser (`:id(int)`, `:u(uuid)`, `*rest`), a radix tree with backtracking, pipeline assembly at startup |
118
+ | `Binding/` | binding descriptors, type conversion (400 on error), model binding with prototype pollution protection and `@Validator` validation |
119
+ | `Results/` | `Ok`, `Created`, `NotFound`, `Redirect`, `File` (through `Bun.file`) and result normalization with an automatic Content-Type |
120
+ | `Middleware/` | the pipeline, `cors` (+ preflight), `errorHandler`, `rateLimit`; the access log is `@/logging/http` |
121
+ | `Versioning/` | reads the API version from a URL segment, a query parameter or a header |
122
+ | `HttpContext/` | the request context (params, DI scope, body cache) and `ResponseBuilder` |
123
+ | `Errors/` | `HttpError` and subclasses (4xx/5xx), `ModelValidationError`, `HttpSetupError` |
124
+ | `HttpServer.ts` | hosted service: `Bun.serve`, a scope per request, 404/405/preflight without the pipeline |
125
+ | `httpModule.ts` | the `BazisModule` factory: scoped controllers + the server |
126
+
127
+ ## Guarantees
128
+
129
+ - **Performance**: all metadata is processed at startup; per request there is a
130
+ radix lookup O(segments), a compiled pipeline and a DI scope; the body is parsed
131
+ once (cached in the context).
132
+ - **Resilience**: a global error boundary is always installed
133
+ (`HttpError` -> status, anything else -> 500 without details in production);
134
+ `@Catch` on a controller for domain errors; broken JSON/conversions -> 400, not 500.
135
+ - **Security**: prototype pollution is filtered in model binding and in route
136
+ parameter names; `..`/`%zz` in the path -> 400; CORS with preflight; auth hooks
137
+ in as regular middleware (`@Middleware` or global); `rateLimit` is one line.
138
+ - **Configuration errors** (a duplicate route, an unknown constraint, a class
139
+ without `@Controller`) are `HttpSetupError` at startup, not at runtime.
@@ -0,0 +1,19 @@
1
+ /**
2
+ * An action result: a recipe for building the final `Response`.
3
+ * Returned by the fluent helpers (`Ok`, `Created`, `NotFound`, ...).
4
+ */
5
+ export class HttpResult {
6
+ constructor(
7
+ readonly status: number,
8
+ /** Body value: object/array -> JSON, string -> text, Blob/bytes -> as-is, undefined -> empty. */
9
+ readonly body?: unknown,
10
+ readonly headers?: readonly [string, string][],
11
+ /** Explicit Content-Type (overrides automatic negotiation). */
12
+ readonly contentType?: string,
13
+ ) {}
14
+
15
+ /** Returns a copy with an extra header. */
16
+ withHeader(name: string, value: string): HttpResult {
17
+ return new HttpResult(this.status, this.body, [...(this.headers ?? []), [name, value]], this.contentType);
18
+ }
19
+ }