alepha 0.14.4 → 0.15.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (322) hide show
  1. package/README.md +44 -102
  2. package/dist/api/audits/index.d.ts +331 -443
  3. package/dist/api/audits/index.d.ts.map +1 -1
  4. package/dist/api/audits/index.js +2 -2
  5. package/dist/api/audits/index.js.map +1 -1
  6. package/dist/api/files/index.d.ts +0 -113
  7. package/dist/api/files/index.d.ts.map +1 -1
  8. package/dist/api/files/index.js +2 -3
  9. package/dist/api/files/index.js.map +1 -1
  10. package/dist/api/jobs/index.d.ts +151 -262
  11. package/dist/api/jobs/index.d.ts.map +1 -1
  12. package/dist/api/notifications/index.browser.js +4 -4
  13. package/dist/api/notifications/index.browser.js.map +1 -1
  14. package/dist/api/notifications/index.d.ts +164 -276
  15. package/dist/api/notifications/index.d.ts.map +1 -1
  16. package/dist/api/notifications/index.js +4 -4
  17. package/dist/api/notifications/index.js.map +1 -1
  18. package/dist/api/parameters/index.d.ts +265 -377
  19. package/dist/api/parameters/index.d.ts.map +1 -1
  20. package/dist/api/users/index.browser.js +1 -2
  21. package/dist/api/users/index.browser.js.map +1 -1
  22. package/dist/api/users/index.d.ts +195 -301
  23. package/dist/api/users/index.d.ts.map +1 -1
  24. package/dist/api/users/index.js +203 -184
  25. package/dist/api/users/index.js.map +1 -1
  26. package/dist/api/verifications/index.d.ts.map +1 -1
  27. package/dist/batch/index.d.ts.map +1 -1
  28. package/dist/batch/index.js +1 -2
  29. package/dist/batch/index.js.map +1 -1
  30. package/dist/bucket/index.d.ts.map +1 -1
  31. package/dist/cache/core/index.d.ts.map +1 -1
  32. package/dist/cache/redis/index.d.ts.map +1 -1
  33. package/dist/cache/redis/index.js +2 -2
  34. package/dist/cache/redis/index.js.map +1 -1
  35. package/dist/cli/index.d.ts +5900 -165
  36. package/dist/cli/index.d.ts.map +1 -1
  37. package/dist/cli/index.js +1481 -639
  38. package/dist/cli/index.js.map +1 -1
  39. package/dist/command/index.d.ts +8 -4
  40. package/dist/command/index.d.ts.map +1 -1
  41. package/dist/command/index.js +29 -25
  42. package/dist/command/index.js.map +1 -1
  43. package/dist/core/index.browser.js +563 -54
  44. package/dist/core/index.browser.js.map +1 -1
  45. package/dist/core/index.d.ts +175 -8
  46. package/dist/core/index.d.ts.map +1 -1
  47. package/dist/core/index.js +564 -54
  48. package/dist/core/index.js.map +1 -1
  49. package/dist/core/index.native.js +563 -54
  50. package/dist/core/index.native.js.map +1 -1
  51. package/dist/datetime/index.d.ts.map +1 -1
  52. package/dist/datetime/index.js +4 -4
  53. package/dist/datetime/index.js.map +1 -1
  54. package/dist/email/index.d.ts +89 -42
  55. package/dist/email/index.d.ts.map +1 -1
  56. package/dist/email/index.js +129 -33
  57. package/dist/email/index.js.map +1 -1
  58. package/dist/fake/index.d.ts +7969 -2
  59. package/dist/fake/index.d.ts.map +1 -1
  60. package/dist/fake/index.js +22 -22
  61. package/dist/fake/index.js.map +1 -1
  62. package/dist/file/index.d.ts +134 -1
  63. package/dist/file/index.d.ts.map +1 -1
  64. package/dist/file/index.js +253 -1
  65. package/dist/file/index.js.map +1 -1
  66. package/dist/lock/core/index.d.ts.map +1 -1
  67. package/dist/lock/redis/index.d.ts.map +1 -1
  68. package/dist/logger/index.d.ts +1 -2
  69. package/dist/logger/index.d.ts.map +1 -1
  70. package/dist/logger/index.js +1 -5
  71. package/dist/logger/index.js.map +1 -1
  72. package/dist/mcp/index.d.ts +19 -1
  73. package/dist/mcp/index.d.ts.map +1 -1
  74. package/dist/mcp/index.js +28 -4
  75. package/dist/mcp/index.js.map +1 -1
  76. package/dist/orm/chunk-DH6iiROE.js +38 -0
  77. package/dist/orm/index.browser.js +9 -9
  78. package/dist/orm/index.browser.js.map +1 -1
  79. package/dist/orm/index.bun.js +2821 -0
  80. package/dist/orm/index.bun.js.map +1 -0
  81. package/dist/orm/index.d.ts +318 -169
  82. package/dist/orm/index.d.ts.map +1 -1
  83. package/dist/orm/index.js +2086 -1776
  84. package/dist/orm/index.js.map +1 -1
  85. package/dist/queue/core/index.d.ts +4 -4
  86. package/dist/queue/core/index.d.ts.map +1 -1
  87. package/dist/queue/redis/index.d.ts.map +1 -1
  88. package/dist/redis/index.bun.js +285 -0
  89. package/dist/redis/index.bun.js.map +1 -0
  90. package/dist/redis/index.d.ts +13 -31
  91. package/dist/redis/index.d.ts.map +1 -1
  92. package/dist/redis/index.js +18 -38
  93. package/dist/redis/index.js.map +1 -1
  94. package/dist/retry/index.d.ts.map +1 -1
  95. package/dist/router/index.d.ts.map +1 -1
  96. package/dist/scheduler/index.d.ts +83 -1
  97. package/dist/scheduler/index.d.ts.map +1 -1
  98. package/dist/scheduler/index.js +393 -1
  99. package/dist/scheduler/index.js.map +1 -1
  100. package/dist/security/index.browser.js +5 -1
  101. package/dist/security/index.browser.js.map +1 -1
  102. package/dist/security/index.d.ts +598 -112
  103. package/dist/security/index.d.ts.map +1 -1
  104. package/dist/security/index.js +1808 -97
  105. package/dist/security/index.js.map +1 -1
  106. package/dist/server/auth/index.d.ts +1200 -175
  107. package/dist/server/auth/index.d.ts.map +1 -1
  108. package/dist/server/auth/index.js +1268 -37
  109. package/dist/server/auth/index.js.map +1 -1
  110. package/dist/server/cache/index.d.ts +6 -3
  111. package/dist/server/cache/index.d.ts.map +1 -1
  112. package/dist/server/cache/index.js +1 -1
  113. package/dist/server/cache/index.js.map +1 -1
  114. package/dist/server/compress/index.d.ts.map +1 -1
  115. package/dist/server/cookies/index.d.ts.map +1 -1
  116. package/dist/server/cookies/index.js +3 -3
  117. package/dist/server/cookies/index.js.map +1 -1
  118. package/dist/server/core/index.d.ts +115 -13
  119. package/dist/server/core/index.d.ts.map +1 -1
  120. package/dist/server/core/index.js +321 -139
  121. package/dist/server/core/index.js.map +1 -1
  122. package/dist/server/cors/index.d.ts +0 -1
  123. package/dist/server/cors/index.d.ts.map +1 -1
  124. package/dist/server/health/index.d.ts +0 -1
  125. package/dist/server/health/index.d.ts.map +1 -1
  126. package/dist/server/helmet/index.d.ts.map +1 -1
  127. package/dist/server/links/index.browser.js +9 -1
  128. package/dist/server/links/index.browser.js.map +1 -1
  129. package/dist/server/links/index.d.ts +1 -2
  130. package/dist/server/links/index.d.ts.map +1 -1
  131. package/dist/server/links/index.js +14 -7
  132. package/dist/server/links/index.js.map +1 -1
  133. package/dist/server/metrics/index.d.ts +514 -1
  134. package/dist/server/metrics/index.d.ts.map +1 -1
  135. package/dist/server/metrics/index.js +4462 -4
  136. package/dist/server/metrics/index.js.map +1 -1
  137. package/dist/server/multipart/index.d.ts.map +1 -1
  138. package/dist/server/proxy/index.d.ts +0 -1
  139. package/dist/server/proxy/index.d.ts.map +1 -1
  140. package/dist/server/rate-limit/index.d.ts.map +1 -1
  141. package/dist/server/static/index.d.ts.map +1 -1
  142. package/dist/server/swagger/index.d.ts +1 -2
  143. package/dist/server/swagger/index.d.ts.map +1 -1
  144. package/dist/server/swagger/index.js +1 -2
  145. package/dist/server/swagger/index.js.map +1 -1
  146. package/dist/sms/index.d.ts +3 -1
  147. package/dist/sms/index.d.ts.map +1 -1
  148. package/dist/sms/index.js +10 -10
  149. package/dist/sms/index.js.map +1 -1
  150. package/dist/thread/index.d.ts +0 -1
  151. package/dist/thread/index.d.ts.map +1 -1
  152. package/dist/thread/index.js +2 -2
  153. package/dist/thread/index.js.map +1 -1
  154. package/dist/topic/core/index.d.ts.map +1 -1
  155. package/dist/topic/redis/index.d.ts.map +1 -1
  156. package/dist/vite/index.d.ts +6315 -149
  157. package/dist/vite/index.d.ts.map +1 -1
  158. package/dist/vite/index.js +140 -469
  159. package/dist/vite/index.js.map +1 -1
  160. package/dist/websocket/index.browser.js +9 -9
  161. package/dist/websocket/index.browser.js.map +1 -1
  162. package/dist/websocket/index.d.ts +28 -28
  163. package/dist/websocket/index.d.ts.map +1 -1
  164. package/dist/websocket/index.js +9 -9
  165. package/dist/websocket/index.js.map +1 -1
  166. package/package.json +13 -18
  167. package/src/api/files/controllers/AdminFileStatsController.ts +0 -1
  168. package/src/api/users/atoms/realmAuthSettingsAtom.ts +5 -0
  169. package/src/api/users/controllers/{UserRealmController.ts → RealmController.ts} +11 -11
  170. package/src/api/users/entities/users.ts +1 -1
  171. package/src/api/users/index.ts +8 -8
  172. package/src/api/users/primitives/{$userRealm.ts → $realm.ts} +17 -19
  173. package/src/api/users/providers/{UserRealmProvider.ts → RealmProvider.ts} +26 -30
  174. package/src/api/users/schemas/{userRealmConfigSchema.ts → realmConfigSchema.ts} +2 -2
  175. package/src/api/users/services/CredentialService.ts +7 -7
  176. package/src/api/users/services/IdentityService.ts +4 -4
  177. package/src/api/users/services/RegistrationService.spec.ts +25 -27
  178. package/src/api/users/services/RegistrationService.ts +38 -27
  179. package/src/api/users/services/SessionCrudService.ts +3 -3
  180. package/src/api/users/services/SessionService.spec.ts +3 -3
  181. package/src/api/users/services/SessionService.ts +27 -18
  182. package/src/api/users/services/UserService.ts +7 -7
  183. package/src/batch/providers/BatchProvider.ts +1 -2
  184. package/src/cli/apps/AlephaCli.ts +2 -2
  185. package/src/cli/apps/AlephaPackageBuilderCli.ts +47 -20
  186. package/src/cli/assets/apiHelloControllerTs.ts +19 -0
  187. package/src/cli/assets/apiIndexTs.ts +16 -0
  188. package/src/cli/assets/biomeJson.ts +2 -1
  189. package/src/cli/assets/claudeMd.ts +308 -0
  190. package/src/cli/assets/dummySpecTs.ts +2 -1
  191. package/src/cli/assets/editorconfig.ts +2 -1
  192. package/src/cli/assets/mainBrowserTs.ts +4 -3
  193. package/src/cli/assets/mainCss.ts +24 -0
  194. package/src/cli/assets/mainServerTs.ts +24 -0
  195. package/src/cli/assets/tsconfigJson.ts +2 -1
  196. package/src/cli/assets/webAppRouterTs.ts +16 -0
  197. package/src/cli/assets/webHelloComponentTsx.ts +20 -0
  198. package/src/cli/assets/webIndexTs.ts +16 -0
  199. package/src/cli/atoms/appEntryOptions.ts +13 -0
  200. package/src/cli/atoms/buildOptions.ts +1 -1
  201. package/src/cli/atoms/changelogOptions.ts +1 -1
  202. package/src/cli/commands/build.ts +97 -61
  203. package/src/cli/commands/db.ts +21 -18
  204. package/src/cli/commands/deploy.ts +17 -5
  205. package/src/cli/commands/dev.ts +26 -47
  206. package/src/cli/commands/gen/env.ts +1 -1
  207. package/src/cli/commands/init.ts +79 -25
  208. package/src/cli/commands/lint.ts +9 -3
  209. package/src/cli/commands/test.ts +8 -2
  210. package/src/cli/commands/typecheck.ts +5 -1
  211. package/src/cli/commands/verify.ts +4 -2
  212. package/src/cli/defineConfig.ts +9 -0
  213. package/src/cli/index.ts +2 -1
  214. package/src/cli/providers/AppEntryProvider.ts +131 -0
  215. package/src/cli/providers/ViteBuildProvider.ts +82 -0
  216. package/src/cli/providers/ViteDevServerProvider.ts +350 -0
  217. package/src/cli/providers/ViteTemplateProvider.ts +27 -0
  218. package/src/cli/services/AlephaCliUtils.ts +72 -602
  219. package/src/cli/services/PackageManagerUtils.ts +308 -0
  220. package/src/cli/services/ProjectScaffolder.ts +329 -0
  221. package/src/command/helpers/Runner.ts +15 -3
  222. package/src/core/Alepha.ts +2 -8
  223. package/src/core/__tests__/Alepha-graph.spec.ts +4 -0
  224. package/src/core/index.shared.ts +1 -0
  225. package/src/core/index.ts +2 -0
  226. package/src/core/primitives/$hook.ts +6 -2
  227. package/src/core/primitives/$module.spec.ts +4 -0
  228. package/src/core/primitives/$module.ts +12 -0
  229. package/src/core/providers/AlsProvider.ts +1 -1
  230. package/src/core/providers/CodecManager.spec.ts +12 -6
  231. package/src/core/providers/CodecManager.ts +26 -6
  232. package/src/core/providers/EventManager.ts +169 -13
  233. package/src/core/providers/KeylessJsonSchemaCodec.spec.ts +878 -0
  234. package/src/core/providers/KeylessJsonSchemaCodec.ts +789 -0
  235. package/src/core/providers/SchemaValidator.spec.ts +236 -0
  236. package/src/core/providers/StateManager.spec.ts +27 -16
  237. package/src/email/providers/LocalEmailProvider.spec.ts +111 -87
  238. package/src/email/providers/LocalEmailProvider.ts +52 -15
  239. package/src/email/providers/NodemailerEmailProvider.ts +167 -56
  240. package/src/file/errors/FileError.ts +7 -0
  241. package/src/file/index.ts +9 -1
  242. package/src/file/providers/MemoryFileSystemProvider.ts +393 -0
  243. package/src/logger/providers/PrettyFormatterProvider.ts +0 -9
  244. package/src/mcp/errors/McpError.ts +30 -0
  245. package/src/mcp/index.ts +3 -0
  246. package/src/mcp/transports/SseMcpTransport.ts +16 -6
  247. package/src/orm/index.browser.ts +1 -19
  248. package/src/orm/index.bun.ts +77 -0
  249. package/src/orm/index.shared-server.ts +22 -0
  250. package/src/orm/index.shared.ts +15 -0
  251. package/src/orm/index.ts +19 -39
  252. package/src/orm/providers/DrizzleKitProvider.ts +3 -5
  253. package/src/orm/providers/drivers/BunPostgresProvider.ts +3 -5
  254. package/src/orm/providers/drivers/BunSqliteProvider.ts +1 -1
  255. package/src/orm/providers/drivers/CloudflareD1Provider.ts +4 -0
  256. package/src/orm/providers/drivers/DatabaseProvider.ts +4 -0
  257. package/src/orm/providers/drivers/PglitePostgresProvider.ts +4 -0
  258. package/src/orm/services/Repository.ts +19 -0
  259. package/src/redis/index.bun.ts +35 -0
  260. package/src/redis/providers/BunRedisProvider.ts +12 -43
  261. package/src/redis/providers/BunRedisSubscriberProvider.ts +2 -3
  262. package/src/redis/providers/NodeRedisProvider.ts +16 -34
  263. package/src/{server/security → security}/__tests__/BasicAuth.spec.ts +11 -11
  264. package/src/{server/security → security}/__tests__/ServerSecurityProvider-realm.spec.ts +21 -16
  265. package/src/{server/security/providers → security/__tests__}/ServerSecurityProvider.spec.ts +5 -5
  266. package/src/security/index.browser.ts +5 -0
  267. package/src/security/index.ts +90 -7
  268. package/src/security/primitives/{$realm.spec.ts → $issuer.spec.ts} +11 -11
  269. package/src/security/primitives/{$realm.ts → $issuer.ts} +20 -17
  270. package/src/security/primitives/$role.ts +5 -5
  271. package/src/security/primitives/$serviceAccount.spec.ts +5 -5
  272. package/src/security/primitives/$serviceAccount.ts +3 -3
  273. package/src/{server/security → security}/providers/ServerSecurityProvider.ts +5 -7
  274. package/src/server/auth/primitives/$auth.ts +10 -10
  275. package/src/server/auth/primitives/$authCredentials.ts +3 -3
  276. package/src/server/auth/primitives/$authGithub.ts +3 -3
  277. package/src/server/auth/primitives/$authGoogle.ts +3 -3
  278. package/src/server/auth/providers/ServerAuthProvider.ts +13 -13
  279. package/src/server/cache/providers/ServerCacheProvider.ts +1 -1
  280. package/src/server/cookies/providers/ServerCookiesProvider.ts +3 -3
  281. package/src/server/core/index.ts +1 -1
  282. package/src/server/core/providers/BunHttpServerProvider.ts +1 -1
  283. package/src/server/core/providers/NodeHttpServerProvider.spec.ts +125 -0
  284. package/src/server/core/providers/NodeHttpServerProvider.ts +92 -24
  285. package/src/server/core/providers/ServerBodyParserProvider.ts +19 -23
  286. package/src/server/core/providers/ServerLoggerProvider.ts +23 -19
  287. package/src/server/core/providers/ServerProvider.ts +144 -24
  288. package/src/server/core/providers/ServerRouterProvider.ts +259 -115
  289. package/src/server/core/providers/ServerTimingProvider.ts +2 -2
  290. package/src/server/links/atoms/apiLinksAtom.ts +7 -0
  291. package/src/server/links/index.browser.ts +2 -0
  292. package/src/server/links/index.ts +3 -1
  293. package/src/server/links/providers/LinkProvider.ts +1 -1
  294. package/src/server/swagger/index.ts +1 -1
  295. package/src/sms/providers/LocalSmsProvider.spec.ts +153 -111
  296. package/src/sms/providers/LocalSmsProvider.ts +8 -7
  297. package/src/vite/index.ts +3 -2
  298. package/src/vite/tasks/buildClient.ts +0 -1
  299. package/src/vite/tasks/buildServer.ts +80 -22
  300. package/src/vite/tasks/copyAssets.ts +5 -4
  301. package/src/vite/tasks/generateCloudflare.ts +7 -0
  302. package/src/vite/tasks/generateSitemap.ts +64 -23
  303. package/src/vite/tasks/index.ts +0 -2
  304. package/src/vite/tasks/prerenderPages.ts +49 -24
  305. package/dist/server/security/index.browser.js +0 -13
  306. package/dist/server/security/index.browser.js.map +0 -1
  307. package/dist/server/security/index.d.ts +0 -173
  308. package/dist/server/security/index.d.ts.map +0 -1
  309. package/dist/server/security/index.js +0 -311
  310. package/dist/server/security/index.js.map +0 -1
  311. package/src/cli/assets/appRouterTs.ts +0 -9
  312. package/src/cli/assets/indexHtml.ts +0 -15
  313. package/src/cli/assets/mainTs.ts +0 -13
  314. package/src/cli/commands/format.ts +0 -17
  315. package/src/server/security/index.browser.ts +0 -10
  316. package/src/server/security/index.ts +0 -94
  317. package/src/vite/helpers/boot.ts +0 -106
  318. package/src/vite/plugins/viteAlephaDev.ts +0 -177
  319. package/src/vite/tasks/devServer.ts +0 -69
  320. package/src/vite/tasks/runAlepha.ts +0 -270
  321. /package/src/{server/security → security}/primitives/$basicAuth.ts +0 -0
  322. /package/src/{server/security → security}/providers/ServerBasicAuthProvider.ts +0 -0
