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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "electrobun",
3
- "version": "0.0.19-beta.131",
3
+ "version": "0.0.19-beta.133",
4
4
  "description": "Build ultra fast, tiny, and cross-platform desktop apps with Typescript.",
5
5
  "license": "MIT",
6
6
  "author": "Blackboard Technologies Inc.",
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
- console.log(`Downloading CEF from: ${cefTarballUrl}`);
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
- // Download CEF tarball
313
- const response = await fetch(cefTarballUrl);
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
- // Write response to file
323
- if (response.body) {
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
- // Use Windows native tar.exe on Windows due to npm tar library issues
339
- if (OS === 'win') {
340
- console.log('Using Windows native tar.exe for reliable extraction...');
341
- const relativeTempFile = relative(platformDistPath, tempFile);
342
- execSync(`tar -xf "${relativeTempFile}"`, {
343
- stdio: 'inherit',
344
- cwd: platformDistPath
345
- });
346
- } else {
347
- await tar.x({
348
- file: tempFile,
349
- cwd: platformDistPath,
350
- preservePaths: false,
351
- strip: 0,
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
- // Clean up temp file
356
- unlinkSync(tempFile);
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(`CEF dependencies for ${platformOS}-${platformArch} downloaded and cached successfully`);
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
- console.error('Please ensure you have an internet connection and the release exists.');
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
  }
@@ -7,6 +7,6 @@
7
7
  "start": "electrobun build && electrobun dev"
8
8
  },
9
9
  "dependencies": {
10
- "electrobun": "0.0.19-beta.131"
10
+ "electrobun": "0.0.19-beta.133"
11
11
  }
12
12
  }