Your custom build is in progress. This page will update automatically.
+ +xattr -d com.apple.quarantine
+
+ Failed to load packages. The build server may be unavailable.
'; + }); +}); + +document.addEventListener('DOMContentLoaded', function() { + // auto-detect platform + var detected = detectPlatform(); + var platformEl = document.getElementById('platform'); + if (platformEl) { + platformEl.value = detected[0] + '-' + detected[1]; + } + updatePage(); + + var downloadButtonHtml = document.getElementById('download').innerHTML; + + // filter + document.getElementById('filter').addEventListener('input', function() { + var q = this.value.trim().toLowerCase(); + var count = 0; + document.querySelectorAll('.package').forEach(function(el) { + if (!q) { el.style.display = ''; return; } + var corpus = el.textContent.toLowerCase(); + if (corpus.indexOf(q) === -1) { + el.style.display = 'none'; + } else { + el.style.display = ''; + count++; + } + }); + this.classList.toggle('found', q && count > 0); + this.classList.toggle('not-found', q && count === 0); + if (!q) { this.classList.remove('found', 'not-found'); } + }); + + // platform change + document.getElementById('platform').addEventListener('change', updatePage); + + // package selection + document.getElementById('optional-packages').addEventListener('click', function(e) { + var pkg = e.target.closest('.package'); + if (!pkg) return; + // don't toggle if clicking a link or input + if (e.target.closest('a') || e.target.closest('input')) return; + pkg.classList.toggle('selected'); + updatePage(); + + // update URL + var newUrl = new URL(window.location.href); + var currentSelected = newUrl.searchParams.getAll('package'); + newUrl.searchParams.delete('package'); + var pkgPath = pkg.querySelector('.package-link').textContent.trim(); + if (pkg.classList.contains('selected')) { + if (!currentSelected.includes(pkgPath)) { + currentSelected.push(pkgPath); + } + } else { + var pos = currentSelected.indexOf(pkgPath); + if (pos >= 0) currentSelected.splice(pos, 1); + } + currentSelected.forEach(function(s) { newUrl.searchParams.append('package', s); }); + history.replaceState({}, document.title, newUrl.toString()); + }); + + // download button + document.getElementById('download').addEventListener('click', function(e) { + e.preventDefault(); + var btn = document.getElementById('download'); + if (btn.classList.contains('disabled')) return; + + btn.classList.add('disabled'); + btn.innerHTML = ' Starting build...'; + + // disable fields + document.querySelectorAll('.download-bar select, #optional-packages input').forEach(function(el) { + el.disabled = true; + }); + + var qs = getBuildParams(); + + fetch('/api/build?' + qs.toString(), { method: 'POST' }) + .then(function(r) { return r.json(); }) + .then(function(json) { + if (json.error) { + alert(json.error.message || 'Build request failed'); + enableFields(btn, downloadButtonHtml); + return; + } + var result = json.result; + if (result.status === 'complete') { + // already cached -- go straight to download + window.location.href = '/api/build/' + result.key + '/download'; + enableFields(btn, downloadButtonHtml); + return; + } + // navigate to build progress page + window.location.href = '/download-beta/build/?key=' + result.key; + }) + .catch(function(err) { + alert('Failed to start build: ' + err.message); + enableFields(btn, downloadButtonHtml); + }); + }); + + function enableFields(btn, originalHtml) { + btn.classList.remove('disabled'); + btn.innerHTML = originalHtml; + document.querySelectorAll('.download-bar select, #optional-packages input').forEach(function(el) { + el.disabled = false; + }); + } +}); + +function updatePage() { + var count = document.querySelectorAll('.package.selected').length; + var el = document.getElementById('package-count'); + if (el) el.textContent = count; + + // show/hide darwin warning + var platformVal = document.getElementById('platform').value || ''; + var darwinWarn = document.getElementById('darwin-warning'); + if (darwinWarn) darwinWarn.style.display = platformVal.indexOf('darwin') === 0 ? '' : 'none'; +} From 31c7c7b53c7418fa1a3494ccefcf9b96f7b2809f Mon Sep 17 00:00:00 2001 From: a Date: Tue, 7 Jul 2026 23:09:49 -0500 Subject: [PATCH 2/4] Handle reset event on build page for worker retries When the build server retries on a different worker (503 from a draining node), the SSE stream sends a 'reset' event. The frontend clears the build log, resets the progress bar, and shows a message that the build is retrying on another server. --- src/resources/js/download-beta-build.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/resources/js/download-beta-build.js b/src/resources/js/download-beta-build.js index 866d50e9..afa505fe 100644 --- a/src/resources/js/download-beta-build.js +++ b/src/resources/js/download-beta-build.js @@ -63,6 +63,16 @@ document.addEventListener('DOMContentLoaded', function() { } catch(err) {} }); + evtSource.addEventListener('reset', function(e) { + // server is retrying the build on another worker -- + // clear the UI so we show fresh progress + logEl.textContent = ''; + document.getElementById('current-step').textContent = 'Retrying build...'; + document.getElementById('progress-fill').style.width = '0%'; + document.getElementById('build-title').textContent = 'Building Caddy...'; + document.getElementById('build-subtitle').textContent = 'Build worker was restarted, retrying on another server.'; + }); + evtSource.addEventListener('result', function(e) { evtSource.close(); try { From e0267c01ae0a90afc0f6b9a4cb89f4e5be44dc7c Mon Sep 17 00:00:00 2001 From: a Date: Wed, 8 Jul 2026 17:13:58 -0500 Subject: [PATCH 3/4] Add PGO profile selection and upload to download page The download-beta page now has a collapsible PGO Optimization section: - None (default): no PGO, same as before - Default: selects a pre-configured server-side profile - Upload: lets users upload their own .pprof file When a named profile is selected, it's sent as a ?pgo= query param. When a custom profile is uploaded, it's base64-encoded and sent in the POST body. A badge shows 'enabled' when PGO is active. --- src/download-beta/index.html | 25 +++++++++++ src/resources/css/download-beta.css | 40 ++++++++++++++++++ src/resources/js/download-beta.js | 65 ++++++++++++++++++++++++++++- 3 files changed, 129 insertions(+), 1 deletion(-) diff --git a/src/download-beta/index.html b/src/download-beta/index.html index 839b3530..241cf233 100644 --- a/src/download-beta/index.html +++ b/src/download-beta/index.html @@ -69,6 +69,31 @@ +