@nocobase/cli 2.1.0-beta.44.test.3 → 2.1.0-beta.44.test.4
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.
- package/bin/run.js +40 -3
- package/dist/commands/app/destroy.js +13 -6
- package/dist/commands/app/restart.js +11 -2
- package/dist/commands/app/shared.js +3 -2
- package/dist/commands/app/start.js +10 -2
- package/dist/commands/app/upgrade.js +6 -4
- package/dist/commands/config/delete.js +2 -0
- package/dist/commands/config/get.js +2 -0
- package/dist/commands/config/set.js +2 -0
- package/dist/commands/env/add.js +5 -5
- package/dist/commands/init.js +117 -7
- package/dist/commands/install.js +50 -13
- package/dist/commands/source/download.js +1 -1
- package/dist/commands/source/test.js +13 -14
- package/dist/locale/en-US.json +13 -5
- package/dist/locale/zh-CN.json +13 -5
- package/package.json +1 -7
- package/scripts/build.mjs +34 -0
- package/scripts/clean.mjs +9 -0
- package/tsconfig.json +19 -0
- package/dist/lib/api-client.js +0 -335
- package/dist/lib/api-command-compat.js +0 -641
- package/dist/lib/app-health.js +0 -139
- package/dist/lib/app-managed-resources.js +0 -321
- package/dist/lib/app-public-path.js +0 -80
- package/dist/lib/app-runtime.js +0 -189
- package/dist/lib/auth-store.js +0 -498
- package/dist/lib/backup.js +0 -171
- package/dist/lib/bootstrap.js +0 -409
- package/dist/lib/build-config.js +0 -18
- package/dist/lib/builtin-db.js +0 -86
- package/dist/lib/cli-config.js +0 -398
- package/dist/lib/cli-entry-error.js +0 -44
- package/dist/lib/cli-home.js +0 -47
- package/dist/lib/cli-locale.js +0 -141
- package/dist/lib/command-discovery.js +0 -39
- package/dist/lib/db-connection-check.js +0 -219
- package/dist/lib/docker-env-file.js +0 -60
- package/dist/lib/docker-image.js +0 -37
- package/dist/lib/docker-log-stream.js +0 -45
- package/dist/lib/env-auth.js +0 -960
- package/dist/lib/env-command-config.js +0 -45
- package/dist/lib/env-config.js +0 -100
- package/dist/lib/env-guard.js +0 -61
- package/dist/lib/env-paths.js +0 -101
- package/dist/lib/env-proxy.js +0 -1295
- package/dist/lib/generated-command.js +0 -203
- package/dist/lib/http-request.js +0 -49
- package/dist/lib/inquirer-theme.js +0 -17
- package/dist/lib/inquirer.js +0 -243
- package/dist/lib/managed-env-file.js +0 -98
- package/dist/lib/naming.js +0 -70
- package/dist/lib/object-utils.js +0 -76
- package/dist/lib/openapi.js +0 -62
- package/dist/lib/plugin-import.js +0 -279
- package/dist/lib/plugin-storage.js +0 -64
- package/dist/lib/post-processors.js +0 -23
- package/dist/lib/prompt-catalog-core.js +0 -185
- package/dist/lib/prompt-catalog-terminal.js +0 -375
- package/dist/lib/prompt-catalog.js +0 -10
- package/dist/lib/prompt-validators.js +0 -258
- package/dist/lib/prompt-web-ui.js +0 -2227
- package/dist/lib/resource-command.js +0 -357
- package/dist/lib/resource-request.js +0 -104
- package/dist/lib/run-npm.js +0 -393
- package/dist/lib/runtime-env-vars.js +0 -32
- package/dist/lib/runtime-generator.js +0 -498
- package/dist/lib/runtime-store.js +0 -56
- package/dist/lib/self-manager.js +0 -301
- package/dist/lib/session-id.js +0 -17
- package/dist/lib/session-integration.js +0 -703
- package/dist/lib/session-store.js +0 -118
- package/dist/lib/skills-manager.js +0 -438
- package/dist/lib/source-publish.js +0 -326
- package/dist/lib/source-registry.js +0 -188
- package/dist/lib/startup-update.js +0 -309
- package/dist/lib/ui.js +0 -159
package/dist/lib/app-runtime.js
DELETED
|
@@ -1,189 +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 path from 'node:path';
|
|
10
|
-
import { resolveEnvKind } from './auth-store.js';
|
|
11
|
-
import { getEnv, loadAuthConfig } from './auth-store.js';
|
|
12
|
-
import { DEFAULT_DOCKER_CONTAINER_PREFIX, DEFAULT_DOCKER_NETWORK, getEffectiveCliConfigValue, } from './cli-config.js';
|
|
13
|
-
import { resolveManagedLocalEnvFilePath } from './managed-env-file.js';
|
|
14
|
-
import { commandOutput, commandSucceeds, run, runNocoBaseCommand } from './run-npm.js';
|
|
15
|
-
import { buildRuntimeEnvVars } from './runtime-env-vars.js';
|
|
16
|
-
const DOCKER_APP_WORKDIR = '/app/nocobase';
|
|
17
|
-
function sanitizeDockerResourceName(value) {
|
|
18
|
-
const normalized = value
|
|
19
|
-
.trim()
|
|
20
|
-
.toLowerCase()
|
|
21
|
-
.replace(/[^a-z0-9_.-]+/g, '-')
|
|
22
|
-
.replace(/-+/g, '-')
|
|
23
|
-
.replace(/^-+|-+$/g, '');
|
|
24
|
-
return normalized || 'nocobase';
|
|
25
|
-
}
|
|
26
|
-
export function defaultWorkspaceName(cwd = process.cwd()) {
|
|
27
|
-
return sanitizeDockerResourceName(`nb-${path.basename(cwd)}`);
|
|
28
|
-
}
|
|
29
|
-
export function defaultDockerContainerPrefix(cwd = process.cwd()) {
|
|
30
|
-
const configured = String(DEFAULT_DOCKER_CONTAINER_PREFIX ?? '').trim();
|
|
31
|
-
if (configured) {
|
|
32
|
-
return sanitizeDockerResourceName(configured);
|
|
33
|
-
}
|
|
34
|
-
return defaultWorkspaceName(cwd);
|
|
35
|
-
}
|
|
36
|
-
export function defaultDockerNetworkName() {
|
|
37
|
-
return sanitizeDockerResourceName(DEFAULT_DOCKER_NETWORK);
|
|
38
|
-
}
|
|
39
|
-
export function buildDockerAppContainerName(envName, containerPrefix) {
|
|
40
|
-
const prefix = containerPrefix?.trim() || defaultDockerContainerPrefix();
|
|
41
|
-
return sanitizeDockerResourceName(`${prefix}-${envName}-app`);
|
|
42
|
-
}
|
|
43
|
-
export function buildDockerDbContainerName(envName, dbDialect, containerPrefix) {
|
|
44
|
-
const prefix = containerPrefix?.trim() || defaultDockerContainerPrefix();
|
|
45
|
-
const dialect = dbDialect.trim() || 'postgres';
|
|
46
|
-
return sanitizeDockerResourceName(`${prefix}-${envName}-${dialect}`);
|
|
47
|
-
}
|
|
48
|
-
function normalizeEnvSource(env) {
|
|
49
|
-
const source = String(env.config.source ?? '').trim();
|
|
50
|
-
if (source === 'docker' || source === 'npm' || source === 'git') {
|
|
51
|
-
return source;
|
|
52
|
-
}
|
|
53
|
-
const kind = resolveEnvKind(env.config);
|
|
54
|
-
if (kind === 'local') {
|
|
55
|
-
return 'local';
|
|
56
|
-
}
|
|
57
|
-
return undefined;
|
|
58
|
-
}
|
|
59
|
-
export async function resolveManagedAppRuntime(envName) {
|
|
60
|
-
const config = await loadAuthConfig();
|
|
61
|
-
const env = await getEnv(envName, { config });
|
|
62
|
-
if (!env) {
|
|
63
|
-
return undefined;
|
|
64
|
-
}
|
|
65
|
-
const resolvedName = env.name || envName?.trim() || config.lastEnv || 'default';
|
|
66
|
-
const source = normalizeEnvSource(env);
|
|
67
|
-
const dockerNetworkName = sanitizeDockerResourceName(getEffectiveCliConfigValue(config, 'docker.network') || defaultDockerNetworkName());
|
|
68
|
-
const dockerContainerPrefix = sanitizeDockerResourceName(getEffectiveCliConfigValue(config, 'docker.container-prefix') || defaultDockerContainerPrefix());
|
|
69
|
-
const kind = env.kind ?? resolveEnvKind(env.config);
|
|
70
|
-
if (kind === 'docker') {
|
|
71
|
-
return {
|
|
72
|
-
kind: 'docker',
|
|
73
|
-
env,
|
|
74
|
-
envName: resolvedName,
|
|
75
|
-
source: 'docker',
|
|
76
|
-
dockerNetworkName,
|
|
77
|
-
dockerContainerPrefix,
|
|
78
|
-
workspaceName: dockerNetworkName,
|
|
79
|
-
containerName: buildDockerAppContainerName(resolvedName, dockerContainerPrefix),
|
|
80
|
-
};
|
|
81
|
-
}
|
|
82
|
-
if (kind === 'local') {
|
|
83
|
-
return {
|
|
84
|
-
kind: 'local',
|
|
85
|
-
env,
|
|
86
|
-
envName: resolvedName,
|
|
87
|
-
source: source === 'git' ? 'git' : source === 'npm' ? 'npm' : 'local',
|
|
88
|
-
projectRoot: env.sourcePath,
|
|
89
|
-
dockerNetworkName,
|
|
90
|
-
dockerContainerPrefix,
|
|
91
|
-
workspaceName: dockerNetworkName,
|
|
92
|
-
};
|
|
93
|
-
}
|
|
94
|
-
if (kind === 'ssh') {
|
|
95
|
-
return {
|
|
96
|
-
kind: 'ssh',
|
|
97
|
-
env,
|
|
98
|
-
envName: resolvedName,
|
|
99
|
-
source,
|
|
100
|
-
};
|
|
101
|
-
}
|
|
102
|
-
return {
|
|
103
|
-
kind: 'http',
|
|
104
|
-
env,
|
|
105
|
-
envName: resolvedName,
|
|
106
|
-
source,
|
|
107
|
-
};
|
|
108
|
-
}
|
|
109
|
-
export function formatMissingManagedAppEnvMessage(envName) {
|
|
110
|
-
const requested = String(envName ?? '').trim();
|
|
111
|
-
if (requested) {
|
|
112
|
-
return [
|
|
113
|
-
`Env "${requested}" is not configured in this workspace.`,
|
|
114
|
-
`If you want to create a new NocoBase AI environment, run \`nb init --ui --env ${requested}\` first.`,
|
|
115
|
-
].join('\n');
|
|
116
|
-
}
|
|
117
|
-
return 'No NocoBase env is configured yet. Run `nb init --ui` to create one first.';
|
|
118
|
-
}
|
|
119
|
-
export function managedAppLifecycleEnvVars() {
|
|
120
|
-
return {
|
|
121
|
-
APP_ENV: 'production',
|
|
122
|
-
NODE_ENV: 'production',
|
|
123
|
-
};
|
|
124
|
-
}
|
|
125
|
-
export async function runLocalNocoBaseCommand(runtime, args, options) {
|
|
126
|
-
const envVars = await buildRuntimeEnvVars(runtime);
|
|
127
|
-
const appEnvPath = resolveManagedLocalEnvFilePath(runtime);
|
|
128
|
-
await runNocoBaseCommand(args, {
|
|
129
|
-
cwd: runtime.projectRoot,
|
|
130
|
-
env: {
|
|
131
|
-
...envVars,
|
|
132
|
-
APP_ENV_PATH: appEnvPath,
|
|
133
|
-
...options?.env,
|
|
134
|
-
},
|
|
135
|
-
stdio: options?.stdio,
|
|
136
|
-
onStdout: options?.onStdout,
|
|
137
|
-
onStderr: options?.onStderr,
|
|
138
|
-
});
|
|
139
|
-
}
|
|
140
|
-
export async function dockerContainerExists(containerName) {
|
|
141
|
-
return await commandSucceeds('docker', ['container', 'inspect', containerName]);
|
|
142
|
-
}
|
|
143
|
-
export async function dockerContainerIsRunning(containerName) {
|
|
144
|
-
try {
|
|
145
|
-
const output = await commandOutput('docker', ['inspect', '--format', '{{.State.Running}}', containerName], { errorName: 'docker inspect' });
|
|
146
|
-
return output.trim() === 'true';
|
|
147
|
-
}
|
|
148
|
-
catch (_error) {
|
|
149
|
-
return false;
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
export async function startDockerContainer(containerName, options) {
|
|
153
|
-
const exists = await dockerContainerExists(containerName);
|
|
154
|
-
if (!exists) {
|
|
155
|
-
throw new Error(`Docker app container "${containerName}" does not exist.`);
|
|
156
|
-
}
|
|
157
|
-
if (await dockerContainerIsRunning(containerName)) {
|
|
158
|
-
return 'already-running';
|
|
159
|
-
}
|
|
160
|
-
await run('docker', ['start', containerName], {
|
|
161
|
-
errorName: 'docker start',
|
|
162
|
-
stdio: options?.stdio,
|
|
163
|
-
});
|
|
164
|
-
return 'started';
|
|
165
|
-
}
|
|
166
|
-
export async function stopDockerContainer(containerName, options) {
|
|
167
|
-
const exists = await dockerContainerExists(containerName);
|
|
168
|
-
if (!exists) {
|
|
169
|
-
throw new Error(`Docker app container "${containerName}" does not exist.`);
|
|
170
|
-
}
|
|
171
|
-
if (!(await dockerContainerIsRunning(containerName))) {
|
|
172
|
-
return 'already-stopped';
|
|
173
|
-
}
|
|
174
|
-
await run('docker', ['stop', containerName], {
|
|
175
|
-
errorName: 'docker stop',
|
|
176
|
-
stdio: options?.stdio,
|
|
177
|
-
});
|
|
178
|
-
return 'stopped';
|
|
179
|
-
}
|
|
180
|
-
export async function runDockerNocoBaseCommand(containerName, args, options) {
|
|
181
|
-
await startDockerContainer(containerName, { stdio: options?.stdio });
|
|
182
|
-
const dockerEnvArgs = Object.entries(options?.env ?? {}).flatMap(([key, value]) => ['-e', `${key}=${value}`]);
|
|
183
|
-
await run('docker', ['exec', ...dockerEnvArgs, '-w', DOCKER_APP_WORKDIR, containerName, 'yarn', 'nocobase', ...args], {
|
|
184
|
-
errorName: 'docker exec',
|
|
185
|
-
stdio: options?.stdio,
|
|
186
|
-
onStdout: options?.onStdout,
|
|
187
|
-
onStderr: options?.onStderr,
|
|
188
|
-
});
|
|
189
|
-
}
|
package/dist/lib/auth-store.js
DELETED
|
@@ -1,498 +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 { promises as fs } from 'node:fs';
|
|
10
|
-
import path from 'node:path';
|
|
11
|
-
import { resolveAppPublicPath } from './app-public-path.js';
|
|
12
|
-
import { resolveCliHomeDir, resolveConfiguredEnvPath, resolveEnvRelativePath } from './cli-home.js';
|
|
13
|
-
import { normalizeCliLocale } from './cli-locale.js';
|
|
14
|
-
import { inferConfiguredAppPathFromLegacyConfig, resolveConfiguredAppPath, resolveConfiguredSourcePath, resolveConfiguredStoragePath, } from './env-paths.js';
|
|
15
|
-
import { cleanupCurrentSessionAfterEnvRemoval, resolveEffectiveCurrentEnv, setSessionCurrentEnv, } from './session-store.js';
|
|
16
|
-
function normalizeStoredEnvKind(value) {
|
|
17
|
-
const kind = String(value ?? '').trim();
|
|
18
|
-
if (kind === 'remote') {
|
|
19
|
-
return 'http';
|
|
20
|
-
}
|
|
21
|
-
if (kind === 'local' || kind === 'http' || kind === 'docker' || kind === 'ssh') {
|
|
22
|
-
return kind;
|
|
23
|
-
}
|
|
24
|
-
return undefined;
|
|
25
|
-
}
|
|
26
|
-
function normalizeOptionalString(value) {
|
|
27
|
-
const normalized = String(value ?? '').trim();
|
|
28
|
-
return normalized || undefined;
|
|
29
|
-
}
|
|
30
|
-
function normalizeOptionalCliLocale(value) {
|
|
31
|
-
const normalized = normalizeOptionalString(value);
|
|
32
|
-
if (!normalized) {
|
|
33
|
-
return undefined;
|
|
34
|
-
}
|
|
35
|
-
return normalizeCliLocale(normalized);
|
|
36
|
-
}
|
|
37
|
-
function normalizeOptionalCliUpdatePolicy(value) {
|
|
38
|
-
const normalized = normalizeOptionalString(value);
|
|
39
|
-
if (normalized === 'prompt' || normalized === 'auto' || normalized === 'off') {
|
|
40
|
-
return normalized;
|
|
41
|
-
}
|
|
42
|
-
return undefined;
|
|
43
|
-
}
|
|
44
|
-
export function readEnvApiBaseUrl(config) {
|
|
45
|
-
if (!config) {
|
|
46
|
-
return undefined;
|
|
47
|
-
}
|
|
48
|
-
return (normalizeOptionalString(config.apiBaseUrl) ??
|
|
49
|
-
normalizeOptionalString(config.baseUrl) ??
|
|
50
|
-
normalizeOptionalString(config.apibaseUrl));
|
|
51
|
-
}
|
|
52
|
-
export function resolveEnvKind(config) {
|
|
53
|
-
if (!config) {
|
|
54
|
-
return undefined;
|
|
55
|
-
}
|
|
56
|
-
const explicitKind = normalizeStoredEnvKind(config.kind);
|
|
57
|
-
if (explicitKind) {
|
|
58
|
-
return explicitKind;
|
|
59
|
-
}
|
|
60
|
-
const source = String(config.source ?? '').trim();
|
|
61
|
-
if (source === 'docker') {
|
|
62
|
-
return 'docker';
|
|
63
|
-
}
|
|
64
|
-
if (source === 'npm' || source === 'git' || source === 'local') {
|
|
65
|
-
return 'local';
|
|
66
|
-
}
|
|
67
|
-
if (String(config.appPath ?? '').trim() || String(config.appRootPath ?? '').trim()) {
|
|
68
|
-
return 'local';
|
|
69
|
-
}
|
|
70
|
-
if (readEnvApiBaseUrl(config) || config.auth) {
|
|
71
|
-
return 'http';
|
|
72
|
-
}
|
|
73
|
-
return undefined;
|
|
74
|
-
}
|
|
75
|
-
function normalizeEnvConfigEntry(entry) {
|
|
76
|
-
if (!entry) {
|
|
77
|
-
return entry;
|
|
78
|
-
}
|
|
79
|
-
const { kind: _kind, apiBaseUrl: _apiBaseUrl, baseUrl: _baseUrl, apibaseUrl: _legacyApiBaseUrl, ...rest } = entry;
|
|
80
|
-
const normalizedKind = resolveEnvKind(entry);
|
|
81
|
-
const apiBaseUrl = readEnvApiBaseUrl(entry);
|
|
82
|
-
return {
|
|
83
|
-
...rest,
|
|
84
|
-
...(normalizedKind ? { kind: normalizedKind } : {}),
|
|
85
|
-
...(apiBaseUrl !== undefined ? { apiBaseUrl } : {}),
|
|
86
|
-
...(normalizeOptionalString(entry.appPublicPath) ? { appPublicPath: resolveAppPublicPath(entry.appPublicPath) } : {}),
|
|
87
|
-
};
|
|
88
|
-
}
|
|
89
|
-
function normalizeAuthConfig(config) {
|
|
90
|
-
const settings = config.settings ?? {};
|
|
91
|
-
const locale = normalizeOptionalCliLocale(settings.locale);
|
|
92
|
-
const updatePolicy = normalizeOptionalCliUpdatePolicy(settings.update?.policy);
|
|
93
|
-
return {
|
|
94
|
-
name: config.name || config.dockerResourcePrefix,
|
|
95
|
-
settings: {
|
|
96
|
-
...(locale ? { locale } : {}),
|
|
97
|
-
...(updatePolicy ? { update: { policy: updatePolicy } } : {}),
|
|
98
|
-
...(settings.license?.pkgUrl ? { license: { pkgUrl: normalizeOptionalString(settings.license.pkgUrl) } } : {}),
|
|
99
|
-
...(settings.docker?.network || settings.docker?.containerPrefix
|
|
100
|
-
? {
|
|
101
|
-
docker: {
|
|
102
|
-
...(settings.docker?.network ? { network: normalizeOptionalString(settings.docker.network) } : {}),
|
|
103
|
-
...(settings.docker?.containerPrefix
|
|
104
|
-
? { containerPrefix: normalizeOptionalString(settings.docker.containerPrefix) }
|
|
105
|
-
: {}),
|
|
106
|
-
},
|
|
107
|
-
}
|
|
108
|
-
: {}),
|
|
109
|
-
...(settings.bin?.docker || settings.bin?.caddy || settings.bin?.git || settings.bin?.nginx || settings.bin?.yarn
|
|
110
|
-
? {
|
|
111
|
-
bin: {
|
|
112
|
-
...(settings.bin?.docker ? { docker: normalizeOptionalString(settings.bin.docker) } : {}),
|
|
113
|
-
...(settings.bin?.caddy ? { caddy: normalizeOptionalString(settings.bin.caddy) } : {}),
|
|
114
|
-
...(settings.bin?.git ? { git: normalizeOptionalString(settings.bin.git) } : {}),
|
|
115
|
-
...(settings.bin?.nginx ? { nginx: normalizeOptionalString(settings.bin.nginx) } : {}),
|
|
116
|
-
...(settings.bin?.yarn ? { yarn: normalizeOptionalString(settings.bin.yarn) } : {}),
|
|
117
|
-
},
|
|
118
|
-
}
|
|
119
|
-
: {}),
|
|
120
|
-
...(settings.proxy?.nbCliRoot ||
|
|
121
|
-
settings.proxy?.upstreamHost ||
|
|
122
|
-
settings.proxy?.host
|
|
123
|
-
? {
|
|
124
|
-
proxy: {
|
|
125
|
-
...(settings.proxy?.nbCliRoot ? { nbCliRoot: normalizeOptionalString(settings.proxy.nbCliRoot) } : {}),
|
|
126
|
-
...(settings.proxy?.upstreamHost || settings.proxy?.host
|
|
127
|
-
? {
|
|
128
|
-
upstreamHost: normalizeOptionalString(settings.proxy?.upstreamHost ?? settings.proxy.host),
|
|
129
|
-
}
|
|
130
|
-
: {}),
|
|
131
|
-
},
|
|
132
|
-
}
|
|
133
|
-
: {}),
|
|
134
|
-
},
|
|
135
|
-
lastEnv: config.lastEnv ||
|
|
136
|
-
config.currentEnv ||
|
|
137
|
-
'default',
|
|
138
|
-
envs: Object.fromEntries(Object.entries(config.envs || {}).map(([envName, entry]) => [envName, normalizeEnvConfigEntry(entry) ?? {}])),
|
|
139
|
-
};
|
|
140
|
-
}
|
|
141
|
-
function getConfigFile(options = {}) {
|
|
142
|
-
return path.join(resolveCliHomeDir(options.scope), 'config.json');
|
|
143
|
-
}
|
|
144
|
-
function createDefaultConfig() {
|
|
145
|
-
return {
|
|
146
|
-
lastEnv: 'default',
|
|
147
|
-
envs: {},
|
|
148
|
-
};
|
|
149
|
-
}
|
|
150
|
-
async function readStoredAuthConfig(filePath) {
|
|
151
|
-
try {
|
|
152
|
-
const content = await fs.readFile(filePath, 'utf8');
|
|
153
|
-
const parsed = JSON.parse(content);
|
|
154
|
-
return normalizeAuthConfig(parsed);
|
|
155
|
-
}
|
|
156
|
-
catch (_error) {
|
|
157
|
-
return undefined;
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
export async function loadExactAuthConfig(options = {}) {
|
|
161
|
-
return (await readStoredAuthConfig(getConfigFile(options))) ?? createDefaultConfig();
|
|
162
|
-
}
|
|
163
|
-
export async function loadAuthConfig(options = {}) {
|
|
164
|
-
return await loadExactAuthConfig(options);
|
|
165
|
-
}
|
|
166
|
-
export async function saveAuthConfig(config, options = {}) {
|
|
167
|
-
const filePath = getConfigFile(options);
|
|
168
|
-
await fs.mkdir(path.dirname(filePath), { recursive: true });
|
|
169
|
-
await fs.writeFile(filePath, JSON.stringify(normalizeAuthConfig(config), null, 2));
|
|
170
|
-
}
|
|
171
|
-
export async function listEnvs(options = {}) {
|
|
172
|
-
const config = await loadAuthConfig(options);
|
|
173
|
-
return {
|
|
174
|
-
lastEnv: config.lastEnv || 'default',
|
|
175
|
-
envs: config.envs,
|
|
176
|
-
};
|
|
177
|
-
}
|
|
178
|
-
export async function getCurrentEnvName(options = {}) {
|
|
179
|
-
const config = await loadAuthConfig(options);
|
|
180
|
-
return await resolveEffectiveCurrentEnv(Object.keys(config.envs).sort(), {
|
|
181
|
-
scope: options.scope,
|
|
182
|
-
lastEnv: config.lastEnv,
|
|
183
|
-
});
|
|
184
|
-
}
|
|
185
|
-
export async function setCurrentEnv(envName, options = {}) {
|
|
186
|
-
const config = await loadExactAuthConfig(options);
|
|
187
|
-
if (!config.envs[envName]) {
|
|
188
|
-
throw new Error(`Env "${envName}" is not configured`);
|
|
189
|
-
}
|
|
190
|
-
config.lastEnv = envName;
|
|
191
|
-
await setSessionCurrentEnv(envName, options.scope);
|
|
192
|
-
await saveAuthConfig(config, options);
|
|
193
|
-
}
|
|
194
|
-
export class Env {
|
|
195
|
-
config;
|
|
196
|
-
constructor(config = {}) {
|
|
197
|
-
this.config = config;
|
|
198
|
-
}
|
|
199
|
-
get name() {
|
|
200
|
-
return this.config.name;
|
|
201
|
-
}
|
|
202
|
-
get baseUrl() {
|
|
203
|
-
return readEnvApiBaseUrl(this.config);
|
|
204
|
-
}
|
|
205
|
-
get apiBaseUrl() {
|
|
206
|
-
return readEnvApiBaseUrl(this.config);
|
|
207
|
-
}
|
|
208
|
-
get auth() {
|
|
209
|
-
return this.config.auth;
|
|
210
|
-
}
|
|
211
|
-
get authType() {
|
|
212
|
-
return resolveConfiguredAuthType(this.config);
|
|
213
|
-
}
|
|
214
|
-
get runtime() {
|
|
215
|
-
return this.config.runtime;
|
|
216
|
-
}
|
|
217
|
-
get kind() {
|
|
218
|
-
return resolveEnvKind(this.config);
|
|
219
|
-
}
|
|
220
|
-
get appRootPath() {
|
|
221
|
-
if (this.kind === 'ssh') {
|
|
222
|
-
const configuredPath = String(this.config.appRootPath ?? '').trim();
|
|
223
|
-
if (configuredPath) {
|
|
224
|
-
return configuredPath;
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
const legacyPath = resolveConfiguredEnvPath(this.config.appRootPath);
|
|
228
|
-
if (legacyPath) {
|
|
229
|
-
return legacyPath;
|
|
230
|
-
}
|
|
231
|
-
return this.kind === 'local' ? this.sourcePath : resolveEnvRelativePath('.');
|
|
232
|
-
}
|
|
233
|
-
get appPath() {
|
|
234
|
-
if (this.kind === 'ssh') {
|
|
235
|
-
const configuredPath = String(this.config.appPath ?? inferConfiguredAppPathFromLegacyConfig(this.config) ?? '').trim();
|
|
236
|
-
if (configuredPath) {
|
|
237
|
-
return configuredPath;
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
return resolveConfiguredAppPath(this.config) ?? resolveEnvRelativePath('.');
|
|
241
|
-
}
|
|
242
|
-
get sourcePath() {
|
|
243
|
-
if (this.kind === 'ssh') {
|
|
244
|
-
const configuredPath = String(this.config.appRootPath ?? '').trim();
|
|
245
|
-
if (configuredPath) {
|
|
246
|
-
return configuredPath;
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
return resolveConfiguredSourcePath(this.config) ?? path.join(this.appPath, 'source');
|
|
250
|
-
}
|
|
251
|
-
get storagePath() {
|
|
252
|
-
if (this.kind === 'ssh') {
|
|
253
|
-
const configuredPath = String(this.config.storagePath ?? '').trim();
|
|
254
|
-
if (configuredPath) {
|
|
255
|
-
return configuredPath;
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
|
-
const resolvedStoragePath = resolveConfiguredStoragePath(this.config);
|
|
259
|
-
if (resolvedStoragePath) {
|
|
260
|
-
return resolvedStoragePath;
|
|
261
|
-
}
|
|
262
|
-
return this.kind === 'local' || this.kind === 'docker'
|
|
263
|
-
? path.join(this.appPath, 'storage')
|
|
264
|
-
: resolveEnvRelativePath('.');
|
|
265
|
-
}
|
|
266
|
-
get appPort() {
|
|
267
|
-
return this.config.appPort;
|
|
268
|
-
}
|
|
269
|
-
get envVars() {
|
|
270
|
-
const out = {
|
|
271
|
-
STORAGE_PATH: this.storagePath,
|
|
272
|
-
};
|
|
273
|
-
const put = (key, value) => {
|
|
274
|
-
if (value === undefined || value === null) {
|
|
275
|
-
return;
|
|
276
|
-
}
|
|
277
|
-
out[key] = String(value);
|
|
278
|
-
};
|
|
279
|
-
put('APP_PORT', this.appPort);
|
|
280
|
-
put('APP_PUBLIC_PATH', this.config.appPublicPath ? resolveAppPublicPath(this.config.appPublicPath) : undefined);
|
|
281
|
-
put('CDN_BASE_URL', this.config.cdnBaseUrl);
|
|
282
|
-
put('APP_KEY', this.config.appKey);
|
|
283
|
-
put('TZ', this.config.timezone);
|
|
284
|
-
put('DB_DIALECT', this.config.dbDialect);
|
|
285
|
-
if (!this.config.builtinDb) {
|
|
286
|
-
put('DB_HOST', this.config.dbHost);
|
|
287
|
-
put('DB_PORT', this.config.dbPort);
|
|
288
|
-
}
|
|
289
|
-
else if (String(this.config.source ?? '').trim() !== 'docker') {
|
|
290
|
-
put('DB_PORT', this.config.dbPort);
|
|
291
|
-
}
|
|
292
|
-
put('DB_DATABASE', this.config.dbDatabase);
|
|
293
|
-
put('DB_USER', this.config.dbUser);
|
|
294
|
-
put('DB_PASSWORD', this.config.dbPassword);
|
|
295
|
-
put('DB_SCHEMA', this.config.dbSchema);
|
|
296
|
-
put('DB_TABLE_PREFIX', this.config.dbTablePrefix);
|
|
297
|
-
put('DB_UNDERSCORED', this.config.dbUnderscored);
|
|
298
|
-
return out;
|
|
299
|
-
}
|
|
300
|
-
}
|
|
301
|
-
export async function getEnv(envName, options = {}) {
|
|
302
|
-
const { config: snapshot, ...loadOptions } = options;
|
|
303
|
-
const config = snapshot ?? (await loadAuthConfig(loadOptions));
|
|
304
|
-
const resolved = envName?.trim() ||
|
|
305
|
-
(await resolveEffectiveCurrentEnv(Object.keys(config.envs).sort(), {
|
|
306
|
-
scope: loadOptions.scope,
|
|
307
|
-
lastEnv: config.lastEnv,
|
|
308
|
-
}));
|
|
309
|
-
const envConfig = config.envs[resolved];
|
|
310
|
-
if (!envConfig) {
|
|
311
|
-
return undefined;
|
|
312
|
-
}
|
|
313
|
-
return new Env({ ...(normalizeEnvConfigEntry(envConfig) ?? {}), name: resolved });
|
|
314
|
-
}
|
|
315
|
-
function areAuthConfigsEquivalent(left, right) {
|
|
316
|
-
if (!left && !right) {
|
|
317
|
-
return true;
|
|
318
|
-
}
|
|
319
|
-
if (!left || !right || left.type !== right.type) {
|
|
320
|
-
return false;
|
|
321
|
-
}
|
|
322
|
-
if (left.type === 'token' && right.type === 'token') {
|
|
323
|
-
return left.accessToken === right.accessToken;
|
|
324
|
-
}
|
|
325
|
-
if (left.type === 'oauth' && right.type === 'oauth') {
|
|
326
|
-
return (left.accessToken === right.accessToken &&
|
|
327
|
-
left.refreshToken === right.refreshToken &&
|
|
328
|
-
left.expiresAt === right.expiresAt &&
|
|
329
|
-
left.scope === right.scope &&
|
|
330
|
-
left.issuer === right.issuer &&
|
|
331
|
-
left.clientId === right.clientId &&
|
|
332
|
-
left.resource === right.resource);
|
|
333
|
-
}
|
|
334
|
-
return false;
|
|
335
|
-
}
|
|
336
|
-
async function writeEnv(envName, updater, options = {}) {
|
|
337
|
-
const config = await loadExactAuthConfig(options);
|
|
338
|
-
const previous = config.envs[envName];
|
|
339
|
-
config.envs[envName] = updater(previous);
|
|
340
|
-
await saveAuthConfig(config, options);
|
|
341
|
-
}
|
|
342
|
-
function normalizeConfiguredAuthType(value) {
|
|
343
|
-
return value === 'basic' || value === 'token' || value === 'oauth' ? value : undefined;
|
|
344
|
-
}
|
|
345
|
-
export function resolveConfiguredAuthType(config) {
|
|
346
|
-
return normalizeConfiguredAuthType(config?.authType) ?? normalizeConfiguredAuthType(config?.auth?.type);
|
|
347
|
-
}
|
|
348
|
-
export async function upsertEnv(envName, config, options = {}) {
|
|
349
|
-
await writeEnv(envName, (previous) => {
|
|
350
|
-
const { apiBaseUrl: _apiBaseUrl, baseUrl: _baseUrl, apibaseUrl: _legacyApiBaseUrl, accessToken, authType, authUsername, ...rest } = config;
|
|
351
|
-
const nextApiBaseUrl = readEnvApiBaseUrl(config);
|
|
352
|
-
const previousApiBaseUrl = readEnvApiBaseUrl(previous);
|
|
353
|
-
const baseUrlChanged = previousApiBaseUrl !== nextApiBaseUrl;
|
|
354
|
-
const previousAuthType = resolveConfiguredAuthType(previous);
|
|
355
|
-
const requestedAuthType = normalizeConfiguredAuthType(authType);
|
|
356
|
-
const nextAuthType = requestedAuthType ?? (accessToken ? 'token' : previousAuthType);
|
|
357
|
-
const nextAuthUsername = nextAuthType === 'basic' ? normalizeOptionalString(authUsername) ?? previous?.authUsername : undefined;
|
|
358
|
-
const nextAuth = accessToken
|
|
359
|
-
? {
|
|
360
|
-
type: 'token',
|
|
361
|
-
accessToken,
|
|
362
|
-
}
|
|
363
|
-
: nextAuthType === 'oauth' && !baseUrlChanged && previous?.auth?.type === 'oauth'
|
|
364
|
-
? previous.auth
|
|
365
|
-
: undefined;
|
|
366
|
-
const authChanged = !areAuthConfigsEquivalent(previous?.auth, nextAuth);
|
|
367
|
-
const authTypeChanged = previousAuthType !== nextAuthType;
|
|
368
|
-
const authUsernameChanged = previous?.authUsername !== nextAuthUsername;
|
|
369
|
-
return {
|
|
370
|
-
...previous,
|
|
371
|
-
apiBaseUrl: nextApiBaseUrl,
|
|
372
|
-
authType: nextAuthType,
|
|
373
|
-
authUsername: nextAuthUsername,
|
|
374
|
-
auth: nextAuth,
|
|
375
|
-
...rest,
|
|
376
|
-
runtime: baseUrlChanged || authChanged || authTypeChanged || authUsernameChanged ? undefined : previous?.runtime,
|
|
377
|
-
};
|
|
378
|
-
}, options);
|
|
379
|
-
}
|
|
380
|
-
export async function updateEnvConnection(envName, updates, options = {}) {
|
|
381
|
-
await writeEnv(envName, (previous) => {
|
|
382
|
-
const nextApiBaseUrl = readEnvApiBaseUrl(updates) ?? readEnvApiBaseUrl(previous);
|
|
383
|
-
const previousApiBaseUrl = readEnvApiBaseUrl(previous);
|
|
384
|
-
const baseUrlChanged = previousApiBaseUrl !== nextApiBaseUrl;
|
|
385
|
-
const previousAuthType = resolveConfiguredAuthType(previous);
|
|
386
|
-
const requestedAuthType = normalizeConfiguredAuthType(updates.authType);
|
|
387
|
-
const nextAuthType = requestedAuthType ?? (updates.accessToken ? 'token' : previousAuthType);
|
|
388
|
-
const nextAuthUsername = nextAuthType === 'basic' ? normalizeOptionalString(updates.authUsername) ?? previous?.authUsername : undefined;
|
|
389
|
-
const nextAuth = updates.accessToken
|
|
390
|
-
? {
|
|
391
|
-
type: 'token',
|
|
392
|
-
accessToken: updates.accessToken,
|
|
393
|
-
}
|
|
394
|
-
: nextAuthType === 'oauth' && !baseUrlChanged && previous?.auth?.type === 'oauth'
|
|
395
|
-
? previous.auth
|
|
396
|
-
: undefined;
|
|
397
|
-
const authChanged = !areAuthConfigsEquivalent(previous?.auth, nextAuth);
|
|
398
|
-
const authTypeChanged = previousAuthType !== nextAuthType;
|
|
399
|
-
const authUsernameChanged = previous?.authUsername !== nextAuthUsername;
|
|
400
|
-
return {
|
|
401
|
-
...previous,
|
|
402
|
-
...(nextApiBaseUrl !== undefined ? { apiBaseUrl: nextApiBaseUrl } : {}),
|
|
403
|
-
authType: nextAuthType,
|
|
404
|
-
authUsername: nextAuthUsername,
|
|
405
|
-
auth: nextAuth,
|
|
406
|
-
runtime: baseUrlChanged || authChanged || authTypeChanged || authUsernameChanged ? undefined : previous?.runtime,
|
|
407
|
-
};
|
|
408
|
-
}, options);
|
|
409
|
-
}
|
|
410
|
-
export async function replaceEnvConfig(envName, config, options = {}) {
|
|
411
|
-
await writeEnv(envName, (previous) => {
|
|
412
|
-
if (!previous) {
|
|
413
|
-
throw new Error(`Env "${envName}" is not configured`);
|
|
414
|
-
}
|
|
415
|
-
const { apiBaseUrl: _apiBaseUrl, baseUrl: _baseUrl, apibaseUrl: _legacyApiBaseUrl, accessToken, authType, authUsername, ...rest } = config;
|
|
416
|
-
const nextApiBaseUrl = readEnvApiBaseUrl(config);
|
|
417
|
-
const previousApiBaseUrl = readEnvApiBaseUrl(previous);
|
|
418
|
-
const baseUrlChanged = previousApiBaseUrl !== nextApiBaseUrl;
|
|
419
|
-
const previousAuthType = resolveConfiguredAuthType(previous);
|
|
420
|
-
const nextAuthType = normalizeConfiguredAuthType(authType) ?? (accessToken ? 'token' : undefined);
|
|
421
|
-
const nextAuthUsername = nextAuthType === 'basic' ? normalizeOptionalString(authUsername) : undefined;
|
|
422
|
-
const nextAuth = accessToken
|
|
423
|
-
? {
|
|
424
|
-
type: 'token',
|
|
425
|
-
accessToken,
|
|
426
|
-
}
|
|
427
|
-
: nextAuthType === 'oauth' && !baseUrlChanged && previous?.auth?.type === 'oauth'
|
|
428
|
-
? previous.auth
|
|
429
|
-
: undefined;
|
|
430
|
-
const authChanged = !areAuthConfigsEquivalent(previous?.auth, nextAuth);
|
|
431
|
-
const authTypeChanged = previousAuthType !== nextAuthType;
|
|
432
|
-
const authUsernameChanged = previous?.authUsername !== nextAuthUsername;
|
|
433
|
-
return {
|
|
434
|
-
...rest,
|
|
435
|
-
...(nextApiBaseUrl !== undefined ? { apiBaseUrl: nextApiBaseUrl } : {}),
|
|
436
|
-
...(nextAuthType ? { authType: nextAuthType } : {}),
|
|
437
|
-
...(nextAuthUsername ? { authUsername: nextAuthUsername } : {}),
|
|
438
|
-
...(nextAuth ? { auth: nextAuth } : {}),
|
|
439
|
-
runtime: baseUrlChanged || authChanged || authTypeChanged || authUsernameChanged ? undefined : previous?.runtime,
|
|
440
|
-
};
|
|
441
|
-
}, options);
|
|
442
|
-
}
|
|
443
|
-
export async function setEnvOauthSession(envName, auth, options = {}) {
|
|
444
|
-
await writeEnv(envName, (previous) => ({
|
|
445
|
-
...previous,
|
|
446
|
-
authType: 'oauth',
|
|
447
|
-
auth,
|
|
448
|
-
runtime: options.preserveRuntime ? previous?.runtime : undefined,
|
|
449
|
-
}), options);
|
|
450
|
-
}
|
|
451
|
-
export async function setEnvRuntime(envName, runtime, options = {}) {
|
|
452
|
-
const config = await loadExactAuthConfig(options);
|
|
453
|
-
const current = config.envs[envName] ?? {};
|
|
454
|
-
config.envs[envName] = {
|
|
455
|
-
...current,
|
|
456
|
-
runtime,
|
|
457
|
-
};
|
|
458
|
-
await saveAuthConfig(config, options);
|
|
459
|
-
}
|
|
460
|
-
export async function clearEnvRootSetup(envName, options = {}) {
|
|
461
|
-
const config = await loadExactAuthConfig(options);
|
|
462
|
-
const current = config.envs[envName];
|
|
463
|
-
if (!current) {
|
|
464
|
-
return false;
|
|
465
|
-
}
|
|
466
|
-
const { rootUsername: _rootUsername, rootEmail: _rootEmail, rootPassword: _rootPassword, rootNickname: _rootNickname, ...rest } = current;
|
|
467
|
-
config.envs[envName] = rest;
|
|
468
|
-
await saveAuthConfig(config, options);
|
|
469
|
-
return true;
|
|
470
|
-
}
|
|
471
|
-
export async function removeEnv(envName, options = {}) {
|
|
472
|
-
const config = await loadExactAuthConfig(options);
|
|
473
|
-
if (!config.envs[envName]) {
|
|
474
|
-
throw new Error(`Env "${envName}" is not configured`);
|
|
475
|
-
}
|
|
476
|
-
delete config.envs[envName];
|
|
477
|
-
if (config.lastEnv === envName) {
|
|
478
|
-
const nextEnv = Object.keys(config.envs).sort()[0];
|
|
479
|
-
config.lastEnv = nextEnv ?? 'default';
|
|
480
|
-
}
|
|
481
|
-
await saveAuthConfig(config, options);
|
|
482
|
-
const remainingEnvNames = Object.keys(config.envs).sort();
|
|
483
|
-
const fallbackEnv = remainingEnvNames.length
|
|
484
|
-
? await resolveEffectiveCurrentEnv(remainingEnvNames, {
|
|
485
|
-
scope: options.scope,
|
|
486
|
-
lastEnv: config.lastEnv,
|
|
487
|
-
})
|
|
488
|
-
: undefined;
|
|
489
|
-
await cleanupCurrentSessionAfterEnvRemoval(envName, {
|
|
490
|
-
scope: options.scope,
|
|
491
|
-
fallbackEnv,
|
|
492
|
-
});
|
|
493
|
-
return {
|
|
494
|
-
removed: envName,
|
|
495
|
-
lastEnv: config.lastEnv || 'default',
|
|
496
|
-
hasEnvs: Object.keys(config.envs).length > 0,
|
|
497
|
-
};
|
|
498
|
-
}
|