@nocobase/cli 2.2.0-beta.1 → 2.2.0-beta.10

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 (53) hide show
  1. package/assets/env-proxy/nginx/snippets/proxy-location.conf +1 -0
  2. package/bin/early-locale.js +89 -0
  3. package/bin/node-version.js +35 -0
  4. package/bin/run.js +9 -0
  5. package/bin/windows-admin.js +60 -0
  6. package/dist/commands/app/destroy.js +4 -3
  7. package/dist/commands/app/restart.js +38 -0
  8. package/dist/commands/app/shared.js +49 -3
  9. package/dist/commands/app/start.js +95 -0
  10. package/dist/commands/app/upgrade.js +11 -0
  11. package/dist/commands/env/info.js +11 -1
  12. package/dist/commands/examples/prompts-stages.js +2 -2
  13. package/dist/commands/examples/prompts-test.js +2 -2
  14. package/dist/commands/init.js +33 -11
  15. package/dist/commands/install.js +159 -107
  16. package/dist/commands/license/activate.js +4 -1
  17. package/dist/commands/license/shared.js +24 -15
  18. package/dist/commands/proxy/caddy/generate.js +93 -7
  19. package/dist/commands/proxy/nginx/generate.js +98 -7
  20. package/dist/commands/revision/create.js +1 -1
  21. package/dist/commands/self/check.js +1 -1
  22. package/dist/commands/self/update.js +4 -4
  23. package/dist/commands/skills/check.js +4 -5
  24. package/dist/commands/skills/install.js +18 -1
  25. package/dist/commands/skills/update.js +19 -4
  26. package/dist/commands/source/dev.js +9 -5
  27. package/dist/commands/source/download.js +85 -16
  28. package/dist/lib/api-command-compat.js +51 -8
  29. package/dist/lib/app-managed-resources.js +104 -5
  30. package/dist/lib/auth-store.js +102 -12
  31. package/dist/lib/cli-config.js +73 -1
  32. package/dist/lib/docker-image.js +94 -6
  33. package/dist/lib/env-auth.js +291 -45
  34. package/dist/lib/env-config.js +11 -0
  35. package/dist/lib/env-proxy-config.js +48 -0
  36. package/dist/lib/env-proxy.js +164 -58
  37. package/dist/lib/hook-script.js +160 -0
  38. package/dist/lib/prompt-catalog-terminal.js +32 -19
  39. package/dist/lib/prompt-validators.js +1 -1
  40. package/dist/lib/prompt-web-ui.js +20 -13
  41. package/dist/lib/proxy-caddy.js +77 -9
  42. package/dist/lib/proxy-nginx.js +71 -11
  43. package/dist/lib/run-npm.js +4 -0
  44. package/dist/lib/self-manager.js +254 -46
  45. package/dist/lib/skills-manager.js +116 -23
  46. package/dist/lib/source-publish.js +2 -2
  47. package/dist/lib/startup-update.js +1 -1
  48. package/dist/locale/en-US.json +49 -43
  49. package/dist/locale/zh-CN.json +49 -43
  50. package/package.json +8 -2
  51. package/scripts/build.mjs +0 -34
  52. package/scripts/clean.mjs +0 -9
  53. package/tsconfig.json +0 -19
@@ -11,7 +11,9 @@ 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';
16
+ import { ENV_CONFIG_SCHEMA_VERSION, normalizeEnvConfigSchemaVersion } from './env-config.js';
15
17
  import { cleanupCurrentSessionAfterEnvRemoval, resolveEffectiveCurrentEnv, setSessionCurrentEnv, } from './session-store.js';
