alepha 0.14.2 → 0.14.4

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 (405) hide show
  1. package/README.md +1 -1
  2. package/dist/api/audits/index.browser.js +5 -5
  3. package/dist/api/audits/index.browser.js.map +1 -1
  4. package/dist/api/audits/index.d.ts +706 -785
  5. package/dist/api/audits/index.d.ts.map +1 -1
  6. package/dist/api/audits/index.js +13 -13
  7. package/dist/api/audits/index.js.map +1 -1
  8. package/dist/api/files/index.browser.js +5 -5
  9. package/dist/api/files/index.browser.js.map +1 -1
  10. package/dist/api/files/index.d.ts +58 -137
  11. package/dist/api/files/index.d.ts.map +1 -1
  12. package/dist/api/files/index.js +71 -71
  13. package/dist/api/files/index.js.map +1 -1
  14. package/dist/api/jobs/index.browser.js +5 -5
  15. package/dist/api/jobs/index.browser.js.map +1 -1
  16. package/dist/api/jobs/index.d.ts +29 -108
  17. package/dist/api/jobs/index.d.ts.map +1 -1
  18. package/dist/api/jobs/index.js +10 -10
  19. package/dist/api/jobs/index.js.map +1 -1
  20. package/dist/api/notifications/index.browser.js +10 -10
  21. package/dist/api/notifications/index.browser.js.map +1 -1
  22. package/dist/api/notifications/index.d.ts +504 -171
  23. package/dist/api/notifications/index.d.ts.map +1 -1
  24. package/dist/api/notifications/index.js +12 -12
  25. package/dist/api/notifications/index.js.map +1 -1
  26. package/dist/api/parameters/index.browser.js +163 -10
  27. package/dist/api/parameters/index.browser.js.map +1 -1
  28. package/dist/api/parameters/index.d.ts +277 -351
  29. package/dist/api/parameters/index.d.ts.map +1 -1
  30. package/dist/api/parameters/index.js +196 -91
  31. package/dist/api/parameters/index.js.map +1 -1
  32. package/dist/api/users/index.browser.js +19 -19
  33. package/dist/api/users/index.browser.js.map +1 -1
  34. package/dist/api/users/index.d.ts +787 -852
  35. package/dist/api/users/index.d.ts.map +1 -1
  36. package/dist/api/users/index.js +827 -596
  37. package/dist/api/users/index.js.map +1 -1
  38. package/dist/api/verifications/index.browser.js +6 -6
  39. package/dist/api/verifications/index.browser.js.map +1 -1
  40. package/dist/api/verifications/index.d.ts +128 -128
  41. package/dist/api/verifications/index.d.ts.map +1 -1
  42. package/dist/api/verifications/index.js +6 -6
  43. package/dist/api/verifications/index.js.map +1 -1
  44. package/dist/bin/index.d.ts +1 -2
  45. package/dist/bin/index.js +0 -1
  46. package/dist/bin/index.js.map +1 -1
  47. package/dist/cli/index.d.ts +252 -131
  48. package/dist/cli/index.d.ts.map +1 -1
  49. package/dist/cli/index.js +595 -395
  50. package/dist/cli/index.js.map +1 -1
  51. package/dist/command/index.d.ts +46 -11
  52. package/dist/command/index.d.ts.map +1 -1
  53. package/dist/command/index.js +99 -19
  54. package/dist/command/index.js.map +1 -1
  55. package/dist/core/index.browser.js +40 -22
  56. package/dist/core/index.browser.js.map +1 -1
  57. package/dist/core/index.d.ts +45 -1
  58. package/dist/core/index.d.ts.map +1 -1
  59. package/dist/core/index.js +40 -22
  60. package/dist/core/index.js.map +1 -1
  61. package/dist/core/index.native.js +40 -22
  62. package/dist/core/index.native.js.map +1 -1
  63. package/dist/fake/index.js +195 -168
  64. package/dist/fake/index.js.map +1 -1
  65. package/dist/file/index.d.ts +8 -0
  66. package/dist/file/index.d.ts.map +1 -1
  67. package/dist/file/index.js +3 -0
  68. package/dist/file/index.js.map +1 -1
  69. package/dist/logger/index.d.ts +1 -1
  70. package/dist/logger/index.d.ts.map +1 -1
  71. package/dist/logger/index.js +12 -2
  72. package/dist/logger/index.js.map +1 -1
  73. package/dist/mcp/index.js +1 -1
  74. package/dist/mcp/index.js.map +1 -1
  75. package/dist/orm/index.d.ts +59 -195
  76. package/dist/orm/index.d.ts.map +1 -1
  77. package/dist/orm/index.js +201 -430
  78. package/dist/orm/index.js.map +1 -1
  79. package/dist/security/index.d.ts +1 -1
  80. package/dist/security/index.d.ts.map +1 -1
  81. package/dist/security/index.js +1 -1
  82. package/dist/security/index.js.map +1 -1
  83. package/dist/server/auth/index.d.ts +171 -155
  84. package/dist/server/auth/index.d.ts.map +1 -1
  85. package/dist/server/auth/index.js +0 -1
  86. package/dist/server/auth/index.js.map +1 -1
  87. package/dist/server/cache/index.d.ts +12 -0
  88. package/dist/server/cache/index.d.ts.map +1 -1
  89. package/dist/server/cache/index.js +55 -2
  90. package/dist/server/cache/index.js.map +1 -1
  91. package/dist/server/compress/index.d.ts +6 -0
  92. package/dist/server/compress/index.d.ts.map +1 -1
  93. package/dist/server/compress/index.js +38 -1
  94. package/dist/server/compress/index.js.map +1 -1
  95. package/dist/server/core/index.browser.js +2 -2
  96. package/dist/server/core/index.browser.js.map +1 -1
  97. package/dist/server/core/index.d.ts +10 -10
  98. package/dist/server/core/index.d.ts.map +1 -1
  99. package/dist/server/core/index.js +7 -4
  100. package/dist/server/core/index.js.map +1 -1
  101. package/dist/server/links/index.browser.js +22 -6
  102. package/dist/server/links/index.browser.js.map +1 -1
  103. package/dist/server/links/index.d.ts +46 -44
  104. package/dist/server/links/index.d.ts.map +1 -1
  105. package/dist/server/links/index.js +24 -41
  106. package/dist/server/links/index.js.map +1 -1
  107. package/dist/server/static/index.d.ts.map +1 -1
  108. package/dist/server/static/index.js +4 -0
  109. package/dist/server/static/index.js.map +1 -1
  110. package/dist/server/swagger/index.d.ts +2 -1
  111. package/dist/server/swagger/index.d.ts.map +1 -1
  112. package/dist/server/swagger/index.js +9 -5
  113. package/dist/server/swagger/index.js.map +1 -1
  114. package/dist/vite/index.d.ts +101 -106
  115. package/dist/vite/index.d.ts.map +1 -1
  116. package/dist/vite/index.js +574 -503
  117. package/dist/vite/index.js.map +1 -1
  118. package/dist/websocket/index.d.ts +7 -7
  119. package/package.json +7 -7
  120. package/src/api/audits/controllers/{AuditController.ts → AdminAuditController.ts} +5 -6
  121. package/src/api/audits/entities/audits.ts +5 -5
  122. package/src/api/audits/index.browser.ts +1 -1
  123. package/src/api/audits/index.ts +3 -3
  124. package/src/api/audits/primitives/$audit.spec.ts +276 -0
  125. package/src/api/audits/services/AuditService.spec.ts +495 -0
  126. package/src/api/files/__tests__/$bucket.spec.ts +91 -0
  127. package/src/api/files/controllers/AdminFileStatsController.spec.ts +166 -0
  128. package/src/api/files/controllers/{StorageStatsController.ts → AdminFileStatsController.ts} +2 -2
  129. package/src/api/files/controllers/FileController.spec.ts +558 -0
  130. package/src/api/files/controllers/FileController.ts +4 -5
  131. package/src/api/files/entities/files.ts +5 -5
  132. package/src/api/files/index.browser.ts +1 -1
  133. package/src/api/files/index.ts +4 -4
  134. package/src/api/files/jobs/FileJobs.spec.ts +52 -0
  135. package/src/api/files/services/FileService.spec.ts +109 -0
  136. package/src/api/jobs/__tests__/JobController.spec.ts +343 -0
  137. package/src/api/jobs/controllers/{JobController.ts → AdminJobController.ts} +2 -2
  138. package/src/api/jobs/entities/jobExecutions.ts +5 -5
  139. package/src/api/jobs/index.ts +3 -3
  140. package/src/api/jobs/primitives/$job.spec.ts +476 -0
  141. package/src/api/notifications/controllers/{NotificationController.ts → AdminNotificationController.ts} +4 -5
  142. package/src/api/notifications/entities/notifications.ts +5 -5
  143. package/src/api/notifications/index.browser.ts +1 -1
  144. package/src/api/notifications/index.ts +4 -4
  145. package/src/api/parameters/controllers/{ConfigController.ts → AdminConfigController.ts} +46 -107
  146. package/src/api/parameters/entities/parameters.ts +7 -17
  147. package/src/api/parameters/index.ts +3 -3
  148. package/src/api/parameters/primitives/$config.spec.ts +356 -0
  149. package/src/api/parameters/schemas/activateConfigBodySchema.ts +12 -0
  150. package/src/api/parameters/schemas/checkScheduledResponseSchema.ts +8 -0
  151. package/src/api/parameters/schemas/configCurrentResponseSchema.ts +13 -0
  152. package/src/api/parameters/schemas/configHistoryResponseSchema.ts +9 -0
  153. package/src/api/parameters/schemas/configNameParamSchema.ts +10 -0
  154. package/src/api/parameters/schemas/configNamesResponseSchema.ts +8 -0
  155. package/src/api/parameters/schemas/configTreeNodeSchema.ts +13 -0
  156. package/src/api/parameters/schemas/configVersionParamSchema.ts +9 -0
  157. package/src/api/parameters/schemas/configVersionResponseSchema.ts +9 -0
  158. package/src/api/parameters/schemas/configsByStatusResponseSchema.ts +9 -0
  159. package/src/api/parameters/schemas/createConfigVersionBodySchema.ts +24 -0
  160. package/src/api/parameters/schemas/index.ts +15 -0
  161. package/src/api/parameters/schemas/parameterResponseSchema.ts +26 -0
  162. package/src/api/parameters/schemas/parameterStatusSchema.ts +13 -0
  163. package/src/api/parameters/schemas/rollbackConfigBodySchema.ts +15 -0
  164. package/src/api/parameters/schemas/statusParamSchema.ts +9 -0
  165. package/src/api/users/__tests__/EmailVerification.spec.ts +369 -0
  166. package/src/api/users/__tests__/PasswordReset.spec.ts +550 -0
  167. package/src/api/users/controllers/AdminIdentityController.spec.ts +365 -0
  168. package/src/api/users/controllers/{IdentityController.ts → AdminIdentityController.ts} +3 -4
  169. package/src/api/users/controllers/AdminSessionController.spec.ts +274 -0
  170. package/src/api/users/controllers/{SessionController.ts → AdminSessionController.ts} +3 -4
  171. package/src/api/users/controllers/AdminUserController.spec.ts +372 -0
  172. package/src/api/users/controllers/AdminUserController.ts +116 -0
  173. package/src/api/users/controllers/UserController.ts +4 -107
  174. package/src/api/users/controllers/UserRealmController.ts +3 -0
  175. package/src/api/users/entities/identities.ts +6 -6
  176. package/src/api/users/entities/sessions.ts +6 -6
  177. package/src/api/users/entities/users.ts +9 -9
  178. package/src/api/users/index.ts +9 -6
  179. package/src/api/users/primitives/$userRealm.ts +13 -8
  180. package/src/api/users/services/CredentialService.spec.ts +509 -0
  181. package/src/api/users/services/CredentialService.ts +46 -0
  182. package/src/api/users/services/IdentityService.ts +15 -0
  183. package/src/api/users/services/RegistrationService.spec.ts +630 -0
  184. package/src/api/users/services/RegistrationService.ts +18 -0
  185. package/src/api/users/services/SessionService.spec.ts +301 -0
  186. package/src/api/users/services/SessionService.ts +110 -1
  187. package/src/api/users/services/UserService.ts +67 -2
  188. package/src/api/verifications/__tests__/CodeVerification.spec.ts +318 -0
  189. package/src/api/verifications/__tests__/LinkVerification.spec.ts +279 -0
  190. package/src/api/verifications/entities/verifications.ts +6 -6
  191. package/src/api/verifications/jobs/VerificationJobs.spec.ts +50 -0
  192. package/src/batch/__tests__/startup-buffering.spec.ts +458 -0
  193. package/src/batch/primitives/$batch.spec.ts +766 -0
  194. package/src/batch/providers/BatchProvider.spec.ts +786 -0
  195. package/src/bin/index.ts +0 -1
  196. package/src/bucket/__tests__/shared.ts +194 -0
  197. package/src/bucket/primitives/$bucket.spec.ts +104 -0
  198. package/src/bucket/providers/FileStorageProvider.spec.ts +13 -0
  199. package/src/bucket/providers/LocalFileStorageProvider.spec.ts +77 -0
  200. package/src/bucket/providers/MemoryFileStorageProvider.spec.ts +82 -0
  201. package/src/cache/core/__tests__/shared.ts +377 -0
  202. package/src/cache/core/primitives/$cache.spec.ts +111 -0
  203. package/src/cache/redis/__tests__/cache-redis.spec.ts +70 -0
  204. package/src/cli/apps/AlephaCli.ts +25 -6
  205. package/src/cli/atoms/buildOptions.ts +88 -0
  206. package/src/cli/commands/build.ts +32 -69
  207. package/src/cli/commands/db.ts +0 -4
  208. package/src/cli/commands/dev.ts +34 -10
  209. package/src/cli/commands/gen/changelog.spec.ts +315 -0
  210. package/src/cli/commands/{changelog.ts → gen/changelog.ts} +9 -9
  211. package/src/cli/commands/gen/env.ts +53 -0
  212. package/src/cli/commands/gen/openapi.ts +71 -0
  213. package/src/cli/commands/gen/resource.ts +15 -0
  214. package/src/cli/commands/gen.ts +24 -0
  215. package/src/cli/commands/init.ts +2 -1
  216. package/src/cli/commands/root.ts +12 -3
  217. package/src/cli/commands/test.ts +0 -1
  218. package/src/cli/commands/typecheck.ts +5 -0
  219. package/src/cli/commands/verify.ts +1 -1
  220. package/src/cli/defineConfig.ts +49 -7
  221. package/src/cli/index.ts +2 -2
  222. package/src/cli/services/AlephaCliUtils.ts +105 -55
  223. package/src/cli/services/GitMessageParser.ts +1 -1
  224. package/src/command/helpers/Asker.spec.ts +127 -0
  225. package/src/command/helpers/Runner.spec.ts +126 -0
  226. package/src/command/helpers/Runner.ts +1 -1
  227. package/src/command/primitives/$command.spec.ts +1588 -0
  228. package/src/command/primitives/$command.ts +0 -6
  229. package/src/command/providers/CliProvider.ts +75 -27
  230. package/src/core/Alepha.ts +87 -0
  231. package/src/core/__tests__/Alepha-emit.spec.ts +22 -0
  232. package/src/core/__tests__/Alepha-graph.spec.ts +93 -0
  233. package/src/core/__tests__/Alepha-has.spec.ts +41 -0
  234. package/src/core/__tests__/Alepha-inject.spec.ts +93 -0
  235. package/src/core/__tests__/Alepha-register.spec.ts +81 -0
  236. package/src/core/__tests__/Alepha-start.spec.ts +176 -0
  237. package/src/core/__tests__/Alepha-with.spec.ts +14 -0
  238. package/src/core/__tests__/TypeBox-usecases.spec.ts +35 -0
  239. package/src/core/__tests__/TypeBoxLocale.spec.ts +15 -0
  240. package/src/core/__tests__/descriptor.spec.ts +34 -0
  241. package/src/core/__tests__/fixtures/A.ts +5 -0
  242. package/src/core/__tests__/pagination.spec.ts +77 -0
  243. package/src/core/helpers/jsonSchemaToTypeBox.ts +2 -2
  244. package/src/core/primitives/$atom.spec.ts +43 -0
  245. package/src/core/primitives/$hook.spec.ts +130 -0
  246. package/src/core/primitives/$inject.spec.ts +175 -0
  247. package/src/core/primitives/$module.spec.ts +115 -0
  248. package/src/core/providers/CodecManager.spec.ts +740 -0
  249. package/src/core/providers/EventManager.spec.ts +762 -0
  250. package/src/core/providers/EventManager.ts +4 -0
  251. package/src/core/providers/StateManager.spec.ts +365 -0
  252. package/src/core/providers/TypeProvider.spec.ts +1607 -0
  253. package/src/core/providers/TypeProvider.ts +20 -26
  254. package/src/datetime/primitives/$interval.spec.ts +103 -0
  255. package/src/datetime/providers/DateTimeProvider.spec.ts +86 -0
  256. package/src/email/primitives/$email.spec.ts +175 -0
  257. package/src/email/providers/LocalEmailProvider.spec.ts +341 -0
  258. package/src/fake/__tests__/keyName.example.ts +40 -0
  259. package/src/fake/__tests__/keyName.spec.ts +152 -0
  260. package/src/fake/__tests__/module.example.ts +32 -0
  261. package/src/fake/providers/FakeProvider.spec.ts +438 -0
  262. package/src/file/providers/FileSystemProvider.ts +8 -0
  263. package/src/file/providers/NodeFileSystemProvider.spec.ts +418 -0
  264. package/src/file/providers/NodeFileSystemProvider.ts +5 -0
  265. package/src/file/services/FileDetector.spec.ts +591 -0
  266. package/src/lock/core/__tests__/shared.ts +190 -0
  267. package/src/lock/core/providers/MemoryLockProvider.spec.ts +25 -0
  268. package/src/lock/redis/providers/RedisLockProvider.spec.ts +25 -0
  269. package/src/logger/__tests__/SimpleFormatterProvider.spec.ts +109 -0
  270. package/src/logger/index.ts +15 -3
  271. package/src/logger/primitives/$logger.spec.ts +108 -0
  272. package/src/logger/services/Logger.spec.ts +295 -0
  273. package/src/mcp/__tests__/errors.spec.ts +175 -0
  274. package/src/mcp/__tests__/integration.spec.ts +450 -0
  275. package/src/mcp/helpers/jsonrpc.spec.ts +380 -0
  276. package/src/mcp/primitives/$prompt.spec.ts +468 -0
  277. package/src/mcp/primitives/$resource.spec.ts +390 -0
  278. package/src/mcp/primitives/$tool.spec.ts +406 -0
  279. package/src/mcp/providers/McpServerProvider.spec.ts +797 -0
  280. package/src/mcp/transports/StdioMcpTransport.ts +1 -1
  281. package/src/orm/__tests__/$repository-crud.spec.ts +276 -0
  282. package/src/orm/__tests__/$repository-hooks.spec.ts +325 -0
  283. package/src/orm/__tests__/$repository-orderBy.spec.ts +128 -0
  284. package/src/orm/__tests__/$repository-pagination-sort.spec.ts +149 -0
  285. package/src/orm/__tests__/$repository-save.spec.ts +37 -0
  286. package/src/orm/__tests__/ModelBuilder-integration.spec.ts +490 -0
  287. package/src/orm/__tests__/ModelBuilder-types.spec.ts +186 -0
  288. package/src/orm/__tests__/PostgresProvider.spec.ts +46 -0
  289. package/src/orm/__tests__/delete-returning.spec.ts +256 -0
  290. package/src/orm/__tests__/deletedAt.spec.ts +80 -0
  291. package/src/orm/__tests__/enums.spec.ts +315 -0
  292. package/src/orm/__tests__/execute.spec.ts +72 -0
  293. package/src/orm/__tests__/fixtures/bigEntitySchema.ts +65 -0
  294. package/src/orm/__tests__/fixtures/userEntitySchema.ts +27 -0
  295. package/src/orm/__tests__/joins.spec.ts +1114 -0
  296. package/src/orm/__tests__/page.spec.ts +287 -0
  297. package/src/orm/__tests__/primaryKey.spec.ts +87 -0
  298. package/src/orm/__tests__/query-date-encoding.spec.ts +402 -0
  299. package/src/orm/__tests__/ref-auto-onDelete.spec.ts +156 -0
  300. package/src/orm/__tests__/references.spec.ts +102 -0
  301. package/src/orm/__tests__/security.spec.ts +710 -0
  302. package/src/orm/__tests__/sqlite.spec.ts +111 -0
  303. package/src/orm/__tests__/string-operators.spec.ts +429 -0
  304. package/src/orm/__tests__/timestamps.spec.ts +388 -0
  305. package/src/orm/__tests__/validation.spec.ts +183 -0
  306. package/src/orm/__tests__/version.spec.ts +64 -0
  307. package/src/orm/helpers/parseQueryString.spec.ts +196 -0
  308. package/src/orm/index.ts +2 -8
  309. package/src/orm/primitives/$repository.spec.ts +137 -0
  310. package/src/orm/primitives/$sequence.spec.ts +29 -0
  311. package/src/orm/primitives/$transaction.spec.ts +82 -0
  312. package/src/orm/providers/drivers/BunPostgresProvider.ts +3 -3
  313. package/src/orm/providers/drivers/BunSqliteProvider.ts +1 -1
  314. package/src/orm/providers/drivers/CloudflareD1Provider.ts +1 -1
  315. package/src/orm/providers/drivers/DatabaseProvider.ts +1 -1
  316. package/src/orm/providers/drivers/NodePostgresProvider.ts +3 -3
  317. package/src/orm/providers/drivers/NodeSqliteProvider.ts +1 -1
  318. package/src/orm/providers/drivers/PglitePostgresProvider.ts +2 -2
  319. package/src/orm/services/ModelBuilder.spec.ts +575 -0
  320. package/src/orm/services/Repository.spec.ts +137 -0
  321. package/src/queue/core/__tests__/shared.ts +143 -0
  322. package/src/queue/core/providers/MemoryQueueProvider.spec.ts +23 -0
  323. package/src/queue/core/providers/WorkerProvider.spec.ts +394 -0
  324. package/src/queue/redis/providers/RedisQueueProvider.spec.ts +23 -0
  325. package/src/redis/__tests__/redis.spec.ts +58 -0
  326. package/src/retry/primitives/$retry.spec.ts +234 -0
  327. package/src/retry/providers/RetryProvider.spec.ts +438 -0
  328. package/src/router/__tests__/match.spec.ts +252 -0
  329. package/src/router/providers/RouterProvider.spec.ts +197 -0
  330. package/src/scheduler/__tests__/$scheduler-cron.spec.ts +25 -0
  331. package/src/scheduler/__tests__/$scheduler-interval.spec.ts +25 -0
  332. package/src/scheduler/__tests__/shared.ts +77 -0
  333. package/src/security/__tests__/bug-1-wildcard-after-start.spec.ts +229 -0
  334. package/src/security/__tests__/bug-2-password-validation.spec.ts +245 -0
  335. package/src/security/__tests__/bug-3-regex-vulnerability.spec.ts +407 -0
  336. package/src/security/__tests__/bug-4-oauth2-validation.spec.ts +439 -0
  337. package/src/security/__tests__/multi-layer-permissions.spec.ts +522 -0
  338. package/src/security/primitives/$permission.spec.ts +30 -0
  339. package/src/security/primitives/$permission.ts +2 -2
  340. package/src/security/primitives/$realm.spec.ts +101 -0
  341. package/src/security/primitives/$role.spec.ts +52 -0
  342. package/src/security/primitives/$serviceAccount.spec.ts +61 -0
  343. package/src/security/providers/SecurityProvider.spec.ts +350 -0
  344. package/src/server/auth/providers/ServerAuthProvider.ts +0 -2
  345. package/src/server/cache/providers/ServerCacheProvider.spec.ts +1125 -0
  346. package/src/server/cache/providers/ServerCacheProvider.ts +94 -9
  347. package/src/server/compress/providers/ServerCompressProvider.spec.ts +31 -0
  348. package/src/server/compress/providers/ServerCompressProvider.ts +63 -2
  349. package/src/server/cookies/providers/ServerCookiesProvider.spec.ts +253 -0
  350. package/src/server/core/__tests__/ServerRouterProvider-getRoutes.spec.ts +334 -0
  351. package/src/server/core/__tests__/ServerRouterProvider-requestId.spec.ts +129 -0
  352. package/src/server/core/helpers/ServerReply.ts +2 -2
  353. package/src/server/core/primitives/$action.spec.ts +191 -0
  354. package/src/server/core/primitives/$route.spec.ts +65 -0
  355. package/src/server/core/providers/ServerBodyParserProvider.spec.ts +93 -0
  356. package/src/server/core/providers/ServerLoggerProvider.spec.ts +100 -0
  357. package/src/server/core/providers/ServerProvider.ts +14 -2
  358. package/src/server/core/services/HttpClient.spec.ts +123 -0
  359. package/src/server/core/services/UserAgentParser.spec.ts +111 -0
  360. package/src/server/cors/providers/ServerCorsProvider.spec.ts +481 -0
  361. package/src/server/health/providers/ServerHealthProvider.spec.ts +22 -0
  362. package/src/server/helmet/providers/ServerHelmetProvider.spec.ts +105 -0
  363. package/src/server/links/__tests__/$action.spec.ts +238 -0
  364. package/src/server/links/__tests__/fixtures/CrudApp.ts +122 -0
  365. package/src/server/links/__tests__/requestId.spec.ts +120 -0
  366. package/src/server/links/primitives/$remote.spec.ts +228 -0
  367. package/src/server/links/providers/LinkProvider.spec.ts +54 -0
  368. package/src/server/links/providers/LinkProvider.ts +49 -3
  369. package/src/server/links/providers/ServerLinksProvider.ts +1 -53
  370. package/src/server/links/schemas/apiLinksResponseSchema.ts +7 -0
  371. package/src/server/metrics/providers/ServerMetricsProvider.spec.ts +25 -0
  372. package/src/server/multipart/providers/ServerMultipartProvider.spec.ts +528 -0
  373. package/src/server/proxy/primitives/$proxy.spec.ts +87 -0
  374. package/src/server/rate-limit/__tests__/ActionRateLimit.spec.ts +211 -0
  375. package/src/server/rate-limit/providers/ServerRateLimitProvider.spec.ts +344 -0
  376. package/src/server/security/__tests__/BasicAuth.spec.ts +684 -0
  377. package/src/server/security/__tests__/ServerSecurityProvider-realm.spec.ts +388 -0
  378. package/src/server/security/providers/ServerSecurityProvider.spec.ts +123 -0
  379. package/src/server/static/primitives/$serve.spec.ts +193 -0
  380. package/src/server/static/providers/ServerStaticProvider.ts +10 -0
  381. package/src/server/swagger/__tests__/ui.spec.ts +52 -0
  382. package/src/server/swagger/primitives/$swagger.spec.ts +193 -0
  383. package/src/server/swagger/providers/ServerSwaggerProvider.ts +19 -12
  384. package/src/sms/primitives/$sms.spec.ts +165 -0
  385. package/src/sms/providers/LocalSmsProvider.spec.ts +224 -0
  386. package/src/sms/providers/MemorySmsProvider.spec.ts +193 -0
  387. package/src/thread/primitives/$thread.spec.ts +186 -0
  388. package/src/topic/core/__tests__/shared.ts +144 -0
  389. package/src/topic/core/providers/MemoryTopicProvider.spec.ts +23 -0
  390. package/src/topic/redis/providers/RedisTopicProvider.spec.ts +23 -0
  391. package/src/vite/helpers/importViteReact.ts +13 -0
  392. package/src/vite/index.ts +1 -21
  393. package/src/vite/plugins/viteAlephaDev.ts +32 -5
  394. package/src/vite/plugins/viteAlephaSsrPreload.ts +222 -0
  395. package/src/vite/tasks/buildClient.ts +11 -0
  396. package/src/vite/tasks/buildServer.ts +47 -3
  397. package/src/vite/tasks/devServer.ts +69 -0
  398. package/src/vite/tasks/index.ts +2 -1
  399. package/src/vite/tasks/runAlepha.ts +7 -1
  400. package/src/websocket/__tests__/$websocket-new.spec.ts +195 -0
  401. package/src/websocket/primitives/$channel.spec.ts +30 -0
  402. package/src/cli/assets/viteConfigTs.ts +0 -14
  403. package/src/cli/commands/run.ts +0 -24
  404. package/src/vite/plugins/viteAlepha.ts +0 -37
  405. package/src/vite/plugins/viteAlephaBuild.ts +0 -281
