@nocobase/cli 2.1.0-alpha.45 → 2.1.0-alpha.47
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/LICENSE +201 -0
- package/README.md +63 -380
- package/assets/env-proxy/nginx/app.conf.tpl +23 -0
- package/assets/env-proxy/nginx/nocobase.conf.tpl +5 -0
- package/assets/env-proxy/nginx/snippets/dist-location.conf +5 -0
- package/assets/env-proxy/nginx/snippets/gzip.conf +17 -0
- package/assets/env-proxy/nginx/snippets/log-format-http.conf +13 -0
- package/assets/env-proxy/nginx/snippets/maps-http.conf +14 -0
- package/assets/env-proxy/nginx/snippets/mime-types.conf +98 -0
- package/assets/env-proxy/nginx/snippets/proxy-location.conf +17 -0
- package/assets/env-proxy/nginx/snippets/spa-location.conf +6 -0
- package/assets/env-proxy/nginx/snippets/uploads-location.conf +21 -0
- package/bin/run.js +40 -32
- package/dist/commands/app/autostart/disable.js +55 -0
- package/dist/commands/app/autostart/enable.js +55 -0
- package/dist/commands/app/autostart/list.js +37 -0
- package/dist/commands/app/autostart/run.js +84 -0
- package/dist/commands/app/autostart/shared.js +49 -0
- package/dist/commands/app/destroy.js +21 -12
- package/dist/commands/app/down.js +2 -2
- package/dist/commands/app/logs.js +2 -1
- package/dist/commands/app/restart.js +92 -20
- package/dist/commands/app/shared.js +3 -2
- package/dist/commands/app/start.js +143 -38
- package/dist/commands/app/stop.js +31 -2
- package/dist/commands/app/upgrade.js +11 -7
- package/dist/commands/config/delete.js +10 -2
- package/dist/commands/config/get.js +7 -1
- package/dist/commands/config/set.js +12 -2
- package/dist/commands/db/ps.js +5 -18
- package/dist/commands/env/add.js +24 -44
- package/dist/commands/env/auth.js +1 -1
- package/dist/commands/env/info.js +3 -2
- package/dist/commands/env/list.js +4 -5
- package/dist/commands/env/proxy/caddy.js +28 -0
- package/dist/commands/env/proxy/index.js +353 -0
- package/dist/commands/env/proxy/nginx.js +28 -0
- package/dist/commands/env/remove.js +112 -22
- package/dist/commands/env/shared.js +17 -9
- package/dist/commands/env/status.js +10 -7
- package/dist/commands/env/update.js +385 -21
- package/dist/commands/init.js +368 -98
- package/dist/commands/install.js +271 -104
- package/dist/commands/license/activate.js +63 -244
- package/dist/commands/license/plugins/shared.js +64 -13
- package/dist/commands/plugin/import.js +108 -0
- package/dist/commands/revision/create.js +89 -0
- package/dist/commands/self/update.js +58 -1
- package/dist/commands/source/dev.js +5 -5
- package/dist/commands/source/test.js +13 -14
- package/dist/lib/app-health.js +39 -32
- package/dist/lib/app-managed-resources.js +25 -9
- package/dist/lib/app-public-path.js +80 -0
- package/dist/lib/app-runtime.js +12 -3
- package/dist/lib/auth-store.js +128 -4
- package/dist/lib/backup.js +3 -3
- package/dist/lib/bootstrap.js +14 -8
- package/dist/lib/cli-config.js +229 -3
- package/dist/lib/cli-entry-error.js +52 -0
- package/dist/lib/command-log.js +284 -0
- package/dist/lib/docker-env-file.js +10 -2
- package/dist/lib/docker-log-stream.js +45 -0
- package/dist/lib/env-auth.js +25 -14
- package/dist/lib/env-command-config.js +45 -0
- package/dist/lib/env-config.js +7 -2
- package/dist/lib/env-guard.js +9 -10
- package/dist/lib/env-paths.js +101 -0
- package/dist/lib/env-proxy.js +1295 -0
- package/dist/lib/inquirer.js +4 -5
- package/dist/lib/managed-env-file.js +98 -0
- package/dist/lib/plugin-import.js +279 -0
- 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 +56 -12
- package/dist/lib/skills-manager.js +3 -1
- package/dist/lib/source-publish.js +22 -2
- package/dist/lib/startup-update.js +74 -50
- package/dist/lib/ui.js +2 -1
- package/dist/locale/en-US.json +122 -22
- package/dist/locale/zh-CN.json +119 -19
- package/package.json +5 -7
- package/scripts/build.mjs +34 -0
- package/scripts/clean.mjs +9 -0
- package/tsconfig.json +19 -0
- package/LICENSE.txt +0 -107
- package/README.zh-CN.md +0 -355
package/dist/commands/install.js
CHANGED
|
@@ -11,23 +11,27 @@ import crypto from 'node:crypto';
|
|
|
11
11
|
import { access, mkdir } from 'node:fs/promises';
|
|
12
12
|
import path from 'node:path';
|
|
13
13
|
import { exit } from 'node:process';
|
|
14
|
+
import { appendAppPublicPath } from '../lib/app-public-path.js';
|
|
14
15
|
import { runPromptCatalog, } from "../lib/prompt-catalog.js";
|
|
15
16
|
import { applyCliLocale, localeText, resolveCliLocale, translateCli } from "../lib/cli-locale.js";
|
|
16
17
|
import { resolveConfiguredEnvPath, resolveDefaultConfigScope, resolveEnvRoot, resolveEnvRelativePath, } from '../lib/cli-home.js';
|
|
17
18
|
import { defaultDockerContainerPrefix, defaultDockerNetworkName } from '../lib/app-runtime.js';
|
|
18
|
-
import { resolveDockerContainerPrefix, resolveDockerNetworkName } from '../lib/cli-config.js';
|
|
19
|
+
import { resolveDefaultApiHost, resolveDockerContainerPrefix, resolveDockerNetworkName } from '../lib/cli-config.js';
|
|
19
20
|
import { DEFAULT_DOCKER_VERSION, resolveDockerImageRef } from "../lib/docker-image.js";
|
|
20
|
-
import { findAvailableTcpPort, validateAvailableTcpPort, validateTcpPort, validateEnvKey, } from "../lib/prompt-validators.js";
|
|
21
|
+
import { findAvailableTcpPort, validateAppPublicPath, validateAvailableTcpPort, validateTcpPort, validateEnvKey, } from "../lib/prompt-validators.js";
|
|
21
22
|
import { validateExternalDbConfig, validateMysqlLowerCaseTableNamesCompatibility } from "../lib/db-connection-check.js";
|
|
22
23
|
import { formatMissingManagedAppEnvMessage } from '../lib/app-runtime.js';
|
|
23
|
-
import { commandOutput, commandSucceeds, run, runNocoBaseCommand } from '../lib/run-npm.js';
|
|
24
|
+
import { commandOutput, commandSucceeds, ensureDockerDaemonRunning, run, runNocoBaseCommand } from '../lib/run-npm.js';
|
|
24
25
|
import { printInfo, printStage, printVerbose, printWarning, setVerboseMode } from '../lib/ui.js';
|
|
25
26
|
import { omitKeys, upperFirst } from "../lib/object-utils.js";
|
|
26
|
-
import { getEnv, setCurrentEnv, upsertEnv } from '../lib/auth-store.js';
|
|
27
|
+
import { clearEnvRootSetup, getEnv, setCurrentEnv, upsertEnv } from '../lib/auth-store.js';
|
|
27
28
|
import { buildStoredEnvConfig } from '../lib/env-config.js';
|
|
28
29
|
import { resolveDockerEnvFileArg } from "../lib/docker-env-file.js";
|
|
30
|
+
import { startDockerLogFollower } from '../lib/docker-log-stream.js';
|
|
31
|
+
import { areConfiguredPathsEquivalent, deriveConfiguredSourcePath, deriveConfiguredStoragePath, inferConfiguredAppPathFromLegacyConfig, } from '../lib/env-paths.js';
|
|
29
32
|
import Download, { defaultDockerRegistryForLang } from './download.js';
|
|
30
33
|
import EnvAdd from "./env/add.js";
|
|
34
|
+
import { resolveAppUrlFromApiBaseUrl } from "./env/shared.js";
|
|
31
35
|
const DEFAULT_INSTALL_ENV_NAME = 'local';
|
|
32
36
|
const DEFAULT_INSTALL_LANG = 'en-US';
|
|
33
37
|
const DEFAULT_INSTALL_APP_PORT = '13000';
|
|
@@ -58,6 +62,19 @@ const DEFAULT_INSTALL_ROOT_USERNAME = 'nocobase';
|
|
|
58
62
|
const DEFAULT_INSTALL_ROOT_EMAIL = 'admin@nocobase.com';
|
|
59
63
|
const DEFAULT_INSTALL_ROOT_PASSWORD = 'admin123';
|
|
60
64
|
const DEFAULT_INSTALL_ROOT_NICKNAME = 'Super Admin';
|
|
65
|
+
const DEFAULT_INSTALL_API_HOST = '127.0.0.1';
|
|
66
|
+
function toOptionalPromptString(value) {
|
|
67
|
+
const text = String(value ?? '').trim();
|
|
68
|
+
return text || undefined;
|
|
69
|
+
}
|
|
70
|
+
function buildInstallApiBaseUrl(appResults, defaultApiHost = DEFAULT_INSTALL_API_HOST) {
|
|
71
|
+
const appPort = String(appResults.appPort ?? DEFAULT_INSTALL_APP_PORT).trim() || DEFAULT_INSTALL_APP_PORT;
|
|
72
|
+
const appPublicPath = String(appResults.appPublicPath ?? '').trim();
|
|
73
|
+
return `http://${defaultApiHost}:${appPort}${appendAppPublicPath(appPublicPath, 'api', { trailingSlash: false })}`;
|
|
74
|
+
}
|
|
75
|
+
function formatInstallDisplayUrl(apiBaseUrl) {
|
|
76
|
+
return resolveAppUrlFromApiBaseUrl(apiBaseUrl) || apiBaseUrl.replace(/\/api\/?$/, '');
|
|
77
|
+
}
|
|
61
78
|
const APP_HEALTH_CHECK_INTERVAL_MS = 2_000;
|
|
62
79
|
const APP_HEALTH_CHECK_TIMEOUT_MS = 600_000;
|
|
63
80
|
const APP_HEALTH_CHECK_REQUEST_TIMEOUT_MS = 5_000;
|
|
@@ -206,13 +223,41 @@ async function validateExternalDbPromptField(value, values) {
|
|
|
206
223
|
}
|
|
207
224
|
return await validateMysqlLowerCaseTableNamesCompatibility(values);
|
|
208
225
|
}
|
|
209
|
-
function
|
|
226
|
+
function defaultInstallAppPath(envName) {
|
|
210
227
|
const name = String(envName ?? DEFAULT_INSTALL_ENV_NAME).trim() || DEFAULT_INSTALL_ENV_NAME;
|
|
211
|
-
return `./${name}
|
|
228
|
+
return `./${name}/`;
|
|
229
|
+
}
|
|
230
|
+
function defaultInstallAppRootPath(envName) {
|
|
231
|
+
return deriveConfiguredSourcePath(defaultInstallAppPath(envName));
|
|
212
232
|
}
|
|
213
233
|
function defaultInstallStoragePath(envName) {
|
|
214
|
-
|
|
215
|
-
|
|
234
|
+
return deriveConfiguredStoragePath(defaultInstallAppPath(envName));
|
|
235
|
+
}
|
|
236
|
+
function resolveConfiguredAppPathValue(values) {
|
|
237
|
+
const explicitAppPath = toOptionalPromptString(values.appPath);
|
|
238
|
+
if (explicitAppPath) {
|
|
239
|
+
return explicitAppPath;
|
|
240
|
+
}
|
|
241
|
+
return inferConfiguredAppPathFromLegacyConfig({
|
|
242
|
+
appRootPath: toOptionalPromptString(values.appRootPath),
|
|
243
|
+
storagePath: toOptionalPromptString(values.storagePath),
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
function resolveConfiguredSourcePathValue(values, envName) {
|
|
247
|
+
const legacyAppRootPath = toOptionalPromptString(values.appRootPath);
|
|
248
|
+
if (legacyAppRootPath) {
|
|
249
|
+
return legacyAppRootPath;
|
|
250
|
+
}
|
|
251
|
+
const appPath = resolveConfiguredAppPathValue(values) ?? defaultInstallAppPath(envName);
|
|
252
|
+
return deriveConfiguredSourcePath(appPath);
|
|
253
|
+
}
|
|
254
|
+
function resolveConfiguredStoragePathValue(values, envName) {
|
|
255
|
+
const legacyStoragePath = toOptionalPromptString(values.storagePath);
|
|
256
|
+
if (legacyStoragePath) {
|
|
257
|
+
return legacyStoragePath;
|
|
258
|
+
}
|
|
259
|
+
const appPath = resolveConfiguredAppPathValue(values) ?? defaultInstallAppPath(envName);
|
|
260
|
+
return deriveConfiguredStoragePath(appPath);
|
|
216
261
|
}
|
|
217
262
|
function pickPresetKeys(source, keys) {
|
|
218
263
|
const out = {};
|
|
@@ -233,6 +278,15 @@ function optionalEnvBoolean(value) {
|
|
|
233
278
|
}
|
|
234
279
|
return Boolean(value);
|
|
235
280
|
}
|
|
281
|
+
function resolveExtractClientAssetsDefaultEnabled(value) {
|
|
282
|
+
const text = String(value ?? '')
|
|
283
|
+
.trim()
|
|
284
|
+
.toLowerCase();
|
|
285
|
+
if (!text) {
|
|
286
|
+
return true;
|
|
287
|
+
}
|
|
288
|
+
return !['0', 'false', 'no', 'off'].includes(text);
|
|
289
|
+
}
|
|
236
290
|
function pushOptionalEnvArg(args, key, value) {
|
|
237
291
|
if (typeof value === 'string') {
|
|
238
292
|
if (!value) {
|
|
@@ -275,9 +329,9 @@ export default class Install extends Command {
|
|
|
275
329
|
'<%= config.bin %> <%= command.id %> --env app1 -l zh-CN',
|
|
276
330
|
'<%= config.bin %> <%= command.id %> --env app1 --root-username nocobase --root-email admin@nocobase.com --root-password admin123',
|
|
277
331
|
'<%= config.bin %> <%= command.id %> --env app1 --root-nickname "Super Admin"',
|
|
278
|
-
'<%= config.bin %> <%= command.id %> --env myenv --app-
|
|
279
|
-
'<%= config.bin %> <%= command.id %> --env dev -y --app-
|
|
280
|
-
'<%= config.bin %> <%= command.id %> --env dev -y --skip-download --source git --app-
|
|
332
|
+
'<%= config.bin %> <%= command.id %> --env myenv --app-path=./myenv/',
|
|
333
|
+
'<%= config.bin %> <%= command.id %> --env dev -y --app-path=./dev/',
|
|
334
|
+
'<%= config.bin %> <%= command.id %> --env dev -y --skip-download --source git --app-path=./dev/',
|
|
281
335
|
];
|
|
282
336
|
static flags = {
|
|
283
337
|
yes: Flags.boolean({
|
|
@@ -299,7 +353,7 @@ export default class Install extends Command {
|
|
|
299
353
|
}),
|
|
300
354
|
env: Flags.string({
|
|
301
355
|
char: 'e',
|
|
302
|
-
description: 'App/env name to create or update. Defaults app
|
|
356
|
+
description: 'App/env name to create or update. Defaults the app path to ./<envName>/ and derives source/storage inside it.',
|
|
303
357
|
}),
|
|
304
358
|
'default-api-base-url': Flags.string({
|
|
305
359
|
char: 'd',
|
|
@@ -336,14 +390,24 @@ export default class Install extends Command {
|
|
|
336
390
|
char: 'f',
|
|
337
391
|
required: false,
|
|
338
392
|
}),
|
|
393
|
+
'app-path': Flags.string({
|
|
394
|
+
description: 'App directory for a local npm/git app (default: ./<envName>/)',
|
|
395
|
+
}),
|
|
339
396
|
'app-root-path': Flags.string({
|
|
340
|
-
|
|
397
|
+
hidden: true,
|
|
398
|
+
deprecated: true,
|
|
399
|
+
description: 'Legacy source directory for a local npm/git app',
|
|
341
400
|
}),
|
|
342
401
|
'app-port': Flags.string({
|
|
343
402
|
description: 'HTTP port for the local app (default: 13000, or an available port with --yes)',
|
|
344
403
|
}),
|
|
345
404
|
'storage-path': Flags.string({
|
|
346
|
-
|
|
405
|
+
hidden: true,
|
|
406
|
+
deprecated: true,
|
|
407
|
+
description: 'Legacy storage directory for uploads and managed database data',
|
|
408
|
+
}),
|
|
409
|
+
'app-public-path': Flags.string({
|
|
410
|
+
description: 'Public path for the local app, for example / or /console/',
|
|
347
411
|
}),
|
|
348
412
|
'root-username': Flags.string({
|
|
349
413
|
description: 'Initial admin username for the installed app',
|
|
@@ -415,39 +479,44 @@ export default class Install extends Command {
|
|
|
415
479
|
validate: validateEnvKey,
|
|
416
480
|
},
|
|
417
481
|
};
|
|
418
|
-
static appPrompts
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
482
|
+
static get appPrompts() {
|
|
483
|
+
return {
|
|
484
|
+
lang: {
|
|
485
|
+
type: 'select',
|
|
486
|
+
message: installText('prompts.lang.message'),
|
|
487
|
+
options: INSTALL_LANGUAGE_OPTIONS,
|
|
488
|
+
initialValue: DEFAULT_INSTALL_LANG,
|
|
489
|
+
yesInitialValue: DEFAULT_INSTALL_LANG,
|
|
490
|
+
},
|
|
491
|
+
// force: {
|
|
492
|
+
// type: 'boolean',
|
|
493
|
+
// message: 'Reinstall the application by clearing the database? (-f / --force)',
|
|
494
|
+
// initialValue: false,
|
|
495
|
+
// yesInitialValue: false,
|
|
496
|
+
// },
|
|
497
|
+
appPath: {
|
|
498
|
+
type: 'text',
|
|
499
|
+
message: installText('prompts.appPath.message', { root: resolveEnvRoot() }),
|
|
500
|
+
placeholder: installText('prompts.appPath.placeholder'),
|
|
501
|
+
initialValue: (values) => defaultInstallAppPath(values.env ?? values.appName),
|
|
502
|
+
hidden: (values) => Boolean(Install.toOptionalPromptString(values.appRootPath)),
|
|
503
|
+
},
|
|
504
|
+
appPort: {
|
|
505
|
+
type: 'text',
|
|
506
|
+
message: installText('prompts.appPort.message'),
|
|
507
|
+
placeholder: installText('prompts.appPort.placeholder'),
|
|
508
|
+
validate: Install.validateAppPort,
|
|
509
|
+
},
|
|
510
|
+
appPublicPath: {
|
|
511
|
+
type: 'text',
|
|
512
|
+
message: installText('prompts.appPublicPath.message'),
|
|
513
|
+
placeholder: installText('prompts.appPublicPath.placeholder'),
|
|
514
|
+
initialValue: '/',
|
|
515
|
+
yesInitialValue: '/',
|
|
516
|
+
validate: validateAppPublicPath,
|
|
517
|
+
},
|
|
518
|
+
};
|
|
519
|
+
}
|
|
451
520
|
static dbPrompts = {
|
|
452
521
|
dbDialect: {
|
|
453
522
|
type: 'select',
|
|
@@ -571,8 +640,8 @@ export default class Install extends Command {
|
|
|
571
640
|
},
|
|
572
641
|
};
|
|
573
642
|
/**
|
|
574
|
-
* App catalog with `env` seeded into `out` first so
|
|
575
|
-
*
|
|
643
|
+
* App catalog with `env` seeded into `out` first so app path defaults can see `values.env`
|
|
644
|
+
* (same iteration order as {@link runPromptCatalog}).
|
|
576
645
|
*/
|
|
577
646
|
static buildAppPromptsCatalog(seedEnv, options) {
|
|
578
647
|
return {
|
|
@@ -673,6 +742,12 @@ export default class Install extends Command {
|
|
|
673
742
|
if (argvHasToken(argv, ['--force', '-f'])) {
|
|
674
743
|
preset.force = flags.force;
|
|
675
744
|
}
|
|
745
|
+
if (flags['app-path'] !== undefined) {
|
|
746
|
+
const v = flags['app-path']?.trim();
|
|
747
|
+
if (v) {
|
|
748
|
+
preset.appPath = v;
|
|
749
|
+
}
|
|
750
|
+
}
|
|
676
751
|
if (flags['app-root-path'] !== undefined) {
|
|
677
752
|
const v = flags['app-root-path']?.trim();
|
|
678
753
|
if (v) {
|
|
@@ -691,6 +766,12 @@ export default class Install extends Command {
|
|
|
691
766
|
preset.storagePath = v;
|
|
692
767
|
}
|
|
693
768
|
}
|
|
769
|
+
if (flags['app-public-path'] !== undefined) {
|
|
770
|
+
const v = String(flags['app-public-path'] ?? '').trim();
|
|
771
|
+
if (v) {
|
|
772
|
+
preset.appPublicPath = v;
|
|
773
|
+
}
|
|
774
|
+
}
|
|
694
775
|
if (flags['root-username'] !== undefined) {
|
|
695
776
|
preset.rootUsername = String(flags['root-username'] ?? '').trim();
|
|
696
777
|
}
|
|
@@ -777,9 +858,11 @@ export default class Install extends Command {
|
|
|
777
858
|
return pickPresetKeys(Install.buildPresetValuesFromFlags(flags, argv), [
|
|
778
859
|
'lang',
|
|
779
860
|
'force',
|
|
861
|
+
'appPath',
|
|
780
862
|
'appRootPath',
|
|
781
863
|
'appPort',
|
|
782
864
|
'storagePath',
|
|
865
|
+
'appPublicPath',
|
|
783
866
|
]);
|
|
784
867
|
}
|
|
785
868
|
static buildDbPresetValuesFromFlags(flags, argv = process.argv.slice(2)) {
|
|
@@ -836,11 +919,26 @@ export default class Install extends Command {
|
|
|
836
919
|
};
|
|
837
920
|
}
|
|
838
921
|
static toOptionalPromptString(value) {
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
922
|
+
return toOptionalPromptString(value);
|
|
923
|
+
}
|
|
924
|
+
static resolveManagedAppKey(value) {
|
|
925
|
+
return Install.toOptionalPromptString(value) ?? crypto.randomBytes(32).toString('hex');
|
|
926
|
+
}
|
|
927
|
+
static resolveManagedTimeZone(value) {
|
|
928
|
+
return Install.toOptionalPromptString(value) ?? (Intl.DateTimeFormat().resolvedOptions().timeZone || 'UTC');
|
|
929
|
+
}
|
|
930
|
+
static formatLocalClientExtractWarning(envName, message) {
|
|
931
|
+
return [
|
|
932
|
+
`Client assets were not extracted for "${envName}".`,
|
|
933
|
+
'NocoBase will keep starting, but versioned client files for CDN or external distribution may be stale or missing.',
|
|
934
|
+
`Details: ${message}`,
|
|
935
|
+
].join('\n');
|
|
936
|
+
}
|
|
937
|
+
async ensureManagedAppRuntimeConfig(params) {
|
|
938
|
+
const savedEnv = await getEnv(params.envName, { scope: resolveDefaultConfigScope() });
|
|
939
|
+
const savedConfig = savedEnv?.config;
|
|
940
|
+
params.appResults.appKey = Install.resolveManagedAppKey(params.appResults.appKey ?? savedConfig?.appKey);
|
|
941
|
+
params.appResults.timeZone = Install.resolveManagedTimeZone(params.appResults.timeZone ?? savedConfig?.timezone);
|
|
844
942
|
}
|
|
845
943
|
static async validateAppPort(value, values) {
|
|
846
944
|
const formatError = validateTcpPort(value);
|
|
@@ -916,7 +1014,7 @@ export default class Install extends Command {
|
|
|
916
1014
|
const source = Install.toOptionalPromptString(values.source);
|
|
917
1015
|
const builtinDb = values.builtinDb === undefined ? undefined : Boolean(values.builtinDb);
|
|
918
1016
|
const dbDialect = Install.toOptionalPromptString(values.dbDialect);
|
|
919
|
-
const appRootPath =
|
|
1017
|
+
const appRootPath = resolveConfiguredSourcePathValue(values, envName);
|
|
920
1018
|
const dockerNetworkName = await Install.resolveResumeDockerNetworkName();
|
|
921
1019
|
const dockerContainerPrefix = await Install.resolveResumeDockerContainerPrefix();
|
|
922
1020
|
return {
|
|
@@ -987,9 +1085,12 @@ export default class Install extends Command {
|
|
|
987
1085
|
const envName = String(env.name ?? '').trim();
|
|
988
1086
|
const config = env.config ?? {};
|
|
989
1087
|
const source = Install.toOptionalPromptString(config.source);
|
|
1088
|
+
const appPath = Install.toOptionalPromptString(config.appPath) ?? inferConfiguredAppPathFromLegacyConfig(config);
|
|
990
1089
|
const appRootPath = Install.toOptionalPromptString(config.appRootPath);
|
|
991
1090
|
const appPort = Install.toOptionalPromptString(config.appPort);
|
|
992
1091
|
const storagePath = Install.toOptionalPromptString(config.storagePath);
|
|
1092
|
+
const appPublicPath = Install.toOptionalPromptString(config.appPublicPath);
|
|
1093
|
+
const apiBaseUrl = Install.toOptionalPromptString(config.apiBaseUrl);
|
|
993
1094
|
const downloadVersion = Install.toOptionalPromptString(config.downloadVersion);
|
|
994
1095
|
const dockerRegistry = Install.toOptionalPromptString(config.dockerRegistry);
|
|
995
1096
|
const dockerPlatform = Install.toOptionalPromptString(config.dockerPlatform);
|
|
@@ -1012,9 +1113,11 @@ export default class Install extends Command {
|
|
|
1012
1113
|
const auth = config.auth;
|
|
1013
1114
|
const savedAuthType = Install.toOptionalPromptString(config.authType) ?? Install.toOptionalPromptString(auth?.type);
|
|
1014
1115
|
const appPreset = {
|
|
1116
|
+
...(appPath ? { appPath } : {}),
|
|
1015
1117
|
...(appRootPath ? { appRootPath } : {}),
|
|
1016
1118
|
...(appPort ? { appPort } : {}),
|
|
1017
1119
|
...(storagePath ? { storagePath } : {}),
|
|
1120
|
+
...(appPublicPath ? { appPublicPath } : {}),
|
|
1018
1121
|
};
|
|
1019
1122
|
const downloadPreset = {
|
|
1020
1123
|
...(source ? { source } : {}),
|
|
@@ -1052,6 +1155,9 @@ export default class Install extends Command {
|
|
|
1052
1155
|
...(rootNickname ? { rootNickname } : {}),
|
|
1053
1156
|
};
|
|
1054
1157
|
const envAddPreset = {};
|
|
1158
|
+
if (apiBaseUrl) {
|
|
1159
|
+
envAddPreset.apiBaseUrl = apiBaseUrl;
|
|
1160
|
+
}
|
|
1055
1161
|
if (savedAuthType === 'token') {
|
|
1056
1162
|
envAddPreset.authType = 'token';
|
|
1057
1163
|
if (Install.toOptionalPromptString(auth.accessToken)) {
|
|
@@ -1112,7 +1218,7 @@ export default class Install extends Command {
|
|
|
1112
1218
|
throw new Error([
|
|
1113
1219
|
`Cannot continue setup for "${env.name}" in non-interactive resume mode yet.`,
|
|
1114
1220
|
`These setup-only flags are not saved in the env config: ${missingFlags.join(', ')}`,
|
|
1115
|
-
`Run \`nb init --env ${env.name} --resume\` without \`--yes\`, or pass those flags again.`,
|
|
1221
|
+
`Run \`nb init --ui --env ${env.name} --resume\` without \`--yes\`, or pass those flags again.`,
|
|
1116
1222
|
].join('\n'));
|
|
1117
1223
|
}
|
|
1118
1224
|
}
|
|
@@ -1133,6 +1239,9 @@ export default class Install extends Command {
|
|
|
1133
1239
|
static async buildAppPromptInitialValues(params) {
|
|
1134
1240
|
const initialValues = {};
|
|
1135
1241
|
const envName = params.envName ?? DEFAULT_INSTALL_ENV_NAME;
|
|
1242
|
+
if (params.flags['app-path'] === undefined && params.flags['app-root-path'] === undefined) {
|
|
1243
|
+
initialValues.appPath = defaultInstallAppPath(envName);
|
|
1244
|
+
}
|
|
1136
1245
|
if (params.flags['app-root-path'] === undefined) {
|
|
1137
1246
|
initialValues.appRootPath = defaultInstallAppRootPath(envName);
|
|
1138
1247
|
}
|
|
@@ -1176,7 +1285,7 @@ export default class Install extends Command {
|
|
|
1176
1285
|
* output directory with app settings, while Docker registry defaults follow the CLI locale.
|
|
1177
1286
|
*/
|
|
1178
1287
|
static buildDownloadPromptOptionsForInstall(appResults, envName) {
|
|
1179
|
-
const appRoot =
|
|
1288
|
+
const appRoot = resolveConfiguredSourcePathValue(appResults, envName);
|
|
1180
1289
|
const lang = String(appResults.lang ?? DEFAULT_INSTALL_LANG).trim() || DEFAULT_INSTALL_LANG;
|
|
1181
1290
|
const initialValues = {
|
|
1182
1291
|
lang,
|
|
@@ -1207,7 +1316,7 @@ export default class Install extends Command {
|
|
|
1207
1316
|
*/
|
|
1208
1317
|
static buildDownloadPresetValuesForInstall(flags, appResults, envName, yes, argv = process.argv.slice(2)) {
|
|
1209
1318
|
const preset = {};
|
|
1210
|
-
const appRoot =
|
|
1319
|
+
const appRoot = resolveConfiguredSourcePathValue(appResults, envName);
|
|
1211
1320
|
const lang = String(appResults.lang ?? DEFAULT_INSTALL_LANG).trim() || DEFAULT_INSTALL_LANG;
|
|
1212
1321
|
preset.lang = lang;
|
|
1213
1322
|
if (flags.source !== undefined && String(flags.source).trim() !== '') {
|
|
@@ -1338,7 +1447,8 @@ export default class Install extends Command {
|
|
|
1338
1447
|
: dbHostInput && dbHostInput !== DEFAULT_INSTALL_DB_HOST && dbHostInput !== 'localhost'
|
|
1339
1448
|
? dbHostInput
|
|
1340
1449
|
: containerName;
|
|
1341
|
-
const storagePath = resolveConfiguredEnvPath(params.storagePath) ??
|
|
1450
|
+
const storagePath = resolveConfiguredEnvPath(params.storagePath) ??
|
|
1451
|
+
resolveEnvRelativePath(resolveConfiguredStoragePathValue({ appPath: params.appPath, storagePath: params.storagePath }, params.envName));
|
|
1342
1452
|
if (dbDialect === 'postgres') {
|
|
1343
1453
|
const image = String(params.builtinDbImage ?? '').trim() || defaultBuiltinDbImageForDialect(dbDialect);
|
|
1344
1454
|
const dataDir = path.resolve(storagePath, 'db', 'postgres');
|
|
@@ -1529,6 +1639,7 @@ export default class Install extends Command {
|
|
|
1529
1639
|
if (this.ensuredDockerNetworks.has(name)) {
|
|
1530
1640
|
return;
|
|
1531
1641
|
}
|
|
1642
|
+
await ensureDockerDaemonRunning('prepare Docker resources for this environment');
|
|
1532
1643
|
printVerbose(`Checking Docker network: ${name}`);
|
|
1533
1644
|
const exists = await commandSucceeds('docker', ['network', 'inspect', name]);
|
|
1534
1645
|
if (exists) {
|
|
@@ -1607,12 +1718,13 @@ export default class Install extends Command {
|
|
|
1607
1718
|
});
|
|
1608
1719
|
}
|
|
1609
1720
|
async startBuiltinDb(params) {
|
|
1610
|
-
const storagePath =
|
|
1721
|
+
const storagePath = resolveConfiguredStoragePathValue(params.appResults, params.envName);
|
|
1611
1722
|
const plan = Install.buildBuiltinDbPlan({
|
|
1612
1723
|
envName: params.envName,
|
|
1613
1724
|
workspaceName: params.workspaceName,
|
|
1614
1725
|
dockerNetworkName: params.dockerNetworkName,
|
|
1615
1726
|
dockerContainerPrefix: params.dockerContainerPrefix,
|
|
1727
|
+
appPath: params.appResults.appPath,
|
|
1616
1728
|
storagePath,
|
|
1617
1729
|
source: params.downloadResults.source,
|
|
1618
1730
|
dbDialect: params.dbResults.dbDialect,
|
|
@@ -1653,7 +1765,9 @@ export default class Install extends Command {
|
|
|
1653
1765
|
defaultVersion: DEFAULT_DOCKER_VERSION,
|
|
1654
1766
|
});
|
|
1655
1767
|
const appPort = String(params.appResults.appPort ?? DEFAULT_INSTALL_APP_PORT).trim() || DEFAULT_INSTALL_APP_PORT;
|
|
1656
|
-
const
|
|
1768
|
+
const configuredStoragePath = resolveConfiguredStoragePathValue(params.appResults, params.envName);
|
|
1769
|
+
const storagePath = resolveConfiguredEnvPath(configuredStoragePath) ??
|
|
1770
|
+
resolveEnvRelativePath(defaultInstallStoragePath(params.envName));
|
|
1657
1771
|
const dbDialect = String(params.dbResults.dbDialect ?? 'postgres').trim() || 'postgres';
|
|
1658
1772
|
const dbHost = String(params.dbResults.dbHost ?? DEFAULT_INSTALL_DB_HOST).trim() || DEFAULT_INSTALL_DB_HOST;
|
|
1659
1773
|
const dbPort = String(params.dbResults.dbPort ?? defaultDbPortForDialect(dbDialect)).trim() ||
|
|
@@ -1664,8 +1778,10 @@ export default class Install extends Command {
|
|
|
1664
1778
|
const dbSchema = optionalEnvString(params.dbResults.dbSchema);
|
|
1665
1779
|
const dbTablePrefix = optionalEnvString(params.dbResults.dbTablePrefix);
|
|
1666
1780
|
const dbUnderscored = optionalEnvBoolean(params.dbResults.dbUnderscored);
|
|
1667
|
-
const
|
|
1668
|
-
const
|
|
1781
|
+
const extractClientAssets = resolveExtractClientAssetsDefaultEnabled(process.env.NOCOBASE_EXTRACT_CLIENT_ASSETS);
|
|
1782
|
+
const appKey = Install.resolveManagedAppKey(params.appResults.appKey);
|
|
1783
|
+
const appPublicPath = Install.toOptionalPromptString(params.appResults.appPublicPath);
|
|
1784
|
+
const timeZone = Install.resolveManagedTimeZone(params.appResults.timeZone);
|
|
1669
1785
|
const containerName = Install.buildDockerAppContainerName(params.envName, params.dockerContainerPrefix ?? params.workspaceName);
|
|
1670
1786
|
const configuredEnvFile = String(params.appResults.envFile ?? '').trim();
|
|
1671
1787
|
const envFile = await resolveDockerEnvFileArg(params.envName, configuredEnvFile ? { envFile: configuredEnvFile } : undefined);
|
|
@@ -1692,9 +1808,11 @@ export default class Install extends Command {
|
|
|
1692
1808
|
args.push('-e', `${key}=${value}`);
|
|
1693
1809
|
}
|
|
1694
1810
|
args.push('-e', `APP_KEY=${appKey}`, '-e', `DB_DIALECT=${dbDialect}`, '-e', `DB_HOST=${dbHost}`, '-e', `DB_PORT=${dbPort}`, '-e', `DB_DATABASE=${dbDatabase}`, '-e', `DB_USER=${dbUser}`, '-e', `DB_PASSWORD=${dbPassword}`, '-e', `TZ=${timeZone}`, '-v', `${storagePath}:/app/nocobase/storage`);
|
|
1811
|
+
pushOptionalEnvArg(args, 'APP_PUBLIC_PATH', appPublicPath);
|
|
1695
1812
|
pushOptionalEnvArg(args, 'DB_SCHEMA', dbSchema);
|
|
1696
1813
|
pushOptionalEnvArg(args, 'DB_TABLE_PREFIX', dbTablePrefix);
|
|
1697
1814
|
pushOptionalEnvArg(args, 'DB_UNDERSCORED', dbUnderscored);
|
|
1815
|
+
pushOptionalEnvArg(args, 'NOCOBASE_EXTRACT_CLIENT_ASSETS', extractClientAssets);
|
|
1698
1816
|
args.push(imageRef);
|
|
1699
1817
|
return {
|
|
1700
1818
|
source: 'docker',
|
|
@@ -1801,17 +1919,15 @@ export default class Install extends Command {
|
|
|
1801
1919
|
return projectRoot;
|
|
1802
1920
|
}
|
|
1803
1921
|
const outputDir = String(params.downloadResults.outputDir ?? '').trim() ||
|
|
1804
|
-
|
|
1805
|
-
defaultInstallAppRootPath(params.envName);
|
|
1922
|
+
resolveConfiguredSourcePathValue(params.appResults, params.envName);
|
|
1806
1923
|
return resolveConfiguredEnvPath(outputDir) ?? resolveEnvRelativePath(defaultInstallAppRootPath(params.envName));
|
|
1807
1924
|
}
|
|
1808
1925
|
static resolveLocalProjectConfigPath(params) {
|
|
1809
1926
|
return (String(params.downloadResults.outputDir ?? '').trim() ||
|
|
1810
|
-
|
|
1811
|
-
defaultInstallAppRootPath(params.envName));
|
|
1927
|
+
resolveConfiguredSourcePathValue(params.appResults, params.envName));
|
|
1812
1928
|
}
|
|
1813
1929
|
static buildSkipDownloadValues(envName, appResults) {
|
|
1814
|
-
const appRoot =
|
|
1930
|
+
const appRoot = resolveConfiguredSourcePathValue(appResults, envName);
|
|
1815
1931
|
return {
|
|
1816
1932
|
outputDir: appRoot,
|
|
1817
1933
|
replace: false,
|
|
@@ -1884,12 +2000,12 @@ export default class Install extends Command {
|
|
|
1884
2000
|
return downloadedProjectRoot;
|
|
1885
2001
|
}
|
|
1886
2002
|
static buildLocalAppEnvVars(params) {
|
|
1887
|
-
const configuredStoragePath =
|
|
2003
|
+
const configuredStoragePath = resolveConfiguredStoragePathValue(params.appResults, params.envName);
|
|
1888
2004
|
const storagePath = resolveConfiguredEnvPath(configuredStoragePath) ??
|
|
1889
2005
|
resolveEnvRelativePath(defaultInstallStoragePath(params.envName));
|
|
1890
2006
|
const dbDialect = String(params.dbResults.dbDialect ?? 'postgres').trim() || 'postgres';
|
|
1891
|
-
const appKey =
|
|
1892
|
-
const timeZone =
|
|
2007
|
+
const appKey = Install.resolveManagedAppKey(params.appResults.appKey);
|
|
2008
|
+
const timeZone = Install.resolveManagedTimeZone(params.appResults.timeZone);
|
|
1893
2009
|
const env = {
|
|
1894
2010
|
STORAGE_PATH: storagePath,
|
|
1895
2011
|
APP_PORT: String(params.appResults.appPort ?? DEFAULT_INSTALL_APP_PORT).trim() || DEFAULT_INSTALL_APP_PORT,
|
|
@@ -1907,6 +2023,7 @@ export default class Install extends Command {
|
|
|
1907
2023
|
rootResults: params.rootResults,
|
|
1908
2024
|
}),
|
|
1909
2025
|
};
|
|
2026
|
+
setOptionalEnvVar(env, 'APP_PUBLIC_PATH', Install.toOptionalPromptString(params.appResults.appPublicPath));
|
|
1910
2027
|
setOptionalEnvVar(env, 'DB_SCHEMA', optionalEnvString(params.dbResults.dbSchema));
|
|
1911
2028
|
setOptionalEnvVar(env, 'DB_TABLE_PREFIX', optionalEnvString(params.dbResults.dbTablePrefix));
|
|
1912
2029
|
setOptionalEnvVar(env, 'DB_UNDERSCORED', optionalEnvBoolean(params.dbResults.dbUnderscored));
|
|
@@ -1932,6 +2049,24 @@ export default class Install extends Command {
|
|
|
1932
2049
|
const message = error instanceof Error ? error.message : String(error);
|
|
1933
2050
|
this.logDetail(`Skipped local process cleanup before start: ${message}`);
|
|
1934
2051
|
}
|
|
2052
|
+
this.logDetail(`Running local postinstall in ${params.projectRoot}`);
|
|
2053
|
+
await runNocoBaseCommand(['postinstall'], {
|
|
2054
|
+
cwd: params.projectRoot,
|
|
2055
|
+
env,
|
|
2056
|
+
stdio: params.commandStdio ?? 'ignore',
|
|
2057
|
+
});
|
|
2058
|
+
this.logDetail(`Extracting local client assets in ${params.projectRoot}`);
|
|
2059
|
+
try {
|
|
2060
|
+
await runNocoBaseCommand(['client:extract'], {
|
|
2061
|
+
cwd: params.projectRoot,
|
|
2062
|
+
env,
|
|
2063
|
+
stdio: params.commandStdio ?? 'ignore',
|
|
2064
|
+
});
|
|
2065
|
+
}
|
|
2066
|
+
catch (error) {
|
|
2067
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
2068
|
+
printWarning(Install.formatLocalClientExtractWarning(params.envName, message));
|
|
2069
|
+
}
|
|
1935
2070
|
this.logDetail(`Starting local NocoBase app from ${params.projectRoot}`);
|
|
1936
2071
|
await runNocoBaseCommand(args, {
|
|
1937
2072
|
cwd: params.projectRoot,
|
|
@@ -1951,8 +2086,8 @@ export default class Install extends Command {
|
|
|
1951
2086
|
};
|
|
1952
2087
|
}
|
|
1953
2088
|
static resolveApiBaseUrl(params) {
|
|
1954
|
-
|
|
1955
|
-
|
|
2089
|
+
return (String(params.envAddResults.apiBaseUrl ?? '').trim() ||
|
|
2090
|
+
buildInstallApiBaseUrl(params.appResults, params.defaultApiHost));
|
|
1956
2091
|
}
|
|
1957
2092
|
static buildHealthCheckUrl(apiBaseUrl) {
|
|
1958
2093
|
return `${apiBaseUrl.replace(/\/+$/, '')}/__health_check`;
|
|
@@ -2010,35 +2145,44 @@ export default class Install extends Command {
|
|
|
2010
2145
|
let lastMessage = 'No response yet';
|
|
2011
2146
|
let lastLoggedStatus = '';
|
|
2012
2147
|
printInfo('Waiting for NocoBase to become ready...');
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
lastLoggedStatus
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2148
|
+
const dockerLogFollower = options?.verbose && options.containerName ? startDockerLogFollower(options.containerName) : undefined;
|
|
2149
|
+
try {
|
|
2150
|
+
while (Date.now() - startedAt < timeoutMs) {
|
|
2151
|
+
const result = await Install.requestAppHealthCheck({
|
|
2152
|
+
healthCheckUrl,
|
|
2153
|
+
fetchImpl,
|
|
2154
|
+
requestTimeoutMs,
|
|
2155
|
+
});
|
|
2156
|
+
if (result.ok) {
|
|
2157
|
+
return;
|
|
2158
|
+
}
|
|
2159
|
+
lastMessage = result.message;
|
|
2160
|
+
const elapsedSeconds = Math.max(1, Math.floor((Date.now() - startedAt) / 1000));
|
|
2161
|
+
const statusLine = `Waiting for NocoBase to become ready... (${elapsedSeconds}s elapsed, last status: ${Install.formatHealthCheckMessage(lastMessage)})`;
|
|
2162
|
+
if (statusLine !== lastLoggedStatus) {
|
|
2163
|
+
printInfo(statusLine);
|
|
2164
|
+
lastLoggedStatus = statusLine;
|
|
2165
|
+
}
|
|
2166
|
+
const remainingMs = timeoutMs - (Date.now() - startedAt);
|
|
2167
|
+
if (remainingMs <= 0) {
|
|
2168
|
+
break;
|
|
2169
|
+
}
|
|
2170
|
+
await Install.sleep(Math.min(intervalMs, remainingMs));
|
|
2032
2171
|
}
|
|
2033
|
-
|
|
2172
|
+
const logHint = options?.containerName
|
|
2173
|
+
? ` You can inspect startup logs with: docker logs ${options.containerName}`
|
|
2174
|
+
: '';
|
|
2175
|
+
throw new Error(`The application did not become ready in time. Expected \`${healthCheckUrl}\` to respond with \`ok\`, but the last status was: ${Install.formatHealthCheckMessage(lastMessage)}.${logHint}`);
|
|
2176
|
+
}
|
|
2177
|
+
finally {
|
|
2178
|
+
await dockerLogFollower?.stop();
|
|
2034
2179
|
}
|
|
2035
|
-
const logHint = options?.containerName
|
|
2036
|
-
? ` You can inspect startup logs with: docker logs ${options.containerName}`
|
|
2037
|
-
: '';
|
|
2038
|
-
throw new Error(`The application did not become ready in time. Expected \`${healthCheckUrl}\` to respond with \`ok\`, but the last status was: ${Install.formatHealthCheckMessage(lastMessage)}.${logHint}`);
|
|
2039
2180
|
}
|
|
2040
2181
|
async saveInstalledEnv(params) {
|
|
2041
|
-
|
|
2182
|
+
const defaultApiHost = await resolveDefaultApiHost();
|
|
2183
|
+
await upsertEnv(params.envName, Install.buildSavedEnvConfig(params, { defaultApiHost }), {
|
|
2184
|
+
scope: resolveDefaultConfigScope(),
|
|
2185
|
+
});
|
|
2042
2186
|
await setCurrentEnv(params.envName, { scope: resolveDefaultConfigScope() });
|
|
2043
2187
|
}
|
|
2044
2188
|
async syncInstalledEnvConnection(params) {
|
|
@@ -2067,13 +2211,19 @@ export default class Install extends Command {
|
|
|
2067
2211
|
}
|
|
2068
2212
|
await this.config.runCommand('env:update', [params.envName]);
|
|
2069
2213
|
}
|
|
2070
|
-
static buildSavedEnvConfig(params) {
|
|
2214
|
+
static buildSavedEnvConfig(params, options = {}) {
|
|
2215
|
+
const appPath = resolveConfiguredAppPathValue(params.appResults);
|
|
2216
|
+
const appRootPath = Install.toOptionalPromptString(params.appResults.appRootPath);
|
|
2217
|
+
const storagePath = Install.toOptionalPromptString(params.appResults.storagePath);
|
|
2218
|
+
const appPublicPath = Install.toOptionalPromptString(params.appResults.appPublicPath);
|
|
2219
|
+
const derivedAppRootPath = appPath ? deriveConfiguredSourcePath(appPath) : undefined;
|
|
2220
|
+
const derivedStoragePath = appPath ? deriveConfiguredStoragePath(appPath) : undefined;
|
|
2071
2221
|
const appPort = String(params.appResults.appPort ?? DEFAULT_INSTALL_APP_PORT).trim() || DEFAULT_INSTALL_APP_PORT;
|
|
2072
|
-
const storagePath = String(params.appResults.storagePath ?? '').trim() || defaultInstallStoragePath(params.envName);
|
|
2073
2222
|
const envFile = String(params.appResults.envFile ?? '').trim() || undefined;
|
|
2074
2223
|
const apiBaseUrl = Install.resolveApiBaseUrl({
|
|
2075
2224
|
appResults: params.appResults,
|
|
2076
2225
|
envAddResults: params.envAddResults,
|
|
2226
|
+
defaultApiHost: options.defaultApiHost,
|
|
2077
2227
|
});
|
|
2078
2228
|
const authType = String(params.envAddResults.authType ?? 'oauth').trim() || 'oauth';
|
|
2079
2229
|
const authUsername = authType === 'basic' ? String(params.envAddResults.username ?? params.rootResults.rootUsername ?? '').trim() : '';
|
|
@@ -2091,9 +2241,11 @@ export default class Install extends Command {
|
|
|
2091
2241
|
devDependencies: downloadResultsValue(params.downloadResults, 'devDependencies'),
|
|
2092
2242
|
build: downloadResultsValue(params.downloadResults, 'build'),
|
|
2093
2243
|
buildDts: downloadResultsValue(params.downloadResults, 'buildDts'),
|
|
2094
|
-
|
|
2244
|
+
...(appPath ? { appPath } : {}),
|
|
2245
|
+
...(appRootPath && !areConfiguredPathsEquivalent(appRootPath, derivedAppRootPath) ? { appRootPath } : {}),
|
|
2095
2246
|
appPort,
|
|
2096
|
-
storagePath,
|
|
2247
|
+
...(storagePath && !areConfiguredPathsEquivalent(storagePath, derivedStoragePath) ? { storagePath } : {}),
|
|
2248
|
+
...(appPublicPath ? { appPublicPath } : {}),
|
|
2097
2249
|
...(envFile ? { envFile } : {}),
|
|
2098
2250
|
appKey: params.appResults.appKey,
|
|
2099
2251
|
timezone: params.appResults.timeZone,
|
|
@@ -2116,6 +2268,7 @@ export default class Install extends Command {
|
|
|
2116
2268
|
}
|
|
2117
2269
|
async collectPromptResults(parsed, yes) {
|
|
2118
2270
|
const commandArgv = this.argv ?? process.argv.slice(2);
|
|
2271
|
+
const defaultApiHost = await resolveDefaultApiHost();
|
|
2119
2272
|
const resumePreset = await this.resolveResumePresetValues(parsed, yes);
|
|
2120
2273
|
const envPreset = {
|
|
2121
2274
|
...(resumePreset?.envPreset ?? {}),
|
|
@@ -2141,6 +2294,7 @@ export default class Install extends Command {
|
|
|
2141
2294
|
envName,
|
|
2142
2295
|
flags: {
|
|
2143
2296
|
...parsed,
|
|
2297
|
+
'app-path': parsed['app-path'] ?? Install.toOptionalPromptString(appPreset.appPath),
|
|
2144
2298
|
'app-root-path': parsed['app-root-path'] ?? Install.toOptionalPromptString(appPreset.appRootPath),
|
|
2145
2299
|
'app-port': parsed['app-port'] ?? Install.toOptionalPromptString(appPreset.appPort),
|
|
2146
2300
|
'storage-path': parsed['storage-path'] ?? Install.toOptionalPromptString(appPreset.storagePath),
|
|
@@ -2210,7 +2364,7 @@ export default class Install extends Command {
|
|
|
2210
2364
|
};
|
|
2211
2365
|
const resolvedEnvAddAuthType = String(envAddPreset.authType ?? '').trim();
|
|
2212
2366
|
const envAddInitialValues = {
|
|
2213
|
-
apiBaseUrl:
|
|
2367
|
+
apiBaseUrl: buildInstallApiBaseUrl(appResults, defaultApiHost),
|
|
2214
2368
|
...envAddResumePreset,
|
|
2215
2369
|
...(!parsed['skip-auth'] && resolvedEnvAddAuthType === 'basic'
|
|
2216
2370
|
? {
|
|
@@ -2257,6 +2411,7 @@ export default class Install extends Command {
|
|
|
2257
2411
|
const parsed = {
|
|
2258
2412
|
...flags,
|
|
2259
2413
|
};
|
|
2414
|
+
const defaultApiHost = await resolveDefaultApiHost();
|
|
2260
2415
|
if (parsed['skip-auth'] && (parsed['access-token'] !== undefined || parsed.token !== undefined)) {
|
|
2261
2416
|
this.error('--skip-auth cannot be used with --access-token or --token.');
|
|
2262
2417
|
}
|
|
@@ -2273,6 +2428,10 @@ export default class Install extends Command {
|
|
|
2273
2428
|
}
|
|
2274
2429
|
const promptResults = await this.collectPromptResults(parsed, flags.yes);
|
|
2275
2430
|
const { envName, appResults, downloadResults, dbResults, rootResults, envAddResults } = promptResults;
|
|
2431
|
+
await this.ensureManagedAppRuntimeConfig({
|
|
2432
|
+
envName,
|
|
2433
|
+
appResults,
|
|
2434
|
+
});
|
|
2276
2435
|
const source = String(downloadResultsValue(downloadResults, 'source') ?? '').trim();
|
|
2277
2436
|
const usesDockerResources = Boolean(dbResults.builtinDb) || source === 'docker';
|
|
2278
2437
|
const dockerNetworkName = usesDockerResources
|
|
@@ -2390,10 +2549,17 @@ export default class Install extends Command {
|
|
|
2390
2549
|
await this.waitForAppHealthCheck(Install.resolveApiBaseUrl({
|
|
2391
2550
|
appResults,
|
|
2392
2551
|
envAddResults,
|
|
2552
|
+
defaultApiHost,
|
|
2393
2553
|
}), {
|
|
2394
2554
|
containerName: dockerAppPlan?.containerName,
|
|
2555
|
+
verbose: parsed.verbose,
|
|
2556
|
+
});
|
|
2557
|
+
const displayApiBaseUrl = Install.resolveApiBaseUrl({
|
|
2558
|
+
appResults,
|
|
2559
|
+
envAddResults,
|
|
2560
|
+
defaultApiHost,
|
|
2395
2561
|
});
|
|
2396
|
-
printInfo(`NocoBase is ready at
|
|
2562
|
+
printInfo(`NocoBase is ready at ${formatInstallDisplayUrl(displayApiBaseUrl)}`);
|
|
2397
2563
|
}
|
|
2398
2564
|
if (dockerAppPlan || localAppPlan || builtinDbPlan) {
|
|
2399
2565
|
await this.saveInstalledEnv({
|
|
@@ -2411,6 +2577,7 @@ export default class Install extends Command {
|
|
|
2411
2577
|
appReady: Boolean(dockerAppPlan || localAppPlan),
|
|
2412
2578
|
skipAuth: Boolean(parsed['skip-auth']),
|
|
2413
2579
|
});
|
|
2580
|
+
await clearEnvRootSetup(envName, { scope: resolveDefaultConfigScope() });
|
|
2414
2581
|
if (!dockerAppPlan && !localAppPlan) {
|
|
2415
2582
|
printInfo(`Install config for "${envName}" has been saved.`);
|
|
2416
2583
|
}
|