seabox 0.1.0-beta.2 → 0.1.0-beta.4

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/README.md CHANGED
@@ -1,22 +1,23 @@
1
1
  # seabox
2
2
 
3
- A reusable tool for building Node.js Single Executable Applications (SEA) with native-module support.
3
+ A reusable tool for building Node.js Single Executable Applications (SEA) with native-module support and binary extraction.
4
4
 
5
5
  ## Features
6
6
 
7
7
  - Bundle Node.js applications into standalone executables
8
- - Automatic native module (.node, .dll, .so, .dylib) extraction and loading
9
- - Asset encryption with obfuscated keys embedded in V8 snapshots
8
+ - **Automatic asset detection** from `path.join(__dirname, ...)` patterns
9
+ - **Automatic native module detection** (.node files) with pattern transforms
10
+ - Platform-specific library extraction (DLLs, shared libraries)
11
+ - Asset encryption with obfuscated keys
10
12
  - Multi-platform targeting (Windows, Linux, macOS)
11
13
  - V8 snapshot support for faster startup
12
14
  - Integrity checking for extracted binaries
13
15
  - Automatic code signature removal before injection
14
- - Simple configuration via package.json
15
16
 
16
17
  ## Use case
17
- This tooling was created as an alternative to pkg, which is unfortunatly deprecated, and where forks were running foul of virus checkers. By using node's SEA, the executables are directly from nodejs's distribution source, and built using node's native Single Executable Application solution. Unfortunatly this does mean native modules embedded within the exe cannot run directly and must be extracted to a location on the disk on first run - This tooling automates that process for you, while providing arbitrary asset embedding. Embedded assets are _not_ extracted and access to them is handled by intercepting require and fs.
18
+ This tooling was created as an alternative to pkg, which is unfortunatly deprecated, and where forks were running foul of virus checkers. By using node's SEA, the executables are directly downloaded from nodejs's distribution source, and built using node's native Single Executable Application solution. Unfortunatly this does mean native modules embedded within the exe cannot run directly and must be extracted to a location on the disk on first run - This tooling automates that process for you, while providing arbitrary asset embedding. Embedded assets are _not_ extracted and access to them is handled by intercepting require and fs.
18
19
 
19
- Note: **V8 snapshot includes and embedds the original source**, this is currently a limitation of Node's SEA tooling as far as I can tell; thus the snapshot is only useful for faster startup.
20
+ Note: **V8 snapshot includes and embedds the original source**, this is currently a limitation of Node's SEA tooling as far as I can tell; thus the snapshot is only useful for faster startup. Its possible to get around this by using bytenode's vm.script hack (embed the bytenode code as an asset and run another vm snapshot with the faux script input) and I'll look into supporting it in the future.
20
21
 
21
22
  ## Installation
22
23
 
@@ -26,64 +27,81 @@ npm install --save-dev seabox
26
27
 
27
28
  ## Configuration
28
29
 
29
- Add a `sea` configuration to your `package.json`:
30
+ Create a `seabox.config.json` file in your project root:
30
31
 
31
32
  ```json
32
33
  {
33
- "sea": {
34
- "entry": "./out/server.js",
35
- "assets": [
36
- "./out/client/**/*",
37
- "./out/lib/**/*",
38
- "./out/native/**/*",
39
- "!**/*.md",
40
- "!**/test/**"
41
- ],
42
- "binaries": [
43
- "*.node",
44
- "*.dll"
45
- ],
46
- "targets": [
47
- "node24.11.0-win32-x64"
48
- ],
49
- "output": "myapp.exe",
50
- "outputPath": "dist",
51
- "disableExperimentalSEAWarning": true,
52
- "useSnapshot": true,
53
- "useCodeCache": false
54
- }
34
+ "entry": "./src/index.js",
35
+ "outputs": [
36
+ {
37
+ "path": "./dist/win",
38
+ "target": "node24.11.0-win32-x64",
39
+ "output": "myapp.exe"
40
+ }
41
+ ],
42
+ "bundler": {
43
+ "external": []
44
+ },
45
+ "encryptAssets": false,
46
+ "useSnapshot": true,
47
+ "verbose": false
55
48
  }
56
49
  ```
57
50
 
58
51
  ## Configuration Options
59
52
 
