@nocobase/cli 2.2.0-alpha.3 → 2.2.0-alpha.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/env-proxy/nginx/app.conf.tpl +23 -0
- package/assets/env-proxy/nginx/nocobase.conf.tpl +5 -0
- package/assets/env-proxy/nginx/snippets/dist-location.conf +5 -0
- package/assets/env-proxy/nginx/snippets/gzip.conf +17 -0
- package/assets/env-proxy/nginx/snippets/log-format-http.conf +13 -0
- package/assets/env-proxy/nginx/snippets/maps-http.conf +14 -0
- package/assets/env-proxy/nginx/snippets/mime-types.conf +98 -0
- package/assets/env-proxy/nginx/snippets/proxy-location.conf +17 -0
- package/assets/env-proxy/nginx/snippets/spa-location.conf +6 -0
- package/assets/env-proxy/nginx/snippets/uploads-location.conf +21 -0
- package/dist/commands/install.js +0 -10
- package/dist/commands/proxy/caddy/generate.js +82 -4
- package/dist/commands/proxy/nginx/generate.js +87 -4
- package/dist/lib/app-managed-resources.js +0 -2
- package/dist/lib/env-proxy.js +138 -58
- package/dist/lib/proxy-caddy.js +24 -2
- package/dist/lib/proxy-nginx.js +18 -4
- package/dist/locale/en-US.json +1 -1
- package/dist/locale/zh-CN.json +1 -1
- package/package.json +3 -2
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Rendered by `nb env proxy`.
|
|
2
|
+
# Context:
|
|
3
|
+
# publicBasePath={{publicBasePath}}
|
|
4
|
+
# apiBasePath={{apiBasePath}}
|
|
5
|
+
# wsPath={{wsPath}}
|
|
6
|
+
# v2PublicPath={{v2PublicPath}}
|
|
7
|
+
# backendUrl={{backendUrl}}
|
|
8
|
+
# snippetsDir={{snippetsDir}}
|
|
9
|
+
# uploadsDir={{uploadsDir}}
|
|
10
|
+
# distRootDir={{distRootDir}}
|
|
11
|
+
# entryDir={{entryDir}}
|
|
12
|
+
# publicDir={{publicDir}}
|
|
13
|
+
|
|
14
|
+
server {
|
|
15
|
+
listen 80;
|
|
16
|
+
server_name _;
|
|
17
|
+
|
|
18
|
+
# Add custom directives or locations above the managed block as needed.
|
|
19
|
+
|
|
20
|
+
{{managedConfigBlock}}
|
|
21
|
+
|
|
22
|
+
# Add custom directives or locations below the managed block as needed.
|
|
23
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
gzip on;
|
|
2
|
+
gzip_types
|
|
3
|
+
text/plain
|
|
4
|
+
text/css
|
|
5
|
+
text/xml
|
|
6
|
+
text/markdown
|
|
7
|
+
text/javascript
|
|
8
|
+
application/javascript
|
|
9
|
+
application/json
|
|
10
|
+
application/manifest+json
|
|
11
|
+
application/atom+xml
|
|
12
|
+
application/rss+xml
|
|
13
|
+
application/xml
|
|
14
|
+
application/xml+rss
|
|
15
|
+
application/xhtml+xml
|
|
16
|
+
application/wasm
|
|
17
|
+
image/svg+xml;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
log_format apm '"$time_local" client=$remote_addr '
|
|
2
|
+
'method=$request_method request="$request" '
|
|
3
|
+
'request_length=$request_length '
|
|
4
|
+
'status=$status bytes_sent=$bytes_sent '
|
|
5
|
+
'body_bytes_sent=$body_bytes_sent '
|
|
6
|
+
'referer=$http_referer '
|
|
7
|
+
'user_agent="$http_user_agent" '
|
|
8
|
+
'upstream_addr=$upstream_addr '
|
|
9
|
+
'upstream_status=$upstream_status '
|
|
10
|
+
'request_time=$request_time '
|
|
11
|
+
'upstream_response_time=$upstream_response_time '
|
|
12
|
+
'upstream_connect_time=$upstream_connect_time '
|
|
13
|
+
'upstream_header_time=$upstream_header_time';
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
map $http_upgrade $connection_upgrade {
|
|
2
|
+
default upgrade;
|
|
3
|
+
"" close;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
map $http_x_forwarded_proto $upstream_x_forwarded_proto {
|
|
7
|
+
default $http_x_forwarded_proto;
|
|
8
|
+
"" $scheme;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
map $http_host $final_host {
|
|
12
|
+
default $http_host;
|
|
13
|
+
"" $host;
|
|
14
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
types {
|
|
2
|
+
text/html html htm shtml;
|
|
3
|
+
text/css css;
|
|
4
|
+
text/xml xml;
|
|
5
|
+
image/gif gif;
|
|
6
|
+
image/jpeg jpeg jpg;
|
|
7
|
+
application/javascript js mjs;
|
|
8
|
+
application/atom+xml atom;
|
|
9
|
+
application/rss+xml rss;
|
|
10
|
+
|
|
11
|
+
text/mathml mml;
|
|
12
|
+
text/plain txt;
|
|
13
|
+
text/vnd.sun.j2me.app-descriptor jad;
|
|
14
|
+
text/vnd.wap.wml wml;
|
|
15
|
+
text/x-component htc;
|
|
16
|
+
|
|
17
|
+
image/avif avif;
|
|
18
|
+
image/png png;
|
|
19
|
+
image/svg+xml svg svgz;
|
|
20
|
+
image/tiff tif tiff;
|
|
21
|
+
image/vnd.wap.wbmp wbmp;
|
|
22
|
+
image/webp webp;
|
|
23
|
+
image/x-icon ico;
|
|
24
|
+
image/x-jng jng;
|
|
25
|
+
image/x-ms-bmp bmp;
|
|
26
|
+
|
|
27
|
+
font/woff woff;
|
|
28
|
+
font/woff2 woff2;
|
|
29
|
+
|
|
30
|
+
application/java-archive jar war ear;
|
|
31
|
+
application/json json;
|
|
32
|
+
application/mac-binhex40 hqx;
|
|
33
|
+
application/msword doc;
|
|
34
|
+
application/pdf pdf;
|
|
35
|
+
application/postscript ps eps ai;
|
|
36
|
+
application/rtf rtf;
|
|
37
|
+
application/vnd.apple.mpegurl m3u8;
|
|
38
|
+
application/vnd.google-earth.kml+xml kml;
|
|
39
|
+
application/vnd.google-earth.kmz kmz;
|
|
40
|
+
application/vnd.ms-excel xls;
|
|
41
|
+
application/vnd.ms-fontobject eot;
|
|
42
|
+
application/vnd.ms-powerpoint ppt;
|
|
43
|
+
application/vnd.oasis.opendocument.graphics odg;
|
|
44
|
+
application/vnd.oasis.opendocument.presentation odp;
|
|
45
|
+
application/vnd.oasis.opendocument.spreadsheet ods;
|
|
46
|
+
application/vnd.oasis.opendocument.text odt;
|
|
47
|
+
application/vnd.openxmlformats-officedocument.presentationml.presentation
|
|
48
|
+
pptx;
|
|
49
|
+
application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
|
|
50
|
+
xlsx;
|
|
51
|
+
application/vnd.openxmlformats-officedocument.wordprocessingml.document
|
|
52
|
+
docx;
|
|
53
|
+
application/vnd.wap.wmlc wmlc;
|
|
54
|
+
application/wasm wasm;
|
|
55
|
+
application/x-7z-compressed 7z;
|
|
56
|
+
application/x-cocoa cco;
|
|
57
|
+
application/x-java-archive-diff jardiff;
|
|
58
|
+
application/x-java-jnlp-file jnlp;
|
|
59
|
+
application/x-makeself run;
|
|
60
|
+
application/x-perl pl pm;
|
|
61
|
+
application/x-pilot prc pdb;
|
|
62
|
+
application/x-rar-compressed rar;
|
|
63
|
+
application/x-redhat-package-manager rpm;
|
|
64
|
+
application/x-sea sea;
|
|
65
|
+
application/x-shockwave-flash swf;
|
|
66
|
+
application/x-stuffit sit;
|
|
67
|
+
application/x-tcl tcl tk;
|
|
68
|
+
application/x-x509-ca-cert der pem crt;
|
|
69
|
+
application/x-xpinstall xpi;
|
|
70
|
+
application/xhtml+xml xhtml;
|
|
71
|
+
application/xspf+xml xspf;
|
|
72
|
+
application/zip zip;
|
|
73
|
+
|
|
74
|
+
application/octet-stream bin exe dll;
|
|
75
|
+
application/octet-stream deb;
|
|
76
|
+
application/octet-stream dmg;
|
|
77
|
+
application/octet-stream iso img;
|
|
78
|
+
application/octet-stream msi msp msm;
|
|
79
|
+
|
|
80
|
+
audio/midi mid midi kar;
|
|
81
|
+
audio/mpeg mp3;
|
|
82
|
+
audio/ogg ogg;
|
|
83
|
+
audio/x-m4a m4a;
|
|
84
|
+
audio/x-realaudio ra;
|
|
85
|
+
|
|
86
|
+
video/3gpp 3gpp 3gp;
|
|
87
|
+
video/mp2t ts;
|
|
88
|
+
video/mp4 mp4;
|
|
89
|
+
video/mpeg mpeg mpg;
|
|
90
|
+
video/quicktime mov;
|
|
91
|
+
video/webm webm;
|
|
92
|
+
video/x-flv flv;
|
|
93
|
+
video/x-m4v m4v;
|
|
94
|
+
video/x-mng mng;
|
|
95
|
+
video/x-ms-asf asx asf;
|
|
96
|
+
video/x-ms-wmv wmv;
|
|
97
|
+
video/x-msvideo avi;
|
|
98
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
proxy_http_version 1.1;
|
|
2
|
+
|
|
3
|
+
proxy_set_header Upgrade $http_upgrade;
|
|
4
|
+
proxy_set_header Connection $connection_upgrade;
|
|
5
|
+
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
6
|
+
proxy_set_header X-Forwarded-Proto $upstream_x_forwarded_proto;
|
|
7
|
+
proxy_set_header Host $final_host;
|
|
8
|
+
proxy_set_header Referer $http_referer;
|
|
9
|
+
proxy_set_header User-Agent $http_user_agent;
|
|
10
|
+
|
|
11
|
+
add_header Cache-Control "no-cache, no-store" always;
|
|
12
|
+
proxy_cache_bypass $http_upgrade;
|
|
13
|
+
|
|
14
|
+
proxy_connect_timeout 600;
|
|
15
|
+
proxy_send_timeout 600;
|
|
16
|
+
proxy_read_timeout 600;
|
|
17
|
+
send_timeout 600;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
add_header Cache-Control "public" always;
|
|
2
|
+
add_header X-Content-Type-Options "nosniff" always;
|
|
3
|
+
|
|
4
|
+
access_log off;
|
|
5
|
+
autoindex off;
|
|
6
|
+
|
|
7
|
+
# Force potentially renderable uploaded files to download.
|
|
8
|
+
location ~* \.(?:htm|html|svg|svgz|xhtml)$ {
|
|
9
|
+
add_header Cache-Control "public" always;
|
|
10
|
+
add_header X-Content-Type-Options "nosniff" always;
|
|
11
|
+
add_header Content-Disposition "attachment" always;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
# Let Markdown files render as plain Markdown text.
|
|
15
|
+
location ~* \.md$ {
|
|
16
|
+
default_type text/markdown;
|
|
17
|
+
|
|
18
|
+
add_header Cache-Control "public" always;
|
|
19
|
+
add_header X-Content-Type-Options "nosniff" always;
|
|
20
|
+
add_header Content-Disposition "inline" always;
|
|
21
|
+
}
|
package/dist/commands/install.js
CHANGED
|
@@ -1468,8 +1468,6 @@ export default class Install extends Command {
|
|
|
1468
1468
|
'-d',
|
|
1469
1469
|
'--name',
|
|
1470
1470
|
containerName,
|
|
1471
|
-
'--restart',
|
|
1472
|
-
'always',
|
|
1473
1471
|
'--network',
|
|
1474
1472
|
networkName,
|
|
1475
1473
|
'-e',
|
|
@@ -1512,8 +1510,6 @@ export default class Install extends Command {
|
|
|
1512
1510
|
'-d',
|
|
1513
1511
|
'--name',
|
|
1514
1512
|
containerName,
|
|
1515
|
-
'--restart',
|
|
1516
|
-
'always',
|
|
1517
1513
|
'--network',
|
|
1518
1514
|
networkName,
|
|
1519
1515
|
'-e',
|
|
@@ -1558,8 +1554,6 @@ export default class Install extends Command {
|
|
|
1558
1554
|
'-d',
|
|
1559
1555
|
'--name',
|
|
1560
1556
|
containerName,
|
|
1561
|
-
'--restart',
|
|
1562
|
-
'always',
|
|
1563
1557
|
'--network',
|
|
1564
1558
|
networkName,
|
|
1565
1559
|
'-e',
|
|
@@ -1604,8 +1598,6 @@ export default class Install extends Command {
|
|
|
1604
1598
|
'-d',
|
|
1605
1599
|
'--name',
|
|
1606
1600
|
containerName,
|
|
1607
|
-
'--restart',
|
|
1608
|
-
'always',
|
|
1609
1601
|
'--network',
|
|
1610
1602
|
networkName,
|
|
1611
1603
|
'--platform',
|
|
@@ -1805,8 +1797,6 @@ export default class Install extends Command {
|
|
|
1805
1797
|
'-d',
|
|
1806
1798
|
'--name',
|
|
1807
1799
|
containerName,
|
|
1808
|
-
'--restart',
|
|
1809
|
-
'always',
|
|
1810
1800
|
'--network',
|
|
1811
1801
|
params.networkName,
|
|
1812
1802
|
'-p',
|
|
@@ -8,20 +8,49 @@
|
|
|
8
8
|
*/
|
|
9
9
|
import { Command, Flags } from '@oclif/core';
|
|
10
10
|
import { formatMissingManagedAppEnvMessage, resolveManagedAppRuntime, } from '../../../lib/app-runtime.js';
|
|
11
|
-
import { getCaddyProxyDriver, writeCaddyProxyBundle, resolveCaddyProxyRuntimeContext, } from '../../../lib/proxy-caddy.js';
|
|
11
|
+
import { getCaddyProxyDriver, writeManualCaddyProxyBundle, writeCaddyProxyBundle, resolveCaddyProxyRuntimeContext, } from '../../../lib/proxy-caddy.js';
|
|
12
12
|
import { normalizeProxyListenPort } from '../../../lib/proxy-nginx.js';
|
|
13
13
|
import { announceTargetEnv, failTask, startTask, succeedTask } from '../../../lib/ui.js';
|
|
14
14
|
export default class ProxyCaddyGenerate extends Command {
|
|
15
15
|
static summary = 'Generate caddy proxy files for one managed env';
|
|
16
16
|
static examples = [
|
|
17
|
+
'<%= config.bin %> proxy caddy generate --host app1.example.com',
|
|
17
18
|
'<%= config.bin %> proxy caddy generate --env app1 --host app1.example.com',
|
|
18
19
|
'<%= config.bin %> proxy caddy generate --env app1 --host app1.example.com --port 8080',
|
|
20
|
+
'<%= config.bin %> proxy caddy generate --manual --name default --app-port 13000 --storage-path /path/to/storage --dist-root-path /path/to/dist-client --runtime-version 2.1.0',
|
|
19
21
|
];
|
|
20
22
|
static flags = {
|
|
21
23
|
env: Flags.string({
|
|
22
24
|
char: 'e',
|
|
23
|
-
description: 'CLI env name to generate proxy files for',
|
|
24
|
-
|
|
25
|
+
description: 'CLI env name to generate proxy files for. Defaults to the current env when omitted',
|
|
26
|
+
}),
|
|
27
|
+
manual: Flags.boolean({
|
|
28
|
+
description: 'Generate proxy files from explicit runtime flags instead of a saved env',
|
|
29
|
+
default: false,
|
|
30
|
+
}),
|
|
31
|
+
name: Flags.string({
|
|
32
|
+
description: 'Output bundle name used under .nocobase/proxy/caddy in manual mode',
|
|
33
|
+
}),
|
|
34
|
+
'app-port': Flags.string({
|
|
35
|
+
description: 'Upstream NocoBase app port in manual mode',
|
|
36
|
+
}),
|
|
37
|
+
'storage-path': Flags.string({
|
|
38
|
+
description: 'Path to the NocoBase storage directory in manual mode',
|
|
39
|
+
}),
|
|
40
|
+
'dist-root-path': Flags.string({
|
|
41
|
+
description: 'Path to the dist-client root directory used to generate index-v1.html and index-v2.html in manual mode',
|
|
42
|
+
}),
|
|
43
|
+
'runtime-version': Flags.string({
|
|
44
|
+
description: 'Frontend runtime version under dist-root-path in manual mode',
|
|
45
|
+
}),
|
|
46
|
+
'app-public-path': Flags.string({
|
|
47
|
+
description: 'Public base path served by the proxied app in manual mode. Defaults to /',
|
|
48
|
+
}),
|
|
49
|
+
'upstream-host': Flags.string({
|
|
50
|
+
description: 'Upstream host used by caddy reverse_proxy in manual mode',
|
|
51
|
+
}),
|
|
52
|
+
'cdn-base-url': Flags.string({
|
|
53
|
+
description: 'Client asset CDN base URL used when generating runtime HTML',
|
|
25
54
|
}),
|
|
26
55
|
host: Flags.string({
|
|
27
56
|
description: 'Host exposed by the caddy site block, such as example.com or localhost',
|
|
@@ -35,9 +64,56 @@ export default class ProxyCaddyGenerate extends Command {
|
|
|
35
64
|
const requestedEnv = flags.env?.trim() || undefined;
|
|
36
65
|
const requestedPort = flags.port?.trim() || undefined;
|
|
37
66
|
const normalizedPort = normalizeProxyListenPort(requestedPort);
|
|
67
|
+
const manual = Boolean(flags.manual);
|
|
38
68
|
if (requestedPort && !normalizedPort) {
|
|
39
69
|
this.error(`Invalid proxy entry port "${requestedPort}". Use an integer between 1 and 65535.`);
|
|
40
70
|
}
|
|
71
|
+
if (manual && requestedEnv) {
|
|
72
|
+
this.error('`--manual` cannot be combined with `--env`.');
|
|
73
|
+
}
|
|
74
|
+
if (manual) {
|
|
75
|
+
const name = flags.name?.trim() || undefined;
|
|
76
|
+
const requestedAppPort = flags['app-port']?.trim() || undefined;
|
|
77
|
+
const appPort = normalizeProxyListenPort(requestedAppPort);
|
|
78
|
+
const storagePath = flags['storage-path']?.trim() || undefined;
|
|
79
|
+
const distRootPath = flags['dist-root-path']?.trim() || undefined;
|
|
80
|
+
const runtimeVersion = flags['runtime-version']?.trim() || undefined;
|
|
81
|
+
if (requestedAppPort && !appPort) {
|
|
82
|
+
this.error(`Invalid manual app port "${requestedAppPort}". Use an integer between 1 and 65535.`);
|
|
83
|
+
}
|
|
84
|
+
if (!name || !appPort || !storagePath || !distRootPath || !runtimeVersion) {
|
|
85
|
+
this.error('Manual mode requires `--name`, `--app-port`, `--storage-path`, `--dist-root-path`, and `--runtime-version`.');
|
|
86
|
+
}
|
|
87
|
+
const driver = await getCaddyProxyDriver();
|
|
88
|
+
const runtimeContext = await resolveCaddyProxyRuntimeContext();
|
|
89
|
+
announceTargetEnv(name);
|
|
90
|
+
startTask(`Generating caddy proxy config for env "${name}" with the ${driver} driver...`);
|
|
91
|
+
try {
|
|
92
|
+
const { bundle, status } = await writeManualCaddyProxyBundle({
|
|
93
|
+
name,
|
|
94
|
+
appPort,
|
|
95
|
+
storagePath,
|
|
96
|
+
distRootPath,
|
|
97
|
+
runtimeVersion,
|
|
98
|
+
appPublicPath: flags['app-public-path']?.trim() || undefined,
|
|
99
|
+
upstreamHost: flags['upstream-host']?.trim() || undefined,
|
|
100
|
+
cdnBaseUrl: flags['cdn-base-url']?.trim() || undefined,
|
|
101
|
+
}, {
|
|
102
|
+
host: flags.host?.trim() || undefined,
|
|
103
|
+
port: normalizedPort,
|
|
104
|
+
}, runtimeContext, {
|
|
105
|
+
cdnBaseUrl: flags['cdn-base-url']?.trim() || undefined,
|
|
106
|
+
});
|
|
107
|
+
succeedTask(status === 'created'
|
|
108
|
+
? `Saved caddy proxy files for env "${name}" under ${bundle.entryDir}, and created app.caddy at ${bundle.appConfigPath}.`
|
|
109
|
+
: `Saved caddy proxy files for env "${name}" under ${bundle.entryDir}, and refreshed app.caddy at ${bundle.appConfigPath}.`);
|
|
110
|
+
}
|
|
111
|
+
catch (error) {
|
|
112
|
+
failTask(`Failed to generate caddy proxy config for env "${name}".`);
|
|
113
|
+
this.error(error instanceof Error ? error.message : String(error));
|
|
114
|
+
}
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
41
117
|
const runtime = await resolveManagedAppRuntime(requestedEnv);
|
|
42
118
|
if (!runtime) {
|
|
43
119
|
this.error(formatMissingManagedAppEnvMessage(requestedEnv));
|
|
@@ -56,7 +132,9 @@ export default class ProxyCaddyGenerate extends Command {
|
|
|
56
132
|
const { bundle, status } = await writeCaddyProxyBundle(runtime, {
|
|
57
133
|
host: flags.host?.trim() || undefined,
|
|
58
134
|
port: normalizedPort,
|
|
59
|
-
}, runtimeContext
|
|
135
|
+
}, runtimeContext, {
|
|
136
|
+
cdnBaseUrl: flags['cdn-base-url']?.trim() || undefined,
|
|
137
|
+
});
|
|
60
138
|
succeedTask(status === 'created'
|
|
61
139
|
? `Saved caddy proxy files for env "${runtime.envName}" under ${bundle.entryDir}, and created app.caddy at ${bundle.appConfigPath}.`
|
|
62
140
|
: `Saved caddy proxy files for env "${runtime.envName}" under ${bundle.entryDir}, and refreshed app.caddy at ${bundle.appConfigPath}.`);
|
|
@@ -8,19 +8,52 @@
|
|
|
8
8
|
*/
|
|
9
9
|
import { Command, Flags } from '@oclif/core';
|
|
10
10
|
import { formatMissingManagedAppEnvMessage, resolveManagedAppRuntime, } from '../../../lib/app-runtime.js';
|
|
11
|
-
import { getNginxProxyDriver, normalizeProxyListenPort, resolveNginxProxyRuntimeContext, writeNginxProxyBundle, } from '../../../lib/proxy-nginx.js';
|
|
11
|
+
import { getNginxProxyDriver, normalizeProxyListenPort, resolveNginxProxyRuntimeContext, writeManualNginxProxyBundle, writeNginxProxyBundle, } from '../../../lib/proxy-nginx.js';
|
|
12
12
|
import { announceTargetEnv, failTask, startTask, succeedTask } from '../../../lib/ui.js';
|
|
13
13
|
export default class ProxyNginxGenerate extends Command {
|
|
14
14
|
static summary = 'Generate nginx proxy files for one managed env';
|
|
15
15
|
static examples = [
|
|
16
|
+
'<%= config.bin %> proxy nginx generate --host app1.example.com',
|
|
16
17
|
'<%= config.bin %> proxy nginx generate --env app1 --host app1.example.com',
|
|
17
18
|
'<%= config.bin %> proxy nginx generate --env app1 --host app1.example.com --port 8080',
|
|
19
|
+
'<%= config.bin %> proxy nginx generate --manual --name default --app-port 13000 --storage-path /path/to/storage --dist-root-path /path/to/dist-client --runtime-version 2.1.0',
|
|
18
20
|
];
|
|
19
21
|
static flags = {
|
|
20
22
|
env: Flags.string({
|
|
21
23
|
char: 'e',
|
|
22
|
-
description: 'CLI env name to generate proxy files for',
|
|
23
|
-
|
|
24
|
+
description: 'CLI env name to generate proxy files for. Defaults to the current env when omitted',
|
|
25
|
+
}),
|
|
26
|
+
manual: Flags.boolean({
|
|
27
|
+
description: 'Generate proxy files from explicit runtime flags instead of a saved env',
|
|
28
|
+
default: false,
|
|
29
|
+
}),
|
|
30
|
+
name: Flags.string({
|
|
31
|
+
description: 'Output bundle name used under .nocobase/proxy/nginx in manual mode',
|
|
32
|
+
}),
|
|
33
|
+
'app-port': Flags.string({
|
|
34
|
+
description: 'Upstream NocoBase app port in manual mode',
|
|
35
|
+
}),
|
|
36
|
+
'storage-path': Flags.string({
|
|
37
|
+
description: 'Path to the NocoBase storage directory in manual mode',
|
|
38
|
+
}),
|
|
39
|
+
'dist-root-path': Flags.string({
|
|
40
|
+
description: 'Path to the dist-client root directory used to generate index-v1.html and index-v2.html in manual mode',
|
|
41
|
+
}),
|
|
42
|
+
'runtime-version': Flags.string({
|
|
43
|
+
description: 'Frontend runtime version under dist-root-path in manual mode',
|
|
44
|
+
}),
|
|
45
|
+
'app-public-path': Flags.string({
|
|
46
|
+
description: 'Public base path served by the proxied app in manual mode. Defaults to /',
|
|
47
|
+
}),
|
|
48
|
+
'upstream-host': Flags.string({
|
|
49
|
+
description: 'Upstream host used by nginx proxy_pass in manual mode',
|
|
50
|
+
}),
|
|
51
|
+
'cdn-base-url': Flags.string({
|
|
52
|
+
description: 'Client asset CDN base URL used when generating runtime HTML',
|
|
53
|
+
}),
|
|
54
|
+
force: Flags.boolean({
|
|
55
|
+
description: 'Overwrite existing app.conf even when the managed block is missing',
|
|
56
|
+
default: false,
|
|
24
57
|
}),
|
|
25
58
|
host: Flags.string({
|
|
26
59
|
description: 'Host exposed by the nginx entry config, such as example.com or localhost',
|
|
@@ -34,9 +67,56 @@ export default class ProxyNginxGenerate extends Command {
|
|
|
34
67
|
const requestedEnv = flags.env?.trim() || undefined;
|
|
35
68
|
const requestedPort = flags.port?.trim() || undefined;
|
|
36
69
|
const normalizedPort = normalizeProxyListenPort(requestedPort);
|
|
70
|
+
const manual = Boolean(flags.manual);
|
|
37
71
|
if (requestedPort && !normalizedPort) {
|
|
38
72
|
this.error(`Invalid proxy entry port "${requestedPort}". Use an integer between 1 and 65535.`);
|
|
39
73
|
}
|
|
74
|
+
if (manual && requestedEnv) {
|
|
75
|
+
this.error('`--manual` cannot be combined with `--env`.');
|
|
76
|
+
}
|
|
77
|
+
if (manual) {
|
|
78
|
+
const name = flags.name?.trim() || undefined;
|
|
79
|
+
const requestedAppPort = flags['app-port']?.trim() || undefined;
|
|
80
|
+
const appPort = normalizeProxyListenPort(requestedAppPort);
|
|
81
|
+
const storagePath = flags['storage-path']?.trim() || undefined;
|
|
82
|
+
const distRootPath = flags['dist-root-path']?.trim() || undefined;
|
|
83
|
+
const runtimeVersion = flags['runtime-version']?.trim() || undefined;
|
|
84
|
+
if (requestedAppPort && !appPort) {
|
|
85
|
+
this.error(`Invalid manual app port "${requestedAppPort}". Use an integer between 1 and 65535.`);
|
|
86
|
+
}
|
|
87
|
+
if (!name || !appPort || !storagePath || !distRootPath || !runtimeVersion) {
|
|
88
|
+
this.error('Manual mode requires `--name`, `--app-port`, `--storage-path`, `--dist-root-path`, and `--runtime-version`.');
|
|
89
|
+
}
|
|
90
|
+
const driver = await getNginxProxyDriver();
|
|
91
|
+
const runtimeContext = await resolveNginxProxyRuntimeContext();
|
|
92
|
+
announceTargetEnv(name);
|
|
93
|
+
startTask(`Generating nginx proxy config for env "${name}" with the ${driver} driver...`);
|
|
94
|
+
try {
|
|
95
|
+
const { bundle, status } = await writeManualNginxProxyBundle({
|
|
96
|
+
name,
|
|
97
|
+
appPort,
|
|
98
|
+
storagePath,
|
|
99
|
+
distRootPath,
|
|
100
|
+
runtimeVersion,
|
|
101
|
+
appPublicPath: flags['app-public-path']?.trim() || undefined,
|
|
102
|
+
upstreamHost: flags['upstream-host']?.trim() || undefined,
|
|
103
|
+
cdnBaseUrl: flags['cdn-base-url']?.trim() || undefined,
|
|
104
|
+
}, {
|
|
105
|
+
host: flags.host?.trim() || undefined,
|
|
106
|
+
port: normalizedPort,
|
|
107
|
+
}, runtimeContext, {
|
|
108
|
+
force: flags.force,
|
|
109
|
+
});
|
|
110
|
+
succeedTask(status === 'created'
|
|
111
|
+
? `Saved nginx proxy files for env "${name}" under ${bundle.entryDir}, and created editable app entry config at ${bundle.appConfigPath}.`
|
|
112
|
+
: `Saved nginx proxy files for env "${name}" under ${bundle.entryDir}, and refreshed editable app entry config at ${bundle.appConfigPath}.`);
|
|
113
|
+
}
|
|
114
|
+
catch (error) {
|
|
115
|
+
failTask(`Failed to generate nginx proxy config for env "${name}".`);
|
|
116
|
+
this.error(error instanceof Error ? error.message : String(error));
|
|
117
|
+
}
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
40
120
|
const runtime = await resolveManagedAppRuntime(requestedEnv);
|
|
41
121
|
if (!runtime) {
|
|
42
122
|
this.error(formatMissingManagedAppEnvMessage(requestedEnv));
|
|
@@ -55,7 +135,10 @@ export default class ProxyNginxGenerate extends Command {
|
|
|
55
135
|
const { bundle, status } = await writeNginxProxyBundle(runtime, {
|
|
56
136
|
host: flags.host?.trim() || undefined,
|
|
57
137
|
port: normalizedPort,
|
|
58
|
-
}, runtimeContext
|
|
138
|
+
}, runtimeContext, {
|
|
139
|
+
cdnBaseUrl: flags['cdn-base-url']?.trim() || undefined,
|
|
140
|
+
force: flags.force,
|
|
141
|
+
});
|
|
59
142
|
succeedTask(status === 'created'
|
|
60
143
|
? `Saved nginx proxy files for env "${runtime.envName}" under ${bundle.entryDir}, and created editable app entry config at ${bundle.appConfigPath}.`
|
|
61
144
|
: `Saved nginx proxy files for env "${runtime.envName}" under ${bundle.entryDir}, and refreshed editable app entry config at ${bundle.appConfigPath}.`);
|
package/dist/lib/env-proxy.js
CHANGED
|
@@ -259,7 +259,7 @@ export function applyEnvProxyAppEntryOptions(content, provider, options) {
|
|
|
259
259
|
function toCaddyPathMatcher(prefixPath) {
|
|
260
260
|
return `${prefixPath}*`;
|
|
261
261
|
}
|
|
262
|
-
export async function loadEnvProxySettings(runtime) {
|
|
262
|
+
export async function loadEnvProxySettings(runtime, options) {
|
|
263
263
|
const { envFilePath, envValues } = await readManagedRuntimeEnvValues(runtime);
|
|
264
264
|
const appPublicPath = resolveAppPublicPath(runtime.env.config.appPublicPath || envValues.APP_PUBLIC_PATH || DEFAULT_APP_PUBLIC_PATH);
|
|
265
265
|
const apiClientShareToken = /^true$/i.test(String(envValues.API_CLIENT_SHARE_TOKEN ?? '').trim());
|
|
@@ -274,7 +274,9 @@ export async function loadEnvProxySettings(runtime) {
|
|
|
274
274
|
wsPath: prefixRuntimePath(appPublicPath, envValues.WS_PATH || DEFAULT_WS_PATH),
|
|
275
275
|
pluginStaticsPath: prefixRuntimePath(appPublicPath, envValues.PLUGIN_STATICS_PATH || DEFAULT_PLUGIN_STATICS_PATH, { trailingSlash: true }),
|
|
276
276
|
modernClientPrefix: normalizeModernClientPrefix(envValues.APP_MODERN_CLIENT_PREFIX),
|
|
277
|
-
cdnBaseUrl: trimValue(
|
|
277
|
+
cdnBaseUrl: trimValue(options?.cdnBaseUrl) ??
|
|
278
|
+
trimValue(runtime.env.envVars?.CDN_BASE_URL) ??
|
|
279
|
+
trimValue(envValues.CDN_BASE_URL),
|
|
278
280
|
apiClientStoragePrefix: trimValue(envValues.API_CLIENT_STORAGE_PREFIX) ?? DEFAULT_API_CLIENT_STORAGE_PREFIX,
|
|
279
281
|
apiClientStorageType: trimValue(envValues.API_CLIENT_STORAGE_TYPE) ?? DEFAULT_API_CLIENT_STORAGE_TYPE,
|
|
280
282
|
apiClientShareToken,
|
|
@@ -284,6 +286,40 @@ export async function loadEnvProxySettings(runtime) {
|
|
|
284
286
|
},
|
|
285
287
|
};
|
|
286
288
|
}
|
|
289
|
+
function createManualProxyEnvSettings(input) {
|
|
290
|
+
const appPublicPath = resolveAppPublicPath(input.appPublicPath || DEFAULT_APP_PUBLIC_PATH);
|
|
291
|
+
return {
|
|
292
|
+
appPublicPath,
|
|
293
|
+
apiBasePath: prefixRuntimePath(appPublicPath, DEFAULT_API_BASE_PATH, {
|
|
294
|
+
trailingSlash: true,
|
|
295
|
+
}),
|
|
296
|
+
distPath: resolveDistPublicPath(appPublicPath),
|
|
297
|
+
wsPath: prefixRuntimePath(appPublicPath, DEFAULT_WS_PATH),
|
|
298
|
+
pluginStaticsPath: prefixRuntimePath(appPublicPath, DEFAULT_PLUGIN_STATICS_PATH, {
|
|
299
|
+
trailingSlash: true,
|
|
300
|
+
}),
|
|
301
|
+
modernClientPrefix: DEFAULT_MODERN_CLIENT_PREFIX,
|
|
302
|
+
cdnBaseUrl: trimValue(input.cdnBaseUrl),
|
|
303
|
+
apiClientStoragePrefix: DEFAULT_API_CLIENT_STORAGE_PREFIX,
|
|
304
|
+
apiClientStorageType: DEFAULT_API_CLIENT_STORAGE_TYPE,
|
|
305
|
+
apiClientShareToken: false,
|
|
306
|
+
wsUrl: '',
|
|
307
|
+
esmCdnBaseUrl: DEFAULT_ESM_CDN_BASE_URL,
|
|
308
|
+
esmCdnSuffix: '',
|
|
309
|
+
};
|
|
310
|
+
}
|
|
311
|
+
function normalizeManualNginxInput(input) {
|
|
312
|
+
return {
|
|
313
|
+
name: String(input.name).trim(),
|
|
314
|
+
appPort: String(input.appPort).trim(),
|
|
315
|
+
storagePath: String(input.storagePath).trim(),
|
|
316
|
+
distRootPath: String(input.distRootPath).trim(),
|
|
317
|
+
runtimeVersion: String(input.runtimeVersion).trim(),
|
|
318
|
+
appPublicPath: trimValue(input.appPublicPath),
|
|
319
|
+
upstreamHost: trimValue(input.upstreamHost),
|
|
320
|
+
cdnBaseUrl: trimValue(input.cdnBaseUrl),
|
|
321
|
+
};
|
|
322
|
+
}
|
|
287
323
|
async function parseVersionFromPackageJson(content, sourceLabel) {
|
|
288
324
|
let parsed;
|
|
289
325
|
try {
|
|
@@ -525,65 +561,91 @@ function buildNginxRuntimeConfig(context, variant) {
|
|
|
525
561
|
function buildCaddyRuntimeConfig(context, variant) {
|
|
526
562
|
return buildNginxRuntimeConfig(context, variant);
|
|
527
563
|
}
|
|
528
|
-
async function buildEnvProxyNginxRenderContext(
|
|
529
|
-
const apiPort = trimValue(runtime.env.appPort ?? runtime.env.config.appPort);
|
|
530
|
-
if (!apiPort) {
|
|
531
|
-
throw new Error(translateCli('commands.envProxy.errors.missingAppPort', { envName: runtime.envName }, {
|
|
532
|
-
fallback: `Missing appPort for env "${runtime.envName}". Save or update the app port before generating proxy config.`,
|
|
533
|
-
}));
|
|
534
|
-
}
|
|
535
|
-
const activeVersion = trimValue(await readDistClientActiveVersion(runtime.env.storagePath));
|
|
536
|
-
if (!activeVersion) {
|
|
537
|
-
throw new Error(translateCli('commands.envProxy.errors.missingVersion', { envName: runtime.envName }, {
|
|
538
|
-
fallback: `Couldn't determine the app version for env "${runtime.envName}". Run \`nb env update ${runtime.envName}\` and try again.`,
|
|
539
|
-
}));
|
|
540
|
-
}
|
|
541
|
-
const { envFilePath, settings } = await loadEnvProxySettings(runtime);
|
|
564
|
+
async function buildEnvProxyNginxRenderContext(source, options) {
|
|
542
565
|
const proxyHost = await resolveProxyUpstreamHost(options);
|
|
543
|
-
const backendUrl = `http://${proxyHost}:${apiPort}`;
|
|
544
|
-
const cdnBaseUrl = settings.cdnBaseUrl ?? buildDefaultCdnBaseUrl(settings.appPublicPath, activeVersion);
|
|
545
|
-
const entryDir = resolveEnvProxyEntryDir(
|
|
546
|
-
const publicDir = resolveEnvProxyNginxPublicOutputDir(
|
|
566
|
+
const backendUrl = `http://${proxyHost}:${source.apiPort}`;
|
|
567
|
+
const cdnBaseUrl = source.settings.cdnBaseUrl ?? buildDefaultCdnBaseUrl(source.settings.appPublicPath, source.activeVersion);
|
|
568
|
+
const entryDir = resolveEnvProxyEntryDir(source.envName, { scope: options?.scope });
|
|
569
|
+
const publicDir = resolveEnvProxyNginxPublicOutputDir(source.envName, { scope: options?.scope });
|
|
547
570
|
const snippetsDir = resolveEnvProxyNginxSnippetsOutputDir({ scope: options?.scope });
|
|
548
|
-
const distRootDir =
|
|
549
|
-
const uploadsDir = path.join(
|
|
571
|
+
const distRootDir = source.distRootPath;
|
|
572
|
+
const uploadsDir = path.join(source.storagePath, 'uploads');
|
|
550
573
|
const mappedEntryDir = await mapProxyPathFromCliRoot(entryDir, options);
|
|
551
574
|
const mappedPublicDir = await mapProxyPathFromCliRoot(publicDir, options);
|
|
552
575
|
const mappedSnippetsDir = await mapProxyPathFromCliRoot(snippetsDir, options);
|
|
553
576
|
const mappedDistRootDir = await mapProxyPathFromCliRoot(distRootDir, options);
|
|
554
577
|
const mappedUploadsDir = await mapProxyPathFromCliRoot(uploadsDir, options);
|
|
555
|
-
const v2PublicPath = `${settings.appPublicPath.replace(/\/$/, '')}/${settings.modernClientPrefix}/`;
|
|
578
|
+
const v2PublicPath = `${source.settings.appPublicPath.replace(/\/$/, '')}/${source.settings.modernClientPrefix}/`;
|
|
556
579
|
return {
|
|
557
|
-
envName:
|
|
558
|
-
envFilePath,
|
|
559
|
-
apiBasePath: settings.apiBasePath,
|
|
560
|
-
apiClientShareToken: settings.apiClientShareToken,
|
|
561
|
-
apiClientStoragePrefix: settings.apiClientStoragePrefix,
|
|
562
|
-
apiClientStorageType: settings.apiClientStorageType,
|
|
563
|
-
apiPort,
|
|
564
|
-
appPublicPath: settings.appPublicPath,
|
|
580
|
+
envName: source.envName,
|
|
581
|
+
envFilePath: source.envFilePath,
|
|
582
|
+
apiBasePath: source.settings.apiBasePath,
|
|
583
|
+
apiClientShareToken: source.settings.apiClientShareToken,
|
|
584
|
+
apiClientStoragePrefix: source.settings.apiClientStoragePrefix,
|
|
585
|
+
apiClientStorageType: source.settings.apiClientStorageType,
|
|
586
|
+
apiPort: source.apiPort,
|
|
587
|
+
appPublicPath: source.settings.appPublicPath,
|
|
565
588
|
backendUrl,
|
|
566
589
|
cdnBaseUrl: ensureTrailingSlash(cdnBaseUrl),
|
|
567
|
-
distPath: settings.distPath,
|
|
590
|
+
distPath: source.settings.distPath,
|
|
568
591
|
distRootDir: mappedDistRootDir,
|
|
569
592
|
entryDir: mappedEntryDir,
|
|
570
593
|
publicDir: mappedPublicDir,
|
|
571
|
-
esmCdnBaseUrl: settings.esmCdnBaseUrl,
|
|
572
|
-
esmCdnSuffix: settings.esmCdnSuffix,
|
|
573
|
-
indexV1Path: await mapProxyPathFromCliRoot(resolveEnvProxyNginxIndexOutputPath(
|
|
574
|
-
indexV2Path: await mapProxyPathFromCliRoot(resolveEnvProxyNginxIndexOutputPath(
|
|
575
|
-
modernClientPrefix: settings.modernClientPrefix,
|
|
594
|
+
esmCdnBaseUrl: source.settings.esmCdnBaseUrl,
|
|
595
|
+
esmCdnSuffix: source.settings.esmCdnSuffix,
|
|
596
|
+
indexV1Path: await mapProxyPathFromCliRoot(resolveEnvProxyNginxIndexOutputPath(source.envName, 'v1', { scope: options?.scope }), options),
|
|
597
|
+
indexV2Path: await mapProxyPathFromCliRoot(resolveEnvProxyNginxIndexOutputPath(source.envName, 'v2', { scope: options?.scope }), options),
|
|
598
|
+
modernClientPrefix: source.settings.modernClientPrefix,
|
|
576
599
|
proxyHost,
|
|
577
600
|
snippetsDir: mappedSnippetsDir,
|
|
578
601
|
uploadsDir: mappedUploadsDir,
|
|
579
602
|
v2PublicPath,
|
|
580
|
-
wsPath: settings.wsPath,
|
|
581
|
-
wsUrl: settings.wsUrl,
|
|
603
|
+
wsPath: source.settings.wsPath,
|
|
604
|
+
wsUrl: source.settings.wsUrl,
|
|
605
|
+
activeVersion: source.activeVersion,
|
|
606
|
+
};
|
|
607
|
+
}
|
|
608
|
+
async function resolveRuntimeNginxBundleSource(runtime, options) {
|
|
609
|
+
const apiPort = trimValue(runtime.env.appPort ?? runtime.env.config.appPort);
|
|
610
|
+
if (!apiPort) {
|
|
611
|
+
throw new Error(translateCli('commands.envProxy.errors.missingAppPort', { envName: runtime.envName }, {
|
|
612
|
+
fallback: `Missing appPort for env "${runtime.envName}". Save or update the app port before generating proxy config.`,
|
|
613
|
+
}));
|
|
614
|
+
}
|
|
615
|
+
const activeVersion = trimValue(await readDistClientActiveVersion(runtime.env.storagePath));
|
|
616
|
+
if (!activeVersion) {
|
|
617
|
+
throw new Error(translateCli('commands.envProxy.errors.missingVersion', { envName: runtime.envName }, {
|
|
618
|
+
fallback: `Couldn't determine the app version for env "${runtime.envName}". Run \`nb env update ${runtime.envName}\` and try again.`,
|
|
619
|
+
}));
|
|
620
|
+
}
|
|
621
|
+
const { envFilePath, settings } = await loadEnvProxySettings(runtime, options);
|
|
622
|
+
return {
|
|
623
|
+
envName: runtime.envName,
|
|
624
|
+
envFilePath,
|
|
625
|
+
storagePath: runtime.env.storagePath,
|
|
626
|
+
distRootPath: resolveDistClientRoot(runtime.env.storagePath),
|
|
627
|
+
settings,
|
|
628
|
+
apiPort,
|
|
582
629
|
activeVersion,
|
|
583
630
|
};
|
|
584
631
|
}
|
|
632
|
+
async function resolveManualNginxBundleSource(input) {
|
|
633
|
+
const normalized = normalizeManualNginxInput(input);
|
|
634
|
+
return {
|
|
635
|
+
envName: normalized.name,
|
|
636
|
+
envFilePath: undefined,
|
|
637
|
+
storagePath: normalized.storagePath,
|
|
638
|
+
distRootPath: normalized.distRootPath,
|
|
639
|
+
settings: createManualProxyEnvSettings(normalized),
|
|
640
|
+
apiPort: normalized.appPort,
|
|
641
|
+
activeVersion: normalized.runtimeVersion,
|
|
642
|
+
};
|
|
643
|
+
}
|
|
585
644
|
async function buildEnvProxyCaddyRenderContext(runtime, options) {
|
|
586
|
-
return await
|
|
645
|
+
return await buildEnvProxyCaddyRenderContextFromSource(await resolveRuntimeNginxBundleSource(runtime), options);
|
|
646
|
+
}
|
|
647
|
+
async function buildEnvProxyCaddyRenderContextFromSource(source, options) {
|
|
648
|
+
return await buildEnvProxyNginxRenderContext(source, {
|
|
587
649
|
...options,
|
|
588
650
|
provider: 'caddy',
|
|
589
651
|
});
|
|
@@ -636,11 +698,20 @@ export function resolveEnvProxyCaddyIndexOutputPath(envName, variant, options) {
|
|
|
636
698
|
return path.join(resolveEnvProxyCaddyPublicOutputDir(envName, { scope: options?.scope }), `index-${variant}.html`);
|
|
637
699
|
}
|
|
638
700
|
export async function buildEnvProxyNginxBundle(runtime, options) {
|
|
639
|
-
|
|
701
|
+
return await buildNginxBundleFromSource(await resolveRuntimeNginxBundleSource(runtime, options), options);
|
|
702
|
+
}
|
|
703
|
+
export async function buildManualEnvProxyNginxBundle(input, options) {
|
|
704
|
+
return await buildNginxBundleFromSource(await resolveManualNginxBundleSource(input), {
|
|
705
|
+
...options,
|
|
706
|
+
upstreamHost: trimValue(input.upstreamHost) ?? options?.upstreamHost,
|
|
707
|
+
});
|
|
708
|
+
}
|
|
709
|
+
async function buildNginxBundleFromSource(source, options) {
|
|
710
|
+
const context = await buildEnvProxyNginxRenderContext(source, options);
|
|
640
711
|
const appTemplate = await readEnvProxyNginxAssetText('app.conf.tpl');
|
|
641
712
|
const mainTemplate = await readEnvProxyNginxAssetText('nocobase.conf.tpl');
|
|
642
|
-
const sourceIndexV1Path = path.join(
|
|
643
|
-
const sourceIndexV2Path = path.join(
|
|
713
|
+
const sourceIndexV1Path = path.join(source.distRootPath, context.activeVersion, 'index.html');
|
|
714
|
+
const sourceIndexV2Path = path.join(source.distRootPath, context.activeVersion, DEFAULT_MODERN_CLIENT_PREFIX, 'index.html');
|
|
644
715
|
const [sourceIndexV1Content, sourceIndexV2Content] = await Promise.all([
|
|
645
716
|
readFile(sourceIndexV1Path, 'utf8'),
|
|
646
717
|
readFile(sourceIndexV2Path, 'utf8'),
|
|
@@ -667,13 +738,13 @@ export async function buildEnvProxyNginxBundle(runtime, options) {
|
|
|
667
738
|
wsPath: context.wsPath,
|
|
668
739
|
};
|
|
669
740
|
return {
|
|
670
|
-
envName:
|
|
741
|
+
envName: source.envName,
|
|
671
742
|
envFilePath: context.envFilePath,
|
|
672
|
-
entryDir: resolveEnvProxyEntryDir(
|
|
673
|
-
publicDir: resolveEnvProxyNginxPublicOutputDir(
|
|
674
|
-
appConfigPath: resolveEnvProxyAppOutputPath(
|
|
675
|
-
indexV1Path: resolveEnvProxyNginxIndexOutputPath(
|
|
676
|
-
indexV2Path: resolveEnvProxyNginxIndexOutputPath(
|
|
743
|
+
entryDir: resolveEnvProxyEntryDir(source.envName, { scope: options?.scope, provider: 'nginx' }),
|
|
744
|
+
publicDir: resolveEnvProxyNginxPublicOutputDir(source.envName, { scope: options?.scope }),
|
|
745
|
+
appConfigPath: resolveEnvProxyAppOutputPath(source.envName, { scope: options?.scope, provider: 'nginx' }),
|
|
746
|
+
indexV1Path: resolveEnvProxyNginxIndexOutputPath(source.envName, 'v1', { scope: options?.scope }),
|
|
747
|
+
indexV2Path: resolveEnvProxyNginxIndexOutputPath(source.envName, 'v2', { scope: options?.scope }),
|
|
677
748
|
mainConfigPath: resolveEnvProxyMainOutputPath({ scope: options?.scope, provider: 'nginx' }),
|
|
678
749
|
snippetsDir: resolveEnvProxyNginxSnippetsOutputDir({ scope: options?.scope }),
|
|
679
750
|
appPublicPath: context.appPublicPath,
|
|
@@ -694,9 +765,18 @@ export async function buildEnvProxyNginxBundle(runtime, options) {
|
|
|
694
765
|
};
|
|
695
766
|
}
|
|
696
767
|
export async function buildEnvProxyCaddyBundle(runtime, options) {
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
768
|
+
return await buildCaddyBundleFromSource(await resolveRuntimeNginxBundleSource(runtime), options);
|
|
769
|
+
}
|
|
770
|
+
export async function buildManualEnvProxyCaddyBundle(input, options) {
|
|
771
|
+
return await buildCaddyBundleFromSource(await resolveManualNginxBundleSource(input), {
|
|
772
|
+
...options,
|
|
773
|
+
upstreamHost: trimValue(input.upstreamHost) ?? options?.upstreamHost,
|
|
774
|
+
});
|
|
775
|
+
}
|
|
776
|
+
async function buildCaddyBundleFromSource(source, options) {
|
|
777
|
+
const context = await buildEnvProxyCaddyRenderContextFromSource(source, options);
|
|
778
|
+
const sourceIndexV1Path = path.join(source.distRootPath, context.activeVersion, 'index.html');
|
|
779
|
+
const sourceIndexV2Path = path.join(source.distRootPath, context.activeVersion, DEFAULT_MODERN_CLIENT_PREFIX, 'index.html');
|
|
700
780
|
const [sourceIndexV1Content, sourceIndexV2Content] = await Promise.all([
|
|
701
781
|
readFile(sourceIndexV1Path, 'utf8'),
|
|
702
782
|
readFile(sourceIndexV2Path, 'utf8'),
|
|
@@ -707,9 +787,9 @@ export async function buildEnvProxyCaddyBundle(runtime, options) {
|
|
|
707
787
|
const sourceV2PublicPath = extractRuntimePublicPath(sourceIndexV2Content);
|
|
708
788
|
const indexV1AssetPublicPath = context.cdnBaseUrl;
|
|
709
789
|
const indexV2AssetPublicPath = `${trimTrailingSlash(context.cdnBaseUrl)}/${DEFAULT_MODERN_CLIENT_PREFIX}/`;
|
|
710
|
-
const appConfigPath = resolveEnvProxyAppOutputPath(
|
|
711
|
-
const entryDir = resolveEnvProxyEntryDir(
|
|
712
|
-
const publicDir = resolveEnvProxyCaddyPublicOutputDir(
|
|
790
|
+
const appConfigPath = resolveEnvProxyAppOutputPath(source.envName, { scope: options?.scope, provider: 'caddy' });
|
|
791
|
+
const entryDir = resolveEnvProxyEntryDir(source.envName, { scope: options?.scope, provider: 'caddy' });
|
|
792
|
+
const publicDir = resolveEnvProxyCaddyPublicOutputDir(source.envName, { scope: options?.scope });
|
|
713
793
|
const renderedPublicDir = await mapProxyPathFromCliRoot(publicDir, { ...options, provider: 'caddy' });
|
|
714
794
|
const appConfigContent = renderCaddyAppTemplate(buildCaddySiteAddress(), {
|
|
715
795
|
appPublicPath: context.appPublicPath,
|
|
@@ -725,13 +805,13 @@ export async function buildEnvProxyCaddyBundle(runtime, options) {
|
|
|
725
805
|
wsPath: context.wsPath,
|
|
726
806
|
}, renderedPublicDir);
|
|
727
807
|
return {
|
|
728
|
-
envName:
|
|
808
|
+
envName: source.envName,
|
|
729
809
|
envFilePath: context.envFilePath,
|
|
730
810
|
entryDir,
|
|
731
811
|
publicDir,
|
|
732
812
|
appConfigPath,
|
|
733
|
-
indexV1Path: resolveEnvProxyCaddyIndexOutputPath(
|
|
734
|
-
indexV2Path: resolveEnvProxyCaddyIndexOutputPath(
|
|
813
|
+
indexV1Path: resolveEnvProxyCaddyIndexOutputPath(source.envName, 'v1', { scope: options?.scope }),
|
|
814
|
+
indexV2Path: resolveEnvProxyCaddyIndexOutputPath(source.envName, 'v2', { scope: options?.scope }),
|
|
735
815
|
mainConfigPath: resolveEnvProxyMainOutputPath({ scope: options?.scope, provider: 'caddy' }),
|
|
736
816
|
appPublicPath: context.appPublicPath,
|
|
737
817
|
apiBasePath: context.apiBasePath,
|
package/dist/lib/proxy-caddy.js
CHANGED
|
@@ -11,7 +11,7 @@ import path from 'node:path';
|
|
|
11
11
|
import { dockerContainerExists, dockerContainerIsRunning, startDockerContainer, stopDockerContainer, } from './app-runtime.js';
|
|
12
12
|
import { CADDY_PROXY_DRIVER_OPTIONS, DEFAULT_CADDY_PROXY_DRIVER, getCliConfigValue, normalizeCaddyProxyDriver, resolveDockerContainerPrefix, setCliConfigValue, } from './cli-config.js';
|
|
13
13
|
import { resolveCliHomeRoot } from './cli-home.js';
|
|
14
|
-
import { applyEnvProxyAppEntryOptions, buildEnvProxyCaddyBundle, buildEnvProxyMainConfig, mapProxyPathFromCliRoot, resolveEnvProxyMainOutputPath, } from './env-proxy.js';
|
|
14
|
+
import { applyEnvProxyAppEntryOptions, buildManualEnvProxyCaddyBundle, buildEnvProxyCaddyBundle, buildEnvProxyMainConfig, mapProxyPathFromCliRoot, resolveEnvProxyMainOutputPath, } from './env-proxy.js';
|
|
15
15
|
import { run } from './run-npm.js';
|
|
16
16
|
const DOCKER_CADDY_PROXY_CONTAINER_SUFFIX = 'caddy-proxy';
|
|
17
17
|
const DOCKER_CADDY_PROXY_IMAGE = 'caddy:latest';
|
|
@@ -62,8 +62,9 @@ export async function resolveCaddyProxyRuntimeContext(options) {
|
|
|
62
62
|
upstreamHost: resolveCaddyProxyUpstreamHost(driver),
|
|
63
63
|
};
|
|
64
64
|
}
|
|
65
|
-
export async function writeCaddyProxyBundle(runtime, appEntryOptions, runtimeContext) {
|
|
65
|
+
export async function writeCaddyProxyBundle(runtime, appEntryOptions, runtimeContext, options) {
|
|
66
66
|
const bundle = await buildEnvProxyCaddyBundle(runtime, {
|
|
67
|
+
cdnBaseUrl: options?.cdnBaseUrl,
|
|
67
68
|
runtimeCliRoot: runtimeContext.runtimeCliRoot,
|
|
68
69
|
upstreamHost: runtimeContext.upstreamHost,
|
|
69
70
|
});
|
|
@@ -82,6 +83,27 @@ export async function writeCaddyProxyBundle(runtime, appEntryOptions, runtimeCon
|
|
|
82
83
|
status,
|
|
83
84
|
};
|
|
84
85
|
}
|
|
86
|
+
export async function writeManualCaddyProxyBundle(input, appEntryOptions, runtimeContext, options) {
|
|
87
|
+
const bundle = await buildManualEnvProxyCaddyBundle(input, {
|
|
88
|
+
cdnBaseUrl: options?.cdnBaseUrl,
|
|
89
|
+
runtimeCliRoot: runtimeContext.runtimeCliRoot,
|
|
90
|
+
upstreamHost: input.upstreamHost || runtimeContext.upstreamHost,
|
|
91
|
+
});
|
|
92
|
+
const currentAppConfigContent = await readOptionalTextFile(bundle.appConfigPath);
|
|
93
|
+
const nextAppConfigContent = applyEnvProxyAppEntryOptions(bundle.appConfigContent, 'caddy', appEntryOptions);
|
|
94
|
+
const status = currentAppConfigContent ? 'updated' : 'created';
|
|
95
|
+
await Promise.all([mkdir(bundle.entryDir, { recursive: true }), mkdir(bundle.publicDir, { recursive: true })]);
|
|
96
|
+
await Promise.all([
|
|
97
|
+
writeFile(bundle.appConfigPath, nextAppConfigContent, 'utf8'),
|
|
98
|
+
writeFile(bundle.indexV1Path, bundle.indexV1Content, 'utf8'),
|
|
99
|
+
writeFile(bundle.indexV2Path, bundle.indexV2Content, 'utf8'),
|
|
100
|
+
writeFile(bundle.mainConfigPath, bundle.mainConfigContent, 'utf8'),
|
|
101
|
+
]);
|
|
102
|
+
return {
|
|
103
|
+
bundle,
|
|
104
|
+
status,
|
|
105
|
+
};
|
|
106
|
+
}
|
|
85
107
|
function resolveLocalCaddyPidFilePath() {
|
|
86
108
|
return path.join(path.dirname(resolveEnvProxyMainOutputPath({ provider: 'caddy' })), 'caddy.pid');
|
|
87
109
|
}
|
package/dist/lib/proxy-nginx.js
CHANGED
|
@@ -11,7 +11,7 @@ import path from 'node:path';
|
|
|
11
11
|
import { dockerContainerExists, dockerContainerIsRunning, startDockerContainer, stopDockerContainer, } from './app-runtime.js';
|
|
12
12
|
import { DEFAULT_NGINX_PROXY_DRIVER, getCliConfigValue, NGINX_PROXY_DRIVER_OPTIONS, normalizeNginxProxyDriver, resolveDockerContainerPrefix, setCliConfigValue, } from './cli-config.js';
|
|
13
13
|
import { resolveCliHomeRoot } from './cli-home.js';
|
|
14
|
-
import { applyEnvProxyAppEntryOptions, appConfigHasManagedNginxBlock, buildEnvProxyMainConfig, buildEnvProxyNginxBundle, extractManagedNginxConfigBlock, installEnvProxyProvider, mapProxyPathFromCliRoot, reloadEnvProxyProvider, resolveEnvProxyMainOutputPath, replaceManagedNginxConfigBlock, syncEnvProxyNginxSnippets, } from './env-proxy.js';
|
|
14
|
+
import { applyEnvProxyAppEntryOptions, appConfigHasManagedNginxBlock, buildManualEnvProxyNginxBundle, buildEnvProxyMainConfig, buildEnvProxyNginxBundle, extractManagedNginxConfigBlock, installEnvProxyProvider, mapProxyPathFromCliRoot, reloadEnvProxyProvider, resolveEnvProxyMainOutputPath, replaceManagedNginxConfigBlock, syncEnvProxyNginxSnippets, } from './env-proxy.js';
|
|
15
15
|
import { run } from './run-npm.js';
|
|
16
16
|
const DOCKER_NGINX_PROXY_CONTAINER_SUFFIX = 'nginx-proxy';
|
|
17
17
|
const DOCKER_NGINX_PROXY_IMAGE = 'nginx:latest';
|
|
@@ -66,11 +66,23 @@ function buildNginxManagedBlockMissingMessage(appConfigPath) {
|
|
|
66
66
|
return (`The editable nginx app entry config at ${appConfigPath} does not contain the NocoBase managed block. ` +
|
|
67
67
|
'Restore the managed block or delete the file and regenerate the proxy config.');
|
|
68
68
|
}
|
|
69
|
-
export async function writeNginxProxyBundle(runtime, appEntryOptions, runtimeContext) {
|
|
69
|
+
export async function writeNginxProxyBundle(runtime, appEntryOptions, runtimeContext, options) {
|
|
70
70
|
const bundle = await buildEnvProxyNginxBundle(runtime, {
|
|
71
|
+
cdnBaseUrl: options?.cdnBaseUrl,
|
|
71
72
|
runtimeCliRoot: runtimeContext.runtimeCliRoot,
|
|
72
73
|
upstreamHost: runtimeContext.upstreamHost,
|
|
73
74
|
});
|
|
75
|
+
return await writeResolvedNginxProxyBundle(bundle, appEntryOptions, options);
|
|
76
|
+
}
|
|
77
|
+
export async function writeManualNginxProxyBundle(input, appEntryOptions, runtimeContext, options) {
|
|
78
|
+
const bundle = await buildManualEnvProxyNginxBundle(input, {
|
|
79
|
+
cdnBaseUrl: options?.cdnBaseUrl,
|
|
80
|
+
runtimeCliRoot: runtimeContext.runtimeCliRoot,
|
|
81
|
+
upstreamHost: runtimeContext.upstreamHost,
|
|
82
|
+
});
|
|
83
|
+
return await writeResolvedNginxProxyBundle(bundle, appEntryOptions, options);
|
|
84
|
+
}
|
|
85
|
+
async function writeResolvedNginxProxyBundle(bundle, appEntryOptions, options) {
|
|
74
86
|
const managedConfigBlock = extractManagedNginxConfigBlock(bundle.appConfigContent);
|
|
75
87
|
if (!managedConfigBlock) {
|
|
76
88
|
throw new Error('Failed to render the managed nginx config block.');
|
|
@@ -79,10 +91,12 @@ export async function writeNginxProxyBundle(runtime, appEntryOptions, runtimeCon
|
|
|
79
91
|
let nextAppConfigContent = applyEnvProxyAppEntryOptions(bundle.appConfigContent, 'nginx', appEntryOptions);
|
|
80
92
|
let status = 'created';
|
|
81
93
|
if (currentAppConfigContent) {
|
|
82
|
-
if (!appConfigHasManagedNginxBlock(currentAppConfigContent)) {
|
|
94
|
+
if (!appConfigHasManagedNginxBlock(currentAppConfigContent) && !options?.force) {
|
|
83
95
|
throw new Error(buildNginxManagedBlockMissingMessage(bundle.appConfigPath));
|
|
84
96
|
}
|
|
85
|
-
nextAppConfigContent =
|
|
97
|
+
nextAppConfigContent = appConfigHasManagedNginxBlock(currentAppConfigContent)
|
|
98
|
+
? applyEnvProxyAppEntryOptions(replaceManagedNginxConfigBlock(currentAppConfigContent, managedConfigBlock), 'nginx', appEntryOptions)
|
|
99
|
+
: applyEnvProxyAppEntryOptions(bundle.appConfigContent, 'nginx', appEntryOptions);
|
|
86
100
|
status = 'updated';
|
|
87
101
|
}
|
|
88
102
|
await Promise.all([mkdir(bundle.entryDir, { recursive: true }), mkdir(bundle.publicDir, { recursive: true })]);
|
package/dist/locale/en-US.json
CHANGED
|
@@ -263,7 +263,7 @@
|
|
|
263
263
|
"version": {
|
|
264
264
|
"message": "Which version would you like to use?",
|
|
265
265
|
"latestLabel": "latest",
|
|
266
|
-
"latestHint": "Stable release. Best for production use and the most predictable experience.
|
|
266
|
+
"latestHint": "Stable release. Best for production use and the most predictable experience.",
|
|
267
267
|
"betaLabel": "beta",
|
|
268
268
|
"betaHint": "Preview release. Good for trying upcoming features before general release.",
|
|
269
269
|
"alphaLabel": "alpha",
|
package/dist/locale/zh-CN.json
CHANGED
|
@@ -263,7 +263,7 @@
|
|
|
263
263
|
"version": {
|
|
264
264
|
"message": "你想使用哪个版本?",
|
|
265
265
|
"latestLabel": "latest",
|
|
266
|
-
"latestHint": "
|
|
266
|
+
"latestHint": "稳定版。适合生产环境和希望获得稳定体验的场景。",
|
|
267
267
|
"betaLabel": "beta",
|
|
268
268
|
"betaHint": "测试版。包含即将发布的新功能,适合提前体验和反馈。",
|
|
269
269
|
"alphaLabel": "alpha",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nocobase/cli",
|
|
3
|
-
"version": "2.2.0-alpha.
|
|
3
|
+
"version": "2.2.0-alpha.4",
|
|
4
4
|
"description": "NocoBase Command Line Tool",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/generated/command-registry.js",
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
"author": "",
|
|
14
14
|
"license": "Apache-2.0",
|
|
15
15
|
"files": [
|
|
16
|
+
"assets",
|
|
16
17
|
"bin",
|
|
17
18
|
"dist",
|
|
18
19
|
"nocobase-ctl.config.json"
|
|
@@ -143,5 +144,5 @@
|
|
|
143
144
|
"type": "git",
|
|
144
145
|
"url": "git+https://github.com/nocobase/nocobase.git"
|
|
145
146
|
},
|
|
146
|
-
"gitHead": "
|
|
147
|
+
"gitHead": "81bf8733db4bccf08a6bc5e6d97f274bce349161"
|
|
147
148
|
}
|