mirror of
https://github.com/NanmiCoder/cc-haha
synced 2026-07-30 16:23:35 +08:00
fix(desktop): align haha-oauth handler with sibling error-handling convention
Code review follow-up on 142eb9cd:
- 加 outer try/catch + errorResponse wrapper (parity with providers.ts)
- 400 响应改用 ApiError.badRequest (shape 跟其他 handler 一致: {error: 'BAD_REQUEST', message})
- test 加上对 error shape 的断言
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
142eb9cd11
commit
7421db2857
@ -64,6 +64,8 @@ describe('POST /api/haha-oauth/start', () => {
|
|||||||
const { req, url, segments } = buildReq('POST', '/api/haha-oauth/start', {})
|
const { req, url, segments } = buildReq('POST', '/api/haha-oauth/start', {})
|
||||||
const res = await handleHahaOAuthApi(req, url, segments)
|
const res = await handleHahaOAuthApi(req, url, segments)
|
||||||
expect(res.status).toBe(400)
|
expect(res.status).toBe(400)
|
||||||
|
const body = (await res.json()) as { error: string; message?: string }
|
||||||
|
expect(body.error).toBe('BAD_REQUEST')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@ -10,6 +10,7 @@
|
|||||||
|
|
||||||
import { z } from 'zod'
|
import { z } from 'zod'
|
||||||
import { hahaOAuthService } from '../services/hahaOAuthService.js'
|
import { hahaOAuthService } from '../services/hahaOAuthService.js'
|
||||||
|
import { ApiError, errorResponse } from '../middleware/errorHandler.js'
|
||||||
|
|
||||||
const StartRequestSchema = z.object({
|
const StartRequestSchema = z.object({
|
||||||
serverPort: z.number().int().positive(),
|
serverPort: z.number().int().positive(),
|
||||||
@ -27,71 +28,72 @@ export async function handleHahaOAuthApi(
|
|||||||
url: URL,
|
url: URL,
|
||||||
segments: string[],
|
segments: string[],
|
||||||
): Promise<Response> {
|
): Promise<Response> {
|
||||||
const action = segments[2] // segments: ['api', 'haha-oauth', <action?>]
|
try {
|
||||||
|
const action = segments[2] // segments: ['api', 'haha-oauth', <action?>]
|
||||||
|
|
||||||
if (action === 'start' && req.method === 'POST') {
|
if (action === 'start' && req.method === 'POST') {
|
||||||
let body: unknown
|
let body: unknown
|
||||||
try {
|
try {
|
||||||
body = await req.json()
|
body = await req.json()
|
||||||
} catch {
|
} catch {
|
||||||
return Response.json({ error: 'Invalid JSON body' }, { status: 400 })
|
throw ApiError.badRequest('Invalid JSON body')
|
||||||
|
}
|
||||||
|
const parsed = StartRequestSchema.safeParse(body)
|
||||||
|
if (!parsed.success) {
|
||||||
|
throw ApiError.badRequest('serverPort (positive integer) required')
|
||||||
|
}
|
||||||
|
const session = hahaOAuthService.startSession({
|
||||||
|
serverPort: parsed.data.serverPort,
|
||||||
|
})
|
||||||
|
return Response.json({
|
||||||
|
authorizeUrl: session.authorizeUrl,
|
||||||
|
state: session.state,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
const parsed = StartRequestSchema.safeParse(body)
|
|
||||||
if (!parsed.success) {
|
if (action === 'callback' && req.method === 'GET') {
|
||||||
return Response.json(
|
const code = url.searchParams.get('code')
|
||||||
{ error: 'serverPort (positive integer) required' },
|
const state = url.searchParams.get('state')
|
||||||
{ status: 400 },
|
const error = url.searchParams.get('error')
|
||||||
)
|
|
||||||
|
if (error) {
|
||||||
|
return html(renderCallbackPage(false, `OAuth provider returned: ${error}`))
|
||||||
|
}
|
||||||
|
if (!code || !state) {
|
||||||
|
return html(renderCallbackPage(false, 'Missing code or state parameter'))
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await hahaOAuthService.completeSession(code, state)
|
||||||
|
return html(renderCallbackPage(true, null))
|
||||||
|
} catch (err) {
|
||||||
|
const msg = err instanceof Error ? err.message : String(err)
|
||||||
|
return html(renderCallbackPage(false, msg))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
const session = hahaOAuthService.startSession({
|
|
||||||
serverPort: parsed.data.serverPort,
|
if ((action === undefined || action === 'status') && req.method === 'GET') {
|
||||||
})
|
const tokens = await hahaOAuthService.loadTokens()
|
||||||
return Response.json({
|
if (!tokens) {
|
||||||
authorizeUrl: session.authorizeUrl,
|
return Response.json({ loggedIn: false })
|
||||||
state: session.state,
|
}
|
||||||
})
|
return Response.json({
|
||||||
|
loggedIn: true,
|
||||||
|
expiresAt: tokens.expiresAt,
|
||||||
|
scopes: tokens.scopes,
|
||||||
|
subscriptionType: tokens.subscriptionType,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if (action === undefined && req.method === 'DELETE') {
|
||||||
|
await hahaOAuthService.deleteTokens()
|
||||||
|
return Response.json({ ok: true })
|
||||||
|
}
|
||||||
|
|
||||||
|
return Response.json({ error: 'Not Found' }, { status: 404 })
|
||||||
|
} catch (error) {
|
||||||
|
return errorResponse(error)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (action === 'callback' && req.method === 'GET') {
|
|
||||||
const code = url.searchParams.get('code')
|
|
||||||
const state = url.searchParams.get('state')
|
|
||||||
const error = url.searchParams.get('error')
|
|
||||||
|
|
||||||
if (error) {
|
|
||||||
return html(renderCallbackPage(false, `OAuth provider returned: ${error}`))
|
|
||||||
}
|
|
||||||
if (!code || !state) {
|
|
||||||
return html(renderCallbackPage(false, 'Missing code or state parameter'))
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
await hahaOAuthService.completeSession(code, state)
|
|
||||||
return html(renderCallbackPage(true, null))
|
|
||||||
} catch (err) {
|
|
||||||
const msg = err instanceof Error ? err.message : String(err)
|
|
||||||
return html(renderCallbackPage(false, msg))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((action === undefined || action === 'status') && req.method === 'GET') {
|
|
||||||
const tokens = await hahaOAuthService.loadTokens()
|
|
||||||
if (!tokens) {
|
|
||||||
return Response.json({ loggedIn: false })
|
|
||||||
}
|
|
||||||
return Response.json({
|
|
||||||
loggedIn: true,
|
|
||||||
expiresAt: tokens.expiresAt,
|
|
||||||
scopes: tokens.scopes,
|
|
||||||
subscriptionType: tokens.subscriptionType,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
if (action === undefined && req.method === 'DELETE') {
|
|
||||||
await hahaOAuthService.deleteTokens()
|
|
||||||
return Response.json({ ok: true })
|
|
||||||
}
|
|
||||||
|
|
||||||
return Response.json({ error: 'Not Found' }, { status: 404 })
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderCallbackPage(success: boolean, errorMsg: string | null): string {
|
function renderCallbackPage(success: boolean, errorMsg: string | null): string {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user