Files
JakeBreath 7ca84f4fea
CI / Backend tests (push) Successful in 2m41s
CI / Frontend build & lint (push) Successful in 25s
Point desktop updates at the Gitea release feed
The updater now resolves the newest non-draft desktop-v* release through the
Gitea API at check time (J621_UPDATE_REPO, lowercase because the API path is
case-sensitive), picks the platform's latest*.yml asset and uses that release
as a generic electron-updater feed; J621_UPDATE_URL still overrides
everything. Verified against the live API: release picked, yml fetched,
artifact HEAD 200.

electron-builder's publish.url is now metadata only (still needed so the
build emits latest*.yml). Docs updated: CD release assets are the feed, the
website /desktop/ feed only matters for installs before 0.1.2.
2026-09-23 22:00:49 -05:00
..
2026-09-23 21:40:43 -05:00

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

The main process attaches a Referer to requests for e621 hosts: Chromium sends no referrer from a custom-scheme page, and e621's CDN answers cross-site image loads without one with a 403 (which Chromium then blocks as ORB). API calls work either way.

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

deploy/build_desktop.sh wraps the same commands, installs dependencies on first run and prints sizes plus SHA-256 sums for release notes. Nothing is published by it; the CD workflow attaches the artifacts to the Gitea release, which is also the update feed.

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 resolves the feed itself: it asks the Gitea API for the newest non-draft desktop-v* release (J621_UPDATE_REPO, default https://gitea.rainbow-herring.ts.net/jakebreath/j621 — lowercase on purpose, the API path is case-sensitive), picks the latest-linux.yml / latest.yml asset for the platform and uses that release as an electron-updater generic feed. The baked publish.url in electron-builder.yml is metadata only. J621_UPDATE_URL overrides the whole lookup (the smoke test uses this).

Publishing a release:

  1. Bump version in desktop/package.json — that is what the updater compares.
  2. Run the manual CD workflow, which builds the packages and attaches them plus both channel files to the Gitea release desktop-v<version>. ./deploy/push_desktop.sh --win does the same build locally (and can also copy the files to the website feed, which is optional now).
  3. Existing installs find the new version on their next manual check.

Note for the 0.1.1 → 0.1.2 step: 0.1.1 only knows the old /desktop/ feed, so publish 0.1.2 there once (./deploy/push_desktop.sh --no-build, or install it manually). From 0.1.2 on, updates come from Gitea.

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. Pointing J621_DEV_SERVER at the Vite dev server checks the development path instead of the bundled one.

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.