Files
Fractured/tools/fractured-launcher-electron/README.md
T
Docker Build 15c476c12d ci(gitea-sync): overlay launcher from default branch before pack
Release tags can point at commits older than launcher lib additions; building
only from the tag omitted gitea-release.js etc. Fetch default branch and
checkout tools/fractured-launcher-electron from it before npm ci/pack.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-10 19:15:27 -05:00

13 KiB
Raw Blame History

Fractured Launcher (Electron)

Windows launcher with no extra console window, native Browse folder dialog, Gitea or GitHub release assets + GitHub repo file sync, realmlist, optional auth, Play, and auto-update (via electron-updater). This is the only supported client launcher in this repo.

Requirements

Run from source

cd tools/fractured-launcher-electron
npm install
npm start

On first run, launcher.json is created next to the app (dev: in this folder).

Where patches download from

  • Recommended (self-hosted Gitea): set gitea.base_url, gitea.owner, gitea.repo in launcher.json (see default-launcher.json). Players need GITEA_TOKEN (or the env name in gitea.token_env) if the Gitea repo is private — same trade-off as any private host (per-player token, SSO proxy, or a read-only deploy token you accept distributing).
  • Fallback: if gitea.base_url is empty, from_release uses the GitHub Releases API against github.owner / github.repo (defaults to this Fractured repo for non-release paths), with optional GITHUB_TOKEN for private assets.

Build Windows installers

npm install
npm run pack:win

Produces under dist/:

Artifact Purpose
Fractured-Launcher-${version}-Setup.exe (NSIS) Recommended for players — supports seamless auto-update and restart.
Fractured-Launcher-${version}-Windows-Portable.exe No installer; players replace the file manually. Auto-update is less reliable than NSIS.

Baked Gitea channel (non-token)

npm run pack:win runs scripts/inject-release-channel.js first. It merges gitea.base_url, owner, repo, and optional release_tag into default-launcher.json for that build only (then electron-builder packs that file).

  • GitHub ActionsSync release to Gitea and Fractured launcher CI export GITEA_BASE_URL, GITEA_OWNER, GITEA_REPO (same names as your upload secrets) for the pack step, so installers match the repo you sync to. Nothing embeds GITEA_TOKEN.
  • Local packs — put the same values in fractured-release-channel.json (committed or personal copy) or export those env vars before npm run pack:win.

First launch still copies default-launcher.jsonlauncher.json beside the exe, so players get the baked gitea.* without editing unless they override.

Auto-update behaviour

  • Packaged builds only (npm run pack:win output). In npm start dev mode, update checks are skipped (button still explains that).
  • No implicit GitHub feed: the app does not guess package.jsonrepository anymore. Without configuration you get a clear “skipped” message instead of a 404 on a private repo.
  • Configured feeds (first match wins): update_feed_url / LAUNCHER_UPDATE_URL (generic latest.yml); or gitea block filled in + GITEA_TOKEN when the instance is private (resolves …/releases/download/{tag}/); or GITHUB_TOKEN + github.owner / github.repo for private GitHub releases only.
  • ~5 seconds after launch, then every 6 hours, the app checks when a feed is configured.
  • When a download finishes, a dialog offers Restart now (calls quitAndInstall) or Later.
  • Manual check: button Check launcher updates in the UI.

Where launcher updates are hosted

npm run publish:win runs electron-builder with --publish never — artifacts stay in dist/; CI uploads them to Gitea when you publish a GitHub release. For ad-hoc uploads, use scripts/upload-release-to-gitea.sh. For launcher auto-update, prefer:

  • Set update_feed_url (or LAUNCHER_UPDATE_URL) to a generic HTTPS base URL where latest.yml and the installer files are hosted (often the same Gitea release attachment URLs pattern your reverse proxy exposes), or
  • Keep publishing to a GitHub release only for latest.yml + installers if you accept that small metadata/binary channel there.

Private GitHub updater: set GH_TOKEN / GITHUB_TOKEN / github.token_env as documented in lib/auto-update.js behaviour.

Generic feed: optional Bearer token via the same token envs if your static host checks Authorization.

Publishing a new launcher version

  1. Bump version in package.json on main (or your release branch) and merge.
  2. Create a GitHub release (tag + attach patches / Wow.exe if needed) and click PublishSync release to Gitea builds Windows installers and mirrors everything to Gitea.
  3. Local check: npm run pack:win then scripts/upload-release-to-gitea.sh with the same GITEA_* env vars as CI if you need a manual upload.

Sync to Gitea (patches + launcher binaries)

