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/config.mjs CHANGED
@@ -1,243 +1,243 @@
1
- /**
2
- * config.mjs
3
- * Load and validate SEA configuration from seabox.config.json or package.json.
4
- */
5
-
6
- import fs from 'fs';
7
- import path from 'path';
8
-
9
- /**
10
- * @typedef {Object} OutputTarget
11
- * @property {string} path - Output directory
12
- * @property {string} target - Node version and platform (e.g., node24.11.0-win32-x64)
13
- * @property {string} output - Executable filename
14
- * @property {string[]} [libraries] - Glob patterns for shared libraries (DLLs/SOs) requiring filesystem extraction
15
- * @property {Object} [rcedit] - Windows executable customization options
16
- */
17
-
18
- /**
19
- * @typedef {Object} BundlerConfig
20
- * @property {string[]} [external] - Modules to externalize
21
- * @property {Array} [plugins] - Rollup plugins
22
- * @property {boolean} [minify] - Minify output
23
- * @property {boolean} [sourcemap] - Generate sourcemaps
24
- */
25
-
26
- /**
27
- * @typedef {Object} SeaboxConfig
28
- * @property {string} entry - Entry point source file
29
- * @property {OutputTarget[]} outputs - Multi-target output configurations
30
- * @property {string[]} [assets] - Glob patterns for assets to embed (auto-detected assets are merged)
31
- * @property {BundlerConfig} [bundler] - Bundler configuration
32
- * @property {boolean} [encryptAssets] - Enable asset encryption
33
- * @property {string[]} [encryptExclude] - Assets to exclude from encryption
34
- * @property {boolean} [useSnapshot] - Enable V8 snapshot
35
- * @property {boolean} [useCodeCache] - Enable V8 code cache
36
- * @property {string} [cacheLocation] - Cache directory for extracted binaries
37
- * @property {string} [sign] - Path to signing script (.mjs/.cjs) that exports a function(config) => Promise<void>
38
- * @property {boolean} [verbose] - Enable verbose logging
39
- */
40
-
41
- /**
42
- * Load SEA configuration from seabox.config.json or package.json
43
- * @param {string} [configPath] - Optional path to config file
44
- * @param {string} [projectRoot] - Project root directory
45
- * @returns {SeaboxConfig|null} Config object or null if not found
46
- */
47
- export function loadConfig(configPath, projectRoot = process.cwd()) {
48
- let config;
49
-
50
- // Priority: CLI arg > seabox.config.json > package.json "seabox" field
51
- if (configPath) {
52
- // If explicit config path provided, it must exist
53
- const fullPath = path.resolve(projectRoot, configPath);
54
- if (!fs.existsSync(fullPath)) {
55
- throw new Error(`Config file not found: ${fullPath}`);
56
- }
57
- config = JSON.parse(fs.readFileSync(fullPath, 'utf8'));
58
- } else if (fs.existsSync(path.join(projectRoot, 'seabox.config.json'))) {
59
- // Check for seabox.config.json
60
- const configFile = path.join(projectRoot, 'seabox.config.json');
61
- config = JSON.parse(fs.readFileSync(configFile, 'utf8'));
62
- } else {
63
- // Check for "seabox" field in package.json
64
- const pkgPath = path.join(projectRoot, 'package.json');
65
-
66
- if (fs.existsSync(pkgPath)) {
67
- const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
68
-
69
- if (pkg.seabox) {
70
- config = normalizeConfig(pkg.seabox, pkg);
71
- } else {
72
- // No config found anywhere - return null
73
- return null;
74
- }
75
- } else {
76
- // No package.json - return null
77
- return null;
78
- }
79
- }
80
-
81
- validateConfig(config);
82
-
83
- return config;
84
- }
85
-
86
- /**
87
- * Normalize config from package.json to standard format
88
- * @param {Object} pkgConfig - Config from package.json "seabox" field
89
- * @param {Object} pkg - package.json contents
90
- * @returns {SeaboxConfig}
91
- */
92
- export function normalizeConfig(pkgConfig, pkg) {
93
- // Helper to normalize assets to array
94
- const normalizeAssets = (assets) => {
95
- if (!assets) return [];
96
- if (Array.isArray(assets)) return assets;
97
- if (typeof assets === 'string') return [assets];
98
- return [];
99
- };
100
-
101
- // If already in outputs format, return as-is
102
- if (pkgConfig.outputs) {
103
- return {
104
- ...pkgConfig,
105
- assets: normalizeAssets(pkgConfig.assets),
106
- bundler: pkgConfig.bundler || { external: [] },
107
- _packageName: pkg.name,
108
- _packageVersion: pkg.version
109
- };
110
- }
111
-
112
- // Convert old targets format to outputs format
113
- const outputs = (pkgConfig.targets || []).map(target => ({
114
- path: pkgConfig.outputPath || 'dist',
115
- target: target,
116
- output: pkgConfig.output || 'app.exe',
117
- libraries: pkgConfig.binaries || pkgConfig.libraries,
118
- rcedit: pkgConfig.rcedit
119
- }));
120
-
121
- return {
122
- entry: pkgConfig.entry,
123
- outputs: outputs,
124
- assets: normalizeAssets(pkgConfig.assets),
125
- bundler: {
126
- external: pkgConfig.external || []
127
- },
128
- encryptAssets: pkgConfig.encryptAssets || false,
129
- encryptExclude: pkgConfig.encryptExclude || [],
130
- useSnapshot: pkgConfig.useSnapshot || false,
131
- useCodeCache: pkgConfig.useCodeCache || false,
132
- cacheLocation: pkgConfig.cacheLocation,
133
- verbose: pkgConfig.verbose || false,
134
- _packageName: pkg.name,
135
- _packageVersion: pkg.version
136
- };
137
- }
138
-
139
- /**
140
- * Validate configuration
141
- * @param {SeaboxConfig} config
142
- */
143
- export function validateConfig(config) {
144
- // Required fields
145
- if (!config.entry) {
146
- throw new Error('Missing required field: entry');
147
- }
148
-
149
- if (!config.outputs || !Array.isArray(config.outputs) || config.outputs.length === 0) {
150
- throw new Error('Missing required field: outputs (must be non-empty array)');
151
- }
152
-
153
- // Validate each output target
154
- for (const output of config.outputs) {
155
- if (!output.path) {
156
- throw new Error('Output target missing required field: path');
157
- }
158
- if (!output.target) {
159
- throw new Error('Output target missing required field: target');
160
- }
161
- if (!output.output) {
162
- throw new Error('Output target missing required field: output');
163
- }
164
-
165
- // Validate target format
166
- const targetPattern = /^node\d+\.\d+\.\d+-\w+-\w+$/;
167
- if (!targetPattern.test(output.target)) {
168
- throw new Error(`Invalid target format: "${output.target}". Expected: nodeX.Y.Z-platform-arch`);
169
- }
170
- }
171
- }
172
-
173
- /**
174
- * Parse a target string into components
175
- * @param {string} target - e.g., "node24.11.0-win32-x64"
176
- * @returns {{nodeVersion: string, platform: string, arch: string}}
177
- */
178
- export function parseTarget(target) {
179
- const match = target.match(/^node(\d+\.\d+\.\d+)-(\w+)-(\w+)$/);
180
- if (!match) {
181
- throw new Error(`Cannot parse target: ${target}`);
182
- }
183
- return {
184
- nodeVersion: match[1],
185
- platform: match[2],
186
- arch: match[3]
187
- };
188
- }
189
-
190
- /**
191
- * Get default library patterns for a platform
192
- * @param {string} platform - Platform name (win32, linux, darwin)
193
- * @returns {string[]}
194
- */
195
- export function getDefaultLibraryPatterns(platform) {
196
- switch (platform) {
197
- case 'win32':
198
- return ['**/*.dll'];
199
- case 'linux':
200
- return ['**/*.so', '**/*.so.*'];
201
- case 'darwin':
202
- return ['**/*.dylib'];
203
- default:
204
- return [];
205
- }
206
- }
207
-
208
- /**
209
- * Generate default configuration
210
- * @param {Object} options - Options for config generation
211
- * @returns {SeaboxConfig}
212
- */
213
- export function generateDefaultConfig(options = {}) {
214
- return {
215
- entry: options.entry || './src/index.js',
216
- outputs: [
217
- {
218
- path: './dist/win',
219
- target: 'node24.11.0-win32-x64',
220
- output: 'app.exe',
221
- libraries: ['**/*.dll']
222
- },
223
- {
224
- path: './dist/linux',
225
- target: 'node24.11.0-linux-x64',
226
- output: 'app',
227
- libraries: ['**/*.so', '**/*.so.*']
228
- },
229
- {
230
- path: './dist/macos',
231
- target: 'node24.11.0-darwin-arm64',
232
- output: 'app',
233
- libraries: ['**/*.dylib']
234
- }
235
- ],
236
- assets: [],
237
- bundler: {
238
- external: []
239
- },
240
- encryptAssets: false,
241
- useSnapshot: true
242
- };
243
- }
1
+ /**
2
+ * config.mjs
3
+ * Load and validate SEA configuration from seabox.config.json or package.json.
4
+ */
5
+
6
+ import fs from 'fs';
7
+ import path from 'path';
8
+
9
+ /**
10
+ * @typedef {Object} OutputTarget
11
+ * @property {string} path - Output directory
12
+ * @property {string} target - Node version and platform (e.g., node24.11.0-win32-x64)
13
+ * @property {string} output - Executable filename
14
+ * @property {string[]} [libraries] - Glob patterns for shared libraries (DLLs/SOs) requiring filesystem extraction
15
+ * @property {Object} [rcedit] - Windows executable customization options
16
+ */
17
+
18
+ /**
19
+ * @typedef {Object} BundlerConfig
20
+ * @property {string[]} [external] - Modules to externalize
21
+ * @property {Array} [plugins] - Rollup plugins
22
+ * @property {boolean} [minify] - Minify output
23
+ * @property {boolean} [sourcemap] - Generate sourcemaps
24
+ */
25
+
26
+ /**
27
+ * @typedef {Object} SeaboxConfig
28
+ * @property {string} entry - Entry point source file
29
+ * @property {OutputTarget[]} outputs - Multi-target output configurations
30
+ * @property {string[]} [assets] - Glob patterns for assets to embed (auto-detected assets are merged)
31
+ * @property {BundlerConfig} [bundler] - Bundler configuration
32
+ * @property {boolean} [encryptAssets] - Enable asset encryption
33
+ * @property {string[]} [encryptExclude] - Assets to exclude from encryption
34
+ * @property {boolean} [useSnapshot] - Enable V8 snapshot
35
+ * @property {boolean} [useCodeCache] - Enable V8 code cache
36
+ * @property {string} [cacheLocation] - Cache directory for extracted binaries
37
+ * @property {string} [sign] - Path to signing script (.mjs/.cjs) that exports a function(config) => Promise<void>
38
+ * @property {boolean} [verbose] - Enable verbose logging
39
+ */
40
+
41
+ /**
42
+ * Load SEA configuration from seabox.config.json or package.json
43
+ * @param {string} [configPath] - Optional path to config file
44
+ * @param {string} [projectRoot] - Project root directory
45
+ * @returns {SeaboxConfig|null} Config object or null if not found
46
+ */
47
+ export function loadConfig(configPath, projectRoot = process.cwd()) {
48
+ let config;
49
+
50
+ // Priority: CLI arg > seabox.config.json > package.json "seabox" field
51
+ if (configPath) {
52
+ // If explicit config path provided, it must exist
53
+ const fullPath = path.resolve(projectRoot, configPath);
54
+ if (!fs.existsSync(fullPath)) {
55
+ throw new Error(`Config file not found: ${fullPath}`);
56
+ }
57
+ config = JSON.parse(fs.readFileSync(fullPath, 'utf8'));
58
+ } else if (fs.existsSync(path.join(projectRoot, 'seabox.config.json'))) {
59
+ // Check for seabox.config.json
60
+ const configFile = path.join(projectRoot, 'seabox.config.json');
61
+ config = JSON.parse(fs.readFileSync(configFile, 'utf8'));
62
+ } else {
63
+ // Check for "seabox" field in package.json
64
+ const pkgPath = path.join(projectRoot, 'package.json');
65
+
66
+ if (fs.existsSync(pkgPath)) {
67
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
68
+
69
+ if (pkg.seabox) {
70
+ config = normalizeConfig(pkg.seabox, pkg);
71
+ } else {
72
+ // No config found anywhere - return null
73
+ return null;
74
+ }
75
+ } else {
76
+ // No package.json - return null
77
+ return null;
78
+ }
79
+ }
80
+
81
+ validateConfig(config);
82
+
83
+ return config;
84
+ }
85
+
86
+ /**
87
+ * Normalize config from package.json to standard format
88
+ * @param {Object} pkgConfig - Config from package.json "seabox" field
89
+ * @param {Object} pkg - package.json contents
90
+ * @returns {SeaboxConfig}
91
+ */
92
+ export function normalizeConfig(pkgConfig, pkg) {
93
+ // Helper to normalize assets to array
94
+ const normalizeAssets = (assets) => {
95
+ if (!assets) return [];
96
+ if (Array.isArray(assets)) return assets;
97
+ if (typeof assets === 'string') return [assets];
98
+ return [];
99
+ };
100
+
101
+ // If already in outputs format, return as-is
102
+ if (pkgConfig.outputs) {
103
+ return {
104
+ ...pkgConfig,
105
+ assets: normalizeAssets(pkgConfig.assets),
106
+ bundler: pkgConfig.bundler || { external: [] },
107
+ _packageName: pkg.name,
108
+ _packageVersion: pkg.version
109
+ };
110
+ }
111
+
112
+ // Convert old targets format to outputs format
113
+ const outputs = (pkgConfig.targets || []).map(target => ({
114
+ path: pkgConfig.outputPath || 'dist',
115
+ target: target,
116
+ output: pkgConfig.output || 'app.exe',
117
+ libraries: pkgConfig.binaries || pkgConfig.libraries,
118
+ rcedit: pkgConfig.rcedit
119
+ }));
120
+
121
+ return {
122
+ entry: pkgConfig.entry,
123
+ outputs: outputs,
124
+ assets: normalizeAssets(pkgConfig.assets),
125
+ bundler: {
126
+ external: pkgConfig.external || []
127
+ },
128
+ encryptAssets: pkgConfig.encryptAssets || false,
129
+ encryptExclude: pkgConfig.encryptExclude || [],
130
+ useSnapshot: pkgConfig.useSnapshot || false,
131
+ useCodeCache: pkgConfig.useCodeCache || false,
132
+ cacheLocation: pkgConfig.cacheLocation,
133
+ verbose: pkgConfig.verbose || false,
134
+ _packageName: pkg.name,
135
+ _packageVersion: pkg.version
136
+ };
137
+ }
138
+
139
+ /**
140
+ * Validate configuration
141
+ * @param {SeaboxConfig} config
142
+ */
143
+ export function validateConfig(config) {
144
+ // Required fields
145
+ if (!config.entry) {
146
+ throw new Error('Missing required field: entry');
147
+ }
148
+
149
+ if (!config.outputs || !Array.isArray(config.outputs) || config.outputs.length === 0) {
150
+ throw new Error('Missing required field: outputs (must be non-empty array)');
151
+ }
152
+
153
+ // Validate each output target
154
+ for (const output of config.outputs) {
155
+ if (!output.path) {
156
+ throw new Error('Output target missing required field: path');
157
+ }
158
+ if (!output.target) {
159
+ throw new Error('Output target missing required field: target');
160
+ }
161
+ if (!output.output) {
162
+ throw new Error('Output target missing required field: output');
163
+ }
164
+
165
+ // Validate target format
166
+ const targetPattern = /^node\d+\.\d+\.\d+-\w+-\w+$/;
167
+ if (!targetPattern.test(output.target)) {
168
+ throw new Error(`Invalid target format: "${output.target}". Expected: nodeX.Y.Z-platform-arch`);
169
+ }
170
+ }
171
+ }
172
+
173
+ /**
174
+ * Parse a target string into components
175
+ * @param {string} target - e.g., "node24.11.0-win32-x64"
176
+ * @returns {{nodeVersion: string, platform: string, arch: string}}
177
+ */
178
+ export function parseTarget(target) {
179
+ const match = target.match(/^node(\d+\.\d+\.\d+)-(\w+)-(\w+)$/);
180
+ if (!match) {
181
+ throw new Error(`Cannot parse target: ${target}`);
182
+ }
183
+ return {
184
+ nodeVersion: match[1],
185
+ platform: match[2],
186
+ arch: match[3]
187
+ };
188
+ }
189
+
190
+ /**
191
+ * Get default library patterns for a platform
192
+ * @param {string} platform - Platform name (win32, linux, darwin)
193
+ * @returns {string[]}
194
+ */
195
+ export function getDefaultLibraryPatterns(platform) {
196
+ switch (platform) {
197
+ case 'win32':
198
+ return ['**/*.dll'];
199
+ case 'linux':
200
+ return ['**/*.so', '**/*.so.*'];
201
+ case 'darwin':
202
+ return ['**/*.dylib'];
203
+ default:
204
+ return [];
205
+ }
206
+ }
207
+
208
+ /**
209
+ * Generate default configuration
210
+ * @param {Object} options - Options for config generation
211
+ * @returns {SeaboxConfig}
212
+ */
213
+ export function generateDefaultConfig(options = {}) {
214
+ return {
215
+ entry: options.entry || './src/index.js',
216
+ outputs: [
217
+ {
218
+ path: './dist/win',
219
+ target: 'node24.11.0-win32-x64',
220
+ output: 'app.exe',
221
+ libraries: ['**/*.dll']
222
+ },
223
+ {
224
+ path: './dist/linux',
225
+ target: 'node24.11.0-linux-x64',
226
+ output: 'app',
227
+ libraries: ['**/*.so', '**/*.so.*']
228
+ },
229
+ {
230
+ path: './dist/macos',
231
+ target: 'node24.11.0-darwin-arm64',
232
+ output: 'app',
233
+ libraries: ['**/*.dylib']
234
+ }
235
+ ],
236
+ assets: [],
237
+ bundler: {
238
+ external: []
239
+ },
240
+ encryptAssets: false,
241
+ useSnapshot: true
242
+ };
243
+ }