Files
OmniRoute/scripts/build/afterpack-copy-node-modules.mjs
WebPerson 9dc7711dc2 fix(electron): make the packaged Windows build pass the #7592 cold-restart smoke
Five defects found while validating #7592 on a real packaged Windows build:

- optionalPackStaging: GNU tar reads the drive letter in an absolute
  -f C:\... archive path as a remote rsh host (Cannot connect to C:),
  failing optional-pack staging on Git-for-Windows machines. Pass a
  bare filename with cwd at the tarball directory; surface tar stderr.
- electron/package.json: lib/loginHeaderCapture.js was missing from the
  asar files allowlist; loginManager.js requires it top-level, so the
  packaged main process crashed on launch.
- electron-builder >=26 injects !**/node_modules/** into every
  extraResources pattern list and no positive filter can override it,
  silently dropping the staged runtime node_modules (including the
  better-sqlite3 N-API prebuild) from resources/app. Add an afterPack
  hook (scripts/build/afterpack-copy-node-modules.mjs) that restores it.
- smoke harness: Electron resolves userData from
  %USERPROFILE%/AppData/Roaming/<name> (USERPROFILE wins over APPDATA)
  and the path service throws when it is missing, so
  requestSingleInstanceLock() returned false and the app exited(0)
  silently before whenReady. ensureSmokeEnvDirs now pre-creates the
  derived tree and is exported for tests.
- core.ts: the #7592 guard parses a [DB] Driver: ... line that only the
  unused openDatabaseAsync() emitted; getDbInstance() now logs the same
  line on its primary open so the assertion is reachable.

Also makes the smoke env-allowlist unit test host-agnostic (it
hardcoded POSIX paths) and adds regression tests for the USERPROFILE
derived tree and tarPack under Windows-style absolute paths.

Closes #7592
2026-08-24 18:06:06 -05:00

35 lines
1.5 KiB
JavaScript

import { cpSync, existsSync, readdirSync, rmSync } from "node:fs";
import { join } from "node:path";
// electron-builder >=26 injects an "!**/node_modules/**" ignore into every
// extraResources/extraFiles pattern list (app-builder-lib/out/fileMatcher.js),
// and that ignore cannot be overridden by any later positive filter pattern —
// verified empirically with a minimal fixture on 26.15.3. The standalone
// server resolves better-sqlite3 (and other runtime deps) from the *primary*
// node_modules at resources/app/node_modules (see
// prepare-electron-standalone.mjs: "Verify better-sqlite3 Node-API prebuilds in
// the primary node_modules"), so without this hook the packaged desktop app silently loses its native
// SQLite driver and falls back to sql.js — the exact regression guarded by
// issue #7592's cold-restart smoke check.
export default async function afterPack(context) {
const stagingNodeModules = join(
context.packager.projectDir,
"..",
".build",
"electron-standalone",
"node_modules"
);
const destNodeModules = join(context.appOutDir, "resources", "app", "node_modules");
if (!existsSync(stagingNodeModules)) {
console.warn(`[afterpack] no staged node_modules at ${stagingNodeModules} — skipping restore`);
return;
}
rmSync(destNodeModules, { recursive: true, force: true });
cpSync(stagingNodeModules, destNodeModules, { recursive: true });
console.log(
`[afterpack] restored ${readdirSync(destNodeModules).length} runtime module(s) into resources/app/node_modules`
);
}