aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorAdam Soltys <[email protected]>2026-11-12 23:19:23 -0700
committerAdam Soltys <[email protected]>2026-11-12 23:19:23 -0700
commit5026227de10e424f590d2a042e5a8770266a6b5e (patch)
tree2692082e5ee8a4d7ca21f45fa3d837cb4c3eac93 /tools
parent5465eccfce94a53ad48cfdafbc90e7462d387840 (diff)
downloadcoinosv3-5026227de10e424f590d2a042e5a8770266a6b5e.tar.gz
coinosv3-5026227de10e424f590d2a042e5a8770266a6b5e.zip
A relay group joined on one device shows up on the others. "Not seeing the pyramid runners chat I joined and messaged in on my laptop appear on my phone" (Adam, 2026-11-12). The joined groups live in the kind 10009 list, but it was read once, when Messages started (a phone open in the background since before the join never looked again), and written only to the four home relays and the user's own, of which relay.coinos.io refused kind 10009 (allowed since, desk write-policy) and nos.lol and damus kept nothing: the laptop's list sat on primal and ditto alone, beside a stale copy on purplepag.es. Now the list is followed live (a limit-1 subscription on the home relays; a newer copy is adopted and its groups join the list here), read again whenever Messages resubscribes after an absence (at most every 30 s), always read deep (home, index and own relays) before a write, and published to all of those, so the newest copy is where any device looks. Groups dropped from the list elsewhere are still kept here. nip29-group-test: the same twelve words open a second browser, which follows the list live and shows the group once the laptop's signed list arrives on that subscription
Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01VMan6UKGJyuGyZFxddYRxS
Diffstat (limited to 'tools')
-rw-r--r--tools/nip29-group-test.js45
1 files changed, 45 insertions, 0 deletions
diff --git a/tools/nip29-group-test.js b/tools/nip29-group-test.js
index 2ff1192..9096a47 100644
--- a/tools/nip29-group-test.js
+++ b/tools/nip29-group-test.js
@@ -31,6 +31,7 @@ try {
await sleep(400);
await page.evaluate(() => [...document.querySelectorAll('button')].find((n) => /create a new wallet/i.test(n.textContent))?.click()); await sleep(600);
await seedWords(page);
+ const phrase = (await page.$$eval('.words .w .t', (l) => l.map((e) => e.textContent.trim()))).join(' ');
await skipSeedCheck(page);
await waitText('receive', 20000);
await page.click('[aria-label="Messages"]');
@@ -80,6 +81,50 @@ try {
for (let i = 0; i < 40 && !kept; i++) { kept = await page.evaluate(() => [...document.querySelectorAll('.chat-thread-row')].some((r) => r.textContent.includes('pyramid runners'))); if (!kept) await sleep(250); }
check('...and still is after a reload', kept);
+ // the same wallet on another device, already open: the laptop's list
+ // arrives on its live 10009 subscription and the group appears there
+ // ("Not seeing the pyramid runners chat I joined … on my laptop appear on
+ // my phone", Adam, 2026-11-12)
+ {
+ const ctx = await browser.createBrowserContext();
+ const p2 = await ctx.newPage();
+ p2.on('console', (m) => { if (process.env.DEBUG && /nip29|chat|10009/.test(m.text())) console.log(' [p2]', m.text()); });
+ p2.on('pageerror', (e) => errs.push('p2: ' + e));
+ await p2.evaluateOnNewDocument(() => {
+ window.__subs = [];
+ const send = WebSocket.prototype.send;
+ WebSocket.prototype.send = function (d) {
+ try { const m = JSON.parse(d); if (m[0] === 'REQ') window.__subs.push({ ws: this, id: m[1], filters: m.slice(2) }); } catch {}
+ return send.call(this, d);
+ };
+ });
+ const t2 = async (x, ms = 20000) => { for (let i = 0; i < ms / 250; i++) { if ((await p2.evaluate(() => document.body.innerText)).toLowerCase().includes(x)) return true; await sleep(250); } return false; };
+ await p2.setViewport({ width: 390, height: 844 });
+ await p2.goto(server.url.href, { waitUntil: 'domcontentloaded' });
+ await p2.evaluate(() => localStorage.setItem('btc-wallet-network', 'regtest'));
+ await p2.reload({ waitUntil: 'domcontentloaded' });
+ await t2('sign in to an existing account');
+ await p2.evaluate(() => document.getElementById('onb-signin')?.click()); await sleep(500);
+ await p2.evaluate(() => document.getElementById('onb-restore')?.click()); await sleep(600);
+ await p2.type('textarea[placeholder*="seed words" i]', phrase);
+ await p2.evaluate(() => [...document.querySelectorAll('button')].find((n) => /open wallet/i.test(n.textContent))?.click());
+ await t2('receive');
+ await p2.click('[aria-label="Messages"]'); await sleep(500);
+ let subbed = false;
+ for (let i = 0; i < 60 && !subbed; i++) { subbed = await p2.evaluate(() => window.__subs.some((x) => x.ws.readyState === 1 && x.filters.some((f) => (f.kinds || []).includes(10009) && f.limit === 1))); if (!subbed) await sleep(250); }
+ check('another device follows the 10009 list live', subbed);
+ const before = await p2.evaluate(() => [...document.querySelectorAll('.chat-thread-row')].some((r) => r.textContent.includes('pyramid runners')));
+ const fromLaptop = list; // the laptop's own signed list, from before its reload
+ await p2.evaluate((ev) => {
+ for (const x of window.__subs.filter((x) => x.ws.readyState === 1 && x.filters.some((f) => (f.kinds || []).includes(10009) && f.limit === 1)))
+ x.ws.dispatchEvent(new MessageEvent('message', { data: JSON.stringify(['EVENT', x.id, ev]) }));
+ }, fromLaptop);
+ let shown = false;
+ for (let i = 0; i < 60 && !shown; i++) { shown = await p2.evaluate(() => [...document.querySelectorAll('.chat-thread-row')].some((r) => r.textContent.includes('pyramid runners'))); if (!shown) await sleep(250); }
+ check('...and the group joined on the laptop appears there', !before && shown);
+ await ctx.close();
+ }
+
// leave: two taps, a 9022 to the relay, and off the list
await page.evaluate(() => [...document.querySelectorAll('.chat-thread-row')].find((r) => r.textContent.includes('pyramid runners'))?.click()); await sleep(800);
await page.click('[aria-label="Leave group"]'); await sleep(200);