package/dist/cli/index.js CHANGED
@@ -1,17 +1,108 @@
1
- import { createRequire } from "node:module";
2
- import { join } from "node:path";
3
- import { $atom, $hook, $inject, $module, $use, Alepha, AlephaError, OPTIONS, t } from "alepha";
1
+ import { $atom, $hook, $inject, $module, $use, Alepha, AlephaError, t } from "alepha";
4
2
  import { FileSystemProvider } from "alepha/file";
5
3
  import { access, mkdir, readFile, readdir, unlink, writeFile } from "node:fs/promises";
4
+ import { join } from "node:path";
6
5
  import { $command, CliProvider, EnvUtils } from "alepha/command";
7
- import { $logger } from "alepha/logger";
8
- import { boot, buildClient, buildServer, copyAssets, generateCloudflare, generateDocker, generateSitemap, generateVercel, prerenderPages } from "alepha/vite";
6
+ import { $logger, ConsoleColorProvider } from "alepha/logger";
7
+ import { boot, buildClient, buildServer, copyAssets, devServer, generateCloudflare, generateDocker, generateSitemap, generateVercel, prerenderPages } from "alepha/vite";
9
8
  import { exec, spawn } from "node:child_process";
10
- import { tsImport } from "tsx/esm/api";
11
9
  import { readFileSync } from "node:fs";
