seabox 0.1.0-beta.3 → 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,65 +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
- - **rcedit**: (Windows only) Customize executable icon and version information. See [rcedit options](#windows-executable-customization-rcedit)
73
- - **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) |
74
74
 
75
75
  ## Usage
76
76
 
77
- 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
78
85
 
79
- ### npm script (recommended)
86
+ # Specify custom config file
87
+ npx seabox build --config custom-config.json
80
88
 
81
- Add a build script to your `package.json`:
89
+ # Initialize a new config file
90
+ npx seabox init
91
+
92
+ # Show help
93
+ npx seabox help
94
+ ```
95
+
96
+ ### npm Scripts (Recommended)
97
+
98
+ Add to your `package.json`:
82
99
 
83
100
  ```json
84
101
  {
85
102
  "scripts": {
86
- "build:exe": "seabox",
87
- "build:exe:verbose": "seabox --verbose"
103
+ "build": "seabox build",
104
+ "build:verbose": "seabox build --verbose"
88
105
  }
89
106
  }
90
107
  ```
@@ -92,27 +109,13 @@ Add a build script to your `package.json`:
92
109
  Then run:
93
110
 
94
111
  ```bash
95
- npm run build:exe
96
- ```
97
-
98
- ### CLI
99
-
100
- ```bash
101
- # Build using package.json configuration
102
- npx seabox
103
-
104
- # Build using a standalone config file (alternative to package.json)
105
- npx seabox --config sea-config.json
106
-
107
- # Verbose output
108
- npx seabox --verbose
109
-
112
+ npm run build
110
113
  ```
111
114
 
112
115
  ### Programmatic API
113
116
 
114
117
  ```javascript
115
- const { build } = require('seabox');
118
+ import { build } from 'seabox';
116
119
 
