Files
J621/desktop/README.md
T
JakeBreath 7c39383655 Wire desktop updates through a generic feed
electron-builder now publishes latest-linux.yml / latest.yml and embeds
app-update.yml plus package-type, so electron-updater runs pacman -U or
dpkg -i through pkexec for packages and updates the per-user NSIS install
without elevation. The app checks only when asked (menu item), asks before
downloading and before installing, and J621_UPDATE_URL overrides the feed
for tests or forks.

deploy/push_desktop.sh builds and publishes the artifacts to
deploy/data/desktop, which the frontend nginx mounts read-only at
/desktop/. Verified detection and up-to-date handling against a local feed
with the packaged Arch build.
2026-09-20 17:32:41 -05:00

3.6 KiB

J621 desktop (Electron)

An Electron shell around the web build. The main process serves the SPA from the privileged app://j621 scheme — a real origin, so localStorage, OPFS, Web Workers and WebCodecs all behave exactly like they do in Chrome — and the SPA keeps its normal first-run flow: on launch it asks where the backend is (or runs in local mode with no backend at all).

The renderer code is not forked: the shell loads frontend/dist as built by npm run build in frontend/.

Licensed under the Jake Labs Non-Commercial Software Licence — see ../LICENSE.

Layout

src/main.ts      window, app:// protocol handler, menu, external links
src/preload.ts   window.j621Desktop bridge
electron-builder.yml   deb + pacman + nsis packaging

Development

# terminal 1: the SPA with its /api proxy (needs the backend for library pages)
cd frontend && npm run dev

# terminal 2
cd desktop && npm run dev

npm run dev builds the main process and points the window at http://localhost:5173 (J621_DEV_SERVER). Without the dev server, npm start builds both halves and serves the bundled SPA over app://j621.

Builds

npm run dist:linux   # release/j621-desktop_0.1.0_amd64.deb + j621-desktop-0.1.0.pkg.tar.zst
npm run dist:win     # release/J621 Setup 0.1.0.exe (cross-built with wine; untested)
npm run dist:all

The Arch package can be installed and removed with pacman:

sudo pacman -U release/j621-desktop-*.pkg.tar.zst
sudo pacman -R j621-desktop

It installs to /opt/J621 with a /usr/bin/j621-desktop symlink and a io.j621.desktop launcher entry (StartupWMClass matches the shell's desktopName). The Windows installer is a per-user NSIS build, so no admin rights are needed to install or update it — but it is unsigned, so SmartScreen will warn, and it has not been smoke-tested on real Windows.

Updates

The app checks only when asked (J621 → Check for updates… in the menu): Linux packages install through pacman/dpkg, which needs administrator rights, and the Windows build is unsigned, so nothing installs silently. The check reads latest-linux.yml / latest.yml from the feed configured in electron-builder.yml (publish.url, baked into app-update.yml); set J621_UPDATE_URL to point a build at another feed (the smoke test uses this).

Publishing a release:

  1. Bump version in desktop/package.json — that is what the updater compares.
  2. ./deploy/push_desktop.sh --win builds deb/pacman/NSIS and copies the artifacts plus both channel files into deploy/data/desktop/, which the frontend nginx serves read-only at /desktop/.
  3. Existing installs find the new version on their next manual check.

package-type in the app resources tells electron-updater whether to run pacman -U or dpkg -i (both via pkexec/sudo); the per-user NSIS install updates without elevation.

Smoke test

npm run smoke builds everything, runs Electron headless through xvfb-run and checks that the bundled SPA loads over app://j621: the SPA fallback, an asset fetch, localStorage, OPFS, WebCodecs and the preload bridge. It exits non-zero on failure. With J621_UPDATE_URL set it also checks that the feed reports the expected version.

Backend CORS

A desktop app is cross-origin to the backend, exactly like the frontend-only Docker deployment. Add the shell's origin to the backend:

CORS_ALLOWED_ORIGINS=app://j621

The setup screen shows this hint (with the actual origin) when the connection test fails. Without a backend, choose "Continue without a backend" — the e621-facing pages work the same as in the browser.