12
10
  import { promisify } from "node:util";
11
+ import { ServerSwaggerProvider } from "alepha/server/swagger";
13
12
  import * as os from "node:os";
14
13
 
14
+ //#region ../../src/core/constants/KIND.ts
15
+ /**
16
+ * Used for identifying primitives.
17
+ *
18
+ * @internal
19
+ */
20
+ const KIND = Symbol.for("Alepha.Kind");
21
+
22
+ //#endregion
23
+ //#region ../../src/core/primitives/$atom.ts
24
+ /**
25
+ * Define an atom for state management.
26
+ *
27
+ * Atom lets you define a piece of state with a name, schema, and default value.
28
+ *
29
+ * By default, Alepha state is just a simple key-value store.
30
+ * Using atoms allows you to have type safety, validation, and default values for your state.
31
+ *
32
+ * You control how state is structured and validated.
33
+ *
34
+ * Features:
35
+ * - Set a schema for validation
36
+ * - Set a default value for initial state
37
+ * - Rules, like read-only, custom validation, etc.
38
+ * - Automatic getter access in services with {@link $use}
39
+ * - SSR support (server state automatically serialized and hydrated on client)
40
+ * - React integration (useAtom hook for automatic component re-renders)
41
+ * - Middleware
42
+ * - Persistence adapters (localStorage, Redis, database, file system, cookie, etc.)
43
+ * - State migrations (version upgrades when schema changes)
44
+ * - Documentation generation & devtools integration
45
+ *
46
+ * Common use cases:
47
+ * - user preferences
48
+ * - feature flags
49
+ * - configuration options
50
+ * - session data
51
+ *
52
+ * Atom must contain only serializable data.
53
+ * Avoid storing complex objects like class instances, functions, or DOM elements.
54
+ * If you need to store complex data, consider using identifiers or references instead.
55
+ */
56
+ const $atom$1 = (options) => {
57
+ return new Atom(options);
58
+ };
59
+ var Atom = class {
60
+ options;
61
+ get schema() {
62
+ return this.options.schema;
63
+ }
64
+ get key() {
65
+ return this.options.name;
66
+ }
67
+ constructor(options) {
68
+ this.options = options;
69
+ }
70
+ };
71
+ $atom$1[KIND] = "atom";
72
+
73
+ //#endregion
74
+ //#region ../../src/cli/atoms/buildOptions.ts
75
+ /**
76
+ * Build options atom for CLI build command.
77
+ *
78
+ * Defines the available build configuration options with their defaults.
79
+ * Options can be overridden via vite.config.ts or CLI flags.
80
+ */
81
+ const buildOptions = $atom$1({
82
+ name: "alepha.build.options",
83
+ description: "Build configuration options",
84
+ schema: t.object({
85
+ stats: t.optional(t.boolean({ default: false })),
86
+ vercel: t.optional(t.object({
87
+ projectName: t.optional(t.string()),
88
+ orgId: t.optional(t.string()),
89
+ projectId: t.optional(t.string()),
90
+ config: t.optional(t.object({ crons: t.optional(t.array(t.object({
91
+ path: t.string(),
92
+ schedule: t.string()
93
+ }))) }))
94
+ })),
95
+ cloudflare: t.optional(t.object({ config: t.optional(t.json()) })),
96
+ docker: t.optional(t.object({
97
+ image: t.optional(t.string({ default: "node:24-alpine" })),
98
+ command: t.optional(t.string({ default: "node" }))
99
+ })),
100
+ sitemap: t.optional(t.object({ hostname: t.string() }))
101
+ }),
102
+ default: {}
103
+ });
104
+
105
+ //#endregion
15
106
  //#region ../../src/cli/assets/appRouterTs.ts
