@nocobase/cli 2.1.0-beta.45 → 2.1.0-beta.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/dist/commands/app/destroy.js +3 -3
- package/dist/commands/app/stop.js +4 -11
- 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 +28 -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 +28 -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/auth-store.js +8 -0
- package/dist/lib/cli-config.js +73 -1
- package/dist/lib/env-proxy.js +105 -75
- package/dist/lib/proxy-caddy.js +274 -0
- package/dist/lib/proxy-nginx.js +330 -0
- package/dist/locale/en-US.json +2 -2
- package/dist/locale/zh-CN.json +2 -2
- 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,30 @@
|
|
|
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 } from '@oclif/core';
|
|
10
|
+
import { getNginxProxyDriver, resolveNginxProxyRuntimeContext, startNginxProxy } from '../../../lib/proxy-nginx.js';
|
|
11
|
+
import { failTask, startTask, succeedTask } from '../../../lib/ui.js';
|
|
12
|
+
export default class ProxyNginxStart extends Command {
|
|
13
|
+
static summary = 'Start the managed nginx proxy';
|
|
14
|
+
async run() {
|
|
15
|
+
await this.parse(ProxyNginxStart);
|
|
16
|
+
const driver = await getNginxProxyDriver();
|
|
17
|
+
const runtimeContext = await resolveNginxProxyRuntimeContext();
|
|
18
|
+
startTask(`Starting nginx proxy with the ${driver} driver...`);
|
|
19
|
+
try {
|
|
20
|
+
const result = await startNginxProxy(runtimeContext);
|
|
21
|
+
succeedTask(result === 'already-running'
|
|
22
|
+
? `Nginx proxy is already running with the ${driver} driver.`
|
|
23
|
+
: `Nginx proxy started with the ${driver} driver.`);
|
|
24
|
+
}
|
|
25
|
+
catch (error) {
|
|
26
|
+
failTask(`Failed to start nginx proxy with the ${driver} driver.`);
|
|
27
|
+
this.error(error instanceof Error ? error.message : String(error));
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
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 } from '@oclif/core';
|
|
10
|
+
import { formatNginxProxyStatusLines, getNginxProxyStatus, resolveNginxProxyRuntimeContext, } from '../../../lib/proxy-nginx.js';
|
|
11
|
+
export default class ProxyNginxStatus extends Command {
|
|
12
|
+
static summary = 'Show the current nginx proxy runtime status';
|
|
13
|
+
async run() {
|
|
14
|
+
await this.parse(ProxyNginxStatus);
|
|
15
|
+
const runtimeContext = await resolveNginxProxyRuntimeContext();
|
|
16
|
+
const status = await getNginxProxyStatus(runtimeContext);
|
|
17
|
+
this.log(formatNginxProxyStatusLines(status).join('\n'));
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
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 } from '@oclif/core';
|
|
10
|
+
import { getNginxProxyDriver, resolveNginxProxyRuntimeContext, stopNginxProxy } from '../../../lib/proxy-nginx.js';
|
|
11
|
+
import { failTask, startTask, succeedTask } from '../../../lib/ui.js';
|
|
12
|
+
export default class ProxyNginxStop extends Command {
|
|
13
|
+
static summary = 'Stop the managed nginx proxy';
|
|
14
|
+
async run() {
|
|
15
|
+
await this.parse(ProxyNginxStop);
|
|
16
|
+
const driver = await getNginxProxyDriver();
|
|
17
|
+
const runtimeContext = await resolveNginxProxyRuntimeContext();
|
|
18
|
+
startTask(`Stopping nginx proxy with the ${driver} driver...`);
|
|
19
|
+
try {
|
|
20
|
+
const result = await stopNginxProxy(runtimeContext);
|
|
21
|
+
succeedTask(result === 'already-stopped'
|
|
22
|
+
? `Nginx proxy is already stopped with the ${driver} driver.`
|
|
23
|
+
: `Nginx proxy stopped with the ${driver} driver.`);
|
|
24
|
+
}
|
|
25
|
+
catch (error) {
|
|
26
|
+
failTask(`Failed to stop nginx proxy with the ${driver} driver.`);
|
|
27
|
+
this.error(error instanceof Error ? error.message : String(error));
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -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
|
}
|
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-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
|
}
|