@nocobase/cli 2.2.0-beta.8 → 2.3.0-alpha.1

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 (32) hide show
  1. package/assets/env-proxy/nginx/app.conf.tpl +23 -0
  2. package/assets/env-proxy/nginx/nocobase.conf.tpl +5 -0
  3. package/assets/env-proxy/nginx/snippets/dist-location.conf +5 -0
  4. package/assets/env-proxy/nginx/snippets/gzip.conf +17 -0
  5. package/assets/env-proxy/nginx/snippets/log-format-http.conf +13 -0
  6. package/assets/env-proxy/nginx/snippets/maps-http.conf +14 -0
  7. package/assets/env-proxy/nginx/snippets/mime-types.conf +98 -0
  8. package/assets/env-proxy/nginx/snippets/proxy-location.conf +18 -0
  9. package/assets/env-proxy/nginx/snippets/spa-location.conf +6 -0
  10. package/assets/env-proxy/nginx/snippets/uploads-location.conf +21 -0
  11. package/dist/commands/app/start.js +4 -1
  12. package/dist/commands/env/info.js +11 -1
  13. package/dist/commands/init.js +11 -1
  14. package/dist/commands/install.js +61 -130
  15. package/dist/commands/proxy/caddy/generate.js +93 -7
  16. package/dist/commands/proxy/nginx/generate.js +98 -7
  17. package/dist/commands/revision/create.js +1 -1
  18. package/dist/commands/source/download.js +18 -14
  19. package/dist/lib/app-managed-resources.js +3 -2
  20. package/dist/lib/auth-store.js +68 -0
  21. package/dist/lib/cli-config.js +54 -1
  22. package/dist/lib/docker-image.js +94 -6
  23. package/dist/lib/env-config.js +5 -0
  24. package/dist/lib/env-proxy-config.js +48 -0
  25. package/dist/lib/env-proxy.js +193 -59
  26. package/dist/lib/prompt-catalog-terminal.js +32 -19
  27. package/dist/lib/prompt-web-ui.js +13 -2
  28. package/dist/lib/proxy-caddy.js +77 -9
  29. package/dist/lib/proxy-nginx.js +71 -11
  30. package/dist/locale/en-US.json +38 -38
  31. package/dist/locale/zh-CN.json +38 -38
  32. package/package.json +3 -2
@@ -12,9 +12,10 @@ import path from 'node:path';
12
12
  import { stdin as stdinStream, stdout as stdoutStream } from 'node:process';
13
13
  import { runPromptCatalog, } from "../../lib/prompt-catalog.js";
14
14
  import { applyCliLocale, CLI_LOCALE_FLAG_DESCRIPTION, CLI_LOCALE_FLAG_OPTIONS, localeText, resolveCliLocale, translateCli, } from "../../lib/cli-locale.js";
15
- import { DEFAULT_DOCKER_REGISTRY, DEFAULT_DOCKER_REGISTRY_ZH_CN, resolveDockerImageRef, } from "../../lib/docker-image.js";
15
+ import { DEFAULT_DOCKER_REGISTRY, DEFAULT_DOCKER_REGISTRY_ZH_CN, resolveOfficialDockerRegistry, resolveDockerImageRef, } from "../../lib/docker-image.js";
16
16
  import { getEnv } from '../../lib/auth-store.js';
17
17
  import { resolveDefaultConfigScope } from '../../lib/cli-home.js';
18
+ import { getCliConfigValue } from '../../lib/cli-config.js';
18
19
  import { buildBeforeDependencyInstallHookContext, runBeforeDependencyInstallHook, } from '../../lib/hook-script.js';
19
20
  import { run } from "../../lib/run-npm.js";
20
21
  import { printVerbose, setVerboseMode, startTask, stopTask, updateTask } from '../../lib/ui.js';
@@ -344,8 +345,8 @@ export default class SourceDownload extends Command {
344
345
  label: downloadText('prompts.dockerPlatform.autoLabel'),
345
346
  hint: downloadText('prompts.dockerPlatform.autoHint'),
346
347
  },
347
- { value: 'linux/amd64', label: 'linux/amd64' },
348
- { value: 'linux/arm64', label: 'linux/arm64' },
348
+ { value: 'linux/amd64', label: 'amd64' },
349
+ { value: 'linux/arm64', label: 'arm64' },
349
350
  ],
350
351
  initialValue: DEFAULT_DOCKER_PLATFORM,
