@juniorsir/vessel 1.0.0 → 1.0.1
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/index.js +29 -3
- package/package.json +30 -9
- package/scripts/install.js +55 -25
package/bin/index.js
CHANGED
|
@@ -1,14 +1,40 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
const { spawn } = require('child_process');
|
|
3
|
+
const fs = require('fs');
|
|
3
4
|
const path = require('path');
|
|
4
5
|
|
|
5
6
|
const binaryPath = path.join(__dirname, 'vessel-native');
|
|
6
7
|
|
|
7
|
-
//
|
|
8
|
+
// 1. Sanity check: Ensure the postinstall script actually succeeded
|
|
9
|
+
if (!fs.existsSync(binaryPath)) {
|
|
10
|
+
console.error(`\x1b[1m\x1b[31m[vessel-npm] Fatal Error: Native core missing.\x1b[0m`);
|
|
11
|
+
console.error(`Could not find the executable at: ${binaryPath}`);
|
|
12
|
+
console.error(`It looks like the install script failed or was skipped by your package manager.`);
|
|
13
|
+
console.error(`Try running: \x1b[1mnpm rebuild @juniorsir/vessel\x1b[0m\n`);
|
|
14
|
+
process.exit(1);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// 2. Spawn the Rust binary
|
|
18
|
+
// We pass process.env explicitly to ensure variables like $PREFIX reach the Rust Termux detector
|
|
8
19
|
const child = spawn(binaryPath, process.argv.slice(2), {
|
|
9
|
-
stdio: 'inherit'
|
|
20
|
+
stdio: 'inherit',
|
|
21
|
+
env: process.env
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
// 3. Transparent Signal Forwarding
|
|
25
|
+
// If the user presses Ctrl+C (SIGINT), we must forward it to Rust so it can cleanly detach mounted filesystems
|
|
26
|
+
const SIGNALS = ['SIGINT', 'SIGTERM', 'SIGQUIT'];
|
|
27
|
+
SIGNALS.forEach(signal => {
|
|
28
|
+
process.on(signal, () => {
|
|
29
|
+
child.kill(signal);
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
child.on('error', (err) => {
|
|
34
|
+
console.error(`\x1b[1m\x1b[31m[vessel-npm] Execution failed:\x1b[0m ${err.message}`);
|
|
35
|
+
process.exit(1);
|
|
10
36
|
});
|
|
11
37
|
|
|
12
38
|
child.on('close', (code) => {
|
|
13
|
-
process.exit(code);
|
|
39
|
+
process.exit(code ?? 0);
|
|
14
40
|
});
|
package/package.json
CHANGED
|
@@ -1,19 +1,40 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@juniorsir/vessel",
|
|
3
|
-
"version": "1.0.
|
|
4
|
-
"description": "NEXUS: High-performance local containerization engine",
|
|
5
|
-
"
|
|
6
|
-
"type": "git",
|
|
7
|
-
"url": "git+https://github.com/juniorsir/vessel.git"
|
|
8
|
-
},
|
|
3
|
+
"version": "1.0.1",
|
|
4
|
+
"description": "NEXUS: High-performance local containerization engine & zero-latency sandbox",
|
|
5
|
+
"main": "bin/index.js",
|
|
9
6
|
"bin": {
|
|
10
7
|
"vessel": "./bin/index.js"
|
|
11
8
|
},
|
|
12
9
|
"scripts": {
|
|
13
10
|
"postinstall": "node ./scripts/install.js"
|
|
14
11
|
},
|
|
15
|
-
"
|
|
16
|
-
"
|
|
12
|
+
"repository": {
|
|
13
|
+
"type": "git",
|
|
14
|
+
"url": "git+https://github.com/juniorsir/vessel.git"
|
|
17
15
|
},
|
|
18
|
-
"
|
|
16
|
+
"keywords": [
|
|
17
|
+
"container",
|
|
18
|
+
"sandbox",
|
|
19
|
+
"docker",
|
|
20
|
+
"termux",
|
|
21
|
+
"linux",
|
|
22
|
+
"namespaces",
|
|
23
|
+
"cgroups",
|
|
24
|
+
"virtualization",
|
|
25
|
+
"rust"
|
|
26
|
+
],
|
|
27
|
+
"author": "JuniorSir <https://github.com/juniorsir>",
|
|
28
|
+
"license": "MIT",
|
|
29
|
+
"bugs": {
|
|
30
|
+
"url": "https://github.com/juniorsir/vessel/issues"
|
|
31
|
+
},
|
|
32
|
+
"homepage": "https://github.com/juniorsir/vessel#readme",
|
|
33
|
+
"os": [
|
|
34
|
+
"linux",
|
|
35
|
+
"android"
|
|
36
|
+
],
|
|
37
|
+
"engines": {
|
|
38
|
+
"node": ">=14.0.0"
|
|
39
|
+
}
|
|
19
40
|
}
|
package/scripts/install.js
CHANGED
|
@@ -2,51 +2,81 @@ const fs = require('fs');
|
|
|
2
2
|
const path = require('path');
|
|
3
3
|
const https = require('https');
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
const
|
|
5
|
+
// Respect environment variable overrides for CI/CD testing
|
|
6
|
+
const VERSION = process.env.VESSEL_VERSION || 'v1.0.1';
|
|
7
|
+
const REPO = process.env.VESSEL_REPO || 'juniorsir/vessel';
|
|
7
8
|
const BIN_DIR = path.join(__dirname, '../bin');
|
|
8
9
|
const BIN_PATH = path.join(BIN_DIR, 'vessel-native');
|
|
9
10
|
|
|
10
|
-
//
|
|
11
|
+
// Smart Platform/Arch Mapping (Includes Termux Android support)
|
|
11
12
|
const platforms = {
|
|
12
13
|
'linux-x64': 'vessel-linux-amd64',
|
|
13
|
-
'linux-arm64': 'vessel-linux-arm64'
|
|
14
|
+
'linux-arm64': 'vessel-linux-arm64',
|
|
15
|
+
'android-arm64': 'vessel-linux-arm64', // Termux 64-bit
|
|
16
|
+
'android-x64': 'vessel-linux-amd64' // Termux x86_64 emulator
|
|
14
17
|
};
|
|
15
18
|
|
|
16
19
|
const key = `${process.platform}-${process.arch}`;
|
|
17
20
|
const assetName = platforms[key];
|
|
18
21
|
|
|
19
22
|
if (!assetName) {
|
|
20
|
-
console.error(
|
|
23
|
+
console.error(`\x1b[1m\x1b[31m[vessel-npm] Unsupported environment: ${key}\x1b[0m`);
|
|
24
|
+
console.error(`Vessel relies on low-level Linux namespaces and is only supported on Linux and Android (Termux).`);
|
|
21
25
|
process.exit(1);
|
|
22
26
|
}
|
|
23
27
|
|
|
24
28
|
if (!fs.existsSync(BIN_DIR)) {
|
|
25
|
-
fs.mkdirSync(BIN_DIR);
|
|
29
|
+
fs.mkdirSync(BIN_DIR, { recursive: true });
|
|
26
30
|
}
|
|
27
31
|
|
|
28
32
|
const url = `https://github.com/${REPO}/releases/download/${VERSION}/${assetName}`;
|
|
33
|
+
console.log(`\x1b[1m\x1b[36m[vessel-npm]\x1b[0m Fetching native binary for \x1b[33m${key}\x1b[0m...`);
|
|
29
34
|
|
|
30
|
-
|
|
35
|
+
// Advanced download function with recursive redirect following and progress tracking
|
|
36
|
+
function downloadFile(url, dest, redirectCount = 0) {
|
|
37
|
+
if (redirectCount > 5) {
|
|
38
|
+
console.error('\x1b[31m[vessel-npm] Error: Too many redirects.\x1b[0m');
|
|
39
|
+
process.exit(1);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
https.get(url, (res) => {
|
|
43
|
+
if (res.statusCode === 301 || res.statusCode === 302) {
|
|
44
|
+
return downloadFile(res.headers.location, dest, redirectCount + 1);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (res.statusCode !== 200) {
|
|
48
|
+
console.error(`\x1b[31m[vessel-npm] Error downloading binary: HTTP ${res.statusCode}\x1b[0m`);
|
|
49
|
+
console.error(`Attempted URL: ${url}`);
|
|
50
|
+
process.exit(1);
|
|
51
|
+
}
|
|
31
52
|
|
|
32
|
-
const
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
53
|
+
const totalBytes = parseInt(res.headers['content-length'], 10);
|
|
54
|
+
let downloadedBytes = 0;
|
|
55
|
+
const file = fs.createWriteStream(dest);
|
|
56
|
+
|
|
57
|
+
res.on('data', (chunk) => {
|
|
58
|
+
downloadedBytes += chunk.length;
|
|
59
|
+
if (totalBytes) {
|
|
60
|
+
const percent = ((downloadedBytes / totalBytes) * 100).toFixed(1);
|
|
61
|
+
process.stdout.write(`\r\x1b[36m ↳ Downloading:\x1b[0m ${percent}% (${(downloadedBytes / 1024 / 1024).toFixed(2)} MB)`);
|
|
62
|
+
} else {
|
|
63
|
+
process.stdout.write(`\r\x1b[36m ↳ Downloading:\x1b[0m ${(downloadedBytes / 1024 / 1024).toFixed(2)} MB`);
|
|
64
|
+
}
|
|
38
65
|
});
|
|
39
|
-
} else {
|
|
40
|
-
response.pipe(file);
|
|
41
|
-
}
|
|
42
66
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
67
|
+
res.pipe(file);
|
|
68
|
+
|
|
69
|
+
file.on('finish', () => {
|
|
70
|
+
file.close();
|
|
71
|
+
fs.chmodSync(dest, 0o755); // Ensure executable permissions
|
|
72
|
+
console.log('\n\x1b[1m\x1b[32m✔ [vessel-npm] Native core installed successfully.\x1b[0m');
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
}).on('error', (err) => {
|
|
76
|
+
fs.unlink(dest, () => {});
|
|
77
|
+
console.error(`\n\x1b[31m[vessel-npm] Network error: ${err.message}\x1b[0m`);
|
|
78
|
+
process.exit(1);
|
|
47
79
|
});
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
process.exit(1);
|
|
52
|
-
});
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
downloadFile(url, BIN_PATH);
|