alepha 0.14.3 → 0.15.0

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 (317) hide show
  1. package/README.md +2 -5
  2. package/dist/api/audits/index.d.ts +620 -811
  3. package/dist/api/audits/index.d.ts.map +1 -1
  4. package/dist/api/files/index.d.ts +185 -377
  5. package/dist/api/files/index.d.ts.map +1 -1
  6. package/dist/api/files/index.js +0 -1
  7. package/dist/api/files/index.js.map +1 -1
  8. package/dist/api/jobs/index.d.ts +245 -435
  9. package/dist/api/jobs/index.d.ts.map +1 -1
  10. package/dist/api/notifications/index.d.ts +238 -429
  11. package/dist/api/notifications/index.d.ts.map +1 -1
  12. package/dist/api/parameters/index.d.ts +236 -427
  13. package/dist/api/parameters/index.d.ts.map +1 -1
  14. package/dist/api/users/index.browser.js +1 -2
  15. package/dist/api/users/index.browser.js.map +1 -1
  16. package/dist/api/users/index.d.ts +1010 -1196
  17. package/dist/api/users/index.d.ts.map +1 -1
  18. package/dist/api/users/index.js +178 -151
  19. package/dist/api/users/index.js.map +1 -1
  20. package/dist/api/verifications/index.d.ts +17 -17
  21. package/dist/api/verifications/index.d.ts.map +1 -1
  22. package/dist/batch/index.d.ts +122 -122
  23. package/dist/batch/index.d.ts.map +1 -1
  24. package/dist/batch/index.js +1 -2
  25. package/dist/batch/index.js.map +1 -1
  26. package/dist/bucket/index.d.ts +163 -163
  27. package/dist/bucket/index.d.ts.map +1 -1
  28. package/dist/cache/core/index.d.ts +46 -46
  29. package/dist/cache/core/index.d.ts.map +1 -1
  30. package/dist/cache/redis/index.d.ts.map +1 -1
  31. package/dist/cli/index.d.ts +384 -285
  32. package/dist/cli/index.d.ts.map +1 -1
  33. package/dist/cli/index.js +1113 -623
  34. package/dist/cli/index.js.map +1 -1
  35. package/dist/command/index.d.ts +299 -300
  36. package/dist/command/index.d.ts.map +1 -1
  37. package/dist/command/index.js +13 -9
  38. package/dist/command/index.js.map +1 -1
  39. package/dist/core/index.browser.js +445 -103
  40. package/dist/core/index.browser.js.map +1 -1
  41. package/dist/core/index.d.ts +733 -625
  42. package/dist/core/index.d.ts.map +1 -1
  43. package/dist/core/index.js +446 -103
  44. package/dist/core/index.js.map +1 -1
  45. package/dist/core/index.native.js +445 -103
  46. package/dist/core/index.native.js.map +1 -1
  47. package/dist/datetime/index.d.ts +44 -44
  48. package/dist/datetime/index.d.ts.map +1 -1
  49. package/dist/datetime/index.js +4 -4
  50. package/dist/datetime/index.js.map +1 -1
  51. package/dist/email/index.d.ts +97 -50
  52. package/dist/email/index.d.ts.map +1 -1
  53. package/dist/email/index.js +129 -33
  54. package/dist/email/index.js.map +1 -1
  55. package/dist/fake/index.d.ts +7981 -14
  56. package/dist/fake/index.d.ts.map +1 -1
  57. package/dist/file/index.d.ts +523 -390
  58. package/dist/file/index.d.ts.map +1 -1
  59. package/dist/file/index.js +253 -1
  60. package/dist/file/index.js.map +1 -1
  61. package/dist/lock/core/index.d.ts +208 -208
  62. package/dist/lock/core/index.d.ts.map +1 -1
  63. package/dist/lock/redis/index.d.ts.map +1 -1
  64. package/dist/logger/index.d.ts +25 -26
  65. package/dist/logger/index.d.ts.map +1 -1
  66. package/dist/logger/index.js +12 -2
  67. package/dist/logger/index.js.map +1 -1
  68. package/dist/mcp/index.d.ts +197 -197
  69. package/dist/mcp/index.d.ts.map +1 -1
  70. package/dist/mcp/index.js +1 -1
  71. package/dist/mcp/index.js.map +1 -1
  72. package/dist/orm/chunk-DtkW-qnP.js +38 -0
  73. package/dist/orm/index.browser.js.map +1 -1
  74. package/dist/orm/index.bun.js +2814 -0
  75. package/dist/orm/index.bun.js.map +1 -0
  76. package/dist/orm/index.d.ts +1228 -1216
  77. package/dist/orm/index.d.ts.map +1 -1
  78. package/dist/orm/index.js +2041 -1967
  79. package/dist/orm/index.js.map +1 -1
  80. package/dist/queue/core/index.d.ts +248 -248
  81. package/dist/queue/core/index.d.ts.map +1 -1
  82. package/dist/queue/redis/index.d.ts.map +1 -1
  83. package/dist/redis/index.bun.js +285 -0
  84. package/dist/redis/index.bun.js.map +1 -0
  85. package/dist/redis/index.d.ts +118 -136
  86. package/dist/redis/index.d.ts.map +1 -1
  87. package/dist/redis/index.js +18 -38
  88. package/dist/redis/index.js.map +1 -1
  89. package/dist/retry/index.d.ts +69 -69
  90. package/dist/retry/index.d.ts.map +1 -1
  91. package/dist/router/index.d.ts +6 -6
  92. package/dist/router/index.d.ts.map +1 -1
  93. package/dist/scheduler/index.d.ts +25 -25
  94. package/dist/scheduler/index.d.ts.map +1 -1
  95. package/dist/security/index.browser.js +5 -1
  96. package/dist/security/index.browser.js.map +1 -1
  97. package/dist/security/index.d.ts +417 -254
  98. package/dist/security/index.d.ts.map +1 -1
  99. package/dist/security/index.js +386 -86
  100. package/dist/security/index.js.map +1 -1
  101. package/dist/server/auth/index.d.ts +110 -110
  102. package/dist/server/auth/index.d.ts.map +1 -1
  103. package/dist/server/auth/index.js +20 -20
  104. package/dist/server/auth/index.js.map +1 -1
  105. package/dist/server/cache/index.d.ts +62 -47
  106. package/dist/server/cache/index.d.ts.map +1 -1
  107. package/dist/server/cache/index.js +56 -3
  108. package/dist/server/cache/index.js.map +1 -1
  109. package/dist/server/compress/index.d.ts +6 -0
  110. package/dist/server/compress/index.d.ts.map +1 -1
  111. package/dist/server/compress/index.js +36 -1
  112. package/dist/server/compress/index.js.map +1 -1
  113. package/dist/server/cookies/index.d.ts +6 -6
  114. package/dist/server/cookies/index.d.ts.map +1 -1
  115. package/dist/server/cookies/index.js +3 -3
  116. package/dist/server/cookies/index.js.map +1 -1
  117. package/dist/server/core/index.browser.js +2 -2
  118. package/dist/server/core/index.browser.js.map +1 -1
  119. package/dist/server/core/index.d.ts +242 -150
  120. package/dist/server/core/index.d.ts.map +1 -1
  121. package/dist/server/core/index.js +294 -125
  122. package/dist/server/core/index.js.map +1 -1
  123. package/dist/server/cors/index.d.ts +11 -12
  124. package/dist/server/cors/index.d.ts.map +1 -1
  125. package/dist/server/health/index.d.ts +0 -1
  126. package/dist/server/health/index.d.ts.map +1 -1
  127. package/dist/server/helmet/index.d.ts +2 -2
  128. package/dist/server/helmet/index.d.ts.map +1 -1
  129. package/dist/server/links/index.browser.js.map +1 -1
  130. package/dist/server/links/index.d.ts +123 -124
  131. package/dist/server/links/index.d.ts.map +1 -1
  132. package/dist/server/links/index.js +1 -2
  133. package/dist/server/links/index.js.map +1 -1
  134. package/dist/server/metrics/index.d.ts.map +1 -1
  135. package/dist/server/multipart/index.d.ts +6 -6
  136. package/dist/server/multipart/index.d.ts.map +1 -1
  137. package/dist/server/proxy/index.d.ts +102 -103
  138. package/dist/server/proxy/index.d.ts.map +1 -1
  139. package/dist/server/rate-limit/index.d.ts +16 -16
  140. package/dist/server/rate-limit/index.d.ts.map +1 -1
  141. package/dist/server/static/index.d.ts +44 -44
  142. package/dist/server/static/index.d.ts.map +1 -1
  143. package/dist/server/static/index.js +4 -0
  144. package/dist/server/static/index.js.map +1 -1
  145. package/dist/server/swagger/index.d.ts +48 -49
  146. package/dist/server/swagger/index.d.ts.map +1 -1
  147. package/dist/server/swagger/index.js +3 -5
  148. package/dist/server/swagger/index.js.map +1 -1
  149. package/dist/sms/index.d.ts +13 -11
  150. package/dist/sms/index.d.ts.map +1 -1
  151. package/dist/sms/index.js +7 -7
  152. package/dist/sms/index.js.map +1 -1
  153. package/dist/thread/index.d.ts +71 -72
  154. package/dist/thread/index.d.ts.map +1 -1
  155. package/dist/topic/core/index.d.ts +318 -318
  156. package/dist/topic/core/index.d.ts.map +1 -1
  157. package/dist/topic/redis/index.d.ts +6 -6
  158. package/dist/topic/redis/index.d.ts.map +1 -1
  159. package/dist/vite/index.d.ts +5805 -249
  160. package/dist/vite/index.d.ts.map +1 -1
  161. package/dist/vite/index.js +599 -513
  162. package/dist/vite/index.js.map +1 -1
  163. package/dist/websocket/index.browser.js +6 -6
  164. package/dist/websocket/index.browser.js.map +1 -1
  165. package/dist/websocket/index.d.ts +247 -247
  166. package/dist/websocket/index.d.ts.map +1 -1
  167. package/dist/websocket/index.js +6 -6
  168. package/dist/websocket/index.js.map +1 -1
  169. package/package.json +9 -14
  170. package/src/api/files/controllers/AdminFileStatsController.ts +0 -1
  171. package/src/api/users/atoms/realmAuthSettingsAtom.ts +5 -0
  172. package/src/api/users/controllers/{UserRealmController.ts → RealmController.ts} +11 -11
  173. package/src/api/users/entities/users.ts +1 -1
  174. package/src/api/users/index.ts +8 -8
  175. package/src/api/users/primitives/{$userRealm.ts → $realm.ts} +17 -19
  176. package/src/api/users/providers/{UserRealmProvider.ts → RealmProvider.ts} +26 -30
  177. package/src/api/users/schemas/{userRealmConfigSchema.ts → realmConfigSchema.ts} +2 -2
  178. package/src/api/users/services/CredentialService.ts +7 -7
  179. package/src/api/users/services/IdentityService.ts +4 -4
  180. package/src/api/users/services/RegistrationService.spec.ts +25 -27
  181. package/src/api/users/services/RegistrationService.ts +38 -27
  182. package/src/api/users/services/SessionCrudService.ts +3 -3
  183. package/src/api/users/services/SessionService.spec.ts +3 -3
  184. package/src/api/users/services/SessionService.ts +28 -9
  185. package/src/api/users/services/UserService.ts +7 -7
  186. package/src/batch/providers/BatchProvider.ts +1 -2
  187. package/src/cli/apps/AlephaCli.ts +0 -2
  188. package/src/cli/apps/AlephaPackageBuilderCli.ts +38 -19
  189. package/src/cli/assets/apiHelloControllerTs.ts +18 -0
  190. package/src/cli/assets/apiIndexTs.ts +16 -0
  191. package/src/cli/assets/claudeMd.ts +303 -0
  192. package/src/cli/assets/mainBrowserTs.ts +2 -2
  193. package/src/cli/assets/mainServerTs.ts +24 -0
  194. package/src/cli/assets/webAppRouterTs.ts +15 -0
  195. package/src/cli/assets/webHelloComponentTsx.ts +16 -0
  196. package/src/cli/assets/webIndexTs.ts +16 -0
  197. package/src/cli/atoms/buildOptions.ts +88 -0
  198. package/src/cli/commands/build.ts +70 -87
  199. package/src/cli/commands/db.ts +21 -22
  200. package/src/cli/commands/deploy.ts +17 -5
  201. package/src/cli/commands/dev.ts +22 -14
  202. package/src/cli/commands/format.ts +8 -2
  203. package/src/cli/commands/gen/env.ts +53 -0
  204. package/src/cli/commands/gen/openapi.ts +1 -1
  205. package/src/cli/commands/gen/resource.ts +15 -0
  206. package/src/cli/commands/gen.ts +7 -1
  207. package/src/cli/commands/init.ts +74 -30
  208. package/src/cli/commands/lint.ts +8 -2
  209. package/src/cli/commands/test.ts +8 -3
  210. package/src/cli/commands/typecheck.ts +5 -1
  211. package/src/cli/commands/verify.ts +5 -3
  212. package/src/cli/defineConfig.ts +49 -7
  213. package/src/cli/index.ts +0 -1
  214. package/src/cli/services/AlephaCliUtils.ts +39 -589
  215. package/src/cli/services/PackageManagerUtils.ts +301 -0
  216. package/src/cli/services/ProjectScaffolder.ts +306 -0
  217. package/src/command/helpers/Runner.spec.ts +2 -2
  218. package/src/command/helpers/Runner.ts +16 -4
  219. package/src/command/primitives/$command.ts +0 -6
  220. package/src/command/providers/CliProvider.ts +1 -3
  221. package/src/core/Alepha.ts +42 -0
  222. package/src/core/__tests__/Alepha-graph.spec.ts +4 -0
  223. package/src/core/index.shared.ts +1 -0
  224. package/src/core/index.ts +2 -0
  225. package/src/core/primitives/$hook.ts +6 -2
  226. package/src/core/primitives/$module.spec.ts +4 -0
  227. package/src/core/providers/AlsProvider.ts +1 -1
  228. package/src/core/providers/CodecManager.spec.ts +12 -6
  229. package/src/core/providers/CodecManager.ts +26 -6
  230. package/src/core/providers/EventManager.ts +169 -13
  231. package/src/core/providers/KeylessJsonSchemaCodec.spec.ts +621 -0
  232. package/src/core/providers/KeylessJsonSchemaCodec.ts +407 -0
  233. package/src/core/providers/StateManager.spec.ts +27 -16
  234. package/src/email/providers/LocalEmailProvider.spec.ts +111 -87
  235. package/src/email/providers/LocalEmailProvider.ts +52 -15
  236. package/src/email/providers/NodemailerEmailProvider.ts +167 -56
  237. package/src/file/errors/FileError.ts +7 -0
  238. package/src/file/index.ts +9 -1
  239. package/src/file/providers/MemoryFileSystemProvider.ts +393 -0
  240. package/src/logger/index.ts +15 -3
  241. package/src/mcp/transports/StdioMcpTransport.ts +1 -1
  242. package/src/orm/index.browser.ts +1 -19
  243. package/src/orm/index.bun.ts +77 -0
  244. package/src/orm/index.shared-server.ts +22 -0
  245. package/src/orm/index.shared.ts +15 -0
  246. package/src/orm/index.ts +13 -39
  247. package/src/orm/providers/drivers/BunPostgresProvider.ts +3 -5
  248. package/src/orm/providers/drivers/BunSqliteProvider.ts +1 -1
  249. package/src/orm/providers/drivers/CloudflareD1Provider.ts +4 -0
  250. package/src/orm/providers/drivers/DatabaseProvider.ts +4 -0
  251. package/src/orm/providers/drivers/PglitePostgresProvider.ts +4 -0
  252. package/src/orm/services/Repository.ts +8 -0
  253. package/src/queue/core/providers/WorkerProvider.spec.ts +48 -32
  254. package/src/redis/index.bun.ts +35 -0
  255. package/src/redis/providers/BunRedisProvider.ts +12 -43
  256. package/src/redis/providers/BunRedisSubscriberProvider.ts +2 -3
  257. package/src/redis/providers/NodeRedisProvider.ts +16 -34
  258. package/src/{server/security → security}/__tests__/BasicAuth.spec.ts +11 -11
  259. package/src/{server/security → security}/__tests__/ServerSecurityProvider-realm.spec.ts +21 -16
  260. package/src/{server/security/providers → security/__tests__}/ServerSecurityProvider.spec.ts +5 -5
  261. package/src/security/index.browser.ts +5 -0
  262. package/src/security/index.ts +90 -7
  263. package/src/security/primitives/{$realm.spec.ts → $issuer.spec.ts} +11 -11
  264. package/src/security/primitives/{$realm.ts → $issuer.ts} +20 -17
  265. package/src/security/primitives/$role.ts +5 -5
  266. package/src/security/primitives/$serviceAccount.spec.ts +5 -5
  267. package/src/security/primitives/$serviceAccount.ts +3 -3
  268. package/src/{server/security → security}/providers/ServerSecurityProvider.ts +5 -7
  269. package/src/server/auth/primitives/$auth.ts +10 -10
  270. package/src/server/auth/primitives/$authCredentials.ts +3 -3
  271. package/src/server/auth/primitives/$authGithub.ts +3 -3
  272. package/src/server/auth/primitives/$authGoogle.ts +3 -3
  273. package/src/server/auth/providers/ServerAuthProvider.ts +13 -13
  274. package/src/server/cache/providers/ServerCacheProvider.spec.ts +183 -0
  275. package/src/server/cache/providers/ServerCacheProvider.ts +95 -10
  276. package/src/server/compress/providers/ServerCompressProvider.ts +61 -2
  277. package/src/server/cookies/providers/ServerCookiesProvider.ts +3 -3
  278. package/src/server/core/helpers/ServerReply.ts +2 -2
  279. package/src/server/core/providers/NodeHttpServerProvider.ts +25 -6
  280. package/src/server/core/providers/ServerBodyParserProvider.ts +19 -23
  281. package/src/server/core/providers/ServerLoggerProvider.ts +23 -19
  282. package/src/server/core/providers/ServerProvider.ts +155 -22
  283. package/src/server/core/providers/ServerRouterProvider.ts +259 -115
  284. package/src/server/core/providers/ServerTimingProvider.ts +2 -2
  285. package/src/server/links/index.ts +1 -1
  286. package/src/server/links/providers/LinkProvider.ts +1 -1
  287. package/src/server/static/providers/ServerStaticProvider.ts +10 -0
  288. package/src/server/swagger/index.ts +1 -1
  289. package/src/server/swagger/providers/ServerSwaggerProvider.ts +5 -8
  290. package/src/sms/providers/LocalSmsProvider.spec.ts +153 -111
  291. package/src/sms/providers/LocalSmsProvider.ts +8 -7
  292. package/src/vite/helpers/boot.ts +28 -17
  293. package/src/vite/helpers/importViteReact.ts +13 -0
  294. package/src/vite/index.ts +1 -21
  295. package/src/vite/plugins/viteAlephaDev.ts +16 -1
  296. package/src/vite/plugins/viteAlephaSsrPreload.ts +222 -0
  297. package/src/vite/tasks/buildClient.ts +11 -0
  298. package/src/vite/tasks/buildServer.ts +59 -4
  299. package/src/vite/tasks/devServer.ts +71 -0
  300. package/src/vite/tasks/generateCloudflare.ts +7 -0
  301. package/src/vite/tasks/index.ts +2 -1
  302. package/dist/server/security/index.browser.js +0 -13
  303. package/dist/server/security/index.browser.js.map +0 -1
  304. package/dist/server/security/index.d.ts +0 -173
  305. package/dist/server/security/index.d.ts.map +0 -1
  306. package/dist/server/security/index.js +0 -311
  307. package/dist/server/security/index.js.map +0 -1
  308. package/src/cli/assets/appRouterTs.ts +0 -9
  309. package/src/cli/assets/mainTs.ts +0 -13
  310. package/src/cli/assets/viteConfigTs.ts +0 -14
  311. package/src/cli/commands/run.ts +0 -24
  312. package/src/server/security/index.browser.ts +0 -10
  313. package/src/server/security/index.ts +0 -94
  314. package/src/vite/plugins/viteAlepha.ts +0 -37
  315. package/src/vite/plugins/viteAlephaBuild.ts +0 -281
  316. /package/src/{server/security → security}/primitives/$basicAuth.ts +0 -0
  317. /package/src/{server/security → security}/providers/ServerBasicAuthProvider.ts +0 -0
