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 path from "node:path";
2
+ import { copyFile, lstat, mkdir, mkdtemp, readFile, readdir, realpath, rename, rm, writeFile } from "node:fs/promises";
3
+ import { parseModuleName } from "./naming";
4
+
5
+ export interface GenerateProjectOptions {
6
+ readonly name: string;
7
+ /** Exact destination directory; defaults to ./<kebab-name>. */
8
+ readonly outputPath?: string;
9
+ /** Local Bazis package source; defaults to this checkout's src/bazis. */
10
+ readonly frameworkPath?: string;
11
+ /** Opt into a live link to the source checkout instead of a portable snapshot. */
12
+ readonly linkFramework?: boolean;
13
+ readonly dryRun?: boolean;
14
+ }
15
+
16
+ export interface GenerateProjectResult {
17
+ readonly projectDir: string;
18
+ /** Application scaffold files; framework sources are summarized separately. */
19
+ readonly files: readonly string[];
20
+ readonly dryRun: boolean;
21
+ readonly frameworkMode: "snapshot" | "link";
22
+ readonly frameworkFileCount: number;
23
+ }
24
+
25
+ /** Create a separate application without mutating the framework checkout. */
26
+ export async function generateProject(options: GenerateProjectOptions): Promise<GenerateProjectResult> {
27
+ const name = parseModuleName(options.name).folder;
28
+ const requested = path.resolve(options.outputPath ?? name);
29
+ const parent = await realpath(path.dirname(requested)).catch((error: NodeJS.ErrnoException) => {
30
+ if (error.code === "ENOENT") throw new Error(`Parent directory does not exist: ${path.dirname(requested)}. Create it first or choose another --path.`);
31
+ throw error;
32
+ });
33
+ const parentInfo = await lstat(parent);
34
+ if (!parentInfo.isDirectory()) throw new Error(`Project parent is not a directory: ${parent}`);
35
+ const projectDir = path.join(parent, path.basename(requested));
36
+ if (await exists(projectDir)) throw new Error(`Project path already exists: ${projectDir}`);
37
+
38
+ const frameworkDir = await resolveFramework(options.frameworkPath);
39
+ if (projectDir.startsWith(`${frameworkDir}${path.sep}`)) {
40
+ throw new Error("Project directory must be outside the Bazis package.");
41
+ }
42
+ const dependencyPath = path.relative(projectDir, frameworkDir).replaceAll("\\", "/");
43
+ const frameworkMode = options.linkFramework ? "link" : "snapshot";
44
+ const frameworkFiles = options.linkFramework ? [] : await collectFrameworkFiles(frameworkDir);
45
+ const dependency = options.linkFramework
46
+ ? `file:${dependencyPath.startsWith(".") ? dependencyPath : `./${dependencyPath}`}`
47
+ : "file:./vendor/bazis";
48
+ const files = buildProjectFiles(name, dependency, frameworkMode);
49
+ if (!options.dryRun) {
50
+ const staged = await mkdtemp(path.join(parent, `.${name}.bazis-`));
51
+ try {
52
+ for (const [relative, content] of files) {
53
+ const output = path.join(staged, relative);
54
+ await mkdir(path.dirname(output), { recursive: true });
55
+ await writeFile(output, content, { encoding: "utf8", flag: "wx" });
56
+ }
57
+ for (const relative of frameworkFiles) {
58
+ const output = path.join(staged, "vendor/bazis", relative);
59
+ await mkdir(path.dirname(output), { recursive: true });
60
+ await copyFile(path.join(frameworkDir, relative), output);
61
+ }
62
+ if (await exists(projectDir)) throw new Error(`Project path appeared during generation: ${projectDir}`);
63
+ await rename(staged, projectDir);
64
+ } catch (error) {
65
+ await rm(staged, { recursive: true, force: true });
66
+ throw error;
67
+ }
68
+ }
69
+ return { projectDir, files: files.map(([relative]) => path.join(projectDir, relative)), dryRun: options.dryRun === true,
70
+ frameworkMode, frameworkFileCount: frameworkFiles.length };
71
+ }
72
+
73
+ /** Package sources only: do not carry checkout state, dependencies or test fixtures. */
74
+ async function collectFrameworkFiles(directory: string): Promise<string[]> {
75
+ const files: string[] = [];
76
+ const excluded = new Set(["node_modules", "test", "tests", "__tests__"]);
77
+ const visit = async (relative: string): Promise<void> => {
78
+ const file = path.join(directory, relative);
79
+ const info = await lstat(file);
80
+ if (info.isSymbolicLink()) throw new Error(`Framework snapshot cannot include a symbolic link: ${relative}`);
81
+ if (info.isDirectory()) {
82
+ for (const entry of (await readdir(file)).sort()) {
83
+ // Same contents as the npm package: no tests, fixtures or internal passports.
84
+ if (entry.startsWith(".") || excluded.has(entry) || entry === "MODULE.md" || /\.(test|spec)\.[^.]+$/.test(entry) || entry.endsWith(".bun-build")) continue;
85
+ await visit(path.join(relative, entry));
86
+ }
87
+ } else if (info.isFile()) files.push(relative);
88
+ else throw new Error(`Unsupported framework package entry: ${relative}`);
89
+ };
90
+ for (const entry of ["index.ts", "package.json", "core", "library", "cli"]) await visit(entry);
91
+ // MIT requires the license text to travel with every copy of the package.
92
+ for (const entry of ["LICENSE", "README.md"]) if (await exists(path.join(directory, entry))) await visit(entry);
93
+ return files;
94
+ }
95
+
96
+ async function resolveFramework(requested?: string): Promise<string> {
97
+ const candidates = requested === undefined
98
+ ? [path.resolve("src/bazis"), path.resolve(import.meta.dir, "..")]
99
+ : [path.resolve(requested)];
100
+ for (const candidate of candidates) {
101
+ let directory: string;
102
+ try { directory = await realpath(candidate); } catch { continue; }
103
+ const info = await lstat(path.join(directory, "package.json")).catch(() => undefined);
104
+ if (!info?.isFile()) continue;
105
+ try {
106
+ const manifest = JSON.parse(await readFile(path.join(directory, "package.json"), "utf8"));
107
+ const required = await Promise.all(["index.ts", "cli/main.ts", "core/scripts/di-generate.ts"]
108
+ .map((file) => lstat(path.join(directory, file)).then((entry) => entry.isFile()).catch(() => false)));
109
+ if (manifest.name === "bazis" && required.every(Boolean)) {
110
+ return directory;
111
+ }
112
+ } catch { /* Try the next candidate. */ }
113
+ }
114
+ throw new Error("Local Bazis package not found. Pass --framework <path-to-src/bazis>.");
115
+ }
116
+
117
+ async function exists(file: string): Promise<boolean> {
118
+ try { await lstat(file); return true; }
119
+ catch (error) {
120
+ if ((error as NodeJS.ErrnoException).code === "ENOENT") return false;
121
+ throw error;
122
+ }
123
+ }
124
+
125
+ function buildProjectFiles(name: string, dependency: string, frameworkMode: "snapshot" | "link"): readonly (readonly [string, string])[] {
126
+ const manifest = {
127
+ name, version: "0.1.0", private: true, type: "module",
128
+ scripts: {
129
+ "codegen": "bazis codegen",
130
+ "dev": "bazis dev",
131
+ "test": "bazis test",
132
+ "build": "bazis build",
133
+ "build:bin": "bazis build --bin",
134
+ "start": `./bin/${name}`,
135
+ },
136
+ dependencies: { bazis: dependency },
137
+ devDependencies: { "@types/bun": "1.4.0", typescript: "^5" },
138
+ };
139
+ const tsconfig = {
140
+ compilerOptions: {
141
+ target: "ESNext", module: "ESNext", moduleResolution: "bundler", lib: ["ESNext"],
142
+ types: ["bun"], strict: true, noUncheckedIndexedAccess: true, noImplicitOverride: true,
143
+ skipLibCheck: true, noEmit: true,
144
+ },
145
+ include: ["src/**/*"],
146
+ };
147
+ const codegen = { version: 1, defaultTarget: "production", targets: { production: { entrypoints: ["src/index.ts"] } } };
148
+ return [
149
+ ["package.json", `${JSON.stringify(manifest, null, 2)}\n`],
150
+ ["tsconfig.json", `${JSON.stringify(tsconfig, null, 2)}\n`],
151
+ ["bazis.config.json", `${JSON.stringify(codegen, null, 2)}\n`],
152
+ [".gitignore", "node_modules/\nbin/\nsrc/generated/\n.env\n"],
153
+ [".env.example", "# Copy to .env (Bun loads it automatically).\nBAZIS_ENV=development\nHOST=127.0.0.1\nPORT=3000\n"],
154
+ ["src/app/test/health.test.ts", HEALTH_TEST],
155
+ ["AGENTS.md", "# Working on this bazis project\n\nBefore changing the application, read the [module architecture](docs/architecture/MODULE_ARCHITECTURE.md). Create new modules only with `bunx bazis g module` or `bunx bazis g pack`; fill in the generated `MODULE.md` afterwards. Only codegen updates `src/generated/`.\n"],
156
+ ["docs/architecture/MODULE_ARCHITECTURE.md", "# Application module architecture\n\n`src/index.ts` calls `runApp`; `src/app/modules/App.module.ts` composes feature modules through `imports`. The application root owns no domain logic.\n\nOne self-contained function is an atomic module. It owns its data, services, HTTP and background handlers. A composite module is only for several independent functions; its root does composition. Layers and file counts alone do not create submodules.\n\nCreate new modules only with `bunx bazis g module <Name> --empty|--minimal|--full` or `bunx bazis g pack <Name> --parts <a,b>`. Before implementing, define the responsibility and public entries, then fill in the generated `MODULE.md`: fields, errors, dependencies, exports and checks. Use the public APIs of the `bazis` package and its DI and ORM. Do not edit `src/generated/` by hand; run `bunx bazis codegen`.\n\n`--minimal` creates a sample CRUD with the ORM. To run it the application needs a database provider and a ready schema. For a first function without a database use `--empty`. Check types and the binary build after changes that affect startup.\n"],
157
+ ["src/app/modules/App.module.ts", 'import { Module } from "bazis/core/di";\n\n@Module({ imports: [], exports: [] })\nexport class AppModule {}\n'],
158
+ ["src/index.ts", 'import { runApp } from "bazis/core/app";\nimport { AppModule } from "./app/modules/App.module";\nimport { registerBazisGeneratedRuntime } from "./generated/bazis/runtime";\n\nawait registerBazisGeneratedRuntime();\nawait runApp(AppModule, { http: { hostname: process.env.HOST ?? "127.0.0.1", port: Number(process.env.PORT ?? 3000), health: true } });\n'],
159
+ ["README.md", `# ${name}\n\nAn [bazis](https://www.npmjs.com/package/bazis) application. ${frameworkMode === "snapshot"
160
+ ? "The framework package is copied to `vendor/bazis`; keep it in Git and move it with the project. The framework checkout is no longer needed. Framework updates do not reach this copy automatically."
161
+ : "The `bazis` dependency links an external local checkout (`--link-framework`). Moving the project needs the same package and an updated path in `package.json`."}\nRead the [local architecture](docs/architecture/MODULE_ARCHITECTURE.md) before changing modules.\n\nNeeds Bun ≥ 1.4.0. Settings go to \`.env\` (example: \`.env.example\`).\n\n\`\`\`sh\nbun install\nbunx bazis dev\n# GET http://127.0.0.1:3000/health\n# If the port is busy: PORT=3100 bunx bazis dev\n\`\`\`\n\nAdd an atomic module from the project root: \`bunx bazis g module Task --empty\`.\nAfter filling in its passport and implementation, run \`bunx bazis codegen\`.\nTests: \`bunx bazis test\`. Typecheck: \`bunx bazis build\`. Binary: \`bunx bazis build --bin\`, run it with \`bun run start\`.\n\n\`--minimal\` creates a sample CRUD with paging (20 records by default, at most 100 over HTTP); it needs a database provider and a schema to run. The service returns \`PageResult\`; the HTTP controller builds JSON:API. \`DbContext.saveChanges()\` saves every change of its context. In ORM predicates combine conditions with \`.and()\` and \`.or()\`; codegen rejects \`&&\` and \`||\` between predicates.\n`],
162
+ ];
163
+ }
164
+
165
+ const HEALTH_TEST = `import { expect, test } from "bun:test";
166
+
167
+ // Starts the app from source exactly as \`bazis dev\` does and checks /health.
168
+ test("app starts and answers /health", async () => {
169
+ const port = String(20000 + Math.floor(Math.random() * 20000));
170
+ const app = Bun.spawn([process.execPath, "run", "src/index.ts"], { env: { ...process.env, HOST: "127.0.0.1", PORT: port }, stdout: "ignore", stderr: "inherit" });
171
+ try {
172
+ let status = 0;
173
+ for (let attempt = 0; attempt < 100 && status !== 200; attempt++) {
174
+ await Bun.sleep(100);
175
+ status = await fetch(\`http://127.0.0.1:\${port}/health\`).then((response) => response.status, () => 0);
176
+ }
177
+ expect(status).toBe(200);
178
+ } finally {
179
+ app.kill();
180
+ await app.exited;
181
+ }
182
+ });
183
+ `;
package/cli/main.ts ADDED
@@ -0,0 +1,125 @@
1
+ #!/usr/bin/env bun
2
+ import { generateModule, generateModulePack } from "./generateModule";
3
+ import { parseCliArgs } from "./parseCli";
4
+ import { runCodegen } from "./codegen";
5
+ import { generateProject } from "./generateProject";
6
+ import { runBuild, runDev, runTest } from "./build";
7
+
8
+ export const USAGE = `Usage:
9
+ bazis new <Name> [options] Create a new application project
10
+ bazis g module <Name> [options] Atomic module (alias: m)
11
+ bazis g pack <Name> --parts <a,b> [options] Composite module (aliases: p, module-pack)
12
+ bazis codegen [--target <name|all>] Generate DI wiring into src/generated/bazis
13
+ bazis dev [--watch] Codegen, then run the app from source with
14
+ BAZIS_ENV=development (unless set);
15
+ --watch reruns both when src/ changes
16
+ bazis test [<bun test args>] Codegen, then bun test
17
+ bazis build Codegen and typecheck
18
+ bazis build --bin [--outfile <path>] Also compile a standalone executable (default bin/<name>)
19
+ bazis --help
20
+ g can also be written as generate.
21
+
22
+ Generation options:
23
+ --path <directory> Exact project directory (new only; default: ./<name>)
24
+ --framework <path> Local bazis package directory (new only)
25
+ --link-framework Link that checkout instead of copying vendor/bazis (new only)
26
+ --modules-root <path> Modules root (default: src/app/modules)
27
+ --app-module <path> Host module (default: {modules-root}/App.module.ts)
28
+ --empty Module entry and MODULE.md only
29
+ --minimal Compact example CRUD and MODULE.md (default)
30
+ --full Example CRUD/list/cache/auth/background/AI and MODULE.md;
31
+ uses src/app/modules/auth helpers when the project has them.
32
+ To run, the host needs a cache (runApp({ cache: memory() }))
33
+ and a database provider. Legacy alias: --enterprise
34
+ --parts <a,b,...> Independent empty atomic parts; pack only, at least two
35
+ --dry-run Validate and list planned changes without writing
36
+ --no-register Skip host registration and automatic codegen
37
+ --no-codegen Generate and register without running codegen
38
+ --target <name|all> Codegen target (default: project's default target)
39
+ --force Overwrite scaffold files, including MODULE.md
40
+ -h, --help Show help at any position without changing files
41
+
42
+ Examples (from the project root):
43
+ bunx bazis new MyApp --dry-run
44
+ bunx bazis new MyApp
45
+ bunx bazis g module Task --dry-run
46
+ bunx bazis g m Guest --no-codegen
47
+ bunx bazis g module Mailer --empty --no-register
48
+ bunx bazis g pack DataManager --parts tables,fields,validators,records
49
+ bunx bazis codegen --target production
50
+ bunx bazis dev --watch
51
+ bunx bazis test
52
+ bunx bazis build --bin
53
+
54
+ Read AGENTS.md and docs/architecture/MODULE_ARCHITECTURE.md before implementing.
55
+ `;
56
+
57
+ export interface CliRuntime {
58
+ readonly log: (message: string) => void;
59
+ readonly error: (message: string) => void;
60
+ readonly codegen: (cwd: string, target?: string) => Promise<number>;
61
+ }
62
+
63
+ const defaultRuntime: CliRuntime = {
64
+ log: (message) => console.log(message),
65
+ error: (message) => console.error(message),
66
+ codegen: runCodegen,
67
+ };
68
+
69
+ export async function runCli(argv: readonly string[], runtime: CliRuntime = defaultRuntime): Promise<number> {
70
+ const parsed = parseCliArgs(argv);
71
+ if (parsed.kind === "help") {
72
+ runtime.log(USAGE.trim());
73
+ return parsed.help ? 0 : 1;
74
+ }
75
+ if (parsed.kind === "error") {
76
+ runtime.error(`[bazis] ${parsed.message}`);
77
+ runtime.error("Use bazis --help to list commands and options.");
78
+ return 1;
79
+ }
80
+ try {
81
+ if (parsed.kind === "codegen") return await runtime.codegen(process.cwd(), parsed.target);
82
+ if (parsed.kind === "dev") return await runDev(process.cwd(), runtime.codegen, runtime.log, { watch: parsed.watch });
83
+ if (parsed.kind === "test") return await runTest(process.cwd(), parsed.args, runtime.codegen);
84
+ if (parsed.kind === "build") return await runBuild(process.cwd(), { bin: parsed.bin, outfile: parsed.outfile }, runtime.codegen, runtime.log);
85
+ if (parsed.kind === "new") {
86
+ const result = await generateProject({ name: parsed.name, outputPath: parsed.outputPath, frameworkPath: parsed.frameworkPath, linkFramework: parsed.linkFramework, dryRun: parsed.dryRun });
87
+ runtime.log(`[bazis] ${result.dryRun ? "planned" : "created"} project: ${result.projectDir}`);
88
+ for (const file of result.files) runtime.log(` + ${file}`);
89
+ runtime.log(result.frameworkMode === "snapshot"
90
+ ? `[bazis] vendor/bazis: ${result.frameworkFileCount} package files${result.dryRun ? " planned" : " copied"}. Keep this directory in version control.`
91
+ : "[bazis] Framework is linked to an external checkout (--link-framework).");
92
+ if (!result.dryRun) runtime.log(`[bazis] Next: cd ${result.projectDir} && bun install && bunx bazis dev`);
93
+ return 0;
94
+ }
95
+ const args = parsed.args;
96
+ const options = {
97
+ name: args.name, modulesRoot: args.modulesRoot, appModulePath: args.appModule,
98
+ register: args.register, force: args.force, dryRun: args.dryRun,
99
+ };
100
+ const result = args.generator === "pack"
101
+ ? await generateModulePack({ ...options, parts: args.parts })
102
+ : await generateModule({ ...options, profile: args.profile });
103
+ runtime.log(`[bazis] ${result.dryRun ? "planned" : "generated"} ${args.generator}: ${result.moduleDir}`);
104
+ for (const change of result.changes) runtime.log(` ${change.action === "create" ? "+" : "~"} ${change.path}`);
105
+ for (const warning of result.warnings) runtime.log(`[bazis] ${warning}`);
106
+ if (result.dryRun) {
107
+ runtime.log("[bazis] dry-run: no files written; codegen not run.");
108
+ return 0;
109
+ }
110
+ if (result.registered) runtime.log("[bazis] connected in host module.");
111
+ if (!args.codegen || !result.registered) {
112
+ runtime.log(`[bazis] codegen skipped: ${!args.codegen ? "--no-codegen" : "module is not connected by this command"}.`);
113
+ return 0;
114
+ }
115
+ runtime.log("[bazis] running di:generate...");
116
+ const exitCode = await runtime.codegen(process.cwd(), args.target);
117
+ if (exitCode !== 0) runtime.error("[bazis] codegen failed; scaffold files were kept. Fix the error and run bazis codegen.");
118
+ return exitCode;
119
+ } catch (error) {
120
+ runtime.error(`[bazis] ${error instanceof Error ? error.message : String(error)}`);
121
+ return 1;
122
+ }
123
+ }
124
+
125
+ if (import.meta.main) process.exitCode = await runCli(Bun.argv.slice(2));
@@ -0,0 +1,127 @@
1
+ import path from "node:path";
2
+ import ts from "typescript";
3
+
4
+ interface Edit { readonly at: number; readonly text: string }
5
+
6
+ export function moduleImportPath(fromFile: string, moduleFile: string): string {
7
+ const relative = path.relative(path.dirname(fromFile), moduleFile).split(path.sep).join("/").replace(/\.ts$/, "");
8
+ return relative.startsWith(".") ? relative : `./${relative}`;
9
+ }
10
+
11
+ /** Edits only the import and the selected @Module metadata, preserving other source text. */
12
+ export function registerModuleInSource(content: string, appFile: string, moduleFile: string, moduleClass: string): string {
13
+ const diagnostics = ts.transpileModule(content, { fileName: appFile, reportDiagnostics: true }).diagnostics ?? [];
14
+ if (diagnostics.some((diagnostic) => diagnostic.category === ts.DiagnosticCategory.Error)) {
15
+ throw new Error(`Cannot register a module in invalid TypeScript: ${appFile}`);
16
+ }
17
+ const source = ts.createSourceFile(appFile, content, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);
18
+ const importPath = moduleImportPath(appFile, moduleFile);
19
+ const eol = content.includes("\r\n") ? "\r\n" : "\n";
20
+ const imports = source.statements.filter(ts.isImportDeclaration);
21
+ const decoratorNames = new Set(["Module"]);
22
+ const decoratorNamespaces = new Set<string>();
23
+ let binding = moduleClass;
24
+ let imported = false;
25
+ const otherBindings = new Set<string>();
26
+ for (const declaration of imports) {
27
+ const clause = declaration.importClause;
28
+ if (!clause || !ts.isStringLiteral(declaration.moduleSpecifier)) continue;
29
+ const specifier = declaration.moduleSpecifier.text;
30
+ const isDI = /(?:bazis|bazis|@)\/core\/di$/.test(specifier);
31
+ if (clause.name) otherBindings.add(clause.name.text);
32
+ const named = clause.namedBindings;
33
+ if (named && ts.isNamespaceImport(named)) {
34
+ otherBindings.add(named.name.text);
35
+ if (isDI) decoratorNamespaces.add(named.name.text);
36
+ }
37
+ if (!named || !ts.isNamedImports(named)) continue;
38
+ for (const item of named.elements) {
39
+ const exported = item.propertyName?.text ?? item.name.text;
40
+ if (isDI && exported === "Module") decoratorNames.add(item.name.text);
41
+ const sameFile = specifier.startsWith(".") && path.resolve(path.dirname(appFile), specifier.replace(/\.(?:ts|js)$/, "")) === moduleFile.replace(/\.ts$/, "");
42
+ if (sameFile && exported === moduleClass) {
43
+ if (clause.isTypeOnly || item.isTypeOnly) throw new Error(`${moduleClass} has a type-only import; use a value import before registration.`);
44
+ binding = item.name.text;
45
+ imported = true;
46
+ } else {
47
+ otherBindings.add(item.name.text);
48
+ }
49
+ }
50
+ }
51
+ for (const statement of source.statements) {
52
+ if ((ts.isClassDeclaration(statement) || ts.isFunctionDeclaration(statement) || ts.isEnumDeclaration(statement)) && statement.name) {
53
+ otherBindings.add(statement.name.text);
54
+ }
55
+ if (ts.isVariableStatement(statement)) {
56
+ for (const declaration of statement.declarationList.declarations) {
57
+ if (ts.isIdentifier(declaration.name)) otherBindings.add(declaration.name.text);
58
+ }
59
+ }
60
+ }
61
+ if (otherBindings.has(binding)) throw new Error(`Cannot register ${moduleClass}: local name ${binding} is already in use.`);
62
+
63
+ const candidates: { name?: string; metadata: ts.ObjectLiteralExpression }[] = [];
64
+ for (const statement of source.statements.filter(ts.isClassDeclaration)) {
65
+ for (const decorator of ts.getDecorators(statement) ?? []) {
66
+ const call = decorator.expression;
67
+ if (!ts.isCallExpression(call)) continue;
68
+ const expression = call.expression;
69
+ const isModule = (ts.isIdentifier(expression) && decoratorNames.has(expression.text))
70
+ || (ts.isPropertyAccessExpression(expression) && ts.isIdentifier(expression.expression)
71
+ && decoratorNamespaces.has(expression.expression.text) && expression.name.text === "Module");
72
+ if (!isModule) continue;
73
+ const metadata = call.arguments[0];
74
+ if (!metadata || !ts.isObjectLiteralExpression(metadata)) throw new Error("@Module metadata must be an object literal for automatic registration.");
75
+ candidates.push({ name: statement.name?.text, metadata });
76
+ }
77
+ }
78
+ const candidate = candidates.find((item) => item.name === "AppModule") ?? (candidates.length === 1 ? candidates[0] : undefined);
79
+ if (!candidate) throw new Error("Could not select a unique @Module class for registration in App.module.ts.");
80
+ const metadata = candidate.metadata;
81
+ if (metadata.properties.some(ts.isSpreadAssignment)) throw new Error("Automatic registration does not support spread @Module metadata; register the module explicitly.");
82
+ if (metadata.properties.some((property) => property.name && ts.isComputedPropertyName(property.name))) throw new Error("Automatic registration does not support computed @Module properties; register the module explicitly.");
83
+ const importProperties = metadata.properties.filter((property) => property.name && (ts.isIdentifier(property.name) || ts.isStringLiteral(property.name)) && property.name.text === "imports");
84
+ if (importProperties.length > 1) throw new Error("Duplicate imports properties in @Module metadata.");
85
+ const property = importProperties[0];
86
+ const edits: Edit[] = [];
87
+ if (property) {
88
+ if (!ts.isPropertyAssignment(property) || !ts.isArrayLiteralExpression(property.initializer)) {
89
+ throw new Error("@Module imports must be an array literal for automatic registration.");
90
+ }
91
+ const array = property.initializer;
92
+ if (array.elements.some(ts.isOmittedExpression)) throw new Error("@Module imports contains an empty element; fix the array before registration.");
93
+ if (!array.elements.some((element) => ts.isIdentifier(element) && element.text === binding)) {
94
+ appendMember(content, array, array.elements, binding, edits, eol);
95
+ }
96
+ } else {
97
+ appendMember(content, metadata, metadata.properties, `imports: [${binding}]`, edits, eol);
98
+ }
99
+ if (!imported) {
100
+ const lastImport = imports.at(-1);
101
+ const end = lastImport?.end ?? 0;
102
+ const nextLine = content.indexOf("\n", end);
103
+ const hasLineEnd = lastImport && nextLine >= 0 && /^\s*(?:\/\/.*)?$/.test(content.slice(end, nextLine));
104
+ const at = hasLineEnd ? nextLine + 1 : end;
105
+ edits.push({ at, text: `${at > 0 && content[at - 1] !== "\n" ? eol : ""}import { ${moduleClass} } from "${importPath}";${eol}` });
106
+ }
107
+ return edits.reverse().sort((left, right) => right.at - left.at).reduce((text, edit) => text.slice(0, edit.at) + edit.text + text.slice(edit.at), content);
108
+ }
109
+
110
+ function appendMember(content: string, node: ts.Node, members: ts.NodeArray<ts.Node>, member: string, edits: Edit[], eol: string): void {
111
+ const close = node.end - 1;
112
+ const last = members.at(-1);
113
+ if (last && !members.hasTrailingComma) edits.push({ at: last.end, text: "," });
114
+ const inner = content.slice(node.getStart() + 1, close);
115
+ if (!inner.includes("\n")) {
116
+ edits.push({ at: close, text: `${last || inner.trim() ? " " : ""}${member}${members.hasTrailingComma ? "," : ""}` });
117
+ return;
118
+ }
119
+ const lineStart = content.lastIndexOf("\n", close) + 1;
120
+ const closingIndent = content.slice(lineStart, close);
121
+ if (/^\s*$/.test(closingIndent)) {
122
+ edits.push({ at: lineStart, text: `${closingIndent} ${member},${eol}` });
123
+ } else {
124
+ const indent = content.slice(content.lastIndexOf("\n", node.getStart()) + 1, node.getStart()).match(/^\s*/)?.[0] ?? "";
125
+ edits.push({ at: close, text: `${eol}${indent} ${member},${eol}${indent}` });
126
+ }
127
+ }
package/cli/naming.ts ADDED
@@ -0,0 +1,124 @@
1
+ /** Parsed module name for scaffold file/class naming. */
2
+ export interface ModuleNaming {
3
+ /** CLI input as given (trimmed). */
4
+ readonly input: string;
5
+ /** Folder under `modules/` — lowercase as given (`users`, `order-items`). */
6
+ readonly folder: string;
7
+ /** PascalCase name as given (`Users`, `OrderItems`): module class and file. */
8
+ readonly module: string;
9
+ /** PascalCase singular entity (`User`, `OrderItem`). */
10
+ readonly entity: string;
11
+ /** HTTP route segment, usually plural (`users`, `order-items`). */
12
+ readonly route: string;
13
+ /** DbContext collection property (`users`, `orderItems`). */
14
+ readonly collection: string;
15
+ /** `{Module}Module` class name (`UsersModule`). */
16
+ readonly moduleClass: string;
17
+ /** API list base path segment (`/api/users`). */
18
+ readonly apiBasePath: string;
19
+ /** PostgreSQL schema (module folder name, `-` → `_`). */
20
+ readonly dbSchema: string;
21
+ }
22
+
23
+ const SINGULAR_TO_PLURAL: Readonly<Record<string, string>> = {
24
+ person: "people",
25
+ child: "children",
26
+ man: "men",
27
+ woman: "women",
28
+ status: "statuses",
29
+ bus: "buses",
30
+ analysis: "analyses",
31
+ };
32
+
33
+ const PLURAL_TO_SINGULAR: Readonly<Record<string, string>> = Object.freeze(
34
+ Object.fromEntries(Object.entries(SINGULAR_TO_PLURAL).map(([singular, plural]) => [plural, singular])),
35
+ );
36
+
37
+ /**
38
+ * Converts the CLI name into scaffold names. The module keeps the name as given
39
+ * (`Users` → `UsersModule`, `Users.module.ts`); the CRUD entity is singular (`User`).
40
+ */
41
+ export function parseModuleName(raw: string): ModuleNaming {
42
+ const input = raw.trim();
43
+ if (input.length === 0) {
44
+ throw new Error("Module name is required.");
45
+ }
46
+ if (!/^[a-zA-Z][a-zA-Z0-9]*(?:-[a-zA-Z0-9]+)*$/.test(input)) {
47
+ throw new Error(`Invalid module name "${input}". Use letters, digits, and hyphens only.`);
48
+ }
49
+
50
+ const parts = input
51
+ .replace(/([A-Z]+)([A-Z][a-z])/g, "$1-$2")
52
+ .replace(/([a-z0-9])([A-Z])/g, "$1-$2")
53
+ .toLowerCase()
54
+ .split("-")
55
+ .filter((part) => part.length > 0);
56
+
57
+ const folder = parts.join("-");
58
+ const module = pascal(parts);
59
+ const singular = toSingular(parts);
60
+ const entity = pascal(singular);
61
+ const route = toRoute(singular);
62
+ const collection = toCamelPlural(singular);
63
+
64
+ return {
65
+ input,
66
+ folder,
67
+ module,
68
+ entity,
69
+ route,
70
+ collection,
71
+ moduleClass: `${module}Module`,
72
+ apiBasePath: `/api/${route}`,
73
+ dbSchema: folder.replace(/-/g, "_"),
74
+ };
75
+ }
76
+
77
+ function pascal(parts: readonly string[]): string {
78
+ return parts.map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join("");
79
+ }
80
+
81
+ function toSingular(parts: readonly string[]): readonly string[] {
82
+ if (parts.length === 0) {
83
+ return parts;
84
+ }
85
+ const last = parts[parts.length - 1] as string;
86
+ const lower = last.toLowerCase();
87
+
88
+ if (Object.hasOwn(PLURAL_TO_SINGULAR, lower)) {
89
+ return [...parts.slice(0, -1), PLURAL_TO_SINGULAR[lower] as string];
90
+ }
91
+ if (lower.endsWith("ies") && lower.length > 3) {
92
+ return [...parts.slice(0, -1), `${lower.slice(0, -3)}y`];
93
+ }
94
+ if (/(?:ches|shes|xes|zes|sses)$/.test(lower)) {
95
+ return [...parts.slice(0, -1), lower.slice(0, -2)];
96
+ }
97
+ if (lower.endsWith("s") && lower.length > 1 && !/(?:ss|us|is)$/.test(lower)) {
98
+ return [...parts.slice(0, -1), lower.slice(0, -1)];
99
+ }
100
+ return parts;
101
+ }
102
+
103
+ function toRoute(parts: readonly string[]): string {
104
+ const last = parts[parts.length - 1] as string;
105
+ const lower = last.toLowerCase();
106
+
107
+ if (Object.hasOwn(SINGULAR_TO_PLURAL, lower)) {
108
+ return [...parts.slice(0, -1), SINGULAR_TO_PLURAL[lower] as string].join("-");
109
+ }
110
+ if (/[^aeiou]y$/.test(lower)) {
111
+ return [...parts.slice(0, -1), `${lower.slice(0, -1)}ies`].join("-");
112
+ }
113
+ if (/(?:s|x|z|ch|sh)$/.test(lower)) {
114
+ return [...parts.slice(0, -1), `${lower}es`].join("-");
115
+ }
116
+ return [...parts.slice(0, -1), `${lower}s`].join("-");
117
+ }
118
+
119
+ function toCamelPlural(parts: readonly string[]): string {
120
+ const routeParts = toRoute(parts).split("-");
121
+ return routeParts
122
+ .map((part, index) => (index === 0 ? part : part.charAt(0).toUpperCase() + part.slice(1)))
123
+ .join("");
124
+ }