@nocobase/cli 2.1.0-alpha.46 → 2.1.0-alpha.47

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +63 -380
  3. package/assets/env-proxy/nginx/app.conf.tpl +23 -0
  4. package/assets/env-proxy/nginx/nocobase.conf.tpl +5 -0
  5. package/assets/env-proxy/nginx/snippets/dist-location.conf +5 -0
  6. package/assets/env-proxy/nginx/snippets/gzip.conf +17 -0
  7. package/assets/env-proxy/nginx/snippets/log-format-http.conf +13 -0
  8. package/assets/env-proxy/nginx/snippets/maps-http.conf +14 -0
  9. package/assets/env-proxy/nginx/snippets/mime-types.conf +98 -0
  10. package/assets/env-proxy/nginx/snippets/proxy-location.conf +17 -0
  11. package/assets/env-proxy/nginx/snippets/spa-location.conf +6 -0
  12. package/assets/env-proxy/nginx/snippets/uploads-location.conf +21 -0
  13. package/bin/run.js +40 -3
  14. package/dist/commands/app/autostart/disable.js +55 -0
  15. package/dist/commands/app/autostart/enable.js +55 -0
  16. package/dist/commands/app/autostart/list.js +37 -0
  17. package/dist/commands/app/autostart/run.js +84 -0
  18. package/dist/commands/app/autostart/shared.js +49 -0
  19. package/dist/commands/app/destroy.js +21 -12
  20. package/dist/commands/app/down.js +2 -2
  21. package/dist/commands/app/logs.js +2 -1
  22. package/dist/commands/app/restart.js +89 -24
  23. package/dist/commands/app/shared.js +3 -2
  24. package/dist/commands/app/start.js +142 -38
  25. package/dist/commands/app/stop.js +31 -2
  26. package/dist/commands/app/upgrade.js +9 -5
  27. package/dist/commands/config/delete.js +6 -1
  28. package/dist/commands/config/get.js +6 -1
  29. package/dist/commands/config/set.js +7 -2
  30. package/dist/commands/env/add.js +24 -44
  31. package/dist/commands/env/info.js +3 -2
  32. package/dist/commands/env/proxy/caddy.js +28 -0
  33. package/dist/commands/env/proxy/index.js +353 -0
  34. package/dist/commands/env/proxy/nginx.js +28 -0
  35. package/dist/commands/env/remove.js +112 -22
  36. package/dist/commands/env/shared.js +17 -9
  37. package/dist/commands/env/update.js +385 -21
  38. package/dist/commands/init.js +350 -98
  39. package/dist/commands/install.js +218 -75
  40. package/dist/commands/license/activate.js +63 -244
  41. package/dist/commands/license/plugins/shared.js +64 -13
  42. package/dist/commands/plugin/import.js +108 -0
  43. package/dist/commands/revision/create.js +89 -0
  44. package/dist/commands/source/test.js +13 -14
  45. package/dist/lib/app-health.js +5 -5
  46. package/dist/lib/app-managed-resources.js +24 -8
  47. package/dist/lib/app-public-path.js +80 -0
  48. package/dist/lib/app-runtime.js +10 -1
  49. package/dist/lib/auth-store.js +119 -4
  50. package/dist/lib/cli-config.js +191 -3
  51. package/dist/lib/cli-entry-error.js +8 -0
  52. package/dist/lib/command-log.js +284 -0
  53. package/dist/lib/docker-env-file.js +10 -2
  54. package/dist/lib/env-auth.js +4 -1
  55. package/dist/lib/env-command-config.js +45 -0
  56. package/dist/lib/env-config.js +7 -2
  57. package/dist/lib/env-guard.js +9 -10
  58. package/dist/lib/env-paths.js +101 -0
  59. package/dist/lib/env-proxy.js +1295 -0
  60. package/dist/lib/inquirer.js +4 -5
  61. package/dist/lib/managed-env-file.js +98 -0
  62. package/dist/lib/plugin-import.js +279 -0
  63. package/dist/lib/prompt-catalog-core.js +3 -2
  64. package/dist/lib/prompt-validators.js +14 -0
  65. package/dist/lib/prompt-web-ui.js +8 -1
  66. package/dist/lib/run-npm.js +56 -12
  67. package/dist/lib/skills-manager.js +3 -1
  68. package/dist/lib/source-publish.js +18 -1
  69. package/dist/lib/ui.js +2 -1
  70. package/dist/locale/en-US.json +116 -22
  71. package/dist/locale/zh-CN.json +113 -19
  72. package/package.json +5 -7
  73. package/scripts/build.mjs +34 -0
  74. package/scripts/clean.mjs +9 -0
  75. package/tsconfig.json +19 -0
  76. package/LICENSE.txt +0 -107
  77. package/README.zh-CN.md +0 -355