@@ -1,55 +1,40 @@
1
1
  import { spawn } from "node:child_process";
2
- import { access, mkdir, readFile, writeFile } from "node:fs/promises";
3
- import { join } from "node:path";
4
2
  import { $inject, Alepha, AlephaError } from "alepha";
5
- import { EnvUtils, type RunnerMethod } from "alepha/command";
3
+ import { EnvUtils } from "alepha/command";
6
4
  import { FileSystemProvider } from "alepha/file";
7
5
  import { $logger } from "alepha/logger";
8
6
  import { boot } from "alepha/vite";
9
- import { appRouterTs } from "../assets/appRouterTs.ts";
10
- import { biomeJson } from "../assets/biomeJson.ts";
11
- import { dummySpecTs } from "../assets/dummySpecTs.ts";
12
- import { editorconfig } from "../assets/editorconfig.ts";
13
- import { indexHtml } from "../assets/indexHtml.ts";
14
- import { mainBrowserTs } from "../assets/mainBrowserTs.ts";
15
- import { mainTs } from "../assets/mainTs.ts";
16
- import { tsconfigJson } from "../assets/tsconfigJson.ts";
17
- import { viteConfigTs } from "../assets/viteConfigTs.ts";
18
- import { version } from "../version.ts";
19
7
 
