From 983cc84e2e71a1dd8da768b896ed9bc2a1a2bb48 Mon Sep 17 00:00:00 2001 From: MrBlenny Date: Sat, 13 Jun 2026 22:47:43 +1000 Subject: [PATCH 01/16] fix: treat all certs as valid --- packages/main/src/index.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/packages/main/src/index.ts b/packages/main/src/index.ts index 5a9e1e6..1b4a39b 100644 --- a/packages/main/src/index.ts +++ b/packages/main/src/index.ts @@ -1,4 +1,5 @@ import 'reflect-metadata'; +import { session } from 'electron'; import { container } from 'tsyringe'; import type { AppInitConfig } from './AppInitConfig.js'; import { setupDI } from './di.js'; @@ -43,6 +44,14 @@ export async function initApp(initConfig: AppInitConfig) { callback(true); }); + // Treat self-signed certs as valid (0) so the origin is a secure context — + // required for service workers to register (offline PWA support). + app.whenReady().then(() => { + session.defaultSession.setCertificateVerifyProc((_request, callback) => { + callback(0); + }); + }); + // Services auto-initialize when resolved from container (constructor-based initialization) // Order matters for some dependencies From 6d0986d300e4d95a2882507dcde281ef71bb570e Mon Sep 17 00:00:00 2001 From: MrBlenny Date: Sat, 13 Jun 2026 22:52:59 +1000 Subject: [PATCH 02/16] chore: open apps even if not connected --- packages/renderer/src/components/ApplicationTile.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/renderer/src/components/ApplicationTile.tsx b/packages/renderer/src/components/ApplicationTile.tsx index 755abb7..938f5e3 100644 --- a/packages/renderer/src/components/ApplicationTile.tsx +++ b/packages/renderer/src/components/ApplicationTile.tsx @@ -53,11 +53,11 @@ export const ApplicationTile = ({ const { loading, value } = connectivityState; const connected = value?.connected ?? false; - const isClickable = connected && onClick; + const isClickable = onClick; // Handle click with loading state const handleClick = async () => { - if (!onClick || !connected) return; + if (!onClick) return; setIsClickLoading(true); try { From d6e56039650fd92dcc1f9f5f801cdc377ecd2ffd Mon Sep 17 00:00:00 2001 From: MrBlenny Date: Sun, 14 Jun 2026 11:55:47 +1000 Subject: [PATCH 03/16] chore: update CI --- .github/workflows/compile-and-test.yml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/.github/workflows/compile-and-test.yml b/.github/workflows/compile-and-test.yml index 1a350e2..753df1f 100644 --- a/.github/workflows/compile-and-test.yml +++ b/.github/workflows/compile-and-test.yml @@ -65,6 +65,23 @@ jobs: node-version: '24' api-token-github: ${{ secrets.SOFTWARE_TEAM_READ_PACKAGES_API_TOKEN_GITHUB }} + - name: Cache Electron binary + uses: actions/cache@v4 + with: + path: ${{ runner.temp }}/electron-cache + key: electron-${{ runner.os }}-${{ hashFiles('**/package-lock.json') }} + restore-keys: | + electron-${{ runner.os }}- + + # `npm ci` does not reliably run electron's postinstall, which leaves the + # binary (and node_modules/electron/path.txt) missing and breaks both the + # Vite build and electron-builder. Run the installer explicitly so the + # binary is always present. + - name: Ensure Electron binary is installed + run: node node_modules/electron/install.js + env: + ELECTRON_CACHE: ${{ runner.temp }}/electron-cache + # - name: Cache build artifacts # uses: actions/cache@v4 # with: From 33928dc21c57b9decdd83fb6d42f0cb64b069f38 Mon Sep 17 00:00:00 2001 From: MrBlenny Date: Sun, 14 Jun 2026 12:03:55 +1000 Subject: [PATCH 04/16] chore: try again --- .github/workflows/compile-and-test.yml | 31 ++++++++++++++++---------- 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/.github/workflows/compile-and-test.yml b/.github/workflows/compile-and-test.yml index 753df1f..d430328 100644 --- a/.github/workflows/compile-and-test.yml +++ b/.github/workflows/compile-and-test.yml @@ -57,30 +57,37 @@ jobs: - ubuntu-latest - macos-latest runs-on: ${{ matrix.os }} + env: + # ELECTRON_SKIP_BINARY_DOWNLOAD is set org-wide and makes electron's + # postinstall a no-op, leaving the binary (and node_modules/electron/ + # path.txt) missing — which breaks the Vite build and electron-builder. + # This job needs the real binary, so clear it here. (lint/typecheck don't + # need the binary, so the org-wide skip still applies to them.) + ELECTRON_SKIP_BINARY_DOWNLOAD: '' steps: - uses: actions/checkout@v6 - - uses: ./.github/actions/setup-app - name: Setup application - with: - node-version: '24' - api-token-github: ${{ secrets.SOFTWARE_TEAM_READ_PACKAGES_API_TOKEN_GITHUB }} - name: Cache Electron binary uses: actions/cache@v4 with: - path: ${{ runner.temp }}/electron-cache + path: | + ~/.cache/electron + ~/Library/Caches/electron + ~/AppData/Local/electron/Cache key: electron-${{ runner.os }}-${{ hashFiles('**/package-lock.json') }} restore-keys: | electron-${{ runner.os }}- - # `npm ci` does not reliably run electron's postinstall, which leaves the - # binary (and node_modules/electron/path.txt) missing and breaks both the - # Vite build and electron-builder. Run the installer explicitly so the - # binary is always present. + - uses: ./.github/actions/setup-app + name: Setup application + with: + node-version: '24' + api-token-github: ${{ secrets.SOFTWARE_TEAM_READ_PACKAGES_API_TOKEN_GITHUB }} + + # Guarantee the binary (and path.txt) exist even if npm's postinstall is + # skipped; no-ops quickly when already installed. - name: Ensure Electron binary is installed run: node node_modules/electron/install.js - env: - ELECTRON_CACHE: ${{ runner.temp }}/electron-cache # - name: Cache build artifacts # uses: actions/cache@v4 From c806a1b81b73e8da4e3183f24640b1a1c51dd60e Mon Sep 17 00:00:00 2001 From: MrBlenny Date: Sun, 14 Jun 2026 12:17:13 +1000 Subject: [PATCH 05/16] chore: update --- .github/workflows/compile-and-test.yml | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/.github/workflows/compile-and-test.yml b/.github/workflows/compile-and-test.yml index d430328..d029ff8 100644 --- a/.github/workflows/compile-and-test.yml +++ b/.github/workflows/compile-and-test.yml @@ -57,13 +57,6 @@ jobs: - ubuntu-latest - macos-latest runs-on: ${{ matrix.os }} - env: - # ELECTRON_SKIP_BINARY_DOWNLOAD is set org-wide and makes electron's - # postinstall a no-op, leaving the binary (and node_modules/electron/ - # path.txt) missing — which breaks the Vite build and electron-builder. - # This job needs the real binary, so clear it here. (lint/typecheck don't - # need the binary, so the org-wide skip still applies to them.) - ELECTRON_SKIP_BINARY_DOWNLOAD: '' steps: - uses: actions/checkout@v6 @@ -84,10 +77,12 @@ jobs: node-version: '24' api-token-github: ${{ secrets.SOFTWARE_TEAM_READ_PACKAGES_API_TOKEN_GITHUB }} - # Guarantee the binary (and path.txt) exist even if npm's postinstall is - # skipped; no-ops quickly when already installed. - - name: Ensure Electron binary is installed - run: node node_modules/electron/install.js + # Force electron's binary install (org-wide ELECTRON_SKIP_BINARY_DOWNLOAD + # otherwise skips it, breaking the build). + - name: Install Electron binary + run: | + rm -rf node_modules/electron/dist node_modules/electron/path.txt + env -u ELECTRON_SKIP_BINARY_DOWNLOAD node node_modules/electron/install.js # - name: Cache build artifacts # uses: actions/cache@v4 From 3e79bf65d9c2744a222ebe36be41a89155b3d1ad Mon Sep 17 00:00:00 2001 From: MrBlenny Date: Sun, 14 Jun 2026 12:51:13 +1000 Subject: [PATCH 06/16] ci: instrument electron install to diagnose missing binary One-shot diagnostics in the compile job to capture node/npm versions, ignore-scripts config, ELECTRON_SKIP_BINARY_DOWNLOAD, and install.js behavior on the runner. Co-Authored-By: Claude Opus 4.8 --- .github/workflows/compile-and-test.yml | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/.github/workflows/compile-and-test.yml b/.github/workflows/compile-and-test.yml index d029ff8..a77a9aa 100644 --- a/.github/workflows/compile-and-test.yml +++ b/.github/workflows/compile-and-test.yml @@ -77,12 +77,17 @@ jobs: node-version: '24' api-token-github: ${{ secrets.SOFTWARE_TEAM_READ_PACKAGES_API_TOKEN_GITHUB }} - # Force electron's binary install (org-wide ELECTRON_SKIP_BINARY_DOWNLOAD - # otherwise skips it, breaking the build). - name: Install Electron binary run: | + set +e + echo "node=$(node -v) npm=$(npm -v)" + echo "ignore-scripts=$(npm config get ignore-scripts)" + echo "SKIP=[${ELECTRON_SKIP_BINARY_DOWNLOAD-}]" rm -rf node_modules/electron/dist node_modules/electron/path.txt + echo "--- install.js ---" env -u ELECTRON_SKIP_BINARY_DOWNLOAD node node_modules/electron/install.js + echo "install rc=$?" + cat node_modules/electron/path.txt && echo " <- path.txt ok" || echo "NO path.txt" # - name: Cache build artifacts # uses: actions/cache@v4 From 11fa1faf081151f8aefdf051a1440aa9c4b141cb Mon Sep 17 00:00:00 2001 From: MrBlenny Date: Sun, 14 Jun 2026 12:58:00 +1000 Subject: [PATCH 07/16] ci: deeper electron install diagnostics (DEBUG + before/after) Co-Authored-By: Claude Opus 4.8 --- .github/workflows/compile-and-test.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/compile-and-test.yml b/.github/workflows/compile-and-test.yml index a77a9aa..22ddba9 100644 --- a/.github/workflows/compile-and-test.yml +++ b/.github/workflows/compile-and-test.yml @@ -80,14 +80,14 @@ jobs: - name: Install Electron binary run: | set +e - echo "node=$(node -v) npm=$(npm -v)" - echo "ignore-scripts=$(npm config get ignore-scripts)" - echo "SKIP=[${ELECTRON_SKIP_BINARY_DOWNLOAD-}]" + echo "=== before (as left by npm ci) ===" + ls -la node_modules/electron/ | head -30 + echo "pre path.txt: $(cat node_modules/electron/path.txt 2>/dev/null || echo MISSING)" rm -rf node_modules/electron/dist node_modules/electron/path.txt - echo "--- install.js ---" - env -u ELECTRON_SKIP_BINARY_DOWNLOAD node node_modules/electron/install.js + echo "=== install.js (DEBUG) ===" + DEBUG='@electron/get:*' env -u ELECTRON_SKIP_BINARY_DOWNLOAD node node_modules/electron/install.js 2>&1 echo "install rc=$?" - cat node_modules/electron/path.txt && echo " <- path.txt ok" || echo "NO path.txt" + echo "post path.txt: $(cat node_modules/electron/path.txt 2>/dev/null || echo MISSING)" # - name: Cache build artifacts # uses: actions/cache@v4 From c54adb04145db8c6a662f71f9e418d83847f936b Mon Sep 17 00:00:00 2001 From: MrBlenny Date: Sun, 14 Jun 2026 13:02:52 +1000 Subject: [PATCH 08/16] ci: fix electron install on Node 24 by writing path.txt electron's postinstall extracts dist/ but exits before writing path.txt on Node 24, so index.js/electron-builder treat it as failed. Write path.txt after running the installer. Co-Authored-By: Claude Opus 4.8 --- .github/workflows/compile-and-test.yml | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/.github/workflows/compile-and-test.yml b/.github/workflows/compile-and-test.yml index 22ddba9..49def4d 100644 --- a/.github/workflows/compile-and-test.yml +++ b/.github/workflows/compile-and-test.yml @@ -77,17 +77,12 @@ jobs: node-version: '24' api-token-github: ${{ secrets.SOFTWARE_TEAM_READ_PACKAGES_API_TOKEN_GITHUB }} + # On Node 24 electron's postinstall extracts dist/ but exits before writing + # path.txt, so index.js reports it as failed. Extract, then write path.txt. - name: Install Electron binary run: | - set +e - echo "=== before (as left by npm ci) ===" - ls -la node_modules/electron/ | head -30 - echo "pre path.txt: $(cat node_modules/electron/path.txt 2>/dev/null || echo MISSING)" - rm -rf node_modules/electron/dist node_modules/electron/path.txt - echo "=== install.js (DEBUG) ===" - DEBUG='@electron/get:*' env -u ELECTRON_SKIP_BINARY_DOWNLOAD node node_modules/electron/install.js 2>&1 - echo "install rc=$?" - echo "post path.txt: $(cat node_modules/electron/path.txt 2>/dev/null || echo MISSING)" + node node_modules/electron/install.js + node -e "const fs=require('fs'),f='node_modules/electron/path.txt';if(!fs.existsSync(f)){fs.writeFileSync(f,{linux:'electron',win32:'electron.exe',darwin:'Electron.app/Contents/MacOS/Electron'}[process.platform]);console.log('wrote '+f)}" # - name: Cache build artifacts # uses: actions/cache@v4 From 11b066224a1fbcc07e7a76f90c0d9db8aafd411f Mon Sep 17 00:00:00 2001 From: MrBlenny Date: Sun, 14 Jun 2026 13:06:31 +1000 Subject: [PATCH 09/16] ci: install electron via awaited download+extract for Node 24 electron's postinstall exits mid-extract on Node 24, leaving the binary and path.txt missing. Replace it with a fully-awaited download+extract so the binary is reliably present for the build and electron-builder. Co-Authored-By: Claude Opus 4.8 --- .github/workflows/compile-and-test.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/compile-and-test.yml b/.github/workflows/compile-and-test.yml index 49def4d..5ace179 100644 --- a/.github/workflows/compile-and-test.yml +++ b/.github/workflows/compile-and-test.yml @@ -77,12 +77,12 @@ jobs: node-version: '24' api-token-github: ${{ secrets.SOFTWARE_TEAM_READ_PACKAGES_API_TOKEN_GITHUB }} - # On Node 24 electron's postinstall extracts dist/ but exits before writing - # path.txt, so index.js reports it as failed. Extract, then write path.txt. + # On Node 24 electron's postinstall exits mid-extract, leaving the binary + # and path.txt missing. Install it via a fully-awaited download+extract. - name: Install Electron binary + working-directory: node_modules/electron run: | - node node_modules/electron/install.js - node -e "const fs=require('fs'),f='node_modules/electron/path.txt';if(!fs.existsSync(f)){fs.writeFileSync(f,{linux:'electron',win32:'electron.exe',darwin:'Electron.app/Contents/MacOS/Electron'}[process.platform]);console.log('wrote '+f)}" + node -e "const {downloadArtifact}=require('@electron/get');const extract=require('extract-zip');const fs=require('fs'),path=require('path');const {version}=require('./package.json');(async()=>{const zip=await downloadArtifact({version,artifactName:'electron',platform:process.platform,arch:process.arch});await extract(zip,{dir:path.resolve('dist')});const bin={linux:'electron',win32:'electron.exe',darwin:'Electron.app/Contents/MacOS/Electron'}[process.platform];fs.writeFileSync('path.txt',bin);console.log('electron ready: '+bin)})().catch(e=>{console.error(e);process.exit(1)})" # - name: Cache build artifacts # uses: actions/cache@v4 From 2d28d37758089fafd55fb78a652aad3b107ac3fd Mon Sep 17 00:00:00 2001 From: MrBlenny Date: Sun, 14 Jun 2026 13:11:12 +1000 Subject: [PATCH 10/16] ci: install electron via top-level-await helper for Node 24 A floating promise does not keep Node 24's event loop alive, so electron's postinstall (and inline variants) exit before the binary extracts. Use a helper script with top-level await so the process waits for completion. Co-Authored-By: Claude Opus 4.8 --- .github/workflows/compile-and-test.yml | 7 ++---- scripts/ci-install-electron.mjs | 35 ++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 5 deletions(-) create mode 100644 scripts/ci-install-electron.mjs diff --git a/.github/workflows/compile-and-test.yml b/.github/workflows/compile-and-test.yml index 5ace179..2ab2a10 100644 --- a/.github/workflows/compile-and-test.yml +++ b/.github/workflows/compile-and-test.yml @@ -77,12 +77,9 @@ jobs: node-version: '24' api-token-github: ${{ secrets.SOFTWARE_TEAM_READ_PACKAGES_API_TOKEN_GITHUB }} - # On Node 24 electron's postinstall exits mid-extract, leaving the binary - # and path.txt missing. Install it via a fully-awaited download+extract. + # electron's own postinstall is unreliable on Node 24 (see script). - name: Install Electron binary - working-directory: node_modules/electron - run: | - node -e "const {downloadArtifact}=require('@electron/get');const extract=require('extract-zip');const fs=require('fs'),path=require('path');const {version}=require('./package.json');(async()=>{const zip=await downloadArtifact({version,artifactName:'electron',platform:process.platform,arch:process.arch});await extract(zip,{dir:path.resolve('dist')});const bin={linux:'electron',win32:'electron.exe',darwin:'Electron.app/Contents/MacOS/Electron'}[process.platform];fs.writeFileSync('path.txt',bin);console.log('electron ready: '+bin)})().catch(e=>{console.error(e);process.exit(1)})" + run: node scripts/ci-install-electron.mjs # - name: Cache build artifacts # uses: actions/cache@v4 diff --git a/scripts/ci-install-electron.mjs b/scripts/ci-install-electron.mjs new file mode 100644 index 0000000..321a6a7 --- /dev/null +++ b/scripts/ci-install-electron.mjs @@ -0,0 +1,35 @@ +// Installs electron's prebuilt binary in CI. +// +// On Node 24, electron's own postinstall (node install.js) exits before its +// download/extract promise settles — it floats the promise, and a pending +// promise alone does not keep the event loop alive — leaving dist/ and +// path.txt missing so the build fails with "Electron failed to install +// correctly". This script does the same work but with top-level await, so the +// process stays alive until the binary is fully extracted. +import { createRequire } from 'node:module'; +import { writeFileSync } from 'node:fs'; +import path from 'node:path'; + +const require = createRequire(import.meta.url); +const { downloadArtifact } = require('@electron/get'); +const extract = require('extract-zip'); + +const electronDir = path.resolve('node_modules/electron'); +const { version } = require('electron/package.json'); + +const binary = { + linux: 'electron', + win32: 'electron.exe', + darwin: 'Electron.app/Contents/MacOS/Electron', +}[process.platform]; + +const zip = await downloadArtifact({ + version, + artifactName: 'electron', + platform: process.platform, + arch: process.arch, +}); +await extract(zip, { dir: path.join(electronDir, 'dist') }); +writeFileSync(path.join(electronDir, 'path.txt'), binary); + +console.log(`electron ${version} ready: ${binary}`); From b30f00967c53d447ee9a047bf4b69fdd8b1714ff Mon Sep 17 00:00:00 2001 From: MrBlenny Date: Sun, 14 Jun 2026 13:15:46 +1000 Subject: [PATCH 11/16] ci: download electron via native fetch (Node 24 @electron/get unsettles) @electron/get's downloadArtifact promise never settles on Node 24 (exit 13, unsettled top-level await), so the binary never installs. Download the release zip with Node's native fetch + extract-zip instead. Co-Authored-By: Claude Opus 4.8 --- scripts/ci-install-electron.mjs | 38 ++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/scripts/ci-install-electron.mjs b/scripts/ci-install-electron.mjs index 321a6a7..4bfff89 100644 --- a/scripts/ci-install-electron.mjs +++ b/scripts/ci-install-electron.mjs @@ -1,35 +1,39 @@ // Installs electron's prebuilt binary in CI. // -// On Node 24, electron's own postinstall (node install.js) exits before its -// download/extract promise settles — it floats the promise, and a pending -// promise alone does not keep the event loop alive — leaving dist/ and -// path.txt missing so the build fails with "Electron failed to install -// correctly". This script does the same work but with top-level await, so the -// process stays alive until the binary is fully extracted. +// electron's own postinstall (and @electron/get) is unreliable on Node 24: its +// download promise never settles, so the process exits before the binary is +// extracted, leaving dist/ and path.txt missing ("Electron failed to install +// correctly"). This downloads the release zip with Node's native fetch and +// extracts it, all top-level-awaited so the process waits for completion. import { createRequire } from 'node:module'; -import { writeFileSync } from 'node:fs'; +import { writeFileSync, createWriteStream, mkdirSync } from 'node:fs'; +import { Readable } from 'node:stream'; +import { pipeline } from 'node:stream/promises'; import path from 'node:path'; +import os from 'node:os'; const require = createRequire(import.meta.url); -const { downloadArtifact } = require('@electron/get'); const extract = require('extract-zip'); const electronDir = path.resolve('node_modules/electron'); const { version } = require('electron/package.json'); +const { platform, arch } = process; + +const url = `https://github.com/electron/electron/releases/download/v${version}/electron-v${version}-${platform}-${arch}.zip`; +const zipPath = path.join(os.tmpdir(), `electron-v${version}-${platform}-${arch}.zip`); + +const res = await fetch(url, { redirect: 'follow' }); +if (!res.ok) throw new Error(`Failed to download ${url}: ${res.status}`); +await pipeline(Readable.fromWeb(res.body), createWriteStream(zipPath)); + +mkdirSync(path.join(electronDir, 'dist'), { recursive: true }); +await extract(zipPath, { dir: path.join(electronDir, 'dist') }); const binary = { linux: 'electron', win32: 'electron.exe', darwin: 'Electron.app/Contents/MacOS/Electron', -}[process.platform]; - -const zip = await downloadArtifact({ - version, - artifactName: 'electron', - platform: process.platform, - arch: process.arch, -}); -await extract(zip, { dir: path.join(electronDir, 'dist') }); +}[platform]; writeFileSync(path.join(electronDir, 'path.txt'), binary); console.log(`electron ${version} ready: ${binary}`); From b59c0109e336529bfa88769b2d99124d322361ea Mon Sep 17 00:00:00 2001 From: MrBlenny Date: Sun, 14 Jun 2026 13:22:39 +1000 Subject: [PATCH 12/16] ci: hold event loop open during electron install for Node 24 Node 24 exits as soon as the loop is momentarily empty, before electron's download/extract promises settle. Keep a timer open until they do. Co-Authored-By: Claude Opus 4.8 --- scripts/ci-install-electron.mjs | 35 +++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/scripts/ci-install-electron.mjs b/scripts/ci-install-electron.mjs index 4bfff89..e070e7e 100644 --- a/scripts/ci-install-electron.mjs +++ b/scripts/ci-install-electron.mjs @@ -1,10 +1,11 @@ // Installs electron's prebuilt binary in CI. // -// electron's own postinstall (and @electron/get) is unreliable on Node 24: its -// download promise never settles, so the process exits before the binary is -// extracted, leaving dist/ and path.txt missing ("Electron failed to install -// correctly"). This downloads the release zip with Node's native fetch and -// extracts it, all top-level-awaited so the process waits for completion. +// electron's own postinstall is unreliable on Node 24: it floats its +// download/extract promise, and Node 24 exits the moment the event loop is +// momentarily empty — before the promise settles — so dist/ and path.txt end +// up missing ("Electron failed to install correctly"). We do the same work +// (download the release zip, extract it, write path.txt) but hold a timer open +// so the process can't exit until everything has settled. import { createRequire } from 'node:module'; import { writeFileSync, createWriteStream, mkdirSync } from 'node:fs'; import { Readable } from 'node:stream'; @@ -21,19 +22,23 @@ const { platform, arch } = process; const url = `https://github.com/electron/electron/releases/download/v${version}/electron-v${version}-${platform}-${arch}.zip`; const zipPath = path.join(os.tmpdir(), `electron-v${version}-${platform}-${arch}.zip`); - -const res = await fetch(url, { redirect: 'follow' }); -if (!res.ok) throw new Error(`Failed to download ${url}: ${res.status}`); -await pipeline(Readable.fromWeb(res.body), createWriteStream(zipPath)); - -mkdirSync(path.join(electronDir, 'dist'), { recursive: true }); -await extract(zipPath, { dir: path.join(electronDir, 'dist') }); - const binary = { linux: 'electron', win32: 'electron.exe', darwin: 'Electron.app/Contents/MacOS/Electron', }[platform]; -writeFileSync(path.join(electronDir, 'path.txt'), binary); -console.log(`electron ${version} ready: ${binary}`); +const keepAlive = setInterval(() => {}, 1000); +try { + const res = await fetch(url, { redirect: 'follow' }); + if (!res.ok) throw new Error(`Failed to download ${url}: ${res.status}`); + await pipeline(Readable.fromWeb(res.body), createWriteStream(zipPath)); + + mkdirSync(path.join(electronDir, 'dist'), { recursive: true }); + await extract(zipPath, { dir: path.join(electronDir, 'dist') }); + writeFileSync(path.join(electronDir, 'path.txt'), binary); + + console.log(`electron ${version} ready: ${binary}`); +} finally { + clearInterval(keepAlive); +} From ca4a97a434d0bb692108ce4d3cec35fbeea045ce Mon Sep 17 00:00:00 2001 From: MrBlenny Date: Sun, 14 Jun 2026 14:34:43 +1000 Subject: [PATCH 13/16] ci: install electron synchronously (curl+unzip) for Node 24 extract-zip hangs on Node 24 (never settles), like @electron/get. Do the download+extract with synchronous shell tools so there is no async to stall. Co-Authored-By: Claude Opus 4.8 --- scripts/ci-install-electron.mjs | 49 ++++++++++++++------------------- 1 file changed, 20 insertions(+), 29 deletions(-) diff --git a/scripts/ci-install-electron.mjs b/scripts/ci-install-electron.mjs index e070e7e..8f45ce1 100644 --- a/scripts/ci-install-electron.mjs +++ b/scripts/ci-install-electron.mjs @@ -1,44 +1,35 @@ // Installs electron's prebuilt binary in CI. // -// electron's own postinstall is unreliable on Node 24: it floats its -// download/extract promise, and Node 24 exits the moment the event loop is -// momentarily empty — before the promise settles — so dist/ and path.txt end -// up missing ("Electron failed to install correctly"). We do the same work -// (download the release zip, extract it, write path.txt) but hold a timer open -// so the process can't exit until everything has settled. +// electron's postinstall (and its @electron/get / extract-zip deps) hangs or +// exits early on Node 24 — its promises never settle, leaving dist/ and +// path.txt missing ("Electron failed to install correctly"). This does the same +// work synchronously (curl + unzip/tar), so there is no async to stall. +import { execFileSync } from 'node:child_process'; +import { writeFileSync, mkdirSync } from 'node:fs'; import { createRequire } from 'node:module'; -import { writeFileSync, createWriteStream, mkdirSync } from 'node:fs'; -import { Readable } from 'node:stream'; -import { pipeline } from 'node:stream/promises'; import path from 'node:path'; import os from 'node:os'; const require = createRequire(import.meta.url); -const extract = require('extract-zip'); - const electronDir = path.resolve('node_modules/electron'); const { version } = require('electron/package.json'); const { platform, arch } = process; const url = `https://github.com/electron/electron/releases/download/v${version}/electron-v${version}-${platform}-${arch}.zip`; const zipPath = path.join(os.tmpdir(), `electron-v${version}-${platform}-${arch}.zip`); -const binary = { - linux: 'electron', - win32: 'electron.exe', - darwin: 'Electron.app/Contents/MacOS/Electron', -}[platform]; - -const keepAlive = setInterval(() => {}, 1000); -try { - const res = await fetch(url, { redirect: 'follow' }); - if (!res.ok) throw new Error(`Failed to download ${url}: ${res.status}`); - await pipeline(Readable.fromWeb(res.body), createWriteStream(zipPath)); +const dist = path.join(electronDir, 'dist'); - mkdirSync(path.join(electronDir, 'dist'), { recursive: true }); - await extract(zipPath, { dir: path.join(electronDir, 'dist') }); - writeFileSync(path.join(electronDir, 'path.txt'), binary); - - console.log(`electron ${version} ready: ${binary}`); -} finally { - clearInterval(keepAlive); +execFileSync('curl', ['-fL', '--retry', '3', '-o', zipPath, url], { stdio: 'inherit' }); +mkdirSync(dist, { recursive: true }); +// bsdtar (the `tar` on Windows runners) reads zips; unzip elsewhere. +if (platform === 'win32') { + execFileSync('tar', ['-xf', zipPath, '-C', dist], { stdio: 'inherit' }); +} else { + execFileSync('unzip', ['-q', '-o', zipPath, '-d', dist], { stdio: 'inherit' }); } +writeFileSync( + path.join(electronDir, 'path.txt'), + { linux: 'electron', win32: 'electron.exe', darwin: 'Electron.app/Contents/MacOS/Electron' }[platform], +); + +console.log(`electron ${version} ready`); From 83070385cafb1228f14edefa571e88737bfd2ab4 Mon Sep 17 00:00:00 2001 From: MrBlenny Date: Sun, 14 Jun 2026 14:39:59 +1000 Subject: [PATCH 14/16] ci: extract electron via Expand-Archive on Windows + format git-bash tar is GNU tar (mangles C: paths, can't read zips). Use PowerShell Expand-Archive on Windows; unzip on posix. Co-Authored-By: Claude Opus 4.8 --- scripts/ci-install-electron.mjs | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/scripts/ci-install-electron.mjs b/scripts/ci-install-electron.mjs index 8f45ce1..17ea98f 100644 --- a/scripts/ci-install-electron.mjs +++ b/scripts/ci-install-electron.mjs @@ -21,15 +21,24 @@ const dist = path.join(electronDir, 'dist'); execFileSync('curl', ['-fL', '--retry', '3', '-o', zipPath, url], { stdio: 'inherit' }); mkdirSync(dist, { recursive: true }); -// bsdtar (the `tar` on Windows runners) reads zips; unzip elsewhere. if (platform === 'win32') { - execFileSync('tar', ['-xf', zipPath, '-C', dist], { stdio: 'inherit' }); + execFileSync( + 'powershell', + [ + '-NoProfile', + '-Command', + `Expand-Archive -LiteralPath '${zipPath}' -DestinationPath '${dist}' -Force`, + ], + { stdio: 'inherit' } + ); } else { execFileSync('unzip', ['-q', '-o', zipPath, '-d', dist], { stdio: 'inherit' }); } writeFileSync( path.join(electronDir, 'path.txt'), - { linux: 'electron', win32: 'electron.exe', darwin: 'Electron.app/Contents/MacOS/Electron' }[platform], + { linux: 'electron', win32: 'electron.exe', darwin: 'Electron.app/Contents/MacOS/Electron' }[ + platform + ] ); console.log(`electron ${version} ready`); From f5768960575936cb46d58189bd1c9cdd42839fce Mon Sep 17 00:00:00 2001 From: MrBlenny Date: Sun, 14 Jun 2026 14:46:21 +1000 Subject: [PATCH 15/16] ci: drop dead electron cache step The install helper downloads to a temp dir, so caching ~/.cache/electron no longer feeds it. Co-Authored-By: Claude Opus 4.8 --- .github/workflows/compile-and-test.yml | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/.github/workflows/compile-and-test.yml b/.github/workflows/compile-and-test.yml index 2ab2a10..2f530a3 100644 --- a/.github/workflows/compile-and-test.yml +++ b/.github/workflows/compile-and-test.yml @@ -60,17 +60,6 @@ jobs: steps: - uses: actions/checkout@v6 - - name: Cache Electron binary - uses: actions/cache@v4 - with: - path: | - ~/.cache/electron - ~/Library/Caches/electron - ~/AppData/Local/electron/Cache - key: electron-${{ runner.os }}-${{ hashFiles('**/package-lock.json') }} - restore-keys: | - electron-${{ runner.os }}- - - uses: ./.github/actions/setup-app name: Setup application with: From 54f8ca1cee4b218ff68d39bf3295cd8943b080d4 Mon Sep 17 00:00:00 2001 From: MrBlenny Date: Sun, 14 Jun 2026 16:55:07 +1000 Subject: [PATCH 16/16] build: upgrade electron to 42, drop CI install workaround electron 42 uses @electron/get@5 (native fetch) which installs cleanly on Node 24, so electron's own postinstall works and the custom CI install script is no longer needed. Co-Authored-By: Claude Opus 4.8 --- .github/workflows/compile-and-test.yml | 4 - package-lock.json | 378 ++++--------------------- package.json | 2 +- scripts/ci-install-electron.mjs | 44 --- 4 files changed, 54 insertions(+), 374 deletions(-) delete mode 100644 scripts/ci-install-electron.mjs diff --git a/.github/workflows/compile-and-test.yml b/.github/workflows/compile-and-test.yml index 2f530a3..2c8a1a6 100644 --- a/.github/workflows/compile-and-test.yml +++ b/.github/workflows/compile-and-test.yml @@ -66,10 +66,6 @@ jobs: node-version: '24' api-token-github: ${{ secrets.SOFTWARE_TEAM_READ_PACKAGES_API_TOKEN_GITHUB }} - # electron's own postinstall is unreliable on Node 24 (see script). - - name: Install Electron binary - run: node scripts/ci-install-electron.mjs - # - name: Cache build artifacts # uses: actions/cache@v4 # with: diff --git a/package-lock.json b/package-lock.json index ba27eee..e97b3f5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,7 +19,7 @@ "@playwright/test": "1.57.0", "@types/node": "25.0.3", "create-vite": "8.2.0", - "electron": "39.2.7", + "electron": "42.4.0", "electron-builder": "26.0.13", "eslint": "^9.39.2", "eslint-config-prettier": "^10.1.8", @@ -374,6 +374,15 @@ "url": "https://opencollective.com/webpack" } }, + "node_modules/@electron-internal/extract-zip": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@electron-internal/extract-zip/-/extract-zip-1.0.3.tgz", + "integrity": "sha512-OjKpjB7gohtEjZiq6nDx1egqjZJhGPN1iFOIED+NFhB/MMkXw/XRcHjh1DGXKT5z2W9eW7Jy2UKU3gpjvusFTQ==", + "dev": true, + "engines": { + "node": ">=22.12.0" + } + }, "node_modules/@electron/asar": { "version": "3.2.18", "resolved": "https://registry.npmjs.org/@electron/asar/-/asar-3.2.18.tgz", @@ -475,33 +484,35 @@ } }, "node_modules/@electron/get": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@electron/get/-/get-2.0.3.tgz", - "integrity": "sha512-Qkzpg2s9GnVV2I2BjRksUi43U5e6+zaQMcjoJy0C+C5oxaKl+fmckGDQFtRpZpZV0NQekuZZ+tGz7EA9TVnQtQ==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@electron/get/-/get-5.0.0.tgz", + "integrity": "sha512-pjoBpru1KdEtcExBnuHAP1cAc/5faoedw0hzJkL3o4/IJp7HNF1+fbrdxT3gMYRX2oJfvnA/WXeCTVQpYYxyJA==", "dev": true, "dependencies": { "debug": "^4.1.1", - "env-paths": "^2.2.0", - "fs-extra": "^8.1.0", - "got": "^11.8.5", + "env-paths": "^3.0.0", + "graceful-fs": "^4.2.11", "progress": "^2.0.3", - "semver": "^6.2.0", + "semver": "^7.6.3", "sumchecker": "^3.0.1" }, "engines": { - "node": ">=12" + "node": ">=22.12.0" }, "optionalDependencies": { - "global-agent": "^3.0.0" + "undici": "^7.24.4" } }, - "node_modules/@electron/get/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "node_modules/@electron/get/node_modules/env-paths": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-3.0.0.tgz", + "integrity": "sha512-dtJUTepzMW3Lm/NPxRf3wP4642UWhjL2sQxc+ym2YMj1m/H2zDNQOlezafzkHwn6sMstjHTwG6iQQsctDW/b1A==", "dev": true, - "bin": { - "semver": "bin/semver.js" + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/@electron/node-gyp": { @@ -2766,16 +2777,6 @@ "dev": true, "optional": true }, - "node_modules/@types/yauzl": { - "version": "2.10.3", - "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz", - "integrity": "sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==", - "dev": true, - "optional": true, - "dependencies": { - "@types/node": "*" - } - }, "node_modules/@typescript-eslint/eslint-plugin": { "version": "8.52.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.52.0.tgz", @@ -3462,14 +3463,6 @@ "multicast-dns": "^7.2.5" } }, - "node_modules/boolean": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/boolean/-/boolean-3.2.0.tgz", - "integrity": "sha512-d0II/GO9uf9lfUHH2BQsjxzRJZBdsjgsBiW4BvhWk/3qoKwQFjIDVN19PfX8F2D/r9PCMTtLWjYVCFrpeYUzsw==", - "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", - "dev": true, - "optional": true - }, "node_modules/bowser": { "version": "2.13.1", "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.13.1.tgz", @@ -3542,15 +3535,6 @@ "ieee754": "^1.1.13" } }, - "node_modules/buffer-crc32": { - "version": "0.2.13", - "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", - "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", - "dev": true, - "engines": { - "node": "*" - } - }, "node_modules/buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", @@ -4383,42 +4367,6 @@ "node": ">=10" } }, - "node_modules/define-data-property": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", - "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", - "dev": true, - "optional": true, - "dependencies": { - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "gopd": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/define-properties": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", - "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", - "dev": true, - "optional": true, - "dependencies": { - "define-data-property": "^1.0.1", - "has-property-descriptors": "^1.0.0", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -4436,13 +4384,6 @@ "node": ">=8" } }, - "node_modules/detect-node": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", - "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", - "dev": true, - "optional": true - }, "node_modules/dir-compare": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/dir-compare/-/dir-compare-4.2.0.tgz", @@ -4667,21 +4608,21 @@ } }, "node_modules/electron": { - "version": "39.2.7", - "resolved": "https://registry.npmjs.org/electron/-/electron-39.2.7.tgz", - "integrity": "sha512-KU0uFS6LSTh4aOIC3miolcbizOFP7N1M46VTYVfqIgFiuA2ilfNaOHLDS9tCMvwwHRowAsvqBrh9NgMXcTOHCQ==", + "version": "42.4.0", + "resolved": "https://registry.npmjs.org/electron/-/electron-42.4.0.tgz", + "integrity": "sha512-OXXqh9LD9KxXPv2Fe25EfU9N9AvWTuV6V81sfhQaNvTAXCd9ONA+Q4OWvMe+CmYD6xIwjFxGGtG/ZphDYYC5OQ==", "dev": true, - "hasInstallScript": true, "dependencies": { - "@electron/get": "^2.0.0", - "@types/node": "^22.7.7", - "extract-zip": "^2.0.1" + "@electron-internal/extract-zip": "^1.0.1", + "@electron/get": "^5.0.0", + "@types/node": "^24.9.0" }, "bin": { - "electron": "cli.js" + "electron": "cli.js", + "install-electron": "install.js" }, "engines": { - "node": ">= 12.20.55" + "node": ">= 22.12.0" } }, "node_modules/electron-builder": { @@ -4914,18 +4855,18 @@ } }, "node_modules/electron/node_modules/@types/node": { - "version": "22.19.3", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.3.tgz", - "integrity": "sha512-1N9SBnWYOJTrNZCdh/yJE+t910Y128BoyY+zBLWhL3r0TYzlTmFdXrPwHL9DyFZmlEXNQQolTZh3KHV31QDhyA==", + "version": "24.13.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.13.2.tgz", + "integrity": "sha512-fRa09kZTgu8o71KFcDjUFuc7F+dEbZYZmkI0mg5YBTRs0yMKjYHsq/c0urDKeDb+D5qVgXOdFcuu+DZPKOITwA==", "dev": true, "dependencies": { - "undici-types": "~6.21.0" + "undici-types": "~7.18.0" } }, "node_modules/electron/node_modules/undici-types": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", - "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz", + "integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==", "dev": true }, "node_modules/emoji-regex": { @@ -5017,13 +4958,6 @@ "node": ">= 0.4" } }, - "node_modules/es6-error": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", - "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", - "dev": true, - "optional": true - }, "node_modules/esbuild": { "version": "0.27.2", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.2.tgz", @@ -5293,26 +5227,6 @@ "integrity": "sha512-ZgEeZXj30q+I0EN+CbSSpIyPaJ5HVQD18Z1m+u1FXbAeT94mr1zw50q4q6jiiC447Nl/YTcIYSAftiGqetwXCA==", "dev": true }, - "node_modules/extract-zip": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", - "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", - "dev": true, - "dependencies": { - "debug": "^4.1.1", - "get-stream": "^5.1.0", - "yauzl": "^2.10.0" - }, - "bin": { - "extract-zip": "cli.js" - }, - "engines": { - "node": ">= 10.17.0" - }, - "optionalDependencies": { - "@types/yauzl": "^2.9.1" - } - }, "node_modules/extsprintf": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.4.1.tgz", @@ -5365,15 +5279,6 @@ "resolved": "https://registry.npmjs.org/fastest-stable-stringify/-/fastest-stable-stringify-2.0.2.tgz", "integrity": "sha512-bijHueCGd0LqqNK9b5oCMHc0MluJAx0cwqASgbWMvkO01lCYgIhacVRLcaDz3QnyYIRNJRDwMb41VuT6pHJ91Q==" }, - "node_modules/fd-slicer": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", - "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", - "dev": true, - "dependencies": { - "pend": "~1.2.0" - } - }, "node_modules/fdir": { "version": "6.5.0", "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", @@ -5530,20 +5435,6 @@ "node": ">= 6" } }, - "node_modules/fs-extra": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", - "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - }, - "engines": { - "node": ">=6 <7 || >=8" - } - }, "node_modules/fs-minipass": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", @@ -5699,24 +5590,6 @@ "node": ">=10.13.0" } }, - "node_modules/global-agent": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/global-agent/-/global-agent-3.0.0.tgz", - "integrity": "sha512-PT6XReJ+D07JvGoxQMkT6qji/jVNfX/h364XHZOWeRzy64sSFr+xJ5OX7LI3b4MPQzdL4H8Y8M0xzPpsVMwA8Q==", - "dev": true, - "optional": true, - "dependencies": { - "boolean": "^3.0.1", - "es6-error": "^4.1.1", - "matcher": "^3.0.0", - "roarr": "^2.15.3", - "semver": "^7.3.2", - "serialize-error": "^7.0.1" - }, - "engines": { - "node": ">=10.0" - } - }, "node_modules/globals": { "version": "17.0.0", "resolved": "https://registry.npmjs.org/globals/-/globals-17.0.0.tgz", @@ -5729,23 +5602,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/globalthis": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", - "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", - "dev": true, - "optional": true, - "dependencies": { - "define-properties": "^1.2.1", - "gopd": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/gopd": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", @@ -5836,19 +5692,6 @@ "node": ">=8" } }, - "node_modules/has-property-descriptors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", - "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", - "dev": true, - "optional": true, - "dependencies": { - "es-define-property": "^1.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/has-symbols": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", @@ -6361,13 +6204,6 @@ "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", "dev": true }, - "node_modules/json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", - "dev": true, - "optional": true - }, "node_modules/json5": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", @@ -6380,15 +6216,6 @@ "node": ">=6" } }, - "node_modules/jsonfile": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", - "dev": true, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, "node_modules/jsonpointer": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-5.0.1.tgz", @@ -6673,19 +6500,6 @@ } } }, - "node_modules/matcher": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/matcher/-/matcher-3.0.0.tgz", - "integrity": "sha512-OkeDaAZ/bQCxeFAozM55PKcKU0yJMPGifLwV4Qgjitu+5MoAfSQN4lsLJeXZ1b8w0x+/Emda6MZgXS1jvsapng==", - "dev": true, - "optional": true, - "dependencies": { - "escape-string-regexp": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/math-intrinsics": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", @@ -7155,16 +6969,6 @@ "node": ">=0.10.0" } }, - "node_modules/object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true, - "optional": true, - "engines": { - "node": ">= 0.4" - } - }, "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -7370,12 +7174,6 @@ "url": "https://github.com/sponsors/jet2jet" } }, - "node_modules/pend": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", - "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", - "dev": true - }, "node_modules/picocolors": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", @@ -7999,24 +7797,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/roarr": { - "version": "2.15.4", - "resolved": "https://registry.npmjs.org/roarr/-/roarr-2.15.4.tgz", - "integrity": "sha512-CHhPh+UNHD2GTXNYhPWLnU8ONHdI+5DI+4EYIAOaiD63rHeYlZvyh8P+in5999TTSFgUYuKUAjzRI4mdh/p+2A==", - "dev": true, - "optional": true, - "dependencies": { - "boolean": "^3.0.1", - "detect-node": "^2.0.4", - "globalthis": "^1.0.1", - "json-stringify-safe": "^5.0.1", - "semver-compare": "^1.0.0", - "sprintf-js": "^1.1.2" - }, - "engines": { - "node": ">=8.0" - } - }, "node_modules/rollup": { "version": "4.55.1", "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.55.1.tgz", @@ -8136,29 +7916,6 @@ "node": ">=10" } }, - "node_modules/semver-compare": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz", - "integrity": "sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==", - "dev": true, - "optional": true - }, - "node_modules/serialize-error": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-7.0.1.tgz", - "integrity": "sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw==", - "dev": true, - "optional": true, - "dependencies": { - "type-fest": "^0.13.1" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/set-cookie-parser": { "version": "2.7.2", "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.2.tgz", @@ -8345,13 +8102,6 @@ "integrity": "sha512-4PRT4nh1EImPbt2jASOKHX7PB7I+e4IWNLvkKFDxNhJlfjbYlleYQh285Z/3mPTHSAK/AvdMmw5BNNuYH8ShgQ==", "dev": true }, - "node_modules/sprintf-js": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", - "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==", - "dev": true, - "optional": true - }, "node_modules/ssri": { "version": "9.0.1", "resolved": "https://registry.npmjs.org/ssri/-/ssri-9.0.1.tgz", @@ -8820,19 +8570,6 @@ "node": ">= 0.8.0" } }, - "node_modules/type-fest": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.13.1.tgz", - "integrity": "sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==", - "dev": true, - "optional": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/typescript": { "version": "5.9.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", @@ -8885,6 +8622,16 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/undici": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/undici/-/undici-7.27.2.tgz", + "integrity": "sha512-uZsKNuzQxDMUY6M3pIMvy5tvlGmtq8XJ2oLAkfRKGNu+1VQAIvLy2xIVG5ATZl5wDXl/tddByAWCizRbOme+TA==", + "dev": true, + "optional": true, + "engines": { + "node": ">=20.18.1" + } + }, "node_modules/undici-types": { "version": "7.16.0", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", @@ -8915,15 +8662,6 @@ "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/universalify": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", - "dev": true, - "engines": { - "node": ">= 4.0.0" - } - }, "node_modules/unzip-crx-3": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/unzip-crx-3/-/unzip-crx-3-0.2.0.tgz", @@ -9328,16 +9066,6 @@ "node": ">=12" } }, - "node_modules/yauzl": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", - "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", - "dev": true, - "dependencies": { - "buffer-crc32": "~0.2.3", - "fd-slicer": "~1.1.0" - } - }, "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", diff --git a/package.json b/package.json index ceab332..ce05f38 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,7 @@ "@playwright/test": "1.57.0", "@types/node": "25.0.3", "create-vite": "8.2.0", - "electron": "39.2.7", + "electron": "42.4.0", "electron-builder": "26.0.13", "eslint": "^9.39.2", "eslint-config-prettier": "^10.1.8", diff --git a/scripts/ci-install-electron.mjs b/scripts/ci-install-electron.mjs deleted file mode 100644 index 17ea98f..0000000 --- a/scripts/ci-install-electron.mjs +++ /dev/null @@ -1,44 +0,0 @@ -// Installs electron's prebuilt binary in CI. -// -// electron's postinstall (and its @electron/get / extract-zip deps) hangs or -// exits early on Node 24 — its promises never settle, leaving dist/ and -// path.txt missing ("Electron failed to install correctly"). This does the same -// work synchronously (curl + unzip/tar), so there is no async to stall. -import { execFileSync } from 'node:child_process'; -import { writeFileSync, mkdirSync } from 'node:fs'; -import { createRequire } from 'node:module'; -import path from 'node:path'; -import os from 'node:os'; - -const require = createRequire(import.meta.url); -const electronDir = path.resolve('node_modules/electron'); -const { version } = require('electron/package.json'); -const { platform, arch } = process; - -const url = `https://github.com/electron/electron/releases/download/v${version}/electron-v${version}-${platform}-${arch}.zip`; -const zipPath = path.join(os.tmpdir(), `electron-v${version}-${platform}-${arch}.zip`); -const dist = path.join(electronDir, 'dist'); - -execFileSync('curl', ['-fL', '--retry', '3', '-o', zipPath, url], { stdio: 'inherit' }); -mkdirSync(dist, { recursive: true }); -if (platform === 'win32') { - execFileSync( - 'powershell', - [ - '-NoProfile', - '-Command', - `Expand-Archive -LiteralPath '${zipPath}' -DestinationPath '${dist}' -Force`, - ], - { stdio: 'inherit' } - ); -} else { - execFileSync('unzip', ['-q', '-o', zipPath, '-d', dist], { stdio: 'inherit' }); -} -writeFileSync( - path.join(electronDir, 'path.txt'), - { linux: 'electron', win32: 'electron.exe', darwin: 'Electron.app/Contents/MacOS/Electron' }[ - platform - ] -); - -console.log(`electron ${version} ready`);