diff --git a/src/app/api/claude-sub/route.ts b/src/app/api/claude-sub/route.ts index 6f83f59..0c3a82a 100644 --- a/src/app/api/claude-sub/route.ts +++ b/src/app/api/claude-sub/route.ts @@ -1,97 +1,38 @@ export const dynamic = "force-dynamic"; import { NextResponse } from "next/server"; -const GATEWAY_URL = "ws://192.168.31.103:18789"; -const GATEWAY_TOKEN = "c55292f854e8308c4fed926c40c3a8995a7213fde79fed72"; - -async function gatewayRequest(method: string, params: object = {}): Promise { - return new Promise((resolve, reject) => { - const timeout = setTimeout(() => { - ws.close(); - reject(new Error("Gateway timeout")); - }, 8000); - - const ws = new (require("ws"))(`${GATEWAY_URL}`); - let connected = false; - let reqId = 1; - - ws.on("open", () => {}); - - ws.on("message", (data: Buffer) => { - try { - const msg = JSON.parse(data.toString()); - - // Auth challenge - if (msg.type === "event" && msg.event === "connect.challenge") { - ws.send(JSON.stringify({ - type: "request", - id: String(reqId++), - method: "connect", - params: { token: GATEWAY_TOKEN }, - })); - return; - } - - // Connect response - if (msg.type === "response" && !connected) { - if (msg.ok) { - connected = true; - // Send actual request - ws.send(JSON.stringify({ - type: "request", - id: String(reqId++), - method, - params, - })); - } else { - clearTimeout(timeout); - ws.close(); - reject(new Error("Auth failed")); - } - return; - } - - // Method response - if (msg.type === "response" && connected) { - clearTimeout(timeout); - ws.close(); - if (msg.ok) { - resolve(msg.payload); - } else { - reject(new Error(msg.error || "Request failed")); - } - } - } catch {} - }); - - ws.on("error", (err: Error) => { - clearTimeout(timeout); - reject(err); - }); - }); -} +// Bridge HTTP API (cosmo-studio bridge в той же сети coolify) +const BRIDGE_URL = "http://172.18.0.5:3402/api/usage"; export async function GET() { try { - const [statusResult, costResult] = await Promise.allSettled([ - gatewayRequest("usage.status", {}), - gatewayRequest("usage.cost", {}), - ]); + const res = await fetch(BRIDGE_URL, { + signal: AbortSignal.timeout(5000), + cache: "no-store", + }); - const status = statusResult.status === "fulfilled" ? statusResult.value : null; - const cost = costResult.status === "fulfilled" ? costResult.value : null; + if (!res.ok) throw new Error(`Bridge HTTP ${res.status}`); + const data = await res.json(); - // Извлечь данные Anthropic - const anthropic = (status as any)?.providers?.find((p: any) => p.provider === "anthropic"); - const windows = anthropic?.windows || []; + const usage = data.usage; + if (!usage) { + return NextResponse.json({ ok: false, error: "No usage data yet" }); + } + // Найти данные Anthropic + const anthropicProvider = usage.planLimits?.providers?.find( + (p: any) => p.provider === "anthropic" + ); + const windows = anthropicProvider?.windows || []; const window5h = windows.find((w: any) => w.label?.includes("5") || w.label === "5h"); - const windowWeek = windows.find((w: any) => w.label?.toLowerCase().includes("week") || w.label === "Week"); + const windowWeek = windows.find((w: any) => w.label?.toLowerCase().includes("week")); const windowSonnet = windows.find((w: any) => w.label?.toLowerCase().includes("sonnet")); - const todayCost = (cost as any)?.daily?.[0]?.totalCost || 0; - const todayTokens = (cost as any)?.daily?.[0]?.totalTokens || 0; - const totalCost = (cost as any)?.totals?.totalCost || 0; + // Стоимость сегодня + const todayEntry = usage.cost?.daily?.find((d: any) => { + const today = new Date().toISOString().split("T")[0]; + return d.date === today; + }); return NextResponse.json({ ok: true, @@ -99,14 +40,15 @@ export async function GET() { window5h: window5h || null, windowWeek: windowWeek || null, windowSonnet: windowSonnet || null, - error: anthropic?.error || null, + error: anthropicProvider?.error || null, + plan: anthropicProvider?.plan || null, }, cost: { - today: todayCost, - todayTokens, - total: totalCost, + today: todayEntry?.totalCost || 0, + todayTokens: todayEntry?.totalTokens || 0, + total: usage.cost?.totals?.totalCost || 0, }, - raw: { status, cost }, + updatedAt: usage.updatedAt, }); } catch (e) { return NextResponse.json({