@nocobase/cli 2.1.0-beta.44.test.3 → 2.1.0-beta.44.test.4

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.
Files changed (77) hide show
  1. package/bin/run.js +40 -3
  2. package/dist/commands/app/destroy.js +13 -6
  3. package/dist/commands/app/restart.js +11 -2
  4. package/dist/commands/app/shared.js +3 -2
  5. package/dist/commands/app/start.js +10 -2
  6. package/dist/commands/app/upgrade.js +6 -4
  7. package/dist/commands/config/delete.js +2 -0
  8. package/dist/commands/config/get.js +2 -0
  9. package/dist/commands/config/set.js +2 -0
  10. package/dist/commands/env/add.js +5 -5
  11. package/dist/commands/init.js +117 -7
  12. package/dist/commands/install.js +50 -13
  13. package/dist/commands/source/download.js +1 -1
  14. package/dist/commands/source/test.js +13 -14
  15. package/dist/locale/en-US.json +13 -5
  16. package/dist/locale/zh-CN.json +13 -5
  17. package/package.json +1 -7
  18. package/scripts/build.mjs +34 -0
  19. package/scripts/clean.mjs +9 -0
  20. package/tsconfig.json +19 -0
  21. package/dist/lib/api-client.js +0 -335
  22. package/dist/lib/api-command-compat.js +0 -641
  23. package/dist/lib/app-health.js +0 -139
  24. package/dist/lib/app-managed-resources.js +0 -321
  25. package/dist/lib/app-public-path.js +0 -80
  26. package/dist/lib/app-runtime.js +0 -189
  27. package/dist/lib/auth-store.js +0 -498
  28. package/dist/lib/backup.js +0 -171
  29. package/dist/lib/bootstrap.js +0 -409
  30. package/dist/lib/build-config.js +0 -18
  31. package/dist/lib/builtin-db.js +0 -86
  32. package/dist/lib/cli-config.js +0 -398
  33. package/dist/lib/cli-entry-error.js +0 -44
  34. package/dist/lib/cli-home.js +0 -47
  35. package/dist/lib/cli-locale.js +0 -141
  36. package/dist/lib/command-discovery.js +0 -39
  37. package/dist/lib/db-connection-check.js +0 -219
  38. package/dist/lib/docker-env-file.js +0 -60
  39. package/dist/lib/docker-image.js +0 -37
  40. package/dist/lib/docker-log-stream.js +0 -45
  41. package/dist/lib/env-auth.js +0 -960
  42. package/dist/lib/env-command-config.js +0 -45
  43. package/dist/lib/env-config.js +0 -100
  44. package/dist/lib/env-guard.js +0 -61
  45. package/dist/lib/env-paths.js +0 -101
  46. package/dist/lib/env-proxy.js +0 -1295
  47. package/dist/lib/generated-command.js +0 -203
  48. package/dist/lib/http-request.js +0 -49
  49. package/dist/lib/inquirer-theme.js +0 -17
  50. package/dist/lib/inquirer.js +0 -243
  51. package/dist/lib/managed-env-file.js +0 -98
  52. package/dist/lib/naming.js +0 -70
  53. package/dist/lib/object-utils.js +0 -76
  54. package/dist/lib/openapi.js +0 -62
  55. package/dist/lib/plugin-import.js +0 -279
  56. package/dist/lib/plugin-storage.js +0 -64
  57. package/dist/lib/post-processors.js +0 -23
  58. package/dist/lib/prompt-catalog-core.js +0 -185
  59. package/dist/lib/prompt-catalog-terminal.js +0 -375
  60. package/dist/lib/prompt-catalog.js +0 -10
  61. package/dist/lib/prompt-validators.js +0 -258
  62. package/dist/lib/prompt-web-ui.js +0 -2227
  63. package/dist/lib/resource-command.js +0 -357
  64. package/dist/lib/resource-request.js +0 -104
  65. package/dist/lib/run-npm.js +0 -393
  66. package/dist/lib/runtime-env-vars.js +0 -32
  67. package/dist/lib/runtime-generator.js +0 -498
  68. package/dist/lib/runtime-store.js +0 -56
  69. package/dist/lib/self-manager.js +0 -301
  70. package/dist/lib/session-id.js +0 -17
  71. package/dist/lib/session-integration.js +0 -703
  72. package/dist/lib/session-store.js +0 -118
  73. package/dist/lib/skills-manager.js +0 -438
  74. package/dist/lib/source-publish.js +0 -326
  75. package/dist/lib/source-registry.js +0 -188
  76. package/dist/lib/startup-update.js +0 -309
  77. package/dist/lib/ui.js +0 -159
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 = formatCliEntryError(error, process.argv.slice(2));
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
- else if (runtime.kind === 'local') {
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 appUrl = formatAppUrl(runtime.env.appPort === undefined || runtime.env.appPort === null ? undefined : String(runtime.env.appPort), runtime.env.config?.appPublicPath);
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: resolveManagedAppApiBaseUrl(runtime),
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
- if (!value) {
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({
@@ -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,
@@ -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 promptCatalog = this.buildPromptCatalog(normalizedFlags);
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() || '127.0.0.1',
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
- preset.apiBaseUrl = String(flags['default-api-base-url']).trim();
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
- preset.authType = String(flags['auth-type']).trim();
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
- preset.username = String(flags.username ?? '').trim();
827
+ const username = String(flags.username ?? '').trim();
828
+ preset.username = username;
829
+ preset.installUsername = username;
746
830
  }
747
831
  if (flags.password !== undefined) {
748
- preset.password = String(flags.password ?? '');
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
  }