github electron-userland/electron-builder electron-updater@7.0.0-alpha.13

pre-release5 hours ago

Minor Changes

  • Feat(updater): on Linux (deb, rpm, pacman), a failed install on quit (e.g. the authentication dialog dismissed) emits and logs error and the app exits without the update, unless the new cancelQuitOnInstallFailure option is set: the install on quit then runs from will-quit and cancels the quit when it fails (the app keeps running with its windows closed, so reopen a window or quit from a later tick on error; register the app's own will-quit listeners before checking for updates, the updater only sees cancellations from listeners registered before its own). A quit while an update install runs waits for it to finish, a failed install is not retried by a later quit of the session (also for update info with only a legacy sha2 checksum), and a dismissed or denied pkexec dialog stops the install instead of showing a second dialog for the apt-get -f or pacman -Sy recovery #10460 e15f702

  • Feat: binary, range-fetchable .blockmap format, chosen from electronUpdaterCompatibility (default raised to >=7). The block map published next to NSIS installers and macOS update zips is read by the electron-updater already installed in the users' apps, so its format follows the declared range: a range of electron-updater 7 and later (the new default) writes the binary map, a range that includes earlier versions writes the gzipped JSON map, with a once-per-build warning. The new blockmap option, "v2" | "v3" | "latest", overrides the choice: "v2" is the JSON map (format version 2), "v3" the binary map (failing the build when the range includes electron-updater before 7), "latest" the newest format the range allows. The build also fails when the app's own electron-updater dependency is outside electronUpdaterCompatibility, e.g. electron-updater 6 with the default >=7: upgrade it, or set electronUpdaterCompatibility: ">=6" to keep the JSON map. #10312 c983462 — electron-updater, builder-util-runtime

    The binary map is uncompressed with fixed-size tables (header, content-defined super-groups of groups, content-defined groups of blocks, 10-byte per-block records, with 8-byte hashes at every level). electron-updater fetches the header and super-group table with one Range request, matches super-groups against its cached previous map, fetches only the group entries of the super-groups that changed, matches those groups and fetches only the records of the groups that changed, verifies every hash, then runs the existing block-level plan and download pipeline. If that range fetch fails, it downloads the new map with a plain GET and stays differential. Because the map cost grows with the change rather than with the installer, the stored app.asar region (nsis.differentialPackage: "store-asar", ideally with asar.contentAlignment) uses 512 B / 1 KiB / 2 KiB blocks and a block boundary at every packed file, and the 7z header of a differential-aware package is stored as is (-mhc=off) and chunked into its own small blocks, so a changed CRC no longer re-downloads the trailing block of the package (5–30 KB on every update). Builds that write the JSON map keep packages and block maps byte-for-byte as before. electron-updater tells the formats apart by the file's first bytes, so there is no extra artifact and latest.yml is unchanged. Installs still on electron-updater 6 download the first release with a binary map in full once; the update brings an updater that reads it. A format change between two releases costs the same one-time full download, logged once at info. Block maps embedded in an artifact (AppImage, NSIS web installer packages) stay JSON. A binary .blockmap is uploaded to S3 as application/octet-stream.

    electron-updater additionally downloads through COPY gaps smaller than 8 KiB between two changed ranges on single-range hosts such as GitHub and S3 (one request per range there makes re-downloading a few KiB cheaper than an extra request), only up to 256 B on hosts that serve multipart/byteranges, and caps multipart/byteranges requests at 200 ranges (Apache's MaxRanges default; larger Range headers exceed common 8 KB header limits).

Patch Changes

  • Fix(updater): install deb/rpm/pacman updates without freezing the app while the elevation dialog is open. quitAndInstall() and installPendingUpdateIfAvailable() now run the package manager asynchronously and quit once it finished; the commands, environment and elevation helper are unchanged, the on-quit install stays synchronous, and other platforms are unaffected. The package manager's output goes to a file instead of a pipe, so quitting the app mid-install no longer kills it with SIGPIPE, and a failed install's error now ends with what it wrote to stderr #10094 3c4d9b5
  • Fix(updater): the install on quit follows autoInstallEvent as it is when the app quits, also when it was "manual" while the update downloaded, and the updater logs why nothing is installed when the app quits before the update finished downloading and verifying, without installing an update cached by an earlier launch that verifyUpdateFile has not accepted yet #10095 ea65a06
  • Fix(updater): deb/rpm/pacman installs pass the package-manager command to pkexec and sudo as an argv array, without a shell, both for quitAndInstall() / installPendingUpdateIfAvailable() and for the install when the app quits (autoInstallEvent: "onQuit"): the authentication dialog shows the command being authorized, the installer path is passed unescaped (paths containing a single quote are supported), the command is looked up in /usr/sbin, /usr/bin, /sbin and /bin rather than the caller's PATH, and Node's DEP0190 warning does not apply. gksudo, kdesudo and beesu take a single command string and keep the /bin/bash -c form. A command killed by a signal during the install on quit is reported as a failure #10095 ea65a06
  • Fix(updater): elevate Linux package installs with pkexec (polkit) whenever it is installed; gksudo and kdesudo, which are unmaintained, removed from Debian and Ubuntu and do not work under Wayland, are only used on systems without polkit, and the updater logs once when it skips one #10095 ea65a06
  • Fix: cache the downloaded update's blockmap before emitting update-downloaded, so an app that calls quitAndInstall() from that listener still makes its next update differential #10463 a712cc9
  • Fix: download the full update, without a failed differential attempt, when the installed version's blockmap URL is the update's own (artifact name without version) or the downloaded old blockmap does not describe the cached installer #10463 a712cc9
  • Fix(updater): a failed install() or installAsync() no longer blocks every later install in the session: the next quit installs the update (on Linux deb/rpm/pacman, only a different update, so the dismissed authentication dialog is not shown again on quit), and the protected quitAndInstallCalled is deprecated #10467 476c3d5
  • Fix(updater): the Linux install only elevates a bare command name found as an executable regular file in the system directories (/usr/sbin, /usr/bin, /sbin, /bin), symlinks included only when their target lies there too #10460 e15f702
  • Fix(updater): route all updater logging through a non-throwing logger (with an always-present debug), so a throwing logger or one without debug() cannot interrupt the update logic (exposed to subclasses as a protected log getter); autoUpdater.logger still returns the logger the app set #10470 cbd5c80
  • Fix: don't log "Differential download failed" on macOS when no differential download was attempted #10486 26195ba

Don't miss a new electron-builder release

NewReleases is sending notifications on new releases.