feat(update): add nightly Velopack update channel (#80)
Addon CI / addon (arm64, macos-14, mac) (push) Waiting to run
Addon CI / addon (x64, ubuntu-22.04, linux) (push) Waiting to run
Addon CI / addon (x64, windows-latest, win) (push) Waiting to run
Ship CI / CI (push) Waiting to run

Adds `nightly` as a selectable auto-update channel (Windows + macOS).

Client:
- update-manager.ts: add 'nightly' to UpdateChannel (veloChannel already
  yields win-x64-nightly / osx-arm64-nightly, so no logic change)
- main.ts: allow 'nightly' in the runtime IPC channel guard
- preload.ts: add 'nightly' to the preload-local UpdateChannel union
- screen.js / settings.html: add the Nightly option + helper text

CI (nightly.yml):
- derive <pkg>-nightly.<UTC date> version in the setup job
- setup-dotnet (pinned from .build-config.json) so the vpk CLI has net8,
  matching build.yml
- vpk pack win-x64-nightly / osx-arm64-nightly (mac signed + notarized,
  mirroring build.yml's signed/unsigned fallback)
- publish a rolling `nightly` GitHub Release (prerelease=false, latest=false)
  that the in-app updater reads for the nightly channel
- concurrency guard so an overlapping dispatch can't race the rolling release

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Byron Gamatos
2026-07-07 00:10:03 +02:00
committed by GitHub
co-authored by Claude Opus 4.8
parent 34e1aa099d
commit dd7ad9b786
6 changed files with 240 additions and 7 deletions
+1 -1
View File
@@ -1108,7 +1108,7 @@ async function startup(): Promise<void> {
// IPC is untyped at runtime — validate the channel string before forwarding
// so a renderer bug or compromised page can't pass arbitrary values into
// the Velopack SDK.
const VALID_CHANNELS: readonly string[] = ['stable', 'rc', 'beta', 'alpha'];
const VALID_CHANNELS: readonly string[] = ['stable', 'rc', 'beta', 'alpha', 'nightly'];
if (typeof channel !== 'string' || !VALID_CHANNELS.includes(channel)) {
return updateManager.getStatus();
}
+1 -1
View File
@@ -39,7 +39,7 @@ import {
// from update-manager.ts) so the preload bundle doesn't drag in the Velopack
// SDK — preload runs in a restricted context and we don't want native
// require()s evaluated here.
export type UpdateChannel = 'stable' | 'rc' | 'beta' | 'alpha';
export type UpdateChannel = 'stable' | 'rc' | 'beta' | 'alpha' | 'nightly';
export interface UpdateAvailablePayload { version: string; channel: UpdateChannel }
export interface UpdateDownloadedPayload { version: string; channel: UpdateChannel }
+5 -2
View File
@@ -3,7 +3,10 @@
// Architecture:
// - The renderer persists the user's release channel in localStorage and
// calls setChannel() on boot so this module's UpdateManager is bound to
// the right feed (stable | rc | beta | alpha).
// the right feed (stable | rc | beta | alpha | nightly). The nightly feed
// is published by .github/workflows/nightly.yml as a rolling `nightly`
// GitHub Release (rid channels win-x64-nightly / osx-arm64-nightly),
// unlike the tag-driven alpha/beta/rc/stable feeds from build.yml.
// - On init() and then every 4 hours we run checkForUpdatesAsync(); when a
// hit comes back we download in the background, broadcast
// update:available immediately and update:downloaded once the .nupkg is
@@ -41,7 +44,7 @@ import { app, BrowserWindow } from 'electron';
import type { UpdateInfo } from 'velopack';
import { IPC_UPDATE_EVENT_AVAILABLE, IPC_UPDATE_EVENT_DOWNLOADED } from './ipc-channels';
export type UpdateChannel = 'stable' | 'rc' | 'beta' | 'alpha';
export type UpdateChannel = 'stable' | 'rc' | 'beta' | 'alpha' | 'nightly';
export type UpdateStatus =
| { status: 'unsupported'; platform: 'linux' }
+1 -1
View File
@@ -1873,7 +1873,7 @@ window.__feedBackDesktopAudioHooks = window.__feedBackDesktopAudioHooks || {};
const linuxNote = document.getElementById('update-linux-note');
if (!channelSelect || !checkBtn || !statusEl) return;
const VALID_CHANNELS = ['stable', 'rc', 'beta', 'alpha'];
const VALID_CHANNELS = ['stable', 'rc', 'beta', 'alpha', 'nightly'];
const storedChannelRaw = localStorage.getItem('slopsmith-update-channel');
const storedChannel = VALID_CHANNELS.includes(storedChannelRaw) ? storedChannelRaw : 'stable';
channelSelect.value = storedChannel;
+2 -1
View File
@@ -9,8 +9,9 @@
<option value="rc">Release candidate</option>
<option value="beta">Beta</option>
<option value="alpha">Alpha</option>
<option value="nightly">Nightly</option>
</select>
<p class="text-xs text-slate-500 mt-1">Pre-release channels (alpha/beta/rc) opt you into early builds.</p>
<p class="text-xs text-slate-500 mt-1">Pre-release channels (rc/beta/alpha) opt you into early builds. Nightly rebuilds from the latest code every night and is the least stable.</p>
</div>
<div class="flex flex-col">
<label class="block text-xs text-slate-400 mb-1">Manual check</label>