alepha 0.14.3 → 0.14.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (114) hide show
  1. package/README.md +1 -1
  2. package/dist/api/audits/index.d.ts +338 -417
  3. package/dist/api/audits/index.d.ts.map +1 -1
  4. package/dist/api/files/index.d.ts +1 -80
  5. package/dist/api/files/index.d.ts.map +1 -1
  6. package/dist/api/jobs/index.d.ts +156 -235
  7. package/dist/api/jobs/index.d.ts.map +1 -1
  8. package/dist/api/notifications/index.d.ts +170 -249
  9. package/dist/api/notifications/index.d.ts.map +1 -1
  10. package/dist/api/parameters/index.d.ts +266 -345
  11. package/dist/api/parameters/index.d.ts.map +1 -1
  12. package/dist/api/users/index.d.ts +755 -834
  13. package/dist/api/users/index.d.ts.map +1 -1
  14. package/dist/api/verifications/index.d.ts +125 -125
  15. package/dist/api/verifications/index.d.ts.map +1 -1
  16. package/dist/cli/index.d.ts +116 -20
  17. package/dist/cli/index.d.ts.map +1 -1
  18. package/dist/cli/index.js +212 -124
  19. package/dist/cli/index.js.map +1 -1
  20. package/dist/command/index.d.ts +6 -11
  21. package/dist/command/index.d.ts.map +1 -1
  22. package/dist/command/index.js +2 -2
  23. package/dist/command/index.js.map +1 -1
  24. package/dist/core/index.browser.js +26 -4
  25. package/dist/core/index.browser.js.map +1 -1
  26. package/dist/core/index.d.ts +16 -1
  27. package/dist/core/index.d.ts.map +1 -1
  28. package/dist/core/index.js +26 -4
  29. package/dist/core/index.js.map +1 -1
  30. package/dist/core/index.native.js +26 -4
  31. package/dist/core/index.native.js.map +1 -1
  32. package/dist/logger/index.d.ts +1 -1
  33. package/dist/logger/index.d.ts.map +1 -1
  34. package/dist/logger/index.js +12 -2
  35. package/dist/logger/index.js.map +1 -1
  36. package/dist/mcp/index.d.ts.map +1 -1
  37. package/dist/mcp/index.js +1 -1
  38. package/dist/mcp/index.js.map +1 -1
  39. package/dist/orm/index.d.ts +37 -173
  40. package/dist/orm/index.d.ts.map +1 -1
  41. package/dist/orm/index.js +193 -422
  42. package/dist/orm/index.js.map +1 -1
  43. package/dist/server/auth/index.d.ts +167 -167
  44. package/dist/server/cache/index.d.ts +12 -0
  45. package/dist/server/cache/index.d.ts.map +1 -1
  46. package/dist/server/cache/index.js +55 -2
  47. package/dist/server/cache/index.js.map +1 -1
  48. package/dist/server/compress/index.d.ts +6 -0
  49. package/dist/server/compress/index.d.ts.map +1 -1
  50. package/dist/server/compress/index.js +36 -1
  51. package/dist/server/compress/index.js.map +1 -1
  52. package/dist/server/core/index.browser.js +2 -2
  53. package/dist/server/core/index.browser.js.map +1 -1
  54. package/dist/server/core/index.d.ts +10 -10
  55. package/dist/server/core/index.d.ts.map +1 -1
  56. package/dist/server/core/index.js +6 -3
  57. package/dist/server/core/index.js.map +1 -1
  58. package/dist/server/links/index.d.ts +39 -39
  59. package/dist/server/links/index.d.ts.map +1 -1
  60. package/dist/server/security/index.d.ts +9 -9
  61. package/dist/server/static/index.d.ts.map +1 -1
  62. package/dist/server/static/index.js +4 -0
  63. package/dist/server/static/index.js.map +1 -1
  64. package/dist/server/swagger/index.d.ts.map +1 -1
  65. package/dist/server/swagger/index.js +2 -3
  66. package/dist/server/swagger/index.js.map +1 -1
  67. package/dist/vite/index.d.ts +101 -106
  68. package/dist/vite/index.d.ts.map +1 -1
  69. package/dist/vite/index.js +571 -508
  70. package/dist/vite/index.js.map +1 -1
  71. package/package.json +1 -1
  72. package/src/cli/apps/AlephaCli.ts +0 -2
  73. package/src/cli/atoms/buildOptions.ts +88 -0
  74. package/src/cli/commands/build.ts +32 -69
  75. package/src/cli/commands/db.ts +0 -4
  76. package/src/cli/commands/dev.ts +16 -4
  77. package/src/cli/commands/gen/env.ts +53 -0
  78. package/src/cli/commands/gen/openapi.ts +1 -1
  79. package/src/cli/commands/gen/resource.ts +15 -0
  80. package/src/cli/commands/gen.ts +7 -1
  81. package/src/cli/commands/init.ts +0 -1
  82. package/src/cli/commands/test.ts +0 -1
  83. package/src/cli/commands/verify.ts +1 -1
  84. package/src/cli/defineConfig.ts +49 -7
  85. package/src/cli/index.ts +0 -1
  86. package/src/cli/services/AlephaCliUtils.ts +36 -25
  87. package/src/command/helpers/Runner.spec.ts +2 -2
  88. package/src/command/helpers/Runner.ts +1 -1
  89. package/src/command/primitives/$command.ts +0 -6
  90. package/src/command/providers/CliProvider.ts +1 -3
  91. package/src/core/Alepha.ts +42 -0
  92. package/src/logger/index.ts +15 -3
  93. package/src/mcp/transports/StdioMcpTransport.ts +1 -1
  94. package/src/orm/index.ts +2 -8
  95. package/src/queue/core/providers/WorkerProvider.spec.ts +48 -32
  96. package/src/server/cache/providers/ServerCacheProvider.spec.ts +183 -0
  97. package/src/server/cache/providers/ServerCacheProvider.ts +94 -9
  98. package/src/server/compress/providers/ServerCompressProvider.ts +61 -2
  99. package/src/server/core/helpers/ServerReply.ts +2 -2
  100. package/src/server/core/providers/ServerProvider.ts +11 -1
  101. package/src/server/static/providers/ServerStaticProvider.ts +10 -0
  102. package/src/server/swagger/providers/ServerSwaggerProvider.ts +5 -8
  103. package/src/vite/helpers/importViteReact.ts +13 -0
  104. package/src/vite/index.ts +1 -21
  105. package/src/vite/plugins/viteAlephaDev.ts +16 -1
  106. package/src/vite/plugins/viteAlephaSsrPreload.ts +222 -0
  107. package/src/vite/tasks/buildClient.ts +11 -0
  108. package/src/vite/tasks/buildServer.ts +47 -3
  109. package/src/vite/tasks/devServer.ts +69 -0
  110. package/src/vite/tasks/index.ts +2 -1
  111. package/src/cli/assets/viteConfigTs.ts +0 -14
  112. package/src/cli/commands/run.ts +0 -24
  113. package/src/vite/plugins/viteAlepha.ts +0 -37
  114. package/src/vite/plugins/viteAlephaBuild.ts +0 -281
