/* ========================================================================= billing.js — the credits & wallet console • fetches /auth/me for billing state (enabled, balance, deposit, key) • renders the key-reveal banner on first signup (?new=1) • renders balance / deposit / key-prefix cards • polls /api/me/balance every 10s for a live feel • gracefully hides if billing isn't configured (unmetered mode) ========================================================================= */ (async function () { 'use strict'; var grid = document.getElementById('billing-grid'); var section = document.getElementById('billing-section'); if (!grid || !section) return; // not on the dashboard page var reduceMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches; var pollTimer = null; var lastBalance = -1; /* ---- escape helpers --------------------------------------------------- */ function esc(s) { return String(s).replace(/[&<>"']/g, function (c) { return { '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' }[c]; }); } /* ---- inline SVG icons (no external dep, mobile-robust) ---------------- */ var ICON = { wallet: '', deposit: '', key: '' /* (kept for the reveal banner; key card moved to the hero) */, alert: '' }; /* ---- copy-to-clipboard with feedback ---------------------------------- */ function copyButton(text) { var btn = document.createElement('button'); btn.type = 'button'; btn.className = 'copy-btn'; btn.textContent = 'Copy'; btn.addEventListener('click', function () { navigator.clipboard.writeText(text).then(function () { btn.classList.add('copied'); btn.textContent = 'Copied!'; setTimeout(function () { btn.classList.remove('copied'); btn.textContent = 'Copy'; }, 1500); }).catch(function () { // fallback for non-secure contexts var ta = document.createElement('textarea'); ta.value = text; document.body.appendChild(ta); ta.select(); try { document.execCommand('copy'); btn.classList.add('copied'); btn.textContent = 'Copied!'; } catch (e) {} document.body.removeChild(ta); setTimeout(function () { btn.classList.remove('copied'); btn.textContent = 'Copy'; }, 1500); }); }); return btn; } /* ---- render the key-reveal banner (first signup only) --------------- */ function renderKeyReveal(plaintextKey) { var banner = document.createElement('div'); banner.className = 'key-reveal'; banner.setAttribute('role', 'alert'); banner.innerHTML = '' + '
Here’s your key. It’s sk- + your deposit address, so you can always find it again on the dashboard — no need to panic if you lose it. Use it as Authorization: Bearer for API calls outside the browser.
' + esc(plaintextKey) + '' +
'' + esc(billing.deposit_address) + '';
var depCopy = copyButton(billing.deposit_address);
depCopy.style.marginTop = '.4rem';
depCard.appendChild(depCopy);
grid.innerHTML = '';
grid.appendChild(balCard);
grid.appendChild(depCard);
// trigger the flash animation
if (flash && !reduceMotion) {
var val = balCard.querySelector('.bc-value');
void val.offsetWidth; // force reflow
val.classList.add('flash');
}
}
/* ---- render the "out of credits" state -------------------------------- */
function renderEmpty() {
grid.innerHTML =
'