Minor Changes
-
Feat(updater): on Linux (deb, rpm, pacman), a failed install on quit (e.g. the authentication dialog dismissed) emits and logs
errorand the app exits without the update, unless the newcancelQuitOnInstallFailureoption is set: the install on quit then runs fromwill-quitand cancels the quit when it fails (the app keeps running with its windows closed, so reopen a window or quit from a later tick onerror; register the app's ownwill-quitlisteners 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 legacysha2checksum), and a dismissed or denied pkexec dialog stops the install instead of showing a second dialog for theapt-get -forpacman -Syrecovery#10460e15f702 -
Feat: binary, range-fetchable
.blockmapformat, chosen fromelectronUpdaterCompatibility(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 newblockmapoption,"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 outsideelectronUpdaterCompatibility, e.g. electron-updater 6 with the default>=7: upgrade it, or setelectronUpdaterCompatibility: ">=6"to keep the JSON map.#10312c983462—electron-updater,builder-util-runtimeThe 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
Rangerequest, 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 storedapp.asarregion (nsis.differentialPackage: "store-asar", ideally withasar.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 andlatest.ymlis 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 atinfo. Block maps embedded in an artifact (AppImage, NSIS web installer packages) stay JSON. A binary.blockmapis uploaded to S3 asapplication/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 capsmultipart/byterangesrequests at 200 ranges (Apache'sMaxRangesdefault; largerRangeheaders 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()andinstallPendingUpdateIfAvailable()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#100943c4d9b5 - Fix(updater): the install on quit follows
autoInstallEventas 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 thatverifyUpdateFilehas not accepted yet#10095ea65a06 - 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 -cform. A command killed by a signal during the install on quit is reported as a failure#10095ea65a06 - 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
#10095ea65a06 - Fix: cache the downloaded update's blockmap before emitting
update-downloaded, so an app that callsquitAndInstall()from that listener still makes its next update differential#10463a712cc9 - 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
#10463a712cc9 - Fix(updater): a failed
install()orinstallAsync()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 protectedquitAndInstallCalledis deprecated#10467476c3d5 - 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#10460e15f702 - Fix(updater): route all updater logging through a non-throwing logger (with an always-present
debug), so a throwing logger or one withoutdebug()cannot interrupt the update logic (exposed to subclasses as a protectedloggetter);autoUpdater.loggerstill returns the logger the app set#10470cbd5c80 - Fix: don't log "Differential download failed" on macOS when no differential download was attempted
#1048626195ba