const { chromium } = require('playwright');
const fs = require('node:fs');
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
async function resolveDeclineCode(arg) {
if (!arg) return undefined;
if (!arg.startsWith('@')) return arg; const logPath = arg.slice(1);
for (let i = 0; i < 100; i++) {
try {
const txt = fs.readFileSync(logPath, 'utf8');
const m = txt.match(/[a-z]+-[a-z]+-[0-9]{3,5}/i);
if (m) return m[0];
} catch { }
await sleep(300);
}
throw new Error('decline sender never minted a code');
}
(async () => {
const url = process.argv[2] || 'http://127.0.0.1:8077/';
const code = process.argv[3];
const declineArg = process.argv[4];
const browser = await chromium.launch({ headless: true });
const page = await (await browser.newContext()).newPage();
page.on('pageerror', (e) => console.log('[page-error]', String(e).slice(0, 200)));
await page.goto(url, { waitUntil: 'networkidle' });
console.log('[pw] app loaded');
await page.getByText('pair with code', { exact: true }).first().click();
await page.getByPlaceholder('ENTER CODE').fill(code);
await page.getByText('pair', { exact: true }).first().click();
console.log('[pw] code submitted');
const remember = page.getByText('remember', { exact: true }).first();
await remember.waitFor({ timeout: 60000 });
const before = await page.evaluate(() => localStorage.getItem('filament-known-devices') || '[]');
if (JSON.parse(before).length > 0) throw new Error('secret stored BEFORE consent');
await remember.click();
console.log('[pw] consent given');
await page.waitForFunction(() => {
try { return JSON.parse(localStorage.getItem('filament-known-devices') || '[]').length > 0 } catch { return false }
}, { timeout: 15000 });
console.log('[pw] SECRET STORED');
const accept1 = page.getByText('accept', { exact: true }).first();
await accept1.waitFor({ timeout: 60000 });
await accept1.click();
await page.getByText('save', { exact: true }).first().waitFor({ timeout: 60000 });
console.log('[pw] PHASE1 COMPLETE');
const accept2 = page.getByText('accept', { exact: true }).first();
await accept2.waitFor({ timeout: 90000 });
await accept2.click();
await page.waitForFunction(() => {
const saves = [...document.querySelectorAll('*')]
.filter((e) => e.childElementCount === 0 && e.textContent.trim() === 'save')
return saves.length >= 2
}, { timeout: 60000 });
console.log('[pw] PHASE2 COMPLETE (channel rendezvous, no code)');
if (declineArg) {
await sleep(6000) const declineCode = await resolveDeclineCode(declineArg)
await page.getByText('← back to nearby', { exact: true }).first().click();
await page.getByText('pair with code', { exact: true }).first().click();
await page.getByPlaceholder('ENTER CODE').fill(declineCode);
await page.getByText('pair', { exact: true }).first().click();
const notNow = page.getByText('not now', { exact: true }).first();
await notNow.waitFor({ timeout: 60000 });
await notNow.click();
await new Promise((r) => setTimeout(r, 2500)) console.log('[pw] PHASE3 DECLINED');
}
await browser.close();
process.exit(0);
})().catch((e) => {
console.error('[pw] FAILED:', String(e).slice(0, 300));
process.exit(1);
});