From bfc06c34da793bce584be55a3a92a772c9c0d901 Mon Sep 17 00:00:00 2001 From: Dylan Audius Date: Thu, 5 Nov 2026 19:50:34 -0800 Subject: [PATCH] fix(desktop): use native fetch in the Electron main process node-fetch is only a devDependency of @audius/web, so electron-builder leaves it out of app.asar and the packaged app crashes on launch with "Cannot find module 'node-fetch'" (#14745). Electron 33 ships Node 20, which has fetch built in, so drop the require. The web-update download now converts the web ReadableStream with Readable.fromWeb, since .body.pipe() only exists on node-fetch responses, and skips the update instead of writing an error page to disk when S3 returns a non-2xx. Fixes #14745 Co-Authored-By: Claude Opus 5.5 --- packages/web/src/electron.js | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/packages/web/src/electron.js b/packages/web/src/electron.js index 02655767bde..c6e77b5e3e9 100644 --- a/packages/web/src/electron.js +++ b/packages/web/src/electron.js @@ -1,5 +1,7 @@ const fs = require('fs') const path = require('path') +const { Readable } = require('stream') +const { pipeline } = require('stream/promises') const url = require('url') const util = require('util') const stat = util.promisify(fs.stat) @@ -16,7 +18,6 @@ const { } = require('electron') const logger = require('electron-log') const { autoUpdater } = require('electron-updater') -const fetch = require('node-fetch') const semver = require('semver') const tar = require('tar') @@ -156,17 +157,20 @@ const getNewestBuildDirectory = () => { const downloadWebUpdateAndNotify = async (newVersion) => { const newBuildPath = appDataPath(`${buildName}.tar.gz`) const webUpdateDir = appDataPath('web-update') - const fileStream = fs.createWriteStream(newBuildPath) - // Fetch the build tar.gz file and write to file + // Fetch the build tar.gz file and write to file. Native fetch returns a web + // ReadableStream, so convert it to a Node stream to pipe it to disk. const data = await fetch( `https://s3.us-west-1.amazonaws.com/${s3Bucket}/${buildName}.tar.gz` ) - await new Promise((resolve, reject) => { - data.body.pipe(fileStream) - data.body.on('error', reject) - fileStream.on('finish', resolve) - }) + if (!data.ok || !data.body) { + logger.error(`Failed to download web update: ${data.status}`) + return + } + await pipeline( + Readable.fromWeb(data.body), + fs.createWriteStream(newBuildPath) + ) // Create web-update directory and untar the build inside if (!fs.existsSync(webUpdateDir)) fs.mkdirSync(webUpdateDir)