seabox 0.1.0-beta.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/.mocharc.json +6 -0
- package/LICENSE.MD +21 -0
- package/README.md +209 -0
- package/bin/seabox-rebuild.js +395 -0
- package/bin/seabox.js +81 -0
- package/lib/bindings.js +31 -0
- package/lib/blob.js +109 -0
- package/lib/bootstrap.js +655 -0
- package/lib/build.js +283 -0
- package/lib/config.js +117 -0
- package/lib/crypto-assets.js +160 -0
- package/lib/fetch-node.js +177 -0
- package/lib/index.js +27 -0
- package/lib/inject.js +81 -0
- package/lib/manifest.js +98 -0
- package/lib/obfuscate.js +73 -0
- package/lib/scanner.js +153 -0
- package/lib/unsign.js +184 -0
- package/package.json +47 -0
package/lib/bindings.js
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* bindings.js - SEA-compatible replacement for the 'bindings' npm package
|
|
3
|
+
* This version uses process.dlopen to load native modules from the SEA cache
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const path = require('path');
|
|
7
|
+
|
|
8
|
+
module.exports = function bindings(name) {
|
|
9
|
+
// Ensure .node extension
|
|
10
|
+
if (!name.endsWith('.node')) {
|
|
11
|
+
name += '.node';
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
// Get cache directory from environment
|
|
15
|
+
const cacheDir = process.env.SEA_CACHE_DIR;
|
|
16
|
+
if (!cacheDir) {
|
|
17
|
+
throw new Error('SEA_CACHE_DIR not set - bindings shim requires SEA context');
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// Construct path to native module in cache
|
|
21
|
+
const binaryPath = path.join(cacheDir, name);
|
|
22
|
+
|
|
23
|
+
// Load using process.dlopen
|
|
24
|
+
const exports = {};
|
|
25
|
+
try {
|
|
26
|
+
process.dlopen({ exports }, binaryPath);
|
|
27
|
+
return exports;
|
|
28
|
+
} catch (err) {
|
|
29
|
+
throw new Error(`Could not load native module "${name}" from SEA cache: ${err.message}`);
|
|
30
|
+
}
|
|
31
|
+
};
|
package/lib/blob.js
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* blob.js
|
|
3
|
+
* Create SEA configuration JSON and prepare blob for injection.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const fs = require('fs');
|
|
7
|
+
const path = require('path');
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* @typedef {Object} SeaBlobConfig
|
|
11
|
+
* @property {string} main - Path to the entry script
|
|
12
|
+
* @property {string} output - Output blob filename
|
|
13
|
+
* @property {boolean} disableExperimentalSEAWarning - Suppress SEA warning
|
|
14
|
+
* @property {boolean} useSnapshot - Enable V8 snapshot
|
|
15
|
+
* @property {boolean} useCodeCache - Enable V8 code cache
|
|
16
|
+
* @property {Object.<string, string|Buffer>} assets - Asset key -> content map
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Create the SEA configuration object for Node.js SEA tooling.
|
|
21
|
+
* @param {string} entryScript - Path to the bundled entry script
|
|
22
|
+
* @param {string} outputBlob - Output blob filename
|
|
23
|
+
* @param {import('./scanner').AssetEntry[]} assets - All assets to embed
|
|
24
|
+
* @param {Object} config - SEA configuration
|
|
25
|
+
* @returns {SeaBlobConfig}
|
|
26
|
+
*/
|
|
27
|
+
function createSeaConfig(entryScript, outputBlob, assets, config) {
|
|
28
|
+
const seaConfig = {
|
|
29
|
+
main: entryScript,
|
|
30
|
+
output: outputBlob,
|
|
31
|
+
disableExperimentalSEAWarning: config.disableExperimentalSEAWarning ?? true,
|
|
32
|
+
useSnapshot: config.useSnapshot ?? false,
|
|
33
|
+
useCodeCache: config.useCodeCache ?? false,
|
|
34
|
+
assets: {}
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
// Add all assets as key -> buffer mappings
|
|
38
|
+
for (const asset of assets) {
|
|
39
|
+
// Handle inline content (e.g., manifest) vs file-based assets
|
|
40
|
+
const content = asset.content
|
|
41
|
+
? asset.content
|
|
42
|
+
: fs.readFileSync(asset.sourcePath);
|
|
43
|
+
seaConfig.assets[asset.assetKey] = content;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return seaConfig;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Write the SEA configuration to a JSON file.
|
|
51
|
+
* This config file is consumed by `node --experimental-sea-config`.
|
|
52
|
+
* @param {SeaBlobConfig} seaConfig
|
|
53
|
+
* @param {string} outputPath - Path to write the config JSON
|
|
54
|
+
* @param {import('./scanner').AssetEntry[]} assets - Original asset entries
|
|
55
|
+
* @param {string} tempDir - Temporary directory for inline assets
|
|
56
|
+
*/
|
|
57
|
+
function writeSeaConfigJson(seaConfig, outputPath, assets, tempDir) {
|
|
58
|
+
// Node's SEA config expects asset values to be file paths (raw assets)
|
|
59
|
+
const jsonConfig = {
|
|
60
|
+
main: seaConfig.main,
|
|
61
|
+
output: seaConfig.output,
|
|
62
|
+
disableExperimentalSEAWarning: seaConfig.disableExperimentalSEAWarning,
|
|
63
|
+
useSnapshot: seaConfig.useSnapshot,
|
|
64
|
+
useCodeCache: seaConfig.useCodeCache,
|
|
65
|
+
assets: {}
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
// Map asset keys to file paths
|
|
69
|
+
for (const asset of assets) {
|
|
70
|
+
if (asset.content) {
|
|
71
|
+
// Inline content (e.g., manifest) - write to temp file
|
|
72
|
+
const tempFilePath = path.join(tempDir, asset.assetKey.replace(/\//g, '_'));
|
|
73
|
+
fs.mkdirSync(path.dirname(tempFilePath), { recursive: true });
|
|
74
|
+
fs.writeFileSync(tempFilePath, asset.content);
|
|
75
|
+
jsonConfig.assets[asset.assetKey] = tempFilePath;
|
|
76
|
+
} else {
|
|
77
|
+
// File-based asset - use source path
|
|
78
|
+
jsonConfig.assets[asset.assetKey] = asset.sourcePath;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
fs.writeFileSync(outputPath, JSON.stringify(jsonConfig, null, 2), 'utf8');
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Generate the SEA blob using Node.js CLI.
|
|
87
|
+
* Executes: node --experimental-sea-config sea-config.json
|
|
88
|
+
* @param {string} seaConfigPath - Path to the SEA config JSON
|
|
89
|
+
* @param {string} nodeBinary - Path to the Node.js binary to use
|
|
90
|
+
* @returns {Promise<void>}
|
|
91
|
+
*/
|
|
92
|
+
async function generateBlob(seaConfigPath, nodeBinary = process.execPath) {
|
|
93
|
+
const { execFile } = require('child_process');
|
|
94
|
+
const { promisify } = require('util');
|
|
95
|
+
const execFileAsync = promisify(execFile);
|
|
96
|
+
|
|
97
|
+
try {
|
|
98
|
+
await execFileAsync(nodeBinary, ['--experimental-sea-config', seaConfigPath]);
|
|
99
|
+
console.log('✓ SEA blob generated successfully');
|
|
100
|
+
} catch (error) {
|
|
101
|
+
throw new Error(`Failed to generate SEA blob: ${error.message}`);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
module.exports = {
|
|
106
|
+
createSeaConfig,
|
|
107
|
+
writeSeaConfigJson,
|
|
108
|
+
generateBlob
|
|
109
|
+
};
|