chat routes accept workspace API key (thin-client Change 8.1)
This commit is contained in:
@@ -15,8 +15,8 @@
|
||||
* data: {"type":"error","error":"..."}
|
||||
*/
|
||||
import { NextResponse } from "next/server";
|
||||
import { authSession } from "@/lib/auth/session-server";
|
||||
import { query } from "@/lib/db-postgres";
|
||||
import { requireWorkspacePrincipal } from "@/lib/auth/workspace-auth";
|
||||
import { query, queryOne } from "@/lib/db-postgres";
|
||||
import { callVibnChat } from "@/lib/ai/vibn-chat-model";
|
||||
import { VIBN_TOOL_DEFINITIONS, executeMcpTool } from "@/lib/ai/vibn-tools";
|
||||
import {
|
||||
@@ -394,10 +394,17 @@ function lastToolResultsHadFailure(messages: ChatMessage[], lookback = 3) {
|
||||
export async function POST(request: Request) {
|
||||
await ensureChatTables();
|
||||
|
||||
const session = await authSession();
|
||||
if (!session?.user?.email) {
|
||||
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
||||
const principal = await requireWorkspacePrincipal(request);
|
||||
if (principal instanceof NextResponse) return principal;
|
||||
|
||||
const userRow = await queryOne<{ data: any }>(
|
||||
`SELECT data FROM fs_users WHERE id = $1 LIMIT 1`,
|
||||
[principal.userId]
|
||||
);
|
||||
if (!userRow?.data?.email) {
|
||||
return NextResponse.json({ error: "Unauthorized user" }, { status: 401 });
|
||||
}
|
||||
const sessionEmail = userRow.data.email;
|
||||
|
||||
let body: {
|
||||
thread_id: string;
|
||||
@@ -428,7 +435,7 @@ export async function POST(request: Request) {
|
||||
);
|
||||
}
|
||||
|
||||
const email = session.user.email;
|
||||
const email = sessionEmail;
|
||||
|
||||
// Verify thread belongs to user, and capture its project scope (if any).
|
||||
const threads = await query<{ id: string; project_id: string | null }>(
|
||||
|
||||
@@ -4,18 +4,25 @@
|
||||
* DELETE /api/chat/threads/[id] — delete a thread
|
||||
*/
|
||||
import { NextResponse } from 'next/server';
|
||||
import { authSession } from '@/lib/auth/session-server';
|
||||
import { query } from '@/lib/db-postgres';
|
||||
import { requireWorkspacePrincipal } from '@/lib/auth/workspace-auth';
|
||||
import { query, queryOne } from '@/lib/db-postgres';
|
||||
|
||||
export async function GET(request: Request, { params }: { params: Promise<{ id: string }> }) {
|
||||
const session = await authSession();
|
||||
if (!session?.user?.email) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
|
||||
const principal = await requireWorkspacePrincipal(request);
|
||||
if (principal instanceof NextResponse) return principal;
|
||||
|
||||
const userRow = await queryOne<{ data: any }>(
|
||||
`SELECT data FROM fs_users WHERE id = $1 LIMIT 1`,
|
||||
[principal.userId]
|
||||
);
|
||||
if (!userRow?.data?.email) return NextResponse.json({ error: 'Unauthorized user' }, { status: 401 });
|
||||
const sessionEmail = userRow.data.email;
|
||||
|
||||
const { id } = await params;
|
||||
|
||||
const threads = await query<any>(
|
||||
`SELECT id, data, created_at, updated_at FROM fs_chat_threads WHERE id = $1 AND user_id = $2`,
|
||||
[id, session.user.email],
|
||||
[id, sessionEmail],
|
||||
);
|
||||
if (!threads.length) return NextResponse.json({ error: 'Not found' }, { status: 404 });
|
||||
|
||||
@@ -32,8 +39,15 @@ export async function GET(request: Request, { params }: { params: Promise<{ id:
|
||||
}
|
||||
|
||||
export async function PATCH(request: Request, { params }: { params: Promise<{ id: string }> }) {
|
||||
const session = await authSession();
|
||||
if (!session?.user?.email) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
|
||||
const principal = await requireWorkspacePrincipal(request);
|
||||
if (principal instanceof NextResponse) return principal;
|
||||
|
||||
const userRow = await queryOne<{ data: any }>(
|
||||
`SELECT data FROM fs_users WHERE id = $1 LIMIT 1`,
|
||||
[principal.userId]
|
||||
);
|
||||
if (!userRow?.data?.email) return NextResponse.json({ error: 'Unauthorized user' }, { status: 401 });
|
||||
const sessionEmail = userRow.data.email;
|
||||
|
||||
const { id } = await params;
|
||||
const { title } = await request.json().catch(() => ({}));
|
||||
@@ -41,16 +55,23 @@ export async function PATCH(request: Request, { params }: { params: Promise<{ id
|
||||
|
||||
await query(
|
||||
`UPDATE fs_chat_threads SET data = data || $3, updated_at = NOW() WHERE id = $1 AND user_id = $2`,
|
||||
[id, session.user.email, JSON.stringify({ title })],
|
||||
[id, sessionEmail, JSON.stringify({ title })],
|
||||
);
|
||||
return NextResponse.json({ ok: true });
|
||||
}
|
||||
|
||||
export async function DELETE(request: Request, { params }: { params: Promise<{ id: string }> }) {
|
||||
const session = await authSession();
|
||||
if (!session?.user?.email) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
|
||||
const principal = await requireWorkspacePrincipal(request);
|
||||
if (principal instanceof NextResponse) return principal;
|
||||
|
||||
const userRow = await queryOne<{ data: any }>(
|
||||
`SELECT data FROM fs_users WHERE id = $1 LIMIT 1`,
|
||||
[principal.userId]
|
||||
);
|
||||
if (!userRow?.data?.email) return NextResponse.json({ error: 'Unauthorized user' }, { status: 401 });
|
||||
const sessionEmail = userRow.data.email;
|
||||
|
||||
const { id } = await params;
|
||||
await query(`DELETE FROM fs_chat_threads WHERE id = $1 AND user_id = $2`, [id, session.user.email]);
|
||||
await query(`DELETE FROM fs_chat_threads WHERE id = $1 AND user_id = $2`, [id, sessionEmail]);
|
||||
return NextResponse.json({ ok: true });
|
||||
}
|
||||
|
||||
@@ -12,8 +12,8 @@
|
||||
* after deploy (no manual migration needed).
|
||||
*/
|
||||
import { NextResponse } from 'next/server';
|
||||
import { authSession } from '@/lib/auth/session-server';
|
||||
import { query } from '@/lib/db-postgres';
|
||||
import { requireWorkspacePrincipal } from '@/lib/auth/workspace-auth';
|
||||
import { query, queryOne } from '@/lib/db-postgres';
|
||||
|
||||
let chatTablesReady = false;
|
||||
async function ensureChatTables() {
|
||||
@@ -54,8 +54,15 @@ async function ensureChatTables() {
|
||||
|
||||
export async function GET(request: Request) {
|
||||
await ensureChatTables();
|
||||
const session = await authSession();
|
||||
if (!session?.user?.email) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
|
||||
const principal = await requireWorkspacePrincipal(request);
|
||||
if (principal instanceof NextResponse) return principal;
|
||||
|
||||
const userRow = await queryOne<{ data: any }>(
|
||||
`SELECT data FROM fs_users WHERE id = $1 LIMIT 1`,
|
||||
[principal.userId]
|
||||
);
|
||||
if (!userRow?.data?.email) return NextResponse.json({ error: 'Unauthorized user' }, { status: 401 });
|
||||
const sessionEmail = userRow.data.email;
|
||||
|
||||
const { searchParams } = new URL(request.url);
|
||||
const workspace = searchParams.get('workspace') || '';
|
||||
@@ -90,8 +97,8 @@ export async function GET(request: Request) {
|
||||
WHERE t.user_id = $1 AND t.workspace = $2 AND t.project_id IS NULL
|
||||
ORDER BY t.updated_at DESC LIMIT 50`;
|
||||
const args = projectId
|
||||
? [session.user.email, workspace, projectId]
|
||||
: [session.user.email, workspace];
|
||||
? [sessionEmail, workspace, projectId]
|
||||
: [sessionEmail, workspace];
|
||||
|
||||
const rows = await query<any>(sql, args);
|
||||
|
||||
@@ -110,8 +117,15 @@ export async function GET(request: Request) {
|
||||
|
||||
export async function POST(request: Request) {
|
||||
await ensureChatTables();
|
||||
const session = await authSession();
|
||||
if (!session?.user?.email) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
|
||||
const principal = await requireWorkspacePrincipal(request);
|
||||
if (principal instanceof NextResponse) return principal;
|
||||
|
||||
const userRow = await queryOne<{ data: any }>(
|
||||
`SELECT data FROM fs_users WHERE id = $1 LIMIT 1`,
|
||||
[principal.userId]
|
||||
);
|
||||
if (!userRow?.data?.email) return NextResponse.json({ error: 'Unauthorized user' }, { status: 401 });
|
||||
const sessionEmail = userRow.data.email;
|
||||
|
||||
const { workspace, title, projectId } = await request.json().catch(() => ({}));
|
||||
if (!workspace) return NextResponse.json({ error: 'workspace required' }, { status: 400 });
|
||||
@@ -125,17 +139,17 @@ export async function POST(request: Request) {
|
||||
`SELECT p.id FROM fs_projects p
|
||||
JOIN fs_users u ON u.id = p.user_id
|
||||
WHERE p.id = $1 AND u.data->>'email' = $2 LIMIT 1`,
|
||||
[projectId, session.user.email],
|
||||
);
|
||||
if (owned.length > 0) safeProjectId = projectId;
|
||||
}
|
||||
[projectId, sessionEmail],
|
||||
);
|
||||
if (owned.length > 0) safeProjectId = projectId;
|
||||
}
|
||||
|
||||
const rows = await query<any>(
|
||||
`INSERT INTO fs_chat_threads (user_id, workspace, project_id, data)
|
||||
VALUES ($1, $2, $3, $4)
|
||||
RETURNING id, project_id, data, created_at, updated_at`,
|
||||
[
|
||||
session.user.email,
|
||||
const rows = await query<any>(
|
||||
`INSERT INTO fs_chat_threads (user_id, workspace, project_id, data)
|
||||
VALUES ($1, $2, $3, $4)
|
||||
RETURNING id, project_id, data, created_at, updated_at`,
|
||||
[
|
||||
sessionEmail,
|
||||
workspace,
|
||||
safeProjectId,
|
||||
JSON.stringify({ title: title || 'New conversation', createdAt: new Date().toISOString(), updatedAt: new Date().toISOString() }),
|
||||
|
||||
Reference in New Issue
Block a user