alepha 0.13.8 → 0.14.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 (160) hide show
  1. package/dist/api/audits/index.d.ts +418 -338
  2. package/dist/api/audits/index.d.ts.map +1 -0
  3. package/dist/api/files/index.d.ts +81 -1
  4. package/dist/api/files/index.d.ts.map +1 -0
  5. package/dist/api/jobs/index.d.ts +107 -27
  6. package/dist/api/jobs/index.d.ts.map +1 -0
  7. package/dist/api/notifications/index.d.ts +21 -1
  8. package/dist/api/notifications/index.d.ts.map +1 -0
  9. package/dist/api/parameters/index.d.ts +455 -8
  10. package/dist/api/parameters/index.d.ts.map +1 -0
  11. package/dist/api/users/index.d.ts +844 -840
  12. package/dist/api/users/index.d.ts.map +1 -0
  13. package/dist/api/verifications/index.d.ts.map +1 -0
  14. package/dist/batch/index.d.ts.map +1 -0
  15. package/dist/bucket/index.d.ts.map +1 -0
  16. package/dist/cache/core/index.d.ts.map +1 -0
  17. package/dist/cache/redis/index.d.ts.map +1 -0
  18. package/dist/cli/index.d.ts +254 -59
  19. package/dist/cli/index.d.ts.map +1 -0
  20. package/dist/cli/index.js +499 -127
  21. package/dist/cli/index.js.map +1 -1
  22. package/dist/command/index.d.ts +217 -10
  23. package/dist/command/index.d.ts.map +1 -0
  24. package/dist/command/index.js +350 -74
  25. package/dist/command/index.js.map +1 -1
  26. package/dist/core/index.browser.js +1334 -1318
  27. package/dist/core/index.browser.js.map +1 -1
  28. package/dist/core/index.d.ts +76 -72
  29. package/dist/core/index.d.ts.map +1 -0
  30. package/dist/core/index.js +1337 -1321
  31. package/dist/core/index.js.map +1 -1
  32. package/dist/core/index.native.js +1337 -1321
  33. package/dist/core/index.native.js.map +1 -1
  34. package/dist/datetime/index.d.ts.map +1 -0
  35. package/dist/email/index.d.ts.map +1 -0
  36. package/dist/fake/index.d.ts.map +1 -0
  37. package/dist/file/index.d.ts.map +1 -0
  38. package/dist/file/index.js.map +1 -1
  39. package/dist/lock/core/index.d.ts.map +1 -0
  40. package/dist/lock/redis/index.d.ts.map +1 -0
  41. package/dist/logger/index.d.ts +1 -0
  42. package/dist/logger/index.d.ts.map +1 -0
  43. package/dist/mcp/index.d.ts +820 -0
  44. package/dist/mcp/index.d.ts.map +1 -0
  45. package/dist/mcp/index.js +978 -0
  46. package/dist/mcp/index.js.map +1 -0
  47. package/dist/orm/index.d.ts +234 -107
  48. package/dist/orm/index.d.ts.map +1 -0
  49. package/dist/orm/index.js +376 -316
  50. package/dist/orm/index.js.map +1 -1
  51. package/dist/queue/core/index.d.ts +4 -4
  52. package/dist/queue/core/index.d.ts.map +1 -0
  53. package/dist/queue/redis/index.d.ts.map +1 -0
  54. package/dist/queue/redis/index.js +2 -4
  55. package/dist/queue/redis/index.js.map +1 -1
  56. package/dist/redis/index.d.ts +400 -29
  57. package/dist/redis/index.d.ts.map +1 -0
  58. package/dist/redis/index.js +412 -21
  59. package/dist/redis/index.js.map +1 -1
  60. package/dist/retry/index.d.ts.map +1 -0
  61. package/dist/router/index.d.ts.map +1 -0
  62. package/dist/scheduler/index.d.ts +6 -6
  63. package/dist/scheduler/index.d.ts.map +1 -0
  64. package/dist/security/index.d.ts +28 -28
  65. package/dist/security/index.d.ts.map +1 -0
  66. package/dist/server/auth/index.d.ts +155 -155
  67. package/dist/server/auth/index.d.ts.map +1 -0
  68. package/dist/server/cache/index.d.ts.map +1 -0
  69. package/dist/server/compress/index.d.ts.map +1 -0
  70. package/dist/server/cookies/index.d.ts.map +1 -0
  71. package/dist/server/core/index.d.ts +0 -1
  72. package/dist/server/core/index.d.ts.map +1 -0
  73. package/dist/server/core/index.js.map +1 -1
  74. package/dist/server/cors/index.d.ts.map +1 -0
  75. package/dist/server/health/index.d.ts +17 -17
  76. package/dist/server/health/index.d.ts.map +1 -0
  77. package/dist/server/helmet/index.d.ts +4 -1
  78. package/dist/server/helmet/index.d.ts.map +1 -0
  79. package/dist/server/links/index.d.ts +33 -33
  80. package/dist/server/links/index.d.ts.map +1 -0
  81. package/dist/server/metrics/index.d.ts.map +1 -0
  82. package/dist/server/multipart/index.d.ts.map +1 -0
  83. package/dist/server/multipart/index.js.map +1 -1
  84. package/dist/server/proxy/index.d.ts.map +1 -0
  85. package/dist/server/proxy/index.js.map +1 -1
  86. package/dist/server/rate-limit/index.d.ts.map +1 -0
  87. package/dist/server/security/index.d.ts +9 -9
  88. package/dist/server/security/index.d.ts.map +1 -0
  89. package/dist/server/static/index.d.ts.map +1 -0
  90. package/dist/server/swagger/index.d.ts.map +1 -0
  91. package/dist/sms/index.d.ts.map +1 -0
  92. package/dist/thread/index.d.ts.map +1 -0
  93. package/dist/topic/core/index.d.ts.map +1 -0
  94. package/dist/topic/redis/index.d.ts.map +1 -0
  95. package/dist/topic/redis/index.js +3 -3
  96. package/dist/topic/redis/index.js.map +1 -1
  97. package/dist/vite/index.d.ts +10 -2
  98. package/dist/vite/index.d.ts.map +1 -0
  99. package/dist/vite/index.js +45 -20
  100. package/dist/vite/index.js.map +1 -1
  101. package/dist/websocket/index.d.ts.map +1 -0
  102. package/package.json +9 -4
  103. package/src/cli/apps/AlephaCli.ts +10 -3
  104. package/src/cli/apps/AlephaPackageBuilderCli.ts +15 -8
  105. package/src/cli/assets/mainTs.ts +9 -10
  106. package/src/cli/atoms/changelogOptions.ts +45 -0
  107. package/src/cli/commands/ChangelogCommands.ts +259 -0
  108. package/src/cli/commands/DeployCommands.ts +118 -0
  109. package/src/cli/commands/DrizzleCommands.ts +230 -10
  110. package/src/cli/commands/ViteCommands.ts +47 -23
  111. package/src/cli/defineConfig.ts +15 -0
  112. package/src/cli/index.ts +3 -0
  113. package/src/cli/services/AlephaCliUtils.ts +10 -154
  114. package/src/cli/services/GitMessageParser.ts +77 -0
  115. package/src/command/helpers/EnvUtils.ts +37 -0
  116. package/src/command/index.ts +3 -1
  117. package/src/command/primitives/$command.ts +172 -6
  118. package/src/command/providers/CliProvider.ts +499 -95
  119. package/src/core/Alepha.ts +1 -1
  120. package/src/core/providers/SchemaValidator.ts +23 -1
  121. package/src/file/providers/NodeFileSystemProvider.ts +3 -1
  122. package/src/mcp/errors/McpError.ts +72 -0
  123. package/src/mcp/helpers/jsonrpc.ts +163 -0
  124. package/src/mcp/index.ts +132 -0
  125. package/src/mcp/interfaces/McpTypes.ts +248 -0
  126. package/src/mcp/primitives/$prompt.ts +188 -0
  127. package/src/mcp/primitives/$resource.ts +171 -0
  128. package/src/mcp/primitives/$tool.ts +285 -0
  129. package/src/mcp/providers/McpServerProvider.ts +382 -0
  130. package/src/mcp/transports/SseMcpTransport.ts +172 -0
  131. package/src/mcp/transports/StdioMcpTransport.ts +126 -0
  132. package/src/orm/index.ts +20 -4
  133. package/src/orm/interfaces/PgQueryWhere.ts +1 -26
  134. package/src/orm/providers/drivers/BunPostgresProvider.ts +225 -0
  135. package/src/orm/providers/drivers/BunSqliteProvider.ts +180 -0
  136. package/src/orm/providers/drivers/CloudflareD1Provider.ts +164 -0
  137. package/src/orm/providers/drivers/DatabaseProvider.ts +25 -0
  138. package/src/orm/providers/drivers/NodePostgresProvider.ts +0 -25
  139. package/src/orm/providers/drivers/NodeSqliteProvider.ts +3 -1
  140. package/src/orm/services/QueryManager.ts +10 -125
  141. package/src/queue/redis/providers/RedisQueueProvider.ts +2 -7
  142. package/src/redis/index.ts +65 -3
  143. package/src/redis/providers/BunRedisProvider.ts +304 -0
  144. package/src/redis/providers/BunRedisSubscriberProvider.ts +94 -0
  145. package/src/redis/providers/NodeRedisProvider.ts +280 -0
  146. package/src/redis/providers/NodeRedisSubscriberProvider.ts +94 -0
  147. package/src/redis/providers/RedisProvider.ts +134 -140
  148. package/src/redis/providers/RedisSubscriberProvider.ts +58 -49
  149. package/src/server/core/providers/BunHttpServerProvider.ts +0 -3
  150. package/src/server/core/providers/ServerBodyParserProvider.ts +3 -1
  151. package/src/server/core/providers/ServerProvider.ts +7 -4
  152. package/src/server/multipart/providers/ServerMultipartProvider.ts +3 -1
  153. package/src/server/proxy/providers/ServerProxyProvider.ts +1 -1
  154. package/src/topic/redis/providers/RedisTopicProvider.ts +3 -3
  155. package/src/vite/plugins/viteAlephaBuild.ts +8 -2
  156. package/src/vite/plugins/viteAlephaDev.ts +6 -2
  157. package/src/vite/tasks/buildServer.ts +2 -1
  158. package/src/vite/tasks/generateCloudflare.ts +43 -15
  159. package/src/vite/tasks/runAlepha.ts +1 -0
  160. package/src/orm/services/PgJsonQueryManager.ts +0 -511
