feat(chats): GET /api/chats/[id] (chatId → chat row incl. sessionId)#625
feat(chats): GET /api/chats/[id] (chatId → chat row incl. sessionId)#625sweetmantech wants to merge 1 commit into
Conversation
Lets a client holding only a /chat/[roomId] URL recover the sessionId the workflow transport and chat_messages history read require. Authenticates via validateAuthContext, loads the chat with selectChats, and confirms the caller owns the chat's parent session (mirrors validateGetSessionChatRequest, resolving the session from the chat instead of the path). Reuses toChatResponse for camelCase wire format. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
📝 WalkthroughWalkthroughThis PR implements a new GET endpoint at ChangesSingle Chat Retrieval Endpoint
Sequence DiagramsequenceDiagram
participant Client
participant RouteHandler as Route Handler<br/>/api/chats/[id]
participant getChatHandler as getChatHandler
participant validateGetChatRequest as validateGetChatRequest
participant AuthService as validateAuthContext
participant ChatDB as selectChats
participant SessionDB as selectSessions
Client->>RouteHandler: GET /api/chats/[id]
RouteHandler->>RouteHandler: await context.params.id
RouteHandler->>getChatHandler: getChatHandler(request, id)
getChatHandler->>validateGetChatRequest: validateGetChatRequest(request, chatId)
validateGetChatRequest->>AuthService: validateAuthContext(request)
alt auth fails
AuthService-->>validateGetChatRequest: error NextResponse
validateGetChatRequest-->>getChatHandler: error NextResponse
getChatHandler-->>RouteHandler: error response (401)
else auth succeeds
validateGetChatRequest->>ChatDB: selectChats(chatId)
alt chat not found
ChatDB-->>validateGetChatRequest: empty
validateGetChatRequest-->>getChatHandler: error NextResponse (404)
getChatHandler-->>RouteHandler: error response (404)
else chat found
validateGetChatRequest->>SessionDB: selectSessions(chat.session_id)
alt session missing or not owned
SessionDB-->>validateGetChatRequest: error NextResponse (403)
validateGetChatRequest-->>getChatHandler: error NextResponse (403)
getChatHandler-->>RouteHandler: error response (403)
else session owned by caller
validateGetChatRequest-->>getChatHandler: chat row
getChatHandler->>getChatHandler: toChatResponse(chat)
getChatHandler-->>RouteHandler: { chat } + 200 + CORS headers
RouteHandler-->>Client: JSON response with chat data
end
end
end
Estimated Code Review Effort🎯 2 (Simple) | ⏱️ ~12 minutes Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 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 |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
lib/chats/getChatHandler.ts (1)
7-9: Interface export alongside function is idiomatic TypeScript.While the guideline for
lib/**/*.tsstates "one exported function per file", exporting theChatResponseinterface alongsidegetChatHandleris standard TypeScript practice. The interface directly supports the function by defining its response shape and is used only for type-checking viasatisfieson line 27. This doesn't violate the spirit of SRP—the file has a single responsibility: handling GET chat requests.Consider this compliant with the architectural intent of the guideline.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@lib/chats/getChatHandler.ts` around lines 7 - 9, Keep the exported ChatResponse interface in the file; it's fine to export ChatResponse alongside getChatHandler because it defines the response shape used for type-checking with the satisfies usage (and ties to toChatResponse), so no code change is needed—leave ChatResponse exported and ensure it's only used for typing around getChatHandler/toChatResponse.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@lib/chats/getChatHandler.ts`:
- Around line 7-9: Keep the exported ChatResponse interface in the file; it's
fine to export ChatResponse alongside getChatHandler because it defines the
response shape used for type-checking with the satisfies usage (and ties to
toChatResponse), so no code change is needed—leave ChatResponse exported and
ensure it's only used for typing around getChatHandler/toChatResponse.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: f56ac62c-c7a6-4502-ba15-1bebb1eb3d56
⛔ Files ignored due to path filters (2)
lib/chats/__tests__/getChatHandler.test.tsis excluded by!**/*.test.*,!**/__tests__/**and included bylib/**lib/chats/__tests__/validateGetChatRequest.test.tsis excluded by!**/*.test.*,!**/__tests__/**and included bylib/**
📒 Files selected for processing (3)
app/api/chats/[id]/route.tslib/chats/getChatHandler.tslib/chats/validateGetChatRequest.ts
There was a problem hiding this comment.
No issues found across 5 files
Confidence score: 5/5
- Automated review surfaced no issues in the provided summaries.
- No files require special attention.
Architecture diagram
sequenceDiagram
participant Client as Client (browser/API consumer)
participant Route as GET /api/chats/[id]
participant Handler as getChatHandler
participant Validator as validateGetChatRequest
participant Auth as validateAuthContext
participant DB as Supabase DB
Client->>Route: GET /api/chats/{chatId}
Route->>Handler: getChatHandler(request, chatId)
Handler->>Validator: validateGetChatRequest(request, chatId)
Validator->>Auth: validateAuthContext(request)
alt Auth failure (401)
Auth-->>Validator: NextResponse (401)
Validator-->>Handler: Forward NextResponse (401)
Handler-->>Route: 401 response
Route-->>Client: 401 Unauthorized
else Auth success
Auth-->>Validator: { accountId, orgId, authToken }
Validator->>DB: selectChats({ id: chatId })
DB-->>Validator: chat row or empty
alt Chat not found (404)
Validator-->>Handler: NextResponse (404)
Handler-->>Route: 404 response
Route-->>Client: 404 Chat Not Found
else Chat found
Validator->>DB: selectSessions({ id: chat.session_id })
DB-->>Validator: session row or empty
alt Session missing or wrong account (403)
Validator-->>Handler: NextResponse (403)
Handler-->>Route: 403 response
Route-->>Client: 403 Forbidden
else Session owned by caller
Validator-->>Handler: raw chat row
Handler->>Handler: toChatResponse(chat) → camelCase
Handler-->>Route: 200 { chat: { id, sessionId, ... } }
Route-->>Client: 200 { chat: { id, sessionId, ... } }
end
end
end
Requires human review: This PR introduces a new API endpoint with authentication, database queries, and access control logic; any bug in authorization or data exposure could have security or data integrity consequences, so it requires human review.
Re-trigger cubic
|
Closing — superseded by the pivot to the session-scoped URL approach (chat#1752 + arpit's series). This endpoint was originally the lookup the legacy URL redirect (
No file overlap with api#626 (that PR migrates the LIST endpoint; this was the singular by-id reader), so closing has no impact on that work. |
Summary
Prerequisite for the chat-side cutover unification (recoupable/chat#1747). Adds
GET /api/chats/{chatId}returning the chat row in camelCase wire format, includingsessionId.Today a client holding only a legacy
/chat/[roomId]URL has no way to recover thesession_idit needs to (a) target the workflow transport (/api/chat/workflow) and (b) read history fromchat_messagesviaGET /api/sessions/{sessionId}/chats/{chatId}./api/chats(list) still returnsrooms(nosession_id), and no single-chat endpoint existed. This fills that gap.After the Phase 2 backfill (
chats.id == rooms.id,chats.session_idset), this resolves thesessionIdfor any backfilled or new chat.Changes
app/api/chats/[id]/route.ts—GET+OPTIONS.lib/chats/getChatHandler.ts— maps the validated chat to{ chat: toChatResponse(chat) }.lib/chats/validateGetChatRequest.ts— auth + load chat + confirm caller owns the chat's parent session. MirrorsvalidateGetSessionChatRequest, but resolves the session from the chat row instead of requiringsessionIdin the path.validateAuthContext,selectChats,selectSessions,toChatResponse(DRY; no new Supabase queries).Test plan
validateGetChatRequestunit tests: 401 forward, 404 missing chat, 403 wrong-account, 403 orphan session, 200 owner. (5)getChatHandlerunit tests: forwards failure NextResponse, 200 with camelCase{ chat }incl.sessionId. (2)tsc --noEmitclean on changed files;eslintclean.GET /api/chats/<backfilled-room-id>returns{ chat: { id, sessionId, ... } }for the owner; 403 for a non-owner; 404 for an unknown id.🤖 Generated with Claude Code
Summary by cubic
Adds
GET /api/chats/{chatId}to return a single chat in camelCase, includingsessionId. This lets clients with only a legacy/chat/[roomId]URL recover thesessionIdfor workflow transport and history reads.GET /api/chats/{chatId}+OPTIONSwith CORS; returns{ chat }includingsessionId.selectChats,selectSessions, andtoChatResponse(no new queries).Written for commit b67ba5a. Summary will update on new commits.
Summary by CodeRabbit