electrobun 0.0.19-beta.131 → 0.0.19-beta.133
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/package.json +1 -1
- package/src/cli/index.ts +166 -39
- package/templates/multitab-browser/package.json +1 -1
package/package.json
CHANGED
package/src/cli/index.ts
CHANGED
|
@@ -306,54 +306,164 @@ async function ensureCEFDependencies(targetOS?: 'macos' | 'win' | 'linux', targe
|
|
|
306
306
|
const archName = platformArch;
|
|
307
307
|
const cefTarballUrl = `https://github.com/blackboardsh/electrobun/releases/download/${version}/electrobun-cef-${platformName}-${archName}.tar.gz`;
|
|
308
308
|
|
|
309
|
-
|
|
309
|
+
// Helper function to download with retry logic
|
|
310
|
+
async function downloadWithRetry(url: string, filePath: string, maxRetries = 3): Promise<void> {
|
|
311
|
+
for (let attempt = 1; attempt <= maxRetries; attempt++) {
|
|
312
|
+
try {
|
|
313
|
+
console.log(`Downloading CEF (attempt ${attempt}/${maxRetries}) from: ${url}`);
|
|
314
|
+
|
|
315
|
+
const response = await fetch(url);
|
|
316
|
+
if (!response.ok) {
|
|
317
|
+
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
// Get content length for progress tracking
|
|
321
|
+
const contentLength = response.headers.get('content-length');
|
|
322
|
+
const totalSize = contentLength ? parseInt(contentLength, 10) : 0;
|
|
323
|
+
|
|
324
|
+
// Create temp file with unique name to avoid conflicts
|
|
325
|
+
const fileStream = createWriteStream(filePath);
|
|
326
|
+
let downloadedSize = 0;
|
|
327
|
+
let lastReportedPercent = -1;
|
|
328
|
+
|
|
329
|
+
// Stream download with progress
|
|
330
|
+
if (response.body) {
|
|
331
|
+
const reader = response.body.getReader();
|
|
332
|
+
while (true) {
|
|
333
|
+
const { done, value } = await reader.read();
|
|
334
|
+
if (done) break;
|
|
335
|
+
|
|
336
|
+
const chunk = Buffer.from(value);
|
|
337
|
+
fileStream.write(chunk);
|
|
338
|
+
downloadedSize += chunk.length;
|
|
339
|
+
|
|
340
|
+
if (totalSize > 0) {
|
|
341
|
+
const percent = Math.round((downloadedSize / totalSize) * 100);
|
|
342
|
+
const percentTier = Math.floor(percent / 10) * 10;
|
|
343
|
+
if (percentTier > lastReportedPercent && percentTier <= 100) {
|
|
344
|
+
console.log(` Progress: ${percentTier}% (${Math.round(downloadedSize / 1024 / 1024)}MB/${Math.round(totalSize / 1024 / 1024)}MB)`);
|
|
345
|
+
lastReportedPercent = percentTier;
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
await new Promise((resolve, reject) => {
|
|
352
|
+
fileStream.end((error: any) => {
|
|
353
|
+
if (error) reject(error);
|
|
354
|
+
else resolve(void 0);
|
|
355
|
+
});
|
|
356
|
+
});
|
|
357
|
+
|
|
358
|
+
// Verify file size if content-length was provided
|
|
359
|
+
if (totalSize > 0) {
|
|
360
|
+
const actualSize = (await import('fs')).statSync(filePath).size;
|
|
361
|
+
if (actualSize !== totalSize) {
|
|
362
|
+
throw new Error(`Downloaded file size mismatch: expected ${totalSize}, got ${actualSize}`);
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
console.log(`✓ Download completed successfully (${Math.round(downloadedSize / 1024 / 1024)}MB)`);
|
|
367
|
+
return; // Success, exit retry loop
|
|
368
|
+
|
|
369
|
+
} catch (error: any) {
|
|
370
|
+
console.error(`Download attempt ${attempt} failed:`, error.message);
|
|
371
|
+
|
|
372
|
+
// Clean up partial download
|
|
373
|
+
if (existsSync(filePath)) {
|
|
374
|
+
unlinkSync(filePath);
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
if (attempt === maxRetries) {
|
|
378
|
+
throw new Error(`Failed to download after ${maxRetries} attempts: ${error.message}`);
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
// Wait before retrying (exponential backoff)
|
|
382
|
+
const delay = Math.pow(2, attempt) * 1000; // 2s, 4s, 8s...
|
|
383
|
+
console.log(`Retrying in ${delay / 1000} seconds...`);
|
|
384
|
+
await new Promise(resolve => setTimeout(resolve, delay));
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
}
|
|
310
388
|
|
|
311
389
|
try {
|
|
312
|
-
//
|
|
313
|
-
const
|
|
314
|
-
if (!response.ok) {
|
|
315
|
-
throw new Error(`Failed to download CEF: ${response.status} ${response.statusText}`);
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
// Create temp file
|
|
319
|
-
const tempFile = join(ELECTROBUN_DEP_PATH, `cef-${platformOS}-${platformArch}-temp.tar.gz`);
|
|
320
|
-
const fileStream = createWriteStream(tempFile);
|
|
390
|
+
// Create temp file with unique name
|
|
391
|
+
const tempFile = join(ELECTROBUN_DEP_PATH, `cef-${platformOS}-${platformArch}-${Date.now()}.tar.gz`);
|
|
321
392
|
|
|
322
|
-
//
|
|
323
|
-
|
|
324
|
-
const reader = response.body.getReader();
|
|
325
|
-
while (true) {
|
|
326
|
-
const { done, value } = await reader.read();
|
|
327
|
-
if (done) break;
|
|
328
|
-
fileStream.write(Buffer.from(value));
|
|
329
|
-
}
|
|
330
|
-
}
|
|
331
|
-
fileStream.end();
|
|
393
|
+
// Download with retry logic
|
|
394
|
+
await downloadWithRetry(cefTarballUrl, tempFile);
|
|
332
395
|
|
|
333
396
|
// Extract to platform-specific dist directory
|
|
334
397
|
console.log(`Extracting CEF dependencies for ${platformOS}-${platformArch}...`);
|
|
335
398
|
const platformDistPath = join(ELECTROBUN_DEP_PATH, `dist-${platformOS}-${platformArch}`);
|
|
336
399
|
mkdirSync(platformDistPath, { recursive: true });
|
|
337
400
|
|
|
338
|
-
//
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
}
|
|
401
|
+
// Helper function to validate tar file before extraction
|
|
402
|
+
async function validateTarFile(filePath: string): Promise<void> {
|
|
403
|
+
try {
|
|
404
|
+
// Quick validation - try to read the tar file header
|
|
405
|
+
const fd = await import('fs').then(fs => fs.promises.readFile(filePath));
|
|
406
|
+
|
|
407
|
+
// Check if it's a gzip file (magic bytes: 1f 8b)
|
|
408
|
+
if (fd.length < 2 || fd[0] !== 0x1f || fd[1] !== 0x8b) {
|
|
409
|
+
throw new Error('Invalid gzip header - file may be corrupted');
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
console.log(`✓ Tar file validation passed (${Math.round(fd.length / 1024 / 1024)}MB)`);
|
|
413
|
+
} catch (error: any) {
|
|
414
|
+
throw new Error(`Tar file validation failed: ${error.message}`);
|
|
415
|
+
}
|
|
353
416
|
}
|
|
354
417
|
|
|
355
|
-
//
|
|
356
|
-
|
|
418
|
+
// Validate downloaded file before extraction
|
|
419
|
+
await validateTarFile(tempFile);
|
|
420
|
+
|
|
421
|
+
try {
|
|
422
|
+
// Use Windows native tar.exe on Windows due to npm tar library issues
|
|
423
|
+
if (OS === 'win') {
|
|
424
|
+
console.log('Using Windows native tar.exe for reliable extraction...');
|
|
425
|
+
const relativeTempFile = relative(platformDistPath, tempFile);
|
|
426
|
+
execSync(`tar -xf "${relativeTempFile}"`, {
|
|
427
|
+
stdio: 'inherit',
|
|
428
|
+
cwd: platformDistPath
|
|
429
|
+
});
|
|
430
|
+
} else {
|
|
431
|
+
await tar.x({
|
|
432
|
+
file: tempFile,
|
|
433
|
+
cwd: platformDistPath,
|
|
434
|
+
preservePaths: false,
|
|
435
|
+
strip: 0,
|
|
436
|
+
});
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
console.log(`✓ Extraction completed successfully`);
|
|
440
|
+
|
|
441
|
+
} catch (error: any) {
|
|
442
|
+
// Check if CEF directory was created despite the error (partial extraction)
|
|
443
|
+
const cefDir = join(platformDistPath, 'cef');
|
|
444
|
+
if (existsSync(cefDir)) {
|
|
445
|
+
const cefFiles = readdirSync(cefDir);
|
|
446
|
+
if (cefFiles.length > 0) {
|
|
447
|
+
console.warn(`⚠️ Extraction warning: ${error.message}`);
|
|
448
|
+
console.warn(` However, CEF files were extracted (${cefFiles.length} files found).`);
|
|
449
|
+
console.warn(` Proceeding with partial extraction - this usually works fine.`);
|
|
450
|
+
// Don't throw - continue with what we have
|
|
451
|
+
} else {
|
|
452
|
+
// No files extracted, this is a real failure
|
|
453
|
+
throw new Error(`Extraction failed (no files extracted): ${error.message}`);
|
|
454
|
+
}
|
|
455
|
+
} else {
|
|
456
|
+
// No CEF directory created, this is a real failure
|
|
457
|
+
throw new Error(`Extraction failed (no CEF directory created): ${error.message}`);
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
// Clean up temp file only after successful extraction
|
|
462
|
+
try {
|
|
463
|
+
unlinkSync(tempFile);
|
|
464
|
+
} catch (cleanupError) {
|
|
465
|
+
console.warn('Could not clean up temp file:', cleanupError);
|
|
466
|
+
}
|
|
357
467
|
|
|
358
468
|
// Debug: List what was actually extracted for CEF
|
|
359
469
|
try {
|
|
@@ -370,11 +480,28 @@ async function ensureCEFDependencies(targetOS?: 'macos' | 'win' | 'linux', targe
|
|
|
370
480
|
console.error('Could not list CEF extracted files:', e);
|
|
371
481
|
}
|
|
372
482
|
|
|
373
|
-
console.log(
|
|
483
|
+
console.log(`✓ CEF dependencies for ${platformOS}-${platformArch} downloaded and cached successfully`);
|
|
374
484
|
|
|
375
485
|
} catch (error: any) {
|
|
376
486
|
console.error(`Failed to download CEF dependencies for ${platformOS}-${platformArch}:`, error.message);
|
|
377
|
-
|
|
487
|
+
|
|
488
|
+
// Provide helpful guidance based on the error
|
|
489
|
+
if (error.message.includes('corrupted download') || error.message.includes('zlib') || error.message.includes('unexpected end')) {
|
|
490
|
+
console.error('\n💡 This appears to be a download corruption issue. Suggestions:');
|
|
491
|
+
console.error(' • Check your internet connection stability');
|
|
492
|
+
console.error(' • Try running the command again (it will retry automatically)');
|
|
493
|
+
console.error(' • Clear the cache if the issue persists:');
|
|
494
|
+
console.error(` rm -rf "${ELECTROBUN_DEP_PATH}"`);
|
|
495
|
+
} else if (error.message.includes('HTTP 404') || error.message.includes('Not Found')) {
|
|
496
|
+
console.error('\n💡 The CEF release was not found. This could mean:');
|
|
497
|
+
console.error(' • The version specified doesn\'t have CEF binaries available');
|
|
498
|
+
console.error(' • You\'re using a development/unreleased version');
|
|
499
|
+
console.error(' • Try using a stable version instead');
|
|
500
|
+
} else {
|
|
501
|
+
console.error('\nPlease ensure you have an internet connection and the release exists.');
|
|
502
|
+
console.error(`If the problem persists, try clearing the cache: rm -rf "${ELECTROBUN_DEP_PATH}"`);
|
|
503
|
+
}
|
|
504
|
+
|
|
378
505
|
process.exit(1);
|
|
379
506
|
}
|
|
380
507
|
}
|