@nocobase/cli 2.2.0-alpha.3 → 2.2.0-alpha.5

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.
@@ -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(runtime.env.envVars?.CDN_BASE_URL) ?? trimValue(envValues.CDN_BASE_URL),
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,53 @@ 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
+ const upstreamPort = trimValue(input.upstreamPort) ?? trimValue(input.appPort);
313
+ return {
314
+ name: String(input.name).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
+ upstreamPort,
321
+ appPort: trimValue(input.appPort),
322
+ cdnBaseUrl: trimValue(input.cdnBaseUrl),
323
+ };
324
+ }
325
+ function normalizeProxyPort(value) {
326
+ const normalized = trimValue(value);
327
+ if (!normalized || !/^\d+$/.test(normalized)) {
328
+ return undefined;
329
+ }
330
+ const port = Number(normalized);
331
+ if (!Number.isInteger(port) || port < 1 || port > 65535) {
332
+ return undefined;
333
+ }
334
+ return normalized;
335
+ }
287
336
  async function parseVersionFromPackageJson(content, sourceLabel) {
288
337
  let parsed;
289
338
  try {
@@ -525,65 +574,92 @@ function buildNginxRuntimeConfig(context, variant) {
525
574
  function buildCaddyRuntimeConfig(context, variant) {
526
575
  return buildNginxRuntimeConfig(context, variant);
527
576
  }
528
- async function buildEnvProxyNginxRenderContext(runtime, options) {
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);
577
+ async function buildEnvProxyNginxRenderContext(source, options) {
542
578
  const proxyHost = await resolveProxyUpstreamHost(options);
543
- const backendUrl = `http://${proxyHost}:${apiPort}`;
544
- const cdnBaseUrl = settings.cdnBaseUrl ?? buildDefaultCdnBaseUrl(settings.appPublicPath, activeVersion);
545
- const entryDir = resolveEnvProxyEntryDir(runtime.envName, { scope: options?.scope });
546
- const publicDir = resolveEnvProxyNginxPublicOutputDir(runtime.envName, { scope: options?.scope });
579
+ const upstreamPort = normalizeProxyPort(options?.upstreamPort) ?? source.apiPort;
580
+ const backendUrl = `http://${proxyHost}:${upstreamPort}`;
581
+ const cdnBaseUrl = source.settings.cdnBaseUrl ?? buildDefaultCdnBaseUrl(source.settings.appPublicPath, source.activeVersion);
582
+ const entryDir = resolveEnvProxyEntryDir(source.envName, { scope: options?.scope });
583
+ const publicDir = resolveEnvProxyNginxPublicOutputDir(source.envName, { scope: options?.scope });
547
584
  const snippetsDir = resolveEnvProxyNginxSnippetsOutputDir({ scope: options?.scope });
548
- const distRootDir = resolveDistClientRoot(runtime.env.storagePath);
549
- const uploadsDir = path.join(runtime.env.storagePath, 'uploads');
585
+ const distRootDir = source.distRootPath;
586
+ const uploadsDir = path.join(source.storagePath, 'uploads');
550
587
  const mappedEntryDir = await mapProxyPathFromCliRoot(entryDir, options);
551
588
  const mappedPublicDir = await mapProxyPathFromCliRoot(publicDir, options);
552
589
  const mappedSnippetsDir = await mapProxyPathFromCliRoot(snippetsDir, options);
553
590
  const mappedDistRootDir = await mapProxyPathFromCliRoot(distRootDir, options);
554
591
  const mappedUploadsDir = await mapProxyPathFromCliRoot(uploadsDir, options);
555
- const v2PublicPath = `${settings.appPublicPath.replace(/\/$/, '')}/${settings.modernClientPrefix}/`;
592
+ const v2PublicPath = `${source.settings.appPublicPath.replace(/\/$/, '')}/${source.settings.modernClientPrefix}/`;
556
593
  return {
557
- envName: runtime.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,
594
+ envName: source.envName,
595
+ envFilePath: source.envFilePath,
596
+ apiBasePath: source.settings.apiBasePath,
597
+ apiClientShareToken: source.settings.apiClientShareToken,
598
+ apiClientStoragePrefix: source.settings.apiClientStoragePrefix,
599
+ apiClientStorageType: source.settings.apiClientStorageType,
600
+ apiPort: source.apiPort,
601
+ appPublicPath: source.settings.appPublicPath,
565
602
  backendUrl,
566
603
  cdnBaseUrl: ensureTrailingSlash(cdnBaseUrl),
567
- distPath: settings.distPath,
604
+ distPath: source.settings.distPath,
568
605
  distRootDir: mappedDistRootDir,
569
606
  entryDir: mappedEntryDir,
570
607
  publicDir: mappedPublicDir,
571
- esmCdnBaseUrl: settings.esmCdnBaseUrl,
572
- esmCdnSuffix: settings.esmCdnSuffix,
573
- indexV1Path: await mapProxyPathFromCliRoot(resolveEnvProxyNginxIndexOutputPath(runtime.envName, 'v1', { scope: options?.scope }), options),
574
- indexV2Path: await mapProxyPathFromCliRoot(resolveEnvProxyNginxIndexOutputPath(runtime.envName, 'v2', { scope: options?.scope }), options),
575
- modernClientPrefix: settings.modernClientPrefix,
608
+ esmCdnBaseUrl: source.settings.esmCdnBaseUrl,
609
+ esmCdnSuffix: source.settings.esmCdnSuffix,
610
+ indexV1Path: await mapProxyPathFromCliRoot(resolveEnvProxyNginxIndexOutputPath(source.envName, 'v1', { scope: options?.scope }), options),
611
+ indexV2Path: await mapProxyPathFromCliRoot(resolveEnvProxyNginxIndexOutputPath(source.envName, 'v2', { scope: options?.scope }), options),
612
+ modernClientPrefix: source.settings.modernClientPrefix,
576
613
  proxyHost,
577
614
  snippetsDir: mappedSnippetsDir,
578
615
  uploadsDir: mappedUploadsDir,
579
616
  v2PublicPath,
580
- wsPath: settings.wsPath,
581
- wsUrl: settings.wsUrl,
617
+ wsPath: source.settings.wsPath,
618
+ wsUrl: source.settings.wsUrl,
619
+ activeVersion: source.activeVersion,
620
+ };
621
+ }
622
+ async function resolveRuntimeNginxBundleSource(runtime, options) {
623
+ const apiPort = trimValue(runtime.env.appPort ?? runtime.env.config.appPort);
624
+ if (!apiPort) {
625
+ throw new Error(translateCli('commands.envProxy.errors.missingAppPort', { envName: runtime.envName }, {
626
+ fallback: `Missing appPort for env "${runtime.envName}". Save or update the app port before generating proxy config.`,
627
+ }));
628
+ }
629
+ const activeVersion = trimValue(await readDistClientActiveVersion(runtime.env.storagePath));
630
+ if (!activeVersion) {
631
+ throw new Error(translateCli('commands.envProxy.errors.missingVersion', { envName: runtime.envName }, {
632
+ fallback: `Couldn't determine the app version for env "${runtime.envName}". Run \`nb env update ${runtime.envName}\` and try again.`,
633
+ }));
634
+ }
635
+ const { envFilePath, settings } = await loadEnvProxySettings(runtime, options);
636
+ return {
637
+ envName: runtime.envName,
638
+ envFilePath,
639
+ storagePath: runtime.env.storagePath,
640
+ distRootPath: resolveDistClientRoot(runtime.env.storagePath),
641
+ settings,
642
+ apiPort,
582
643
  activeVersion,
583
644
  };
584
645
  }
646
+ async function resolveManualNginxBundleSource(input) {
647
+ const normalized = normalizeManualNginxInput(input);
648
+ return {
649
+ envName: normalized.name,
650
+ envFilePath: undefined,
651
+ storagePath: normalized.storagePath,
652
+ distRootPath: normalized.distRootPath,
653
+ settings: createManualProxyEnvSettings(normalized),
654
+ apiPort: normalized.upstreamPort,
655
+ activeVersion: normalized.runtimeVersion,
656
+ };
657
+ }
585
658
  async function buildEnvProxyCaddyRenderContext(runtime, options) {
586
- return await buildEnvProxyNginxRenderContext(runtime, {
659
+ return await buildEnvProxyCaddyRenderContextFromSource(await resolveRuntimeNginxBundleSource(runtime), options);
660
+ }
661
+ async function buildEnvProxyCaddyRenderContextFromSource(source, options) {
662
+ return await buildEnvProxyNginxRenderContext(source, {
587
663
  ...options,
588
664
  provider: 'caddy',
589
665
  });
@@ -636,11 +712,21 @@ export function resolveEnvProxyCaddyIndexOutputPath(envName, variant, options) {
636
712
  return path.join(resolveEnvProxyCaddyPublicOutputDir(envName, { scope: options?.scope }), `index-${variant}.html`);
637
713
  }
638
714
  export async function buildEnvProxyNginxBundle(runtime, options) {
639
- const context = await buildEnvProxyNginxRenderContext(runtime, options);
715
+ return await buildNginxBundleFromSource(await resolveRuntimeNginxBundleSource(runtime, options), options);
716
+ }
717
+ export async function buildManualEnvProxyNginxBundle(input, options) {
718
+ return await buildNginxBundleFromSource(await resolveManualNginxBundleSource(input), {
719
+ ...options,
720
+ upstreamHost: trimValue(input.upstreamHost) ?? options?.upstreamHost,
721
+ upstreamPort: normalizeProxyPort(input.upstreamPort) ?? options?.upstreamPort,
722
+ });
723
+ }
724
+ async function buildNginxBundleFromSource(source, options) {
725
+ const context = await buildEnvProxyNginxRenderContext(source, options);
640
726
  const appTemplate = await readEnvProxyNginxAssetText('app.conf.tpl');
641
727
  const mainTemplate = await readEnvProxyNginxAssetText('nocobase.conf.tpl');
642
- const sourceIndexV1Path = path.join(runtime.env.storagePath, 'dist-client', context.activeVersion, 'index.html');
643
- const sourceIndexV2Path = path.join(runtime.env.storagePath, 'dist-client', context.activeVersion, DEFAULT_MODERN_CLIENT_PREFIX, 'index.html');
728
+ const sourceIndexV1Path = path.join(source.distRootPath, context.activeVersion, 'index.html');
729
+ const sourceIndexV2Path = path.join(source.distRootPath, context.activeVersion, DEFAULT_MODERN_CLIENT_PREFIX, 'index.html');
644
730
  const [sourceIndexV1Content, sourceIndexV2Content] = await Promise.all([
645
731
  readFile(sourceIndexV1Path, 'utf8'),
646
732
  readFile(sourceIndexV2Path, 'utf8'),
@@ -667,13 +753,13 @@ export async function buildEnvProxyNginxBundle(runtime, options) {
667
753
  wsPath: context.wsPath,
668
754
  };
669
755
  return {
670
- envName: runtime.envName,
756
+ envName: source.envName,
671
757
  envFilePath: context.envFilePath,
672
- entryDir: resolveEnvProxyEntryDir(runtime.envName, { scope: options?.scope, provider: 'nginx' }),
673
- publicDir: resolveEnvProxyNginxPublicOutputDir(runtime.envName, { scope: options?.scope }),
674
- appConfigPath: resolveEnvProxyAppOutputPath(runtime.envName, { scope: options?.scope, provider: 'nginx' }),
675
- indexV1Path: resolveEnvProxyNginxIndexOutputPath(runtime.envName, 'v1', { scope: options?.scope }),
676
- indexV2Path: resolveEnvProxyNginxIndexOutputPath(runtime.envName, 'v2', { scope: options?.scope }),
758
+ entryDir: resolveEnvProxyEntryDir(source.envName, { scope: options?.scope, provider: 'nginx' }),
759
+ publicDir: resolveEnvProxyNginxPublicOutputDir(source.envName, { scope: options?.scope }),
760
+ appConfigPath: resolveEnvProxyAppOutputPath(source.envName, { scope: options?.scope, provider: 'nginx' }),
761
+ indexV1Path: resolveEnvProxyNginxIndexOutputPath(source.envName, 'v1', { scope: options?.scope }),
762
+ indexV2Path: resolveEnvProxyNginxIndexOutputPath(source.envName, 'v2', { scope: options?.scope }),
677
763
  mainConfigPath: resolveEnvProxyMainOutputPath({ scope: options?.scope, provider: 'nginx' }),
678
764
  snippetsDir: resolveEnvProxyNginxSnippetsOutputDir({ scope: options?.scope }),
679
765
  appPublicPath: context.appPublicPath,
@@ -694,9 +780,19 @@ export async function buildEnvProxyNginxBundle(runtime, options) {
694
780
  };
695
781
  }
696
782
  export async function buildEnvProxyCaddyBundle(runtime, options) {
697
- const context = await buildEnvProxyCaddyRenderContext(runtime, options);
698
- const sourceIndexV1Path = path.join(runtime.env.storagePath, 'dist-client', context.activeVersion, 'index.html');
699
- const sourceIndexV2Path = path.join(runtime.env.storagePath, 'dist-client', context.activeVersion, DEFAULT_MODERN_CLIENT_PREFIX, 'index.html');
783
+ return await buildCaddyBundleFromSource(await resolveRuntimeNginxBundleSource(runtime), options);
784
+ }
785
+ export async function buildManualEnvProxyCaddyBundle(input, options) {
786
+ return await buildCaddyBundleFromSource(await resolveManualNginxBundleSource(input), {
787
+ ...options,
788
+ upstreamHost: trimValue(input.upstreamHost) ?? options?.upstreamHost,
789
+ upstreamPort: normalizeProxyPort(input.upstreamPort) ?? options?.upstreamPort,
790
+ });
791
+ }
792
+ async function buildCaddyBundleFromSource(source, options) {
793
+ const context = await buildEnvProxyCaddyRenderContextFromSource(source, options);
794
+ const sourceIndexV1Path = path.join(source.distRootPath, context.activeVersion, 'index.html');
795
+ const sourceIndexV2Path = path.join(source.distRootPath, context.activeVersion, DEFAULT_MODERN_CLIENT_PREFIX, 'index.html');
700
796
  const [sourceIndexV1Content, sourceIndexV2Content] = await Promise.all([
701
797
  readFile(sourceIndexV1Path, 'utf8'),
702
798
  readFile(sourceIndexV2Path, 'utf8'),
@@ -707,9 +803,9 @@ export async function buildEnvProxyCaddyBundle(runtime, options) {
707
803
  const sourceV2PublicPath = extractRuntimePublicPath(sourceIndexV2Content);
708
804
  const indexV1AssetPublicPath = context.cdnBaseUrl;
709
805
  const indexV2AssetPublicPath = `${trimTrailingSlash(context.cdnBaseUrl)}/${DEFAULT_MODERN_CLIENT_PREFIX}/`;
710
- const appConfigPath = resolveEnvProxyAppOutputPath(runtime.envName, { scope: options?.scope, provider: 'caddy' });
711
- const entryDir = resolveEnvProxyEntryDir(runtime.envName, { scope: options?.scope, provider: 'caddy' });
712
- const publicDir = resolveEnvProxyCaddyPublicOutputDir(runtime.envName, { scope: options?.scope });
806
+ const appConfigPath = resolveEnvProxyAppOutputPath(source.envName, { scope: options?.scope, provider: 'caddy' });
807
+ const entryDir = resolveEnvProxyEntryDir(source.envName, { scope: options?.scope, provider: 'caddy' });
808
+ const publicDir = resolveEnvProxyCaddyPublicOutputDir(source.envName, { scope: options?.scope });
713
809
  const renderedPublicDir = await mapProxyPathFromCliRoot(publicDir, { ...options, provider: 'caddy' });
714
810
  const appConfigContent = renderCaddyAppTemplate(buildCaddySiteAddress(), {
715
811
  appPublicPath: context.appPublicPath,
@@ -725,13 +821,13 @@ export async function buildEnvProxyCaddyBundle(runtime, options) {
725
821
  wsPath: context.wsPath,
726
822
  }, renderedPublicDir);
727
823
  return {
728
- envName: runtime.envName,
824
+ envName: source.envName,
729
825
  envFilePath: context.envFilePath,
730
826
  entryDir,
731
827
  publicDir,
732
828
  appConfigPath,
733
- indexV1Path: resolveEnvProxyCaddyIndexOutputPath(runtime.envName, 'v1', { scope: options?.scope }),
734
- indexV2Path: resolveEnvProxyCaddyIndexOutputPath(runtime.envName, 'v2', { scope: options?.scope }),
829
+ indexV1Path: resolveEnvProxyCaddyIndexOutputPath(source.envName, 'v1', { scope: options?.scope }),
830
+ indexV2Path: resolveEnvProxyCaddyIndexOutputPath(source.envName, 'v2', { scope: options?.scope }),
735
831
  mainConfigPath: resolveEnvProxyMainOutputPath({ scope: options?.scope, provider: 'caddy' }),
736
832
  appPublicPath: context.appPublicPath,
737
833
  apiBasePath: context.apiBasePath,
@@ -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
  }
@@ -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 = applyEnvProxyAppEntryOptions(replaceManagedNginxConfigBlock(currentAppConfigContent, managedConfigBlock), 'nginx', appEntryOptions);
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 })]);
@@ -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. Currently unavailable.",
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",
@@ -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",
3
+ "version": "2.2.0-alpha.5",
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": "e3ec19361fd7981af9fe2a7f24ad335025cbefcd"
147
+ "gitHead": "814ff497dd1233ca7218c9f7f2a016c2ead6516d"
147
148
  }