| import { getProviderConnections, updateProviderConnection } from "@/lib/localDb.js"; |
| import { getExecutor } from "open-sse/index.js"; |
|
|
| async function persistRefreshedCredentials(connection, newCredentials) { |
| const updateData = {}; |
|
|
| if (newCredentials.accessToken) updateData.accessToken = newCredentials.accessToken; |
| if (newCredentials.refreshToken) updateData.refreshToken = newCredentials.refreshToken; |
| if (newCredentials.idToken) updateData.idToken = newCredentials.idToken; |
| if (newCredentials.lastRefreshAt) updateData.lastRefreshAt = newCredentials.lastRefreshAt; |
| if (newCredentials.expiresIn) { |
| updateData.expiresIn = newCredentials.expiresIn; |
| updateData.expiresAt = new Date(Date.now() + newCredentials.expiresIn * 1000).toISOString(); |
| } else if (newCredentials.expiresAt) { |
| updateData.expiresAt = newCredentials.expiresAt; |
| } |
|
|
| const providerSpecificUpdates = { |
| ...(newCredentials.providerSpecificData || {}), |
| ...(newCredentials.copilotToken ? { copilotToken: newCredentials.copilotToken } : {}), |
| ...(newCredentials.copilotTokenExpiresAt ? { copilotTokenExpiresAt: newCredentials.copilotTokenExpiresAt } : {}), |
| }; |
| if (Object.keys(providerSpecificUpdates).length > 0) { |
| updateData.providerSpecificData = { |
| ...(connection.providerSpecificData || {}), |
| ...providerSpecificUpdates, |
| }; |
| } |
|
|
| if (Object.keys(updateData).length > 0) { |
| await updateProviderConnection(connection.id, updateData); |
| } |
| } |
|
|
| export async function POST(request) { |
| try { |
| const { provider, model, body } = await request.json(); |
|
|
| if (!provider || !model || !body) { |
| return Response.json({ success: false, error: "provider, model, and body required" }, { status: 400 }); |
| } |
|
|
| const connections = await getProviderConnections({ provider }); |
| const connection = connections.find(c => c.isActive !== false); |
| if (!connection) { |
| return Response.json({ success: false, error: `No active connection for provider: ${provider}` }, { status: 400 }); |
| } |
|
|
| const credentials = { |
| apiKey: connection.apiKey, |
| accessToken: connection.accessToken, |
| refreshToken: connection.refreshToken, |
| idToken: connection.idToken, |
| lastRefreshAt: connection.lastRefreshAt, |
| connectionId: connection.id, |
| copilotToken: connection.providerSpecificData?.copilotToken, |
| copilotTokenExpiresAt: connection.providerSpecificData?.copilotTokenExpiresAt, |
| projectId: connection.projectId, |
| providerSpecificData: connection.providerSpecificData |
| }; |
|
|
| const executor = getExecutor(provider); |
| const stream = body.stream !== false; |
|
|
| let { response } = await executor.execute({ model, body, stream, credentials }); |
|
|
| |
| if (response.status === 401 || response.status === 403) { |
| const newCredentials = await executor.refreshCredentials(credentials, console); |
| if (newCredentials?.accessToken || newCredentials?.copilotToken) { |
| Object.assign(credentials, newCredentials); |
| await persistRefreshedCredentials(connection, newCredentials); |
| ({ response } = await executor.execute({ model, body, stream, credentials })); |
| } |
| } |
|
|
| if (!response.ok) { |
| const errorText = await response.text(); |
| console.error(`[Translator] Provider error ${response.status}:`, errorText.slice(0, 500)); |
| return Response.json({ success: false, error: `Provider error: ${response.status}`, details: errorText }, { status: response.status }); |
| } |
|
|
| return new Response(response.body, { |
| headers: { |
| "Content-Type": "text/event-stream", |
| "Cache-Control": "no-cache", |
| "Connection": "keep-alive" |
| } |
| }); |
| } catch (error) { |
| console.error("[Translator] Send error:", error); |
| return Response.json({ success: false, error: error.message }, { status: 500 }); |
| } |
| } |
|
|