mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-18 21:22:28 +03:00
fix(cli): recognize {connections} envelope from /api/providers (#10491)
* fix(cli): recognize {connections} envelope from /api/providers
GET /api/providers returns {connections, total} (src/app/api/providers/
route.ts:78), but `omniroute test --all-providers` and `omniroute oauth
providers` both parsed the response as `data.providers ?? data.items ??
data` -- an object, not an array -- so `.filter` threw
"(data.providers ?? data.items ?? data).filter is not a function" on
every call. keys.mjs already had the correct fallback chain
(`data.keys || data.connections || data.items || data`); apply the same
`connections` field to both remaining call sites.
* test(cli): cover provider connections envelope
Add regression coverage for both CLI consumers of the /api/providers connections envelope.
Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
---------
Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
This commit is contained in:
@@ -302,7 +302,7 @@ export async function runOAuthStatus(opts, cmd) {
|
||||
process.exit(1);
|
||||
}
|
||||
const data = await res.json();
|
||||
const connections = (data.providers ?? data.items ?? data).filter(
|
||||
const connections = (data.connections ?? data.providers ?? data.items ?? data).filter(
|
||||
(c) => c.authType === "oauth" || c.authType === "oauth2"
|
||||
);
|
||||
emit(connections, globalOpts, connectionSchema);
|
||||
|
||||
@@ -80,7 +80,7 @@ async function _runAllProviders(opts) {
|
||||
return 1;
|
||||
}
|
||||
const data = await res.json();
|
||||
const connections = (data.providers ?? data.items ?? data).filter(
|
||||
const connections = (data.connections ?? data.providers ?? data.items ?? data).filter(
|
||||
(c) => c.authType === "apikey" || c.testStatus !== "unavailable"
|
||||
);
|
||||
if (connections.length === 0) {
|
||||
|
||||
@@ -305,3 +305,54 @@ test("test-provider — compare requer pelo menos dois modelos sem server retorn
|
||||
}
|
||||
assert.ok(code === 0 || code === 1);
|
||||
});
|
||||
|
||||
test("test-provider --all-providers consumes the connections envelope", async () => {
|
||||
const origFetch = globalThis.fetch;
|
||||
const connections = [
|
||||
{ id: "conn1", provider: "anthropic", defaultModel: "claude", authType: "apikey" },
|
||||
{ id: "conn2", provider: "gemini", defaultModel: "gemini", authType: "oauth" },
|
||||
];
|
||||
const requests: string[] = [];
|
||||
globalThis.fetch = ((url: string) => {
|
||||
requests.push(url);
|
||||
if (url.includes("/api/health")) return Promise.resolve(new Response("{}", { status: 200 }));
|
||||
if (url.includes("/api/providers?limit=200")) {
|
||||
return Promise.resolve(new Response(JSON.stringify({ connections }), { status: 200 }));
|
||||
}
|
||||
if (url.includes("/api/v1/providers/test")) {
|
||||
return Promise.resolve(new Response(JSON.stringify({ success: true }), { status: 201 }));
|
||||
}
|
||||
throw new Error(`unexpected URL: ${url}`);
|
||||
}) as typeof fetch;
|
||||
|
||||
try {
|
||||
const { runTestProviderCommand } = await import("../../bin/cli/commands/test-provider.mjs");
|
||||
const output: string[] = [];
|
||||
const origWrite = process.stdout.write.bind(process.stdout);
|
||||
process.stdout.write = ((chunk: string | Uint8Array) => {
|
||||
if (typeof chunk === "string") output.push(chunk);
|
||||
return true;
|
||||
}) as typeof process.stdout.write;
|
||||
try {
|
||||
const code = await runTestProviderCommand(undefined, undefined, {
|
||||
allProviders: true,
|
||||
json: true,
|
||||
});
|
||||
assert.equal(code, 0);
|
||||
} finally {
|
||||
process.stdout.write = origWrite;
|
||||
}
|
||||
assert.ok(requests.some((url) => url.includes("/api/providers?limit=200")));
|
||||
const parsed = JSON.parse(output.join(""));
|
||||
assert.deepEqual(
|
||||
parsed.map(({ provider, model }: { provider: string; model: string }) => ({ provider, model })),
|
||||
[
|
||||
{ provider: "anthropic", model: "claude" },
|
||||
{ provider: "gemini", model: "gemini" },
|
||||
],
|
||||
);
|
||||
assert.ok(parsed.every(({ success }: { success: boolean }) => success));
|
||||
} finally {
|
||||
globalThis.fetch = origFetch;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -95,6 +95,26 @@ test("runOAuthStatus filtra por provider", async () => {
|
||||
assert.ok(capturedUrl.includes("provider=gemini"));
|
||||
});
|
||||
|
||||
test("runOAuthStatus consumes the connections envelope", async () => {
|
||||
const origFetch = globalThis.fetch;
|
||||
globalThis.fetch = ((url: string) => {
|
||||
assert.ok(url.includes("/api/providers"));
|
||||
return Promise.resolve(makeResp({ connections: CONNECTIONS }));
|
||||
}) as any;
|
||||
|
||||
try {
|
||||
const { runOAuthStatus } = await import("../../bin/cli/commands/oauth.mjs");
|
||||
const out = await captureStdout(() => runOAuthStatus({}, makeCmd() as any));
|
||||
const parsed = JSON.parse(out);
|
||||
assert.deepEqual(
|
||||
parsed.map((connection: { id: string }) => connection.id),
|
||||
["conn1", "conn2"],
|
||||
);
|
||||
} finally {
|
||||
globalThis.fetch = origFetch;
|
||||
}
|
||||
});
|
||||
|
||||
test("runOAuthRevoke com --yes chama endpoint de revogação", async () => {
|
||||
let capturedUrl = "";
|
||||
let capturedMethod = "";
|
||||
|
||||
Reference in New Issue
Block a user