alepha 0.14.1 → 0.14.2

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 (97) hide show
  1. package/README.md +3 -3
  2. package/dist/api/audits/index.d.ts +342 -342
  3. package/dist/api/audits/index.d.ts.map +1 -1
  4. package/dist/api/audits/index.js.map +1 -1
  5. package/dist/api/files/index.js.map +1 -1
  6. package/dist/api/jobs/index.d.ts +161 -161
  7. package/dist/api/jobs/index.js.map +1 -1
  8. package/dist/api/parameters/index.js.map +1 -1
  9. package/dist/api/users/index.d.ts +791 -791
  10. package/dist/api/users/index.d.ts.map +1 -1
  11. package/dist/api/users/index.js +4 -0
  12. package/dist/api/users/index.js.map +1 -1
  13. package/dist/api/verifications/index.d.ts +128 -128
  14. package/dist/api/verifications/index.d.ts.map +1 -1
  15. package/dist/batch/index.js.map +1 -1
  16. package/dist/cache/core/index.js.map +1 -1
  17. package/dist/cli/index.d.ts +173 -167
  18. package/dist/cli/index.d.ts.map +1 -1
  19. package/dist/cli/index.js +427 -409
  20. package/dist/cli/index.js.map +1 -1
  21. package/dist/command/index.d.ts +5 -5
  22. package/dist/command/index.js.map +1 -1
  23. package/dist/core/index.browser.js.map +1 -1
  24. package/dist/core/index.d.ts.map +1 -1
  25. package/dist/core/index.js +7 -6
  26. package/dist/core/index.js.map +1 -1
  27. package/dist/core/index.native.js +7 -6
  28. package/dist/core/index.native.js.map +1 -1
  29. package/dist/datetime/index.js.map +1 -1
  30. package/dist/fake/index.js.map +1 -1
  31. package/dist/file/index.js.map +1 -1
  32. package/dist/lock/redis/index.js.map +1 -1
  33. package/dist/logger/index.js.map +1 -1
  34. package/dist/mcp/index.js.map +1 -1
  35. package/dist/orm/index.browser.js +26 -5
  36. package/dist/orm/index.browser.js.map +1 -1
  37. package/dist/orm/index.d.ts +115 -90
  38. package/dist/orm/index.d.ts.map +1 -1
  39. package/dist/orm/index.js +37 -12
  40. package/dist/orm/index.js.map +1 -1
  41. package/dist/redis/index.js.map +1 -1
  42. package/dist/retry/index.js.map +1 -1
  43. package/dist/router/index.js.map +1 -1
  44. package/dist/scheduler/index.d.ts +6 -6
  45. package/dist/scheduler/index.js.map +1 -1
  46. package/dist/security/index.d.ts +28 -28
  47. package/dist/security/index.d.ts.map +1 -1
  48. package/dist/security/index.js.map +1 -1
  49. package/dist/server/auth/index.d.ts +155 -155
  50. package/dist/server/auth/index.js.map +1 -1
  51. package/dist/server/cache/index.js.map +1 -1
  52. package/dist/server/cookies/index.browser.js.map +1 -1
  53. package/dist/server/cookies/index.js.map +1 -1
  54. package/dist/server/core/index.browser.js.map +1 -1
  55. package/dist/server/core/index.js.map +1 -1
  56. package/dist/server/health/index.d.ts +17 -17
  57. package/dist/server/helmet/index.js.map +1 -1
  58. package/dist/server/links/index.browser.js.map +1 -1
  59. package/dist/server/links/index.js.map +1 -1
  60. package/dist/server/multipart/index.js.map +1 -1
  61. package/dist/server/rate-limit/index.js.map +1 -1
  62. package/dist/server/security/index.d.ts +9 -9
  63. package/dist/server/security/index.js.map +1 -1
  64. package/dist/server/swagger/index.js.map +1 -1
  65. package/dist/thread/index.js.map +1 -1
  66. package/dist/topic/core/index.js.map +1 -1
  67. package/dist/vite/index.js.map +1 -1
  68. package/dist/websocket/index.browser.js.map +1 -1
  69. package/dist/websocket/index.d.ts +7 -7
  70. package/dist/websocket/index.js.map +1 -1
  71. package/package.json +3 -3
  72. package/src/api/users/index.ts +4 -0
  73. package/src/cli/apps/AlephaCli.ts +31 -14
  74. package/src/cli/apps/AlephaPackageBuilderCli.ts +2 -1
  75. package/src/cli/assets/appRouterTs.ts +1 -1
  76. package/src/cli/commands/{ViteCommands.ts → build.ts} +2 -105
  77. package/src/cli/commands/{ChangelogCommands.ts → changelog.ts} +7 -22
  78. package/src/cli/commands/clean.ts +14 -0
  79. package/src/cli/commands/{DrizzleCommands.ts → db.ts} +10 -117
  80. package/src/cli/commands/{DeployCommands.ts → deploy.ts} +1 -1
  81. package/src/cli/commands/dev.ts +57 -0
  82. package/src/cli/commands/format.ts +17 -0
  83. package/src/cli/commands/{CoreCommands.ts → init.ts} +2 -40
  84. package/src/cli/commands/lint.ts +17 -0
  85. package/src/cli/commands/root.ts +32 -0
  86. package/src/cli/commands/run.ts +24 -0
  87. package/src/cli/commands/test.ts +42 -0
  88. package/src/cli/commands/typecheck.ts +19 -0
  89. package/src/cli/commands/{VerifyCommands.ts → verify.ts} +1 -13
  90. package/src/cli/defineConfig.ts +10 -1
  91. package/src/cli/index.ts +16 -7
  92. package/src/cli/services/GitMessageParser.ts +1 -1
  93. package/src/core/Alepha.ts +7 -4
  94. package/src/orm/index.browser.ts +1 -1
  95. package/src/orm/index.ts +10 -6
  96. package/src/orm/providers/{PostgresTypeProvider.ts → DatabaseTypeProvider.ts} +25 -3
  97. package/src/cli/commands/BiomeCommands.ts +0 -29
