From 5528abe4b0d69d356031f552af79f301e0949710 Mon Sep 17 00:00:00 2001 From: Admin Date: Tue, 10 Mar 2026 20:12:46 +0500 Subject: [PATCH] fix: resolve SvelteKit route conflict by moving vote endpoint to /api/comment/[id]/vote /api/comments/[id] and /api/comments/[slug] were ambiguous dynamic segments at the same path level, causing a build error. Moved the vote handler to the singular /api/comment/ prefix and updated all callers (web + iOS). --- .../LibNovel/Networking/APIClient.swift | 2 +- ui/src/lib/components/CommentsSection.svelte | 2 +- .../[id]/vote/+server.ts | 4 +-- ui/src/routes/api/comments/[id]/+server.ts | 25 ------------------- 4 files changed, 4 insertions(+), 29 deletions(-) rename ui/src/routes/api/{comments => comment}/[id]/vote/+server.ts (88%) delete mode 100644 ui/src/routes/api/comments/[id]/+server.ts diff --git a/ios/LibNovel/LibNovel/Networking/APIClient.swift b/ios/LibNovel/LibNovel/Networking/APIClient.swift index b1555a9..0e6a410 100644 --- a/ios/LibNovel/LibNovel/Networking/APIClient.swift +++ b/ios/LibNovel/LibNovel/Networking/APIClient.swift @@ -342,7 +342,7 @@ actor APIClient { /// Cast, change, or toggle-off a vote on a comment. /// Returns the updated BookComment (with refreshed upvotes/downvotes counts). func voteComment(commentId: String, vote: String) async throws -> BookComment { - try await fetch("/api/comments/\(commentId)/vote", method: "POST", body: VoteBody(vote: vote)) + try await fetch("/api/comment/\(commentId)/vote", method: "POST", body: VoteBody(vote: vote)) } /// Delete a comment (and its replies) by ID. Only the owner can delete. diff --git a/ui/src/lib/components/CommentsSection.svelte b/ui/src/lib/components/CommentsSection.svelte index a3c921f..f165fae 100644 --- a/ui/src/lib/components/CommentsSection.svelte +++ b/ui/src/lib/components/CommentsSection.svelte @@ -180,7 +180,7 @@ if (votingIds.has(commentId)) return; votingIds = new Set([...votingIds, commentId]); try { - const res = await fetch(`/api/comments/${commentId}/vote`, { + const res = await fetch(`/api/comment/${commentId}/vote`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ vote: v }) diff --git a/ui/src/routes/api/comments/[id]/vote/+server.ts b/ui/src/routes/api/comment/[id]/vote/+server.ts similarity index 88% rename from ui/src/routes/api/comments/[id]/vote/+server.ts rename to ui/src/routes/api/comment/[id]/vote/+server.ts index 13e743e..5a7526e 100644 --- a/ui/src/routes/api/comments/[id]/vote/+server.ts +++ b/ui/src/routes/api/comment/[id]/vote/+server.ts @@ -4,7 +4,7 @@ import { voteComment } from '$lib/server/pocketbase'; import { log } from '$lib/server/logger'; /** - * POST /api/comments/[id]/vote + * POST /api/comment/[id]/vote * Body: { vote: 'up' | 'down' } * Casts, changes, or toggles off a vote on a comment. * Works for both authenticated and anonymous users (session-scoped). @@ -27,7 +27,7 @@ export const POST: RequestHandler = async ({ params, request, locals }) => { const updated = await voteComment(id, body.vote, locals.sessionId, locals.user?.id); return json(updated); } catch (e) { - log.error('api/comments/[id]/vote', 'voteComment failed', { id, err: String(e) }); + log.error('api/comment/[id]/vote', 'voteComment failed', { id, err: String(e) }); error(500, 'Failed to record vote'); } }; diff --git a/ui/src/routes/api/comments/[id]/+server.ts b/ui/src/routes/api/comments/[id]/+server.ts deleted file mode 100644 index 37df021..0000000 --- a/ui/src/routes/api/comments/[id]/+server.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { json, error } from '@sveltejs/kit'; -import type { RequestHandler } from './$types'; -import { deleteComment } from '$lib/server/pocketbase'; -import { log } from '$lib/server/logger'; - -/** - * DELETE /api/comments/[id] - * Deletes a comment (and its replies) by ID. - * Requires authentication — only the comment owner can delete their own comment. - */ -export const DELETE: RequestHandler = async ({ params, locals }) => { - if (!locals.user) error(401, 'Login required'); - - const { id } = params; - try { - await deleteComment(id, locals.user.id); - return json({ ok: true }); - } catch (e) { - const msg = String(e); - if (msg.includes('Not authorized')) error(403, 'Not authorized to delete this comment'); - if (msg.includes('not found')) error(404, 'Comment not found'); - log.error('api/comments/[id]', 'deleteComment failed', { id, err: msg }); - error(500, 'Failed to delete comment'); - } -};