feat: add session idle timeout and concurrent session limit

Idle timeout: reads `sessionIdleTimeoutMinutes` from settings, tracks
last activity in Redis (with Postgres fallback on cache miss), and
invalidates sessions that exceed the configured idle window.

Concurrent session limit: reads `maxSessionsPerUser` from settings
and evicts oldest sessions (FIFO) when a new login exceeds the cap.

Both features are opt-in (disabled when value is 0 or absent).
This commit is contained in:
SnapOtter
2026-06-13 22:07:31 +08:00
parent 7ed043ec53
commit 3cc4ef6895
2 changed files with 73 additions and 1 deletions
+23
View File
@@ -0,0 +1,23 @@
import { eq } from "drizzle-orm";
import { db, schema } from "../db/index.js";
/**
* Read a numeric setting from the DB `settings` table.
* Returns `defaultValue` when the key is missing, non-numeric, or on DB error.
*/
export async function getSettingNumber(key: string, defaultValue = 0): Promise<number> {
try {
const result = await db
.select({ value: schema.settings.value })
.from(schema.settings)
.where(eq(schema.settings.key, key))
.limit(1);
if (result.length > 0) {
const num = Number(result[0].value);
if (!Number.isNaN(num)) return num;
}
} catch {
/* DB not ready or key absent -- fall through */
}
return defaultValue;
}