@nocobase/cli 2.1.0-beta.45 → 2.1.0-beta.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 (35) hide show
  1. package/dist/commands/app/destroy.js +3 -3
  2. package/dist/commands/app/stop.js +4 -11
  3. package/dist/commands/proxy/caddy/current.js +17 -0
  4. package/dist/commands/proxy/caddy/generate.js +69 -0
  5. package/dist/commands/proxy/caddy/index.js +28 -0
  6. package/dist/commands/proxy/caddy/info.js +31 -0
  7. package/dist/commands/proxy/caddy/reload.js +28 -0
  8. package/dist/commands/proxy/caddy/restart.js +28 -0
  9. package/dist/commands/proxy/caddy/start.js +30 -0
  10. package/dist/commands/proxy/caddy/status.js +19 -0
  11. package/dist/commands/proxy/caddy/stop.js +30 -0
  12. package/dist/commands/proxy/caddy/use.js +26 -0
  13. package/dist/commands/proxy/index.js +28 -0
  14. package/dist/commands/proxy/nginx/current.js +18 -0
  15. package/dist/commands/proxy/nginx/generate.js +68 -0
  16. package/dist/commands/proxy/nginx/index.js +28 -0
  17. package/dist/commands/proxy/nginx/info.js +34 -0
  18. package/dist/commands/proxy/nginx/reload.js +28 -0
  19. package/dist/commands/proxy/nginx/restart.js +28 -0
  20. package/dist/commands/proxy/nginx/start.js +30 -0
  21. package/dist/commands/proxy/nginx/status.js +19 -0
  22. package/dist/commands/proxy/nginx/stop.js +30 -0
  23. package/dist/commands/proxy/nginx/use.js +31 -0
  24. package/dist/commands/revision/create.js +31 -2
  25. package/dist/lib/auth-store.js +8 -0
  26. package/dist/lib/cli-config.js +73 -1
  27. package/dist/lib/env-proxy.js +105 -75
  28. package/dist/lib/proxy-caddy.js +274 -0
  29. package/dist/lib/proxy-nginx.js +330 -0
  30. package/dist/locale/en-US.json +2 -2
  31. package/dist/locale/zh-CN.json +2 -2
  32. package/package.json +2 -2
  33. package/dist/commands/env/proxy/caddy.js +0 -28
  34. package/dist/commands/env/proxy/index.js +0 -353
  35. package/dist/commands/env/proxy/nginx.js +0 -28
