@nocobase/cli 2.2.0-beta.8 → 2.2.0-test.15

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 (56) 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 +24 -0
  11. package/dist/commands/app/start.js +25 -2
  12. package/dist/commands/config/set.js +1 -0
  13. package/dist/commands/env/info.js +11 -1
  14. package/dist/commands/init.js +131 -4
  15. package/dist/commands/install.js +179 -131
  16. package/dist/commands/portal/create.js +105 -0
  17. package/dist/commands/portal/deploy.js +81 -0
  18. package/dist/commands/portal/destroy.js +104 -0
  19. package/dist/commands/portal/dev.js +71 -0
  20. package/dist/commands/portal/index.js +20 -0
  21. package/dist/commands/portal/info.js +82 -0
  22. package/dist/commands/portal/list.js +98 -0
  23. package/dist/commands/portal/pull.js +77 -0
  24. package/dist/commands/portal/push.js +79 -0
  25. package/dist/commands/proxy/caddy/generate.js +93 -7
  26. package/dist/commands/proxy/nginx/generate.js +98 -7
  27. package/dist/commands/revision/create.js +1 -1
  28. package/dist/commands/source/dev.js +1 -1
  29. package/dist/commands/source/download.js +18 -14
  30. package/dist/lib/app-managed-resources.js +3 -2
  31. package/dist/lib/auth-store.js +71 -1
  32. package/dist/lib/cli-config.js +74 -2
  33. package/dist/lib/docker-image.js +94 -6
  34. package/dist/lib/env-config.js +8 -0
  35. package/dist/lib/env-proxy-config.js +48 -0
  36. package/dist/lib/env-proxy.js +266 -61
  37. package/dist/lib/managed-init-env.js +6 -1
  38. package/dist/lib/portal-command-env.js +31 -0
  39. package/dist/lib/portal-create.js +488 -0
  40. package/dist/lib/portal-deploy.js +275 -0
  41. package/dist/lib/portal-destroy.js +100 -0
  42. package/dist/lib/portal-dev.js +79 -0
  43. package/dist/lib/portal-env-files.js +53 -0
  44. package/dist/lib/portal-info.js +31 -0
  45. package/dist/lib/portal-list.js +197 -0
  46. package/dist/lib/portal-source.js +416 -0
  47. package/dist/lib/portal-template.js +190 -0
  48. package/dist/lib/prompt-catalog-terminal.js +32 -19
  49. package/dist/lib/prompt-web-ui.js +13 -2
  50. package/dist/lib/proxy-caddy.js +77 -9
  51. package/dist/lib/proxy-nginx.js +71 -11
  52. package/dist/lib/run-npm.js +17 -16
  53. package/dist/lib/ui.js +28 -1
  54. package/dist/locale/en-US.json +192 -38
  55. package/dist/locale/zh-CN.json +192 -38
  56. package/package.json +6 -3