@@ -3,7 +3,11 @@ import { join } from "node:path";
3
3
  import { $inject, AlephaError, t } from "alepha";
4
4
  import { $command } from "alepha/command";
5
5
  import { $logger } from "alepha/logger";
6
- import type { DrizzleKitProvider, RepositoryProvider } from "alepha/orm";
6
+ import type {
7
+ DatabaseProvider,
8
+ DrizzleKitProvider,
9
+ RepositoryProvider,
10
+ } from "alepha/orm";
7
11
  import { AlephaCliUtils } from "../services/AlephaCliUtils.ts";
8
12
 
9
13
  const drizzleCommandFlags = t.object({
@@ -13,6 +17,12 @@ const drizzleCommandFlags = t.object({
13
17
  "Database provider name to target (e.g., 'postgres', 'sqlite')",
14
18
  }),
15
19
  ),
20
+ mode: t.optional(
21
+ t.text({
22
+ description:
23
+ "Environment variable file(s) to load (e.g., 'production' to load .env.production) https://vite.dev/guide/env-and-mode",
24
+ }),
25
+ ),
16
26
  });
17
27
 
18
28
  export class DrizzleCommands {
@@ -23,7 +33,7 @@ export class DrizzleCommands {
23
33
  * Check if database migrations are up to date.
24
34
  */
25
35
  check = $command({
26
- name: "db:check-migrations",
36
+ name: "check-migrations",
27
37
  description: "Check if database migration files are up to date",
28
38
  args: t.optional(
29
39
  t.text({
@@ -128,7 +138,7 @@ export class DrizzleCommands {
128
138
  * - Invokes Drizzle Kit's CLI to generate migration files based on the current schema.
129
139
  */
130
140
  generate = $command({
131
- name: "db:generate",
141
+ name: "generate",
132
142
  description: "Generate migration files based on current database schema",
133
143
  summary: false,
134
144
  args: t.optional(
@@ -149,12 +159,14 @@ export class DrizzleCommands {
149
159
  const commandFlags = flags.custom
150
160
  ? `--custom=${flags.custom}`
151
161
  : undefined;
152
- await this.utils.runDrizzleKitCommand({
162
+
163
+ await this.runDrizzleKitCommand({
153
164
  root,
154
165
  args,
155
166
  command: "generate",
156
167
  commandFlags,
157
168
  provider: flags.provider,
169
+ env: flags.mode,
158
170
  logMessage: (providerName, dialect) =>
159
171
  `Generate '${providerName}' migrations (${dialect}) ...`,
160
172
  });
@@ -170,7 +182,7 @@ export class DrizzleCommands {
170
182
  * - Invokes Drizzle Kit's push command to apply schema changes directly.
171
183
  */
172
184
  push = $command({
173
- name: "db:push",
185
+ name: "push",
174
186
  description: "Push database schema changes directly to the database",
175
187
  summary: false,
176
188
  args: t.optional(
@@ -181,11 +193,12 @@ export class DrizzleCommands {
181
193
  ),
182
194
  flags: drizzleCommandFlags,
183
195
  handler: async ({ root, args, flags }) => {
184
- await this.utils.runDrizzleKitCommand({
196
+ await this.runDrizzleKitCommand({
185
197
  root,
186
198
  args,
187
199
  command: "push",
188
200
  provider: flags.provider,
201
+ env: flags.mode,
189
202
  logMessage: (providerName, dialect) =>
190
203
  `Push '${providerName}' schema (${dialect}) ...`,
191
204
  });
@@ -201,7 +214,7 @@ export class DrizzleCommands {
201
214
  * - Invokes Drizzle Kit's migrate command to apply pending migrations.
202
215
  */
203
216
  migrate = $command({
204
- name: "db:migrate",
217
+ name: "migrate",
205
218
  description: "Apply pending database migrations",
206
219
  summary: false,
207
220
  args: t.optional(
@@ -212,11 +225,12 @@ export class DrizzleCommands {
212
225
  ),
213
226
  flags: drizzleCommandFlags,
214
227
  handler: async ({ root, args, flags }) => {
215
- await this.utils.runDrizzleKitCommand({
228
+ await this.runDrizzleKitCommand({
216
229
  root,
217
230
  args,
218
231
  command: "migrate",
219
232
  provider: flags.provider,
233
+ env: flags.mode,
220
234
  logMessage: (providerName, dialect) =>
221
235
  `Migrate '${providerName}' database (${dialect}) ...`,
222
236
  });
@@ -232,7 +246,7 @@ export class DrizzleCommands {
232
246
  * - Invokes Drizzle Kit's studio command to launch the web-based database browser.
233
247
  */
234
248
  studio = $command({
235
- name: "db:studio",
249
+ name: "studio",
236
250
  description: "Launch Drizzle Studio database browser",
237
251
  summary: false,
238
252
  args: t.optional(
@@ -243,17 +257,223 @@ export class DrizzleCommands {
243
257
  ),
244
258
  flags: drizzleCommandFlags,
245
259
  handler: async ({ root, args, flags }) => {
246
- await this.utils.runDrizzleKitCommand({
260
+ await this.runDrizzleKitCommand({
247
261
  root,
248
262
  args,
249
263
  command: "studio",
250
264
  provider: flags.provider,
265
+ env: flags.mode,
251
266
  logMessage: (providerName, dialect) =>
252
267
  `Launch Studio for '${providerName}' (${dialect}) ...`,
253
268
  });
254
269
  },
255
270
  });
256
271
 
272
+ /**
273
+ * Parent command for database operations.
274
+ */
275
+ db = $command({
276
+ name: "db",
277
+ description: "Database management commands",
278
+ children: [this.check, this.generate, this.push, this.migrate, this.studio],
279
+ handler: async ({ help }) => {
280
+ help();
281
+ },
282
+ });
283
+
284
+ /**
285
+ * 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
+ */
292
+ public async runDrizzleKitCommand(options: {
293
+ root: string;
294
+ args?: string;
295
+ command: string;
296
+ commandFlags?: string;
297
+ provider?: string;
298
+ logMessage: (providerName: string, dialect: string) => string;
299
+ env?: string;
300
+ }): Promise<void> {
301
+ const rootDir = options.root;
302
+
303
+ const envFiles = [".env"];
304
+ if (options.env) {
305
+ envFiles.push(`.env.${options.env}`);
306
+ }
307
+
308
+ await this.utils.loadEnv(rootDir, envFiles);
309
+
310
+ this.log.debug(`Using project root: ${rootDir}`);
311
+
312
+ const { alepha, entry } = await this.utils.loadAlephaFromServerEntryFile(
313
+ rootDir,
314
+ options.args,
315
+ );
316
+
317
+ const drizzleKitProvider =
318
+ alepha.inject<DrizzleKitProvider>("DrizzleKitProvider");
319
+ const repositoryProvider =
320
+ alepha.inject<RepositoryProvider>("RepositoryProvider");
321
+ const accepted = new Set<string>([]);
322
+
323
+ for (const primitive of repositoryProvider.getRepositories()) {
324
+ const provider = primitive.provider;
325
+ const providerName = provider.name;
326
+ const dialect = provider.dialect;
327
+
328
+ if (accepted.has(providerName)) {
329
+ continue;
330
+ }
331
+ accepted.add(providerName);
332
+
333
+ // Skip if provider filter is set and doesn't match
334
+ if (options.provider && options.provider !== providerName) {
335
+ this.log.debug(
336
+ `Skipping provider '${providerName}' (filter: ${options.provider})`,
337
+ );
338
+ continue;
339
+ }
340
+
341
+ this.log.info("");
342
+ this.log.info(options.logMessage(providerName, dialect));
343
+
344
+ const drizzleConfigJsPath = await this.prepareDrizzleConfig({
345
+ kit: drizzleKitProvider,
346
+ provider,
347
+ providerName,
348
+ providerUrl: provider.url,
349
+ dialect,
350
+ entry,
351
+ rootDir,
352
+ });
353
+
354
+ const flags = options.commandFlags ? ` ${options.commandFlags}` : "";
355
+ await this.utils.exec(
356
+ `drizzle-kit ${options.command} --config=${drizzleConfigJsPath}${flags}`,
357
+ {
358
+ env: {
359
+ NODE_OPTIONS: "--import tsx",
360
+ },
361
+ },
362
+ );
363
+ }
364
+ }
365
+
366
+ /**
367
+ * 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
+ */
375
+ public async prepareDrizzleConfig(options: {
376
+ kit: any;
377
+ provider: DatabaseProvider;
378
+ providerName: string;
379
+ providerUrl: string;
380
+ dialect: string;
381
+ entry: string;
382
+ rootDir: string;
383
+ }): Promise<string> {
384
+ const models = Object.keys(options.kit.getModels(options.provider));
385
+ const entitiesJs = this.utils.generateEntitiesJs(
386
+ options.entry,
387
+ options.providerName,
388
+ models,
389
+ );
390
+
391
+ const entitiesJsPath = await this.utils.writeConfigFile(
392
+ "entities.js",
393
+ entitiesJs,
394
+ options.rootDir,
395
+ );
396
+
397
+ const config: Record<string, any> = {
398
+ schema: entitiesJsPath,
399
+ out: `./migrations/${options.providerName}`,
400
+ dialect: options.dialect,
401
+ dbCredentials: {
402
+ url: options.providerUrl,
403
+ },
404
+ };
405
+
406
+ if (options.provider.schema) {
407
+ config.schemaFilter = options.provider.schema;
408
+ }
409
+
410
+ if (options.providerName === "d1") {
411
+ config.driver = "d1-http";
412
+ }
413
+
414
+ if (options.providerName === "pglite") {
415
+ config.driver = "pglite";
416
+ }
417
+
418
+ if (options.dialect === "sqlite") {
419
+ if (options.providerName === "d1") {
420
+ const token = process.env.CLOUDFLARE_API_TOKEN;
421
+ if (!token) {
422
+ throw new AlephaError(
423
+ "CLOUDFLARE_API_TOKEN environment variable is not set. https://orm.drizzle.team/docs/guides/d1-http-with-drizzle-kit",
424
+ );
425
+ }
426
+
427
+ const accountId = process.env.CLOUDFLARE_ACCOUNT_ID;
428
+ if (!accountId) {
429
+ throw new AlephaError(
430
+ "CLOUDFLARE_ACCOUNT_ID environment variable is not set. https://orm.drizzle.team/docs/guides/d1-http-with-drizzle-kit",
431
+ );
432
+ }
433
+
434
+ const url = options.providerUrl;
435
+ if (!url.startsWith("cloudflare-d1://")) {
436
+ throw new AlephaError(
437
+ "D1 provider URL must start with 'cloudflare-d1://'.",
438
+ );
439
+ }
440
+
441
+ const [, databaseId] = url
442
+ .replace("cloudflare-d1://", "")
443
+ .replace("cloudflare-d1:", "")
444
+ .split(":");
445
+
446
+ if (!databaseId) {
447
+ throw new AlephaError(
448
+ "Database ID is missing in the D1 provider URL. Cloudflare D1 URL format: cloudflare-d1://<database_name>:<database_id>",
449
+ );
450
+ }
451
+
452
+ config.dbCredentials = {
453
+ accountId,
454
+ databaseId,
455
+ token,
456
+ };
457
+ } else {
458
+ let url = options.providerUrl;
459
+ url = url.replace("sqlite://", "").replace("file://", "");
460
+ url = join(options.rootDir, url);
461
+
462
+ config.dbCredentials = {
463
+ url,
464
+ };
465
+ }
466
+ }
467
+
468
+ const drizzleConfigJs = `export default ${JSON.stringify(config, null, 2)}`;
469
+
470
+ return await this.utils.writeConfigFile(
471
+ "drizzle.config.js",
472
+ drizzleConfigJs,
473
+ options.rootDir,
474
+ );
475
+ }
476
+
257
477
  // /**
258
478
  // * Drop database schema (development only)
259
479
  // *
@@ -1,4 +1,5 @@
1
1
  import { access, readFile, unlink, writeFile } from "node:fs/promises";
2
+ import { createRequire } from "node:module";
2
3
  import { join } from "node:path";
3
4
  import { $env, $inject, OPTIONS, t } from "alepha";
4
5
  import { $command } from "alepha/command";
@@ -13,8 +14,8 @@ import {
13
14
  generateSitemap,
14
15
  generateVercel,
15
16
  prerenderPages,
16
- type ViteAlephaBuildOptions,
17
17
  } from "alepha/vite";
18
+ import type * as Vite from "vite";
18
19
  import { AlephaCliUtils } from "../services/AlephaCliUtils.ts";
19
20
 
20
21
  export class ViteCommands {
@@ -121,15 +122,11 @@ export class ViteCommands {
121
122
  description: "Generate sitemap.xml with base URL",
122
123
  }),
123
124
  ),
124
- prerender: t.optional(
125
- t.boolean({
126
- description: "Pre-render static pages",
127
- }),
128
- ),
129
125
  }),
130
126
  handler: async ({ flags, args, run, root }) => {
131
127
  // Tell viteAlephaBuild plugin to skip - CLI handles all tasks
132
128
  process.env.ALEPHA_BUILD_MODE = "cli";
129
+ process.env.NODE_ENV = "production";
133
130
 
134
131
  if (await this.utils.hasExpo(root)) {
135
132
  // will coming soon
@@ -156,11 +153,14 @@ export class ViteCommands {
156
153
  alias: "clean dist",
157
154
  });
158
155
 
159
- const viteConfig = await import(join(root, "vite.config.ts"));
160
- const viteAlephaBuildOptions: ViteAlephaBuildOptions =
161
- viteConfig?.default?.plugins.find((it: any) => !!it[OPTIONS])?.[
162
- OPTIONS
163
- ] ?? {};
156
+ const vite: typeof Vite = createRequire(import.meta.url)("vite");
157
+ const config = await vite.resolveConfig({}, "build", "production");
158
+ const alephaPlugin: any = config.plugins.find(
159
+ (it) => it.name === "alepha:build",
160
+ );
161
+ const viteAlephaBuildOptions = alephaPlugin?.[OPTIONS] || {};
162
+
163
+ await this.utils.loadEnv(root, [".env", ".env.production"]);
164
164
 
165
165
  const stats = flags.stats ?? viteAlephaBuildOptions.stats ?? false;
166
166
  const hasServer = viteAlephaBuildOptions.serverEntry !== false;
@@ -173,6 +173,12 @@ export class ViteCommands {
173
173
  // No index.html
174
174
  }
175
175
 
176
+ // Extract client options
177
+ const clientOptions =
178
+ typeof viteAlephaBuildOptions.client === "object"
179
+ ? viteAlephaBuildOptions.client
180
+ : {};
181
+
176
182
  // Build client
177
183
  if (hasClient) {
178
184
  await run({
@@ -182,6 +188,7 @@ export class ViteCommands {
182
188
  silent: true,
183
189
  dist: `${distDir}/${clientDir}`,
184
190
  stats,
191
+ precompress: clientOptions.precompress,
185
192
  }),
186
193
  });
187
194
  }
@@ -224,11 +231,7 @@ export class ViteCommands {
224
231
 
225
232
  if (hasClient) {
226
233
  // Generate sitemap
227
- const sitemapBaseUrl =
228
- flags.sitemap ??
229
- (typeof viteAlephaBuildOptions.client === "object"
230
- ? viteAlephaBuildOptions.client.sitemap?.hostname
231
- : undefined);
234
+ const sitemapBaseUrl = flags.sitemap ?? clientOptions.sitemap?.hostname;
232
235
 
233
236
  if (sitemapBaseUrl) {
234
237
  await run({
@@ -246,11 +249,7 @@ export class ViteCommands {
246
249
  }
247
250
 
248
251
  // Pre-render static pages
249
- const shouldPrerender =
250
- flags.prerender ??
251
- (typeof viteAlephaBuildOptions.client === "object"
252
- ? viteAlephaBuildOptions.client.prerender
253
- : false);
252
+ const shouldPrerender = clientOptions.prerender;
254
253
 
255
254
  if (shouldPrerender) {
256
255
  await run({
@@ -259,6 +258,7 @@ export class ViteCommands {
259
258
  await prerenderPages({
260
259
  dist: `${distDir}/${clientDir}`,
261
260
  entry: `${distDir}/index.js`,
261
+ compress: clientOptions.precompress,
262
262
  });
263
263
  },
264
264
  });
@@ -283,11 +283,16 @@ export class ViteCommands {
283
283
  }
284
284
 
285
285
  if (flags.cloudflare || viteAlephaBuildOptions.cloudflare) {
286
+ const config =
287
+ typeof viteAlephaBuildOptions.cloudflare === "boolean"
288
+ ? {}
289
+ : viteAlephaBuildOptions.cloudflare;
286
290
  await run({
287
291
  name: "add Cloudflare config",
288
292
  handler: () =>
289
293
  generateCloudflare({
290
294
  distDir,
295
+ config,
291
296
  }),
292
297
  });
293
298
  }
@@ -312,7 +317,24 @@ export class ViteCommands {
312
317
  public readonly test = $command({
313
318
  name: "test",
314
319
  description: "Run tests using Vitest",
315
- handler: async ({ root }) => {
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 }) => {
316
338
  await this.utils.ensureConfig(root, {
317
339
  tsconfigJson: true,
318
340
  viteConfigTs: true,
@@ -321,7 +343,9 @@ export class ViteCommands {
321
343
  // Ensure vitest is installed before running
322
344
  await this.utils.ensureDependency(root, "vitest");
323
345
 
324
- await this.utils.exec(`vitest run ${this.env.VITEST_ARGS}`);
346
+ const config = flags.config ? `--config=${flags.config}` : "";
347
+
348
+ await this.utils.exec(`vitest run ${config} ${env.VITEST_ARGS}`);
325
349
  },
326
350
  });
327
351
  }
@@ -0,0 +1,15 @@
1
+ import type { Alepha } from "alepha";
2
+ import type { CommandPrimitive } from "alepha/command";
3
+
4
+ export type AlephaCliConfig = (alepha: Alepha) => {
5
+ commands?: Record<string, CommandPrimitive>;
6
+ };
7
+
8
+ export const defineConfig = (config: AlephaCliConfig) => {
9
+ return (alepha: Alepha) => {
10
+ const { commands } = config(alepha);
11
+ return {
12
+ ...commands,
13
+ };
14
+ };
15
+ };
package/src/cli/index.ts CHANGED
@@ -1,9 +1,12 @@
1
1
  export * from "./apps/AlephaCli.ts";
2
2
  export * from "./apps/AlephaPackageBuilderCli.ts";
3
3
  export * from "./commands/BiomeCommands.ts";
4
+ export * from "./commands/ChangelogCommands.ts";
4
5
  export * from "./commands/CoreCommands.ts";
6
+ export * from "./commands/DeployCommands.ts";
5
7
  export * from "./commands/DrizzleCommands.ts";
6
8
  export * from "./commands/VerifyCommands.ts";
7
9
  export * from "./commands/ViteCommands.ts";
10
+ export * from "./defineConfig.ts";
8
11
  export * from "./services/AlephaCliUtils.ts";
9
12
  export * from "./version.ts";