@nocobase/cli 2.1.0-beta.20 → 2.1.0-beta.22
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 +32 -50
- package/README.zh-CN.md +29 -46
- package/bin/run.js +15 -0
- package/dist/commands/app/down.js +260 -0
- package/dist/commands/app/info.js +140 -0
- package/dist/commands/app/logs.js +98 -0
- package/dist/commands/app/ps.js +60 -0
- package/dist/commands/app/restart.js +75 -0
- package/dist/commands/app/shared.js +95 -0
- package/dist/commands/app/start.js +252 -0
- package/dist/commands/app/stop.js +98 -0
- package/dist/commands/app/upgrade.js +595 -0
- package/dist/commands/build.js +3 -48
- package/dist/commands/db/shared.js +19 -5
- package/dist/commands/dev.js +3 -140
- package/dist/commands/down.js +3 -184
- package/dist/commands/download.js +4 -856
- package/dist/commands/env/add.js +33 -48
- package/dist/commands/env/auth.js +6 -13
- package/dist/commands/env/list.js +10 -15
- package/dist/commands/env/remove.js +4 -10
- package/dist/commands/env/update.js +7 -13
- package/dist/commands/env/use.js +5 -13
- package/dist/commands/{prompts-stages.js → examples/prompts-stages.js} +3 -3
- package/dist/commands/{prompts-test.js → examples/prompts-test.js} +3 -3
- package/dist/commands/init.js +262 -63
- package/dist/commands/install.js +352 -86
- package/dist/commands/logs.js +3 -81
- package/dist/commands/plugin/disable.js +64 -0
- package/dist/commands/plugin/enable.js +64 -0
- package/dist/commands/plugin/list.js +62 -0
- package/dist/commands/pm/disable.js +3 -54
- package/dist/commands/pm/enable.js +3 -54
- package/dist/commands/pm/list.js +3 -45
- package/dist/commands/ps.js +3 -107
- package/dist/commands/restart.js +3 -65
- package/dist/commands/scaffold/migration.js +1 -1
- package/dist/commands/scaffold/plugin.js +1 -1
- package/dist/commands/self/check.js +1 -1
- package/dist/commands/self/update.js +13 -3
- package/dist/commands/skills/check.js +11 -5
- package/dist/commands/skills/index.js +1 -1
- package/dist/commands/skills/install.js +20 -7
- package/dist/commands/skills/remove.js +71 -0
- package/dist/commands/skills/update.js +27 -7
- package/dist/commands/source/build.js +58 -0
- package/dist/commands/source/dev.js +157 -0
- package/dist/commands/source/download.js +866 -0
- package/dist/commands/source/test.js +467 -0
- package/dist/commands/start.js +3 -202
- package/dist/commands/stop.js +3 -81
- package/dist/commands/test.js +3 -457
- package/dist/commands/upgrade.js +3 -574
- package/dist/help/runtime-help.js +3 -0
- package/dist/lib/api-client.js +3 -2
- package/dist/lib/app-health.js +126 -0
- package/dist/lib/app-managed-resources.js +264 -0
- package/dist/lib/app-runtime.js +16 -5
- package/dist/lib/auth-store.js +162 -43
- package/dist/lib/bootstrap.js +13 -12
- package/dist/lib/cli-home.js +38 -6
- package/dist/lib/cli-locale.js +15 -1
- package/dist/lib/env-auth.js +3 -3
- package/dist/lib/env-config.js +80 -0
- package/dist/lib/generated-command.js +10 -2
- package/dist/lib/http-request.js +49 -0
- package/dist/lib/resource-command.js +10 -2
- package/dist/lib/runtime-generator.js +1 -1
- package/dist/lib/self-manager.js +1 -1
- package/dist/lib/skills-manager.js +173 -79
- package/dist/lib/startup-update.js +203 -0
- package/dist/locale/en-US.json +4 -1
- package/dist/locale/zh-CN.json +4 -1
- package/package.json +26 -3
package/dist/lib/auth-store.js
CHANGED
|
@@ -7,33 +7,129 @@
|
|
|
7
7
|
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
8
|
*/
|
|
9
9
|
import { promises as fs } from 'node:fs';
|
|
10
|
-
import path
|
|
11
|
-
import { resolveCliHomeDir } from './cli-home.js';
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
10
|
+
import path from 'node:path';
|
|
11
|
+
import { NB_CLI_ROOT_ENV, resolveCliHomeDir, resolveConfiguredEnvPath, resolveDefaultConfigScope, resolveEnvRelativePath, } from './cli-home.js';
|
|
12
|
+
function normalizeStoredEnvKind(value) {
|
|
13
|
+
const kind = String(value ?? '').trim();
|
|
14
|
+
if (kind === 'remote') {
|
|
15
|
+
return 'http';
|
|
16
|
+
}
|
|
17
|
+
if (kind === 'local' || kind === 'http' || kind === 'docker' || kind === 'ssh') {
|
|
18
|
+
return kind;
|
|
19
|
+
}
|
|
20
|
+
return undefined;
|
|
21
|
+
}
|
|
22
|
+
function normalizeOptionalString(value) {
|
|
23
|
+
const normalized = String(value ?? '').trim();
|
|
24
|
+
return normalized || undefined;
|
|
25
|
+
}
|
|
26
|
+
export function readEnvApiBaseUrl(config) {
|
|
27
|
+
if (!config) {
|
|
28
|
+
return undefined;
|
|
29
|
+
}
|
|
30
|
+
return (normalizeOptionalString(config.apiBaseUrl)
|
|
31
|
+
?? normalizeOptionalString(config.baseUrl)
|
|
32
|
+
?? normalizeOptionalString(config.apibaseUrl));
|
|
33
|
+
}
|
|
34
|
+
export function resolveEnvKind(config) {
|
|
35
|
+
if (!config) {
|
|
36
|
+
return undefined;
|
|
37
|
+
}
|
|
38
|
+
const explicitKind = normalizeStoredEnvKind(config.kind);
|
|
39
|
+
if (explicitKind) {
|
|
40
|
+
return explicitKind;
|
|
41
|
+
}
|
|
42
|
+
const source = String(config.source ?? '').trim();
|
|
43
|
+
if (source === 'docker') {
|
|
44
|
+
return 'docker';
|
|
45
|
+
}
|
|
46
|
+
if (source === 'npm' || source === 'git' || source === 'local') {
|
|
47
|
+
return 'local';
|
|
48
|
+
}
|
|
49
|
+
if (String(config.appRootPath ?? '').trim()) {
|
|
50
|
+
return 'local';
|
|
51
|
+
}
|
|
52
|
+
if (readEnvApiBaseUrl(config) || config.auth) {
|
|
53
|
+
return 'http';
|
|
54
|
+
}
|
|
55
|
+
return undefined;
|
|
56
|
+
}
|
|
57
|
+
function normalizeEnvConfigEntry(entry) {
|
|
58
|
+
if (!entry) {
|
|
59
|
+
return entry;
|
|
60
|
+
}
|
|
61
|
+
const { kind: _kind, apiBaseUrl: _apiBaseUrl, baseUrl: _baseUrl, apibaseUrl: _legacyApiBaseUrl, ...rest } = entry;
|
|
62
|
+
const normalizedKind = resolveEnvKind(entry);
|
|
63
|
+
const apiBaseUrl = readEnvApiBaseUrl(entry);
|
|
64
|
+
return {
|
|
65
|
+
...rest,
|
|
66
|
+
...(normalizedKind ? { kind: normalizedKind } : {}),
|
|
67
|
+
...(apiBaseUrl !== undefined ? { apiBaseUrl } : {}),
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
function normalizeAuthConfig(config) {
|
|
71
|
+
return {
|
|
72
|
+
name: config.name || config.dockerResourcePrefix,
|
|
73
|
+
currentEnv: config.currentEnv || 'default',
|
|
74
|
+
envs: Object.fromEntries(Object.entries(config.envs || {}).map(([envName, entry]) => [envName, normalizeEnvConfigEntry(entry) ?? {}])),
|
|
75
|
+
};
|
|
76
|
+
}
|
|
16
77
|
function getConfigFile(options = {}) {
|
|
17
78
|
return path.join(resolveCliHomeDir(options.scope), 'config.json');
|
|
18
79
|
}
|
|
19
|
-
|
|
80
|
+
function createDefaultConfig() {
|
|
81
|
+
return {
|
|
82
|
+
currentEnv: 'default',
|
|
83
|
+
envs: {},
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
function hasConfiguredEnvs(config) {
|
|
87
|
+
return Object.keys(config.envs).length > 0;
|
|
88
|
+
}
|
|
89
|
+
function shouldFallbackToLegacyProjectScope(options = {}) {
|
|
90
|
+
const requestedScope = options.scope ?? resolveDefaultConfigScope();
|
|
91
|
+
if (requestedScope !== 'global') {
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
94
|
+
return !process.env[NB_CLI_ROOT_ENV];
|
|
95
|
+
}
|
|
96
|
+
async function loadExactAuthConfig(options = {}) {
|
|
20
97
|
try {
|
|
21
98
|
const content = await fs.readFile(getConfigFile(options), 'utf8');
|
|
22
99
|
const parsed = JSON.parse(content);
|
|
23
|
-
return
|
|
24
|
-
name: parsed.name || parsed.dockerResourcePrefix,
|
|
25
|
-
currentEnv: parsed.currentEnv || 'default',
|
|
26
|
-
envs: parsed.envs || {},
|
|
27
|
-
};
|
|
100
|
+
return normalizeAuthConfig(parsed);
|
|
28
101
|
}
|
|
29
102
|
catch (_error) {
|
|
30
|
-
return
|
|
103
|
+
return createDefaultConfig();
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
async function resolveEnvStorageScope(envName, options = {}) {
|
|
107
|
+
const requestedScope = options.scope ?? resolveDefaultConfigScope();
|
|
108
|
+
if (requestedScope !== 'global') {
|
|
109
|
+
return { ...options, scope: requestedScope };
|
|
110
|
+
}
|
|
111
|
+
const globalConfig = await loadExactAuthConfig({ scope: 'global' });
|
|
112
|
+
if (globalConfig.envs[envName]) {
|
|
113
|
+
return { ...options, scope: 'global' };
|
|
31
114
|
}
|
|
115
|
+
const projectConfig = await loadExactAuthConfig({ scope: 'project' });
|
|
116
|
+
if (projectConfig.envs[envName]) {
|
|
117
|
+
return { ...options, scope: 'project' };
|
|
118
|
+
}
|
|
119
|
+
return { ...options, scope: 'global' };
|
|
120
|
+
}
|
|
121
|
+
export async function loadAuthConfig(options = {}) {
|
|
122
|
+
const config = await loadExactAuthConfig(options);
|
|
123
|
+
if (!shouldFallbackToLegacyProjectScope(options) || hasConfiguredEnvs(config)) {
|
|
124
|
+
return config;
|
|
125
|
+
}
|
|
126
|
+
const legacyProjectConfig = await loadExactAuthConfig({ scope: 'project' });
|
|
127
|
+
return hasConfiguredEnvs(legacyProjectConfig) ? legacyProjectConfig : config;
|
|
32
128
|
}
|
|
33
129
|
export async function saveAuthConfig(config, options = {}) {
|
|
34
130
|
const filePath = getConfigFile(options);
|
|
35
131
|
await fs.mkdir(path.dirname(filePath), { recursive: true });
|
|
36
|
-
await fs.writeFile(filePath, JSON.stringify(config, null, 2));
|
|
132
|
+
await fs.writeFile(filePath, JSON.stringify(normalizeAuthConfig(config), null, 2));
|
|
37
133
|
}
|
|
38
134
|
export async function listEnvs(options = {}) {
|
|
39
135
|
const config = await loadAuthConfig(options);
|
|
@@ -47,15 +143,16 @@ export async function getCurrentEnvName(options = {}) {
|
|
|
47
143
|
return config.currentEnv || 'default';
|
|
48
144
|
}
|
|
49
145
|
export async function setCurrentEnv(envName, options = {}) {
|
|
50
|
-
const
|
|
146
|
+
const writeOptions = await resolveEnvStorageScope(envName, options);
|
|
147
|
+
const config = await loadExactAuthConfig(writeOptions);
|
|
51
148
|
if (!config.envs[envName]) {
|
|
52
149
|
throw new Error(`Env "${envName}" is not configured`);
|
|
53
150
|
}
|
|
54
151
|
config.currentEnv = envName;
|
|
55
|
-
await saveAuthConfig(config,
|
|
152
|
+
await saveAuthConfig(config, writeOptions);
|
|
56
153
|
}
|
|
57
154
|
export async function ensureWorkspaceName(defaultName, options = {}) {
|
|
58
|
-
const config = await
|
|
155
|
+
const config = await loadExactAuthConfig(options);
|
|
59
156
|
const existing = config.name?.trim();
|
|
60
157
|
if (existing) {
|
|
61
158
|
return existing;
|
|
@@ -74,7 +171,10 @@ export class Env {
|
|
|
74
171
|
return this.config.name;
|
|
75
172
|
}
|
|
76
173
|
get baseUrl() {
|
|
77
|
-
return this.config
|
|
174
|
+
return readEnvApiBaseUrl(this.config);
|
|
175
|
+
}
|
|
176
|
+
get apiBaseUrl() {
|
|
177
|
+
return readEnvApiBaseUrl(this.config);
|
|
78
178
|
}
|
|
79
179
|
get auth() {
|
|
80
180
|
return this.config.auth;
|
|
@@ -82,22 +182,26 @@ export class Env {
|
|
|
82
182
|
get runtime() {
|
|
83
183
|
return this.config.runtime;
|
|
84
184
|
}
|
|
185
|
+
get kind() {
|
|
186
|
+
return resolveEnvKind(this.config);
|
|
187
|
+
}
|
|
85
188
|
get appRootPath() {
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
return appRootPath;
|
|
189
|
+
if (this.kind === 'ssh') {
|
|
190
|
+
const configuredPath = String(this.config.appRootPath ?? '').trim();
|
|
191
|
+
if (configuredPath) {
|
|
192
|
+
return configuredPath;
|
|
193
|
+
}
|
|
92
194
|
}
|
|
93
|
-
return
|
|
195
|
+
return resolveConfiguredEnvPath(this.config.appRootPath) ?? resolveEnvRelativePath('.');
|
|
94
196
|
}
|
|
95
197
|
get storagePath() {
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
198
|
+
if (this.kind === 'ssh') {
|
|
199
|
+
const configuredPath = String(this.config.storagePath ?? '').trim();
|
|
200
|
+
if (configuredPath) {
|
|
201
|
+
return configuredPath;
|
|
202
|
+
}
|
|
99
203
|
}
|
|
100
|
-
return
|
|
204
|
+
return resolveConfiguredEnvPath(this.config.storagePath) ?? resolveEnvRelativePath('.');
|
|
101
205
|
}
|
|
102
206
|
get appPort() {
|
|
103
207
|
return this.config.appPort;
|
|
@@ -130,9 +234,18 @@ export async function getEnv(envName, options = {}) {
|
|
|
130
234
|
const resolved = envName?.trim() || config.currentEnv || 'default';
|
|
131
235
|
const envConfig = config.envs[resolved];
|
|
132
236
|
if (!envConfig) {
|
|
133
|
-
|
|
237
|
+
if (!shouldFallbackToLegacyProjectScope(loadOptions)) {
|
|
238
|
+
return undefined;
|
|
239
|
+
}
|
|
240
|
+
const legacyProjectConfig = await loadExactAuthConfig({ scope: 'project' });
|
|
241
|
+
const legacyResolved = envName?.trim() || legacyProjectConfig.currentEnv || 'default';
|
|
242
|
+
const legacyEnvConfig = legacyProjectConfig.envs[legacyResolved];
|
|
243
|
+
if (!legacyEnvConfig) {
|
|
244
|
+
return undefined;
|
|
245
|
+
}
|
|
246
|
+
return new Env({ ...(normalizeEnvConfigEntry(legacyEnvConfig) ?? {}), name: legacyResolved });
|
|
134
247
|
}
|
|
135
|
-
return new Env({ ...envConfig, name: resolved });
|
|
248
|
+
return new Env({ ...(normalizeEnvConfigEntry(envConfig) ?? {}), name: resolved });
|
|
136
249
|
}
|
|
137
250
|
function areAuthConfigsEquivalent(left, right) {
|
|
138
251
|
if (!left && !right) {
|
|
@@ -156,16 +269,19 @@ function areAuthConfigsEquivalent(left, right) {
|
|
|
156
269
|
return false;
|
|
157
270
|
}
|
|
158
271
|
async function writeEnv(envName, updater, options = {}) {
|
|
159
|
-
const
|
|
272
|
+
const writeOptions = await resolveEnvStorageScope(envName, options);
|
|
273
|
+
const config = await loadExactAuthConfig(writeOptions);
|
|
160
274
|
const previous = config.envs[envName];
|
|
161
275
|
config.envs[envName] = updater(previous);
|
|
162
276
|
config.currentEnv = envName;
|
|
163
|
-
await saveAuthConfig(config,
|
|
277
|
+
await saveAuthConfig(config, writeOptions);
|
|
164
278
|
}
|
|
165
279
|
export async function upsertEnv(envName, config, options = {}) {
|
|
166
280
|
await writeEnv(envName, (previous) => {
|
|
167
|
-
const { baseUrl, accessToken, ...rest } = config;
|
|
168
|
-
const
|
|
281
|
+
const { apiBaseUrl: _apiBaseUrl, baseUrl: _baseUrl, apibaseUrl: _legacyApiBaseUrl, accessToken, ...rest } = config;
|
|
282
|
+
const nextApiBaseUrl = readEnvApiBaseUrl(config);
|
|
283
|
+
const previousApiBaseUrl = readEnvApiBaseUrl(previous);
|
|
284
|
+
const baseUrlChanged = previousApiBaseUrl !== nextApiBaseUrl;
|
|
169
285
|
const nextAuth = accessToken
|
|
170
286
|
? {
|
|
171
287
|
type: 'token',
|
|
@@ -177,7 +293,7 @@ export async function upsertEnv(envName, config, options = {}) {
|
|
|
177
293
|
const authChanged = !areAuthConfigsEquivalent(previous?.auth, nextAuth);
|
|
178
294
|
return {
|
|
179
295
|
...previous,
|
|
180
|
-
|
|
296
|
+
apiBaseUrl: nextApiBaseUrl,
|
|
181
297
|
auth: nextAuth,
|
|
182
298
|
...rest,
|
|
183
299
|
runtime: baseUrlChanged || authChanged ? undefined : previous?.runtime,
|
|
@@ -186,8 +302,9 @@ export async function upsertEnv(envName, config, options = {}) {
|
|
|
186
302
|
}
|
|
187
303
|
export async function updateEnvConnection(envName, updates, options = {}) {
|
|
188
304
|
await writeEnv(envName, (previous) => {
|
|
189
|
-
const
|
|
190
|
-
const
|
|
305
|
+
const nextApiBaseUrl = readEnvApiBaseUrl(updates) ?? readEnvApiBaseUrl(previous);
|
|
306
|
+
const previousApiBaseUrl = readEnvApiBaseUrl(previous);
|
|
307
|
+
const baseUrlChanged = previousApiBaseUrl !== nextApiBaseUrl;
|
|
191
308
|
const nextAuth = updates.accessToken
|
|
192
309
|
? {
|
|
193
310
|
type: 'token',
|
|
@@ -199,7 +316,7 @@ export async function updateEnvConnection(envName, updates, options = {}) {
|
|
|
199
316
|
const authChanged = !areAuthConfigsEquivalent(previous?.auth, nextAuth);
|
|
200
317
|
return {
|
|
201
318
|
...previous,
|
|
202
|
-
...(
|
|
319
|
+
...(nextApiBaseUrl !== undefined ? { apiBaseUrl: nextApiBaseUrl } : {}),
|
|
203
320
|
auth: nextAuth,
|
|
204
321
|
runtime: baseUrlChanged || authChanged ? undefined : previous?.runtime,
|
|
205
322
|
};
|
|
@@ -213,17 +330,19 @@ export async function setEnvOauthSession(envName, auth, options = {}) {
|
|
|
213
330
|
}), options);
|
|
214
331
|
}
|
|
215
332
|
export async function setEnvRuntime(envName, runtime, options = {}) {
|
|
216
|
-
const
|
|
333
|
+
const writeOptions = await resolveEnvStorageScope(envName, options);
|
|
334
|
+
const config = await loadExactAuthConfig(writeOptions);
|
|
217
335
|
const current = config.envs[envName] ?? {};
|
|
218
336
|
config.envs[envName] = {
|
|
219
337
|
...current,
|
|
220
338
|
runtime,
|
|
221
339
|
};
|
|
222
340
|
config.currentEnv = envName;
|
|
223
|
-
await saveAuthConfig(config,
|
|
341
|
+
await saveAuthConfig(config, writeOptions);
|
|
224
342
|
}
|
|
225
343
|
export async function removeEnv(envName, options = {}) {
|
|
226
|
-
const
|
|
344
|
+
const writeOptions = await resolveEnvStorageScope(envName, options);
|
|
345
|
+
const config = await loadExactAuthConfig(writeOptions);
|
|
227
346
|
if (!config.envs[envName]) {
|
|
228
347
|
throw new Error(`Env "${envName}" is not configured`);
|
|
229
348
|
}
|
|
@@ -232,7 +351,7 @@ export async function removeEnv(envName, options = {}) {
|
|
|
232
351
|
const nextEnv = Object.keys(config.envs).sort()[0];
|
|
233
352
|
config.currentEnv = nextEnv ?? 'default';
|
|
234
353
|
}
|
|
235
|
-
await saveAuthConfig(config,
|
|
354
|
+
await saveAuthConfig(config, writeOptions);
|
|
236
355
|
return {
|
|
237
356
|
removed: envName,
|
|
238
357
|
currentEnv: config.currentEnv || 'default',
|
package/dist/lib/bootstrap.js
CHANGED
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
*/
|
|
9
9
|
import { getCurrentEnvName, getEnv, setEnvRuntime, updateEnvConnection } from './auth-store.js';
|
|
10
10
|
import { resolveAccessToken } from './env-auth.js';
|
|
11
|
+
import { fetchWithPreservedAuthRedirect } from './http-request.js';
|
|
11
12
|
import { generateRuntime } from './runtime-generator.js';
|
|
12
13
|
import { hasRuntimeSync, saveRuntime } from './runtime-store.js';
|
|
13
14
|
import { confirmAction, printInfo, printVerbose, printWarningBlock, setVerboseMode, stopTask, updateTask } from './ui.js';
|
|
@@ -92,7 +93,7 @@ async function requestJson(url, options) {
|
|
|
92
93
|
}
|
|
93
94
|
let response;
|
|
94
95
|
try {
|
|
95
|
-
response = await
|
|
96
|
+
response = await fetchWithPreservedAuthRedirect(url, {
|
|
96
97
|
method: options.method ?? 'GET',
|
|
97
98
|
headers,
|
|
98
99
|
});
|
|
@@ -144,7 +145,7 @@ async function waitForServiceReady(baseUrl, token, role) {
|
|
|
144
145
|
const startedAt = Date.now();
|
|
145
146
|
let notified = false;
|
|
146
147
|
while (Date.now() - startedAt < APP_RETRY_TIMEOUT) {
|
|
147
|
-
const response = await
|
|
148
|
+
const response = await fetchWithPreservedAuthRedirect(healthCheckUrl, {
|
|
148
149
|
method: 'GET',
|
|
149
150
|
headers: token || role
|
|
150
151
|
? {
|
|
@@ -228,14 +229,14 @@ function collectErrorEntries(data) {
|
|
|
228
229
|
}
|
|
229
230
|
return [];
|
|
230
231
|
}
|
|
231
|
-
function
|
|
232
|
-
return collectErrorEntries(data).some((entry) => entry?.code === 'INVALID_TOKEN');
|
|
232
|
+
function hasAuthenticationError(data) {
|
|
233
|
+
return collectErrorEntries(data).some((entry) => entry?.code === 'INVALID_TOKEN' || entry?.code === 'EMPTY_TOKEN');
|
|
233
234
|
}
|
|
234
235
|
function isNetworkFetchFailure(response) {
|
|
235
236
|
return response.status === 0;
|
|
236
237
|
}
|
|
237
238
|
export function formatSwaggerSchemaError(response, context) {
|
|
238
|
-
if (
|
|
239
|
+
if (hasAuthenticationError(response.data)) {
|
|
239
240
|
const entries = collectErrorEntries(response.data);
|
|
240
241
|
const details = entries
|
|
241
242
|
.map((entry) => {
|
|
@@ -251,7 +252,7 @@ export function formatSwaggerSchemaError(response, context) {
|
|
|
251
252
|
`Authentication failed while loading the command runtime from \`swagger:get\`${envLabel}.`,
|
|
252
253
|
`Base URL: ${context.baseUrl}`,
|
|
253
254
|
details,
|
|
254
|
-
'Update the API key with `nb env add <name> --base-url <url> --auth-type token --token <api-key>`, log in with `nb env auth <name>`, or rerun the command with `--token <api-key>`.',
|
|
255
|
+
'Update the API key with `nb env add <name> --api-base-url <url> --auth-type token --token <api-key>`, log in with `nb env auth <name>`, or rerun the command with `--token <api-key>`.',
|
|
255
256
|
commandHint,
|
|
256
257
|
].join('\n');
|
|
257
258
|
}
|
|
@@ -262,7 +263,7 @@ export function formatSwaggerSchemaError(response, context) {
|
|
|
262
263
|
`Base URL: ${context.baseUrl}`,
|
|
263
264
|
`Network error: ${rawMessage}`,
|
|
264
265
|
'Check that the NocoBase app is running, the base URL is correct, and the server is reachable from this machine.',
|
|
265
|
-
'If you recently changed the server address, update it with `nb env add <name> --base-url <url>` and retry `nb env update`.',
|
|
266
|
+
'If you recently changed the server address, update it with `nb env add <name> --api-base-url <url>` and retry `nb env update`.',
|
|
266
267
|
'Use `nb env list` to inspect the current env configuration.',
|
|
267
268
|
].join('\n');
|
|
268
269
|
}
|
|
@@ -272,7 +273,7 @@ export function formatMissingRuntimeEnvError(commandToken) {
|
|
|
272
273
|
if (!commandToken) {
|
|
273
274
|
return [
|
|
274
275
|
'No env is configured for runtime commands.',
|
|
275
|
-
'Run `nb env add <name> --base-url <url>` first.',
|
|
276
|
+
'Run `nb env add <name> --api-base-url <url>` first.',
|
|
276
277
|
'If you configure multiple environments later, switch with `nb env use <name>`.',
|
|
277
278
|
].join('\n');
|
|
278
279
|
}
|
|
@@ -280,7 +281,7 @@ export function formatMissingRuntimeEnvError(commandToken) {
|
|
|
280
281
|
`Unable to resolve runtime command \`${commandToken}\`.`,
|
|
281
282
|
'No env is configured, so the CLI cannot load runtime commands from `swagger:get`.',
|
|
282
283
|
'If this is a built-in command or a typo, run `nb --help` to inspect available commands.',
|
|
283
|
-
'If this should be an application runtime command, run `nb env add <name> --base-url <url>` and then `nb env update`.',
|
|
284
|
+
'If this should be an application runtime command, run `nb env add <name> --api-base-url <url>` and then `nb env update`.',
|
|
284
285
|
].join('\n');
|
|
285
286
|
}
|
|
286
287
|
export async function ensureRuntimeFromArgv(argv, options) {
|
|
@@ -294,7 +295,7 @@ export async function ensureRuntimeFromArgv(argv, options) {
|
|
|
294
295
|
try {
|
|
295
296
|
const envName = readFlag(argv, 'env') ?? (await getCurrentEnvName());
|
|
296
297
|
const env = await getEnv(envName);
|
|
297
|
-
const baseUrl = readFlag(argv, 'base-url') ?? env?.baseUrl;
|
|
298
|
+
const baseUrl = readFlag(argv, 'api-base-url') ?? env?.baseUrl;
|
|
298
299
|
const role = readFlag(argv, 'role');
|
|
299
300
|
const token = await resolveAccessToken({
|
|
300
301
|
envName,
|
|
@@ -357,7 +358,7 @@ export async function updateEnvRuntime(options) {
|
|
|
357
358
|
env
|
|
358
359
|
? `Env "${envName}" is missing a base URL.`
|
|
359
360
|
: `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
|
+
env ? 'Update it with `nb env add <name> --api-base-url <url>` first.' : '',
|
|
361
362
|
]
|
|
362
363
|
.filter(Boolean)
|
|
363
364
|
.join('\n'));
|
|
@@ -370,7 +371,7 @@ export async function updateEnvRuntime(options) {
|
|
|
370
371
|
await saveRuntime(runtime, { scope: options.scope });
|
|
371
372
|
if (options.baseUrl !== undefined || options.token !== undefined) {
|
|
372
373
|
await updateEnvConnection(envName, {
|
|
373
|
-
|
|
374
|
+
apiBaseUrl: options.baseUrl,
|
|
374
375
|
accessToken: options.token,
|
|
375
376
|
}, { scope: options.scope });
|
|
376
377
|
}
|
package/dist/lib/cli-home.js
CHANGED
|
@@ -1,14 +1,29 @@
|
|
|
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
|
+
*/
|
|
1
9
|
import fs from 'node:fs';
|
|
2
10
|
import os from 'node:os';
|
|
3
11
|
import path from 'node:path';
|
|
4
12
|
export const CLI_HOME_DIRNAME = '.nocobase';
|
|
13
|
+
export const NB_CONFIG_SCOPE_ENV = 'NB_CONFIG_SCOPE';
|
|
14
|
+
export const NB_CLI_ROOT_ENV = 'NB_CLI_ROOT';
|
|
15
|
+
export function resolveDefaultConfigScope() {
|
|
16
|
+
const raw = String(process.env[NB_CONFIG_SCOPE_ENV] ?? '').trim().toLowerCase();
|
|
17
|
+
return raw === 'project' ? 'project' : 'global';
|
|
18
|
+
}
|
|
19
|
+
function readConfiguredPath(name) {
|
|
20
|
+
const value = String(process.env[name] ?? '').trim();
|
|
21
|
+
return value || undefined;
|
|
22
|
+
}
|
|
5
23
|
function resolveGlobalCliHomeRoot() {
|
|
6
|
-
|
|
7
|
-
return process.env.NOCOBASE_CTL_HOME;
|
|
8
|
-
}
|
|
9
|
-
return os.homedir();
|
|
24
|
+
return readConfiguredPath(NB_CLI_ROOT_ENV) ?? os.homedir();
|
|
10
25
|
}
|
|
11
|
-
export function resolveCliHomeRoot(scope =
|
|
26
|
+
export function resolveCliHomeRoot(scope = resolveDefaultConfigScope()) {
|
|
12
27
|
const cwdRoot = process.cwd();
|
|
13
28
|
if (scope === 'project') {
|
|
14
29
|
return cwdRoot;
|
|
@@ -22,9 +37,26 @@ export function resolveCliHomeRoot(scope = 'auto') {
|
|
|
22
37
|
}
|
|
23
38
|
return resolveGlobalCliHomeRoot();
|
|
24
39
|
}
|
|
25
|
-
export function resolveCliHomeDir(scope =
|
|
40
|
+
export function resolveCliHomeDir(scope = resolveDefaultConfigScope()) {
|
|
26
41
|
return path.join(resolveCliHomeRoot(scope), CLI_HOME_DIRNAME);
|
|
27
42
|
}
|
|
43
|
+
export function resolveEnvRoot(scope = resolveDefaultConfigScope()) {
|
|
44
|
+
const envRoot = readConfiguredPath(NB_CLI_ROOT_ENV);
|
|
45
|
+
if (envRoot) {
|
|
46
|
+
return path.resolve(envRoot);
|
|
47
|
+
}
|
|
48
|
+
return resolveCliHomeRoot(scope);
|
|
49
|
+
}
|
|
50
|
+
export function resolveEnvRelativePath(relativePath, scope = resolveDefaultConfigScope()) {
|
|
51
|
+
return path.resolve(resolveEnvRoot(scope), relativePath);
|
|
52
|
+
}
|
|
53
|
+
export function resolveConfiguredEnvPath(value, scope = resolveDefaultConfigScope()) {
|
|
54
|
+
const text = String(value ?? '').trim();
|
|
55
|
+
if (!text) {
|
|
56
|
+
return undefined;
|
|
57
|
+
}
|
|
58
|
+
return path.isAbsolute(text) ? text : resolveEnvRelativePath(text, scope);
|
|
59
|
+
}
|
|
28
60
|
export function formatCliHomeScope(scope) {
|
|
29
61
|
return scope === 'project' ? 'project' : 'global';
|
|
30
62
|
}
|
package/dist/lib/cli-locale.js
CHANGED
|
@@ -7,6 +7,8 @@
|
|
|
7
7
|
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
8
|
*/
|
|
9
9
|
import { readFileSync } from 'node:fs';
|
|
10
|
+
import path from 'node:path';
|
|
11
|
+
import { fileURLToPath } from 'node:url';
|
|
10
12
|
export const SUPPORTED_CLI_LOCALES = ['en-US', 'zh-CN'];
|
|
11
13
|
export const CLI_LOCALE_FLAG_OPTIONS = [...SUPPORTED_CLI_LOCALES];
|
|
12
14
|
export const CLI_LOCALE_FLAG_DESCRIPTION = 'Language for CLI prompts and the local setup UI.';
|
|
@@ -30,8 +32,20 @@ function loadLocaleMessages(locale) {
|
|
|
30
32
|
if (localeCache[locale]) {
|
|
31
33
|
return localeCache[locale];
|
|
32
34
|
}
|
|
35
|
+
const moduleDir = path.dirname(fileURLToPath(import.meta.url));
|
|
36
|
+
const fallbackPath = path.resolve(moduleDir, '..', 'locale', `${locale}.json`);
|
|
33
37
|
const fileUrl = new URL(`../locale/${locale}.json`, import.meta.url);
|
|
34
|
-
|
|
38
|
+
let parsed;
|
|
39
|
+
try {
|
|
40
|
+
parsed = JSON.parse(readFileSync(fileUrl, 'utf8'));
|
|
41
|
+
}
|
|
42
|
+
catch (error) {
|
|
43
|
+
const code = error && typeof error === 'object' && 'code' in error ? String(error.code) : '';
|
|
44
|
+
if (code !== 'ENOENT') {
|
|
45
|
+
throw error;
|
|
46
|
+
}
|
|
47
|
+
parsed = JSON.parse(readFileSync(fallbackPath, 'utf8'));
|
|
48
|
+
}
|
|
35
49
|
localeCache[locale] = parsed;
|
|
36
50
|
return parsed;
|
|
37
51
|
}
|
package/dist/lib/env-auth.js
CHANGED
|
@@ -750,7 +750,7 @@ export async function resolveAccessToken(options) {
|
|
|
750
750
|
}
|
|
751
751
|
const baseUrl = options.baseUrl ?? env.baseUrl;
|
|
752
752
|
if (!baseUrl) {
|
|
753
|
-
throw new Error(`Env "${envName}" is missing a base URL. Run \`nb env add ${envName} --base-url <url>\`.`);
|
|
753
|
+
throw new Error(`Env "${envName}" is missing a base URL. Run \`nb env add ${envName} --api-base-url <url>\`.`);
|
|
754
754
|
}
|
|
755
755
|
printVerbose(`Refreshing OAuth session for env "${envName}"`);
|
|
756
756
|
return refreshOauthAccessToken({
|
|
@@ -771,7 +771,7 @@ export async function resolveServerRequestTarget(options) {
|
|
|
771
771
|
scope: options.scope,
|
|
772
772
|
});
|
|
773
773
|
if (!baseUrl) {
|
|
774
|
-
throw new Error('Missing base URL. Use --base-url or configure one with `nb env add`.');
|
|
774
|
+
throw new Error('Missing base URL. Use --api-base-url or configure one with `nb env add`.');
|
|
775
775
|
}
|
|
776
776
|
return { baseUrl, token };
|
|
777
777
|
}
|
|
@@ -785,7 +785,7 @@ export async function authenticateEnvWithOauth(options) {
|
|
|
785
785
|
? `Environment "${envName}" does not have an API base URL yet.`
|
|
786
786
|
: `Environment "${envName}" has not been set up yet.`,
|
|
787
787
|
env
|
|
788
|
-
? `Run \`nb env add ${envName} --base-url <url>\` to finish setting it up.`
|
|
788
|
+
? `Run \`nb env add ${envName} --api-base-url <url>\` to finish setting it up.`
|
|
789
789
|
: `Run \`nb env add ${envName}\` first.`,
|
|
790
790
|
]
|
|
791
791
|
.filter(Boolean)
|
|
@@ -0,0 +1,80 @@
|
|
|
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
|
+
const STRING_ENV_CONFIG_KEYS = [
|
|
10
|
+
'source',
|
|
11
|
+
'downloadVersion',
|
|
12
|
+
'dockerRegistry',
|
|
13
|
+
'dockerPlatform',
|
|
14
|
+
'gitUrl',
|
|
15
|
+
'npmRegistry',
|
|
16
|
+
'appRootPath',
|
|
17
|
+
'storagePath',
|
|
18
|
+
'appPort',
|
|
19
|
+
'appKey',
|
|
20
|
+
'timezone',
|
|
21
|
+
'dbDialect',
|
|
22
|
+
'builtinDbImage',
|
|
23
|
+
'dbHost',
|
|
24
|
+
'dbPort',
|
|
25
|
+
'dbDatabase',
|
|
26
|
+
'dbUser',
|
|
27
|
+
'dbPassword',
|
|
28
|
+
'rootUsername',
|
|
29
|
+
'rootEmail',
|
|
30
|
+
'rootPassword',
|
|
31
|
+
'rootNickname',
|
|
32
|
+
];
|
|
33
|
+
const BOOLEAN_ENV_CONFIG_KEYS = [
|
|
34
|
+
'builtinDb',
|
|
35
|
+
'devDependencies',
|
|
36
|
+
'build',
|
|
37
|
+
'buildDts',
|
|
38
|
+
];
|
|
39
|
+
function trimConfigValue(value) {
|
|
40
|
+
const text = String(value ?? '').trim();
|
|
41
|
+
return text || undefined;
|
|
42
|
+
}
|
|
43
|
+
function resolveEnvKind(input) {
|
|
44
|
+
const source = trimConfigValue(input.source);
|
|
45
|
+
const appRootPath = trimConfigValue(input.appRootPath);
|
|
46
|
+
if (source === 'docker') {
|
|
47
|
+
return 'docker';
|
|
48
|
+
}
|
|
49
|
+
if (source === 'npm' || source === 'git' || source === 'local' || appRootPath) {
|
|
50
|
+
return 'local';
|
|
51
|
+
}
|
|
52
|
+
return 'http';
|
|
53
|
+
}
|
|
54
|
+
export function buildStoredEnvConfig(input) {
|
|
55
|
+
const envConfig = {
|
|
56
|
+
kind: resolveEnvKind(input),
|
|
57
|
+
apiBaseUrl: trimConfigValue(input.apiBaseUrl) ?? '',
|
|
58
|
+
};
|
|
59
|
+
for (const key of STRING_ENV_CONFIG_KEYS) {
|
|
60
|
+
const value = trimConfigValue(input[key]);
|
|
61
|
+
if (value) {
|
|
62
|
+
envConfig[key] = value;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
for (const key of BOOLEAN_ENV_CONFIG_KEYS) {
|
|
66
|
+
const value = input[key];
|
|
67
|
+
if (typeof value === 'boolean') {
|
|
68
|
+
envConfig[key] = value;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
if (input.builtinDb === false) {
|
|
72
|
+
envConfig.builtinDbImage = undefined;
|
|
73
|
+
}
|
|
74
|
+
const authType = trimConfigValue(input.authType);
|
|
75
|
+
const accessToken = trimConfigValue(input.accessToken);
|
|
76
|
+
if (authType === 'token' && accessToken) {
|
|
77
|
+
envConfig.accessToken = accessToken;
|
|
78
|
+
}
|
|
79
|
+
return envConfig;
|
|
80
|
+
}
|
|
@@ -1,3 +1,11 @@
|
|
|
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
|
+
*/
|
|
1
9
|
import { Command, Flags } from '@oclif/core';
|
|
2
10
|
import { executeApiRequest } from './api-client.js';
|
|
3
11
|
import { applyPostProcessor } from './post-processors.js';
|
|
@@ -74,7 +82,7 @@ export function createGeneratedFlags(operation) {
|
|
|
74
82
|
exclusive: ['body'],
|
|
75
83
|
});
|
|
76
84
|
}
|
|
77
|
-
flags['base-url'] = Flags.string({
|
|
85
|
+
flags['api-base-url'] = Flags.string({
|
|
78
86
|
description: 'NocoBase API base URL, for example http://localhost:13000/api',
|
|
79
87
|
helpGroup: 'Global',
|
|
80
88
|
});
|
|
@@ -114,7 +122,7 @@ export class GeneratedApiCommand extends Command {
|
|
|
114
122
|
const { flags } = await this.parse(ctor);
|
|
115
123
|
const response = await executeApiRequest({
|
|
116
124
|
envName: flags.env,
|
|
117
|
-
baseUrl: flags['base-url'],
|
|
125
|
+
baseUrl: flags['api-base-url'],
|
|
118
126
|
role: flags.role,
|
|
119
127
|
token: flags.token,
|
|
120
128
|
flags,
|