refactor(open-sse): usage.js dispatcher switch → USAGE_HANDLERS registry
Gộp switch 13 nhánh getUsageForProvider thành 1 registry object (provider → handler), mỗi handler giữ nguyên signature/args qua ctx. Behavior giữ nguyên (ollama vẫn chỉ nhận accessToken như cũ). Thêm tests/unit/usage-dispatch.test.js guard dispatch. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -63,6 +63,25 @@ const CLAUDE_CONFIG = {
|
||||
* @param {Object} connection - Provider connection with accessToken
|
||||
* @returns {Object} Usage data with quotas
|
||||
*/
|
||||
// provider → usage handler (ctx carries every arg each handler needs)
|
||||
const USAGE_HANDLERS = {
|
||||
github: (c) => getGitHubUsage(c.accessToken, c.providerSpecificData, c.proxyOptions),
|
||||
"gemini-cli": (c) => getGeminiUsage(c.accessToken, c.providerDataWithProjectId, c.proxyOptions),
|
||||
antigravity: (c) => getAntigravityUsage(c.accessToken, c.providerSpecificData, c.proxyOptions),
|
||||
claude: (c) => getClaudeUsage(c.accessToken, c.proxyOptions),
|
||||
codex: (c) => getCodexUsage(c.accessToken, c.proxyOptions),
|
||||
kiro: (c) => getKiroUsage(c.accessToken, c.providerSpecificData, c.proxyOptions),
|
||||
qoder: (c) => getQoderUsage(c.accessToken, c.proxyOptions),
|
||||
qwen: (c) => getQwenUsage(c.accessToken, c.providerSpecificData),
|
||||
iflow: (c) => getIflowUsage(c.accessToken),
|
||||
ollama: (c) => getOllamaUsage(c.accessToken),
|
||||
glm: (c) => getGlmUsage(c.apiKey, c.provider, c.proxyOptions),
|
||||
"glm-cn": (c) => getGlmUsage(c.apiKey, c.provider, c.proxyOptions),
|
||||
minimax: (c) => getMiniMaxUsage(c.apiKey, c.provider, c.proxyOptions),
|
||||
"minimax-cn": (c) => getMiniMaxUsage(c.apiKey, c.provider, c.proxyOptions),
|
||||
"vercel-ai-gateway": (c) => getVercelAiGatewayUsage(c.apiKey, c.proxyOptions),
|
||||
};
|
||||
|
||||
export async function getUsageForProvider(connection, proxyOptions = null) {
|
||||
const { provider, accessToken, apiKey, providerSpecificData, projectId } = connection;
|
||||
const providerDataWithProjectId = {
|
||||
@@ -70,38 +89,9 @@ export async function getUsageForProvider(connection, proxyOptions = null) {
|
||||
...(projectId ? { projectId } : {}),
|
||||
};
|
||||
|
||||
switch (provider) {
|
||||
case "github":
|
||||
return await getGitHubUsage(accessToken, providerSpecificData, proxyOptions);
|
||||
case "gemini-cli":
|
||||
return await getGeminiUsage(accessToken, providerDataWithProjectId, proxyOptions);
|
||||
case "antigravity":
|
||||
return await getAntigravityUsage(accessToken, providerSpecificData, proxyOptions);
|
||||
case "claude":
|
||||
return await getClaudeUsage(accessToken, proxyOptions);
|
||||
case "codex":
|
||||
return await getCodexUsage(accessToken, proxyOptions);
|
||||
case "kiro":
|
||||
return await getKiroUsage(accessToken, providerSpecificData, proxyOptions);
|
||||
case "qoder":
|
||||
return await getQoderUsage(accessToken, proxyOptions);
|
||||
case "qwen":
|
||||
return await getQwenUsage(accessToken, providerSpecificData);
|
||||
case "iflow":
|
||||
return await getIflowUsage(accessToken);
|
||||
case "ollama":
|
||||
return await getOllamaUsage(accessToken);
|
||||
case "glm":
|
||||
case "glm-cn":
|
||||
return await getGlmUsage(apiKey, provider, proxyOptions);
|
||||
case "minimax":
|
||||
case "minimax-cn":
|
||||
return await getMiniMaxUsage(apiKey, provider, proxyOptions);
|
||||
case "vercel-ai-gateway":
|
||||
return await getVercelAiGatewayUsage(apiKey, proxyOptions);
|
||||
default:
|
||||
return { message: `Usage API not implemented for ${provider}` };
|
||||
}
|
||||
const handler = USAGE_HANDLERS[provider];
|
||||
if (!handler) return { message: `Usage API not implemented for ${provider}` };
|
||||
return await handler({ provider, accessToken, apiKey, providerSpecificData, providerDataWithProjectId, proxyOptions });
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
39
tests/unit/usage-dispatch.test.js
Normal file
39
tests/unit/usage-dispatch.test.js
Normal file
@@ -0,0 +1,39 @@
|
||||
// Guards the refactored USAGE_HANDLERS dispatch: unsupported → message, supported → routed.
|
||||
import { describe, it, expect, vi, beforeEach } from "vitest";
|
||||
|
||||
// Stub network so handlers don't hit real APIs; each call resolves an empty 200.
|
||||
vi.mock("../../open-sse/utils/proxyFetch.js", () => ({
|
||||
proxyAwareFetch: vi.fn(async () => ({
|
||||
ok: true,
|
||||
status: 200,
|
||||
json: async () => ({}),
|
||||
text: async () => "{}",
|
||||
})),
|
||||
}));
|
||||
|
||||
const load = () => import("../../open-sse/services/usage.js");
|
||||
const SUPPORTED = [
|
||||
"github", "gemini-cli", "antigravity", "claude", "codex", "kiro",
|
||||
"qoder", "qwen", "iflow", "ollama", "glm", "glm-cn",
|
||||
"minimax", "minimax-cn", "vercel-ai-gateway",
|
||||
];
|
||||
|
||||
describe("usage dispatch", () => {
|
||||
beforeEach(() => vi.clearAllMocks());
|
||||
|
||||
it("unsupported provider → not-implemented message", async () => {
|
||||
const { getUsageForProvider } = await load();
|
||||
const res = await getUsageForProvider({ provider: "totally-unknown" });
|
||||
expect(res).toEqual({ message: "Usage API not implemented for totally-unknown" });
|
||||
});
|
||||
|
||||
it("every supported provider routes to its handler (no fallback message)", async () => {
|
||||
const { getUsageForProvider } = await load();
|
||||
for (const provider of SUPPORTED) {
|
||||
const res = await getUsageForProvider({ provider, accessToken: "t", apiKey: "k" });
|
||||
// Routed handler must return an object and never the unsupported fallback
|
||||
expect(res, `${provider} routed`).toBeTypeOf("object");
|
||||
expect(res?.message).not.toBe(`Usage API not implemented for ${provider}`);
|
||||
}
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user