+server.ts

  1import { json } from '@sveltejs/kit';
  2import {
  3	addComment,
  4	getThreads,
  5	resolveThread,
  6	deleteComment,
  7	deleteThread,
  8	getStats,
  9	markOutdated
 10} from '$lib/server/review-store';
 11import { getRepoDir } from '$lib/server/vcs';
 12import { readFile } from 'fs/promises';
 13import { join } from 'path';
 14import type { RequestHandler } from './$types.ts';
 15
 16export const GET: RequestHandler = async ({ url }) => {
 17	const filePath = url.searchParams.get('file') || undefined;
 18	const threads = getThreads(filePath);
 19	const stats = getStats();
 20	return json({ threads, stats });
 21};
 22
 23export const POST: RequestHandler = async ({ request }) => {
 24	const body = await request.json();
 25	const { filePath, lineNumber, side, text, type, threadId, originalLineContent } = body;
 26
 27	if (!filePath || lineNumber === undefined || !text) {
 28		return json({ error: 'Missing required fields' }, { status: 400 });
 29	}
 30
 31	const thread = addComment(filePath, lineNumber, side || 'new', text, type || 'comment', threadId, originalLineContent);
 32	return json(thread);
 33};
 34
 35export const PATCH: RequestHandler = async ({ request }) => {
 36	const body = await request.json();
 37	const { threadId, action } = body;
 38
 39	if (action === 'resolve' && threadId) {
 40		resolveThread(threadId);
 41		return json({ success: true });
 42	}
 43
 44	if (action === 'check-outdated') {
 45		const threads = getThreads();
 46		const repoDir = getRepoDir();
 47		const fileCache = new Map<string, string[]>();
 48		let outdatedCount = 0;
 49
 50		for (const thread of threads) {
 51			if (!thread.originalLineContent || thread.resolved) continue;
 52
 53			// Read file content (cached)
 54			let lines = fileCache.get(thread.filePath);
 55			if (!lines) {
 56				try {
 57					const content = await readFile(join(repoDir, thread.filePath), 'utf-8');
 58					lines = content.split('\n');
 59					fileCache.set(thread.filePath, lines);
 60				} catch {
 61					continue;
 62				}
 63			}
 64
 65			// Check if the line content still matches
 66			const lineIdx = thread.lineNumber - 1;
 67			if (lineIdx >= 0 && lineIdx < lines.length) {
 68				const currentContent = lines[lineIdx].trim();
 69				const originalContent = thread.originalLineContent.trim();
 70				const isOutdated = currentContent !== originalContent;
 71				if (isOutdated !== thread.outdated) {
 72					markOutdated(thread.id, isOutdated);
 73					if (isOutdated) outdatedCount++;
 74				}
 75			} else {
 76				// Line no longer exists — outdated
 77				if (!thread.outdated) {
 78					markOutdated(thread.id, true);
 79					outdatedCount++;
 80				}
 81			}
 82		}
 83
 84		return json({ success: true, outdatedCount, threads: getThreads() });
 85	}
 86
 87	return json({ error: 'Unknown action' }, { status: 400 });
 88};
 89
 90export const DELETE: RequestHandler = async ({ request }) => {
 91	const body = await request.json();
 92	const { commentId, threadId } = body;
 93
 94	if (threadId) {
 95		deleteThread(threadId);
 96		return json({ success: true });
 97	}
 98
 99	if (commentId) {
100		deleteComment(commentId);
101		return json({ success: true });
102	}
103
104	return json({ error: 'Missing commentId or threadId' }, { status: 400 });
105};