16
107
  const appRouterTs = () => `
17
108
  import { $page } from "@alepha/react/router";
@@ -138,21 +229,6 @@ const tsconfigJson = `
138
229
  }
139
230
  `.trim();
140
231
 
141
- //#endregion
142
- //#region ../../src/cli/assets/viteConfigTs.ts
143
- const viteConfigTs = (serverEntry) => `
144
- import { viteAlepha } from "alepha/vite";
145
-
146
- export default {
147
- plugins: [
148
- viteAlepha(${serverEntry ? `{ serverEntry: "${serverEntry}" }` : ""}),
149
- ],
150
- test: {
151
- globals: true,
152
- },
153
- };
154
- `.trim();
155
-
156
232
  //#endregion
157
233
  //#region ../../src/cli/version.ts
158
234
  const packageJson = JSON.parse(readFileSync(new URL("../../package.json", import.meta.url), "utf-8"));
@@ -174,6 +250,7 @@ var AlephaCliUtils = class {
174
250
  log = $logger();
175
251
  fs = $inject(FileSystemProvider);
176
252
  envUtils = $inject(EnvUtils);
253
+ alepha = $inject(Alepha);
177
254
  /**
178
255
  * Execute a command using npx with inherited stdio.
179
256
  *
@@ -235,6 +312,54 @@ var AlephaCliUtils = class {
235
312
  this.log.debug(`Config file written: ${path}`);
236
313
  return path;
237
314
  }
315
+ async editFile(root, name, editFn) {
316
+ const filePath = join(root, name);
317
+ try {
318
+ await writeFile(filePath, await editFn(await readFile(filePath, "utf8")));
319
+ } catch (error) {
320
+ this.log.debug("Could not edit file", error);
321
+ }
322
+ }
323
+ async editJsonFile(root, name, editFn) {
324
+ return await this.editFile(root, name, async (content) => {
325
+ const newObj = await editFn(JSON.parse(content));
326
+ return JSON.stringify(newObj, null, 2);
327
+ });
328
+ }
329
+ async removeFiles(root, files) {
330
+ await Promise.all(files.map((file) => this.fs.rm(join(root, file), {
331
+ force: true,
332
+ recursive: true
333
+ })));
334
+ }
335
+ async removeYarn(root) {
336
+ await this.removeFiles(root, [
337
+ ".yarn",
338
+ ".yarnrc.yml",
339
+ "yarn.lock"
340
+ ]);
341
+ await this.editJsonFile(root, "package.json", (pkg) => {
342
+ delete pkg.packageManager;
343
+ });
344
+ }
345
+ async removePnpm(root) {
346
+ await this.removeFiles(root, ["pnpm-lock.yaml", "pnpm-workspace.yaml"]);
347
+ await this.editJsonFile(root, "package.json", (pkg) => {
348
+ delete pkg.packageManager;
349
+ });
350
+ }
351
+ async removeNpm(root) {
352
+ await this.removeFiles(root, ["package-lock.json"]);
353
+ }
354
+ async removeBun(root) {
355
+ await this.removeFiles(root, ["bun.lockb", "bun.lock"]);
356
+ }
357
+ async removeAllPmFilesExcept(root, except) {
358
+ if (except !== "yarn") await this.removeYarn(root);
359
+ if (except !== "pnpm") await this.removePnpm(root);
360
+ if (except !== "npm") await this.removeNpm(root);
361
+ if (except !== "bun") await this.removeBun(root);
362
+ }
238
363
  /**
239
364
  * Ensure Yarn is configured in the project directory.
240
365
  *
@@ -244,26 +369,16 @@ var AlephaCliUtils = class {
244
369
  */
245
370
  async ensureYarn(root) {
246
371
  await this.ensureFileExists(root, ".yarnrc.yml", "nodeLinker: node-modules", false);
247
- await this.fs.rm(join(root, "package-lock.json"), { force: true });
248
- await this.fs.rm(join(root, "pnpm-lock.yaml"), { force: true });
372
+ await this.removeAllPmFilesExcept(root, "yarn");
373
+ }
374
+ async ensureBun(root) {
375
+ await this.removeAllPmFilesExcept(root, "bun");
249
376
  }
250
377
  async ensurePnpm(root) {
251
- await this.fs.rm(join(root, "package-lock.json"), { force: true });
252
- await this.fs.rm(join(root, "yarn.lock"), { force: true });
253
- await this.fs.rm(join(root, ".yarn"), {
254
- force: true,
255
- recursive: true
256
- });
257
- await this.fs.rm(join(root, ".yarnrc.yml"), { force: true });
378
+ await this.removeAllPmFilesExcept(root, "pnpm");
258
379
  }
259
380
  async ensureNpm(root) {
260
- await this.fs.rm(join(root, "pnpm-lock.yaml"), { force: true });
261
- await this.fs.rm(join(root, "yarn.lock"), { force: true });
262
- await this.fs.rm(join(root, ".yarn"), {
263
- force: true,
264
- recursive: true
265
- });
266
- await this.fs.rm(join(root, ".yarnrc.yml"), { force: true });
381
+ await this.removeAllPmFilesExcept(root, "npm");
267
382
  }
268
383
  /**
269
384
  * Generate package.json content with Alepha dependencies.
@@ -335,7 +450,6 @@ var AlephaCliUtils = class {
335
450
  const tasks = [];
336
451
  if (opts.packageJson) tasks.push(this.ensurePackageJson(root, typeof opts.packageJson === "boolean" ? {} : opts.packageJson));
337
452
  if (opts.tsconfigJson) tasks.push(this.ensureTsConfig(root));
338
- if (opts.viteConfigTs) tasks.push(this.ensureViteConfig(root));
339
453
  if (opts.indexHtml) tasks.push(this.ensureIndexHtml(root));
340
454
  if (opts.biomeJson) tasks.push(this.ensureBiomeConfig(root));
341
455
  if (opts.editorconfig) tasks.push(this.ensureEditorConfig(root));
@@ -351,14 +465,6 @@ var AlephaCliUtils = class {
351
465
  async ensureTsConfig(root) {
352
466
  await this.ensureFileExists(root, "tsconfig.json", tsconfigJson, true);
353
467
  }
354
- /**
355
- * Ensure vite.config.ts exists in the project.
356
- *
357
- * Creates a standard Alepha vite.config.ts if none exists.
358
- */
359
- async ensureViteConfig(root, serverEntry) {
360
- await this.ensureFileExists(root, "vite.config.ts", viteConfigTs(serverEntry), false);
361
- }
362
468
  async checkFileExists(root, name, checkParentDirectories = false) {
363
469
  const configPath = join(root, name);
364
470
  if (!checkParentDirectories) try {
@@ -418,7 +524,8 @@ var AlephaCliUtils = class {
418
524
  async loadAlephaFromServerEntryFile(rootDir, explicitEntry) {
419
525
  process.env.ALEPHA_CLI_IMPORT = "true";
420
526
  const entry = await boot.getServerEntry(rootDir, explicitEntry);
421
- const mod = await tsImport(entry, { parentURL: import.meta.url });
527
+ delete global.__alepha;
528
+ const mod = await import(entry);
422
529
  this.log.debug(`Load entry: ${entry}`);
423
530
  if (mod.default instanceof Alepha) return {
424
531
  alepha: mod.default,
@@ -470,6 +577,7 @@ ${models.map((it) => `export const ${it} = models["${it}"];`).join("\n")}
470
577
  if (flags?.pnpm) return "pnpm";
471
578
  if (flags?.npm) return "npm";
472
579
  if (flags?.bun) return "bun";
580
+ if (this.alepha.isBun()) return "bun";
473
581
  if (await this.checkFileExists(root, "yarn.lock", true)) return "yarn";
474
582
  if (await this.checkFileExists(root, "pnpm-lock.yaml", true)) return "pnpm";
475
583
  return "npm";
@@ -527,7 +635,7 @@ ${models.map((it) => `export const ${it} = models["${it}"];`).join("\n")}
527
635
  if ((await this.fs.ls(testDir)).length === 0) await this.fs.writeFile(dummyPath, dummySpecTs());
528
636
  }
529
637
  async readPackageJson(root) {
530
- const packageJson$1 = await this.fs.createFile({ path: join(root, "package.json") }).text();
638
+ const packageJson$1 = await this.fs.createFile({ path: this.fs.join(root, "package.json") }).text();
531
639
  return JSON.parse(packageJson$1);
532
640
  }
533
641
  /**
@@ -554,6 +662,23 @@ ${models.map((it) => `export const ${it} = models["${it}"];`).join("\n")}
554
662
  async hasExpo(root) {
555
663
  return this.hasDependency(root, "expo");
556
664
  }
665
+ async getInstallCommand(root, packageName, dev = true) {
666
+ const pm = await this.getPackageManager(root);
667
+ let cmd;
668
+ switch (pm) {
669
+ case "yarn":
670
+ cmd = `yarn add ${dev ? "-D" : ""} ${packageName}`;
671
+ break;
672
+ case "pnpm":
673
+ cmd = `pnpm add ${dev ? "-D" : ""} ${packageName}`;
674
+ break;
675
+ case "bun":
676
+ cmd = `bun add ${dev ? "-d" : ""} ${packageName}`;
677
+ break;
678
+ default: cmd = `npm install ${dev ? "--save-dev" : ""} ${packageName}`;
679
+ }
680
+ return cmd.replace(/\s+/g, " ").trim();
681
+ }
557
682
  /**
558
683
  * Install a dependency if it's missing from the project.
559
684
  *
@@ -566,18 +691,7 @@ ${models.map((it) => `export const ${it} = models["${it}"];`).join("\n")}
566
691
  this.log.debug(`Dependency '${packageName}' is already installed`);
567
692
  return;
568
693
  }
569
- const pm = await this.getPackageManager(root);
570
- let cmd;
571
- switch (pm) {
572
- case "yarn":
573
- cmd = `yarn add ${dev ? "-D" : ""} ${packageName}`;
574
- break;
575
- case "pnpm":
576
- cmd = `pnpm add ${dev ? "-D" : ""} ${packageName}`;
577
- break;
578
- default: cmd = `npm install ${dev ? "--save-dev" : ""} ${packageName}`;
579
- }
580
- cmd = cmd.replace(/\s+/g, " ").trim();
694
+ const cmd = await this.getInstallCommand(root, packageName, dev);
581
695
  if (options.run) await options.run(cmd, { alias: `installing ${packageName}` });
582
696
  else {
583
697
  this.log.debug(`Installing ${packageName}`);
@@ -591,8 +705,10 @@ ${models.map((it) => `export const ${it} = models["${it}"];`).join("\n")}
591
705
  var BuildCommand = class {
592
706
  log = $logger();
593
707
  utils = $inject(AlephaCliUtils);
708
+ options = $use(buildOptions);
594
709
  build = $command({
595
710
  name: "build",
711
+ mode: "production",
596
712
  description: "Build the project for production",
597
713
  args: t.optional(t.text({
598
714
  title: "path",
@@ -609,33 +725,28 @@ var BuildCommand = class {
609
725
  process.env.ALEPHA_BUILD_MODE = "cli";
610
726
  process.env.NODE_ENV = "production";
611
727
  if (await this.utils.hasExpo(root)) return;
612
- await this.utils.ensureConfig(root, {
613
- viteConfigTs: true,
614
- tsconfigJson: true
615
- });
728
+ await this.utils.ensureConfig(root, { tsconfigJson: true });
616
729
  const entry = await boot.getServerEntry(root, args);
617
730
  this.log.trace("Entry file found", { entry });
618
731
  const distDir = "dist";
619
732
  const clientDir = "public";
620
733
  await this.utils.ensureDependency(root, "vite", { run });
621
734
  await run.rm("dist", { alias: "clean dist" });
622
- const viteAlephaBuildOptions = (await createRequire(import.meta.url)("vite").resolveConfig({}, "build", "production")).plugins.find((it) => it.name === "alepha:build")?.[OPTIONS] || {};
735
+ const options = this.options;
623
736
  await this.utils.loadEnv(root, [".env", ".env.production"]);
624
- const stats = flags.stats ?? viteAlephaBuildOptions.stats ?? false;
625
- const hasServer = viteAlephaBuildOptions.serverEntry !== false;
737
+ const stats = flags.stats ?? options.stats ?? false;
626
738
  let hasClient = false;
627
739
  try {
628
740
  await access(join(root, "index.html"));
629
741
  hasClient = true;
630
742
  } catch {}
631
- const clientOptions = typeof viteAlephaBuildOptions.client === "object" ? viteAlephaBuildOptions.client : {};
632
743
  if (hasClient) await run({
633
744
  name: "vite build client",
634
745
  handler: () => buildClient({
635
746
  silent: true,
636
747
  dist: `${distDir}/${clientDir}`,
637
748
  stats,
638
- precompress: clientOptions.precompress
749
+ precompress: true
639
750
  })
640
751
  });
641
752
  await run({
@@ -653,7 +764,7 @@ var BuildCommand = class {
653
764
  clientDir: clientBuilt ? clientDir : void 0,
654
765
  stats
655
766
  });
656
- if (clientBuilt && hasServer) await unlink(`${distDir}/${clientDir}/index.html`);
767
+ if (clientBuilt) await unlink(`${distDir}/${clientDir}/index.html`);
657
768
  }
658
769
  });
659
770
  await copyAssets({
@@ -663,304 +774,79 @@ var BuildCommand = class {
663
774
  run
664
775
  });
665
776
  if (hasClient) {
666
- const sitemapBaseUrl = flags.sitemap ?? clientOptions.sitemap?.hostname;
667
- if (sitemapBaseUrl) await run({
777
+ const sitemapHostname = flags.sitemap ?? options.sitemap?.hostname;
778
+ if (sitemapHostname) await run({
668
779
  name: "add sitemap",
669
780
  handler: async () => {
670
781
  await writeFile(`${distDir}/${clientDir}/sitemap.xml`, await generateSitemap({
671
782
  entry: `${distDir}/index.js`,
672
- baseUrl: sitemapBaseUrl
783
+ baseUrl: sitemapHostname
673
784
  }));
674
785
  }
675
786
  });
676
- if (clientOptions.prerender) await run({
787
+ await run({
677
788
  name: "pre-render pages",
678
789
  handler: async () => {
679
790
  await prerenderPages({
680
791
  dist: `${distDir}/${clientDir}`,
681
792
  entry: `${distDir}/index.js`,
682
- compress: clientOptions.precompress
793
+ compress: true
683
794
  });
684
795
  }
685
796
  });
686
797
  }
687
- if (flags.vercel || viteAlephaBuildOptions.vercel) {
688
- const config = typeof viteAlephaBuildOptions.vercel === "object" ? viteAlephaBuildOptions.vercel : {};
689
- await run({
690
- name: "add Vercel config",
691
- handler: () => generateVercel({
692
- distDir,
693
- clientDir,
694
- config
695
- })
696
- });
697
- }
698
- if (flags.cloudflare || viteAlephaBuildOptions.cloudflare) {
699
- const config = typeof viteAlephaBuildOptions.cloudflare === "boolean" ? {} : viteAlephaBuildOptions.cloudflare;
700
- await run({
701
- name: "add Cloudflare config",
702
- handler: () => generateCloudflare({
703
- distDir,
704
- config
705
- })
706
- });
707
- }
708
- if (flags.docker || viteAlephaBuildOptions.docker) {
709
- const dockerConfig = typeof viteAlephaBuildOptions.docker === "object" ? viteAlephaBuildOptions.docker : {};
710
- await run({
711
- name: "add Docker config",
712
- handler: () => generateDocker({
713
- distDir,
714
- ...dockerConfig
715
- })
716
- });
717
- }
798
+ if (flags.vercel || options.vercel) await run({
799
+ name: "add Vercel config",
800
+ handler: () => generateVercel({
801
+ distDir,
802
+ clientDir,
803
+ config: options.vercel
804
+ })
805
+ });
806
+ if (flags.cloudflare || options.cloudflare) await run({
807
+ name: "add Cloudflare config",
808
+ handler: () => generateCloudflare({
809
+ distDir,
810
+ config: options.cloudflare?.config
811
+ })
812
+ });
813
+ if (flags.docker || options.docker) await run({
814
+ name: "add Docker config",
815
+ handler: () => generateDocker({
816
+ distDir,
817
+ ...options.docker
818
+ })
819
+ });
718
820
  }
719
821
  });
720
822
  };
721
823
 
722
824
  //#endregion
723
- //#region ../../src/cli/atoms/changelogOptions.ts
724
- /**
725
- * Default scopes to ignore in changelog generation.
726
- * Commits with these scopes won't appear in release notes.
727
- */
728
- const DEFAULT_IGNORE = [
729
- "project",
730
- "release",
731
- "starter",
732
- "example",
733
- "chore",
734
- "ci",
735
- "build",
736
- "test",
737
- "style"
738
- ];
739
- /**
740
- * Changelog configuration atom.
741
- *
742
- * Configure in `alepha.config.ts`:
743
- * ```ts
744
- * import { changelogOptions } from "alepha/cli";
745
- *
746
- * alepha.set(changelogOptions, {
747
- * ignore: ["project", "release", "chore", "docs"],
748
- * });
749
- * ```
750
- */
751
- const changelogOptions = $atom({
752
- name: "alepha.changelog",
753
- schema: t.object({ ignore: t.optional(t.array(t.string())) }),
754
- default: { ignore: DEFAULT_IGNORE }
755
- });
756
-
757
- //#endregion
758
- //#region ../../src/cli/services/GitMessageParser.ts
759
- /**
760
- * Service for parsing git commit messages into structured format.
761
- *
762
- * Only parses **conventional commits with a scope**:
763
- * - `feat(scope): description` → feature
764
- * - `fix(scope): description` → bug fix
765
- * - `feat(scope)!: description` → breaking change
766
- *
767
- * Commits without scope are ignored, allowing developers to commit
768
- * work-in-progress changes without polluting release notes:
769
- * - `cli: work in progress` → ignored (no type)
770
- * - `fix: quick patch` → ignored (no scope)
771
- * - `feat(cli): add command` → included
772
- */
773
- var GitMessageParser = class {
774
- log = $logger();
825
+ //#region ../../src/cli/commands/clean.ts
826
+ var CleanCommand = class {
775
827
  /**
776
- * Parse a git commit line into a structured Commit object.
777
- *
778
- * **Format:** `type(scope): description` or `type(scope)!: description`
779
- *
780
- * **Supported types:** feat, fix, docs, refactor, perf, revert
781
- *
782
- * **Breaking changes:** Use `!` before `:` (e.g., `feat(api)!: remove endpoint`)
783
- *
784
- * @returns Commit object or null if not matching/ignored
828
+ * Clean the project, removing the "dist" directory
785
829
  */
786
- parseCommit(line, config) {
787
- const match = line.match(/^([a-f0-9]+)\s+(.+)$/);
788
- if (!match) return null;
789
- const [, hash, message] = match;
790
- const ignore = config.ignore ?? DEFAULT_IGNORE;
791
- const conventionalMatch = message.match(/^(feat|fix|docs|refactor|perf|revert)\(([^)]+)\)(!)?:\s*(.+)$/i);
792
- if (!conventionalMatch) return null;
793
- const [, type, scope, breakingMark, description] = conventionalMatch;
794
- const baseScope = scope.split("/")[0];
795
- if (ignore.includes(baseScope) || ignore.includes(scope)) return null;
796
- const breaking = breakingMark === "!" || description.toLowerCase().includes("breaking");
797
- return {
798
- hash: hash.substring(0, 8),
799
- type: type.toLowerCase(),
800
- scope,
801
- description: description.trim(),
802
- breaking
803
- };
804
- }
830
+ clean = $command({
831
+ name: "clean",
832
+ description: "Clean the project",
833
+ handler: async ({ run }) => {
834
+ await run.rm("./dist");
835
+ }
836
+ });
805
837
  };
806
838
 
807
839
  //#endregion
808
- //#region ../../src/cli/commands/changelog.ts
809
- const execAsync = promisify(exec);
810
- /**
811
- * Git provider for executing git commands.
812
- * Can be substituted in tests with a mock implementation.
813
- */
814
- var GitProvider = class {
815
- async exec(cmd, cwd) {
816
- const { stdout } = await execAsync(`git ${cmd}`, { cwd });
817
- return stdout;
818
- }
819
- };
820
- /**
821
- * Changelog command for generating release notes from git commits.
822
- *
823
- * Usage:
824
- * - `alepha changelog` - Show unreleased changes since latest tag to HEAD
825
- * - `alepha changelog --from=1.0.0` - Show changes from version to HEAD
826
- * - `alepha changelog --from=1.0.0 --to=1.1.0` - Show changes between two refs
827
- * - `alepha changelog | tee -a CHANGELOG.md` - Append to file
828
- */
829
- var ChangelogCommand = class {
840
+ //#region ../../src/cli/commands/db.ts
841
+ const drizzleCommandFlags = t.object({
842
+ provider: t.optional(t.text({ description: "Database provider name to target (e.g., 'postgres', 'sqlite')" })),
843
+ mode: t.optional(t.text({ description: "Environment variable file(s) to load (e.g., 'production' to load .env.production) https://vite.dev/guide/env-and-mode" }))
844
+ });
845
+ var DbCommand = class {
830
846
  log = $logger();
831
- git = $inject(GitProvider);
832
- parser = $inject(GitMessageParser);
833
- config = $use(changelogOptions);
834
- /**
835
- * Format a single commit line.
836
- * Example: `- **cli**: add new command (\`abc1234\`)`
837
- * Breaking changes are flagged: `- **cli**: add new command [BREAKING] (\`abc1234\`)`
838
- */
839
- formatCommit(commit) {
840
- const breaking = commit.breaking ? " [BREAKING]" : "";
841
- return `- **${commit.scope}**: ${commit.description}${breaking} (\`${commit.hash}\`)`;
842
- }
843
- /**
844
- * Format the changelog entry with sections.
845
- */
846
- formatEntry(entry) {
847
- const sections = [];
848
- if (entry.features.length > 0) {
849
- sections.push("### Features\n");
850
- for (const commit of entry.features) sections.push(this.formatCommit(commit));
851
- sections.push("");
852
- }
853
- if (entry.fixes.length > 0) {
854
- sections.push("### Bug Fixes\n");
855
- for (const commit of entry.fixes) sections.push(this.formatCommit(commit));
856
- sections.push("");
857
- }
858
- return sections.join("\n");
859
- }
847
+ utils = $inject(AlephaCliUtils);
860
848
  /**
861
- * Parse git log output into a changelog entry.
862
- */
863
- parseCommits(commitsOutput) {
864
- const entry = {
865
- features: [],
866
- fixes: []
867
- };
868
- for (const line of commitsOutput.trim().split("\n")) {
869
- if (!line.trim()) continue;
870
- const commit = this.parser.parseCommit(line, this.config);
871
- if (!commit) {
872
- this.log.trace("Skipping commit", { line });
873
- continue;
874
- }
875
- this.log.trace("Parsed commit", { commit });
876
- if (commit.type === "feat") entry.features.push(commit);
877
- else if (commit.type === "fix") entry.fixes.push(commit);
878
- }
879
- return entry;
880
- }
881
- /**
882
- * Check if entry has any public commits.
883
- */
884
- hasChanges(entry) {
885
- return entry.features.length > 0 || entry.fixes.length > 0;
886
- }
887
- /**
888
- * Get the latest version tag.
889
- */
890
- async getLatestTag(git) {
891
- return (await git("tag --sort=-version:refname")).trim().split("\n").filter((tag) => tag.match(/^\d+\.\d+\.\d+$/))[0] || null;
892
- }
893
- changelog = $command({
894
- name: "changelog",
895
- description: "Generate changelog from conventional commits (outputs to stdout)",
896
- flags: t.object({
897
- from: t.optional(t.string({
898
- aliases: ["f"],
899
- description: "Starting ref (default: latest tag)"
900
- })),
901
- to: t.optional(t.string({
902
- aliases: ["t"],
903
- description: "Ending ref (default: HEAD)"
904
- }))
905
- }),
906
- handler: async ({ flags, root }) => {
907
- const git = (cmd) => this.git.exec(cmd, root);
908
- let fromRef;
909
- if (flags.from) {
910
- fromRef = flags.from;
911
- this.log.debug("Using specified from ref", { from: fromRef });
912
- } else {
913
- const latestTag = await this.getLatestTag(git);
914
- if (!latestTag) {
915
- process.stdout.write("No version tags found in repository\n");
916
- return;
917
- }
918
- fromRef = latestTag;
919
- this.log.debug("Using latest tag", { from: fromRef });
920
- }
921
- const toRef = flags.to || "HEAD";
922
- this.log.debug("Using to ref", { to: toRef });
923
- const commitsOutput = await git(`log ${fromRef}..${toRef} --oneline`);
924
- if (!commitsOutput.trim()) {
925
- process.stdout.write(`No changes in range ${fromRef}..${toRef}\n`);
926
- return;
927
- }
928
- const entry = this.parseCommits(commitsOutput);
929
- if (!this.hasChanges(entry)) {
930
- process.stdout.write(`No public changes in range ${fromRef}..${toRef}\n`);
931
- return;
932
- }
933
- process.stdout.write(this.formatEntry(entry));
934
- }
935
- });
936
- };
937
-
938
- //#endregion
939
- //#region ../../src/cli/commands/clean.ts
940
- var CleanCommand = class {
941
- /**
942
- * Clean the project, removing the "dist" directory
943
- */
944
- clean = $command({
945
- name: "clean",
946
- description: "Clean the project",
947
- handler: async ({ run }) => {
948
- await run.rm("./dist");
949
- }
950
- });
951
- };
952
-
953
- //#endregion
954
- //#region ../../src/cli/commands/db.ts
955
- const drizzleCommandFlags = t.object({
956
- provider: t.optional(t.text({ description: "Database provider name to target (e.g., 'postgres', 'sqlite')" })),
957
- mode: t.optional(t.text({ description: "Environment variable file(s) to load (e.g., 'production' to load .env.production) https://vite.dev/guide/env-and-mode" }))
958
- });
959
- var DbCommand = class {
960
- log = $logger();
961
- utils = $inject(AlephaCliUtils);
962
- /**
963
- * Check if database migrations are up to date.
849
+ * Check if database migrations are up to date.
964
850
  */
965
851
  check = $command({
966
852
  name: "check-migrations",
@@ -1026,7 +912,6 @@ var DbCommand = class {
1026
912
  generate = $command({
1027
913
  name: "generate",
1028
914
  description: "Generate migration files based on current database schema",
1029
- summary: false,
1030
915
  args: t.optional(t.text({
1031
916
  title: "path",
1032
917
  description: "Path to the Alepha server entry file"
@@ -1051,7 +936,6 @@ var DbCommand = class {
1051
936
  push = $command({
1052
937
  name: "push",
1053
938
  description: "Push database schema changes directly to the database",
1054
- summary: false,
1055
939
  args: t.optional(t.text({
1056
940
  title: "path",
1057
941
  description: "Path to the Alepha server entry file"
@@ -1074,7 +958,6 @@ var DbCommand = class {
1074
958
  migrate = $command({
1075
959
  name: "migrate",
1076
960
  description: "Apply pending database migrations",
1077
- summary: false,
1078
961
  args: t.optional(t.text({
1079
962
  title: "path",
1080
963
  description: "Path to the Alepha server entry file"
@@ -1097,7 +980,6 @@ var DbCommand = class {
1097
980
  studio = $command({
1098
981
  name: "studio",
1099
982
  description: "Launch Drizzle Studio database browser",
1100
- summary: false,
1101
983
  args: t.optional(t.text({
1102
984
  title: "path",
1103
985
  description: "Path to the Alepha server entry file"
@@ -1295,6 +1177,7 @@ var DeployCommand = class {
1295
1177
  var DevCommand = class {
1296
1178
  log = $logger();
1297
1179
  utils = $inject(AlephaCliUtils);
1180
+ alepha = $inject(Alepha);
1298
1181
  /**
1299
1182
  * Will run the project in watch mode.
1300
1183
  *
@@ -1310,30 +1193,42 @@ var DevCommand = class {
1310
1193
  })),
1311
1194
  handler: async ({ args, root }) => {
1312
1195
  const expo = await this.utils.hasExpo(root);
1313
- await this.utils.ensureConfig(root, {
1314
- viteConfigTs: !expo,
1315
- tsconfigJson: true
1316
- });
1196
+ await this.utils.ensureConfig(root, { tsconfigJson: true });
1317
1197
  if (expo) {
1318
1198
  await this.utils.exec("expo start");
1319
1199
  return;
1320
1200
  }
1321
1201
  const entry = await boot.getServerEntry(root, args);
1322
1202
  this.log.trace("Entry file found", { entry });
1323
- try {
1324
- await access(join(root, "index.html"));
1325
- } catch {
1326
- this.log.trace("No index.html found, running entry file with tsx");
1327
- let cmd = "tsx --watch";
1203
+ if (!await this.isFullstackProject(root)) {
1204
+ const exe = await this.isBunProject(root) ? "bun" : "tsx";
1205
+ let cmd = `${exe} --watch`;
1328
1206
  if (await this.utils.exists(root, ".env")) cmd += " --env-file=./.env";
1329
1207
  cmd += ` ${entry}`;
1330
- await this.utils.exec(cmd);
1208
+ await this.utils.exec(cmd, { global: exe === "bun" });
1331
1209
  return;
1332
1210
  }
1333
1211
  await this.utils.ensureDependency(root, "vite");
1334
- await this.utils.exec("vite");
1212
+ await devServer();
1335
1213
  }
1336
1214
  });
1215
+ async isBunProject(root) {
1216
+ if (this.alepha.isBun()) return true;
1217
+ try {
1218
+ await access(join(root, "bun.lock"));
1219
+ return true;
1220
+ } catch {
1221
+ return false;
1222
+ }
1223
+ }
1224
+ async isFullstackProject(root) {
1225
+ try {
1226
+ await access(join(root, "index.html"));
1227
+ return true;
1228
+ } catch {
1229
+ return false;
1230
+ }
1231
+ }
1337
1232
  };
1338
1233
 
1339
1234
  //#endregion
@@ -1351,6 +1246,316 @@ var FormatCommand = class {
1351
1246
  });
1352
1247
  };
1353
1248
 
1249
+ //#endregion
1250
+ //#region ../../src/cli/atoms/changelogOptions.ts
1251
+ /**
1252
+ * Default scopes to ignore in changelog generation.
1253
+ * Commits with these scopes won't appear in release notes.
1254
+ */
1255
+ const DEFAULT_IGNORE = [
1256
+ "project",
1257
+ "release",
1258
+ "starter",
1259
+ "example",
1260
+ "chore",
1261
+ "ci",
1262
+ "build",
1263
+ "test",
1264
+ "style"
1265
+ ];
1266
+ /**
1267
+ * Changelog configuration atom.
1268
+ *
1269
+ * Configure in `alepha.config.ts`:
1270
+ * ```ts
1271
+ * import { changelogOptions } from "alepha/cli";
1272
+ *
1273
+ * alepha.set(changelogOptions, {
1274
+ * ignore: ["project", "release", "chore", "docs"],
1275
+ * });
1276
+ * ```
1277
+ */
1278
+ const changelogOptions = $atom({
1279
+ name: "alepha.changelog",
1280
+ schema: t.object({ ignore: t.optional(t.array(t.string())) }),
1281
+ default: { ignore: DEFAULT_IGNORE }
1282
+ });
1283
+
1284
+ //#endregion
1285
+ //#region ../../src/cli/services/GitMessageParser.ts
1286
+ /**
1287
+ * Service for parsing git commit messages into structured format.
1288
+ *
1289
+ * Only parses **conventional commits with a scope**:
1290
+ * - `feat(scope): description` → feature
1291
+ * - `fix(scope): description` → bug fix
1292
+ * - `feat(scope)!: description` → breaking change
1293
+ *
1294
+ * Commits without scope are ignored, allowing developers to commit
1295
+ * work-in-progress changes without polluting release notes:
1296
+ * - `cli: work in progress` → ignored (no type)
1297
+ * - `fix: quick patch` → ignored (no scope)
1298
+ * - `feat(cli): add command` → included
1299
+ */
1300
+ var GitMessageParser = class {
1301
+ log = $logger();
1302
+ /**
1303
+ * Parse a git commit line into a structured Commit object.
1304
+ *
1305
+ * **Format:** `type(scope): description` or `type(scope)!: description`
1306
+ *
1307
+ * **Supported types:** feat, fix, docs, refactor, perf, revert
1308
+ *
1309
+ * **Breaking changes:** Use `!` before `:` (e.g., `feat(api)!: remove endpoint`)
1310
+ *
1311
+ * @returns Commit object or null if not matching/ignored
1312
+ */
1313
+ parseCommit(line, config) {
1314
+ const match = line.match(/^([a-f0-9]+)\s+(.+)$/);
1315
+ if (!match) return null;
1316
+ const [, hash, message] = match;
1317
+ const ignore = config.ignore ?? DEFAULT_IGNORE;
1318
+ const conventionalMatch = message.match(/^(feat|fix|docs|refactor|perf|revert)\(([^)]+)\)(!)?:\s*(.+)$/i);
1319
+ if (!conventionalMatch) return null;
1320
+ const [, type, scope, breakingMark, description] = conventionalMatch;
1321
+ const baseScope = scope.split("/")[0];
1322
+ if (ignore.includes(baseScope) || ignore.includes(scope)) return null;
1323
+ const breaking = breakingMark === "!" || description.toLowerCase().includes("breaking");
1324
+ return {
1325
+ hash: hash.substring(0, 8),
1326
+ type: type.toLowerCase(),
1327
+ scope,
1328
+ description: description.trim(),
1329
+ breaking
1330
+ };
1331
+ }
1332
+ };
1333
+
1334
+ //#endregion
1335
+ //#region ../../src/cli/commands/gen/changelog.ts
1336
+ const execAsync = promisify(exec);
1337
+ /**
1338
+ * Git provider for executing git commands.
1339
+ * Can be substituted in tests with a mock implementation.
1340
+ */
1341
+ var GitProvider = class {
1342
+ async exec(cmd, cwd) {
1343
+ const { stdout } = await execAsync(`git ${cmd}`, { cwd });
1344
+ return stdout;
1345
+ }
1346
+ };
1347
+ /**
1348
+ * Changelog command for generating release notes from git commits.
1349
+ *
1350
+ * Usage:
1351
+ * - `alepha gen changelog` - Show unreleased changes since latest tag to HEAD
1352
+ * - `alepha gen changelog --from=1.0.0` - Show changes from version to HEAD
1353
+ * - `alepha gen changelog --from=1.0.0 --to=1.1.0` - Show changes between two refs
1354
+ * - `alepha gen changelog | tee -a CHANGELOG.md` - Append to file
1355
+ */
1356
+ var ChangelogCommand = class {
1357
+ log = $logger();
1358
+ git = $inject(GitProvider);
1359
+ parser = $inject(GitMessageParser);
1360
+ config = $use(changelogOptions);
1361
+ /**
1362
+ * Format a single commit line.
1363
+ * Example: `- **cli**: add new command (\`abc1234\`)`
1364
+ * Breaking changes are flagged: `- **cli**: add new command [BREAKING] (\`abc1234\`)`
1365
+ */
1366
+ formatCommit(commit) {
1367
+ const breaking = commit.breaking ? " [BREAKING]" : "";
1368
+ return `- **${commit.scope}**: ${commit.description}${breaking} (\`${commit.hash}\`)`;
1369
+ }
1370
+ /**
1371
+ * Format the changelog entry with sections.
1372
+ */
1373
+ formatEntry(entry) {
1374
+ const sections = [];
1375
+ if (entry.features.length > 0) {
1376
+ sections.push("### Features\n");
1377
+ for (const commit of entry.features) sections.push(this.formatCommit(commit));
1378
+ sections.push("");
1379
+ }
1380
+ if (entry.fixes.length > 0) {
1381
+ sections.push("### Bug Fixes\n");
1382
+ for (const commit of entry.fixes) sections.push(this.formatCommit(commit));
1383
+ sections.push("");
1384
+ }
1385
+ return sections.join("\n");
1386
+ }
1387
+ /**
1388
+ * Parse git log output into a changelog entry.
1389
+ */
1390
+ parseCommits(commitsOutput) {
1391
+ const entry = {
1392
+ features: [],
1393
+ fixes: []
1394
+ };
1395
+ for (const line of commitsOutput.trim().split("\n")) {
1396
+ if (!line.trim()) continue;
1397
+ const commit = this.parser.parseCommit(line, this.config);
1398
+ if (!commit) {
1399
+ this.log.trace("Skipping commit", { line });
1400
+ continue;
1401
+ }
1402
+ this.log.trace("Parsed commit", { commit });
1403
+ if (commit.type === "feat") entry.features.push(commit);
1404
+ else if (commit.type === "fix") entry.fixes.push(commit);
1405
+ }
1406
+ return entry;
1407
+ }
1408
+ /**
1409
+ * Check if entry has any public commits.
1410
+ */
1411
+ hasChanges(entry) {
1412
+ return entry.features.length > 0 || entry.fixes.length > 0;
1413
+ }
1414
+ /**
1415
+ * Get the latest version tag.
1416
+ */
1417
+ async getLatestTag(git) {
1418
+ return (await git("tag --sort=-version:refname")).trim().split("\n").filter((tag) => tag.match(/^\d+\.\d+\.\d+$/))[0] || null;
1419
+ }
1420
+ command = $command({
1421
+ name: "changelog",
1422
+ description: "Generate changelog from conventional commits (outputs to stdout)",
1423
+ flags: t.object({
1424
+ from: t.optional(t.string({
1425
+ aliases: ["f"],
1426
+ description: "Starting ref (default: latest tag)"
1427
+ })),
1428
+ to: t.optional(t.string({
1429
+ aliases: ["t"],
1430
+ description: "Ending ref (default: HEAD)"
1431
+ }))
1432
+ }),
1433
+ handler: async ({ flags, root }) => {
1434
+ const git = (cmd) => this.git.exec(cmd, root);
1435
+ let fromRef;
1436
+ if (flags.from) {
1437
+ fromRef = flags.from;
1438
+ this.log.debug("Using specified from ref", { from: fromRef });
1439
+ } else {
1440
+ const latestTag = await this.getLatestTag(git);
1441
+ if (!latestTag) {
1442
+ process.stdout.write("No version tags found in repository\n");
1443
+ return;
1444
+ }
1445
+ fromRef = latestTag;
1446
+ this.log.debug("Using latest tag", { from: fromRef });
1447
+ }
1448
+ const toRef = flags.to || "HEAD";
1449
+ this.log.debug("Using to ref", { to: toRef });
1450
+ const commitsOutput = await git(`log ${fromRef}..${toRef} --oneline`);
1451
+ if (!commitsOutput.trim()) {
1452
+ process.stdout.write(`No changes in range ${fromRef}..${toRef}\n`);
1453
+ return;
1454
+ }
1455
+ const entry = this.parseCommits(commitsOutput);
1456
+ if (!this.hasChanges(entry)) {
1457
+ process.stdout.write(`No public changes in range ${fromRef}..${toRef}\n`);
1458
+ return;
1459
+ }
1460
+ process.stdout.write(this.formatEntry(entry));
1461
+ }
1462
+ });
1463
+ };
1464
+
1465
+ //#endregion
1466
+ //#region ../../src/cli/commands/gen/env.ts
1467
+ var GenEnvCommand = class {
1468
+ log = $logger();
1469
+ utils = $inject(AlephaCliUtils);
1470
+ fs = $inject(FileSystemProvider);
1471
+ command = $command({
1472
+ name: "env",
1473
+ description: "Extract environment variables from server entry file",
1474
+ flags: t.object({ out: t.optional(t.text({
1475
+ aliases: ["o"],
1476
+ description: "Output file path (e.g., .env)"
1477
+ })) }),
1478
+ handler: async ({ root, flags }) => {
1479
+ const { alepha } = await this.utils.loadAlephaFromServerEntryFile(root);
1480
+ try {
1481
+ const { env } = alepha.dump();
1482
+ let dotEnvFile = "";
1483
+ for (const [key, value] of Object.entries(env)) {
1484
+ if (value.description) dotEnvFile += `# ${value.description.split("\n").join("\n# ")}\n`;
1485
+ if (value.required && !value.default) dotEnvFile += `# (required)\n`;
1486
+ if (value.enum) dotEnvFile += `# Possible values: ${value.enum.join(", ")}\n`;
1487
+ dotEnvFile += `${key}=${value.default || ""}\n\n`;
1488
+ }
1489
+ if (flags.out) await this.fs.writeFile(this.fs.join(root, flags.out), dotEnvFile);
1490
+ else this.log.info(dotEnvFile);
1491
+ } catch (err) {
1492
+ this.log.error("Failed to extract environment variables", err);
1493
+ }
1494
+ }
1495
+ });
1496
+ };
1497
+
1498
+ //#endregion
1499
+ //#region ../../src/cli/commands/gen/openapi.ts
1500
+ var OpenApiCommand = class {
1501
+ log = $logger();
1502
+ utils = $inject(AlephaCliUtils);
1503
+ fs = $inject(FileSystemProvider);
1504
+ command = $command({
1505
+ name: "openapi",
1506
+ description: "Generate OpenAPI specification from actions",
1507
+ flags: t.object({ out: t.optional(t.text({
1508
+ aliases: ["o"],
1509
+ description: "Output file path"
1510
+ })) }),
1511
+ handler: async ({ root, flags }) => {
1512
+ const { alepha } = await this.utils.loadAlephaFromServerEntryFile(root);
1513
+ try {
1514
+ const openapiProvider = alepha.inject(ServerSwaggerProvider);
1515
+ await alepha.events.emit("configure", alepha);
1516
+ let json = openapiProvider.json;
1517
+ if (!json) json = openapiProvider.generateSwaggerDoc({ info: {
1518
+ title: "API Documentation",
1519
+ version: "1.0.0"
1520
+ } });
1521
+ if (!json) {
1522
+ this.log.error("No actions found to generate OpenAPI specification.");
1523
+ return;
1524
+ }
1525
+ if (flags.out) await this.fs.writeFile(this.fs.join(root, flags.out), JSON.stringify(json, null, 2));
1526
+ else this.log.info(JSON.stringify(json, null, 2));
1527
+ } catch (err) {
1528
+ const message = err instanceof Error ? err.message : String(err);
1529
+ if (message.includes("Service not found")) {
1530
+ this.log.error("Missing $swagger() primitive in your server configuration.");
1531
+ return;
1532
+ }
1533
+ this.log.error(`OpenAPI generation failed - ${message}`, err);
1534
+ }
1535
+ }
1536
+ });
1537
+ };
1538
+
1539
+ //#endregion
1540
+ //#region ../../src/cli/commands/gen.ts
1541
+ var GenCommand = class {
1542
+ changelog = $inject(ChangelogCommand);
1543
+ openapi = $inject(OpenApiCommand);
1544
+ genEnv = $inject(GenEnvCommand);
1545
+ gen = $command({
1546
+ name: "gen",
1547
+ description: "Generate code, documentation, ...",
1548
+ children: [
1549
+ this.changelog.command,
1550
+ this.openapi.command,
1551
+ this.genEnv.command
1552
+ ],
1553
+ handler: async ({ help }) => {
1554
+ help();
1555
+ }
1556
+ });
1557
+ };
1558
+
1354
1559
  //#endregion
1355
1560
  //#region ../../src/cli/commands/init.ts
1356
1561
  var InitCommand = class {
@@ -1381,7 +1586,6 @@ var InitCommand = class {
1381
1586
  tsconfigJson: true,
1382
1587
  packageJson: flags,
1383
1588
  biomeJson: true,
1384
- viteConfigTs: !isExpo,
1385
1589
  editorconfig: true,
1386
1590
  indexHtml: !!flags.react && !isExpo
1387
1591
  });
@@ -1392,7 +1596,8 @@ var InitCommand = class {
1392
1596
  if (pm === "yarn") {
1393
1597
  await this.utils.ensureYarn(root);
1394
1598
  await run("yarn set version stable");
1395
- } else if (pm === "pnpm") await this.utils.ensurePnpm(root);
1599
+ } else if (pm === "bun") await this.utils.ensureBun(root);
1600
+ else if (pm === "pnpm") await this.utils.ensurePnpm(root);
1396
1601
  else await this.utils.ensureNpm(root);
1397
1602
  await run(`${pm} install`, { alias: `installing dependencies with ${pm}` });
1398
1603
  if (!isExpo) await this.utils.ensureDependency(root, "vite", { run });
@@ -1425,6 +1630,8 @@ var LintCommand = class {
1425
1630
  var RootCommand = class {
1426
1631
  log = $logger();
1427
1632
  cli = $inject(CliProvider);
1633
+ alepha = $inject(Alepha);
1634
+ color = $inject(ConsoleColorProvider);
1428
1635
  /**
1429
1636
  * Called when no command is provided
1430
1637
  */
@@ -1436,7 +1643,9 @@ var RootCommand = class {
1436
1643
  })) }),
1437
1644
  handler: async ({ flags }) => {
1438
1645
  if (flags.version) {
1439
- this.log.info(version);
1646
+ this.log.info(this.color.set("WHITE_BOLD", `Alepha v${version}`));
1647
+ if (this.alepha.isBun()) this.log.info(this.color.set("GREY_DARK", `└─ Bun v${Bun.version}`));
1648
+ else this.log.info(this.color.set("GREY_DARK", `└─ Node ${process.version}`));
1440
1649
  return;
1441
1650
  }
1442
1651
  this.cli.printHelp();
@@ -1444,30 +1653,6 @@ var RootCommand = class {
1444
1653
  });
1445
1654
  };
1446
1655
 
1447
- //#endregion
1448
- //#region ../../src/cli/commands/run.ts
1449
- var RunCommand = class {
1450
- utils = $inject(AlephaCliUtils);
1451
- run = $command({
1452
- name: "run",
1453
- hide: true,
1454
- description: "Run a TypeScript file directly",
1455
- flags: t.object({ watch: t.optional(t.boolean({
1456
- description: "Watch file for changes",
1457
- alias: "w"
1458
- })) }),
1459
- summary: false,
1460
- args: t.text({
1461
- title: "path",
1462
- description: "Filepath to run"
1463
- }),
1464
- handler: async ({ args, flags, root }) => {
1465
- await this.utils.ensureTsConfig(root);
1466
- await this.utils.exec(`tsx ${flags.watch ? "watch " : ""}${args}`);
1467
- }
1468
- });
1469
- };
1470
-
1471
1656
  //#endregion
1472
1657
  //#region ../../src/cli/commands/test.ts
1473
1658
  var TestCommand = class {
@@ -1484,10 +1669,7 @@ var TestCommand = class {
1484
1669
  description: "Additional arguments to pass to Vitest. E.g., --coverage"
1485
1670
  })) }),
1486
1671
  handler: async ({ root, flags, env }) => {
1487
- await this.utils.ensureConfig(root, {
1488
- tsconfigJson: true,
1489
- viteConfigTs: true
1490
- });
1672
+ await this.utils.ensureConfig(root, { tsconfigJson: true });
1491
1673
  await this.utils.ensureDependency(root, "vitest");
1492
1674
  const config = flags.config ? `--config=${flags.config}` : "";
1493
1675
  await this.utils.exec(`vitest run ${config} ${env.VITEST_ARGS}`);
@@ -1499,15 +1681,19 @@ var TestCommand = class {
1499
1681
  //#region ../../src/cli/commands/typecheck.ts
1500
1682
  var TypecheckCommand = class {
1501
1683
  utils = $inject(AlephaCliUtils);
1684
+ log = $logger();
1502
1685
  /**
1503
1686
  * Run TypeScript type checking across the codebase with no emit.
1504
1687
  */
1505
1688
  typecheck = $command({
1506
1689
  name: "typecheck",
1690
+ aliases: ["tc"],
1507
1691
  description: "Check TypeScript types across the codebase",
1508
1692
  handler: async ({ root }) => {
1693
+ this.log.info("Starting TypeScript type checking...");
1509
1694
  await this.utils.ensureDependency(root, "typescript");
1510
1695
  await this.utils.exec("tsc --noEmit");
1696
+ this.log.info("TypeScript type checking completed successfully.");
1511
1697
  }
1512
1698
  });
1513
1699
  };
@@ -1538,7 +1724,7 @@ var VerifyCommand = class {
1538
1724
  await run("alepha lint");
1539
1725
  await run("alepha typecheck");
1540
1726
  if ((await this.utils.readPackageJson(root)).devDependencies?.vitest) await run("alepha test");
1541
- if (await this.utils.exists(root, "migrations")) await run("alepha db:check-migrations");
1727
+ if (await this.utils.exists(root, "migrations")) await run("alepha db check-migrations");
1542
1728
  if (!await this.utils.hasExpo(root)) await run("alepha build");
1543
1729
  await run("alepha clean");
1544
1730
  }
@@ -1547,13 +1733,26 @@ var VerifyCommand = class {
1547
1733
 
1548
1734
  //#endregion
1549
1735
  //#region ../../src/cli/apps/AlephaCli.ts
1736
+ /**
1737
+ * Register `tsx` when running in Node.js, ignore for Bun.
1738
+ *
1739
+ * It's required to have a full TypeScript support. (mostly .tsx files)
1740
+ */
1741
+ if (typeof Bun === "undefined") {
1742
+ const { register } = await import("tsx/esm/api");
1743
+ register();
1744
+ }
1745
+ /**
1746
+ * Allow to extend Alepha CLI via `alepha.config.ts` file located in the project root.
1747
+ */
1550
1748
  var AlephaCliExtension = class {
1551
1749
  alepha = $inject(Alepha);
1552
1750
  fs = $inject(FileSystemProvider);
1553
1751
  onConfigure = $hook({
1554
1752
  on: "configure",
1555
1753
  handler: async () => {
1556
- const extensionPath = join(process.cwd(), "alepha.config.ts");
1754
+ const root = process.cwd();
1755
+ const extensionPath = this.fs.join(root, "alepha.config.ts");
1557
1756
  if (!await this.fs.exists(extensionPath)) return;
1558
1757
  const { default: Extension } = await import(extensionPath);
1559
1758
  if (typeof Extension !== "function") return;
@@ -1566,7 +1765,6 @@ const AlephaCli = $module({
1566
1765
  services: [
1567
1766
  AlephaCliExtension,
1568
1767
  BuildCommand,
1569
- ChangelogCommand,
1570
1768
  CleanCommand,
1571
1769
  DbCommand,
1572
1770
  DeployCommand,
@@ -1575,10 +1773,10 @@ const AlephaCli = $module({
1575
1773
  InitCommand,
1576
1774
  LintCommand,
1577
1775
  RootCommand,
1578
- RunCommand,
1579
1776
  TestCommand,
1580
1777
  TypecheckCommand,
1581
1778
  VerifyCommand,
1779
+ GenCommand,
1582
1780
  GitProvider
1583
1781
  ]
1584
1782
  });
@@ -1778,11 +1976,13 @@ async function analyzeModules(srcDir, packageName) {
1778
1976
 
1779
1977
  //#endregion
1780
1978
  //#region ../../src/cli/defineConfig.ts
1781
- const defineConfig = (config) => {
1979
+ const defineConfig = (runConfig) => {
1782
1980
  return (alepha) => {
1783
- const { commands, services = [] } = config(alepha);
1784
- for (const it of services) alepha.with(it);
1785
- return { ...commands };
1981
+ const config = typeof runConfig === "function" ? runConfig(alepha) : runConfig;
1982
+ if (config.services) for (const it of config.services) alepha.with(it);
1983
+ if (config.env) for (const [key, value] of Object.entries(config.env)) process.env[key] = String(value);
1984
+ if (config.build) alepha.set(buildOptions, config.build);
1985
+ return { ...config.commands };
1786
1986
  };
1787
1987
  };
1788
1988
  /**
@@ -1791,5 +1991,5 @@ const defineConfig = (config) => {
1791
1991
  const defineAlephaConfig = defineConfig;
1792
1992
 
1793
1993
  //#endregion
1794
- export { AlephaCli, AlephaCliUtils, AlephaPackageBuilderCli, BuildCommand, ChangelogCommand, CleanCommand, DEFAULT_IGNORE, DbCommand, DeployCommand, DevCommand, FormatCommand, GitMessageParser, GitProvider, InitCommand, LintCommand, RootCommand, RunCommand, TestCommand, TypecheckCommand, VerifyCommand, analyzeModules, changelogOptions, defineAlephaConfig, defineConfig, version };
1994
+ export { AlephaCli, AlephaCliUtils, AlephaPackageBuilderCli, BuildCommand, ChangelogCommand, CleanCommand, DEFAULT_IGNORE, DbCommand, DeployCommand, DevCommand, FormatCommand, GitMessageParser, GitProvider, InitCommand, LintCommand, OpenApiCommand, RootCommand, TestCommand, TypecheckCommand, VerifyCommand, analyzeModules, changelogOptions, defineAlephaConfig, defineConfig, version };
1795
1995
  //# sourceMappingURL=index.js.map