@@ -1,7 +1,6 @@
1
1
  import { access, readFile, unlink, writeFile } from "node:fs/promises";
2
- import { createRequire } from "node:module";
3
2
  import { join } from "node:path";
4
- import { $inject, OPTIONS, t } from "alepha";
3
+ import { $inject, $use, t } from "alepha";
5
4
  import { $command } from "alepha/command";
6
5
  import { $logger } from "alepha/logger";
7
6
  import {
@@ -15,15 +14,17 @@ import {
15
14
  generateVercel,
16
15
  prerenderPages,
17
16
  } from "alepha/vite";
18
- import type * as Vite from "vite";
17
+ import { buildOptions } from "../atoms/buildOptions.ts";
19
18
  import { AlephaCliUtils } from "../services/AlephaCliUtils.ts";
20
19
 
21
20
  export class BuildCommand {
22
21
  protected readonly log = $logger();
23
22
  protected readonly utils = $inject(AlephaCliUtils);
23
+ protected readonly options = $use(buildOptions);
24
24
 
25
25
  public readonly build = $command({
26
26
  name: "build",
27
+ mode: "production",
27
28
  description: "Build the project for production",
28
29
  args: t.optional(
29
30
  t.text({ title: "path", description: "Filepath to build" }),
@@ -61,13 +62,11 @@ export class BuildCommand {
61
62
  process.env.NODE_ENV = "production";
62
63
 
63
64
  if (await this.utils.hasExpo(root)) {
64
- // will coming soon
65
- // 1. ensure "expo prebuild" is run
65
+ // will come soon
66
66
  return;
67
67
  }
68
68
 
69
69
  await this.utils.ensureConfig(root, {
70
- viteConfigTs: true,
71
70
  tsconfigJson: true,
72
71
  });
73
72
 
@@ -77,25 +76,13 @@ export class BuildCommand {
77
76
  const distDir = "dist";
78
77
  const clientDir = "public";
79
78
 
80
- await this.utils.ensureDependency(root, "vite", {
81
- run,
82
- });
83
-
84
- await run.rm("dist", {
85
- alias: "clean dist",
86
- });
87
-
88
- const vite: typeof Vite = createRequire(import.meta.url)("vite");
89
- const config = await vite.resolveConfig({}, "build", "production");
90
- const alephaPlugin: any = config.plugins.find(
91
- (it) => it.name === "alepha:build",
92
- );
93
- const viteAlephaBuildOptions = alephaPlugin?.[OPTIONS] || {};
79
+ await this.utils.ensureDependency(root, "vite", { run });
80
+ await run.rm("dist", { alias: "clean dist" });
94
81
 
82
+ const options = this.options;
95
83
  await this.utils.loadEnv(root, [".env", ".env.production"]);
96
84
 
97
- const stats = flags.stats ?? viteAlephaBuildOptions.stats ?? false;
98
- const hasServer = viteAlephaBuildOptions.serverEntry !== false;
85
+ const stats = flags.stats ?? options.stats ?? false;
99
86
 
100
87
  let hasClient = false;
101
88
  try {
@@ -105,13 +92,7 @@ export class BuildCommand {
105
92
  // No index.html
106
93
  }
107
94
 
108
- // Extract client options
109
- const clientOptions =
110
- typeof viteAlephaBuildOptions.client === "object"
111
- ? viteAlephaBuildOptions.client
112
- : {};
113
-
114
- // Build client
95
+ // Build client (precompress always enabled)
115
96
  if (hasClient) {
116
97
  await run({
117
98
  name: "vite build client",
@@ -120,7 +101,7 @@ export class BuildCommand {
120
101
  silent: true,
121
102
  dist: `${distDir}/${clientDir}`,
122
103
  stats,
123
- precompress: clientOptions.precompress,
104
+ precompress: true,
124
105
  }),
125
106
  });
126
107
  }
@@ -129,7 +110,6 @@ export class BuildCommand {
129
110
  await run({
130
111
  name: "vite build server",
131
112
  handler: async () => {
132
- // Check if client template exists
133
113
  let clientBuilt = false;
134
114
  try {
135
115
  await readFile(`${distDir}/${clientDir}/index.html`, "utf-8");
@@ -147,7 +127,7 @@ export class BuildCommand {
147
127
  });
148
128
 
149
129
  // Server will handle index.html if both client & server are built
150
- if (clientBuilt && hasServer) {
130
+ if (clientBuilt) {
151
131
  await unlink(`${distDir}/${clientDir}/index.html`);
152
132
  }
153
133
  },
@@ -163,9 +143,8 @@ export class BuildCommand {
163
143
 
164
144
  if (hasClient) {
165
145
  // Generate sitemap
166
- const sitemapBaseUrl = flags.sitemap ?? clientOptions.sitemap?.hostname;
167
-
168
- if (sitemapBaseUrl) {
146
+ const sitemapHostname = flags.sitemap ?? options.sitemap?.hostname;
147
+ if (sitemapHostname) {
169
148
  await run({
170
149
  name: "add sitemap",
171
150
  handler: async () => {
@@ -173,73 +152,57 @@ export class BuildCommand {
173
152
  `${distDir}/${clientDir}/sitemap.xml`,
174
153
  await generateSitemap({
175
154
  entry: `${distDir}/index.js`,
176
- baseUrl: sitemapBaseUrl,
155
+ baseUrl: sitemapHostname,
177
156
  }),
178
157
  );
179
158
  },
180
159
  });
181
160
  }
182
161
 
183
- // Pre-render static pages
184
- const shouldPrerender = clientOptions.prerender;
185
-
186
- if (shouldPrerender) {
187
- await run({
188
- name: "pre-render pages",
189
- handler: async () => {
190
- await prerenderPages({
191
- dist: `${distDir}/${clientDir}`,
192
- entry: `${distDir}/index.js`,
193
- compress: clientOptions.precompress,
194
- });
195
- },
196
- });
197
- }
162
+ // Pre-render static pages (always enabled)
163
+ await run({
164
+ name: "pre-render pages",
165
+ handler: async () => {
166
+ await prerenderPages({
167
+ dist: `${distDir}/${clientDir}`,
168
+ entry: `${distDir}/index.js`,
169
+ compress: true,
170
+ });
171
+ },
172
+ });
198
173
  }
199
174
 
200
175
  // Generate deployment configurations
201
- if (flags.vercel || viteAlephaBuildOptions.vercel) {
202
- const config =
203
- typeof viteAlephaBuildOptions.vercel === "object"
204
- ? viteAlephaBuildOptions.vercel
205
- : {};
176
+ if (flags.vercel || options.vercel) {
206
177
  await run({
207
178
  name: "add Vercel config",
208
179
  handler: () =>
209
180
  generateVercel({
210
181
  distDir,
211
182
  clientDir,
212
- config,
183
+ config: options.vercel,
213
184
  }),
214
185
  });
215
186
  }
216
187
 
217
- if (flags.cloudflare || viteAlephaBuildOptions.cloudflare) {
218
- const config =
219
- typeof viteAlephaBuildOptions.cloudflare === "boolean"
220
- ? {}
221
- : viteAlephaBuildOptions.cloudflare;
188
+ if (flags.cloudflare || options.cloudflare) {
222
189
  await run({
223
190
  name: "add Cloudflare config",
224
191
  handler: () =>
225
192
  generateCloudflare({
226
193
  distDir,
227
- config,
194
+ config: options.cloudflare?.config,
228
195
  }),
229
196
  });
230
197
  }
231
198
 
232
- if (flags.docker || viteAlephaBuildOptions.docker) {
233
- const dockerConfig =
234
- typeof viteAlephaBuildOptions.docker === "object"
235
- ? viteAlephaBuildOptions.docker
236
- : {};
199
+ if (flags.docker || options.docker) {
237
200
  await run({
238
201
  name: "add Docker config",
239
202
  handler: () =>
240
203
  generateDocker({
241
204
  distDir,
242
- ...dockerConfig,
205
+ ...options.docker,
243
206
  }),
244
207
  });
245
208
  }
@@ -134,7 +134,6 @@ export class DbCommand {
134
134
  protected readonly generate = $command({
135
135
  name: "generate",
136
136
  description: "Generate migration files based on current database schema",
137
- summary: false,
138
137
  args: t.optional(
139
138
  t.text({
140
139
  title: "path",
@@ -173,7 +172,6 @@ export class DbCommand {
173
172
  protected readonly push = $command({
174
173
  name: "push",
175
174
  description: "Push database schema changes directly to the database",
176
- summary: false,
177
175
  args: t.optional(
178
176
  t.text({
179
177
  title: "path",
@@ -200,7 +198,6 @@ export class DbCommand {
200
198
  protected readonly migrate = $command({
201
199
  name: "migrate",
202
200
  description: "Apply pending database migrations",
203
- summary: false,
204
201
  args: t.optional(
205
202
  t.text({
206
203
  title: "path",
@@ -227,7 +224,6 @@ export class DbCommand {
227
224
  protected readonly studio = $command({
228
225
  name: "studio",
229
226
  description: "Launch Drizzle Studio database browser",
230
- summary: false,
231
227
  args: t.optional(
232
228
  t.text({
233
229
  title: "path",
@@ -3,7 +3,7 @@ import { join } from "node:path";
3
3
  import { $inject, Alepha, t } from "alepha";
4
4
  import { $command } from "alepha/command";
5
5
  import { $logger } from "alepha/logger";
6
- import { boot } from "alepha/vite";
6
+ import { boot, devServer } from "alepha/vite";
7
7
  import { AlephaCliUtils } from "../services/AlephaCliUtils.ts";
8
8
 
9
9
  export class DevCommand {
@@ -25,7 +25,6 @@ export class DevCommand {
25
25
  const expo = await this.utils.hasExpo(root);
26
26
 
27
27
  await this.utils.ensureConfig(root, {
28
- viteConfigTs: !expo,
29
28
  tsconfigJson: true,
30
29
  });
31
30
 
@@ -40,7 +39,7 @@ export class DevCommand {
40
39
  const isFullstack = await this.isFullstackProject(root);
41
40
 
42
41
  if (!isFullstack) {
43
- const exe = this.alepha.isBun() ? "bun" : "tsx";
42
+ const exe = (await this.isBunProject(root)) ? "bun" : "tsx";
44
43
  let cmd = `${exe} --watch`;
45
44
  if (await this.utils.exists(root, ".env")) {
46
45
  cmd += " --env-file=./.env";
@@ -54,10 +53,23 @@ export class DevCommand {
54
53
 
55
54
  // Ensure vite is installed before running
56
55
  await this.utils.ensureDependency(root, "vite");
57
- await this.utils.exec("vite");
56
+
57
+ await devServer();
58
58
  },
59
59
  });
60
60
 
61
+ protected async isBunProject(root: string): Promise<boolean> {
62
+ if (this.alepha.isBun()) {
63
+ return true;
64
+ }
65
+ try {
66
+ await access(join(root, "bun.lock"));
67
+ return true;
68
+ } catch {
69
+ return false;
70
+ }
71
+ }
72
+
61
73
  protected async isFullstackProject(root: string): Promise<boolean> {
62
74
  try {
63
75
  await access(join(root, "index.html"));
@@ -0,0 +1,53 @@
1
+ import { $inject, t } from "alepha";
2
+ import { $command } from "alepha/command";
3
+ import { FileSystemProvider } from "alepha/file";
4
+ import { $logger } from "alepha/logger";
5
+ import { AlephaCliUtils } from "../../services/AlephaCliUtils.ts";
6
+
7
+ export class GenEnvCommand {
8
+ protected readonly log = $logger();
9
+ protected readonly utils = $inject(AlephaCliUtils);
10
+ protected readonly fs = $inject(FileSystemProvider);
11
+
12
+ public readonly command = $command({
13
+ name: "env",
14
+ description: "Extract environment variables from server entry file",
15
+ flags: t.object({
16
+ out: t.optional(
17
+ t.text({
18
+ aliases: ["o"],
19
+ description: "Output file path (e.g., .env)",
20
+ }),
21
+ ),
22
+ }),
23
+ handler: async ({ root, flags }) => {
24
+ const { alepha } = await this.utils.loadAlephaFromServerEntryFile(root);
25
+
26
+ try {
27
+ const { env } = alepha.dump();
28
+
29
+ let dotEnvFile = "";
30
+ for (const [key, value] of Object.entries(env)) {
31
+ if (value.description) {
32
+ dotEnvFile += `# ${value.description.split("\n").join("\n# ")}\n`;
33
+ }
34
+ if (value.required && !value.default) {
35
+ dotEnvFile += `# (required)\n`;
36
+ }
37
+ if (value.enum) {
38
+ dotEnvFile += `# Possible values: ${value.enum.join(", ")}\n`;
39
+ }
40
+ dotEnvFile += `${key}=${value.default || ""}\n\n`;
41
+ }
42
+
43
+ if (flags.out) {
44
+ await this.fs.writeFile(this.fs.join(root, flags.out), dotEnvFile);
45
+ } else {
46
+ this.log.info(dotEnvFile);
47
+ }
48
+ } catch (err) {
49
+ this.log.error("Failed to extract environment variables", err);
50
+ }
51
+ },
52
+ });
53
+ }
@@ -64,7 +64,7 @@ export class OpenApiCommand {
64
64
  return;
65
65
  }
66
66
 
67
- this.log.error(`OpenAPI generation failed - ${message}`, { err });
67
+ this.log.error(`OpenAPI generation failed - ${message}`, err);
68
68
  }
69
69
  },
70
70
  });
@@ -0,0 +1,15 @@
1
+ /**
2
+ * TODO:
3
+ *
4
+ * alepha gen resource <name>
5
+ *
6
+ * will generate:
7
+ *
8
+ * src/api/controllers/<name>Controller.ts
9
+ * src/api/entity/<name>Entity.ts
10
+ * (maybe) src/api/services/<name>Service.ts
11
+ * (maybe) src/api/repositories/<name>Repository.ts
12
+ *
13
+ * Each file will contain a basic scaffold for the respective component.
14
+ *
15
+ */
@@ -1,16 +1,22 @@
1
1
  import { $inject } from "alepha";
2
2
  import { $command } from "alepha/command";
3
3
  import { ChangelogCommand } from "./gen/changelog.ts";
4
+ import { GenEnvCommand } from "./gen/env.ts";
4
5
  import { OpenApiCommand } from "./gen/openapi.ts";
5
6
 
6
7
  export class GenCommand {
7
8
  protected readonly changelog = $inject(ChangelogCommand);
8
9
  protected readonly openapi = $inject(OpenApiCommand);
10
+ protected readonly genEnv = $inject(GenEnvCommand);
9
11
 
10
12
  public readonly gen = $command({
11
13
  name: "gen",
12
14
  description: "Generate code, documentation, ...",
13
- children: [this.changelog.command, this.openapi.command],
15
+ children: [
16
+ this.changelog.command,
17
+ this.openapi.command,
18
+ this.genEnv.command,
19
+ ],
14
20
  handler: async ({ help }) => {
15
21
  help();
16
22
  },
@@ -43,7 +43,6 @@ export class InitCommand {
43
43
  tsconfigJson: true,
44
44
  packageJson: flags,
45
45
  biomeJson: true,
46
- viteConfigTs: !isExpo,
47
46
  editorconfig: true,
48
47
  indexHtml: !!flags.react && !isExpo,
49
48
  });
@@ -28,7 +28,6 @@ export class TestCommand {
28
28
  handler: async ({ root, flags, env }) => {
29
29
  await this.utils.ensureConfig(root, {
30
30
  tsconfigJson: true,
31
- viteConfigTs: true,
32
31
  });
33
32
 
34
33
  // Ensure vitest is installed before running
@@ -34,7 +34,7 @@ export class VerifyCommand {
34
34
  }
35
35
 
36
36
  if (await this.utils.exists(root, "migrations")) {
37
- await run("alepha db:check-migrations");
37
+ await run("alepha db check-migrations");
38
38
  }
39
39
 
40
40
  const isExpo = await this.utils.hasExpo(root);
@@ -1,19 +1,61 @@
1
1
  import type { Alepha } from "alepha";
2
2
  import type { CommandPrimitive } from "alepha/command";
3
+ import { type BuildOptions, buildOptions } from "./atoms/buildOptions.ts";
3
4
 
4
- export type AlephaCliConfig = (alepha: Alepha) => {
5
+ export interface AlephaCliConfig {
6
+ /**
7
+ * Add custom commands to the Alepha CLI.
8
+ *
9
+ * You can override 'deploy', 'build', 'dev', 'start' commands this way.
10
+ * But you can also add your own commands and run them via `alepha <command>`.
11
+ */
5
12
  commands?: Record<string, CommandPrimitive>;
13
+
14
+ /**
15
+ * Register more services to the Alepha CLI (enhancements, commands, etc.).
16
+ */
6
17
  services?: Array<any>;
7
- };
8
18
 
9
- export const defineConfig = (config: AlephaCliConfig) => {
19
+ /**
20
+ * Configure Alepha build command.
21
+ */
22
+ build?: BuildOptions;
23
+
24
+ /**
25
+ * Environment variables to set before running commands.
26
+ *
27
+ * Always use .env files by default, this is only for dynamic values.
28
+ */
29
+ env?: Record<string, unknown>;
30
+ }
31
+
32
+ export type AlephaCliConfigFn = (alepha: Alepha) => AlephaCliConfig;
33
+
34
+ export const defineConfig = (
35
+ runConfig: AlephaCliConfig | AlephaCliConfigFn,
36
+ ) => {
10
37
  return (alepha: Alepha) => {
11
- const { commands, services = [] } = config(alepha);
12
- for (const it of services) {
13
- alepha.with(it);
38
+ const config =
39
+ typeof runConfig === "function" ? runConfig(alepha) : runConfig;
40
+
41
+ if (config.services) {
42
+ for (const it of config.services) {
43
+ alepha.with(it);
44
+ }
14
45
  }
46
+
47
+ if (config.env) {
48
+ for (const [key, value] of Object.entries(config.env)) {
49
+ process.env[key] = String(value);
50
+ }
51
+ }
52
+
53
+ if (config.build) {
54
+ alepha.set(buildOptions, config.build);
55
+ }
56
+
15
57
  return {
16
- ...commands,
58
+ ...config.commands,
17
59
  };
18
60
  };
19
61
  };
package/src/cli/index.ts CHANGED
@@ -12,7 +12,6 @@ export * from "./commands/gen/openapi.ts";
12
12
  export * from "./commands/init.ts";
13
13
  export * from "./commands/lint.ts";
14
14
  export * from "./commands/root.ts";
15
- export * from "./commands/run.ts";
16
15
  export * from "./commands/test.ts";
17
16
  export * from "./commands/typecheck.ts";
18
17
  export * from "./commands/verify.ts";
@@ -14,7 +14,6 @@ import { indexHtml } from "../assets/indexHtml.ts";
14
14
  import { mainBrowserTs } from "../assets/mainBrowserTs.ts";
15
15
  import { mainTs } from "../assets/mainTs.ts";
16
16
  import { tsconfigJson } from "../assets/tsconfigJson.ts";
17
- import { viteConfigTs } from "../assets/viteConfigTs.ts";
18
17
  import { version } from "../version.ts";
19
18
 
20
19
  /**
@@ -142,6 +141,33 @@ export class AlephaCliUtils {
142
141
  // Package Manager & Project Setup
143
142
  // ===================================================================================================================
144
143
 
144
+ public async editFile(
145
+ root: string,
146
+ name: string,
147
+ editFn: (content: string) => string | Promise<string>,
148
+ ): Promise<void> {
149
+ const filePath = join(root, name);
150
+ try {
151
+ const content = await readFile(filePath, "utf8");
152
+ const newContent = await editFn(content);
153
+ await writeFile(filePath, newContent);
154
+ } catch (error) {
155
+ this.log.debug("Could not edit file", error);
156
+ }
157
+ }
158
+
159
+ public async editJsonFile(
160
+ root: string,
161
+ name: string,
162
+ editFn: (obj: any) => any | Promise<any>,
163
+ ): Promise<void> {
164
+ return await this.editFile(root, name, async (content) => {
165
+ const obj = JSON.parse(content);
166
+ const newObj = await editFn(obj);
167
+ return JSON.stringify(newObj, null, 2);
168
+ });
169
+ }
170
+
145
171
  public async removeFiles(root: string, files: string[]): Promise<void> {
146
172
  await Promise.all(
147
173
  files.map((file) =>
@@ -151,11 +177,17 @@ export class AlephaCliUtils {
151
177
  }
152
178
 
153
179
  public async removeYarn(root: string): Promise<void> {
154
- await this.removeFiles(root, [".yarn", ".yarnrc.yml", ".yarn"]);
180
+ await this.removeFiles(root, [".yarn", ".yarnrc.yml", "yarn.lock"]);
181
+ await this.editJsonFile(root, "package.json", (pkg) => {
182
+ delete pkg.packageManager;
183
+ });
155
184
  }
156
185
 
157
186
  public async removePnpm(root: string): Promise<void> {
158
187
  await this.removeFiles(root, ["pnpm-lock.yaml", "pnpm-workspace.yaml"]);
188
+ await this.editJsonFile(root, "package.json", (pkg) => {
189
+ delete pkg.packageManager;
190
+ });
159
191
  }
160
192
 
161
193
  public async removeNpm(root: string): Promise<void> {
@@ -163,7 +195,7 @@ export class AlephaCliUtils {
163
195
  }
164
196
 
165
197
  public async removeBun(root: string): Promise<void> {
166
- await this.removeFiles(root, ["bun.lockb"]);
198
+ await this.removeFiles(root, ["bun.lockb", "bun.lock"]);
167
199
  }
168
200
 
169
201
  public async removeAllPmFilesExcept(
@@ -300,7 +332,6 @@ export class AlephaCliUtils {
300
332
  opts: {
301
333
  packageJson?: boolean | DependencyModes;
302
334
  tsconfigJson?: boolean;
303
- viteConfigTs?: boolean;
304
335
  indexHtml?: boolean;
305
336
  biomeJson?: boolean;
306
337
  editorconfig?: boolean;
@@ -319,9 +350,6 @@ export class AlephaCliUtils {
319
350
  if (opts.tsconfigJson) {
320
351
  tasks.push(this.ensureTsConfig(root));
321
352
  }
322
- if (opts.viteConfigTs) {
323
- tasks.push(this.ensureViteConfig(root));
324
- }
325
353
  if (opts.indexHtml) {
326
354
  tasks.push(this.ensureIndexHtml(root));
327
355
  }
@@ -346,23 +374,6 @@ export class AlephaCliUtils {
346
374
  await this.ensureFileExists(root, "tsconfig.json", tsconfigJson, true);
347
375
  }
348
376
 
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
377
  protected async checkFileExists(
367
378
  root: string,
368
379
  name: string,
@@ -657,7 +668,7 @@ ${models.map((it: string) => `export const ${it} = models["${it}"];`).join("\n")
657
668
  async readPackageJson(root: string): Promise<Record<string, any>> {
658
669
  const packageJson = await this.fs
659
670
  .createFile({
660
- path: join(root, "package.json"),
671
+ path: this.fs.join(root, "package.json"),
661
672
  })
662
673
  .text();
663
674
  return JSON.parse(packageJson);
@@ -109,7 +109,7 @@ describe("Runner", () => {
109
109
  await runner.run(`echo "Task 1"`);
110
110
  await runner.run("A slightly longer task name", () => {});
111
111
 
112
- runner.summary();
112
+ runner.end();
113
113
 
114
114
  const logs = mockLogger.logs
115
115
  .slice(4)
@@ -118,7 +118,7 @@ describe("Runner", () => {
118
118
  });
119
119
 
120
120
  test("summary() should not print a table if no tasks were run", () => {
121
- runner.summary();
121
+ runner.end();
122
122
 
123
123
  const logs = mockLogger.logs.map((l) => l.message);
124
124
  expect(logs.length).toBe(0);
@@ -179,7 +179,7 @@ export class Runner {
179
179
  /**
180
180
  * Prints a summary of all executed tasks and their durations.
181
181
  */
182
- public summary(): void {
182
+ public end(): void {
183
183
  if (this.useDynamicLogger && this.firstTaskStarted) {
184
184
  this.prettyPrint.endCommand();
185
185
  return;
@@ -105,12 +105,6 @@ export interface CommandPrimitiveOptions<
105
105
  */
106
106
  args?: A;
107
107
 
108
- /**
109
- * If false, skip summary message at the end of the command execution.
110
- * Summary will display only if ({ run }) method calls were made.
111
- */
112
- summary?: boolean;
113
-
114
108
  /**
115
109
  * Marks this command as the root command.
116
110
  * Equivalent to setting name to an empty string "".
@@ -237,9 +237,7 @@ export class CliProvider {
237
237
  await hook.options.handler(args as CommandHandlerArgs<TObject>);
238
238
  }
239
239
 
240
- if (command.options.summary !== false) {
241
- runner.summary();
242
- }
240
+ runner.end();
243
241
 
244
242
  this.log.debug(`Command '${command.name}' executed successfully.`);
245
243
  });