seabox 0.1.1 → 0.2.0
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/.mocharc.json +6 -6
- package/LICENSE.MD +21 -21
- package/README.md +310 -310
- package/bin/seabox-rebuild.mjs +88 -88
- package/bin/seabox.mjs +150 -147
- package/lib/blob.mjs +104 -104
- package/lib/bootstrap.cjs +756 -753
- package/lib/build-cache.mjs +199 -199
- package/lib/build.mjs +77 -77
- package/lib/config.mjs +243 -243
- package/lib/crypto-assets.mjs +125 -125
- package/lib/diagnostics.mjs +203 -203
- package/lib/entry-bundler.mjs +64 -64
- package/lib/fetch-node.mjs +172 -172
- package/lib/index.mjs +26 -26
- package/lib/inject.mjs +106 -106
- package/lib/manifest.mjs +100 -100
- package/lib/multi-target-builder.mjs +697 -705
- package/lib/native-scanner.mjs +203 -203
- package/lib/obfuscate.mjs +51 -51
- package/lib/require-shim.mjs +113 -113
- package/lib/rolldown-bundler.mjs +411 -411
- package/lib/unsign.cjs +197 -169
- package/package.json +61 -61
package/lib/entry-bundler.mjs
CHANGED
|
@@ -1,64 +1,64 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* entry-bundler.mjs
|
|
3
|
-
* Bundles the entry file with bootstrap and require shim
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import Module from 'module';
|
|
7
|
-
import { fileURLToPath } from 'url';
|
|
8
|
-
|
|
9
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
10
|
-
const require = Module.createRequire(import.meta.url);
|
|
11
|
-
|
|
12
|
-
const { generateRequireShim, replaceRequireCalls } = require('./require-shim.mjs');
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Bundle the entry file for SEA
|
|
16
|
-
* @param {string} entryContent - The entry file content
|
|
17
|
-
* @param {string} augmentedBootstrap - The bootstrap code
|
|
18
|
-
* @param {boolean} useSnapshot - Whether to use snapshot mode
|
|
19
|
-
* @param {boolean} verbose - Enable verbose logging
|
|
20
|
-
* @returns {string} - The bundled entry content
|
|
21
|
-
*/
|
|
22
|
-
export function bundleEntry(entryContent, augmentedBootstrap, useSnapshot, verbose) {
|
|
23
|
-
// Generate the require shim and replace require() calls
|
|
24
|
-
const requireSeaboxShim = generateRequireShim();
|
|
25
|
-
const transformed = replaceRequireCalls(entryContent, verbose);
|
|
26
|
-
const transformedContent = transformed.code;
|
|
27
|
-
|
|
28
|
-
let bundledEntry;
|
|
29
|
-
|
|
30
|
-
if (useSnapshot) {
|
|
31
|
-
// Snapshot mode
|
|
32
|
-
const parts = [
|
|
33
|
-
augmentedBootstrap,
|
|
34
|
-
'\n\n',
|
|
35
|
-
requireSeaboxShim,
|
|
36
|
-
'\n\n',
|
|
37
|
-
'// Application entry - will be wrapped by bootstrap\'s setDeserializeMainFunction interceptor\n',
|
|
38
|
-
'(function() {\n',
|
|
39
|
-
' const v8 = __originalRequire(\'v8\');\n',
|
|
40
|
-
' if (v8.startupSnapshot && v8.startupSnapshot.isBuildingSnapshot()) {\n',
|
|
41
|
-
' v8.startupSnapshot.setDeserializeMainFunction(() => {\n',
|
|
42
|
-
' if (typeof exports === \'undefined\') {\n',
|
|
43
|
-
' var exports = {};\n',
|
|
44
|
-
' var module = { exports: exports };\n',
|
|
45
|
-
' }\n',
|
|
46
|
-
' // Run the application code\n',
|
|
47
|
-
transformedContent,
|
|
48
|
-
'\n',
|
|
49
|
-
' });\n',
|
|
50
|
-
' } else {\n',
|
|
51
|
-
' // Not building snapshot, run normally\n',
|
|
52
|
-
transformedContent,
|
|
53
|
-
'\n',
|
|
54
|
-
' }\n',
|
|
55
|
-
'})();\n'
|
|
56
|
-
];
|
|
57
|
-
bundledEntry = parts.join('');
|
|
58
|
-
} else {
|
|
59
|
-
// Non-snapshot mode
|
|
60
|
-
bundledEntry = augmentedBootstrap + '\n\n' + requireSeaboxShim + '\n' + transformedContent;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
return bundledEntry;
|
|
64
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* entry-bundler.mjs
|
|
3
|
+
* Bundles the entry file with bootstrap and require shim
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import Module from 'module';
|
|
7
|
+
import { fileURLToPath } from 'url';
|
|
8
|
+
|
|
9
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
10
|
+
const require = Module.createRequire(import.meta.url);
|
|
11
|
+
|
|
12
|
+
const { generateRequireShim, replaceRequireCalls } = require('./require-shim.mjs');
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Bundle the entry file for SEA
|
|
16
|
+
* @param {string} entryContent - The entry file content
|
|
17
|
+
* @param {string} augmentedBootstrap - The bootstrap code
|
|
18
|
+
* @param {boolean} useSnapshot - Whether to use snapshot mode
|
|
19
|
+
* @param {boolean} verbose - Enable verbose logging
|
|
20
|
+
* @returns {string} - The bundled entry content
|
|
21
|
+
*/
|
|
22
|
+
export function bundleEntry(entryContent, augmentedBootstrap, useSnapshot, verbose) {
|
|
23
|
+
// Generate the require shim and replace require() calls
|
|
24
|
+
const requireSeaboxShim = generateRequireShim();
|
|
25
|
+
const transformed = replaceRequireCalls(entryContent, verbose);
|
|
26
|
+
const transformedContent = transformed.code;
|
|
27
|
+
|
|
28
|
+
let bundledEntry;
|
|
29
|
+
|
|
30
|
+
if (useSnapshot) {
|
|
31
|
+
// Snapshot mode
|
|
32
|
+
const parts = [
|
|
33
|
+
augmentedBootstrap,
|
|
34
|
+
'\n\n',
|
|
35
|
+
requireSeaboxShim,
|
|
36
|
+
'\n\n',
|
|
37
|
+
'// Application entry - will be wrapped by bootstrap\'s setDeserializeMainFunction interceptor\n',
|
|
38
|
+
'(function() {\n',
|
|
39
|
+
' const v8 = __originalRequire(\'v8\');\n',
|
|
40
|
+
' if (v8.startupSnapshot && v8.startupSnapshot.isBuildingSnapshot()) {\n',
|
|
41
|
+
' v8.startupSnapshot.setDeserializeMainFunction(() => {\n',
|
|
42
|
+
' if (typeof exports === \'undefined\') {\n',
|
|
43
|
+
' var exports = {};\n',
|
|
44
|
+
' var module = { exports: exports };\n',
|
|
45
|
+
' }\n',
|
|
46
|
+
' // Run the application code\n',
|
|
47
|
+
transformedContent,
|
|
48
|
+
'\n',
|
|
49
|
+
' });\n',
|
|
50
|
+
' } else {\n',
|
|
51
|
+
' // Not building snapshot, run normally\n',
|
|
52
|
+
transformedContent,
|
|
53
|
+
'\n',
|
|
54
|
+
' }\n',
|
|
55
|
+
'})();\n'
|
|
56
|
+
];
|
|
57
|
+
bundledEntry = parts.join('');
|
|
58
|
+
} else {
|
|
59
|
+
// Non-snapshot mode
|
|
60
|
+
bundledEntry = augmentedBootstrap + '\n\n' + requireSeaboxShim + '\n' + transformedContent;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return bundledEntry;
|
|
64
|
+
}
|
package/lib/fetch-node.mjs
CHANGED
|
@@ -1,172 +1,172 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* fetch-node.mjs
|
|
3
|
-
* Download target Node.js binary for SEA injection.
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import fs from 'fs';
|
|
7
|
-
import path from 'path';
|
|
8
|
-
import https from 'https';
|
|
9
|
-
import { pipeline } from 'stream';
|
|
10
|
-
import { promisify } from 'util';
|
|
11
|
-
import AdmZip from 'adm-zip';
|
|
12
|
-
import tar from 'tar';
|
|
13
|
-
import * as diag from './diagnostics.mjs';
|
|
14
|
-
|
|
15
|
-
const pipelineAsync = promisify(pipeline);
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* Construct the Node.js download URL for a given target.
|
|
19
|
-
* @param {string} nodeVersion - e.g., "24.11.0"
|
|
20
|
-
* @param {string} platform - e.g., "win", "linux", "darwin"
|
|
21
|
-
* @param {string} arch - e.g., "x64", "arm64"
|
|
22
|
-
* @returns {string}
|
|
23
|
-
*/
|
|
24
|
-
function getNodeDownloadUrl(nodeVersion, platform, arch) {
|
|
25
|
-
const baseUrl = 'https://nodejs.org/dist';
|
|
26
|
-
|
|
27
|
-
// Map platform names to Node.js naming
|
|
28
|
-
const platformMap = {
|
|
29
|
-
win32: 'win',
|
|
30
|
-
linux: 'linux',
|
|
31
|
-
darwin: 'darwin'
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
const mappedPlatform = platformMap[platform] || platform;
|
|
35
|
-
|
|
36
|
-
// Construct filename
|
|
37
|
-
let filename;
|
|
38
|
-
if (mappedPlatform === 'win') {
|
|
39
|
-
filename = `node-v${nodeVersion}-${mappedPlatform}-${arch}.zip`;
|
|
40
|
-
} else {
|
|
41
|
-
filename = `node-v${nodeVersion}-${mappedPlatform}-${arch}.tar.gz`;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
return `${baseUrl}/v${nodeVersion}/${filename}`;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* Download a file from a URL to a local path.
|
|
49
|
-
* @param {string} url
|
|
50
|
-
* @param {string} outputPath
|
|
51
|
-
* @returns {Promise<void>}
|
|
52
|
-
*/
|
|
53
|
-
async function downloadFile(url, outputPath) {
|
|
54
|
-
return new Promise((resolve, reject) => {
|
|
55
|
-
https.get(url, response => {
|
|
56
|
-
if (response.statusCode === 302 || response.statusCode === 301) {
|
|
57
|
-
// Follow redirect
|
|
58
|
-
return downloadFile(response.headers.location, outputPath)
|
|
59
|
-
.then(resolve)
|
|
60
|
-
.catch(reject);
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
if (response.statusCode !== 200) {
|
|
64
|
-
reject(new Error(`HTTP ${response.statusCode}: ${url}`));
|
|
65
|
-
return;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
const file = fs.createWriteStream(outputPath);
|
|
69
|
-
pipelineAsync(response, file)
|
|
70
|
-
.then(resolve)
|
|
71
|
-
.catch(reject);
|
|
72
|
-
}).on('error', reject);
|
|
73
|
-
});
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
/**
|
|
77
|
-
* Extract node.exe or node binary from downloaded archive.
|
|
78
|
-
* @param {string} archivePath - Path to .zip or .tar.gz
|
|
79
|
-
* @param {string} outputDir - Directory to extract to
|
|
80
|
-
* @param {string} platform - Platform identifier
|
|
81
|
-
* @returns {Promise<string>} - Path to extracted node binary
|
|
82
|
-
*/
|
|
83
|
-
async function extractNodeBinary(archivePath, outputDir, platform) {
|
|
84
|
-
if (platform === 'win32') {
|
|
85
|
-
// Extract from ZIP
|
|
86
|
-
const zip = new AdmZip(archivePath);
|
|
87
|
-
zip.extractAllTo(outputDir, true);
|
|
88
|
-
|
|
89
|
-
// Find node.exe in the extracted directory structure
|
|
90
|
-
const extracted = fs.readdirSync(outputDir);
|
|
91
|
-
for (const item of extracted) {
|
|
92
|
-
const itemPath = path.join(outputDir, item);
|
|
93
|
-
if (fs.statSync(itemPath).isDirectory()) {
|
|
94
|
-
const nodeExePath = path.join(itemPath, 'node.exe');
|
|
95
|
-
if (fs.existsSync(nodeExePath)) {
|
|
96
|
-
const finalPath = path.join(outputDir, 'node.exe');
|
|
97
|
-
fs.renameSync(nodeExePath, finalPath);
|
|
98
|
-
// Clean up extracted directory
|
|
99
|
-
fs.rmSync(itemPath, { recursive: true, force: true });
|
|
100
|
-
return finalPath;
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
throw new Error('node.exe not found in archive');
|
|
106
|
-
} else {
|
|
107
|
-
// Extract from tar.gz
|
|
108
|
-
await tar.extract({
|
|
109
|
-
file: archivePath,
|
|
110
|
-
cwd: outputDir,
|
|
111
|
-
filter: (p) => p.endsWith('/bin/node')
|
|
112
|
-
});
|
|
113
|
-
|
|
114
|
-
// Find the extracted node binary
|
|
115
|
-
const extracted = fs.readdirSync(outputDir);
|
|
116
|
-
for (const dir of extracted) {
|
|
117
|
-
const nodePath = path.join(outputDir, dir, 'bin', 'node');
|
|
118
|
-
if (fs.existsSync(nodePath)) {
|
|
119
|
-
const finalPath = path.join(outputDir, 'node');
|
|
120
|
-
fs.renameSync(nodePath, finalPath);
|
|
121
|
-
fs.chmodSync(finalPath, 0o755);
|
|
122
|
-
return finalPath;
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
throw new Error('node binary not found in archive');
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
/**
|
|
131
|
-
* Fetch and prepare a Node.js binary for SEA injection.
|
|
132
|
-
* @param {string} nodeVersion
|
|
133
|
-
* @param {string} platform
|
|
134
|
-
* @param {string} arch
|
|
135
|
-
* @param {string} cacheDir - Directory to cache downloads
|
|
136
|
-
* @returns {Promise<string>} - Path to the node binary
|
|
137
|
-
*/
|
|
138
|
-
export async function fetchNodeBinary(nodeVersion, platform, arch, cacheDir) {
|
|
139
|
-
if (!fs.existsSync(cacheDir)) {
|
|
140
|
-
fs.mkdirSync(cacheDir, { recursive: true });
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
const binaryName = platform === 'win32' ? 'node.exe' : 'node';
|
|
144
|
-
const cachedBinary = path.join(cacheDir, `${nodeVersion}-${platform}-${arch}`, binaryName);
|
|
145
|
-
|
|
146
|
-
// Check cache
|
|
147
|
-
if (fs.existsSync(cachedBinary)) {
|
|
148
|
-
diag.verbose(`Using cached Node binary: ${cachedBinary}`, 1);
|
|
149
|
-
return cachedBinary;
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
diag.verbose(`Downloading Node.js v${nodeVersion} for ${platform}-${arch}...`, 1);
|
|
153
|
-
const url = getNodeDownloadUrl(nodeVersion, platform, arch);
|
|
154
|
-
const archiveName = path.basename(url);
|
|
155
|
-
const archivePath = path.join(cacheDir, archiveName);
|
|
156
|
-
|
|
157
|
-
await downloadFile(url, archivePath);
|
|
158
|
-
diag.verbose(`Downloaded: ${archivePath}`, 1);
|
|
159
|
-
|
|
160
|
-
const extractDir = path.join(cacheDir, `${nodeVersion}-${platform}-${arch}`);
|
|
161
|
-
fs.mkdirSync(extractDir, { recursive: true });
|
|
162
|
-
|
|
163
|
-
const binaryPath = await extractNodeBinary(archivePath, extractDir, platform);
|
|
164
|
-
diag.verbose(`Extracted Node binary: ${binaryPath}`, 1);
|
|
165
|
-
|
|
166
|
-
// Clean up archive
|
|
167
|
-
fs.unlinkSync(archivePath);
|
|
168
|
-
|
|
169
|
-
return binaryPath;
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
export { getNodeDownloadUrl, downloadFile, extractNodeBinary };
|
|
1
|
+
/**
|
|
2
|
+
* fetch-node.mjs
|
|
3
|
+
* Download target Node.js binary for SEA injection.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import fs from 'fs';
|
|
7
|
+
import path from 'path';
|
|
8
|
+
import https from 'https';
|
|
9
|
+
import { pipeline } from 'stream';
|
|
10
|
+
import { promisify } from 'util';
|
|
11
|
+
import AdmZip from 'adm-zip';
|
|
12
|
+
import tar from 'tar';
|
|
13
|
+
import * as diag from './diagnostics.mjs';
|
|
14
|
+
|
|
15
|
+
const pipelineAsync = promisify(pipeline);
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Construct the Node.js download URL for a given target.
|
|
19
|
+
* @param {string} nodeVersion - e.g., "24.11.0"
|
|
20
|
+
* @param {string} platform - e.g., "win", "linux", "darwin"
|
|
21
|
+
* @param {string} arch - e.g., "x64", "arm64"
|
|
22
|
+
* @returns {string}
|
|
23
|
+
*/
|
|
24
|
+
function getNodeDownloadUrl(nodeVersion, platform, arch) {
|
|
25
|
+
const baseUrl = 'https://nodejs.org/dist';
|
|
26
|
+
|
|
27
|
+
// Map platform names to Node.js naming
|
|
28
|
+
const platformMap = {
|
|
29
|
+
win32: 'win',
|
|
30
|
+
linux: 'linux',
|
|
31
|
+
darwin: 'darwin'
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const mappedPlatform = platformMap[platform] || platform;
|
|
35
|
+
|
|
36
|
+
// Construct filename
|
|
37
|
+
let filename;
|
|
38
|
+
if (mappedPlatform === 'win') {
|
|
39
|
+
filename = `node-v${nodeVersion}-${mappedPlatform}-${arch}.zip`;
|
|
40
|
+
} else {
|
|
41
|
+
filename = `node-v${nodeVersion}-${mappedPlatform}-${arch}.tar.gz`;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return `${baseUrl}/v${nodeVersion}/${filename}`;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Download a file from a URL to a local path.
|
|
49
|
+
* @param {string} url
|
|
50
|
+
* @param {string} outputPath
|
|
51
|
+
* @returns {Promise<void>}
|
|
52
|
+
*/
|
|
53
|
+
async function downloadFile(url, outputPath) {
|
|
54
|
+
return new Promise((resolve, reject) => {
|
|
55
|
+
https.get(url, response => {
|
|
56
|
+
if (response.statusCode === 302 || response.statusCode === 301) {
|
|
57
|
+
// Follow redirect
|
|
58
|
+
return downloadFile(response.headers.location, outputPath)
|
|
59
|
+
.then(resolve)
|
|
60
|
+
.catch(reject);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (response.statusCode !== 200) {
|
|
64
|
+
reject(new Error(`HTTP ${response.statusCode}: ${url}`));
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const file = fs.createWriteStream(outputPath);
|
|
69
|
+
pipelineAsync(response, file)
|
|
70
|
+
.then(resolve)
|
|
71
|
+
.catch(reject);
|
|
72
|
+
}).on('error', reject);
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Extract node.exe or node binary from downloaded archive.
|
|
78
|
+
* @param {string} archivePath - Path to .zip or .tar.gz
|
|
79
|
+
* @param {string} outputDir - Directory to extract to
|
|
80
|
+
* @param {string} platform - Platform identifier
|
|
81
|
+
* @returns {Promise<string>} - Path to extracted node binary
|
|
82
|
+
*/
|
|
83
|
+
async function extractNodeBinary(archivePath, outputDir, platform) {
|
|
84
|
+
if (platform === 'win32') {
|
|
85
|
+
// Extract from ZIP
|
|
86
|
+
const zip = new AdmZip(archivePath);
|
|
87
|
+
zip.extractAllTo(outputDir, true);
|
|
88
|
+
|
|
89
|
+
// Find node.exe in the extracted directory structure
|
|
90
|
+
const extracted = fs.readdirSync(outputDir);
|
|
91
|
+
for (const item of extracted) {
|
|
92
|
+
const itemPath = path.join(outputDir, item);
|
|
93
|
+
if (fs.statSync(itemPath).isDirectory()) {
|
|
94
|
+
const nodeExePath = path.join(itemPath, 'node.exe');
|
|
95
|
+
if (fs.existsSync(nodeExePath)) {
|
|
96
|
+
const finalPath = path.join(outputDir, 'node.exe');
|
|
97
|
+
fs.renameSync(nodeExePath, finalPath);
|
|
98
|
+
// Clean up extracted directory
|
|
99
|
+
fs.rmSync(itemPath, { recursive: true, force: true });
|
|
100
|
+
return finalPath;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
throw new Error('node.exe not found in archive');
|
|
106
|
+
} else {
|
|
107
|
+
// Extract from tar.gz
|
|
108
|
+
await tar.extract({
|
|
109
|
+
file: archivePath,
|
|
110
|
+
cwd: outputDir,
|
|
111
|
+
filter: (p) => p.endsWith('/bin/node')
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
// Find the extracted node binary
|
|
115
|
+
const extracted = fs.readdirSync(outputDir);
|
|
116
|
+
for (const dir of extracted) {
|
|
117
|
+
const nodePath = path.join(outputDir, dir, 'bin', 'node');
|
|
118
|
+
if (fs.existsSync(nodePath)) {
|
|
119
|
+
const finalPath = path.join(outputDir, 'node');
|
|
120
|
+
fs.renameSync(nodePath, finalPath);
|
|
121
|
+
fs.chmodSync(finalPath, 0o755);
|
|
122
|
+
return finalPath;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
throw new Error('node binary not found in archive');
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Fetch and prepare a Node.js binary for SEA injection.
|
|
132
|
+
* @param {string} nodeVersion
|
|
133
|
+
* @param {string} platform
|
|
134
|
+
* @param {string} arch
|
|
135
|
+
* @param {string} cacheDir - Directory to cache downloads
|
|
136
|
+
* @returns {Promise<string>} - Path to the node binary
|
|
137
|
+
*/
|
|
138
|
+
export async function fetchNodeBinary(nodeVersion, platform, arch, cacheDir) {
|
|
139
|
+
if (!fs.existsSync(cacheDir)) {
|
|
140
|
+
fs.mkdirSync(cacheDir, { recursive: true });
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
const binaryName = platform === 'win32' ? 'node.exe' : 'node';
|
|
144
|
+
const cachedBinary = path.join(cacheDir, `${nodeVersion}-${platform}-${arch}`, binaryName);
|
|
145
|
+
|
|
146
|
+
// Check cache
|
|
147
|
+
if (fs.existsSync(cachedBinary)) {
|
|
148
|
+
diag.verbose(`Using cached Node binary: ${cachedBinary}`, 1);
|
|
149
|
+
return cachedBinary;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
diag.verbose(`Downloading Node.js v${nodeVersion} for ${platform}-${arch}...`, 1);
|
|
153
|
+
const url = getNodeDownloadUrl(nodeVersion, platform, arch);
|
|
154
|
+
const archiveName = path.basename(url);
|
|
155
|
+
const archivePath = path.join(cacheDir, archiveName);
|
|
156
|
+
|
|
157
|
+
await downloadFile(url, archivePath);
|
|
158
|
+
diag.verbose(`Downloaded: ${archivePath}`, 1);
|
|
159
|
+
|
|
160
|
+
const extractDir = path.join(cacheDir, `${nodeVersion}-${platform}-${arch}`);
|
|
161
|
+
fs.mkdirSync(extractDir, { recursive: true });
|
|
162
|
+
|
|
163
|
+
const binaryPath = await extractNodeBinary(archivePath, extractDir, platform);
|
|
164
|
+
diag.verbose(`Extracted Node binary: ${binaryPath}`, 1);
|
|
165
|
+
|
|
166
|
+
// Clean up archive
|
|
167
|
+
fs.unlinkSync(archivePath);
|
|
168
|
+
|
|
169
|
+
return binaryPath;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
export { getNodeDownloadUrl, downloadFile, extractNodeBinary };
|
package/lib/index.mjs
CHANGED
|
@@ -1,26 +1,26 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* index.mjs
|
|
3
|
-
* Main entry point for Seabox v2 library.
|
|
4
|
-
* Exports all public APIs.
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
export { build } from './build.mjs';
|
|
8
|
-
export {
|
|
9
|
-
loadConfig,
|
|
10
|
-
validateConfig,
|
|
11
|
-
parseTarget,
|
|
12
|
-
generateDefaultConfig,
|
|
13
|
-
normalizeConfig,
|
|
14
|
-
getDefaultLibraryPatterns
|
|
15
|
-
} from './config.mjs';
|
|
16
|
-
export { MultiTargetBuilder } from './multi-target-builder.mjs';
|
|
17
|
-
export { bundleWithRollup, NativeModuleDetectorPlugin } from './rolldown-bundler.mjs';
|
|
18
|
-
export { scanDependenciesForNativeModules, findNativeModuleBuildPath } from './native-scanner.mjs';
|
|
19
|
-
export { BuildCache } from './build-cache.mjs';
|
|
20
|
-
export { generateManifest, serializeManifest } from './manifest.mjs';
|
|
21
|
-
export { createSeaConfig, writeSeaConfigJson, generateBlob } from './blob.mjs';
|
|
22
|
-
export { fetchNodeBinary } from './fetch-node.mjs';
|
|
23
|
-
export { injectBlob } from './inject.mjs';
|
|
24
|
-
export { generateEncryptionKey, encryptAsset, decryptAsset, encryptAssets, keyToObfuscatedCode } from './crypto-assets.mjs';
|
|
25
|
-
export { obfuscateBootstrap } from './obfuscate.mjs';
|
|
26
|
-
export { bundleEntry } from './entry-bundler.mjs';
|
|
1
|
+
/**
|
|
2
|
+
* index.mjs
|
|
3
|
+
* Main entry point for Seabox v2 library.
|
|
4
|
+
* Exports all public APIs.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export { build } from './build.mjs';
|
|
8
|
+
export {
|
|
9
|
+
loadConfig,
|
|
10
|
+
validateConfig,
|
|
11
|
+
parseTarget,
|
|
12
|
+
generateDefaultConfig,
|
|
13
|
+
normalizeConfig,
|
|
14
|
+
getDefaultLibraryPatterns
|
|
15
|
+
} from './config.mjs';
|
|
16
|
+
export { MultiTargetBuilder } from './multi-target-builder.mjs';
|
|
17
|
+
export { bundleWithRollup, NativeModuleDetectorPlugin } from './rolldown-bundler.mjs';
|
|
18
|
+
export { scanDependenciesForNativeModules, findNativeModuleBuildPath } from './native-scanner.mjs';
|
|
19
|
+
export { BuildCache } from './build-cache.mjs';
|
|
20
|
+
export { generateManifest, serializeManifest } from './manifest.mjs';
|
|
21
|
+
export { createSeaConfig, writeSeaConfigJson, generateBlob } from './blob.mjs';
|
|
22
|
+
export { fetchNodeBinary } from './fetch-node.mjs';
|
|
23
|
+
export { injectBlob } from './inject.mjs';
|
|
24
|
+
export { generateEncryptionKey, encryptAsset, decryptAsset, encryptAssets, keyToObfuscatedCode } from './crypto-assets.mjs';
|
|
25
|
+
export { obfuscateBootstrap } from './obfuscate.mjs';
|
|
26
|
+
export { bundleEntry } from './entry-bundler.mjs';
|