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,158 @@
1
+ import {
2
+ DI,
3
+ HOSTED_SERVICE,
4
+ Module,
5
+ createToken,
6
+ createModuleOwnedMetadataChannel,
7
+ registerModuleOwnedProviderContributor,
8
+ registerModuleOwnedContributionValidator,
9
+ type ModuleConfig,
10
+ type ModuleExport,
11
+ type BazisModuleRef,
12
+ type ProviderDefinition,
13
+ } from "../di";
14
+ import { ConfigRegistry, HEALTH_CHECK } from "../kernel";
15
+ import { InfraError, type InfraConnector } from "./InfraConnector";
16
+ import { InfraLifecycle } from "./InfraLifecycle";
17
+
18
+ /**
19
+ * Infrastructure manifest: a readable "logical name → connector" map.
20
+ * The key (`db`, `cache`, `search`) is the instance name: it appears in the
21
+ * health check (`infra:db`) and in diagnostics, so the manifest file reads as
22
+ * the application's connection spec.
23
+ */
24
+ export type InfraManifest = Readonly<Record<string, InfraConnector>>;
25
+
26
+ const instances = new WeakMap<ProviderDefinition, { name: string; token: InfraConnector["token"] }>();
27
+ const instanceChannel = createModuleOwnedMetadataChannel<{ name: string; token: InfraConnector["token"] }>("infra.instances");
28
+ registerModuleOwnedProviderContributor((metadata, context) => {
29
+ for (const provider of metadata.providers ?? []) {
30
+ const instance = instances.get(provider);
31
+ if (instance) context.addMetadata(instanceChannel, instance);
32
+ }
33
+ });
34
+ registerModuleOwnedContributionValidator((snapshot) => {
35
+ const owners = new Map<InfraConnector["token"], string>();
36
+ for (const { ownerName, payload } of snapshot.getMetadataContributions(instanceChannel)) {
37
+ const name = `${ownerName}:${payload.name}`;
38
+ const previous = owners.get(payload.token);
39
+ if (previous !== undefined) {
40
+ throw new InfraError(`Infra instances "${previous}" and "${name}" share the same connector token; each instance needs a distinct token.`);
41
+ }
42
+ owners.set(payload.token, name);
43
+ }
44
+ });
45
+
46
+ function buildInfraDefinitions(manifest: InfraManifest): {
47
+ providers: ProviderDefinition[];
48
+ exports: ModuleExport[];
49
+ config: ModuleConfig[];
50
+ } {
51
+ const providers: ProviderDefinition[] = [];
52
+ const exports: ModuleExport[] = [];
53
+ const config: ModuleConfig[] = [];
54
+ const seenConfig = new Set<ModuleConfig>();
55
+ // One token = one singleton client. Two instances under one token would give
56
+ // a shared client with two lifecycles (double connect/dispose), so fail loudly.
57
+ const seenTokens = new Map<InfraConnector["token"], string>();
58
+
59
+ for (const [name, connector] of Object.entries(manifest)) {
60
+ if (!name.trim() || name !== name.trim()) throw new InfraError("Infra instance names must be non-empty and trimmed.");
61
+ if (connector.phase !== undefined && !Number.isSafeInteger(connector.phase)) {
62
+ throw new InfraError(`Infra instance "${name}": phase must be a finite safe integer.`);
63
+ }
64
+ const previous = seenTokens.get(connector.token);
65
+ if (previous !== undefined) {
66
+ throw new InfraError(
67
+ `Infra manifest: instances "${previous}" and "${name}" share the same connector token; each instance needs a distinct token.`,
68
+ );
69
+ }
70
+ seenTokens.set(connector.token, name);
71
+
72
+ const connectorConfigs =
73
+ connector.config === undefined ? [] : Array.isArray(connector.config) ? connector.config : [connector.config];
74
+ for (let index = 0; index < connectorConfigs.length; index += 1) {
75
+ const item = connectorConfigs[index] as ModuleConfig;
76
+ if (!seenConfig.has(item)) {
77
+ seenConfig.add(item);
78
+ config.push(item);
79
+ }
80
+ }
81
+
82
+ // DI registers the owner before the client: even an early resolution or
83
+ // a failing factory elsewhere cannot leave a created resource without cleanup.
84
+ const ownerToken = createToken<InfraLifecycle<unknown>>(`infra:${name}:lifetime`);
85
+ const owner = DI.singleton(DI.factoryProviderWithResolver(ownerToken, [], (resolver) =>
86
+ new InfraLifecycle(name, connector, undefined, resolver.has(ConfigRegistry) ? resolver.resolve(ConfigRegistry) : undefined)));
87
+ instances.set(owner, { name, token: connector.token });
88
+ providers.push(owner);
89
+ providers.push(
90
+ DI.singleton(DI.externallyOwned(DI.factoryProvider(connector.token, [ownerToken], (lifetime) => lifetime.getClient()))),
91
+ );
92
+
93
+ // 2. Lifecycle: opens/closes the connection in the kernel phases.
94
+ providers.push(
95
+ DI.singleton(
96
+ DI.factoryProvider(HOSTED_SERVICE, [ownerToken], (lifetime) => lifetime),
97
+ ),
98
+ );
99
+
100
+ // 3. Health check: only if the connector supports it.
101
+ if (connector.healthCheck) {
102
+ const healthCheck = connector.healthCheck.bind(connector);
103
+ providers.push(
104
+ DI.singleton(
105
+ DI.factoryProvider(HEALTH_CHECK, [connector.token], (client) => ({
106
+ name: `infra:${name}`,
107
+ check: async (signal?: AbortSignal) => ({ healthy: await healthCheck(client, signal) }),
108
+ })),
109
+ ),
110
+ );
111
+ }
112
+
113
+ exports.push(connector.token);
114
+
115
+ // 4. Extra connector providers (for example a distributed cache on top of Redis).
116
+ if (connector.providers !== undefined) {
117
+ providers.push(...connector.providers);
118
+ }
119
+ if (connector.exports !== undefined) {
120
+ exports.push(...connector.exports);
121
+ }
122
+ }
123
+
124
+ return { providers, exports, config };
125
+ }
126
+
127
+ /**
128
+ * Dynamic infrastructure module (a plain metadata object): the same as
129
+ * `@Infra`, but without a class. Handy for `imports` or `runApp({ infra })`.
130
+ */
131
+ export function infraModule(manifest: InfraManifest): BazisModuleRef {
132
+ const { providers, exports, config } = buildInfraDefinitions(manifest);
133
+ return { global: true, providers, exports, config };
134
+ }
135
+
136
+ /**
137
+ * Infrastructure decorator. Puts the metadata of a regular **global module**
138
+ * on the class, so the class becomes a valid `BazisModuleRef`: it can be passed
139
+ * to `runApp({ infra: AppInfra })` or to `imports`.
140
+ *
141
+ * The class stays pure metadata (like `@Module`) and is **never instantiated**:
142
+ * only the clients it lists live and hold state.
143
+ *
144
+ * ```ts
145
+ * @Infra({
146
+ * db: postgres(dbConfig),
147
+ * cache: redisConnect(redisConfig),
148
+ * search: openSearchConnect(searchConfig),
149
+ * })
150
+ * export class AppInfra {}
151
+ * ```
152
+ */
153
+ export function Infra(manifest: InfraManifest) {
154
+ const { providers, exports, config } = buildInfraDefinitions(manifest);
155
+ return (target: abstract new (...args: never) => unknown, _context: ClassDecoratorContext): void => {
156
+ Module({ global: true, providers, exports, config })(target, _context);
157
+ };
158
+ }
@@ -0,0 +1,86 @@
1
+ import type { InjectionToken, ModuleConfig, ModuleExport, ProviderDefinition } from "../di";
2
+ import { redactSensitiveText } from "../../library/redaction";
3
+ import type { ConfigRegistry } from "../kernel/config/ConfigRegistry";
4
+
5
+ /**
6
+ * Infrastructure connector contract: one shape for "a connection to something
7
+ * external" (a database, cache, search engine, bus). A connector encapsulates
8
+ * four things that would otherwise be hand-written in every integration module:
9
+ *
10
+ * 1. **creating the client** from the subsystem config ({@link create}): the
11
+ * connector gets a typed `defineConfig` object and reads the declared keys
12
+ * itself (secrets are revealed at the boundary, not read from `process.env`);
13
+ * 2. **opening the connection** at application start ({@link connect});
14
+ * 3. **closing the connection** at shutdown ({@link dispose}): graceful shutdown;
15
+ * 4. **health check** ({@link healthCheck}) for the built-in `/health`.
16
+ *
17
+ * The {@link Infra} decorator expands a set of connectors into a regular global
18
+ * module: the client is registered as a singleton under its {@link token}, the
19
+ * lifecycle as a `HOSTED_SERVICE` (the default phase is negative so that
20
+ * infrastructure starts before the servers), the health check as `HEALTH_CHECK`.
21
+ * The connector implementation defines the connection type; there is no common
22
+ * list of types. The manifest entry name is used for diagnostics; the client is
23
+ * identified by its DI token.
24
+ *
25
+ * @typeParam TClient Type of the client injected in the application by {@link token}.
26
+ */
27
+ export interface InfraConnector<TClient = unknown> {
28
+ /** Token under which the client is available for injection into application services. */
29
+ readonly token: InjectionToken<TClient>;
30
+
31
+ /**
32
+ * Configs owned by the connector. `@Infra` lifts them into the module
33
+ * metadata, and `runApp` validates them before the application starts.
34
+ */
35
+ readonly config?: ModuleConfig | readonly ModuleConfig[];
36
+
37
+ /**
38
+ * Start phase of the hosted lifecycle. Lower starts earlier and stops later.
39
+ * Defaults to `-100`, so infrastructure is ready before the servers.
40
+ */
41
+ readonly phase?: number;
42
+
43
+ /**
44
+ * Creates the client (**not** connected yet: the connection is opened in
45
+ * {@link connect}). The connector keeps the subsystem config itself (it was
46
+ * passed to its factory, e.g. `postgres(dbConfig)`); this is where
47
+ * credentials are read and required keys are validated.
48
+ */
49
+ create(configs?: ConfigRegistry): TClient;
50
+
51
+ /** Opens the connection / warms up the pool. Called at application start. */
52
+ connect(client: TClient, signal?: AbortSignal): Promise<void> | void;
53
+
54
+ /** Closes the connection / releases resources. Called at shutdown. */
55
+ dispose(client: TClient): Promise<void> | void;
56
+
57
+ /**
58
+ * Connection liveness check for `/health`. If not set, no health check is
59
+ * registered for this connector.
60
+ */
61
+ healthCheck?(client: TClient, signal?: AbortSignal): Promise<boolean> | boolean;
62
+
63
+ /**
64
+ * Extra providers the connector adds to the infrastructure module besides
65
+ * the client itself (for example `redisConnect(cfg, { cache: "distributed" })`
66
+ * publishes a distributed cache backend on top of the client). Usually a
67
+ * `factoryProvider` that refers to {@link token}. Exposed through {@link exports}.
68
+ */
69
+ readonly providers?: readonly ProviderDefinition[];
70
+
71
+ /** Tokens from {@link providers} to make visible to the application. */
72
+ readonly exports?: readonly ModuleExport[];
73
+ }
74
+
75
+ /** Infrastructure configuration/connection error. */
76
+ export class InfraError extends Error {
77
+ public constructor(message: string) {
78
+ super(message);
79
+ this.name = "InfraError";
80
+ }
81
+ }
82
+
83
+ /** Safely extracts the error text (in case a non-`Error` was thrown). */
84
+ export function errorMessage(error: unknown): string {
85
+ return redactSensitiveText(error instanceof Error ? error.message : String(error));
86
+ }
@@ -0,0 +1,86 @@
1
+ import type { HostedService } from "../di";
2
+ import { InfraError, type InfraConnector } from "./InfraConnector";
3
+ import { bindConnectorLifecycle } from "./connectorIdentity";
4
+ import { awaitAbortable } from "../kernel/internal/awaitAbortable";
5
+ import type { ConfigRegistry } from "../kernel/config/ConfigRegistry";
6
+
7
+ const DEFAULT_INFRA_PHASE = -100;
8
+
9
+ /**
10
+ * Hosted service that wraps an {@link InfraConnector} into the kernel
11
+ * lifecycle: opens the connection at start and closes it at shutdown. One
12
+ * lifecycle per connector. DI owns the lifecycle even when the client is
13
+ * resolved before start.
14
+ *
15
+ * The phase comes from the connector (negative by default), so connections
16
+ * come up before the HTTP server and background tasks and go down after them.
17
+ */
18
+ export class InfraLifecycle<TClient> implements HostedService {
19
+ public readonly phase: number;
20
+ private client?: TClient;
21
+ private created = false;
22
+ private disposed = false;
23
+ private startPromise?: Promise<void>;
24
+ private disposePromise?: Promise<void>;
25
+
26
+ public constructor(
27
+ private readonly name: string,
28
+ private readonly connector: InfraConnector<TClient>,
29
+ client?: TClient,
30
+ private readonly configs?: ConfigRegistry,
31
+ ) {
32
+ this.client = client;
33
+ this.created = client !== undefined;
34
+ this.phase = connector.phase ?? DEFAULT_INFRA_PHASE;
35
+ bindConnectorLifecycle(connector, this);
36
+ }
37
+
38
+ public getClient(): TClient {
39
+ if (this.disposed) throw new InfraError(`Infra connector "${this.name}" is already disposed.`);
40
+ if (!this.created) {
41
+ this.client = this.connector.create(this.configs);
42
+ this.created = true;
43
+ }
44
+ return this.client as TClient;
45
+ }
46
+
47
+ public start(signal?: AbortSignal): Promise<void> {
48
+ this.startPromise ??= Promise.resolve().then(() => this.connect(signal));
49
+ return this.startPromise;
50
+ }
51
+
52
+ private async connect(signal?: AbortSignal): Promise<void> {
53
+ try {
54
+ signal?.throwIfAborted();
55
+ const client = this.getClient();
56
+ await awaitAbortable(Promise.resolve(this.connector.connect(client, signal)), signal);
57
+ } catch (error) {
58
+ try {
59
+ await this.dispose();
60
+ } catch (cleanupError) {
61
+ throw new AggregateError(
62
+ [error, cleanupError],
63
+ `Infra connector "${this.name}" failed to start and rollback also failed.`,
64
+ );
65
+ }
66
+ throw error;
67
+ }
68
+ }
69
+
70
+ public stop(): Promise<void> {
71
+ return this.dispose();
72
+ }
73
+
74
+ public dispose(): Promise<void> {
75
+ this.disposed = true;
76
+ this.disposePromise ??= Promise.resolve().then(async () => {
77
+ if (this.created) await this.connector.dispose(this.client as TClient);
78
+ });
79
+ return this.disposePromise;
80
+ }
81
+
82
+ /** Infrastructure instance name (the key in the `@Infra` manifest), for diagnostics. */
83
+ public get instanceName(): string {
84
+ return this.name;
85
+ }
86
+ }
@@ -0,0 +1,88 @@
1
+ import {
2
+ DistributedCache,
3
+ NamedCacheRegistry,
4
+ httpPayloadCacheCodec,
5
+ jsonCacheCodec,
6
+ type CachedHttpPayload,
7
+ type DistributedCacheStores,
8
+ type DistributedCachePing,
9
+ type IDistributedCache,
10
+ } from "../../cache";
11
+ import type { RedisCommandClient } from "./RedisDistributedCacheDriver";
12
+ import { RedisDistributedCacheDriver } from "./RedisDistributedCacheDriver";
13
+
14
+ /** Tuning of the Redis-backed distributed cache (all optional). */
15
+ export interface RedisDistributedCacheTuning {
16
+ /** Connection name for the decorators (`connection`). Defaults to `"default"`. */
17
+ readonly connection?: string;
18
+ /** Prefix of all keys; isolates the application cache in a shared Redis. */
19
+ readonly keyPrefix?: string;
20
+ /** TTL of the anti-stampede lock on a miss (seconds). */
21
+ readonly defaultLockSeconds?: number;
22
+ /** Maximum key length. */
23
+ readonly maxKeyLength?: number;
24
+ /** Size limit of a serialized value (bytes); `set` degrades gracefully. */
25
+ readonly maxValueBytes?: number;
26
+ /** Polling interval (ms) while waiting for another worker's result. */
27
+ readonly pollIntervalMs?: number;
28
+ }
29
+
30
+ const DEFAULT_KEY_PREFIX = "bazis:cache:";
31
+ const DEFAULT_LOCK_SECONDS = 10;
32
+ const DEFAULT_CONNECTION = "default";
33
+
34
+ /**
35
+ * Distributed cache backend on top of one Redis connection. Builds two stores
36
+ * (HTTP responses and method values) with separate namespaces and codecs and
37
+ * exposes them as a {@link NamedCacheRegistry}. The `redisConnect(...)`
38
+ * connector opens and closes the connection.
39
+ */
40
+ export class RedisDistributedCacheBackend implements DistributedCacheStores {
41
+ public readonly connectionNames: readonly string[];
42
+ public readonly outputCache: NamedCacheRegistry<IDistributedCache<CachedHttpPayload>>;
43
+ public readonly serviceCache: NamedCacheRegistry<IDistributedCache>;
44
+
45
+ private readonly connection: string;
46
+
47
+ public constructor(
48
+ private readonly client: RedisCommandClient,
49
+ tuning: RedisDistributedCacheTuning = {},
50
+ ) {
51
+ this.connection = tuning.connection ?? DEFAULT_CONNECTION;
52
+ this.connectionNames = [this.connection];
53
+
54
+ const driver = new RedisDistributedCacheDriver(client);
55
+ const base = {
56
+ connectionName: this.connection,
57
+ keyPrefix: tuning.keyPrefix ?? DEFAULT_KEY_PREFIX,
58
+ defaultLockSeconds: tuning.defaultLockSeconds ?? DEFAULT_LOCK_SECONDS,
59
+ maxKeyLength: tuning.maxKeyLength,
60
+ maxValueBytes: tuning.maxValueBytes,
61
+ pollIntervalMs: tuning.pollIntervalMs,
62
+ };
63
+
64
+ const output = new DistributedCache<CachedHttpPayload>(driver, httpPayloadCacheCodec, {
65
+ ...base,
66
+ namespace: "out:",
67
+ });
68
+ const service = new DistributedCache(driver, jsonCacheCodec, { ...base, namespace: "svc:" });
69
+
70
+ this.outputCache = new NamedCacheRegistry(new Map([[this.connection, output]]));
71
+ this.serviceCache = new NamedCacheRegistry(new Map([[this.connection, service]]));
72
+ }
73
+
74
+ public async ping(): Promise<readonly DistributedCachePing[]> {
75
+ try {
76
+ const reply = await this.client.send("PING", []);
77
+ return [{ connection: this.connection, healthy: reply === "PONG" }];
78
+ } catch (error) {
79
+ return [
80
+ {
81
+ connection: this.connection,
82
+ healthy: false,
83
+ detail: error instanceof Error ? error.message : String(error),
84
+ },
85
+ ];
86
+ }
87
+ }
88
+ }
@@ -0,0 +1,186 @@
1
+ import type { DistributedCacheDriver, DistributedCacheFencedWrite } from "../../cache";
2
+
3
+ /**
4
+ * The narrow Redis client contract the driver needs. Bun `RedisClient`
5
+ * satisfies it structurally, and the interface lets the driver be tested
6
+ * without a live server (any fake implementing these five methods).
7
+ */
8
+ export interface RedisCommandClient {
9
+ get(key: string): Promise<string | null>;
10
+ set(key: string, value: string, ...options: string[]): Promise<string | null>;
11
+ del(...keys: string[]): Promise<number>;
12
+ expire(key: string, seconds: number): Promise<number>;
13
+ send(command: string, args: string[]): Promise<unknown>;
14
+ }
15
+
16
+ /**
17
+ * Releases the lock only if it still holds our fencing token (atomically).
18
+ * Otherwise a slow worker could delete a lock already re-acquired by another.
19
+ */
20
+ const RELEASE_LOCK_SCRIPT =
21
+ "if redis.call('get', KEYS[1]) == ARGV[1] then redis.call('del', KEYS[1]); if KEYS[2] then redis.call('del', KEYS[2]) end; return 1 else return 0 end";
22
+
23
+ const DELETE_IF_VALUE_SCRIPT =
24
+ "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
25
+
26
+ const INVALIDATE_SCRIPT =
27
+ "redis.call('incr', KEYS[1]); return redis.call('del', KEYS[2])";
28
+
29
+ const INVALIDATE_WHILE_LOCKED_SCRIPT =
30
+ "if redis.call('exists', KEYS[3]) == 1 then local lockTtl = redis.call('pttl', KEYS[3]); redis.call('incr', KEYS[1]); if lockTtl > 0 then redis.call('pexpire', KEYS[1], lockTtl + 60000) end else redis.call('del', KEYS[1]) end; return redis.call('del', KEYS[2])";
31
+
32
+ const ADVANCE_TAG_GENERATION_SCRIPT =
33
+ "local next = redis.call('incr', KEYS[1]); redis.call('sadd', KEYS[2], tostring(next - 1)); return next";
34
+
35
+ const ADD_TAG_MEMBERS_SCRIPT = `
36
+ local previousTtl = redis.call('ttl', KEYS[1])
37
+ for i = 2, #ARGV do redis.call('sadd', KEYS[1], ARGV[i]) end
38
+ if ARGV[1] == '' then
39
+ redis.call('persist', KEYS[1])
40
+ elseif previousTtl == -2 or (previousTtl >= 0 and previousTtl < tonumber(ARGV[1])) then
41
+ redis.call('expire', KEYS[1], ARGV[1])
42
+ end
43
+ return 1`;
44
+
45
+ const WRITE_IF_LOCK_OWNER_SCRIPT = `
46
+ if redis.call('get', KEYS[1]) ~= ARGV[1] then return 0 end
47
+ local versionCount = tonumber(ARGV[4])
48
+ local tagCount = tonumber(ARGV[5])
49
+ for i = 1, versionCount do
50
+ local actual = redis.call('get', KEYS[2 + i])
51
+ local expected = ARGV[5 + i]
52
+ if expected == '__BAZIS_MISSING_VERSION__' then
53
+ if actual then return 0 end
54
+ elseif actual ~= expected then
55
+ return 0
56
+ end
57
+ end
58
+ if ARGV[3] == '' then
59
+ redis.call('set', KEYS[2], ARGV[2])
60
+ else
61
+ redis.call('set', KEYS[2], ARGV[2], 'EX', ARGV[3])
62
+ end
63
+ for i = 1, tagCount do
64
+ local tagKey = KEYS[2 + versionCount + i]
65
+ local previousTtl = redis.call('ttl', tagKey)
66
+ redis.call('sadd', tagKey, ARGV[5 + versionCount + i])
67
+ if ARGV[3] == '' then
68
+ redis.call('persist', tagKey)
69
+ elseif previousTtl == -2 or (previousTtl >= 0 and previousTtl < tonumber(ARGV[3])) then
70
+ redis.call('expire', tagKey, ARGV[3])
71
+ end
72
+ end
73
+ return 1`;
74
+
75
+ /**
76
+ * {@link DistributedCacheDriver} implementation on top of Redis/Valkey (the
77
+ * native Bun `RedisClient`). Low-level primitives only: the whole cache policy
78
+ * (anti-stampede, tags, limits) lives in the kernel `DistributedCache`.
79
+ */
80
+ export class RedisDistributedCacheDriver implements DistributedCacheDriver {
81
+ public constructor(private readonly client: RedisCommandClient) {}
82
+
83
+ public read(key: string): Promise<string | null> {
84
+ return this.client.get(key);
85
+ }
86
+
87
+ public async write(key: string, value: string, ttlSeconds?: number): Promise<void> {
88
+ if (ttlSeconds !== undefined) {
89
+ await this.client.set(key, value, "EX", String(ttlSeconds));
90
+ } else {
91
+ await this.client.set(key, value);
92
+ }
93
+ }
94
+
95
+ public delete(keys: readonly string[]): Promise<number> {
96
+ if (keys.length === 0) {
97
+ return Promise.resolve(0);
98
+ }
99
+ return this.client.del(...keys);
100
+ }
101
+
102
+ public async acquireLock(lockKey: string, token: string, ttlSeconds: number): Promise<boolean> {
103
+ const reply = await this.client.set(lockKey, token, "NX", "EX", String(ttlSeconds));
104
+ return reply === "OK";
105
+ }
106
+
107
+ public async releaseLock(lockKey: string, token: string, entryVersionKey?: string): Promise<void> {
108
+ const keys = entryVersionKey === undefined ? [lockKey] : [lockKey, entryVersionKey];
109
+ await this.client.send("EVAL", [RELEASE_LOCK_SCRIPT, String(keys.length), ...keys, token]);
110
+ }
111
+
112
+ public async writeIfLockOwner(request: DistributedCacheFencedWrite): Promise<boolean> {
113
+ const versionKeys = request.versionChecks.map((check) => check.key);
114
+ const tagKeys = request.tags.map((tag) => tag.key);
115
+ const expectedVersions = request.versionChecks.map((check) => check.expected ?? "__BAZIS_MISSING_VERSION__");
116
+ const tagMembers = request.tags.map((tag) => tag.member);
117
+ const keys = [request.lockKey, request.key, ...versionKeys, ...tagKeys];
118
+ const args = [
119
+ request.lockToken,
120
+ request.value,
121
+ request.ttlSeconds === undefined ? "" : String(request.ttlSeconds),
122
+ String(versionKeys.length),
123
+ String(tagKeys.length),
124
+ ...expectedVersions,
125
+ ...tagMembers,
126
+ ];
127
+ const reply = await this.client.send("EVAL", [WRITE_IF_LOCK_OWNER_SCRIPT, String(keys.length), ...keys, ...args]);
128
+ return Number(reply) === 1;
129
+ }
130
+
131
+ public async deleteIfValue(key: string, expectedValue: string): Promise<boolean> {
132
+ const reply = await this.client.send("EVAL", [DELETE_IF_VALUE_SCRIPT, "1", key, expectedValue]);
133
+ return Number(reply) === 1;
134
+ }
135
+
136
+ public async increment(key: string): Promise<number> {
137
+ const reply = await this.client.send("INCR", [key]);
138
+ const value = Number(reply);
139
+ if (!Number.isSafeInteger(value) || value < 1) {
140
+ throw new Error("Redis returned an invalid cache invalidation generation");
141
+ }
142
+ return value;
143
+ }
144
+
145
+ public async invalidate(versionKey: string, valueKey: string, lockKey?: string): Promise<boolean> {
146
+ const reply = lockKey === undefined
147
+ ? await this.client.send("EVAL", [INVALIDATE_SCRIPT, "2", versionKey, valueKey])
148
+ : await this.client.send(
149
+ "EVAL",
150
+ [INVALIDATE_WHILE_LOCKED_SCRIPT, "3", versionKey, valueKey, lockKey],
151
+ );
152
+ return Number(reply) > 0;
153
+ }
154
+
155
+ public async advanceTagGeneration(versionKey: string, pendingKey: string): Promise<number> {
156
+ const reply = await this.client.send("EVAL", [ADVANCE_TAG_GENERATION_SCRIPT, "2", versionKey, pendingKey]);
157
+ const value = Number(reply);
158
+ if (!Number.isSafeInteger(value) || value < 1) {
159
+ throw new Error("Redis returned an invalid tag invalidation generation");
160
+ }
161
+ return value;
162
+ }
163
+
164
+ public async addTagMembers(tagKey: string, members: readonly string[], ttlSeconds?: number): Promise<void> {
165
+ if (members.length === 0) {
166
+ return;
167
+ }
168
+ await this.client.send("EVAL", [
169
+ ADD_TAG_MEMBERS_SCRIPT,
170
+ "1",
171
+ tagKey,
172
+ ttlSeconds === undefined ? "" : String(ttlSeconds),
173
+ ...members,
174
+ ]);
175
+ }
176
+
177
+ public async removeTagMembers(tagKey: string, members: readonly string[]): Promise<void> {
178
+ if (members.length === 0) return;
179
+ await this.client.send("SREM", [tagKey, ...members]);
180
+ }
181
+
182
+ public async tagMembers(tagKey: string): Promise<readonly string[]> {
183
+ const reply = await this.client.send("SMEMBERS", [tagKey]);
184
+ return Array.isArray(reply) ? (reply as string[]) : [];
185
+ }
186
+ }
@@ -0,0 +1,7 @@
1
+ // Distributed cache backend on top of Redis. It implements the `@/core/cache`
2
+ // abstractions (DistributedCacheDriver/Backend), so the cache core stays backend-agnostic.
3
+ export {
4
+ RedisDistributedCacheBackend,
5
+ type RedisDistributedCacheTuning,
6
+ } from "./RedisDistributedCacheBackend";
7
+ export { RedisDistributedCacheDriver, type RedisCommandClient } from "./RedisDistributedCacheDriver";
@@ -0,0 +1,29 @@
1
+ import { InfraError } from "./InfraConnector";
2
+ import type { AppConfig } from "../kernel/config/defineConfig";
3
+ import type { ConfigRegistry } from "../kernel/config/ConfigRegistry";
4
+
5
+ /**
6
+ * Minimal dynamic access to a declarative subsystem config.
7
+ *
8
+ * Connectors accept a typed config (`AppConfig<...Shape>`): at the call site
9
+ * this guarantees that the required keys are declared with the right types.
10
+ * Inside, the connector reads them by name; the runtime shape is known from
11
+ * `Shape`, so a narrow cast to this reader is acceptable here.
12
+ */
13
+ export interface ConfigReader {
14
+ get(key: string): unknown;
15
+ has(key: string): boolean;
16
+ }
17
+
18
+ /** Narrow cast of a config to the dynamic reader (the shape is type-checked at the input). */
19
+ export function reader(config: object, configs?: ConfigRegistry): ConfigReader {
20
+ return (configs?.get(config as AppConfig<object>) ?? config) as ConfigReader;
21
+ }
22
+
23
+ /** Reads a required non-empty string value or fails with a clear error. */
24
+ export function requireValue(value: unknown, field: string, kind: string): string {
25
+ if (typeof value !== "string" || value.trim().length === 0) {
26
+ throw new InfraError(`Infra connector "${kind}": "${field}" is required and must be a non-empty string.`);
27
+ }
28
+ return value;
29
+ }
@@ -0,0 +1,39 @@
1
+ import type { HostedService } from "../di";
2
+ import type { InfraConnector } from "./InfraConnector";
3
+
4
+ type ConnectorIdentity = Readonly<{ role: string; fingerprint: readonly unknown[] }>;
5
+ type LifecycleBinding = Readonly<{ connector: InfraConnector; identity?: ConnectorIdentity }>;
6
+
7
+ const identities = new WeakMap<object, ConnectorIdentity>();
8
+ const lifecycles = new WeakMap<object, LifecycleBinding>();
9
+ const values = (c: InfraConnector) => [c.token, c.config, c.phase, c.create, c.connect, c.dispose, c.healthCheck, c.providers, c.exports] as const;
10
+ const unchanged = (c: InfraConnector, identity: ConnectorIdentity) => values(c).every((value, index) => Object.is(value, identity.fingerprint[index]));
11
+
12
+ /** @internal A factory identifies its original connector; copies inherit no identity. */
13
+ export function identifyConnector<T>(connector: InfraConnector<T>, role: string): InfraConnector<T> {
14
+ identities.set(connector, Object.freeze({ role, fingerprint: values(connector) }));
15
+ return connector;
16
+ }
17
+
18
+ /** @internal Records resource ownership without interpreting role, token or phase. */
19
+ export function bindConnectorLifecycle(connector: InfraConnector, lifecycle: HostedService): void {
20
+ const identity = identities.get(connector);
21
+ lifecycles.set(lifecycle, Object.freeze({
22
+ connector,
23
+ identity: identity !== undefined && unchanged(connector, identity) ? identity : undefined,
24
+ }));
25
+ }
26
+
27
+ /** @internal Read-only evidence for the owning integration's plan validator. */
28
+ export function getLifecycleConnector(lifecycle: HostedService): InfraConnector | undefined {
29
+ return lifecycles.get(lifecycle)?.connector;
30
+ }
31
+
32
+ /** @internal Both binding-time and current fingerprints must match the original factory result. */
33
+ export function getLifecycleConnectorRole(lifecycle: HostedService): string | undefined {
34
+ const binding = lifecycles.get(lifecycle);
35
+ if (binding?.identity === undefined) return undefined;
36
+ return identities.get(binding.connector) === binding.identity && unchanged(binding.connector, binding.identity)
37
+ ? binding.identity.role
38
+ : undefined;
39
+ }