v3: code quality pass, various bug fixes

This commit is contained in:
khannurien
2026-03-23 07:47:49 +00:00
parent d94a319d96
commit fbbbb43258
44 changed files with 1060 additions and 698 deletions

10
api/lib/auth.ts Normal file
View File

@@ -0,0 +1,10 @@
import type { Context } from "@oak/oak";
import { verifyJWT } from "./jwt.ts";
/** Extracts the userId from an optional Bearer token. Returns null if absent or invalid. */
export async function parseOptionalAuth(ctx: Context): Promise<string | null> {
const authHeader = ctx.request.headers.get("Authorization");
if (!authHeader?.startsWith("Bearer ")) return null;
const payload = await verifyJWT(authHeader.substring(7));
return payload?.userId ?? null;
}

View File

@@ -8,8 +8,13 @@ import {
isInvitePayload,
} from "../model/interfaces.ts";
const JWT_SECRET = "FIXME-gerbeur-dev-env";
const JWT_KEY = new TextEncoder().encode(JWT_SECRET);
const jwtSecret = Deno.env.get("JWT_SECRET");
if (!jwtSecret) {
throw new Error(
"JWT_SECRET environment variable is required. Generate one with: openssl rand -hex 32",
);
}
const JWT_KEY = new TextEncoder().encode(jwtSecret);
// ── Invite tokens ─────────────────────────────────────────────────────────────

22
api/lib/pagination.ts Normal file
View File

@@ -0,0 +1,22 @@
/**
* Parses page/limit query parameters with sensible defaults and bounds.
* page: clamped to [1, ∞)
* limit: clamped to [1, 100], defaults to 20
*/
export function parsePagination(
params: URLSearchParams,
defaultLimit = 20,
): { page: number; limit: number } {
const page = Math.max(
1,
parseInt(params.get("page") ?? "1") || 1,
);
const limit = Math.min(
Math.max(
1,
parseInt(params.get("limit") ?? String(defaultLimit)) || defaultLimit,
),
100,
);
return { page, limit };
}