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,7 +2,9 @@ import { join } from "node:path";
|
|
|
2
2
|
import { $hook, $inject, $module, Alepha } from "alepha";
|
|
3
3
|
import { FileSystemProvider } from "alepha/file";
|
|
4
4
|
import { BiomeCommands } from "../commands/BiomeCommands.ts";
|
|
5
|
+
import { ChangelogCommands } from "../commands/ChangelogCommands.ts";
|
|
5
6
|
import { CoreCommands } from "../commands/CoreCommands.ts";
|
|
7
|
+
import { DeployCommands } from "../commands/DeployCommands.ts";
|
|
6
8
|
import { DrizzleCommands } from "../commands/DrizzleCommands.ts";
|
|
7
9
|
import { VerifyCommands } from "../commands/VerifyCommands.ts";
|
|
8
10
|
import { ViteCommands } from "../commands/ViteCommands.ts";
|
|
@@ -14,7 +16,8 @@ class AlephaCliExtension {
|
|
|
14
16
|
protected readonly onConfigure = $hook({
|
|
15
17
|
on: "configure",
|
|
16
18
|
handler: async () => {
|
|
17
|
-
const
|
|
19
|
+
const root = process.cwd();
|
|
20
|
+
const extensionPath = join(root, "alepha.config.ts");
|
|
18
21
|
const hasExtension = await this.fs.exists(extensionPath);
|
|
19
22
|
if (!hasExtension) {
|
|
20
23
|
return;
|
|
@@ -26,7 +29,9 @@ class AlephaCliExtension {
|
|
|
26
29
|
return;
|
|
27
30
|
}
|
|
28
31
|
|
|
29
|
-
this.alepha.
|
|
32
|
+
this.alepha.inject(Extension, {
|
|
33
|
+
args: [this.alepha],
|
|
34
|
+
});
|
|
30
35
|
},
|
|
31
36
|
});
|
|
32
37
|
}
|
|
@@ -35,10 +40,12 @@ export const AlephaCli = $module({
|
|
|
35
40
|
name: "alepha.cli",
|
|
36
41
|
services: [
|
|
37
42
|
AlephaCliExtension,
|
|
43
|
+
BiomeCommands,
|
|
44
|
+
ChangelogCommands,
|
|
38
45
|
CoreCommands,
|
|
46
|
+
DeployCommands,
|
|
39
47
|
DrizzleCommands,
|
|
40
48
|
VerifyCommands,
|
|
41
49
|
ViteCommands,
|
|
42
|
-
BiomeCommands,
|
|
43
50
|
],
|
|
44
51
|
});
|
|
@@ -79,14 +79,17 @@ export class AlephaPackageBuilderCli {
|
|
|
79
79
|
JSON.stringify(modules, null, 2),
|
|
80
80
|
);
|
|
81
81
|
|
|
82
|
-
const
|
|
83
|
-
"
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
),
|
|
89
|
-
|
|
82
|
+
const tsconfig = await readFile(
|
|
83
|
+
join(root, "../../tsconfig.json"),
|
|
84
|
+
"utf-8",
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
const external: string[] = Object.keys(
|
|
88
|
+
JSON.parse(tsconfig).compilerOptions.paths,
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
external.push("bun");
|
|
92
|
+
external.push("bun:sqlite");
|
|
90
93
|
|
|
91
94
|
await run.rm(this.dist);
|
|
92
95
|
|
|
@@ -103,6 +106,10 @@ export class AlephaPackageBuilderCli {
|
|
|
103
106
|
fixedExtension: false,
|
|
104
107
|
platform: "node", // TODO: node must be enabled only if index.node.ts exists
|
|
105
108
|
external,
|
|
109
|
+
dts: {
|
|
110
|
+
sourcemap: true,
|
|
111
|
+
resolve: false,
|
|
112
|
+
},
|
|
106
113
|
});
|
|
107
114
|
|
|
108
115
|
if (item.native) {
|
package/src/cli/assets/mainTs.ts
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
export const mainTs = () => `
|
|
2
|
-
import {
|
|
3
|
-
import { $
|
|
2
|
+
import { run } from "alepha";
|
|
3
|
+
import { $route } from "alepha/server";
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
class App {
|
|
6
|
+
root = $route({
|
|
7
|
+
path: "/",
|
|
8
|
+
handler: () => "Hello, Alepha!",
|
|
9
|
+
});
|
|
10
|
+
}
|
|
6
11
|
|
|
7
|
-
|
|
8
|
-
const log = $logger();
|
|
9
|
-
|
|
10
|
-
log.info("Hello from Alepha!");
|
|
11
|
-
});
|
|
12
|
-
|
|
13
|
-
run(alepha);
|
|
12
|
+
run(App);
|
|
14
13
|
`.trim();
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { $atom, type Static, t } from "alepha";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Default scopes to ignore in changelog generation.
|
|
5
|
+
* Commits with these scopes won't appear in release notes.
|
|
6
|
+
*/
|
|
7
|
+
export const DEFAULT_IGNORE = [
|
|
8
|
+
"project",
|
|
9
|
+
"release",
|
|
10
|
+
"starter",
|
|
11
|
+
"example",
|
|
12
|
+
"chore",
|
|
13
|
+
"ci",
|
|
14
|
+
"build",
|
|
15
|
+
"test",
|
|
16
|
+
"style",
|
|
17
|
+
];
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Changelog configuration atom.
|
|
21
|
+
*
|
|
22
|
+
* Configure in `alepha.config.ts`:
|
|
23
|
+
* ```ts
|
|
24
|
+
* import { changelogOptions } from "alepha/cli";
|
|
25
|
+
*
|
|
26
|
+
* alepha.set(changelogOptions, {
|
|
27
|
+
* ignore: ["project", "release", "chore", "docs"],
|
|
28
|
+
* });
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
export const changelogOptions = $atom({
|
|
32
|
+
name: "alepha.changelog",
|
|
33
|
+
schema: t.object({
|
|
34
|
+
/**
|
|
35
|
+
* Scopes to ignore (e.g., "project", "release", "chore").
|
|
36
|
+
* Commits like `feat(chore): ...` will be excluded from changelog.
|
|
37
|
+
*/
|
|
38
|
+
ignore: t.optional(t.array(t.string())),
|
|
39
|
+
}),
|
|
40
|
+
default: {
|
|
41
|
+
ignore: DEFAULT_IGNORE,
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
export type ChangelogOptions = Static<typeof changelogOptions.schema>;
|
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
import { exec } from "node:child_process";
|
|
2
|
+
import { promisify } from "node:util";
|
|
3
|
+
import { $inject, $use, t } from "alepha";
|
|
4
|
+
import { $command } from "alepha/command";
|
|
5
|
+
import { $logger } from "alepha/logger";
|
|
6
|
+
import { changelogOptions } from "../atoms/changelogOptions.ts";
|
|
7
|
+
import { GitMessageParser } from "../services/GitMessageParser.ts";
|
|
8
|
+
|
|
9
|
+
export {
|
|
10
|
+
type ChangelogOptions,
|
|
11
|
+
changelogOptions,
|
|
12
|
+
DEFAULT_IGNORE,
|
|
13
|
+
} from "../atoms/changelogOptions.ts";
|
|
14
|
+
export { GitMessageParser } from "../services/GitMessageParser.ts";
|
|
15
|
+
|
|
16
|
+
const execAsync = promisify(exec);
|
|
17
|
+
|
|
18
|
+
// =============================================================================
|
|
19
|
+
// GIT PROVIDER
|
|
20
|
+
// =============================================================================
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Git provider for executing git commands.
|
|
24
|
+
* Can be substituted in tests with a mock implementation.
|
|
25
|
+
*/
|
|
26
|
+
export class GitProvider {
|
|
27
|
+
async exec(cmd: string, cwd: string): Promise<string> {
|
|
28
|
+
const { stdout } = await execAsync(`git ${cmd}`, { cwd });
|
|
29
|
+
return stdout;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// =============================================================================
|
|
34
|
+
// TYPES
|
|
35
|
+
// =============================================================================
|
|
36
|
+
|
|
37
|
+
export interface Commit {
|
|
38
|
+
hash: string;
|
|
39
|
+
type: string;
|
|
40
|
+
scope: string | null;
|
|
41
|
+
description: string;
|
|
42
|
+
breaking: boolean;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
interface ChangelogEntry {
|
|
46
|
+
features: Commit[];
|
|
47
|
+
fixes: Commit[];
|
|
48
|
+
breaking: Commit[];
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// =============================================================================
|
|
52
|
+
// CHANGELOG COMMANDS
|
|
53
|
+
// =============================================================================
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Changelog command for generating release notes from git commits.
|
|
57
|
+
*
|
|
58
|
+
* Usage:
|
|
59
|
+
* - `alepha changelog` - Show unreleased changes since latest tag to HEAD
|
|
60
|
+
* - `alepha changelog --from=1.0.0` - Show changes from version to HEAD
|
|
61
|
+
* - `alepha changelog --from=1.0.0 --to=1.1.0` - Show changes between two refs
|
|
62
|
+
* - `alepha changelog | tee -a CHANGELOG.md` - Append to file
|
|
63
|
+
*/
|
|
64
|
+
export class ChangelogCommands {
|
|
65
|
+
protected readonly log = $logger();
|
|
66
|
+
protected readonly git = $inject(GitProvider);
|
|
67
|
+
protected readonly parser = $inject(GitMessageParser);
|
|
68
|
+
protected readonly config = $use(changelogOptions);
|
|
69
|
+
|
|
70
|
+
// ---------------------------------------------------------------------------
|
|
71
|
+
// FORMATTING
|
|
72
|
+
// ---------------------------------------------------------------------------
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Format a single commit line.
|
|
76
|
+
* Example: `- **cli**: add new command (\`abc1234\`)`
|
|
77
|
+
*/
|
|
78
|
+
protected formatCommit(commit: Commit): string {
|
|
79
|
+
return `- **${commit.scope}**: ${commit.description} (\`${commit.hash}\`)`;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Format the changelog entry with sections.
|
|
84
|
+
*/
|
|
85
|
+
protected formatEntry(entry: ChangelogEntry): string {
|
|
86
|
+
const sections: string[] = [];
|
|
87
|
+
|
|
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
|
+
if (entry.features.length > 0) {
|
|
97
|
+
sections.push("### Features\n");
|
|
98
|
+
for (const commit of entry.features) {
|
|
99
|
+
sections.push(this.formatCommit(commit));
|
|
100
|
+
}
|
|
101
|
+
sections.push("");
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if (entry.fixes.length > 0) {
|
|
105
|
+
sections.push("### Bug Fixes\n");
|
|
106
|
+
for (const commit of entry.fixes) {
|
|
107
|
+
sections.push(this.formatCommit(commit));
|
|
108
|
+
}
|
|
109
|
+
sections.push("");
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return sections.join("\n");
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// ---------------------------------------------------------------------------
|
|
116
|
+
// PARSING
|
|
117
|
+
// ---------------------------------------------------------------------------
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Parse git log output into a changelog entry.
|
|
121
|
+
*/
|
|
122
|
+
protected parseCommits(commitsOutput: string): ChangelogEntry {
|
|
123
|
+
const entry: ChangelogEntry = {
|
|
124
|
+
features: [],
|
|
125
|
+
fixes: [],
|
|
126
|
+
breaking: [],
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
for (const line of commitsOutput.trim().split("\n")) {
|
|
130
|
+
if (!line.trim()) continue;
|
|
131
|
+
|
|
132
|
+
const commit = this.parser.parseCommit(line, this.config);
|
|
133
|
+
if (!commit) {
|
|
134
|
+
this.log.trace("Skipping commit", { line });
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
this.log.trace("Parsed commit", { commit });
|
|
139
|
+
|
|
140
|
+
// Categorize commit
|
|
141
|
+
if (commit.breaking) {
|
|
142
|
+
entry.breaking.push(commit);
|
|
143
|
+
}
|
|
144
|
+
if (commit.type === "feat") {
|
|
145
|
+
entry.features.push(commit);
|
|
146
|
+
} else if (commit.type === "fix") {
|
|
147
|
+
entry.fixes.push(commit);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
return entry;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Check if entry has any public commits.
|
|
156
|
+
*/
|
|
157
|
+
protected hasChanges(entry: ChangelogEntry): boolean {
|
|
158
|
+
return (
|
|
159
|
+
entry.features.length > 0 ||
|
|
160
|
+
entry.fixes.length > 0 ||
|
|
161
|
+
entry.breaking.length > 0
|
|
162
|
+
);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Get the latest version tag.
|
|
167
|
+
*/
|
|
168
|
+
protected async getLatestTag(
|
|
169
|
+
git: (cmd: string) => Promise<string>,
|
|
170
|
+
): Promise<string | null> {
|
|
171
|
+
const tagsOutput = await git("tag --sort=-version:refname");
|
|
172
|
+
const tags = tagsOutput
|
|
173
|
+
.trim()
|
|
174
|
+
.split("\n")
|
|
175
|
+
.filter((tag) => tag.match(/^\d+\.\d+\.\d+$/));
|
|
176
|
+
|
|
177
|
+
return tags[0] || null;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// ---------------------------------------------------------------------------
|
|
181
|
+
// COMMAND
|
|
182
|
+
// ---------------------------------------------------------------------------
|
|
183
|
+
|
|
184
|
+
public readonly changelog = $command({
|
|
185
|
+
name: "changelog",
|
|
186
|
+
description:
|
|
187
|
+
"Generate changelog from conventional commits (outputs to stdout)",
|
|
188
|
+
flags: t.object({
|
|
189
|
+
/**
|
|
190
|
+
* Show changes from this ref (tag, commit, branch).
|
|
191
|
+
* Defaults to the latest version tag.
|
|
192
|
+
* Example: --from=1.0.0
|
|
193
|
+
*/
|
|
194
|
+
from: t.optional(
|
|
195
|
+
t.string({
|
|
196
|
+
aliases: ["f"],
|
|
197
|
+
description: "Starting ref (default: latest tag)",
|
|
198
|
+
}),
|
|
199
|
+
),
|
|
200
|
+
/**
|
|
201
|
+
* Show changes up to this ref (tag, commit, branch).
|
|
202
|
+
* Defaults to HEAD.
|
|
203
|
+
* Example: --to=main
|
|
204
|
+
*/
|
|
205
|
+
to: t.optional(
|
|
206
|
+
t.string({
|
|
207
|
+
aliases: ["t"],
|
|
208
|
+
description: "Ending ref (default: HEAD)",
|
|
209
|
+
}),
|
|
210
|
+
),
|
|
211
|
+
}),
|
|
212
|
+
handler: async ({ flags, root }) => {
|
|
213
|
+
const git = (cmd: string) => this.git.exec(cmd, root);
|
|
214
|
+
|
|
215
|
+
// Determine the starting point
|
|
216
|
+
let fromRef: string;
|
|
217
|
+
|
|
218
|
+
if (flags.from) {
|
|
219
|
+
// User specified a ref
|
|
220
|
+
fromRef = flags.from;
|
|
221
|
+
this.log.debug("Using specified from ref", { from: fromRef });
|
|
222
|
+
} else {
|
|
223
|
+
// Use latest tag
|
|
224
|
+
const latestTag = await this.getLatestTag(git);
|
|
225
|
+
if (!latestTag) {
|
|
226
|
+
process.stdout.write("No version tags found in repository\n");
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
fromRef = latestTag;
|
|
230
|
+
this.log.debug("Using latest tag", { from: fromRef });
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
// Determine the ending point
|
|
234
|
+
const toRef = flags.to || "HEAD";
|
|
235
|
+
this.log.debug("Using to ref", { to: toRef });
|
|
236
|
+
|
|
237
|
+
// Get commits in range
|
|
238
|
+
const commitsOutput = await git(`log ${fromRef}..${toRef} --oneline`);
|
|
239
|
+
|
|
240
|
+
if (!commitsOutput.trim()) {
|
|
241
|
+
process.stdout.write(`No changes in range ${fromRef}..${toRef}\n`);
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
// Parse and format
|
|
246
|
+
const entry = this.parseCommits(commitsOutput);
|
|
247
|
+
|
|
248
|
+
if (!this.hasChanges(entry)) {
|
|
249
|
+
process.stdout.write(
|
|
250
|
+
`No public changes in range ${fromRef}..${toRef}\n`,
|
|
251
|
+
);
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// Output the formatted changelog (no header - caller adds it if needed)
|
|
256
|
+
process.stdout.write(this.formatEntry(entry));
|
|
257
|
+
},
|
|
258
|
+
});
|
|
259
|
+
}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { join } from "node:path";
|
|
2
|
+
import { $inject, AlephaError, t } from "alepha";
|
|
3
|
+
import { $command } from "alepha/command";
|
|
4
|
+
import { $logger } from "alepha/logger";
|
|
5
|
+
import { AlephaCliUtils } from "../services/AlephaCliUtils.ts";
|
|
6
|
+
|
|
7
|
+
export class DeployCommands {
|
|
8
|
+
protected readonly log = $logger();
|
|
9
|
+
protected readonly utils = $inject(AlephaCliUtils);
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Deploy the project to a hosting platform (e.g., Vercel, Cloudflare, Surge)
|
|
13
|
+
*
|
|
14
|
+
* Deploy command can be overridden by creating a alepha.config.ts in the project root:
|
|
15
|
+
*
|
|
16
|
+
* ```ts
|
|
17
|
+
* import { defineConfig } from "alepha/cli";
|
|
18
|
+
*
|
|
19
|
+
* export default defineConfig({
|
|
20
|
+
* commands: {
|
|
21
|
+
* deploy: {
|
|
22
|
+
* handler: async ({ root, mode, flags }) => {
|
|
23
|
+
* // Custom deployment logic here
|
|
24
|
+
* },
|
|
25
|
+
* },
|
|
26
|
+
* },
|
|
27
|
+
* });
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
public readonly deploy = $command({
|
|
31
|
+
name: "deploy",
|
|
32
|
+
description:
|
|
33
|
+
"Deploy the project to a hosting platform (e.g., Vercel, Cloudflare, Surge)",
|
|
34
|
+
mode: true,
|
|
35
|
+
flags: t.object({
|
|
36
|
+
build: t.boolean({
|
|
37
|
+
description: "Build the project before deployment",
|
|
38
|
+
default: false,
|
|
39
|
+
}),
|
|
40
|
+
migrate: t.boolean({
|
|
41
|
+
description:
|
|
42
|
+
"Run database migrations before deployment (if applicable)",
|
|
43
|
+
default: false,
|
|
44
|
+
}),
|
|
45
|
+
}),
|
|
46
|
+
env: t.object({
|
|
47
|
+
VERCEL_TOKEN: t.optional(
|
|
48
|
+
t.text({
|
|
49
|
+
description: "Vercel API token (e.g., xxxxxxxxxxxxxxxxxxxx)",
|
|
50
|
+
}),
|
|
51
|
+
),
|
|
52
|
+
VERCEL_ORG_ID: t.optional(
|
|
53
|
+
t.text({
|
|
54
|
+
description: "Vercel organization ID (e.g., team_abc123...)",
|
|
55
|
+
}),
|
|
56
|
+
),
|
|
57
|
+
VERCEL_PROJECT_ID: t.optional(
|
|
58
|
+
t.text({ description: "Vercel project ID (e.g., prj_abc123...)" }),
|
|
59
|
+
),
|
|
60
|
+
CLOUDFLARE_API_TOKEN: t.optional(
|
|
61
|
+
t.text({
|
|
62
|
+
description: "Cloudflare API token (e.g., xxxx-xxxx-xxxx-xxxx)",
|
|
63
|
+
}),
|
|
64
|
+
),
|
|
65
|
+
CLOUDFLARE_ACCOUNT_ID: t.optional(
|
|
66
|
+
t.text({
|
|
67
|
+
description: "Cloudflare account ID (e.g., abc123def456...)",
|
|
68
|
+
}),
|
|
69
|
+
),
|
|
70
|
+
}),
|
|
71
|
+
handler: async ({ root, mode, flags }) => {
|
|
72
|
+
if (flags.build) {
|
|
73
|
+
await this.utils.exec("alepha build");
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Vercel deployment
|
|
77
|
+
if (await this.utils.exists(root, "dist/vercel.json")) {
|
|
78
|
+
if (flags.migrate) {
|
|
79
|
+
this.log.debug("Running database migrations before deployment...");
|
|
80
|
+
await this.utils.exec(`alepha db migrate --mode=${mode}`);
|
|
81
|
+
}
|
|
82
|
+
await this.utils.ensureDependency(root, "vercel", { dev: true });
|
|
83
|
+
const command =
|
|
84
|
+
`vercel . --cwd=dist ${mode === "production" ? "--prod" : ""}`.trim();
|
|
85
|
+
this.log.debug(`Deploying to Vercel with command: ${command}`);
|
|
86
|
+
await this.utils.exec(command);
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Cloudflare deployment
|
|
91
|
+
if (await this.utils.exists(root, "dist/wrangler.jsonc")) {
|
|
92
|
+
if (flags.migrate) {
|
|
93
|
+
this.log.debug("Running database migrations before deployment...");
|
|
94
|
+
await this.utils.exec(`alepha db migrate --mode=${mode}`);
|
|
95
|
+
}
|
|
96
|
+
await this.utils.ensureDependency(root, "wrangler", { dev: true });
|
|
97
|
+
const command =
|
|
98
|
+
`wrangler deploy ${mode === "production" ? "" : "--env preview"} --config=dist/wrangler.jsonc`.trim();
|
|
99
|
+
this.log.info(`Deploying to Cloudflare with command: ${command}`);
|
|
100
|
+
await this.utils.exec(command);
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Surge deployment
|
|
105
|
+
if (await this.utils.exists(root, "dist/public/404.html")) {
|
|
106
|
+
await this.utils.ensureDependency(root, "surge", { dev: true });
|
|
107
|
+
const distPath = join(root, "dist/public");
|
|
108
|
+
this.log.debug(`Deploying to Surge from directory: ${distPath}`);
|
|
109
|
+
await this.utils.exec(`surge ${distPath}`);
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
throw new AlephaError(
|
|
114
|
+
"No deployment configuration found in the dist folder.",
|
|
115
|
+
);
|
|
116
|
+
},
|
|
117
|
+
});
|
|
118
|
+
}
|