diff options
| author | Adam Soltys <[email protected]> | 2026-10-02 23:20:42 -0700 |
|---|---|---|
| committer | Adam Soltys <[email protected]> | 2026-10-02 23:20:42 -0700 |
| commit | d4d5a8b65dde249bc6eb27b7c120b7f5c9b238fe (patch) | |
| tree | 127276077dc776827ee73c90bf8166dc27cc03be /tools | |
| parent | 9e12335231f3fa4c4222bea71c4a1737a15a4994 (diff) | |
| download | coinosv3-d4d5a8b65dde249bc6eb27b7c120b7f5c9b238fe.tar.gz coinosv3-d4d5a8b65dde249bc6eb27b7c120b7f5c9b238fe.zip | |
Zaps find lightning addresses our relays have pruned
Zapping a post looked the author's lightning address up on our four home
relays only. Those prune old events, so anyone whose kind 0 hadn't changed
in a while (1776, Brad Mills) came back as "no Lightning address or Ark
address" — while their profile page, which also asks the index relays and
the author's own relays, showed the address right there. The zap lookup
now asks both ways at once and takes whichever carries a lightning address.
And when someone does have one but Lightning can't be paid right now, the
toast says that instead of claiming they have no address.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01VKv2uEFRR42Gp6NyqcN3A9
Diffstat (limited to 'tools')
| -rw-r--r-- | tools/zap-deep-profile-test.js | 56 |
1 files changed, 56 insertions, 0 deletions
diff --git a/tools/zap-deep-profile-test.js b/tools/zap-deep-profile-test.js new file mode 100644 index 0000000..555b54c --- /dev/null +++ b/tools/zap-deep-profile-test.js @@ -0,0 +1,56 @@ +// A zap must find the author's lightning address even when our relays have +// pruned their kind 0 — the profile page already finds it through index +// relays and the author's own relays; the zap path has to look there too. +// +// Live: real relays, a throwaway mainnet wallet (no funds, so the zap stops +// at "not enough in Spending" — past the address lookup, which is the point). +// +// Run: bun tools/zap-deep-profile-test.js +import puppeteer from 'puppeteer-core'; +import { generateMnemonic } from '@scure/bip39'; +import { wordlist } from '@scure/bip39/wordlists/english'; +import { buildHtml } from '../build.js'; + +// 1776: a kind 0 with lud16 that none of our home relays still carry (2026-10-02) +const NPUB = 'npub1e7dj5ymf5nxezvnrnvf6uwfqp4crqschn2q5apjga8jngzfhamqsemfw7d'; +const sleep = (ms) => new Promise((r) => setTimeout(r, ms)); +let ok = true; +const check = (n, c, d = '') => { console.log(` ${c ? '✓' : '✗'} ${n}${d ? ' — ' + d : ''}`); if (!c) ok = false; }; + +const html = await buildHtml({ minify: true, pwa: false }); +const server = Bun.serve({ port: 5253, fetch: () => new Response(html, { headers: { 'content-type': 'text/html' } }) }); +const browser = await puppeteer.launch({ executablePath: '/usr/bin/google-chrome', headless: 'new', args: ['--no-sandbox'] }); +const page = await browser.newPage(); +await page.setViewport({ width: 420, height: 900 }); +const click = (sel, t) => page.evaluate((s, x) => { const e = [...document.querySelectorAll(s)].find((n) => n.textContent.trim().toLowerCase().includes(x.toLowerCase())); if (e) { e.click(); return true; } return false; }, sel, t); +const text = () => page.evaluate(() => document.body.innerText); +const until = async (fn, ms) => { const end = Date.now() + ms; for (;;) { const v = await fn(); if (v) return v; if (Date.now() > end) return null; await sleep(400); } }; + +try { + await page.goto('http://localhost:5253/', { waitUntil: 'domcontentloaded' }); + await sleep(500); + await click('button', 'Create a new wallet'); await sleep(300); + await click('button', 'Have an existing seed'); await sleep(300); + await page.waitForSelector('textarea'); + await page.type('textarea', generateMnemonic(wordlist)); + await click('button', 'Open wallet'); + await until(async () => /receive|not now/i.test(await text()), 20000); + for (let i = 0; i < 3 && await click('button', 'Not now'); i++) await sleep(600); + await page.goto('http://localhost:5253/' + NPUB, { waitUntil: 'domcontentloaded' }); + check('their profile shows the lightning address', !!await until(async () => /fervidwage316/.test(await text()), 30000)); + const zapBtn = await until(() => page.$('.note-actions .zap, button.zap, [aria-label*="zap" i]'), 20000); + check('a post with a zap button', !!zapBtn); + if (zapBtn) { + await zapBtn.click(); + // whatever the zap ends in, it says so in a toast or on the zap screen + const said = await until(() => page.evaluate(() => { + const t = [...document.querySelectorAll('.toast, .notice')].map((n) => n.textContent.trim()).filter(Boolean).join(' | '); + return t || null; + }), 30000); + check('the zap gets past the address lookup', !!said && !/no Lightning address or Ark/.test(said), said || 'nothing said'); + } +} catch (e) { console.log(e); ok = false; } +await browser.close(); +server.stop(); +console.log(ok ? '\nall passed' : '\nFAILED'); +process.exit(ok ? 0 : 1); |
