seabox 0.1.2 → 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.
package/lib/inject.mjs CHANGED
@@ -1,106 +1,106 @@
1
- /**
2
- * inject.mjs
3
- * Inject SEA blob into Node binary using postject.
4
- */
5
-
6
- import fs from 'fs';
7
- import path from 'path';
8
- import Module from 'module';
9
- import { fileURLToPath } from 'url';
10
- import * as diag from './diagnostics.mjs';
11
-
12
- const __filename = fileURLToPath(import.meta.url);
13
- const __dirname = path.dirname(__filename);
14
-
15
- // Import unsign using require since it's CommonJS
16
- const require = Module.createRequire(import.meta.url);
17
- const { removeSignature, setVerbose: setUnsignVerbose } = require('./unsign.cjs');
18
-
19
- /**
20
- * Inject a SEA blob into a Node.js binary using postject.
21
- * @param {string} nodeBinaryPath - Path to the source Node binary
22
- * @param {string} blobPath - Path to the SEA blob file
23
- * @param {string} outputPath - Path for the output executable
24
- * @param {string} platform - Target platform (win32, linux, darwin)
25
- * @param {boolean} verbose - Enable verbose logging
26
- * @param {Object} [rceditOptions] - Optional rcedit configuration for Windows executables
27
- * @returns {Promise<void>}
28
- */
29
- export async function injectBlob(nodeBinaryPath, blobPath, outputPath, platform, verbose, rceditOptions) {
30
- // Ensure output directory exists
31
- const outputDir = path.dirname(outputPath);
32
- if (!fs.existsSync(outputDir)) {
33
- fs.mkdirSync(outputDir, { recursive: true });
34
- }
35
-
36
- // Copy node binary to output location
37
- fs.copyFileSync(nodeBinaryPath, outputPath);
38
-
39
- // Remove existing signature before postject injection
40
- setUnsignVerbose(verbose);
41
- await removeSignature(outputPath, platform);
42
-
43
- // Apply rcedit changes (Windows only, before postject)
44
- if (platform === 'win32' && rceditOptions && typeof rceditOptions === 'object') {
45
- await applyRcedit(outputPath, rceditOptions, verbose);
46
- }
47
-
48
- // Prepare postject command
49
- const sentinel = 'NODE_SEA_BLOB';
50
- const sentinelFuse = 'NODE_SEA_FUSE_fce680ab2cc467b6e072b8b5df1996b2';
51
-
52
- diag.verbose(`Injecting SEA blob into: ${outputPath}`, 1);
53
-
54
- // Use postject programmatically
55
- const postject = (await import('postject')).default;
56
-
57
- // Read blob data as buffer
58
- const blobData = fs.readFileSync(blobPath);
59
-
60
- const injectOptions = {
61
- sentinelFuse,
62
- machoSegmentName: platform === 'darwin' ? 'NODE_SEA' : undefined
63
- };
64
-
65
- try {
66
- await postject.inject(outputPath, sentinel, blobData, injectOptions);
67
- diag.verbose('SEA blob injected successfully', 2);
68
- } catch (error) {
69
- throw new Error(`Postject injection failed: ${error.message}`);
70
- }
71
- }
72
-
73
- /**
74
- * Apply rcedit to modify Windows executable resources.
75
- * @param {string} exePath - Path to the executable
76
- * @param {Object} options - rcedit options (icon, version-string, file-version, product-version, etc.)
77
- * @param {boolean} verbose - Enable verbose logging
78
- * @returns {Promise<void>}
79
- */
80
- async function applyRcedit(exePath, options, verbose) {
81
- diag.verbose('Applying rcedit to modify executable resources...', 2);
82
- diag.verbose(`Options: ${JSON.stringify(options, null, 2)}`, 2);
83
-
84
- // Try to import rcedit - it's a peer dependency
85
- let rcedit;
86
- try {
87
- rcedit = (await import('rcedit')).default;
88
- } catch (error) {
89
- if (error.code === 'ERR_MODULE_NOT_FOUND') {
90
- throw new Error(
91
- 'rcedit is required for Windows executable metadata but not installed. ' +
92
- 'Install it with: npm install rcedit'
93
- );
94
- }
95
- throw error;
96
- }
97
-
98
- try {
99
- await rcedit(exePath, options);
100
- diag.verbose('rcedit applied successfully', 2);
101
- } catch (error) {
102
- throw new Error(`rcedit failed: ${error.message}`);
103
- }
104
- }
105
-
106
- export { applyRcedit };
1
+ /**
2
+ * inject.mjs
3
+ * Inject SEA blob into Node binary using postject.
4
+ */
5
+
6
+ import fs from 'fs';
7
+ import path from 'path';
8
+ import Module from 'module';
9
+ import { fileURLToPath } from 'url';
10
+ import * as diag from './diagnostics.mjs';
11
+
12
+ const __filename = fileURLToPath(import.meta.url);
13
+ const __dirname = path.dirname(__filename);
14
+
15
+ // Import unsign using require since it's CommonJS
16
+ const require = Module.createRequire(import.meta.url);
17
+ const { removeSignature, setVerbose: setUnsignVerbose } = require('./unsign.cjs');
18
+
19
+ /**
20
+ * Inject a SEA blob into a Node.js binary using postject.
21
+ * @param {string} nodeBinaryPath - Path to the source Node binary
22
+ * @param {string} blobPath - Path to the SEA blob file
23
+ * @param {string} outputPath - Path for the output executable
24
+ * @param {string} platform - Target platform (win32, linux, darwin)
25
+ * @param {boolean} verbose - Enable verbose logging
26
+ * @param {Object} [rceditOptions] - Optional rcedit configuration for Windows executables
27
+ * @returns {Promise<void>}
28
+ */
29
+ export async function injectBlob(nodeBinaryPath, blobPath, outputPath, platform, verbose, rceditOptions) {
30
+ // Ensure output directory exists
31
+ const outputDir = path.dirname(outputPath);
32
+ if (!fs.existsSync(outputDir)) {
33
+ fs.mkdirSync(outputDir, { recursive: true });
34
+ }
35
+
36
+ // Copy node binary to output location
37
+ fs.copyFileSync(nodeBinaryPath, outputPath);
38
+
39
+ // Remove existing signature before postject injection
40
+ setUnsignVerbose(verbose);
41
+ await removeSignature(outputPath, platform);
42
+
43
+ // Apply rcedit changes (Windows only, before postject)
44
+ if (platform === 'win32' && rceditOptions && typeof rceditOptions === 'object') {
45
+ await applyRcedit(outputPath, rceditOptions, verbose);
46
+ }
47
+
48
+ // Prepare postject command
49
+ const sentinel = 'NODE_SEA_BLOB';
50
+ const sentinelFuse = 'NODE_SEA_FUSE_fce680ab2cc467b6e072b8b5df1996b2';
51
+
52
+ diag.verbose(`Injecting SEA blob into: ${outputPath}`, 1);
53
+
54
+ // Use postject programmatically
55
+ const postject = (await import('postject')).default;
56
+
57
+ // Read blob data as buffer
58
+ const blobData = fs.readFileSync(blobPath);
59
+
60
+ const injectOptions = {
61
+ sentinelFuse,
62
+ machoSegmentName: platform === 'darwin' ? 'NODE_SEA' : undefined
63
+ };
64
+
65
+ try {
66
+ await postject.inject(outputPath, sentinel, blobData, injectOptions);
67
+ diag.verbose('SEA blob injected successfully', 2);
68
+ } catch (error) {
69
+ throw new Error(`Postject injection failed: ${error.message}`);
70
+ }
71
+ }
72
+
73
+ /**
74
+ * Apply rcedit to modify Windows executable resources.
75
+ * @param {string} exePath - Path to the executable
76
+ * @param {Object} options - rcedit options (icon, version-string, file-version, product-version, etc.)
77
+ * @param {boolean} verbose - Enable verbose logging
78
+ * @returns {Promise<void>}
79
+ */
80
+ async function applyRcedit(exePath, options, verbose) {
81
+ diag.verbose('Applying rcedit to modify executable resources...', 2);
82
+ diag.verbose(`Options: ${JSON.stringify(options, null, 2)}`, 2);
83
+
84
+ // Try to import rcedit - it's a peer dependency
85
+ let rcedit;
86
+ try {
87
+ rcedit = (await import('rcedit')).default;
88
+ } catch (error) {
89
+ if (error.code === 'ERR_MODULE_NOT_FOUND') {
90
+ throw new Error(
91
+ 'rcedit is required for Windows executable metadata but not installed. ' +
92
+ 'Install it with: npm install rcedit'
93
+ );
94
+ }
95
+ throw error;
96
+ }
97
+
98
+ try {
99
+ await rcedit(exePath, options);
100
+ diag.verbose('rcedit applied successfully', 2);
101
+ } catch (error) {
102
+ throw new Error(`rcedit failed: ${error.message}`);
103
+ }
104
+ }
105
+
106
+ export { applyRcedit };
package/lib/manifest.mjs CHANGED
@@ -1,100 +1,100 @@
1
- /**
2
- * manifest.mjs
3
- * Generate runtime manifest with asset metadata and extraction rules.
4
- */
5
-
6
- import path from 'path';
7
-
8
- /**
9
- * @typedef {Object} BinaryManifestEntry
10
- * @property {string} assetKey - Key in the SEA blob
11
- * @property {string} fileName - Original filename
12
- * @property {string} platform - Target platform (win32, linux, darwin, *)
13
- * @property {string} arch - Target architecture (x64, arm64, *)
14
- * @property {number} order - Extraction order priority (lower = earlier)
15
- * @property {string} hash - SHA-256 hash for integrity check
16
- */
17
-
18
- /**
19
- * @typedef {Object} RuntimeManifest
20
- * @property {string} appName - Application name
21
- * @property {string} appVersion - Application version
22
- * @property {string} platform - Target platform
23
- * @property {string} arch - Target architecture
24
- * @property {BinaryManifestEntry[]} binaries - Binary extraction rules
25
- * @property {string[]} allAssetKeys - All embedded asset keys
26
- * @property {string} [cacheLocation] - Configured cache location (optional)
27
- */
28
-
29
- /**
30
- * Generate a runtime manifest from scanned assets.
31
- * @param {Array} assets - All scanned assets
32
- * @param {Object} config - SEA configuration
33
- * @param {string} targetPlatform - Target platform (win32, linux, darwin)
34
- * @param {string} targetArch - Target architecture (x64, arm64)
35
- * @returns {RuntimeManifest}
36
- */
37
- export function generateManifest(assets, config, targetPlatform, targetArch) {
38
- const binaries = assets
39
- .filter(a => a.isBinary)
40
- .map((asset, index) => {
41
- const fileName = path.basename(asset.sourcePath);
42
- return {
43
- assetKey: asset.assetKey,
44
- fileName,
45
- platform: targetPlatform,
46
- arch: targetArch,
47
- order: inferExtractionOrder(fileName, index),
48
- hash: asset.hash
49
- };
50
- });
51
-
52
- const manifest = {
53
- appName: config._packageName || 'app',
54
- appVersion: config._packageVersion || '1.0.0',
55
- platform: targetPlatform,
56
- arch: targetArch,
57
- binaries,
58
- allAssetKeys: assets.map(a => a.assetKey)
59
- };
60
-
61
- // Include cacheLocation if configured
62
- if (config.cacheLocation) {
63
- manifest.cacheLocation = config.cacheLocation;
64
- }
65
-
66
- return manifest;
67
- }
68
-
69
- /**
70
- * Infer extraction order based on file type.
71
- * Libraries (.dll, .so, .dylib) should extract before .node addons.
72
- * @param {string} fileName
73
- * @param {number} fallbackIndex - Fallback order if heuristic doesn't apply
74
- * @returns {number}
75
- */
76
- function inferExtractionOrder(fileName, fallbackIndex) {
77
- const ext = path.extname(fileName).toLowerCase();
78
-
79
- // Extract shared libraries first
80
- if (['.dll', '.so', '.dylib'].includes(ext)) {
81
- return 10;
82
- }
83
-
84
- // Then native addons
85
- if (ext === '.node') {
86
- return 20;
87
- }
88
-
89
- // Fallback for other binaries
90
- return 100 + fallbackIndex;
91
- }
92
-
93
- /**
94
- * Serialize manifest to JSON string for embedding.
95
- * @param {RuntimeManifest} manifest
96
- * @returns {string}
97
- */
98
- export function serializeManifest(manifest) {
99
- return JSON.stringify(manifest, null, 2);
100
- }
1
+ /**
2
+ * manifest.mjs
3
+ * Generate runtime manifest with asset metadata and extraction rules.
4
+ */
5
+
6
+ import path from 'path';
7
+
8
+ /**
9
+ * @typedef {Object} BinaryManifestEntry
10
+ * @property {string} assetKey - Key in the SEA blob
11
+ * @property {string} fileName - Original filename
12
+ * @property {string} platform - Target platform (win32, linux, darwin, *)
13
+ * @property {string} arch - Target architecture (x64, arm64, *)
14
+ * @property {number} order - Extraction order priority (lower = earlier)
15
+ * @property {string} hash - SHA-256 hash for integrity check
16
+ */
17
+
18
+ /**
19
+ * @typedef {Object} RuntimeManifest
20
+ * @property {string} appName - Application name
21
+ * @property {string} appVersion - Application version
22
+ * @property {string} platform - Target platform
23
+ * @property {string} arch - Target architecture
24
+ * @property {BinaryManifestEntry[]} binaries - Binary extraction rules
25
+ * @property {string[]} allAssetKeys - All embedded asset keys
26
+ * @property {string} [cacheLocation] - Configured cache location (optional)
27
+ */
28
+
29
+ /**
30
+ * Generate a runtime manifest from scanned assets.
31
+ * @param {Array} assets - All scanned assets
32
+ * @param {Object} config - SEA configuration
33
+ * @param {string} targetPlatform - Target platform (win32, linux, darwin)
34
+ * @param {string} targetArch - Target architecture (x64, arm64)
35
+ * @returns {RuntimeManifest}
36
+ */
37
+ export function generateManifest(assets, config, targetPlatform, targetArch) {
38
+ const binaries = assets
39
+ .filter(a => a.isBinary)
40
+ .map((asset, index) => {
41
+ const fileName = path.basename(asset.sourcePath);
42
+ return {
43
+ assetKey: asset.assetKey,
44
+ fileName,
45
+ platform: targetPlatform,
46
+ arch: targetArch,
47
+ order: inferExtractionOrder(fileName, index),
48
+ hash: asset.hash
49
+ };
50
+ });
51
+
52
+ const manifest = {
53
+ appName: config._packageName || 'app',
54
+ appVersion: config._packageVersion || '1.0.0',
55
+ platform: targetPlatform,
56
+ arch: targetArch,
57
+ binaries,
58
+ allAssetKeys: assets.map(a => a.assetKey)
59
+ };
60
+
61
+ // Include cacheLocation if configured
62
+ if (config.cacheLocation) {
63
+ manifest.cacheLocation = config.cacheLocation;
64
+ }
65
+
66
+ return manifest;
67
+ }
68
+
69
+ /**
70
+ * Infer extraction order based on file type.
71
+ * Libraries (.dll, .so, .dylib) should extract before .node addons.
72
+ * @param {string} fileName
73
+ * @param {number} fallbackIndex - Fallback order if heuristic doesn't apply
74
+ * @returns {number}
75
+ */
76
+ function inferExtractionOrder(fileName, fallbackIndex) {
77
+ const ext = path.extname(fileName).toLowerCase();
78
+
79
+ // Extract shared libraries first
80
+ if (['.dll', '.so', '.dylib'].includes(ext)) {
81
+ return 10;
82
+ }
83
+
84
+ // Then native addons
85
+ if (ext === '.node') {
86
+ return 20;
87
+ }
88
+
89
+ // Fallback for other binaries
90
+ return 100 + fallbackIndex;
91
+ }
92
+
93
+ /**
94
+ * Serialize manifest to JSON string for embedding.
95
+ * @param {RuntimeManifest} manifest
96
+ * @returns {string}
97
+ */
98
+ export function serializeManifest(manifest) {
99
+ return JSON.stringify(manifest, null, 2);
100
+ }