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,183 @@
1
+ import { rulesOf } from "./metadata";
2
+ import type { ValidatorOptions } from "./types/ValidatorOptions";
3
+
4
+ /**
5
+ * Nested validation mode for a specific rule:
6
+ * - `explicit`: `nested: true`, recursion even without auto-detection;
7
+ * - `auto`: recursion if the value is an instance of a decorated class;
8
+ * - `none`: this rule does not run nested validation.
9
+ *
10
+ * On a field with several decorators exactly one rule is assigned to carry the
11
+ * nested check; otherwise the nested object's errors would be duplicated.
12
+ */
13
+ export type NestedMode = "explicit" | "auto" | "none";
14
+
15
+ /**
16
+ * Compiled rule of one decorator: everything expensive (RegExp compilation,
17
+ * collecting enum values into a Set) is done in advance, so only the checks
18
+ * remain on the hot validation path.
19
+ */
20
+ export interface CompiledRule {
21
+ readonly property: string;
22
+ readonly options: ValidatorOptions;
23
+ /** Whether this rule runs nested validation and in which mode. */
24
+ nested: NestedMode;
25
+ /** Precompiled `pattern` (from a RegExp or a source string). */
26
+ readonly pattern?: RegExp;
27
+ /** Allowed enum values (O(1) membership check). */
28
+ readonly enumValues?: ReadonlySet<unknown>;
29
+ /** Human-readable list of enum values for the `{allowed}` message. */
30
+ readonly enumLabel?: string;
31
+ /** There are string rules: the value must be a string. */
32
+ readonly needsString: boolean;
33
+ /** There are number rules: the value must be a number. */
34
+ readonly needsNumber: boolean;
35
+ /** There are boolean rules: the value must be a boolean. */
36
+ readonly needsBoolean: boolean;
37
+ /** Flag checks, taking the `type` hint into account (type: "email" === email: true). */
38
+ readonly checkEmail: boolean;
39
+ readonly checkUrl: boolean;
40
+ readonly checkUuid: boolean;
41
+ readonly checkJson: boolean;
42
+ readonly checkPhone: boolean;
43
+ readonly checkDate: boolean;
44
+ }
45
+
46
+ /**
47
+ * Compiles and caches the validation plan of a class.
48
+ *
49
+ * The cache is a WeakMap by constructor: rules are collected on the first access
50
+ * to the class and reused by all later `validate` calls. The WeakMap does not
51
+ * keep classes from being garbage collected.
52
+ */
53
+ export class RuleCompiler {
54
+ private static readonly cache = new WeakMap<object, readonly CompiledRule[]>();
55
+
56
+ /**
57
+ * Validation plan for a constructor, or `undefined` if the class (and its
58
+ * parents) has no `@Validator` decorators.
59
+ */
60
+ static planFor(ctor: object | undefined | null): readonly CompiledRule[] | undefined {
61
+ if (typeof ctor !== "function") {
62
+ return undefined;
63
+ }
64
+ const cached = RuleCompiler.cache.get(ctor);
65
+ if (cached) {
66
+ return cached;
67
+ }
68
+ const rules = rulesOf(ctor);
69
+ if (!rules) {
70
+ return undefined;
71
+ }
72
+ const plan = rules.map((rule) => RuleCompiler.compile(rule.property, rule.options));
73
+ RuleCompiler.assignNestedCarriers(plan);
74
+ RuleCompiler.cache.set(ctor, plan);
75
+ return plan;
76
+ }
77
+
78
+ /**
79
+ * Picks the single nested-validation carrier rule for each field: an explicit
80
+ * `nested: true` wins over auto-detection; if any decorator of the field set
81
+ * `nested: false` and there is no explicit `true`, nested checking is turned
82
+ * off for the field entirely.
83
+ */
84
+ private static assignNestedCarriers(plan: CompiledRule[]): void {
85
+ const carrierByProperty = new Map<string, CompiledRule>();
86
+ const disabledProperties = new Set<string>();
87
+ for (const rule of plan) {
88
+ const declared = rule.options.nested;
89
+ if (declared === false) {
90
+ disabledProperties.add(rule.property);
91
+ continue;
92
+ }
93
+ const current = carrierByProperty.get(rule.property);
94
+ if (!current || (declared === true && current.options.nested !== true)) {
95
+ carrierByProperty.set(rule.property, rule);
96
+ }
97
+ }
98
+ for (const [property, carrier] of carrierByProperty) {
99
+ if (carrier.options.nested === true) {
100
+ carrier.nested = "explicit";
101
+ } else if (!disabledProperties.has(property)) {
102
+ carrier.nested = "auto";
103
+ }
104
+ }
105
+ }
106
+
107
+ private static compile(property: string, o: ValidatorOptions): CompiledRule {
108
+ const checkEmail = o.email === true || o.type === "email";
109
+ const checkUrl = o.url === true;
110
+ const checkUuid = o.uuid === true;
111
+ const checkJson = o.json === true || o.type === "json";
112
+ const checkPhone = o.phone === true || o.type === "phone";
113
+ const checkDate = o.type === "date";
114
+
115
+ const needsString =
116
+ o.type === "string" ||
117
+ o.notEmpty === true ||
118
+ o.minLength !== undefined ||
119
+ o.maxLength !== undefined ||
120
+ o.length !== undefined ||
121
+ o.contains !== undefined ||
122
+ o.notContains !== undefined ||
123
+ o.pattern !== undefined ||
124
+ checkEmail ||
125
+ checkUrl ||
126
+ checkUuid ||
127
+ checkJson ||
128
+ checkPhone;
129
+
130
+ const needsNumber =
131
+ o.type === "number" ||
132
+ o.min !== undefined ||
133
+ o.max !== undefined ||
134
+ o.range !== undefined ||
135
+ o.positive === true ||
136
+ o.negative === true ||
137
+ o.integer === true;
138
+
139
+ const needsBoolean = o.type === "boolean" || o.mustBeTrue === true || o.mustBeFalse === true;
140
+
141
+ // A source string is compiled here once; it is the regular RegExp
142
+ // constructor, with no eval or dynamic code compilation.
143
+ const pattern = o.pattern === undefined ? undefined : o.pattern instanceof RegExp ? o.pattern : new RegExp(o.pattern);
144
+
145
+ let enumValues: ReadonlySet<unknown> | undefined;
146
+ let enumLabel: string | undefined;
147
+ if (o.enumType !== undefined) {
148
+ const values = new Set<unknown>();
149
+ for (const key of Object.keys(o.enumType)) {
150
+ // hasOwnProperty: protection against prototype pollution in the given object.
151
+ if (!Object.prototype.hasOwnProperty.call(o.enumType, key)) {
152
+ continue;
153
+ }
154
+ // TypeScript numeric enums contain reverse keys ("0" -> "Admin");
155
+ // skip them, otherwise the value names would become allowed values.
156
+ if (/^\d+$/.test(key)) {
157
+ continue;
158
+ }
159
+ values.add(o.enumType[key]);
160
+ }
161
+ enumValues = values;
162
+ enumLabel = [...values].join(", ");
163
+ }
164
+
165
+ return {
166
+ property,
167
+ options: o,
168
+ nested: "none",
169
+ pattern,
170
+ enumValues,
171
+ enumLabel,
172
+ needsString,
173
+ needsNumber,
174
+ needsBoolean,
175
+ checkEmail,
176
+ checkUrl,
177
+ checkUuid,
178
+ checkJson,
179
+ checkPhone,
180
+ checkDate,
181
+ };
182
+ }
183
+ }
@@ -0,0 +1,401 @@
1
+ import { MessageRegistry } from "./MessageRegistry";
2
+ import { RuleCompiler, type CompiledRule } from "./RuleCompiler";
3
+ import { ValidationError } from "./ValidationError";
4
+ import { ValidationResult } from "./ValidationResult";
5
+ import { hasRules } from "./metadata";
6
+ import { ValidationCodes } from "./types/ValidationCode";
7
+ import type { CustomOutcome, ValidatorOptions } from "./types/ValidatorOptions";
8
+
9
+ /** Email is checked with linear passes; whitespace is forbidden in both parts. */
10
+ const EMAIL_WHITESPACE_PATTERN = /\s/;
11
+
12
+ /**
13
+ * UUID versions 1–8 (including v4 from `crypto.randomUUID()` and v7 from
14
+ * `Bun.randomUUIDv7()`) with a correct variant, plus the nil UUID.
15
+ * Character classes only, no backtracking.
16
+ */
17
+ const UUID_PATTERN =
18
+ /^(?:[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}|00000000-0000-0000-0000-000000000000)$/i;
19
+
20
+ /** Phone number after normalization: an optional `+` and 7–15 digits. */
21
+ const PHONE_PATTERN = /^\+?\d{7,15}$/;
22
+
23
+ /** Characters dropped when normalizing a phone number: spaces, hyphens, parentheses. */
24
+ const PHONE_NOISE = /[\s\-()]/g;
25
+
26
+ /** Deferred async check (a custom function that needs await). */
27
+ type AsyncJob = () => Promise<void>;
28
+
29
+ /**
30
+ * Validation engine: one pass over the compiled plan of a class.
31
+ *
32
+ * Principles:
33
+ * - errors are collected into one array; string content checks are skipped
34
+ * when the value exceeds the upper length bound of the same decorator;
35
+ * - the hot path (a valid object) barely allocates: the plan is cached, and
36
+ * message parameter objects are created only on error;
37
+ * - exceptions from user functions (`custom`, `validateIf`) are caught and
38
+ * turned into an error with the `customError` code; validation continues;
39
+ * - nested objects are checked recursively with protection against circular references.
40
+ */
41
+ export class RuleEngine {
42
+ /**
43
+ * Synchronous validation. If a field has an async `custom` function
44
+ * (it returned a Promise), an `asyncCustomInSyncCall` error is added.
45
+ */
46
+ static validate(instance: object): ValidationResult {
47
+ const errors: ValidationError[] = [];
48
+ RuleEngine.collect(instance, "", errors, undefined, undefined);
49
+ return new ValidationResult(errors);
50
+ }
51
+
52
+ /**
53
+ * Asynchronous validation: all synchronous rules run immediately, async
54
+ * `custom` functions run sequentially after them (deterministic error order).
55
+ */
56
+ static async validateAsync(instance: object): Promise<ValidationResult> {
57
+ const errors: ValidationError[] = [];
58
+ const jobs: AsyncJob[] = [];
59
+ RuleEngine.collect(instance, "", errors, jobs, undefined);
60
+ for (const job of jobs) {
61
+ await job();
62
+ }
63
+ return new ValidationResult(errors);
64
+ }
65
+
66
+ /** Runs the plan of the instance's class; without decorators it silently returns. */
67
+ private static collect(
68
+ instance: object,
69
+ prefix: string,
70
+ errors: ValidationError[],
71
+ jobs: AsyncJob[] | undefined,
72
+ seen: Set<object> | undefined,
73
+ ): void {
74
+ const plan = RuleCompiler.planFor(instance.constructor);
75
+ if (!plan) {
76
+ return;
77
+ }
78
+ for (const rule of plan) {
79
+ RuleEngine.applyRule(rule, instance, prefix, errors, jobs, seen);
80
+ }
81
+ }
82
+
83
+ private static applyRule(
84
+ rule: CompiledRule,
85
+ instance: object,
86
+ prefix: string,
87
+ errors: ValidationError[],
88
+ jobs: AsyncJob[] | undefined,
89
+ seen: Set<object> | undefined,
90
+ ): void {
91
+ const o = rule.options;
92
+ const path = prefix === "" ? rule.property : `${prefix}.${rule.property}`;
93
+
94
+ // 1. Conditional validation: false -> the whole decorator is skipped.
95
+ if (o.validateIf !== undefined) {
96
+ try {
97
+ if (!(o.validateIf as (instance: unknown) => boolean)(instance)) {
98
+ return;
99
+ }
100
+ } catch (error) {
101
+ RuleEngine.fail(errors, ValidationCodes.customError, path, undefined, o, { error: RuleEngine.describeError(error) });
102
+ return;
103
+ }
104
+ }
105
+
106
+ const value = (instance as Record<string, unknown>)[rule.property];
107
+
108
+ // 2. Missing value: an error only with required, otherwise the field is optional.
109
+ if (value === undefined || value === null) {
110
+ if (o.required === true) {
111
+ RuleEngine.fail(errors, ValidationCodes.required, path, value, o, undefined);
112
+ }
113
+ return;
114
+ }
115
+
116
+ // 3. String rules: first one type check, then the rules themselves.
117
+ if (rule.needsString) {
118
+ if (typeof value !== "string") {
119
+ RuleEngine.failType(errors, path, value, o, "string");
120
+ return;
121
+ }
122
+ RuleEngine.applyStringRules(rule, value, path, errors);
123
+ }
124
+
125
+ // 4. Number rules.
126
+ if (rule.needsNumber) {
127
+ if (typeof value !== "number" || Number.isNaN(value)) {
128
+ RuleEngine.failType(errors, path, value, o, "number");
129
+ return;
130
+ }
131
+ RuleEngine.applyNumberRules(o, value, path, errors);
132
+ }
133
+
134
+ // 5. Boolean rules.
135
+ if (rule.needsBoolean) {
136
+ if (typeof value !== "boolean") {
137
+ RuleEngine.failType(errors, path, value, o, "boolean");
138
+ return;
139
+ }
140
+ if (o.mustBeTrue === true && value !== true) {
141
+ RuleEngine.fail(errors, ValidationCodes.mustBeTrue, path, value, o, undefined);
142
+ }
143
+ if (o.mustBeFalse === true && value !== false) {
144
+ RuleEngine.fail(errors, ValidationCodes.mustBeFalse, path, value, o, undefined);
145
+ }
146
+ }
147
+
148
+ // 6. Enum: membership in a precomputed Set (O(1)).
149
+ if (rule.enumValues !== undefined && !rule.enumValues.has(value)) {
150
+ RuleEngine.fail(errors, ValidationCodes.enum, path, value, o, { allowed: rule.enumLabel });
151
+ }
152
+
153
+ // 7. Date (the type: "date" hint).
154
+ if (rule.checkDate && !RuleEngine.isValidDate(value)) {
155
+ RuleEngine.fail(errors, ValidationCodes.date, path, value, o, undefined);
156
+ }
157
+
158
+ // 8. Custom check.
159
+ if (o.custom !== undefined) {
160
+ RuleEngine.applyCustom(o, value, instance, path, errors, jobs);
161
+ }
162
+
163
+ // 9. Nested validation: only the carrier rule (see RuleCompiler),
164
+ // so several decorators on a field do not duplicate errors.
165
+ if (rule.nested !== "none") {
166
+ RuleEngine.applyNested(rule.nested === "explicit", value, instance, path, errors, jobs, seen);
167
+ }
168
+ }
169
+
170
+ private static applyStringRules(rule: CompiledRule, value: string, path: string, errors: ValidationError[]): void {
171
+ const o = rule.options;
172
+ if (o.notEmpty === true && value.length === 0) {
173
+ RuleEngine.fail(errors, ValidationCodes.notEmpty, path, value, o, undefined);
174
+ }
175
+ if (o.minLength !== undefined && value.length < o.minLength) {
176
+ RuleEngine.fail(errors, ValidationCodes.minLength, path, value, o, { min: o.minLength });
177
+ }
178
+ const exceedsMaxLength = o.maxLength !== undefined && value.length > o.maxLength;
179
+ if (exceedsMaxLength) {
180
+ RuleEngine.fail(errors, ValidationCodes.maxLength, path, value, o, { max: o.maxLength });
181
+ }
182
+ const exceedsLengthRange = o.length !== undefined && value.length > o.length[1];
183
+ if (o.length !== undefined && (value.length < o.length[0] || value.length > o.length[1])) {
184
+ RuleEngine.fail(errors, ValidationCodes.length, path, value, o, { min: o.length[0], max: o.length[1] });
185
+ }
186
+ // The upper bound limits the input of RegExp/parsers. Other fields, decorators
187
+ // and custom checks still run and collect their errors in order.
188
+ if (exceedsMaxLength || exceedsLengthRange) {
189
+ return;
190
+ }
191
+ if (o.contains !== undefined && !value.includes(o.contains)) {
192
+ RuleEngine.fail(errors, ValidationCodes.contains, path, value, o, { contains: o.contains });
193
+ }
194
+ if (o.notContains !== undefined && value.includes(o.notContains)) {
195
+ RuleEngine.fail(errors, ValidationCodes.notContains, path, value, o, { contains: o.notContains });
196
+ }
197
+ if (rule.pattern !== undefined && !rule.pattern.test(value)) {
198
+ RuleEngine.fail(errors, ValidationCodes.pattern, path, value, o, { pattern: rule.pattern.source });
199
+ }
200
+ if (rule.checkEmail && !RuleEngine.isEmail(value)) {
201
+ RuleEngine.fail(errors, ValidationCodes.email, path, value, o, undefined);
202
+ }
203
+ if (rule.checkUrl && !URL.canParse(value)) {
204
+ RuleEngine.fail(errors, ValidationCodes.url, path, value, o, undefined);
205
+ }
206
+ if (rule.checkUuid && !UUID_PATTERN.test(value)) {
207
+ RuleEngine.fail(errors, ValidationCodes.uuid, path, value, o, undefined);
208
+ }
209
+ if (rule.checkJson && !RuleEngine.isJson(value)) {
210
+ RuleEngine.fail(errors, ValidationCodes.json, path, value, o, undefined);
211
+ }
212
+ if (rule.checkPhone && !PHONE_PATTERN.test(value.replace(PHONE_NOISE, ""))) {
213
+ RuleEngine.fail(errors, ValidationCodes.phone, path, value, o, undefined);
214
+ }
215
+ }
216
+
217
+ private static applyNumberRules(o: ValidatorOptions, value: number, path: string, errors: ValidationError[]): void {
218
+ if (o.min !== undefined && value < o.min) {
219
+ RuleEngine.fail(errors, ValidationCodes.min, path, value, o, { min: o.min });
220
+ }
221
+ if (o.max !== undefined && value > o.max) {
222
+ RuleEngine.fail(errors, ValidationCodes.max, path, value, o, { max: o.max });
223
+ }
224
+ if (o.range !== undefined && (value < o.range[0] || value > o.range[1])) {
225
+ RuleEngine.fail(errors, ValidationCodes.range, path, value, o, { min: o.range[0], max: o.range[1] });
226
+ }
227
+ if (o.positive === true && value <= 0) {
228
+ RuleEngine.fail(errors, ValidationCodes.positive, path, value, o, undefined);
229
+ }
230
+ if (o.negative === true && value >= 0) {
231
+ RuleEngine.fail(errors, ValidationCodes.negative, path, value, o, undefined);
232
+ }
233
+ if (o.integer === true && !Number.isInteger(value)) {
234
+ RuleEngine.fail(errors, ValidationCodes.integer, path, value, o, undefined);
235
+ }
236
+ }
237
+
238
+ /**
239
+ * Custom check. In synchronous mode a Promise is an `asyncCustomInSyncCall`
240
+ * error; in asynchronous mode the check is queued.
241
+ */
242
+ private static applyCustom(
243
+ o: ValidatorOptions,
244
+ value: unknown,
245
+ instance: object,
246
+ path: string,
247
+ errors: ValidationError[],
248
+ jobs: AsyncJob[] | undefined,
249
+ ): void {
250
+ const custom = o.custom!;
251
+ if (jobs !== undefined) {
252
+ jobs.push(async () => {
253
+ try {
254
+ RuleEngine.handleCustomOutcome(await custom(value, instance), o, value, path, errors);
255
+ } catch (error) {
256
+ RuleEngine.fail(errors, ValidationCodes.customError, path, value, o, { error: RuleEngine.describeError(error) });
257
+ }
258
+ });
259
+ return;
260
+ }
261
+ try {
262
+ const outcome = custom(value, instance);
263
+ if (outcome instanceof Promise) {
264
+ // A pending Promise cannot be awaited synchronously; silently treating
265
+ // the field as valid would be unsafe, so record a usage error.
266
+ outcome.catch(() => {});
267
+ RuleEngine.fail(errors, ValidationCodes.asyncCustomInSyncCall, path, value, o, undefined);
268
+ return;
269
+ }
270
+ RuleEngine.handleCustomOutcome(outcome, o, value, path, errors);
271
+ } catch (error) {
272
+ RuleEngine.fail(errors, ValidationCodes.customError, path, value, o, { error: RuleEngine.describeError(error) });
273
+ }
274
+ }
275
+
276
+ private static handleCustomOutcome(
277
+ outcome: CustomOutcome,
278
+ o: ValidatorOptions,
279
+ value: unknown,
280
+ path: string,
281
+ errors: ValidationError[],
282
+ ): void {
283
+ if (outcome === true || outcome === undefined) {
284
+ return;
285
+ }
286
+ if (outcome instanceof ValidationError) {
287
+ errors.push(outcome);
288
+ return;
289
+ }
290
+ if (typeof outcome === "string") {
291
+ // A returned string is the most local message and wins over message.
292
+ errors.push(new ValidationError(path, value, MessageRegistry.format(ValidationCodes.custom, outcome, { property: path, value }), ValidationCodes.custom));
293
+ return;
294
+ }
295
+ RuleEngine.fail(errors, ValidationCodes.custom, path, value, o, undefined);
296
+ }
297
+
298
+ /**
299
+ * Nested validation. Enabled by an explicit `nested: true` or automatically
300
+ * when the value (or an array element) is an instance of a decorated class.
301
+ * Cycle protection: objects already visited in the chain are skipped.
302
+ */
303
+ private static applyNested(
304
+ explicit: boolean,
305
+ value: unknown,
306
+ instance: object,
307
+ path: string,
308
+ errors: ValidationError[],
309
+ jobs: AsyncJob[] | undefined,
310
+ seen: Set<object> | undefined,
311
+ ): void {
312
+ if (Array.isArray(value)) {
313
+ for (let index = 0; index < value.length; index += 1) {
314
+ const item: unknown = value[index];
315
+ if (item !== null && typeof item === "object" && (explicit || hasRules(item))) {
316
+ RuleEngine.nest(item as object, `${path}[${index}]`, instance, errors, jobs, seen);
317
+ }
318
+ }
319
+ return;
320
+ }
321
+ if (value !== null && typeof value === "object" && (explicit || hasRules(value))) {
322
+ RuleEngine.nest(value as object, path, instance, errors, jobs, seen);
323
+ }
324
+ }
325
+
326
+ private static nest(
327
+ child: object,
328
+ path: string,
329
+ parent: object,
330
+ errors: ValidationError[],
331
+ jobs: AsyncJob[] | undefined,
332
+ seen: Set<object> | undefined,
333
+ ): void {
334
+ // The Set is created lazily, only when nesting actually occurs.
335
+ const visited = seen ?? new Set<object>([parent]);
336
+ if (visited.has(child)) {
337
+ return;
338
+ }
339
+ visited.add(child);
340
+ RuleEngine.collect(child, path, errors, jobs, visited);
341
+ }
342
+
343
+ // ── Helpers ───────────────────────────────────────────────────────────────
344
+
345
+ /** Creates a ValidationError with the message by priority local > global > built-in. */
346
+ private static fail(
347
+ errors: ValidationError[],
348
+ code: string,
349
+ path: string,
350
+ value: unknown,
351
+ o: ValidatorOptions,
352
+ extra: Record<string, unknown> | undefined,
353
+ ): void {
354
+ const params: Record<string, unknown> = { property: path, value };
355
+ if (extra !== undefined) {
356
+ for (const key of Object.keys(extra)) {
357
+ params[key] = extra[key];
358
+ }
359
+ }
360
+ errors.push(new ValidationError(path, value, MessageRegistry.format(code, o.message, params), code));
361
+ }
362
+
363
+ private static failType(errors: ValidationError[], path: string, value: unknown, o: ValidatorOptions, expected: string): void {
364
+ const actual = typeof value === "number" && Number.isNaN(value) ? "NaN" : value === null ? "null" : typeof value;
365
+ RuleEngine.fail(errors, ValidationCodes.type, path, value, o, { expected, actual });
366
+ }
367
+
368
+ private static isJson(value: string): boolean {
369
+ try {
370
+ JSON.parse(value);
371
+ return true;
372
+ } catch {
373
+ return false;
374
+ }
375
+ }
376
+
377
+ private static isEmail(value: string): boolean {
378
+ const at = value.indexOf("@");
379
+ if (at <= 0 || at !== value.lastIndexOf("@") || EMAIL_WHITESPACE_PATTERN.test(value)) {
380
+ return false;
381
+ }
382
+ // Grammar: at least one character before and after the dot that separates
383
+ // the domain; extra dots are allowed.
384
+ const dot = value.indexOf(".", at + 2);
385
+ return dot !== -1 && dot < value.length - 1;
386
+ }
387
+
388
+ private static isValidDate(value: unknown): boolean {
389
+ if (value instanceof Date) {
390
+ return !Number.isNaN(value.getTime());
391
+ }
392
+ if (typeof value === "string" || typeof value === "number") {
393
+ return !Number.isNaN(new Date(value).getTime());
394
+ }
395
+ return false;
396
+ }
397
+
398
+ private static describeError(error: unknown): string {
399
+ return error instanceof Error ? error.message : String(error);
400
+ }
401
+ }