60
- - **entry**: Path to your bundled application entry point
61
- - **assets**: Array of glob patterns for files to include (supports `!` prefix for exclusions, e.g., `"!**/*.md"`)
62
- - **binaries**: Patterns to identify binary files that need extraction (e.g., `.node`, `.dll`)
63
- - **targets**: Array of target platforms (format: `nodeX.Y.Z-platform-arch`)
64
- - **output**: Name of the output executable
65
- - **outputPath**: Directory for build output
66
- - **disableExperimentalSEAWarning**: Suppress Node.js SEA experimental warnings (default: true)
67
- - **useSnapshot**: Enable V8 snapshot for faster startup (default: false)
68
- - **useCodeCache**: Enable V8 code cache (default: false)
69
- - **encryptAssets**: Enable encryption for assets (default: false)
70
- - **encryptExclude**: Patterns to exclude from encryption (e.g., `['*.txt']`)
71
- - **rebuild**: Automatically rebuild native modules for the target platform before building the SEA (default: false)
72
- - **cacheLocation**: Custom cache directory for extracted binaries (default: `'./.sea-cache'`). Supports environment variable expansion (e.g., `'%LOCALAPPDATA%\\myapp-cache'` on Windows or `'$HOME/.cache/myapp'` on Unix)
53
+ | Option | Type | Required | Description |
54
+ |--------|------|----------|-------------|
55
+ | `entry` | `string` | Yes | Path to your application's entry point |
56
+ | `outputs` | `array` | Yes | Array of build targets |
57
+ | `outputs[].path` | `string` | Yes | Output directory for this target |
58
+ | `outputs[].target` | `string` | Yes | Build target (format: `nodeX.Y.Z-platform-arch`) |
59
+ | `outputs[].output` | `string` | Yes | Output filename |
60
+ | `outputs[].libraries` | `array` | No | Glob patterns for shared libraries (DLLs/SOs) requiring filesystem extraction (defaults: `**/*.dll` for Windows, `**/*.so*` for Linux, `**/*.dylib` for macOS) |
61
+ | `outputs[].rcedit` | `object` | No | Windows executable metadata (icon, version info) |
62
+ | `assets` | `array` | No | Glob patterns for assets to embed (merged with auto-detected assets) |
63
+ | `bundler` | `object` | No | Bundler options |
64
+ | `bundler.external` | `array` | No | Modules to exclude from bundling |
65
+ | `bundler.plugins` | `array` | No | Additional Rollup plugins |
66
+ | `bundler.minify` | `boolean` | No | Minify bundled code |
67
+ | `bundler.sourcemap` | `boolean` | No | Generate source maps |
68
+ | `encryptAssets` | `boolean` | No | Enable asset encryption (default: false) |
69
+ | `encryptExclude` | `array` | No | Glob patterns to exclude from encryption |
70
+ | `useSnapshot` | `boolean` | No | Enable V8 startup snapshots (default: true) |
71
+ | `useCodeCache` | `boolean` | No | Enable V8 code cache (default: false) |
72
+ | `cacheLocation` | `string` | No | Path for code cache storage |
73
+ | `verbose` | `boolean` | No | Enable verbose logging (default: false) |
73
74
 
74
75
  ## Usage
75
76
 
76
- After installing `seabox` as a dev dependency and configuring your `package.json`, build your SEA executable:
77
+ ### CLI Commands
78
+
79
+ ```bash
80
+ # Build executable(s)
81
+ npx seabox build
82
+
83
+ # Build with verbose output
84
+ npx seabox build --verbose
85
+
86
+ # Specify custom config file
87
+ npx seabox build --config custom-config.json
77
88
 
78
- ### npm script (recommended)
89
+ # Initialize a new config file
90
+ npx seabox init
91
+
92
+ # Show help
93
+ npx seabox help
94
+ ```
79
95
 
80
- Add a build script to your `package.json`:
96
+ ### npm Scripts (Recommended)
97
+
98
+ Add to your `package.json`:
81
99
 
82
100
  ```json
83
101
  {
84
102
  "scripts": {
85
- "build:exe": "seabox",
86
- "build:exe:verbose": "seabox --verbose"
103
+ "build": "seabox build",
104
+ "build:verbose": "seabox build --verbose"
87
105
  }
88
106
  }
89
107
  ```
@@ -91,27 +109,13 @@ Add a build script to your `package.json`:
91
109
  Then run:
92
110
 
93
111
  ```bash
94
- npm run build:exe
95
- ```
96
-
97
- ### CLI
98
-
99
- ```bash
100
- # Build using package.json configuration
101
- npx seabox
102
-
103
- # Build using a standalone config file (alternative to package.json)
104
- npx seabox --config sea-config.json
105
-
106
- # Verbose output
107
- npx seabox --verbose
108
-
112
+ npm run build
109
113
  ```
