Files
punktfunk/scripts/windows/build-web.ps1
T
enricobuehlerandClaude Fable 5 5926306a4c
windows-host / package (push) Failing after 22s
windows-host / canary-manifest (push) Skipped
windows-host / winget-source (push) Skipped
ci / docs-site (push) Successful in 1m47s
ci / web (push) Successful in 1m53s
ci / rust-arm64 (push) Successful in 1m58s
docker / builders (--build-arg FEDORA_VERSION=44, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm, -f44) (push) Successful in 11s
docker / builders (ci/android-ci.Dockerfile, punktfunk-android-ci) (push) Successful in 9s
docker / builders (ci/arch-ci.Dockerfile, punktfunk-arch-ci) (push) Successful in 7s
docker / builders (ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 7s
docker / builders (ci/rust-ci-noble.Dockerfile, punktfunk-rust-ci-noble) (push) Successful in 8s
docker / builders (ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 6s
docker / apps (., web/Dockerfile, punktfunk-web) (push) Successful in 58s
apple / swift (push) Successful in 4m45s
deb / build-publish-client-arm64 (push) Successful in 3m28s
docker / apps (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 1m27s
deb / build-publish (push) Successful in 5m26s
docker / builders-arm64cross (push) Successful in 6s
android / android (push) Successful in 6m22s
docker / deploy-docs (push) Successful in 38s
ci / rust (push) Successful in 7m10s
deb / build-publish-host (push) Successful in 5m27s
arch / build-publish (push) Successful in 8m42s
rpm / build-publish (44, fedora-44, punktfunk-fedora44-rpm) (push) Successful in 16m58s
rpm / build-publish (43, bazzite, punktfunk-fedora-rpm) (push) Successful in 17m16s
apple / screenshots (push) Successful in 20m19s
feat(windows): the web console becomes a supervised child of the host service
Three silent console outages in one week (0x1 / 0xFFFFFFFF / 0x41306),
each a different proximate cause of the same structural defect: the
console's lifecycle was owned by Task Scheduler — one best-effort start
per boot/logon/install, no retry on a plain non-zero exit, no watchdog —
while the product already shipped a real supervisor.

The service now supervises the console as a second child slot: plain
session-0 spawn (suspended → own no-breakaway kill-on-close job →
resume), started only once the host has written mgmt-token + cert.pem +
key.pem (the cert race dies by construction), secrets read from their
files at every respawn, bun's stdout finally captured in logs\web.log,
doubling backoff 0.5s→60s that never gives up. Session switches never
touch it; a service stop takes it down via the job.

The PunktfunkWeb task is retired: web setup slims to password + legacy
task delete + firewall, the 127-line web-run.cmd batch supervisor is
deleted, an [InstallDelete] entry reaps the stale copy, and service
install now sets SCM crash-recovery actions (restart 1s/5s/60s) since
the console rides on the service process. StopBunRuntimes stays for the
scripting runner + the one migrating upgrade.

Design: punktfunk-planning design/windows-web-console-lifecycle.md

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-31 20:16:19 +02:00

57 lines
2.4 KiB
PowerShell

<#
Rebuild the web mgmt console from the CURRENT web/ source and swap it into an installed host.
powershell -ExecutionPolicy Bypass -File scripts\windows\build-web.ps1
bun is both the build tool AND the runtime: vite.config's Nitro noExternals bundles every dep
into the self-contained .output (no node_modules, nothing for bun to fail to resolve). The
console runs as a supervised child of the PunktfunkHost service (bun {app}\web\.output\server\
index.mjs on :47992), so the swap is: stop the service (its kill-on-close job takes the console's
bun down and unlocks the files), replace {app}\web\.output, start the service — the supervisor
brings the console back by itself. Needs an elevated shell (service control + Program Files).
#>
$ErrorActionPreference = 'Stop'
$repo = Split-Path (Split-Path $PSScriptRoot)
$web = Join-Path $repo 'web'
$bun = 'C:\Users\Public\bun\bin\bun.exe'
$app = 'C:\Program Files\punktfunk'
if (-not (Test-Path $bun)) { throw "bun not found at $bun" }
Set-Location $web
Write-Host "bun install + build ..."
& $bun install
& $bun run build
if ($LASTEXITCODE -ne 0) { throw "web build failed (exit $LASTEXITCODE)" }
# No .output/server install step: noExternals means the output has no externalized deps to resolve.
$appWeb = Join-Path $app 'web'
if (-not (Test-Path $appWeb)) {
Write-Host "no installed console at $appWeb - built web\.output only (run it by hand: bun web\.output\server\index.mjs)"
return
}
Write-Host "swapping $appWeb\.output (stopping the PunktfunkHost service) ..."
& net stop PunktfunkHost | Out-Null
try {
Remove-Item (Join-Path $appWeb '.output') -Recurse -Force -ErrorAction SilentlyContinue
Copy-Item (Join-Path $web '.output') -Destination $appWeb -Recurse -Force
}
finally {
& net start PunktfunkHost | Out-Null
}
# The console serves HTTPS-only (PUNKTFUNK_UI_SECURE=1, the host's own cert) - probe with curl.exe
# (-k for the self-signed cert; Invoke-WebRequest under Windows PowerShell 5.1, which this script
# runs under, has no -SkipCertificateCheck), retrying while the service/bun cold-starts.
$code = $null
for ($i = 0; $i -lt 15; $i++) {
Start-Sleep 2
$code = & curl.exe -sk -o NUL -w '%{http_code}' --max-time 5 'https://127.0.0.1:47992/login' 2>$null
if ($code -eq '200') { break }
}
if ($code -eq '200') {
Write-Host "DONE - web /login -> HTTP $code"
} else {
Write-Warning "console swapped but /login did not return 200 yet (last: $code) - check %ProgramData%\punktfunk\logs\web.log"
}