3 changed files with 59 additions and 0 deletions
@ -0,0 +1,37 @@ |
|||
import { getRedis } from "./redis"; |
|||
import { sessionTtlSeconds } from "./session-ttl"; |
|||
|
|||
export type SessionPayload = { |
|||
userId: number; |
|||
sessionVersion: number; |
|||
createdAt: string; |
|||
}; |
|||
|
|||
const sessionKey = (id: string) => `sess:${id}`; |
|||
|
|||
export async function createSession( |
|||
sessionId: string, |
|||
payload: SessionPayload, |
|||
): Promise<void> { |
|||
const redis = getRedis(); |
|||
const ttl = sessionTtlSeconds(); |
|||
await redis.set(sessionKey(sessionId), JSON.stringify(payload), "EX", ttl); |
|||
} |
|||
|
|||
export async function readSession( |
|||
sessionId: string, |
|||
): Promise<SessionPayload | null> { |
|||
const redis = getRedis(); |
|||
const raw = await redis.get(sessionKey(sessionId)); |
|||
if (!raw) return null; |
|||
try { |
|||
return JSON.parse(raw) as SessionPayload; |
|||
} catch { |
|||
return null; |
|||
} |
|||
} |
|||
|
|||
export async function deleteSession(sessionId: string): Promise<void> { |
|||
const redis = getRedis(); |
|||
await redis.del(sessionKey(sessionId)); |
|||
} |
|||
@ -0,0 +1,5 @@ |
|||
export function sessionTtlSeconds(): number { |
|||
const raw = process.env.SESSION_TTL_SECONDS; |
|||
const n = raw ? Number(raw) : NaN; |
|||
return Number.isFinite(n) && n > 0 ? n : 604800; |
|||
} |
|||
@ -0,0 +1,17 @@ |
|||
import { describe, expect, it, beforeEach } from "bun:test"; |
|||
import { sessionTtlSeconds } from "../../server/utils/session-ttl"; |
|||
|
|||
describe("sessionTtlSeconds", () => { |
|||
beforeEach(() => { |
|||
delete process.env.SESSION_TTL_SECONDS; |
|||
}); |
|||
|
|||
it("defaults to 7d", () => { |
|||
expect(sessionTtlSeconds()).toBe(604800); |
|||
}); |
|||
|
|||
it("respects env", () => { |
|||
process.env.SESSION_TTL_SECONDS = "120"; |
|||
expect(sessionTtlSeconds()).toBe(120); |
|||
}); |
|||
}); |
|||
Loading…
Reference in new issue