@nocobase/cli 2.3.0-beta.6 → 2.4.0-alpha.2
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/dist/commands/api/swagger/get.js +96 -0
- package/dist/commands/api/swagger/index.js +20 -0
- package/dist/commands/api/swagger/list.js +92 -0
- package/dist/commands/config/set.js +1 -0
- package/dist/commands/env/add.js +6 -0
- package/dist/commands/env/update.js +13 -0
- package/dist/commands/init.js +51 -5
- package/dist/commands/install.js +60 -3
- package/dist/commands/portal/config.js +99 -0
- package/dist/commands/portal/create.js +96 -0
- package/dist/commands/portal/deploy.js +81 -0
- package/dist/commands/portal/destroy.js +126 -0
- package/dist/commands/portal/dev.js +73 -0
- package/dist/commands/portal/index.js +20 -0
- package/dist/commands/portal/info.js +82 -0
- package/dist/commands/portal/list.js +98 -0
- package/dist/commands/portal/pull.js +113 -0
- package/dist/commands/portal/push.js +79 -0
- package/dist/commands/source/dev.js +1 -1
- package/dist/lib/api-client.js +35 -9
- package/dist/lib/app-client-entry-mode.js +28 -0
- package/dist/lib/app-managed-resources.js +2 -0
- package/dist/lib/auth-store.js +55 -2
- package/dist/lib/bootstrap.js +3 -1
- package/dist/lib/cli-config.js +20 -1
- package/dist/lib/env-auth.js +2 -36
- package/dist/lib/env-command-config.js +1 -0
- package/dist/lib/env-config.js +11 -0
- package/dist/lib/env-portal-config.js +30 -0
- package/dist/lib/env-proxy.js +154 -7
- package/dist/lib/managed-env-file.js +119 -9
- package/dist/lib/managed-init-env.js +4 -1
- package/dist/lib/portal-build-html.js +27 -0
- package/dist/lib/portal-command-env.js +31 -0
- package/dist/lib/portal-config.js +119 -0
- package/dist/lib/portal-configure.js +110 -0
- package/dist/lib/portal-create.js +515 -0
- package/dist/lib/portal-deploy.js +266 -0
- package/dist/lib/portal-destroy.js +114 -0
- package/dist/lib/portal-dev.js +78 -0
- package/dist/lib/portal-env-files.js +54 -0
- package/dist/lib/portal-info.js +28 -0
- package/dist/lib/portal-list.js +205 -0
- package/dist/lib/portal-path-safety.js +76 -0
- package/dist/lib/portal-source.js +692 -0
- package/dist/lib/prompt-catalog-core.js +2 -2
- package/dist/lib/prompt-catalog-terminal.js +4 -5
- package/dist/lib/prompt-web-ui.js +12 -6
- package/dist/lib/proxy-caddy.js +2 -0
- package/dist/lib/proxy-nginx.js +1 -0
- package/dist/lib/run-npm.js +85 -20
- package/dist/lib/swagger-command.js +52 -0
- package/dist/lib/ui.js +28 -1
- package/dist/locale/en-US.json +245 -1
- package/dist/locale/zh-CN.json +245 -1
- package/package.json +5 -2
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is part of the NocoBase (R) project.
|
|
3
|
+
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
|
4
|
+
* Authors: NocoBase Team.
|
|
5
|
+
*
|
|
6
|
+
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
|
7
|
+
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
|
+
*/
|
|
9
|
+
import { promises as fs } from 'node:fs';
|
|
10
|
+
import path from 'node:path';
|
|
11
|
+
import { Command, Flags } from '@oclif/core';
|
|
12
|
+
import { translateCli } from '../../../lib/cli-locale.js';
|
|
13
|
+
import { executeSwaggerRequest, swaggerRequestFlags } from '../../../lib/swagger-command.js';
|
|
14
|
+
import { renderTable } from '../../../lib/ui.js';
|
|
15
|
+
const swaggerText = (key, values, fallback) => translateCli(`commands.swagger.${key}`, values, { fallback });
|
|
16
|
+
function isRecord(value) {
|
|
17
|
+
return Boolean(value && typeof value === 'object' && !Array.isArray(value));
|
|
18
|
+
}
|
|
19
|
+
function unwrapData(value) {
|
|
20
|
+
if (!isRecord(value) || typeof value.openapi === 'string') {
|
|
21
|
+
return value;
|
|
22
|
+
}
|
|
23
|
+
return Object.prototype.hasOwnProperty.call(value, 'data') ? value.data : value;
|
|
24
|
+
}
|
|
25
|
+
function normalizeDocument(value) {
|
|
26
|
+
const document = unwrapData(value);
|
|
27
|
+
if (!isRecord(document) ||
|
|
28
|
+
typeof document.openapi !== 'string' ||
|
|
29
|
+
!isRecord(document.info) ||
|
|
30
|
+
!isRecord(document.paths)) {
|
|
31
|
+
return undefined;
|
|
32
|
+
}
|
|
33
|
+
return document;
|
|
34
|
+
}
|
|
35
|
+
export default class SwaggerGet extends Command {
|
|
36
|
+
static summary = 'Get a NocoBase OpenAPI document';
|
|
37
|
+
static examples = [
|
|
38
|
+
'<%= config.bin %> <%= command.id %> --json',
|
|
39
|
+
'<%= config.bin %> <%= command.id %> --namespace collections/orders --json',
|
|
40
|
+
'<%= config.bin %> <%= command.id %> --namespace plugins/ai --output ./openapi/ai.json',
|
|
41
|
+
];
|
|
42
|
+
static flags = {
|
|
43
|
+
...swaggerRequestFlags,
|
|
44
|
+
namespace: Flags.string({
|
|
45
|
+
aliases: ['ns'],
|
|
46
|
+
description: 'Document namespace, such as core, plugins/ai, or collections/orders',
|
|
47
|
+
}),
|
|
48
|
+
output: Flags.string({
|
|
49
|
+
char: 'o',
|
|
50
|
+
description: 'Write the OpenAPI document to a file',
|
|
51
|
+
}),
|
|
52
|
+
'json-output': Flags.boolean({
|
|
53
|
+
char: 'j',
|
|
54
|
+
aliases: ['json'],
|
|
55
|
+
description: 'Print the complete OpenAPI document as JSON',
|
|
56
|
+
default: false,
|
|
57
|
+
}),
|
|
58
|
+
};
|
|
59
|
+
async run() {
|
|
60
|
+
const { flags } = await this.parse(SwaggerGet);
|
|
61
|
+
const namespace = flags.namespace?.trim() || undefined;
|
|
62
|
+
const response = await executeSwaggerRequest(this, flags, '/swagger:get', { ns: namespace });
|
|
63
|
+
if (!response) {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
if (!response.ok) {
|
|
67
|
+
const details = JSON.stringify(response.data, null, 2);
|
|
68
|
+
this.error(response.status === 404
|
|
69
|
+
? swaggerText('errors.pluginDisabled', undefined, 'The API documentation plugin is not enabled. Enable it before requesting Swagger documents.')
|
|
70
|
+
: swaggerText('errors.requestFailed', { status: response.status, details }, `Swagger request failed with status ${response.status}\n${details}`));
|
|
71
|
+
}
|
|
72
|
+
const document = normalizeDocument(response.data);
|
|
73
|
+
if (!document) {
|
|
74
|
+
this.error(swaggerText('errors.invalidDocument', undefined, 'swagger:get returned an invalid OpenAPI document.'));
|
|
75
|
+
}
|
|
76
|
+
const json = `${JSON.stringify(document, null, 2)}\n`;
|
|
77
|
+
if (flags.output) {
|
|
78
|
+
const outputPath = path.resolve(flags.output);
|
|
79
|
+
await fs.mkdir(path.dirname(outputPath), { recursive: true });
|
|
80
|
+
await fs.writeFile(outputPath, json);
|
|
81
|
+
this.log(swaggerText('messages.saved', { output: outputPath }, `Saved Swagger document to ${outputPath}.`));
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
if (flags['json-output']) {
|
|
85
|
+
this.log(json.trimEnd());
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
this.log(renderTable([swaggerText('table.field', undefined, 'Field'), swaggerText('table.value', undefined, 'Value')], [
|
|
89
|
+
[swaggerText('fields.namespace', undefined, 'Namespace'), namespace ?? 'all'],
|
|
90
|
+
[swaggerText('fields.title', undefined, 'Title'), document.info.title ?? ''],
|
|
91
|
+
[swaggerText('fields.version', undefined, 'Version'), document.info.version ?? ''],
|
|
92
|
+
[swaggerText('fields.openapi', undefined, 'OpenAPI'), document.openapi],
|
|
93
|
+
[swaggerText('fields.paths', undefined, 'Paths'), String(Object.keys(document.paths).length)],
|
|
94
|
+
]));
|
|
95
|
+
}
|
|
96
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is part of the NocoBase (R) project.
|
|
3
|
+
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
|
4
|
+
* Authors: NocoBase Team.
|
|
5
|
+
*
|
|
6
|
+
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
|
7
|
+
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
|
+
*/
|
|
9
|
+
import { Command, loadHelpClass } from '@oclif/core';
|
|
10
|
+
export default class Swagger extends Command {
|
|
11
|
+
static summary = 'Inspect the current NocoBase OpenAPI documentation';
|
|
12
|
+
async run() {
|
|
13
|
+
await this.parse(Swagger);
|
|
14
|
+
const Help = await loadHelpClass(this.config);
|
|
15
|
+
await new Help(this.config, this.config.pjson.oclif.helpOptions ?? this.config.pjson.helpOptions).showHelp([
|
|
16
|
+
this.id ?? 'api:swagger',
|
|
17
|
+
...this.argv,
|
|
18
|
+
]);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is part of the NocoBase (R) project.
|
|
3
|
+
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
|
4
|
+
* Authors: NocoBase Team.
|
|
5
|
+
*
|
|
6
|
+
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
|
7
|
+
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
|
+
*/
|
|
9
|
+
import { Command, Flags } from '@oclif/core';
|
|
10
|
+
import { translateCli } from '../../../lib/cli-locale.js';
|
|
11
|
+
import { executeSwaggerRequest, swaggerRequestFlags } from '../../../lib/swagger-command.js';
|
|
12
|
+
import { renderTable } from '../../../lib/ui.js';
|
|
13
|
+
const swaggerText = (key, values, fallback) => translateCli(`commands.swagger.${key}`, values, { fallback });
|
|
14
|
+
function isRecord(value) {
|
|
15
|
+
return Boolean(value && typeof value === 'object' && !Array.isArray(value));
|
|
16
|
+
}
|
|
17
|
+
function unwrapData(value) {
|
|
18
|
+
return isRecord(value) && Object.prototype.hasOwnProperty.call(value, 'data') ? value.data : value;
|
|
19
|
+
}
|
|
20
|
+
function readNamespace(url) {
|
|
21
|
+
try {
|
|
22
|
+
return new URL(url, 'http://localhost').searchParams.get('ns') || 'all';
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
return 'all';
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
function normalizeDestinations(value) {
|
|
29
|
+
const data = unwrapData(value);
|
|
30
|
+
if (!Array.isArray(data)) {
|
|
31
|
+
return undefined;
|
|
32
|
+
}
|
|
33
|
+
const destinations = [];
|
|
34
|
+
for (const item of data) {
|
|
35
|
+
if (!isRecord(item) || typeof item.name !== 'string' || typeof item.url !== 'string') {
|
|
36
|
+
return undefined;
|
|
37
|
+
}
|
|
38
|
+
destinations.push({
|
|
39
|
+
name: item.name,
|
|
40
|
+
namespace: readNamespace(item.url),
|
|
41
|
+
url: item.url,
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
return destinations;
|
|
45
|
+
}
|
|
46
|
+
export default class SwaggerList extends Command {
|
|
47
|
+
static summary = 'List available NocoBase OpenAPI document namespaces';
|
|
48
|
+
static examples = [
|
|
49
|
+
'<%= config.bin %> <%= command.id %>',
|
|
50
|
+
'<%= config.bin %> <%= command.id %> --json',
|
|
51
|
+
'<%= config.bin %> <%= command.id %> --env dev --yes --json',
|
|
52
|
+
];
|
|
53
|
+
static flags = {
|
|
54
|
+
...swaggerRequestFlags,
|
|
55
|
+
'json-output': Flags.boolean({
|
|
56
|
+
char: 'j',
|
|
57
|
+
aliases: ['json'],
|
|
58
|
+
description: 'Print namespaces as JSON',
|
|
59
|
+
default: false,
|
|
60
|
+
}),
|
|
61
|
+
};
|
|
62
|
+
async run() {
|
|
63
|
+
const { flags } = await this.parse(SwaggerList);
|
|
64
|
+
const response = await executeSwaggerRequest(this, flags, '/swagger:getUrls');
|
|
65
|
+
if (!response) {
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
if (!response.ok) {
|
|
69
|
+
const details = JSON.stringify(response.data, null, 2);
|
|
70
|
+
this.error(response.status === 404
|
|
71
|
+
? swaggerText('errors.pluginDisabled', undefined, 'The API documentation plugin is not enabled. Enable it before requesting Swagger documents.')
|
|
72
|
+
: swaggerText('errors.requestFailed', { status: response.status, details }, `Swagger request failed with status ${response.status}\n${details}`));
|
|
73
|
+
}
|
|
74
|
+
const destinations = normalizeDestinations(response.data);
|
|
75
|
+
if (!destinations) {
|
|
76
|
+
this.error(swaggerText('errors.invalidDestinations', undefined, 'swagger:getUrls returned an invalid destination list.'));
|
|
77
|
+
}
|
|
78
|
+
if (flags['json-output']) {
|
|
79
|
+
this.log(JSON.stringify(destinations, null, 2));
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
if (!destinations.length) {
|
|
83
|
+
this.log(swaggerText('messages.empty', undefined, 'No Swagger document namespaces are available.'));
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
this.log(renderTable([
|
|
87
|
+
swaggerText('table.name', undefined, 'Name'),
|
|
88
|
+
swaggerText('table.namespace', undefined, 'Namespace'),
|
|
89
|
+
swaggerText('table.url', undefined, 'URL'),
|
|
90
|
+
], destinations.map((item) => [item.name, item.namespace, item.url])));
|
|
91
|
+
}
|
|
92
|
+
}
|
|
@@ -14,6 +14,7 @@ export default class ConfigSet extends Command {
|
|
|
14
14
|
static description = 'Set a CLI configuration value for a supported configuration key.';
|
|
15
15
|
static examples = [
|
|
16
16
|
'<%= config.bin %> <%= command.id %> locale zh-CN',
|
|
17
|
+
'<%= config.bin %> <%= command.id %> default-portal-template @nocobase/portal-template-default',
|
|
17
18
|
'<%= config.bin %> <%= command.id %> update.policy prompt',
|
|
18
19
|
'<%= config.bin %> <%= command.id %> docker.network nocobase',
|
|
19
20
|
'<%= config.bin %> <%= command.id %> docker.container-prefix nb',
|
package/dist/commands/env/add.js
CHANGED
|
@@ -11,6 +11,7 @@ import { setCurrentEnv, upsertEnv } from '../../lib/auth-store.js';
|
|
|
11
11
|
import { resolveDefaultConfigScope } from '../../lib/cli-home.js';
|
|
12
12
|
import { ENV_BOOLEAN_CONFIG_FLAG_MAP, ENV_STRING_CONFIG_FLAG_MAP } from '../../lib/env-command-config.js';
|
|
13
13
|
import { buildStoredEnvConfig } from '../../lib/env-config.js';
|
|
14
|
+
import { PUBLIC_APP_CLIENT_ENTRY_MODES } from '../../lib/app-client-entry-mode.js';
|
|
14
15
|
import { runPromptCatalog, } from '../../lib/prompt-catalog.js';
|
|
15
16
|
import { applyCliLocale, CLI_LOCALE_FLAG_DESCRIPTION, CLI_LOCALE_FLAG_OPTIONS, localeText, } from '../../lib/cli-locale.js';
|
|
16
17
|
import { validateApiBaseUrl } from '../../lib/prompt-validators.js';
|
|
@@ -172,6 +173,11 @@ export default class EnvAdd extends Command {
|
|
|
172
173
|
hidden: true,
|
|
173
174
|
description: 'Docker env file saved with this env',
|
|
174
175
|
}),
|
|
176
|
+
'app-client-entry-mode': Flags.string({
|
|
177
|
+
hidden: true,
|
|
178
|
+
description: 'UI entry mode saved with this env',
|
|
179
|
+
options: [...PUBLIC_APP_CLIENT_ENTRY_MODES],
|
|
180
|
+
}),
|
|
175
181
|
'app-port': Flags.string({
|
|
176
182
|
hidden: true,
|
|
177
183
|
description: 'Application HTTP port saved with this env',
|
|
@@ -16,6 +16,8 @@ import { appendDiagnosticLogPath } from '../../lib/cli-entry-error.js';
|
|
|
16
16
|
import { getActiveCommandLogFile } from '../../lib/command-log.js';
|
|
17
17
|
import { ENV_BOOLEAN_CONFIG_FLAG_MAP, ENV_STRING_CONFIG_FLAG_MAP } from '../../lib/env-command-config.js';
|
|
18
18
|
import { buildStoredEnvConfig } from '../../lib/env-config.js';
|
|
19
|
+
import { PUBLIC_APP_CLIENT_ENTRY_MODES } from '../../lib/app-client-entry-mode.js';
|
|
20
|
+
import { upsertManagedEnvFileValues } from '../../lib/managed-env-file.js';
|
|
19
21
|
import { validateApiBaseUrl } from '../../lib/prompt-validators.js';
|
|
20
22
|
import { failTask, printInfo, printVerbose, printWarningBlock, setVerboseMode, startTask, stopTask, succeedTask, } from '../../lib/ui.js';
|
|
21
23
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
@@ -35,6 +37,7 @@ const UPDATE_STRING_FLAGS = [
|
|
|
35
37
|
'app-public-path',
|
|
36
38
|
'cdn-base-url',
|
|
37
39
|
'env-file',
|
|
40
|
+
'app-client-entry-mode',
|
|
38
41
|
'app-port',
|
|
39
42
|
'app-key',
|
|
40
43
|
'timezone',
|
|
@@ -68,6 +71,7 @@ const APP_RESTART_FIELDS = new Set([
|
|
|
68
71
|
'storage-path',
|
|
69
72
|
'app-public-path',
|
|
70
73
|
'env-file',
|
|
74
|
+
'app-client-entry-mode',
|
|
71
75
|
'app-port',
|
|
72
76
|
'app-key',
|
|
73
77
|
'timezone',
|
|
@@ -255,6 +259,10 @@ export default class EnvUpdate extends Command {
|
|
|
255
259
|
hidden: true,
|
|
256
260
|
description: 'Saved Docker --env-file path for this env',
|
|
257
261
|
}),
|
|
262
|
+
'app-client-entry-mode': Flags.string({
|
|
263
|
+
description: 'Saved UI entry mode for this env',
|
|
264
|
+
options: [...PUBLIC_APP_CLIENT_ENTRY_MODES],
|
|
265
|
+
}),
|
|
258
266
|
'app-port': Flags.string({
|
|
259
267
|
description: 'Saved application HTTP port for this env',
|
|
260
268
|
}),
|
|
@@ -423,6 +431,11 @@ export default class EnvUpdate extends Command {
|
|
|
423
431
|
startTask(`Saving env config: ${envName}`);
|
|
424
432
|
try {
|
|
425
433
|
await replaceEnvConfig(envName, nextConfig, { scope: resolveDefaultConfigScope() });
|
|
434
|
+
if (providedFields.has('app-client-entry-mode') && nextConfig.appClientEntryMode) {
|
|
435
|
+
await upsertManagedEnvFileValues(envName, nextConfig, {
|
|
436
|
+
APP_CLIENT_ENTRY_MODE: nextConfig.appClientEntryMode,
|
|
437
|
+
});
|
|
438
|
+
}
|
|
426
439
|
succeedTask(`Saved env config for "${envName}".`);
|
|
427
440
|
}
|
|
428
441
|
catch (error) {
|
package/dist/commands/init.js
CHANGED
|
@@ -13,6 +13,7 @@ import { existsSync } from 'node:fs';
|
|
|
13
13
|
import path from 'node:path';
|
|
14
14
|
import { stdin as stdinStream, stdout as stdoutStream } from 'node:process';
|
|
15
15
|
import { getEnv, upsertEnv } from "../lib/auth-store.js";
|
|
16
|
+
import { defaultAppClientEntryModeForDownloadVersion, normalizePublicAppClientEntryMode, PUBLIC_APP_CLIENT_ENTRY_MODES, } from '../lib/app-client-entry-mode.js';
|
|
16
17
|
import { runPromptCatalog, } from "../lib/prompt-catalog.js";
|
|
17
18
|
import { applyCliLocale, localeText, translateCli } from "../lib/cli-locale.js";
|
|
18
19
|
import { resolveConfiguredEnvPath, resolveDefaultConfigScope, resolveEnvRelativePath } from '../lib/cli-home.js';
|
|
@@ -27,6 +28,7 @@ import { omitKeys, pickKeys } from "../lib/object-utils.js";
|
|
|
27
28
|
import { ENV_CONFIG_SCHEMA_VERSION } from '../lib/env-config.js';
|
|
28
29
|
import { printInfo, printStage, printVerbose, printWarning } from '../lib/ui.js';
|
|
29
30
|
import { persistHookScript } from '../lib/hook-script.js';
|
|
31
|
+
import { ensureManagedEnvFileDefaults } from '../lib/managed-env-file.js';
|
|
30
32
|
import Download from "./download.js";
|
|
31
33
|
import EnvAdd from "./env/add.js";
|
|
32
34
|
import Install, { defaultDbPortForDialect } from "./install.js";
|
|
@@ -105,9 +107,23 @@ function resolveInitDownloadVersion(results) {
|
|
|
105
107
|
}
|
|
106
108
|
return preset;
|
|
107
109
|
}
|
|
110
|
+
function resolveInitAppClientEntryMode(results, explicitValue) {
|
|
111
|
+
return (normalizePublicAppClientEntryMode(explicitValue) ??
|
|
112
|
+
normalizePublicAppClientEntryMode(results.appClientEntryMode) ??
|
|
113
|
+
defaultAppClientEntryModeForDownloadVersion(resolveInitDownloadVersion(results)));
|
|
114
|
+
}
|
|
108
115
|
function initVersionPromptValue(version) {
|
|
109
116
|
return version === 'latest' || version === 'beta' || version === 'alpha' ? version : 'other';
|
|
110
117
|
}
|
|
118
|
+
export function defaultInitDownloadVersionForCliVersion(cliVersion) {
|
|
119
|
+
if (/-alpha(?:[.-]|$)/i.test(cliVersion)) {
|
|
120
|
+
return 'alpha';
|
|
121
|
+
}
|
|
122
|
+
if (/-beta(?:[.-]|$)/i.test(cliVersion)) {
|
|
123
|
+
return 'beta';
|
|
124
|
+
}
|
|
125
|
+
return 'latest';
|
|
126
|
+
}
|
|
111
127
|
function yesInitialValue(def, fallback) {
|
|
112
128
|
if ('yesInitialValue' in def && def.yesInitialValue !== undefined) {
|
|
113
129
|
return String(def.yesInitialValue);
|
|
@@ -408,8 +424,15 @@ Prompt modes:
|
|
|
408
424
|
installAccessToken: installConnectionAccessTokenPrompt,
|
|
409
425
|
};
|
|
410
426
|
buildPromptCatalog(flags, options) {
|
|
427
|
+
const downloadVersion = defaultInitDownloadVersionForCliVersion(String(this.config.pjson?.version ?? '').trim());
|
|
428
|
+
const versionPrompt = Init.prompts.version;
|
|
411
429
|
const prompts = {
|
|
412
430
|
...Init.prompts,
|
|
431
|
+
version: {
|
|
432
|
+
...versionPrompt,
|
|
433
|
+
initialValue: downloadVersion,
|
|
434
|
+
yesInitialValue: downloadVersion,
|
|
435
|
+
},
|
|
413
436
|
installApiBaseUrl: createInstallConnectionApiBaseUrlPrompt(options.defaultApiHost),
|
|
414
437
|
};
|
|
415
438
|
if (flags['skip-auth']) {
|
|
@@ -473,6 +496,10 @@ Prompt modes:
|
|
|
473
496
|
description: 'Skip installing NocoBase AI coding skills during init',
|
|
474
497
|
default: false,
|
|
475
498
|
}),
|
|
499
|
+
'app-client-entry-mode': Flags.string({
|
|
500
|
+
description: 'UI entry mode for this app env: modern-only, modern-default, or legacy-default',
|
|
501
|
+
options: [...PUBLIC_APP_CLIENT_ENTRY_MODES],
|
|
502
|
+
}),
|
|
476
503
|
'ui-host': Flags.string({
|
|
477
504
|
description: 'Browser-accessible host for the --ui setup page URL (default: 127.0.0.1)',
|
|
478
505
|
}),
|
|
@@ -607,6 +634,7 @@ Prompt modes:
|
|
|
607
634
|
? { setupMode: normalizeInitSetupMode(presetValues.hasNocobase) }
|
|
608
635
|
: {}),
|
|
609
636
|
},
|
|
637
|
+
yesInitialValues: {},
|
|
610
638
|
values: presetValues,
|
|
611
639
|
yes: normalizedFlags.yes || useBrowserUi || !interactive,
|
|
612
640
|
hooks: {
|
|
@@ -679,7 +707,8 @@ Prompt modes:
|
|
|
679
707
|
}
|
|
680
708
|
static async buildDynamicInitialValuesForInstall(flags, presetValues) {
|
|
681
709
|
const out = {};
|
|
682
|
-
|
|
710
|
+
const shouldResolveAppInitialValues = !Object.prototype.hasOwnProperty.call(presetValues, 'appPort');
|
|
711
|
+
if (shouldResolveAppInitialValues) {
|
|
683
712
|
const appInitialValues = await Install.buildAppPromptInitialValues({
|
|
684
713
|
envName: String(presetValues.appName ?? '').trim(),
|
|
685
714
|
flags: {
|
|
@@ -690,7 +719,7 @@ Prompt modes:
|
|
|
690
719
|
},
|
|
691
720
|
warnOnPortFallback: false,
|
|
692
721
|
});
|
|
693
|
-
if (appInitialValues.appPort !== undefined) {
|
|
722
|
+
if (appInitialValues.appPort !== undefined && !Object.prototype.hasOwnProperty.call(presetValues, 'appPort')) {
|
|
694
723
|
out.appPort = appInitialValues.appPort;
|
|
695
724
|
}
|
|
696
725
|
}
|
|
@@ -871,6 +900,9 @@ Prompt modes:
|
|
|
871
900
|
if (flags['app-public-path'] !== undefined && String(flags['app-public-path']).trim() !== '') {
|
|
872
901
|
preset.appPublicPath = String(flags['app-public-path']).trim();
|
|
873
902
|
}
|
|
903
|
+
if (flags['app-client-entry-mode'] !== undefined && String(flags['app-client-entry-mode']).trim() !== '') {
|
|
904
|
+
preset.appClientEntryMode = String(flags['app-client-entry-mode']).trim();
|
|
905
|
+
}
|
|
874
906
|
if (flags['root-username'] !== undefined) {
|
|
875
907
|
preset.rootUsername = String(flags['root-username'] ?? '').trim();
|
|
876
908
|
}
|
|
@@ -1008,6 +1040,7 @@ Prompt modes:
|
|
|
1008
1040
|
const existingEnv = await getEnv(envName, { scope: resolveDefaultConfigScope() });
|
|
1009
1041
|
const appPort = String(results.appPort ?? '').trim();
|
|
1010
1042
|
const appPublicPath = String(results.appPublicPath ?? '').trim();
|
|
1043
|
+
const appClientEntryMode = resolveInitAppClientEntryMode(results, flags['app-client-entry-mode']);
|
|
1011
1044
|
const source = String(results.source ?? '').trim();
|
|
1012
1045
|
const version = resolveInitDownloadVersion(results);
|
|
1013
1046
|
const dockerRegistry = String(results.dockerRegistry ?? '').trim();
|
|
@@ -1034,7 +1067,8 @@ Prompt modes:
|
|
|
1034
1067
|
const dbSchema = String(results.dbSchema ?? '').trim();
|
|
1035
1068
|
const dbTablePrefix = String(results.dbTablePrefix ?? '').trim();
|
|
1036
1069
|
const apiBaseUrl = String(results.apiBaseUrl ?? '').trim();
|
|
1037
|
-
const
|
|
1070
|
+
const authTypeInput = String(results.authType ?? '').trim();
|
|
1071
|
+
const authType = authTypeInput === 'basic' || authTypeInput === 'token' || authTypeInput === 'oauth' ? authTypeInput : 'oauth';
|
|
1038
1072
|
const authUsername = authType === 'basic' ? String(results.username ?? results.rootUsername ?? '').trim() : '';
|
|
1039
1073
|
const accessToken = String(results.accessToken ?? '');
|
|
1040
1074
|
const skipDownload = results.skipDownload === true;
|
|
@@ -1055,7 +1089,7 @@ Prompt modes:
|
|
|
1055
1089
|
: Boolean(results.builtinDb);
|
|
1056
1090
|
results.appKey = appKey;
|
|
1057
1091
|
results.timeZone = timeZone;
|
|
1058
|
-
|
|
1092
|
+
const savedEnvConfig = {
|
|
1059
1093
|
schemaVersion: ENV_CONFIG_SCHEMA_VERSION,
|
|
1060
1094
|
...(source === 'docker'
|
|
1061
1095
|
? { kind: 'docker' }
|
|
@@ -1080,6 +1114,7 @@ Prompt modes:
|
|
|
1080
1114
|
...(storagePath && !areConfiguredPathsEquivalent(storagePath, derivedStoragePath) ? { storagePath } : {}),
|
|
1081
1115
|
...(appPort ? { appPort } : {}),
|
|
1082
1116
|
...(appPublicPath ? { appPublicPath } : {}),
|
|
1117
|
+
...(appClientEntryMode ? { appClientEntryMode } : {}),
|
|
1083
1118
|
...(appKey ? { appKey } : {}),
|
|
1084
1119
|
...(timeZone ? { timezone: timeZone } : {}),
|
|
1085
1120
|
...(!skipDownload && results.devDependencies !== undefined
|
|
@@ -1100,7 +1135,11 @@ Prompt modes:
|
|
|
1100
1135
|
...(results.dbUnderscored !== undefined ? { dbUnderscored: Boolean(results.dbUnderscored) } : {}),
|
|
1101
1136
|
setupState: 'prepared',
|
|
1102
1137
|
...(String(results.lang ?? '').trim() ? { lang: String(results.lang ?? '').trim() } : {}),
|
|
1103
|
-
}
|
|
1138
|
+
};
|
|
1139
|
+
await upsertEnv(envName, savedEnvConfig, { scope: resolveDefaultConfigScope() });
|
|
1140
|
+
if (source === 'docker' || appPath) {
|
|
1141
|
+
await ensureManagedEnvFileDefaults(envName, savedEnvConfig);
|
|
1142
|
+
}
|
|
1104
1143
|
}
|
|
1105
1144
|
buildEnvAddArgv(results) {
|
|
1106
1145
|
const argv = [String(results.appName ?? DEFAULT_INIT_APP_NAME)];
|
|
@@ -1204,6 +1243,13 @@ Prompt modes:
|
|
|
1204
1243
|
if (appPublicPath) {
|
|
1205
1244
|
argv.push('--app-public-path', appPublicPath);
|
|
1206
1245
|
}
|
|
1246
|
+
const appClientEntryMode = normalizePublicAppClientEntryMode(flags['app-client-entry-mode']) ||
|
|
1247
|
+
(results.setupMode === 'install-new' && results.hasNocobase === undefined
|
|
1248
|
+
? resolveInitAppClientEntryMode(results)
|
|
1249
|
+
: undefined);
|
|
1250
|
+
if (appClientEntryMode) {
|
|
1251
|
+
argv.push('--app-client-entry-mode', appClientEntryMode);
|
|
1252
|
+
}
|
|
1207
1253
|
if (flags.force) {
|
|
1208
1254
|
argv.push('--force');
|
|
1209
1255
|
}
|
package/dist/commands/install.js
CHANGED
|
@@ -25,10 +25,12 @@ import { commandOutput, commandSucceeds, ensureDockerDaemonRunning, run, runNoco
|
|
|
25
25
|
import { printInfo, printStage, printVerbose, printWarning, setVerboseMode } from '../lib/ui.js';
|
|
26
26
|
import { omitKeys, upperFirst } from "../lib/object-utils.js";
|
|
27
27
|
import { clearEnvRootSetup, getEnv, setCurrentEnv, upsertEnv } from '../lib/auth-store.js';
|
|
28
|
+
import { defaultAppClientEntryModeForDownloadVersion, normalizePublicAppClientEntryMode, PUBLIC_APP_CLIENT_ENTRY_MODES, } from '../lib/app-client-entry-mode.js';
|
|
28
29
|
import { buildStoredEnvConfig } from '../lib/env-config.js';
|
|
29
30
|
import { resolveDockerEnvFileArg } from "../lib/docker-env-file.js";
|
|
30
31
|
import { startDockerLogFollower } from '../lib/docker-log-stream.js';
|
|
31
32
|
import { buildInitAppEnvVarsFromConfig } from '../lib/managed-init-env.js';
|
|
33
|
+
import { ensureManagedEnvFileDefaults } from '../lib/managed-env-file.js';
|
|
32
34
|
import { buildHookContext, persistHookScript, resolveHookScriptPath, runHookScriptHook, } from '../lib/hook-script.js';
|
|
33
35
|
import { areConfiguredPathsEquivalent, deriveConfiguredSourcePath, deriveConfiguredStoragePath, inferConfiguredAppPathFromLegacyConfig, } from '../lib/env-paths.js';
|
|
34
36
|
import Download from './download.js';
|
|
@@ -53,6 +55,7 @@ const DEFAULT_INSTALL_ROOT_EMAIL = 'admin@nocobase.com';
|
|
|
53
55
|
const DEFAULT_INSTALL_ROOT_PASSWORD = 'admin123';
|
|
54
56
|
const DEFAULT_INSTALL_ROOT_NICKNAME = 'Super Admin';
|
|
55
57
|
const DEFAULT_INSTALL_API_HOST = '127.0.0.1';
|
|
58
|
+
const DEFAULT_INSTALL_PORTAL_TEMPLATE = '@nocobase/portal-template-default';
|
|
56
59
|
function toOptionalPromptString(value) {
|
|
57
60
|
const text = String(value ?? '').trim();
|
|
58
61
|
return text || undefined;
|
|
@@ -404,6 +407,13 @@ export default class Install extends Command {
|
|
|
404
407
|
'app-public-path': Flags.string({
|
|
405
408
|
description: 'Public path for the local app, for example / or /console/',
|
|
406
409
|
}),
|
|
410
|
+
'app-client-entry-mode': Flags.string({
|
|
411
|
+
description: 'UI entry mode for this app env: modern-only, modern-default, or legacy-default',
|
|
412
|
+
options: [...PUBLIC_APP_CLIENT_ENTRY_MODES],
|
|
413
|
+
}),
|
|
414
|
+
'portal-template': Flags.string({
|
|
415
|
+
description: 'Template npm package or local path for the default AI Portal "main"',
|
|
416
|
+
}),
|
|
407
417
|
'root-username': Flags.string({
|
|
408
418
|
description: 'Initial admin username for the installed app',
|
|
409
419
|
required: false,
|
|
@@ -513,6 +523,14 @@ export default class Install extends Command {
|
|
|
513
523
|
yesInitialValue: '/',
|
|
514
524
|
validate: validateAppPublicPath,
|
|
515
525
|
},
|
|
526
|
+
portalTemplate: {
|
|
527
|
+
type: 'text',
|
|
528
|
+
message: installText('prompts.portalTemplate.message'),
|
|
529
|
+
placeholder: DEFAULT_INSTALL_PORTAL_TEMPLATE,
|
|
530
|
+
initialValue: DEFAULT_INSTALL_PORTAL_TEMPLATE,
|
|
531
|
+
yesInitialValue: DEFAULT_INSTALL_PORTAL_TEMPLATE,
|
|
532
|
+
required: true,
|
|
533
|
+
},
|
|
516
534
|
};
|
|
517
535
|
}
|
|
518
536
|
static dbPrompts = {
|
|
@@ -772,6 +790,18 @@ export default class Install extends Command {
|
|
|
772
790
|
preset.appPublicPath = v;
|
|
773
791
|
}
|
|
774
792
|
}
|
|
793
|
+
if (flags['app-client-entry-mode'] !== undefined) {
|
|
794
|
+
const v = normalizePublicAppClientEntryMode(flags['app-client-entry-mode']);
|
|
795
|
+
if (v) {
|
|
796
|
+
preset.appClientEntryMode = v;
|
|
797
|
+
}
|
|
798
|
+
}
|
|
799
|
+
if (flags['portal-template'] !== undefined) {
|
|
800
|
+
const v = String(flags['portal-template'] ?? '').trim();
|
|
801
|
+
if (v) {
|
|
802
|
+
preset.portalTemplate = v;
|
|
803
|
+
}
|
|
804
|
+
}
|
|
775
805
|
if (flags['root-username'] !== undefined) {
|
|
776
806
|
preset.rootUsername = String(flags['root-username'] ?? '').trim();
|
|
777
807
|
}
|
|
@@ -863,6 +893,8 @@ export default class Install extends Command {
|
|
|
863
893
|
'appPort',
|
|
864
894
|
'storagePath',
|
|
865
895
|
'appPublicPath',
|
|
896
|
+
'appClientEntryMode',
|
|
897
|
+
'portalTemplate',
|
|
866
898
|
]);
|
|
867
899
|
}
|
|
868
900
|
static buildDbPresetValuesFromFlags(flags, argv = process.argv.slice(2)) {
|
|
@@ -1112,6 +1144,7 @@ export default class Install extends Command {
|
|
|
1112
1144
|
const rootPassword = Install.toOptionalPromptString(config.rootPassword);
|
|
1113
1145
|
const rootNickname = Install.toOptionalPromptString(config.rootNickname);
|
|
1114
1146
|
const lang = Install.toOptionalPromptString(config.lang);
|
|
1147
|
+
const portalTemplate = Install.toOptionalPromptString(config.portalTemplate);
|
|
1115
1148
|
const auth = config.auth;
|
|
1116
1149
|
const savedAuthType = Install.toOptionalPromptString(config.authType) ?? Install.toOptionalPromptString(auth?.type);
|
|
1117
1150
|
const appPreset = {
|
|
@@ -1121,6 +1154,7 @@ export default class Install extends Command {
|
|
|
1121
1154
|
...(appPort ? { appPort } : {}),
|
|
1122
1155
|
...(storagePath ? { storagePath } : {}),
|
|
1123
1156
|
...(appPublicPath ? { appPublicPath } : {}),
|
|
1157
|
+
...(portalTemplate ? { portalTemplate } : {}),
|
|
1124
1158
|
...(hookScript ? { hookScript } : {}),
|
|
1125
1159
|
};
|
|
1126
1160
|
const downloadPreset = {
|
|
@@ -1263,6 +1297,12 @@ export default class Install extends Command {
|
|
|
1263
1297
|
warn: params.warnOnPortFallback ?? true,
|
|
1264
1298
|
});
|
|
1265
1299
|
}
|
|
1300
|
+
if (params.flags['portal-template'] === undefined) {
|
|
1301
|
+
const defaultPortalTemplate = Install.toOptionalPromptString(await getCliConfigValue('default-portal-template'));
|
|
1302
|
+
if (defaultPortalTemplate) {
|
|
1303
|
+
initialValues.portalTemplate = defaultPortalTemplate;
|
|
1304
|
+
}
|
|
1305
|
+
}
|
|
1266
1306
|
return initialValues;
|
|
1267
1307
|
}
|
|
1268
1308
|
static shouldPublishBuiltinDbPortForValues(values) {
|
|
@@ -1430,14 +1470,15 @@ export default class Install extends Command {
|
|
|
1430
1470
|
static buildDockerAppContainerName(envName, containerPrefix) {
|
|
1431
1471
|
return Install.sanitizeDockerResourceName(`${Install.buildBuiltinDbContainerPrefix(containerPrefix)}-${envName}-app`);
|
|
1432
1472
|
}
|
|
1433
|
-
static buildInitAppEnvVars(params) {
|
|
1473
|
+
static buildInitAppEnvVars(params, options = {}) {
|
|
1434
1474
|
return buildInitAppEnvVarsFromConfig({
|
|
1435
1475
|
lang: String(params.appResults.lang ?? ''),
|
|
1436
1476
|
rootUsername: String(params.rootResults.rootUsername ?? ''),
|
|
1437
1477
|
rootEmail: String(params.rootResults.rootEmail ?? ''),
|
|
1438
1478
|
rootPassword: String(params.rootResults.rootPassword ?? ''),
|
|
1439
1479
|
rootNickname: String(params.rootResults.rootNickname ?? ''),
|
|
1440
|
-
|
|
1480
|
+
portalTemplate: String(params.appResults.portalTemplate ?? ''),
|
|
1481
|
+
}, options);
|
|
1441
1482
|
}
|
|
1442
1483
|
static shouldPublishBuiltinDbPort(source) {
|
|
1443
1484
|
return String(source ?? '').trim() !== 'docker';
|
|
@@ -1785,6 +1826,7 @@ export default class Install extends Command {
|
|
|
1785
1826
|
const extractClientAssets = resolveExtractClientAssetsDefaultEnabled(process.env.NOCOBASE_EXTRACT_CLIENT_ASSETS);
|
|
1786
1827
|
const appKey = Install.resolveManagedAppKey(params.appResults.appKey);
|
|
1787
1828
|
const appPublicPath = Install.toOptionalPromptString(params.appResults.appPublicPath);
|
|
1829
|
+
const appClientEntryMode = Install.toOptionalPromptString(params.appResults.appClientEntryMode);
|
|
1788
1830
|
const timeZone = Install.resolveManagedTimeZone(params.appResults.timeZone);
|
|
1789
1831
|
const containerName = Install.buildDockerAppContainerName(params.envName, params.dockerContainerPrefix ?? params.workspaceName);
|
|
1790
1832
|
const configuredEnvFile = String(params.appResults.envFile ?? '').trim();
|
|
@@ -1812,6 +1854,7 @@ export default class Install extends Command {
|
|
|
1812
1854
|
}
|
|
1813
1855
|
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`);
|
|
1814
1856
|
pushOptionalEnvArg(args, 'APP_PUBLIC_PATH', appPublicPath);
|
|
1857
|
+
pushOptionalEnvArg(args, 'APP_CLIENT_ENTRY_MODE', appClientEntryMode);
|
|
1815
1858
|
pushOptionalEnvArg(args, 'DB_SCHEMA', dbSchema);
|
|
1816
1859
|
pushOptionalEnvArg(args, 'DB_TABLE_PREFIX', dbTablePrefix);
|
|
1817
1860
|
pushOptionalEnvArg(args, 'DB_UNDERSCORED', dbUnderscored);
|
|
@@ -2072,6 +2115,7 @@ export default class Install extends Command {
|
|
|
2072
2115
|
}),
|
|
2073
2116
|
};
|
|
2074
2117
|
setOptionalEnvVar(env, 'APP_PUBLIC_PATH', Install.toOptionalPromptString(params.appResults.appPublicPath));
|
|
2118
|
+
setOptionalEnvVar(env, 'APP_CLIENT_ENTRY_MODE', Install.toOptionalPromptString(params.appResults.appClientEntryMode));
|
|
2075
2119
|
setOptionalEnvVar(env, 'DB_SCHEMA', optionalEnvString(params.dbResults.dbSchema));
|
|
2076
2120
|
setOptionalEnvVar(env, 'DB_TABLE_PREFIX', optionalEnvString(params.dbResults.dbTablePrefix));
|
|
2077
2121
|
setOptionalEnvVar(env, 'DB_UNDERSCORED', optionalEnvBoolean(params.dbResults.dbUnderscored));
|
|
@@ -2228,9 +2272,13 @@ export default class Install extends Command {
|
|
|
2228
2272
|
}
|
|
2229
2273
|
async saveInstalledEnv(params) {
|
|
2230
2274
|
const defaultApiHost = await resolveDefaultApiHost();
|
|
2231
|
-
|
|
2275
|
+
const savedEnvConfig = Install.buildSavedEnvConfig(params, { defaultApiHost });
|
|
2276
|
+
await upsertEnv(params.envName, savedEnvConfig, {
|
|
2232
2277
|
scope: resolveDefaultConfigScope(),
|
|
2233
2278
|
});
|
|
2279
|
+
if (params.ensureEnvFileDefaults !== false) {
|
|
2280
|
+
await ensureManagedEnvFileDefaults(params.envName, savedEnvConfig);
|
|
2281
|
+
}
|
|
2234
2282
|
await setCurrentEnv(params.envName, { scope: resolveDefaultConfigScope() });
|
|
2235
2283
|
}
|
|
2236
2284
|
async syncInstalledEnvConnection(params) {
|
|
@@ -2309,6 +2357,8 @@ export default class Install extends Command {
|
|
|
2309
2357
|
const appRootPath = Install.toOptionalPromptString(params.appResults.appRootPath);
|
|
2310
2358
|
const storagePath = Install.toOptionalPromptString(params.appResults.storagePath);
|
|
2311
2359
|
const appPublicPath = Install.toOptionalPromptString(params.appResults.appPublicPath);
|
|
2360
|
+
const appClientEntryMode = Install.toOptionalPromptString(params.appResults.appClientEntryMode);
|
|
2361
|
+
const portalTemplate = Install.toOptionalPromptString(params.appResults.portalTemplate);
|
|
2312
2362
|
const derivedAppRootPath = appPath ? deriveConfiguredSourcePath(appPath) : undefined;
|
|
2313
2363
|
const derivedStoragePath = appPath ? deriveConfiguredStoragePath(appPath) : undefined;
|
|
2314
2364
|
const appPort = String(params.appResults.appPort ?? DEFAULT_INSTALL_APP_PORT).trim() || DEFAULT_INSTALL_APP_PORT;
|
|
@@ -2341,8 +2391,10 @@ export default class Install extends Command {
|
|
|
2341
2391
|
appPort,
|
|
2342
2392
|
...(storagePath && !areConfiguredPathsEquivalent(storagePath, derivedStoragePath) ? { storagePath } : {}),
|
|
2343
2393
|
...(appPublicPath ? { appPublicPath } : {}),
|
|
2394
|
+
...(appClientEntryMode ? { appClientEntryMode } : {}),
|
|
2344
2395
|
...(envFile ? { envFile } : {}),
|
|
2345
2396
|
lang: params.appResults.lang,
|
|
2397
|
+
portalTemplate,
|
|
2346
2398
|
appKey: params.appResults.appKey,
|
|
2347
2399
|
timezone: params.appResults.timeZone,
|
|
2348
2400
|
builtinDb: params.dbResults.builtinDb,
|
|
@@ -2394,6 +2446,7 @@ export default class Install extends Command {
|
|
|
2394
2446
|
'app-root-path': parsed['app-root-path'] ?? Install.toOptionalPromptString(appPreset.appRootPath),
|
|
2395
2447
|
'app-port': parsed['app-port'] ?? Install.toOptionalPromptString(appPreset.appPort),
|
|
2396
2448
|
'storage-path': parsed['storage-path'] ?? Install.toOptionalPromptString(appPreset.storagePath),
|
|
2449
|
+
'portal-template': parsed['portal-template'] ?? Install.toOptionalPromptString(appPreset.portalTemplate),
|
|
2397
2450
|
},
|
|
2398
2451
|
}),
|
|
2399
2452
|
values: appPreset,
|
|
@@ -2412,6 +2465,9 @@ export default class Install extends Command {
|
|
|
2412
2465
|
};
|
|
2413
2466
|
downloadOpts.yes = yes;
|
|
2414
2467
|
const downloadResults = await runPromptCatalog(Download.prompts, downloadOpts);
|
|
2468
|
+
appResults.appClientEntryMode =
|
|
2469
|
+
normalizePublicAppClientEntryMode(appResults.appClientEntryMode) ??
|
|
2470
|
+
defaultAppClientEntryModeForDownloadVersion(downloadResultsValue(downloadResults, 'version'));
|
|
2415
2471
|
if (parsed['skip-download']) {
|
|
2416
2472
|
delete downloadResults.outputDir;
|
|
2417
2473
|
delete downloadResults.replace;
|
|
@@ -2565,6 +2621,7 @@ export default class Install extends Command {
|
|
|
2565
2621
|
dbResults,
|
|
2566
2622
|
rootResults,
|
|
2567
2623
|
envAddResults,
|
|
2624
|
+
ensureEnvFileDefaults: false,
|
|
2568
2625
|
});
|
|
2569
2626
|
if (!parsed['skip-save-env-log']) {
|
|
2570
2627
|
printInfo(`Saved env config for "${envName}".`);
|