import { after, type NextRequest } from 'next/server'; import { nanoid } from 'nanoid'; import { createCourse, runCourseFrameworkGeneration } from '@/lib/course-framework/runner'; import { authorizeLearningRuntime, runtimeUnauthorized } from '@/lib/makelore-runtime/auth'; import { LEARNING_GENERATION_CONTRACT_VERSION, LearningGenerationRequestError, parseLearningGenerationRequest, } from '@/lib/makelore-runtime/generation-request'; import { createClassroomGenerationJob } from '@/lib/server/classroom-job-store'; import { runClassroomGenerationJob } from '@/lib/server/classroom-job-runner'; import { buildRequestOrigin } from '@/lib/server/classroom-storage'; export const maxDuration = 300; export async function POST(request: NextRequest) { if (!authorizeLearningRuntime(request)) return runtimeUnauthorized(); try { const generation = await parseLearningGenerationRequest(request); const jobId = nanoid(10); const baseUrl = buildRequestOrigin(request); if (generation.mode === 'large') { await createCourse(jobId, generation.input, { ownerPrincipalId: generation.ownerUserId, }); // Phase 1 only. The original Ops builder reviews the framework and calls // /api/courses/:id/start before the original per-module runner is used. after(() => runCourseFrameworkGeneration(jobId, baseUrl)); } else { await createClassroomGenerationJob(jobId, generation.input, { ownerPrincipalId: generation.ownerUserId, }); after(() => runClassroomGenerationJob(jobId, generation.input, baseUrl)); } return Response.json( { contractVersion: LEARNING_GENERATION_CONTRACT_VERSION, jobId, status: 'queued', mode: generation.mode, done: false, }, { status: 202 }, ); } catch (error) { if (error instanceof LearningGenerationRequestError) { return Response.json( { error: error.code, message: error.message }, { status: error.status }, ); } return Response.json( { error: 'generation_request_failed', message: error instanceof Error ? error.message : 'Generation request failed', }, { status: 500 }, ); } }