import { type NextRequest, NextResponse } from 'next/server'; import { isAuthorized, unauthorized } from './auth'; import { getServerLocaleMap } from './localeServer'; import { matchKeys } from './localization'; type RouteContext = { params: Promise> }; type Handler = (req: NextRequest, ctx: RouteContext) => Promise; /** * Wraps a route handler with auth checking and unified error handling. * * @example * export const GET = withAuth(async (req) => { * const rows = await pool.query('...'); * return NextResponse.json(rows); * }); */ export function withAuth(handler: Handler): Handler { return async (req, ctx) => { if (!isAuthorized(req)) return unauthorized(); try { return await handler(req, ctx); } catch (err) { console.error(err); return NextResponse.json({ error: 'Internal server error' }, { status: 500 }); } }; } /** * Builds a SQL WHERE clause fragment for item whitelist/blacklist filtering. * * - `isWhitelist=true`: `item_key ~* $N OR item_key = ANY($N+1)` (regex), `item_key = ANY($N)` (exact) * - `isWhitelist=false`: `item_key !~* $N AND item_key != ALL($N+1)` (regex), `item_key != ALL($N)` (exact) * * Mutates `values` and `param.current` to track parameter bindings. */ export function buildItemFilter( items: string[], useRegex: boolean, isWhitelist: boolean, values: unknown[], param: { current: number }, ): string | null { if (items.length === 0) return null; if (useRegex) { const localeMap = getServerLocaleMap(); const localeKeys = [...new Set(items.flatMap((p) => matchKeys(p, localeMap)))]; const sqlPattern = items.map((p) => `(${p})`).join('|'); if (isWhitelist) { const orConds: string[] = [`item_key ~* $${param.current++}`]; values.push(sqlPattern); if (localeKeys.length > 0) { orConds.push(`item_key = ANY($${param.current++})`); values.push(localeKeys); } return `(${orConds.join(' OR ')})`; } else { const andConds: string[] = [`item_key !~* $${param.current++}`]; values.push(sqlPattern); if (localeKeys.length > 0) { andConds.push(`item_key != ALL($${param.current++})`); values.push(localeKeys); } return `(${andConds.join(' AND ')})`; } } if (isWhitelist) { values.push(items); return `item_key = ANY($${param.current++})`; } else { values.push(items); return `item_key != ALL($${param.current++})`; } }