@@ -1,7 +1,7 @@
1
1
  import { access, readFile, unlink, writeFile } from "node:fs/promises";
2
2
  import { createRequire } from "node:module";
3
3
  import { join } from "node:path";
4
- import { $env, $inject, OPTIONS, t } from "alepha";
4
+ import { $inject, OPTIONS, t } from "alepha";
5
5
  import { $command } from "alepha/command";
6
6
  import { $logger } from "alepha/logger";
7
7
  import {
@@ -18,78 +18,10 @@ import {
18
18
  import type * as Vite from "vite";
19
19
  import { AlephaCliUtils } from "../services/AlephaCliUtils.ts";
20
20
 
21
- export class ViteCommands {
21
+ export class BuildCommand {
22
22
  protected readonly log = $logger();
23
23
  protected readonly utils = $inject(AlephaCliUtils);
24
24
 
25
- protected readonly env = $env(
26
- t.object({
27
- VITEST_ARGS: t.string({ default: "" }),
28
- }),
29
- );
30
-
31
- public readonly run = $command({
32
- name: "run",
33
- hide: true,
34
- description: "Run a TypeScript file directly",
35
- flags: t.object({
36
- watch: t.optional(
37
- t.boolean({ description: "Watch file for changes", alias: "w" }),
38
- ),
39
- }),
40
- summary: false,
41
- args: t.text({ title: "path", description: "Filepath to run" }),
42
- handler: async ({ args, flags, root }) => {
43
- await this.utils.ensureTsConfig(root);
44
- await this.utils.exec(`tsx ${flags.watch ? "watch " : ""}${args}`);
45
- },
46
- });
47
-
48
- /**
49
- * Will run the project in watch mode.
50
- *
51
- * - If an index.html file is found in the project root, it will run Vite in dev mode.
52
- * - Otherwise, it will look for a server entry file and run it with tsx in watch mode.
53
- */
54
- public readonly dev = $command({
55
- name: "dev",
56
- description: "Run the project in development mode",
57
- args: t.optional(t.text({ title: "path", description: "Filepath to run" })),
58
- handler: async ({ args, root }) => {
59
- const expo = await this.utils.hasExpo(root);
60
-
61
- await this.utils.ensureConfig(root, {
62
- viteConfigTs: !expo,
63
- tsconfigJson: true,
64
- });
65
-
66
- if (expo) {
67
- await this.utils.exec(`expo start`);
68
- return;
69
- }
70
-
71
- const entry = await boot.getServerEntry(root, args);
72
- this.log.trace("Entry file found", { entry });
73
-
74
- try {
75
- await access(join(root, "index.html"));
76
- } catch {
77
- this.log.trace("No index.html found, running entry file with tsx");
78
- let cmd = "tsx --watch";
79
- if (await this.utils.exists(root, ".env")) {
80
- cmd += ` --env-file=./.env`;
81
- }
82
- cmd += ` ${entry}`;
83
- await this.utils.exec(cmd);
84
- return;
85
- }
86
-
87
- // Ensure vite is installed before running
88
- await this.utils.ensureDependency(root, "vite");
89
- await this.utils.exec(`vite`);
90
- },
91
- });
92
-
93
25
  public readonly build = $command({
94
26
  name: "build",
95
27
  description: "Build the project for production",
@@ -313,39 +245,4 @@ export class ViteCommands {
313
245
  }
314
246
  },
315
247
  });
316
-
317
- public readonly test = $command({
318
- name: "test",
319
- description: "Run tests using Vitest",
320
- flags: t.object({
321
- config: t.optional(
322
- t.string({
323
- description: "Path to Vitest config file",
324
- alias: "c",
325
- }),
326
- ),
327
- }),
328
- env: t.object({
329
- VITEST_ARGS: t.optional(
330
- t.string({
331
- default: "",
332
- description:
333
- "Additional arguments to pass to Vitest. E.g., --coverage",
334
- }),
335
- ),
336
- }),
337
- handler: async ({ root, flags, env }) => {
338
- await this.utils.ensureConfig(root, {
339
- tsconfigJson: true,
340
- viteConfigTs: true,
341
- });
342
-
343
- // Ensure vitest is installed before running
344
- await this.utils.ensureDependency(root, "vitest");
345
-
346
- const config = flags.config ? `--config=${flags.config}` : "";
347
-
348
- await this.utils.exec(`vitest run ${config} ${env.VITEST_ARGS}`);
349
- },
350
- });
351
248
  }
@@ -45,11 +45,10 @@ export interface Commit {
45
45
  interface ChangelogEntry {
46
46
  features: Commit[];
47
47
  fixes: Commit[];
48
- breaking: Commit[];
49
48
  }
50
49
 
51
50
  // =============================================================================
52
- // CHANGELOG COMMANDS
51
+ // CHANGELOG COMMAND
53
52
  // =============================================================================
54
53
 
55
54
  /**
@@ -61,7 +60,7 @@ interface ChangelogEntry {
61
60
  * - `alepha changelog --from=1.0.0 --to=1.1.0` - Show changes between two refs
62
61
  * - `alepha changelog | tee -a CHANGELOG.md` - Append to file
63
62
  */
64
- export class ChangelogCommands {
63
+ export class ChangelogCommand {
65
64
  protected readonly log = $logger();
66
65
  protected readonly git = $inject(GitProvider);
67
66
  protected readonly parser = $inject(GitMessageParser);
@@ -74,9 +73,11 @@ export class ChangelogCommands {
74
73
  /**
75
74
  * Format a single commit line.
76
75
  * Example: `- **cli**: add new command (\`abc1234\`)`
76
+ * Breaking changes are flagged: `- **cli**: add new command [BREAKING] (\`abc1234\`)`
77
77
  */
78
78
  protected formatCommit(commit: Commit): string {
79
- return `- **${commit.scope}**: ${commit.description} (\`${commit.hash}\`)`;
79
+ const breaking = commit.breaking ? " [BREAKING]" : "";
80
+ return `- **${commit.scope}**: ${commit.description}${breaking} (\`${commit.hash}\`)`;
80
81
  }
81
82
 
82
83
  /**
@@ -85,14 +86,6 @@ export class ChangelogCommands {
85
86
  protected formatEntry(entry: ChangelogEntry): string {
86
87
  const sections: string[] = [];
87
88
 
88
- if (entry.breaking.length > 0) {
89
- sections.push("### Breaking Changes\n");
90
- for (const commit of entry.breaking) {
91
- sections.push(this.formatCommit(commit));
92
- }
93
- sections.push("");
94
- }
95
-
96
89
  if (entry.features.length > 0) {
97
90
  sections.push("### Features\n");
98
91
  for (const commit of entry.features) {
@@ -123,7 +116,6 @@ export class ChangelogCommands {
123
116
  const entry: ChangelogEntry = {
124
117
  features: [],
125
118
  fixes: [],
126
- breaking: [],
127
119
  };
128
120
 
129
121
  for (const line of commitsOutput.trim().split("\n")) {
@@ -137,10 +129,7 @@ export class ChangelogCommands {
137
129
 
138
130
  this.log.trace("Parsed commit", { commit });
139
131
 
140
- // Categorize commit
141
- if (commit.breaking) {
142
- entry.breaking.push(commit);
143
- }
132
+ // Categorize commit (breaking flag is preserved on the commit itself)
144
133
  if (commit.type === "feat") {
145
134
  entry.features.push(commit);
146
135
  } else if (commit.type === "fix") {
@@ -155,11 +144,7 @@ export class ChangelogCommands {
155
144
  * Check if entry has any public commits.
156
145
  */
157
146
  protected hasChanges(entry: ChangelogEntry): boolean {
158
- return (
159
- entry.features.length > 0 ||
160
- entry.fixes.length > 0 ||
161
- entry.breaking.length > 0
162
- );
147
+ return entry.features.length > 0 || entry.fixes.length > 0;
163
148
  }
164
149
 
165
150
  /**
@@ -0,0 +1,14 @@
1
+ import { $command } from "alepha/command";
2
+
3
+ export class CleanCommand {
4
+ /**
5
+ * Clean the project, removing the "dist" directory
6
+ */
7
+ public readonly clean = $command({
8
+ name: "clean",
9
+ description: "Clean the project",
10
+ handler: async ({ run }) => {
11
+ await run.rm("./dist");
12
+ },
13
+ });
14
+ }
@@ -25,14 +25,14 @@ const drizzleCommandFlags = t.object({
25
25
  ),
26
26
  });
27
27
 
28
- export class DrizzleCommands {
29
- log = $logger();
30
- utils = $inject(AlephaCliUtils);
28
+ export class DbCommand {
29
+ protected readonly log = $logger();
30
+ protected readonly utils = $inject(AlephaCliUtils);
31
31
 
32
32
  /**
33
33
  * Check if database migrations are up to date.
34
34
  */
35
- check = $command({
35
+ protected readonly check = $command({
36
36
  name: "check-migrations",
37
37
  description: "Check if database migration files are up to date",
38
38
  args: t.optional(
@@ -74,7 +74,7 @@ export class DrizzleCommands {
74
74
  ).catch(() => null);
75
75
 
76
76
  if (!journalFile) {
77
- this.log.info(`No migration journal found.`);
77
+ this.log.info("No migration journal found.");
78
78
  return;
79
79
  }
80
80
 
@@ -130,14 +130,8 @@ export class DrizzleCommands {
130
130
 
131
131
  /**
132
132
  * Generate database migration files
133
- *
134
- * - Loads the Alepha instance from the specified entry file.
135
- * - Retrieves all repository primitives to gather database models.
136
- * - Creates temporary entity definitions based on the current database schema.
137
- * - Writes these definitions to a temporary schema file. (node_modules/.db/entities.ts)
138
- * - Invokes Drizzle Kit's CLI to generate migration files based on the current schema.
139
133
  */
140
- generate = $command({
134
+ protected readonly generate = $command({
141
135
  name: "generate",
142
136
  description: "Generate migration files based on current database schema",
143
137
  summary: false,
@@ -175,13 +169,8 @@ export class DrizzleCommands {
175
169
 
176
170
  /**
177
171
  * Push database schema changes directly to the database
178
- *
179
- * - Loads the Alepha instance from the specified entry file.
180
- * - Retrieves all repository primitives to gather database models.
181
- * - Creates temporary entity definitions and Drizzle config.
182
- * - Invokes Drizzle Kit's push command to apply schema changes directly.
183
172
  */
184
- push = $command({
173
+ protected readonly push = $command({
185
174
  name: "push",
186
175
  description: "Push database schema changes directly to the database",
187
176
  summary: false,
@@ -207,13 +196,8 @@ export class DrizzleCommands {
207
196
 
208
197
  /**
209
198
  * Apply pending database migrations
210
- *
211
- * - Loads the Alepha instance from the specified entry file.
212
- * - Retrieves all repository primitives to gather database models.
213
- * - Creates temporary entity definitions and Drizzle config.
214
- * - Invokes Drizzle Kit's migrate command to apply pending migrations.
215
199
  */
216
- migrate = $command({
200
+ protected readonly migrate = $command({
217
201
  name: "migrate",
218
202
  description: "Apply pending database migrations",
219
203
  summary: false,
@@ -239,13 +223,8 @@ export class DrizzleCommands {
239
223
 
240
224
  /**
241
225
  * Launch Drizzle Studio database browser
242
- *
243
- * - Loads the Alepha instance from the specified entry file.
244
- * - Retrieves all repository primitives to gather database models.
245
- * - Creates temporary entity definitions and Drizzle config.
246
- * - Invokes Drizzle Kit's studio command to launch the web-based database browser.
247
226
  */
248
- studio = $command({
227
+ protected readonly studio = $command({
249
228
  name: "studio",
250
229
  description: "Launch Drizzle Studio database browser",
251
230
  summary: false,
@@ -272,7 +251,7 @@ export class DrizzleCommands {
272
251
  /**
273
252
  * Parent command for database operations.
274
253
  */
275
- db = $command({
254
+ public readonly db = $command({
276
255
  name: "db",
277
256
  description: "Database management commands",
278
257
  children: [this.check, this.generate, this.push, this.migrate, this.studio],
@@ -283,11 +262,6 @@ export class DrizzleCommands {
283
262
 
284
263
  /**
285
264
  * Run a drizzle-kit command for all database providers in an Alepha instance.
286
- *
287
- * Iterates through all repository providers, prepares Drizzle config for each,
288
- * and executes the specified drizzle-kit command.
289
- *
290
- * @param options - Configuration including command to run, flags, and logging
291
265
  */
292
266
  public async runDrizzleKitCommand(options: {
293
267
  root: string;
@@ -365,12 +339,6 @@ export class DrizzleCommands {
365
339
 
366
340
  /**
367
341
  * Prepare Drizzle configuration files for a database provider.
368
- *
369
- * Creates temporary entities.js and drizzle.config.js files needed
370
- * for Drizzle Kit commands to run properly.
371
- *
372
- * @param options - Configuration options including kit, provider info, and paths
373
- * @returns Path to the generated drizzle.config.js file
374
342
  */
375
343
  public async prepareDrizzleConfig(options: {
376
344
  kit: any;
@@ -473,79 +441,4 @@ export class DrizzleCommands {
473
441
  options.rootDir,
474
442
  );
475
443
  }
476
-
477
- // /**
478
- // * Drop database schema (development only)
479
- // *
480
- // * @experimental
481
- // */
482
- // drop = $command({
483
- // name: "db:drop",
484
- // description: "Drop database schema (development only)",
485
- // summary: false,
486
- // args: t.optional(
487
- // t.text({
488
- // title: "path",
489
- // description: "Path to the Alepha server entry file",
490
- // }),
491
- // ),
492
- // flags: drizzleCommandFlags,
493
- // handler: async ({ flags }) => {
494
- // // TODO: Implement db:drop
495
- // this.log.warn("db:drop is not yet implemented");
496
- // if (flags.provider) {
497
- // this.log.info(`Provider filter: ${flags.provider}`);
498
- // }
499
- // },
500
- // });
501
- //
502
- // /**
503
- // * Seed database with initial data
504
- // *
505
- // * @experimental
506
- // */
507
- // seed = $command({
508
- // name: "db:seed",
509
- // description: "Seed database with initial data",
510
- // summary: false,
511
- // args: t.optional(
512
- // t.text({
513
- // title: "path",
514
- // description: "Path to the Alepha server entry file",
515
- // }),
516
- // ),
517
- // flags: drizzleCommandFlags,
518
- // handler: async ({ flags }) => {
519
- // // TODO: Implement db:seed
520
- // this.log.warn("db:seed is not yet implemented");
521
- // if (flags.provider) {
522
- // this.log.info(`Provider filter: ${flags.provider}`);
523
- // }
524
- // },
525
- // });
526
- //
527
- // /**
528
- // * Show pending database migrations status
529
- // *
530
- // * @experimental
531
- // */
532
- // status = $command({
533
- // name: "db:status",
534
- // description: "Show pending database migrations status",
535
- // summary: false,
536
- // args: t.optional(
537
- // t.text({
538
- // title: "path",
539
- // description: "Path to the Alepha server entry file",
540
- // }),
541
- // ),
542
- // flags: drizzleCommandFlags,
543
- // handler: async ({ flags }) => {
544
- // // TODO: Implement db:status
545
- // this.log.warn("db:status is not yet implemented");
546
- // if (flags.provider) {
547
- // this.log.info(`Provider filter: ${flags.provider}`);
548
- // }
549
- // },
550
- // });
551
444
  }
@@ -4,7 +4,7 @@ import { $command } from "alepha/command";
4
4
  import { $logger } from "alepha/logger";
5
5
  import { AlephaCliUtils } from "../services/AlephaCliUtils.ts";
6
6
 
7
- export class DeployCommands {
7
+ export class DeployCommand {
8
8
  protected readonly log = $logger();
9
9
  protected readonly utils = $inject(AlephaCliUtils);
10
10
 
@@ -0,0 +1,57 @@
1
+ import { access } from "node:fs/promises";
2
+ import { join } from "node:path";
3
+ import { $inject, t } from "alepha";
4
+ import { $command } from "alepha/command";
5
+ import { $logger } from "alepha/logger";
6
+ import { boot } from "alepha/vite";
7
+ import { AlephaCliUtils } from "../services/AlephaCliUtils.ts";
8
+
9
+ export class DevCommand {
10
+ protected readonly log = $logger();
11
+ protected readonly utils = $inject(AlephaCliUtils);
12
+
13
+ /**
14
+ * Will run the project in watch mode.
15
+ *
16
+ * - If an index.html file is found in the project root, it will run Vite in dev mode.
17
+ * - Otherwise, it will look for a server entry file and run it with tsx in watch mode.
18
+ */
19
+ public readonly dev = $command({
20
+ name: "dev",
21
+ description: "Run the project in development mode",
22
+ args: t.optional(t.text({ title: "path", description: "Filepath to run" })),
23
+ handler: async ({ args, root }) => {
24
+ const expo = await this.utils.hasExpo(root);
25
+
26
+ await this.utils.ensureConfig(root, {
27
+ viteConfigTs: !expo,
28
+ tsconfigJson: true,
29
+ });
30
+
31
+ if (expo) {
32
+ await this.utils.exec("expo start");
33
+ return;
34
+ }
35
+
36
+ const entry = await boot.getServerEntry(root, args);
37
+ this.log.trace("Entry file found", { entry });
38
+
39
+ try {
40
+ await access(join(root, "index.html"));
41
+ } catch {
42
+ this.log.trace("No index.html found, running entry file with tsx");
43
+ let cmd = "tsx --watch";
44
+ if (await this.utils.exists(root, ".env")) {
45
+ cmd += " --env-file=./.env";
46
+ }
47
+ cmd += ` ${entry}`;
48
+ await this.utils.exec(cmd);
49
+ return;
50
+ }
51
+
52
+ // Ensure vite is installed before running
53
+ await this.utils.ensureDependency(root, "vite");
54
+ await this.utils.exec("vite");
55
+ },
56
+ });
57
+ }
@@ -0,0 +1,17 @@
1
+ import { $inject } from "alepha";
2
+ import { $command } from "alepha/command";
3
+ import { AlephaCliUtils } from "../services/AlephaCliUtils.ts";
4
+
5
+ export class FormatCommand {
6
+ protected readonly utils = $inject(AlephaCliUtils);
7
+
8
+ public readonly format = $command({
9
+ name: "format",
10
+ description: "Format the codebase using Biome",
11
+ 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 format --fix");
15
+ },
16
+ });
17
+ }
@@ -1,48 +1,10 @@
1
1
  import { $inject, t } from "alepha";
2
- import { $command, CliProvider } from "alepha/command";
3
- import { $logger } from "alepha/logger";
2
+ import { $command } from "alepha/command";
4
3
  import { AlephaCliUtils } from "../services/AlephaCliUtils.ts";
5
- import { version } from "../version.ts";
6
4
 
7
- export class CoreCommands {
8
- protected readonly log = $logger();
9
- protected readonly cli = $inject(CliProvider);
5
+ export class InitCommand {
10
6
  protected readonly utils = $inject(AlephaCliUtils);
11
7
 
12
- /**
13
- * Called when no command is provided
14
- */
15
- public readonly root = $command({
16
- root: true,
17
- flags: t.object({
18
- version: t.optional(
19
- t.boolean({
20
- description: "Show Alepha CLI version",
21
- aliases: ["v"],
22
- }),
23
- ),
24
- }),
25
- handler: async ({ flags }) => {
26
- if (flags.version) {
27
- this.log.info(version);
28
- return;
29
- }
30
-
31
- this.cli.printHelp();
32
- },
33
- });
34
-
35
- /**
36
- * Clean the project, removing the "dist" directory
37
- */
38
- public readonly clean = $command({
39
- name: "clean",
40
- description: "Clean the project",
41
- handler: async ({ run }) => {
42
- await run.rm("./dist");
43
- },
44
- });
45
-
46
8
  /**
47
9
  * Ensure the project has the necessary Alepha configuration files.
48
10
  * Add the correct dependencies to package.json and install them.
@@ -0,0 +1,17 @@
1
+ import { $inject } from "alepha";
2
+ import { $command } from "alepha/command";
3
+ import { AlephaCliUtils } from "../services/AlephaCliUtils.ts";
4
+
5
+ export class LintCommand {
6
+ protected readonly utils = $inject(AlephaCliUtils);
7
+
8
+ public readonly lint = $command({
9
+ name: "lint",
10
+ description: "Run linter across the codebase using Biome",
11
+ 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");
15
+ },
16
+ });
17
+ }
@@ -0,0 +1,32 @@
1
+ import { $inject, t } from "alepha";
2
+ import { $command, CliProvider } from "alepha/command";
3
+ import { $logger } from "alepha/logger";
4
+ import { version } from "../version.ts";
5
+
6
+ export class RootCommand {
7
+ protected readonly log = $logger();
8
+ protected readonly cli = $inject(CliProvider);
9
+
10
+ /**
11
+ * Called when no command is provided
12
+ */
13
+ public readonly root = $command({
14
+ root: true,
15
+ flags: t.object({
16
+ version: t.optional(
17
+ t.boolean({
18
+ description: "Show Alepha CLI version",
19
+ aliases: ["v"],
20
+ }),
21
+ ),
22
+ }),
23
+ handler: async ({ flags }) => {
24
+ if (flags.version) {
25
+ this.log.info(version);
26
+ return;
27
+ }
28
+
29
+ this.cli.printHelp();
30
+ },
31
+ });
32
+ }
@@ -0,0 +1,24 @@
1
+ import { $inject, t } from "alepha";
2
+ import { $command } from "alepha/command";
3
+ import { AlephaCliUtils } from "../services/AlephaCliUtils.ts";
4
+
5
+ export class RunCommand {
6
+ protected readonly utils = $inject(AlephaCliUtils);
7
+
8
+ public readonly run = $command({
9
+ name: "run",
10
+ hide: true,
11
+ description: "Run a TypeScript file directly",
12
+ flags: t.object({
13
+ watch: t.optional(
14
+ t.boolean({ description: "Watch file for changes", alias: "w" }),
15
+ ),
16
+ }),
17
+ summary: false,
18
+ args: t.text({ title: "path", description: "Filepath to run" }),
19
+ handler: async ({ args, flags, root }) => {
20
+ await this.utils.ensureTsConfig(root);
21
+ await this.utils.exec(`tsx ${flags.watch ? "watch " : ""}${args}`);
22
+ },
23
+ });
24
+ }
@@ -0,0 +1,42 @@
1
+ import { $inject, t } from "alepha";
2
+ import { $command } from "alepha/command";
3
+ import { AlephaCliUtils } from "../services/AlephaCliUtils.ts";
4
+
5
+ export class TestCommand {
6
+ protected readonly utils = $inject(AlephaCliUtils);
7
+
8
+ public readonly test = $command({
9
+ name: "test",
10
+ description: "Run tests using Vitest",
11
+ flags: t.object({
12
+ config: t.optional(
13
+ t.string({
14
+ description: "Path to Vitest config file",
15
+ alias: "c",
16
+ }),
17
+ ),
18
+ }),
19
+ env: t.object({
20
+ VITEST_ARGS: t.optional(
21
+ t.string({
22
+ default: "",
23
+ description:
24
+ "Additional arguments to pass to Vitest. E.g., --coverage",
25
+ }),
26
+ ),
27
+ }),
28
+ handler: async ({ root, flags, env }) => {
29
+ await this.utils.ensureConfig(root, {
30
+ tsconfigJson: true,
31
+ viteConfigTs: true,
32
+ });
33
+
34
+ // Ensure vitest is installed before running
35
+ await this.utils.ensureDependency(root, "vitest");
36
+
37
+ const config = flags.config ? `--config=${flags.config}` : "";
38
+
39
+ await this.utils.exec(`vitest run ${config} ${env.VITEST_ARGS}`);
40
+ },
41
+ });
42
+ }