Show Reddit recovery status in dashboard

This commit is contained in:
jjbrunton committed 2026-08-08 14:42:19 +01:00
1 parent d2b3a1b31d
commit 316dc3dd3e
6 files changed
+208 -5

No files matched your search

+27 -1
View File
@@ -4,10 +4,24 @@ import type { Logger } from '../utils/logger.js';
import path from 'path';
import fs from 'fs';
export type RedditSessionState =
| 'unknown'
| 'authenticated'
| 'login-required'
| 'unreachable';
export function classifyRedditSessionError(error: unknown): Exclude<RedditSessionState, 'unknown' | 'authenticated'> {
const message = error instanceof Error ? error.message : String(error);
return /ERR_(?:HTTP_RESPONSE_CODE_FAILURE|CONNECTION|TIMED_OUT|NAME_NOT_RESOLVED|NETWORK_CHANGED)|net::|ENOTFOUND|ECONN(?:REFUSED|RESET)|fetch failed/i.test(message)
? 'unreachable'
: 'login-required';
}
export class BrowserClient {
private context: BrowserContext | null = null;
private sessionDir: string | null = null;
private sessionValidityInFlight: Promise<boolean> | null = null;
private sessionState: RedditSessionState = 'unknown';
constructor(
private config: Config,
@@ -51,6 +65,10 @@ export class BrowserClient {
return this.context;
}
getSessionState(): RedditSessionState {
return this.sessionState;
}
async close(): Promise<void> {
if (this.context) {
this.logger.info('Closing browser');
@@ -85,6 +103,7 @@ export class BrowserClient {
for (const selector of visibleIndicators) {
const el = page.locator(selector).first();
if (await el.isVisible().catch(() => false)) {
this.sessionState = 'authenticated';
return true;
}
}
@@ -97,13 +116,17 @@ export class BrowserClient {
for (const selector of attributeIndicators) {
const el = await page.$(selector);
if (el) {
this.sessionState = 'authenticated';
return true;
}
}
// Fallback to a direct auth check; this avoids false negatives from hidden login buttons.
return await this.isLoggedInViaApi(page);
const loggedIn = await this.isLoggedInViaApi(page);
this.sessionState = loggedIn ? 'authenticated' : 'login-required';
return loggedIn;
} catch (error) {
this.sessionState = classifyRedditSessionError(error);
this.logger.error('Failed to check session validity:', error);
return false;
}
@@ -128,6 +151,7 @@ export class BrowserClient {
async login(): Promise<boolean> {
if (!this.config.reddit.username || !this.config.reddit.password) {
this.sessionState = 'login-required';
this.logger.error('Login failed: Missing credentials in config/env');
return false;
}
@@ -202,6 +226,7 @@ export class BrowserClient {
const isValid = await this.isSessionValid();
if (isValid) {
this.sessionState = 'authenticated';
this.logger.info('Login successful!');
return true;
}
@@ -236,6 +261,7 @@ export class BrowserClient {
return false;
} catch (error) {
this.sessionState = classifyRedditSessionError(error);
this.logger.error('Error during automated login:', error);
return false;
}