@@ -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';
@@ -33,10 +34,13 @@ export const SUPPORTED_CLI_CONFIG_KEYS = [
33
34
  'locale',
34
35
  'default-ui-host',
35
36
  'default-api-host',
37
+ 'default-portal-template',
36
38
  'update.policy',
37
39
  'license.pkg-url',
38
40
  'docker.network',
39
41
  'docker.container-prefix',
42
+ 'nb-image-registry',
43
+ 'nb-image-variant',
40
44
  'bin.docker',
41
45
  'bin.caddy',
42
46
  'bin.git',
@@ -117,7 +121,10 @@ function pruneSettings(config) {
117
121
  delete config.settings.locale;
118
122
  }
119
123
  const init = config.settings?.init;
120
- if (init && !trimValue(init.defaultUiHost) && !trimValue(init.defaultApiHost)) {
124
+ if (init &&
125
+ !trimValue(init.defaultUiHost) &&
126
+ !trimValue(init.defaultApiHost) &&
127
+ !trimValue(init.defaultPortalTemplate)) {
121
128
  delete config.settings?.init;
122
129
  }
123
130
  const update = config.settings?.update;
@@ -129,7 +136,11 @@ function pruneSettings(config) {
129
136
  delete config.settings?.license;
130
137
  }
131
138
  const docker = config.settings?.docker;
132
- if (docker && !trimValue(docker.network) && !trimValue(docker.containerPrefix)) {
139
+ if (docker &&
140
+ !trimValue(docker.network) &&
141
+ !trimValue(docker.containerPrefix) &&
142
+ !trimValue(docker.nbImageRegistry) &&
143
+ !trimValue(docker.nbImageVariant)) {
133
144
  delete config.settings?.docker;
134
145
  }
135
146
  const bin = config.settings?.bin;
@@ -174,6 +185,8 @@ export function getExplicitCliConfigValue(config, key) {
174
185
  return trimValue(config.settings?.init?.defaultUiHost);
175
186
  case 'default-api-host':
176
187
  return trimValue(config.settings?.init?.defaultApiHost);
188
+ case 'default-portal-template':
189
+ return trimValue(config.settings?.init?.defaultPortalTemplate);
177
190
  case 'update.policy':
178
191
  return normalizeCliUpdatePolicy(config.settings?.update?.policy);
179
192
  case 'license.pkg-url':
@@ -182,6 +195,10 @@ export function getExplicitCliConfigValue(config, key) {
182
195
  return trimValue(config.settings?.docker?.network);
183
196
  case 'docker.container-prefix':
184
197
  return trimValue(config.settings?.docker?.containerPrefix);
198
+ case 'nb-image-registry':
199
+ return normalizeNbImageRegistry(config.settings?.docker?.nbImageRegistry);
200
+ case 'nb-image-variant':
201
+ return normalizeNbImageVariant(config.settings?.docker?.nbImageVariant);
185
202
  case 'bin.docker':
186
203
  return trimValue(config.settings?.bin?.docker);
187
204
  case 'bin.caddy':
@@ -222,6 +239,8 @@ export function getEffectiveCliConfigValue(config, key) {
222
239
  return '127.0.0.1';
223
240
  case 'default-api-host':
224
241
  return '127.0.0.1';
242
+ case 'default-portal-template':
243
+ return explicit ?? '';
225
244
  case 'update.policy':
226
245
  return explicit ?? DEFAULT_UPDATE_POLICY;
227
246
  case 'license.pkg-url':
@@ -230,6 +249,12 @@ export function getEffectiveCliConfigValue(config, key) {
230
249
  return trimValue(config.name) || DEFAULT_DOCKER_NETWORK;
231
250
  case 'docker.container-prefix':
232
251
  return trimValue(config.name) || DEFAULT_DOCKER_CONTAINER_PREFIX;
252
+ case 'nb-image-registry':
253
+ return explicit ?? (resolveCliLocale(undefined, { configuredLocale: trimValue(config.settings?.locale) }) === 'zh-CN'
254
+ ? 'aliyun'
255
+ : DEFAULT_NB_IMAGE_REGISTRY);
256
+ case 'nb-image-variant':
257
+ return explicit ?? DEFAULT_NB_IMAGE_VARIANT;
233
258
  case 'bin.docker':
234
259
  return DEFAULT_DOCKER_BIN;
235
260
  case 'bin.caddy':
@@ -305,6 +330,20 @@ export function normalizeCliConfigValue(key, value) {
305
330
  }
306
331
  return driver;
307
332
  }
333
+ if (key === 'nb-image-registry') {
334
+ const registry = normalizeNbImageRegistry(normalized);
335
+ if (!registry) {
336
+ throw new Error(`Config key "${key}" must be one of: ${NB_IMAGE_REGISTRY_OPTIONS.join(', ')}`);
337
+ }
338
+ return registry;
339
+ }
340
+ if (key === 'nb-image-variant') {
341
+ const variant = normalizeNbImageVariant(normalized);
342
+ if (!variant) {
343
+ throw new Error(`Config key "${key}" must be one of: ${NB_IMAGE_VARIANT_OPTIONS.join(', ')}`);
344
+ }
345
+ return variant;
346
+ }
308
347
  return normalized;
309
348
  }
310
349
  export async function loadCliConfig(options = {}) {
@@ -346,6 +385,12 @@ export async function setCliConfigValue(key, value, options = {}) {
346
385
  defaultApiHost: normalized,
347
386
  };
348
387
  break;
388
+ case 'default-portal-template':
389
+ config.settings.init = {
390
+ ...(config.settings.init ?? {}),
391
+ defaultPortalTemplate: normalized,
392
+ };
393
+ break;
349
394
  case 'update.policy':
350
395
  config.settings.update = {
351
396
  ...(config.settings.update ?? {}),
@@ -370,6 +415,18 @@ export async function setCliConfigValue(key, value, options = {}) {
370
415
  containerPrefix: normalized,
371
416
  };
372
417
  break;
418
+ case 'nb-image-registry':
419
+ config.settings.docker = {
420
+ ...(config.settings.docker ?? {}),
421
+ nbImageRegistry: normalized,
422
+ };
423
+ break;
424
+ case 'nb-image-variant':
425
+ config.settings.docker = {
426
+ ...(config.settings.docker ?? {}),
427
+ nbImageVariant: normalized,
428
+ };
429
+ break;
373
430
  case 'bin.docker':
374
431
  config.settings.bin = {
375
432
  ...(config.settings.bin ?? {}),
@@ -469,6 +526,11 @@ export async function deleteCliConfigValue(key, options = {}) {
469
526
  delete config.settings.init.defaultApiHost;
470
527
  }
471
528
  break;
529
+ case 'default-portal-template':
530
+ if (config.settings.init) {
531
+ delete config.settings.init.defaultPortalTemplate;
532
+ }
533
+ break;
472
534
  case 'update.policy':
473
535
  if (config.settings.update) {
474
536
  delete config.settings.update.policy;
@@ -489,6 +551,16 @@ export async function deleteCliConfigValue(key, options = {}) {
489
551
  delete config.settings.docker.containerPrefix;
490
552
  }
491
553
  break;
554
+ case 'nb-image-registry':
555
+ if (config.settings.docker) {
556
+ delete config.settings.docker.nbImageRegistry;
557
+ }
558
+ break;
559
+ case 'nb-image-variant':
560
+ if (config.settings.docker) {
561
+ delete config.settings.docker.nbImageVariant;
562
+ }
563
+ break;
492
564
  case 'bin.docker':
493
565
  if (config.settings.bin) {
494
566
  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',
@@ -35,6 +36,9 @@ const STRING_ENV_CONFIG_KEYS = [
35
36
  'dbSchema',
36
37
  'dbTablePrefix',
37
38
  'lang',
39
+ 'developmentMode',
40
+ 'portalName',
41
+ 'portalTemplate',
38
42
  'rootUsername',
39
43
  'rootEmail',
40
44
  'rootPassword',
@@ -110,5 +114,9 @@ export function buildStoredEnvConfig(input) {
110
114
  if ((authType === 'basic' || authType === 'token') && accessToken) {
111
115
  envConfig.accessToken = accessToken;
112
116
  }
117
+ const proxy = normalizeEnvProxyConfig(input.proxy);
118
+ if (proxy) {
119
+ envConfig.proxy = proxy;
120
+ }
113
121
  return envConfig;
114
122
  }
@@ -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
+ }