110
114
 
111
115
  ### Programmatic API
112
116
 
113
117
  ```javascript
114
- const { build } = require('seabox');
118
+ import { build } from 'seabox';
115
119
 
116
120
  await build({
117
121
  projectRoot: process.cwd(),
@@ -121,72 +125,99 @@ await build({
121
125
 
122
126
  ## How It Works
123
127
 
124
- 1. **Asset Scanning**: Scans and resolves all files matching your asset patterns
125
- 2. **Manifest Generation**: Creates a runtime manifest with metadata for binary extraction
126
- 3. **Bootstrap Injection**: Prepends bootstrap code to handle native module extraction
127
- 4. **Blob Creation**: Uses Node.js SEA tooling to create the application blob
128
- 5. **Binary Fetching**: Downloads the target Node.js binary and removes its signature
129
- 6. **Injection**: Uses postject to inject the blob into the Node binary
130
- 7. **Output**: Produces a standalone executable ready for signing and distribution
128
+ seabox automates the entire SEA build process:
131
129
 
132
- ## Binary Extraction
130
+ 1. **Bundling** - Automatically bundles your app with Rollup, detecting:
131
+ - Native module patterns (`bindings`, `node-gyp-build`, direct `.node` requires)
132
+ - Asset references via `path.join(__dirname, 'relative/path')`
133
133
 
134
- Native modules (`.node`, `.dll`, `.so`, `.dylib`) are automatically:
135
- - Extracted to a cache directory on first run
136
- - Integrity-checked using SHA-256 hashes
137
- - Loaded via custom module resolution
134
+ 2. **Asset Collection** - Gathers assets from three sources:
135
+ - **Auto-detected**: Files referenced via `path.join(__dirname, ...)` patterns
136
+ - **Config globs**: Patterns specified in `assets` array
137
+ - **Libraries**: Platform-specific shared libraries (DLLs/SOs)
138
138
 
139
- ### Cache Location
139
+ 3. **Native Module Rebuilding** - Rebuilds native modules for target platform
140
140
 
141
- By default, binaries are extracted to: `./.sea-cache/<appname>/<version>-<platform>-<arch>`
141
+ 4. **Bootstrap Injection** - Adds runtime code for asset loading and native module extraction
142
142
 
143
- You can customize the cache location in your configuration:
143
+ 5. **SEA Blob Creation** - Packages everything using Node.js SEA tooling
144
144
 
145
- ```json
146
- {
147
- "sea": {
148
- "cacheLocation": "%LOCALAPPDATA%\\myapp-cache"
149
- }
150
- }
151
- ```
145
+ 6. **Binary Preparation** - Downloads target Node.js binary and removes code signature
152
146
 
153
- The cache location supports environment variable expansion:
154
- - **Windows**: `%LOCALAPPDATA%`, `%APPDATA%`, `%TEMP%`, etc.
155
- - **Unix/Linux/macOS**: `$HOME`, `$TMPDIR`, `${XDG_CACHE_HOME}`, etc.
147
+ 7. **Injection** - Uses `postject` to inject the blob into the Node.js binary
156
148
 
157
- **Override at runtime**: Set the `SEACACHE` environment variable to override the configured location:
149
+ 8. **Output** - Produces standalone executable(s) ready for distribution
158
150
 
159
- ```bash
160
- # Windows
161
- set SEACACHE=C:\custom\cache\path
162
- myapp.exe
151
+ ### Automatic Asset Detection
163
152
 
164
- # Unix/Linux/macOS
165
- export SEACACHE=/custom/cache/path
166
- ./myapp
153
+ **Like pkg**, seabox automatically detects and embeds assets referenced in your code:
154
+
155
+ ```javascript
156
+ import path from 'path';
157
+ import { fileURLToPath } from 'url';
158
+
159
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
160
+
161
+ // This asset will be automatically detected and embedded
162
+ const configPath = path.join(__dirname, '../config/app.json');
163
+ const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
167
164
  ```
168
165
 
169
- ## Native Module Rebuilding
166
+ **Detection works with:**
167
+ - `path.join(__dirname, 'relative/path')`
168
+ - `path.resolve(__dirname, 'relative/path')`
169
+ - Multiple path segments: `path.join(__dirname, '..', 'assets', 'file.txt')`
170
170
 
