mirror of
https://github.com/Nezumi-2711/9router.git
synced 2026-09-22 20:00:47 +00:00
feat: update the permission for showing the usage of the user
This commit is contained in:
@@ -5,6 +5,7 @@ import { getProviderConnectionById } from "@/lib/localDb";
|
||||
import { consumeCodexRateLimitResetCredit, getCodexRateLimitResetCredits } from "open-sse/services/usage.js";
|
||||
import { resolveConnectionProxyConfig } from "@/lib/network/connectionProxy";
|
||||
import { refreshAndUpdateCredentials } from "../route.js";
|
||||
import { requireUsageDashboardUser } from "@/lib/auth/currentUser";
|
||||
|
||||
const AUTH_EXPIRED_PATTERNS = ["expired", "authentication", "unauthorized", "401", "re-authorize"];
|
||||
|
||||
@@ -47,8 +48,8 @@ function getResponseForConsumeResult(result, redeemRequestId) {
|
||||
}, { status: result.status >= 400 && result.status < 500 ? result.status : 502 });
|
||||
}
|
||||
|
||||
async function getCodexConnection(connectionId) {
|
||||
const connection = await getProviderConnectionById(connectionId);
|
||||
async function getCodexConnection(connectionId, user) {
|
||||
const connection = await getProviderConnectionById(connectionId, user.role === "admin" ? null : user.id);
|
||||
if (!connection) {
|
||||
return { response: Response.json({ error: "Connection not found" }, { status: 404 }) };
|
||||
}
|
||||
@@ -89,7 +90,8 @@ export async function GET(_request, { params }) {
|
||||
let connection;
|
||||
try {
|
||||
const { connectionId } = await params;
|
||||
const resolved = await getCodexConnection(connectionId);
|
||||
const user = await requireUsageDashboardUser();
|
||||
const resolved = await getCodexConnection(connectionId, user);
|
||||
if (resolved.response) return resolved.response;
|
||||
({ connection } = resolved);
|
||||
const { isOAuth, proxyOptions } = resolved;
|
||||
@@ -112,6 +114,7 @@ export async function GET(_request, { params }) {
|
||||
|
||||
return Response.json(result);
|
||||
} catch (error) {
|
||||
if (error?.message === "Unauthorized") return Response.json({ error: "Unauthorized" }, { status: 401 });
|
||||
const provider = connection?.provider ?? "unknown";
|
||||
console.warn(`[Codex Reset Credits] ${provider}: ${error.message}`);
|
||||
return Response.json({ error: error.message }, { status: 500 });
|
||||
@@ -122,7 +125,8 @@ export async function POST(request, { params }) {
|
||||
let connection;
|
||||
try {
|
||||
const { connectionId } = await params;
|
||||
const resolved = await getCodexConnection(connectionId);
|
||||
const user = await requireUsageDashboardUser();
|
||||
const resolved = await getCodexConnection(connectionId, user);
|
||||
if (resolved.response) return resolved.response;
|
||||
({ connection } = resolved);
|
||||
const { isOAuth, proxyOptions } = resolved;
|
||||
@@ -149,6 +153,7 @@ export async function POST(request, { params }) {
|
||||
|
||||
return getResponseForConsumeResult(consumeResult, redeemRequestId);
|
||||
} catch (error) {
|
||||
if (error?.message === "Unauthorized") return Response.json({ error: "Unauthorized" }, { status: 401 });
|
||||
const provider = connection?.provider ?? "unknown";
|
||||
console.warn(`[Codex Reset Credits] ${provider}: ${error.message}`);
|
||||
return Response.json({ error: error.message }, { status: 500 });
|
||||
|
||||
@@ -6,6 +6,7 @@ import { getUsageForProvider } from "open-sse/services/usage.js";
|
||||
import { getExecutor } from "open-sse/executors/index.js";
|
||||
import { resolveConnectionProxyConfig } from "@/lib/network/connectionProxy";
|
||||
import { USAGE_APIKEY_PROVIDERS } from "@/shared/constants/providers";
|
||||
import { requireUsageDashboardUser } from "@/lib/auth/currentUser";
|
||||
|
||||
// Detect auth-expired messages returned by usage providers instead of throwing
|
||||
const AUTH_EXPIRED_PATTERNS = ["expired", "authentication", "unauthorized", "401", "re-authorize"];
|
||||
@@ -166,9 +167,10 @@ export async function GET(request, { params }) {
|
||||
}, { status: 401 });
|
||||
}
|
||||
}
|
||||
const user = await requireUsageDashboardUser();
|
||||
|
||||
// Fetch usage from provider API
|
||||
let usage = await getUsageForProvider(connection, proxyOptions);
|
||||
connection = await getProviderConnectionById(connectionId, user.role === "admin" ? null : user.id);
|
||||
|
||||
// If provider returned an auth-expired message instead of throwing,
|
||||
// force-refresh token and retry once (OAuth only)
|
||||
@@ -184,6 +186,7 @@ export async function GET(request, { params }) {
|
||||
|
||||
return Response.json(usage);
|
||||
} catch (error) {
|
||||
if (error?.message === "Unauthorized") return Response.json({ error: "Unauthorized" }, { status: 401 });
|
||||
const provider = connection?.provider ?? "unknown";
|
||||
console.warn(`[Usage] ${provider}: ${error.message}`);
|
||||
return Response.json({ error: error.message }, { status: 500 });
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
import { NextResponse } from "next/server";
|
||||
import { getChartData } from "@/lib/usageDb";
|
||||
import { requireUsageDashboardUser } from "@/lib/auth/currentUser";
|
||||
|
||||
const VALID_PERIODS = new Set(["today", "24h", "7d", "30d", "60d"]);
|
||||
|
||||
export async function GET(request) {
|
||||
try {
|
||||
const user = await requireUsageDashboardUser();
|
||||
const { searchParams } = new URL(request.url);
|
||||
const period = searchParams.get("period") || "7d";
|
||||
|
||||
@@ -12,9 +14,10 @@ export async function GET(request) {
|
||||
return NextResponse.json({ error: "Invalid period" }, { status: 400 });
|
||||
}
|
||||
|
||||
const data = await getChartData(period);
|
||||
const data = await getChartData(period, user);
|
||||
return NextResponse.json(data);
|
||||
} catch (error) {
|
||||
if (error?.message === "Unauthorized") return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
||||
console.error("[API] Failed to get chart data:", error);
|
||||
return NextResponse.json({ error: "Failed to fetch chart data" }, { status: 500 });
|
||||
}
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
import { NextResponse } from "next/server";
|
||||
import { getUsageStats } from "@/lib/usageDb";
|
||||
import { requireUsageDashboardUser } from "@/lib/auth/currentUser";
|
||||
|
||||
export async function GET() {
|
||||
try {
|
||||
const stats = await getUsageStats();
|
||||
const user = await requireUsageDashboardUser();
|
||||
const stats = await getUsageStats("all", user);
|
||||
return NextResponse.json(stats);
|
||||
} catch (error) {
|
||||
if (error?.message === "Unauthorized") return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
||||
console.error("Error fetching usage stats:", error);
|
||||
return NextResponse.json({ error: "Failed to fetch usage stats" }, { status: 500 });
|
||||
}
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
import { NextResponse } from "next/server";
|
||||
import { getRecentLogs } from "@/lib/usageDb";
|
||||
import { requireUsageDashboardUser } from "@/lib/auth/currentUser";
|
||||
|
||||
export async function GET() {
|
||||
try {
|
||||
const logs = await getRecentLogs(200);
|
||||
const user = await requireUsageDashboardUser();
|
||||
const logs = await getRecentLogs(200, user);
|
||||
return NextResponse.json(logs);
|
||||
} catch (error) {
|
||||
if (error?.message === "Unauthorized") return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
||||
console.error("Error fetching logs:", error);
|
||||
return NextResponse.json({ error: "Failed to fetch logs" }, { status: 500 });
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ import { NextResponse } from "next/server";
|
||||
import { getDistinctProviders } from "@/lib/requestDetailsDb";
|
||||
import { getProviderNodes } from "@/lib/localDb";
|
||||
import { AI_PROVIDERS, getProviderByAlias } from "@/shared/constants/providers";
|
||||
import { requireUsageDashboardUser } from "@/lib/auth/currentUser";
|
||||
|
||||
/**
|
||||
* GET /api/usage/providers
|
||||
@@ -9,9 +10,10 @@ import { AI_PROVIDERS, getProviderByAlias } from "@/shared/constants/providers";
|
||||
*/
|
||||
export async function GET() {
|
||||
try {
|
||||
const user = await requireUsageDashboardUser();
|
||||
// Query DISTINCT provider column directly — avoids parsing every row's
|
||||
// full JSON blob (can be hundreds of MB), which previously caused OOM.
|
||||
const providerIds = await getDistinctProviders();
|
||||
const providerIds = await getDistinctProviders(user);
|
||||
|
||||
const providerNodes = await getProviderNodes();
|
||||
const nodeMap = {};
|
||||
@@ -32,6 +34,7 @@ export async function GET() {
|
||||
|
||||
return NextResponse.json({ providers });
|
||||
} catch (error) {
|
||||
if (error?.message === "Unauthorized") return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
||||
console.error("[API] Failed to get providers:", error);
|
||||
return NextResponse.json(
|
||||
{ error: "Failed to fetch providers" },
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { NextResponse } from "next/server";
|
||||
import { getRequestDetails } from "@/lib/usageDb";
|
||||
import { requireUsageDashboardUser } from "@/lib/auth/currentUser";
|
||||
|
||||
/**
|
||||
* GET /api/usage/request-details
|
||||
@@ -7,6 +8,7 @@ import { getRequestDetails } from "@/lib/usageDb";
|
||||
*/
|
||||
export async function GET(request) {
|
||||
try {
|
||||
const user = await requireUsageDashboardUser();
|
||||
const { searchParams } = new URL(request.url);
|
||||
|
||||
const pageRaw = parseInt(searchParams.get("page"));
|
||||
@@ -46,10 +48,11 @@ export async function GET(request) {
|
||||
if (startDate) filter.startDate = startDate;
|
||||
if (endDate) filter.endDate = endDate;
|
||||
|
||||
const result = await getRequestDetails(filter);
|
||||
const result = await getRequestDetails(filter, user);
|
||||
|
||||
return NextResponse.json(result);
|
||||
} catch (error) {
|
||||
if (error?.message === "Unauthorized") return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
||||
console.error("[API] Failed to get request details:", error);
|
||||
return NextResponse.json(
|
||||
{ error: "Failed to fetch request details" },
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
import { NextResponse } from "next/server";
|
||||
import { getRecentLogs } from "@/lib/usageDb";
|
||||
import { requireUsageDashboardUser } from "@/lib/auth/currentUser";
|
||||
|
||||
export async function GET() {
|
||||
try {
|
||||
const logs = await getRecentLogs(200);
|
||||
const user = await requireUsageDashboardUser();
|
||||
const logs = await getRecentLogs(200, user);
|
||||
return NextResponse.json(logs);
|
||||
} catch (error) {
|
||||
if (error?.message === "Unauthorized") return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
||||
console.error("[API ERROR] /api/usage/logs failed:", error);
|
||||
console.error("[API ERROR] Stack:", error?.stack);
|
||||
return NextResponse.json({ error: "Failed to fetch logs" }, { status: 500 });
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { NextResponse } from "next/server";
|
||||
import { getUsageStats } from "@/lib/usageDb";
|
||||
import { requireUsageDashboardUser } from "@/lib/auth/currentUser";
|
||||
|
||||
const VALID_PERIODS = new Set(["today", "24h", "7d", "30d", "60d", "all"]);
|
||||
|
||||
@@ -7,6 +8,7 @@ export const dynamic = "force-dynamic";
|
||||
|
||||
export async function GET(request) {
|
||||
try {
|
||||
const user = await requireUsageDashboardUser();
|
||||
const { searchParams } = new URL(request.url);
|
||||
const period = searchParams.get("period") || "7d";
|
||||
|
||||
@@ -14,9 +16,10 @@ export async function GET(request) {
|
||||
return NextResponse.json({ error: "Invalid period" }, { status: 400 });
|
||||
}
|
||||
|
||||
const stats = await getUsageStats(period);
|
||||
const stats = await getUsageStats(period, user);
|
||||
return NextResponse.json(stats);
|
||||
} catch (error) {
|
||||
if (error?.message === "Unauthorized") return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
||||
console.error("[API] Failed to get usage stats:", error);
|
||||
return NextResponse.json({ error: "Failed to fetch usage stats" }, { status: 500 });
|
||||
}
|
||||
|
||||
@@ -1,8 +1,16 @@
|
||||
import { getUsageStats, statsEmitter, getActiveRequests } from "@/lib/usageDb";
|
||||
import { requireUsageDashboardUser } from "@/lib/auth/currentUser";
|
||||
|
||||
export const dynamic = "force-dynamic";
|
||||
|
||||
export async function GET() {
|
||||
let user;
|
||||
try {
|
||||
user = await requireUsageDashboardUser();
|
||||
} catch (error) {
|
||||
if (error?.message === "Unauthorized") return Response.json({ error: "Unauthorized" }, { status: 401 });
|
||||
return Response.json({ error: "Failed to authorize usage stream" }, { status: 500 });
|
||||
}
|
||||
const encoder = new TextEncoder();
|
||||
const state = { closed: false, keepalive: null, send: null, sendPending: null, cachedStats: null };
|
||||
|
||||
@@ -14,12 +22,12 @@ export async function GET() {
|
||||
try {
|
||||
// Push lightweight update immediately so UI reflects changes fast
|
||||
if (state.cachedStats) {
|
||||
const { activeRequests, recentRequests, errorProvider } = await getActiveRequests();
|
||||
const { activeRequests, recentRequests, errorProvider } = await getActiveRequests(user);
|
||||
const quickStats = { ...state.cachedStats, activeRequests, recentRequests, errorProvider };
|
||||
controller.enqueue(encoder.encode(`data: ${JSON.stringify(quickStats)}\n\n`));
|
||||
}
|
||||
// Then do full recalc and update cache
|
||||
const stats = await getUsageStats();
|
||||
const stats = await getUsageStats("all", user);
|
||||
state.cachedStats = stats;
|
||||
controller.enqueue(encoder.encode(`data: ${JSON.stringify(stats)}\n\n`));
|
||||
} catch {
|
||||
@@ -34,7 +42,7 @@ export async function GET() {
|
||||
state.sendPending = async () => {
|
||||
if (state.closed || !state.cachedStats) return;
|
||||
try {
|
||||
const { activeRequests, recentRequests, errorProvider } = await getActiveRequests();
|
||||
const { activeRequests, recentRequests, errorProvider } = await getActiveRequests(user);
|
||||
const stats = { ...state.cachedStats, activeRequests, recentRequests, errorProvider };
|
||||
controller.enqueue(encoder.encode(`data: ${JSON.stringify(stats)}\n\n`));
|
||||
} catch {
|
||||
|
||||
Reference in New Issue
Block a user