From 74654f1aa41e5e79ce228621615ccdcf03be2b0a Mon Sep 17 00:00:00 2001 From: Bryan Brooks Date: Wed, 7 Jan 2026 09:33:38 -0600 Subject: [PATCH] fix: use single quotes for SQLite datetime('now') keyword SQLite interprets double quotes as identifiers (column names), not string literals. This caused cleanupExpiredSessions() to fail with: "no such column: now" Changed datetime("now") to datetime('now') to properly reference the SQLite datetime function's special 'now' keyword. --- gateway/src/services/database.ts | 36 +++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/gateway/src/services/database.ts b/gateway/src/services/database.ts index 9448d01..cb6fc6b 100644 --- a/gateway/src/services/database.ts +++ b/gateway/src/services/database.ts @@ -190,7 +190,7 @@ export class DatabaseService { } cleanupExpiredSessions(): number { - const stmt = this.db.prepare('DELETE FROM sessions WHERE expires_at < datetime("now")'); + const stmt = this.db.prepare("DELETE FROM sessions WHERE expires_at < datetime('now')"); const result = stmt.run(); return result.changes; } @@ -254,6 +254,40 @@ export class DatabaseService { return result.changes; } + // Admin methods for listing and managing apps + getAllApps(): Omit[] { + const stmt = this.db.prepare( + 'SELECT id, name, token_ttl_seconds, callback_url, created_at FROM apps ORDER BY created_at DESC' + ); + return stmt.all() as Omit[]; + } + + deleteApp(appId: string): void { + // Delete in order respecting foreign keys + this.db.prepare('DELETE FROM oauth_states WHERE app_id = ?').run(appId); + this.db.prepare('DELETE FROM sessions WHERE app_id = ?').run(appId); + this.db.prepare('DELETE FROM user_mappings WHERE app_id = ?').run(appId); + this.db.prepare('DELETE FROM apps WHERE id = ?').run(appId); + } + + getStats(): { appCount: number; activeSessions: number; pendingOAuthStates: number } { + const appCount = ( + this.db.prepare('SELECT COUNT(*) as count FROM apps').get() as { count: number } + ).count; + + const activeSessions = ( + this.db + .prepare("SELECT COUNT(*) as count FROM sessions WHERE expires_at > datetime('now')") + .get() as { count: number } + ).count; + + const pendingOAuthStates = ( + this.db.prepare('SELECT COUNT(*) as count FROM oauth_states').get() as { count: number } + ).count; + + return { appCount, activeSessions, pendingOAuthStates }; + } + close(): void { this.db.close(); } -- knotmirror 0.0.1