62 lines
2.4 KiB
TypeScript
62 lines
2.4 KiB
TypeScript
/**
|
|
* Swapped-bundle detection.
|
|
*
|
|
* The detached updater (scripts/desktop-update/posix.sh mac_swap /
|
|
* windows.ps1) rebuilds and swaps the packaged app on disk AFTER
|
|
* `hermes update` exits. An instance that was launched from the PRE-swap
|
|
* bundle — the user reopened Hermes mid-update, the #50238 gesture the boot
|
|
* gate exists for — would otherwise proceed to run the NEW runtime under the
|
|
* OLD renderer. The updater's own `open`/relaunch leg cannot rescue it: the
|
|
* single-instance lock turns that into a focus of the parked process, so no
|
|
* process ever loads the new build.
|
|
*
|
|
* That is the stale-renderer tail of a FULLY SUCCESSFUL update: the "App
|
|
* build out of date" banner appears right after the update, while the Updates
|
|
* card says "You're on the latest version" and so offers nothing that would
|
|
* clear it.
|
|
*
|
|
* Detection: compare the install stamp this process loaded at boot with the
|
|
* one on disk now. A different commit — or a different builtAt at the same
|
|
* commit (a dirty-tree or content-hash rebuild) — means the bundle under our
|
|
* feet is not the one we are running, and a plain relaunch loads it.
|
|
*
|
|
* Fail-quiet like bundle-skew: a missing stamp on either side (dev runs,
|
|
* unreadable resources) or a fallback all-zero commit reports "not swapped".
|
|
* This must never false-positive — a positive triggers an automatic relaunch.
|
|
*
|
|
* Pure so it is testable without booting Electron.
|
|
*/
|
|
|
|
import { isFallbackCommit } from './bundle-skew'
|
|
|
|
export interface BundleSwapStamp {
|
|
/** write-build-stamp.mjs build timestamp — differs on every rebuild. */
|
|
builtAt?: null | string
|
|
commit: string
|
|
/** write-build-stamp.mjs source tag — 'fallback' means the commit is fake. */
|
|
source?: null | string
|
|
}
|
|
|
|
/** True only on positive proof that the bundle on disk is not the running one. */
|
|
export function detectBundleSwap(running: BundleSwapStamp | null, onDisk: BundleSwapStamp | null): boolean {
|
|
if (!running?.commit || !onDisk?.commit) {
|
|
return false
|
|
}
|
|
|
|
if (running.source === 'fallback' || isFallbackCommit(running.commit)) {
|
|
return false
|
|
}
|
|
|
|
if (onDisk.source === 'fallback' || isFallbackCommit(onDisk.commit)) {
|
|
return false
|
|
}
|
|
|
|
if (running.commit !== onDisk.commit) {
|
|
return true
|
|
}
|
|
|
|
// Same commit: only a builtAt PRESENT ON BOTH sides can prove a rebuild —
|
|
// a missing timestamp (older stamp schema) proves nothing.
|
|
return Boolean(running.builtAt && onDisk.builtAt && running.builtAt !== onDisk.builtAt)
|
|
}
|