@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.
Files changed (35) hide show
  1. package/dist/commands/app/destroy.js +3 -3
  2. package/dist/commands/app/stop.js +4 -11
  3. package/dist/commands/proxy/caddy/current.js +17 -0
  4. package/dist/commands/proxy/caddy/generate.js +69 -0
  5. package/dist/commands/proxy/caddy/index.js +28 -0
  6. package/dist/commands/proxy/caddy/info.js +31 -0
  7. package/dist/commands/proxy/caddy/reload.js +28 -0
  8. package/dist/commands/proxy/caddy/restart.js +28 -0
  9. package/dist/commands/proxy/caddy/start.js +30 -0
  10. package/dist/commands/proxy/caddy/status.js +19 -0
  11. package/dist/commands/proxy/caddy/stop.js +30 -0
  12. package/dist/commands/proxy/caddy/use.js +26 -0
  13. package/dist/commands/proxy/index.js +28 -0
  14. package/dist/commands/proxy/nginx/current.js +18 -0
  15. package/dist/commands/proxy/nginx/generate.js +68 -0
  16. package/dist/commands/proxy/nginx/index.js +28 -0
  17. package/dist/commands/proxy/nginx/info.js +34 -0
  18. package/dist/commands/proxy/nginx/reload.js +28 -0
  19. package/dist/commands/proxy/nginx/restart.js +28 -0
  20. package/dist/commands/proxy/nginx/start.js +30 -0
  21. package/dist/commands/proxy/nginx/status.js +19 -0
  22. package/dist/commands/proxy/nginx/stop.js +30 -0
  23. package/dist/commands/proxy/nginx/use.js +31 -0
  24. package/dist/commands/revision/create.js +31 -2
  25. package/dist/lib/auth-store.js +8 -0
  26. package/dist/lib/cli-config.js +73 -1
  27. package/dist/lib/env-proxy.js +105 -75
  28. package/dist/lib/proxy-caddy.js +274 -0
  29. package/dist/lib/proxy-nginx.js +330 -0
  30. package/dist/locale/en-US.json +2 -2
  31. package/dist/locale/zh-CN.json +2 -2
  32. package/package.json +2 -2
  33. package/dist/commands/env/proxy/caddy.js +0 -28
  34. package/dist/commands/env/proxy/index.js +0 -353
  35. 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: true,
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(`HTTP ${response.status}`);
116
+ this.log('Revision created successfully');
88
117
  }
89
118
  }
@@ -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),
@@ -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 && !trimValue(proxy.nbCliRoot) && !trimValue(proxy.upstreamHost)) {
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;
@@ -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 `nb env proxy` can refresh managed routes.'
113
- : ' # Keep this include so `nb env proxy` can refresh managed routes.',
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
- return content.replace(currentAddress, nextAddress);
249
+ nextContent = nextContent.replace(/^([^\s#][^\n{]*)\s*\{/m, `${nextAddress} {`);
249
250
  }
250
- return content;
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 generatedConfigContent = renderCaddyGeneratedTemplate({
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: buildEnvProxyAppConfig('caddy', renderedGeneratedConfigPath),
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 \`nb env proxy\`. Changes will be overwritten.
971
+ return `# Managed by NocoBase CLI. Changes will be overwritten.
961
972
 
962
973
  ${renderNginxLocationTemplate(context)}`;
963
974
  }
964
- function renderCaddyGeneratedTemplate(context, publicDir) {
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 `# Managed by \`nb env proxy\`. Changes will be overwritten.
1002
-
1003
- route {
1004
- encode zstd gzip${rootRedirectBlock}${appPublicPathRedirectBlock}${modernClientRedirectBlock}${shorthandModernClientRedirectBlock}
1005
-
1006
- handle_path ${uploadsPathMatcher} {
1007
- root * ${context.uploadsPath}
1008
- header Cache-Control public
1009
- header X-Content-Type-Options nosniff
1010
- file_server
1011
- }
1012
-
1013
- handle_path ${distPathMatcher} {
1014
- root * ${context.distClientRoot}
1015
- header Cache-Control public
1016
- file_server
1017
- }
1018
-
1019
- @oauth path_regexp oauth ^/\\.well-known/oauth-authorization-server/(.+)$
1020
- handle @oauth {
1021
- rewrite * /{re.oauth.1}/.well-known/oauth-authorization-server
1022
- reverse_proxy ${context.proxyHost}:${context.apiPort}
1023
- }
1024
-
1025
- @openid path_regexp openid ^/\\.well-known/openid-configuration/(.+)$
1026
- handle @openid {
1027
- rewrite * /{re.openid.1}/.well-known/openid-configuration
1028
- reverse_proxy ${context.proxyHost}:${context.apiPort}
1029
- }
1030
-
1031
- handle ${apiPathMatcher} {
1032
- reverse_proxy ${context.proxyHost}:${context.apiPort}
1033
- }
1034
-
1035
- handle ${context.wsPath} {
1036
- reverse_proxy ${context.proxyHost}:${context.apiPort}
1037
- }
1038
-
1039
- handle_path ${toCaddyPathMatcher(context.v2PublicPath)} {
1040
- root * ${publicDir}
1041
- header Cache-Control "no-store, no-cache, must-revalidate"
1042
- header X-Robots-Tag "noindex, nofollow"
1043
- try_files {path} /index-v2.html
1044
- file_server
1045
- }
1046
-
1047
- handle_path ${toCaddyPathMatcher(context.appPublicPath)} {
1048
- root * ${publicDir}
1049
- header Cache-Control "no-store, no-cache, must-revalidate"
1050
- header X-Robots-Tag "noindex, nofollow"
1051
- try_files {path} /index-v1.html
1052
- file_server
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 \`nb env proxy\`. Changes will be overwritten.
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
- ? renderCaddyGeneratedTemplate(templateContext, publicDir ?? '')
1179
+ ? renderCaddyAppTemplate(buildCaddySiteAddress(), templateContext, publicDir ?? '')
1150
1180
  : renderNginxGeneratedTemplate(templateContext),
1151
1181
  };
1152
1182
  }