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,981 @@
1
+ # HTTP middleware and `@Middleware`: specification
2
+
3
+ A per-request middleware pipeline in the style of ASP.NET Core / Koa: `(ctx, next)`
4
+ functions compiled **once per route** when the server starts. The `@Middleware`
5
+ decorator is the declarative way to attach middleware to a controller or an action.
6
+
7
+ Quick navigation:
8
+ - [1. What it is and why](#1-what-it-is-and-why)
9
+ - [2. Pipeline architecture](#2-pipeline-architecture)
10
+ - [3. Quick start](#3-quick-start)
11
+ - [4. `@Middleware` reference](#4-middleware-reference)
12
+ - [5. The `HttpMiddleware` contract](#5-the-httpmiddleware-contract)
13
+ - [6. Ways to connect middleware](#6-ways-to-connect-middleware)
14
+ - [7. Built-in middleware](#7-built-in-middleware)
15
+ - [8. `HttpContext` in middleware](#8-httpcontext-in-middleware)
16
+ - [9. Scenarios and examples](#9-scenarios-and-examples)
17
+ - [10. Execution order and details](#10-execution-order-and-details)
18
+ - [11. Authorization and output cache](#11-authorization-and-output-cache)
19
+ - [12. Middleware vs ActionFilter vs `@Catch`](#12-middleware-vs-actionfilter-vs-catch)
20
+ - [13. Good and bad practices](#13-good-and-bad-practices)
21
+ - [14. Limits](#14-limits)
22
+ - [15. FAQ](#15-faq)
23
+ - [16. Folder map](#16-folder-map)
24
+
25
+ ---
26
+
27
+ ## 1. What it is and why
28
+
29
+ **Middleware** is a function that runs **before** (and/or **after**) a controller action
30
+ within one HTTP request. Typical tasks:
31
+
32
+ | Task | Example |
33
+ | --- | --- |
34
+ | Authorization | `@Authorize(check)` compiles into a built-in middleware (see §11) |
35
+ | Response cache | `@OutputCache` compiles into a route middleware of the cache module |
36
+ | CORS | `httpModule({ cors: { origin: "..." } })` or `cors({ ... })` |
37
+ | Rate limiting | `rateLimit({ windowMs, max })` |
38
+ | Correlation / tracing | `createCorrelationIdMiddleware()` with the `x-request-id` header |
39
+ | API key check | a middleware before the action, without body binding |
40
+
41
+ **`@Middleware`** is a TC39 decorator that writes one or more middleware functions into
42
+ the metadata of a controller or a method. At startup `RouterBuilder` builds a **ready
43
+ array** from the metadata; the hot path never reads metadata.
44
+
45
+ Why a decorator and not only `httpModule({ middleware })`:
46
+
47
+ | Criterion | Global middleware | `@Middleware` |
48
+ | --- | --- | --- |
49
+ | Scope | all routes | one controller / one action |
50
+ | Declarativeness | module configuration | next to `@Get` / `@Post` |
51
+ | Reuse | one function for the whole application | different chains per controller |
52
+ | Build time | an array in `httpModule` | metadata → pipeline at startup |
53
+
54
+ Import:
55
+
56
+ ```ts
57
+ import {
58
+ Middleware,
59
+ type HttpMiddleware,
60
+ rateLimit,
61
+ cors,
62
+ HttpContext,
63
+ UnauthorizedError,
64
+ } from "bazis/core/http";
65
+ ```
66
+
67
+ ---
68
+
69
+ ## 2. Pipeline architecture
70
+
71
+ ### The full chain of one route
72
+
73
+ ```
74
+ HTTP Request
75
+ │
76
+ ▼
77
+ [1] accessLog? ← httpModule({ accessLog })
78
+ [2] cors? ← httpModule({ cors })
79
+ [3] securityHeaders ← on by default; httpModule({ securityHeaders: false }) turns it off
80
+ [4] errorHandler ← always (the global error boundary)
81
+ [5] server middleware ← httpModule({ middleware }) + DI SERVER_MIDDLEWARE, by order
82
+ [6] authorization ← @Authorize / @AllowAnonymous (built-in, compiled per route)
83
+ [7] @Middleware (class) ← decorator on the controller
84
+ [8] @Middleware (method) ← decorator or RouteOptions.middleware
85
+ [9] action boundary ← binding + ActionFilter.before
86
+ [10] route composers ← httpModule({ routeMiddlewareComposer }) + DI ROUTE_MIDDLEWARE_COMPOSER (e.g. output cache)
87
+ [11] terminal ← action + ActionFilter.after; @Catch handles errors of [9]–[11]
88
+ │
89
+ ▼
90
+ HTTP Response
91
+ ```
92
+
93
+ Assembly in `RouterBuilder`:
94
+
95
+ ```ts
96
+ const chain = [
97
+ ...serverChain, // [1]–[5]
98
+ ...authorization, // [6]
99
+ ...meta.middleware, // [7]
100
+ ...action.middleware, // [8]
101
+ pipeline.boundary, // [9]
102
+ ...composed, // [10]
103
+ pipeline.terminal, // [11]
104
+ ];
105
+ ```
106
+
107
+ Authorization comes before controller middleware, so an unauthorized request cannot
108
+ trigger controller-level work. The output cache runs after the action boundary, so a
109
+ cache hit still passes authorization, binding and `ActionFilter.before`, but skips the
110
+ controller and the action.
111
+
112
+ ### What does **not** go through the pipeline
113
+
114
+ | Situation | Behavior |
115
+ | --- | --- |
116
+ | CORS preflight (`OPTIONS` + `Access-Control-Request-Method`) | answered before routing |
117
+ | 404 Not Found | JSON without the pipeline |
118
+ | 405 Method Not Allowed | JSON without the pipeline |
119
+ | Malformed path (`..`, `%zz`) | 400 without the pipeline |
120
+
121
+ ### Lifetime and DI
122
+
123
+ Each request creates a **new DI scope** (`ctx.services`). Middleware and the action share
124
+ one scope for the request; the scope is disposed after the response.
125
+
126
+ ---
127
+
128
+ ## 3. Quick start
129
+
130
+ ### Middleware on a controller
131
+
132
+ ```ts
133
+ import { Controller, Get, Middleware, type HttpMiddleware } from "bazis/core/http";
134
+
135
+ const requestId: HttpMiddleware = async (ctx, next) => {
136
+ const id = crypto.randomUUID();
137
+ ctx.state.set("requestId", id);
138
+ await next();
139
+ ctx.response?.headers.set("x-request-id", id);
140
+ };
141
+
142
+ @Controller("users")
143
+ @Middleware(requestId)
144
+ class UsersController {
145
+ @Get()
146
+ list() {
147
+ return [{ id: 1 }];
148
+ }
149
+ }
150
+ ```
151
+
152
+ ### Middleware on one action
153
+
154
+ ```ts
155
+ @Controller("webhooks")
156
+ class WebhooksController {
157
+ @Post("stripe")
158
+ @Middleware(verifyStripeSignature)
159
+ handleStripe() {
160
+ return { ok: true };
161
+ }
162
+ }
163
+ ```
164
+
165
+ ### Globally through `httpModule`
166
+
167
+ ```ts
168
+ import { createCorrelationIdMiddleware, httpModule, rateLimit } from "bazis/core/http";
169
+
170
+ httpModule({
171
+ imports: [FeatureModule],
172
+ accessLog: true,
173
+ middleware: [
174
+ createCorrelationIdMiddleware(),
175
+ rateLimit({ windowMs: 60_000, max: 600 }),
176
+ ],
177
+ });
178
+ ```
179
+
180
+ ---
181
+
182
+ ## 4. `@Middleware` reference
183
+
184
+ ### Signature
185
+
186
+ ```ts
187
+ function Middleware(...middleware: HttpMiddleware[]): ClassOrMethodDecorator;
188
+ ```
189
+
190
+ | Parameter | Type | Required | Description |
191
+ | --- | --- | --- | --- |
192
+ | `...middleware` | `HttpMiddleware[]` | yes (≥1) | One or more functions in execution order |
193
+
194
+ **`@Middleware` has no options object**, only a variadic list of functions.
195
+ Settings go through the factory closure (`rateLimit({ max: 100 })`).
196
+
197
+ ### Where it can be used
198
+
199
+ | Place | Scope | Metadata |
200
+ | --- | --- | --- |
201
+ | A controller class | all actions of the controller | `ControllerMeta.middleware` |
202
+ | A method with `@Get`/`@Post`/… | only this action | `ActionMeta.middleware` |
203
+
204
+ ### Accumulation
205
+
206
+ Several decorators **add** middleware to the array (they do not overwrite it):
207
+
208
+ ```ts
209
+ @Controller("api")
210
+ @Middleware(mwA)
211
+ @Middleware(mwB)
212
+ class ApiController {}
213
+ // order on the route: mwA → mwB → …
214
+ ```
215
+
216
+ ### Inheritance (copy-on-write)
217
+
218
+ Controller metadata is inherited from the base class through TC39 `Symbol.metadata`.
219
+ The first write in a subclass **clones** it, so the base class is not mutated.
220
+
221
+ ```ts
222
+ @Controller("base")
223
+ @Middleware(sharedMiddleware)
224
+ class BaseController {}
225
+
226
+ @Controller("derived")
227
+ class DerivedController extends BaseController {}
228
+ // DerivedController inherits sharedMiddleware
229
+ ```
230
+
231
+ ### The equivalent through inline route options
232
+
233
+ `RouteOptions.middleware` on `@Get`/`@Post` writes into the same `ActionMeta.middleware`:
234
+
235
+ ```ts
236
+ @Get("export", { middleware: [exportOnlyMiddleware] })
237
+ export() { ... }
238
+
239
+ // equivalent:
240
+ @Get("export")
241
+ @Middleware(exportOnlyMiddleware)
242
+ export() { ... }
243
+ ```
244
+
245
+ With several route decorators on one method the `middleware` field **accumulates**
246
+ (like push), while scalar fields (`code`, `produces`) are overwritten.
247
+
248
+ ---
249
+
250
+ ## 5. The `HttpMiddleware` contract
251
+
252
+ ```ts
253
+ type HttpMiddleware = (
254
+ ctx: HttpContext,
255
+ next: () => Promise<void>,
256
+ ) => void | Promise<void>;
257
+ ```
258
+
259
+ ### Rules
260
+
261
+ | Rule | Description |
262
+ | --- | --- |
263
+ | Calling `next()` | passes control to the next link of the chain |
264
+ | No `next()` | **short-circuit**: the pipeline stops; set `ctx.response` |
265
+ | A second `next()` | **an error**: `next() called multiple times` |
266
+ | An exception | caught by `errorHandler` (middleware runs inside it) |
267
+ | Sync / async | both are allowed |
268
+
269
+ ### Short-circuit (a response without the action)
270
+
271
+ ```ts
272
+ const maintenanceMode: HttpMiddleware = async (ctx, next) => {
273
+ if (process.env.MAINTENANCE === "1") {
274
+ ctx.response = new Response(JSON.stringify({ error: "Maintenance" }), {
275
+ status: 503,
276
+ headers: { "content-type": "application/json" },
277
+ });
278
+ return; // next() is not called
279
+ }
280
+ await next();
281
+ };
282
+ ```
283
+
284
+ ### "Around" middleware (before and after the action)
285
+
286
+ ```ts
287
+ const timing: HttpMiddleware = async (ctx, next) => {
288
+ const started = performance.now();
289
+ await next();
290
+ const ms = (performance.now() - started).toFixed(1);
291
+ ctx.response?.headers.set("x-duration-ms", ms);
292
+ };
293
+ ```
294
+
295
+ ### Middleware with DI
296
+
297
+ ```ts
298
+ import { IAuditLog } from "./tokens";
299
+
300
+ const audit: HttpMiddleware = async (ctx, next) => {
301
+ await next();
302
+ const log = ctx.services.resolve(IAuditLog);
303
+ await log.write({ method: ctx.method, path: ctx.path, status: ctx.response?.status });
304
+ };
305
+ ```
306
+
307
+ > Middleware is a **function**, not a DI class. Dependencies are resolved from
308
+ > `ctx.services` inside the function. For reusable guard-like classes see
309
+ > [13. Good and bad practices](#13-good-and-bad-practices).
310
+
311
+ ---
312
+
313
+ ## 6. Ways to connect middleware
314
+
315
+ | # | Way | When | Place in the pipeline |
316
+ | --- | --- | --- | --- |
317
+ | 1 | `httpModule({ accessLog, cors, securityHeaders })` | built-in cross-cutting concerns | [1]–[3] |
318
+ | 2 | `httpModule({ middleware })` | globally for the whole API | [5] |
319
+ | 3 | DI `SERVER_MIDDLEWARE` | a module wires its own global middleware | [5] |
320
+ | 4 | `@Authorize` / `@AllowAnonymous` | authorization per controller/action | [6] |
321
+ | 5 | `@Middleware` on a class | all actions of the controller | [7] |
322
+ | 6 | `@Middleware` on a method, `RouteOptions.middleware` | one action | [8] |
323
+ | 7 | `routeMiddlewareComposer`, DI `ROUTE_MIDDLEWARE_COMPOSER` | build-time per route (output cache) | [10] |
324
+
325
+ ### `HttpModuleOptions.middleware`
326
+
327
+ ```ts
328
+ interface HttpModuleOptions {
329
+ /** Global middleware after errorHandler, before route middleware. */
330
+ readonly middleware?: readonly HttpMiddleware[];
331
+ }
332
+ ```
333
+
334
+ | Field | Type | Default | Description |
335
+ | --- | --- | --- | --- |
336
+ | `middleware` | `readonly HttpMiddleware[]` | `[]` | Global application middleware (order 0) |
337
+
338
+ Typical content: correlation id, metrics, custom headers.
339
+
340
+ ### DI `SERVER_MIDDLEWARE`
341
+
342
+ A module can contribute global middleware without threading it through
343
+ `httpModule`. Registrations are collected with `resolveAll` and sorted by `order`
344
+ (lower runs further out; explicit `httpModule({ middleware })` has order 0):
345
+
346
+ ```ts
347
+ import { singletonValue } from "bazis/core/di";
348
+ import { SERVER_MIDDLEWARE } from "bazis/core/http";
349
+
350
+ @Module({
351
+ providers: [singletonValue(SERVER_MIDDLEWARE, { order: -10, middleware: httpMetrics })],
352
+ })
353
+ class MetricsModule {}
354
+ ```
355
+
356
+ ### `RouteMiddlewareComposer`
357
+
358
+ ```ts
359
+ type RouteMiddlewareComposer = (
360
+ controllerClass: Class<object>,
361
+ methodName: string | symbol,
362
+ httpMeta: ControllerMeta,
363
+ action: ActionMeta,
364
+ ) => readonly HttpMiddleware[];
365
+ ```
366
+
367
+ | Field | Type | Description |
368
+ | --- | --- | --- |
369
+ | return | `readonly HttpMiddleware[]` | Middleware for a **specific** action |
370
+
371
+ It is called **once** per route when `HttpServer` starts. Modules usually self-wire
372
+ through the `ROUTE_MIDDLEWARE_COMPOSER` DI token (the cache module does this for
373
+ `@OutputCache`). Several explicit composers can be combined:
374
+
375
+ ```ts
376
+ import { composeRouteMiddlewareComposers } from "bazis/core/http";
377
+
378
+ routeMiddlewareComposer: composeRouteMiddlewareComposers(auditComposer, metricsComposer),
379
+ ```
380
+
381
+ ### `RouteOptions.middleware`
382
+
383
+ ```ts
384
+ interface RouteOptions {
385
+ readonly middleware?: readonly HttpMiddleware[];
386
+ // also: code, produces, consumes, version, maxBodyBytes
387
+ }
388
+ ```
389
+
390
+ | Field | Type | Description |
391
+ | --- | --- | --- |
392
+ | `middleware` | `readonly HttpMiddleware[]` | Middleware only for actions with this route decorator |
393
+
394
+ ---
395
+
396
+ ## 7. Built-in middleware
397
+
398
+ Exported from `bazis/core/http`. They are connected through `@Middleware(...)`,
399
+ `httpModule({ middleware })` or the built-in module options.
400
+
401
+ ### `errorHandler(options?)`
402
+
403
+ **Always** in the server chain (position [4]). Configure it through
404
+ `httpModule({ errorHandler })`; do not attach it to a route by hand.
405
+
406
+ | `ErrorHandlerOptions` field | Type | Default | Description |
407
+ | --- | --- | --- | --- |
408
+ | `exposeDetails` | `boolean` | `httpModule({ exposeErrorDetails })` / environment | message/stack in 500 responses; never enable in production |
409
+ | `onUnexpectedError` | `(ctx, error) => void` | DI `HTTP_ERROR_HOOK` hooks | called for non-`HttpError` failures |
410
+ | `logError` | `(error) => void` | `console.error` | fallback when no hook handles the error |
411
+
412
+ `HttpError` → JSON with its status; anything else → 500.
413
+
414
+ ### `accessLog(options?)`
415
+
416
+ Enabled with `httpModule({ accessLog: true })` or `httpModule({ accessLog: { ... } })`
417
+ at position [1]. With a `LOGGER` in DI it writes structured entries, otherwise one
418
+ line per request: `[http] GET /api/users 200 12.3ms <request-id>`.
419
+
420
+ | `AccessLogOptions` field | Type | Default | Description |
421
+ | --- | --- | --- | --- |
422
+ | `log` | `(entry: AccessLogEntry) => void` | — | Sink for entries (highest precedence) |
423
+ | `logger` | `Logger` | the `LOGGER` from DI | Structured sink: `logger.info` per request |
424
+ | `skip` | `(ctx) => boolean` | — | Return `true` to skip a request (e.g. noisy probes) |
425
+
426
+ ### `createCorrelationIdMiddleware(options?)`
427
+
428
+ Reads `x-request-id` or generates a UUID, stores it in `ctx.state`, echoes it on the
429
+ response and binds it to async local storage for application logs. The keys
430
+ `REQUEST_ID_HEADER` and `REQUEST_ID_STATE_KEY` are exported from `bazis/core/kernel`.
431
+
432
+ ### `cors(options?)`
433
+
434
+ Globally: `httpModule({ cors: { origin: "..." } })` handles **both** preflight **and**
435
+ response headers.
436
+
437
+ Per route: `@Middleware(cors({ origin: "https://admin.example.com" }))` adds only the
438
+ response headers (preflight is still handled globally if `cors` is set in `httpModule`).
439
+
440
+ | `CorsOptions` field | Type | Default | Description |
441
+ | --- | --- | --- | --- |
442
+ | `origin` | `string \| string[] \| (origin) => boolean \| "*"` | `"*"` | allowed origins |
443
+ | `methods` | `readonly string[]` | common verbs | for preflight |
444
+ | `allowedHeaders` | `readonly string[]` | echo the request | for preflight |
445
+ | `exposedHeaders` | `readonly string[]` | — | `Access-Control-Expose-Headers` |
446
+ | `credentials` | `boolean` | `false` | cookies; needs an explicit origin allow list or predicate |
447
+ | `maxAgeSeconds` | `number` | — | preflight cache |
448
+
449
+ `credentials: true` cannot be combined with an omitted origin, `"*"` or `["*"]`: the
450
+ server fails at startup so it never opens credentialed allow-any-origin.
451
+
452
+ ### `rateLimit(options)`
453
+
454
+ | `RateLimitOptions` field | Type | Default | Description |
455
+ | --- | --- | --- | --- |
456
+ | `windowMs` | `number` | — | window size (ms) |
457
+ | `max` | `number` | — | max requests per key per window |
458
+ | `keyOf` | `(ctx) => string` | the direct peer IP, else one shared bucket | the bucket key |
459
+ | `trustProxy` | `boolean` | `false` | trust the first forwarded hop |
460
+ | `proxyHeader` | `string` | `x-forwarded-for` | the forwarded address header, only with `trustProxy` |
461
+ | `maxBuckets` | `number` | `10000` | hard cap of in-process buckets; new keys get 429 when full |
462
+
463
+ Exceeding the limit → `TooManyRequestsError` (429 + `Retry-After`).
464
+
465
+ > In-memory, per process. For a cluster write your own middleware on shared storage,
466
+ > or key by user id after authorization.
467
+
468
+ ---
469
+
470
+ ## 8. `HttpContext` in middleware
471
+
472
+ | API | Description |
473
+ | --- | --- |
474
+ | `ctx.request` | the native Bun `Request` |
475
+ | `ctx.url` | the parsed URL (query: `ctx.url.searchParams`) |
476
+ | `ctx.params` | route params after conversion (`:id(int)` → `number`) |
477
+ | `ctx.method`, `ctx.path` | shortcuts |
478
+ | `ctx.header(name)` | a header (case-insensitive) |
479
+ | `ctx.query(name)` | a query parameter |
480
+ | `ctx.services` | the request-scoped DI (`resolve`, `tryResolve`) |
481
+ | `ctx.state` | `Map<string, unknown>`: data shared between middleware |
482
+ | `ctx.response` | the final `Response` (read/write) |
483
+ | `ctx.res` | the `ResponseBuilder` for status and headers of a plain result |
484
+ | `ctx.json()` | the JSON body (cached per request) |
485
+ | `ctx.text()`, `ctx.formData()` | alternative bodies |
486
+ | `ctx.apiVersion` | the API version when versioning is on |
487
+ | `ctx.clientIp` | the direct peer IP, when available |
488
+
489
+ ### Passing data between middleware
490
+
491
+ ```ts
492
+ // middleware A
493
+ ctx.state.set("tenantId", tenantId);
494
+
495
+ // middleware B or the action
496
+ const tenantId = ctx.state.get("tenantId");
497
+ ```
498
+
499
+ An authorization check may store the request subject under `PRINCIPAL_STATE_KEY`
500
+ (a `RequestPrincipal` with `subject` and an optional `claim(type)`); the output cache
501
+ uses it for `varyByUser`/`varyByClaim`.
502
+
503
+ ---
504
+
505
+ ## 9. Scenarios and examples
506
+
507
+ ### 9.1. Request ID on all routes (globally)
508
+
509
+ ```ts
510
+ import { createCorrelationIdMiddleware, httpModule } from "bazis/core/http";
511
+
512
+ httpModule({
513
+ accessLog: true,
514
+ middleware: [createCorrelationIdMiddleware()],
515
+ });
516
+ ```
517
+
518
+ Application logs in the same request get the `requestId` through
519
+ `AsyncLocalStorage` (`runWithRequestContext` in `bazis/core/kernel`).
520
+
521
+ ### 9.2. Rate limit only on public endpoints
522
+
523
+ ```ts
524
+ import { AllowAnonymous, Authorize, Controller, Get, Middleware, rateLimit } from "bazis/core/http";
525
+
526
+ const publicLimiter = rateLimit({ windowMs: 60_000, max: 30 });
527
+
528
+ @Controller("search")
529
+ @AllowAnonymous()
530
+ @Middleware(publicLimiter)
531
+ class SearchController {
532
+ @Get()
533
+ search(q: string) { /* … */ }
534
+ }
535
+
536
+ @Controller("admin")
537
+ @Authorize(isAdmin)
538
+ class AdminController {
539
+ // publicLimiter does not apply
540
+ }
541
+ ```
542
+
543
+ ### 9.3. API key on a webhook (one action)
544
+
545
+ ```ts
546
+ import { UnauthorizedError } from "bazis/core/http";
547
+
548
+ function requireApiKey(expected: string): HttpMiddleware {
549
+ return async (ctx, next) => {
550
+ const key = ctx.header("x-api-key");
551
+ if (key !== expected) {
552
+ throw new UnauthorizedError("Invalid API key");
553
+ }
554
+ await next();
555
+ };
556
+ }
557
+
558
+ @Controller("integrations")
559
+ class IntegrationsController {
560
+ @Post("partner")
561
+ @Middleware(requireApiKey(process.env.PARTNER_KEY!))
562
+ partnerWebhook() {
563
+ return { received: true };
564
+ }
565
+ }
566
+ ```
567
+
568
+ ### 9.4. Content-Type check before binding
569
+
570
+ ```ts
571
+ import { UnsupportedMediaTypeError } from "bazis/core/http";
572
+
573
+ const requireJson: HttpMiddleware = async (ctx, next) => {
574
+ const ct = ctx.header("content-type") ?? "";
575
+ if (!ct.includes("application/json")) {
576
+ throw new UnsupportedMediaTypeError("application/json");
577
+ }
578
+ await next();
579
+ };
580
+
581
+ @Post("bulk")
582
+ @Middleware(requireJson)
583
+ @Consumes("application/json")
584
+ bulkImport(dto: BulkDto) { /* body binding + validation */ }
585
+ ```
586
+
587
+ > `@Consumes` checks Content-Type **at binding** ([9]). A middleware rejects earlier,
588
+ > before the body is parsed, which helps with large uploads.
589
+
590
+ ### 9.5. CORS only for the admin controller
591
+
592
+ ```ts
593
+ @Controller("admin")
594
+ @Middleware(cors({
595
+ origin: ["https://admin.example.com"],
596
+ credentials: true,
597
+ }))
598
+ class AdminController {
599
+ @Get("stats")
600
+ stats() { return { users: 100 }; }
601
+ }
602
+ ```
603
+
604
+ Browser preflight still needs the global `httpModule({ cors })` or separate OPTIONS handling.
605
+
606
+ ### 9.6. Tenant from the subdomain
607
+
608
+ ```ts
609
+ const resolveTenant: HttpMiddleware = async (ctx, next) => {
610
+ const host = ctx.header("host") ?? "";
611
+ const tenant = host.split(".")[0];
612
+ if (!tenant || tenant === "www") {
613
+ throw new BadRequestError("Unknown tenant");
614
+ }
615
+ ctx.state.set("tenant", tenant);
616
+ await next();
617
+ };
618
+
619
+ @Controller("app")
620
+ @Middleware(resolveTenant)
621
+ class AppController {}
622
+ ```
623
+
624
+ ### 9.7. Logging the body (careful: PII)
625
+
626
+ ```ts
627
+ const logBody: HttpMiddleware = async (ctx, next) => {
628
+ if (ctx.method === "POST" || ctx.method === "PUT") {
629
+ const clone = ctx.request.clone();
630
+ const text = await clone.text();
631
+ console.log("[debug-body]", ctx.path, text.slice(0, 500));
632
+ }
633
+ await next();
634
+ };
635
+ ```
636
+
637
+ ### 9.8. Several middleware in one decorator
638
+
639
+ ```ts
640
+ @Post("submit")
641
+ @Middleware(verifyCsrf, rateLimit({ windowMs: 60_000, max: 5 }))
642
+ submit(dto: SubmitDto) { /* … */ }
643
+ ```
644
+
645
+ ### 9.9. Inline options + a decorator on one method
646
+
647
+ ```ts
648
+ @Get("report", { middleware: [cacheBustHeaders] })
649
+ @Middleware(requireReportAccess)
650
+ report() { /* … */ }
651
+ ```
652
+
653
+ Both go into `ActionMeta.middleware` [8]. If the order matters, combine them in one
654
+ decorator: `@Middleware(cacheBustHeaders, requireReportAccess)`.
655
+
656
+ ### 9.10. Middleware + `@Authorize` + `@OutputCache`
657
+
658
+ ```ts
659
+ import { Authorize, Controller, Get, Middleware, rateLimit } from "bazis/core/http";
660
+ import { OutputCache } from "bazis/core/cache";
661
+
662
+ @Controller("catalog")
663
+ @Authorize(isSignedIn)
664
+ @Middleware(rateLimit({ windowMs: 60_000, max: 120 }))
665
+ class CatalogController {
666
+ @Get()
667
+ @OutputCache({ seconds: 60, varyByUser: true })
668
+ list() {
669
+ return this.service.list();
670
+ }
671
+ }
672
+ ```
673
+
674
+ The pipeline for `list`:
675
+
676
+ ```
677
+ authorize → rateLimit → binding/ActionFilter.before → outputCache → action
678
+ ```
679
+
680
+ (authorization is built in [6], rate limit is a class `@Middleware` [7], the output
681
+ cache is a route composer [10])
682
+
683
+ ### 9.11. Ownership check (guard-like, without a separate `@Guard`)
684
+
685
+ ```ts
686
+ import { ForbiddenError, PRINCIPAL_STATE_KEY, type RequestPrincipal } from "bazis/core/http";
687
+
688
+ function postOwnerGuard(): HttpMiddleware {
689
+ return async (ctx, next) => {
690
+ const store = ctx.services.resolve(IPostStore);
691
+ const id = ctx.params.id as number;
692
+ const principal = ctx.state.get(PRINCIPAL_STATE_KEY) as RequestPrincipal | undefined;
693
+ const post = await store.byId(id);
694
+ if (!post || post.authorId !== principal?.subject) {
695
+ throw new ForbiddenError("Not your post");
696
+ }
697
+ await next();
698
+ };
699
+ }
700
+
701
+ @Controller("posts")
702
+ @Authorize(isSignedIn)
703
+ class PostsController {
704
+ @Patch(":id(int)")
705
+ @Middleware(postOwnerGuard())
706
+ update(id: number, dto: UpdatePostDto) { /* … */ }
707
+ }
708
+ ```
709
+
710
+ For "who may call this at all" prefer `@Authorize` checks; keep middleware for
711
+ per-resource rules like ownership.
712
+
713
+ ### 9.12. Metrics / Prometheus
714
+
715
+ ```ts
716
+ const httpMetrics: HttpMiddleware = async (ctx, next) => {
717
+ const end = metrics.startTimer({ method: ctx.method });
718
+ try {
719
+ await next();
720
+ } finally {
721
+ end({ path: ctx.path, status: ctx.response?.status ?? 0 });
722
+ }
723
+ };
724
+
725
+ httpModule({ middleware: [httpMetrics] });
726
+ ```
727
+
728
+ ---
729
+
730
+ ## 10. Execution order and details
731
+
732
+ ### "Inward" and "outward"
733
+
734
+ Middleware with `await next()` runs the code **before** `next` on the way in and
735
+ **after** `next` on the way out (like an onion):
736
+
737
+ ```
738
+ global BEFORE → controller BEFORE → action BEFORE
739
+ → action
740
+ action AFTER ← controller AFTER ← global AFTER
741
+ ```
742
+
743
+ The e2e test records the header order when appending **after** `next()`:
744
+
745
+ ```
746
+ GET /api/users/1 → x-trace: controller, global
747
+ ```
748
+
749
+ `controller` is closer to the action (it appends first), `global` is outside.
750
+
751
+ ### Authorization vs class/method middleware vs composers
752
+
753
+ On one route:
754
+
755
+ ```
756
+ [6] authorization → first among route links
757
+ [7] controller @Middleware
758
+ [8] method @Middleware
759
+ [9] binding + ActionFilter.before
760
+ [10] route composers → output cache
761
+ ```
762
+
763
+ **Authorization runs before controller and method middleware**, so every `@Middleware`
764
+ already sees the principal an `@Authorize` check stored in `ctx.state`. A route with
765
+ `@AllowAnonymous` has no authorization link.
766
+
767
+ ### Short-circuit and CORS
768
+
769
+ The `cors()` middleware adds headers **after** `next()`, when `ctx.response` exists.
770
+ On a short-circuit without `next()` the per-route CORS headers are not added: set the
771
+ headers by hand, or rely on the global `httpModule({ cors })`, which sits outside.
772
+
773
+ ### Errors in middleware
774
+
775
+ | Error source | Who handles it |
776
+ | --- | --- |
777
+ | `HttpError` thrown in middleware | `errorHandler` → JSON + status |
778
+ | `Error` thrown in middleware | `errorHandler` → 500 |
779
+ | thrown in binding, `ActionFilter` or the action | `@Catch` on the controller, then `errorHandler` |
780
+
781
+ `@Catch` does **not** catch errors from middleware [5]–[8]; only from [9]–[11].
782
+
783
+ ### Body parsing
784
+
785
+ `ctx.json()` is cached. The first call (middleware or binding) parses the body; repeated
786
+ calls get the same promise. Broken JSON → `BadRequestError` (400).
787
+
788
+ ### State in a closure
789
+
790
+ ```ts
791
+ const buckets = new Map(); // inside rateLimit: fine for a factory called once
792
+
793
+ @Middleware(createOnce()) // createOnce() runs when the module loads: fine
794
+ ```
795
+
796
+ Do not create a **new** middleware function per request, only at load/startup.
797
+
798
+ ---
799
+
800
+ ## 11. Authorization and output cache
801
+
802
+ ### Authorization (`@Authorize`)
803
+
804
+ `@Authorize(check, ...checks)` on a controller or a method compiles into the built-in
805
+ authorization link [6]. A check is `(ctx) => boolean | Promise<boolean>`: `true` lets the
806
+ request through, `false` gives `403`, and a thrown `HttpError` defines the response
807
+ itself (for example `UnauthorizedError` → `401`). A method-level `@Authorize` or
808
+ `@AllowAnonymous` overrides the controller's.
809
+
810
+ ```ts
811
+ const isSignedIn: AuthorizeCheck = (ctx) => {
812
+ const token = ctx.header("authorization");
813
+ if (!token) throw new UnauthorizedError();
814
+ const principal = ctx.services.resolve(ITokenReader).read(token); // your service
815
+ ctx.state.set(PRINCIPAL_STATE_KEY, principal);
816
+ return true;
817
+ };
818
+ ```
819
+
820
+ The kernel does not know what a check verifies (JWT, a session, an API key): that stays
821
+ inside the function. `@Authorize` does not use `@Middleware`; it has its own metadata layer.
822
+
823
+ ### Output cache (`bazis/core/cache`)
824
+
825
+ `@OutputCache` / `@OutputRedisCache` turn into a route middleware through the cache
826
+ module's `ROUTE_MIDDLEWARE_COMPOSER` registration ([10]). Connecting the cache module
827
+ (`memory()` or `buildCacheModule(...)`) is enough; no manual composer wiring is needed.
828
+
829
+ The output cache runs **after** authorization and the action boundary, so a cached
830
+ response is never served to a caller who fails `@Authorize`. For per-user data use
831
+ `varyByUser`/`varyByClaim` (see the [cache SPEC](../cache/SPEC.md)).
832
+
833
+ ---
834
+
835
+ ## 12. Middleware vs ActionFilter vs `@Catch`
836
+
837
+ | Mechanism | When it runs | Access to action args | Typical use |
838
+ | --- | --- | --- | --- |
839
+ | **Middleware** | before the action boundary | no (only `ctx.params`) | rate limit, CORS, tenant, ownership |
840
+ | **`@ActionFilter`** | `before` after binding, `after` around the result | `before` without args, the result in `after` | wrapping the result, audit after binding |
841
+ | **`@Catch`** | on a throw from binding/filters/the action | error + ctx | domain 404/409 |
842
+
843
+ ```ts
844
+ @ActionFilter({
845
+ before: (ctx) => { /* runs after binding; args are not in the filter API */ },
846
+ after: (ctx, result) => ({ ...result, meta: { version: "1" } }),
847
+ })
848
+ ```
849
+
850
+ To "not let the request reach the endpoint", use **middleware** or `@Authorize`, not a filter.
851
+
852
+ ---
853
+
854
+ ## 13. Good and bad practices
855
+
856
+ ### Good practices
857
+
858
+ | Practice | Why |
859
+ | --- | --- |
860
+ | Access rules through `@Authorize` checks, not custom middleware | one authorization model, compiled per route |
861
+ | Global cross-cutting concerns (metrics, request id) in `httpModule({ middleware })` | once, all routes |
862
+ | Per-route limits through `@Middleware` on a controller/action | an explicit scope |
863
+ | `throw new UnauthorizedError()` / `ForbiddenError` | correct statuses through errorHandler |
864
+ | `ctx.services.resolve()` for DI | scoped services, testability |
865
+ | `ctx.state` for data between middleware | no global variables |
866
+ | The `rateLimit({ ... })`, `cors({ ... })` factories | reusable configurations |
867
+ | Ownership / API key through method-level `@Middleware` | a narrow scope |
868
+
869
+ ### Bad practices
870
+
871
+ | Anti-pattern | Problem | Instead |
872
+ | --- | --- | --- |
873
+ | Re-checking access in every middleware | duplicated, divergent rules | one `@Authorize` check |
874
+ | Heavy business logic in middleware | hard to test | a service or the action |
875
+ | A class `@Middleware` for a check one action needs | extra database round trips | method level |
876
+ | `await ctx.json()` in middleware "just in case" | an extra parse of large bodies | `@Consumes` + binding |
877
+ | Mutable global state without synchronization | races in a cluster | shared external storage |
878
+ | Catching errors in middleware without rethrowing | swallowed bugs | throw or `HttpError` |
879
+ | Attaching `errorHandler` through `@Middleware` | a second boundary, confusion | only the built-in [4] |
880
+ | Caching per-user data without `varyByUser` | data leaks between users | `varyByUser` / `varyByClaim` |
881
+ | Logging secrets / bodies with passwords | a PII leak | redaction, sampling |
882
+
883
+ ### Guard-like classes (if you want the NestJS style)
884
+
885
+ bazis has **no** `@UseGuards(GuardClass)`. The replacement pattern:
886
+
887
+ ```ts
888
+ interface CanActivate {
889
+ canActivate(ctx: HttpContext): boolean | Promise<boolean>;
890
+ }
891
+
892
+ function useGuard(GuardClass: Class<CanActivate>): HttpMiddleware {
893
+ return async (ctx, next) => {
894
+ const guard = ctx.services.resolve(GuardClass);
895
+ if (!(await guard.canActivate(ctx))) {
896
+ throw new ForbiddenError();
897
+ }
898
+ await next();
899
+ };
900
+ }
901
+
902
+ @Patch(":id(int)")
903
+ @Middleware(useGuard(PostOwnerGuard))
904
+ update(id: number) { /* … */ }
905
+ ```
906
+
907
+ The guard class is registered in DI as a regular `scoped`/`singleton` provider.
908
+
909
+ ---
910
+
911
+ ## 14. Limits
912
+
913
+ | Limit | Details |
914
+ | --- | --- |
915
+ | No `@Inject` in middleware | only `ctx.services.resolve(token)` |
916
+ | Middleware is not an async DI factory | the function is captured when the route is built |
917
+ | `rateLimit` is in-memory | not shared between processes |
918
+ | Preflight without the global `cors` | a per-route `cors()` registers no OPTIONS handler |
919
+ | Several `@Controller` on a class | not supported: one controller class |
920
+ | Parameter decorators | codegen infers argument sources from the signature |
921
+ | Middleware on abstract/private methods | route decorators apply only to public instance methods |
922
+
923
+ ---
924
+
925
+ ## 15. FAQ
926
+
927
+ **How does `@Middleware` differ from `httpModule({ middleware })`?**
928
+
929
+ The scope: global vs controller/action. Both use the same `HttpMiddleware` type.
930
+
931
+ **Can middleware return a result without the action?**
932
+
933
+ Yes: set `ctx.response` and do not call `next()`.
934
+
935
+ **Does middleware run for a 404?**
936
+
937
+ No. 404/405 are answered before the pipeline runs.
938
+
939
+ **How many times is the chain created?**
940
+
941
+ Once per registered route when `HttpServer` starts.
942
+
943
+ **Does it work with `bun build --compile`?**
944
+
945
+ Yes. Metadata goes through TC39 decorators, without `reflect-metadata`.
946
+
947
+ **Do I need `@Middleware` for authorization?**
948
+
949
+ No. Use `@Authorize(check)`; it is compiled into the route automatically.
950
+
951
+ **`@Middleware` vs `RouteOptions.middleware`: which one?**
952
+
953
+ They are equivalent for an action. `@Middleware` reads well with several decorators;
954
+ inline is handy when the route options are already one object `{ code: 201, middleware: [...] }`.
955
+
956
+ ---
957
+
958
+ ## 16. Folder map
959
+
960
+ | File | Purpose |
961
+ | --- | --- |
962
+ | `Decorators/attributes.ts` | `@Middleware`, `@ActionFilter`, … |
963
+ | `Decorators/routes.ts` | `RouteOptions.middleware` |
964
+ | `Decorators/metadata.ts` | `ControllerMeta.middleware`, `ActionMeta.middleware` |
965
+ | `Authorization/` | `@Authorize`, `@AllowAnonymous` and the built-in authorization composer |
966
+ | `Middleware/types.ts` | `HttpMiddleware`, `ActionFilterHooks` |
967
+ | `Middleware/pipeline.ts` | `runPipeline` |
968
+ | `Middleware/errorHandler.ts` | the global error boundary |
969
+ | `Middleware/accessLog.ts` | the access log |
970
+ | `Middleware/securityHeaders.ts` | default security headers |
971
+ | `Middleware/cors.ts` | CORS + preflight helpers |
972
+ | `Middleware/rateLimit.ts` | the in-memory rate limiter |
973
+ | `correlation/` | `createCorrelationIdMiddleware` |
974
+ | `middlewareTokens.ts` | `SERVER_MIDDLEWARE`, `ROUTE_MIDDLEWARE_COMPOSER`, `HTTP_ERROR_HOOK` |
975
+ | `Routing/RouterBuilder.ts` | builds the chain at startup |
976
+ | `HttpServer.ts` | the server chain + dispatch |
977
+ | `options.ts` | `HttpModuleOptions`, `RouteMiddlewareComposer` |
978
+ | `composeRouteMiddlewareComposers.ts` | combining explicit composers |
979
+ | `test/http.e2e.test.ts` | middleware order, inline, global |
980
+
981
+ Related specifications: [cache SPEC](../cache/SPEC.md).