351
352
  yesInitialValue: DEFAULT_DOCKER_PLATFORM,
@@ -450,9 +451,9 @@ export default class SourceDownload extends Command {
450
451
  }
451
452
  return outputAbs;
452
453
  }
453
- dockerTarPath(flags, outputAbs) {
454
+ async dockerTarPath(flags, outputAbs) {
454
455
  const imageRef = resolveDockerImageRef(flags['docker-registry'], flags.version, {
455
- defaultRegistry: defaultDockerRegistryForLang(process.env.NB_LOCALE),
456
+ defaultRegistry: await this.resolveConfiguredDockerRegistryDefault(),
456
457
  defaultVersion: 'latest',
457
458
  });
458
459
  const safeBase = imageRef.replace(/[\\/:]/g, '-');
@@ -462,9 +463,11 @@ export default class SourceDownload extends Command {
462
463
  * Defaults for prompts only. Keys present in **`preset`** are omitted so `runPromptCatalog` uses
463
464
  * **`values`** (preset) alone for those steps — no duplicate prefill for skipped prompts.
464
465
  */
465
- buildInitialValuesFromParsed(flags, preset) {
466
+ async resolveConfiguredDockerRegistryDefault() {
467
+ return resolveOfficialDockerRegistry(await getCliConfigValue('nb-image-registry'));
468
+ }
469
+ buildInitialValuesFromParsed(flags, preset, defaultDockerRegistry) {
466
470
  const initialValues = {};
467
- const localeDefaultDockerRegistry = defaultDockerRegistryForLang(flags.locale ?? process.env.NB_LOCALE);
468
471
  const source = flags.source?.trim();
469
472
  if (source) {
470
473
  initialValues.source = source;
@@ -488,7 +491,7 @@ export default class SourceDownload extends Command {
488
491
  initialValues.dockerRegistry = String(flags['docker-registry'] ?? '').trim();
489
492
  }
490
493
  else {
491
- initialValues.dockerRegistry = localeDefaultDockerRegistry;
494
+ initialValues.dockerRegistry = defaultDockerRegistry;
492
495
  }
493
496
  initialValues.dockerPlatform = normalizeDockerPlatform(flags['docker-platform']);
494
497
  initialValues.dockerSave = flags['docker-save'];
@@ -569,7 +572,7 @@ export default class SourceDownload extends Command {
569
572
  }
570
573
  return flags.build;
571
574
  }
572
- mapCatalogResultsToResolved(results, flags) {
575
+ mapCatalogResultsToResolved(results, flags, defaultDockerRegistry) {
573
576
  const source = String(results.source);
574
577
  const version = resolveVersionFromResults(results, flags.version) || 'latest';
575
578
  const devDependencies = source === 'npm' ? Boolean(results.devDependencies) : undefined;
@@ -583,7 +586,7 @@ export default class SourceDownload extends Command {
583
586
  const dockerRegistry = source === 'docker'
584
587
  ? results.dockerRegistry !== undefined
585
588
  ? String(results.dockerRegistry).trim() || undefined
586
- : flags['docker-registry']?.trim() || defaultDockerRegistryForLang(flags.locale ?? process.env.NB_LOCALE)
589
+ : flags['docker-registry']?.trim() || defaultDockerRegistry
587
590
  : undefined;
588
591
  const dockerPlatform = source === 'docker'
589
592
  ? normalizeDockerPlatform(results.dockerPlatform !== undefined ? results.dockerPlatform : flags['docker-platform'])
@@ -628,7 +631,8 @@ export default class SourceDownload extends Command {
628
631
  this.error('Download source is required in non-interactive mode. Use --source npm, --source git, or --source docker.');
629
632
  }
630
633
  const presetValues = this.buildPresetValuesFromFlags(flags);
631
- const initialValues = this.buildInitialValuesFromParsed(flags, presetValues);
634
+ const defaultDockerRegistry = await this.resolveConfiguredDockerRegistryDefault();
635
+ const initialValues = this.buildInitialValuesFromParsed(flags, presetValues, defaultDockerRegistry);
632
636
  const results = await runPromptCatalog(SourceDownload.prompts, {
633
637
  initialValues,
634
638
  values: presetValues,
@@ -654,7 +658,7 @@ export default class SourceDownload extends Command {
654
658
  if (flags['docker-save'] && source !== 'docker') {
655
659
  this.error('--docker-save is only available when --source docker is selected.');
656
660
  }
657
- return this.mapCatalogResultsToResolved(results, flags);
661
+ return this.mapCatalogResultsToResolved(results, flags, defaultDockerRegistry);
658
662
  }
659
663
  npmRegistryUrl(flags) {
660
664
  const url = flags['npm-registry']?.trim();
@@ -784,7 +788,7 @@ export default class SourceDownload extends Command {
784
788
  }
785
789
  async downloadFromDocker(flags) {
786
790
  const imageRef = resolveDockerImageRef(flags['docker-registry'], flags.version, {
787
- defaultRegistry: defaultDockerRegistryForLang(process.env.NB_LOCALE),
791
+ defaultRegistry: await this.resolveConfiguredDockerRegistryDefault(),
788
792
  defaultVersion: 'latest',
789
793
  });
790
794
  const platform = dockerPlatformArg(flags['docker-platform']);
@@ -811,7 +815,7 @@ export default class SourceDownload extends Command {
811
815
  await fsp.rm(outAbs, { recursive: true, force: true });
812
816
  }
813
817
  await fsp.mkdir(outAbs, { recursive: true });
814
- const tarPath = this.dockerTarPath(flags, outAbs);
818
+ const tarPath = await this.dockerTarPath(flags, outAbs);
815
819
  this.log(`Saving Docker image tarball to ${tarPath}`);
816
820
  await this.runExternalCommand('docker', ['save', '-o', tarPath, imageRef], {
817
821
  errorName: 'docker save',
@@ -14,7 +14,7 @@ import { dockerContainerExists, managedAppLifecycleEnvVars, runLocalNocoBaseComm
14
14
  import { deriveBuiltinDbConnection, resolveBuiltinDbConnection } from './builtin-db.js';
15
15
  import { resolveConfiguredStoragePath } from './env-paths.js';
16
16
  import { resolveDockerEnvFileArg } from "./docker-env-file.js";
17
- import { DEFAULT_DOCKER_REGISTRY, DEFAULT_DOCKER_VERSION, resolveDockerImageRef, } from "./docker-image.js";
17
+ import { DEFAULT_DOCKER_REGISTRY, DEFAULT_DOCKER_VERSION, resolveDockerImageContainerPort, resolveDockerImageRef, } from "./docker-image.js";
18
18
  import { resolveHookScriptPath } from './hook-script.js';
19
19
  import { commandSucceeds, ensureDockerDaemonRunning, run } from './run-npm.js';
20
20
  import Install from '../commands/install.js';
@@ -192,6 +192,7 @@ export async function buildSavedDockerRunArgs(runtime, options) {
192
192
  defaultRegistry: DEFAULT_DOCKER_REGISTRY,
193
193
  defaultVersion: DEFAULT_DOCKER_VERSION,
194
194
  });
195
+ const containerPort = resolveDockerImageContainerPort(imageRef);
195
196
  const missing = [];
196
197
  if (!storagePath) {
197
198
  missing.push('storagePath');
@@ -233,7 +234,7 @@ export async function buildSavedDockerRunArgs(runtime, options) {
233
234
  args.push('--platform', dockerPlatform);
234
235
  }
235
236
  if (appPort) {
236
- args.push('-p', `${appPort}:80`);
237
+ args.push('-p', `${appPort}:${containerPort}`);
237
238
  }
238
239
  if (envFile) {
239
240
  args.push('--env-file', envFile);
@@ -11,6 +11,7 @@ import path from 'node:path';
11
11
  import { resolveAppPublicPath } from './app-public-path.js';
12
12
  import { resolveCliHomeDir, resolveConfiguredEnvPath, resolveEnvRelativePath } from './cli-home.js';
13
13
  import { normalizeCliLocale } from './cli-locale.js';
14
+ import { normalizeEnvProxyConfig, normalizeEnvProxyProviderConfig, } from './env-proxy-config.js';
14
15
  import { inferConfiguredAppPathFromLegacyConfig, resolveConfiguredAppPath, resolveConfiguredSourcePath, resolveConfiguredStoragePath, } from './env-paths.js';
15
16
  import { ENV_CONFIG_SCHEMA_VERSION, normalizeEnvConfigSchemaVersion } from './env-config.js';
16
17
  import { cleanupCurrentSessionAfterEnvRemoval, resolveEffectiveCurrentEnv, setSessionCurrentEnv, } from './session-store.js';
@@ -81,12 +82,14 @@ function normalizeEnvConfigEntry(entry) {
81
82
  const normalizedKind = resolveEnvKind(entry);
82
83
  const apiBaseUrl = readEnvApiBaseUrl(entry);
83
84
  const schemaVersion = normalizeEnvConfigSchemaVersion(entry.schemaVersion);
85
+ const proxy = normalizeEnvProxyConfig(entry.proxy);
84
86
  return {
85
87
  ...rest,
86
88
  ...(schemaVersion ? { schemaVersion } : {}),
87
89
  ...(normalizedKind ? { kind: normalizedKind } : {}),
88
90
  ...(apiBaseUrl !== undefined ? { apiBaseUrl } : {}),
89
91
  ...(normalizeOptionalString(entry.appPublicPath) ? { appPublicPath: resolveAppPublicPath(entry.appPublicPath) } : {}),
92
+ ...(proxy ? { proxy } : {}),
90
93
  };
91
94
  }
92
95
  function normalizeAuthConfig(config) {
@@ -125,12 +128,19 @@ function normalizeAuthConfig(config) {
125
128
  ...(updatePolicy ? { update: { policy: updatePolicy } } : {}),
126
129
  ...(settings.license?.pkgUrl ? { license: { pkgUrl: normalizeOptionalString(settings.license.pkgUrl) } } : {}),
127
130
  ...(settings.docker?.network || settings.docker?.containerPrefix
131
+ || settings.docker?.nbImageRegistry || settings.docker?.nbImageVariant
128
132
  ? {
129
133
  docker: {
130
134
  ...(settings.docker?.network ? { network: normalizeOptionalString(settings.docker.network) } : {}),
131
135
  ...(settings.docker?.containerPrefix
132
136
  ? { containerPrefix: normalizeOptionalString(settings.docker.containerPrefix) }
133
137
  : {}),
138
+ ...(settings.docker?.nbImageRegistry
139
+ ? { nbImageRegistry: normalizeOptionalString(settings.docker.nbImageRegistry) }
140
+ : {}),
141
+ ...(settings.docker?.nbImageVariant
142
+ ? { nbImageVariant: normalizeOptionalString(settings.docker.nbImageVariant) }
143
+ : {}),
134
144
  },
135
145
  }
136
146
  : {}),
@@ -509,6 +519,64 @@ export async function setEnvRuntime(envName, runtime, options = {}) {
509
519
  };
510
520
  await saveAuthConfig(config, options);
511
521
  }
522
+ export function resolveEnvProxyEntry(config, provider) {
523
+ const proxy = normalizeEnvProxyConfig(config?.proxy);
524
+ const resolved = {
525
+ ...(proxy?.host ? { host: proxy.host } : {}),
526
+ ...(proxy?.port !== undefined ? { port: proxy.port } : {}),
527
+ ...((provider === 'nginx' ? proxy?.nginx : proxy?.caddy) ?? {}),
528
+ };
529
+ return Object.keys(resolved).length > 0 ? resolved : undefined;
530
+ }
531
+ export async function setEnvProxyEntry(envName, provider, entry, options = {}) {
532
+ await writeEnv(envName, (previous) => {
533
+ const currentProxy = normalizeEnvProxyConfig(previous?.proxy) ?? {};
534
+ const nextEntry = normalizeEnvProxyProviderConfig(entry);
535
+ const nextProxy = { ...currentProxy };
536
+ if (nextEntry && 'host' in nextEntry) {
537
+ const host = normalizeOptionalString(nextEntry.host);
538
+ if (host) {
539
+ nextProxy.host = host;
540
+ }
541
+ else {
542
+ delete nextProxy.host;
543
+ }
544
+ }
545
+ if (nextEntry && 'port' in nextEntry) {
546
+ const portValue = nextEntry.port;
547
+ const port = typeof portValue === 'number' && Number.isInteger(portValue) && portValue >= 1 && portValue <= 65535
548
+ ? portValue
549
+ : undefined;
550
+ if (port !== undefined) {
551
+ nextProxy.port = port;
552
+ }
553
+ else {
554
+ delete nextProxy.port;
555
+ }
556
+ }
557
+ const providerConfig = nextEntry && Object.keys(nextEntry).some((key) => key !== 'host' && key !== 'port')
558
+ ? Object.fromEntries(Object.entries(nextEntry).filter(([key]) => key !== 'host' && key !== 'port'))
559
+ : undefined;
560
+ if (provider === 'nginx') {
561
+ if (providerConfig && Object.keys(providerConfig).length > 0) {
562
+ nextProxy.nginx = providerConfig;
563
+ }
564
+ else {
565
+ delete nextProxy.nginx;
566
+ }
567
+ }
568
+ else if (providerConfig && Object.keys(providerConfig).length > 0) {
569
+ nextProxy.caddy = providerConfig;
570
+ }
571
+ else {
572
+ delete nextProxy.caddy;
573
+ }
574
+ return {
575
+ ...previous,
576
+ proxy: nextProxy,
577
+ };
578
+ }, options);
579
+ }
512
580
  export async function clearEnvRootSetup(envName, options = {}) {
513
581
  const config = await loadExactAuthConfig(options);
514
582
  const current = config.envs[envName];
@@ -9,6 +9,7 @@
9
9
  import { loadExactAuthConfig, saveAuthConfig } from './auth-store.js';
10
10
  import { resolveCliHomeRoot, resolveDefaultConfigScope } from './cli-home.js';
11
11
  import { CLI_LOCALE_FLAG_OPTIONS, normalizeCliLocale, resolveCliLocale } from './cli-locale.js';
12
+ import { DEFAULT_NB_IMAGE_REGISTRY, DEFAULT_NB_IMAGE_VARIANT, NB_IMAGE_REGISTRY_OPTIONS, NB_IMAGE_VARIANT_OPTIONS, normalizeNbImageRegistry, normalizeNbImageVariant, } from './docker-image.js';
12
13
  export const DEFAULT_LICENSE_PKG_URL = 'https://pkg.nocobase.com/';
13
14
  export const DEFAULT_DOCKER_NETWORK = 'nocobase';
14
15
  export const DEFAULT_DOCKER_CONTAINER_PREFIX = 'nb';
@@ -37,6 +38,8 @@ export const SUPPORTED_CLI_CONFIG_KEYS = [
37
38
  'license.pkg-url',
38
39
  'docker.network',
39
40
  'docker.container-prefix',
41
+ 'nb-image-registry',
42
+ 'nb-image-variant',
40
43
  'bin.docker',
41
44
  'bin.caddy',
42
45
  'bin.git',
@@ -129,7 +132,11 @@ function pruneSettings(config) {
129
132
  delete config.settings?.license;
130
133
  }
131
134
  const docker = config.settings?.docker;
132
- if (docker && !trimValue(docker.network) && !trimValue(docker.containerPrefix)) {
135
+ if (docker &&
136
+ !trimValue(docker.network) &&
137
+ !trimValue(docker.containerPrefix) &&
138
+ !trimValue(docker.nbImageRegistry) &&
139
+ !trimValue(docker.nbImageVariant)) {
133
140
  delete config.settings?.docker;
134
141
  }
135
142
  const bin = config.settings?.bin;
@@ -182,6 +189,10 @@ export function getExplicitCliConfigValue(config, key) {
182
189
  return trimValue(config.settings?.docker?.network);
183
190
  case 'docker.container-prefix':
184
191
  return trimValue(config.settings?.docker?.containerPrefix);
192
+ case 'nb-image-registry':
193
+ return normalizeNbImageRegistry(config.settings?.docker?.nbImageRegistry);
194
+ case 'nb-image-variant':
195
+ return normalizeNbImageVariant(config.settings?.docker?.nbImageVariant);
185
196
  case 'bin.docker':
186
197
  return trimValue(config.settings?.bin?.docker);
187
198
  case 'bin.caddy':
@@ -230,6 +241,12 @@ export function getEffectiveCliConfigValue(config, key) {
230
241
  return trimValue(config.name) || DEFAULT_DOCKER_NETWORK;
231
242
  case 'docker.container-prefix':
232
243
  return trimValue(config.name) || DEFAULT_DOCKER_CONTAINER_PREFIX;
244
+ case 'nb-image-registry':
245
+ return explicit ?? (resolveCliLocale(undefined, { configuredLocale: trimValue(config.settings?.locale) }) === 'zh-CN'
246
+ ? 'aliyun'
247
+ : DEFAULT_NB_IMAGE_REGISTRY);
248
+ case 'nb-image-variant':
249
+ return explicit ?? DEFAULT_NB_IMAGE_VARIANT;
233
250
  case 'bin.docker':
234
251
  return DEFAULT_DOCKER_BIN;
235
252
  case 'bin.caddy':
@@ -305,6 +322,20 @@ export function normalizeCliConfigValue(key, value) {
305
322
  }
306
323
  return driver;
307
324
  }
325
+ if (key === 'nb-image-registry') {
326
+ const registry = normalizeNbImageRegistry(normalized);
327
+ if (!registry) {
328
+ throw new Error(`Config key "${key}" must be one of: ${NB_IMAGE_REGISTRY_OPTIONS.join(', ')}`);
329
+ }
330
+ return registry;
331
+ }
332
+ if (key === 'nb-image-variant') {
333
+ const variant = normalizeNbImageVariant(normalized);
334
+ if (!variant) {
335
+ throw new Error(`Config key "${key}" must be one of: ${NB_IMAGE_VARIANT_OPTIONS.join(', ')}`);
336
+ }
337
+ return variant;
338
+ }
308
339
  return normalized;
309
340
  }
310
341
  export async function loadCliConfig(options = {}) {
@@ -370,6 +401,18 @@ export async function setCliConfigValue(key, value, options = {}) {
370
401
  containerPrefix: normalized,
371
402
  };
372
403
  break;
404
+ case 'nb-image-registry':
405
+ config.settings.docker = {
406
+ ...(config.settings.docker ?? {}),
407
+ nbImageRegistry: normalized,
408
+ };
409
+ break;
410
+ case 'nb-image-variant':
411
+ config.settings.docker = {
412
+ ...(config.settings.docker ?? {}),
413
+ nbImageVariant: normalized,
414
+ };
415
+ break;
373
416
  case 'bin.docker':
374
417
  config.settings.bin = {
375
418
  ...(config.settings.bin ?? {}),
@@ -489,6 +532,16 @@ export async function deleteCliConfigValue(key, options = {}) {
489
532
  delete config.settings.docker.containerPrefix;
490
533
  }
491
534
  break;
535
+ case 'nb-image-registry':
536
+ if (config.settings.docker) {
537
+ delete config.settings.docker.nbImageRegistry;
538
+ }
539
+ break;
540
+ case 'nb-image-variant':
541
+ if (config.settings.docker) {
542
+ delete config.settings.docker.nbImageVariant;
543
+ }
544
+ break;
492
545
  case 'bin.docker':
493
546
  if (config.settings.bin) {
494
547
  delete config.settings.bin.docker;
@@ -9,7 +9,30 @@
9
9
  export const DEFAULT_DOCKER_REGISTRY = 'nocobase/nocobase';
10
10
  export const DEFAULT_DOCKER_REGISTRY_ZH_CN = 'registry.cn-shanghai.aliyuncs.com/nocobase/nocobase';
11
11
  export const DEFAULT_DOCKER_VERSION = 'alpha';
12
+ export const NB_IMAGE_REGISTRY_OPTIONS = ['dockerhub', 'aliyun'];
13
+ export const DEFAULT_NB_IMAGE_REGISTRY = 'dockerhub';
14
+ export const NB_IMAGE_VARIANT_OPTIONS = ['standard', 'no-nginx', 'full', 'full-no-nginx'];
15
+ export const DEFAULT_NB_IMAGE_VARIANT = 'full';
12
16
  export const DOCKER_IMAGE_FULL_SUFFIX = '-full';
17
+ export const DOCKER_IMAGE_NO_NGINX_SUFFIX = '-no-nginx';
18
+ export const DOCKER_IMAGE_FULL_NO_NGINX_SUFFIX = '-full-no-nginx';
19
+ export const DEFAULT_KINGBASE_IMAGE = 'registry.cn-shanghai.aliyuncs.com/nocobase/kingbase:v009r001c001b0030_single_x86';
20
+ const OFFICIAL_DOCKER_REGISTRY_REPOSITORIES = {
21
+ dockerhub: DEFAULT_DOCKER_REGISTRY,
22
+ aliyun: DEFAULT_DOCKER_REGISTRY_ZH_CN,
23
+ };
24
+ const DEFAULT_BUILTIN_DB_IMAGES = {
25
+ postgres: 'postgres:16',
26
+ mysql: 'mysql:8',
27
+ mariadb: 'mariadb:11',
28
+ kingbase: DEFAULT_KINGBASE_IMAGE,
29
+ };
30
+ const ALIYUN_BUILTIN_DB_IMAGES = {
31
+ postgres: 'registry.cn-shanghai.aliyuncs.com/nocobase/postgres:16',
32
+ mysql: 'registry.cn-shanghai.aliyuncs.com/nocobase/mysql:8',
33
+ mariadb: 'registry.cn-shanghai.aliyuncs.com/nocobase/mariadb:11',
34
+ kingbase: DEFAULT_KINGBASE_IMAGE,
35
+ };
13
36
  const OFFICIAL_FULL_IMAGE_REGISTRIES = new Set([
14
37
  DEFAULT_DOCKER_REGISTRY,
15
38
  DEFAULT_DOCKER_REGISTRY_ZH_CN,
@@ -17,21 +40,86 @@ const OFFICIAL_FULL_IMAGE_REGISTRIES = new Set([
17
40
  function trimValue(value) {
18
41
  return String(value ?? '').trim();
19
42
  }
43
+ export function normalizeNbImageRegistry(value) {
44
+ const normalized = trimValue(value);
45
+ if (!normalized) {
46
+ return undefined;
47
+ }
48
+ return NB_IMAGE_REGISTRY_OPTIONS.includes(normalized)
49
+ ? normalized
50
+ : undefined;
51
+ }
52
+ export function normalizeNbImageVariant(value) {
53
+ const normalized = trimValue(value);
54
+ if (!normalized) {
55
+ return undefined;
56
+ }
57
+ return NB_IMAGE_VARIANT_OPTIONS.includes(normalized)
58
+ ? normalized
59
+ : undefined;
60
+ }
61
+ export function resolveOfficialDockerRegistry(value) {
62
+ const registry = normalizeNbImageRegistry(value) ?? DEFAULT_NB_IMAGE_REGISTRY;
63
+ return OFFICIAL_DOCKER_REGISTRY_REPOSITORIES[registry];
64
+ }
65
+ export function inferNbImageRegistryFromRepository(value) {
66
+ const repository = trimValue(value);
67
+ return Object.entries(OFFICIAL_DOCKER_REGISTRY_REPOSITORIES).find(([, candidate]) => candidate === repository)?.[0];
68
+ }
69
+ function hasKnownVariantSuffix(tag) {
70
+ return (tag.endsWith(DOCKER_IMAGE_FULL_NO_NGINX_SUFFIX) ||
71
+ tag.endsWith(DOCKER_IMAGE_NO_NGINX_SUFFIX) ||
72
+ tag.endsWith(DOCKER_IMAGE_FULL_SUFFIX));
73
+ }
20
74
  export function shouldUseFullDockerImageTag(registry) {
21
75
  return OFFICIAL_FULL_IMAGE_REGISTRIES.has(trimValue(registry));
22
76
  }
23
- export function normalizeDockerImageTag(registry, version) {
77
+ export function normalizeDockerImageTag(registry, version, options) {
24
78
  const tag = trimValue(version) || DEFAULT_DOCKER_VERSION;
25
- if (!shouldUseFullDockerImageTag(registry)) {
79
+ if (hasKnownVariantSuffix(tag)) {
26
80
  return tag;
27
81
  }
28
- return tag.endsWith(DOCKER_IMAGE_FULL_SUFFIX)
29
- ? tag
30
- : `${tag}${DOCKER_IMAGE_FULL_SUFFIX}`;
82
+ const explicitVariant = normalizeNbImageVariant(options?.variant) ?? normalizeNbImageVariant(options?.defaultVariant);
83
+ const inferredVariant = shouldUseFullDockerImageTag(registry) ? DEFAULT_NB_IMAGE_VARIANT : 'standard';
84
+ const variant = explicitVariant ?? inferredVariant;
85
+ switch (variant) {
86
+ case 'standard':
87
+ return tag;
88
+ case 'no-nginx':
89
+ return `${tag}${DOCKER_IMAGE_NO_NGINX_SUFFIX}`;
90
+ case 'full':
91
+ return `${tag}${DOCKER_IMAGE_FULL_SUFFIX}`;
92
+ case 'full-no-nginx':
93
+ return `${tag}${DOCKER_IMAGE_FULL_NO_NGINX_SUFFIX}`;
94
+ }
31
95
  }
32
96
  export function resolveDockerImageRef(registry, version, options) {
33
97
  const resolvedRegistry = trimValue(registry) || options?.defaultRegistry || DEFAULT_DOCKER_REGISTRY;
34
98
  const rawVersion = trimValue(version) || options?.defaultVersion || DEFAULT_DOCKER_VERSION;
35
- const normalizedTag = normalizeDockerImageTag(resolvedRegistry, rawVersion);
99
+ const normalizedTag = normalizeDockerImageTag(resolvedRegistry, rawVersion, {
100
+ variant: options?.variant,
101
+ defaultVariant: options?.defaultVariant,
102
+ });
36
103
  return `${resolvedRegistry}:${normalizedTag}`;
37
104
  }
105
+ function extractDockerImageTag(imageRef) {
106
+ const ref = trimValue(imageRef);
107
+ const lastSlashIndex = ref.lastIndexOf('/');
108
+ const lastColonIndex = ref.lastIndexOf(':');
109
+ if (lastColonIndex <= lastSlashIndex) {
110
+ return undefined;
111
+ }
112
+ return ref.slice(lastColonIndex + 1) || undefined;
113
+ }
114
+ export function resolveDockerImageContainerPort(imageRef) {
115
+ const tag = extractDockerImageTag(imageRef);
116
+ return tag?.endsWith(DOCKER_IMAGE_NO_NGINX_SUFFIX) ? '13000' : '80';
117
+ }
118
+ export function resolveBuiltinDbImage(dbDialect, options) {
119
+ const dialect = trimValue(dbDialect) || 'postgres';
120
+ const configuredRegistry = normalizeNbImageRegistry(options?.registry) ??
121
+ inferNbImageRegistryFromRepository(options?.registry) ??
122
+ DEFAULT_NB_IMAGE_REGISTRY;
123
+ const defaults = configuredRegistry === 'aliyun' ? ALIYUN_BUILTIN_DB_IMAGES : DEFAULT_BUILTIN_DB_IMAGES;
124
+ return defaults[dialect] ?? defaults.postgres;
125
+ }
@@ -6,6 +6,7 @@
6
6
  * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
7
7
  * For more information, please refer to: https://www.nocobase.com/agreement.
8
8
  */
9
+ import { normalizeEnvProxyConfig } from './env-proxy-config.js';
9
10
  import { resolveAppPublicPath } from './app-public-path.js';
10
11
  const STRING_ENV_CONFIG_KEYS = [
11
12
  'source',
@@ -110,5 +111,9 @@ export function buildStoredEnvConfig(input) {
110
111
  if ((authType === 'basic' || authType === 'token') && accessToken) {
111
112
  envConfig.accessToken = accessToken;
112
113
  }
114
+ const proxy = normalizeEnvProxyConfig(input.proxy);
115
+ if (proxy) {
116
+ envConfig.proxy = proxy;
117
+ }
113
118
  return envConfig;
114
119
  }
@@ -0,0 +1,48 @@
1
+ /**
2
+ * This file is part of the NocoBase (R) project.
3
+ * Copyright (c) 2020-2024 NocoBase Co., Ltd.
4
+ * Authors: NocoBase Team.
5
+ *
6
+ * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
7
+ * For more information, please refer to: https://www.nocobase.com/agreement.
8
+ */
9
+ function normalizeOptionalString(value) {
10
+ const normalized = String(value ?? '').trim();
11
+ return normalized || undefined;
12
+ }
13
+ function normalizeOptionalPort(value) {
14
+ const normalized = normalizeOptionalString(value);
15
+ if (!normalized || !/^\d+$/.test(normalized)) {
16
+ return undefined;
17
+ }
18
+ const port = Number(normalized);
19
+ if (!Number.isInteger(port) || port < 1 || port > 65535) {
20
+ return undefined;
21
+ }
22
+ return port;
23
+ }
24
+ export function normalizeEnvProxyProviderConfig(value) {
25
+ if (!value || typeof value !== 'object') {
26
+ return undefined;
27
+ }
28
+ return { ...value };
29
+ }
30
+ export function normalizeEnvProxyConfig(value) {
31
+ if (!value || typeof value !== 'object') {
32
+ return undefined;
33
+ }
34
+ const proxy = value;
35
+ const host = normalizeOptionalString(proxy.host);
36
+ const port = normalizeOptionalPort(proxy.port);
37
+ const nginx = normalizeEnvProxyProviderConfig(proxy.nginx);
38
+ const caddy = normalizeEnvProxyProviderConfig(proxy.caddy);
39
+ if (!host && port === undefined && !nginx && !caddy) {
40
+ return undefined;
41
+ }
42
+ return {
43
+ ...(host ? { host } : {}),
44
+ ...(port !== undefined ? { port } : {}),
45
+ ...(nginx ? { nginx } : {}),
46
+ ...(caddy ? { caddy } : {}),
47
+ };
48
+ }