diff --git a/src/services/chat/matrix/token-extractor.ts b/src/services/chat/matrix/token-extractor.ts index ad16bec..ac60ce4 100644 --- a/src/services/chat/matrix/token-extractor.ts +++ b/src/services/chat/matrix/token-extractor.ts @@ -102,11 +102,27 @@ export async function extractMatrixCredentials( page.on('request', onRequest); - logger.info('[matrix] loading chat.reddit.com to capture access token...'); - await page.goto('https://chat.reddit.com/', { - waitUntil: 'domcontentloaded', - timeout: 30_000, - }); + // Reddit now redirects `chat.reddit.com` → `www.reddit.com/chat/`. Going + // direct to the canonical URL avoids one redirect hop and means the + // session cookie the bot already has for www.reddit.com is applied to + // the very first request, rather than only after a cross-subdomain + // bounce that's been bouncing logged-in sessions to the login wall. + // + // We start the navigation but don't await it — the request listener + // resolves credsPromise the moment the SPA fires off its first authed + // call to matrix.redditspace.com, which may happen well before the page + // reaches `networkidle`. Awaiting goto would block past that point. + logger.info('[matrix] loading www.reddit.com/chat/ to capture access token...'); + void page + .goto('https://www.reddit.com/chat/', { + waitUntil: 'domcontentloaded', + timeout: timeoutMs, + }) + .catch((err) => { + logger.warn( + `[matrix] page.goto error (ignored, still listening): ${err instanceof Error ? err.message : String(err)}`, + ); + }); const timeout = new Promise((_, reject) => setTimeout( diff --git a/src/web/routes/debug.ts b/src/web/routes/debug.ts index 2fd9fcf..2837d46 100644 --- a/src/web/routes/debug.ts +++ b/src/web/routes/debug.ts @@ -21,6 +21,45 @@ export function createDebugRouter(ctx: WebContext): Router { res.sendFile(p); }); + // Dumps the browser context's cookies (names + metadata only — values are + // hashed) so we can tell which session/OAuth cookies are set after the + // auto-login and which the chat surface might be missing. + router.get('/debug/cookies', async (req, res) => { + const browser = ctx.services.browser; + if (!browser) { + res.status(500).json({ error: 'Browser client not initialized' }); + return; + } + const context = browser.getContext(); + if (!context) { + res.status(500).json({ error: 'Browser context not available' }); + return; + } + try { + const reveal = req.query.reveal === '1'; + const urls = ['https://www.reddit.com', 'https://chat.reddit.com', 'https://matrix.redditspace.com']; + const out: Record = {}; + for (const u of urls) { + const cookies = await context.cookies(u); + out[u] = cookies.map((c) => ({ + name: c.name, + domain: c.domain, + path: c.path, + httpOnly: c.httpOnly, + secure: c.secure, + sameSite: c.sameSite, + expires: c.expires, + valueLen: c.value.length, + value: reveal ? c.value : undefined, + })); + } + res.json(out); + } catch (error) { + ctx.logger.error('Cookie dump failed:', error); + res.status(500).json({ error: String(error) }); + } + }); + router.post('/debug/inspect-dom', async (req, res) => { if (!ctx.services.chat) { res.status(500).json({ error: 'Chat service not initialized' });