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,448 @@
1
+ import { isDatabaseGenerated, type EntityModel, type PropertyModel } from "../Metadata/types";
2
+ import { DbUpdateError, OrmError } from "../errors";
3
+ import { KeyTuple } from "../Metadata/KeyTuple";
4
+ import { EntityState } from "./EntityState";
5
+
6
+ /** Snapshot of the original property values (for snapshot change tracking). */
7
+ type Snapshot = Record<string, unknown>;
8
+
9
+ interface SnapshotState {
10
+ readonly values: Snapshot;
11
+ readonly jsonSignatures: Map<string, string>;
12
+ }
13
+
14
+ /** Tracker record for one entity. */
15
+ export interface TrackedEntry {
16
+ readonly entity: object;
17
+ readonly model: EntityModel;
18
+ state: EntityState;
19
+ /** Snapshot taken at load/attach time; Added entries have none. */
20
+ snapshot?: Snapshot;
21
+ /** Precomputed JSON signatures of the snapshot, so DetectChanges does not serialize it again. */
22
+ snapshotJsonSignatures?: Map<string, string>;
23
+ /** Names of properties changed relative to the snapshot (after DetectChanges). */
24
+ modifiedProperties: Set<string>;
25
+ }
26
+
27
+ /**
28
+ * Snapshot change tracking + identity map.
29
+ *
30
+ * On load/attach a copy of the values is kept; `DetectChanges` compares the
31
+ * current values with the snapshot. An identity map by (model, key value) is
32
+ * also maintained: materializing the same row again returns the already tracked
33
+ * instance (like `Find`/identity resolution in EF Core), which prevents
34
+ * duplicate objects and tracking drift.
35
+ */
36
+ export class ChangeTracker {
37
+ private readonly entries = new Map<object, TrackedEntry>();
38
+ /** Explicit Update is an instruction to write every non-key column, even if no snapshot diff exists. */
39
+ private readonly explicitUpdateSets = new WeakSet<Set<string>>();
40
+ /** Secondary index by key: model -> (keyValue -> entry). */
41
+ private readonly identity = new Map<EntityModel, Map<string, TrackedEntry>>();
42
+
43
+ constructor() { trackerEntries.set(this, this.entries); }
44
+
45
+ /**
46
+ * Registers an entity read from the database as Unchanged. Returns the
47
+ * CANONICAL instance: if a row with this key is already tracked, the
48
+ * previously loaded object is returned (and `entity` is discarded).
49
+ */
50
+ trackLoaded(entity: object, model: EntityModel): object {
51
+ const keyValue = KeyTuple.fromEntity(model, entity as Record<string, unknown>);
52
+ if (keyValue) {
53
+ const existing = this.identityMap(model).get(keyValue.toString());
54
+ if (existing) {
55
+ return existing.entity; // already tracked: the canonical instance wins
56
+ }
57
+ }
58
+ if (this.entries.has(entity)) {
59
+ return entity;
60
+ }
61
+ this.assertIdentityAvailable(entity, model, keyValue);
62
+ const entry: TrackedEntry = {
63
+ entity,
64
+ model,
65
+ state: EntityState.Unchanged,
66
+ modifiedProperties: new Set(),
67
+ };
68
+ this.applySnapshot(entry, this.snapshot(entity, model));
69
+ this.entries.set(entity, entry);
70
+ this.indexByKey(entry, keyValue);
71
+ return entity;
72
+ }
73
+
74
+ /**
75
+ * Refreshes the canonical tracked instance from a locking query. Authorization
76
+ * and the following mutation must observe the row version that was actually
77
+ * locked, never an older identity-map snapshot.
78
+ */
79
+ trackReloaded(entity: object, model: EntityModel): object {
80
+ const keyValue = KeyTuple.fromEntity(model, entity as Record<string, unknown>);
81
+ const existing = !keyValue
82
+ ? undefined
83
+ : this.identityMap(model).get(keyValue.toString());
84
+ if (!existing) {
85
+ return this.trackLoaded(entity, model);
86
+ }
87
+ this.detectEntryChanges(existing);
88
+ if (existing.state !== EntityState.Unchanged) {
89
+ throw new OrmError(
90
+ `Cannot refresh locked entity "${model.name}" while it has pending tracked changes.`,
91
+ );
92
+ }
93
+ const source = entity as Record<string, unknown>;
94
+ const target = existing.entity as Record<string, unknown>;
95
+ for (const property of model.properties) {
96
+ target[property.propertyName] = source[property.propertyName];
97
+ }
98
+ this.applySnapshot(existing, this.snapshot(existing.entity, model));
99
+ existing.modifiedProperties = new Set();
100
+ return existing.entity;
101
+ }
102
+
103
+ add(entity: object, model: EntityModel): void {
104
+ // The Added key is not known yet (the database generates it); index it after save.
105
+ this.set(entity, model, EntityState.Added, undefined);
106
+ }
107
+
108
+ attach(entity: object, model: EntityModel): void {
109
+ this.set(entity, model, EntityState.Unchanged, this.snapshot(entity, model));
110
+ }
111
+
112
+ update(entity: object, model: EntityModel): void {
113
+ const entry = this.entries.get(entity) ?? this.set(entity, model, EntityState.Modified, this.snapshot(entity, model));
114
+ this.assertKeyUnchanged(entry);
115
+ entry.state = EntityState.Modified;
116
+ // Explicit Update without a source snapshot: treat all non-key columns as modified.
117
+ entry.modifiedProperties = new Set(
118
+ model.properties.filter((property) => !property.isKey).map((property) => property.propertyName),
119
+ );
120
+ this.explicitUpdateSets.add(entry.modifiedProperties);
121
+ }
122
+
123
+ remove(entity: object, model: EntityModel): void {
124
+ const existing = this.entries.get(entity);
125
+ // Removing a not yet saved (Added) entity just detaches it.
126
+ if (existing?.state === EntityState.Added) {
127
+ this.entries.delete(entity);
128
+ this.unindexByKey(existing);
129
+ return;
130
+ }
131
+ this.set(
132
+ entity,
133
+ model,
134
+ EntityState.Deleted,
135
+ existing?.snapshot
136
+ ? { values: existing.snapshot, jsonSignatures: existing.snapshotJsonSignatures ?? new Map() }
137
+ : this.snapshot(entity, model),
138
+ );
139
+ }
140
+
141
+ /**
142
+ * Compares the current values of tracked Unchanged/Modified entities with the
143
+ * snapshots and marks the changed properties. Called before SaveChanges.
144
+ */
145
+ detectChanges(): void {
146
+ for (const entry of this.entries.values()) {
147
+ this.detectEntryChanges(entry);
148
+ }
149
+ assertUniqueTrackedKeys(this);
150
+ }
151
+
152
+ private detectEntryChanges(entry: TrackedEntry): void {
153
+ if (entry.snapshot && entry.state !== EntityState.Added) {
154
+ this.assertKeyUnchanged(entry);
155
+ }
156
+ if (entry.state !== EntityState.Unchanged && entry.state !== EntityState.Modified) {
157
+ return;
158
+ }
159
+ const snapshot = entry.snapshot;
160
+ if (!snapshot) {
161
+ return;
162
+ }
163
+ const current = entry.entity as Record<string, unknown>;
164
+ const explicitUpdate = this.explicitUpdateSets.has(entry.modifiedProperties);
165
+ const modified = new Set<string>();
166
+ for (const property of entry.model.properties) {
167
+ if (property.isKey) {
168
+ continue;
169
+ }
170
+ const name = property.propertyName;
171
+ if (!valuesEqual(current[name], snapshot[name], property, entry.snapshotJsonSignatures?.get(name))) {
172
+ modified.add(name);
173
+ }
174
+ }
175
+ if (explicitUpdate) {
176
+ for (const property of entry.model.properties) if (!property.isKey) modified.add(property.propertyName);
177
+ }
178
+ entry.modifiedProperties = modified;
179
+ if (explicitUpdate) this.explicitUpdateSets.add(modified);
180
+ entry.state = modified.size > 0 ? EntityState.Modified : EntityState.Unchanged;
181
+ }
182
+
183
+ entriesToProcess(): TrackedEntry[] {
184
+ const pending: TrackedEntry[] = [];
185
+ for (const entry of this.entries.values()) {
186
+ if (entry.state === EntityState.Added || entry.state === EntityState.Modified || entry.state === EntityState.Deleted) {
187
+ pending.push(entry);
188
+ }
189
+ }
190
+ return pending;
191
+ }
192
+
193
+ stateOf(entity: object): EntityState {
194
+ return this.entries.get(entity)?.state ?? EntityState.Detached;
195
+ }
196
+
197
+ /** Returns the tracked (not deleted) entity by key, if any. */
198
+ tryGetByKey(model: EntityModel, key: unknown): object | undefined {
199
+ if (key === null || key === undefined) {
200
+ return undefined;
201
+ }
202
+ const entry = this.identityMap(model).get(KeyTuple.fromInput(model, key).toString());
203
+ return entry && entry.state !== EntityState.Deleted ? entry.entity : undefined;
204
+ }
205
+
206
+ /** Applies the result of a successful save: commits the new snapshot/state. */
207
+ acceptChanges(entry: TrackedEntry): void {
208
+ if (entry.state === EntityState.Deleted) {
209
+ this.entries.delete(entry.entity);
210
+ this.unindexByKey(entry);
211
+ return;
212
+ }
213
+ const key = KeyTuple.fromEntity(entry.model, entry.entity as Record<string, unknown>);
214
+ this.assertIdentityAvailable(entry.entity, entry.model, key);
215
+ const snapshot = this.snapshot(entry.entity, entry.model);
216
+ entry.state = EntityState.Unchanged;
217
+ this.applySnapshot(entry, snapshot);
218
+ entry.modifiedProperties = new Set();
219
+ // The Added entry got a generated key: index it for identity resolution.
220
+ this.indexByKey(entry, key);
221
+ }
222
+
223
+ /**
224
+ * Restores an Added entry whose database-generated key was assigned while a
225
+ * transaction was running and subsequently rolled back. This also repairs
226
+ * the identity map when SaveChanges had provisionally accepted the entry
227
+ * inside an ambient user transaction.
228
+ */
229
+ restoreAddedAfterRollback(entry: TrackedEntry, originalKey: unknown): void {
230
+ const entity = entry.entity as Record<string, unknown>;
231
+ const currentKey = KeyTuple.fromEntity(entry.model, entity);
232
+ if (currentKey) {
233
+ const identity = this.identityMap(entry.model);
234
+ if (identity.get(currentKey.toString()) === entry) {
235
+ identity.delete(currentKey.toString());
236
+ }
237
+ }
238
+ if (entry.model.key.length === 1) entity[entry.model.key[0].propertyName] = originalKey;
239
+ entry.state = EntityState.Added;
240
+ entry.snapshot = undefined;
241
+ entry.snapshotJsonSignatures = undefined;
242
+ entry.modifiedProperties = new Set();
243
+ this.entries.set(entry.entity, entry);
244
+ }
245
+
246
+ clear(): void {
247
+ this.entries.clear();
248
+ this.identity.clear();
249
+ }
250
+
251
+ private set(entity: object, model: EntityModel, state: EntityState, snapshot: SnapshotState | undefined): TrackedEntry {
252
+ // Generated Added keys are placeholders until INSERT ... RETURNING. Manual
253
+ // Added keys can still change before saving, but cannot replace a loaded row.
254
+ const key = state === EntityState.Added && hasGeneratedKey(model)
255
+ ? undefined : KeyTuple.fromEntity(model, entity as Record<string, unknown>);
256
+ this.assertIdentityAvailable(entity, model, key);
257
+ let entry = this.entries.get(entity);
258
+ if (entry) {
259
+ this.assertKeyUnchanged(entry);
260
+ this.unindexByKey(entry);
261
+ entry.state = state;
262
+ this.applySnapshot(entry, snapshot);
263
+ } else {
264
+ entry = { entity, model, state, modifiedProperties: new Set() };
265
+ this.applySnapshot(entry, snapshot);
266
+ this.entries.set(entity, entry);
267
+ }
268
+ // Index everything by key except Added (its key is not known yet).
269
+ if (state !== EntityState.Added) {
270
+ this.indexByKey(entry, key);
271
+ }
272
+ return entry;
273
+ }
274
+
275
+ private identityMap(model: EntityModel): Map<string, TrackedEntry> {
276
+ let map = this.identity.get(model);
277
+ if (!map) {
278
+ map = new Map();
279
+ this.identity.set(model, map);
280
+ }
281
+ return map;
282
+ }
283
+
284
+ private indexByKey(entry: TrackedEntry, keyValue: KeyTuple | undefined): void {
285
+ if (keyValue) {
286
+ this.assertIdentityAvailable(entry.entity, entry.model, keyValue);
287
+ this.identityMap(entry.model).set(keyValue.toString(), entry);
288
+ }
289
+ }
290
+
291
+ private assertIdentityAvailable(entity: object, model: EntityModel, key: KeyTuple | undefined): void {
292
+ if (!key) return;
293
+ const existing = this.identity.get(model)?.get(key.toString());
294
+ if (existing && existing.entity !== entity) throw duplicateIdentity(model);
295
+ const held = deletedIdentities.get(this)?.get(model)?.get(key.toString());
296
+ if (held && held.entity !== entity) throw duplicateIdentity(model);
297
+ }
298
+
299
+ private unindexByKey(entry: TrackedEntry): void {
300
+ const keyValue = KeyTuple.fromEntity(entry.model, entry.entity as Record<string, unknown>);
301
+ if (keyValue && this.identity.get(entry.model)?.get(keyValue.toString()) === entry) {
302
+ this.identityMap(entry.model).delete(keyValue.toString());
303
+ }
304
+ }
305
+
306
+ private applySnapshot(entry: TrackedEntry, snapshot: SnapshotState | undefined): void {
307
+ entry.snapshot = snapshot?.values;
308
+ entry.snapshotJsonSignatures = snapshot?.jsonSignatures;
309
+ }
310
+
311
+ private snapshot(entity: object, model: EntityModel): SnapshotState {
312
+ const source = entity as Record<string, unknown>;
313
+ const snapshot: Snapshot = {};
314
+ const jsonSignatures = new Map<string, string>();
315
+ for (const property of model.properties) {
316
+ const value = source[property.propertyName];
317
+ // json columns are mutable: clone the snapshot, otherwise an in-place mutation
318
+ // (entity.meta.x = 1) would make the snapshot equal to the current value and go undetected.
319
+ if (property.type === "json") {
320
+ const cloned = cloneJson(value);
321
+ snapshot[property.propertyName] = cloned;
322
+ jsonSignatures.set(property.propertyName, jsonSignature(cloned));
323
+ } else if ((property.type === "datetime" || property.isKey) && value instanceof Date) {
324
+ snapshot[property.propertyName] = new Date(value.getTime());
325
+ } else if (property.isKey && value instanceof Uint8Array) {
326
+ // KeyTuple compares byte content. Its snapshot must not retain mutable key bytes.
327
+ snapshot[property.propertyName] = new Uint8Array(value);
328
+ } else {
329
+ snapshot[property.propertyName] = value;
330
+ }
331
+ }
332
+ return { values: snapshot, jsonSignatures };
333
+ }
334
+
335
+ private assertKeyUnchanged(entry: TrackedEntry): void {
336
+ if (!entry.snapshot || entry.state === EntityState.Added) return;
337
+ const original = KeyTuple.fromEntity(entry.model, entry.snapshot);
338
+ const current = KeyTuple.fromEntity(entry.model, entry.entity as Record<string, unknown>);
339
+ if (!original || !current || !original.equals(current)) {
340
+ throw new DbUpdateError(`Primary key for tracked entity "${entry.model.name}" cannot be changed.`);
341
+ }
342
+ }
343
+ }
344
+
345
+ /** Non-barrel helper used only by immediate DML admission. */
346
+ export function hasTrackedEntriesForModel(tracker: ChangeTracker, model: EntityModel): boolean {
347
+ return [...(trackerEntries.get(tracker)?.values() ?? [])].some((entry) => entry.model === model);
348
+ }
349
+
350
+ const trackerEntries = new WeakMap<ChangeTracker, Map<object, TrackedEntry>>();
351
+ const deletedIdentities = new WeakMap<ChangeTracker, Map<EntityModel, Map<string, { entity: object; count: number }>>>();
352
+
353
+ /** Non-barrel rollback ownership: a provisionally deleted row can still be
354
+ * restored by its transaction. Keep its canonical identity until that outcome. */
355
+ export function holdDeletedIdentity(tracker: ChangeTracker, entry: TrackedEntry): () => void {
356
+ if (entry.state !== EntityState.Deleted) return () => {};
357
+ const key = KeyTuple.fromEntity(entry.model, entry.entity as Record<string, unknown>)?.toString();
358
+ if (key === undefined) return () => {};
359
+ let models = deletedIdentities.get(tracker);
360
+ if (!models) { models = new Map(); deletedIdentities.set(tracker, models); }
361
+ let keys = models.get(entry.model);
362
+ if (!keys) { keys = new Map(); models.set(entry.model, keys); }
363
+ const held = keys.get(key) ?? { entity: entry.entity, count: 0 };
364
+ held.count++;
365
+ keys.set(key, held);
366
+ let released = false;
367
+ return () => {
368
+ if (released) return;
369
+ released = true;
370
+ if (--held.count === 0) keys!.delete(key);
371
+ if (keys!.size === 0) models!.delete(entry.model);
372
+ if (models!.size === 0) deletedIdentities.delete(tracker);
373
+ };
374
+ }
375
+
376
+ /** Non-barrel save preflight. Added keys remain mutable until save; generated
377
+ * placeholders are excluded until the caller has collected every RETURNING row.
378
+ * Validate the whole batch before accepting any entry or committing the SQL. */
379
+ export function assertUniqueTrackedKeys(tracker: ChangeTracker, generated: readonly TrackedEntry[] = []): void {
380
+ const returned = new Set(generated);
381
+ const identities = new Map<EntityModel, Map<string, object>>();
382
+ for (const [model, held] of deletedIdentities.get(tracker) ?? []) {
383
+ identities.set(model, new Map([...held].map(([key, value]) => [key, value.entity])));
384
+ }
385
+ for (const entry of trackerEntries.get(tracker)?.values() ?? []) {
386
+ if (entry.state === EntityState.Added && hasGeneratedKey(entry.model) && !returned.has(entry)) continue;
387
+ // The ORM assigns an unset UUID v7 key during save; the preflight after that checks the real value.
388
+ if (entry.state === EntityState.Added && hasUnassignedUuidV7Key(entry)) continue;
389
+ const key = KeyTuple.fromEntity(entry.model, entry.entity as Record<string, unknown>)?.toString();
390
+ if (key === undefined) continue;
391
+ let modelKeys = identities.get(entry.model);
392
+ if (!modelKeys) { modelKeys = new Map(); identities.set(entry.model, modelKeys); }
393
+ const existing = modelKeys.get(key);
394
+ if (existing && existing !== entry.entity) throw duplicateIdentity(entry.model);
395
+ modelKeys.set(key, entry.entity);
396
+ }
397
+ }
398
+
399
+ function hasGeneratedKey(model: EntityModel): boolean {
400
+ return model.key.length === 1 && isDatabaseGenerated(model.key[0].generation);
401
+ }
402
+
403
+ function hasUnassignedUuidV7Key(entry: TrackedEntry): boolean {
404
+ const key = entry.model.key;
405
+ if (key.length !== 1 || key[0].generation !== "uuidV7") return false;
406
+ const value = (entry.entity as Record<string, unknown>)[key[0].propertyName];
407
+ return value === undefined || value === null || value === "";
408
+ }
409
+
410
+ function duplicateIdentity(model: EntityModel): DbUpdateError {
411
+ return new DbUpdateError(`Another instance of entity "${model.name}" with the same primary key is already tracked.`);
412
+ }
413
+
414
+ /** Compares a property value with the snapshot (structurally for json). */
415
+ function valuesEqual(current: unknown, snapshot: unknown, property: PropertyModel, snapshotJsonSignature?: string): boolean {
416
+ if (property.type === "json") {
417
+ return jsonEqual(current, snapshot, snapshotJsonSignature);
418
+ }
419
+ if (property.type === "datetime" && current instanceof Date && snapshot instanceof Date) {
420
+ return Object.is(current.getTime(), snapshot.getTime());
421
+ }
422
+ return Object.is(current, snapshot);
423
+ }
424
+
425
+ function cloneJson(value: unknown): unknown {
426
+ if (value === null || value === undefined || typeof value !== "object") {
427
+ return value;
428
+ }
429
+ try {
430
+ return structuredClone(value);
431
+ } catch {
432
+ return JSON.parse(JSON.stringify(value));
433
+ }
434
+ }
435
+
436
+ function jsonEqual(a: unknown, b: unknown, snapshotSignature?: string): boolean {
437
+ if (a === b) {
438
+ return true;
439
+ }
440
+ if (snapshotSignature !== undefined) {
441
+ return jsonSignature(a) === snapshotSignature;
442
+ }
443
+ return jsonSignature(a) === jsonSignature(b);
444
+ }
445
+
446
+ function jsonSignature(value: unknown): string {
447
+ return JSON.stringify(value ?? null);
448
+ }
@@ -0,0 +1,13 @@
1
+ /** Entity state in the tracker (as in EF Core). */
2
+ export enum EntityState {
3
+ /** Not tracked. */
4
+ Detached = "Detached",
5
+ /** Loaded/attached, no changes. */
6
+ Unchanged = "Unchanged",
7
+ /** New, will be inserted. */
8
+ Added = "Added",
9
+ /** Changed, will be updated. */
10
+ Modified = "Modified",
11
+ /** Will be deleted. */
12
+ Deleted = "Deleted",
13
+ }
@@ -0,0 +1,30 @@
1
+ import type { DbContext } from "../DbContext";
2
+
3
+ /** A database wall-clock value obtained from the active database session. */
4
+ export interface OrmDatabaseTimeV1 {
5
+ readonly instant: Date;
6
+ readonly epochMilliseconds: number;
7
+ readonly precision: "millisecond";
8
+ }
9
+
10
+ /** Bounded scope work, including reservation admission and physical COMMIT.
11
+ * Cancellation cleanup has the provider's separate finite budget. A COMMIT
12
+ * without acknowledgement reports an unknown outcome; afterCommit is user
13
+ * work after a confirmed commit and is not undone by a late abort. */
14
+ export interface OrmTransactionScopeOptions {
15
+ readonly signal?: AbortSignal;
16
+ /** Total work budget in milliseconds, including admission and COMMIT; positive integer. */
17
+ readonly timeoutMs?: number;
18
+ }
19
+
20
+ /** Opaque transaction capability. It deliberately exposes no executor or completion authority. */
21
+ export abstract class OrmTransaction {
22
+ abstract use<TContext extends DbContext, TResult>(
23
+ context: TContext,
24
+ work: (context: TContext) => Promise<TResult>,
25
+ ): Promise<TResult>;
26
+
27
+ abstract databaseTime(): Promise<OrmDatabaseTimeV1>;
28
+
29
+ abstract afterCommit(callback: () => void | Promise<void>): void;
30
+ }