import { timingSafeEqual } from 'node:crypto'; import type { NextRequest } from 'next/server'; export const LEARNING_ENGINE_TOKEN_ENV = 'LEARNING_ENGINE_TOKEN'; export const LEGACY_LEARNING_ENGINE_TOKEN_ENV = 'MAKELORE_RUNTIME_TOKEN'; /** * Server-to-server credential for the private Learning Engine API. * * LEARNING_ENGINE_TOKEN is the canonical deployment name shared with Works * Square. MAKELORE_RUNTIME_TOKEN remains a migration alias so existing private * deployments can rotate without downtime. */ export function configuredLearningRuntimeToken(): string | undefined { return ( process.env[LEARNING_ENGINE_TOKEN_ENV]?.trim() || process.env[LEGACY_LEARNING_ENGINE_TOKEN_ENV]?.trim() || undefined ); } export function authorizeLearningRuntime(request: NextRequest): boolean { const expected = configuredLearningRuntimeToken(); const header = request.headers.get('authorization') || ''; const received = header.startsWith('Bearer ') ? header.slice(7).trim() : ''; if (!expected || !received) return false; const expectedBytes = Buffer.from(expected); const receivedBytes = Buffer.from(received); return expectedBytes.length === receivedBytes.length && timingSafeEqual(expectedBytes, receivedBytes); } export function runtimeUnauthorized(): Response { return Response.json({ error: 'unauthorized' }, { status: 401 }); }