| import { NextRequest, NextResponse } from 'next/server' |
|
|
| import { apiUrl, API_BASE } from '@/lib/runtime-config' |
| import { requireAuth } from '@/lib/api-auth' |
| import { apiError, ApiErrors } from '@/lib/api-response' |
|
|
| export const dynamic = 'force-dynamic' |
|
|
| export async function GET(req: NextRequest) { |
| const auth = await requireAuth(req) |
| if (!auth.authenticated) return auth.response |
|
|
| try { |
| const { searchParams } = new URL(req.url) |
| const limitRaw = searchParams.get('limit') |
| const sourceRaw = searchParams.get('source') |
|
|
| const limit = Math.max(1, Math.min(Number(limitRaw || 100) || 100, 300)) |
| const source = (sourceRaw || 'live').trim() |
|
|
| const qs = new URLSearchParams({ limit: String(limit), source }) |
|
|
| const controller = new AbortController() |
| const timeout = setTimeout(() => controller.abort(), 30000) |
|
|
| let resp: Response |
| try { |
| resp = await fetch(`${apiUrl('/api/stocks')}?${qs.toString()}`, { |
| headers: { accept: 'application/json' }, |
| next: { revalidate: 300 }, |
| signal: controller.signal, |
| }) |
| } finally { |
| clearTimeout(timeout) |
| } |
|
|
| if (!resp.ok) { |
| return apiError(`Stocks backend failed (HTTP ${resp.status})`, 502, { data: [] }) |
| } |
|
|
| const payload = await resp.json().catch(() => null) |
| if (!payload) { |
| return apiError('Invalid payload from stocks backend', 502, { data: [] }) |
| } |
|
|
| if (Array.isArray(payload)) { |
| return NextResponse.json(payload, { status: 200 }) |
| } |
|
|
| |
| const payloadObj = payload as Record<string, unknown> |
| if (Array.isArray(payloadObj?.data)) { |
| return NextResponse.json(payloadObj.data as unknown[], { status: 200 }) |
| } |
|
|
| return apiError('Unexpected payload format from stocks backend', 502, { data: [] }) |
| } catch (e: unknown) { |
| const message = e instanceof Error ? e.message : 'Unknown' |
| return apiError(`Stocks fetch failed: ${message}`, 502, { data: [] }) |
| } |
| } |
|
|