@@ -1,9 +1,15 @@
1
1
  import { $inject, t } from "alepha";
2
2
  import { $command } from "alepha/command";
3
+ import { FileSystemProvider } from "alepha/file";
3
4
  import { AlephaCliUtils } from "../services/AlephaCliUtils.ts";
5
+ import { PackageManagerUtils } from "../services/PackageManagerUtils.ts";
6
+ import { ProjectScaffolder } from "../services/ProjectScaffolder.ts";
4
7
 
5
8
  export class InitCommand {
6
9
  protected readonly utils = $inject(AlephaCliUtils);
10
+ protected readonly pm = $inject(PackageManagerUtils);
11
+ protected readonly scaffolder = $inject(ProjectScaffolder);
12
+ protected readonly fs = $inject(FileSystemProvider);
7
13
 
8
14
  /**
9
15
  * Ensure the project has the necessary Alepha configuration files.
@@ -12,7 +18,20 @@ export class InitCommand {
12
18
  public readonly init = $command({
13
19
  name: "init",
14
20
  description: "Add missing Alepha configuration files to the project",
21
+ args: t.optional(
22
+ t.text({
23
+ title: "path",
24
+ trim: true,
25
+ lowercase: true,
26
+ }),
27
+ ),
15
28
  flags: t.object({
29
+ agent: t.optional(
30
+ t.boolean({
31
+ aliases: ["a"],
32
+ description: "Add CLAUDE.md for Claude Code AI assistant",
33
+ }),
34
+ ),
16
35
  // choose package manager
17
36
  yarn: t.optional(t.boolean({ description: "Use Yarn package manager" })),
18
37
  pnpm: t.optional(t.boolean({ description: "Use pnpm package manager" })),
@@ -20,7 +39,10 @@ export class InitCommand {
20
39
  bun: t.optional(t.boolean({ description: "Use Bun package manager" })),
21
40
  // choose which dependencies to add
22
41
  react: t.optional(
23
- t.boolean({ description: "Include Alepha React dependencies" }),
42
+ t.boolean({
43
+ aliases: ["r"],
44
+ description: "Include Alepha React dependencies",
45
+ }),
24
46
  ),
25
47
  ui: t.optional(
26
48
  t.boolean({ description: "Include Alepha UI dependencies" }),
@@ -28,63 +50,95 @@ export class InitCommand {
28
50
  test: t.optional(
29
51
  t.boolean({ description: "Include Vitest and create test directory" }),
30
52
  ),
53
+ force: t.optional(
54
+ t.boolean({
55
+ aliases: ["f"],
56
+ description: "Override existing files",
57
+ }),
58
+ ),
31
59
  }),
32
- handler: async ({ run, flags, root }) => {
33
- if (flags.ui) {
34
- flags.react = true;
60
+ handler: async ({ run, flags, root, args }) => {
61
+ if (flags.react) {
62
+ flags.ui = true;
35
63
  }
36
64
 
37
- const isExpo = await this.utils.hasExpo(root);
65
+ if (args) {
66
+ root = this.fs.join(root, args);
67
+ await this.fs.mkdir(root);
68
+ }
69
+
70
+ const isExpo = await this.pm.hasExpo(root);
71
+
72
+ const force = !!flags.force;
38
73
 
39
74
  await run({
40
75
  name: "ensuring configuration files",
41
76
  handler: async () => {
42
- await this.utils.ensureConfig(root, {
77
+ await this.scaffolder.ensureConfig(root, {
78
+ force,
43
79
  tsconfigJson: true,
44
80
  packageJson: flags,
45
81
  biomeJson: true,
46
82
  editorconfig: true,
47
83
  indexHtml: !!flags.react && !isExpo,
84
+ claudeMd: flags.agent
85
+ ? { react: !!flags.react, ui: !!flags.ui }
86
+ : false,
48
87
  });
49
88
 
50
- // Create src/main.ts if src directory is empty or doesn't exist
89
+ // Create API project structure if not React
51
90
  if (!flags.react) {
52
- await this.utils.ensureSrcMain(root);
91
+ await this.scaffolder.ensureApiProject(root, { force });
53
92
  }
54
93
  },
55
94
  });
56
95
 
57
96
  // TODO: check if all alepha dependencies are same version
58
97
 
59
- const pm = await this.utils.getPackageManager(root, flags);
60
- if (pm === "yarn") {
61
- await this.utils.ensureYarn(root);
62
- await run("yarn set version stable");
63
- } else if (pm === "bun") {
64
- await this.utils.ensureBun(root);
65
- } else if (pm === "pnpm") {
66
- await this.utils.ensurePnpm(root);
98
+ const pmName = await this.pm.getPackageManager(root, flags);
99
+ if (pmName === "yarn") {
100
+ await this.pm.ensureYarn(root);
101
+ await run("yarn set version stable", { root });
102
+ } else if (pmName === "bun") {
103
+ await this.pm.ensureBun(root);
104
+ } else if (pmName === "pnpm") {
105
+ await this.pm.ensurePnpm(root);
67
106
  } else {
68
- await this.utils.ensureNpm(root);
107
+ await this.pm.ensureNpm(root);
69
108
  }
70
109
 
71
- await run(`${pm} install`, {
72
- alias: `installing dependencies with ${pm}`,
110
+ await run(`${pmName} install`, {
111
+ alias: `installing dependencies with ${pmName}`,
112
+ root,
73
113
  });
74
114
 
75
115
  if (!isExpo) {
76
- await this.utils.ensureDependency(root, "vite", { run });
116
+ await this.pm.ensureDependency(root, "vite", {
117
+ run,
118
+ exec: (cmd, opts) => this.utils.exec(cmd, opts),
119
+ });
77
120
  }
78
121
 
79
- await this.utils.ensureDependency(root, "@biomejs/biome", { run });
122
+ await this.pm.ensureDependency(root, "@biomejs/biome", {
123
+ run,
124
+ exec: (cmd, opts) => this.utils.exec(cmd, opts),
125
+ });
80
126
 
81
127
  // Install vitest and create test directory if --test flag is set
82
128
  if (flags.test) {
83
- await this.utils.ensureTestDir(root);
84
- await run(`${pm} ${pm === "yarn" ? "add" : "install"} -D vitest`, {
85
- alias: "setup testing with Vitest",
86
- });
129
+ await this.scaffolder.ensureTestDir(root);
130
+ await run(
131
+ `${pmName} ${pmName === "yarn" ? "add" : "install"} -D vitest`,
132
+ {
133
+ alias: "setup testing with Vitest",
134
+ },
135
+ );
87
136
  }
137
+
138
+ await run(`${pmName} run lint`, {
139
+ alias: "running linter",
140
+ root,
141
+ });
88
142
  },
89
143
  });
90
144
  }
@@ -1,17 +1,23 @@
1
1
  import { $inject } from "alepha";
2
2
  import { $command } from "alepha/command";
3
3
  import { AlephaCliUtils } from "../services/AlephaCliUtils.ts";
4
+ import { PackageManagerUtils } from "../services/PackageManagerUtils.ts";
5
+ import { ProjectScaffolder } from "../services/ProjectScaffolder.ts";
4
6
 
5
7
  export class LintCommand {
6
8
  protected readonly utils = $inject(AlephaCliUtils);
9
+ protected readonly pm = $inject(PackageManagerUtils);
10
+ protected readonly scaffolder = $inject(ProjectScaffolder);
7
11
 
8
12
  public readonly lint = $command({
9
13
  name: "lint",
10
14
  description: "Run linter across the codebase using Biome",
11
15
  handler: async ({ root }) => {
12
- await this.utils.ensureConfig(root, { biomeJson: true });
13
- await this.utils.ensureDependency(root, "@biomejs/biome");
14
- await this.utils.exec("biome check --formatter-enabled=false --fix");
16
+ await this.scaffolder.ensureConfig(root, { biomeJson: true });
17
+ await this.pm.ensureDependency(root, "@biomejs/biome", {
18
+ exec: (cmd, opts) => this.utils.exec(cmd, opts),
19
+ });
20
+ await this.utils.exec("biome check --fix");
15
21
  },
16
22
  });
17
23
  }
@@ -1,9 +1,13 @@
1
1
  import { $inject, t } from "alepha";
2
2
  import { $command } from "alepha/command";
3
3
  import { AlephaCliUtils } from "../services/AlephaCliUtils.ts";
4
+ import { PackageManagerUtils } from "../services/PackageManagerUtils.ts";
5
+ import { ProjectScaffolder } from "../services/ProjectScaffolder.ts";
4
6
 
5
7
  export class TestCommand {
6
8
  protected readonly utils = $inject(AlephaCliUtils);
9
+ protected readonly pm = $inject(PackageManagerUtils);
10
+ protected readonly scaffolder = $inject(ProjectScaffolder);
7
11
 
8
12
  public readonly test = $command({
9
13
  name: "test",
@@ -26,12 +30,14 @@ export class TestCommand {
26
30
  ),
27
31
  }),
28
32
  handler: async ({ root, flags, env }) => {
29
- await this.utils.ensureConfig(root, {
33
+ await this.scaffolder.ensureConfig(root, {
30
34
  tsconfigJson: true,
31
35
  });
32
36
 
33
37
  // Ensure vitest is installed before running
34
- await this.utils.ensureDependency(root, "vitest");
38
+ await this.pm.ensureDependency(root, "vitest", {
39
+ exec: (cmd, opts) => this.utils.exec(cmd, opts),
40
+ });
35
41
 
36
42
  const config = flags.config ? `--config=${flags.config}` : "";
37
43
 
@@ -2,9 +2,11 @@ import { $inject } from "alepha";
2
2
  import { $command } from "alepha/command";
3
3
  import { $logger } from "alepha/logger";
4
4
  import { AlephaCliUtils } from "../services/AlephaCliUtils.ts";
5
+ import { PackageManagerUtils } from "../services/PackageManagerUtils.ts";
5
6
 
6
7
  export class TypecheckCommand {
7
8
  protected readonly utils = $inject(AlephaCliUtils);
9
+ protected readonly pm = $inject(PackageManagerUtils);
8
10
  protected readonly log = $logger();
9
11
 
10
12
  /**
@@ -16,7 +18,9 @@ export class TypecheckCommand {
16
18
  description: "Check TypeScript types across the codebase",
17
19
  handler: async ({ root }) => {
18
20
  this.log.info("Starting TypeScript type checking...");
19
- await this.utils.ensureDependency(root, "typescript");
21
+ await this.pm.ensureDependency(root, "typescript", {
22
+ exec: (cmd, opts) => this.utils.exec(cmd, opts),
23
+ });
20
24
  await this.utils.exec("tsc --noEmit");
21
25
  this.log.info("TypeScript type checking completed successfully.");
22
26
  },
@@ -1,9 +1,11 @@
1
1
  import { $inject } from "alepha";
2
2
  import { $command } from "alepha/command";
3
3
  import { AlephaCliUtils } from "../services/AlephaCliUtils.ts";
4
+ import { PackageManagerUtils } from "../services/PackageManagerUtils.ts";
4
5
 
5
6
  export class VerifyCommand {
6
7
  protected readonly utils = $inject(AlephaCliUtils);
8
+ protected readonly pm = $inject(PackageManagerUtils);
7
9
 
8
10
  /**
9
11
  * Run a series of verification commands to ensure code quality and correctness.
@@ -28,7 +30,7 @@ export class VerifyCommand {
28
30
 
29
31
  await run("alepha typecheck");
30
32
 
31
- const pkg = await this.utils.readPackageJson(root);
33
+ const pkg = await this.pm.readPackageJson(root);
32
34
  if (pkg.devDependencies?.vitest) {
33
35
  await run("alepha test");
34
36
  }
@@ -37,7 +39,7 @@ export class VerifyCommand {
37
39
  await run("alepha db check-migrations");
38
40
  }
39
41
 
40
- const isExpo = await this.utils.hasExpo(root);
42
+ const isExpo = await this.pm.hasExpo(root);
41
43
  if (!isExpo) {
42
44
  await run("alepha build");
43
45
  }
@@ -1,8 +1,13 @@
1
1
  import type { Alepha } from "alepha";
2
2
  import type { CommandPrimitive } from "alepha/command";
3
+ import {
4
+ type AppEntryOptions,
5
+ appEntryOptions,
6
+ } from "./atoms/appEntryOptions.ts";
3
7
  import { type BuildOptions, buildOptions } from "./atoms/buildOptions.ts";
4
8
 
5
9
  export interface AlephaCliConfig {
10
+ entry?: AppEntryOptions;
6
11
  /**
7
12
  * Add custom commands to the Alepha CLI.
8
13
  *
@@ -54,6 +59,10 @@ export const defineConfig = (
54
59
  alepha.set(buildOptions, config.build);
55
60
  }
56
61
 
62
+ if (config.entry) {
63
+ alepha.set(appEntryOptions, config.entry);
64
+ }
65
+
57
66
  return {
58
67
  ...config.commands,
59
68
  };
package/src/cli/index.ts CHANGED
@@ -1,12 +1,12 @@
1
1
  export * from "./apps/AlephaCli.ts";
2
2
  export * from "./apps/AlephaPackageBuilderCli.ts";
3
+ export { default as AlephaPackageBuilderCli } from "./apps/AlephaPackageBuilderCli.ts";
3
4
  export * from "./atoms/changelogOptions.ts";
4
5
  export * from "./commands/build.ts";
5
6
  export * from "./commands/clean.ts";
6
7
  export * from "./commands/db.ts";
7
8
  export * from "./commands/deploy.ts";
8
9
  export * from "./commands/dev.ts";
9
- export * from "./commands/format.ts";
10
10
  export * from "./commands/gen/changelog.ts";
11
11
  export * from "./commands/gen/openapi.ts";
12
12
  export * from "./commands/init.ts";
@@ -16,6 +16,7 @@ export * from "./commands/test.ts";
16
16
  export * from "./commands/typecheck.ts";
17
17
  export * from "./commands/verify.ts";
18
18
  export * from "./defineConfig.ts";
19
+ export * from "./providers/AppEntryProvider.ts";
19
20
  export * from "./services/AlephaCliUtils.ts";
20
21
  export * from "./services/GitMessageParser.ts";
21
22
  export * from "./version.ts";
@@ -0,0 +1,131 @@
1
+ import { $inject, $use, AlephaError } from "alepha";
2
+ import { FileSystemProvider } from "alepha/file";
3
+ import { appEntryOptions } from "../atoms/appEntryOptions.ts";
4
+
5
+ /**
6
+ * Service for locating entry files in Alepha projects.
7
+ *
8
+ * Originally in alepha/vite, moved to CLI to avoid cli -> vite dependency.
9
+ */
10
+ export class AppEntryProvider {
11
+ protected readonly fs = $inject(FileSystemProvider);
12
+ protected readonly options = $use(appEntryOptions);
13
+
14
+ protected readonly serverEntries = [
15
+ "main.server.ts",
16
+ "main.server.tsx",
17
+ "main.ts",
18
+ "main.tsx",
19
+ ] as const;
20
+
21
+ protected readonly browserEntries = [
22
+ "main.browser.ts",
23
+ "main.browser.tsx",
24
+ "main.ts",
25
+ "main.tsx",
26
+ ] as const;
27
+
28
+ protected readonly styleEntries = [
29
+ "main.css",
30
+ "styles.css",
31
+ "style.css",
32
+ ] as const;
33
+
34
+ /**
35
+ * Get application entry points.
36
+ *
37
+ * Server entry is required, an error is thrown if not found.
38
+ * Browser entry is optional.
39
+ *
40
+ * It will first check for custom entries in options, see appEntryOptions.
41
+ */
42
+ public async getAppEntry(root: string): Promise<AppEntry> {
43
+ const appEntry: AppEntry = {
44
+ root,
45
+ server: "",
46
+ };
47
+
48
+ if (this.options.server) {
49
+ const serverExists = await this.fs.exists(
50
+ this.fs.join(root, this.options.server),
51
+ );
52
+ if (!serverExists) {
53
+ throw new AlephaError(
54
+ `Custom server entry "${this.options.server}" not found.`,
55
+ );
56
+ }
57
+ appEntry.server = this.options.server;
58
+ }
59
+
60
+ if (this.options.browser) {
61
+ const browserExists = await this.fs.exists(
62
+ this.fs.join(root, this.options.browser),
63
+ );
64
+ if (!browserExists) {
65
+ throw new AlephaError(
66
+ `Custom browser entry "${this.options.browser}" not found.`,
67
+ );
68
+ }
69
+ appEntry.browser = this.options.browser;
70
+ }
71
+
72
+ if (this.options.style) {
73
+ const styleExists = await this.fs.exists(
74
+ this.fs.join(root, this.options.style),
75
+ );
76
+ if (!styleExists) {
77
+ throw new AlephaError(
78
+ `Custom style entry "${this.options.style}" not found.`,
79
+ );
80
+ }
81
+ appEntry.style = this.options.style;
82
+ }
83
+
84
+ const srcFiles = await this.fs.ls(this.fs.join(root, "src"));
85
+
86
+ if (!appEntry.server) {
87
+ // find in conventional locations
88
+ for (const entry of this.serverEntries) {
89
+ if (srcFiles.includes(entry)) {
90
+ appEntry.server = this.fs.join("src", entry);
91
+ break;
92
+ }
93
+ }
94
+ }
95
+
96
+ if (!appEntry.server) {
97
+ throw new AlephaError(
98
+ "No server entry found. Please, add a main.server.ts file in the src/ directory or configure a custom entry in alepha.config.ts.",
99
+ );
100
+ }
101
+
102
+ if (!appEntry.browser) {
103
+ // find in conventional locations
104
+ for (const entry of this.browserEntries) {
105
+ if (srcFiles.includes(entry)) {
106
+ appEntry.browser = this.fs.join("src", entry);
107
+ break;
108
+ }
109
+ }
110
+ }
111
+
112
+ if (!appEntry.style) {
113
+ // find in conventional locations
114
+ for (const entry of this.styleEntries) {
115
+ if (srcFiles.includes(entry)) {
116
+ appEntry.style = this.fs.join("src", entry);
117
+ break;
118
+ }
119
+ }
120
+ }
121
+
122
+ return appEntry;
123
+ }
124
+ }
125
+
126
+ export interface AppEntry {
127
+ root: string;
128
+ server: string;
129
+ browser?: string;
130
+ style?: string;
131
+ }
@@ -0,0 +1,82 @@
1
+ import { $hook, $inject, type Alepha, AlephaError } from "alepha";
2
+ import { importVite } from "alepha/vite";
3
+ import type { InlineConfig, ViteDevServer } from "vite";
4
+ import type { AppEntry } from "./AppEntryProvider.ts";
5
+ import { ViteTemplateProvider } from "./ViteTemplateProvider.ts";
6
+
7
+ export class ViteBuildProvider {
8
+ protected alepha?: Alepha;
9
+ protected appEntry?: AppEntry;
10
+ protected viteDevServer?: ViteDevServer;
11
+ protected readonly templateProvider = $inject(ViteTemplateProvider);
12
+
13
+ /**
14
+ * We need to close the Vite dev server after build is done.
15
+ */
16
+ protected onReady = $hook({
17
+ on: "ready",
18
+ priority: "last",
19
+ handler: async () => {
20
+ await this.viteDevServer?.close();
21
+ },
22
+ });
23
+ protected onStop = $hook({
24
+ on: "stop",
25
+ handler: async () => {
26
+ await this.viteDevServer?.close();
27
+ },
28
+ });
29
+
30
+ public async init(opts: { entry: AppEntry }) {
31
+ const { createServer } = await importVite();
32
+
33
+ process.env.ALEPHA_CLI_IMPORT = "true"; // signal Alepha App about CLI import, run(alepha) won't start server
34
+ process.env.NODE_ENV = "production"; // force Alepha App in production mode for getting "production" metadata
35
+ process.env.LOG_LEVEL ??= "warn"; // reduce log noise
36
+
37
+ /**
38
+ * 01/26 Vite 7
39
+ * "runnerImport" doesn't work as expected here. (e.g. build docs fail)
40
+ * -> We still use devServer and ssrLoadModule for now.
41
+ * -> This is clearly a bad stuff, we need to find better way.
42
+ */
43
+ this.viteDevServer = await createServer({
44
+ server: { middlewareMode: true },
45
+ appType: "custom",
46
+ logLevel: "silent",
47
+ } satisfies InlineConfig);
48
+
49
+ await this.viteDevServer.ssrLoadModule(opts.entry.server);
50
+
51
+ const alepha: Alepha = (globalThis as any).__alepha;
52
+ if (!alepha) {
53
+ throw new AlephaError(
54
+ "Alepha instance not found after loading entry module",
55
+ );
56
+ }
57
+
58
+ this.alepha = alepha;
59
+ this.appEntry = opts.entry;
60
+
61
+ return alepha;
62
+ }
63
+
64
+ public hasClient(): boolean {
65
+ if (!this.alepha) {
66
+ throw new AlephaError("ViteBuildProvider not initialized");
67
+ }
68
+ try {
69
+ this.alepha.inject("ReactServerProvider");
70
+ return true;
71
+ } catch {
72
+ return false;
73
+ }
74
+ }
75
+
76
+ public generateIndexHtml(): string {
77
+ if (!this.appEntry) {
78
+ throw new AlephaError("ViteBuildProvider not initialized");
79
+ }
80
+ return this.templateProvider.generateIndexHtml(this.appEntry);
81
+ }
82
+ }