seabox 0.2.0 → 0.3.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.
@@ -16,15 +16,16 @@ const __dirname = path.dirname(__filename);
16
16
  /**
17
17
  * Rebuild a native module for a specific target
18
18
  * @param {string} modulePath - Path to the native module
19
+ * @param {string} nodeVersion - Target Node.js version (e.g., "24.13.0")
19
20
  * @param {string} platform - Target platform (win32, linux, darwin)
20
21
  * @param {string} arch - Target architecture (x64, arm64)
21
22
  * @param {boolean} verbose - Enable verbose logging
22
23
  */
23
- function rebuildNativeModule(modulePath, platform, arch, verbose = false) {
24
+ function rebuildNativeModule(modulePath, nodeVersion, platform, arch, verbose = false) {
24
25
  diag.setVerbose(verbose);
25
26
 
26
27
  diag.verbose(`Rebuilding native module: ${modulePath}`);
27
- diag.verbose(`Target: ${platform}-${arch}`);
28
+ diag.verbose(`Target: Node.js ${nodeVersion} ${platform}-${arch}`);
28
29
 
29
30
  const packageJsonPath = path.join(modulePath, 'package.json');
30
31
  if (!fs.existsSync(packageJsonPath)) {
@@ -42,42 +43,60 @@ function rebuildNativeModule(modulePath, platform, arch, verbose = false) {
42
43
  }
43
44
 
44
45
  try {
45
- // Use node-gyp to rebuild for the target platform
46
- const cmd = `npx node-gyp rebuild --target_platform=${platform} --target_arch=${arch}`;
46
+ // Use node-gyp to rebuild for the target Node.js version, platform, and architecture
47
+ // --target specifies the Node.js version (critical for NODE_MODULE_VERSION)
48
+ // --dist-url ensures node-gyp downloads headers from the correct location
49
+ const cmd = `npx node-gyp rebuild --target=${nodeVersion} --arch=${arch} --dist-url=https://nodejs.org/dist`;
47
50
 
48
- diag.verbose(`Running: ${cmd}`);
51
+ diag.verbose(`Building for Node.js ${nodeVersion} (${platform}-${arch})`, 2);
52
+ diag.verbose(`Command: ${cmd}`, 2);
49
53
 
50
54
  execSync(cmd, {
51
55
  cwd: modulePath,
52
- stdio: verbose ? 'inherit' : 'pipe',
56
+ stdio: 'pipe', // Hide output unless error occurs
53
57
  env: {
54
58
  ...process.env,
55
- npm_config_target_platform: platform,
56
- npm_config_target_arch: arch
59
+ npm_config_target: nodeVersion,
60
+ npm_config_arch: arch,
61
+ npm_config_target_arch: arch,
62
+ npm_config_disturl: 'https://nodejs.org/dist'
57
63
  }
58
64
  });
59
65
 
60
- diag.verbose(`Successfully rebuilt ${moduleName}`);
66
+ diag.verbose(`Successfully built for Node.js ${nodeVersion}`, 2);
61
67
  } catch (error) {
68
+ // Show node-gyp output on error
69
+ if (error.stdout) console.error(error.stdout.toString());
70
+ if (error.stderr) console.error(error.stderr.toString());
62
71
  diag.verbose(`Failed to rebuild ${moduleName}: ${error.message}`);
63
72
  throw error;
64
73
  }
65
74
  }
66
75
 
67
- // CLI entry point
68
- if (import.meta.url === `file://${process.argv[1]}`) {
76
+ // CLI entry point - compare normalized paths for cross-platform compatibility
77
+ const isMainModule = (() => {
78
+ try {
79
+ const scriptPath = fileURLToPath(import.meta.url);
80
+ const argPath = path.resolve(process.argv[1]);
81
+ return scriptPath === argPath;
82
+ } catch {
83
+ return false;
84
+ }
85
+ })();
86
+
87
+ if (isMainModule) {
69
88
  const args = process.argv.slice(2);
70
89
 
71
- if (args.length < 3) {
72
- diag.error('Usage: seabox-rebuild <module-path> <platform> <arch> [--verbose]');
90
+ if (args.length < 4) {
91
+ diag.error('Usage: seabox-rebuild <module-path> <node-version> <platform> <arch> [--verbose]');
73
92
  process.exit(1);
74
93
  }
75
94
 
76
- const [modulePath, platform, arch] = args;
95
+ const [modulePath, nodeVersion, platform, arch] = args;
77
96
  const verbose = args.includes('--verbose') || args.includes('-v');
78
97
 
79
98
  try {
80
- rebuildNativeModule(modulePath, platform, arch, verbose);
99
+ rebuildNativeModule(modulePath, nodeVersion, platform, arch, verbose);
81
100
  process.exit(0);
82
101
  } catch (error) {
83
102
  diag.error(`Rebuild failed: ${error.message}`);
@@ -110,13 +110,15 @@ export class BuildCache {
110
110
  /**
111
111
  * Get cached native module build
112
112
  * @param {string} moduleRoot - Module root path
113
- * @param {string} target - Build target
113
+ * @param {string} target - Build target (e.g., node24.11.0-win32-x64)
114
114
  * @returns {string|null} - Path to cached .node file
115
115
  */
116
116
  getCachedNativeBuild(moduleRoot, target) {
117
+ // Include the FULL target string (with Node.js version) in cache key
118
+ // This ensures different Node.js versions have separate cache entries
117
119
  const cacheKey = crypto
118
120
  .createHash('sha256')
119
- .update(moduleRoot + target)
121
+ .update(`${moduleRoot}||${target}`)
120
122
  .digest('hex')
121
123
  .substring(0, 16);
122
124
 
@@ -132,6 +134,9 @@ export class BuildCache {
132
134
  if (cacheStats.mtime > sourceStats.mtime) {
133
135
  return cachePath;
134
136
  }
137
+ } else {
138
+ // If no binding.gyp, still return cached binary (e.g., prebuild scenario)
139
+ return cachePath;
135
140
  }
136
141
  }
137
142
 
@@ -141,13 +146,15 @@ export class BuildCache {
141
146
  /**
142
147
  * Cache a native module build
143
148
  * @param {string} moduleRoot - Module root path
144
- * @param {string} target - Build target
149
+ * @param {string} target - Build target (e.g., node24.11.0-win32-x64)
145
150
  * @param {string} builtBinaryPath - Path to built .node file
146
151
  */
147
152
  cacheNativeBuild(moduleRoot, target, builtBinaryPath) {
153
+ // Use the FULL target string (with Node.js version) in cache key
154
+ // This ensures different Node.js versions have separate cache entries
148
155
  const cacheKey = crypto
149
156
  .createHash('sha256')
150
- .update(moduleRoot + target)
157
+ .update(`${moduleRoot}||${target}`)
151
158
  .digest('hex')
152
159
  .substring(0, 16);
153
160
 
@@ -287,7 +287,7 @@ export class MultiTargetBuilder {
287
287
  }
288
288
 
289
289
  // Rebuild the module
290
- diag.verbose(`Rebuilding: ${moduleName}`, 2);
290
+ diag.verbose(`Rebuilding: ${moduleName} for Node.js ${parseTarget(target).nodeVersion}`, 2);
291
291
 
292
292
  await this.rebuildNativeModule(moduleInfo.packageRoot, target);
293
293
 
@@ -326,9 +326,12 @@ export class MultiTargetBuilder {
326
326
  throw new Error('seabox-rebuild.mjs not found');
327
327
  }
328
328
 
329
+ const { nodeVersion, platform, arch } = parseTarget(target);
330
+
329
331
  try {
330
- execSync(`node "${rebuildScript}" --target ${target} "${packageRoot}"`, {
331
- stdio: this.verbose ? 'inherit' : 'pipe',
332
+ // Always inherit stdio to show node-gyp progress (header downloads, etc.)
333
+ execSync(`node "${rebuildScript}" "${packageRoot}" ${nodeVersion} ${platform} ${arch}${this.verbose ? ' --verbose' : ''}`, {
334
+ stdio: 'inherit', // Show node-gyp output including header downloads
332
335
  cwd: this.projectRoot
333
336
  });
334
337
  } catch (err) {
@@ -613,16 +616,17 @@ const SEA_ENCRYPTED_ASSETS = new Set([]);
613
616
  const seaConfigPath = path.join(tempDir, 'sea-config.json');
614
617
  writeSeaConfigJson(seaConfig, seaConfigPath, allAssets, tempDir);
615
618
 
616
- // Generate blob
617
- await generateBlob(seaConfigPath, process.execPath);
618
- diag.success('SEA blob generated');
619
-
620
- // Fetch Node binary
619
+ // Fetch Node binary FIRST - needed for blob generation
621
620
  diag.buildStep(buildNumber, 5, 'Fetching Node.js binary...');
622
621
  const cacheDir = path.join(this.projectRoot, 'node_modules', '.cache', 'sea-node-binaries');
623
622
  const nodeBinary = await fetchNodeBinary(nodeVersion, platform, arch, cacheDir);
624
623
  diag.success('Node binary ready');
625
624
 
625
+ // Generate blob using the TARGET Node.js binary (not current process.execPath)
626
+ // This is critical for snapshots - they must be built with the target Node version
627
+ await generateBlob(seaConfigPath, nodeBinary);
628
+ diag.success('SEA blob generated');
629
+
626
630
  // Inject blob
627
631
  diag.buildStep(buildNumber, 6, 'Injecting blob into executable...');
628
632
  const outputExe = path.join(outputDir, executableName);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "seabox",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "Node.js Single Executable Application (SEA) builder tool with native and library extraction",
5
5
  "main": "lib/index.mjs",
6
6
  "type": "module",