feat: add PATCH /api/chats endpoint to update chat topic#191
Conversation
Migrate Recoup-Chat/app/api/room/update/route.ts to PATCH /api/chats following the new API docs at developers.recoupable.com/api-reference/chat/update - Add PATCH method to app/api/chats/route.ts - Add lib/chats/updateChatHandler.ts for business logic - Add lib/chats/validateUpdateChatBody.ts for Zod validation - Add lib/supabase/rooms/updateRoom.ts for database operations The endpoint: - Accepts chatId (UUID) and topic (3-50 chars) in request body - Supports both x-api-key and Authorization Bearer token auth - Validates access using buildGetChatsParams (same as GET /api/chats) - Returns 404 if chat not found, 403 if no access, 200 on success Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Warning Rate limit exceeded
⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. 📝 WalkthroughWalkthroughThis PR introduces a new PATCH Changes
Sequence DiagramsequenceDiagram
participant Client
participant Route as PATCH Handler
participant Validator as validateUpdateChatBody
participant Auth as validateAuthContext
participant Handler as updateChatHandler
participant DB as updateRoom (Supabase)
Client->>Route: PATCH /api/chats
Route->>Validator: validate request body
Validator->>Auth: authenticate user
Auth-->>Validator: user context
Validator->>DB: select room by chatId
DB-->>Validator: room data
Validator-->>Route: validated data
Route->>Handler: delegate to handler
Handler->>Handler: check access control<br/>(admin or account_id match)
Handler->>DB: updateRoom with topic
DB-->>Handler: updated room
Handler-->>Route: JSON response
Route-->>Client: 200 + updated chat data<br/>or 403/500 error
Estimated Code Review Effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly Related PRs
Poem
🚥 Pre-merge checks | ❌ 1❌ Failed checks (1 warning)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Braintrust eval reportCatalog Opportunity Analysis Evaluation (HEAD-1770086204)
Catalog Songs Count Evaluation (HEAD-1770086204)
First Week Album Sales Evaluation (HEAD-1770086204)
Memory & Storage Tools Evaluation (HEAD-1770086204)
Monthly Listeners Tracking Evaluation (HEAD-1770086204)
Search Web Tool Evaluation (HEAD-1770086204)
Social Scraping Evaluation (HEAD-1770086204)
Spotify Followers Evaluation (HEAD-1770086204)
Spotify Tools Evaluation (HEAD-1770086204)
TikTok Analytics Questions Evaluation (HEAD-1770086204)
|
Bug fix: - Remove target_account_id from buildGetChatsParams call which was causing "Personal API keys cannot filter by account_id" error for users updating their own chats - Access control now correctly checks if room's account_id is in the user's allowed account_ids Tests: - Add comprehensive test suite for updateChatHandler covering: - Successful updates (personal key, org key) - Validation errors (invalid UUID, topic length) - Auth errors (401) - Not found errors (404) - Access denied errors (403) Documentation: - Add TDD section to CLAUDE.md requiring tests before implementation Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- validateUpdateChatBody now takes NextRequest instead of unknown body - Handles JSON parsing internally with try/catch - Remove safeParseJson import from updateChatHandler - Add comprehensive tests for validateUpdateChatBody (10 tests) - Update handler tests to mock validateUpdateChatBody instead of safeParseJson Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- validateUpdateChatBody now handles: - JSON parsing - Body schema validation - Authentication via validateAuthContext - Room existence check via selectRoom - Returns ValidatedUpdateChat with chatId, topic, room, accountId, orgId - Handler now only handles access control and update logic - Updated tests for both validation (13 tests) and handler (7 tests) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Fix all issues with AI agents
In `@lib/chats/updateChatHandler.ts`:
- Around line 29-38: The access check currently skips rooms with falsy
room.account_id which can grant unintended access; update the logic in the
handler around params.account_ids and room.account_id so that when
params.account_ids is present you explicitly treat null/undefined account IDs as
unauthorized: inside the branch that checks params.account_ids, first check if
room.account_id == null and return the same 403 NextResponse.json(...) (or a 500
if you want to assert the invariant), otherwise continue to check
!params.account_ids.includes(room.account_id) and return 403; reference the
existing symbols params.account_ids, room.account_id, NextResponse.json and
getCorsHeaders when making this change.
In `@lib/chats/validateUpdateChatBody.ts`:
- Around line 44-49: The try/catch around request.json() in
validateUpdateChatBody.ts currently swallows JSON parse errors and sets body =
{}, causing misleading validation errors; update the catch to detect JSON parse
failures from request.json() and immediately return/throw a 400 Bad Request with
a clear message like "Invalid JSON body" (including the parse error message for
debugging) instead of falling back to an empty object, keeping the rest of the
validation flow (the code that inspects body and checks chatId, title, etc.)
unchanged.
lib/chats/updateChatHandler.ts
Outdated
There was a problem hiding this comment.
Potential access control gap when room.account_id is null.
The condition if (params.account_ids && room.account_id) short-circuits when room.account_id is falsy. If a room can legitimately have a null account_id (e.g., orphaned data, system-owned rooms), this would grant access to any authenticated user.
If account_id should always be present on rooms, consider adding a defensive check or asserting this invariant.
🛡️ Proposed defensive fix
// Check if the room's account_id is in the allowed account_ids
// If params.account_ids is undefined, it means admin access (all records)
- if (params.account_ids && room.account_id) {
- if (!params.account_ids.includes(room.account_id)) {
+ if (params.account_ids) {
+ // Deny access if room has no account_id (orphaned) or account not in allowed list
+ if (!room.account_id || !params.account_ids.includes(room.account_id)) {
return NextResponse.json(
{ status: "error", error: "Access denied to this chat" },
{ status: 403, headers: getCorsHeaders() },
);
}
}Please verify whether room.account_id can legitimately be null in your data model:
#!/bin/bash
# Check if rooms table allows null account_id and find any existing null values
rg -n "account_id" --type=ts -C2 | grep -i "rooms\|null"🤖 Prompt for AI Agents
In `@lib/chats/updateChatHandler.ts` around lines 29 - 38, The access check
currently skips rooms with falsy room.account_id which can grant unintended
access; update the logic in the handler around params.account_ids and
room.account_id so that when params.account_ids is present you explicitly treat
null/undefined account IDs as unauthorized: inside the branch that checks
params.account_ids, first check if room.account_id == null and return the same
403 NextResponse.json(...) (or a 500 if you want to assert the invariant),
otherwise continue to check !params.account_ids.includes(room.account_id) and
return 403; reference the existing symbols params.account_ids, room.account_id,
NextResponse.json and getCorsHeaders when making this change.
| let body: unknown; | ||
| try { | ||
| body = await request.json(); | ||
| } catch { | ||
| body = {}; | ||
| } |
There was a problem hiding this comment.
JSON parse failure is silently swallowed, masking the root cause.
When request.json() throws (e.g., malformed JSON), the catch block silently converts it to an empty object. The user receives a generic validation error like "chatId is required" instead of a more helpful "Invalid JSON body" message.
Consider returning a specific 400 error for JSON parse failures to help API consumers debug issues faster.
🛠️ Proposed fix
// Parse JSON body
let body: unknown;
try {
body = await request.json();
} catch {
- body = {};
+ return NextResponse.json(
+ { status: "error", error: "Invalid JSON body" },
+ { status: 400, headers: getCorsHeaders() },
+ );
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| let body: unknown; | |
| try { | |
| body = await request.json(); | |
| } catch { | |
| body = {}; | |
| } | |
| let body: unknown; | |
| try { | |
| body = await request.json(); | |
| } catch { | |
| return NextResponse.json( | |
| { status: "error", error: "Invalid JSON body" }, | |
| { status: 400, headers: getCorsHeaders() }, | |
| ); | |
| } |
🤖 Prompt for AI Agents
In `@lib/chats/validateUpdateChatBody.ts` around lines 44 - 49, The try/catch
around request.json() in validateUpdateChatBody.ts currently swallows JSON parse
errors and sets body = {}, causing misleading validation errors; update the
catch to detect JSON parse failures from request.json() and immediately
return/throw a 400 Bad Request with a clear message like "Invalid JSON body"
(including the parse error message for debugging) instead of falling back to an
empty object, keeping the rest of the validation flow (the code that inspects
body and checks chatId, title, etc.) unchanged.
- validateUpdateChatBody now handles complete request validation:
- JSON parsing
- Body schema validation (chatId UUID, topic 3-50 chars)
- Authentication via validateAuthContext
- Room existence check via selectRoom
- Access control via buildGetChatsParams
- Returns only { chatId, topic } on success (simpler interface)
- Handler now only calls updateRoom and formats response
- Validation tests: 16 tests (including 2 new access denied tests)
- Handler tests: 7 tests (simplified, validation errors pass through)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…-api-migrate-recoup-chatappapiroomupdateroutets-to-patch
Summary
Recoup-Chat/app/api/room/update/route.tstoPATCH /api/chatsfollowing the new API docsChanges
app/api/chats/route.ts- Add PATCH exportlib/chats/updateChatHandler.ts- Business logic handlerlib/chats/validateUpdateChatBody.ts- Zod schema validationlib/supabase/rooms/updateRoom.ts- Database update functionAPI Specification
PATCH /api/chats
Request body:
chatId(string, UUID): Required identifier for the chat roomtopic(string, 3-50 characters): Required display name for the chatResponse (200):
{ "status": "success", "chat": { "id": "uuid", "account_id": "uuid", "topic": "string", "updated_at": "timestamp", "artist_id": "uuid" } }Error responses: 400 (validation), 401 (auth), 403 (access denied), 404 (not found)
Test plan
🤖 Generated with Claude Code
Summary by CodeRabbit