import { NextResponse } from 'next/server'; /** * Sets cache prevention headers to prevent CDN/proxy caching. * @param headers - The Headers object to set the cache prevention headers on. */ export function setCachePreventionHeaders(headers: Headers): void { headers.set('Cache-Control', 'private, no-cache, no-store, must-revalidate, max-age=0'); headers.set('x-middleware-cache', 'no-cache'); } export function redirectWithFallback(redirectUri: string, headers?: Headers) { const newHeaders = headers ? new Headers(headers) : new Headers(); newHeaders.set('Location', redirectUri); // Fall back to standard Response if NextResponse is not available. // This is to support Next.js 13. return NextResponse?.redirect ? NextResponse.redirect(redirectUri, { headers }) : new Response(null, { status: 307, headers: newHeaders }); } export function errorResponseWithFallback(errorBody: { error: { message: string; description: string } }) { // Fall back to standard Response if NextResponse is not available. // This is to support Next.js 13. return NextResponse?.json ? NextResponse.json(errorBody, { status: 500 }) : new Response(JSON.stringify(errorBody), { status: 500, headers: { 'Content-Type': 'application/json' }, }); } type EvaluateRecentAuthParameters = { authTime: unknown; maxAgeSeconds: number; nowSeconds: number; }; /** * Evaluate whether an authentication is recent enough. * * Fails closed: a missing or non-finite `authTime` is reported as stale. A * future `authTime` (clock skew) is treated as recent rather than stale, and * the `maxAge` boundary is inclusive. */ export function evaluateRecentAuth({ authTime, maxAgeSeconds, nowSeconds }: EvaluateRecentAuthParameters) { if (typeof authTime !== 'number' || !Number.isFinite(authTime)) { return { authenticatedAt: null, isStale: true, } as const; } return { authenticatedAt: new Date(authTime * 1000), isStale: nowSeconds - authTime > maxAgeSeconds, } as const; } /** * Returns a function that can only be called once. * Subsequent calls will return the result of the first call. * This is useful for lazy initialization. * @param fn - The function to be called once. * @returns A function that can only be called once. */ export function lazy(fn: (...args: TArgs) => TResult): (...args: TArgs) => TResult { let called = false; let result: TResult; return (...args: TArgs) => { if (!called) { result = fn(...args); called = true; } return result; }; }