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.
@@ -1,64 +1,64 @@
1
- /**
2
- * entry-bundler.mjs
3
- * Bundles the entry file with bootstrap and require shim
4
- */
5
-
6
- import Module from 'module';
7
- import { fileURLToPath } from 'url';
8
-
9
- const __filename = fileURLToPath(import.meta.url);
10
- const require = Module.createRequire(import.meta.url);
11
-
12
- const { generateRequireShim, replaceRequireCalls } = require('./require-shim.mjs');
13
-
14
- /**
15
- * Bundle the entry file for SEA
16
- * @param {string} entryContent - The entry file content
17
- * @param {string} augmentedBootstrap - The bootstrap code
18
- * @param {boolean} useSnapshot - Whether to use snapshot mode
19
- * @param {boolean} verbose - Enable verbose logging
20
- * @returns {string} - The bundled entry content
21
- */
22
- export function bundleEntry(entryContent, augmentedBootstrap, useSnapshot, verbose) {
23
- // Generate the require shim and replace require() calls
24
- const requireSeaboxShim = generateRequireShim();
25
- const transformed = replaceRequireCalls(entryContent, verbose);
26
- const transformedContent = transformed.code;
27
-
28
- let bundledEntry;
29
-
30
- if (useSnapshot) {
31
- // Snapshot mode
32
- const parts = [
33
- augmentedBootstrap,
34
- '\n\n',
35
- requireSeaboxShim,
36
- '\n\n',
37
- '// Application entry - will be wrapped by bootstrap\'s setDeserializeMainFunction interceptor\n',
38
- '(function() {\n',
39
- ' const v8 = __originalRequire(\'v8\');\n',
40
- ' if (v8.startupSnapshot && v8.startupSnapshot.isBuildingSnapshot()) {\n',
41
- ' v8.startupSnapshot.setDeserializeMainFunction(() => {\n',
42
- ' if (typeof exports === \'undefined\') {\n',
43
- ' var exports = {};\n',
44
- ' var module = { exports: exports };\n',
45
- ' }\n',
46
- ' // Run the application code\n',
47
- transformedContent,
48
- '\n',
49
- ' });\n',
50
- ' } else {\n',
51
- ' // Not building snapshot, run normally\n',
52
- transformedContent,
53
- '\n',
54
- ' }\n',
55
- '})();\n'
56
- ];
57
- bundledEntry = parts.join('');
58
- } else {
59
- // Non-snapshot mode
60
- bundledEntry = augmentedBootstrap + '\n\n' + requireSeaboxShim + '\n' + transformedContent;
61
- }
62
-
63
- return bundledEntry;
64
- }
1
+ /**
2
+ * entry-bundler.mjs
3
+ * Bundles the entry file with bootstrap and require shim
4
+ */
5
+
6
+ import Module from 'module';
7
+ import { fileURLToPath } from 'url';
8
+
9
+ const __filename = fileURLToPath(import.meta.url);
10
+ const require = Module.createRequire(import.meta.url);
11
+
12
+ const { generateRequireShim, replaceRequireCalls } = require('./require-shim.mjs');
13
+
14
+ /**
15
+ * Bundle the entry file for SEA
16
+ * @param {string} entryContent - The entry file content
17
+ * @param {string} augmentedBootstrap - The bootstrap code
18
+ * @param {boolean} useSnapshot - Whether to use snapshot mode
19
+ * @param {boolean} verbose - Enable verbose logging
20
+ * @returns {string} - The bundled entry content
21
+ */
22
+ export function bundleEntry(entryContent, augmentedBootstrap, useSnapshot, verbose) {
23
+ // Generate the require shim and replace require() calls
24
+ const requireSeaboxShim = generateRequireShim();
25
+ const transformed = replaceRequireCalls(entryContent, verbose);
26
+ const transformedContent = transformed.code;
27
+
28
+ let bundledEntry;
29
+
30
+ if (useSnapshot) {
31
+ // Snapshot mode
32
+ const parts = [
33
+ augmentedBootstrap,
34
+ '\n\n',
35
+ requireSeaboxShim,
36
+ '\n\n',
37
+ '// Application entry - will be wrapped by bootstrap\'s setDeserializeMainFunction interceptor\n',
38
+ '(function() {\n',
39
+ ' const v8 = __originalRequire(\'v8\');\n',
40
+ ' if (v8.startupSnapshot && v8.startupSnapshot.isBuildingSnapshot()) {\n',
41
+ ' v8.startupSnapshot.setDeserializeMainFunction(() => {\n',
42
+ ' if (typeof exports === \'undefined\') {\n',
43
+ ' var exports = {};\n',
44
+ ' var module = { exports: exports };\n',
45
+ ' }\n',
46
+ ' // Run the application code\n',
47
+ transformedContent,
48
+ '\n',
49
+ ' });\n',
50
+ ' } else {\n',
51
+ ' // Not building snapshot, run normally\n',
52
+ transformedContent,
53
+ '\n',
54
+ ' }\n',
55
+ '})();\n'
56
+ ];
57
+ bundledEntry = parts.join('');
58
+ } else {
59
+ // Non-snapshot mode
60
+ bundledEntry = augmentedBootstrap + '\n\n' + requireSeaboxShim + '\n' + transformedContent;
61
+ }
62
+
63
+ return bundledEntry;
64
+ }
@@ -1,172 +1,172 @@
1
- /**
2
- * fetch-node.mjs
3
- * Download target Node.js binary for SEA injection.
4
- */
5
-
6
- import fs from 'fs';
7
- import path from 'path';
8
- import https from 'https';
9
- import { pipeline } from 'stream';
10
- import { promisify } from 'util';
11
- import AdmZip from 'adm-zip';
12
- import tar from 'tar';
13
- import * as diag from './diagnostics.mjs';
14
-
15
- const pipelineAsync = promisify(pipeline);
16
-
17
- /**
18
- * Construct the Node.js download URL for a given target.
19
- * @param {string} nodeVersion - e.g., "24.11.0"
20
- * @param {string} platform - e.g., "win", "linux", "darwin"
21
- * @param {string} arch - e.g., "x64", "arm64"
22
- * @returns {string}
23
- */
24
- function getNodeDownloadUrl(nodeVersion, platform, arch) {
25
- const baseUrl = 'https://nodejs.org/dist';
26
-
27
- // Map platform names to Node.js naming
28
- const platformMap = {
29
- win32: 'win',
30
- linux: 'linux',
31
- darwin: 'darwin'
32
- };
33
-
34
- const mappedPlatform = platformMap[platform] || platform;
35
-
36
- // Construct filename
37
- let filename;
38
- if (mappedPlatform === 'win') {
39
- filename = `node-v${nodeVersion}-${mappedPlatform}-${arch}.zip`;
40
- } else {
41
- filename = `node-v${nodeVersion}-${mappedPlatform}-${arch}.tar.gz`;
42
- }
43
-
44
- return `${baseUrl}/v${nodeVersion}/${filename}`;
45
- }
46
-
47
- /**
48
- * Download a file from a URL to a local path.
49
- * @param {string} url
50
- * @param {string} outputPath
51
- * @returns {Promise<void>}
52
- */
53
- async function downloadFile(url, outputPath) {
54
- return new Promise((resolve, reject) => {
55
- https.get(url, response => {
56
- if (response.statusCode === 302 || response.statusCode === 301) {
57
- // Follow redirect
58
- return downloadFile(response.headers.location, outputPath)
59
- .then(resolve)
60
- .catch(reject);
61
- }
62
-
63
- if (response.statusCode !== 200) {
64
- reject(new Error(`HTTP ${response.statusCode}: ${url}`));
65
- return;
66
- }
67
-
68
- const file = fs.createWriteStream(outputPath);
69
- pipelineAsync(response, file)
70
- .then(resolve)
71
- .catch(reject);
72
- }).on('error', reject);
73
- });
74
- }
75
-
76
- /**
77
- * Extract node.exe or node binary from downloaded archive.
78
- * @param {string} archivePath - Path to .zip or .tar.gz
79
- * @param {string} outputDir - Directory to extract to
80
- * @param {string} platform - Platform identifier
81
- * @returns {Promise<string>} - Path to extracted node binary
82
- */
83
- async function extractNodeBinary(archivePath, outputDir, platform) {
84
- if (platform === 'win32') {
85
- // Extract from ZIP
86
- const zip = new AdmZip(archivePath);
87
- zip.extractAllTo(outputDir, true);
88
-
89
- // Find node.exe in the extracted directory structure
90
- const extracted = fs.readdirSync(outputDir);
91
- for (const item of extracted) {
92
- const itemPath = path.join(outputDir, item);
93
- if (fs.statSync(itemPath).isDirectory()) {
94
- const nodeExePath = path.join(itemPath, 'node.exe');
95
- if (fs.existsSync(nodeExePath)) {
96
- const finalPath = path.join(outputDir, 'node.exe');
97
- fs.renameSync(nodeExePath, finalPath);
98
- // Clean up extracted directory
99
- fs.rmSync(itemPath, { recursive: true, force: true });
100
- return finalPath;
101
- }
102
- }
103
- }
104
-
105
- throw new Error('node.exe not found in archive');
106
- } else {
107
- // Extract from tar.gz
108
- await tar.extract({
109
- file: archivePath,
110
- cwd: outputDir,
111
- filter: (p) => p.endsWith('/bin/node')
112
- });
113
-
114
- // Find the extracted node binary
115
- const extracted = fs.readdirSync(outputDir);
116
- for (const dir of extracted) {
117
- const nodePath = path.join(outputDir, dir, 'bin', 'node');
118
- if (fs.existsSync(nodePath)) {
119
- const finalPath = path.join(outputDir, 'node');
120
- fs.renameSync(nodePath, finalPath);
121
- fs.chmodSync(finalPath, 0o755);
122
- return finalPath;
123
- }
124
- }
125
-
126
- throw new Error('node binary not found in archive');
127
- }
128
- }
129
-
130
- /**
131
- * Fetch and prepare a Node.js binary for SEA injection.
132
- * @param {string} nodeVersion
133
- * @param {string} platform
134
- * @param {string} arch
135
- * @param {string} cacheDir - Directory to cache downloads
136
- * @returns {Promise<string>} - Path to the node binary
137
- */
138
- export async function fetchNodeBinary(nodeVersion, platform, arch, cacheDir) {
139
- if (!fs.existsSync(cacheDir)) {
140
- fs.mkdirSync(cacheDir, { recursive: true });
141
- }
142
-
143
- const binaryName = platform === 'win32' ? 'node.exe' : 'node';
144
- const cachedBinary = path.join(cacheDir, `${nodeVersion}-${platform}-${arch}`, binaryName);
145
-
146
- // Check cache
147
- if (fs.existsSync(cachedBinary)) {
148
- diag.verbose(`Using cached Node binary: ${cachedBinary}`, 1);
149
- return cachedBinary;
150
- }
151
-
152
- diag.verbose(`Downloading Node.js v${nodeVersion} for ${platform}-${arch}...`, 1);
153
- const url = getNodeDownloadUrl(nodeVersion, platform, arch);
154
- const archiveName = path.basename(url);
155
- const archivePath = path.join(cacheDir, archiveName);
156
-
157
- await downloadFile(url, archivePath);
158
- diag.verbose(`Downloaded: ${archivePath}`, 1);
159
-
160
- const extractDir = path.join(cacheDir, `${nodeVersion}-${platform}-${arch}`);
161
- fs.mkdirSync(extractDir, { recursive: true });
162
-
163
- const binaryPath = await extractNodeBinary(archivePath, extractDir, platform);
164
- diag.verbose(`Extracted Node binary: ${binaryPath}`, 1);
165
-
166
- // Clean up archive
167
- fs.unlinkSync(archivePath);
168
-
169
- return binaryPath;
170
- }
171
-
172
- export { getNodeDownloadUrl, downloadFile, extractNodeBinary };
1
+ /**
2
+ * fetch-node.mjs
3
+ * Download target Node.js binary for SEA injection.
4
+ */
5
+
6
+ import fs from 'fs';
7
+ import path from 'path';
8
+ import https from 'https';
9
+ import { pipeline } from 'stream';
10
+ import { promisify } from 'util';
11
+ import AdmZip from 'adm-zip';
12
+ import tar from 'tar';
13
+ import * as diag from './diagnostics.mjs';
14
+
15
+ const pipelineAsync = promisify(pipeline);
16
+
17
+ /**
18
+ * Construct the Node.js download URL for a given target.
19
+ * @param {string} nodeVersion - e.g., "24.11.0"
20
+ * @param {string} platform - e.g., "win", "linux", "darwin"
21
+ * @param {string} arch - e.g., "x64", "arm64"
22
+ * @returns {string}
23
+ */
24
+ function getNodeDownloadUrl(nodeVersion, platform, arch) {
25
+ const baseUrl = 'https://nodejs.org/dist';
26
+
27
+ // Map platform names to Node.js naming
28
+ const platformMap = {
29
+ win32: 'win',
30
+ linux: 'linux',
31
+ darwin: 'darwin'
32
+ };
33
+
34
+ const mappedPlatform = platformMap[platform] || platform;
35
+
36
+ // Construct filename
37
+ let filename;
38
+ if (mappedPlatform === 'win') {
39
+ filename = `node-v${nodeVersion}-${mappedPlatform}-${arch}.zip`;
40
+ } else {
41
+ filename = `node-v${nodeVersion}-${mappedPlatform}-${arch}.tar.gz`;
42
+ }
43
+
44
+ return `${baseUrl}/v${nodeVersion}/${filename}`;
45
+ }
46
+
47
+ /**
48
+ * Download a file from a URL to a local path.
49
+ * @param {string} url
50
+ * @param {string} outputPath
51
+ * @returns {Promise<void>}
52
+ */
53
+ async function downloadFile(url, outputPath) {
54
+ return new Promise((resolve, reject) => {
55
+ https.get(url, response => {
56
+ if (response.statusCode === 302 || response.statusCode === 301) {
57
+ // Follow redirect
58
+ return downloadFile(response.headers.location, outputPath)
59
+ .then(resolve)
60
+ .catch(reject);
61
+ }
62
+
63
+ if (response.statusCode !== 200) {
64
+ reject(new Error(`HTTP ${response.statusCode}: ${url}`));
65
+ return;
66
+ }
67
+
68
+ const file = fs.createWriteStream(outputPath);
69
+ pipelineAsync(response, file)
70
+ .then(resolve)
71
+ .catch(reject);
72
+ }).on('error', reject);
73
+ });
74
+ }
75
+
76
+ /**
77
+ * Extract node.exe or node binary from downloaded archive.
78
+ * @param {string} archivePath - Path to .zip or .tar.gz
79
+ * @param {string} outputDir - Directory to extract to
80
+ * @param {string} platform - Platform identifier
81
+ * @returns {Promise<string>} - Path to extracted node binary
82
+ */
83
+ async function extractNodeBinary(archivePath, outputDir, platform) {
84
+ if (platform === 'win32') {
85
+ // Extract from ZIP
86
+ const zip = new AdmZip(archivePath);
87
+ zip.extractAllTo(outputDir, true);
88
+
89
+ // Find node.exe in the extracted directory structure
90
+ const extracted = fs.readdirSync(outputDir);
91
+ for (const item of extracted) {
92
+ const itemPath = path.join(outputDir, item);
93
+ if (fs.statSync(itemPath).isDirectory()) {
94
+ const nodeExePath = path.join(itemPath, 'node.exe');
95
+ if (fs.existsSync(nodeExePath)) {
96
+ const finalPath = path.join(outputDir, 'node.exe');
97
+ fs.renameSync(nodeExePath, finalPath);
98
+ // Clean up extracted directory
99
+ fs.rmSync(itemPath, { recursive: true, force: true });
100
+ return finalPath;
101
+ }
102
+ }
103
+ }
104
+
105
+ throw new Error('node.exe not found in archive');
106
+ } else {
107
+ // Extract from tar.gz
108
+ await tar.extract({
109
+ file: archivePath,
110
+ cwd: outputDir,
111
+ filter: (p) => p.endsWith('/bin/node')
112
+ });
113
+
114
+ // Find the extracted node binary
115
+ const extracted = fs.readdirSync(outputDir);
116
+ for (const dir of extracted) {
117
+ const nodePath = path.join(outputDir, dir, 'bin', 'node');
118
+ if (fs.existsSync(nodePath)) {
119
+ const finalPath = path.join(outputDir, 'node');
120
+ fs.renameSync(nodePath, finalPath);
121
+ fs.chmodSync(finalPath, 0o755);
122
+ return finalPath;
123
+ }
124
+ }
125
+
126
+ throw new Error('node binary not found in archive');
127
+ }
128
+ }
129
+
130
+ /**
131
+ * Fetch and prepare a Node.js binary for SEA injection.
132
+ * @param {string} nodeVersion
133
+ * @param {string} platform
134
+ * @param {string} arch
135
+ * @param {string} cacheDir - Directory to cache downloads
136
+ * @returns {Promise<string>} - Path to the node binary
137
+ */
138
+ export async function fetchNodeBinary(nodeVersion, platform, arch, cacheDir) {
139
+ if (!fs.existsSync(cacheDir)) {
140
+ fs.mkdirSync(cacheDir, { recursive: true });
141
+ }
142
+
143
+ const binaryName = platform === 'win32' ? 'node.exe' : 'node';
144
+ const cachedBinary = path.join(cacheDir, `${nodeVersion}-${platform}-${arch}`, binaryName);
145
+
146
+ // Check cache
147
+ if (fs.existsSync(cachedBinary)) {
148
+ diag.verbose(`Using cached Node binary: ${cachedBinary}`, 1);
149
+ return cachedBinary;
150
+ }
151
+
152
+ diag.verbose(`Downloading Node.js v${nodeVersion} for ${platform}-${arch}...`, 1);
153
+ const url = getNodeDownloadUrl(nodeVersion, platform, arch);
154
+ const archiveName = path.basename(url);
155
+ const archivePath = path.join(cacheDir, archiveName);
156
+
157
+ await downloadFile(url, archivePath);
158
+ diag.verbose(`Downloaded: ${archivePath}`, 1);
159
+
160
+ const extractDir = path.join(cacheDir, `${nodeVersion}-${platform}-${arch}`);
161
+ fs.mkdirSync(extractDir, { recursive: true });
162
+
163
+ const binaryPath = await extractNodeBinary(archivePath, extractDir, platform);
164
+ diag.verbose(`Extracted Node binary: ${binaryPath}`, 1);
165
+
166
+ // Clean up archive
167
+ fs.unlinkSync(archivePath);
168
+
169
+ return binaryPath;
170
+ }
171
+
172
+ export { getNodeDownloadUrl, downloadFile, extractNodeBinary };
package/lib/index.mjs CHANGED
@@ -1,26 +1,26 @@
1
- /**
2
- * index.mjs
3
- * Main entry point for Seabox v2 library.
4
- * Exports all public APIs.
5
- */
6
-
7
- export { build } from './build.mjs';
8
- export {
9
- loadConfig,
10
- validateConfig,
11
- parseTarget,
12
- generateDefaultConfig,
13
- normalizeConfig,
14
- getDefaultLibraryPatterns
15
- } from './config.mjs';
16
- export { MultiTargetBuilder } from './multi-target-builder.mjs';
17
- export { bundleWithRollup, NativeModuleDetectorPlugin } from './rolldown-bundler.mjs';
18
- export { scanDependenciesForNativeModules, findNativeModuleBuildPath } from './native-scanner.mjs';
19
- export { BuildCache } from './build-cache.mjs';
20
- export { generateManifest, serializeManifest } from './manifest.mjs';
21
- export { createSeaConfig, writeSeaConfigJson, generateBlob } from './blob.mjs';
22
- export { fetchNodeBinary } from './fetch-node.mjs';
23
- export { injectBlob } from './inject.mjs';
24
- export { generateEncryptionKey, encryptAsset, decryptAsset, encryptAssets, keyToObfuscatedCode } from './crypto-assets.mjs';
25
- export { obfuscateBootstrap } from './obfuscate.mjs';
26
- export { bundleEntry } from './entry-bundler.mjs';
1
+ /**
2
+ * index.mjs
3
+ * Main entry point for Seabox v2 library.
4
+ * Exports all public APIs.
5
+ */
6
+
7
+ export { build } from './build.mjs';
8
+ export {
9
+ loadConfig,
10
+ validateConfig,
11
+ parseTarget,
12
+ generateDefaultConfig,
13
+ normalizeConfig,
14
+ getDefaultLibraryPatterns
15
+ } from './config.mjs';
16
+ export { MultiTargetBuilder } from './multi-target-builder.mjs';
17
+ export { bundleWithRollup, NativeModuleDetectorPlugin } from './rolldown-bundler.mjs';
18
+ export { scanDependenciesForNativeModules, findNativeModuleBuildPath } from './native-scanner.mjs';
19
+ export { BuildCache } from './build-cache.mjs';
20
+ export { generateManifest, serializeManifest } from './manifest.mjs';
21
+ export { createSeaConfig, writeSeaConfigJson, generateBlob } from './blob.mjs';
22
+ export { fetchNodeBinary } from './fetch-node.mjs';
23
+ export { injectBlob } from './inject.mjs';
24
+ export { generateEncryptionKey, encryptAsset, decryptAsset, encryptAssets, keyToObfuscatedCode } from './crypto-assets.mjs';
25
+ export { obfuscateBootstrap } from './obfuscate.mjs';
26
+ export { bundleEntry } from './entry-bundler.mjs';