@@ -1,353 +0,0 @@
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 { mkdir, readFile, writeFile } from 'node:fs/promises';
10
- import path from 'node:path';
11
- import { Args, Command, Flags, loadHelpClass } from '@oclif/core';
12
- import { formatMissingManagedAppEnvMessage, resolveManagedAppRuntime, } from '../../../lib/app-runtime.js';
13
- import { resolveDefaultConfigScope } from '../../../lib/cli-home.js';
14
- import { translateCli } from '../../../lib/cli-locale.js';
15
- import { applyEnvProxyAppEntryOptions, appConfigIncludesGeneratedConfig, appConfigHasManagedGeneratedConfigBlock, appConfigHasManagedNginxBlock, buildManagedAppEntryGeneratedConfigBlock, buildEnvProxyCaddyBundle, buildEnvProxyNginxBundle, extractManagedNginxConfigBlock, installEnvProxyProvider, reloadEnvProxyProvider, replaceManagedAppEntryGeneratedConfigBlock, replaceManagedNginxConfigBlock, syncEnvProxyNginxSnippets, } from '../../../lib/env-proxy.js';
16
- import { announceTargetEnv, failTask, startTask, succeedTask } from '../../../lib/ui.js';
17
- async function readOptionalTextFile(filePath) {
18
- try {
19
- return await readFile(filePath, 'utf8');
20
- }
21
- catch (error) {
22
- const code = error && typeof error === 'object' && 'code' in error ? error.code : undefined;
23
- if (code === 'ENOENT') {
24
- return undefined;
25
- }
26
- throw error;
27
- }
28
- }
29
- function buildEditableAppEntryReferenceLine(provider, generatedConfigPath) {
30
- if (provider === 'caddy') {
31
- return `import ./${path.basename(generatedConfigPath)}`;
32
- }
33
- return `include ${generatedConfigPath};`;
34
- }
35
- function replaceEditableAppEntryReferenceWithManagedBlock(content, provider, currentGeneratedConfigPath, nextGeneratedConfigPath) {
36
- const currentReferenceLine = buildEditableAppEntryReferenceLine(provider, currentGeneratedConfigPath);
37
- const nextBlock = buildManagedAppEntryGeneratedConfigBlock(provider, nextGeneratedConfigPath);
38
- const escapedComment = provider === 'caddy'
39
- ? '# Keep this import so `nb env proxy` can refresh managed routes.'
40
- : '# Keep this include so `nb env proxy` can refresh managed routes.';
41
- const escapedCommentPattern = escapedComment.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
42
- const escapedLinePattern = currentReferenceLine.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
43
- const legacyBlockPattern = new RegExp(`[ \\t]*${escapedCommentPattern}\\n[ \\t]*${escapedLinePattern.replace(/;$/, ';?')}`, 'm');
44
- if (legacyBlockPattern.test(content)) {
45
- return content.replace(legacyBlockPattern, nextBlock);
46
- }
47
- return content.replace(currentReferenceLine, nextBlock);
48
- }
49
- function normalizeProxyListenPort(value) {
50
- const normalized = value?.trim() || undefined;
51
- if (!normalized || !/^\d+$/.test(normalized)) {
52
- return undefined;
53
- }
54
- const port = Number(normalized);
55
- if (!Number.isInteger(port) || port < 1 || port > 65535) {
56
- return undefined;
57
- }
58
- return normalized;
59
- }
60
- function buildNginxManagedBlockMissingMessage(appConfigPath) {
61
- return translateCli('commands.envProxy.errors.nginxAppEntryMissingManagedBlock', {
62
- appConfigPath,
63
- }, {
64
- fallback: `The editable nginx app entry config at ${appConfigPath} does not contain the NocoBase managed block. ` +
65
- 'Restore the managed block or delete the file and rerun `nb env proxy`.',
66
- });
67
- }
68
- async function writeNginxProxyBundle(runtime, appEntryOptions, options) {
69
- const bundle = await buildEnvProxyNginxBundle(runtime, { scope: options?.scope });
70
- const managedConfigBlock = extractManagedNginxConfigBlock(bundle.appConfigContent);
71
- if (!managedConfigBlock) {
72
- throw new Error('Failed to render the managed nginx config block.');
73
- }
74
- const currentAppConfigContent = await readOptionalTextFile(bundle.appConfigPath);
75
- let nextAppConfigContent = applyEnvProxyAppEntryOptions(bundle.appConfigContent, 'nginx', appEntryOptions);
76
- let status = 'created';
77
- if (currentAppConfigContent) {
78
- if (!appConfigHasManagedNginxBlock(currentAppConfigContent)) {
79
- throw new Error(buildNginxManagedBlockMissingMessage(bundle.appConfigPath));
80
- }
81
- nextAppConfigContent = applyEnvProxyAppEntryOptions(replaceManagedNginxConfigBlock(currentAppConfigContent, managedConfigBlock), 'nginx', appEntryOptions);
82
- status = 'updated';
83
- }
84
- await Promise.all([mkdir(bundle.entryDir, { recursive: true }), mkdir(bundle.publicDir, { recursive: true })]);
85
- await Promise.all([
86
- writeFile(bundle.appConfigPath, nextAppConfigContent, 'utf8'),
87
- writeFile(bundle.indexV1Path, bundle.indexV1Content, 'utf8'),
88
- writeFile(bundle.indexV2Path, bundle.indexV2Content, 'utf8'),
89
- writeFile(bundle.mainConfigPath, bundle.mainConfigContent, 'utf8'),
90
- syncEnvProxyNginxSnippets({ scope: options?.scope }),
91
- ]);
92
- return {
93
- bundle,
94
- status,
95
- };
96
- }
97
- async function writeCaddyProxyBundle(runtime, appEntryOptions, options) {
98
- const bundle = await buildEnvProxyCaddyBundle(runtime, { scope: options?.scope });
99
- const currentAppConfigContent = await readOptionalTextFile(bundle.appConfigPath);
100
- let nextAppConfigContent = applyEnvProxyAppEntryOptions(bundle.appConfigContent, 'caddy', appEntryOptions);
101
- let status = 'created';
102
- if (currentAppConfigContent) {
103
- if (appConfigHasManagedGeneratedConfigBlock(currentAppConfigContent)) {
104
- nextAppConfigContent = applyEnvProxyAppEntryOptions(replaceManagedAppEntryGeneratedConfigBlock(currentAppConfigContent, 'caddy', bundle.generatedConfigPath), 'caddy', appEntryOptions);
105
- status = 'updated';
106
- }
107
- else if (appConfigIncludesGeneratedConfig(currentAppConfigContent, bundle.generatedConfigPath, 'caddy')) {
108
- nextAppConfigContent = applyEnvProxyAppEntryOptions(replaceEditableAppEntryReferenceWithManagedBlock(currentAppConfigContent, 'caddy', bundle.generatedConfigPath, bundle.generatedConfigPath), 'caddy', appEntryOptions);
109
- status = 'migrated';
110
- }
111
- else {
112
- throw new Error(translateCli('commands.envProxy.errors.appEntryMissingInclude', {
113
- envName: runtime.envName,
114
- appConfigPath: bundle.appConfigPath,
115
- generatedConfigPath: bundle.generatedConfigPath,
116
- }, {
117
- fallback: `The editable app entry config at ${bundle.appConfigPath} does not reference ${bundle.generatedConfigPath}. ` +
118
- 'Add the managed generated-config reference back into the editable app entry and rerun the command.',
119
- }));
120
- }
121
- }
122
- await Promise.all([mkdir(bundle.entryDir, { recursive: true }), mkdir(bundle.publicDir, { recursive: true })]);
123
- await Promise.all([
124
- writeFile(bundle.appConfigPath, nextAppConfigContent, 'utf8'),
125
- writeFile(bundle.generatedConfigPath, bundle.generatedConfigContent, 'utf8'),
126
- writeFile(bundle.indexV1Path, bundle.indexV1Content, 'utf8'),
127
- writeFile(bundle.indexV2Path, bundle.indexV2Content, 'utf8'),
128
- writeFile(bundle.mainConfigPath, bundle.mainConfigContent, 'utf8'),
129
- ]);
130
- return {
131
- bundle,
132
- status,
133
- };
134
- }
135
- export const ENV_PROXY_NAME_ARG = Args.string({
136
- description: 'Configured environment name to generate a proxy config for. Defaults to the current env when omitted',
137
- required: false,
138
- });
139
- function createEnvProxySharedFlags() {
140
- return {
141
- env: Flags.string({
142
- char: 'e',
143
- description: 'Configured environment name to generate a proxy config for. Defaults to the current env when omitted',
144
- }),
145
- host: Flags.string({
146
- description: 'Host exposed by the proxy entry config, such as example.com or localhost',
147
- }),
148
- port: Flags.string({
149
- description: 'Port exposed by the proxy entry config, not the upstream NocoBase app port',
150
- }),
151
- install: Flags.boolean({
152
- description: 'Install the rendered provider config into the provider main config when supported',
153
- default: false,
154
- }),
155
- reload: Flags.boolean({
156
- description: 'Validate and reload the provider after writing the proxy config',
157
- default: false,
158
- }),
159
- print: Flags.boolean({
160
- description: 'Print the rendered config to stdout instead of writing files',
161
- default: false,
162
- }),
163
- };
164
- }
165
- export function createEnvProxyNginxFlags() {
166
- return {
167
- ...createEnvProxySharedFlags(),
168
- };
169
- }
170
- export function createEnvProxyCaddyFlags() {
171
- return {
172
- ...createEnvProxySharedFlags(),
173
- output: Flags.string({
174
- char: 'o',
175
- description: 'Output file path for providers that emit a single generated config file',
176
- }),
177
- };
178
- }
179
- function resolveRequestedEnv(command, args, flags) {
180
- const envNameArg = args.name?.trim() || undefined;
181
- const envNameFlag = flags.env?.trim() || undefined;
182
- if (envNameArg && envNameFlag && envNameArg !== envNameFlag) {
183
- command.error(`Environment name was provided both as the argument ("${envNameArg}") and as --env ("${envNameFlag}"). Please use only one.`);
184
- }
185
- return envNameArg || envNameFlag;
186
- }
187
- function resolveAppEntryOptions(command, flags) {
188
- const requestedHost = flags.host?.trim() || undefined;
189
- const requestedPort = flags.port?.trim() || undefined;
190
- if (requestedPort && !normalizeProxyListenPort(requestedPort)) {
191
- command.error(translateCli('commands.envProxy.errors.invalidProxyPort', { port: requestedPort }, {
192
- fallback: `Invalid proxy entry port "${requestedPort}". Use an integer between 1 and 65535.`,
193
- }));
194
- }
195
- return {
196
- host: requestedHost,
197
- port: normalizeProxyListenPort(requestedPort),
198
- };
199
- }
200
- export async function runEnvProxyCommand(command, args, flags, provider) {
201
- const scope = resolveDefaultConfigScope();
202
- const requestedEnv = resolveRequestedEnv(command, args, flags);
203
- if (flags.print && (flags.install || flags.reload)) {
204
- command.error('`--print` cannot be combined with `--install` or `--reload`.');
205
- }
206
- if (flags.output && (flags.install || flags.reload)) {
207
- command.error('`--output` cannot be combined with `--install` or `--reload` in the current implementation.');
208
- }
209
- const appEntryOptions = resolveAppEntryOptions(command, flags);
210
- const runtime = await resolveManagedAppRuntime(requestedEnv);
211
- if (!runtime) {
212
- command.error(formatMissingManagedAppEnvMessage(requestedEnv));
213
- }
214
- if (runtime.kind === 'http') {
215
- command.error(translateCli('commands.envProxy.errors.httpEnvUnsupported', { envName: runtime.envName }, {
216
- fallback: `Can't generate a proxy config for "${runtime.envName}" from this machine because the env only has an API connection.`,
217
- }));
218
- }
219
- if (runtime.kind === 'ssh') {
220
- command.error(translateCli('commands.envProxy.errors.sshEnvUnsupported', { envName: runtime.envName }, {
221
- fallback: `Can't generate a proxy config for "${runtime.envName}" yet because SSH envs are not implemented.`,
222
- }));
223
- }
224
- announceTargetEnv(runtime.envName);
225
- if (flags.output) {
226
- command.error(translateCli(provider === 'nginx'
227
- ? 'commands.envProxy.errors.nginxOutputUnsupported'
228
- : 'commands.envProxy.errors.caddyOutputUnsupported', {
229
- envName: runtime.envName,
230
- }, {
231
- fallback: provider === 'nginx'
232
- ? 'The nginx provider does not support `--output`. It writes `app.conf`, `public/index-v1.html`, `public/index-v2.html`, and `nocobase.conf` into `~/.nocobase/proxy/nginx/<env>/`.'
233
- : 'The caddy provider does not support `--output`. It writes `app.caddy`, `generated.caddy`, `public/index-v1.html`, `public/index-v2.html`, and `nocobase.caddy` into `~/.nocobase/proxy/caddy/<env>/`.',
234
- }));
235
- }
236
- startTask(translateCli('commands.envProxy.messages.generating', { envName: runtime.envName }, {
237
- fallback: `Generating proxy config for env "${runtime.envName}"...`,
238
- }));
239
- const generationFailureMessage = translateCli('commands.envProxy.messages.failed', { envName: runtime.envName }, {
240
- fallback: `Failed to generate proxy config for env "${runtime.envName}".`,
241
- });
242
- const installStartMessage = translateCli('commands.envProxy.messages.installingProvider', { provider }, {
243
- fallback: `Installing the shared proxy config into ${provider}...`,
244
- });
245
- const installFailureMessage = translateCli('commands.envProxy.messages.installProviderFailed', { provider }, {
246
- fallback: `Failed to install the shared proxy config into ${provider}.`,
247
- });
248
- const reloadStartMessage = translateCli('commands.envProxy.messages.reloadingProvider', { provider }, {
249
- fallback: `Validating and reloading ${provider}...`,
250
- });
251
- const reloadFailureMessage = translateCli('commands.envProxy.messages.reloadProviderFailed', { provider }, {
252
- fallback: `Failed to validate and reload ${provider}.`,
253
- });
254
- try {
255
- if (flags.print) {
256
- if (provider === 'nginx') {
257
- const bundle = await buildEnvProxyNginxBundle(runtime, { scope });
258
- process.stdout.write(applyEnvProxyAppEntryOptions(bundle.appConfigContent, provider, appEntryOptions));
259
- }
260
- else {
261
- const bundle = await buildEnvProxyCaddyBundle(runtime, { scope });
262
- process.stdout.write(applyEnvProxyAppEntryOptions(bundle.appConfigContent, provider, appEntryOptions));
263
- }
264
- succeedTask(translateCli('commands.envProxy.messages.printed', { envName: runtime.envName }, {
265
- fallback: `Printed proxy config for env "${runtime.envName}".`,
266
- }));
267
- return;
268
- }
269
- if (provider === 'nginx') {
270
- const { bundle, status } = await writeNginxProxyBundle(runtime, appEntryOptions, { scope });
271
- succeedTask(translateCli(status === 'created'
272
- ? 'commands.envProxy.messages.savedNginxBundleCreated'
273
- : 'commands.envProxy.messages.savedNginxBundleUpdated', {
274
- envName: runtime.envName,
275
- appConfigPath: bundle.appConfigPath,
276
- entryDir: bundle.entryDir,
277
- }, {
278
- fallback: status === 'created'
279
- ? `Saved nginx proxy files for env "${runtime.envName}" under ${bundle.entryDir}, and created editable app entry config at ${bundle.appConfigPath}.`
280
- : `Saved nginx proxy files for env "${runtime.envName}" under ${bundle.entryDir}, and refreshed editable app entry config at ${bundle.appConfigPath}.`,
281
- }));
282
- }
283
- else {
284
- const { bundle, status } = await writeCaddyProxyBundle(runtime, appEntryOptions, { scope });
285
- succeedTask(translateCli(status === 'created'
286
- ? 'commands.envProxy.messages.savedCaddyBundleCreated'
287
- : status === 'migrated'
288
- ? 'commands.envProxy.messages.savedCaddyBundleMigrated'
289
- : 'commands.envProxy.messages.savedCaddyBundleUpdated', { envName: runtime.envName, entryDir: bundle.entryDir, appConfigPath: bundle.appConfigPath }, {
290
- fallback: status === 'created'
291
- ? `Saved caddy proxy files for env "${runtime.envName}" under ${bundle.entryDir}, and created editable app entry config at ${bundle.appConfigPath}.`
292
- : status === 'migrated'
293
- ? `Saved caddy proxy files for env "${runtime.envName}" under ${bundle.entryDir}, and migrated the app entry config at ${bundle.appConfigPath}.`
294
- : `Saved caddy proxy files for env "${runtime.envName}" under ${bundle.entryDir}, and refreshed editable app entry config at ${bundle.appConfigPath}.`,
295
- }));
296
- }
297
- }
298
- catch (error) {
299
- failTask(generationFailureMessage);
300
- command.error(error instanceof Error ? error.message : String(error));
301
- }
302
- if (flags.install) {
303
- startTask(installStartMessage);
304
- try {
305
- const installResult = await installEnvProxyProvider(provider, { scope });
306
- succeedTask(installResult.status === 'already-installed'
307
- ? translateCli('commands.envProxy.messages.providerAlreadyInstalled', { provider, configPath: installResult.configPath }, {
308
- fallback: `The shared proxy config is already installed in the ${provider} main config at ${installResult.configPath}.`,
309
- })
310
- : translateCli('commands.envProxy.messages.providerInstalled', { provider, configPath: installResult.configPath }, {
311
- fallback: `Installed the shared proxy config into the ${provider} main config at ${installResult.configPath}.`,
312
- }));
313
- }
314
- catch (error) {
315
- failTask(installFailureMessage);
316
- command.error(error instanceof Error ? error.message : String(error));
317
- }
318
- }
319
- if (flags.reload) {
320
- startTask(reloadStartMessage);
321
- try {
322
- await reloadEnvProxyProvider(provider, { scope });
323
- succeedTask(translateCli('commands.envProxy.messages.providerReloaded', { provider }, {
324
- fallback: `Validated and reloaded ${provider}.`,
325
- }));
326
- }
327
- catch (error) {
328
- failTask(reloadFailureMessage);
329
- command.error(error instanceof Error ? error.message : String(error));
330
- }
331
- }
332
- }
333
- export default class EnvProxy extends Command {
334
- static summary = 'Generate proxy configs for one managed env through provider subcommands';
335
- static description = 'Use `nb env proxy nginx` or `nb env proxy caddy` to generate provider-specific proxy files.';
336
- static examples = [
337
- '<%= config.bin %> env proxy nginx',
338
- '<%= config.bin %> env proxy nginx --env app1',
339
- '<%= config.bin %> env proxy nginx --env app1 --install --reload',
340
- '<%= config.bin %> env proxy caddy',
341
- '<%= config.bin %> env proxy caddy --env app1',
342
- '<%= config.bin %> env proxy caddy --env app1 --install --reload',
343
- '<%= config.bin %> env proxy caddy --env app1 --print',
344
- ];
345
- async run() {
346
- await this.parse(EnvProxy);
347
- const Help = await loadHelpClass(this.config);
348
- await new Help(this.config, this.config.pjson.oclif.helpOptions ?? this.config.pjson.helpOptions).showHelp([
349
- this.id ?? 'env proxy',
350
- ...this.argv,
351
- ]);
352
- }
353
- }
@@ -1,28 +0,0 @@
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 { createEnvProxyNginxFlags, ENV_PROXY_NAME_ARG, runEnvProxyCommand } from './index.js';
11
- export default class EnvProxyNginx extends Command {
12
- static summary = 'Generate nginx proxy files for one managed env';
13
- static examples = [
14
- '<%= config.bin %> <%= command.id %>',
15
- '<%= config.bin %> <%= command.id %> --env app1',
16
- '<%= config.bin %> <%= command.id %> --env app1 --host a.local.nocobase.com --port 8080',
17
- '<%= config.bin %> <%= command.id %> --env app1 --install --reload',
18
- '<%= config.bin %> <%= command.id %> --env app1 --print',
19
- ];
20
- static args = {
21
- name: ENV_PROXY_NAME_ARG,
22
- };
23
- static flags = createEnvProxyNginxFlags();
24
- async run() {
25
- const { args, flags } = await this.parse(EnvProxyNginx);
26
- await runEnvProxyCommand(this, args, flags, 'nginx');
27
- }
28
- }