117
120
  await build({
118
121
  projectRoot: process.cwd(),
@@ -122,118 +125,99 @@ await build({
122
125
 
123
126
  ## How It Works
124
127
 
125
- 1. **Asset Scanning**: Scans and resolves all files matching your asset patterns
126
- 2. **Manifest Generation**: Creates a runtime manifest with metadata for binary extraction
127
- 3. **Bootstrap Injection**: Prepends bootstrap code to handle native module extraction
128
- 4. **Blob Creation**: Uses Node.js SEA tooling to create the application blob
129
- 5. **Binary Fetching**: Downloads the target Node.js binary and removes its signature
130
- 6. **Injection**: Uses postject to inject the blob into the Node binary
131
- 7. **Output**: Produces a standalone executable ready for signing and distribution
128
+ seabox automates the entire SEA build process:
132
129
 
133
- ## 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')`
134
133
 
135
- Native modules (`.node`, `.dll`, `.so`, `.dylib`) are automatically:
136
- - Extracted to a cache directory on first run
137
- - Integrity-checked using SHA-256 hashes
138
- - 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)
139
138
 
140
- ### Cache Location
139
+ 3. **Native Module Rebuilding** - Rebuilds native modules for target platform
141
140
 
142
- 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
143
142
 
144
- You can customize the cache location in your configuration:
143
+ 5. **SEA Blob Creation** - Packages everything using Node.js SEA tooling
145
144
 
146
- ```json
147
- {
148
- "sea": {
149
- "cacheLocation": "%LOCALAPPDATA%\\myapp-cache"
150
- }
151
- }
152
- ```
145
+ 6. **Binary Preparation** - Downloads target Node.js binary and removes code signature
153
146
 
154
- The cache location supports environment variable expansion:
155
- - **Windows**: `%LOCALAPPDATA%`, `%APPDATA%`, `%TEMP%`, etc.
156
- - **Unix/Linux/macOS**: `$HOME`, `$TMPDIR`, `${XDG_CACHE_HOME}`, etc.
147
+ 7. **Injection** - Uses `postject` to inject the blob into the Node.js binary
157
148
 
158
- **Override at runtime**: Set the `SEACACHE` environment variable to override the configured location:
149
+ 8. **Output** - Produces standalone executable(s) ready for distribution
159
150
 
160
- ```bash
161
- # Windows
162
- set SEACACHE=C:\custom\cache\path
163
- myapp.exe
151
+ ### Automatic Asset Detection
152
+
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';
164
158
 
165
- # Unix/Linux/macOS
166
- export SEACACHE=/custom/cache/path
167
- ./myapp
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'));
168
164
  ```
169
165
 
170
- ## 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')`
171
170
 
172
- 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)
173
175
 
174
- ```bash
175
- # Rebuild for a specific target
176
- npx seabox-rebuild --target node24.11.0-win32-x64
176
+ ### Native Module Support
177
177
 
178
- # Rebuild with separate options
179
- npx seabox-rebuild --node-version 24.11.0 --platform linux --arch x64
178
+ seabox automatically handles native modules without any configuration:
180
179
 
181
- # Rebuild in a specific directory
182
- npx seabox-rebuild /path/to/project --target node24.11.0-linux-x64
183
- ```
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
184
185
 
185
- The rebuilder will:
186
- - Scan all dependencies for native modules (those with `binding.gyp` or `gypfile: true`)
187
- - Rebuild each one using `node-gyp` for the target platform and Node.js version
188
- - Download necessary headers for cross-compilation
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.
189
191
 
190
- **Note**: Cross-compilation may require additional platform-specific build tools installed.
191
192
 
192
- ## Windows Executable Customization (rcedit)
193
+ ### Platform-Specific Libraries
193
194
 
194
- For Windows executables, you can customize the icon and version information using the `rcedit` configuration option:
195
+ Libraries that require filesystem access (like DLLs that are loaded via `dlopen`) can be specified with glob patterns:
195
196
 
196
197
  ```json
197
198
  {
198
- "sea": {
199
- "output": "myapp.exe",
200
- "targets": ["node24.11.0-win32-x64"],
201
- "rcedit": {
202
- "icon": ".\\assets\\myapp.ico",
203
- "file-version": "1.2.3.4",
204
- "product-version": "1.2.3.4",
205
- "version-string": {
206
- "CompanyName": "My Company",
207
- "FileDescription": "My Application",
208
- "ProductName": "MyApp",
209
- "InternalName": "myapp.exe",
210
- "OriginalFilename": "myapp.exe",
211
- "LegalCopyright": "Copyright (C) 2025 My Company"
212
- }
199
+ "outputs": [
200
+ {
201
+ "target": "node24.11.0-win32-x64",
202
+ "libraries": ["**/*.dll"] // Auto-extracted at runtime
213
203
  }
214
- }
204
+ ]
215
205
  }
216
206
  ```
217
207
 
218
- ### rcedit Options
208
+ **Defaults by platform:**
209
+ - **Windows**: `**/*.dll`
210
+ - **Linux**: `**/*.so`, `**/*.so.*`
211
+ - **macOS**: `**/*.dylib`
219
212
 
220
- - **icon**: Path to `.ico` file for the executable icon
221
- - **file-version**: File version in `X.X.X.X` format
222
- - **product-version**: Product version in `X.X.X.X` format
223
- - **version-string**: Object containing version string properties:
224
- - `CompanyName`: Company name
225
- - `FileDescription`: Description of the file
226
- - `ProductName`: Product name
227
- - `InternalName`: Internal name
228
- - `OriginalFilename`: Original filename
229
- - `LegalCopyright`: Copyright notice
230
- - `LegalTrademarks`: Trademark information (optional)
231
- - `PrivateBuild`: Private build description (optional)
232
- - `SpecialBuild`: Special build description (optional)
213
+ These files are extracted on first run (like `.node` files) since they need to be loaded from the filesystem.
233
214
 
234
- The rcedit step runs after signature removal and before the SEA blob injection. This only works for Windows (`win32`) targets.
215
+ ### Code Signature Removal
235
216
 
236
- For more details, see the [rcedit documentation](https://github.com/electron/rcedit).
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
237
221
 
238
222
  ## Asset Encryption
239
223
 
@@ -276,3 +260,215 @@ seabox supports optional AES-256-GCM encryption of embedded assets to protect yo
276
260
 
277
261
  MIT
278
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 };