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 +342 -146
- package/bin/seabox-rebuild.mjs +95 -0
- package/bin/seabox.mjs +135 -0
- package/lib/{blob.js → blob.mjs} +12 -18
- package/lib/bootstrap.cjs +753 -0
- package/lib/build-cache.mjs +199 -0
- package/lib/build.mjs +75 -0
- package/lib/config.mjs +234 -0
- package/lib/{crypto-assets.js → crypto-assets.mjs} +12 -47
- package/lib/entry-bundler.mjs +64 -0
- package/lib/{fetch-node.js → fetch-node.mjs} +10 -16
- package/lib/index.mjs +26 -0
- package/lib/{inject.js → inject.mjs} +24 -27
- package/lib/{manifest.js → manifest.mjs} +5 -11
- package/lib/multi-target-builder.mjs +620 -0
- package/lib/native-scanner.mjs +210 -0
- package/lib/{obfuscate.js → obfuscate.mjs} +9 -31
- package/lib/require-shim.mjs +111 -0
- package/lib/rolldown-bundler.mjs +415 -0
- package/lib/{unsign.js → unsign.cjs} +7 -32
- package/package.json +9 -5
- package/bin/seabox-rebuild.js +0 -395
- package/bin/seabox.js +0 -81
- package/lib/bindings.js +0 -31
- package/lib/bootstrap.js +0 -697
- package/lib/build.js +0 -283
- package/lib/bytenode-hack.js +0 -56
- package/lib/config.js +0 -119
- package/lib/index.js +0 -27
- package/lib/scanner.js +0 -153
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
|
|
9
|
-
-
|
|
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
|
-
|
|
30
|
+
Create a `seabox.config.json` file in your project root:
|
|
30
31
|
|
|
31
32
|
```json
|
|
32
33
|
{
|
|
33
|
-
"
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
"./
|
|
37
|
-
"
|
|
38
|
-
"
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
"
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
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
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
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
|
-
|
|
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
|
-
|
|
86
|
+
# Specify custom config file
|
|
87
|
+
npx seabox build --config custom-config.json
|
|
80
88
|
|
|
81
|
-
|
|
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
|
|
87
|
-
"build:
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
136
|
-
-
|
|
137
|
-
-
|
|
138
|
-
-
|
|
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
|
-
|
|
139
|
+
3. **Native Module Rebuilding** - Rebuilds native modules for target platform
|
|
141
140
|
|
|
142
|
-
|
|
141
|
+
4. **Bootstrap Injection** - Adds runtime code for asset loading and native module extraction
|
|
143
142
|
|
|
144
|
-
|
|
143
|
+
5. **SEA Blob Creation** - Packages everything using Node.js SEA tooling
|
|
145
144
|
|
|
146
|
-
|
|
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
|
-
|
|
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
|
-
**
|
|
149
|
+
8. **Output** - Produces standalone executable(s) ready for distribution
|
|
159
150
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
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
|
-
|
|
166
|
-
|
|
167
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
175
|
-
# Rebuild for a specific target
|
|
176
|
-
npx seabox-rebuild --target node24.11.0-win32-x64
|
|
176
|
+
### Native Module Support
|
|
177
177
|
|
|
178
|
-
|
|
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
|
-
|
|
182
|
-
|
|
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
|
-
|
|
186
|
-
-
|
|
187
|
-
-
|
|
188
|
-
-
|
|
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
|
-
|
|
193
|
+
### Platform-Specific Libraries
|
|
193
194
|
|
|
194
|
-
|
|
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
|
-
"
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
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
|
-
|
|
208
|
+
**Defaults by platform:**
|
|
209
|
+
- **Windows**: `**/*.dll`
|
|
210
|
+
- **Linux**: `**/*.so`, `**/*.so.*`
|
|
211
|
+
- **macOS**: `**/*.dylib`
|
|
219
212
|
|
|
220
|
-
|
|
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
|
-
|
|
215
|
+
### Code Signature Removal
|
|
235
216
|
|
|
236
|
-
|
|
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 };
|