You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Two unrelated frontend fixes in index.html:
1. Mojibake repair. cp1252 round-trip corruption had mangled several
UI glyphs in committed/deployed markup:
a-back-arrow -> back arrow
globe -> globe with meridians
warning -> warning sign + VS16
stopwatch -> stopwatch
lock -> closed lock with key
hourglass -> hourglass done
info -> information source + VS16
Repaired by byte-exact replacement of only the corrupted spans, so
already-clean glyphs (checkmark, ellipsis, arrows, approx) are untouched.
Verified: 0 mojibake markers remain; inline script still parses.
2. Guard the Privy signAndBroadcast path. It called r.json() unconditionally,
so an HTML error response surfaced the opaque
"Unexpected token '<', "<!DOCTYPE "... is not valid JSON".
Now catches a non-JSON body and throws a clear HTTP-status error instead
(mirrors the Keplr broadcast path's .catch guard). Pairs with the
server-side JSON error handler so these responses are JSON anyway.
<div class="import-form-title">Sign in with email</div>
5477
5477
<div class="import-form-sub">
5478
5478
Enter your email. Privy will send a one-time code, then create or unlock an embedded Sentinel wallet for your account. Powered by <a href="https://privy.io" target="_blank" rel="noopener" style="color:var(--accent)">Privy</a>.
@@ -5483,7 +5483,7 @@ <h1 class="mobile-gate-title">View on Desktop</h1>
<div class="import-form-title">Sign in with recovery phrase</div>
5488
5488
<div class="import-form-sub">
5489
5489
Paste your 12 or 24-word mnemonic. It is encrypted with AES-256-GCM and stored only in an httpOnly cookie scoped to your browser. The server never writes plaintext to disk.
@@ -7573,7 +7573,14 @@ <h3 id="securityFaqTitle">
7573
7573
accountNumber: signDoc.accountNumber,
7574
7574
}),
7575
7575
});
7576
-
return await r.json();
7576
+
// Guard against non-JSON responses (e.g. an HTML error page from a
7577
+
// body-parser/413/404 failure) — calling r.json() on HTML throws the
7578
+
// opaque "Unexpected token '<', "<!DOCTYPE "... is not valid JSON".
7579
+
const out = await r.json().catch(() => null);
7580
+
if (out === null) {
7581
+
throw new Error(`Server returned a non-JSON response (HTTP ${r.status}). The request may have failed before reaching the signer.`);
7582
+
}
7583
+
return out;
7577
7584
}
7578
7585
if (!window.keplr) throw new Error('Keplr not available');
<div class="fiat-detail-section-sub">Node + Express. Set <code>STRIPE_SECRET_KEY</code> and <code>STRIPE_WEBHOOK_SECRET</code>, register the URL in your Stripe dashboard, ship.</div>
<div class="fiat-detail-callout-body"><strong><code>express.raw()</code> is required.</strong> If a JSON parser touches the body before <code>constructEvent</code>, the signature check will always fail.</div>
<div class="fiat-detail-section-sub">Zero infrastructure. Public REST. Poll a deposit address every 30s; fire once <code>vout</code> credits the address with the expected sats and the tx has cleared <code>CONFIRMATIONS</code> blocks. Quote each buyer a unique deposit address so you can map the settled payment back to their Sentinel wallet.</div>
<div class="fiat-detail-callout-body"><strong>Finality.</strong> 3 confirmations ≈ 30 min. Drop to 1 for low-value plans, raise to 6 for high-value.</div>
<div class="fiat-detail-section-sub"><code>ethers</code> v6 against any public JSON-RPC (Alchemy, Infura, or <code>ethereum-rpc.publicnode.com</code>). For USDC, filter the <code>Transfer</code> event on the contract by your deposit address. For native ETH, walk every new block. <code>tx.wait(N)</code> blocks until <code>N</code> confirmations land before triggering Plan Manager. Map the depositor to their Sentinel wallet (a unique deposit address per buyer is simplest) before delivering.</div>
<div class="fiat-detail-section-sub"><code>@solana/web3.js</code> v1 against <code>api.mainnet-beta.solana.com</code> at <code>'finalized'</code> — 31 slots, supermajority vote, the strongest guarantee Solana offers. <code>onAccountChange</code> fires on every lamport delta. For USDC, derive the associated token account via <code>@solana/spl-token</code> and watch its logs. Map the payer to their Sentinel wallet (a unique deposit address per buyer is simplest) before delivering.</div>
<div style="font-family:var(--font-display);font-weight:600;font-size:13.5px;color:var(--text)">Not subscribed to plan #${escapeHtml(String(planId))} yet</div>
11379
11386
<div style="font-family:var(--font-display);font-size:12.5px;color:var(--text-muted);margin-top:3px">You hold no subscription to this plan. You can self-subscribe now to mint a bandwidth allocation, or just add a subscriber below — that self-subscribes you automatically before sharing their allocation.</div>
0 commit comments