diff --git a/server/plugins/04.redis.ts b/server/plugins/04.redis.ts new file mode 100644 index 0000000..46c7d34 --- /dev/null +++ b/server/plugins/04.redis.ts @@ -0,0 +1,5 @@ +import { getRedis } from "../utils/redis"; + +export default defineNitroPlugin(() => { + getRedis(); +}); diff --git a/server/utils/redis.ts b/server/utils/redis.ts new file mode 100644 index 0000000..5ad3e73 --- /dev/null +++ b/server/utils/redis.ts @@ -0,0 +1,19 @@ +import Redis from "ioredis"; + +let client: Redis | null = null; + +export function getRedis(): Redis { + if (client) return client; + const url = process.env.REDIS_URL; + if (!url) { + throw new Error("REDIS_URL is required"); + } + client = new Redis(url, { maxRetriesPerRequest: 2 }); + return client; +} + +export async function closeRedis(): Promise { + if (!client) return; + await client.quit(); + client = null; +} diff --git a/server/utils/session-cookie.ts b/server/utils/session-cookie.ts new file mode 100644 index 0000000..552d5d0 --- /dev/null +++ b/server/utils/session-cookie.ts @@ -0,0 +1,37 @@ +import type { H3Event } from "h3"; +import { getCookie, setCookie, deleteCookie } from "h3"; + +export const SESSION_COOKIE_NAME = "pp_session"; + +export function readSessionIdFromCookie(event: H3Event): string | undefined { + return getCookie(event, SESSION_COOKIE_NAME); +} + +export function writeSessionCookie( + event: H3Event, + sessionId: string, + maxAgeSeconds: number, +): void { + const secure = process.env.NODE_ENV === "production"; + const domain = process.env.COOKIE_DOMAIN?.trim() || undefined; + setCookie(event, SESSION_COOKIE_NAME, sessionId, { + httpOnly: true, + sameSite: "lax", + secure, + path: "/", + maxAge: maxAgeSeconds, + domain, + }); +} + +export function clearSessionCookie(event: H3Event): void { + const secure = process.env.NODE_ENV === "production"; + const domain = process.env.COOKIE_DOMAIN?.trim() || undefined; + deleteCookie(event, SESSION_COOKIE_NAME, { + path: "/", + httpOnly: true, + sameSite: "lax", + secure, + domain, + }); +}