Files
9router/src/app/api/oauth/xiaomi-mimo/api-key/route.js
T

136 lines
4.4 KiB
JavaScript
Raw Normal View History

import { NextResponse } from "next/server";
import { createProviderConnection } from "@/models";
/**
* POST /api/oauth/xiaomi-mimo/api-key
* Import a Xiaomi MiMo API key manually (or from auto-import).
* The key is validated against the models endpoint, then stored.
*
* Body: { apiKey, uid?, baseUrl? }
*/
export async function POST(request) {
try {
const { apiKey, uid, baseUrl, mimoPassToken, mimoUserId, mimoCUserId } = await request.json();
if (!apiKey || typeof apiKey !== "string" || !apiKey.trim()) {
return NextResponse.json(
{ error: "API key is required" },
{ status: 400 },
);
}
const key = apiKey.trim();
if (!key.startsWith("sk-")) {
return NextResponse.json(
{ error: "Invalid key format — expected sk- prefix" },
{ status: 400 },
);
}
const effectiveBaseUrl = (baseUrl || "https://api.xiaomimimo.com/v1").replace(/\/+$/, "");
// Validate the key against the models endpoint
let validated = false;
let modelCount = 0;
try {
const resp = await fetch(`${effectiveBaseUrl}/models`, {
method: "GET",
headers: {
Authorization: `Bearer ${key}`,
"X-Mimo-Source": "mimocode-cli",
},
signal: AbortSignal.timeout(10000),
});
if (resp.ok) {
const data = await resp.json();
modelCount = Array.isArray(data?.data) ? data.data.length : 0;
validated = true;
}
} catch {
// Network error — still allow import (key may be valid but network blocked)
}
if (!validated) {
// Soft-fail: store the key but mark as untested
console.log("[xiaomi-mimo] key validation failed, storing as untested");
}
// Dedup: if a connection with the same uid or same key already exists, update it
const { getProviderConnections, updateProviderConnection } = await import("@/models");
const existing = (await getProviderConnections()).find(
(c) => c.provider === "xiaomi-mimo" && (
(uid && c.email === `${uid}@xiaomi`) ||
c.accessToken === key
),
);
if (existing) {
const updated = await updateProviderConnection(existing.id, {
accessToken: key,
providerSpecificData: {
...existing.providerSpecificData,
uid: uid || existing.providerSpecificData?.uid || null,
baseUrl: effectiveBaseUrl,
// Per-account session credential — enables multi-account rotation.
mimoPassToken: mimoPassToken || existing.providerSpecificData?.mimoPassToken || null,
mimoUserId: mimoUserId || existing.providerSpecificData?.mimoUserId || null,
mimoCUserId: mimoCUserId || existing.providerSpecificData?.mimoCUserId || null,
modelCount,
},
testStatus: validated ? "active" : existing.testStatus,
});
return NextResponse.json({
success: true,
validated,
modelCount,
updated: true,
connection: {
id: existing.id,
provider: existing.provider,
email: existing.email,
displayName: existing.displayName,
},
});
}
const connection = await createProviderConnection({
provider: "xiaomi-mimo",
authType: "api_key",
accessToken: key,
refreshToken: null,
// API keys don't expire on a fixed schedule; use a long horizon
expiresAt: new Date(Date.now() + 365 * 24 * 60 * 60 * 1000).toISOString(),
email: uid ? `${uid}@xiaomi` : null,
displayName: uid ? `Xiaomi ${uid}` : "Xiaomi MiMo",
providerSpecificData: {
uid: uid || null,
baseUrl: effectiveBaseUrl,
authMethod: "api_key",
provider: "API Key",
modelCount,
// Per-account session credential — enables multi-account rotation.
mimoPassToken: mimoPassToken || null,
mimoUserId: mimoUserId || null,
mimoCUserId: mimoCUserId || null,
},
testStatus: validated ? "active" : "untested",
});
return NextResponse.json({
success: true,
validated,
modelCount,
connection: {
id: connection.id,
provider: connection.provider,
email: connection.email,
displayName: connection.displayName,
},
});
} catch (error) {
console.log("Xiaomi MiMo API key import error:", error);
return NextResponse.json(
{ error: "API key import failed" },
{ status: 500 },
);
}
}