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.
@@ -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
+ };