67 lines
3.1 KiB
TypeScript
67 lines
3.1 KiB
TypeScript
|
|
/**
|
||
|
|
* GET /api/sessions/:id — session detail + ordered messages
|
||
|
|
* PATCH /api/sessions/:id — rename, archive, toggle public
|
||
|
|
* DELETE /api/sessions/:id — soft-delete (sets archived=true)
|
||
|
|
*/
|
||
|
|
import { NextResponse } from "next/server";
|
||
|
|
import { createClient, isSupabaseConfigured } from "@/lib/supabase/server";
|
||
|
|
|
||
|
|
export async function GET(_req: Request, ctx: { params: Promise<{ id: string }> }) {
|
||
|
|
const { id } = await ctx.params;
|
||
|
|
if (!isSupabaseConfigured()) return NextResponse.json({ error: "auth_disabled" }, { status: 503 });
|
||
|
|
const supabase = await createClient();
|
||
|
|
const { data: { user } } = await supabase.auth.getUser();
|
||
|
|
if (!user) return NextResponse.json({ error: "unauthenticated" }, { status: 401 });
|
||
|
|
|
||
|
|
const { data: session, error: sErr } = await supabase
|
||
|
|
.from("chat_sessions").select("*").eq("id", id).maybeSingle();
|
||
|
|
if (sErr || !session) return NextResponse.json({ error: "not_found" }, { status: 404 });
|
||
|
|
|
||
|
|
const { data: messages, error: mErr } = await supabase
|
||
|
|
.from("messages")
|
||
|
|
.select("id, role, content, tool_calls, citations, model, created_at")
|
||
|
|
.eq("session_id", id)
|
||
|
|
.order("created_at", { ascending: true });
|
||
|
|
if (mErr) return NextResponse.json({ error: mErr.message }, { status: 500 });
|
||
|
|
|
||
|
|
return NextResponse.json({ session, messages });
|
||
|
|
}
|
||
|
|
|
||
|
|
export async function PATCH(request: Request, ctx: { params: Promise<{ id: string }> }) {
|
||
|
|
const { id } = await ctx.params;
|
||
|
|
if (!isSupabaseConfigured()) return NextResponse.json({ error: "auth_disabled" }, { status: 503 });
|
||
|
|
const supabase = await createClient();
|
||
|
|
const { data: { user } } = await supabase.auth.getUser();
|
||
|
|
if (!user) return NextResponse.json({ error: "unauthenticated" }, { status: 401 });
|
||
|
|
|
||
|
|
const body = (await request.json().catch(() => ({}))) as {
|
||
|
|
title?: string; archived?: boolean; is_public?: boolean; summary?: string;
|
||
|
|
};
|
||
|
|
|
||
|
|
const update: Record<string, unknown> = {};
|
||
|
|
if (typeof body.title === "string") update.title = body.title;
|
||
|
|
if (typeof body.archived === "boolean") update.archived = body.archived;
|
||
|
|
if (typeof body.is_public === "boolean") update.is_public = body.is_public;
|
||
|
|
if (typeof body.summary === "string") update.summary = body.summary;
|
||
|
|
|
||
|
|
const { data, error } = await supabase
|
||
|
|
.from("chat_sessions").update(update).eq("id", id)
|
||
|
|
.select().single();
|
||
|
|
if (error) return NextResponse.json({ error: error.message }, { status: 500 });
|
||
|
|
return NextResponse.json({ session: data });
|
||
|
|
}
|
||
|
|
|
||
|
|
export async function DELETE(_req: Request, ctx: { params: Promise<{ id: string }> }) {
|
||
|
|
const { id } = await ctx.params;
|
||
|
|
if (!isSupabaseConfigured()) return NextResponse.json({ error: "auth_disabled" }, { status: 503 });
|
||
|
|
const supabase = await createClient();
|
||
|
|
const { data: { user } } = await supabase.auth.getUser();
|
||
|
|
if (!user) return NextResponse.json({ error: "unauthenticated" }, { status: 401 });
|
||
|
|
|
||
|
|
// Soft delete to preserve history if needed
|
||
|
|
const { error } = await supabase
|
||
|
|
.from("chat_sessions").update({ archived: true }).eq("id", id);
|
||
|
|
if (error) return NextResponse.json({ error: error.message }, { status: 500 });
|
||
|
|
return NextResponse.json({ ok: true });
|
||
|
|
}
|