import { safeCompare } from '@sim/security/compare' import { generateId } from '@sim/utils/id' import type { NextRequest } from 'next/server' import { NextResponse } from 'next/server' import { getSession } from '@/lib/auth' import { ASYNC_TOOL_CONFIRMATION_STATUS } from '@/lib/copilot/async-runs/lifecycle' import { env } from '@/lib/core/config/env' import { generateRequestId } from '@/lib/core/utils/request' export const NotificationStatus = { pending: 'pending', ...ASYNC_TOOL_CONFIRMATION_STATUS, } as const export type NotificationStatus = (typeof NotificationStatus)[keyof typeof NotificationStatus] export interface CopilotAuthResult { userId: string | null isAuthenticated: boolean } export function createUnauthorizedResponse(): NextResponse { return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }) } /** * Creates a 400 Bad Request response for non-validation errors (business rule * failures, missing entities, semantic mismatches). * * For Zod validation failures, use `validationErrorResponse` from * `@/lib/api/server` instead — it returns the canonical * `{ error, details: ZodIssue[] }` shape that lets clients introspect which * field failed. */ export function createBadRequestResponse(message: string): NextResponse { return NextResponse.json({ error: message }, { status: 400 }) } export function createForbiddenResponse(message: string): NextResponse { return NextResponse.json({ error: message }, { status: 403 }) } export function createNotFoundResponse(message: string): NextResponse { return NextResponse.json({ error: message }, { status: 404 }) } export function createInternalServerErrorResponse(message: string): NextResponse { return NextResponse.json({ error: message }, { status: 500 }) } export function createRequestId(): string { return generateId() } function createShortRequestId(): string { return generateRequestId() } export interface RequestTracker { requestId: string startTime: number getDuration(): number } export function createRequestTracker(short = true): RequestTracker { const requestId = short ? createShortRequestId() : createRequestId() const startTime = Date.now() return { requestId, startTime, getDuration(): number { return Date.now() - startTime }, } } export async function authenticateCopilotRequestSessionOnly(): Promise { const session = await getSession() const userId = session?.user?.id || null return { userId, isAuthenticated: userId !== null, } } export function checkInternalApiKey(req: NextRequest) { const apiKey = req.headers.get('x-api-key') const expectedApiKey = env.INTERNAL_API_SECRET if (!expectedApiKey) { return { success: false, error: 'Internal API key not configured' } } if (!apiKey) { return { success: false, error: 'API key required' } } if (!safeCompare(apiKey, expectedApiKey)) { return { success: false, error: 'Invalid API key' } } return { success: true } }