16
18
  function normalizeStoredEnvKind(value) {
17
19
  const kind = String(value ?? '').trim();
@@ -76,14 +78,18 @@ function normalizeEnvConfigEntry(entry) {
76
78
  if (!entry) {
77
79
  return entry;
78
80
  }
79
- const { kind: _kind, apiBaseUrl: _apiBaseUrl, baseUrl: _baseUrl, apibaseUrl: _legacyApiBaseUrl, ...rest } = entry;
81
+ const { kind: _kind, apiBaseUrl: _apiBaseUrl, baseUrl: _baseUrl, apibaseUrl: _legacyApiBaseUrl, schemaVersion: _schemaVersion, ...rest } = entry;
80
82
  const normalizedKind = resolveEnvKind(entry);
81
83
  const apiBaseUrl = readEnvApiBaseUrl(entry);
84
+ const schemaVersion = normalizeEnvConfigSchemaVersion(entry.schemaVersion);
85
+ const proxy = normalizeEnvProxyConfig(entry.proxy);
82
86
  return {
83
87
  ...rest,
88
+ ...(schemaVersion ? { schemaVersion } : {}),
84
89
  ...(normalizedKind ? { kind: normalizedKind } : {}),
85
90
  ...(apiBaseUrl !== undefined ? { apiBaseUrl } : {}),
86
91
  ...(normalizeOptionalString(entry.appPublicPath) ? { appPublicPath: resolveAppPublicPath(entry.appPublicPath) } : {}),
92
+ ...(proxy ? { proxy } : {}),
87
93
  };
88
94
  }
89
95
  function normalizeAuthConfig(config) {
@@ -96,6 +102,17 @@ function normalizeAuthConfig(config) {
96
102
  ? settings.log.retentionDays
97
103
  : undefined;
98
104
  const logEnabled = typeof settings.log?.enabled === 'boolean' ? settings.log.enabled : undefined;
105
+ const hasBinSettings = settings.bin?.docker ||
106
+ settings.bin?.caddy ||
107
+ settings.bin?.git ||
108
+ settings.bin?.nginx ||
109
+ settings.bin?.pnpm ||
110
+ settings.bin?.yarn;
111
+ const hasProxySettings = settings.proxy?.nbCliRoot ||
112
+ settings.proxy?.caddyDriver ||
113
+ settings.proxy?.nginxDriver ||
114
+ settings.proxy?.upstreamHost ||
115
+ settings.proxy?.host;
99
116
  return {
100
117
  name: config.name || config.dockerResourcePrefix,
101
118
  settings: {
@@ -111,31 +128,35 @@ function normalizeAuthConfig(config) {
111
128
  ...(updatePolicy ? { update: { policy: updatePolicy } } : {}),
112
129
  ...(settings.license?.pkgUrl ? { license: { pkgUrl: normalizeOptionalString(settings.license.pkgUrl) } } : {}),
113
130
  ...(settings.docker?.network || settings.docker?.containerPrefix
131
+ || settings.docker?.nbImageRegistry || settings.docker?.nbImageVariant
114
132
  ? {
115
133
  docker: {
116
134
  ...(settings.docker?.network ? { network: normalizeOptionalString(settings.docker.network) } : {}),
117
135
  ...(settings.docker?.containerPrefix
118
136
  ? { containerPrefix: normalizeOptionalString(settings.docker.containerPrefix) }
119
137
  : {}),
138
+ ...(settings.docker?.nbImageRegistry
139
+ ? { nbImageRegistry: normalizeOptionalString(settings.docker.nbImageRegistry) }
140
+ : {}),
141
+ ...(settings.docker?.nbImageVariant
142
+ ? { nbImageVariant: normalizeOptionalString(settings.docker.nbImageVariant) }
143
+ : {}),
120
144
  },
121
145
  }
122
146
  : {}),
123
- ...(settings.bin?.docker || settings.bin?.caddy || settings.bin?.git || settings.bin?.nginx || settings.bin?.yarn
147
+ ...(hasBinSettings
124
148
  ? {
125
149
  bin: {
126
150
  ...(settings.bin?.docker ? { docker: normalizeOptionalString(settings.bin.docker) } : {}),
127
151
  ...(settings.bin?.caddy ? { caddy: normalizeOptionalString(settings.bin.caddy) } : {}),
128
152
  ...(settings.bin?.git ? { git: normalizeOptionalString(settings.bin.git) } : {}),
129
153
  ...(settings.bin?.nginx ? { nginx: normalizeOptionalString(settings.bin.nginx) } : {}),
154
+ ...(settings.bin?.pnpm ? { pnpm: normalizeOptionalString(settings.bin.pnpm) } : {}),
130
155
  ...(settings.bin?.yarn ? { yarn: normalizeOptionalString(settings.bin.yarn) } : {}),
131
156
  },
132
157
  }
133
158
  : {}),
134
- ...(settings.proxy?.nbCliRoot ||
135
- settings.proxy?.caddyDriver ||
136
- settings.proxy?.nginxDriver ||
137
- settings.proxy?.upstreamHost ||
138
- settings.proxy?.host
159
+ ...(hasProxySettings
139
160
  ? {
140
161
  proxy: {
141
162
  ...(settings.proxy?.nbCliRoot ? { nbCliRoot: normalizeOptionalString(settings.proxy.nbCliRoot) } : {}),
@@ -366,7 +387,13 @@ function areAuthConfigsEquivalent(left, right) {
366
387
  async function writeEnv(envName, updater, options = {}) {
367
388
  const config = await loadExactAuthConfig(options);
368
389
  const previous = config.envs[envName];
369
- config.envs[envName] = updater(previous);
390
+ const next = updater(previous);
391
+ config.envs[envName] = {
392
+ ...next,
393
+ schemaVersion: normalizeEnvConfigSchemaVersion(next.schemaVersion) ??
394
+ normalizeEnvConfigSchemaVersion(previous?.schemaVersion) ??
395
+ ENV_CONFIG_SCHEMA_VERSION,
396
+ };
370
397
  await saveAuthConfig(config, options);
371
398
  }
372
399
  function normalizeConfiguredAuthType(value) {
@@ -377,18 +404,19 @@ export function resolveConfiguredAuthType(config) {
377
404
  }
378
405
  export async function upsertEnv(envName, config, options = {}) {
379
406
  await writeEnv(envName, (previous) => {
380
- const { apiBaseUrl: _apiBaseUrl, baseUrl: _baseUrl, apibaseUrl: _legacyApiBaseUrl, accessToken, authType, authUsername, ...rest } = config;
407
+ const { apiBaseUrl: _apiBaseUrl, baseUrl: _baseUrl, apibaseUrl: _legacyApiBaseUrl, accessToken, authType, authUsername, schemaVersion, ...rest } = config;
381
408
  const nextApiBaseUrl = readEnvApiBaseUrl(config);
382
409
  const previousApiBaseUrl = readEnvApiBaseUrl(previous);
383
410
  const baseUrlChanged = previousApiBaseUrl !== nextApiBaseUrl;
384
411
  const previousAuthType = resolveConfiguredAuthType(previous);
385
412
  const requestedAuthType = normalizeConfiguredAuthType(authType);
386
- const nextAuthType = requestedAuthType ?? (accessToken ? 'token' : previousAuthType);
413
+ const nextAccessToken = normalizeOptionalString(accessToken);
414
+ const nextAuthType = requestedAuthType ?? (nextAccessToken ? 'token' : previousAuthType);
387
415
  const nextAuthUsername = nextAuthType === 'basic' ? normalizeOptionalString(authUsername) ?? previous?.authUsername : undefined;
388
- const nextAuth = accessToken
416
+ const nextAuth = nextAccessToken
389
417
  ? {
390
418
  type: 'token',
391
- accessToken,
419
+ accessToken: nextAccessToken,
392
420
  }
393
421
  : nextAuthType === 'oauth' && !baseUrlChanged && previous?.auth?.type === 'oauth'
394
422
  ? previous.auth
@@ -396,6 +424,9 @@ export async function upsertEnv(envName, config, options = {}) {
396
424
  const authChanged = !areAuthConfigsEquivalent(previous?.auth, nextAuth);
397
425
  const authTypeChanged = previousAuthType !== nextAuthType;
398
426
  const authUsernameChanged = previous?.authUsername !== nextAuthUsername;
427
+ const nextSchemaVersion = normalizeEnvConfigSchemaVersion(schemaVersion) ??
428
+ normalizeEnvConfigSchemaVersion(previous?.schemaVersion) ??
429
+ ENV_CONFIG_SCHEMA_VERSION;
399
430
  return {
400
431
  ...previous,
401
432
  apiBaseUrl: nextApiBaseUrl,
@@ -403,6 +434,7 @@ export async function upsertEnv(envName, config, options = {}) {
403
434
  authUsername: nextAuthUsername,
404
435
  auth: nextAuth,
405
436
  ...rest,
437
+ schemaVersion: nextSchemaVersion,
406
438
  runtime: baseUrlChanged || authChanged || authTypeChanged || authUsernameChanged ? undefined : previous?.runtime,
407
439
  };
408
440
  }, options);
@@ -487,6 +519,64 @@ export async function setEnvRuntime(envName, runtime, options = {}) {
487
519
  };
488
520
  await saveAuthConfig(config, options);
489
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
+ }
490
580
  export async function clearEnvRootSetup(envName, options = {}) {
491
581
  const config = await loadExactAuthConfig(options);
492
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';
@@ -16,6 +17,7 @@ export const DEFAULT_DOCKER_BIN = 'docker';
16
17
  export const DEFAULT_CADDY_BIN = 'caddy';
17
18
  export const DEFAULT_GIT_BIN = 'git';
18
19
  export const DEFAULT_NGINX_BIN = 'nginx';
20
+ export const DEFAULT_PNPM_BIN = 'pnpm';
19
21
  export const PROXY_PROVIDER_OPTIONS = ['nginx', 'caddy'];
20
22
  export const DEFAULT_PROXY_PROVIDER = 'nginx';
21
23
  export const NGINX_PROXY_DRIVER_OPTIONS = ['local', 'docker'];
@@ -36,10 +38,13 @@ export const SUPPORTED_CLI_CONFIG_KEYS = [
36
38
  'license.pkg-url',
37
39
  'docker.network',
38
40
  'docker.container-prefix',
41
+ 'nb-image-registry',
42
+ 'nb-image-variant',
39
43
  'bin.docker',
40
44
  'bin.caddy',
41
45
  'bin.git',
42
46
  'bin.nginx',
47
+ 'bin.pnpm',
43
48
  'proxy.nb-cli-root',
44
49
  'proxy.caddy-driver',
45
50
  'proxy.nginx-driver',
@@ -127,7 +132,11 @@ function pruneSettings(config) {
127
132
  delete config.settings?.license;
128
133
  }
129
134
  const docker = config.settings?.docker;
130
- 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)) {
131
140
  delete config.settings?.docker;
132
141
  }
133
142
  const bin = config.settings?.bin;
@@ -136,6 +145,7 @@ function pruneSettings(config) {
136
145
  !trimValue(bin.caddy) &&
137
146
  !trimValue(bin.git) &&
138
147
  !trimValue(bin.nginx) &&
148
+ !trimValue(bin.pnpm) &&
139
149
  !trimValue(bin.yarn)) {
140
150
  delete config.settings?.bin;
141
151
  }
@@ -179,6 +189,10 @@ export function getExplicitCliConfigValue(config, key) {
179
189
  return trimValue(config.settings?.docker?.network);
180
190
  case 'docker.container-prefix':
181
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);
182
196
  case 'bin.docker':
183
197
  return trimValue(config.settings?.bin?.docker);
184
198
  case 'bin.caddy':
@@ -187,6 +201,8 @@ export function getExplicitCliConfigValue(config, key) {
187
201
  return trimValue(config.settings?.bin?.git);
188
202
  case 'bin.nginx':
189
203
  return trimValue(config.settings?.bin?.nginx);
204
+ case 'bin.pnpm':
205
+ return trimValue(config.settings?.bin?.pnpm);
190
206
  case 'proxy.nb-cli-root':
191
207
  return trimValue(config.settings?.proxy?.nbCliRoot);
192
208
  case 'proxy.caddy-driver':
@@ -225,6 +241,12 @@ export function getEffectiveCliConfigValue(config, key) {
225
241
  return trimValue(config.name) || DEFAULT_DOCKER_NETWORK;
226
242
  case 'docker.container-prefix':
227
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;
228
250
  case 'bin.docker':
229
251
  return DEFAULT_DOCKER_BIN;
230
252
  case 'bin.caddy':
@@ -233,6 +255,8 @@ export function getEffectiveCliConfigValue(config, key) {
233
255
  return DEFAULT_GIT_BIN;
234
256
  case 'bin.nginx':
235
257
  return DEFAULT_NGINX_BIN;
258
+ case 'bin.pnpm':
259
+ return DEFAULT_PNPM_BIN;
236
260
  case 'proxy.nb-cli-root':
237
261
  return explicit ?? resolveCliHomeRoot();
238
262
  case 'proxy.caddy-driver':
@@ -298,6 +322,20 @@ export function normalizeCliConfigValue(key, value) {
298
322
  }
299
323
  return driver;
300
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
+ }
301
339
  return normalized;
302
340
  }
303
341
  export async function loadCliConfig(options = {}) {
@@ -363,6 +401,18 @@ export async function setCliConfigValue(key, value, options = {}) {
363
401
  containerPrefix: normalized,
364
402
  };
365
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;
366
416
  case 'bin.docker':
367
417
  config.settings.bin = {
368
418
  ...(config.settings.bin ?? {}),
@@ -387,6 +437,12 @@ export async function setCliConfigValue(key, value, options = {}) {
387
437
  nginx: normalized,
388
438
  };
389
439
  break;
440
+ case 'bin.pnpm':
441
+ config.settings.bin = {
442
+ ...(config.settings.bin ?? {}),
443
+ pnpm: normalized,
444
+ };
445
+ break;
390
446
  case 'proxy.nb-cli-root':
391
447
  config.settings.proxy = {
392
448
  ...(config.settings.proxy ?? {}),
@@ -476,6 +532,16 @@ export async function deleteCliConfigValue(key, options = {}) {
476
532
  delete config.settings.docker.containerPrefix;
477
533
  }
478
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;
479
545
  case 'bin.docker':
480
546
  if (config.settings.bin) {
481
547
  delete config.settings.bin.docker;
@@ -496,6 +562,11 @@ export async function deleteCliConfigValue(key, options = {}) {
496
562
  delete config.settings.bin.nginx;
497
563
  }
498
564
  break;
565
+ case 'bin.pnpm':
566
+ if (config.settings.bin) {
567
+ delete config.settings.bin.pnpm;
568
+ }
569
+ break;
499
570
  case 'proxy.nb-cli-root':
500
571
  if (config.settings.proxy) {
501
572
  delete config.settings.proxy.nbCliRoot;
@@ -556,6 +627,7 @@ const CONFIGURABLE_COMMAND_KEYS = {
556
627
  caddy: 'bin.caddy',
557
628
  git: 'bin.git',
558
629
  nginx: 'bin.nginx',
630
+ pnpm: 'bin.pnpm',
559
631
  yarn: 'bin.yarn',
560
632
  };
561
633
  export function isConfigurableCommandName(value) {
@@ -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
+ }