Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
12 KiB
Wire-compatible with 0.21.x and 0.22.x — nothing about streaming changed, and everything already paired keeps working. This release repairs the Windows installer and gives every host something new: the web console now tells you when a newer Punktfunk is out, and can install it for you where the platform allows. The apps on your phone, tablet, Mac and TV are unchanged.
If you stream to a Windows PC, update that PC. The 0.22.1 and 0.22.2 installers were built without the web console in them at all — not broken, absent. If the tray menu on your PC says "Open web console (not responding)" and the page never loads no matter what you try, that is this, and reinstalling those versions could never have fixed it.
New
-
The console tells you when a newer host is out. The Host page has an Updates card: the version you're running, the channel you follow (stable or canary), and — once something newer exists — release notes and the exact way to update your kind of install. The check is a small signed file the host verifies against keys built into it, so nothing between you and the project can feed it a fake update, and a feed that ever tried to roll you backwards is refused outright. It contacts only the Punktfunk forge, and
PUNKTFUNK_UPDATE_CHECK=0turns it off entirely. Scripts can react too: the host emitsupdate.availableand, after a successful update,update.appliedon its event stream. -
On Windows, updating the host is now one click. The card grows an Update now button: it asks for your console password again (a remembered login alone can't restart your PC's host), then downloads the installer, checks it against the signed release manifest and its code signature, and runs it silently — the service restarts and the page reconnects by itself. If someone is streaming you're warned first, because updating drops the stream. Every attempt leaves its outcome in the card even across the restart, with the installer's log path when something went wrong — and if a freshly installed version ever crash-loops, the host puts the previous installer back on its own and says so.
PUNKTFUNK_UPDATE_APPLY=0inhost.envremoves the button on hosts that should never have it. -
Linux hosts can opt in to the same button. apt, Fedora, Bazzite (sysext and rpm-ostree) installs get one-click updating through a deliberately tiny root helper the packages now ship. It's off until you decide otherwise — enabling it is one command,
sudo usermod -aG punktfunk-update $USER, and that group membership is the entire grant: the button can only ever run your package manager's normal update for the Punktfunk packages, from the same signed repositories you already use, and it never picks versions or URLs. rpm-ostree updates are staged and the card asks you to reboot (it never reboots for you). On Arch the button additionally requires opting into a fullpacman -Syuin/etc/punktfunk/update.conf, because a partial upgrade is how Arch boxes break — we won't run one. Steam Deck on-device installs get the button with no opt-in at all: it runs the same rebuildupdate.shalways did, just from the couch. The full story is on the new Updating the Host docs page.
Fixed
-
The web console is in the installer again. On 0.22.1 and 0.22.2 the Windows installer shipped with the console missing entirely: the files it runs from were never included, so the PC had nothing to start and nothing to open. The host itself was fine the whole time — streaming, pairing and controllers all worked — but the settings page you reach in a browser simply was not there. The tray reported it as "not responding", which was true and also the only clue you got, and because every reinstall produced the same installer, uninstalling and reinstalling made no difference. Updating to 0.22.3 restores it; you don't need to touch your settings, your password, or your paired devices.
-
Updating no longer stops on a "DeleteFile failed; code 5" error. Partway through an update, the installer could stop on a dialog complaining that it could not replace
bun\bun.exe, offering only Try again, Skip, or Cancel — and Try again usually failed the same way. Windows refuses to replace a program while it is running, and the pieces of Punktfunk that were still running weren't the ones the installer knew how to stop. It now shuts all of them down, waits for them to actually exit rather than assuming, and if something still holds the file it finishes the install and puts the new copy in place on your next restart instead of leaving you stuck at a dialog. -
Updating no longer switches your plugins off. If you had enabled the script and plugin runner, every update quietly disabled it again, so plugins stopped running until you noticed and re-enabled them by hand. Updates now leave it exactly as you had it — on if it was on, and still off by default for everyone who has never turned it on.
Improved
-
You can save or share the host's log from the console. The Logs page has two new buttons: one downloads what you're looking at as a timestamped
.logfile, the other hands it to your phone or tablet's share sheet, or copies it to the clipboard on a desktop. Handy when someone asks you for a log — the file carries full dates and times, so it still makes sense once it leaves your browser. Whatever level filter and search you have applied is what you get, and it saves everything that matches rather than just the part on screen. -
Televisions that struggle with the startup speed test can be told to ease off. Two seconds into a session Punktfunk briefly bursts traffic to measure how much room your network really has. On some TVs that burst is enough to disturb the very link it is measuring — one LG set showed no video for fourteen seconds when it went badly. The burst's size can now be capped, so a device that already limits its own speed test can keep ours in line with it. Nothing changes unless a device asks for it.
Under the hood (for developers)
- The console's absence was one CI variable in the wrong place.
windows-host.ymlexportedWEB_OUTPUT_DIRon the last line of "Build + smoke-boot web console (bun)", andbe2fabcfhad just put that step behindif: steps.webconsole.outputs.cache-hit != 'true'. So the first build after the cache was populated — and every build after it withweb/**andsdk/**unchanged — skipped the step, left the variable unset, andpack-host-installer.ps1reads an unsetWEB_OUTPUT_DIRas "omit the console", announcing it in a singleWrite-Hostbefore packing happily. Confirmed from the job logs rather than inferred: on both the v0.22.1 (run 14235) and v0.22.2 (run 14272) tag builds, step 12 isskippedand the job is green.BUN_EXEandSCRIPTING_BUNDLEare exported from unconditional steps, which is why those installers still carried bun and the plugin runner but no{app}\web. - Downstream,
web setupbailed atweb launcher missing: {app}\web\web-run.cmdbefore registering anything, so there was noPunktfunkWebtask, no listener on 47992, and no firewall rule — and Inno ignores[Run]exit codes, so the failure left no trace in the install at all.WEB_OUTPUT_DIRnow comes from its own unconditional step that throws whenweb\.output\server\index.mjsis absent, and a new pre-pack step asserts all five payloads (console, bun, plugin runner, FFmpeg DLLs, VB-CABLE) so a missing input fails the build rather than silently redefining the installer. The shape is borrowed from the packer's existing VB-CABLE check. FFmpeg was the most dangerous of the silent ones: anamf-qsvhost link-imports avcodec, so an installer without those DLLs ships a host that cannot start at all. - The same cache-hit build is why
bun.exelocked. It ships underWithWeborWithScripting, but the installer's pre-copy stop was#ifdef WithWeb— so a console-less installer shipped bun while the only code that stopped bun was compiled out.StopBunRuntimesreplacesStopWebConsolebehind the sameWithWeb || WithScriptinggate the payload uses, and covers what the old routine structurally could not: neither bun runs under the host service (both are Task Scheduler tasks —PunktfunkWebas SYSTEM,PunktfunkScriptingas LocalService), and the runner listens on no port, so a task-name-plus-port sweep could never see it. It now disables both tasks before stopping them — they carry restart-on-failure at 10× and 999× a minute, and the web task also has a logon trigger, so a force-kill alone invited a respawn into the middle of a copy that takes over a minute atlzma2/max— kills any bun whose image lives under the install dir (by path, so an unrelated bun survives), and polls until they are gone, sinceStop-ScheduledTaskreturns on request andStop-ProcessisTerminateProcess.bun.exealso gainedrestartreplace, so a survivor defers to reboot instead of dead-ending the install. - Disabling a task is not free: unlike a stopped one it does not return at the next boot, so an aborted install would have taken the console down permanently. Two restores cover it — a last-in-
[Run]entry for the normal flow andDeinitializeSetup, which Inno calls even on user cancel — both re-enabling only what was enabled before the copy. That is also the plugin-runner fix: the scripting[Run]entry re-registers its task and then unconditionally disables it, correct on a first install and wrong on every upgrade since. PUNKTFUNK_ABR_PROBE_KBPSsets the startup capacity probe's burst target for embedders. Unset, zero or unparseable keeps the 2 Gbps default, so existing sessions are unchanged;PUNKTFUNK_ABR_PROBE=0remains a poor substitute because it pins the climb ceiling at the negotiated ~20 Mbps.- The console's log export serializes the filters' full result rather than the rendered tail — the 1000-row cap is a DOM budget and has no business truncating a file destined for a bug report — and stamps each line with a local ISO 8601 timestamp plus numeric offset. Web Share level 2 is probed at runtime after mount (SSR has no
navigator, and guessing there would mismatch on hydration), falling back to the clipboard, and the button is omitted only where neither exists. - The update check's truth is a per-channel Ed25519-signed manifest (
…/generic/punktfunk-update/{stable,canary}/manifest.json+.sig), verified against keys pinned in the host binary via the plugin-index machinery, with a persisted monotonic serial as the anti-rollback floor and the channel name bound into the signed document. Stable manifests publish fromannounce.yml— the existing manual fleet-green gate doubles as the gate for the fleet learning about a release; canary rideswindows-host.yml. TLS and the registry are transport, never trust. /api/v1/update/*is admin-lane only: whole-prefix denied to the plugin token and absent from the paired-cert allowlist. Apply requests carry no version, URL, or channel — the privileged side derives everything from its own verified state — and the console's BFF re-verifies the console password per apply (sharing the login throttle) while every mutating route now requires a same-originSec-Fetch-Site. Outcomes survive the host's own restart via an intent record reconciled at boot.- The Linux packages grow four pieces: the dep-free root helper
/usr/libexec/punktfunk/pf-update, the fixed-ExecStart oneshotpunktfunk-update.service, a polkit rule granting exactly that unit'sstartverb to thepunktfunk-updategroup, and the group itself — created empty by every postinst, populated by no one. - No wire, ABI or driver-protocol changes: wire protocol 2, C ABI 13, Windows virtual-gamepad channel 3, virtual-display driver protocol 6 — identical to 0.22.0, 0.22.1 and 0.22.2.