@nocobase/cli 2.1.0-beta.44.test.3 → 2.1.0-beta.45
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/bin/run.js +40 -3
- package/dist/commands/app/destroy.js +13 -6
- package/dist/commands/app/restart.js +11 -2
- package/dist/commands/app/shared.js +3 -2
- package/dist/commands/app/start.js +10 -2
- package/dist/commands/app/upgrade.js +6 -4
- package/dist/commands/config/delete.js +2 -0
- package/dist/commands/config/get.js +2 -0
- package/dist/commands/config/set.js +2 -0
- package/dist/commands/env/add.js +5 -5
- package/dist/commands/init.js +117 -7
- package/dist/commands/install.js +50 -13
- package/dist/commands/source/test.js +13 -14
- package/dist/lib/app-managed-resources.js +14 -3
- package/dist/lib/auth-store.js +22 -0
- package/dist/lib/cli-config.js +100 -1
- package/dist/lib/cli-entry-error.js +8 -0
- package/dist/lib/command-log.js +284 -0
- package/dist/lib/env-auth.js +4 -1
- package/dist/lib/prompt-catalog-core.js +3 -2
- package/dist/lib/prompt-validators.js +14 -0
- package/dist/lib/prompt-web-ui.js +8 -1
- package/dist/lib/run-npm.js +48 -12
- package/dist/locale/en-US.json +13 -5
- package/dist/locale/zh-CN.json +13 -5
- package/package.json +3 -8
- package/scripts/build.mjs +34 -0
- package/scripts/clean.mjs +9 -0
- package/tsconfig.json +19 -0
package/bin/run.js
CHANGED
|
@@ -66,6 +66,10 @@ if (isDev && !process.env._NOCO_CLI_TSX_CHILD) {
|
|
|
66
66
|
|
|
67
67
|
const bootstrapPath = isDev ? path.join(root, 'src/lib/bootstrap.ts') : path.join(root, 'dist/lib/bootstrap.js');
|
|
68
68
|
const { ensureRuntimeFromArgv } = await import(pathToFileURL(bootstrapPath).href);
|
|
69
|
+
const commandLogPath = isDev ? path.join(root, 'src/lib/command-log.ts') : path.join(root, 'dist/lib/command-log.js');
|
|
70
|
+
const { finalizeCommandLogSessionSync, initCommandLogSession, installCommandLogWriteHooks } = await import(
|
|
71
|
+
pathToFileURL(commandLogPath).href
|
|
72
|
+
);
|
|
69
73
|
const startupUpdatePath = isDev
|
|
70
74
|
? path.join(root, 'src/lib/startup-update.ts')
|
|
71
75
|
: path.join(root, 'dist/lib/startup-update.js');
|
|
@@ -73,15 +77,43 @@ const { maybeRunStartupUpdate } = await import(pathToFileURL(startupUpdatePath).
|
|
|
73
77
|
const cliEntryErrorPath = isDev
|
|
74
78
|
? path.join(root, 'src/lib/cli-entry-error.ts')
|
|
75
79
|
: path.join(root, 'dist/lib/cli-entry-error.js');
|
|
76
|
-
const { formatCliEntryError } = await import(pathToFileURL(cliEntryErrorPath).href);
|
|
80
|
+
const { appendDiagnosticLogPath, formatCliEntryError } = await import(pathToFileURL(cliEntryErrorPath).href);
|
|
77
81
|
const { flush, run, settings } = await import('@oclif/core');
|
|
78
82
|
|
|
79
83
|
if (isDev) {
|
|
80
84
|
settings.debug = true;
|
|
81
85
|
}
|
|
82
86
|
|
|
87
|
+
const cliPackageJson = requireFromCli(path.join(root, 'package.json'));
|
|
88
|
+
const argv = process.argv.slice(2);
|
|
89
|
+
const commandLogSession = await initCommandLogSession({
|
|
90
|
+
argv,
|
|
91
|
+
cwd: process.cwd(),
|
|
92
|
+
sessionId: process.env.NB_SESSION_ID,
|
|
93
|
+
cliVersion: cliPackageJson?.version,
|
|
94
|
+
nodeVersion: process.version,
|
|
95
|
+
platform: process.platform,
|
|
96
|
+
interactive: Boolean(process.stdin.isTTY && process.stdout.isTTY),
|
|
97
|
+
verbose: argv.includes('--verbose'),
|
|
98
|
+
});
|
|
99
|
+
const restoreCommandLogHooks = installCommandLogWriteHooks();
|
|
100
|
+
let commandLogFinalized = false;
|
|
101
|
+
|
|
102
|
+
function finalizeCommandLogOnce(options = {}) {
|
|
103
|
+
if (commandLogFinalized) {
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
commandLogFinalized = true;
|
|
108
|
+
restoreCommandLogHooks?.();
|
|
109
|
+
finalizeCommandLogSessionSync(commandLogSession, options);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
process.once('exit', (code) => {
|
|
113
|
+
finalizeCommandLogOnce({ exitCode: code ?? undefined });
|
|
114
|
+
});
|
|
115
|
+
|
|
83
116
|
try {
|
|
84
|
-
const argv = process.argv.slice(2);
|
|
85
117
|
const startupUpdate = await maybeRunStartupUpdate(argv);
|
|
86
118
|
if (startupUpdate.kind === 'updated') {
|
|
87
119
|
const result = spawnSync(process.execPath, process.argv.slice(1), {
|
|
@@ -100,8 +132,13 @@ try {
|
|
|
100
132
|
}
|
|
101
133
|
await run(argv, import.meta.url);
|
|
102
134
|
flush();
|
|
135
|
+
finalizeCommandLogOnce({ exitCode: 0 });
|
|
103
136
|
} catch (error) {
|
|
104
|
-
const message =
|
|
137
|
+
const message = appendDiagnosticLogPath(
|
|
138
|
+
formatCliEntryError(error, process.argv.slice(2)),
|
|
139
|
+
commandLogSession?.logFile,
|
|
140
|
+
);
|
|
105
141
|
console.error(pc.red(message));
|
|
142
|
+
finalizeCommandLogOnce({ exitCode: 1, errorMessage: message });
|
|
106
143
|
process.exit(1);
|
|
107
144
|
}
|
|
@@ -10,9 +10,11 @@ import { Command, Flags } from '@oclif/core';
|
|
|
10
10
|
import { removeEnv } from '../../lib/auth-store.js';
|
|
11
11
|
import { formatMissingManagedAppEnvMessage, managedAppLifecycleEnvVars, resolveManagedAppRuntime, runLocalNocoBaseCommand, } from '../../lib/app-runtime.js';
|
|
12
12
|
import { hasExplicitEnvSelection } from '../../lib/env-guard.js';
|
|
13
|
+
import { resolveEnvProxyEntryDir, resolveLegacyNginxEnvProxyAppOutputPath } from "../../lib/env-proxy.js";
|
|
13
14
|
import { resolveConfiguredStoragePath } from '../../lib/env-paths.js';
|
|
14
15
|
import { input } from "../../lib/inquirer.js";
|
|
15
16
|
import { announceTargetEnv, failTask, isInteractiveTerminal, printInfo, startTask, succeedTask } from '../../lib/ui.js';
|
|
17
|
+
import path from 'node:path';
|
|
16
18
|
import { builtinDbContainerName, managedDockerNetworkName, removeDockerContainerIfExists, removeDockerNetworkIfUnused, removePathIfExists, resolveManagedLocalAppPath, shouldRemoveManagedLocalAppFiles, } from './shared.js';
|
|
17
19
|
function formatDestroyFailure(envName, message) {
|
|
18
20
|
return [
|
|
@@ -51,9 +53,7 @@ function buildDestroyPrompt(runtime, options) {
|
|
|
51
53
|
if (options.removesManagedLocalAppFiles) {
|
|
52
54
|
lines.push('CLI-managed local app files will also be removed.');
|
|
53
55
|
}
|
|
54
|
-
|
|
55
|
-
lines.push('Custom local app source files will be kept.');
|
|
56
|
-
}
|
|
56
|
+
lines.push('Env-specific proxy entry files generated by `nb env proxy` will also be removed when present.');
|
|
57
57
|
if (options.removesStorageData) {
|
|
58
58
|
lines.push('Storage data will be removed.');
|
|
59
59
|
}
|
|
@@ -195,13 +195,20 @@ export default class AppDestroy extends Command {
|
|
|
195
195
|
await removePathIfExists(localAppPath, `managed app files for "${runtime.envName}"`);
|
|
196
196
|
succeedTask(`Managed local app files removed for "${runtime.envName}".`);
|
|
197
197
|
}
|
|
198
|
-
else if (localAppPath) {
|
|
199
|
-
printInfo(`Keeping custom local app files for "${runtime.envName}" at "${localAppPath}".`);
|
|
200
|
-
}
|
|
201
198
|
else {
|
|
202
199
|
printInfo(`No saved local app path found for "${runtime.envName}".`);
|
|
203
200
|
}
|
|
204
201
|
}
|
|
202
|
+
const proxyEntryDirs = [
|
|
203
|
+
resolveEnvProxyEntryDir(runtime.envName, { provider: 'nginx' }),
|
|
204
|
+
resolveEnvProxyEntryDir(runtime.envName, { provider: 'caddy' }),
|
|
205
|
+
path.dirname(resolveLegacyNginxEnvProxyAppOutputPath(runtime.envName)),
|
|
206
|
+
];
|
|
207
|
+
startTask(`Removing env proxy entry files for "${runtime.envName}"...`);
|
|
208
|
+
for (const proxyEntryDir of proxyEntryDirs) {
|
|
209
|
+
await removePathIfExists(proxyEntryDir, `proxy entry files for "${runtime.envName}"`);
|
|
210
|
+
}
|
|
211
|
+
succeedTask(`Env proxy entry files removed for "${runtime.envName}".`);
|
|
205
212
|
const configuredStoragePath = resolveConfiguredStoragePath(runtime.env.config);
|
|
206
213
|
if (configuredStoragePath) {
|
|
207
214
|
startTask(`Removing storage data for "${runtime.envName}"...`);
|
|
@@ -11,6 +11,7 @@ import { ensureCrossEnvConfirmed, hasExplicitEnvSelection } from '../../lib/env-
|
|
|
11
11
|
import { formatMissingManagedAppEnvMessage, resolveManagedAppRuntime, stopDockerContainer, } from '../../lib/app-runtime.js';
|
|
12
12
|
import { formatAppUrl, resolveManagedAppApiBaseUrl, waitForAppReady } from '../../lib/app-health.js';
|
|
13
13
|
import { recreateSavedDockerApp } from '../../lib/app-managed-resources.js';
|
|
14
|
+
import { resolveAppUrlFromApiBaseUrl } from '../env/shared.js';
|
|
14
15
|
import { run } from '../../lib/run-npm.js';
|
|
15
16
|
import { announceTargetEnv, failTask, startTask, succeedTask } from '../../lib/ui.js';
|
|
16
17
|
function argvHasToken(argv, tokens) {
|
|
@@ -54,6 +55,13 @@ function formatDockerRestartFailure(envName, message) {
|
|
|
54
55
|
`Details: ${message}`,
|
|
55
56
|
].join('\n');
|
|
56
57
|
}
|
|
58
|
+
function resolveDisplayAppUrl(apiBaseUrl, port, appPublicPath) {
|
|
59
|
+
const resolvedFromApiBaseUrl = resolveAppUrlFromApiBaseUrl(apiBaseUrl);
|
|
60
|
+
if (resolvedFromApiBaseUrl) {
|
|
61
|
+
return resolvedFromApiBaseUrl;
|
|
62
|
+
}
|
|
63
|
+
return formatAppUrl(port, appPublicPath);
|
|
64
|
+
}
|
|
57
65
|
export default class AppRestart extends Command {
|
|
58
66
|
static hidden = false;
|
|
59
67
|
static description = 'Restart NocoBase for the selected env. When applicable, the CLI synchronizes licensed commercial plugins first, then restarts the local app or recreates the saved Docker container.';
|
|
@@ -183,10 +191,11 @@ export default class AppRestart extends Command {
|
|
|
183
191
|
failTask(`Failed to recreate NocoBase for "${runtime.envName}".`);
|
|
184
192
|
this.error(formatDockerRestartFailure(runtime.envName, message));
|
|
185
193
|
}
|
|
186
|
-
const
|
|
194
|
+
const apiBaseUrl = resolveManagedAppApiBaseUrl(runtime);
|
|
195
|
+
const appUrl = resolveDisplayAppUrl(apiBaseUrl, runtime.env.appPort === undefined || runtime.env.appPort === null ? undefined : String(runtime.env.appPort), runtime.env.config?.appPublicPath);
|
|
187
196
|
await waitForAppReady({
|
|
188
197
|
envName: runtime.envName,
|
|
189
|
-
apiBaseUrl
|
|
198
|
+
apiBaseUrl,
|
|
190
199
|
containerName: runtime.containerName,
|
|
191
200
|
logHint: `You can inspect startup logs with \`nb app logs --env ${runtime.envName}\`.`,
|
|
192
201
|
...(flags.verbose ? { verbose: true } : {}),
|
|
@@ -11,6 +11,7 @@ import os from 'node:os';
|
|
|
11
11
|
import path from 'node:path';
|
|
12
12
|
import { buildDockerDbContainerName } from '../../lib/app-runtime.js';
|
|
13
13
|
import { resolveConfiguredEnvPath } from '../../lib/cli-home.js';
|
|
14
|
+
import { resolveConfiguredAppPath } from '../../lib/env-paths.js';
|
|
14
15
|
import { commandOutput, run } from '../../lib/run-npm.js';
|
|
15
16
|
export function resolveConfiguredPath(value) {
|
|
16
17
|
return resolveConfiguredEnvPath(value);
|
|
@@ -115,8 +116,8 @@ export function managedDockerNetworkName(runtime) {
|
|
|
115
116
|
return runtime.dockerNetworkName?.trim() || runtime.workspaceName?.trim() || undefined;
|
|
116
117
|
}
|
|
117
118
|
export function resolveManagedLocalAppPath(runtime) {
|
|
118
|
-
return runtime.projectRoot || resolveConfiguredPath(runtime.env.config.appRootPath);
|
|
119
|
+
return resolveConfiguredAppPath(runtime.env.config) || runtime.projectRoot || resolveConfiguredPath(runtime.env.config.appRootPath);
|
|
119
120
|
}
|
|
120
121
|
export function shouldRemoveManagedLocalAppFiles(runtime) {
|
|
121
|
-
return runtime.source === 'npm' || runtime.source === 'git';
|
|
122
|
+
return runtime.source === 'npm' || runtime.source === 'git' || runtime.source === 'local';
|
|
122
123
|
}
|
|
@@ -12,6 +12,7 @@ import { ensureCrossEnvConfirmed, hasExplicitEnvSelection } from '../../lib/env-
|
|
|
12
12
|
import { formatMissingManagedAppEnvMessage, managedAppLifecycleEnvVars, resolveManagedAppRuntime, runLocalNocoBaseCommand, } from '../../lib/app-runtime.js';
|
|
13
13
|
import { AppHealthCheckError, formatAppUrl, isAppReady, resolveManagedAppApiBaseUrl, waitForAppReady, } from '../../lib/app-health.js';
|
|
14
14
|
import { ensureBuiltinDbReady, ensureLocalPostinstall, ensureSavedLocalSource, recreateSavedDockerApp, } from '../../lib/app-managed-resources.js';
|
|
15
|
+
import { resolveAppUrlFromApiBaseUrl } from '../env/shared.js';
|
|
15
16
|
import { readManagedRuntimeEnvValues } from '../../lib/managed-env-file.js';
|
|
16
17
|
import { run } from '../../lib/run-npm.js';
|
|
17
18
|
import { announceTargetEnv, failTask, printInfo, printWarning, startTask, succeedTask } from '../../lib/ui.js';
|
|
@@ -87,6 +88,13 @@ function formatLocalClientExtractWarning(envName, message) {
|
|
|
87
88
|
`Details: ${message}`,
|
|
88
89
|
].join('\n');
|
|
89
90
|
}
|
|
91
|
+
function resolveDisplayAppUrl(apiBaseUrl, port, appPublicPath) {
|
|
92
|
+
const resolvedFromApiBaseUrl = resolveAppUrlFromApiBaseUrl(apiBaseUrl);
|
|
93
|
+
if (resolvedFromApiBaseUrl) {
|
|
94
|
+
return resolvedFromApiBaseUrl;
|
|
95
|
+
}
|
|
96
|
+
return formatAppUrl(port, appPublicPath);
|
|
97
|
+
}
|
|
90
98
|
async function resolveDefaultLocalCdnBaseUrl(runtime) {
|
|
91
99
|
let envValues = {};
|
|
92
100
|
if (runtime.env.config && typeof runtime.env.config === 'object') {
|
|
@@ -222,8 +230,8 @@ export default class AppStart extends Command {
|
|
|
222
230
|
onSucceedTask: succeedTask,
|
|
223
231
|
onFailTask: failTask,
|
|
224
232
|
});
|
|
225
|
-
const appUrl = formatAppUrl(runtime.env.appPort === undefined || runtime.env.appPort === null ? undefined : String(runtime.env.appPort), runtime.env.config?.appPublicPath);
|
|
226
233
|
const apiBaseUrl = resolveManagedAppApiBaseUrl(runtime);
|
|
234
|
+
const appUrl = resolveDisplayAppUrl(apiBaseUrl, runtime.env.appPort === undefined || runtime.env.appPort === null ? undefined : String(runtime.env.appPort), runtime.env.config?.appPublicPath);
|
|
227
235
|
startTask(`Recreating the Docker app container for "${runtime.envName}"...`);
|
|
228
236
|
try {
|
|
229
237
|
await run('docker', ['rm', '-f', runtime.containerName], {
|
|
@@ -282,10 +290,10 @@ export default class AppStart extends Command {
|
|
|
282
290
|
const effectivePort = runtime.env.appPort !== undefined && runtime.env.appPort !== null
|
|
283
291
|
? String(runtime.env.appPort).trim()
|
|
284
292
|
: undefined;
|
|
285
|
-
const appUrl = formatAppUrl(effectivePort, runtime.env.config?.appPublicPath);
|
|
286
293
|
const apiBaseUrl = resolveManagedAppApiBaseUrl(runtime, {
|
|
287
294
|
portOverride: effectivePort,
|
|
288
295
|
});
|
|
296
|
+
const appUrl = resolveDisplayAppUrl(apiBaseUrl, effectivePort, runtime.env.config?.appPublicPath);
|
|
289
297
|
let defaultCdnBaseUrl;
|
|
290
298
|
if (await isAppReady(apiBaseUrl, { requestTimeoutMs: 1_500 })) {
|
|
291
299
|
if (flags.daemon === false) {
|
|
@@ -13,6 +13,7 @@ import { ensureCrossEnvConfirmed, hasExplicitEnvSelection } from '../../lib/env-
|
|
|
13
13
|
import { DEFAULT_DOCKER_REGISTRY } from "../../lib/docker-image.js";
|
|
14
14
|
import { confirm } from "../../lib/inquirer.js";
|
|
15
15
|
import { announceTargetEnv, isInteractiveTerminal, printInfo, printWarning, succeedTask } from '../../lib/ui.js';
|
|
16
|
+
import { resolveAppUrlFromApiBaseUrl } from '../env/shared.js';
|
|
16
17
|
function trimValue(value) {
|
|
17
18
|
return String(value ?? '').trim();
|
|
18
19
|
}
|
|
@@ -25,15 +26,16 @@ function formatAppUrl(port) {
|
|
|
25
26
|
return value ? `http://127.0.0.1:${value}` : undefined;
|
|
26
27
|
}
|
|
27
28
|
function formatDisplayUrl(apiBaseUrl, appPort) {
|
|
29
|
+
const resolvedFromApiBaseUrl = resolveAppUrlFromApiBaseUrl(apiBaseUrl);
|
|
30
|
+
if (resolvedFromApiBaseUrl) {
|
|
31
|
+
return resolvedFromApiBaseUrl;
|
|
32
|
+
}
|
|
28
33
|
const appUrl = formatAppUrl(appPort);
|
|
29
34
|
if (appUrl) {
|
|
30
35
|
return appUrl;
|
|
31
36
|
}
|
|
32
37
|
const value = trimValue(apiBaseUrl);
|
|
33
|
-
|
|
34
|
-
return undefined;
|
|
35
|
-
}
|
|
36
|
-
return value.replace(/\/api\/?$/, '');
|
|
38
|
+
return value ? value.replace(/\/api\/?$/, '') : undefined;
|
|
37
39
|
}
|
|
38
40
|
function readEnvValue(env, key) {
|
|
39
41
|
return trimValue(env.config[key]);
|
|
@@ -23,6 +23,8 @@ export default class ConfigDelete extends Command {
|
|
|
23
23
|
'<%= config.bin %> <%= command.id %> proxy.nb-cli-root',
|
|
24
24
|
'<%= config.bin %> <%= command.id %> proxy.upstream-host',
|
|
25
25
|
'<%= config.bin %> <%= command.id %> bin.yarn',
|
|
26
|
+
'<%= config.bin %> <%= command.id %> log.enabled',
|
|
27
|
+
'<%= config.bin %> <%= command.id %> log.retention-days',
|
|
26
28
|
];
|
|
27
29
|
static args = {
|
|
28
30
|
key: Args.string({
|
|
@@ -22,6 +22,8 @@ export default class ConfigGet extends Command {
|
|
|
22
22
|
'<%= config.bin %> <%= command.id %> proxy.nb-cli-root',
|
|
23
23
|
'<%= config.bin %> <%= command.id %> proxy.upstream-host',
|
|
24
24
|
'<%= config.bin %> <%= command.id %> bin.yarn',
|
|
25
|
+
'<%= config.bin %> <%= command.id %> log.enabled',
|
|
26
|
+
'<%= config.bin %> <%= command.id %> log.retention-days',
|
|
25
27
|
];
|
|
26
28
|
static args = {
|
|
27
29
|
key: Args.string({
|
|
@@ -24,6 +24,8 @@ export default class ConfigSet extends Command {
|
|
|
24
24
|
'<%= config.bin %> <%= command.id %> proxy.nb-cli-root /workspace',
|
|
25
25
|
'<%= config.bin %> <%= command.id %> proxy.upstream-host host.docker.internal',
|
|
26
26
|
'<%= config.bin %> <%= command.id %> bin.yarn yarn',
|
|
27
|
+
'<%= config.bin %> <%= command.id %> log.enabled false',
|
|
28
|
+
'<%= config.bin %> <%= command.id %> log.retention-days 14',
|
|
27
29
|
];
|
|
28
30
|
static args = {
|
|
29
31
|
key: Args.string({
|
package/dist/commands/env/add.js
CHANGED
|
@@ -265,17 +265,17 @@ export default class EnvAdd extends Command {
|
|
|
265
265
|
type: 'select',
|
|
266
266
|
message: envAddText('prompts.authType.message'),
|
|
267
267
|
options: [
|
|
268
|
-
{
|
|
269
|
-
value: 'basic',
|
|
270
|
-
label: envAddText('prompts.authType.basicLabel'),
|
|
271
|
-
hint: envAddText('prompts.authType.basicHint'),
|
|
272
|
-
},
|
|
273
268
|
{
|
|
274
269
|
value: 'oauth',
|
|
275
270
|
label: envAddText('prompts.authType.oauthLabel'),
|
|
276
271
|
hint: envAddText('prompts.authType.oauthHint'),
|
|
277
272
|
},
|
|
278
273
|
{ value: 'token', label: envAddText('prompts.authType.tokenLabel') },
|
|
274
|
+
{
|
|
275
|
+
value: 'basic',
|
|
276
|
+
label: envAddText('prompts.authType.basicLabel'),
|
|
277
|
+
hint: envAddText('prompts.authType.basicHint'),
|
|
278
|
+
},
|
|
279
279
|
],
|
|
280
280
|
initialValue: 'oauth',
|
|
281
281
|
required: true,
|
package/dist/commands/init.js
CHANGED
|
@@ -16,6 +16,7 @@ import { getEnv, upsertEnv } from "../lib/auth-store.js";
|
|
|
16
16
|
import { runPromptCatalog, } from "../lib/prompt-catalog.js";
|
|
17
17
|
import { applyCliLocale, localeText, translateCli } from "../lib/cli-locale.js";
|
|
18
18
|
import { resolveDefaultConfigScope } from '../lib/cli-home.js';
|
|
19
|
+
import { resolveDefaultApiHost, resolveDefaultUiHost } from '../lib/cli-config.js';
|
|
19
20
|
import { areConfiguredPathsEquivalent, deriveConfiguredSourcePath, deriveConfiguredStoragePath, inferConfiguredAppPathFromLegacyConfig, } from '../lib/env-paths.js';
|
|
20
21
|
import { runPromptCatalogWebUI } from "../lib/prompt-web-ui.js";
|
|
21
22
|
import { validateApiBaseUrl, validateEnvKey } from "../lib/prompt-validators.js";
|
|
@@ -84,6 +85,9 @@ function installLikeOnly(def) {
|
|
|
84
85
|
function installNewOnly(def) {
|
|
85
86
|
return withExtraHidden(def, (values) => !isInstallNewSetupMode(values));
|
|
86
87
|
}
|
|
88
|
+
function installConnectionOnly(def) {
|
|
89
|
+
return withExtraHidden(def, (values) => !isInstallNewSetupMode(values));
|
|
90
|
+
}
|
|
87
91
|
function installLikeDownloadExecutionOnly(def) {
|
|
88
92
|
return withExtraHidden(def, (values) => !isInstallLikeSetupMode(values) || values.skipDownload === true);
|
|
89
93
|
}
|
|
@@ -145,6 +149,39 @@ function resolveManagedAppKey(value) {
|
|
|
145
149
|
function resolveManagedTimeZone(value) {
|
|
146
150
|
return optionalInitString(value) ?? (Intl.DateTimeFormat().resolvedOptions().timeZone || 'UTC');
|
|
147
151
|
}
|
|
152
|
+
function normalizeConnectionString(value) {
|
|
153
|
+
return String(value ?? '').trim();
|
|
154
|
+
}
|
|
155
|
+
function deriveInstallConnectionApiBaseUrl(values, defaultApiHost = '127.0.0.1') {
|
|
156
|
+
const appPort = normalizeConnectionString(values.appPort);
|
|
157
|
+
return appPort ? `http://${defaultApiHost}:${appPort}/api` : DEFAULT_INIT_API_BASE_URL;
|
|
158
|
+
}
|
|
159
|
+
function createInstallConnectionApiBaseUrlPrompt(defaultApiHost) {
|
|
160
|
+
return installConnectionOnly({
|
|
161
|
+
type: 'text',
|
|
162
|
+
message: initText('prompts.apiBaseUrl.message'),
|
|
163
|
+
placeholder: initText('prompts.apiBaseUrl.placeholder'),
|
|
164
|
+
required: true,
|
|
165
|
+
initialValue: (values) => deriveInstallConnectionApiBaseUrl(values, defaultApiHost),
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
const installConnectionAuthTypePrompt = installConnectionOnly({
|
|
169
|
+
...EnvAdd.prompts.authType,
|
|
170
|
+
});
|
|
171
|
+
const installConnectionUsernamePrompt = installConnectionOnly({
|
|
172
|
+
...Install.rootUserPrompts.rootUsername,
|
|
173
|
+
hidden: () => true,
|
|
174
|
+
initialValue: (values) => normalizeConnectionString(values.rootUsername),
|
|
175
|
+
});
|
|
176
|
+
const installConnectionPasswordPrompt = installConnectionOnly({
|
|
177
|
+
...Install.rootUserPrompts.rootPassword,
|
|
178
|
+
hidden: () => true,
|
|
179
|
+
initialValue: (values) => String(values.rootPassword ?? ''),
|
|
180
|
+
});
|
|
181
|
+
const installConnectionAccessTokenPrompt = installConnectionOnly({
|
|
182
|
+
...EnvAdd.prompts.accessToken,
|
|
183
|
+
hidden: (values) => values.installAuthType !== 'token' || values.skipAuth === true,
|
|
184
|
+
});
|
|
148
185
|
function shouldAllowExistingInitEnv() {
|
|
149
186
|
return argvHasToken(process.argv.slice(2), ['--force', '-f']);
|
|
150
187
|
}
|
|
@@ -365,10 +402,15 @@ Prompt modes:
|
|
|
365
402
|
rootEmail: installNewOnly(Install.rootUserPrompts.rootEmail),
|
|
366
403
|
rootPassword: installNewOnly(Install.rootUserPrompts.rootPassword),
|
|
367
404
|
rootNickname: installNewOnly(Install.rootUserPrompts.rootNickname),
|
|
405
|
+
installAuthType: installConnectionAuthTypePrompt,
|
|
406
|
+
installUsername: installConnectionUsernamePrompt,
|
|
407
|
+
installPassword: installConnectionPasswordPrompt,
|
|
408
|
+
installAccessToken: installConnectionAccessTokenPrompt,
|
|
368
409
|
};
|
|
369
|
-
buildPromptCatalog(flags) {
|
|
410
|
+
buildPromptCatalog(flags, options) {
|
|
370
411
|
const prompts = {
|
|
371
412
|
...Init.prompts,
|
|
413
|
+
installApiBaseUrl: createInstallConnectionApiBaseUrlPrompt(options.defaultApiHost),
|
|
372
414
|
};
|
|
373
415
|
if (flags['skip-auth']) {
|
|
374
416
|
const accessTokenPrompt = {
|
|
@@ -383,9 +425,24 @@ Prompt modes:
|
|
|
383
425
|
...EnvAdd.prompts.password,
|
|
384
426
|
hidden: () => true,
|
|
385
427
|
};
|
|
428
|
+
const installAccessTokenPrompt = {
|
|
429
|
+
...installConnectionAccessTokenPrompt,
|
|
430
|
+
hidden: () => true,
|
|
431
|
+
};
|
|
432
|
+
const installUsernamePrompt = {
|
|
433
|
+
...installConnectionUsernamePrompt,
|
|
434
|
+
hidden: () => true,
|
|
435
|
+
};
|
|
436
|
+
const installPasswordPrompt = {
|
|
437
|
+
...installConnectionPasswordPrompt,
|
|
438
|
+
hidden: () => true,
|
|
439
|
+
};
|
|
386
440
|
prompts.username = remoteConnectionOnly(usernamePrompt);
|
|
387
441
|
prompts.password = remoteConnectionOnly(passwordPrompt);
|
|
388
442
|
prompts.accessToken = remoteConnectionOnly(accessTokenPrompt);
|
|
443
|
+
prompts.installUsername = installUsernamePrompt;
|
|
444
|
+
prompts.installPassword = installPasswordPrompt;
|
|
445
|
+
prompts.installAccessToken = installAccessTokenPrompt;
|
|
389
446
|
}
|
|
390
447
|
return prompts;
|
|
391
448
|
}
|
|
@@ -508,7 +565,9 @@ Prompt modes:
|
|
|
508
565
|
}
|
|
509
566
|
}
|
|
510
567
|
const dynamicInitialValues = await Init.buildDynamicInitialValuesForInstall(normalizedFlags, presetValues);
|
|
511
|
-
const
|
|
568
|
+
const defaultUiHost = await resolveDefaultUiHost();
|
|
569
|
+
const defaultApiHost = await resolveDefaultApiHost();
|
|
570
|
+
const promptCatalog = this.buildPromptCatalog(normalizedFlags, { defaultApiHost });
|
|
512
571
|
if (useBrowserUi) {
|
|
513
572
|
presetValues = await runPromptCatalogWebUI({
|
|
514
573
|
stages: Init.buildWebUiStages(promptCatalog),
|
|
@@ -516,7 +575,7 @@ Prompt modes:
|
|
|
516
575
|
...dynamicInitialValues,
|
|
517
576
|
...presetValues,
|
|
518
577
|
},
|
|
519
|
-
host: normalizedFlags['ui-host']?.trim() ||
|
|
578
|
+
host: normalizedFlags['ui-host']?.trim() || defaultUiHost,
|
|
520
579
|
port: normalizedFlags['ui-port'] ?? 0,
|
|
521
580
|
pageTitle: initText('webUi.pageTitle'),
|
|
522
581
|
documentHeading: initText('webUi.documentHeading'),
|
|
@@ -553,15 +612,22 @@ Prompt modes:
|
|
|
553
612
|
});
|
|
554
613
|
const normalizedResults = this.normalizeInitResults({
|
|
555
614
|
...pickKeys(presetValues, [
|
|
615
|
+
'defaultApiHost',
|
|
556
616
|
'authType',
|
|
557
617
|
'accessToken',
|
|
558
618
|
'dbSchema',
|
|
559
619
|
'dbTablePrefix',
|
|
560
620
|
'dbUnderscored',
|
|
621
|
+
'installApiBaseUrl',
|
|
622
|
+
'installAuthType',
|
|
623
|
+
'installAccessToken',
|
|
624
|
+
'installUsername',
|
|
625
|
+
'installPassword',
|
|
561
626
|
'skipAuth',
|
|
562
627
|
'username',
|
|
563
628
|
'password',
|
|
564
629
|
]),
|
|
630
|
+
defaultApiHost,
|
|
565
631
|
...results,
|
|
566
632
|
});
|
|
567
633
|
const setupMode = resolveInitSetupMode(normalizedResults);
|
|
@@ -662,6 +728,7 @@ Prompt modes:
|
|
|
662
728
|
lang: c.lang,
|
|
663
729
|
appPath: c.appPath,
|
|
664
730
|
appPort: c.appPort,
|
|
731
|
+
appPublicPath: c.appPublicPath,
|
|
665
732
|
skipDownload: c.skipDownload,
|
|
666
733
|
},
|
|
667
734
|
},
|
|
@@ -711,6 +778,15 @@ Prompt modes:
|
|
|
711
778
|
rootNickname: c.rootNickname,
|
|
712
779
|
},
|
|
713
780
|
},
|
|
781
|
+
{
|
|
782
|
+
sectionTitle: initText('webUi.connectExistingApp.title'),
|
|
783
|
+
sectionDescription: initText('webUi.connectExistingApp.description'),
|
|
784
|
+
catalog: {
|
|
785
|
+
installApiBaseUrl: c.installApiBaseUrl,
|
|
786
|
+
installAuthType: c.installAuthType,
|
|
787
|
+
installAccessToken: c.installAccessToken,
|
|
788
|
+
},
|
|
789
|
+
},
|
|
714
790
|
];
|
|
715
791
|
}
|
|
716
792
|
buildPresetValuesFromFlags(flags) {
|
|
@@ -727,12 +803,17 @@ Prompt modes:
|
|
|
727
803
|
if (apiBaseUrl) {
|
|
728
804
|
preset.setupMode ??= 'connect-remote';
|
|
729
805
|
preset.apiBaseUrl = apiBaseUrl;
|
|
806
|
+
preset.installApiBaseUrl = apiBaseUrl;
|
|
730
807
|
}
|
|
731
808
|
else if (flags['default-api-base-url'] !== undefined && String(flags['default-api-base-url']).trim() !== '') {
|
|
732
|
-
|
|
809
|
+
const defaultApiBaseUrl = String(flags['default-api-base-url']).trim();
|
|
810
|
+
preset.apiBaseUrl = defaultApiBaseUrl;
|
|
811
|
+
preset.installApiBaseUrl = defaultApiBaseUrl;
|
|
733
812
|
}
|
|
734
813
|
if (flags['auth-type'] !== undefined && String(flags['auth-type']).trim() !== '') {
|
|
735
|
-
|
|
814
|
+
const authType = String(flags['auth-type']).trim();
|
|
815
|
+
preset.authType = authType;
|
|
816
|
+
preset.installAuthType = authType;
|
|
736
817
|
}
|
|
737
818
|
if (flags['skip-auth']) {
|
|
738
819
|
preset.skipAuth = true;
|
|
@@ -740,12 +821,17 @@ Prompt modes:
|
|
|
740
821
|
const accessToken = String(flags['access-token'] ?? flags.token ?? '');
|
|
741
822
|
if (flags['access-token'] !== undefined || flags.token !== undefined) {
|
|
742
823
|
preset.accessToken = accessToken;
|
|
824
|
+
preset.installAccessToken = accessToken;
|
|
743
825
|
}
|
|
744
826
|
if (flags.username !== undefined) {
|
|
745
|
-
|
|
827
|
+
const username = String(flags.username ?? '').trim();
|
|
828
|
+
preset.username = username;
|
|
829
|
+
preset.installUsername = username;
|
|
746
830
|
}
|
|
747
831
|
if (flags.password !== undefined) {
|
|
748
|
-
|
|
832
|
+
const password = String(flags.password ?? '');
|
|
833
|
+
preset.password = password;
|
|
834
|
+
preset.installPassword = password;
|
|
749
835
|
}
|
|
750
836
|
if (flags.lang !== undefined && String(flags.lang).trim() !== '') {
|
|
751
837
|
preset.lang = String(flags.lang).trim();
|
|
@@ -901,6 +987,7 @@ Prompt modes:
|
|
|
901
987
|
const envName = String(results.appName ?? DEFAULT_INIT_APP_NAME).trim() || DEFAULT_INIT_APP_NAME;
|
|
902
988
|
const existingEnv = await getEnv(envName, { scope: resolveDefaultConfigScope() });
|
|
903
989
|
const appPort = String(results.appPort ?? '').trim();
|
|
990
|
+
const appPublicPath = String(results.appPublicPath ?? '').trim();
|
|
904
991
|
const source = String(results.source ?? '').trim();
|
|
905
992
|
const version = resolveInitDownloadVersion(results);
|
|
906
993
|
const dockerRegistry = String(results.dockerRegistry ?? '').trim();
|
|
@@ -962,6 +1049,7 @@ Prompt modes:
|
|
|
962
1049
|
...(appRootPath && !areConfiguredPathsEquivalent(appRootPath, derivedAppRootPath) ? { appRootPath } : {}),
|
|
963
1050
|
...(storagePath && !areConfiguredPathsEquivalent(storagePath, derivedStoragePath) ? { storagePath } : {}),
|
|
964
1051
|
...(appPort ? { appPort } : {}),
|
|
1052
|
+
...(appPublicPath ? { appPublicPath } : {}),
|
|
965
1053
|
...(appKey ? { appKey } : {}),
|
|
966
1054
|
...(timeZone ? { timezone: timeZone } : {}),
|
|
967
1055
|
...(!skipDownload && results.devDependencies !== undefined
|
|
@@ -1298,6 +1386,22 @@ Prompt modes:
|
|
|
1298
1386
|
normalizeInitResults(results) {
|
|
1299
1387
|
const normalized = { ...results };
|
|
1300
1388
|
const setupMode = resolveInitSetupMode(normalized);
|
|
1389
|
+
const defaultApiHost = normalizeConnectionString(normalized.defaultApiHost) || '127.0.0.1';
|
|
1390
|
+
if (setupMode === 'install-new') {
|
|
1391
|
+
normalized.apiBaseUrl =
|
|
1392
|
+
normalizeConnectionString(normalized.installApiBaseUrl) ||
|
|
1393
|
+
deriveInstallConnectionApiBaseUrl(normalized, defaultApiHost);
|
|
1394
|
+
normalized.authType = normalizeConnectionString(normalized.installAuthType) || 'oauth';
|
|
1395
|
+
normalized.username =
|
|
1396
|
+
normalized.authType === 'basic'
|
|
1397
|
+
? normalizeConnectionString(normalized.installUsername) || normalizeConnectionString(normalized.rootUsername)
|
|
1398
|
+
: normalizeConnectionString(normalized.installUsername);
|
|
1399
|
+
normalized.password =
|
|
1400
|
+
normalized.authType === 'basic'
|
|
1401
|
+
? String(normalized.installPassword ?? '') || String(normalized.rootPassword ?? '')
|
|
1402
|
+
: String(normalized.installPassword ?? '');
|
|
1403
|
+
normalized.accessToken = String(normalized.installAccessToken ?? '');
|
|
1404
|
+
}
|
|
1301
1405
|
normalized.setupMode = setupMode;
|
|
1302
1406
|
applyLegacyHasNocobaseAlias(normalized);
|
|
1303
1407
|
if (setupMode === 'manage-local') {
|
|
@@ -1307,6 +1411,12 @@ Prompt modes:
|
|
|
1307
1411
|
delete normalized.rootPassword;
|
|
1308
1412
|
delete normalized.rootNickname;
|
|
1309
1413
|
}
|
|
1414
|
+
delete normalized.installApiBaseUrl;
|
|
1415
|
+
delete normalized.installAuthType;
|
|
1416
|
+
delete normalized.installUsername;
|
|
1417
|
+
delete normalized.installPassword;
|
|
1418
|
+
delete normalized.installAccessToken;
|
|
1419
|
+
delete normalized.defaultApiHost;
|
|
1310
1420
|
return normalized;
|
|
1311
1421
|
}
|
|
1312
1422
|
}
|