feat: improve error messages (#1006)

This commit is contained in:
Jeremy 2025-05-13 19:01:28 -07:00 committed by GitHub
parent 9127e1be88
commit 8a7d3e9950
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 370 additions and 174 deletions

View file

@ -35,6 +35,7 @@ import {
import { after } from 'next/server';
import type { Chat } from '@/lib/db/schema';
import { differenceInSeconds } from 'date-fns';
import { ChatSDKError } from '@/lib/errors';
export const maxDuration = 60;
@ -67,7 +68,7 @@ export async function POST(request: Request) {
const json = await request.json();
requestBody = postRequestBodySchema.parse(json);
} catch (_) {
return new Response('Invalid request body', { status: 400 });
return new ChatSDKError('bad_request:api').toResponse();
}
try {
@ -77,7 +78,7 @@ export async function POST(request: Request) {
const session = await auth();
if (!session?.user) {
return new Response('Unauthorized', { status: 401 });
return new ChatSDKError('unauthorized:chat').toResponse();
}
const userType: UserType = session.user.type;
@ -88,12 +89,7 @@ export async function POST(request: Request) {
});
if (messageCount > entitlementsByUserType[userType].maxMessagesPerDay) {
return new Response(
'You have exceeded your maximum number of messages for the day! Please try again later.',
{
status: 429,
},
);
return new ChatSDKError('rate_limit:chat').toResponse();
}
const chat = await getChatById({ id });
@ -111,7 +107,7 @@ export async function POST(request: Request) {
});
} else {
if (chat.userId !== session.user.id) {
return new Response('Forbidden', { status: 403 });
return new ChatSDKError('forbidden:chat').toResponse();
}
}
@ -237,10 +233,10 @@ export async function POST(request: Request) {
} else {
return new Response(stream);
}
} catch (_) {
return new Response('An error occurred while processing your request!', {
status: 500,
});
} catch (error) {
if (error instanceof ChatSDKError) {
return error.toResponse();
}
}
}
@ -256,13 +252,13 @@ export async function GET(request: Request) {
const chatId = searchParams.get('chatId');
if (!chatId) {
return new Response('id is required', { status: 400 });
return new ChatSDKError('bad_request:api').toResponse();
}
const session = await auth();
if (!session?.user) {
return new Response('Unauthorized', { status: 401 });
return new ChatSDKError('unauthorized:chat').toResponse();
}
let chat: Chat;
@ -270,27 +266,27 @@ export async function GET(request: Request) {
try {
chat = await getChatById({ id: chatId });
} catch {
return new Response('Not found', { status: 404 });
return new ChatSDKError('not_found:chat').toResponse();
}
if (!chat) {
return new Response('Not found', { status: 404 });
return new ChatSDKError('not_found:chat').toResponse();
}
if (chat.visibility === 'private' && chat.userId !== session.user.id) {
return new Response('Forbidden', { status: 403 });
return new ChatSDKError('forbidden:chat').toResponse();
}
const streamIds = await getStreamIdsByChatId({ chatId });
if (!streamIds.length) {
return new Response('No streams found', { status: 404 });
return new ChatSDKError('not_found:stream').toResponse();
}
const recentStreamId = streamIds.at(-1);
if (!recentStreamId) {
return new Response('No recent stream found', { status: 404 });
return new ChatSDKError('not_found:stream').toResponse();
}
const emptyDataStream = createDataStream({
@ -344,29 +340,22 @@ export async function DELETE(request: Request) {
const id = searchParams.get('id');
if (!id) {
return new Response('Not Found', { status: 404 });
return new ChatSDKError('bad_request:api').toResponse();
}
const session = await auth();
if (!session?.user?.id) {
return new Response('Unauthorized', { status: 401 });
if (!session?.user) {
return new ChatSDKError('unauthorized:chat').toResponse();
}
try {
const chat = await getChatById({ id });
const chat = await getChatById({ id });
if (chat.userId !== session.user.id) {
return new Response('Forbidden', { status: 403 });
}
const deletedChat = await deleteChatById({ id });
return Response.json(deletedChat, { status: 200 });
} catch (error) {
console.error(error);
return new Response('An error occurred while processing your request!', {
status: 500,
});
if (chat.userId !== session.user.id) {
return new ChatSDKError('forbidden:chat').toResponse();
}
const deletedChat = await deleteChatById({ id });
return Response.json(deletedChat, { status: 200 });
}

View file

@ -5,19 +5,23 @@ import {
getDocumentsById,
saveDocument,
} from '@/lib/db/queries';
import { ChatSDKError } from '@/lib/errors';
export async function GET(request: Request) {
const { searchParams } = new URL(request.url);
const id = searchParams.get('id');
if (!id) {
return new Response('Missing id', { status: 400 });
return new ChatSDKError(
'bad_request:api',
'Parameter id is missing',
).toResponse();
}
const session = await auth();
if (!session?.user?.id) {
return new Response('Unauthorized', { status: 401 });
if (!session?.user) {
return new ChatSDKError('unauthorized:document').toResponse();
}
const documents = await getDocumentsById({ id });
@ -25,11 +29,11 @@ export async function GET(request: Request) {
const [document] = documents;
if (!document) {
return new Response('Not found', { status: 404 });
return new ChatSDKError('not_found:document').toResponse();
}
if (document.userId !== session.user.id) {
return new Response('Forbidden', { status: 403 });
return new ChatSDKError('forbidden:document').toResponse();
}
return Response.json(documents, { status: 200 });
@ -40,13 +44,16 @@ export async function POST(request: Request) {
const id = searchParams.get('id');
if (!id) {
return new Response('Missing id', { status: 400 });
return new ChatSDKError(
'bad_request:api',
'Parameter id is required.',
).toResponse();
}
const session = await auth();
if (!session?.user?.id) {
return new Response('Unauthorized', { status: 401 });
if (!session?.user) {
return new ChatSDKError('not_found:document').toResponse();
}
const {
@ -62,7 +69,7 @@ export async function POST(request: Request) {
const [document] = documents;
if (document.userId !== session.user.id) {
return new Response('Forbidden', { status: 403 });
return new ChatSDKError('forbidden:document').toResponse();
}
}
@ -83,17 +90,23 @@ export async function DELETE(request: Request) {
const timestamp = searchParams.get('timestamp');
if (!id) {
return new Response('Missing id', { status: 400 });
return new ChatSDKError(
'bad_request:api',
'Parameter id is required.',
).toResponse();
}
if (!timestamp) {
return new Response('Missing timestamp', { status: 400 });
return new ChatSDKError(
'bad_request:api',
'Parameter timestamp is required.',
).toResponse();
}
const session = await auth();
if (!session?.user?.id) {
return new Response('Unauthorized', { status: 401 });
if (!session?.user) {
return new ChatSDKError('unauthorized:document').toResponse();
}
const documents = await getDocumentsById({ id });
@ -101,7 +114,7 @@ export async function DELETE(request: Request) {
const [document] = documents;
if (document.userId !== session.user.id) {
return new Response('Unauthorized', { status: 401 });
return new ChatSDKError('forbidden:document').toResponse();
}
const documentsDeleted = await deleteDocumentsByIdAfterTimestamp({

View file

@ -1,37 +1,34 @@
import { auth } from '@/app/(auth)/auth';
import { NextRequest } from 'next/server';
import type { NextRequest } from 'next/server';
import { getChatsByUserId } from '@/lib/db/queries';
import { ChatSDKError } from '@/lib/errors';
export async function GET(request: NextRequest) {
const { searchParams } = request.nextUrl;
const limit = parseInt(searchParams.get('limit') || '10');
const limit = Number.parseInt(searchParams.get('limit') || '10');
const startingAfter = searchParams.get('starting_after');
const endingBefore = searchParams.get('ending_before');
if (startingAfter && endingBefore) {
return Response.json(
'Only one of starting_after or ending_before can be provided!',
{ status: 400 },
);
return new ChatSDKError(
'bad_request:api',
'Only one of starting_after or ending_before can be provided.',
).toResponse();
}
const session = await auth();
if (!session?.user?.id) {
return Response.json('Unauthorized!', { status: 401 });
if (!session?.user) {
return new ChatSDKError('unauthorized:chat').toResponse();
}
try {
const chats = await getChatsByUserId({
id: session.user.id,
limit,
startingAfter,
endingBefore,
});
const chats = await getChatsByUserId({
id: session.user.id,
limit,
startingAfter,
endingBefore,
});
return Response.json(chats);
} catch (_) {
return Response.json('Failed to fetch chats!', { status: 500 });
}
return Response.json(chats);
}

View file

@ -1,18 +1,22 @@
import { auth } from '@/app/(auth)/auth';
import { getSuggestionsByDocumentId } from '@/lib/db/queries';
import { ChatSDKError } from '@/lib/errors';
export async function GET(request: Request) {
const { searchParams } = new URL(request.url);
const documentId = searchParams.get('documentId');
if (!documentId) {
return new Response('Not Found', { status: 404 });
return new ChatSDKError(
'bad_request:api',
'Parameter documentId is required.',
).toResponse();
}
const session = await auth();
if (!session || !session.user) {
return new Response('Unauthorized', { status: 401 });
if (!session?.user) {
return new ChatSDKError('unauthorized:suggestions').toResponse();
}
const suggestions = await getSuggestionsByDocumentId({
@ -26,7 +30,7 @@ export async function GET(request: Request) {
}
if (suggestion.userId !== session.user.id) {
return new Response('Unauthorized', { status: 401 });
return new ChatSDKError('forbidden:api').toResponse();
}
return Response.json(suggestions, { status: 200 });

View file

@ -1,28 +1,32 @@
import { auth } from '@/app/(auth)/auth';
import { getChatById, getVotesByChatId, voteMessage } from '@/lib/db/queries';
import { ChatSDKError } from '@/lib/errors';
export async function GET(request: Request) {
const { searchParams } = new URL(request.url);
const chatId = searchParams.get('chatId');
if (!chatId) {
return new Response('chatId is required', { status: 400 });
return new ChatSDKError(
'bad_request:api',
'Parameter chatId is required.',
).toResponse();
}
const session = await auth();
if (!session || !session.user || !session.user.email) {
return new Response('Unauthorized', { status: 401 });
if (!session?.user) {
return new ChatSDKError('unauthorized:vote').toResponse();
}
const chat = await getChatById({ id: chatId });
if (!chat) {
return new Response('Chat not found', { status: 404 });
return new ChatSDKError('not_found:chat').toResponse();
}
if (chat.userId !== session.user.id) {
return new Response('Unauthorized', { status: 401 });
return new ChatSDKError('forbidden:vote').toResponse();
}
const votes = await getVotesByChatId({ id: chatId });
@ -39,23 +43,26 @@ export async function PATCH(request: Request) {
await request.json();
if (!chatId || !messageId || !type) {
return new Response('messageId and type are required', { status: 400 });
return new ChatSDKError(
'bad_request:api',
'Parameters chatId, messageId, and type are required.',
).toResponse();
}
const session = await auth();
if (!session || !session.user || !session.user.email) {
return new Response('Unauthorized', { status: 401 });
if (!session?.user) {
return new ChatSDKError('unauthorized:vote').toResponse();
}
const chat = await getChatById({ id: chatId });
if (!chat) {
return new Response('Chat not found', { status: 404 });
return new ChatSDKError('not_found:vote').toResponse();
}
if (chat.userId !== session.user.id) {
return new Response('Unauthorized', { status: 401 });
return new ChatSDKError('forbidden:vote').toResponse();
}
await voteMessage({