mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-09-13 18:32:12 +03:00
Landed with the design call resolved per the owner's pick — **option 1**: the synced store is now endpoint-agnostic (persistDiscoveredModels and managedModelImport no longer drop non-chat models at write time), and chat selectability moved to read time (auto-pool expansion in autoStrategy applies filterChatSelectableModels; the models-route projection already had its chatOnly filter). Your discovery test now passes end-to-end (3/3): /api/show capabilities persist per connection and image/embedding requests route through the advertising host. Reconciliation notes: conflicted areas merged onto the current tip (adobe discovery import, requestedModel preflight signature, resolvedProvider fast-path coexists with the synced-route override — explicit resolution wins); carried base-red drains (#10055 memoization, #11071 test variants) dropped as already-landed; the managed-model-import exclusion test was propagated to the new contract (image/video models persist; the read filter still hides them from chat pickers — pinned by a new assertion). Full battery: 205/206 focused (the one red is a confirmed periodic-timer timing flake on the loaded devbox — 20/20 isolated), autoCombo vitest 30/30, combo suites 46/46, gates + typecheck clean. Thank you @yourspraveen — the capability probe + routing design was right; it just needed the store contract opened up. Fixes #11087.
234 lines
8.5 KiB
TypeScript
234 lines
8.5 KiB
TypeScript
import test from "node:test";
|
|
import assert from "node:assert/strict";
|
|
import dns from "node:dns";
|
|
|
|
import { handleImageGeneration } from "../../open-sse/handlers/imageGeneration.ts";
|
|
import {
|
|
IMAGE_PROVIDERS,
|
|
getImageProvider,
|
|
parseImageModel,
|
|
} from "../../open-sse/config/imageRegistry.ts";
|
|
import { APIKEY_PROVIDERS, resolveProviderId } from "../../src/shared/constants/providers.ts";
|
|
import { IMAGE_ONLY_PROVIDER_IDS } from "../../src/shared/constants/providers.ts";
|
|
import { connectionBelongsToProviderPage } from "../../src/app/(dashboard)/dashboard/providers/providerPageUtils.ts";
|
|
|
|
// Stub DNS for fetchRemoteImage/direct-fetch DNS-rebinding guards, mirroring
|
|
// tests/unit/nanobanana-image-handler.test.ts.
|
|
const originalDnsLookup = dns.promises.lookup;
|
|
(dns.promises as { lookup: unknown }).lookup = (async (
|
|
_hostname: string,
|
|
options?: { all?: boolean }
|
|
) => {
|
|
const record = { address: "203.0.113.1", family: 4 };
|
|
return options && options.all ? [record] : record;
|
|
}) as typeof dns.promises.lookup;
|
|
process.on("exit", () => {
|
|
(dns.promises as { lookup: unknown }).lookup = originalDnsLookup;
|
|
});
|
|
|
|
test("magnific provider is registered (registry shape)", () => {
|
|
assert.ok(APIKEY_PROVIDERS.magnific, "magnific should be in APIKEY_PROVIDERS");
|
|
assert.equal(APIKEY_PROVIDERS.magnific.id, "magnific");
|
|
assert.ok(
|
|
IMAGE_ONLY_PROVIDER_IDS.has("magnific"),
|
|
"magnific should be in IMAGE_ONLY_PROVIDER_IDS"
|
|
);
|
|
assert.ok(!IMAGE_ONLY_PROVIDER_IDS.has("freepik"));
|
|
|
|
const provider = IMAGE_PROVIDERS.magnific;
|
|
assert.ok(provider, "magnific should be in IMAGE_PROVIDERS");
|
|
assert.equal(provider.format, "magnific-image");
|
|
assert.equal(provider.authType, "apikey");
|
|
assert.equal(provider.authHeader, "x-magnific-api-key");
|
|
assert.equal(provider.baseUrl, "https://api.magnific.com/v1/ai/mystic");
|
|
assert.equal(provider.alias, "freepik");
|
|
assert.ok(provider.models.some((m) => m.id === "realism"));
|
|
assert.ok(provider.models.some((m) => m.id === "fluid"));
|
|
assert.equal(APIKEY_PROVIDERS.magnific.alias, "freepik");
|
|
assert.equal(resolveProviderId("freepik"), "magnific");
|
|
assert.equal(resolveProviderId("magnific"), "magnific");
|
|
assert.equal(getImageProvider("freepik")?.id, "magnific");
|
|
assert.deepEqual(parseImageModel("freepik/realism"), { provider: "magnific", model: "realism" });
|
|
assert.deepEqual(parseImageModel("magnific/realism"), { provider: "magnific", model: "realism" });
|
|
assert.equal(connectionBelongsToProviderPage("freepik", "magnific"), true);
|
|
assert.equal(connectionBelongsToProviderPage("magnific", "freepik"), true);
|
|
});
|
|
|
|
test("handleImageGeneration(magnific): async submit+poll returns b64_json payload", async () => {
|
|
const originalFetch = globalThis.fetch;
|
|
let pollCount = 0;
|
|
|
|
globalThis.fetch = (async (
|
|
url: string,
|
|
options: { headers?: Record<string, string>; body?: string } = {}
|
|
) => {
|
|
const u = String(url);
|
|
|
|
if (u === "https://api.magnific.com/v1/ai/mystic") {
|
|
assert.equal(options.headers?.["x-magnific-api-key"], "test-key");
|
|
const parsed = JSON.parse(options.body as string);
|
|
assert.equal(parsed.prompt, "a red panda astronaut");
|
|
assert.equal(parsed.model, "realism");
|
|
return new Response(
|
|
JSON.stringify({ data: { task_id: "task-magnific-1", status: "CREATED" } }),
|
|
{ status: 200, headers: { "content-type": "application/json" } }
|
|
);
|
|
}
|
|
|
|
if (u === "https://api.magnific.com/v1/ai/mystic/task-magnific-1") {
|
|
pollCount += 1;
|
|
if (pollCount < 2) {
|
|
return new Response(
|
|
JSON.stringify({ data: { task_id: "task-magnific-1", status: "IN_PROGRESS" } }),
|
|
{ status: 200, headers: { "content-type": "application/json" } }
|
|
);
|
|
}
|
|
return new Response(
|
|
JSON.stringify({
|
|
data: {
|
|
task_id: "task-magnific-1",
|
|
status: "COMPLETED",
|
|
generated: ["https://cdn.example.com/magnific-result.png"],
|
|
},
|
|
}),
|
|
{ status: 200, headers: { "content-type": "application/json" } }
|
|
);
|
|
}
|
|
|
|
if (u === "https://cdn.example.com/magnific-result.png") {
|
|
return new Response(new Uint8Array([0x89, 0x50, 0x4e, 0x47]), { status: 200 });
|
|
}
|
|
|
|
throw new Error(`Unexpected URL: ${u}`);
|
|
}) as typeof fetch;
|
|
|
|
try {
|
|
const result = await handleImageGeneration({
|
|
body: {
|
|
model: "magnific/realism",
|
|
prompt: "a red panda astronaut",
|
|
poll_interval_ms: 1,
|
|
},
|
|
credentials: { apiKey: "test-key" },
|
|
log: null,
|
|
});
|
|
|
|
assert.equal(result.success, true);
|
|
assert.equal(result.data.data.length, 1);
|
|
assert.equal(result.data.data[0].b64_json, "iVBORw==");
|
|
assert.equal(pollCount, 2);
|
|
} finally {
|
|
globalThis.fetch = originalFetch;
|
|
}
|
|
});
|
|
|
|
test("handleImageGeneration(magnific): FAILED status returns sanitized 502 error", async () => {
|
|
const originalFetch = globalThis.fetch;
|
|
|
|
globalThis.fetch = (async (url: string) => {
|
|
const u = String(url);
|
|
if (u === "https://api.magnific.com/v1/ai/mystic") {
|
|
return new Response(JSON.stringify({ data: { task_id: "task-fail", status: "CREATED" } }), {
|
|
status: 200,
|
|
headers: { "content-type": "application/json" },
|
|
});
|
|
}
|
|
if (u === "https://api.magnific.com/v1/ai/mystic/task-fail") {
|
|
return new Response(JSON.stringify({ data: { task_id: "task-fail", status: "FAILED" } }), {
|
|
status: 200,
|
|
headers: { "content-type": "application/json" },
|
|
});
|
|
}
|
|
throw new Error(`Unexpected URL: ${u}`);
|
|
}) as typeof fetch;
|
|
|
|
try {
|
|
const result = await handleImageGeneration({
|
|
body: { model: "magnific/realism", prompt: "broken prompt", poll_interval_ms: 1 },
|
|
credentials: { apiKey: "test-key" },
|
|
log: null,
|
|
});
|
|
|
|
assert.equal(result.success, false);
|
|
assert.equal(result.status, 502);
|
|
assert.match(result.error, /Magnific Mystic image generation failed/);
|
|
// Hard Rule #12: error responses must never leak a raw stack trace / file path.
|
|
assert.ok(!result.error.includes("at /"));
|
|
} finally {
|
|
globalThis.fetch = originalFetch;
|
|
}
|
|
});
|
|
|
|
test("handleImageGeneration(magnific): submit error response is sanitized, not raw upstream body", async () => {
|
|
const originalFetch = globalThis.fetch;
|
|
|
|
globalThis.fetch = (async () => {
|
|
// Simulate an upstream error body containing something that looks like a
|
|
// stack trace / absolute source path, to prove sanitizeErrorMessage runs.
|
|
const stackyBody = "Error: boom\n at /srv/app/handlers/mystic.ts:42:10";
|
|
return new Response(stackyBody, { status: 500 });
|
|
}) as typeof fetch;
|
|
|
|
try {
|
|
const result = await handleImageGeneration({
|
|
body: { model: "magnific/realism", prompt: "x" },
|
|
credentials: { apiKey: "test-key" },
|
|
log: null,
|
|
});
|
|
|
|
assert.equal(result.success, false);
|
|
assert.equal(result.status, 500);
|
|
assert.ok(!result.error.includes("/srv/app/handlers/mystic.ts"));
|
|
} finally {
|
|
globalThis.fetch = originalFetch;
|
|
}
|
|
});
|
|
|
|
test("handleImageGeneration(freepik/realism): legacy alias routes to the Magnific Mystic adapter", async () => {
|
|
const originalFetch = globalThis.fetch;
|
|
let sawSubmit = false;
|
|
|
|
globalThis.fetch = (async (
|
|
url: string,
|
|
options: { headers?: Record<string, string>; body?: string } = {}
|
|
) => {
|
|
const u = String(url);
|
|
if (u === "https://api.magnific.com/v1/ai/mystic") {
|
|
sawSubmit = true;
|
|
assert.equal(options.headers?.["x-magnific-api-key"], "test-key");
|
|
return new Response(JSON.stringify({ data: { task_id: "task-alias", status: "CREATED" } }), {
|
|
status: 200,
|
|
headers: { "content-type": "application/json" },
|
|
});
|
|
}
|
|
if (u === "https://api.magnific.com/v1/ai/mystic/task-alias") {
|
|
return new Response(
|
|
JSON.stringify({
|
|
data: {
|
|
task_id: "task-alias",
|
|
status: "COMPLETED",
|
|
generated: ["https://cdn.example.com/magnific-result.png"],
|
|
},
|
|
}),
|
|
{ status: 200, headers: { "content-type": "application/json" } }
|
|
);
|
|
}
|
|
if (u === "https://cdn.example.com/magnific-result.png") {
|
|
return new Response(new Uint8Array([0x89, 0x50, 0x4e, 0x47]), { status: 200 });
|
|
}
|
|
throw new Error(`Unexpected URL: ${u}`);
|
|
}) as typeof fetch;
|
|
|
|
try {
|
|
const result = await handleImageGeneration({
|
|
body: { model: "freepik/realism", prompt: "alias probe", poll_interval_ms: 1 },
|
|
credentials: { apiKey: "test-key" },
|
|
log: null,
|
|
});
|
|
assert.equal(result.success, true);
|
|
assert.equal(sawSubmit, true);
|
|
} finally {
|
|
globalThis.fetch = originalFetch;
|
|
}
|
|
});
|