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.
- package/dist/api/audits/index.d.ts +418 -338
- package/dist/api/audits/index.d.ts.map +1 -0
- package/dist/api/files/index.d.ts +81 -1
- package/dist/api/files/index.d.ts.map +1 -0
- package/dist/api/jobs/index.d.ts +107 -27
- package/dist/api/jobs/index.d.ts.map +1 -0
- package/dist/api/notifications/index.d.ts +21 -1
- package/dist/api/notifications/index.d.ts.map +1 -0
- package/dist/api/parameters/index.d.ts +455 -8
- package/dist/api/parameters/index.d.ts.map +1 -0
- package/dist/api/users/index.d.ts +844 -840
- package/dist/api/users/index.d.ts.map +1 -0
- package/dist/api/verifications/index.d.ts.map +1 -0
- package/dist/batch/index.d.ts.map +1 -0
- package/dist/bucket/index.d.ts.map +1 -0
- package/dist/cache/core/index.d.ts.map +1 -0
- package/dist/cache/redis/index.d.ts.map +1 -0
- package/dist/cli/index.d.ts +254 -59
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +499 -127
- package/dist/cli/index.js.map +1 -1
- package/dist/command/index.d.ts +217 -10
- package/dist/command/index.d.ts.map +1 -0
- package/dist/command/index.js +350 -74
- package/dist/command/index.js.map +1 -1
- package/dist/core/index.browser.js +1334 -1318
- package/dist/core/index.browser.js.map +1 -1
- package/dist/core/index.d.ts +76 -72
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +1337 -1321
- package/dist/core/index.js.map +1 -1
- package/dist/core/index.native.js +1337 -1321
- package/dist/core/index.native.js.map +1 -1
- package/dist/datetime/index.d.ts.map +1 -0
- package/dist/email/index.d.ts.map +1 -0
- package/dist/fake/index.d.ts.map +1 -0
- package/dist/file/index.d.ts.map +1 -0
- package/dist/file/index.js.map +1 -1
- package/dist/lock/core/index.d.ts.map +1 -0
- package/dist/lock/redis/index.d.ts.map +1 -0
- package/dist/logger/index.d.ts +1 -0
- package/dist/logger/index.d.ts.map +1 -0
- package/dist/mcp/index.d.ts +820 -0
- package/dist/mcp/index.d.ts.map +1 -0
- package/dist/mcp/index.js +978 -0
- package/dist/mcp/index.js.map +1 -0
- package/dist/orm/index.d.ts +234 -107
- package/dist/orm/index.d.ts.map +1 -0
- package/dist/orm/index.js +376 -316
- package/dist/orm/index.js.map +1 -1
- package/dist/queue/core/index.d.ts +4 -4
- package/dist/queue/core/index.d.ts.map +1 -0
- package/dist/queue/redis/index.d.ts.map +1 -0
- package/dist/queue/redis/index.js +2 -4
- package/dist/queue/redis/index.js.map +1 -1
- package/dist/redis/index.d.ts +400 -29
- package/dist/redis/index.d.ts.map +1 -0
- package/dist/redis/index.js +412 -21
- package/dist/redis/index.js.map +1 -1
- package/dist/retry/index.d.ts.map +1 -0
- package/dist/router/index.d.ts.map +1 -0
- package/dist/scheduler/index.d.ts +6 -6
- package/dist/scheduler/index.d.ts.map +1 -0
- package/dist/security/index.d.ts +28 -28
- package/dist/security/index.d.ts.map +1 -0
- package/dist/server/auth/index.d.ts +155 -155
- package/dist/server/auth/index.d.ts.map +1 -0
- package/dist/server/cache/index.d.ts.map +1 -0
- package/dist/server/compress/index.d.ts.map +1 -0
- package/dist/server/cookies/index.d.ts.map +1 -0
- package/dist/server/core/index.d.ts +0 -1
- package/dist/server/core/index.d.ts.map +1 -0
- package/dist/server/core/index.js.map +1 -1
- package/dist/server/cors/index.d.ts.map +1 -0
- package/dist/server/health/index.d.ts +17 -17
- package/dist/server/health/index.d.ts.map +1 -0
- package/dist/server/helmet/index.d.ts +4 -1
- package/dist/server/helmet/index.d.ts.map +1 -0
- package/dist/server/links/index.d.ts +33 -33
- package/dist/server/links/index.d.ts.map +1 -0
- package/dist/server/metrics/index.d.ts.map +1 -0
- package/dist/server/multipart/index.d.ts.map +1 -0
- package/dist/server/multipart/index.js.map +1 -1
- package/dist/server/proxy/index.d.ts.map +1 -0
- package/dist/server/proxy/index.js.map +1 -1
- package/dist/server/rate-limit/index.d.ts.map +1 -0
- package/dist/server/security/index.d.ts +9 -9
- package/dist/server/security/index.d.ts.map +1 -0
- package/dist/server/static/index.d.ts.map +1 -0
- package/dist/server/swagger/index.d.ts.map +1 -0
- package/dist/sms/index.d.ts.map +1 -0
- package/dist/thread/index.d.ts.map +1 -0
- package/dist/topic/core/index.d.ts.map +1 -0
- package/dist/topic/redis/index.d.ts.map +1 -0
- package/dist/topic/redis/index.js +3 -3
- package/dist/topic/redis/index.js.map +1 -1
- package/dist/vite/index.d.ts +10 -2
- package/dist/vite/index.d.ts.map +1 -0
- package/dist/vite/index.js +45 -20
- package/dist/vite/index.js.map +1 -1
- package/dist/websocket/index.d.ts.map +1 -0
- package/package.json +9 -4
- package/src/cli/apps/AlephaCli.ts +10 -3
- package/src/cli/apps/AlephaPackageBuilderCli.ts +15 -8
- package/src/cli/assets/mainTs.ts +9 -10
- package/src/cli/atoms/changelogOptions.ts +45 -0
- package/src/cli/commands/ChangelogCommands.ts +259 -0
- package/src/cli/commands/DeployCommands.ts +118 -0
- package/src/cli/commands/DrizzleCommands.ts +230 -10
- package/src/cli/commands/ViteCommands.ts +47 -23
- package/src/cli/defineConfig.ts +15 -0
- package/src/cli/index.ts +3 -0
- package/src/cli/services/AlephaCliUtils.ts +10 -154
- package/src/cli/services/GitMessageParser.ts +77 -0
- package/src/command/helpers/EnvUtils.ts +37 -0
- package/src/command/index.ts +3 -1
- package/src/command/primitives/$command.ts +172 -6
- package/src/command/providers/CliProvider.ts +499 -95
- package/src/core/Alepha.ts +1 -1
- package/src/core/providers/SchemaValidator.ts +23 -1
- package/src/file/providers/NodeFileSystemProvider.ts +3 -1
- package/src/mcp/errors/McpError.ts +72 -0
- package/src/mcp/helpers/jsonrpc.ts +163 -0
- package/src/mcp/index.ts +132 -0
- package/src/mcp/interfaces/McpTypes.ts +248 -0
- package/src/mcp/primitives/$prompt.ts +188 -0
- package/src/mcp/primitives/$resource.ts +171 -0
- package/src/mcp/primitives/$tool.ts +285 -0
- package/src/mcp/providers/McpServerProvider.ts +382 -0
- package/src/mcp/transports/SseMcpTransport.ts +172 -0
- package/src/mcp/transports/StdioMcpTransport.ts +126 -0
- package/src/orm/index.ts +20 -4
- package/src/orm/interfaces/PgQueryWhere.ts +1 -26
- package/src/orm/providers/drivers/BunPostgresProvider.ts +225 -0
- package/src/orm/providers/drivers/BunSqliteProvider.ts +180 -0
- package/src/orm/providers/drivers/CloudflareD1Provider.ts +164 -0
- package/src/orm/providers/drivers/DatabaseProvider.ts +25 -0
- package/src/orm/providers/drivers/NodePostgresProvider.ts +0 -25
- package/src/orm/providers/drivers/NodeSqliteProvider.ts +3 -1
- package/src/orm/services/QueryManager.ts +10 -125
- package/src/queue/redis/providers/RedisQueueProvider.ts +2 -7
- package/src/redis/index.ts +65 -3
- package/src/redis/providers/BunRedisProvider.ts +304 -0
- package/src/redis/providers/BunRedisSubscriberProvider.ts +94 -0
- package/src/redis/providers/NodeRedisProvider.ts +280 -0
- package/src/redis/providers/NodeRedisSubscriberProvider.ts +94 -0
- package/src/redis/providers/RedisProvider.ts +134 -140
- package/src/redis/providers/RedisSubscriberProvider.ts +58 -49
- package/src/server/core/providers/BunHttpServerProvider.ts +0 -3
- package/src/server/core/providers/ServerBodyParserProvider.ts +3 -1
- package/src/server/core/providers/ServerProvider.ts +7 -4
- package/src/server/multipart/providers/ServerMultipartProvider.ts +3 -1
- package/src/server/proxy/providers/ServerProxyProvider.ts +1 -1
- package/src/topic/redis/providers/RedisTopicProvider.ts +3 -3
- package/src/vite/plugins/viteAlephaBuild.ts +8 -2
- package/src/vite/plugins/viteAlephaDev.ts +6 -2
- package/src/vite/tasks/buildServer.ts +2 -1
- package/src/vite/tasks/generateCloudflare.ts +43 -15
- package/src/vite/tasks/runAlepha.ts +1 -0
- package/src/orm/services/PgJsonQueryManager.ts +0 -511
|
@@ -2,10 +2,9 @@ import { spawn } from "node:child_process";
|
|
|
2
2
|
import { access, mkdir, readFile, writeFile } from "node:fs/promises";
|
|
3
3
|
import { join } from "node:path";
|
|
4
4
|
import { $inject, Alepha, AlephaError } from "alepha";
|
|
5
|
-
import type
|
|
5
|
+
import { EnvUtils, type RunnerMethod } from "alepha/command";
|
|
6
6
|
import { FileSystemProvider } from "alepha/file";
|
|
7
7
|
import { $logger } from "alepha/logger";
|
|
8
|
-
import type { DrizzleKitProvider, RepositoryProvider } from "alepha/orm";
|
|
9
8
|
import { boot } from "alepha/vite";
|
|
10
9
|
import { tsImport } from "tsx/esm/api";
|
|
11
10
|
import { appRouterTs } from "../assets/appRouterTs.ts";
|
|
@@ -32,6 +31,7 @@ import { version } from "../version.ts";
|
|
|
32
31
|
export class AlephaCliUtils {
|
|
33
32
|
protected readonly log = $logger();
|
|
34
33
|
protected readonly fs = $inject(FileSystemProvider);
|
|
34
|
+
protected readonly envUtils = $inject(EnvUtils);
|
|
35
35
|
|
|
36
36
|
/**
|
|
37
37
|
* Execute a command using npx with inherited stdio.
|
|
@@ -495,160 +495,16 @@ ${models.map((it: string) => `export const ${it} = models["${it}"];`).join("\n")
|
|
|
495
495
|
}
|
|
496
496
|
|
|
497
497
|
/**
|
|
498
|
-
*
|
|
498
|
+
* Load environment variables from a .env file.
|
|
499
499
|
*
|
|
500
|
-
*
|
|
501
|
-
*
|
|
502
|
-
*
|
|
503
|
-
* @param options - Configuration options including kit, provider info, and paths
|
|
504
|
-
* @returns Path to the generated drizzle.config.js file
|
|
500
|
+
* Reads the .env file in the specified root directory and sets
|
|
501
|
+
* the environment variables in process.env.
|
|
505
502
|
*/
|
|
506
|
-
public async
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
dialect: string;
|
|
512
|
-
entry: string;
|
|
513
|
-
rootDir: string;
|
|
514
|
-
}): Promise<string> {
|
|
515
|
-
const models = Object.keys(options.kit.getModels(options.provider));
|
|
516
|
-
const entitiesJs = this.generateEntitiesJs(
|
|
517
|
-
options.entry,
|
|
518
|
-
options.providerName,
|
|
519
|
-
models,
|
|
520
|
-
);
|
|
521
|
-
|
|
522
|
-
const entitiesJsPath = await this.writeConfigFile(
|
|
523
|
-
"entities.js",
|
|
524
|
-
entitiesJs,
|
|
525
|
-
options.rootDir,
|
|
526
|
-
);
|
|
527
|
-
|
|
528
|
-
const config: Record<string, any> = {
|
|
529
|
-
schema: entitiesJsPath,
|
|
530
|
-
out: `./migrations/${options.providerName}`,
|
|
531
|
-
dialect: options.dialect,
|
|
532
|
-
dbCredentials: {
|
|
533
|
-
url: options.providerUrl,
|
|
534
|
-
},
|
|
535
|
-
};
|
|
536
|
-
|
|
537
|
-
if (options.dialect === "sqlite") {
|
|
538
|
-
let url = options.providerUrl;
|
|
539
|
-
url = url.replace("sqlite://", "").replace("file://", "");
|
|
540
|
-
url = join(options.rootDir, url);
|
|
541
|
-
|
|
542
|
-
config.dbCredentials = {
|
|
543
|
-
url,
|
|
544
|
-
};
|
|
545
|
-
}
|
|
546
|
-
|
|
547
|
-
if (options.providerName === "pglite") {
|
|
548
|
-
config.driver = "pglite";
|
|
549
|
-
}
|
|
550
|
-
|
|
551
|
-
const drizzleConfigJs = `export default ${JSON.stringify(config, null, 2)}`;
|
|
552
|
-
|
|
553
|
-
return await this.writeConfigFile(
|
|
554
|
-
"drizzle.config.js",
|
|
555
|
-
drizzleConfigJs,
|
|
556
|
-
options.rootDir,
|
|
557
|
-
);
|
|
558
|
-
}
|
|
559
|
-
|
|
560
|
-
public async loadEnvFile(root: string): Promise<void> {
|
|
561
|
-
const envPath = join(root, ".env");
|
|
562
|
-
try {
|
|
563
|
-
const envContent = await readFile(envPath, "utf8");
|
|
564
|
-
const lines = envContent.split("\n");
|
|
565
|
-
for (const line of lines) {
|
|
566
|
-
const [key, ...rest] = line.split("=");
|
|
567
|
-
if (key) {
|
|
568
|
-
const value = rest.join("=");
|
|
569
|
-
process.env[key.trim()] = value.trim();
|
|
570
|
-
}
|
|
571
|
-
}
|
|
572
|
-
this.log.debug(`Loaded environment variables from ${envPath}`);
|
|
573
|
-
} catch {
|
|
574
|
-
this.log.debug(`No .env file found at ${envPath}, skipping load.`);
|
|
575
|
-
}
|
|
576
|
-
}
|
|
577
|
-
|
|
578
|
-
/**
|
|
579
|
-
* Run a drizzle-kit command for all database providers in an Alepha instance.
|
|
580
|
-
*
|
|
581
|
-
* Iterates through all repository providers, prepares Drizzle config for each,
|
|
582
|
-
* and executes the specified drizzle-kit command.
|
|
583
|
-
*
|
|
584
|
-
* @param options - Configuration including command to run, flags, and logging
|
|
585
|
-
*/
|
|
586
|
-
public async runDrizzleKitCommand(options: {
|
|
587
|
-
root: string;
|
|
588
|
-
args?: string;
|
|
589
|
-
command: string;
|
|
590
|
-
commandFlags?: string;
|
|
591
|
-
provider?: string;
|
|
592
|
-
logMessage: (providerName: string, dialect: string) => string;
|
|
593
|
-
}): Promise<void> {
|
|
594
|
-
const rootDir = options.root;
|
|
595
|
-
|
|
596
|
-
await this.loadEnvFile(rootDir);
|
|
597
|
-
|
|
598
|
-
this.log.debug(`Using project root: ${rootDir}`);
|
|
599
|
-
|
|
600
|
-
const { alepha, entry } = await this.loadAlephaFromServerEntryFile(
|
|
601
|
-
rootDir,
|
|
602
|
-
options.args,
|
|
603
|
-
);
|
|
604
|
-
|
|
605
|
-
const drizzleKitProvider =
|
|
606
|
-
alepha.inject<DrizzleKitProvider>("DrizzleKitProvider");
|
|
607
|
-
const repositoryProvider =
|
|
608
|
-
alepha.inject<RepositoryProvider>("RepositoryProvider");
|
|
609
|
-
const accepted = new Set<string>([]);
|
|
610
|
-
|
|
611
|
-
for (const primitive of repositoryProvider.getRepositories()) {
|
|
612
|
-
const provider = primitive.provider;
|
|
613
|
-
const providerName = provider.name;
|
|
614
|
-
const dialect = provider.dialect;
|
|
615
|
-
|
|
616
|
-
if (accepted.has(providerName)) {
|
|
617
|
-
continue;
|
|
618
|
-
}
|
|
619
|
-
accepted.add(providerName);
|
|
620
|
-
|
|
621
|
-
// Skip if provider filter is set and doesn't match
|
|
622
|
-
if (options.provider && options.provider !== providerName) {
|
|
623
|
-
this.log.debug(
|
|
624
|
-
`Skipping provider '${providerName}' (filter: ${options.provider})`,
|
|
625
|
-
);
|
|
626
|
-
continue;
|
|
627
|
-
}
|
|
628
|
-
|
|
629
|
-
this.log.info("");
|
|
630
|
-
this.log.info(options.logMessage(providerName, dialect));
|
|
631
|
-
|
|
632
|
-
const drizzleConfigJsPath = await this.prepareDrizzleConfig({
|
|
633
|
-
kit: drizzleKitProvider,
|
|
634
|
-
provider,
|
|
635
|
-
providerName,
|
|
636
|
-
providerUrl: provider.url,
|
|
637
|
-
dialect,
|
|
638
|
-
entry,
|
|
639
|
-
rootDir,
|
|
640
|
-
});
|
|
641
|
-
|
|
642
|
-
const flags = options.commandFlags ? ` ${options.commandFlags}` : "";
|
|
643
|
-
await this.exec(
|
|
644
|
-
`drizzle-kit ${options.command} --config=${drizzleConfigJsPath}${flags}`,
|
|
645
|
-
{
|
|
646
|
-
env: {
|
|
647
|
-
NODE_OPTIONS: "--import tsx",
|
|
648
|
-
},
|
|
649
|
-
},
|
|
650
|
-
);
|
|
651
|
-
}
|
|
503
|
+
public async loadEnv(
|
|
504
|
+
root: string,
|
|
505
|
+
files: string[] = [".env"],
|
|
506
|
+
): Promise<void> {
|
|
507
|
+
await this.envUtils.loadEnv(root, files);
|
|
652
508
|
}
|
|
653
509
|
|
|
654
510
|
public async getPackageManager(
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { $logger } from "alepha/logger";
|
|
2
|
+
import {
|
|
3
|
+
type ChangelogOptions,
|
|
4
|
+
DEFAULT_IGNORE,
|
|
5
|
+
} from "../atoms/changelogOptions.ts";
|
|
6
|
+
import type { Commit } from "../commands/ChangelogCommands.ts";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Service for parsing git commit messages into structured format.
|
|
10
|
+
*
|
|
11
|
+
* Only parses **conventional commits with a scope**:
|
|
12
|
+
* - `feat(scope): description` → feature
|
|
13
|
+
* - `fix(scope): description` → bug fix
|
|
14
|
+
* - `feat(scope)!: description` → breaking change
|
|
15
|
+
*
|
|
16
|
+
* Commits without scope are ignored, allowing developers to commit
|
|
17
|
+
* work-in-progress changes without polluting release notes:
|
|
18
|
+
* - `cli: work in progress` → ignored (no type)
|
|
19
|
+
* - `fix: quick patch` → ignored (no scope)
|
|
20
|
+
* - `feat(cli): add command` → included
|
|
21
|
+
*/
|
|
22
|
+
export class GitMessageParser {
|
|
23
|
+
protected readonly log = $logger();
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Parse a git commit line into a structured Commit object.
|
|
27
|
+
*
|
|
28
|
+
* **Format:** `type(scope): description` or `type(scope)!: description`
|
|
29
|
+
*
|
|
30
|
+
* **Supported types:** feat, fix, docs, refactor, perf, revert
|
|
31
|
+
*
|
|
32
|
+
* **Breaking changes:** Use `!` before `:` (e.g., `feat(api)!: remove endpoint`)
|
|
33
|
+
*
|
|
34
|
+
* @returns Commit object or null if not matching/ignored
|
|
35
|
+
*/
|
|
36
|
+
parseCommit(line: string, config: ChangelogOptions): Commit | null {
|
|
37
|
+
// Extract hash and message from git log --oneline format
|
|
38
|
+
const match = line.match(/^([a-f0-9]+)\s+(.+)$/);
|
|
39
|
+
if (!match) return null;
|
|
40
|
+
|
|
41
|
+
const [, hash, message] = match;
|
|
42
|
+
const ignore = config.ignore ?? DEFAULT_IGNORE;
|
|
43
|
+
|
|
44
|
+
// Conventional commit with REQUIRED scope: type(scope): description
|
|
45
|
+
// The `!` before `:` marks a breaking change
|
|
46
|
+
const conventionalMatch = message.match(
|
|
47
|
+
/^(feat|fix|docs|refactor|perf|revert)\(([^)]+)\)(!)?:\s*(.+)$/i,
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
if (!conventionalMatch) {
|
|
51
|
+
// No match - commit doesn't follow required format
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const [, type, scope, breakingMark, description] = conventionalMatch;
|
|
56
|
+
|
|
57
|
+
// Check if scope should be ignored
|
|
58
|
+
const baseScope = scope.split("/")[0];
|
|
59
|
+
if (ignore.includes(baseScope) || ignore.includes(scope)) {
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Breaking change detection:
|
|
64
|
+
// 1. Explicit `!` marker: feat(api)!: change
|
|
65
|
+
// 2. Word "breaking" in description: feat(api): breaking change to auth
|
|
66
|
+
const breaking =
|
|
67
|
+
breakingMark === "!" || description.toLowerCase().includes("breaking");
|
|
68
|
+
|
|
69
|
+
return {
|
|
70
|
+
hash: hash.substring(0, 8),
|
|
71
|
+
type: type.toLowerCase(),
|
|
72
|
+
scope,
|
|
73
|
+
description: description.trim(),
|
|
74
|
+
breaking,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { $logger } from "alepha/logger";
|
|
4
|
+
|
|
5
|
+
export class EnvUtils {
|
|
6
|
+
protected readonly log = $logger();
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Load environment variables from .env files into process.env.
|
|
10
|
+
* By default, it loads from ".env" and ".env.local".
|
|
11
|
+
* You can specify additional files to load, e.g. [".env", ".env.production"].
|
|
12
|
+
*/
|
|
13
|
+
public async loadEnv(
|
|
14
|
+
root: string,
|
|
15
|
+
files: string[] = [".env"],
|
|
16
|
+
): Promise<void> {
|
|
17
|
+
for (const it of files) {
|
|
18
|
+
for (const file of [it, `${it}.local`]) {
|
|
19
|
+
const envPath = join(root, file);
|
|
20
|
+
try {
|
|
21
|
+
const envContent = await readFile(envPath, "utf8");
|
|
22
|
+
const lines = envContent.split("\n");
|
|
23
|
+
for (const line of lines) {
|
|
24
|
+
const [key, ...rest] = line.split("=");
|
|
25
|
+
if (key) {
|
|
26
|
+
const value = rest.join("=");
|
|
27
|
+
process.env[key.trim()] = value.trim();
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
this.log.debug(`Loaded environment variables from ${envPath}`);
|
|
31
|
+
} catch {
|
|
32
|
+
this.log.debug(`No ${file} file found at ${envPath}, skipping load.`);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
package/src/command/index.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { $module } from "alepha";
|
|
2
2
|
import { Asker } from "./helpers/Asker.ts";
|
|
3
|
+
import { EnvUtils } from "./helpers/EnvUtils.ts";
|
|
3
4
|
import { PrettyPrint } from "./helpers/PrettyPrint.ts";
|
|
4
5
|
import { Runner } from "./helpers/Runner.ts";
|
|
5
6
|
import { $command } from "./primitives/$command.ts";
|
|
@@ -9,6 +10,7 @@ import { CliProvider } from "./providers/CliProvider.ts";
|
|
|
9
10
|
|
|
10
11
|
export * from "./errors/CommandError.ts";
|
|
11
12
|
export * from "./helpers/Asker.ts";
|
|
13
|
+
export * from "./helpers/EnvUtils.ts";
|
|
12
14
|
export * from "./helpers/PrettyPrint.ts";
|
|
13
15
|
export * from "./helpers/Runner.ts";
|
|
14
16
|
export * from "./primitives/$command.ts";
|
|
@@ -28,7 +30,7 @@ export * from "./providers/CliProvider.ts";
|
|
|
28
30
|
export const AlephaCommand = $module({
|
|
29
31
|
name: "alepha.command",
|
|
30
32
|
primitives: [$command],
|
|
31
|
-
services: [CliProvider, Runner, Asker, PrettyPrint],
|
|
33
|
+
services: [CliProvider, Runner, Asker, PrettyPrint, EnvUtils],
|
|
32
34
|
});
|
|
33
35
|
|
|
34
36
|
// ---------------------------------------------------------------------------------------------------------------------
|
|
@@ -19,17 +19,29 @@ import type { RunnerMethod } from "../helpers/Runner.ts";
|
|
|
19
19
|
* This primitive allows you to define a command, its flags, and its handler
|
|
20
20
|
* within your Alepha application structure.
|
|
21
21
|
*/
|
|
22
|
-
export const $command = <
|
|
23
|
-
|
|
24
|
-
|
|
22
|
+
export const $command = <
|
|
23
|
+
T extends TObject,
|
|
24
|
+
A extends TSchema,
|
|
25
|
+
E extends TObject,
|
|
26
|
+
>(
|
|
27
|
+
options: CommandPrimitiveOptions<T, A, E>,
|
|
28
|
+
) => createPrimitive(CommandPrimitive<T, A, E>, options);
|
|
25
29
|
|
|
26
30
|
// ---------------------------------------------------------------------------------------------------------------------
|
|
27
31
|
|
|
28
|
-
export interface CommandPrimitiveOptions<
|
|
32
|
+
export interface CommandPrimitiveOptions<
|
|
33
|
+
T extends TObject,
|
|
34
|
+
A extends TSchema,
|
|
35
|
+
E extends TObject = TObject,
|
|
36
|
+
> {
|
|
29
37
|
/**
|
|
30
38
|
* The handler function to execute when the command is matched.
|
|
39
|
+
*
|
|
40
|
+
* For parent commands with children, the handler is called when:
|
|
41
|
+
* - The parent command is invoked without a subcommand
|
|
42
|
+
* - The parent command is invoked with --help (to show available subcommands)
|
|
31
43
|
*/
|
|
32
|
-
handler: (args: CommandHandlerArgs<T, A>) => Async<void>;
|
|
44
|
+
handler: (args: CommandHandlerArgs<T, A, E>) => Async<void>;
|
|
33
45
|
|
|
34
46
|
/**
|
|
35
47
|
* The name of the command. If omitted, the property key is used.
|
|
@@ -53,6 +65,28 @@ export interface CommandPrimitiveOptions<T extends TObject, A extends TSchema> {
|
|
|
53
65
|
*/
|
|
54
66
|
flags?: T;
|
|
55
67
|
|
|
68
|
+
/**
|
|
69
|
+
* A TypeBox object schema defining required environment variables.
|
|
70
|
+
*
|
|
71
|
+
* Environment variables are validated before the handler runs (fail fast).
|
|
72
|
+
* They are displayed in the help output under "Env:" section.
|
|
73
|
+
*
|
|
74
|
+
* @example
|
|
75
|
+
* ```ts
|
|
76
|
+
* $command({
|
|
77
|
+
* env: t.object({
|
|
78
|
+
* VERCEL_TOKEN: t.text({ description: "Vercel API token" }),
|
|
79
|
+
* VERCEL_ORG_ID: t.optional(t.text({ description: "Organization ID" })),
|
|
80
|
+
* }),
|
|
81
|
+
* handler: async ({ env }) => {
|
|
82
|
+
* // env.VERCEL_TOKEN is typed & guaranteed to exist
|
|
83
|
+
* console.log(env.VERCEL_TOKEN);
|
|
84
|
+
* }
|
|
85
|
+
* })
|
|
86
|
+
* ```
|
|
87
|
+
*/
|
|
88
|
+
env?: E;
|
|
89
|
+
|
|
56
90
|
/**
|
|
57
91
|
* An optional TypeBox schema defining the arguments for the command.
|
|
58
92
|
*
|
|
@@ -137,6 +171,86 @@ export interface CommandPrimitiveOptions<T extends TObject, A extends TSchema> {
|
|
|
137
171
|
* If true, this command will be hidden from the help output.
|
|
138
172
|
*/
|
|
139
173
|
hide?: boolean;
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Adds a `--mode, -m` flag to load environment files.
|
|
177
|
+
*
|
|
178
|
+
* When enabled:
|
|
179
|
+
* - Loads `.env` and `.env.local` by default
|
|
180
|
+
* - With `--mode production`, also loads `.env.production` and `.env.production.local`
|
|
181
|
+
* - The mode value is exposed in the handler as `mode: string | undefined`
|
|
182
|
+
*
|
|
183
|
+
* Set to `true` to enable with no default, or a string to set a default mode.
|
|
184
|
+
*
|
|
185
|
+
* This follows Vite's environment loading convention.
|
|
186
|
+
* @see https://vite.dev/guide/env-and-mode
|
|
187
|
+
*
|
|
188
|
+
* @example
|
|
189
|
+
* ```ts
|
|
190
|
+
* // No default mode
|
|
191
|
+
* build = $command({
|
|
192
|
+
* mode: true,
|
|
193
|
+
* handler: async ({ mode }) => {
|
|
194
|
+
* console.log(`Building for ${mode ?? 'development'}...`);
|
|
195
|
+
* }
|
|
196
|
+
* });
|
|
197
|
+
*
|
|
198
|
+
* // Default mode "production"
|
|
199
|
+
* deploy = $command({
|
|
200
|
+
* mode: "production",
|
|
201
|
+
* handler: async ({ mode }) => {
|
|
202
|
+
* console.log(`Deploying for ${mode}...`); // always defined
|
|
203
|
+
* }
|
|
204
|
+
* });
|
|
205
|
+
* ```
|
|
206
|
+
*
|
|
207
|
+
* Usage:
|
|
208
|
+
* - `cli build` - loads .env (mode = undefined)
|
|
209
|
+
* - `cli build --mode production` - loads .env and .env.production
|
|
210
|
+
* - `cli deploy` - loads .env and .env.production (default mode)
|
|
211
|
+
* - `cli deploy --mode staging` - loads .env and .env.staging
|
|
212
|
+
*/
|
|
213
|
+
mode?: boolean | string;
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Child commands (subcommands) for this command.
|
|
217
|
+
*
|
|
218
|
+
* When children are defined, the command becomes a parent command that
|
|
219
|
+
* can be invoked with space-separated subcommands:
|
|
220
|
+
*
|
|
221
|
+
* @example
|
|
222
|
+
* ```ts
|
|
223
|
+
* class DeployCommands {
|
|
224
|
+
* // Subcommands
|
|
225
|
+
* vercel = $command({
|
|
226
|
+
* description: "Deploy to Vercel",
|
|
227
|
+
* handler: async () => { ... }
|
|
228
|
+
* });
|
|
229
|
+
*
|
|
230
|
+
* cloudflare = $command({
|
|
231
|
+
* description: "Deploy to Cloudflare",
|
|
232
|
+
* handler: async () => { ... }
|
|
233
|
+
* });
|
|
234
|
+
*
|
|
235
|
+
* // Parent command with children
|
|
236
|
+
* deploy = $command({
|
|
237
|
+
* description: "Deploy the application",
|
|
238
|
+
* children: [this.vercel, this.cloudflare],
|
|
239
|
+
* handler: async () => {
|
|
240
|
+
* // Called when "deploy" is invoked without subcommand
|
|
241
|
+
* console.log("Available: deploy vercel, deploy cloudflare");
|
|
242
|
+
* }
|
|
243
|
+
* });
|
|
244
|
+
* }
|
|
245
|
+
* ```
|
|
246
|
+
*
|
|
247
|
+
* This allows CLI usage like:
|
|
248
|
+
* - `cli deploy vercel` - runs the vercel subcommand
|
|
249
|
+
* - `cli deploy cloudflare` - runs the cloudflare subcommand
|
|
250
|
+
* - `cli deploy` - runs the parent handler (shows available subcommands)
|
|
251
|
+
* - `cli deploy --help` - shows help with all available subcommands
|
|
252
|
+
*/
|
|
253
|
+
children?: CommandPrimitive<any, any>[];
|
|
140
254
|
}
|
|
141
255
|
|
|
142
256
|
// ---------------------------------------------------------------------------------------------------------------------
|
|
@@ -144,8 +258,10 @@ export interface CommandPrimitiveOptions<T extends TObject, A extends TSchema> {
|
|
|
144
258
|
export class CommandPrimitive<
|
|
145
259
|
T extends TObject = TObject,
|
|
146
260
|
A extends TSchema = TSchema,
|
|
147
|
-
|
|
261
|
+
E extends TObject = TObject,
|
|
262
|
+
> extends Primitive<CommandPrimitiveOptions<T, A, E>> {
|
|
148
263
|
public readonly flags = this.options.flags ?? t.object({});
|
|
264
|
+
public readonly env = this.options.env ?? t.object({});
|
|
149
265
|
public readonly aliases = this.options.aliases ?? [];
|
|
150
266
|
|
|
151
267
|
protected onInit() {
|
|
@@ -166,6 +282,29 @@ export class CommandPrimitive<
|
|
|
166
282
|
}
|
|
167
283
|
return this.options.name ?? `${this.config.propertyKey}`;
|
|
168
284
|
}
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* Get the child commands (subcommands) for this command.
|
|
288
|
+
*/
|
|
289
|
+
public get children(): CommandPrimitive<any, any>[] {
|
|
290
|
+
return this.options.children ?? [];
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
/**
|
|
294
|
+
* Check if this command has child commands (is a parent command).
|
|
295
|
+
*/
|
|
296
|
+
public get hasChildren(): boolean {
|
|
297
|
+
return this.children.length > 0;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/**
|
|
301
|
+
* Find a child command by name or alias.
|
|
302
|
+
*/
|
|
303
|
+
public findChild(name: string): CommandPrimitive<any, any> | undefined {
|
|
304
|
+
return this.children.find(
|
|
305
|
+
(child) => child.name === name || child.aliases.includes(name),
|
|
306
|
+
);
|
|
307
|
+
}
|
|
169
308
|
}
|
|
170
309
|
|
|
171
310
|
$command[KIND] = CommandPrimitive;
|
|
@@ -175,9 +314,11 @@ $command[KIND] = CommandPrimitive;
|
|
|
175
314
|
export interface CommandHandlerArgs<
|
|
176
315
|
T extends TObject,
|
|
177
316
|
A extends TSchema = TSchema,
|
|
317
|
+
E extends TObject = TObject,
|
|
178
318
|
> {
|
|
179
319
|
flags: Static<T>;
|
|
180
320
|
args: A extends TSchema ? Static<A> : Array<string>;
|
|
321
|
+
env: Static<E>;
|
|
181
322
|
run: RunnerMethod;
|
|
182
323
|
ask: AskMethod;
|
|
183
324
|
glob: typeof glob;
|
|
@@ -187,4 +328,29 @@ export interface CommandHandlerArgs<
|
|
|
187
328
|
* The root directory where the command is executed.
|
|
188
329
|
*/
|
|
189
330
|
root: string;
|
|
331
|
+
|
|
332
|
+
/**
|
|
333
|
+
* Display help for the current command.
|
|
334
|
+
*
|
|
335
|
+
* Useful for parent commands with children to show available subcommands
|
|
336
|
+
* when invoked without a specific subcommand.
|
|
337
|
+
*
|
|
338
|
+
* @example
|
|
339
|
+
* ```ts
|
|
340
|
+
* deploy = $command({
|
|
341
|
+
* children: [this.vercel, this.cloudflare],
|
|
342
|
+
* handler: async ({ help }) => {
|
|
343
|
+
* help(); // Shows available subcommands
|
|
344
|
+
* }
|
|
345
|
+
* });
|
|
346
|
+
* ```
|
|
347
|
+
*/
|
|
348
|
+
help: () => void;
|
|
349
|
+
|
|
350
|
+
/**
|
|
351
|
+
* The current execution mode (e.g., "development", "production", "staging").
|
|
352
|
+
*
|
|
353
|
+
* Use --mode flag to set this value when running the command.
|
|
354
|
+
*/
|
|
355
|
+
mode?: string;
|
|
190
356
|
}
|