From 2298edf46e55e7078fc3b76b50fd188554fc09f2 Mon Sep 17 00:00:00 2001 From: Leo dev Date: Sun, 8 Feb 2026 13:40:59 +0100 Subject: [PATCH] /api/run for the vscode extension --- src/app/api/run/route.ts | 62 ++++++++++++++++++++++++++++++++++++ src/modules/account/core.ts | 8 ++--- src/modules/live-run/core.ts | 45 ++++++++++++++++++++++++++ 3 files changed, 109 insertions(+), 6 deletions(-) create mode 100644 src/app/api/run/route.ts diff --git a/src/app/api/run/route.ts b/src/app/api/run/route.ts new file mode 100644 index 0000000..50acf2f --- /dev/null +++ b/src/app/api/run/route.ts @@ -0,0 +1,62 @@ +import { NextRequest, NextResponse } from "next/server"; +import { createClient } from "@/lib/supabase/server"; +import * as Core from "@/modules/live-run/core"; +import { getSession } from "@/modules/account/core"; +import { randomUUID } from "crypto"; + +export async function PUT(req: NextRequest) { + const { problem, category } = await req.json(); + + if (!problem || !category) + return NextResponse.json( + { error: "body requires problem and category" }, + { status: 400 }, + ); + + const supabase = await createClient(); + + const session = await getSession(supabase); + + if (!session) + return NextResponse.json({ error: "Invalid session" }, { status: 401 }); + + const runId = randomUUID(); + + await Core.addRun({ + problem, + category, + id: runId, + username: session[1].username, + views: 0, + start: new Date().getTime(), + runsCount: 0, + }); + + return NextResponse.json({ ok: true, runId }); +} + +export async function POST(req: NextRequest) { + const { runId } = await req.json(); + + if (!runId) + return NextResponse.json({ error: "body requires runId" }, { status: 400 }); + + const supabase = await createClient(); + + const session = await getSession(supabase); + + if (!session) + return NextResponse.json({ error: "Invalid session" }, { status: 401 }); + + const run = await Core.getLiveRun(runId); + + if (!run) + return NextResponse.json( + { error: "Run is not live or does not exist" }, + { status: 401 }, + ); + + await Core.submitRun(supabase, run, session[0].id); + + return NextResponse.json({ ok: true, runId }); +} diff --git a/src/modules/account/core.ts b/src/modules/account/core.ts index 9ec4e7f..d250696 100644 --- a/src/modules/account/core.ts +++ b/src/modules/account/core.ts @@ -67,7 +67,7 @@ export async function getGithubProfile( export async function getSession( supabase: SupabaseClient, -): Promise<[User, UserProfile, string | undefined]> { +): Promise<[User, UserProfile] | null> { const { data: { user }, error: sessionError, @@ -79,9 +79,5 @@ export async function getSession( const profile = await getProfile(supabase, user); - const { - data: { session }, - } = await supabase.auth.getSession(); - - return [user, profile, session?.access_token]; + return user && profile ? [user, profile] : null; } diff --git a/src/modules/live-run/core.ts b/src/modules/live-run/core.ts index bef5c97..01ca5bb 100644 --- a/src/modules/live-run/core.ts +++ b/src/modules/live-run/core.ts @@ -2,6 +2,7 @@ import "server-only"; import { LiveRun, LiveRunMove } from "./types"; +import { SupabaseClient } from "@supabase/supabase-js"; const liveRuns: LiveRun[] = []; const liveRunMoves: Record = {}; @@ -38,3 +39,47 @@ export async function addLiveRunMoves(id: string, moves: LiveRunMove[]) { liveRunMoves[id] = liveRunMoves[id].filter((move) => !moves.includes(move)); }, 3000); } + +export async function removeLiveRun(runId: string) { + delete liveRunMoves[runId]; + + const index = liveRuns.findIndex((run) => run.id === runId); + + if (index !== -1) { + liveRuns.splice(index, 1); + } +} + +export async function submitRun( + supabase: SupabaseClient, + run: LiveRun, + user_id: string, +) { + const now = new Date(); + const durationMs = now.getTime() - run.start; + + const { data, error } = await supabase + .from("runs") + .insert([ + { + id: run.id, + user_id, + problem_id: run.problem, + category: run.category, + assisted: false, + duration_ms: durationMs, + started_at: new Date(run.start), + finished_at: now, + valid: false, + invalid_reason: null, + }, + ]) + .select(); + + if (error) { + console.error("Error inserting run:", error); + throw error; + } + + return data; +}