Skip to content

Auto-updater

One-time steps to get releases flowing. Once done, cutting a new version is just scripts/release.sh patch && git push && git push --tags.

dev machine GitHub Cloudflare Worker end-user app
─────────── ────── ───────────────── ────────────
scripts/release.sh ─────► tag push ─────► (private release)
Actions build
+ sign + publish
latest.json +
.app.tar.gz(.sig)
◄─── fetches latest.json
streams binaries
◄── polls Worker
on startup,
downloads,
installs

Run once per project, keep the private key offline and backed up.

Terminal window
cd src-tauri
../src/node_modules/.bin/tauri signer generate -w ~/.tauri/helm-dj.key
# enter a strong password when prompted

Two files are produced:

  • ~/.tauri/helm-dj.key — private key (never commit, back up securely)
  • ~/.tauri/helm-dj.key.pub — public key (safe to commit)

Paste the contents of the .pub file into src-tauri/tauri.conf.jsonplugins.updater.pubkey, replacing REPLACE_WITH_YOUR_PUBLIC_KEY.

In your repo’s Settings → Secrets and variables → Actions, add:

  • TAURI_SIGNING_PRIVATE_KEY — base64 of ~/.tauri/helm-dj.key
  • TAURI_SIGNING_PRIVATE_KEY_PASSWORD — the password you set
Terminal window
base64 -i ~/.tauri/helm-dj.key | pbcopy # macOS

Then paste it into the GitHub secret form.

If you have an Apple Developer account and want notarized builds (no “unidentified developer” warning, faster Gatekeeper checks on update), also add:

  • APPLE_CERTIFICATE — base64 of your .p12
  • APPLE_CERTIFICATE_PASSWORD — password for the .p12
  • APPLE_SIGNING_IDENTITY — “Developer ID Application: Your Name (TEAMID)”
  • APPLE_ID — your Apple ID email
  • APPLE_PASSWORD — app-specific password
  • APPLE_TEAM_ID — your Apple team ID

Leave these unset to skip notarization — updates still work, users just see the first-launch warning.

The auto-update proxy runs as part of the Helm website (Next.js on Vercel). See docs/src/content/docs/ops/auto-update-service.md for the route implementation, secrets, and deploy steps. Historical note: an earlier Cloudflare Worker lived at updater-worker/ but was retired before v0.3.0 when the Vercel app-facing API landed.

src-tauri/tauri.conf.jsonplugins.updater.endpoints[0] points at https://helm.e-labs.co.uk/api/updates/{{target}}-{{arch}}/{{current_version}}. Auth is via X-Helm-Client-Key — the header is attached in src-tauri/src/main.rs on the updater-plugin builder using env!("HELM_CLIENT_KEY"), so the committed config never holds the secret.

Terminal window
scripts/release.sh patch # or minor / major / explicit like 0.2.1
git push && git push --tags

GitHub Actions builds both arm64 + x64 macOS binaries, signs them, uploads the .app.tar.gz(.sig) + .dmg to the release, and generates a latest.json that the Worker serves to the app.

After the Actions run finishes:

Terminal window
curl -H "X-Helm-Client-Key: $HELM_CLIENT_KEY" \
https://helm.e-labs.co.uk/api/updates/darwin-aarch64/0.0.0 | jq
# expect a manifest with your new version

Open the previous version of the app — badge should appear in the top-left, and the Settings → Updates tab should show the new release notes.

AreaPath
Tauri plugin configsrc-tauri/tauri.conf.json (plugins.updater)
Rust registrationsrc-tauri/src/main.rs
Frontend servicesrc/src/lib/integrations/updater.ts
Svelte storesrc/src/lib/stores/updaterStore.ts
Badge UIsrc/src/lib/components/UpdateBadge.svelte
Settings tabsrc/src/lib/components/SettingsPanel.svelte (updates tab)
Bootstrapsrc/src/lib/components/AppShell.svelte
CI.github/workflows/release.yml
Update service (site-side)website/src/app/api/updates/**
Release scriptscripts/release.sh