mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-06 23:32:12 +03:00
Split open-sse/services/usage.ts (1723 -> 901 LOC) by moving the Cursor, Kimi, Codex, Claude and Kiro usage-fetcher families into cohesive leaves under open-sse/services/usage/ (mirroring the existing glm/minimax/antigravity/quota/ scalars leaves): - usage/cursor.ts getCursorUsage (+ CURSOR_USAGE_CONFIG, decodeCursorJwtSub) - usage/kimi.ts getKimiUsage (+ KIMI_CONFIG, getKimiPlanName) - usage/codex.ts getCodexUsage (+ CODEX_CONFIG) - usage/claude.ts getClaudeUsage / getClaudePlanLabel (+ CLAUDE_CONFIG, legacy) - usage/kiro.ts getKiroUsage / buildKiroUsageResult / discoverKiroProfileArn (+ helpers) The host keeps the getUsageForProvider dispatcher and imports the fetchers back; the public export set is unchanged — buildKiroUsageResult + discoverKiroProfileArn are re-exported from the kiro leaf (the kiro-* tests import them from services/usage) and __testing stays wired to the moved claude/kiro internals. Bodies are verbatim: the code-line multiset of host + leaves equals the original. Adds tests/unit/usage-families-split.test.ts pinning the leaf surface, the kiro re-export identity, the __testing wiring, and getClaudePlanLabel's pure logic.
71 lines
2.3 KiB
TypeScript
71 lines
2.3 KiB
TypeScript
/**
|
|
* usage/codex.ts — Codex (OpenAI / ChatGPT backend) usage fetcher.
|
|
*
|
|
* Extracted from services/usage.ts (god-file decomposition): the Codex family — the ChatGPT
|
|
* backend usage-API config and the getCodexUsage fetcher that reads the persisted workspace
|
|
* binding and shapes quotas via buildCodexUsageQuotas. Depends only on the scalar leaf +
|
|
* codexUsageQuotas — no host coupling — so it lives as a co-located provider leaf. usage.ts
|
|
* imports getCodexUsage (dispatcher). Behavior-preserving move.
|
|
*/
|
|
|
|
import { buildCodexUsageQuotas } from "../codexUsageQuotas.ts";
|
|
import { getFieldValue } from "./scalars.ts";
|
|
|
|
// Codex (OpenAI) API config
|
|
const CODEX_CONFIG = {
|
|
usageUrl: "https://chatgpt.com/backend-api/wham/usage",
|
|
};
|
|
|
|
/**
|
|
* Codex (OpenAI) Usage - Fetch from ChatGPT backend API
|
|
* IMPORTANT: Uses persisted workspaceId from OAuth to ensure correct workspace binding.
|
|
* No fallback to other workspaces - strict binding to user's selected workspace.
|
|
*/
|
|
export async function getCodexUsage(
|
|
accessToken?: string,
|
|
providerSpecificData: Record<string, unknown> = {}
|
|
) {
|
|
try {
|
|
// Use persisted workspace ID from OAuth - NO FALLBACK
|
|
const accountId =
|
|
typeof providerSpecificData.workspaceId === "string"
|
|
? providerSpecificData.workspaceId
|
|
: null;
|
|
|
|
const headers: Record<string, string> = {
|
|
Authorization: `Bearer ${accessToken}`,
|
|
"Content-Type": "application/json",
|
|
Accept: "application/json",
|
|
};
|
|
if (accountId) {
|
|
headers["chatgpt-account-id"] = accountId;
|
|
}
|
|
|
|
const response = await fetch(CODEX_CONFIG.usageUrl, {
|
|
method: "GET",
|
|
headers,
|
|
});
|
|
|
|
if (!response.ok) {
|
|
if (response.status === 401 || response.status === 403) {
|
|
return {
|
|
message: `Codex token expired or access denied. Please re-authenticate the connection.`,
|
|
};
|
|
}
|
|
throw new Error(`Codex API error: ${response.status}`);
|
|
}
|
|
|
|
const data = await response.json();
|
|
|
|
const { rateLimit, quotas } = buildCodexUsageQuotas(data);
|
|
|
|
return {
|
|
plan: String(getFieldValue(data, "plan_type", "planType") || "unknown"),
|
|
limitReached: Boolean(getFieldValue(rateLimit, "limit_reached", "limitReached")),
|
|
quotas,
|
|
};
|
|
} catch (error) {
|
|
return { message: `Failed to fetch Codex usage: ${(error as Error).message}` };
|
|
}
|
|
}
|