@basaltkit/cli 1.2.4 → 1.3.0
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 +10 -4
- package/dist/publish.js +28 -1
- package/dist/runner.js +7 -0
- package/dist/upgrade.d.ts +10 -2
- package/dist/upgrade.js +22 -10
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -94,8 +94,14 @@ Without registering anything, `runCli` always provides:
|
|
|
94
94
|
| `basalt routes` | Lists the HTTP routes registered by the application (read from the `http:routes` metadata bucket, populated by HTTP adapters such as `@basaltkit/fastify`) |
|
|
95
95
|
| `basalt schedule:list` | Lists scheduled tasks and their cron expressions (read from the `schedule:entries` bucket, populated by `@basaltkit/scheduler`) |
|
|
96
96
|
| `basalt dev [--entry] [--worker] [--queue] [--no-routes]` | Runs the app with watch + restart, **prints the route table on boot**, and with `--worker` also starts a watched `queue:work` alongside it (server + worker in one command). Delegates watching to `tsx watch` / `node --watch`. |
|
|
97
|
-
| `basalt upgrade [--dry] [--only=<id>]` | Applies framework upgrade codemods (ships the `@machize/*` → `@basaltkit/*` scope rename; `--dry` previews) |
|
|
98
|
-
| `basalt publish [<id>] [--force]` | Copies a bundled stub group into the app — `dockerfile
|
|
97
|
+
| `basalt upgrade [--dry] [--only=<id>] [--dir=<path>]` | Applies framework upgrade codemods (ships the `@machize/*` → `@basaltkit/*` scope rename; `--dry` previews). `create-basalt update` runs them for you after an install. `nodeUpgradeFs(baseDir)` resolves relative paths against the directory being upgraded, so `--dir=` reads the tree it lists |
|
|
98
|
+
| `basalt publish [<id>] [--force]` | Copies a bundled stub group into the app — `dockerfile` (plus a `.dockerignore` keeping `.env` and keys out of the image), `ci`, `editorconfig` (run with no id to list) |
|
|
99
|
+
|
|
100
|
+
Not served by `runCli`: the **project commands** `update`, `add`, `doctor` and
|
|
101
|
+
`info` belong to `create-basalt` — the scaffolded `bin/basalt.ts` forwards them
|
|
102
|
+
before booting the app (so `pnpm basalt update` works even when the app does
|
|
103
|
+
not boot). On an older `bin/basalt.ts` they hit `Unknown command`, followed by a
|
|
104
|
+
hint to run `npx create-basalt@latest <command>`.
|
|
99
105
|
|
|
100
106
|
If you also install `@basaltkit/generator`, you gain the `make:*` commands. Feature
|
|
101
107
|
plugins register their own: `queue:work|stats|retry|jobs` (`@basaltkit/queue`),
|
|
@@ -243,7 +249,7 @@ The definitions of the built-in `routes` and `schedule:list` commands. *(Advance
|
|
|
243
249
|
## Common errors and solutions (FAQ)
|
|
244
250
|
|
|
245
251
|
**`Unknown command "x". Run "basalt list" to see what is available.`**
|
|
246
|
-
The command isn't registered. Confirm you passed it inside `commandsPlugin([...])` and that plugin is in the `plugins` list of `createApp`. Run `basalt list` to see what's available.
|
|
252
|
+
The command isn't registered. Confirm you passed it inside `commandsPlugin([...])` and that plugin is in the `plugins` list of `createApp`. Run `basalt list` to see what's available. For `update`, `add`, `doctor` or `info`, see the second line of the error: those are create-basalt's project commands, and `npx create-basalt@latest update` teaches an old `bin/basalt.ts` to forward them.
|
|
247
253
|
|
|
248
254
|
**My command runs but the `--step 2` flag doesn't work.**
|
|
249
255
|
The parser only recognizes the equals-sign form: `--step=2`. Written with a space, `2` is treated as a positional argument (it shows up in `args`).
|
|
@@ -263,4 +269,4 @@ Return a number from `handle` (for example `return 3`). `runCli` propagates it;
|
|
|
263
269
|
- **`@basaltkit/generator`** — provides `generatorCommands()`, a list of `make:*` commands (code generators) ready to pass to `commandsPlugin`. That's how `basalt make:resource` shows up.
|
|
264
270
|
- **`@basaltkit/fastify`** — writes routes into the `http:routes` bucket, which the built-in `routes` command reads.
|
|
265
271
|
- **`@basaltkit/scheduler`** — writes tasks into the `schedule:entries` bucket, which `schedule:list` reads.
|
|
266
|
-
- **`create-basalt`** — with the `--cli` flag, the project generator creates `bin/basalt.ts`, the `pnpm basalt` script, and registers `commandsPlugin(generatorCommands())` for you.
|
|
272
|
+
- **`create-basalt`** — with the `--cli` flag (or later, `create-basalt add cli`), the project generator creates `bin/basalt.ts`, the `pnpm basalt` script, and registers `commandsPlugin(generatorCommands())` for you. It also provides the project commands `bin/basalt.ts` forwards: `update`, `add`, `doctor`, `info`.
|
package/dist/publish.js
CHANGED
|
@@ -14,6 +14,26 @@ COPY . .
|
|
|
14
14
|
EXPOSE 3000
|
|
15
15
|
CMD ["node", "dist/main.js"]
|
|
16
16
|
`;
|
|
17
|
+
/**
|
|
18
|
+
* Published with the Dockerfile: its \`COPY . .\` would otherwise bake \`.env\`,
|
|
19
|
+
* private keys and VCS metadata into an image layer. Every rule is \`**\/\`-prefixed:
|
|
20
|
+
* .dockerignore patterns are anchored at the context root, so a bare \`.env\`
|
|
21
|
+
* or \`*.pem\` would still let \`prisma/.env\` or \`certs/server.key\` through.
|
|
22
|
+
*/
|
|
23
|
+
const DOCKERIGNORE = `**/.env
|
|
24
|
+
**/.env.*
|
|
25
|
+
!**/.env.example
|
|
26
|
+
**/.npmrc
|
|
27
|
+
**/.git
|
|
28
|
+
**/node_modules
|
|
29
|
+
**/coverage
|
|
30
|
+
**/*.log
|
|
31
|
+
**/*.pem
|
|
32
|
+
**/*.key
|
|
33
|
+
**/*.p12
|
|
34
|
+
**/*.pfx
|
|
35
|
+
**/.DS_Store
|
|
36
|
+
`;
|
|
17
37
|
const CI_WORKFLOW = `name: ci
|
|
18
38
|
on:
|
|
19
39
|
push: { branches: [main] }
|
|
@@ -42,7 +62,14 @@ trim_trailing_whitespace = true
|
|
|
42
62
|
`;
|
|
43
63
|
/** Stubs bundled with the CLI. Apps can register more via the metadata bucket. */
|
|
44
64
|
export const PUBLISHABLES = [
|
|
45
|
-
{
|
|
65
|
+
{
|
|
66
|
+
id: 'dockerfile',
|
|
67
|
+
description: 'Production multi-stage Dockerfile (+ .dockerignore keeping secrets out of the image)',
|
|
68
|
+
files: () => [
|
|
69
|
+
{ path: 'Dockerfile', content: DOCKERFILE },
|
|
70
|
+
{ path: '.dockerignore', content: DOCKERIGNORE },
|
|
71
|
+
],
|
|
72
|
+
},
|
|
46
73
|
{ id: 'ci', description: 'GitHub Actions CI workflow', files: () => [{ path: '.github/workflows/ci.yml', content: CI_WORKFLOW }] },
|
|
47
74
|
{ id: 'editorconfig', description: 'Shared .editorconfig', files: () => [{ path: '.editorconfig', content: EDITORCONFIG }] },
|
|
48
75
|
];
|
package/dist/runner.js
CHANGED
|
@@ -2,6 +2,8 @@ import { ensureMetadata } from '@basaltkit/core';
|
|
|
2
2
|
import { builtinCommands } from './builtins.js';
|
|
3
3
|
import { consoleIo } from './io.js';
|
|
4
4
|
import { parseArgv } from './parse.js';
|
|
5
|
+
/** Commands create-basalt serves (bin/basalt.ts forwards them before booting the app). */
|
|
6
|
+
const PROJECT_COMMANDS = ['update', 'add', 'doctor', 'info'];
|
|
5
7
|
/**
|
|
6
8
|
* Boots the app, resolves the command (built-ins + everything registered in
|
|
7
9
|
* the 'commands' metadata bucket), runs it and shuts the app down.
|
|
@@ -25,6 +27,11 @@ export async function runCli(options) {
|
|
|
25
27
|
const found = commands.find((candidate) => candidate.name === command);
|
|
26
28
|
if (!found) {
|
|
27
29
|
io.error(`Unknown command "${command}". Run "basalt list" to see what is available.`);
|
|
30
|
+
if (PROJECT_COMMANDS.includes(command)) {
|
|
31
|
+
// A bin/basalt.ts generated before the project commands existed: they
|
|
32
|
+
// live in create-basalt, which also patches this file.
|
|
33
|
+
io.error(`"${command}" is a project command of create-basalt: run \`npx create-basalt@latest ${command}\` (its \`update\` also teaches this bin/basalt.ts to forward it).`);
|
|
34
|
+
}
|
|
28
35
|
return 1;
|
|
29
36
|
}
|
|
30
37
|
const code = await found.handle({ app, container: app.container, io, args, flags });
|
package/dist/upgrade.d.ts
CHANGED
|
@@ -42,7 +42,15 @@ export declare function runUpgrade(migrations: Migration[], fs: UpgradeFs, optio
|
|
|
42
42
|
dry?: boolean;
|
|
43
43
|
only?: string;
|
|
44
44
|
}): Promise<UpgradeReport[]>;
|
|
45
|
-
/**
|
|
46
|
-
|
|
45
|
+
/**
|
|
46
|
+
* Node-backed {@link UpgradeFs}. Recursive, skipping build/vcs directories.
|
|
47
|
+
*
|
|
48
|
+
* `list(dir)` returns paths relative to `dir`; `read`/`write` resolve a relative
|
|
49
|
+
* path against `baseDir` — pass the same directory you upgrade (default: the
|
|
50
|
+
* current working directory). Before `baseDir` existed, relative paths always
|
|
51
|
+
* resolved against `process.cwd()`, so `basalt upgrade --dir=<other>` listed
|
|
52
|
+
* one tree and read another.
|
|
53
|
+
*/
|
|
54
|
+
export declare function nodeUpgradeFs(baseDir?: string): UpgradeFs;
|
|
47
55
|
/** `basalt upgrade [--dir=<path>] [--dry] [--only=<migration-id>]` */
|
|
48
56
|
export declare const upgradeCommand: CommandDefinition;
|
package/dist/upgrade.js
CHANGED
|
@@ -40,13 +40,26 @@ export async function runUpgrade(migrations, fs, options) {
|
|
|
40
40
|
}
|
|
41
41
|
return reports;
|
|
42
42
|
}
|
|
43
|
-
/**
|
|
44
|
-
|
|
43
|
+
/**
|
|
44
|
+
* Node-backed {@link UpgradeFs}. Recursive, skipping build/vcs directories.
|
|
45
|
+
*
|
|
46
|
+
* `list(dir)` returns paths relative to `dir`; `read`/`write` resolve a relative
|
|
47
|
+
* path against `baseDir` — pass the same directory you upgrade (default: the
|
|
48
|
+
* current working directory). Before `baseDir` existed, relative paths always
|
|
49
|
+
* resolved against `process.cwd()`, so `basalt upgrade --dir=<other>` listed
|
|
50
|
+
* one tree and read another.
|
|
51
|
+
*/
|
|
52
|
+
export function nodeUpgradeFs(baseDir) {
|
|
45
53
|
const SKIP = new Set(['node_modules', 'dist', '.git', '.next', 'build', 'coverage']);
|
|
54
|
+
const at = async (path) => {
|
|
55
|
+
const { isAbsolute, resolve } = await import('node:path');
|
|
56
|
+
return isAbsolute(path) ? path : resolve(baseDir ?? process.cwd(), path);
|
|
57
|
+
};
|
|
46
58
|
return {
|
|
47
59
|
async list(dir) {
|
|
48
60
|
const { readdir } = await import('node:fs/promises');
|
|
49
61
|
const { join, relative } = await import('node:path');
|
|
62
|
+
const root = await at(dir);
|
|
50
63
|
const out = [];
|
|
51
64
|
const walk = async (current) => {
|
|
52
65
|
const entries = await readdir(current, { withFileTypes: true });
|
|
@@ -56,22 +69,20 @@ export function nodeUpgradeFs() {
|
|
|
56
69
|
await walk(join(current, entry.name));
|
|
57
70
|
}
|
|
58
71
|
else {
|
|
59
|
-
out.push(relative(
|
|
72
|
+
out.push(relative(root, join(current, entry.name)));
|
|
60
73
|
}
|
|
61
74
|
}
|
|
62
75
|
};
|
|
63
|
-
await walk(
|
|
76
|
+
await walk(root);
|
|
64
77
|
return out;
|
|
65
78
|
},
|
|
66
79
|
async read(path) {
|
|
67
80
|
const { readFile } = await import('node:fs/promises');
|
|
68
|
-
|
|
69
|
-
return readFile(isAbsolute(path) ? path : join(process.cwd(), path), 'utf8');
|
|
81
|
+
return readFile(await at(path), 'utf8');
|
|
70
82
|
},
|
|
71
83
|
async write(path, content) {
|
|
72
84
|
const { writeFile } = await import('node:fs/promises');
|
|
73
|
-
|
|
74
|
-
await writeFile(isAbsolute(path) ? path : join(process.cwd(), path), content, 'utf8');
|
|
85
|
+
await writeFile(await at(path), content, 'utf8');
|
|
75
86
|
},
|
|
76
87
|
};
|
|
77
88
|
}
|
|
@@ -80,14 +91,15 @@ export const upgradeCommand = defineCommand({
|
|
|
80
91
|
name: 'upgrade',
|
|
81
92
|
description: 'Apply framework upgrade codemods (--dry to preview, --only=<id>)',
|
|
82
93
|
async handle({ io, flags }) {
|
|
83
|
-
const
|
|
94
|
+
const { resolve } = await import('node:path');
|
|
95
|
+
const dir = resolve(typeof flags['dir'] === 'string' ? flags['dir'] : process.cwd());
|
|
84
96
|
const dry = flags['dry'] === true;
|
|
85
97
|
const only = typeof flags['only'] === 'string' ? flags['only'] : undefined;
|
|
86
98
|
if (only && !MIGRATIONS.some((m) => m.id === only)) {
|
|
87
99
|
io.error(`Unknown migration "${only}". Available: ${MIGRATIONS.map((m) => m.id).join(', ')}.`);
|
|
88
100
|
return 1;
|
|
89
101
|
}
|
|
90
|
-
const reports = await runUpgrade(MIGRATIONS, nodeUpgradeFs(), {
|
|
102
|
+
const reports = await runUpgrade(MIGRATIONS, nodeUpgradeFs(dir), {
|
|
91
103
|
dir,
|
|
92
104
|
dry,
|
|
93
105
|
...(only ? { only } : {}),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@basaltkit/cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"engines": {
|
|
5
5
|
"node": ">=22.5.0"
|
|
6
6
|
},
|
|
@@ -18,12 +18,12 @@
|
|
|
18
18
|
"dist"
|
|
19
19
|
],
|
|
20
20
|
"dependencies": {
|
|
21
|
-
"@basaltkit/core": "^1.
|
|
21
|
+
"@basaltkit/core": "^1.5.0"
|
|
22
22
|
},
|
|
23
23
|
"devDependencies": {
|
|
24
|
-
"@types/node": "^26.
|
|
24
|
+
"@types/node": "^26.6.1",
|
|
25
25
|
"typescript": "^7.0.2",
|
|
26
|
-
"vitest": "^
|
|
26
|
+
"vitest": "^5.0.1",
|
|
27
27
|
"@basaltkit/tsconfig": "^0.24.0"
|
|
28
28
|
},
|
|
29
29
|
"publishConfig": {
|