kavoru 0.8.9 → 0.8.10
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 +1 -0
- package/package.json +1 -1
- package/src/args.ts +7 -2
- package/src/features.ts +21 -1
- package/src/index.ts +14 -1
- package/src/module-cli.ts +79 -0
package/README.md
CHANGED
|
@@ -55,6 +55,7 @@ During setup you can pick which integrations to scaffold. Core is always include
|
|
|
55
55
|
| `resend` | Resend email |
|
|
56
56
|
| `cron` | Cron jobs |
|
|
57
57
|
| `docker` | Dockerfile + Compose |
|
|
58
|
+
| `cli` | Project CLI (`kavoru module`, bin, scaffolds) |
|
|
58
59
|
|
|
59
60
|
Interactive mode (TTY) shows a checkbox menu (↑↓ move, Space toggle, Enter confirm). Non-interactive runs use the full stack unless you pass flags.
|
|
60
61
|
|
package/package.json
CHANGED
package/src/args.ts
CHANGED
|
@@ -15,9 +15,13 @@ export type CliOptions = {
|
|
|
15
15
|
|
|
16
16
|
const HELP = `\
|
|
17
17
|
Usage: kavoru [options] [directory]
|
|
18
|
+
kavoru module <module-name> [options]
|
|
18
19
|
|
|
19
20
|
Create a new project from the Kavoru Elysia + Bun template.
|
|
20
21
|
|
|
22
|
+
Commands:
|
|
23
|
+
module <name> Generate src/modules/<name> (routes, service, types)
|
|
24
|
+
|
|
21
25
|
Arguments:
|
|
22
26
|
directory Project folder (use "." for current directory)
|
|
23
27
|
|
|
@@ -33,14 +37,15 @@ Options:
|
|
|
33
37
|
--no-features <list> Comma-separated features to exclude
|
|
34
38
|
|
|
35
39
|
Features:
|
|
36
|
-
auth, postgres, otel, sentry, kafka, websocket, resend, cron, docker
|
|
37
|
-
(prisma is accepted as an alias for postgres)
|
|
40
|
+
auth, postgres, otel, sentry, kafka, websocket, resend, cron, docker, cli
|
|
41
|
+
(prisma is accepted as an alias for postgres; kavoru-cli for cli)
|
|
38
42
|
|
|
39
43
|
Examples:
|
|
40
44
|
bunx kavoru@latest my-api
|
|
41
45
|
bunx kavoru@latest my-api --minimal
|
|
42
46
|
bunx kavoru@latest my-api --features auth,postgres,otel
|
|
43
47
|
bunx kavoru@latest my-api --no-features kafka,docker,resend
|
|
48
|
+
bunx kavoru@latest module users
|
|
44
49
|
`;
|
|
45
50
|
|
|
46
51
|
export function parseArgs(argv: string[]): CliOptions {
|
package/src/features.ts
CHANGED
|
@@ -11,10 +11,12 @@ export type FeatureId =
|
|
|
11
11
|
| "websocket"
|
|
12
12
|
| "resend"
|
|
13
13
|
| "cron"
|
|
14
|
-
| "docker"
|
|
14
|
+
| "docker"
|
|
15
|
+
| "cli";
|
|
15
16
|
|
|
16
17
|
const FEATURE_ALIASES: Record<string, FeatureId> = {
|
|
17
18
|
prisma: "postgres",
|
|
19
|
+
"kavoru-cli": "cli",
|
|
18
20
|
};
|
|
19
21
|
|
|
20
22
|
export type FeatureSelection = Record<FeatureId, boolean>;
|
|
@@ -71,6 +73,11 @@ export const FEATURES: FeatureDef[] = [
|
|
|
71
73
|
label: "Docker",
|
|
72
74
|
description: "Dockerfile and Docker Compose stack",
|
|
73
75
|
},
|
|
76
|
+
{
|
|
77
|
+
id: "cli",
|
|
78
|
+
label: "Project CLI",
|
|
79
|
+
description: "kavoru module command, bin, and module scaffolds",
|
|
80
|
+
},
|
|
74
81
|
];
|
|
75
82
|
|
|
76
83
|
export const FEATURE_IDS = FEATURES.map((feature) => feature.id);
|
|
@@ -113,6 +120,13 @@ const FEATURE_PATHS: Record<FeatureId, string[]> = {
|
|
|
113
120
|
resend: ["src/infra/resend"],
|
|
114
121
|
cron: ["src/schedules"],
|
|
115
122
|
docker: ["docker-compose.yaml", "docker"],
|
|
123
|
+
cli: [
|
|
124
|
+
"bin/kavoru.js",
|
|
125
|
+
"scripts/kavoru-cli.ts",
|
|
126
|
+
"scripts/generate-module.ts",
|
|
127
|
+
"__tests__/generate-module.test.ts",
|
|
128
|
+
"__tests__/kavoru-cli.test.ts",
|
|
129
|
+
],
|
|
116
130
|
};
|
|
117
131
|
|
|
118
132
|
const FEATURE_DEPENDENCIES: Partial<
|
|
@@ -141,6 +155,7 @@ const FEATURE_SCRIPTS: Partial<Record<FeatureId, string[]>> = {
|
|
|
141
155
|
otel: ["otel:view", "otel:tui"],
|
|
142
156
|
sentry: ["sentry:spotlight"],
|
|
143
157
|
postgres: ["seed"],
|
|
158
|
+
cli: ["kavoru", "module"],
|
|
144
159
|
};
|
|
145
160
|
|
|
146
161
|
function resolveFeatureId(raw: string): FeatureId | null {
|
|
@@ -446,6 +461,7 @@ async function patchPackageJson(
|
|
|
446
461
|
if (!(await pkgFile.exists())) return;
|
|
447
462
|
|
|
448
463
|
const pkg = (await pkgFile.json()) as {
|
|
464
|
+
bin?: Record<string, string>;
|
|
449
465
|
dependencies?: Record<string, string>;
|
|
450
466
|
devDependencies?: Record<string, string>;
|
|
451
467
|
scripts?: Record<string, string>;
|
|
@@ -476,6 +492,10 @@ async function patchPackageJson(
|
|
|
476
492
|
pkg.scripts.start = "bun run src/index.ts";
|
|
477
493
|
}
|
|
478
494
|
|
|
495
|
+
if (!selection.cli) {
|
|
496
|
+
delete pkg.bin;
|
|
497
|
+
}
|
|
498
|
+
|
|
479
499
|
await Bun.write(pkgPath, `${JSON.stringify(pkg, null, 2)}\n`);
|
|
480
500
|
}
|
|
481
501
|
|
package/src/index.ts
CHANGED
|
@@ -3,10 +3,23 @@
|
|
|
3
3
|
import { parseArgs, printHelp, printVersion } from "./args";
|
|
4
4
|
import { runCli } from "./cli";
|
|
5
5
|
import { log } from "./log";
|
|
6
|
+
import { printModuleHelp, runModuleCommand } from "./module-cli";
|
|
6
7
|
|
|
7
8
|
async function main(): Promise<void> {
|
|
8
9
|
try {
|
|
9
|
-
const
|
|
10
|
+
const argv = process.argv.slice(2);
|
|
11
|
+
|
|
12
|
+
if (argv[0] === "module") {
|
|
13
|
+
if (argv.includes("-h") || argv.includes("--help")) {
|
|
14
|
+
printModuleHelp();
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
await runModuleCommand(argv.slice(1));
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const options = parseArgs(argv);
|
|
10
23
|
|
|
11
24
|
if (options.help) {
|
|
12
25
|
printHelp();
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { log } from "./log";
|
|
4
|
+
|
|
5
|
+
function findProjectRoot(cwd: string): string {
|
|
6
|
+
let current = path.resolve(cwd);
|
|
7
|
+
|
|
8
|
+
while (true) {
|
|
9
|
+
const packageJson = path.join(current, "package.json");
|
|
10
|
+
const localCli = path.join(current, "scripts/kavoru-cli.ts");
|
|
11
|
+
const moduleScript = path.join(current, "scripts/generate-module.ts");
|
|
12
|
+
if (
|
|
13
|
+
existsSync(packageJson) &&
|
|
14
|
+
(existsSync(localCli) || existsSync(moduleScript))
|
|
15
|
+
) {
|
|
16
|
+
return current;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const parent = path.dirname(current);
|
|
20
|
+
if (parent === current) {
|
|
21
|
+
break;
|
|
22
|
+
}
|
|
23
|
+
current = parent;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
throw new Error(
|
|
27
|
+
"Could not find a Kavoru project with the Project CLI enabled. Scaffold with the cli feature or run from a project that includes scripts/kavoru-cli.ts.",
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export async function runModuleCommand(argv: string[]): Promise<void> {
|
|
32
|
+
const force = argv.includes("--force") || argv.includes("-f");
|
|
33
|
+
const name = argv.find((arg) => !arg.startsWith("-"));
|
|
34
|
+
|
|
35
|
+
if (!name) {
|
|
36
|
+
throw new Error("Usage: kavoru module <module-name> [--force]");
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const projectDir = findProjectRoot(process.cwd());
|
|
40
|
+
const localCli = path.join(projectDir, "scripts/kavoru-cli.ts");
|
|
41
|
+
const scriptPath = existsSync(localCli)
|
|
42
|
+
? localCli
|
|
43
|
+
: path.join(projectDir, "scripts/generate-module.ts");
|
|
44
|
+
const cmd = existsSync(localCli)
|
|
45
|
+
? ["bun", scriptPath, "module", name]
|
|
46
|
+
: ["bun", scriptPath, name];
|
|
47
|
+
if (force) cmd.push("--force");
|
|
48
|
+
|
|
49
|
+
log.info(`Generating module "${name}" in ${projectDir}`);
|
|
50
|
+
|
|
51
|
+
const proc = Bun.spawn(cmd, {
|
|
52
|
+
cwd: projectDir,
|
|
53
|
+
stdout: "inherit",
|
|
54
|
+
stderr: "inherit",
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
const exitCode = await proc.exited;
|
|
58
|
+
if (exitCode !== 0) {
|
|
59
|
+
process.exit(exitCode ?? 1);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export function printModuleHelp(): void {
|
|
64
|
+
console.log(`\
|
|
65
|
+
Usage: kavoru module <module-name> [options]
|
|
66
|
+
|
|
67
|
+
Generate a feature module under src/modules/<module-name>/ with:
|
|
68
|
+
routes.ts, service.ts, types.ts
|
|
69
|
+
|
|
70
|
+
Options:
|
|
71
|
+
-f, --force Overwrite an existing module folder
|
|
72
|
+
-h, --help Show help
|
|
73
|
+
|
|
74
|
+
Examples:
|
|
75
|
+
kavoru module users
|
|
76
|
+
kavoru module user-profile --force
|
|
77
|
+
bun run kavoru module billing
|
|
78
|
+
`);
|
|
79
|
+
}
|