CI workflow Sync release to Gitea (.github/workflows/gitea-release-sync.yml) runs on every published GitHub release on this repo:

  1. Triggers on release published on Dawnforger/Fractured (or workflow_dispatch with a tag).
  2. Builds the Electron app on Windows using tools/fractured-launcher-electron from the repo default branch (then overlays onto the tag checkout), so older release tags never ship a launcher thats missing new lib/*.js files.
  3. Downloads all assets attached to that GitHub release (MPQs, patched Wow.exe, etc.).
  4. Merges with the built launcher artifacts and uploads everything to a Gitea release with the same tag (existing attachments on that Gitea release are replaced).

GitHub Actions secrets (repository → Settings → Secrets and variables → Actions):

Secret Example
GITEA_BASE_URL https://git.yourdomain.com (no trailing slash)
GITEA_TOKEN Gitea personal access token with permission to manage releases and attachments on the target repo
GITEA_OWNER Organization or username on Gitea
GITEA_REPO Repository name — must already have at least one commit (Gitea returns HTTP 422 “repo is empty” for zero-commit repos; push e.g. a README on main or set GITEA_TARGET_REF to your default branch)

Optional variable (Settings → Variables): GITEA_TARGET_REF — default branch/commitish used only when the workflow must create a new Gitea release and Gitea needs target_commitish (defaults to main in the upload script if unset).

Player launcher.json: packaged builds should already include gitea.base_url / owner / repo from the bake step above. Players only need to set GITEA_TOKEN (or your token_env) if the Gitea repo is private. To point at another instance, edit gitea in launcher.json:

"gitea": {
  "base_url": "https://git.yourdomain.com",
  "owner": "myorg",
  "repo": "fractured-patches",
  "release_tag": "latest",
  "token_env": "GITEA_TOKEN"
}

Manual upload: bash scripts/upload-release-to-gitea.sh /path/to/files v1.0.0 with the same env vars as CI.

Sync did not run / Gitea unchanged — checklist

  1. Git tag ≠ GitHub Release — Only Releases (published on the GitHub Releases page) trigger this workflow. If your teammate only git push --tags, create a Release from that tag and click Publish (or run Actions → Sync release to Gitea → Run workflow and enter the tag).
  2. Draft release — Must click Publish release; drafts do not mirror.
  3. Workflow on default branch — GitHub runs release workflows from the default branch (e.g. main). Ensure .github/workflows/gitea-release-sync.yml is merged there.
  4. Repo name guard — Jobs use if: github.repository == 'Dawnforger/Fractured'. Forks or renames must change that line or runs are skipped.
  5. SecretsGITEA_BASE_URL, GITEA_TOKEN, GITEA_OWNER, GITEA_REPO must be set under Settings → Secrets and variables → Actions. A failed “Upload to Gitea” step usually prints which is missing.
  6. Actions tab — Open the latest Sync release to Gitea run; a red build-electron (old tag without package-lock.json, etc.) or Upload to Gitea step shows the real error.
  7. HTTP 422 repo is empty — The Gitea repo has no commits yet. Push any initial commit (e.g. Add README in the Gitea web UI, or git push to main). Optionally set GITEA_TARGET_REF to match your real default branch if it is not main. From this repo you can run scripts/bootstrap-gitea-repo.sh (see script header for GITEA_* env or pass the HTTPS/SSH clone URL as the first argument).

Private Gitea token for players

Do not embed a shared admin PAT in a shipped launcher.json. Prefer read-only tokens scoped to one repo, short-lived tokens, or a small auth service that redirects to signed URLs.

Release asset names must match files[].source when from_release: true. Use release_tag: "latest" or a pinned tag matching both GitHub and Gitea.

Patch versions (same filenames, different bytes)

The launcher does not read Git commits. For turn-key updates when asset names stay fixed (patch-Z.MPQ, Wow-patched.exe, …):

  1. Ship patch-manifest.json next to those files on every release (Gitea/GitHub attachment). It lists a version label (any string you bump per release, e.g. v0.9.0-client) and a sha256 per files[].source name.
  2. With patch_manifest.enabled: true (default in default-launcher.json), Download updates first fetches the manifest from the same release channel. If the files already on disk match those checksums, the player sees “already match build … (nothing to download)” — no redundant downloads.
  3. After a real download, the launcher re-hashes installed files and compares to the manifest; mismatch → clear error. It also writes .fractured/patch-state.json under the WoW folder so the UI can show “Installed client files: …”.

If patch-manifest.json is missing on a release, the launcher falls back to always downloading all configured files (same as before).

Generate the manifest when you cut a release (paths are your local patch binaries):

cd /path/to/staging
node tools/fractured-launcher-electron/scripts/generate-patch-manifest.js v0.9.0-client patch-Z.MPQ Wow-patched.exe > patch-manifest.json

Attach patch-manifest.json together with the MPQ/exe to the GitHub release (CI sync copies it to Gitea with everything else).

CI

Workflow Fractured launcher CI (.github/workflows/fractured-launcher-ci.yml) runs on pushes/PRs under tools/fractured-launcher-electron/: Windows pack uses electron-builder … --publish never (not npm run pack:win, so tagged checkouts never require GH_TOKEN). Actions → Fractured launcher CI → Run workflow runs it manually.

Sync release to Gitea (.github/workflows/gitea-release-sync.yml) uses the same pack command. If you see GH_TOKEN / GitHubPublisher errors in logs, the job is almost certainly an old Re-run failed jobs — open Actions → Sync release to Gitea → Run workflow, enter the tag, and start a new run instead.

Config

Schema is defined by default-launcher.json (shipped in the app; first run copies to launcher.json beside the executable):

  • game_dir: WoW 3.3.5a root (contains Wow.exe).
  • update_feed_url: optional generic HTTPS base for launcher auto-update.
  • launcher_updates_from_github: default false. Only when true will a GITHUB_TOKEN (or github.token_env) enable electron-updaters GitHub provider against github.owner / github.repo. Leave false when launcher binaries and latest.yml live on Gitea (use gitea + token instead) so a stray GitHub token does not produce “No published versions on GitHub”.
  • gitea: base_url, owner, repo, release_tag, token_env — when base_url is set (and owner/repo set), from_release downloads and (with token if needed) the generic updater feed use Gitea. Required for players if your CI mirrors patches/launchers to Gitea only.
  • github: used for non-release repo paths (from_release: false) and for GitHub from_release when gitea.base_url is empty.
  • patch_manifest: enabled, source (default patch-manifest.json), from_release — checksum-based skip + verify (see above).
  • files, realmlist, auth, launch.