alepha 0.14.0 → 0.14.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -3
- package/dist/api/audits/index.d.ts +80 -1
- package/dist/api/audits/index.d.ts.map +1 -1
- package/dist/api/audits/index.js.map +1 -1
- package/dist/api/files/index.d.ts +80 -1
- package/dist/api/files/index.d.ts.map +1 -1
- package/dist/api/files/index.js.map +1 -1
- package/dist/api/jobs/index.d.ts +236 -157
- package/dist/api/jobs/index.d.ts.map +1 -1
- package/dist/api/jobs/index.js.map +1 -1
- package/dist/api/notifications/index.d.ts +21 -1
- package/dist/api/notifications/index.d.ts.map +1 -1
- package/dist/api/parameters/index.d.ts +451 -4
- package/dist/api/parameters/index.d.ts.map +1 -1
- package/dist/api/parameters/index.js.map +1 -1
- package/dist/api/users/index.d.ts +252 -249
- package/dist/api/users/index.d.ts.map +1 -1
- package/dist/api/users/index.js +4 -0
- package/dist/api/users/index.js.map +1 -1
- package/dist/api/verifications/index.d.ts +128 -128
- package/dist/api/verifications/index.d.ts.map +1 -1
- package/dist/batch/index.js.map +1 -1
- package/dist/cache/core/index.js.map +1 -1
- package/dist/cli/index.d.ts +304 -115
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +650 -531
- package/dist/cli/index.js.map +1 -1
- package/dist/command/index.d.ts +210 -13
- package/dist/command/index.d.ts.map +1 -1
- package/dist/command/index.js +306 -69
- package/dist/command/index.js.map +1 -1
- package/dist/core/index.browser.js.map +1 -1
- package/dist/core/index.d.ts +1 -1
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +7 -6
- package/dist/core/index.js.map +1 -1
- package/dist/core/index.native.js +7 -6
- package/dist/core/index.native.js.map +1 -1
- package/dist/datetime/index.js.map +1 -1
- package/dist/fake/index.js.map +1 -1
- package/dist/file/index.d.ts.map +1 -1
- package/dist/file/index.js.map +1 -1
- package/dist/lock/redis/index.js.map +1 -1
- package/dist/logger/index.js.map +1 -1
- package/dist/mcp/index.js.map +1 -1
- package/dist/orm/index.browser.js +26 -5
- package/dist/orm/index.browser.js.map +1 -1
- package/dist/orm/index.d.ts +294 -215
- package/dist/orm/index.d.ts.map +1 -1
- package/dist/orm/index.js +522 -523
- package/dist/orm/index.js.map +1 -1
- 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 -1
- package/dist/redis/index.js +412 -21
- package/dist/redis/index.js.map +1 -1
- package/dist/retry/index.js.map +1 -1
- package/dist/router/index.js.map +1 -1
- package/dist/scheduler/index.js.map +1 -1
- package/dist/security/index.d.ts.map +1 -1
- package/dist/security/index.js.map +1 -1
- package/dist/server/auth/index.d.ts +155 -155
- package/dist/server/auth/index.js.map +1 -1
- package/dist/server/cache/index.js.map +1 -1
- package/dist/server/cookies/index.browser.js.map +1 -1
- package/dist/server/cookies/index.js.map +1 -1
- package/dist/server/core/index.browser.js.map +1 -1
- package/dist/server/core/index.d.ts +0 -1
- package/dist/server/core/index.d.ts.map +1 -1
- package/dist/server/core/index.js.map +1 -1
- package/dist/server/helmet/index.d.ts +4 -1
- package/dist/server/helmet/index.d.ts.map +1 -1
- package/dist/server/helmet/index.js.map +1 -1
- package/dist/server/links/index.browser.js.map +1 -1
- package/dist/server/links/index.js.map +1 -1
- package/dist/server/multipart/index.d.ts.map +1 -1
- package/dist/server/multipart/index.js.map +1 -1
- package/dist/server/proxy/index.js.map +1 -1
- package/dist/server/rate-limit/index.js.map +1 -1
- package/dist/server/security/index.d.ts +9 -9
- package/dist/server/security/index.js.map +1 -1
- package/dist/server/swagger/index.js.map +1 -1
- package/dist/thread/index.js.map +1 -1
- package/dist/topic/core/index.js.map +1 -1
- package/dist/topic/redis/index.js +3 -3
- package/dist/topic/redis/index.js.map +1 -1
- package/dist/vite/index.js +9 -6
- package/dist/vite/index.js.map +1 -1
- package/dist/websocket/index.browser.js.map +1 -1
- package/dist/websocket/index.d.ts +7 -7
- package/dist/websocket/index.js.map +1 -1
- package/package.json +3 -3
- package/src/api/users/index.ts +4 -0
- package/src/cli/apps/AlephaCli.ts +36 -14
- package/src/cli/apps/AlephaPackageBuilderCli.ts +5 -1
- package/src/cli/assets/appRouterTs.ts +1 -1
- package/src/cli/atoms/changelogOptions.ts +45 -0
- package/src/cli/commands/{ViteCommands.ts → build.ts} +4 -93
- package/src/cli/commands/changelog.ts +244 -0
- package/src/cli/commands/clean.ts +14 -0
- package/src/cli/commands/{DrizzleCommands.ts → db.ts} +37 -124
- package/src/cli/commands/deploy.ts +118 -0
- package/src/cli/commands/dev.ts +57 -0
- package/src/cli/commands/format.ts +17 -0
- package/src/cli/commands/{CoreCommands.ts → init.ts} +2 -40
- package/src/cli/commands/lint.ts +17 -0
- package/src/cli/commands/root.ts +32 -0
- package/src/cli/commands/run.ts +24 -0
- package/src/cli/commands/test.ts +42 -0
- package/src/cli/commands/typecheck.ts +19 -0
- package/src/cli/commands/{VerifyCommands.ts → verify.ts} +1 -13
- package/src/cli/defineConfig.ts +24 -0
- package/src/cli/index.ts +17 -5
- package/src/cli/services/AlephaCliUtils.ts +4 -21
- 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 +424 -91
- package/src/core/Alepha.ts +8 -5
- package/src/file/providers/NodeFileSystemProvider.ts +3 -1
- package/src/orm/index.browser.ts +1 -1
- package/src/orm/index.ts +18 -10
- package/src/orm/interfaces/PgQueryWhere.ts +1 -26
- package/src/orm/providers/{PostgresTypeProvider.ts → DatabaseTypeProvider.ts} +25 -3
- package/src/orm/providers/drivers/BunPostgresProvider.ts +225 -0
- package/src/orm/providers/drivers/BunSqliteProvider.ts +180 -0
- package/src/orm/providers/drivers/DatabaseProvider.ts +25 -0
- package/src/orm/providers/drivers/NodePostgresProvider.ts +0 -25
- 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/tasks/buildServer.ts +1 -0
- package/src/cli/commands/BiomeCommands.ts +0 -29
- package/src/cli/commands/ChangelogCommands.ts +0 -389
- package/src/orm/services/PgJsonQueryManager.ts +0 -511
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { access, readFile, unlink, writeFile } from "node:fs/promises";
|
|
2
2
|
import { createRequire } from "node:module";
|
|
3
3
|
import { join } from "node:path";
|
|
4
|
-
import { $
|
|
4
|
+
import { $inject, OPTIONS, t } from "alepha";
|
|
5
5
|
import { $command } from "alepha/command";
|
|
6
6
|
import { $logger } from "alepha/logger";
|
|
7
7
|
import {
|
|
@@ -18,78 +18,10 @@ import {
|
|
|
18
18
|
import type * as Vite from "vite";
|
|
19
19
|
import { AlephaCliUtils } from "../services/AlephaCliUtils.ts";
|
|
20
20
|
|
|
21
|
-
export class
|
|
21
|
+
export class BuildCommand {
|
|
22
22
|
protected readonly log = $logger();
|
|
23
23
|
protected readonly utils = $inject(AlephaCliUtils);
|
|
24
24
|
|
|
25
|
-
protected readonly env = $env(
|
|
26
|
-
t.object({
|
|
27
|
-
VITEST_ARGS: t.string({ default: "" }),
|
|
28
|
-
}),
|
|
29
|
-
);
|
|
30
|
-
|
|
31
|
-
public readonly run = $command({
|
|
32
|
-
name: "run",
|
|
33
|
-
hide: true,
|
|
34
|
-
description: "Run a TypeScript file directly",
|
|
35
|
-
flags: t.object({
|
|
36
|
-
watch: t.optional(
|
|
37
|
-
t.boolean({ description: "Watch file for changes", alias: "w" }),
|
|
38
|
-
),
|
|
39
|
-
}),
|
|
40
|
-
summary: false,
|
|
41
|
-
args: t.text({ title: "path", description: "Filepath to run" }),
|
|
42
|
-
handler: async ({ args, flags, root }) => {
|
|
43
|
-
await this.utils.ensureTsConfig(root);
|
|
44
|
-
await this.utils.exec(`tsx ${flags.watch ? "watch " : ""}${args}`);
|
|
45
|
-
},
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* Will run the project in watch mode.
|
|
50
|
-
*
|
|
51
|
-
* - If an index.html file is found in the project root, it will run Vite in dev mode.
|
|
52
|
-
* - Otherwise, it will look for a server entry file and run it with tsx in watch mode.
|
|
53
|
-
*/
|
|
54
|
-
public readonly dev = $command({
|
|
55
|
-
name: "dev",
|
|
56
|
-
description: "Run the project in development mode",
|
|
57
|
-
args: t.optional(t.text({ title: "path", description: "Filepath to run" })),
|
|
58
|
-
handler: async ({ args, root }) => {
|
|
59
|
-
const expo = await this.utils.hasExpo(root);
|
|
60
|
-
|
|
61
|
-
await this.utils.ensureConfig(root, {
|
|
62
|
-
viteConfigTs: !expo,
|
|
63
|
-
tsconfigJson: true,
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
if (expo) {
|
|
67
|
-
await this.utils.exec(`expo start`);
|
|
68
|
-
return;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
const entry = await boot.getServerEntry(root, args);
|
|
72
|
-
this.log.trace("Entry file found", { entry });
|
|
73
|
-
|
|
74
|
-
try {
|
|
75
|
-
await access(join(root, "index.html"));
|
|
76
|
-
} catch {
|
|
77
|
-
this.log.trace("No index.html found, running entry file with tsx");
|
|
78
|
-
let cmd = "tsx --watch";
|
|
79
|
-
if (await this.utils.exists(root, ".env")) {
|
|
80
|
-
cmd += ` --env-file=./.env`;
|
|
81
|
-
}
|
|
82
|
-
cmd += ` ${entry}`;
|
|
83
|
-
await this.utils.exec(cmd);
|
|
84
|
-
return;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
// Ensure vite is installed before running
|
|
88
|
-
await this.utils.ensureDependency(root, "vite");
|
|
89
|
-
await this.utils.exec(`vite`);
|
|
90
|
-
},
|
|
91
|
-
});
|
|
92
|
-
|
|
93
25
|
public readonly build = $command({
|
|
94
26
|
name: "build",
|
|
95
27
|
description: "Build the project for production",
|
|
@@ -122,11 +54,6 @@ export class ViteCommands {
|
|
|
122
54
|
description: "Generate sitemap.xml with base URL",
|
|
123
55
|
}),
|
|
124
56
|
),
|
|
125
|
-
prerender: t.optional(
|
|
126
|
-
t.boolean({
|
|
127
|
-
description: "Pre-render static pages",
|
|
128
|
-
}),
|
|
129
|
-
),
|
|
130
57
|
}),
|
|
131
58
|
handler: async ({ flags, args, run, root }) => {
|
|
132
59
|
// Tell viteAlephaBuild plugin to skip - CLI handles all tasks
|
|
@@ -165,7 +92,7 @@ export class ViteCommands {
|
|
|
165
92
|
);
|
|
166
93
|
const viteAlephaBuildOptions = alephaPlugin?.[OPTIONS] || {};
|
|
167
94
|
|
|
168
|
-
await this.utils.
|
|
95
|
+
await this.utils.loadEnv(root, [".env", ".env.production"]);
|
|
169
96
|
|
|
170
97
|
const stats = flags.stats ?? viteAlephaBuildOptions.stats ?? false;
|
|
171
98
|
const hasServer = viteAlephaBuildOptions.serverEntry !== false;
|
|
@@ -254,7 +181,7 @@ export class ViteCommands {
|
|
|
254
181
|
}
|
|
255
182
|
|
|
256
183
|
// Pre-render static pages
|
|
257
|
-
const shouldPrerender =
|
|
184
|
+
const shouldPrerender = clientOptions.prerender;
|
|
258
185
|
|
|
259
186
|
if (shouldPrerender) {
|
|
260
187
|
await run({
|
|
@@ -318,20 +245,4 @@ export class ViteCommands {
|
|
|
318
245
|
}
|
|
319
246
|
},
|
|
320
247
|
});
|
|
321
|
-
|
|
322
|
-
public readonly test = $command({
|
|
323
|
-
name: "test",
|
|
324
|
-
description: "Run tests using Vitest",
|
|
325
|
-
handler: async ({ root }) => {
|
|
326
|
-
await this.utils.ensureConfig(root, {
|
|
327
|
-
tsconfigJson: true,
|
|
328
|
-
viteConfigTs: true,
|
|
329
|
-
});
|
|
330
|
-
|
|
331
|
-
// Ensure vitest is installed before running
|
|
332
|
-
await this.utils.ensureDependency(root, "vitest");
|
|
333
|
-
|
|
334
|
-
await this.utils.exec(`vitest run ${this.env.VITEST_ARGS}`);
|
|
335
|
-
},
|
|
336
|
-
});
|
|
337
248
|
}
|
|
@@ -0,0 +1,244 @@
|
|
|
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
|
+
}
|
|
49
|
+
|
|
50
|
+
// =============================================================================
|
|
51
|
+
// CHANGELOG COMMAND
|
|
52
|
+
// =============================================================================
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Changelog command for generating release notes from git commits.
|
|
56
|
+
*
|
|
57
|
+
* Usage:
|
|
58
|
+
* - `alepha changelog` - Show unreleased changes since latest tag to HEAD
|
|
59
|
+
* - `alepha changelog --from=1.0.0` - Show changes from version to HEAD
|
|
60
|
+
* - `alepha changelog --from=1.0.0 --to=1.1.0` - Show changes between two refs
|
|
61
|
+
* - `alepha changelog | tee -a CHANGELOG.md` - Append to file
|
|
62
|
+
*/
|
|
63
|
+
export class ChangelogCommand {
|
|
64
|
+
protected readonly log = $logger();
|
|
65
|
+
protected readonly git = $inject(GitProvider);
|
|
66
|
+
protected readonly parser = $inject(GitMessageParser);
|
|
67
|
+
protected readonly config = $use(changelogOptions);
|
|
68
|
+
|
|
69
|
+
// ---------------------------------------------------------------------------
|
|
70
|
+
// FORMATTING
|
|
71
|
+
// ---------------------------------------------------------------------------
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Format a single commit line.
|
|
75
|
+
* Example: `- **cli**: add new command (\`abc1234\`)`
|
|
76
|
+
* Breaking changes are flagged: `- **cli**: add new command [BREAKING] (\`abc1234\`)`
|
|
77
|
+
*/
|
|
78
|
+
protected formatCommit(commit: Commit): string {
|
|
79
|
+
const breaking = commit.breaking ? " [BREAKING]" : "";
|
|
80
|
+
return `- **${commit.scope}**: ${commit.description}${breaking} (\`${commit.hash}\`)`;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Format the changelog entry with sections.
|
|
85
|
+
*/
|
|
86
|
+
protected formatEntry(entry: ChangelogEntry): string {
|
|
87
|
+
const sections: string[] = [];
|
|
88
|
+
|
|
89
|
+
if (entry.features.length > 0) {
|
|
90
|
+
sections.push("### Features\n");
|
|
91
|
+
for (const commit of entry.features) {
|
|
92
|
+
sections.push(this.formatCommit(commit));
|
|
93
|
+
}
|
|
94
|
+
sections.push("");
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
if (entry.fixes.length > 0) {
|
|
98
|
+
sections.push("### Bug Fixes\n");
|
|
99
|
+
for (const commit of entry.fixes) {
|
|
100
|
+
sections.push(this.formatCommit(commit));
|
|
101
|
+
}
|
|
102
|
+
sections.push("");
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return sections.join("\n");
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// ---------------------------------------------------------------------------
|
|
109
|
+
// PARSING
|
|
110
|
+
// ---------------------------------------------------------------------------
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Parse git log output into a changelog entry.
|
|
114
|
+
*/
|
|
115
|
+
protected parseCommits(commitsOutput: string): ChangelogEntry {
|
|
116
|
+
const entry: ChangelogEntry = {
|
|
117
|
+
features: [],
|
|
118
|
+
fixes: [],
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
for (const line of commitsOutput.trim().split("\n")) {
|
|
122
|
+
if (!line.trim()) continue;
|
|
123
|
+
|
|
124
|
+
const commit = this.parser.parseCommit(line, this.config);
|
|
125
|
+
if (!commit) {
|
|
126
|
+
this.log.trace("Skipping commit", { line });
|
|
127
|
+
continue;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
this.log.trace("Parsed commit", { commit });
|
|
131
|
+
|
|
132
|
+
// Categorize commit (breaking flag is preserved on the commit itself)
|
|
133
|
+
if (commit.type === "feat") {
|
|
134
|
+
entry.features.push(commit);
|
|
135
|
+
} else if (commit.type === "fix") {
|
|
136
|
+
entry.fixes.push(commit);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
return entry;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Check if entry has any public commits.
|
|
145
|
+
*/
|
|
146
|
+
protected hasChanges(entry: ChangelogEntry): boolean {
|
|
147
|
+
return entry.features.length > 0 || entry.fixes.length > 0;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Get the latest version tag.
|
|
152
|
+
*/
|
|
153
|
+
protected async getLatestTag(
|
|
154
|
+
git: (cmd: string) => Promise<string>,
|
|
155
|
+
): Promise<string | null> {
|
|
156
|
+
const tagsOutput = await git("tag --sort=-version:refname");
|
|
157
|
+
const tags = tagsOutput
|
|
158
|
+
.trim()
|
|
159
|
+
.split("\n")
|
|
160
|
+
.filter((tag) => tag.match(/^\d+\.\d+\.\d+$/));
|
|
161
|
+
|
|
162
|
+
return tags[0] || null;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// ---------------------------------------------------------------------------
|
|
166
|
+
// COMMAND
|
|
167
|
+
// ---------------------------------------------------------------------------
|
|
168
|
+
|
|
169
|
+
public readonly changelog = $command({
|
|
170
|
+
name: "changelog",
|
|
171
|
+
description:
|
|
172
|
+
"Generate changelog from conventional commits (outputs to stdout)",
|
|
173
|
+
flags: t.object({
|
|
174
|
+
/**
|
|
175
|
+
* Show changes from this ref (tag, commit, branch).
|
|
176
|
+
* Defaults to the latest version tag.
|
|
177
|
+
* Example: --from=1.0.0
|
|
178
|
+
*/
|
|
179
|
+
from: t.optional(
|
|
180
|
+
t.string({
|
|
181
|
+
aliases: ["f"],
|
|
182
|
+
description: "Starting ref (default: latest tag)",
|
|
183
|
+
}),
|
|
184
|
+
),
|
|
185
|
+
/**
|
|
186
|
+
* Show changes up to this ref (tag, commit, branch).
|
|
187
|
+
* Defaults to HEAD.
|
|
188
|
+
* Example: --to=main
|
|
189
|
+
*/
|
|
190
|
+
to: t.optional(
|
|
191
|
+
t.string({
|
|
192
|
+
aliases: ["t"],
|
|
193
|
+
description: "Ending ref (default: HEAD)",
|
|
194
|
+
}),
|
|
195
|
+
),
|
|
196
|
+
}),
|
|
197
|
+
handler: async ({ flags, root }) => {
|
|
198
|
+
const git = (cmd: string) => this.git.exec(cmd, root);
|
|
199
|
+
|
|
200
|
+
// Determine the starting point
|
|
201
|
+
let fromRef: string;
|
|
202
|
+
|
|
203
|
+
if (flags.from) {
|
|
204
|
+
// User specified a ref
|
|
205
|
+
fromRef = flags.from;
|
|
206
|
+
this.log.debug("Using specified from ref", { from: fromRef });
|
|
207
|
+
} else {
|
|
208
|
+
// Use latest tag
|
|
209
|
+
const latestTag = await this.getLatestTag(git);
|
|
210
|
+
if (!latestTag) {
|
|
211
|
+
process.stdout.write("No version tags found in repository\n");
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
fromRef = latestTag;
|
|
215
|
+
this.log.debug("Using latest tag", { from: fromRef });
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// Determine the ending point
|
|
219
|
+
const toRef = flags.to || "HEAD";
|
|
220
|
+
this.log.debug("Using to ref", { to: toRef });
|
|
221
|
+
|
|
222
|
+
// Get commits in range
|
|
223
|
+
const commitsOutput = await git(`log ${fromRef}..${toRef} --oneline`);
|
|
224
|
+
|
|
225
|
+
if (!commitsOutput.trim()) {
|
|
226
|
+
process.stdout.write(`No changes in range ${fromRef}..${toRef}\n`);
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// Parse and format
|
|
231
|
+
const entry = this.parseCommits(commitsOutput);
|
|
232
|
+
|
|
233
|
+
if (!this.hasChanges(entry)) {
|
|
234
|
+
process.stdout.write(
|
|
235
|
+
`No public changes in range ${fromRef}..${toRef}\n`,
|
|
236
|
+
);
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// Output the formatted changelog (no header - caller adds it if needed)
|
|
241
|
+
process.stdout.write(this.formatEntry(entry));
|
|
242
|
+
},
|
|
243
|
+
});
|
|
244
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { $command } from "alepha/command";
|
|
2
|
+
|
|
3
|
+
export class CleanCommand {
|
|
4
|
+
/**
|
|
5
|
+
* Clean the project, removing the "dist" directory
|
|
6
|
+
*/
|
|
7
|
+
public readonly clean = $command({
|
|
8
|
+
name: "clean",
|
|
9
|
+
description: "Clean the project",
|
|
10
|
+
handler: async ({ run }) => {
|
|
11
|
+
await run.rm("./dist");
|
|
12
|
+
},
|
|
13
|
+
});
|
|
14
|
+
}
|
|
@@ -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 {
|
|
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({
|
|
@@ -21,15 +25,15 @@ const drizzleCommandFlags = t.object({
|
|
|
21
25
|
),
|
|
22
26
|
});
|
|
23
27
|
|
|
24
|
-
export class
|
|
25
|
-
log = $logger();
|
|
26
|
-
utils = $inject(AlephaCliUtils);
|
|
28
|
+
export class DbCommand {
|
|
29
|
+
protected readonly log = $logger();
|
|
30
|
+
protected readonly utils = $inject(AlephaCliUtils);
|
|
27
31
|
|
|
28
32
|
/**
|
|
29
33
|
* Check if database migrations are up to date.
|
|
30
34
|
*/
|
|
31
|
-
check = $command({
|
|
32
|
-
name: "
|
|
35
|
+
protected readonly check = $command({
|
|
36
|
+
name: "check-migrations",
|
|
33
37
|
description: "Check if database migration files are up to date",
|
|
34
38
|
args: t.optional(
|
|
35
39
|
t.text({
|
|
@@ -70,7 +74,7 @@ export class DrizzleCommands {
|
|
|
70
74
|
).catch(() => null);
|
|
71
75
|
|
|
72
76
|
if (!journalFile) {
|
|
73
|
-
this.log.info(
|
|
77
|
+
this.log.info("No migration journal found.");
|
|
74
78
|
return;
|
|
75
79
|
}
|
|
76
80
|
|
|
@@ -126,15 +130,9 @@ export class DrizzleCommands {
|
|
|
126
130
|
|
|
127
131
|
/**
|
|
128
132
|
* Generate database migration files
|
|
129
|
-
*
|
|
130
|
-
* - Loads the Alepha instance from the specified entry file.
|
|
131
|
-
* - Retrieves all repository primitives to gather database models.
|
|
132
|
-
* - Creates temporary entity definitions based on the current database schema.
|
|
133
|
-
* - Writes these definitions to a temporary schema file. (node_modules/.db/entities.ts)
|
|
134
|
-
* - Invokes Drizzle Kit's CLI to generate migration files based on the current schema.
|
|
135
133
|
*/
|
|
136
|
-
generate = $command({
|
|
137
|
-
name: "
|
|
134
|
+
protected readonly generate = $command({
|
|
135
|
+
name: "generate",
|
|
138
136
|
description: "Generate migration files based on current database schema",
|
|
139
137
|
summary: false,
|
|
140
138
|
args: t.optional(
|
|
@@ -171,14 +169,9 @@ export class DrizzleCommands {
|
|
|
171
169
|
|
|
172
170
|
/**
|
|
173
171
|
* Push database schema changes directly to the database
|
|
174
|
-
*
|
|
175
|
-
* - Loads the Alepha instance from the specified entry file.
|
|
176
|
-
* - Retrieves all repository primitives to gather database models.
|
|
177
|
-
* - Creates temporary entity definitions and Drizzle config.
|
|
178
|
-
* - Invokes Drizzle Kit's push command to apply schema changes directly.
|
|
179
172
|
*/
|
|
180
|
-
push = $command({
|
|
181
|
-
name: "
|
|
173
|
+
protected readonly push = $command({
|
|
174
|
+
name: "push",
|
|
182
175
|
description: "Push database schema changes directly to the database",
|
|
183
176
|
summary: false,
|
|
184
177
|
args: t.optional(
|
|
@@ -203,14 +196,9 @@ export class DrizzleCommands {
|
|
|
203
196
|
|
|
204
197
|
/**
|
|
205
198
|
* Apply pending database migrations
|
|
206
|
-
*
|
|
207
|
-
* - Loads the Alepha instance from the specified entry file.
|
|
208
|
-
* - Retrieves all repository primitives to gather database models.
|
|
209
|
-
* - Creates temporary entity definitions and Drizzle config.
|
|
210
|
-
* - Invokes Drizzle Kit's migrate command to apply pending migrations.
|
|
211
199
|
*/
|
|
212
|
-
migrate = $command({
|
|
213
|
-
name: "
|
|
200
|
+
protected readonly migrate = $command({
|
|
201
|
+
name: "migrate",
|
|
214
202
|
description: "Apply pending database migrations",
|
|
215
203
|
summary: false,
|
|
216
204
|
args: t.optional(
|
|
@@ -235,14 +223,9 @@ export class DrizzleCommands {
|
|
|
235
223
|
|
|
236
224
|
/**
|
|
237
225
|
* Launch Drizzle Studio database browser
|
|
238
|
-
*
|
|
239
|
-
* - Loads the Alepha instance from the specified entry file.
|
|
240
|
-
* - Retrieves all repository primitives to gather database models.
|
|
241
|
-
* - Creates temporary entity definitions and Drizzle config.
|
|
242
|
-
* - Invokes Drizzle Kit's studio command to launch the web-based database browser.
|
|
243
226
|
*/
|
|
244
|
-
studio = $command({
|
|
245
|
-
name: "
|
|
227
|
+
protected readonly studio = $command({
|
|
228
|
+
name: "studio",
|
|
246
229
|
description: "Launch Drizzle Studio database browser",
|
|
247
230
|
summary: false,
|
|
248
231
|
args: t.optional(
|
|
@@ -265,13 +248,20 @@ export class DrizzleCommands {
|
|
|
265
248
|
},
|
|
266
249
|
});
|
|
267
250
|
|
|
251
|
+
/**
|
|
252
|
+
* Parent command for database operations.
|
|
253
|
+
*/
|
|
254
|
+
public readonly db = $command({
|
|
255
|
+
name: "db",
|
|
256
|
+
description: "Database management commands",
|
|
257
|
+
children: [this.check, this.generate, this.push, this.migrate, this.studio],
|
|
258
|
+
handler: async ({ help }) => {
|
|
259
|
+
help();
|
|
260
|
+
},
|
|
261
|
+
});
|
|
262
|
+
|
|
268
263
|
/**
|
|
269
264
|
* Run a drizzle-kit command for all database providers in an Alepha instance.
|
|
270
|
-
*
|
|
271
|
-
* Iterates through all repository providers, prepares Drizzle config for each,
|
|
272
|
-
* and executes the specified drizzle-kit command.
|
|
273
|
-
*
|
|
274
|
-
* @param options - Configuration including command to run, flags, and logging
|
|
275
265
|
*/
|
|
276
266
|
public async runDrizzleKitCommand(options: {
|
|
277
267
|
root: string;
|
|
@@ -289,7 +279,7 @@ export class DrizzleCommands {
|
|
|
289
279
|
envFiles.push(`.env.${options.env}`);
|
|
290
280
|
}
|
|
291
281
|
|
|
292
|
-
await this.utils.
|
|
282
|
+
await this.utils.loadEnv(rootDir, envFiles);
|
|
293
283
|
|
|
294
284
|
this.log.debug(`Using project root: ${rootDir}`);
|
|
295
285
|
|
|
@@ -349,16 +339,10 @@ export class DrizzleCommands {
|
|
|
349
339
|
|
|
350
340
|
/**
|
|
351
341
|
* Prepare Drizzle configuration files for a database provider.
|
|
352
|
-
*
|
|
353
|
-
* Creates temporary entities.js and drizzle.config.js files needed
|
|
354
|
-
* for Drizzle Kit commands to run properly.
|
|
355
|
-
*
|
|
356
|
-
* @param options - Configuration options including kit, provider info, and paths
|
|
357
|
-
* @returns Path to the generated drizzle.config.js file
|
|
358
342
|
*/
|
|
359
343
|
public async prepareDrizzleConfig(options: {
|
|
360
344
|
kit: any;
|
|
361
|
-
provider:
|
|
345
|
+
provider: DatabaseProvider;
|
|
362
346
|
providerName: string;
|
|
363
347
|
providerUrl: string;
|
|
364
348
|
dialect: string;
|
|
@@ -387,6 +371,10 @@ export class DrizzleCommands {
|
|
|
387
371
|
},
|
|
388
372
|
};
|
|
389
373
|
|
|
374
|
+
if (options.provider.schema) {
|
|
375
|
+
config.schemaFilter = options.provider.schema;
|
|
376
|
+
}
|
|
377
|
+
|
|
390
378
|
if (options.providerName === "d1") {
|
|
391
379
|
config.driver = "d1-http";
|
|
392
380
|
}
|
|
@@ -453,79 +441,4 @@ export class DrizzleCommands {
|
|
|
453
441
|
options.rootDir,
|
|
454
442
|
);
|
|
455
443
|
}
|
|
456
|
-
|
|
457
|
-
// /**
|
|
458
|
-
// * Drop database schema (development only)
|
|
459
|
-
// *
|
|
460
|
-
// * @experimental
|
|
461
|
-
// */
|
|
462
|
-
// drop = $command({
|
|
463
|
-
// name: "db:drop",
|
|
464
|
-
// description: "Drop database schema (development only)",
|
|
465
|
-
// summary: false,
|
|
466
|
-
// args: t.optional(
|
|
467
|
-
// t.text({
|
|
468
|
-
// title: "path",
|
|
469
|
-
// description: "Path to the Alepha server entry file",
|
|
470
|
-
// }),
|
|
471
|
-
// ),
|
|
472
|
-
// flags: drizzleCommandFlags,
|
|
473
|
-
// handler: async ({ flags }) => {
|
|
474
|
-
// // TODO: Implement db:drop
|
|
475
|
-
// this.log.warn("db:drop is not yet implemented");
|
|
476
|
-
// if (flags.provider) {
|
|
477
|
-
// this.log.info(`Provider filter: ${flags.provider}`);
|
|
478
|
-
// }
|
|
479
|
-
// },
|
|
480
|
-
// });
|
|
481
|
-
//
|
|
482
|
-
// /**
|
|
483
|
-
// * Seed database with initial data
|
|
484
|
-
// *
|
|
485
|
-
// * @experimental
|
|
486
|
-
// */
|
|
487
|
-
// seed = $command({
|
|
488
|
-
// name: "db:seed",
|
|
489
|
-
// description: "Seed database with initial data",
|
|
490
|
-
// summary: false,
|
|
491
|
-
// args: t.optional(
|
|
492
|
-
// t.text({
|
|
493
|
-
// title: "path",
|
|
494
|
-
// description: "Path to the Alepha server entry file",
|
|
495
|
-
// }),
|
|
496
|
-
// ),
|
|
497
|
-
// flags: drizzleCommandFlags,
|
|
498
|
-
// handler: async ({ flags }) => {
|
|
499
|
-
// // TODO: Implement db:seed
|
|
500
|
-
// this.log.warn("db:seed is not yet implemented");
|
|
501
|
-
// if (flags.provider) {
|
|
502
|
-
// this.log.info(`Provider filter: ${flags.provider}`);
|
|
503
|
-
// }
|
|
504
|
-
// },
|
|
505
|
-
// });
|
|
506
|
-
//
|
|
507
|
-
// /**
|
|
508
|
-
// * Show pending database migrations status
|
|
509
|
-
// *
|
|
510
|
-
// * @experimental
|
|
511
|
-
// */
|
|
512
|
-
// status = $command({
|
|
513
|
-
// name: "db:status",
|
|
514
|
-
// description: "Show pending database migrations status",
|
|
515
|
-
// summary: false,
|
|
516
|
-
// args: t.optional(
|
|
517
|
-
// t.text({
|
|
518
|
-
// title: "path",
|
|
519
|
-
// description: "Path to the Alepha server entry file",
|
|
520
|
-
// }),
|
|
521
|
-
// ),
|
|
522
|
-
// flags: drizzleCommandFlags,
|
|
523
|
-
// handler: async ({ flags }) => {
|
|
524
|
-
// // TODO: Implement db:status
|
|
525
|
-
// this.log.warn("db:status is not yet implemented");
|
|
526
|
-
// if (flags.provider) {
|
|
527
|
-
// this.log.info(`Provider filter: ${flags.provider}`);
|
|
528
|
-
// }
|
|
529
|
-
// },
|
|
530
|
-
// });
|
|
531
444
|
}
|