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,33 @@
1
+ import ts from "typescript";
2
+
3
+ /** Reject JS truthiness where the caller is constructing an ORM condition. */
4
+ export function analyzeOrmPredicates(checker: ts.TypeChecker, source: ts.SourceFile): readonly string[] {
5
+ const diagnostics: string[] = [];
6
+ const isPredicate = (type: ts.Type): boolean => {
7
+ if (type.isUnionOrIntersection()) return type.types.some(isPredicate);
8
+ const symbol = type.getSymbol();
9
+ return symbol?.name === "Predicate" && (symbol.declarations ?? []).some(declaration =>
10
+ declaration.getSourceFile().fileName.replaceAll("\\", "/").endsWith("/library/orm/Query/conditions.ts"));
11
+ };
12
+ const reject = (node: ts.Node): void => {
13
+ const location = source.getLineAndCharacterOfPosition(node.getStart(source));
14
+ diagnostics.push(`BAZIS_ORM_PREDICATE_LOGIC: ${source.fileName}:${location.line + 1}:${location.character + 1}: `
15
+ + "ORM conditions cannot use JavaScript truthiness. Use .and(), .or(), .not() or an explicit boolean condition.");
16
+ };
17
+ const visit = (node: ts.Node): void => {
18
+ if (ts.isBinaryExpression(node)
19
+ && (node.operatorToken.kind === ts.SyntaxKind.AmpersandAmpersandToken || node.operatorToken.kind === ts.SyntaxKind.BarBarToken)
20
+ && (isPredicate(checker.getTypeAtLocation(node.left)) || isPredicate(checker.getTypeAtLocation(node.right)))) {
21
+ reject(node);
22
+ } else if (ts.isPrefixUnaryExpression(node) && node.operator === ts.SyntaxKind.ExclamationToken
23
+ && isPredicate(checker.getTypeAtLocation(node.operand))) {
24
+ reject(node);
25
+ } else if ((ts.isIfStatement(node) || ts.isConditionalExpression(node) || ts.isWhileStatement(node) || ts.isDoStatement(node))
26
+ && isPredicate(checker.getTypeAtLocation(ts.isConditionalExpression(node) ? node.condition : node.expression))) {
27
+ reject(node);
28
+ }
29
+ ts.forEachChild(node, visit);
30
+ };
31
+ visit(source);
32
+ return diagnostics;
33
+ }
@@ -0,0 +1,326 @@
1
+ import ts from "typescript";
2
+
3
+ export type RequestModelPrimitive = "string" | "number" | "boolean";
4
+
5
+ /** Exactly one of `model` (nested DTO) or `primitive` is set. */
6
+ export interface RequestModelHydrationField {
7
+ readonly property: string;
8
+ readonly model?: ts.ClassDeclaration;
9
+ readonly primitive?: RequestModelPrimitive;
10
+ readonly array: boolean;
11
+ readonly nullable: boolean;
12
+ readonly elementNullable: boolean;
13
+ }
14
+
15
+ export interface RequestModelHydration {
16
+ readonly declarations: readonly ts.ClassDeclaration[];
17
+ readonly fields: ReadonlyMap<ts.ClassDeclaration, readonly RequestModelHydrationField[]>;
18
+ readonly errors: readonly string[];
19
+ }
20
+
21
+ export interface RequestModelHydrationAnalyzerOptions {
22
+ readonly checker: ts.TypeChecker;
23
+ /** Every class whose transitive request shape should be inspected. */
24
+ readonly roots: readonly ts.ClassDeclaration[];
25
+ /** Roots that must be imported even when they have no nested fields. */
26
+ readonly requiredRoots?: readonly ts.ClassDeclaration[];
27
+ readonly isProjectDeclaration: (declaration: ts.ClassDeclaration) => boolean;
28
+ readonly isExcludedDeclaration: (declaration: ts.ClassDeclaration) => boolean;
29
+ readonly isNamedExportedTopLevelClass: (declaration: ts.ClassDeclaration) => boolean;
30
+ readonly sourcePathForDeclaration: (declaration: ts.ClassDeclaration) => string;
31
+ readonly sourceLocation: (node: ts.Node) => string;
32
+ }
33
+
34
+ interface UnwrappedModelType {
35
+ readonly model?: ts.ClassDeclaration;
36
+ readonly array: boolean;
37
+ readonly nullable: boolean;
38
+ readonly elementNullable: boolean;
39
+ readonly ambiguous: boolean;
40
+ }
41
+
42
+ /**
43
+ * Pure TypeScript-source analyzer for generated nested request DTO hydration.
44
+ * It has no filesystem/global-generator state and is therefore directly
45
+ * regression-testable without introducing app fixtures.
46
+ */
47
+ export function analyzeRequestModelHydration(
48
+ options: RequestModelHydrationAnalyzerOptions,
49
+ ): RequestModelHydration {
50
+ const { checker } = options;
51
+ const queue = [...new Set(options.roots)];
52
+ const visited = new Set<ts.ClassDeclaration>();
53
+ const requiredDeclarations = new Set<ts.ClassDeclaration>(options.requiredRoots ?? []);
54
+ const fields = new Map<ts.ClassDeclaration, RequestModelHydrationField[]>();
55
+ const errors: string[] = [];
56
+
57
+ for (let index = 0; index < queue.length; index += 1) {
58
+ const owner = queue[index] as ts.ClassDeclaration;
59
+ if (visited.has(owner)) {
60
+ continue;
61
+ }
62
+ visited.add(owner);
63
+
64
+ const ownerFields: RequestModelHydrationField[] = [];
65
+ for (const member of owner.members) {
66
+ if (
67
+ !ts.isPropertyDeclaration(member) ||
68
+ !ts.isIdentifier(member.name) ||
69
+ hasModifier(member, ts.SyntaxKind.StaticKeyword) ||
70
+ hasModifier(member, ts.SyntaxKind.PrivateKeyword)
71
+ ) {
72
+ continue;
73
+ }
74
+ const nested = modelTypeForProperty(checker, member);
75
+ const explicitNested = hasExplicitNestedValidator(member);
76
+ const primitive = nested.model === undefined && !explicitNested ? primitiveTypeForProperty(checker, member) : undefined;
77
+ if (primitive !== undefined) {
78
+ // Primitive checks are an addition: a DTO that cannot be imported by
79
+ // generated code keeps its previous (unchecked) binding instead of failing.
80
+ if (options.isNamedExportedTopLevelClass(owner)) {
81
+ ownerFields.push({ property: member.name.text, ...primitive });
82
+ requiredDeclarations.add(owner);
83
+ }
84
+ continue;
85
+ }
86
+ if (nested.model === undefined) {
87
+ if (explicitNested && nested.ambiguous) {
88
+ errors.push(
89
+ `${options.sourceLocation(member)}: @Validator({ nested: true }) field "${member.name.text}" ` +
90
+ `must have one concrete class type or class-array element type so HTTP binding can hydrate it safely.`,
91
+ );
92
+ }
93
+ continue;
94
+ }
95
+ if (!options.isProjectDeclaration(nested.model)) {
96
+ if (explicitNested) {
97
+ errors.push(
98
+ `${options.sourceLocation(member)}: nested request model "${nested.model.name?.text ?? "<anonymous>"}" ` +
99
+ `is not declared in project source and cannot be hydrated by Bazis codegen.`,
100
+ );
101
+ }
102
+ continue;
103
+ }
104
+ if (options.isExcludedDeclaration(nested.model)) {
105
+ errors.push(
106
+ `${options.sourceLocation(member)}: nested request model "${nested.model.name?.text ?? "<anonymous>"}" ` +
107
+ `belongs to an excluded source layer and cannot be imported into generated runtime metadata.`,
108
+ );
109
+ continue;
110
+ }
111
+ ownerFields.push({
112
+ property: member.name.text,
113
+ model: nested.model,
114
+ array: nested.array,
115
+ nullable: nested.nullable,
116
+ elementNullable: nested.elementNullable,
117
+ });
118
+ requiredDeclarations.add(owner);
119
+ requiredDeclarations.add(nested.model);
120
+ queue.push(nested.model);
121
+ }
122
+ if (ownerFields.length > 0) {
123
+ ownerFields.sort((left, right) => left.property.localeCompare(right.property));
124
+ fields.set(owner, ownerFields);
125
+ }
126
+
127
+ for (const clause of owner.heritageClauses ?? []) {
128
+ if (clause.token !== ts.SyntaxKind.ExtendsKeyword) {
129
+ continue;
130
+ }
131
+ for (const baseType of clause.types) {
132
+ const base = classDeclarationForExpression(checker, baseType.expression);
133
+ if (base !== undefined && !options.isExcludedDeclaration(base)) {
134
+ queue.push(base);
135
+ }
136
+ }
137
+ }
138
+ }
139
+
140
+ for (const declaration of requiredDeclarations) {
141
+ if (!options.isNamedExportedTopLevelClass(declaration)) {
142
+ errors.push(
143
+ `${options.sourceLocation(declaration)}: request model "${declaration.name?.text ?? "<anonymous>"}" must be a named ` +
144
+ `top-level export so generated nested DTO hydration metadata can import it.`,
145
+ );
146
+ }
147
+ }
148
+
149
+ const declarations = [...requiredDeclarations].sort((left, right) => {
150
+ const byFile = options.sourcePathForDeclaration(left).localeCompare(options.sourcePathForDeclaration(right));
151
+ return byFile !== 0 ? byFile : (left.name?.text ?? "").localeCompare(right.name?.text ?? "");
152
+ });
153
+ return { declarations, fields, errors };
154
+ }
155
+
156
+ /** Renders only the generated `registerRequestModelShape(...)` calls. */
157
+ export function renderRequestModelShapeRegistrations(
158
+ hydration: Pick<RequestModelHydration, "declarations" | "fields">,
159
+ aliasFor: (declaration: ts.ClassDeclaration) => string | undefined,
160
+ ): string[] {
161
+ const lines: string[] = [];
162
+ for (const owner of hydration.declarations) {
163
+ const ownerFields = hydration.fields.get(owner);
164
+ const ownerAlias = aliasFor(owner);
165
+ if (ownerFields === undefined || ownerFields.length === 0 || ownerAlias === undefined) {
166
+ continue;
167
+ }
168
+ lines.push(`registerRequestModelShape(${ownerAlias}, {`);
169
+ for (const field of ownerFields) {
170
+ const modelAlias = field.model === undefined ? undefined : aliasFor(field.model);
171
+ if (field.primitive === undefined && modelAlias === undefined) {
172
+ continue;
173
+ }
174
+ const values: string[] = [field.primitive === undefined ? `model: ${modelAlias}` : `primitive: ${JSON.stringify(field.primitive)}`];
175
+ if (field.array) {
176
+ values.push("array: true");
177
+ }
178
+ if (field.nullable) {
179
+ values.push("nullable: true");
180
+ }
181
+ if (field.elementNullable) {
182
+ values.push("elementNullable: true");
183
+ }
184
+ lines.push(` ${JSON.stringify(field.property)}: { ${values.join(", ")} },`);
185
+ }
186
+ lines.push("});");
187
+ }
188
+ return lines;
189
+ }
190
+
191
+ function modelTypeForProperty(checker: ts.TypeChecker, member: ts.PropertyDeclaration): UnwrappedModelType {
192
+ const outer = unwrapNullableType(checker.getTypeAtLocation(member));
193
+ if (outer.type === undefined) {
194
+ return { array: false, nullable: outer.nullable, elementNullable: false, ambiguous: true };
195
+ }
196
+ if (isArrayModelType(checker, outer.type)) {
197
+ const elementType = checker.getIndexTypeOfType(outer.type, ts.IndexKind.Number);
198
+ if (elementType === undefined) {
199
+ return { array: true, nullable: outer.nullable, elementNullable: false, ambiguous: true };
200
+ }
201
+ const element = unwrapNullableType(elementType);
202
+ const model = element.type === undefined ? undefined : classDeclarationForType(element.type);
203
+ return {
204
+ model,
205
+ array: true,
206
+ nullable: outer.nullable,
207
+ elementNullable: element.nullable,
208
+ ambiguous: element.type === undefined || model === undefined,
209
+ };
210
+ }
211
+ const model = classDeclarationForType(outer.type);
212
+ return {
213
+ model,
214
+ array: false,
215
+ nullable: outer.nullable,
216
+ elementNullable: false,
217
+ ambiguous: model === undefined,
218
+ };
219
+ }
220
+
221
+ /**
222
+ * `string`, `number` or `boolean` exactly (literal unions, enums and other
223
+ * types are left unchecked), optionally `| null`, optional, or as array elements.
224
+ */
225
+ function primitiveTypeForProperty(
226
+ checker: ts.TypeChecker,
227
+ member: ts.PropertyDeclaration,
228
+ ): Pick<RequestModelHydrationField, "primitive" | "array" | "nullable" | "elementNullable"> | undefined {
229
+ const outer = splitNullable(checker.getTypeAtLocation(member));
230
+ const single = outer.types.length === 1 ? outer.types[0] : undefined;
231
+ if (single !== undefined && isArrayModelType(checker, single)) {
232
+ const elementType = checker.getIndexTypeOfType(single, ts.IndexKind.Number);
233
+ if (elementType === undefined || checker.isTupleType(single)) {
234
+ return undefined;
235
+ }
236
+ const element = splitNullable(elementType);
237
+ const primitive = primitiveOf(element.types);
238
+ return primitive === undefined ? undefined : { primitive, array: true, nullable: outer.nullable, elementNullable: element.nullable };
239
+ }
240
+ const primitive = primitiveOf(outer.types);
241
+ return primitive === undefined ? undefined : { primitive, array: false, nullable: outer.nullable, elementNullable: false };
242
+ }
243
+
244
+ function splitNullable(input: ts.Type): { readonly types: readonly ts.Type[]; readonly nullable: boolean } {
245
+ const candidates = input.isUnion() ? input.types : [input];
246
+ const types = candidates.filter((candidate) => (candidate.flags & (ts.TypeFlags.Null | ts.TypeFlags.Undefined | ts.TypeFlags.Void)) === 0);
247
+ return { types, nullable: candidates.some((candidate) => (candidate.flags & ts.TypeFlags.Null) !== 0) };
248
+ }
249
+
250
+ /** `boolean` arrives as the union `true | false`. */
251
+ function primitiveOf(types: readonly ts.Type[]): RequestModelPrimitive | undefined {
252
+ if (types.length === 1 && types[0]!.flags === ts.TypeFlags.String) return "string";
253
+ if (types.length === 1 && types[0]!.flags === ts.TypeFlags.Number) return "number";
254
+ if (types.length === 1 && types[0]!.flags === ts.TypeFlags.Boolean) return "boolean";
255
+ if (types.length === 2 && types.every((type) => (type.flags & ts.TypeFlags.BooleanLiteral) !== 0)) return "boolean";
256
+ return undefined;
257
+ }
258
+
259
+ function unwrapNullableType(input: ts.Type): { readonly type?: ts.Type; readonly nullable: boolean } {
260
+ const candidates = input.isUnion() ? input.types : [input];
261
+ let nullable = false;
262
+ const concrete: ts.Type[] = [];
263
+ for (const candidate of candidates) {
264
+ if ((candidate.flags & ts.TypeFlags.Null) !== 0) {
265
+ nullable = true;
266
+ } else if ((candidate.flags & (ts.TypeFlags.Undefined | ts.TypeFlags.Void)) === 0) {
267
+ concrete.push(candidate);
268
+ }
269
+ }
270
+ return concrete.length === 1 ? { type: concrete[0], nullable } : { nullable };
271
+ }
272
+
273
+ function isArrayModelType(checker: ts.TypeChecker, type: ts.Type): boolean {
274
+ if (checker.isArrayType(type) || checker.isTupleType(type)) {
275
+ return true;
276
+ }
277
+ const symbolName = type.getSymbol()?.getName();
278
+ return symbolName === "ReadonlyArray" || symbolName === "Array";
279
+ }
280
+
281
+ function classDeclarationForType(type: ts.Type): ts.ClassDeclaration | undefined {
282
+ return classDeclarationForSymbol(type.getSymbol() ?? type.aliasSymbol);
283
+ }
284
+
285
+ function classDeclarationForExpression(
286
+ checker: ts.TypeChecker,
287
+ expression: ts.Expression,
288
+ ): ts.ClassDeclaration | undefined {
289
+ let symbol = checker.getSymbolAtLocation(expression);
290
+ if (symbol !== undefined && (symbol.flags & ts.SymbolFlags.Alias) !== 0) {
291
+ symbol = checker.getAliasedSymbol(symbol);
292
+ }
293
+ return classDeclarationForSymbol(symbol);
294
+ }
295
+
296
+ function classDeclarationForSymbol(symbol: ts.Symbol | undefined): ts.ClassDeclaration | undefined {
297
+ return symbol?.declarations?.find(ts.isClassDeclaration);
298
+ }
299
+
300
+ function hasExplicitNestedValidator(member: ts.PropertyDeclaration): boolean {
301
+ for (const decorator of ts.getDecorators(member) ?? []) {
302
+ const expression = decorator.expression;
303
+ if (!ts.isCallExpression(expression) || !ts.isIdentifier(expression.expression) || expression.expression.text !== "Validator") {
304
+ continue;
305
+ }
306
+ const options = expression.arguments[0];
307
+ if (!options || !ts.isObjectLiteralExpression(options)) {
308
+ continue;
309
+ }
310
+ for (const property of options.properties) {
311
+ if (
312
+ ts.isPropertyAssignment(property) &&
313
+ ((ts.isIdentifier(property.name) && property.name.text === "nested") ||
314
+ (ts.isStringLiteralLike(property.name) && property.name.text === "nested")) &&
315
+ property.initializer.kind === ts.SyntaxKind.TrueKeyword
316
+ ) {
317
+ return true;
318
+ }
319
+ }
320
+ }
321
+ return false;
322
+ }
323
+
324
+ function hasModifier(node: ts.HasModifiers, kind: ts.SyntaxKind): boolean {
325
+ return ts.getModifiers(node)?.some((modifier) => modifier.kind === kind) ?? false;
326
+ }
@@ -0,0 +1,297 @@
1
+ # WebSocket Module
2
+
3
+ Status: implemented, single-node by default; optional client-confirmed replay
4
+ and Redis/Valkey adapter. See [MODULE.md](MODULE.md) for the verified scope.
5
+
6
+ WebSocket in bazis shares the HTTP listener and uses native Bun WebSocket. The
7
+ public API is intentionally close to controllers: gateways are classes, message
8
+ handlers are methods, DI creates gateway instances, and the module registers an
9
+ upgrade port for `HttpServer`.
10
+
11
+ ## Minimal Gateway
12
+
13
+ ```ts
14
+ import { SubscribeMessage, WebSocketGateway, type BazisSocket } from "@/core/websocket";
15
+
16
+ @WebSocketGateway({ namespace: "chat" })
17
+ export class ChatGateway {
18
+ @SubscribeMessage("echo")
19
+ echo(_socket: BazisSocket, body: unknown) {
20
+ return { echoed: body };
21
+ }
22
+ }
23
+ ```
24
+
25
+ Register it next to HTTP:
26
+
27
+ ```ts
28
+ import { Module } from "@/core/di";
29
+ import { httpModule } from "@/core/http";
30
+ import { websocketModule } from "@/core/websocket";
31
+
32
+ @Module({
33
+ imports: [
34
+ httpModule({ port: 3000 }),
35
+ websocketModule({ gateways: [ChatGateway] }),
36
+ ],
37
+ })
38
+ export class AppModule {}
39
+ ```
40
+
41
+ The gateway above upgrades on `/ws/chat`.
42
+
43
+ ## Handler Convention
44
+
45
+ `@SubscribeMessage(event)` uses positional convention:
46
+
47
+ ```ts
48
+ handler(socket, body, ack)
49
+ ```
50
+
51
+ Declare only the parameters you need. If the client packet has an `id`, returning
52
+ a value sends an ack. The third argument is an explicit ack callback for deferred
53
+ or error replies.
54
+
55
+ A handler declaring the third argument and returning `undefined` waits for the
56
+ callback within `messageHandlingTimeoutMs`. Other handlers acknowledge their
57
+ return value, including `undefined`. Return and callback share a single reply;
58
+ duplicate or cancelled callbacks are ignored. Without a packet `id`, no reply
59
+ is sent and the dispatcher does not wait for the callback.
60
+
61
+ Parameter decorators such as `@MessageBody` are not part of the current API.
62
+ They can be added later, but the Bun/TC39-compatible path today is positional.
63
+
64
+ ## Current Features
65
+
66
+ - Namespaces and default paths (`/ws`, `/ws/chat`)
67
+ - Rooms via `socket.join(room)` and `socket.to(room).emit(...)`
68
+ - Ack frames via return value or explicit `AckCallback`
69
+ - Reconnect by `sid` with room restoration
70
+ - Missed message replay with transport or client acknowledgement
71
+ - Atomic Redis/Valkey session storage and cross-process live pub/sub
72
+ - Per-message rate limit
73
+ - Optional body validation/transform function
74
+ - Upgrade middleware, origin check and token auth hook
75
+ - Pluggable codec and adapter interfaces
76
+ - Bounded in-process maps for sessions, topics and rate-limit buckets
77
+ - Bounded upgrade, per-message and shutdown-drain operations
78
+
79
+ ## Wire Protocol
80
+
81
+ Client packets are JSON by default:
82
+
83
+ ```ts
84
+ { "v": 1, "type": "event", "event": "echo", "data": "hi", "id": "1" }
85
+ ```
86
+
87
+ Server packets include `connected`, `reconnected`, `event`, `ack`, `error` and
88
+ `pong`.
89
+
90
+ The selected codec applies to all frames, including acknowledgements and room
91
+ broadcasts. With the default JSON codec, browsers receive text frames; the
92
+ binary codec preserves binary framing for automatic, callback and error replies.
93
+
94
+ Replay uses the actual encoded frame size. A fitting prefix is included in
95
+ `reconnected.missed`; the remaining events follow in FIFO order as ordinary
96
+ packets before queued client messages run. Only a prefix accepted by the
97
+ transport is removed from the session queue. A failed send or an individually
98
+ oversized packet closes the connection and retains the unaccepted remainder.
99
+ Transport acceptance does not prove client receipt. This is the compatible
100
+ default, `replayDelivery: "transport"`.
101
+
102
+ ### Client-confirmed replay
103
+
104
+ Opt in with `?replay=client-ack` on each connection, or require it for all clients
105
+ with `websocketModule({ gateways, replayDelivery: "client-ack" })`. The adapter
106
+ must support CAS. A saved client-ack session cannot reconnect in transport mode;
107
+ such an upgrade returns 409. Invalid/duplicate replay query values return 400.
108
+
109
+ In this mode, `connected`/`reconnected` advertise `replayDelivery: "client-ack"`.
110
+ Every queued packet has a stable `deliveryId`; `reconnected.replayCount` counts
111
+ both its `missed` prefix and subsequent standalone replay packets in the current
112
+ bounded batch. The delivery pump continues reading the global mailbox afterward. Process each
113
+ received packet, deduplicate its effect by deliveryId, then confirm received IDs:
114
+
115
+ ```ts
116
+ ws.send(JSON.stringify({
117
+ v: 1,
118
+ type: "replay-ack",
119
+ id: "receipt-1",
120
+ data: { deliveryIds: [receivedPacket.deliveryId] },
121
+ }));
122
+ // After persistence: { v: 1, type: "ack", id: "receipt-1",
123
+ // data: { acknowledged: 1 } }
124
+ ```
125
+
126
+ This example uses the JSON codec; binary clients encode the same packet through
127
+ their selected codec. Batch IDs where possible, for example after receiving the
128
+ advertised replayCount. Split batches to respect the namespace payload bound and
129
+ control-frame rate limit. ACK processing waits for replay/open to finish, so do
130
+ not block reading subsequent replay frames while waiting for the ACK response.
131
+
132
+ The server accepts only UUIDs issued to that physical connection. Partial,
133
+ out-of-order acknowledgement is supported; repeating an accepted ID on the same
134
+ connection acknowledges zero additional packets while it remains in the bounded
135
+ recent-ACK window (maxOutboundQueuePerSession for global deliveries). On a new connection, confirm
136
+ only the replay actually received there. Disconnecting without acknowledgement
137
+ replays the same IDs. The correlation `id` is independent of deliveryId.
138
+
139
+ The queue retains unacknowledged packets and rejects new entries when full,
140
+ instead of evicting old ones. Transport prefix-drain cannot consume it. This
141
+ guarantee applies to admitted queued replay within session TTL. Surviving a
142
+ process crash also requires completed persistence (`flushSession`) and surviving
143
+ storage. Live emits/broadcasts are not automatically durable, and exactly-once
144
+ external effects require application-level deduplication.
145
+
146
+ ### Redis / Valkey
147
+
148
+ Pass an existing native Bun RedisClient from the host infrastructure:
149
+
150
+ ```ts
151
+ const adapter = new RedisWebSocketAdapter(hostRedisClient, {
152
+ keyPrefix: "my-app:ws", // same on participating nodes; distinct per application
153
+ });
154
+ const module = websocketModule({ gateways, adapter, replayDelivery: "client-ack" });
155
+ ```
156
+
157
+ The adapter owns only a duplicate connection for pub/sub. Closing the adapter
158
+ does not close hostRedisClient or erase persisted sessions. An optional host-owned
159
+ deliveryClient separates delivery commands onto another connection; initialization
160
+ verifies both clients see the same logical DB using a temporary nonce. Both share
161
+ the same native-operation admission limit and remain open after adapter.close().
162
+ This option does not establish a throughput guarantee. The adapter uses one Redis
163
+ key per SID, Lua CAS/revision checks, a bounded initial-write protection window,
164
+ and TTL. Session JSON remains opaque to Lua so empty arrays/null are preserved.
165
+ Ordinary SessionManager mutations use CAS too; conflicts fail persistence and
166
+ discard the stale local index instead of overwriting a newer owner.
167
+ Activity-only writes are coalesced within one third of the smaller TTL/lease
168
+ interval. A local touch updates lastSeenAt without extending expiry or lease
169
+ until a persisted renewal; expired leases still reject traffic. Room changes,
170
+ explicit SessionManager.updateContext calls and delivery acknowledgements retain
171
+ their persistence boundaries; arbitrary socket.data mutations are not given a
172
+ new automatic persistence contract.
173
+
174
+ Ordinary emit uses live pub/sub. Reliable room publication uses a separate
175
+ persistent mailbox and global room membership for both connected and offline
176
+ sessions. Session CAS atomically updates membership; mailbox publish/ACK do not
177
+ change the session revision. Polling recovers missed pub/sub notifications.
178
+ Empty READ rows are skipped before local session lookup, avoiding one complete
179
+ expiry sweep per idle mailbox. Nonempty delivery still checks the current owner,
180
+ lease and backpressure after the store read.
181
+
182
+ ### Reliable room publication
183
+
184
+ ```ts
185
+ // Generate these once per logical operation and retain them for retries.
186
+ const options = { messageId: crypto.randomUUID(), expiresAt: Date.now() + 30_000 };
187
+ const receipt = await socket.to("orders").emitReliable("updated", { orderId }, options);
188
+ // receipt = { messageId, recipients, duplicate }
189
+ ```
190
+
191
+ The gateway authorizes room access. Namespace and sender SID come from the
192
+ server. Every recipient must use client-ack. A successful receipt means the
193
+ operation was stored for every recipient selected atomically at publication,
194
+ including offline sessions on other nodes. It does not mean clients processed
195
+ it. Receipt IDs are independent of request correlation IDs.
196
+
197
+ A transport failure or timeout can occur after commit. Retry the same operation
198
+ with exactly the same messageId, expiresAt, room, sender SID and data. The store
199
+ suppresses duplicate publication; a reused ID with different content fails with
200
+ MESSAGE_ID_CONFLICT. JSON property order is immaterial. The acceptance deadline
201
+ must be at most 60 seconds ahead of store time; after expiry, do not retry with
202
+ an extended deadline. Queue retention follows session TTL, not that deadline.
203
+ Clients deduplicate effects by deliveryId and ACK only after successful processing.
204
+
205
+ Queue count/byte, fan-out and operation-history limits reject admission before
206
+ mailbox writes; no unacknowledged packet is evicted. READ/ACK check the physical
207
+ connection owner and live lease. Issued IDs are skipped on subsequent reads;
208
+ reconnect issues any remaining packets again. Per-connection issued/recent ACK
209
+ sets are bounded. Legacy runtime offline overflow now reports
210
+ OFFLINE_QUEUE_CAPACITY instead of hiding truncated delivery behind a successful
211
+ handler ACK. Direct legacy SessionManager enqueue compatibility remains available.
212
+
213
+ Redis strict initialization/readiness requires appendonly=yes,
214
+ appendfsync=always, no-appendfsync-on-rewrite=no, maxmemory-policy=noeviction
215
+ and healthy AOF write status.
216
+ All nodes sharing a prefix must use the same delivery policy. AOF configuration
217
+ is an explicit migration requirement; reliable.requireAof=false disables the
218
+ durability gate and cannot guarantee storage-crash survival. Host credentials
219
+ need CONFIG GET and INFO persistence.
220
+ The application should wire runtime.getHealth() into its readiness endpoint and
221
+ export getStats().delivery or onDiagnostic counters. No application endpoint is
222
+ created by this library change.
223
+
224
+ The adapter bounds native operations and waiting. A timeout does not cancel
225
+ native I/O or free its admission slot; new operations fail STORE_BUSY until the
226
+ old native operation settles. Close owns only the subscriber. The host must use
227
+ bounded connection/retry/offline-queue settings and supervise process restart.
228
+ AOF LOADING is not readiness: keep the application out of traffic until the
229
+ store serves commands, then initialize with bounded retries.
230
+
231
+ Physical evidence and the supported deployment boundary are in the
232
+ [enterprise qualification](https://github.com/asus97178/osnova/blob/33a4513a56abb43a1694e7a6e56373187b928a70/docs/audits/2026-09-14-websocket-enterprise/REPORT.md).
233
+ The atomic boundary is one Redis primary/replication group. Cross-slot Redis
234
+ Cluster, arbitrary automatic replica promotion, WAN and production WSS require
235
+ separate deployment evidence. External exactly-once effects remain application-owned.
236
+
237
+ ## Limits
238
+
239
+ - The default adapter is in-memory and single-node.
240
+ - Cross-process pub/sub can use `RedisWebSocketAdapter` or a custom adapter.
241
+ - Handler argument binding is positional, not decorator-based.
242
+ - `websocketModule({ limits })` tunes in-process memory bounds:
243
+ `maxSessions`, `maxRoomsPerSession`, `maxRoomNameLength`, `maxTopics`,
244
+ `maxRateLimitBuckets` and `maxOutboundQueuePerSession`.
245
+ - The complete upgrade, including middleware, authentication and session I/O,
246
+ defaults to a 10 second deadline. Connection initialization after upgrade has
247
+ a separate deadline of the same duration. Message validation/handling defaults
248
+ to 30 seconds, and graceful shutdown drain to 5 seconds.
249
+ Configure `handshakeTimeoutMs`, `messageHandlingTimeoutMs` and
250
+ `shutdownDrainTimeoutMs`; an explicit `0` disables the corresponding deadline.
251
+ - `maxBackpressureBytes` defaults to 1 MiB of native outgoing buffer. Large replay
252
+ waits for native drain within the open/message deadline. A runtime-initiated
253
+ close forcibly terminates an unresponsive peer after `socketCloseTimeoutMs`
254
+ (default 1 second). Both limits must be positive.
255
+ - `maxConcurrentHandshakes` counts unresolved upgrade operations, and
256
+ `maxConcurrentMessageHandlers` counts unresolved validators/handlers. A timeout
257
+ ends the client's wait but retains the slot until actual success or failure.
258
+ New work fails busy while the limit is occupied. Connection initialization
259
+ after upgrade has its own lifetime and is not an upgrade admission slot.
260
+ - `close()` is shared and idempotent, including its failure result. It aborts
261
+ waits and terminates sockets, but disconnect hooks wait for their connection's
262
+ callback, and gateway/adapter cleanup waits for actual work settlement.
263
+ Expiring `shutdownDrainTimeoutMs` rejects close; ordered cleanup continues
264
+ afterwards. A permanently unresolved callback retains its resources until
265
+ process termination. Timeout is not evidence that application effects ended.
266
+ - Middleware reads cancellation from `ctx.signal`; validators may accept a
267
+ second `AbortSignal`, authenticators an optional context, and handlers can use
268
+ `socket.signal`. Existing positional handler/authenticator signatures remain
269
+ valid. A timed-out message fails and closes its physical socket; late acks and
270
+ socket mutations are suppressed.
271
+ - Messages received immediately after browser `open` wait for session
272
+ persistence and `handleConnection`. The pending-message bound still applies
273
+ during initialization. An initialization timeout closes the connection and
274
+ suppresses queued handlers. Cancellation stops waiting and late activation;
275
+ it cannot roll back I/O already started by an arbitrary adapter.
276
+ - Reconnect always enforces the principal stored with the target session,
277
+ including principals established by custom gateway middleware. The optional
278
+ token on a reconnect control packet is additional reauthentication, not the
279
+ switch that enables ownership checks.
280
+ - Room names are validated; empty names, names containing the internal separator
281
+ and names longer than the configured limit are rejected.
282
+ - Expired sessions and rate-limit buckets are purged during normal operations;
283
+ default rate-limit keys are also forgotten on socket close.
284
+ - `InMemoryWebSocketAdapter.maxEntries` caps only live sessions (default 10,000;
285
+ the default runtime adapter uses `limits.maxSessions`). Deletion markers have
286
+ a separate `maxTombstones` cap, defaulting to maxEntries. Older markers compact
287
+ into a creation floor. Immutable runtime creation tokens allow fresh sessions
288
+ in the same millisecond to use freed live capacity while old deleted snapshots
289
+ remain rejected, including higher-revision writes. Existing sessions can still
290
+ be updated. A full live cap raises SessionCapacityError and closes with 1013.
291
+ - Compaction conservatively rejects absent snapshots predating its floor,
292
+ including delayed first writes. Legacy/imported states without a local token
293
+ additionally use immutable createdAt and `tombstoneTtlMs` (default 60 seconds)
294
+ as an initial-write window. Such states do not have the runtime's precise
295
+ same-millisecond ordering. SIDs are not reused for different sessions.
296
+
297
+ The module passport and verification links are in [MODULE.md](MODULE.md).