import { NextRequest, NextResponse } from 'next/server'; import { getCachedFirm, hasPlatformCredentials } from '@/lib/firm-catalog'; import { setCredentials, clearCredentials } from '@/lib/db'; import { reconcileClients, removeClient } from '@/lib/clients'; import { scheduleBackupPush } from '@/lib/backup-sync'; type Params = { params: Promise<{ id: string }> }; /** The platform login for one firm. This is the only firm data this machine * owns — everything else comes from the master catalog. The one path these * credentials travel is the encrypted, bearer-gated backup to the master * (lib/backup-sync.ts); they are still absent from the catalog and the * control socket. * * Tradovate and DXTrade firms need username + password (DXTrade's server URL * and login domain are set on the master, per firm). TopstepX firms need the * API key; username is optional for now (the loginKey call still wants it, * so the client sits idle with a clear error until one is added) and * password is unused. */ export async function PUT(req: NextRequest, { params }: Params) { const { id } = await params; const firm = getCachedFirm(id); if (!firm) return NextResponse.json({ error: 'Firm not found' }, { status: 404 }); const body = await req.json() as { username?: string; password?: string; apiKey?: string }; const username = body.username?.trim() ?? ''; const password = body.password?.trim() ?? ''; const apiKey = body.apiKey?.trim() ?? ''; if (!hasPlatformCredentials(firm.platform, { username, password, apiKey })) { const error = firm.platform === 'topstepx' ? 'apiKey is required for a TopstepX firm' : firm.platform === 'dxtrade' ? 'username and password are required for a DXtrade firm' : 'username and password are required'; return NextResponse.json({ error }, { status: 400 }); } try { setCredentials(id, firm.name, username, password, apiKey); // Picks up the new login immediately rather than at the next restart. reconcileClients(); scheduleBackupPush(); return NextResponse.json({ ok: true }); } catch (err) { console.error('[PUT /api/firms/:id/credentials]', err); return NextResponse.json({ error: 'Failed to save credentials' }, { status: 500 }); } } export async function DELETE(_req: NextRequest, { params }: Params) { const { id } = await params; const cleared = clearCredentials(id); removeClient(id); scheduleBackupPush(); return NextResponse.json({ ok: cleared }); }