mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-18 13:14:56 +03:00
Compare commits
3 Commits
fix/10104-
...
fix/10096-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
eb340e2a47 | ||
|
|
8179ed630e | ||
|
|
ff6d465140 |
1
changelog.d/fixes/10096-kimi-coding-apikey-save.md
Normal file
1
changelog.d/fixes/10096-kimi-coding-apikey-save.md
Normal file
@@ -0,0 +1 @@
|
||||
- fix(dashboard): remap unified Kimi Code card API-key save to the admitted `kimi-coding-apikey` connection id, fixing 400 "Invalid provider" on Save (#10096)
|
||||
@@ -435,7 +435,7 @@ export default function AddApiKeyModal({
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
provider,
|
||||
provider: provider === "kimi-coding" ? "kimi-coding-apikey" : provider,
|
||||
entries: parsed.entries.map((e) => ({
|
||||
name: e.name,
|
||||
apiKey: e.apiKey,
|
||||
|
||||
@@ -241,6 +241,49 @@ describe("conn-modals (Phase 1c extraction)", () => {
|
||||
);
|
||||
});
|
||||
|
||||
it("AddApiKeyModal remaps Kimi Code bulk API-key additions to the admitted provider id", async () => {
|
||||
const fetchMock = vi.fn(() =>
|
||||
Promise.resolve({
|
||||
ok: true,
|
||||
json: async () => ({ success: 1, failed: 0, total: 1, errors: [] }),
|
||||
text: async () => "",
|
||||
} as Response)
|
||||
);
|
||||
vi.stubGlobal("fetch", fetchMock);
|
||||
const c = renderModal(
|
||||
<AddApiKeyModal
|
||||
isOpen={true}
|
||||
provider="kimi-coding"
|
||||
providerName="Kimi Code"
|
||||
isCompatible={false}
|
||||
onSave={vi.fn().mockResolvedValue(undefined)}
|
||||
onClose={vi.fn()}
|
||||
/>
|
||||
);
|
||||
|
||||
const bulkTab = Array.from(c.querySelectorAll("button")).find(
|
||||
(button) => button.textContent === "providers.bulkTabBulkAdd"
|
||||
);
|
||||
act(() => bulkTab!.click());
|
||||
const bulkInput = c.querySelector<HTMLTextAreaElement>("textarea");
|
||||
setTextareaValue(bulkInput!, "main|sk-kimi-test");
|
||||
const submitButton = Array.from(c.querySelectorAll("button")).find(
|
||||
(button) => button.textContent === "providers.bulkAddAllKeys"
|
||||
);
|
||||
await act(async () => {
|
||||
submitButton!.click();
|
||||
await Promise.resolve();
|
||||
await Promise.resolve();
|
||||
});
|
||||
|
||||
expect(fetchMock).toHaveBeenCalledWith(
|
||||
"/api/providers/bulk",
|
||||
expect.objectContaining({
|
||||
body: expect.stringContaining('"provider":"kimi-coding-apikey"'),
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
it("AddApiKeyModal does not infer a regional provider selection", () => {
|
||||
const c = renderModal(
|
||||
<AddApiKeyModal
|
||||
|
||||
@@ -32,6 +32,19 @@ type UseApiKeySaveParams = {
|
||||
t: ProviderMessageTranslator;
|
||||
};
|
||||
|
||||
// Issue #10096: the unified Kimi Code dashboard card shares one page/providerId
|
||||
// ("kimi-coding") between OAuth and API-key auth. "kimi-coding" is an
|
||||
// OAuth-primary managed id and is NOT an admitted API-key/dual-auth connection
|
||||
// id (see isManagedProviderConnectionId in src/lib/providers/catalog.ts), so
|
||||
// posting it here 400s with "Invalid provider". The dedicated managed
|
||||
// API-key id "kimi-coding-apikey" IS admitted — remap only the POST payload
|
||||
// so the saved connection lands under the correct managed id. The OAuth flow
|
||||
// (handleOAuthSuccess in ProviderDetailPageClient.tsx) does not go through
|
||||
// this hook, so it keeps posting "kimi-coding" unchanged.
|
||||
export function resolveApiKeySaveProviderId(providerId: string): string {
|
||||
return providerId === "kimi-coding" ? "kimi-coding-apikey" : providerId;
|
||||
}
|
||||
|
||||
export function useApiKeySave({
|
||||
providerId,
|
||||
fetchConnections,
|
||||
@@ -48,7 +61,10 @@ export function useApiKeySave({
|
||||
const res = await fetch("/api/providers", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ provider: providerId, ...formData }),
|
||||
body: JSON.stringify({
|
||||
provider: resolveApiKeySaveProviderId(providerId),
|
||||
...formData,
|
||||
}),
|
||||
});
|
||||
if (res.ok) {
|
||||
const connectionData = await res.json();
|
||||
|
||||
37
tests/unit/bug-10096-kimi-coding-apikey-save.test.ts
Normal file
37
tests/unit/bug-10096-kimi-coding-apikey-save.test.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
import test from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
|
||||
// Issue #10096: Kimi Code API key validates OK but Save returns 400 "Invalid provider".
|
||||
//
|
||||
// Root cause: the unified Kimi Code dashboard card's API-key branch posted
|
||||
// provider: "kimi-coding" (an OAuth-primary managed id, NOT an admitted
|
||||
// API-key connection id) to POST /api/providers, which the backend rejects.
|
||||
// The dedicated managed API-key id "kimi-coding-apikey" IS admitted.
|
||||
//
|
||||
// Fix: resolveApiKeySaveProviderId() in useApiKeySave.ts remaps the posted
|
||||
// provider id to "kimi-coding-apikey" for the API-key save flow only, while
|
||||
// the OAuth flow (which never calls this hook) keeps posting "kimi-coding".
|
||||
|
||||
const { isManagedProviderConnectionId } = await import("../../src/lib/providers/catalog.ts");
|
||||
const { resolveApiKeySaveProviderId } = await import(
|
||||
"../../src/app/(dashboard)/dashboard/providers/[id]/hooks/useApiKeySave.ts"
|
||||
);
|
||||
|
||||
test("Kimi Code API-key save flow remaps to the admitted managed API-key id", () => {
|
||||
assert.equal(
|
||||
resolveApiKeySaveProviderId("kimi-coding"),
|
||||
"kimi-coding-apikey",
|
||||
"the unified Kimi Code card's API-key save flow must post kimi-coding-apikey, not kimi-coding"
|
||||
);
|
||||
assert.equal(
|
||||
isManagedProviderConnectionId(resolveApiKeySaveProviderId("kimi-coding")),
|
||||
true,
|
||||
"the remapped id must be an admitted managed provider connection id (POST /api/providers accepts it)"
|
||||
);
|
||||
});
|
||||
|
||||
test("resolveApiKeySaveProviderId leaves every other provider id untouched", () => {
|
||||
assert.equal(resolveApiKeySaveProviderId("openai"), "openai");
|
||||
assert.equal(resolveApiKeySaveProviderId("kimi-coding-apikey"), "kimi-coding-apikey");
|
||||
assert.equal(resolveApiKeySaveProviderId("qoder"), "qoder");
|
||||
});
|
||||
Reference in New Issue
Block a user