@nocobase/app-installer 0.0.0-stage → 0.1.0-beta.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +263 -2
- package/bin/run.js +43 -0
- package/dist/cli.js +212 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/install.js +333 -0
- package/dist/commands/install.js.map +1 -0
- package/dist/commands/rollback.js +289 -0
- package/dist/commands/rollback.js.map +1 -0
- package/dist/commands/status.js +134 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/upgrade.js +598 -0
- package/dist/commands/upgrade.js.map +1 -0
- package/dist/lib/app-cli.js +89 -0
- package/dist/lib/app-cli.js.map +1 -0
- package/dist/lib/app-source.js +163 -0
- package/dist/lib/app-source.js.map +1 -0
- package/dist/lib/backup.js +167 -0
- package/dist/lib/backup.js.map +1 -0
- package/dist/lib/checksum-repair.js +76 -0
- package/dist/lib/checksum-repair.js.map +1 -0
- package/dist/lib/confirm.js +36 -0
- package/dist/lib/confirm.js.map +1 -0
- package/dist/lib/current-link.js +22 -0
- package/dist/lib/current-link.js.map +1 -0
- package/dist/lib/ecosystem.js +82 -0
- package/dist/lib/ecosystem.js.map +1 -0
- package/dist/lib/env-file.js +87 -0
- package/dist/lib/env-file.js.map +1 -0
- package/dist/lib/errors.js +32 -0
- package/dist/lib/errors.js.map +1 -0
- package/dist/lib/health.js +55 -0
- package/dist/lib/health.js.map +1 -0
- package/dist/lib/initial-admin.js +39 -0
- package/dist/lib/initial-admin.js.map +1 -0
- package/dist/lib/interrupt.js +50 -0
- package/dist/lib/interrupt.js.map +1 -0
- package/dist/lib/invocation.js +33 -0
- package/dist/lib/invocation.js.map +1 -0
- package/dist/lib/layout.js +48 -0
- package/dist/lib/layout.js.map +1 -0
- package/dist/lib/lock.js +59 -0
- package/dist/lib/lock.js.map +1 -0
- package/dist/lib/mount-path.js +34 -0
- package/dist/lib/mount-path.js.map +1 -0
- package/dist/lib/offline-bundle.js +91 -0
- package/dist/lib/offline-bundle.js.map +1 -0
- package/dist/lib/output.js +61 -0
- package/dist/lib/output.js.map +1 -0
- package/dist/lib/pm2.js +92 -0
- package/dist/lib/pm2.js.map +1 -0
- package/dist/lib/prechecks.js +199 -0
- package/dist/lib/prechecks.js.map +1 -0
- package/dist/lib/registry.js +9 -0
- package/dist/lib/registry.js.map +1 -0
- package/dist/lib/release.js +173 -0
- package/dist/lib/release.js.map +1 -0
- package/dist/lib/remote.js +331 -0
- package/dist/lib/remote.js.map +1 -0
- package/dist/lib/run-command.js +198 -0
- package/dist/lib/run-command.js.map +1 -0
- package/dist/lib/service.js +100 -0
- package/dist/lib/service.js.map +1 -0
- package/dist/lib/source.js +54 -0
- package/dist/lib/source.js.map +1 -0
- package/dist/lib/state.js +87 -0
- package/dist/lib/state.js.map +1 -0
- package/dist/lib/version.js +51 -0
- package/dist/lib/version.js.map +1 -0
- package/dist/remote-entry.js +98 -0
- package/dist/remote-entry.js.map +1 -0
- package/package.json +53 -3
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import { existsSync } from 'node:fs';
|
|
2
|
+
import { mkdir, readFile, rename, rm } from 'node:fs/promises';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { extract } from 'tar';
|
|
5
|
+
import { EXIT_INVALID, InstallerError, isInstallerError } from "./errors.js";
|
|
6
|
+
import { RELEASE_APP_DIR, releaseDir, releaseId, stagingDir, } from "./layout.js";
|
|
7
|
+
import { currentNodeMajor, rebuildCommandLine } from "./prechecks.js";
|
|
8
|
+
import { CommandFailedError, tail } from "./run-command.js";
|
|
9
|
+
/** Every official database dialect; each has its driver in `@nocobase/db-<dialect>`. */
|
|
10
|
+
export const DIALECTS = [
|
|
11
|
+
'sqlite',
|
|
12
|
+
'postgres',
|
|
13
|
+
'mysql',
|
|
14
|
+
'mssql',
|
|
15
|
+
'oracle',
|
|
16
|
+
'dameng',
|
|
17
|
+
'kingbase',
|
|
18
|
+
'oceanbase',
|
|
19
|
+
];
|
|
20
|
+
export function verifyBuildTarget(target, expected = {
|
|
21
|
+
platform: process.platform,
|
|
22
|
+
arch: process.arch,
|
|
23
|
+
nodeMajor: currentNodeMajor(),
|
|
24
|
+
}) {
|
|
25
|
+
if (!target ||
|
|
26
|
+
target.platform !== expected.platform ||
|
|
27
|
+
target.arch !== expected.arch ||
|
|
28
|
+
target.nodeMajor !== expected.nodeMajor) {
|
|
29
|
+
throw new InstallerError('BUILD_TARGET_MISMATCH', `The build targets ${target ? `${target.platform}-${target.arch} on Node ${target.nodeMajor}` : 'an unknown platform'}, but this machine is ${expected.platform}-${expected.arch} on Node ${expected.nodeMajor}.`);
|
|
30
|
+
}
|
|
31
|
+
return target;
|
|
32
|
+
}
|
|
33
|
+
export async function readReleaseManifest(dir) {
|
|
34
|
+
return JSON.parse(await readFile(path.join(dir, 'dist/package.json'), 'utf8'));
|
|
35
|
+
}
|
|
36
|
+
function stepFailure(code, step, error) {
|
|
37
|
+
// An interrupt, or a failure that already says what went wrong, passes through as it is.
|
|
38
|
+
if (isInstallerError(error))
|
|
39
|
+
return error;
|
|
40
|
+
const output = error instanceof CommandFailedError
|
|
41
|
+
? tail(`${error.stdout}\n${error.stderr}`)
|
|
42
|
+
: undefined;
|
|
43
|
+
return new InstallerError(code, `${step} failed${error instanceof Error ? `: ${error.message}` : '.'}`, { cause: error, ...(output ? { details: { output } } : {}) });
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Unpacks a deployment archive into a staging directory, reads which release it is from its manifest, checks that it
|
|
47
|
+
* was built for this machine, and moves it to `releases/<id>/app`. A release already on disk under the same id is the
|
|
48
|
+
* same build, so the staged copy is dropped and the existing one is used. Nothing here touches the running application,
|
|
49
|
+
* and on failure the staging directory is removed.
|
|
50
|
+
*/
|
|
51
|
+
export async function unpackRelease(options) {
|
|
52
|
+
const staging = stagingDir(options.layout);
|
|
53
|
+
const stagedApp = path.join(staging, RELEASE_APP_DIR);
|
|
54
|
+
await rm(staging, { recursive: true, force: true });
|
|
55
|
+
try {
|
|
56
|
+
await mkdir(stagedApp, { recursive: true });
|
|
57
|
+
try {
|
|
58
|
+
// The library `pnpm build --tar` packs with, so a deployment needs no `tar` of its own. Synchronous for the same
|
|
59
|
+
// reason the packing is: on a tree this size the promise form can leave the event loop with nothing pending.
|
|
60
|
+
extract({
|
|
61
|
+
file: options.archive,
|
|
62
|
+
cwd: stagedApp,
|
|
63
|
+
strict: true,
|
|
64
|
+
sync: true,
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
catch (error) {
|
|
68
|
+
throw stepFailure('UNPACK_FAILED', 'Unpacking the deployment archive', error);
|
|
69
|
+
}
|
|
70
|
+
let manifest;
|
|
71
|
+
try {
|
|
72
|
+
manifest = await readReleaseManifest(stagedApp);
|
|
73
|
+
}
|
|
74
|
+
catch (error) {
|
|
75
|
+
throw new InstallerError('ARCHIVE_INVALID', `${options.archive} holds no dist/package.json; it is not a deployment archive from \`pnpm build --tar\`.`, { exitCode: EXIT_INVALID, cause: error });
|
|
76
|
+
}
|
|
77
|
+
let buildTarget;
|
|
78
|
+
try {
|
|
79
|
+
buildTarget = verifyBuildTarget(manifest.nocobase?.buildTarget);
|
|
80
|
+
}
|
|
81
|
+
catch (error) {
|
|
82
|
+
if (!isInstallerError(error))
|
|
83
|
+
throw error;
|
|
84
|
+
throw new InstallerError(error.code, error.message, {
|
|
85
|
+
exitCode: EXIT_INVALID,
|
|
86
|
+
suggestions: [
|
|
87
|
+
{
|
|
88
|
+
message: 'Build the archive for this machine in the application project, then run this again:',
|
|
89
|
+
run: rebuildCommandLine(),
|
|
90
|
+
},
|
|
91
|
+
],
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
const version = manifest.version ?? '0.0.0';
|
|
95
|
+
const builtAt = manifest.nocobase?.builtAt;
|
|
96
|
+
const relocatable = manifest.nocobase?.relocatable === true;
|
|
97
|
+
const basePath = relocatable ? undefined : manifest.nocobase?.basePath;
|
|
98
|
+
if (!builtAt || (!relocatable && !basePath) || !manifest.name) {
|
|
99
|
+
throw new InstallerError('ARCHIVE_TOO_OLD', `${options.archive} does not record where its client can be mounted and when it was built; it comes from a \`pnpm build\` older than app-installer needs.`, {
|
|
100
|
+
exitCode: EXIT_INVALID,
|
|
101
|
+
suggestions: [
|
|
102
|
+
{
|
|
103
|
+
message: 'Upgrade @nocobase/app-cli in the application project, build the archive again, then run this again:',
|
|
104
|
+
run: rebuildCommandLine(),
|
|
105
|
+
},
|
|
106
|
+
],
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
const id = releaseId(version, builtAt);
|
|
110
|
+
const dir = releaseDir(options.layout, id);
|
|
111
|
+
const reused = existsSync(dir);
|
|
112
|
+
if (!reused) {
|
|
113
|
+
await mkdir(options.layout.releasesDir, { recursive: true });
|
|
114
|
+
await rename(staging, path.dirname(dir));
|
|
115
|
+
}
|
|
116
|
+
return {
|
|
117
|
+
id,
|
|
118
|
+
dir,
|
|
119
|
+
appName: manifest.name,
|
|
120
|
+
version,
|
|
121
|
+
builtAt,
|
|
122
|
+
relocatable,
|
|
123
|
+
...(basePath === undefined ? {} : { basePath }),
|
|
124
|
+
buildTarget,
|
|
125
|
+
reused,
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
finally {
|
|
129
|
+
await rm(staging, { recursive: true, force: true });
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* A deployment archive carries its database drivers in `dist/node_modules`, installed when it was built; nothing adds
|
|
134
|
+
* one afterwards. A dialect whose driver is absent would fail only when the application first connects.
|
|
135
|
+
*/
|
|
136
|
+
export function checkArchiveDriver(dir, dialect) {
|
|
137
|
+
if (dialect === 'sqlite')
|
|
138
|
+
return;
|
|
139
|
+
const driver = `@nocobase/db-${dialect}`;
|
|
140
|
+
if (existsSync(path.join(dir, 'dist/node_modules', driver, 'package.json'))) {
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
throw new InstallerError('DRIVER_MISSING', `The archive holds no ${driver}, which the ${dialect} dialect needs; a deployment archive carries the drivers it was built with.`, {
|
|
144
|
+
exitCode: EXIT_INVALID,
|
|
145
|
+
suggestions: [
|
|
146
|
+
{
|
|
147
|
+
message: 'Add the driver in the application project:',
|
|
148
|
+
run: { command: 'pnpm', args: ['add', driver] },
|
|
149
|
+
},
|
|
150
|
+
{
|
|
151
|
+
message: 'Then build the archive again:',
|
|
152
|
+
run: rebuildCommandLine(),
|
|
153
|
+
},
|
|
154
|
+
],
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* A release older than `APP_STORAGE_DIR` ignores it and keeps its data in `storage/` beside `dist/`, inside the release
|
|
159
|
+
* directory, where the next upgrade would leave it behind. Its first database write shows it.
|
|
160
|
+
*/
|
|
161
|
+
export function assertStorageOutsideRelease(dir) {
|
|
162
|
+
if (!existsSync(path.join(dir, 'storage')))
|
|
163
|
+
return;
|
|
164
|
+
throw new InstallerError('STORAGE_IN_RELEASE', `The release wrote its data into ${path.join(dir, 'storage')} instead of the installation's storage directory: its @nocobase/app-server predates APP_STORAGE_DIR.`, {
|
|
165
|
+
suggestions: [
|
|
166
|
+
{
|
|
167
|
+
message: 'Upgrade @nocobase/app-server and @nocobase/app-cli in the application project, then build the archive again:',
|
|
168
|
+
run: rebuildCommandLine(),
|
|
169
|
+
},
|
|
170
|
+
],
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
//# sourceMappingURL=release.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"release.js","sourceRoot":"","sources":["../../src/lib/release.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,331 @@
|
|
|
1
|
+
import { list } from 'tar';
|
|
2
|
+
import { createHash, randomUUID } from 'node:crypto';
|
|
3
|
+
import { createReadStream } from 'node:fs';
|
|
4
|
+
import { mkdtemp, rm, stat } from 'node:fs/promises';
|
|
5
|
+
import os from 'node:os';
|
|
6
|
+
import path from 'node:path';
|
|
7
|
+
import { fileURLToPath } from 'node:url';
|
|
8
|
+
import { Flags } from '@oclif/core';
|
|
9
|
+
import { quoteForShell } from '@nocobase/cli-envelope';
|
|
10
|
+
import { createOfflineBundle } from "./offline-bundle.js";
|
|
11
|
+
import { CommandFailedError, runCommand } from "./run-command.js";
|
|
12
|
+
import { EXIT_INVALID, InstallerError } from "./errors.js";
|
|
13
|
+
import { INSTALLER_PACKAGE } from "./invocation.js";
|
|
14
|
+
import { checkHealth } from "./health.js";
|
|
15
|
+
export const SSH_FLAGS = {
|
|
16
|
+
ssh: Flags.string({
|
|
17
|
+
description: 'SSH destination (user@host or SSH config alias). The server needs no internet access.',
|
|
18
|
+
}),
|
|
19
|
+
'ssh-port': Flags.integer({
|
|
20
|
+
min: 1,
|
|
21
|
+
max: 65535,
|
|
22
|
+
description: 'SSH port; otherwise use system SSH configuration.',
|
|
23
|
+
}),
|
|
24
|
+
'ssh-identity': Flags.string({
|
|
25
|
+
description: 'Local SSH private key file; SSH agent and config work without this flag.',
|
|
26
|
+
}),
|
|
27
|
+
'ssh-config': Flags.string({
|
|
28
|
+
description: 'Local SSH config file, including ProxyJump and remote PATH setup.',
|
|
29
|
+
}),
|
|
30
|
+
'ssh-timeout': Flags.integer({
|
|
31
|
+
min: 1,
|
|
32
|
+
default: 1800,
|
|
33
|
+
description: 'Maximum seconds for each remote execution or transfer. A timeout does not imply rollback.',
|
|
34
|
+
}),
|
|
35
|
+
};
|
|
36
|
+
export async function sha256(file) {
|
|
37
|
+
const hash = createHash('sha256');
|
|
38
|
+
for await (const chunk of createReadStream(file))
|
|
39
|
+
hash.update(chunk);
|
|
40
|
+
return hash.digest('hex');
|
|
41
|
+
}
|
|
42
|
+
export function sshArgs(flags, scp = false) {
|
|
43
|
+
const host = flags.ssh;
|
|
44
|
+
if (typeof host !== 'string' ||
|
|
45
|
+
!/^(?:[\w.-]+@)?[\w.:[\]-]+$/u.test(host) ||
|
|
46
|
+
host.startsWith('-')) {
|
|
47
|
+
throw new InstallerError('INVALID_USAGE', '--ssh must be a host, user@host or SSH config alias, not a shell command or URL.', { exitCode: EXIT_INVALID });
|
|
48
|
+
}
|
|
49
|
+
const args = [
|
|
50
|
+
'-o',
|
|
51
|
+
'BatchMode=yes',
|
|
52
|
+
'-o',
|
|
53
|
+
'StrictHostKeyChecking=yes',
|
|
54
|
+
'-o',
|
|
55
|
+
'ConnectTimeout=15',
|
|
56
|
+
];
|
|
57
|
+
if (flags['ssh-port'])
|
|
58
|
+
args.push(scp ? '-P' : '-p', String(flags['ssh-port']));
|
|
59
|
+
if (flags['ssh-identity'])
|
|
60
|
+
args.push('-i', String(flags['ssh-identity']));
|
|
61
|
+
if (flags['ssh-config'])
|
|
62
|
+
args.push('-F', String(flags['ssh-config']));
|
|
63
|
+
return args;
|
|
64
|
+
}
|
|
65
|
+
/** Keep recovery commands on the machine whose files and processes they address. */
|
|
66
|
+
function remoteSuggestion(suggestion, flags) {
|
|
67
|
+
const run = suggestion.run;
|
|
68
|
+
if (!run)
|
|
69
|
+
return suggestion;
|
|
70
|
+
const installerIndex = run.command === 'npx'
|
|
71
|
+
? run.args.findIndex((arg) => arg.startsWith(INSTALLER_PACKAGE + '@'))
|
|
72
|
+
: -1;
|
|
73
|
+
if (installerIndex >= 0) {
|
|
74
|
+
const connection = Object.entries(flags)
|
|
75
|
+
.filter(([key, value]) => key in SSH_FLAGS && value !== undefined)
|
|
76
|
+
.flatMap(([key, value]) => [`--${key}`, String(value)]);
|
|
77
|
+
return {
|
|
78
|
+
...suggestion,
|
|
79
|
+
run: {
|
|
80
|
+
command: process.execPath,
|
|
81
|
+
args: [
|
|
82
|
+
fileURLToPath(new URL('../../bin/run.js', import.meta.url)),
|
|
83
|
+
...run.args.slice(installerIndex + 1),
|
|
84
|
+
...connection,
|
|
85
|
+
],
|
|
86
|
+
},
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
// Archive rebuilds and dependency changes belong in the local application project.
|
|
90
|
+
if (run.command === 'pnpm')
|
|
91
|
+
return {
|
|
92
|
+
...suggestion,
|
|
93
|
+
message: `In the local application project: ${suggestion.message}`,
|
|
94
|
+
};
|
|
95
|
+
return {
|
|
96
|
+
...suggestion,
|
|
97
|
+
run: {
|
|
98
|
+
command: 'ssh',
|
|
99
|
+
args: [
|
|
100
|
+
...sshArgs(flags),
|
|
101
|
+
String(flags.ssh),
|
|
102
|
+
[run.command, ...run.args].map(quoteForShell).join(' '),
|
|
103
|
+
],
|
|
104
|
+
},
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
/** Read the manifest without extracting executable files on the local machine. */
|
|
108
|
+
export async function inspectArchive(file) {
|
|
109
|
+
let text = '';
|
|
110
|
+
let bytes = 0;
|
|
111
|
+
let manifests = 0;
|
|
112
|
+
await list({
|
|
113
|
+
file,
|
|
114
|
+
onReadEntry(entry) {
|
|
115
|
+
bytes += entry.size;
|
|
116
|
+
if (entry.path.replace(/^\.\//u, '') === 'dist/package.json') {
|
|
117
|
+
manifests += 1;
|
|
118
|
+
if (entry.size > 1024 * 1024)
|
|
119
|
+
throw new Error('Archive manifest is too large');
|
|
120
|
+
entry.on('data', (chunk) => {
|
|
121
|
+
text += chunk.toString();
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
},
|
|
125
|
+
});
|
|
126
|
+
if (manifests !== 1)
|
|
127
|
+
throw new InstallerError('ARCHIVE_INVALID', 'Archive must contain exactly one dist/package.json.');
|
|
128
|
+
return { manifest: JSON.parse(text), bytes };
|
|
129
|
+
}
|
|
130
|
+
/** Runs before upload. Node and standard Linux tools are prerequisites, not downloaded on the server. */
|
|
131
|
+
const PREFLIGHT = `
|
|
132
|
+
const fs = require('node:fs'); const path = require('node:path');
|
|
133
|
+
const {spawnSync} = require('node:child_process');
|
|
134
|
+
let input=''; process.stdin.setEncoding('utf8'); process.stdin.on('data',x=>input+=x);
|
|
135
|
+
process.stdin.on('end',()=>{try {
|
|
136
|
+
const r=JSON.parse(input);
|
|
137
|
+
if(process.platform!=='linux'||Number(process.versions.node.split('.')[0])<24) throw Error('Linux and Node.js 24+ are required');
|
|
138
|
+
const t=r.target; const libc=process.report.getReport().header.glibcVersionRuntime?'glibc':'musl';
|
|
139
|
+
if(t&&(t.platform!==process.platform||t.arch!==process.arch||t.nodeMajor!==Number(process.versions.node.split('.')[0])||(t.libc&&t.libc!==libc)))throw Error('Archive build target does not match remote platform, architecture, libc or Node major');
|
|
140
|
+
for(const bin of ['tar','pm2']) {const p=spawnSync('sh',['-c','command -v '+bin],{encoding:'utf8'});if(p.status!==0)throw Error(bin+' is missing from the SSH session PATH');}
|
|
141
|
+
let parent=r.dir;while(!fs.existsSync(parent))parent=path.dirname(parent);
|
|
142
|
+
if(!fs.statSync(parent).isDirectory())throw Error('Target parent is not a directory');
|
|
143
|
+
fs.accessSync(parent,fs.constants.W_OK|fs.constants.X_OK);
|
|
144
|
+
for(const dir of [parent,'/tmp']) {const disk=fs.statfsSync(dir);if(disk.bavail*disk.bsize<r.bytes)throw Error('Insufficient disk space in '+dir);}
|
|
145
|
+
fs.mkdirSync(r.staging,{mode:0o700});
|
|
146
|
+
console.log(JSON.stringify({platform:process.platform,arch:process.arch,node:process.versions.node}));
|
|
147
|
+
}catch(e){console.error(e.message);process.exitCode=2;}});
|
|
148
|
+
`;
|
|
149
|
+
export async function runRemote(command, flags, directory, explicit, deps) {
|
|
150
|
+
const ssh = sshArgs(flags);
|
|
151
|
+
const host = String(flags.ssh);
|
|
152
|
+
const root = directory ?? flags.dir;
|
|
153
|
+
if (typeof root !== 'string' ||
|
|
154
|
+
!path.posix.isAbsolute(root) ||
|
|
155
|
+
path.posix.normalize(root) === '/' ||
|
|
156
|
+
root.includes('\0') ||
|
|
157
|
+
root.includes('\n')) {
|
|
158
|
+
throw new InstallerError('INVALID_USAGE', 'SSH operations require an explicit absolute target --dir other than /.', { exitCode: EXIT_INVALID });
|
|
159
|
+
}
|
|
160
|
+
if (directory && flags.dir && directory !== flags.dir)
|
|
161
|
+
throw new InstallerError('INVALID_USAGE', 'Directory argument and --dir disagree.', { exitCode: EXIT_INVALID });
|
|
162
|
+
if (flags.app || flags.rebuild || (command === 'upgrade' && flags.to))
|
|
163
|
+
throw new InstallerError('INVALID_USAGE', 'SSH deployment is archive-only; --app, --rebuild and npm --to require server internet access.', { exitCode: EXIT_INVALID });
|
|
164
|
+
if (['deploy', 'install', 'upgrade'].includes(command) && !flags.archive)
|
|
165
|
+
throw new InstallerError('INVALID_USAGE', '--archive is required for SSH installation and upgrade.', { exitCode: EXIT_INVALID });
|
|
166
|
+
const env = {};
|
|
167
|
+
for (const setting of (flags['set-from-env'] ?? [])) {
|
|
168
|
+
const name = setting.slice(setting.indexOf('=') + 1);
|
|
169
|
+
if (!setting.includes('=') ||
|
|
170
|
+
!/^[A-Za-z_][A-Za-z0-9_]*$/u.test(name) ||
|
|
171
|
+
process.env[name] === undefined)
|
|
172
|
+
throw new InstallerError('INVALID_USAGE', '--set-from-env must name an existing local environment variable.', { exitCode: EXIT_INVALID });
|
|
173
|
+
// Restrict transport to generated names: a user setting must not override PATH, NODE_OPTIONS or the remote runtime.
|
|
174
|
+
const generated = `NOCOBASE_REMOTE_SECRET_${Object.keys(env).length}`;
|
|
175
|
+
env[generated] = process.env[name];
|
|
176
|
+
}
|
|
177
|
+
const secrets = Object.values(env).filter(Boolean);
|
|
178
|
+
const redact = (text) => secrets.reduce((out, secret) => out
|
|
179
|
+
.split(JSON.stringify(secret).slice(1, -1))
|
|
180
|
+
.join('[REDACTED]')
|
|
181
|
+
.split(secret)
|
|
182
|
+
.join('[REDACTED]'), text);
|
|
183
|
+
const local = await mkdtemp(path.join(os.tmpdir(), 'nocobase-ssh-'));
|
|
184
|
+
const staging = `/tmp/nocobase-deploy-${randomUUID()}`;
|
|
185
|
+
const run = deps.run ?? runCommand;
|
|
186
|
+
const timeoutMs = Number(flags['ssh-timeout'] ?? 1800) * 1000;
|
|
187
|
+
let executing = false;
|
|
188
|
+
let staged = false;
|
|
189
|
+
try {
|
|
190
|
+
const bundle = path.join(local, 'installer.tar.gz');
|
|
191
|
+
await createOfflineBundle(bundle);
|
|
192
|
+
const archive = typeof flags.archive === 'string'
|
|
193
|
+
? path.resolve(deps.cwd ?? process.cwd(), flags.archive)
|
|
194
|
+
: undefined;
|
|
195
|
+
const bundleHash = await sha256(bundle);
|
|
196
|
+
const archiveHash = archive ? await sha256(archive) : undefined;
|
|
197
|
+
const inspected = archive ? await inspectArchive(archive) : undefined;
|
|
198
|
+
if (inspected && !inspected.manifest.nocobase?.buildTarget)
|
|
199
|
+
throw new InstallerError('ARCHIVE_INVALID', 'Archive is missing its build target.');
|
|
200
|
+
const bytes = (await stat(bundle)).size * 10 + (inspected?.bytes ?? 0) * 2;
|
|
201
|
+
deps.reporter.progress(`Checking SSH target ${host}`);
|
|
202
|
+
await run('ssh', [...ssh, host, `node -e ${quoteForShell(PREFLIGHT)}`], {
|
|
203
|
+
input: JSON.stringify({
|
|
204
|
+
dir: root,
|
|
205
|
+
staging,
|
|
206
|
+
bytes,
|
|
207
|
+
target: inspected?.manifest.nocobase?.buildTarget,
|
|
208
|
+
}),
|
|
209
|
+
timeoutMs: 30_000,
|
|
210
|
+
});
|
|
211
|
+
staged = true;
|
|
212
|
+
deps.reporter.progress('Uploading offline installer and application archive');
|
|
213
|
+
await run('scp', [...sshArgs(flags, true), bundle, `${host}:${staging}/installer.tar.gz`], { timeoutMs });
|
|
214
|
+
if (archive)
|
|
215
|
+
await run('scp', [...sshArgs(flags, true), archive, `${host}:${staging}/app.tar.gz`], { timeoutMs });
|
|
216
|
+
const verify = `const fs=require('node:fs'),crypto=require('node:crypto');(async()=>{for(const [file,expected] of ${JSON.stringify([[`${staging}/installer.tar.gz`, bundleHash], ...(archive ? [[`${staging}/app.tar.gz`, archiveHash]] : [])])}){const hash=crypto.createHash('sha256');for await(const chunk of fs.createReadStream(file))hash.update(chunk);if(hash.digest('hex')!==expected)throw Error('Upload checksum mismatch');}})().catch(e=>{console.error(e.message);process.exitCode=2});`;
|
|
217
|
+
await run('ssh', [
|
|
218
|
+
...ssh,
|
|
219
|
+
host,
|
|
220
|
+
`node -e ${quoteForShell(verify)} && tar -xzf ${quoteForShell(staging + '/installer.tar.gz')} -C ${quoteForShell(staging)}`,
|
|
221
|
+
], { timeoutMs });
|
|
222
|
+
const forwarded = Object.fromEntries(Object.entries(flags).filter(([key]) => !(key in SSH_FLAGS)));
|
|
223
|
+
forwarded.dir = root;
|
|
224
|
+
forwarded.archive = archive ? staging + '/app.tar.gz' : undefined;
|
|
225
|
+
if (flags['set-from-env'])
|
|
226
|
+
forwarded['set-from-env'] = flags['set-from-env'].map((x, i) => `${x.slice(0, x.indexOf('='))}=NOCOBASE_REMOTE_SECRET_${i}`);
|
|
227
|
+
const request = {
|
|
228
|
+
command,
|
|
229
|
+
flags: forwarded,
|
|
230
|
+
explicit,
|
|
231
|
+
env,
|
|
232
|
+
...(archive
|
|
233
|
+
? { archive: { file: staging + '/app.tar.gz', sha256: archiveHash } }
|
|
234
|
+
: {}),
|
|
235
|
+
};
|
|
236
|
+
executing = true;
|
|
237
|
+
let response;
|
|
238
|
+
let exitCode = 0;
|
|
239
|
+
try {
|
|
240
|
+
response = await run('ssh', [
|
|
241
|
+
...ssh,
|
|
242
|
+
host,
|
|
243
|
+
`node ${quoteForShell(staging + '/installer/dist/remote-entry.js')}`,
|
|
244
|
+
], { input: JSON.stringify(request), timeoutMs });
|
|
245
|
+
}
|
|
246
|
+
catch (error) {
|
|
247
|
+
if (error instanceof InstallerError && error.code === 'INTERRUPTED')
|
|
248
|
+
throw new Error('Local SSH execution was interrupted before returning a remote result.', { cause: error });
|
|
249
|
+
if (!(error instanceof CommandFailedError) ||
|
|
250
|
+
error.exitCode === 255 ||
|
|
251
|
+
error.exitCode === null)
|
|
252
|
+
throw error;
|
|
253
|
+
response = error;
|
|
254
|
+
exitCode = error.exitCode;
|
|
255
|
+
}
|
|
256
|
+
let envelope;
|
|
257
|
+
try {
|
|
258
|
+
envelope = JSON.parse(redact(response.stdout));
|
|
259
|
+
}
|
|
260
|
+
catch {
|
|
261
|
+
throw new Error('Remote installer did not return a JSON result');
|
|
262
|
+
}
|
|
263
|
+
for (const warning of envelope.warnings ?? [])
|
|
264
|
+
deps.reporter.warn(warning);
|
|
265
|
+
if (envelope.ok && exitCode !== 0)
|
|
266
|
+
throw new Error('Remote process exited nonzero despite a success envelope');
|
|
267
|
+
if (!envelope.ok)
|
|
268
|
+
throw new InstallerError(envelope.error?.code ?? 'REMOTE_FAILED', envelope.error?.message ?? 'Remote operation failed.', {
|
|
269
|
+
exitCode: exitCode || 1,
|
|
270
|
+
details: {
|
|
271
|
+
...envelope.error?.details,
|
|
272
|
+
ssh: host,
|
|
273
|
+
directory: root,
|
|
274
|
+
staging,
|
|
275
|
+
},
|
|
276
|
+
suggestions: (envelope.error?.suggestions ?? []).map((suggestion) => remoteSuggestion(suggestion, flags)),
|
|
277
|
+
});
|
|
278
|
+
const result = envelope.result ?? {};
|
|
279
|
+
let publicHealth = null;
|
|
280
|
+
const url = typeof result.url === 'string'
|
|
281
|
+
? result.url
|
|
282
|
+
: result.endpoints?.url;
|
|
283
|
+
if (url && result.started !== false) {
|
|
284
|
+
publicHealth = await checkHealth(url.replace(/\/$/u, '') + '/api/healthz', deps.fetchImpl);
|
|
285
|
+
if (!publicHealth)
|
|
286
|
+
deps.reporter.warn('Remote operation succeeded, but the public health URL is not reachable from this machine. Check routing, firewall and reverse proxy.');
|
|
287
|
+
}
|
|
288
|
+
await run('ssh', [...ssh, host, `rm -rf -- ${quoteForShell(staging)}`], {
|
|
289
|
+
timeoutMs: 30_000,
|
|
290
|
+
}).catch(() => deps.reporter.warn(`Could not remove remote staging directory ${staging}.`));
|
|
291
|
+
return {
|
|
292
|
+
status: envelope.status ?? 'success',
|
|
293
|
+
result: {
|
|
294
|
+
...result,
|
|
295
|
+
remote: {
|
|
296
|
+
host,
|
|
297
|
+
directory: root,
|
|
298
|
+
publicHealth,
|
|
299
|
+
archiveSha256: archiveHash ?? null,
|
|
300
|
+
},
|
|
301
|
+
},
|
|
302
|
+
summary: [
|
|
303
|
+
`Remote ${command} succeeded on ${host}`,
|
|
304
|
+
` Directory ${root}`,
|
|
305
|
+
...(url ? [` URL ${url}`] : []),
|
|
306
|
+
],
|
|
307
|
+
};
|
|
308
|
+
}
|
|
309
|
+
catch (error) {
|
|
310
|
+
if (error instanceof InstallerError)
|
|
311
|
+
throw error;
|
|
312
|
+
throw new InstallerError(executing ? 'REMOTE_STATE_UNKNOWN' : 'SSH_TRANSFER_FAILED', executing
|
|
313
|
+
? 'SSH execution did not return a complete result. The server may still be deploying; query status before retrying.'
|
|
314
|
+
: 'SSH precheck or transfer failed; the application was not changed.', {
|
|
315
|
+
details: {
|
|
316
|
+
ssh: host,
|
|
317
|
+
directory: root,
|
|
318
|
+
...(staged ? { staging } : {}),
|
|
319
|
+
diagnostic: redact(error instanceof CommandFailedError
|
|
320
|
+
? error.stderr
|
|
321
|
+
: error instanceof Error
|
|
322
|
+
? error.message
|
|
323
|
+
: String(error)),
|
|
324
|
+
},
|
|
325
|
+
});
|
|
326
|
+
}
|
|
327
|
+
finally {
|
|
328
|
+
await rm(local, { recursive: true, force: true });
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
//# sourceMappingURL=remote.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"remote.js","sourceRoot":"","sources":["../../src/lib/remote.ts"],"names":[],"mappings":"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"}
|