// Watches for electrobun growing a real window-resize gesture, so the // synthesized one can be deleted the moment it becomes dead weight. // // bun scripts/check-electrobun-resize.ts (also runs from `postinstall`) // // WHY THIS EXISTS // // The win7 skin is frameless, which on GTK means undecorated, which means the // window manager supplies no resize borders. electrobun 1.18.1 exposes no // native resize gesture at all, so the app synthesizes one: handles in the // webview drag the frame via RPC. That is a genuine stopgap — jerkier than a // compositor-side grab and always will be — and the thing most likely to // happen to a stopgap is that it outlives its reason and nobody notices. // // So the trigger is automated rather than a comment somebody has to re-read: an // electrobun bump runs `postinstall`, which runs this, which prints the removal // checklist the moment upstream ships the primitive we are waiting for. // // It NEVER fails the install (always exit 0) and is silent when there is // nothing to say — a check that cries wolf gets muted, and a muted check is // worse than none. import { existsSync, readFileSync, readdirSync } from "node:fs"; import path from "node:path"; /** The version the synthesized resize was written against and verified on. If * the installed version differs, this script says so once — that is the cue to * re-check upstream's changelog and then bump this constant. */ const VALIDATED_VERSION = "1.18.1"; /** * Symbols that would mean "upstream can resize now". Verified ABSENT in 1.18.1: * the shipped library exports `startWindowMove`/`stopWindowMove` with no resize * counterpart, and imports `gtk_window_begin_move_drag` but not the resize * twin. Any of these appearing is the signal. * * Searched as raw ASCII in the binary rather than via `nm`/`strings`: only the * host platform's library is installed (`dist-linux-x64/…so`, `.dylib`, `.dll` * elsewhere), and `nm` does not exist on Windows. Symbol names live in the * binary as plain text either way. */ const NATIVE_NEEDLES = [ "gtk_window_begin_resize_drag", // the GTK primitive, if they ever link it "gtk_window_set_resizable", "startWindowResize", // the obvious sibling of startWindowMove "setWindowResizable", "beginWindowResize", ]; /** Source-level signals in the shipped TS API. */ const SOURCE_NEEDLES: { file: string; needle: string; means: string }[] = [ { file: "dist/api/bun/core/BrowserWindow.ts", needle: "setResizable", means: "BrowserWindow gained a resizability setter", }, { file: "dist/api/bun/core/BrowserWindow.ts", needle: "minWidth", means: "the window constructor gained min-size options (our JS clamp may be redundant)", }, { file: "dist/api/bun/preload/dragRegions.ts", needle: "resize", means: "the drag-region preload now knows about resizing", }, ]; const CHECKLIST = ` ┌────────────────────────────────────────────────────────────────────────┐ │ electrobun may now support window resizing natively. │ │ The synthesized resize is a STOPGAP and should be deleted. │ │ Full checklist: │ │ ui/src/app/skins/7like/window-resize/window-resize.ts │ └────────────────────────────────────────────────────────────────────────┘`; function main(): void { const pkgDir = path.join(import.meta.dir, "..", "node_modules", "electrobun"); if (!existsSync(pkgDir)) return; // not installed yet (fresh clone mid-install) const hits: string[] = []; // --- the shipped native library, whichever platform's is installed --- for (const entry of readdirSync(pkgDir)) { if (!entry.startsWith("dist-")) continue; const dir = path.join(pkgDir, entry); for (const file of readdirSync(dir)) { if (!/^libNativeWrapper.*\.(so|dylib|dll)$/.test(file)) continue; // latin1: we are searching for ASCII symbol names inside a binary, and // utf-8 decoding would mangle bytes >0x7f (and can drop invalid // sequences), which could hide a needle sitting next to one. const text = readFileSync(path.join(dir, file), "latin1"); for (const needle of NATIVE_NEEDLES) { if (text.includes(needle)) hits.push(`${entry}/${file} contains ${needle}`); } } } // --- the shipped TypeScript API --- for (const { file, needle, means } of SOURCE_NEEDLES) { const full = path.join(pkgDir, file); if (!existsSync(full)) continue; if (readFileSync(full, "utf8").includes(needle)) hits.push(`${file} mentions ${needle} — ${means}`); } const version = installedVersion(pkgDir); if (hits.length) { console.log(CHECKLIST); console.log(` electrobun ${version ?? "?"} — what changed:`); for (const hit of hits) console.log(` · ${hit}`); console.log(""); return; } // No resize support. Stay quiet unless the version moved out from under the // hack, in which case one line is the reminder to look. if (version && version !== VALIDATED_VERSION) { console.log( `[electrobun] ${VALIDATED_VERSION} → ${version}: no window-resize API found, so the ` + `synthesized resize stays. Re-check, then bump VALIDATED_VERSION in ` + `scripts/check-electrobun-resize.ts to silence this.`, ); } } function installedVersion(pkgDir: string): string | null { try { return JSON.parse(readFileSync(path.join(pkgDir, "package.json"), "utf8")).version ?? null; } catch { return null; } } // A broken check must never break an install: swallow everything, exit 0. try { main(); } catch (error) { // Deliberately quiet — this is advisory. Surface it only when run by hand. if (process.env["DEBUG"]) console.error("[electrobun] resize check failed:", error); }