TypeScript 97.5%
SQL 1.4%
Python 0.8%
1import { PLAN_LIMITS } from "@fetcha/core";2import { db, fetchRequests, sql } from "@fetcha/db";3import type { ApiPrincipal } from "../auth";4import { monthlyUsage } from "../limits";56export function meResponse(p: ApiPrincipal) {7 return {8 project: { id: p.projectId, name: p.projectName },9 organization: { id: p.organizationId, name: p.organizationName, plan: p.plan },10 key: { id: p.keyId, name: p.keyName, mode: p.mode, scopes: p.scopes },11 };12}1314export async function usageResponse(p: ApiPrincipal) {15 const usage = await monthlyUsage(p);16 const limits = PLAN_LIMITS[p.plan];17 const start = new Date();18 start.setUTCDate(1);19 start.setUTCHours(0, 0, 0, 0);20 const [agg] = await db21 .select({22 total: sql<number>`count(*)::int`,23 ok: sql<number>`count(*) filter (where ${fetchRequests.status} = 'success')::int`,24 bytes: sql<number>`coalesce(sum(${fetchRequests.bytesIn} + ${fetchRequests.bytesOut}), 0)::float`,25 p50: sql<number>`coalesce(percentile_cont(0.5) within group (order by ${fetchRequests.latencyMs}), 0)::float`,26 p95: sql<number>`coalesce(percentile_cont(0.95) within group (order by ${fetchRequests.latencyMs}), 0)::float`,27 })28 .from(fetchRequests)29 .where(sql`${fetchRequests.projectId} = ${p.projectId} and ${fetchRequests.createdAt} >= ${start}`);30 return {31 period_start: start.toISOString(),32 plan: { id: p.plan, label: limits.label, monthly_requests: limits.monthly_requests, concurrency: limits.concurrency },33 organization: { requests: usage.requests, spend_usd: round(usage.spendUsd) },34 project: {35 requests: usage.projectRequests,36 spend_usd: round(usage.projectSpendUsd),37 successful_requests: agg?.ok ?? 0,38 success_rate: agg?.total ? round((agg.ok / agg.total) * 100, 1) : null,39 bandwidth_bytes: agg?.bytes ?? 0,40 latency_p50_ms: Math.round(agg?.p50 ?? 0),41 latency_p95_ms: Math.round(agg?.p95 ?? 0),42 },43 remaining_requests: limits.monthly_requests >= Number.MAX_SAFE_INTEGER ? null : Math.max(0, limits.monthly_requests - usage.requests),44 browser: { enabled: true, concurrency: limits.browser_concurrency },45 crawl: { max_pages: limits.crawl_max_pages, concurrent_jobs: limits.crawl_concurrent_jobs },46 };47}4849function round(n: number, d = 4): number {50 const f = 10 ** d;51 return Math.round(n * f) / f;52}53