20
8
  /**
21
- * Utility service for common project operations used by CLI commands.
9
+ * Core utility service for CLI commands.
22
10
  *
23
- * This service provides helper methods for:
24
- * - Project configuration file management (tsconfig.json, package.json, etc.)
25
- * - Package manager setup (Yarn, npm, pnpm)
26
- * - Sample project downloading
27
- * - Drizzle ORM/Kit utilities
28
- * - Alepha instance loading
11
+ * Provides:
12
+ * - Command execution
13
+ * - File editing helpers
14
+ * - Drizzle/ORM utilities
15
+ * - Environment loading
29
16
  */
30
17
  export class AlephaCliUtils {
31
18
  protected readonly log = $logger();
32
19
  protected readonly fs = $inject(FileSystemProvider);
33
20
  protected readonly envUtils = $inject(EnvUtils);
34
- protected readonly alepha = $inject(Alepha);
21
+
22
+ // ===========================================
23
+ // Command Execution
24
+ // ===========================================
35
25
 
36
26
  /**
37
- * Execute a command using npx with inherited stdio.
38
- *
39
- * @example
40
- * ```ts
41
- * const runner = alepha.inject(ProcessRunner);
42
- * await runner.exec("tsx watch src/index.ts");
43
- * ```
27
+ * Execute a command with inherited stdio.
44
28
  */
45
29
  public async exec(
46
30
  command: string,
47
31
  options: {
32
+ root?: string;
48
33
  env?: Record<string, string>;
49
34
  global?: boolean;
50
35
  } = {},
51
36
  ): Promise<void> {
52
- const root = process.cwd();
37
+ const root = options.root ?? process.cwd();
53
38
  this.log.debug(`Executing command: ${command}`, { cwd: root });
54
39
 
55
40
  const runExec = async (app: string, args: string[]) => {
@@ -82,7 +67,6 @@ export class AlephaCliUtils {
82
67
  let execPath = await this.checkFileExists(
83
68
  root,
84
69
  `node_modules/.bin/${app}${suffix}`,
85
- true,
86
70
  );
87
71
 
88
72
  // or, find executable inside alepha package node_modules (pnpm style)
@@ -90,7 +74,6 @@ export class AlephaCliUtils {
90
74
  execPath = await this.checkFileExists(
91
75
  root,
92
76
  `node_modules/alepha/node_modules/.bin/${app}${suffix}`,
93
- true,
94
77
  );
95
78
  }
96
79
 
@@ -105,354 +88,26 @@ export class AlephaCliUtils {
105
88
 
106
89
  /**
107
90
  * Write a configuration file to node_modules/.alepha directory.
108
- *
109
- * Creates the .alepha directory if it doesn't exist and writes the file with the given content.
110
- *
111
- * @param name - The name of the config file to create
112
- * @param content - The content to write to the file
113
- * @param root - The root directory (defaults to process.cwd())
114
- * @returns The absolute path to the created file
115
- *
116
- * @example
117
- * ```ts
118
- * const runner = alepha.inject(ProcessRunner);
119
- * const configPath = await runner.writeConfigFile("biome.json", biomeConfig);
120
- * ```
121
91
  */
122
92
  public async writeConfigFile(
123
93
  name: string,
124
94
  content: string,
125
95
  root = process.cwd(),
126
96
  ): Promise<string> {
127
- const dir = join(root, "node_modules", ".alepha");
97
+ const dir = this.fs.join(root, "node_modules", ".alepha");
128
98
 
129
- await mkdir(dir, {
130
- recursive: true,
131
- }).catch(() => null);
99
+ await this.fs.mkdir(dir, { recursive: true }).catch(() => null);
132
100
 
133
- const path = join(dir, name);
134
- await writeFile(path, content);
101
+ const path = this.fs.join(dir, name);
102
+ await this.fs.writeFile(path, content);
135
103
 
136
104
  this.log.debug(`Config file written: ${path}`);
137
105
 
138
106
  return path;
139
107
  }
140
108
 
141
- // ===================================================================================================================
142
- // Package Manager & Project Setup
143
- // ===================================================================================================================
144
-
145
- public async removeFiles(root: string, files: string[]): Promise<void> {
146
- await Promise.all(
147
- files.map((file) =>
148
- this.fs.rm(join(root, file), { force: true, recursive: true }),
149
- ),
150
- );
151
- }
152
-
153
- public async removeYarn(root: string): Promise<void> {
154
- await this.removeFiles(root, [".yarn", ".yarnrc.yml", ".yarn"]);
155
- }
156
-
157
- public async removePnpm(root: string): Promise<void> {
158
- await this.removeFiles(root, ["pnpm-lock.yaml", "pnpm-workspace.yaml"]);
159
- }
160
-
161
- public async removeNpm(root: string): Promise<void> {
162
- await this.removeFiles(root, ["package-lock.json"]);
163
- }
164
-
165
- public async removeBun(root: string): Promise<void> {
166
- await this.removeFiles(root, ["bun.lockb"]);
167
- }
168
-
169
- public async removeAllPmFilesExcept(
170
- root: string,
171
- except: string,
172
- ): Promise<void> {
173
- if (except !== "yarn") await this.removeYarn(root);
174
- if (except !== "pnpm") await this.removePnpm(root);
175
- if (except !== "npm") await this.removeNpm(root);
176
- if (except !== "bun") await this.removeBun(root);
177
- }
178
-
179
- /**
180
- * Ensure Yarn is configured in the project directory.
181
- *
182
- * Creates a .yarnrc.yml file with node-modules linker if it doesn't exist.
183
- *
184
- * @param root - The root directory of the project
185
- */
186
- public async ensureYarn(root: string): Promise<void> {
187
- await this.ensureFileExists(
188
- root,
189
- ".yarnrc.yml",
190
- "nodeLinker: node-modules",
191
- false,
192
- );
193
-
194
- await this.removeAllPmFilesExcept(root, "yarn");
195
- }
196
-
197
- public async ensureBun(root: string): Promise<void> {
198
- await this.removeAllPmFilesExcept(root, "bun");
199
- }
200
-
201
- public async ensurePnpm(root: string): Promise<void> {
202
- await this.removeAllPmFilesExcept(root, "pnpm");
203
- }
204
-
205
- public async ensureNpm(root: string): Promise<void> {
206
- await this.removeAllPmFilesExcept(root, "npm");
207
- }
208
-
209
- /**
210
- * Generate package.json content with Alepha dependencies.
211
- *
212
- * @param modes - Configuration for which dependencies to include
213
- * @returns Package.json partial with dependencies, devDependencies, and scripts
214
- */
215
- public generatePackageJsonContent(modes: DependencyModes): {
216
- dependencies: Record<string, string>;
217
- devDependencies: Record<string, string>;
218
- scripts: Record<string, string>;
219
- type: "module";
220
- } {
221
- const dependencies: Record<string, string> = {
222
- alepha: `^${version}`,
223
- };
224
-
225
- const devDependencies: Record<string, string> = {};
226
-
227
- const scripts: Record<string, string> = {
228
- dev: "alepha dev",
229
- build: "alepha build",
230
- lint: "alepha lint",
231
- typecheck: "alepha typecheck",
232
- verify: "alepha verify",
233
- };
234
-
235
- if (modes.ui) {
236
- dependencies["@alepha/ui"] = `^${version}`;
237
- modes.react = true;
238
- }
239
-
240
- if (modes.react) {
241
- dependencies["@alepha/react"] = `^${version}`;
242
- dependencies.react = "^19.2.0";
243
- dependencies["react-dom"] = "^19.2.0";
244
- devDependencies["@types/react"] = "^19.2.0";
245
- }
246
-
247
- return {
248
- type: "module",
249
- dependencies,
250
- devDependencies,
251
- scripts,
252
- };
253
- }
254
-
255
- /**
256
- * Ensure package.json exists and has correct configuration.
257
- *
258
- * Creates a new package.json if none exists, or updates an existing one to:
259
- * - Set "type": "module"
260
- * - Add Alepha dependencies
261
- * - Add standard scripts
262
- *
263
- * @param root - The root directory of the project
264
- * @param modes - Configuration for which dependencies to include
265
- */
266
- public async ensurePackageJson(
267
- root: string,
268
- modes: DependencyModes,
269
- ): Promise<object> {
270
- const packageJsonPath = join(root, "package.json");
271
- try {
272
- await access(packageJsonPath);
273
- } catch (error) {
274
- const obj = this.generatePackageJsonContent(modes);
275
- await writeFile(packageJsonPath, JSON.stringify(obj, null, 2));
276
- return obj;
277
- }
278
-
279
- const content = await readFile(packageJsonPath, "utf8");
280
- const packageJson = JSON.parse(content);
281
-
282
- const newPackageJson = this.generatePackageJsonContent(modes);
283
-
284
- packageJson.type = "module";
285
- packageJson.dependencies ??= {};
286
- packageJson.devDependencies ??= {};
287
- packageJson.scripts ??= {};
288
-
289
- Object.assign(packageJson.dependencies, newPackageJson.dependencies);
290
- Object.assign(packageJson.devDependencies, newPackageJson.devDependencies);
291
- Object.assign(packageJson.scripts, newPackageJson.scripts);
292
-
293
- await writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2));
294
-
295
- return packageJson;
296
- }
297
-
298
- public async ensureConfig(
299
- root: string,
300
- opts: {
301
- packageJson?: boolean | DependencyModes;
302
- tsconfigJson?: boolean;
303
- viteConfigTs?: boolean;
304
- indexHtml?: boolean;
305
- biomeJson?: boolean;
306
- editorconfig?: boolean;
307
- },
308
- ): Promise<Array<void | object>> {
309
- const tasks: Promise<void | object>[] = [];
310
-
311
- if (opts.packageJson) {
312
- tasks.push(
313
- this.ensurePackageJson(
314
- root,
315
- typeof opts.packageJson === "boolean" ? {} : opts.packageJson,
316
- ),
317
- );
318
- }
319
- if (opts.tsconfigJson) {
320
- tasks.push(this.ensureTsConfig(root));
321
- }
322
- if (opts.viteConfigTs) {
323
- tasks.push(this.ensureViteConfig(root));
324
- }
325
- if (opts.indexHtml) {
326
- tasks.push(this.ensureIndexHtml(root));
327
- }
328
- if (opts.biomeJson) {
329
- tasks.push(this.ensureBiomeConfig(root));
330
- }
331
- if (opts.editorconfig) {
332
- tasks.push(this.ensureEditorConfig(root));
333
- }
334
-
335
- return await Promise.all(tasks);
336
- }
337
-
338
- /**
339
- * Ensure tsconfig.json exists in the project.
340
- *
341
- * Creates a standard Alepha tsconfig.json if none exists.
342
- *
343
- * @param root - The root directory of the project
344
- */
345
- public async ensureTsConfig(root: string): Promise<void> {
346
- await this.ensureFileExists(root, "tsconfig.json", tsconfigJson, true);
347
- }
348
-
349
- /**
350
- * Ensure vite.config.ts exists in the project.
351
- *
352
- * Creates a standard Alepha vite.config.ts if none exists.
353
- */
354
- public async ensureViteConfig(
355
- root: string,
356
- serverEntry?: string,
357
- ): Promise<void> {
358
- await this.ensureFileExists(
359
- root,
360
- "vite.config.ts",
361
- viteConfigTs(serverEntry),
362
- false,
363
- );
364
- }
365
-
366
- protected async checkFileExists(
367
- root: string,
368
- name: string,
369
- checkParentDirectories: boolean = false,
370
- ): Promise<string | undefined> {
371
- const configPath = join(root, name);
372
- if (!checkParentDirectories) {
373
- try {
374
- await access(configPath);
375
- return configPath;
376
- } catch {
377
- return;
378
- }
379
- }
380
-
381
- let currentDir = root;
382
- const maxIterations = 10; // safety to prevent infinite loops
383
- let level = 0;
384
-
385
- while (level < maxIterations) {
386
- try {
387
- const maybe = join(currentDir, name);
388
- await access(maybe);
389
- return maybe;
390
- } catch {
391
- const parentDir = join(currentDir, "..");
392
- if (parentDir === currentDir) {
393
- break;
394
- }
395
- currentDir = parentDir;
396
- }
397
- level += 1;
398
- }
399
- }
400
-
401
- protected async ensureFileExists(
402
- root: string,
403
- name: string,
404
- content: string,
405
- checkParentDirectories: boolean = false,
406
- ): Promise<void> {
407
- const found = await this.checkFileExists(
408
- root,
409
- name,
410
- checkParentDirectories,
411
- );
412
-
413
- if (!found) {
414
- await writeFile(join(root, name), content);
415
- }
416
- }
417
-
418
- // ===================================================================================================================
419
- // Biome Configuration
420
- // ===================================================================================================================
421
-
422
- /**
423
- * Get the path to Biome configuration file.
424
- *
425
- * Looks for an existing biome.json in the project root, or creates one if it doesn't exist.
426
- */
427
- public async ensureBiomeConfig(root: string): Promise<void> {
428
- await this.ensureFileExists(root, "biome.json", biomeJson, true);
429
- }
430
-
431
- /**
432
- * Ensure .editorconfig exists in the project.
433
- *
434
- * Creates a standard .editorconfig if none exists.
435
- *
436
- * @param root - The root directory of the project
437
- */
438
- public async ensureEditorConfig(root: string): Promise<void> {
439
- await this.ensureFileExists(root, ".editorconfig", editorconfig, true);
440
- }
441
-
442
- // ===================================================================================================================
443
- // Drizzle ORM & Kit Utilities
444
- // ===================================================================================================================
445
-
446
109
  /**
447
110
  * Load Alepha instance from a server entry file.
448
- *
449
- * Dynamically imports the server entry file and extracts the Alepha instance.
450
- * Skips the automatic start process.
451
- *
452
- * @param rootDir - The root directory of the project
453
- * @param explicitEntry - Optional explicit path to the entry file
454
- * @returns Object containing the Alepha instance and the entry file path
455
- * @throws {AlephaError} If the Alepha instance cannot be found
456
111
  */
457
112
  public async loadAlephaFromServerEntryFile(
458
113
  rootDir?: string,
@@ -473,19 +128,13 @@ export class AlephaCliUtils {
473
128
 
474
129
  // check if alepha is correctly exported
475
130
  if (mod.default instanceof Alepha) {
476
- return {
477
- alepha: mod.default,
478
- entry,
479
- };
131
+ return { alepha: mod.default, entry };
480
132
  }
481
133
 
482
134
  // else, try with global variable
483
135
  const g: any = global;
484
136
  if (g.__alepha) {
485
- return {
486
- alepha: g.__alepha,
487
- entry,
488
- };
137
+ return { alepha: g.__alepha, entry };
489
138
  }
490
139
 
491
140
  throw new AlephaError(
@@ -493,16 +142,12 @@ export class AlephaCliUtils {
493
142
  );
494
143
  }
495
144
 
145
+ // ===========================================
146
+ // Drizzle ORM & Kit Utilities
147
+ // ===========================================
148
+
496
149
  /**
497
150
  * Generate JavaScript code for Drizzle entities export.
498
- *
499
- * Creates a temporary entities.js file that imports from the entry file
500
- * and exports database models for Drizzle Kit to process.
501
- *
502
- * @param entry - Path to the server entry file
503
- * @param provider - Name of the database provider
504
- * @param models - Array of model names to export
505
- * @returns JavaScript code as a string
506
151
  */
507
152
  public generateEntitiesJs(
508
153
  entry: string,
@@ -523,11 +168,12 @@ ${models.map((it: string) => `export const ${it} = models["${it}"];`).join("\n")
523
168
  `.trim();
524
169
  }
525
170
 
171
+ // ===========================================
172
+ // Environment
173
+ // ===========================================
174
+
526
175
  /**
527
176
  * Load environment variables from a .env file.
528
- *
529
- * Reads the .env file in the specified root directory and sets
530
- * the environment variables in process.env.
531
177
  */
532
178
  public async loadEnv(
533
179
  root: string,
@@ -536,217 +182,21 @@ ${models.map((it: string) => `export const ${it} = models["${it}"];`).join("\n")
536
182
  await this.envUtils.loadEnv(root, files);
537
183
  }
538
184
 
539
- public async getPackageManager(
540
- root: string,
541
- flags?: { yarn?: boolean; pnpm?: boolean; npm?: boolean; bun?: boolean },
542
- ): Promise<"yarn" | "pnpm" | "npm" | "bun"> {
543
- if (flags?.yarn) {
544
- return "yarn";
545
- }
546
- if (flags?.pnpm) {
547
- return "pnpm";
548
- }
549
- if (flags?.npm) {
550
- return "npm";
551
- }
552
- if (flags?.bun) {
553
- return "bun";
554
- }
555
- if (this.alepha.isBun()) {
556
- return "bun";
557
- }
558
- if (await this.checkFileExists(root, "yarn.lock", true)) {
559
- return "yarn";
560
- }
561
- if (await this.checkFileExists(root, "pnpm-lock.yaml", true)) {
562
- return "pnpm";
563
- }
564
- return "npm";
565
- }
566
-
567
- public async ensureIndexHtml(root: string) {
568
- if (await this.fs.exists(join(root, "index.html"))) {
569
- return;
570
- }
571
-
572
- const serverEntry = "src/main.server.ts";
573
- const browserEntry = "src/main.browser.ts";
574
- const appRouter = "src/AppRouter.ts";
575
-
576
- await this.fs.writeFile(join(root, "index.html"), indexHtml(browserEntry));
577
-
578
- try {
579
- await this.fs.mkdir(join(root, "src"), { recursive: true });
580
- } catch {}
581
-
582
- if (!(await this.fs.exists(join(root, browserEntry)))) {
583
- await this.fs.writeFile(join(root, browserEntry), mainBrowserTs());
584
- }
585
-
586
- if (!(await this.fs.exists(join(root, serverEntry)))) {
587
- await this.fs.writeFile(join(root, serverEntry), mainBrowserTs());
588
- }
589
-
590
- if (!(await this.fs.exists(join(root, appRouter)))) {
591
- await this.fs.writeFile(join(root, appRouter), appRouterTs());
592
- }
593
- }
594
-
595
- public async exists(root: string, dirName: string): Promise<boolean> {
596
- return this.fs.exists(join(root, dirName));
597
- }
598
-
599
- /**
600
- * Ensure src/main.ts exists with a minimal Alepha bootstrap.
601
- *
602
- * Creates the src directory and main.ts file if the src directory
603
- * doesn't exist or is empty.
604
- *
605
- * @param root - The root directory of the project
606
- */
607
- public async ensureSrcMain(root: string): Promise<void> {
608
- const srcDir = join(root, "src");
609
- const mainPath = join(srcDir, "main.ts");
610
-
611
- // Check if src directory exists
612
- const srcExists = await this.fs.exists(srcDir);
613
-
614
- if (!srcExists) {
615
- // Create src directory and main.ts
616
- await this.fs.mkdir(srcDir, { recursive: true });
617
- await this.fs.writeFile(mainPath, mainTs());
618
- return;
619
- }
620
-
621
- // Check if src directory is empty
622
- const files = await this.fs.ls(srcDir);
623
- if (files.length === 0) {
624
- await this.fs.writeFile(mainPath, mainTs());
625
- }
626
- }
627
-
628
- /**
629
- * Ensure test directory exists with a dummy test file.
630
- *
631
- * Creates the test directory and a dummy.spec.ts file if the test directory
632
- * doesn't exist or is empty.
633
- *
634
- * @param root - The root directory of the project
635
- */
636
- public async ensureTestDir(root: string): Promise<void> {
637
- const testDir = join(root, "test");
638
- const dummyPath = join(testDir, "dummy.spec.ts");
639
-
640
- // Check if test directory exists
641
- const testExists = await this.fs.exists(testDir);
642
-
643
- if (!testExists) {
644
- // Create test directory and dummy.spec.ts
645
- await this.fs.mkdir(testDir, { recursive: true });
646
- await this.fs.writeFile(dummyPath, dummySpecTs());
647
- return;
648
- }
649
-
650
- // Check if test directory is empty
651
- const files = await this.fs.ls(testDir);
652
- if (files.length === 0) {
653
- await this.fs.writeFile(dummyPath, dummySpecTs());
654
- }
655
- }
656
-
657
- async readPackageJson(root: string): Promise<Record<string, any>> {
658
- const packageJson = await this.fs
659
- .createFile({
660
- path: join(root, "package.json"),
661
- })
662
- .text();
663
- return JSON.parse(packageJson);
664
- }
665
-
666
- /**
667
- * Check if a dependency is installed in the project.
668
- *
669
- * @param root - The root directory of the project
670
- * @param packageName - The name of the package to check
671
- * @returns True if the package is in dependencies or devDependencies
672
- */
673
- async hasDependency(root: string, packageName: string): Promise<boolean> {
674
- try {
675
- const pkg = await this.readPackageJson(root);
676
- return !!(
677
- pkg.dependencies?.[packageName] || pkg.devDependencies?.[packageName]
678
- );
679
- } catch {
680
- return false;
681
- }
682
- }
683
-
684
- /**
685
- * Check if Expo is present in the project.
686
- *
687
- * @param root - The root directory of the project
688
- * @returns True if expo is in dependencies or devDependencies
689
- */
690
- async hasExpo(root: string): Promise<boolean> {
691
- return this.hasDependency(root, "expo");
692
- }
693
-
694
- async getInstallCommand(root: string, packageName: string, dev = true) {
695
- const pm = await this.getPackageManager(root);
696
- let cmd: string;
697
-
698
- switch (pm) {
699
- case "yarn":
700
- cmd = `yarn add ${dev ? "-D" : ""} ${packageName}`;
701
- break;
702
- case "pnpm":
703
- cmd = `pnpm add ${dev ? "-D" : ""} ${packageName}`;
704
- break;
705
- case "bun":
706
- cmd = `bun add ${dev ? "-d" : ""} ${packageName}`;
707
- break;
708
- default:
709
- cmd = `npm install ${dev ? "--save-dev" : ""} ${packageName}`;
710
- }
185
+ // ===========================================
186
+ // Helpers
187
+ // ===========================================
711
188
 
712
- return cmd.replace(/\s+/g, " ").trim();
189
+ public async exists(root: string, path: string): Promise<boolean> {
190
+ return this.fs.exists(this.fs.join(root, path));
713
191
  }
714
192
 
715
- /**
716
- * Install a dependency if it's missing from the project.
717
- *
718
- * Automatically detects the package manager (yarn, pnpm, npm) and installs
719
- * the package as a dev dependency if not already present.
720
- */
721
- async ensureDependency(
193
+ protected async checkFileExists(
722
194
  root: string,
723
- packageName: string,
724
- options: { dev?: boolean; run?: RunnerMethod } = {},
725
- ): Promise<void> {
726
- const { dev = true } = options;
727
-
728
- if (await this.hasDependency(root, packageName)) {
729
- this.log.debug(`Dependency '${packageName}' is already installed`);
730
- return;
731
- }
732
-
733
- const cmd = await this.getInstallCommand(root, packageName, dev);
734
-
735
- if (options.run) {
736
- // if it's during a Runner flow, just use the runner's run method
737
- await options.run(cmd, {
738
- alias: `installing ${packageName}`,
739
- });
740
- } else {
741
- // else, run directly with our util exec method
742
- this.log.debug(`Installing ${packageName}`);
743
- await this.exec(cmd, { global: true });
195
+ name: string,
196
+ ): Promise<string | undefined> {
197
+ const configPath = this.fs.join(root, name);
198
+ if (await this.fs.exists(configPath)) {
199
+ return configPath;
744
200
  }
745
201
  }
746
202
  }
747
-
748
- export interface DependencyModes {
749
- react?: boolean;
750
- ui?: boolean;
751
- expo?: boolean;
752
- }