171
- If your project has native modules (e.g., `.node` bindings), you may need to rebuild them for the target Node.js version:
171
+ **Asset sources (merged and deduplicated):**
172
+ 1. **Auto-detected** from code analysis during bundling
173
+ 2. **Config globs** from `assets: ["./data/**/*", "./public/**/*"]`
174
+ 3. **Platform libraries** from `outputs[].libraries` (e.g., DLLs for Windows)
172
175
 
173
- ```bash
174
- # Rebuild for a specific target
175
- npx seabox-rebuild --target node24.11.0-win32-x64
176
+ ### Native Module Support
177
+
178
+ seabox automatically handles native modules without any configuration:
179
+
180
+ **Supported patterns:**
181
+ - `require('bindings')('module')` - Standard bindings package
182
+ - `require('./build/Release/addon.node')` - Direct requires
183
+ - `require('node-gyp-build')(__dirname)` - Prebuild binaries
184
+ - `require('node-pre-gyp')` patterns - Pre-compiled binaries
176
185
 
177
- # Rebuild with separate options
178
- npx seabox-rebuild --node-version 24.11.0 --platform linux --arch x64
186
+ **At runtime:**
187
+ - Native modules are extracted to a cache directory on first run
188
+ - Modules are integrity-checked with SHA-256 hashes
189
+ - Custom `require()` shim loads modules from cache
190
+ - Works transparently with packages like `better-sqlite3`, `sharp`, `canvas`, etc.
179
191
 
180
- # Rebuild in a specific directory
181
- npx seabox-rebuild /path/to/project --target node24.11.0-linux-x64
192
+
193
+ ### Platform-Specific Libraries
194
+
195
+ Libraries that require filesystem access (like DLLs that are loaded via `dlopen`) can be specified with glob patterns:
196
+
197
+ ```json
198
+ {
199
+ "outputs": [
200
+ {
201
+ "target": "node24.11.0-win32-x64",
202
+ "libraries": ["**/*.dll"] // Auto-extracted at runtime
203
+ }
204
+ ]
205
+ }
182
206
  ```
183
207
 
184
- The rebuilder will:
185
- - Scan all dependencies for native modules (those with `binding.gyp` or `gypfile: true`)
186
- - Rebuild each one using `node-gyp` for the target platform and Node.js version
187
- - Download necessary headers for cross-compilation
208
+ **Defaults by platform:**
209
+ - **Windows**: `**/*.dll`
210
+ - **Linux**: `**/*.so`, `**/*.so.*`
211
+ - **macOS**: `**/*.dylib`
212
+
213
+ These files are extracted on first run (like `.node` files) since they need to be loaded from the filesystem.
214
+
215
+ ### Code Signature Removal
188
216
 
189
- **Note**: Cross-compilation may require additional platform-specific build tools installed.
217
+ Required before SEA injection. Platform-specific tools needed:
218
+ - **Windows**: `signtool.exe` (from Windows SDK)
219
+ - **macOS**: `codesign` (included with Xcode)
220
+ - **Linux**: Not required
190
221
 
191
222
  ## Asset Encryption
192
223
 
@@ -229,3 +260,215 @@ seabox supports optional AES-256-GCM encryption of embedded assets to protect yo
229
260
 
230
261
  MIT
231
262
  Copyright Meirion Hughes 2025
263
+ ## Examples
264
+
265
+ ### Basic Application
266
+
267
+ ```javascript
268
+ // src/index.js
269
+ console.log('Hello from SEA!');
270
+ console.log('Platform:', process.platform);
271
+ console.log('Architecture:', process.arch);
272
+ ```
273
+
274
+ ```json
275
+ // seabox.config.json
276
+ {
277
+ "entry": "./src/index.js",
278
+ "outputs": [
279
+ {
280
+ "path": "./dist",
281
+ "target": "node24.11.0-win32-x64",
282
+ "output": "hello.exe"
283
+ }
284
+ ]
285
+ }
286
+ ```
287
+
288
+ ### With Assets (Auto-Detection)
289
+
290
+ ```javascript
291
+ // src/index.js
292
+ import fs from 'fs';
293
+ import path from 'path';
294
+ import { fileURLToPath } from 'url';
295
+
296
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
297
+
298
+ // Assets referenced via path.join(__dirname, ...) are auto-detected
299
+ const configPath = path.join(__dirname, '../config/settings.json');
300
+ const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
301
+
302
+ console.log('Config loaded:', config);
303
+ ```
304
+
305
+ No configuration needed - the asset is automatically detected and embedded!
306
+
307
+ ### With Config Assets
308
+
309
+ ```json
310
+ {
311
+ "entry": "./src/index.js",
312
+ "outputs": [
313
+ {
314
+ "path": "./dist",
315
+ "target": "node24.11.0-win32-x64",
316
+ "output": "myapp.exe"
317
+ }
318
+ ],
319
+ "assets": [
320
+ "./public/**/*",
321
+ "./data/**/*.json",
322
+ "!**/*.md"
323
+ ]
324
+ }
325
+ ```
326
+
327
+ All files matching the glob patterns will be embedded. Auto-detected assets are merged automatically.
328
+
329
+ ### With Native Modules
330
+
331
+ ```javascript
332
+ // src/index.js
333
+ import Database from 'better-sqlite3';
334
+
335
+ const db = new Database(':memory:');
336
+ db.exec('CREATE TABLE users (name TEXT)');
337
+ db.prepare('INSERT INTO users VALUES (?)').run('Alice');
338
+
339
+ const users = db.prepare('SELECT * FROM users').all();
340
+ console.log('Users:', users);
341
+
342
+ db.close();
343
+ ```
344
+
345
+ No special configuration needed - seabox automatically detects and handles the native module!
346
+
347
+ ### Multi-Platform Build
348
+
349
+ ```json
350
+ {
351
+ "entry": "./src/index.js",
352
+ "outputs": [
353
+ {
354
+ "path": "./dist/win",
355
+ "target": "node24.11.0-win32-x64",
356
+ "output": "myapp.exe"
357
+ },
358
+ {
359
+ "path": "./dist/linux",
360
+ "target": "node24.11.0-linux-x64",
361
+ "output": "myapp"
362
+ },
363
+ {
364
+ "path": "./dist/macos",
365
+ "target": "node24.11.0-darwin-arm64",
366
+ "output": "myapp"
367
+ }
368
+ ],
369
+ "bundler": {
370
+ "external": []
371
+ },
372
+ "useSnapshot": true
373
+ }
374
+ ```
375
+
376
+ Run `seabox build` and get executables for all three platforms!
377
+
378
+ ## Advanced Features
379
+
380
+ ### Asset Encryption
381
+
382
+ Protect your source code with AES-256-GCM encryption:
383
+
384
+ ```json
385
+ {
386
+ "entry": "./src/index.js",
387
+ "outputs": [
388
+ {
389
+ "path": "./dist",
390
+ "target": "node24.11.0-win32-x64",
391
+ "output": "myapp.exe"
392
+ }
393
+ ],
394
+ "encryptAssets": true,
395
+ "encryptExclude": ["*.txt"]
396
+ }
397
+ ```
398
+
399
+ ### External Dependencies
400
+
401
+ Exclude packages from bundling:
402
+
403
+ ```json
404
+ {
405
+ "entry": "./src/index.js",
406
+ "outputs": [
407
+ {
408
+ "path": "./dist",
409
+ "target": "node24.11.0-win32-x64",
410
+ "output": "myapp.exe"
411
+ }
412
+ ],
413
+ "bundler": {
414
+ "external": ["fsevents", "some-optional-dep"]
415
+ }
416
+ }
417
+ ```json
418
+ {
419
+ "bundler": {
420
+ "external": ["fsevents", "some-optional-dep"]
421
+ }
422
+ }
423
+ ```
424
+
425
+ Useful for:
426
+ - Platform-specific optional dependencies
427
+ - Packages that don't bundle well
428
+ - Reducing bundle size
429
+
430
+ ## Platform Support
431
+
432
+ ### Supported Targets
433
+
434
+ | Platform | Architectures | Example |
435
+ |----------|--------------|---------|
436
+ | Windows | x64, arm64 | `node24.11.0-win32-x64` |
437
+ | Linux | x64, arm64 | `node24.11.0-linux-x64` |
438
+ | macOS | x64, arm64 | `node24.11.0-darwin-arm64` |
439
+
440
+ ### Node.js Versions
441
+
442
+ Works with Node.js 18.0.0 and above that support SEA.
443
+
444
+ ## Troubleshooting
445
+
446
+ ### Native modules not loading
447
+
448
+ If you see errors about missing `.node` files:
449
+ 1. Check that the module was detected during build (look for "Native modules detected" in output)
450
+ 2. Run with `--verbose` to see detailed bundling info
451
+ 3. Ensure the module uses standard patterns (`bindings`, `node-gyp-build`, etc.)
452
+
453
+ ### Build fails with signature removal error
454
+
455
+ Install the required tools:
456
+ - **Windows**: Install Windows SDK for `signtool.exe`
457
+ - **macOS**: Install Xcode Command Line Tools for `codesign`
458
+
459
+ ### Cross-compilation issues
460
+
461
+ When building for a different platform than your current OS:
462
+ - Native module detection works cross-platform
463
+ - The bundled JavaScript is platform-agnostic
464
+ - Each target is built independently with the correct Node.js binary
465
+
466
+ ## Contributing
467
+
468
+ Contributions welcome! Please open an issue or PR on [GitHub](https://github.com/MeirionHughes/seabox).
469
+
470
+ ## License
471
+
472
+ MIT
473
+
474
+ Copyright © 2025 Meirion Hughes
@@ -0,0 +1,95 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * seabox-rebuild.mjs
4
+ * Rebuild native modules for target platform/architecture
5
+ */
6
+
7
+ import { execSync } from 'child_process';
8
+ import fs from 'fs';
9
+ import path from 'path';
10
+ import { fileURLToPath } from 'url';
11
+
12
+ const __filename = fileURLToPath(import.meta.url);
13
+ const __dirname = path.dirname(__filename);
14
+
15
+ /**
16
+ * Rebuild a native module for a specific target
17
+ * @param {string} modulePath - Path to the native module
18
+ * @param {string} platform - Target platform (win32, linux, darwin)
19
+ * @param {string} arch - Target architecture (x64, arm64)
20
+ * @param {boolean} verbose - Enable verbose logging
21
+ */
22
+ function rebuildNativeModule(modulePath, platform, arch, verbose = false) {
23
+ if (verbose) {
24
+ console.log(`Rebuilding native module: ${modulePath}`);
25
+ console.log(`Target: ${platform}-${arch}`);
26
+ }
27
+
28
+ const packageJsonPath = path.join(modulePath, 'package.json');
29
+ if (!fs.existsSync(packageJsonPath)) {
30
+ throw new Error(`No package.json found in ${modulePath}`);
31
+ }
32
+
33
+ const pkg = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
34
+ const moduleName = pkg.name;
35
+
36
+ // Check if module has native bindings
37
+ const hasBindingGyp = fs.existsSync(path.join(modulePath, 'binding.gyp'));
38
+ if (!hasBindingGyp && !pkg.gypfile) {
39
+ if (verbose) {
40
+ console.log(`Module ${moduleName} does not appear to have native bindings, skipping`);
41
+ }
42
+ return;
43
+ }
44
+
45
+ try {
46
+ // Use node-gyp to rebuild for the target platform
47
+ const cmd = `npx node-gyp rebuild --target_platform=${platform} --target_arch=${arch}`;
48
+
49
+ if (verbose) {
50
+ console.log(`Running: ${cmd}`);
51
+ }
52
+
53
+ execSync(cmd, {
54
+ cwd: modulePath,
55
+ stdio: verbose ? 'inherit' : 'pipe',
56
+ env: {
57
+ ...process.env,
58
+ npm_config_target_platform: platform,
59
+ npm_config_target_arch: arch
60
+ }
61
+ });
62
+
63
+ if (verbose) {
64
+ console.log(`✓ Successfully rebuilt ${moduleName}`);
65
+ }
66
+ } catch (error) {
67
+ if (verbose) {
68
+ console.error(`Failed to rebuild ${moduleName}:`, error.message);
69
+ }
70
+ throw error;
71
+ }
72
+ }
73
+
74
+ // CLI entry point
75
+ if (import.meta.url === `file://${process.argv[1]}`) {
76
+ const args = process.argv.slice(2);
77
+
78
+ if (args.length < 3) {
79
+ console.error('Usage: seabox-rebuild <module-path> <platform> <arch> [--verbose]');
80
+ process.exit(1);
81
+ }
82
+
83
+ const [modulePath, platform, arch] = args;
84
+ const verbose = args.includes('--verbose') || args.includes('-v');
85
+
86
+ try {
87
+ rebuildNativeModule(modulePath, platform, arch, verbose);
88
+ process.exit(0);
89
+ } catch (error) {
90
+ console.error('Rebuild failed:', error.message);
91
+ process.exit(1);
92
+ }
93
+ }
94
+
95
+ export { rebuildNativeModule };