electrobun 0.0.19-beta.131 → 0.0.19-beta.132

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