document.addEventListener("click", async (event) => { const button = event.target.closest("[data-copy]"); if (!button) return; const target = document.querySelector(button.dataset.copy); if (!target) return; try { await navigator.clipboard.writeText(target.textContent.trim()); const original = button.textContent; button.textContent = "Copied"; window.setTimeout(() => { button.textContent = original; }, 1500); } catch { button.textContent = "Copy failed"; } }); document.addEventListener("submit", async (event) => { const form = event.target.closest("[data-upload-form]"); if (!form) return; event.preventDefault(); const button = form.querySelector("button[type=submit]"); const status = form.querySelector("[data-upload-status]"); const csrfToken = form.querySelector('input[name="csrf_token"]').value; button.disabled = true; status.textContent = "Uploading package… keep this page open."; try { const response = await fetch(form.action, { method: "POST", body: new FormData(form), headers: {"X-CSRF-Token": csrfToken}, credentials: "same-origin", }); const result = await response.json().catch(() => ({})); if (!response.ok) { throw new Error(result.error || `Upload failed with HTTP ${response.status}`); } if (result.warning) { status.textContent = `${result.warning} The replacement is active; see the audit trail for details.`; button.disabled = false; } else { status.textContent = `Uploaded ${result.filename}; SHA-256 ${result.sha256}`; window.setTimeout(() => { window.location.assign("/portal?notice=Package+uploaded+and+registered"); }, 900); } } catch (error) { status.textContent = error.message; button.disabled = false; } });