Don't crash bootstrap on Matrix token capture failure

If chat.reddit.com sniffing fails, fall through with a placeholder
credential set so the post-monitoring/processor side of the bot
(and the web UI) stay up. Chat features are disabled until the
next successful token refresh.

Also dump diagnostics on sniff timeout: final page URL, every host
the page touched (with request counts + whether any carried an
Authorization header), and a full-page screenshot to data/matrix-debug.png.
This makes the three failure modes (page didn't load / loaded but
never hit Matrix / hit Matrix without auth) distinguishable from logs.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
jjbruntonandClaude Opus 4.7 committed 2026-05-22 21:09:38 +01:00
1 parent 665ff8b1f3
commit 4a3b44bc87
2 files changed
+58 -5

No files matched your search

+39 -4
View File
@@ -66,15 +66,25 @@ export async function extractMatrixCredentials(
});
let done = false;
// Track every host the page touches so we can tell, on timeout, whether
// chat.reddit.com failed to load at all, loaded but never reached the
// Matrix homeserver, or reached it but without a bearer header.
const seenHosts = new Map<string, { count: number; sawAuth: boolean }>();
const onRequest = (request: import('playwright').Request) => {
if (done) return;
try {
const url = new URL(request.url());
if (!MATRIX_HOST_RE.test(url.hostname)) return;
const isMatrix = MATRIX_HOST_RE.test(url.hostname);
const headers = request.headers();
const auth = headers['authorization'] || headers['Authorization'];
if (!auth || !auth.toLowerCase().startsWith('bearer ')) return;
const token = auth.slice('bearer '.length).trim();
const hasAuth = !!auth && auth.toLowerCase().startsWith('bearer ');
const entry = seenHosts.get(url.hostname) ?? { count: 0, sawAuth: false };
entry.count += 1;
if (hasAuth) entry.sawAuth = true;
seenHosts.set(url.hostname, entry);
if (!isMatrix) return;
if (!hasAuth) return;
const token = auth!.slice('bearer '.length).trim();
if (!token) return;
const homeserver = `${url.protocol}//${url.host}`;
done = true;
@@ -105,7 +115,32 @@ export async function extractMatrixCredentials(
),
);
const captured = await Promise.race([credsPromise, timeout]);
let captured: MatrixCredentials;
try {
captured = await Promise.race([credsPromise, timeout]);
} catch (err) {
// On timeout, surface enough info to tell the three failure modes apart:
// (a) chat.reddit.com never loaded → page.url() still about:blank, almost no hosts
// (b) page loaded, no Matrix host hit → reddit hosts present, no matrix.*
// (c) Matrix hit, but no Authorization → matrix.* present with sawAuth: false
try {
const finalUrl = page.url();
const hostSummary = Array.from(seenHosts.entries())
.map(([host, info]) => `${host}=${info.count}${info.sawAuth ? '*' : ''}`)
.join(', ');
logger.error(
`[matrix] timeout diagnostics: finalUrl=${finalUrl} hosts=[${hostSummary || 'none'}]`,
);
const shotDir = path.dirname(cachePath);
if (!fs.existsSync(shotDir)) fs.mkdirSync(shotDir, { recursive: true });
const shotPath = path.join(shotDir, 'matrix-debug.png');
await page.screenshot({ path: shotPath, fullPage: true }).catch(() => undefined);
logger.error(`[matrix] saved debug screenshot to ${shotPath}`);
} catch (diagErr) {
logger.warn('[matrix] failed to collect timeout diagnostics:', diagErr);
}
throw err;
}
// Resolve the user_id by calling /whoami so the caller knows who we are.
const whoamiRes = await fetchWithTimeout(