@@ -0,0 +1,23 @@
1
+ # Rendered by `nb env proxy`.
2
+ # Context:
3
+ # publicBasePath={{publicBasePath}}
4
+ # apiBasePath={{apiBasePath}}
5
+ # wsPath={{wsPath}}
6
+ # v2PublicPath={{v2PublicPath}}
7
+ # backendUrl={{backendUrl}}
8
+ # snippetsDir={{snippetsDir}}
9
+ # uploadsDir={{uploadsDir}}
10
+ # distRootDir={{distRootDir}}
11
+ # entryDir={{entryDir}}
12
+ # publicDir={{publicDir}}
13
+
14
+ server {
15
+ listen 80;
16
+ server_name _;
17
+
18
+ # Add custom directives or locations above the managed block as needed.
19
+
20
+ {{managedConfigBlock}}
21
+
22
+ # Add custom directives or locations below the managed block as needed.
23
+ }
@@ -0,0 +1,5 @@
1
+ # Managed by `nb env proxy`. Changes will be overwritten.
2
+
3
+ include {{snippetsDir}}/log-format-http.conf;
4
+ include {{snippetsDir}}/maps-http.conf;
5
+ include {{appConfigIncludePath}};
@@ -0,0 +1,5 @@
1
+ expires 365d;
2
+ add_header Cache-Control "public" always;
3
+
4
+ access_log off;
5
+ autoindex off;
@@ -0,0 +1,17 @@
1
+ gzip on;
2
+ gzip_types
3
+ text/plain
4
+ text/css
5
+ text/xml
6
+ text/markdown
7
+ text/javascript
8
+ application/javascript
9
+ application/json
10
+ application/manifest+json
11
+ application/atom+xml
12
+ application/rss+xml
13
+ application/xml
14
+ application/xml+rss
15
+ application/xhtml+xml
16
+ application/wasm
17
+ image/svg+xml;
@@ -0,0 +1,13 @@
1
+ log_format apm '"$time_local" client=$remote_addr '
2
+ 'method=$request_method request="$request" '
3
+ 'request_length=$request_length '
4
+ 'status=$status bytes_sent=$bytes_sent '
5
+ 'body_bytes_sent=$body_bytes_sent '
6
+ 'referer=$http_referer '
7
+ 'user_agent="$http_user_agent" '
8
+ 'upstream_addr=$upstream_addr '
9
+ 'upstream_status=$upstream_status '
10
+ 'request_time=$request_time '
11
+ 'upstream_response_time=$upstream_response_time '
12
+ 'upstream_connect_time=$upstream_connect_time '
13
+ 'upstream_header_time=$upstream_header_time';
@@ -0,0 +1,14 @@
1
+ map $http_upgrade $connection_upgrade {
2
+ default upgrade;
3
+ "" close;
4
+ }
5
+
6
+ map $http_x_forwarded_proto $upstream_x_forwarded_proto {
7
+ default $http_x_forwarded_proto;
8
+ "" $scheme;
9
+ }
10
+
11
+ map $http_host $final_host {
12
+ default $http_host;
13
+ "" $host;
14
+ }
@@ -0,0 +1,98 @@
1
+ types {
2
+ text/html html htm shtml;
3
+ text/css css;
4
+ text/xml xml;
5
+ image/gif gif;
6
+ image/jpeg jpeg jpg;
7
+ application/javascript js mjs;
8
+ application/atom+xml atom;
9
+ application/rss+xml rss;
10
+
11
+ text/mathml mml;
12
+ text/plain txt;
13
+ text/vnd.sun.j2me.app-descriptor jad;
14
+ text/vnd.wap.wml wml;
15
+ text/x-component htc;
16
+
17
+ image/avif avif;
18
+ image/png png;
19
+ image/svg+xml svg svgz;
20
+ image/tiff tif tiff;
21
+ image/vnd.wap.wbmp wbmp;
22
+ image/webp webp;
23
+ image/x-icon ico;
24
+ image/x-jng jng;
25
+ image/x-ms-bmp bmp;
26
+
27
+ font/woff woff;
28
+ font/woff2 woff2;
29
+
30
+ application/java-archive jar war ear;
31
+ application/json json;
32
+ application/mac-binhex40 hqx;
33
+ application/msword doc;
34
+ application/pdf pdf;
35
+ application/postscript ps eps ai;
36
+ application/rtf rtf;
37
+ application/vnd.apple.mpegurl m3u8;
38
+ application/vnd.google-earth.kml+xml kml;
39
+ application/vnd.google-earth.kmz kmz;
40
+ application/vnd.ms-excel xls;
41
+ application/vnd.ms-fontobject eot;
42
+ application/vnd.ms-powerpoint ppt;
43
+ application/vnd.oasis.opendocument.graphics odg;
44
+ application/vnd.oasis.opendocument.presentation odp;
45
+ application/vnd.oasis.opendocument.spreadsheet ods;
46
+ application/vnd.oasis.opendocument.text odt;
47
+ application/vnd.openxmlformats-officedocument.presentationml.presentation
48
+ pptx;
49
+ application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
50
+ xlsx;
51
+ application/vnd.openxmlformats-officedocument.wordprocessingml.document
52
+ docx;
53
+ application/vnd.wap.wmlc wmlc;
54
+ application/wasm wasm;
55
+ application/x-7z-compressed 7z;
56
+ application/x-cocoa cco;
57
+ application/x-java-archive-diff jardiff;
58
+ application/x-java-jnlp-file jnlp;
59
+ application/x-makeself run;
60
+ application/x-perl pl pm;
61
+ application/x-pilot prc pdb;
62
+ application/x-rar-compressed rar;
63
+ application/x-redhat-package-manager rpm;
64
+ application/x-sea sea;
65
+ application/x-shockwave-flash swf;
66
+ application/x-stuffit sit;
67
+ application/x-tcl tcl tk;
68
+ application/x-x509-ca-cert der pem crt;
69
+ application/x-xpinstall xpi;
70
+ application/xhtml+xml xhtml;
71
+ application/xspf+xml xspf;
72
+ application/zip zip;
73
+
74
+ application/octet-stream bin exe dll;
75
+ application/octet-stream deb;
76
+ application/octet-stream dmg;
77
+ application/octet-stream iso img;
78
+ application/octet-stream msi msp msm;
79
+
80
+ audio/midi mid midi kar;
81
+ audio/mpeg mp3;
82
+ audio/ogg ogg;
83
+ audio/x-m4a m4a;
84
+ audio/x-realaudio ra;
85
+
86
+ video/3gpp 3gpp 3gp;
87
+ video/mp2t ts;
88
+ video/mp4 mp4;
89
+ video/mpeg mpeg mpg;
90
+ video/quicktime mov;
91
+ video/webm webm;
92
+ video/x-flv flv;
93
+ video/x-m4v m4v;
94
+ video/x-mng mng;
95
+ video/x-ms-asf asx asf;
96
+ video/x-ms-wmv wmv;
97
+ video/x-msvideo avi;
98
+ }
@@ -0,0 +1,17 @@
1
+ proxy_http_version 1.1;
2
+
3
+ proxy_set_header Upgrade $http_upgrade;
4
+ proxy_set_header Connection $connection_upgrade;
5
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
6
+ proxy_set_header X-Forwarded-Proto $upstream_x_forwarded_proto;
7
+ proxy_set_header Host $final_host;
8
+ proxy_set_header Referer $http_referer;
9
+ proxy_set_header User-Agent $http_user_agent;
10
+
11
+ add_header Cache-Control "no-cache, no-store" always;
12
+ proxy_cache_bypass $http_upgrade;
13
+
14
+ proxy_connect_timeout 600;
15
+ proxy_send_timeout 600;
16
+ proxy_read_timeout 600;
17
+ send_timeout 600;
@@ -0,0 +1,6 @@
1
+ add_header Cache-Control "no-store, no-cache, must-revalidate" always;
2
+ add_header X-Robots-Tag "noindex, nofollow" always;
3
+
4
+ if_modified_since off;
5
+ expires off;
6
+ etag off;
@@ -0,0 +1,21 @@
1
+ add_header Cache-Control "public" always;
2
+ add_header X-Content-Type-Options "nosniff" always;
3
+
4
+ access_log off;
5
+ autoindex off;
6
+
7
+ # Force potentially renderable uploaded files to download.
8
+ location ~* \.(?:htm|html|svg|svgz|xhtml)$ {
9
+ add_header Cache-Control "public" always;
10
+ add_header X-Content-Type-Options "nosniff" always;
11
+ add_header Content-Disposition "attachment" always;
12
+ }
13
+
14
+ # Let Markdown files render as plain Markdown text.
15
+ location ~* \.md$ {
16
+ default_type text/markdown;
17
+
18
+ add_header Cache-Control "public" always;
19
+ add_header X-Content-Type-Options "nosniff" always;
20
+ add_header Content-Disposition "inline" always;
21
+ }
package/bin/run.js CHANGED
@@ -66,6 +66,10 @@ if (isDev && !process.env._NOCO_CLI_TSX_CHILD) {
66
66
 
67
67
  const bootstrapPath = isDev ? path.join(root, 'src/lib/bootstrap.ts') : path.join(root, 'dist/lib/bootstrap.js');
68
68
  const { ensureRuntimeFromArgv } = await import(pathToFileURL(bootstrapPath).href);
69
+ const commandLogPath = isDev ? path.join(root, 'src/lib/command-log.ts') : path.join(root, 'dist/lib/command-log.js');
70
+ const { finalizeCommandLogSessionSync, initCommandLogSession, installCommandLogWriteHooks } = await import(
71
+ pathToFileURL(commandLogPath).href
72
+ );
69
73
  const startupUpdatePath = isDev
70
74
  ? path.join(root, 'src/lib/startup-update.ts')
71
75
  : path.join(root, 'dist/lib/startup-update.js');
@@ -73,15 +77,43 @@ const { maybeRunStartupUpdate } = await import(pathToFileURL(startupUpdatePath).
73
77
  const cliEntryErrorPath = isDev
74
78
  ? path.join(root, 'src/lib/cli-entry-error.ts')
75
79
  : path.join(root, 'dist/lib/cli-entry-error.js');
76
- const { formatCliEntryError } = await import(pathToFileURL(cliEntryErrorPath).href);
80
+ const { appendDiagnosticLogPath, formatCliEntryError } = await import(pathToFileURL(cliEntryErrorPath).href);
77
81
  const { flush, run, settings } = await import('@oclif/core');
78
82
 
79
83
  if (isDev) {
80
84
  settings.debug = true;
81
85
  }
82
86
 
87
+ const cliPackageJson = requireFromCli(path.join(root, 'package.json'));
88
+ const argv = process.argv.slice(2);
89
+ const commandLogSession = await initCommandLogSession({
90
+ argv,
91
+ cwd: process.cwd(),
92
+ sessionId: process.env.NB_SESSION_ID,
93
+ cliVersion: cliPackageJson?.version,
94
+ nodeVersion: process.version,
95
+ platform: process.platform,
96
+ interactive: Boolean(process.stdin.isTTY && process.stdout.isTTY),
97
+ verbose: argv.includes('--verbose'),
98
+ });
99
+ const restoreCommandLogHooks = installCommandLogWriteHooks();
100
+ let commandLogFinalized = false;
101
+
102
+ function finalizeCommandLogOnce(options = {}) {
103
+ if (commandLogFinalized) {
104
+ return;
105
+ }
106
+
107
+ commandLogFinalized = true;
108
+ restoreCommandLogHooks?.();
109
+ finalizeCommandLogSessionSync(commandLogSession, options);
110
+ }
111
+
112
+ process.once('exit', (code) => {
113
+ finalizeCommandLogOnce({ exitCode: code ?? undefined });
114
+ });
115
+
83
116
  try {
84
- const argv = process.argv.slice(2);
85
117
  const startupUpdate = await maybeRunStartupUpdate(argv);
86
118
  if (startupUpdate.kind === 'updated') {
87
119
  const result = spawnSync(process.execPath, process.argv.slice(1), {
@@ -100,8 +132,13 @@ try {
100
132
  }
101
133
  await run(argv, import.meta.url);
102
134
  flush();
135
+ finalizeCommandLogOnce({ exitCode: 0 });
103
136
  } catch (error) {
104
- const message = formatCliEntryError(error, process.argv.slice(2));
137
+ const message = appendDiagnosticLogPath(
138
+ formatCliEntryError(error, process.argv.slice(2)),
139
+ commandLogSession?.logFile,
140
+ );
105
141
  console.error(pc.red(message));
142
+ finalizeCommandLogOnce({ exitCode: 1, errorMessage: message });
106
143
  process.exit(1);
107
144
  }
@@ -0,0 +1,55 @@
1
+ /**
2
+ * This file is part of the NocoBase (R) project.
3
+ * Copyright (c) 2020-2024 NocoBase Co., Ltd.
4
+ * Authors: NocoBase Team.
5
+ *
6
+ * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
7
+ * For more information, please refer to: https://www.nocobase.com/agreement.
8
+ */
9
+ import { Command, Flags } from '@oclif/core';
10
+ import { ensureCrossEnvConfirmed, hasExplicitEnvSelection } from '../../../lib/env-guard.js';
11
+ import { getEnv } from '../../../lib/auth-store.js';
12
+ import { formatMissingManagedAppEnvMessage } from '../../../lib/app-runtime.js';
13
+ import { announceTargetEnv } from '../../../lib/ui.js';
14
+ import { updateAutostartSetting } from './shared.js';
15
+ export default class AppAutostartDisable extends Command {
16
+ static description = 'Disable app autostart for the selected env.';
17
+ static examples = [
18
+ '<%= config.bin %> <%= command.id %>',
19
+ '<%= config.bin %> <%= command.id %> --env app1',
20
+ '<%= config.bin %> <%= command.id %> --env app1 --yes',
21
+ ];
22
+ static flags = {
23
+ env: Flags.string({
24
+ char: 'e',
25
+ description: 'CLI env name to remove from app autostart. Defaults to the current env when omitted',
26
+ }),
27
+ yes: Flags.boolean({
28
+ char: 'y',
29
+ description: 'Confirm using --env when it targets a different env than the current env',
30
+ default: false,
31
+ }),
32
+ };
33
+ async run() {
34
+ const { flags } = await this.parse(AppAutostartDisable);
35
+ const requestedEnv = flags.env?.trim() || undefined;
36
+ if (requestedEnv && hasExplicitEnvSelection(this.argv)) {
37
+ const confirmed = await ensureCrossEnvConfirmed({
38
+ command: this,
39
+ requestedEnv,
40
+ yes: flags.yes,
41
+ });
42
+ if (!confirmed) {
43
+ return;
44
+ }
45
+ }
46
+ const env = await getEnv(requestedEnv);
47
+ if (!env?.name) {
48
+ this.error(formatMissingManagedAppEnvMessage(requestedEnv));
49
+ }
50
+ const envName = env.name;
51
+ await updateAutostartSetting(envName, false);
52
+ announceTargetEnv(envName);
53
+ this.log(`Disabled app autostart for "${envName}".`);
54
+ }
55
+ }
@@ -0,0 +1,55 @@
1
+ /**
2
+ * This file is part of the NocoBase (R) project.
3
+ * Copyright (c) 2020-2024 NocoBase Co., Ltd.
4
+ * Authors: NocoBase Team.
5
+ *
6
+ * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
7
+ * For more information, please refer to: https://www.nocobase.com/agreement.
8
+ */
9
+ import { Command, Flags } from '@oclif/core';
10
+ import { ensureCrossEnvConfirmed, hasExplicitEnvSelection } from '../../../lib/env-guard.js';
11
+ import { getEnv } from '../../../lib/auth-store.js';
12
+ import { formatMissingManagedAppEnvMessage } from '../../../lib/app-runtime.js';
13
+ import { announceTargetEnv } from '../../../lib/ui.js';
14
+ import { updateAutostartSetting } from './shared.js';
15
+ export default class AppAutostartEnable extends Command {
16
+ static description = 'Enable app autostart for the selected local or Docker env.';
17
+ static examples = [
18
+ '<%= config.bin %> <%= command.id %>',
19
+ '<%= config.bin %> <%= command.id %> --env app1',
20
+ '<%= config.bin %> <%= command.id %> --env app1 --yes',
21
+ ];
22
+ static flags = {
23
+ env: Flags.string({
24
+ char: 'e',
25
+ description: 'CLI env name to add to app autostart. Defaults to the current env when omitted',
26
+ }),
27
+ yes: Flags.boolean({
28
+ char: 'y',
29
+ description: 'Confirm using --env when it targets a different env than the current env',
30
+ default: false,
31
+ }),
32
+ };
33
+ async run() {
34
+ const { flags } = await this.parse(AppAutostartEnable);
35
+ const requestedEnv = flags.env?.trim() || undefined;
36
+ if (requestedEnv && hasExplicitEnvSelection(this.argv)) {
37
+ const confirmed = await ensureCrossEnvConfirmed({
38
+ command: this,
39
+ requestedEnv,
40
+ yes: flags.yes,
41
+ });
42
+ if (!confirmed) {
43
+ return;
44
+ }
45
+ }
46
+ const env = await getEnv(requestedEnv);
47
+ if (!env?.name) {
48
+ this.error(formatMissingManagedAppEnvMessage(requestedEnv));
49
+ }
50
+ const envName = env.name;
51
+ await updateAutostartSetting(envName, true);
52
+ announceTargetEnv(envName);
53
+ this.log(`Enabled app autostart for "${envName}".`);
54
+ }
55
+ }
@@ -0,0 +1,37 @@
1
+ /**
2
+ * This file is part of the NocoBase (R) project.
3
+ * Copyright (c) 2020-2024 NocoBase Co., Ltd.
4
+ * Authors: NocoBase Team.
5
+ *
6
+ * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
7
+ * For more information, please refer to: https://www.nocobase.com/agreement.
8
+ */
9
+ import { Command } from '@oclif/core';
10
+ import { getCurrentEnvName, listEnvs } from '../../../lib/auth-store.js';
11
+ import { renderTable } from '../../../lib/ui.js';
12
+ import { isAutostartEnabled } from './shared.js';
13
+ export default class AppAutostartList extends Command {
14
+ static description = 'List app autostart status for configured envs.';
15
+ static examples = ['<%= config.bin %> <%= command.id %>'];
16
+ async run() {
17
+ await this.parse(AppAutostartList);
18
+ const { envs } = await listEnvs();
19
+ const currentEnv = await getCurrentEnvName();
20
+ const names = Object.keys(envs).sort();
21
+ if (!names.length) {
22
+ this.log('No environments are configured.');
23
+ return;
24
+ }
25
+ const rows = names.map((name) => {
26
+ const env = envs[name];
27
+ return [
28
+ name === currentEnv ? '*' : '',
29
+ name,
30
+ env.kind ?? '-',
31
+ env.source ? String(env.source) : '-',
32
+ isAutostartEnabled(env) ? 'yes' : 'no',
33
+ ];
34
+ });
35
+ this.log(renderTable(['Current', 'Env', 'Kind', 'Source', 'Autostart'], rows));
36
+ }
37
+ }
@@ -0,0 +1,84 @@
1
+ /**
2
+ * This file is part of the NocoBase (R) project.
3
+ * Copyright (c) 2020-2024 NocoBase Co., Ltd.
4
+ * Authors: NocoBase Team.
5
+ *
6
+ * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
7
+ * For more information, please refer to: https://www.nocobase.com/agreement.
8
+ */
9
+ import { Command, Flags } from '@oclif/core';
10
+ import { listEnvs } from '../../../lib/auth-store.js';
11
+ import { resolveManagedAppRuntime } from '../../../lib/app-runtime.js';
12
+ import { renderTable } from '../../../lib/ui.js';
13
+ import { ensureManagedAutostartRuntime, isAutostartEnabled } from './shared.js';
14
+ function formatSummary(results) {
15
+ return renderTable(['Env', 'Status', 'Detail'], results.map((result) => [result.env, result.status, result.detail]));
16
+ }
17
+ export default class AppAutostartRun extends Command {
18
+ static description = 'Start every env that has app autostart enabled.';
19
+ static examples = ['<%= config.bin %> <%= command.id %>', '<%= config.bin %> <%= command.id %> --verbose'];
20
+ static flags = {
21
+ verbose: Flags.boolean({
22
+ description: 'Show raw startup output from the underlying local or Docker command',
23
+ default: false,
24
+ }),
25
+ };
26
+ async run() {
27
+ const { flags } = await this.parse(AppAutostartRun);
28
+ const { envs } = await listEnvs();
29
+ const enabledNames = Object.keys(envs)
30
+ .filter((name) => isAutostartEnabled(envs[name]))
31
+ .sort((left, right) => left.localeCompare(right));
32
+ if (!enabledNames.length) {
33
+ this.log('No environments have app autostart enabled.');
34
+ return;
35
+ }
36
+ const results = [];
37
+ for (const envName of enabledNames) {
38
+ const env = envs[envName];
39
+ try {
40
+ ensureManagedAutostartRuntime({ ...env, name: envName });
41
+ }
42
+ catch (error) {
43
+ results.push({
44
+ env: envName,
45
+ status: 'skipped',
46
+ detail: error instanceof Error ? error.message : String(error),
47
+ });
48
+ continue;
49
+ }
50
+ const runtime = await resolveManagedAppRuntime(envName);
51
+ if (!runtime) {
52
+ results.push({
53
+ env: envName,
54
+ status: 'failed',
55
+ detail: 'Env configuration could not be resolved.',
56
+ });
57
+ continue;
58
+ }
59
+ try {
60
+ const argv = ['--env', envName, '--yes'];
61
+ if (flags.verbose) {
62
+ argv.push('--verbose');
63
+ }
64
+ await this.config.runCommand('app:start', argv);
65
+ results.push({
66
+ env: envName,
67
+ status: 'started',
68
+ detail: `Started ${runtime.kind} app runtime.`,
69
+ });
70
+ }
71
+ catch (error) {
72
+ results.push({
73
+ env: envName,
74
+ status: 'failed',
75
+ detail: error instanceof Error ? error.message : String(error),
76
+ });
77
+ }
78
+ }
79
+ this.log(formatSummary(results));
80
+ if (results.some((result) => result.status === 'failed')) {
81
+ this.error('Some app autostart envs failed to start.');
82
+ }
83
+ }
84
+ }
@@ -0,0 +1,49 @@
1
+ /**
2
+ * This file is part of the NocoBase (R) project.
3
+ * Copyright (c) 2020-2024 NocoBase Co., Ltd.
4
+ * Authors: NocoBase Team.
5
+ *
6
+ * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
7
+ * For more information, please refer to: https://www.nocobase.com/agreement.
8
+ */
9
+ import { loadExactAuthConfig, saveAuthConfig } from '../../../lib/auth-store.js';
10
+ export function isAutostartEnabled(config) {
11
+ return config?.autostart?.enabled === true;
12
+ }
13
+ export function ensureManagedAutostartRuntime(config) {
14
+ const kind = String(config.kind ?? '').trim();
15
+ const source = String(config.source ?? '').trim();
16
+ const inferredLocal = source === 'npm' || source === 'git' || source === 'local';
17
+ if (kind === 'local' || kind === 'docker' || (!kind && (source === 'docker' || inferredLocal))) {
18
+ return;
19
+ }
20
+ const envName = String(config.name ?? '').trim() || 'unknown';
21
+ throw new Error([
22
+ `Env "${envName}" cannot be added to app autostart.`,
23
+ 'Only local and Docker envs with CLI-managed app runtimes can be started automatically on this machine.',
24
+ ].join('\n'));
25
+ }
26
+ export async function updateAutostartSetting(envName, enabled) {
27
+ const config = await loadExactAuthConfig();
28
+ const previous = config.envs[envName];
29
+ if (!previous) {
30
+ throw new Error(`Env "${envName}" is not configured`);
31
+ }
32
+ ensureManagedAutostartRuntime({ ...previous, name: envName });
33
+ const next = { ...previous };
34
+ const wasEnabled = isAutostartEnabled(previous);
35
+ if (enabled) {
36
+ next.autostart = { enabled: true };
37
+ }
38
+ else {
39
+ delete next.autostart;
40
+ }
41
+ config.envs[envName] = next;
42
+ if (wasEnabled !== enabled) {
43
+ await saveAuthConfig(config);
44
+ }
45
+ return {
46
+ config,
47
+ changed: wasEnabled !== enabled,
48
+ };
49
+ }