@nocobase/cli 2.1.0-beta.46 → 2.1.0-beta.48
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/run.js +2 -1
- package/dist/commands/app/destroy.js +3 -3
- package/dist/commands/app/restart.js +1 -2
- package/dist/commands/app/start.js +28 -3
- package/dist/commands/app/upgrade.js +1 -1
- package/dist/commands/env/update.js +11 -1
- package/dist/commands/init.js +44 -76
- package/dist/commands/install.js +68 -50
- package/dist/commands/license/activate.js +1 -1
- package/dist/commands/proxy/caddy/current.js +17 -0
- package/dist/commands/proxy/caddy/generate.js +69 -0
- package/dist/commands/proxy/caddy/index.js +28 -0
- package/dist/commands/proxy/caddy/info.js +31 -0
- package/dist/commands/proxy/caddy/reload.js +30 -0
- package/dist/commands/proxy/caddy/restart.js +28 -0
- package/dist/commands/proxy/caddy/start.js +30 -0
- package/dist/commands/proxy/caddy/status.js +19 -0
- package/dist/commands/proxy/caddy/stop.js +30 -0
- package/dist/commands/proxy/caddy/use.js +26 -0
- package/dist/commands/proxy/index.js +28 -0
- package/dist/commands/proxy/nginx/current.js +18 -0
- package/dist/commands/proxy/nginx/generate.js +68 -0
- package/dist/commands/proxy/nginx/index.js +28 -0
- package/dist/commands/proxy/nginx/info.js +34 -0
- package/dist/commands/proxy/nginx/reload.js +30 -0
- package/dist/commands/proxy/nginx/restart.js +28 -0
- package/dist/commands/proxy/nginx/start.js +30 -0
- package/dist/commands/proxy/nginx/status.js +19 -0
- package/dist/commands/proxy/nginx/stop.js +30 -0
- package/dist/commands/proxy/nginx/use.js +31 -0
- package/dist/commands/revision/create.js +31 -2
- package/dist/lib/app-managed-resources.js +7 -2
- package/dist/lib/auth-store.js +8 -0
- package/dist/lib/cli-config.js +73 -1
- package/dist/lib/env-config.js +8 -0
- package/dist/lib/env-proxy.js +105 -75
- package/dist/lib/managed-env-file.js +7 -4
- package/dist/lib/managed-init-env.js +32 -0
- package/dist/lib/prompt-catalog-terminal.js +1 -2
- package/dist/lib/prompt-validators.js +6 -0
- package/dist/lib/proxy-caddy.js +274 -0
- package/dist/lib/proxy-nginx.js +330 -0
- package/dist/locale/en-US.json +4 -3
- package/dist/locale/zh-CN.json +4 -3
- package/package.json +2 -2
- package/dist/commands/env/proxy/caddy.js +0 -28
- package/dist/commands/env/proxy/index.js +0 -353
- package/dist/commands/env/proxy/nginx.js +0 -28
|
@@ -0,0 +1,31 @@
|
|
|
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 { Args, Command } from '@oclif/core';
|
|
10
|
+
import { NGINX_PROXY_DRIVER_OPTIONS, normalizeNginxProxyDriver } from '../../../lib/cli-config.js';
|
|
11
|
+
import { setNginxProxyDriver } from '../../../lib/proxy-nginx.js';
|
|
12
|
+
export default class ProxyNginxUse extends Command {
|
|
13
|
+
static summary = 'Choose whether nginx runs locally or in Docker';
|
|
14
|
+
static examples = ['<%= config.bin %> proxy nginx use local', '<%= config.bin %> proxy nginx use docker'];
|
|
15
|
+
static args = {
|
|
16
|
+
driver: Args.string({
|
|
17
|
+
description: 'Nginx runtime driver',
|
|
18
|
+
required: true,
|
|
19
|
+
options: [...NGINX_PROXY_DRIVER_OPTIONS],
|
|
20
|
+
}),
|
|
21
|
+
};
|
|
22
|
+
async run() {
|
|
23
|
+
const { args } = await this.parse(ProxyNginxUse);
|
|
24
|
+
const driver = normalizeNginxProxyDriver(args.driver);
|
|
25
|
+
if (!driver) {
|
|
26
|
+
this.error(`Unsupported nginx driver "${args.driver}". Use one of: ${NGINX_PROXY_DRIVER_OPTIONS.join(', ')}`);
|
|
27
|
+
}
|
|
28
|
+
const saved = await setNginxProxyDriver(driver);
|
|
29
|
+
this.log(saved);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -9,6 +9,17 @@
|
|
|
9
9
|
import { Args, Command, Flags } from '@oclif/core';
|
|
10
10
|
import { executeRawApiRequest } from '../../lib/api-client.js';
|
|
11
11
|
import { ensureCrossEnvConfirmed } from '../../lib/env-guard.js';
|
|
12
|
+
const VERSION_CONTROL_PLUGIN_PACKAGE = '@nocobase/plugin-version-control';
|
|
13
|
+
function isRecord(value) {
|
|
14
|
+
return typeof value === 'object' && value !== null;
|
|
15
|
+
}
|
|
16
|
+
function extractPluginList(data) {
|
|
17
|
+
const list = Array.isArray(data) ? data : isRecord(data) && Array.isArray(data.data) ? data.data : [];
|
|
18
|
+
return list.filter(isRecord).map((item) => ({
|
|
19
|
+
packageName: typeof item.packageName === 'string' ? item.packageName : undefined,
|
|
20
|
+
enabled: typeof item.enabled === 'boolean' ? item.enabled : undefined,
|
|
21
|
+
}));
|
|
22
|
+
}
|
|
12
23
|
export default class RevisionCreate extends Command {
|
|
13
24
|
static summary = 'Save the current NocoBase build as a restorable revision';
|
|
14
25
|
static examples = [
|
|
@@ -44,7 +55,7 @@ export default class RevisionCreate extends Command {
|
|
|
44
55
|
'json-output': Flags.boolean({
|
|
45
56
|
char: 'j',
|
|
46
57
|
description: 'Print raw JSON response',
|
|
47
|
-
default:
|
|
58
|
+
default: false,
|
|
48
59
|
allowNo: true,
|
|
49
60
|
}),
|
|
50
61
|
};
|
|
@@ -62,6 +73,24 @@ export default class RevisionCreate extends Command {
|
|
|
62
73
|
if (!confirmed) {
|
|
63
74
|
return;
|
|
64
75
|
}
|
|
76
|
+
const pluginListResponse = await executeRawApiRequest({
|
|
77
|
+
envName: flags.env,
|
|
78
|
+
baseUrl: flags['api-base-url'],
|
|
79
|
+
role: flags.role,
|
|
80
|
+
token: flags.token,
|
|
81
|
+
method: 'GET',
|
|
82
|
+
path: '/pm:list',
|
|
83
|
+
query: {
|
|
84
|
+
mode: 'summary',
|
|
85
|
+
},
|
|
86
|
+
});
|
|
87
|
+
if (!pluginListResponse.ok) {
|
|
88
|
+
this.error(`Failed to check plugin status with status ${pluginListResponse.status}\n${JSON.stringify(pluginListResponse.data, null, 2)}`);
|
|
89
|
+
}
|
|
90
|
+
const versionControlPlugin = extractPluginList(pluginListResponse.data).find((plugin) => plugin.packageName === VERSION_CONTROL_PLUGIN_PACKAGE);
|
|
91
|
+
if (!versionControlPlugin?.enabled) {
|
|
92
|
+
this.error(`The ${VERSION_CONTROL_PLUGIN_PACKAGE} plugin is not enabled. Enable it first with \`nb plugin enable ${VERSION_CONTROL_PLUGIN_PACKAGE}\`.`);
|
|
93
|
+
}
|
|
65
94
|
const response = await executeRawApiRequest({
|
|
66
95
|
envName: flags.env,
|
|
67
96
|
baseUrl: flags['api-base-url'],
|
|
@@ -84,6 +113,6 @@ export default class RevisionCreate extends Command {
|
|
|
84
113
|
this.log(JSON.stringify(response.data, null, 2));
|
|
85
114
|
return;
|
|
86
115
|
}
|
|
87
|
-
this.log(
|
|
116
|
+
this.log('Revision created successfully');
|
|
88
117
|
}
|
|
89
118
|
}
|
|
@@ -114,7 +114,7 @@ async function localProjectHasFiles(projectRoot) {
|
|
|
114
114
|
return false;
|
|
115
115
|
}
|
|
116
116
|
}
|
|
117
|
-
export async function buildSavedDockerRunArgs(runtime) {
|
|
117
|
+
export async function buildSavedDockerRunArgs(runtime, options) {
|
|
118
118
|
const config = runtime.env.config ?? {};
|
|
119
119
|
const storagePath = trimValue(resolveConfiguredStoragePath(config));
|
|
120
120
|
const envFile = await resolveDockerEnvFileArg(runtime.envName, config);
|
|
@@ -189,6 +189,9 @@ export async function buildSavedDockerRunArgs(runtime) {
|
|
|
189
189
|
if (envFile) {
|
|
190
190
|
args.push('--env-file', envFile);
|
|
191
191
|
}
|
|
192
|
+
for (const [key, value] of Object.entries(options?.initEnvVars ?? {})) {
|
|
193
|
+
args.push('-e', `${key}=${value}`);
|
|
194
|
+
}
|
|
192
195
|
const lifecycleEnvVars = managedAppLifecycleEnvVars();
|
|
193
196
|
args.push('-e', `APP_ENV=${lifecycleEnvVars.APP_ENV}`, '-e', `NODE_ENV=${lifecycleEnvVars.NODE_ENV}`, '-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}:${DOCKER_APP_STORAGE_DESTINATION}`);
|
|
194
197
|
pushOptionalEnvArg(args, 'APP_PUBLIC_PATH', appPublicPath ? resolveAppPublicPath(appPublicPath) : undefined);
|
|
@@ -206,7 +209,9 @@ export async function buildSavedDockerRunArgs(runtime) {
|
|
|
206
209
|
};
|
|
207
210
|
}
|
|
208
211
|
export async function recreateSavedDockerApp(runtime, options) {
|
|
209
|
-
const plan = await buildSavedDockerRunArgs(runtime
|
|
212
|
+
const plan = await buildSavedDockerRunArgs(runtime, {
|
|
213
|
+
initEnvVars: options?.initEnvVars,
|
|
214
|
+
});
|
|
210
215
|
try {
|
|
211
216
|
await ensureDockerNetwork(runtime.workspaceName);
|
|
212
217
|
await mkdir(plan.storagePath, { recursive: true });
|
package/dist/lib/auth-store.js
CHANGED
|
@@ -132,11 +132,19 @@ function normalizeAuthConfig(config) {
|
|
|
132
132
|
}
|
|
133
133
|
: {}),
|
|
134
134
|
...(settings.proxy?.nbCliRoot ||
|
|
135
|
+
settings.proxy?.caddyDriver ||
|
|
136
|
+
settings.proxy?.nginxDriver ||
|
|
135
137
|
settings.proxy?.upstreamHost ||
|
|
136
138
|
settings.proxy?.host
|
|
137
139
|
? {
|
|
138
140
|
proxy: {
|
|
139
141
|
...(settings.proxy?.nbCliRoot ? { nbCliRoot: normalizeOptionalString(settings.proxy.nbCliRoot) } : {}),
|
|
142
|
+
...(settings.proxy?.caddyDriver
|
|
143
|
+
? { caddyDriver: normalizeOptionalString(settings.proxy.caddyDriver) }
|
|
144
|
+
: {}),
|
|
145
|
+
...(settings.proxy?.nginxDriver
|
|
146
|
+
? { nginxDriver: normalizeOptionalString(settings.proxy.nginxDriver) }
|
|
147
|
+
: {}),
|
|
140
148
|
...(settings.proxy?.upstreamHost || settings.proxy?.host
|
|
141
149
|
? {
|
|
142
150
|
upstreamHost: normalizeOptionalString(settings.proxy?.upstreamHost ?? settings.proxy.host),
|
package/dist/lib/cli-config.js
CHANGED
|
@@ -18,6 +18,10 @@ export const DEFAULT_GIT_BIN = 'git';
|
|
|
18
18
|
export const DEFAULT_NGINX_BIN = 'nginx';
|
|
19
19
|
export const PROXY_PROVIDER_OPTIONS = ['nginx', 'caddy'];
|
|
20
20
|
export const DEFAULT_PROXY_PROVIDER = 'nginx';
|
|
21
|
+
export const NGINX_PROXY_DRIVER_OPTIONS = ['local', 'docker'];
|
|
22
|
+
export const DEFAULT_NGINX_PROXY_DRIVER = 'local';
|
|
23
|
+
export const CADDY_PROXY_DRIVER_OPTIONS = ['local', 'docker'];
|
|
24
|
+
export const DEFAULT_CADDY_PROXY_DRIVER = 'local';
|
|
21
25
|
export const DEFAULT_PROXY_HOST = '127.0.0.1';
|
|
22
26
|
export const DEFAULT_YARN_BIN = 'yarn';
|
|
23
27
|
export const DEFAULT_LOG_RETENTION_DAYS = 14;
|
|
@@ -37,6 +41,8 @@ export const SUPPORTED_CLI_CONFIG_KEYS = [
|
|
|
37
41
|
'bin.git',
|
|
38
42
|
'bin.nginx',
|
|
39
43
|
'proxy.nb-cli-root',
|
|
44
|
+
'proxy.caddy-driver',
|
|
45
|
+
'proxy.nginx-driver',
|
|
40
46
|
'proxy.upstream-host',
|
|
41
47
|
'bin.yarn',
|
|
42
48
|
'log.enabled',
|
|
@@ -74,6 +80,24 @@ export function normalizeProxyProvider(value) {
|
|
|
74
80
|
}
|
|
75
81
|
return PROXY_PROVIDER_OPTIONS.includes(normalized) ? normalized : undefined;
|
|
76
82
|
}
|
|
83
|
+
export function normalizeNginxProxyDriver(value) {
|
|
84
|
+
const normalized = trimValue(value);
|
|
85
|
+
if (!normalized) {
|
|
86
|
+
return undefined;
|
|
87
|
+
}
|
|
88
|
+
return NGINX_PROXY_DRIVER_OPTIONS.includes(normalized)
|
|
89
|
+
? normalized
|
|
90
|
+
: undefined;
|
|
91
|
+
}
|
|
92
|
+
export function normalizeCaddyProxyDriver(value) {
|
|
93
|
+
const normalized = trimValue(value);
|
|
94
|
+
if (!normalized) {
|
|
95
|
+
return undefined;
|
|
96
|
+
}
|
|
97
|
+
return CADDY_PROXY_DRIVER_OPTIONS.includes(normalized)
|
|
98
|
+
? normalized
|
|
99
|
+
: undefined;
|
|
100
|
+
}
|
|
77
101
|
function cloneSettings(config) {
|
|
78
102
|
return {
|
|
79
103
|
...(config.settings?.locale ? { locale: trimValue(config.settings.locale) } : {}),
|
|
@@ -116,7 +140,11 @@ function pruneSettings(config) {
|
|
|
116
140
|
delete config.settings?.bin;
|
|
117
141
|
}
|
|
118
142
|
const proxy = config.settings?.proxy;
|
|
119
|
-
if (proxy &&
|
|
143
|
+
if (proxy &&
|
|
144
|
+
!trimValue(proxy.nbCliRoot) &&
|
|
145
|
+
!trimValue(proxy.caddyDriver) &&
|
|
146
|
+
!trimValue(proxy.nginxDriver) &&
|
|
147
|
+
!trimValue(proxy.upstreamHost)) {
|
|
120
148
|
delete config.settings?.proxy;
|
|
121
149
|
}
|
|
122
150
|
const log = config.settings?.log;
|
|
@@ -161,6 +189,10 @@ export function getExplicitCliConfigValue(config, key) {
|
|
|
161
189
|
return trimValue(config.settings?.bin?.nginx);
|
|
162
190
|
case 'proxy.nb-cli-root':
|
|
163
191
|
return trimValue(config.settings?.proxy?.nbCliRoot);
|
|
192
|
+
case 'proxy.caddy-driver':
|
|
193
|
+
return normalizeCaddyProxyDriver(config.settings?.proxy?.caddyDriver);
|
|
194
|
+
case 'proxy.nginx-driver':
|
|
195
|
+
return normalizeNginxProxyDriver(config.settings?.proxy?.nginxDriver);
|
|
164
196
|
case 'proxy.upstream-host':
|
|
165
197
|
return trimValue(config.settings?.proxy?.upstreamHost);
|
|
166
198
|
case 'bin.yarn':
|
|
@@ -203,6 +235,10 @@ export function getEffectiveCliConfigValue(config, key) {
|
|
|
203
235
|
return DEFAULT_NGINX_BIN;
|
|
204
236
|
case 'proxy.nb-cli-root':
|
|
205
237
|
return explicit ?? resolveCliHomeRoot();
|
|
238
|
+
case 'proxy.caddy-driver':
|
|
239
|
+
return explicit ?? DEFAULT_CADDY_PROXY_DRIVER;
|
|
240
|
+
case 'proxy.nginx-driver':
|
|
241
|
+
return explicit ?? DEFAULT_NGINX_PROXY_DRIVER;
|
|
206
242
|
case 'proxy.upstream-host':
|
|
207
243
|
return explicit ?? DEFAULT_PROXY_HOST;
|
|
208
244
|
case 'bin.yarn':
|
|
@@ -248,6 +284,20 @@ export function normalizeCliConfigValue(key, value) {
|
|
|
248
284
|
}
|
|
249
285
|
return normalized;
|
|
250
286
|
}
|
|
287
|
+
if (key === 'proxy.nginx-driver') {
|
|
288
|
+
const driver = normalizeNginxProxyDriver(normalized);
|
|
289
|
+
if (!driver) {
|
|
290
|
+
throw new Error(`Config key "${key}" must be one of: ${NGINX_PROXY_DRIVER_OPTIONS.join(', ')}`);
|
|
291
|
+
}
|
|
292
|
+
return driver;
|
|
293
|
+
}
|
|
294
|
+
if (key === 'proxy.caddy-driver') {
|
|
295
|
+
const driver = normalizeCaddyProxyDriver(normalized);
|
|
296
|
+
if (!driver) {
|
|
297
|
+
throw new Error(`Config key "${key}" must be one of: ${CADDY_PROXY_DRIVER_OPTIONS.join(', ')}`);
|
|
298
|
+
}
|
|
299
|
+
return driver;
|
|
300
|
+
}
|
|
251
301
|
return normalized;
|
|
252
302
|
}
|
|
253
303
|
export async function loadCliConfig(options = {}) {
|
|
@@ -343,6 +393,18 @@ export async function setCliConfigValue(key, value, options = {}) {
|
|
|
343
393
|
nbCliRoot: normalized,
|
|
344
394
|
};
|
|
345
395
|
break;
|
|
396
|
+
case 'proxy.caddy-driver':
|
|
397
|
+
config.settings.proxy = {
|
|
398
|
+
...(config.settings.proxy ?? {}),
|
|
399
|
+
caddyDriver: normalized,
|
|
400
|
+
};
|
|
401
|
+
break;
|
|
402
|
+
case 'proxy.nginx-driver':
|
|
403
|
+
config.settings.proxy = {
|
|
404
|
+
...(config.settings.proxy ?? {}),
|
|
405
|
+
nginxDriver: normalized,
|
|
406
|
+
};
|
|
407
|
+
break;
|
|
346
408
|
case 'proxy.upstream-host':
|
|
347
409
|
config.settings.proxy = {
|
|
348
410
|
...(config.settings.proxy ?? {}),
|
|
@@ -439,6 +501,16 @@ export async function deleteCliConfigValue(key, options = {}) {
|
|
|
439
501
|
delete config.settings.proxy.nbCliRoot;
|
|
440
502
|
}
|
|
441
503
|
break;
|
|
504
|
+
case 'proxy.caddy-driver':
|
|
505
|
+
if (config.settings.proxy) {
|
|
506
|
+
delete config.settings.proxy.caddyDriver;
|
|
507
|
+
}
|
|
508
|
+
break;
|
|
509
|
+
case 'proxy.nginx-driver':
|
|
510
|
+
if (config.settings.proxy) {
|
|
511
|
+
delete config.settings.proxy.nginxDriver;
|
|
512
|
+
}
|
|
513
|
+
break;
|
|
442
514
|
case 'proxy.upstream-host':
|
|
443
515
|
if (config.settings.proxy) {
|
|
444
516
|
delete config.settings.proxy.upstreamHost;
|
package/dist/lib/env-config.js
CHANGED
|
@@ -33,6 +33,7 @@ const STRING_ENV_CONFIG_KEYS = [
|
|
|
33
33
|
'dbPassword',
|
|
34
34
|
'dbSchema',
|
|
35
35
|
'dbTablePrefix',
|
|
36
|
+
'lang',
|
|
36
37
|
'rootUsername',
|
|
37
38
|
'rootEmail',
|
|
38
39
|
'rootPassword',
|
|
@@ -49,6 +50,9 @@ function trimConfigValue(value) {
|
|
|
49
50
|
const text = String(value ?? '').trim();
|
|
50
51
|
return text || undefined;
|
|
51
52
|
}
|
|
53
|
+
function resolveSetupState(value) {
|
|
54
|
+
return value === 'prepared' || value === 'installed' ? value : undefined;
|
|
55
|
+
}
|
|
52
56
|
function resolveEnvKind(input) {
|
|
53
57
|
const source = trimConfigValue(input.source);
|
|
54
58
|
const appPath = trimConfigValue(input.appPath);
|
|
@@ -72,6 +76,10 @@ export function buildStoredEnvConfig(input) {
|
|
|
72
76
|
envConfig[key] = key === 'appPublicPath' ? resolveAppPublicPath(value) : value;
|
|
73
77
|
}
|
|
74
78
|
}
|
|
79
|
+
const setupState = resolveSetupState(input.setupState);
|
|
80
|
+
if (setupState) {
|
|
81
|
+
envConfig.setupState = setupState;
|
|
82
|
+
}
|
|
75
83
|
for (const key of BOOLEAN_ENV_CONFIG_KEYS) {
|
|
76
84
|
const value = input[key];
|
|
77
85
|
if (typeof value === 'boolean') {
|
package/dist/lib/env-proxy.js
CHANGED
|
@@ -109,8 +109,8 @@ export function buildManagedAppEntryGeneratedConfigBlock(provider, generatedConf
|
|
|
109
109
|
return [
|
|
110
110
|
` ${MANAGED_APP_ENTRY_BLOCK_BEGIN}`,
|
|
111
111
|
provider === 'caddy'
|
|
112
|
-
? ' # Keep this import so
|
|
113
|
-
: ' # Keep this include so
|
|
112
|
+
? ' # Keep this import so the CLI can refresh managed routes.'
|
|
113
|
+
: ' # Keep this include so the CLI can refresh managed routes.',
|
|
114
114
|
` ${referenceLine}`,
|
|
115
115
|
` ${MANAGED_APP_ENTRY_BLOCK_END}`,
|
|
116
116
|
].join('\n');
|
|
@@ -244,10 +244,11 @@ function applyCaddyAppEntryOptions(content, options) {
|
|
|
244
244
|
}
|
|
245
245
|
const currentAddress = parseCaddySiteAddress(content);
|
|
246
246
|
const nextAddress = buildCaddySiteAddress(options, currentAddress);
|
|
247
|
+
let nextContent = content;
|
|
247
248
|
if (currentAddress) {
|
|
248
|
-
|
|
249
|
+
nextContent = nextContent.replace(/^([^\s#][^\n{]*)\s*\{/m, `${nextAddress} {`);
|
|
249
250
|
}
|
|
250
|
-
return
|
|
251
|
+
return nextContent.replace(/^# host=.*$/m, `# host=${nextAddress}`);
|
|
251
252
|
}
|
|
252
253
|
export function applyEnvProxyAppEntryOptions(content, provider, options) {
|
|
253
254
|
if (!trimValue(options?.host) && !trimValue(options?.port)) {
|
|
@@ -320,9 +321,15 @@ export async function resolveManagedProxyAppVersion(runtime) {
|
|
|
320
321
|
return trimValue(runtime.env.config.downloadVersion);
|
|
321
322
|
}
|
|
322
323
|
export async function resolveProxyNbCliRoot(options) {
|
|
324
|
+
if (trimValue(options?.runtimeCliRoot)) {
|
|
325
|
+
return trimValue(options?.runtimeCliRoot);
|
|
326
|
+
}
|
|
323
327
|
return await getCliConfigValue('proxy.nb-cli-root', { scope: options?.scope });
|
|
324
328
|
}
|
|
325
329
|
export async function resolveProxyUpstreamHost(options) {
|
|
330
|
+
if (trimValue(options?.upstreamHost)) {
|
|
331
|
+
return trimValue(options?.upstreamHost);
|
|
332
|
+
}
|
|
326
333
|
return await getCliConfigValue('proxy.upstream-host', { scope: options?.scope });
|
|
327
334
|
}
|
|
328
335
|
function isPathInsideRoot(targetPath, rootPath) {
|
|
@@ -376,6 +383,19 @@ function ensureTrailingSlash(value) {
|
|
|
376
383
|
function trimTrailingSlash(value) {
|
|
377
384
|
return value.endsWith('/') ? value.slice(0, -1) : value;
|
|
378
385
|
}
|
|
386
|
+
function dedupeAssetPrefix(value, prefix) {
|
|
387
|
+
const normalizedPrefix = ensureTrailingSlash(prefix);
|
|
388
|
+
const nestedPrefix = normalizedPrefix.replace(/^\/+/, '');
|
|
389
|
+
if (!nestedPrefix) {
|
|
390
|
+
return value;
|
|
391
|
+
}
|
|
392
|
+
let result = value;
|
|
393
|
+
const duplicatePrefix = `${normalizedPrefix}${nestedPrefix}`;
|
|
394
|
+
while (result.startsWith(duplicatePrefix)) {
|
|
395
|
+
result = `${normalizedPrefix}${result.slice(duplicatePrefix.length)}`;
|
|
396
|
+
}
|
|
397
|
+
return result;
|
|
398
|
+
}
|
|
379
399
|
function renderTemplateString(template, values) {
|
|
380
400
|
return template.replace(/{{\s*([\w.]+)\s*}}/g, (_match, key) => values[key] ?? '');
|
|
381
401
|
}
|
|
@@ -413,6 +433,7 @@ function rewriteHtmlAssetPublicPath(html, currentPublicPath, nextPublicPath) {
|
|
|
413
433
|
let rewritten = html.replace(new RegExp(`((?:src|href)=["'])${escapedCurrentPrefix}`, 'g'), `$1${nextPrefix}`);
|
|
414
434
|
rewritten = rewritten.replace(/((?:src|href)=["'])(?:\.\/)?assets\//g, `$1${nextPrefix}assets/`);
|
|
415
435
|
rewritten = rewritten.replace(/((?:src|href)=["'])\/assets\//g, `$1${nextPrefix}assets/`);
|
|
436
|
+
rewritten = rewritten.replace(/((?:src|href)=["'])([^"']+)/g, (_match, attributePrefix, assetPath) => `${attributePrefix}${dedupeAssetPrefix(assetPath, nextPrefix)}`);
|
|
416
437
|
return rewritten.replace(new RegExp(`((?:src|href)=["'])${escapeRegExp(trimTrailingSlash(nextPrefix))}//+`, 'g'), '$1');
|
|
417
438
|
}
|
|
418
439
|
function buildNginxManagedConfigBlock(context) {
|
|
@@ -686,19 +707,11 @@ export async function buildEnvProxyCaddyBundle(runtime, options) {
|
|
|
686
707
|
const sourceV2PublicPath = extractRuntimePublicPath(sourceIndexV2Content);
|
|
687
708
|
const indexV1AssetPublicPath = context.cdnBaseUrl;
|
|
688
709
|
const indexV2AssetPublicPath = `${trimTrailingSlash(context.cdnBaseUrl)}/${DEFAULT_MODERN_CLIENT_PREFIX}/`;
|
|
689
|
-
const generatedConfigPath = resolveEnvProxyOutputPath(runtime.envName, {
|
|
690
|
-
provider: 'caddy',
|
|
691
|
-
scope: options?.scope,
|
|
692
|
-
});
|
|
693
|
-
const renderedGeneratedConfigPath = await mapProxyPathFromCliRoot(generatedConfigPath, {
|
|
694
|
-
...options,
|
|
695
|
-
provider: 'caddy',
|
|
696
|
-
});
|
|
697
710
|
const appConfigPath = resolveEnvProxyAppOutputPath(runtime.envName, { scope: options?.scope, provider: 'caddy' });
|
|
698
711
|
const entryDir = resolveEnvProxyEntryDir(runtime.envName, { scope: options?.scope, provider: 'caddy' });
|
|
699
712
|
const publicDir = resolveEnvProxyCaddyPublicOutputDir(runtime.envName, { scope: options?.scope });
|
|
700
713
|
const renderedPublicDir = await mapProxyPathFromCliRoot(publicDir, { ...options, provider: 'caddy' });
|
|
701
|
-
const
|
|
714
|
+
const appConfigContent = renderCaddyAppTemplate(buildCaddySiteAddress(), {
|
|
702
715
|
appPublicPath: context.appPublicPath,
|
|
703
716
|
apiBasePath: context.apiBasePath,
|
|
704
717
|
apiPort: context.apiPort,
|
|
@@ -717,7 +730,6 @@ export async function buildEnvProxyCaddyBundle(runtime, options) {
|
|
|
717
730
|
entryDir,
|
|
718
731
|
publicDir,
|
|
719
732
|
appConfigPath,
|
|
720
|
-
generatedConfigPath,
|
|
721
733
|
indexV1Path: resolveEnvProxyCaddyIndexOutputPath(runtime.envName, 'v1', { scope: options?.scope }),
|
|
722
734
|
indexV2Path: resolveEnvProxyCaddyIndexOutputPath(runtime.envName, 'v2', { scope: options?.scope }),
|
|
723
735
|
mainConfigPath: resolveEnvProxyMainOutputPath({ scope: options?.scope, provider: 'caddy' }),
|
|
@@ -729,8 +741,7 @@ export async function buildEnvProxyCaddyBundle(runtime, options) {
|
|
|
729
741
|
activeVersion: context.activeVersion,
|
|
730
742
|
cdnBaseUrl: context.cdnBaseUrl,
|
|
731
743
|
backendUrl: context.backendUrl,
|
|
732
|
-
appConfigContent
|
|
733
|
-
generatedConfigContent,
|
|
744
|
+
appConfigContent,
|
|
734
745
|
mainConfigContent: await buildEnvProxyMainConfig({ provider: 'caddy', scope: options?.scope }),
|
|
735
746
|
indexV1Content: injectRuntimeScriptIntoHtml(rewriteHtmlAssetPublicPath(sourceIndexV1Content, sourceV1PublicPath, indexV1AssetPublicPath), v1RuntimeScript),
|
|
736
747
|
indexV2Content: injectRuntimeScriptIntoHtml(rewriteHtmlAssetPublicPath(sourceIndexV2Content, sourceV2PublicPath, indexV2AssetPublicPath), v2RuntimeScript),
|
|
@@ -957,11 +968,26 @@ ${renderNginxLocationTemplate(context)}}
|
|
|
957
968
|
`;
|
|
958
969
|
}
|
|
959
970
|
function renderNginxGeneratedTemplate(context) {
|
|
960
|
-
return `# Managed by
|
|
971
|
+
return `# Managed by NocoBase CLI. Changes will be overwritten.
|
|
961
972
|
|
|
962
973
|
${renderNginxLocationTemplate(context)}`;
|
|
963
974
|
}
|
|
964
|
-
function
|
|
975
|
+
function buildCaddyContextCommentLines(siteAddress, context, publicDir) {
|
|
976
|
+
return [
|
|
977
|
+
'# Rendered by `nb proxy caddy generate`.',
|
|
978
|
+
'# Context:',
|
|
979
|
+
`# host=${siteAddress}`,
|
|
980
|
+
`# publicBasePath=${context.appPublicPath}`,
|
|
981
|
+
`# apiBasePath=${context.apiBasePath}`,
|
|
982
|
+
`# wsPath=${context.wsPath}`,
|
|
983
|
+
`# v2PublicPath=${context.v2PublicPath}`,
|
|
984
|
+
`# backendUrl=http://${context.proxyHost}:${context.apiPort}`,
|
|
985
|
+
`# uploadsDir=${context.uploadsPath}`,
|
|
986
|
+
`# distRootDir=${context.distClientRoot}`,
|
|
987
|
+
`# publicDir=${publicDir}`,
|
|
988
|
+
];
|
|
989
|
+
}
|
|
990
|
+
function renderCaddyAppTemplate(siteAddress, context, publicDir) {
|
|
965
991
|
const uploadsPath = `${context.appPublicPath}storage/uploads/`;
|
|
966
992
|
const distPathMatcher = toCaddyPathMatcher(context.distPath);
|
|
967
993
|
const uploadsPathMatcher = toCaddyPathMatcher(uploadsPath);
|
|
@@ -998,61 +1024,65 @@ function renderCaddyGeneratedTemplate(context, publicDir) {
|
|
|
998
1024
|
handle /${context.modernClientPrefix}/* {
|
|
999
1025
|
redir * ${appPublicPathNoTrailingSlash}{uri} 302
|
|
1000
1026
|
}`;
|
|
1001
|
-
return
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
header
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
}
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
}
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
}
|
|
1055
|
-
|
|
1027
|
+
return [
|
|
1028
|
+
...buildCaddyContextCommentLines(siteAddress, context, publicDir),
|
|
1029
|
+
'',
|
|
1030
|
+
`${siteAddress} {`,
|
|
1031
|
+
` encode zstd gzip${rootRedirectBlock}${appPublicPathRedirectBlock}${modernClientRedirectBlock}${shorthandModernClientRedirectBlock}`,
|
|
1032
|
+
'',
|
|
1033
|
+
` handle_path ${uploadsPathMatcher} {`,
|
|
1034
|
+
` root * ${context.uploadsPath}`,
|
|
1035
|
+
' header Cache-Control public',
|
|
1036
|
+
' header X-Content-Type-Options nosniff',
|
|
1037
|
+
' file_server',
|
|
1038
|
+
' }',
|
|
1039
|
+
'',
|
|
1040
|
+
` handle_path ${distPathMatcher} {`,
|
|
1041
|
+
` root * ${context.distClientRoot}`,
|
|
1042
|
+
' header Cache-Control public',
|
|
1043
|
+
' file_server',
|
|
1044
|
+
' }',
|
|
1045
|
+
'',
|
|
1046
|
+
' @oauth path_regexp oauth ^/\\.well-known/oauth-authorization-server/(.+)$',
|
|
1047
|
+
' handle @oauth {',
|
|
1048
|
+
' rewrite * /{re.oauth.1}/.well-known/oauth-authorization-server',
|
|
1049
|
+
` reverse_proxy ${context.proxyHost}:${context.apiPort}`,
|
|
1050
|
+
' }',
|
|
1051
|
+
'',
|
|
1052
|
+
' @openid path_regexp openid ^/\\.well-known/openid-configuration/(.+)$',
|
|
1053
|
+
' handle @openid {',
|
|
1054
|
+
' rewrite * /{re.openid.1}/.well-known/openid-configuration',
|
|
1055
|
+
` reverse_proxy ${context.proxyHost}:${context.apiPort}`,
|
|
1056
|
+
' }',
|
|
1057
|
+
'',
|
|
1058
|
+
' # Keep API and WS routes above the SPA fallbacks.',
|
|
1059
|
+
` handle ${apiPathMatcher} {`,
|
|
1060
|
+
` reverse_proxy ${context.proxyHost}:${context.apiPort}`,
|
|
1061
|
+
' }',
|
|
1062
|
+
'',
|
|
1063
|
+
` handle ${context.wsPath} {`,
|
|
1064
|
+
` reverse_proxy ${context.proxyHost}:${context.apiPort}`,
|
|
1065
|
+
' }',
|
|
1066
|
+
'',
|
|
1067
|
+
' # Keep the v2 SPA route above the fallback SPA route.',
|
|
1068
|
+
` handle_path ${toCaddyPathMatcher(context.v2PublicPath)} {`,
|
|
1069
|
+
` root * ${publicDir}`,
|
|
1070
|
+
' header Cache-Control "no-store, no-cache, must-revalidate"',
|
|
1071
|
+
' header X-Robots-Tag "noindex, nofollow"',
|
|
1072
|
+
' try_files {path} /index-v2.html',
|
|
1073
|
+
' file_server',
|
|
1074
|
+
' }',
|
|
1075
|
+
'',
|
|
1076
|
+
` handle_path ${toCaddyPathMatcher(context.appPublicPath)} {`,
|
|
1077
|
+
` root * ${publicDir}`,
|
|
1078
|
+
' header Cache-Control "no-store, no-cache, must-revalidate"',
|
|
1079
|
+
' header X-Robots-Tag "noindex, nofollow"',
|
|
1080
|
+
' try_files {path} /index-v1.html',
|
|
1081
|
+
' file_server',
|
|
1082
|
+
' }',
|
|
1083
|
+
'}',
|
|
1084
|
+
'',
|
|
1085
|
+
].join('\n');
|
|
1056
1086
|
}
|
|
1057
1087
|
export function buildEnvProxyAppConfig(provider, generatedConfigPath, options) {
|
|
1058
1088
|
if (provider === 'caddy') {
|
|
@@ -1082,7 +1112,7 @@ export function appConfigIncludesGeneratedConfig(content, generatedConfigPath, p
|
|
|
1082
1112
|
return new RegExp(`\\binclude\\s+${escapedReference}\\s*;`).test(content);
|
|
1083
1113
|
}
|
|
1084
1114
|
function renderCaddyMainTemplate(appConfigImportPath) {
|
|
1085
|
-
return `# Managed by
|
|
1115
|
+
return `# Managed by NocoBase CLI. Changes will be overwritten.
|
|
1086
1116
|
|
|
1087
1117
|
import ${appConfigImportPath}
|
|
1088
1118
|
`;
|
|
@@ -1146,7 +1176,7 @@ export async function buildEnvProxyConfig(runtime, options) {
|
|
|
1146
1176
|
return {
|
|
1147
1177
|
...base,
|
|
1148
1178
|
content: provider === 'caddy'
|
|
1149
|
-
?
|
|
1179
|
+
? renderCaddyAppTemplate(buildCaddySiteAddress(), templateContext, publicDir ?? '')
|
|
1150
1180
|
: renderNginxGeneratedTemplate(templateContext),
|
|
1151
1181
|
};
|
|
1152
1182
|
}
|
|
@@ -15,6 +15,9 @@ function trimValue(value) {
|
|
|
15
15
|
const text = String(value ?? '').trim();
|
|
16
16
|
return text || undefined;
|
|
17
17
|
}
|
|
18
|
+
function normalizeEnvFilePath(value) {
|
|
19
|
+
return value.replace(/\\/g, '/');
|
|
20
|
+
}
|
|
18
21
|
function stripWrappingQuotes(value) {
|
|
19
22
|
if (value.length >= 2 && value.startsWith('"') && value.endsWith('"')) {
|
|
20
23
|
return value
|
|
@@ -54,16 +57,16 @@ export function resolveManagedLocalEnvFilePath(runtime) {
|
|
|
54
57
|
const config = runtime.env.config ?? {};
|
|
55
58
|
const explicitEnvFile = trimValue(config.envFile);
|
|
56
59
|
if (explicitEnvFile) {
|
|
57
|
-
return resolveConfiguredEnvPath(explicitEnvFile) ?? explicitEnvFile;
|
|
60
|
+
return normalizeEnvFilePath(resolveConfiguredEnvPath(explicitEnvFile) ?? explicitEnvFile);
|
|
58
61
|
}
|
|
59
62
|
const configuredAppPath = resolveConfiguredAppPath(config);
|
|
60
63
|
if (configuredAppPath) {
|
|
61
|
-
return path.join(configuredAppPath, '.env');
|
|
64
|
+
return normalizeEnvFilePath(path.join(configuredAppPath, '.env'));
|
|
62
65
|
}
|
|
63
66
|
if (path.basename(runtime.projectRoot) === 'source') {
|
|
64
|
-
return path.resolve(runtime.projectRoot, '..', '.env');
|
|
67
|
+
return normalizeEnvFilePath(path.resolve(runtime.projectRoot, '..', '.env'));
|
|
65
68
|
}
|
|
66
|
-
return path.join(runtime.projectRoot, '.env');
|
|
69
|
+
return normalizeEnvFilePath(path.join(runtime.projectRoot, '.env'));
|
|
67
70
|
}
|
|
68
71
|
export async function resolveManagedRuntimeEnvFilePath(runtime) {
|
|
69
72
|
if (runtime.kind === 'local') {
|
|
@@ -0,0 +1,32 @@
|
|
|
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
|
+
function trimValue(value) {
|
|
10
|
+
return String(value ?? '').trim();
|
|
11
|
+
}
|
|
12
|
+
export function resolveManagedSetupState(value) {
|
|
13
|
+
return value === 'prepared' || value === 'installed' ? value : undefined;
|
|
14
|
+
}
|
|
15
|
+
export function isPreparedSetupState(value) {
|
|
16
|
+
return resolveManagedSetupState(value) === 'prepared';
|
|
17
|
+
}
|
|
18
|
+
export function buildInitAppEnvVarsFromConfig(config) {
|
|
19
|
+
const out = {};
|
|
20
|
+
const put = (key, value) => {
|
|
21
|
+
const text = trimValue(value);
|
|
22
|
+
if (text) {
|
|
23
|
+
out[key] = text;
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
put('INIT_APP_LANG', config?.lang);
|
|
27
|
+
put('INIT_ROOT_USERNAME', config?.rootUsername);
|
|
28
|
+
put('INIT_ROOT_EMAIL', config?.rootEmail);
|
|
29
|
+
put('INIT_ROOT_PASSWORD', config?.rootPassword);
|
|
30
|
+
put('INIT_ROOT_NICKNAME', config?.rootNickname);
|
|
31
|
+
return out;
|
|
32
|
+
}
|
|
@@ -84,8 +84,7 @@ function defaultOnCancel(locale) {
|
|
|
84
84
|
exit(0);
|
|
85
85
|
}
|
|
86
86
|
function defaultOnMissingNonInteractive(message) {
|
|
87
|
-
|
|
88
|
-
exit(1);
|
|
87
|
+
throw new Error(message);
|
|
89
88
|
}
|
|
90
89
|
function createTerminalHooks(locale, overrides) {
|
|
91
90
|
return createPromptCatalogHooks(locale, overrides, {
|