seabox 0.1.0-beta.4 → 0.1.1

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.
@@ -11,7 +11,6 @@ import { fileURLToPath } from 'url';
11
11
  import Module from 'module';
12
12
 
13
13
  import { bundleWithRollup } from './rolldown-bundler.mjs';
14
- import { scanDependenciesForNativeModules } from './native-scanner.mjs';
15
14
  import { BuildCache } from './build-cache.mjs';
16
15
  import { parseTarget } from './config.mjs';
17
16
  import { generateManifest, serializeManifest } from './manifest.mjs';
@@ -21,6 +20,7 @@ import { injectBlob } from './inject.mjs';
21
20
  import { generateEncryptionKey, encryptAssets, keyToObfuscatedCode } from './crypto-assets.mjs';
22
21
  import { obfuscateBootstrap } from './obfuscate.mjs';
23
22
  import { bundleEntry } from './entry-bundler.mjs';
23
+ import * as diag from './diagnostics.mjs';
24
24
 
25
25
  const __filename = fileURLToPath(import.meta.url);
26
26
  const __dirname = path.dirname(__filename);
@@ -37,8 +37,11 @@ export class MultiTargetBuilder {
37
37
  constructor(config, projectRoot = process.cwd()) {
38
38
  this.config = config;
39
39
  this.projectRoot = projectRoot;
40
- this.cache = new BuildCache(path.join(projectRoot, '.seabox-cache'));
40
+ this.cache = new BuildCache(path.join(projectRoot, 'node_modules', '.cache', '.seabox-cache'));
41
41
  this.verbose = config.verbose || false;
42
+
43
+ // Set verbose mode for diagnostics
44
+ diag.setVerbose(this.verbose);
42
45
  }
43
46
 
44
47
  /**
@@ -46,43 +49,39 @@ export class MultiTargetBuilder {
46
49
  * @returns {Promise<Array<{target: string, path: string}>>}
47
50
  */
48
51
  async buildAll() {
49
- console.log('šŸš€ Seabox Multi-Target Build');
50
- console.log('═══════════════════════════════════════\n');
52
+ diag.header('Seabox Multi-Target Build');
51
53
 
52
54
  // Step 1: Bundle entry once (platform-agnostic JavaScript)
53
55
  const { bundledPath, nativeModules, detectedAssets } = await this.bundleEntry();
54
56
 
55
57
  if (this.verbose && detectedAssets.size > 0) {
56
- console.log('\nšŸ” Auto-detected assets:');
58
+ diag.separator();
59
+ diag.info('Auto-detected assets:');
57
60
  for (const assetPath of detectedAssets) {
58
- console.log(` - ${assetPath}`);
61
+ diag.listItem(assetPath, 1);
59
62
  }
60
63
  }
61
64
 
62
- // Step 2: Scan for additional native modules in node_modules
63
- const scannedNatives = await this.scanNativeModules();
64
-
65
- // Merge detected native modules
66
- const allNativeModules = this.mergeNativeModules(nativeModules, scannedNatives);
67
-
68
- if (this.verbose && allNativeModules.size > 0) {
69
- console.log('\nšŸ“¦ Native modules detected:');
70
- for (const [name, info] of allNativeModules) {
71
- console.log(` - ${name}: ${info.packageRoot}`);
65
+ if (this.verbose && nativeModules.size > 0) {
66
+ diag.separator();
67
+ diag.info('Native modules detected:');
68
+ for (const [name, info] of nativeModules) {
69
+ diag.listItem(`${name}: ${info.packageRoot}`, 1);
72
70
  }
73
71
  }
74
72
 
75
- // Step 3: Build all targets (can be parallelized)
76
- console.log(`\nšŸŽÆ Building ${this.config.outputs.length} target(s)...\n`);
73
+ // Step 2: Build all targets (can be parallelized)
74
+ diag.separator();
75
+ diag.info(`Building ${this.config.outputs.length} target(s)...`);
76
+ diag.separator();
77
77
 
78
78
  const buildPromises = this.config.outputs.map((output, index) =>
79
- this.buildTarget(output, bundledPath, allNativeModules, detectedAssets, index + 1)
79
+ this.buildTarget(output, bundledPath, nativeModules, detectedAssets, index + 1)
80
80
  );
81
81
 
82
82
  const results = await Promise.all(buildPromises);
83
83
 
84
- console.log('\nāœ… All builds completed successfully!');
85
- console.log('═══════════════════════════════════════\n');
84
+ diag.summary('All builds completed successfully!');
86
85
 
87
86
  return results;
88
87
  }
@@ -92,7 +91,7 @@ export class MultiTargetBuilder {
92
91
  * @returns {Promise<{bundledPath: string, nativeModules: Map}>}
93
92
  */
94
93
  async bundleEntry() {
95
- console.log('[1/6] šŸ“ Bundling application with Rollup...');
94
+ diag.step(1, 6, 'Bundling application with Rollup...');
96
95
 
97
96
  const entryPath = path.resolve(this.projectRoot, this.config.entry);
98
97
 
@@ -114,45 +113,12 @@ export class MultiTargetBuilder {
114
113
  this.verbose
115
114
  );
116
115
 
117
- console.log(` āœ“ Bundle created: ${bundledPath}`);
116
+ diag.success(`Bundle created: ${bundledPath}`);
118
117
 
119
118
  return result;
120
119
  }
121
120
 
122
- /**
123
- * Scan node_modules for native modules
124
- * @returns {Promise<Array>}
125
- */
126
- async scanNativeModules() {
127
- if (this.verbose) {
128
- console.log('\n[2/6] šŸ” Scanning node_modules for native modules...');
129
- }
130
-
131
- const nativeModules = await scanDependenciesForNativeModules(this.projectRoot, this.verbose);
132
-
133
- return nativeModules;
134
- }
135
121
 
136
- /**
137
- * Merge detected native modules from bundler and scanner
138
- */
139
- mergeNativeModules(bundlerModules, scannedModules) {
140
- const merged = new Map(bundlerModules);
141
-
142
- // Add scanned modules that weren't detected during bundling
143
- for (const scanned of scannedModules) {
144
- if (!merged.has(scanned.name)) {
145
- merged.set(scanned.name, {
146
- packageRoot: scanned.path,
147
- moduleName: scanned.name,
148
- buildPath: path.join(scanned.path, 'build/Release'),
149
- binaryFiles: scanned.binaryFiles
150
- });
151
- }
152
- }
153
-
154
- return merged;
155
- }
156
122
 
157
123
  /**
158
124
  * Build a single target
@@ -167,8 +133,7 @@ export class MultiTargetBuilder {
167
133
  const { target, path: outputPath, output: executableName } = outputConfig;
168
134
  const { nodeVersion, platform, arch } = parseTarget(target);
169
135
 
170
- console.log(`\n[Build ${buildNumber}] Target: ${target}`);
171
- console.log('─────────────────────────────────────────');
136
+ diag.subheader(`[Build ${buildNumber}] Target: ${target}`);
172
137
 
173
138
  // Step 1: Rebuild native modules for this target
174
139
  const rebuiltModules = await this.rebuildNativeModulesForTarget(
@@ -213,6 +178,41 @@ export class MultiTargetBuilder {
213
178
 
214
179
  const allAssets = Array.from(assetMap.values());
215
180
 
181
+ // Verbose logging: List all embedded assets
182
+ if (this.verbose) {
183
+ diag.separator();
184
+ diag.verbose(`Embedded Assets (${allAssets.length} total):`, 1);
185
+
186
+ const nativeAssets = allAssets.filter(a => a.assetKey.includes('.node'));
187
+ const libraryAssets = allAssets.filter(a => a.isBinary && !a.assetKey.includes('.node'));
188
+ const regularAssets = allAssets.filter(a => !a.isBinary);
189
+
190
+ if (nativeAssets.length > 0) {
191
+ diag.verbose(`Native Modules (${nativeAssets.length}):`, 1);
192
+ for (const asset of nativeAssets) {
193
+ const size = diag.formatSize(fs.statSync(asset.sourcePath).size);
194
+ const displayName = path.basename(asset.assetKey);
195
+ diag.verbose(`- ${displayName} (${size})`, 2);
196
+ }
197
+ }
198
+
199
+ if (libraryAssets.length > 0) {
200
+ diag.verbose(`Platform Libraries (${libraryAssets.length}):`, 1);
201
+ for (const asset of libraryAssets) {
202
+ const size = diag.formatSize(fs.statSync(asset.sourcePath).size);
203
+ diag.verbose(`- ${asset.assetKey} (${size})`, 2);
204
+ }
205
+ }
206
+
207
+ if (regularAssets.length > 0) {
208
+ diag.verbose(`Regular Assets (${regularAssets.length}):`, 1);
209
+ for (const asset of regularAssets) {
210
+ const size = diag.formatSize(fs.statSync(asset.sourcePath).size);
211
+ diag.verbose(`- ${asset.assetKey} (${size})`, 2);
212
+ }
213
+ }
214
+ }
215
+
216
216
  // Step 7: Generate SEA
217
217
  await this.generateSEAForTarget({
218
218
  assets: allAssets,
@@ -228,7 +228,12 @@ export class MultiTargetBuilder {
228
228
  });
229
229
 
230
230
  const finalPath = path.join(outputPath, executableName);
231
- console.log(` āœ… Build complete: ${finalPath}`);
231
+ diag.success(`Build complete: ${finalPath}`);
232
+
233
+ // Apply custom signing if configured
234
+ if (this.config.sign) {
235
+ await this.applyCustomSigning(finalPath, target, platform, arch, nodeVersion, buildNumber);
236
+ }
232
237
 
233
238
  return {
234
239
  target,
@@ -244,24 +249,42 @@ export class MultiTargetBuilder {
244
249
  return [];
245
250
  }
246
251
 
247
- console.log(` [${buildNumber}.1] šŸ”Ø Rebuilding ${nativeModules.size} native module(s)...`);
252
+ diag.buildStep(buildNumber, 1, `Rebuilding ${nativeModules.size} native module(s)...`);
248
253
 
249
254
  const rebuiltAssets = [];
250
255
  const { platform, arch } = parseTarget(target);
251
256
 
252
- for (const [moduleName, moduleInfo] of nativeModules) {
257
+ for (const [moduleKey, moduleInfo] of nativeModules) {
258
+ const moduleName = moduleInfo.moduleName || path.basename(moduleKey, '.node');
259
+
253
260
  try {
261
+ // Skip rebuilding if this is already a prebuild for the target platform
262
+ if (moduleInfo.isPrebuild) {
263
+ diag.verbose(`Using prebuild: ${moduleName}`, 2);
264
+
265
+ const relativeFromProject = path.relative(this.projectRoot, moduleInfo.binaryPath).replace(/\\/g, '/');
266
+
267
+ rebuiltAssets.push({
268
+ sourcePath: moduleInfo.binaryPath,
269
+ assetKey: relativeFromProject,
270
+ isBinary: true,
271
+ hash: await this.computeHash(moduleInfo.binaryPath)
272
+ });
273
+ continue;
274
+ }
275
+
254
276
  // Check cache first
255
277
  const cachedBuild = this.cache.getCachedNativeBuild(moduleInfo.packageRoot, target);
256
278
 
257
279
  if (cachedBuild) {
258
- if (this.verbose) {
259
- console.log(` āœ“ Using cached build: ${moduleName}`);
260
- }
280
+ diag.verbose(`Using cached build: ${moduleName}`, 2);
281
+
282
+ // Use relative path from project root
283
+ const relativeFromProject = path.relative(this.projectRoot, cachedBuild).replace(/\\/g, '/');
261
284
 
262
285
  rebuiltAssets.push({
263
286
  sourcePath: cachedBuild,
264
- assetKey: `native/${moduleName}.node`,
287
+ assetKey: relativeFromProject,
265
288
  isBinary: true,
266
289
  hash: await this.computeHash(cachedBuild)
267
290
  });
@@ -269,9 +292,7 @@ export class MultiTargetBuilder {
269
292
  }
270
293
 
271
294
  // Rebuild the module
272
- if (this.verbose) {
273
- console.log(` šŸ”§ Rebuilding: ${moduleName}`);
274
- }
295
+ diag.verbose(`Rebuilding: ${moduleName}`, 2);
275
296
 
276
297
  await this.rebuildNativeModule(moduleInfo.packageRoot, target);
277
298
 
@@ -282,23 +303,24 @@ export class MultiTargetBuilder {
282
303
  // Cache the build
283
304
  this.cache.cacheNativeBuild(moduleInfo.packageRoot, target, builtPath);
284
305
 
306
+ // Use relative path from project root
307
+ const relativeFromProject = path.relative(this.projectRoot, builtPath).replace(/\\/g, '/');
308
+
285
309
  rebuiltAssets.push({
286
310
  sourcePath: builtPath,
287
- assetKey: `native/${moduleName}.node`,
311
+ assetKey: relativeFromProject,
288
312
  isBinary: true,
289
313
  hash: await this.computeHash(builtPath)
290
314
  });
291
315
 
292
- if (this.verbose) {
293
- console.log(` āœ“ Built: ${moduleName} -> ${builtPath}`);
294
- }
316
+ diag.verbose(`Built: ${moduleName} -> ${builtPath}`, 2);
295
317
  }
296
318
  } catch (err) {
297
- console.warn(` āš ļø Failed to rebuild ${moduleName}:`, err.message);
319
+ diag.warn(`Failed to rebuild ${moduleName}: ${err.message}`, 2);
298
320
  }
299
321
  }
300
322
 
301
- console.log(` āœ“ Native modules processed`);
323
+ diag.success('Native modules processed');
302
324
  return rebuiltAssets;
303
325
  }
304
326
 
@@ -349,33 +371,43 @@ export class MultiTargetBuilder {
349
371
 
350
372
  /**
351
373
  * Collect platform-specific libraries (DLLs, SOs, DYLIBs) that need filesystem extraction
352
- * @param {string[]} libraryPatterns - Glob patterns for libraries
374
+ * Only includes libraries explicitly listed in config patterns - no automatic discovery.
375
+ * Libraries referenced in code (e.g., path.join(__dirname, './lib/foo.dll')) are
376
+ * already captured by the bundler's asset detection.
377
+ *
378
+ * @param {string[]} libraryPatterns - Explicit glob patterns for libraries from config
353
379
  * @param {string} platform - Target platform
354
380
  * @param {string} arch - Target architecture
355
381
  * @param {number} buildNumber - Build number for display
356
382
  */
357
383
  async collectPlatformLibraries(libraryPatterns, platform, arch, buildNumber) {
358
- // Use provided patterns or default to platform-specific patterns
359
- const { getDefaultLibraryPatterns } = await import('./config.mjs');
360
- const patterns = libraryPatterns && libraryPatterns.length > 0
361
- ? libraryPatterns
362
- : getDefaultLibraryPatterns(platform);
363
-
364
- if (!patterns || patterns.length === 0) {
384
+ // Only process explicitly configured library patterns
385
+ // Do NOT use default patterns - this prevents automatic inclusion of unrelated DLLs
386
+ if (!libraryPatterns || libraryPatterns.length === 0) {
365
387
  return [];
366
388
  }
367
389
 
368
- console.log(` [${buildNumber}.4] šŸ“š Collecting platform libraries (${platform})...`);
390
+ diag.buildStep(buildNumber, 4, `Collecting platform libraries (${platform})...`);
369
391
 
370
392
  const { glob } = await import('glob');
371
393
  const libraries = [];
372
394
 
373
- for (const pattern of patterns) {
395
+ for (const pattern of libraryPatterns) {
374
396
  const matches = await glob(pattern, {
375
397
  cwd: this.projectRoot,
376
398
  nodir: true,
377
399
  absolute: false,
378
- ignore: ['**/node_modules/**', '**/.git/**']
400
+ ignore: [
401
+ '**/node_modules/**',
402
+ '**/.git/**',
403
+ '**/dist/**',
404
+ '**/build/**',
405
+ '**/out/**',
406
+ '**/bin/**',
407
+ '**/obj/**',
408
+ '**/tools/**',
409
+ '**/.seabox-cache/**'
410
+ ]
379
411
  });
380
412
 
381
413
  for (const match of matches) {
@@ -391,7 +423,7 @@ export class MultiTargetBuilder {
391
423
  }
392
424
 
393
425
  if (libraries.length > 0) {
394
- console.log(` āœ“ Collected ${libraries.length} library file(s)`);
426
+ diag.success(`Collected ${libraries.length} library file(s)`);
395
427
  }
396
428
 
397
429
  return libraries;
@@ -407,7 +439,7 @@ export class MultiTargetBuilder {
407
439
  return [];
408
440
  }
409
441
 
410
- console.log(` [${buildNumber}.2] šŸ“¦ Collecting config assets...`);
442
+ diag.buildStep(buildNumber, 2, 'Collecting config assets...');
411
443
 
412
444
  const { glob } = await import('glob');
413
445
  const assets = [];
@@ -417,7 +449,17 @@ export class MultiTargetBuilder {
417
449
  cwd: this.projectRoot,
418
450
  nodir: true,
419
451
  absolute: false,
420
- ignore: ['**/node_modules/**', '**/.git/**']
452
+ ignore: [
453
+ '**/node_modules/**',
454
+ '**/.git/**',
455
+ '**/dist/**',
456
+ '**/build/**',
457
+ '**/out/**',
458
+ '**/bin/**',
459
+ '**/obj/**',
460
+ '**/tools/**',
461
+ '**/.seabox-cache/**'
462
+ ]
421
463
  });
422
464
 
423
465
  for (const match of matches) {
@@ -433,7 +475,7 @@ export class MultiTargetBuilder {
433
475
  }
434
476
 
435
477
  if (assets.length > 0) {
436
- console.log(` āœ“ Collected ${assets.length} config asset(s)`);
478
+ diag.success(`Collected ${assets.length} config asset(s)`);
437
479
  }
438
480
 
439
481
  return assets;
@@ -449,7 +491,7 @@ export class MultiTargetBuilder {
449
491
  return [];
450
492
  }
451
493
 
452
- console.log(` [${buildNumber}.3] šŸ” Processing auto-detected assets...`);
494
+ diag.buildStep(buildNumber, 3, 'Processing auto-detected assets...');
453
495
 
454
496
  const assets = [];
455
497
 
@@ -468,7 +510,7 @@ export class MultiTargetBuilder {
468
510
  }
469
511
 
470
512
  if (assets.length > 0) {
471
- console.log(` āœ“ Collected ${assets.length} auto-detected asset(s)`);
513
+ diag.success(`Collected ${assets.length} auto-detected asset(s)`);
472
514
  }
473
515
 
474
516
  return assets;
@@ -487,7 +529,7 @@ export class MultiTargetBuilder {
487
529
  * Prepare final entry with bootstrap
488
530
  */
489
531
  async prepareFinalEntry(bundledEntryPath, buildNumber) {
490
- console.log(` [${buildNumber}.3] šŸŽ Preparing bootstrap...`);
532
+ diag.buildStep(buildNumber, 3, 'Preparing bootstrap...');
491
533
 
492
534
  const bootstrapPath = path.join(__dirname, 'bootstrap.cjs');
493
535
  const bootstrapContent = fs.readFileSync(bootstrapPath, 'utf8');
@@ -509,9 +551,7 @@ const SEA_ENCRYPTED_ASSETS = new Set([]);
509
551
  " 'use strict';\n" + encryptionSetup
510
552
  );
511
553
 
512
- if (this.verbose) {
513
- console.log(' āœ“ Encryption enabled and bootstrap obfuscated');
514
- }
554
+ diag.verbose('Encryption enabled and bootstrap obfuscated', 2);
515
555
 
516
556
  augmentedBootstrap = obfuscateBootstrap(augmentedBootstrap);
517
557
  }
@@ -526,7 +566,7 @@ const SEA_ENCRYPTED_ASSETS = new Set([]);
526
566
  const finalPath = bundledEntryPath.replace('.js', '-final.js');
527
567
  fs.writeFileSync(finalPath, finalEntry, 'utf8');
528
568
 
529
- console.log(` āœ“ Bootstrap prepared`);
569
+ diag.success('Bootstrap prepared');
530
570
  return finalPath;
531
571
  }
532
572
 
@@ -547,7 +587,7 @@ const SEA_ENCRYPTED_ASSETS = new Set([]);
547
587
  buildNumber
548
588
  } = options;
549
589
 
550
- console.log(` [${buildNumber}.4] šŸ”§ Generating SEA blob...`);
590
+ diag.buildStep(buildNumber, 4, 'Generating SEA blob...');
551
591
 
552
592
  // Generate manifest
553
593
  const manifest = generateManifest(
@@ -583,16 +623,16 @@ const SEA_ENCRYPTED_ASSETS = new Set([]);
583
623
 
584
624
  // Generate blob
585
625
  await generateBlob(seaConfigPath, process.execPath);
586
- console.log(` āœ“ SEA blob generated`);
626
+ diag.success('SEA blob generated');
587
627
 
588
628
  // Fetch Node binary
589
- console.log(` [${buildNumber}.5] šŸ“„ Fetching Node.js binary...`);
629
+ diag.buildStep(buildNumber, 5, 'Fetching Node.js binary...');
590
630
  const cacheDir = path.join(this.projectRoot, 'node_modules', '.cache', 'sea-node-binaries');
591
631
  const nodeBinary = await fetchNodeBinary(nodeVersion, platform, arch, cacheDir);
592
- console.log(` āœ“ Node binary ready`);
632
+ diag.success('Node binary ready');
593
633
 
594
634
  // Inject blob
595
- console.log(` [${buildNumber}.6] šŸ’‰ Injecting blob into executable...`);
635
+ diag.buildStep(buildNumber, 6, 'Injecting blob into executable...');
596
636
  const outputExe = path.join(outputDir, executableName);
597
637
  await injectBlob(nodeBinary, blobOutputPath, outputExe, platform, this.verbose, rcedit);
598
638
 
@@ -601,8 +641,8 @@ const SEA_ENCRYPTED_ASSETS = new Set([]);
601
641
  fs.rmSync(tempDir, { recursive: true, force: true });
602
642
  }
603
643
 
604
- const sizeMB = (fs.statSync(outputExe).size / 1024 / 1024).toFixed(2);
605
- console.log(` āœ“ Injected (${sizeMB} MB)`);
644
+ const size = diag.formatSize(fs.statSync(outputExe).size);
645
+ diag.success(`Injected (${size})`);
606
646
  }
607
647
 
608
648
  /**
@@ -617,4 +657,49 @@ const SEA_ENCRYPTED_ASSETS = new Set([]);
617
657
  stream.on('error', reject);
618
658
  });
619
659
  }
660
+
661
+ /**
662
+ * Apply custom signing script
663
+ * @param {string} exePath - Path to executable
664
+ * @param {string} target - Build target
665
+ * @param {string} platform - Platform (win32, linux, darwin)
666
+ * @param {string} arch - Architecture (x64, arm64)
667
+ * @param {string} nodeVersion - Node version
668
+ * @param {number} buildNumber - Build number
669
+ */
670
+ async applyCustomSigning(exePath, target, platform, arch, nodeVersion, buildNumber) {
671
+ diag.buildStep(buildNumber, 7, 'Applying custom signing...');
672
+
673
+ try {
674
+ const signScriptPath = path.resolve(this.projectRoot, this.config.sign);
675
+
676
+ if (!fs.existsSync(signScriptPath)) {
677
+ throw new Error(`Signing script not found: ${signScriptPath}`);
678
+ }
679
+
680
+ // Dynamic import of the signing script - convert to file:// URL for Windows
681
+ const { pathToFileURL } = await import('url');
682
+ const signModuleURL = pathToFileURL(signScriptPath).href;
683
+ const signModule = await import(signModuleURL);
684
+ const signFunction = signModule.default;
685
+
686
+ if (typeof signFunction !== 'function') {
687
+ throw new Error('Signing script must export a default function');
688
+ }
689
+
690
+ // Call the signing function with config
691
+ await signFunction({
692
+ exePath: path.resolve(exePath),
693
+ target,
694
+ platform,
695
+ arch,
696
+ nodeVersion,
697
+ projectRoot: this.projectRoot
698
+ });
699
+
700
+ diag.success('Custom signing applied');
701
+ } catch (error) {
702
+ throw new Error(`Signing failed: ${error.message}`);
703
+ }
704
+ }
620
705
  }
@@ -6,6 +6,7 @@
6
6
  import fs from 'fs/promises';
7
7
  import fsSync from 'fs';
8
8
  import path from 'path';
9
+ import * as diag from './diagnostics.mjs';
9
10
 
10
11
  /**
11
12
  * @typedef {Object} NativeModuleMetadata
@@ -27,15 +28,11 @@ export async function scanDependenciesForNativeModules(projectRoot, verbose = fa
27
28
  const nodeModulesPath = path.join(projectRoot, 'node_modules');
28
29
 
29
30
  if (!fsSync.existsSync(nodeModulesPath)) {
30
- if (verbose) {
31
- console.log('[NativeScanner] No node_modules directory found');
32
- }
31
+ diag.verbose('No node_modules directory found');
33
32
  return [];
34
33
  }
35
34
 
36
- if (verbose) {
37
- console.log('[NativeScanner] Scanning node_modules for native modules');
38
- }
35
+ diag.verbose('Scanning node_modules for native modules');
39
36
 
40
37
  /**
41
38
  * Recursively scan a directory for packages
@@ -71,9 +68,7 @@ export async function scanDependenciesForNativeModules(projectRoot, verbose = fa
71
68
  }
72
69
  }
73
70
  } catch (err) {
74
- if (verbose) {
75
- console.warn('[NativeScanner] Error scanning directory:', dir, err.message);
76
- }
71
+ diag.verbose(`Error scanning directory: ${dir} - ${err.message}`);
77
72
  }
78
73
  }
79
74
 
@@ -152,11 +147,9 @@ export async function scanDependenciesForNativeModules(projectRoot, verbose = fa
152
147
 
153
148
  await scanDir(nodeModulesPath);
154
149
 
155
- if (verbose) {
156
- console.log(`[NativeScanner] Found ${nativeModules.length} native modules`);
157
- for (const mod of nativeModules) {
158
- console.log(` - ${mod.name}@${mod.version} (${mod.binaryFiles.length} binaries)`);
159
- }
150
+ diag.verbose(`Found ${nativeModules.length} native modules`);
151
+ for (const mod of nativeModules) {
152
+ diag.verbose(`- ${mod.name}@${mod.version} (${mod.binaryFiles.length} binaries)`, 1);
160
153
  }
161
154
 
162
155
  return nativeModules;
@@ -3,6 +3,8 @@
3
3
  * SEA-aware require replacement that intercepts .node module loads
4
4
  */
5
5
 
6
+ import * as diag from './diagnostics.mjs';
7
+
6
8
  /**
7
9
  * Generate the __requireSeabox shim code
8
10
  * @returns {string} - The shim code to inject
@@ -58,9 +60,9 @@ function __requireSeabox(id) {
58
60
  process.dlopen(module, resolvedPath);
59
61
  return module.exports;
60
62
  } else {
61
- console.error('[__requireSeabox] āœ— Native module not found in map');
62
- console.error('[__requireSeabox] Requested:', id);
63
- console.error('[__requireSeabox] Available:', Object.keys(global.__seaNativeModuleMap));
63
+ console.error('[X] Native module not found in map');
64
+ console.error(' Requested:', id);
65
+ console.error(' Available:', Object.keys(global.__seaNativeModuleMap));
64
66
  }
65
67
  }
66
68
  }
@@ -88,7 +90,7 @@ function __requireSeabox(id) {
88
90
  * @returns {Object} - { code: string, count: number }
89
91
  */
90
92
  export function replaceRequireCalls(sourceCode, verbose = false) {
91
- if (verbose) console.log('Replacing require() calls with __requireSeabox()');
93
+ diag.verbose('Replacing require() calls with __requireSeabox()');
92
94
 
93
95
  const requirePattern = /\brequire\s*\(/g;
94
96
  let replacementCount = 0;
@@ -98,7 +100,7 @@ export function replaceRequireCalls(sourceCode, verbose = false) {
98
100
  return '__requireSeabox(';
99
101
  });
100
102
 
101
- if (verbose) console.log('Replaced ' + replacementCount + ' require() calls');
103
+ diag.verbose(`Replaced ${replacementCount} require() calls`);
102
104
 
103
105
  return {
104
106
  code: transformedCode,