@nocobase/cli 2.1.0-alpha.20 → 2.1.0-alpha.21
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 +256 -89
- package/README.zh-CN.md +332 -0
- package/bin/run.js +21 -2
- package/dist/commands/build.js +7 -1
- package/dist/commands/db/logs.js +85 -0
- package/dist/commands/db/ps.js +60 -0
- package/dist/commands/db/shared.js +81 -0
- package/dist/commands/db/start.js +55 -7
- package/dist/commands/db/stop.js +70 -0
- package/dist/commands/dev.js +112 -21
- package/dist/commands/down.js +193 -0
- package/dist/commands/download.js +622 -183
- package/dist/commands/env/add.js +233 -131
- package/dist/commands/env/auth.js +9 -8
- package/dist/commands/init.js +696 -103
- package/dist/commands/install.js +1588 -566
- package/dist/commands/logs.js +90 -0
- package/dist/commands/pm/disable.js +35 -3
- package/dist/commands/pm/enable.js +35 -3
- package/dist/commands/pm/list.js +37 -4
- package/dist/commands/prompts-stages.js +144 -0
- package/dist/commands/prompts-test.js +175 -0
- package/dist/commands/ps.js +116 -0
- package/dist/commands/start.js +171 -15
- package/dist/commands/stop.js +90 -0
- package/dist/commands/upgrade.js +559 -11
- package/dist/lib/app-runtime.js +142 -0
- package/dist/lib/auth-store.js +44 -3
- package/dist/lib/bootstrap.js +7 -3
- package/dist/lib/env-auth.js +427 -82
- package/dist/lib/prompt-catalog.js +552 -0
- package/dist/lib/prompt-validators.js +184 -0
- package/dist/lib/prompt-web-ui.js +2027 -0
- package/dist/lib/run-npm.js +71 -7
- package/package.json +3 -3
- package/dist/commands/restart.js +0 -32
- package/dist/lib/init-browser-wizard.js +0 -431
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is part of the NocoBase (R) project.
|
|
3
|
+
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
|
4
|
+
* Authors: NocoBase Team.
|
|
5
|
+
*
|
|
6
|
+
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
|
7
|
+
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
|
+
*/
|
|
9
|
+
import path from 'node:path';
|
|
10
|
+
import { getEnv, loadAuthConfig } from './auth-store.js';
|
|
11
|
+
import { commandOutput, commandSucceeds, run, runNocoBaseCommand } from './run-npm.js';
|
|
12
|
+
const DOCKER_APP_WORKDIR = '/app/nocobase';
|
|
13
|
+
function sanitizeDockerResourceName(value) {
|
|
14
|
+
const normalized = value
|
|
15
|
+
.trim()
|
|
16
|
+
.toLowerCase()
|
|
17
|
+
.replace(/[^a-z0-9_.-]+/g, '-')
|
|
18
|
+
.replace(/-+/g, '-')
|
|
19
|
+
.replace(/^-+|-+$/g, '');
|
|
20
|
+
return normalized || 'nocobase';
|
|
21
|
+
}
|
|
22
|
+
export function defaultWorkspaceName(cwd = process.cwd()) {
|
|
23
|
+
return sanitizeDockerResourceName(`nb-${path.basename(cwd)}`);
|
|
24
|
+
}
|
|
25
|
+
export function buildDockerAppContainerName(envName, workspaceName) {
|
|
26
|
+
const workspace = workspaceName?.trim() || defaultWorkspaceName();
|
|
27
|
+
return sanitizeDockerResourceName(`${workspace}-${envName}-app`);
|
|
28
|
+
}
|
|
29
|
+
export function buildDockerDbContainerName(envName, dbDialect, workspaceName) {
|
|
30
|
+
const workspace = workspaceName?.trim() || defaultWorkspaceName();
|
|
31
|
+
const dialect = dbDialect.trim() || 'postgres';
|
|
32
|
+
return sanitizeDockerResourceName(`${workspace}-${envName}-${dialect}`);
|
|
33
|
+
}
|
|
34
|
+
function normalizeEnvSource(env) {
|
|
35
|
+
const source = String(env.config.source ?? '').trim();
|
|
36
|
+
if (source === 'docker' || source === 'npm' || source === 'git') {
|
|
37
|
+
return source;
|
|
38
|
+
}
|
|
39
|
+
if (env.config.appRootPath) {
|
|
40
|
+
return 'local';
|
|
41
|
+
}
|
|
42
|
+
return undefined;
|
|
43
|
+
}
|
|
44
|
+
export async function resolveManagedAppRuntime(envName) {
|
|
45
|
+
const config = await loadAuthConfig();
|
|
46
|
+
const env = await getEnv(envName, { config });
|
|
47
|
+
if (!env) {
|
|
48
|
+
return undefined;
|
|
49
|
+
}
|
|
50
|
+
const resolvedName = env.name || envName?.trim() || config.currentEnv || 'default';
|
|
51
|
+
const source = normalizeEnvSource(env);
|
|
52
|
+
const workspaceName = config.name?.trim() || defaultWorkspaceName();
|
|
53
|
+
if (source === 'docker') {
|
|
54
|
+
return {
|
|
55
|
+
kind: 'docker',
|
|
56
|
+
env,
|
|
57
|
+
envName: resolvedName,
|
|
58
|
+
source,
|
|
59
|
+
workspaceName,
|
|
60
|
+
containerName: buildDockerAppContainerName(resolvedName, workspaceName),
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
if (env.config.appRootPath) {
|
|
64
|
+
return {
|
|
65
|
+
kind: 'local',
|
|
66
|
+
env,
|
|
67
|
+
envName: resolvedName,
|
|
68
|
+
source: source === 'git' ? 'git' : source === 'npm' ? 'npm' : 'local',
|
|
69
|
+
projectRoot: env.appRootPath,
|
|
70
|
+
workspaceName,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
return {
|
|
74
|
+
kind: 'remote',
|
|
75
|
+
env,
|
|
76
|
+
envName: resolvedName,
|
|
77
|
+
source,
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
export function formatMissingManagedAppEnvMessage(envName) {
|
|
81
|
+
const requested = String(envName ?? '').trim();
|
|
82
|
+
if (requested) {
|
|
83
|
+
return [
|
|
84
|
+
`Env "${requested}" is not configured in this workspace.`,
|
|
85
|
+
`If you want to create a new NocoBase AI environment, run \`nb init --env ${requested}\` first.`,
|
|
86
|
+
].join('\n');
|
|
87
|
+
}
|
|
88
|
+
return 'No NocoBase env is configured yet. Run `nb init` to create one first.';
|
|
89
|
+
}
|
|
90
|
+
export async function runLocalNocoBaseCommand(runtime, args, options) {
|
|
91
|
+
await runNocoBaseCommand(args, {
|
|
92
|
+
cwd: runtime.projectRoot,
|
|
93
|
+
env: runtime.env.envVars,
|
|
94
|
+
stdio: options?.stdio,
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
export async function dockerContainerExists(containerName) {
|
|
98
|
+
return await commandSucceeds('docker', ['container', 'inspect', containerName]);
|
|
99
|
+
}
|
|
100
|
+
export async function dockerContainerIsRunning(containerName) {
|
|
101
|
+
try {
|
|
102
|
+
const output = await commandOutput('docker', ['inspect', '--format', '{{.State.Running}}', containerName], { errorName: 'docker inspect' });
|
|
103
|
+
return output.trim() === 'true';
|
|
104
|
+
}
|
|
105
|
+
catch (_error) {
|
|
106
|
+
return false;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
export async function startDockerContainer(containerName, options) {
|
|
110
|
+
const exists = await dockerContainerExists(containerName);
|
|
111
|
+
if (!exists) {
|
|
112
|
+
throw new Error(`Docker app container "${containerName}" does not exist.`);
|
|
113
|
+
}
|
|
114
|
+
if (await dockerContainerIsRunning(containerName)) {
|
|
115
|
+
return 'already-running';
|
|
116
|
+
}
|
|
117
|
+
await run('docker', ['start', containerName], {
|
|
118
|
+
errorName: 'docker start',
|
|
119
|
+
stdio: options?.stdio,
|
|
120
|
+
});
|
|
121
|
+
return 'started';
|
|
122
|
+
}
|
|
123
|
+
export async function stopDockerContainer(containerName, options) {
|
|
124
|
+
const exists = await dockerContainerExists(containerName);
|
|
125
|
+
if (!exists) {
|
|
126
|
+
throw new Error(`Docker app container "${containerName}" does not exist.`);
|
|
127
|
+
}
|
|
128
|
+
if (!(await dockerContainerIsRunning(containerName))) {
|
|
129
|
+
return 'already-stopped';
|
|
130
|
+
}
|
|
131
|
+
await run('docker', ['stop', containerName], {
|
|
132
|
+
errorName: 'docker stop',
|
|
133
|
+
stdio: options?.stdio,
|
|
134
|
+
});
|
|
135
|
+
return 'stopped';
|
|
136
|
+
}
|
|
137
|
+
export async function runDockerNocoBaseCommand(containerName, args) {
|
|
138
|
+
await startDockerContainer(containerName);
|
|
139
|
+
await run('docker', ['exec', '-w', DOCKER_APP_WORKDIR, containerName, 'yarn', 'nocobase', ...args], {
|
|
140
|
+
errorName: 'docker exec',
|
|
141
|
+
});
|
|
142
|
+
}
|
package/dist/lib/auth-store.js
CHANGED
|
@@ -21,6 +21,7 @@ export async function loadAuthConfig(options = {}) {
|
|
|
21
21
|
const content = await fs.readFile(getConfigFile(options), 'utf8');
|
|
22
22
|
const parsed = JSON.parse(content);
|
|
23
23
|
return {
|
|
24
|
+
name: parsed.name || parsed.dockerResourcePrefix,
|
|
24
25
|
currentEnv: parsed.currentEnv || 'default',
|
|
25
26
|
envs: parsed.envs || {},
|
|
26
27
|
};
|
|
@@ -53,6 +54,17 @@ export async function setCurrentEnv(envName, options = {}) {
|
|
|
53
54
|
config.currentEnv = envName;
|
|
54
55
|
await saveAuthConfig(config, options);
|
|
55
56
|
}
|
|
57
|
+
export async function ensureWorkspaceName(defaultName, options = {}) {
|
|
58
|
+
const config = await loadAuthConfig(options);
|
|
59
|
+
const existing = config.name?.trim();
|
|
60
|
+
if (existing) {
|
|
61
|
+
return existing;
|
|
62
|
+
}
|
|
63
|
+
const next = defaultName.trim();
|
|
64
|
+
config.name = next;
|
|
65
|
+
await saveAuthConfig(config, options);
|
|
66
|
+
return next;
|
|
67
|
+
}
|
|
56
68
|
export class Env {
|
|
57
69
|
config;
|
|
58
70
|
constructor(config = {}) {
|
|
@@ -87,11 +99,40 @@ export class Env {
|
|
|
87
99
|
}
|
|
88
100
|
return path.resolve(process.cwd(), storagePath);
|
|
89
101
|
}
|
|
102
|
+
get appPort() {
|
|
103
|
+
return this.config.appPort;
|
|
104
|
+
}
|
|
105
|
+
get envVars() {
|
|
106
|
+
const out = {
|
|
107
|
+
STORAGE_PATH: this.storagePath,
|
|
108
|
+
};
|
|
109
|
+
const put = (key, value) => {
|
|
110
|
+
if (value === undefined || value === null) {
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
out[key] = String(value);
|
|
114
|
+
};
|
|
115
|
+
put('APP_PORT', this.appPort);
|
|
116
|
+
put('APP_KEY', this.config.appKey);
|
|
117
|
+
put('TZ', this.config.timezone);
|
|
118
|
+
put('DB_DIALECT', this.config.dbDialect);
|
|
119
|
+
put('DB_HOST', this.config.dbHost);
|
|
120
|
+
put('DB_PORT', this.config.dbPort);
|
|
121
|
+
put('DB_DATABASE', this.config.dbDatabase);
|
|
122
|
+
put('DB_USER', this.config.dbUser);
|
|
123
|
+
put('DB_PASSWORD', this.config.dbPassword);
|
|
124
|
+
return out;
|
|
125
|
+
}
|
|
90
126
|
}
|
|
91
127
|
export async function getEnv(envName, options = {}) {
|
|
92
|
-
const config =
|
|
93
|
-
const
|
|
94
|
-
|
|
128
|
+
const { config: snapshot, ...loadOptions } = options;
|
|
129
|
+
const config = snapshot ?? (await loadAuthConfig(loadOptions));
|
|
130
|
+
const resolved = envName?.trim() || config.currentEnv || 'default';
|
|
131
|
+
const envConfig = config.envs[resolved];
|
|
132
|
+
if (!envConfig) {
|
|
133
|
+
return undefined;
|
|
134
|
+
}
|
|
135
|
+
return new Env({ ...envConfig, name: resolved });
|
|
95
136
|
}
|
|
96
137
|
function areAuthConfigsEquivalent(left, right) {
|
|
97
138
|
if (!left && !right) {
|
package/dist/lib/bootstrap.js
CHANGED
|
@@ -354,9 +354,13 @@ export async function updateEnvRuntime(options) {
|
|
|
354
354
|
});
|
|
355
355
|
if (!baseUrl) {
|
|
356
356
|
throw new Error([
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
357
|
+
env
|
|
358
|
+
? `Env "${envName}" is missing a base URL.`
|
|
359
|
+
: `Env "${envName}" is not configured. Run \`nb env add ${envName}\` first.`,
|
|
360
|
+
env ? 'Update it with `nb env add <name> --base-url <url>` first.' : '',
|
|
361
|
+
]
|
|
362
|
+
.filter(Boolean)
|
|
363
|
+
.join('\n'));
|
|
360
364
|
}
|
|
361
365
|
updateTask('Loading command runtime...');
|
|
362
366
|
try {
|