mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-07 07:42:13 +03:00
feat(bazaarlink): add authHint to existing APIKEY_PROVIDERS entry (#4522)
Adds authHint + enriched freeNote/apiHint on the existing bazaarlink entry (distinct from the closed-redundant #4497). Integrity test included. Integrated into release/v3.8.33.
This commit is contained in:
@@ -999,9 +999,12 @@ export const APIKEY_PROVIDERS = {
|
||||
textIcon: "BZ",
|
||||
website: "https://bazaarlink.ai",
|
||||
hasFree: true,
|
||||
freeNote: "Free tier with auto:free routing — zero-cost inference, no credit card required",
|
||||
freeNote:
|
||||
"Free tier: 4M tokens/day per account with auto:free routing — zero-cost inference, no credit card required.",
|
||||
authHint:
|
||||
"Use your BazaarLink API key (starts with sk-bl-) in Authorization: Bearer <key>. OpenAI SDK works with base URL https://bazaarlink.ai/api/v1. Models use provider/model-name format.",
|
||||
apiHint:
|
||||
"Get free API key at https://bazaarlink.ai — use model 'auto:free' for zero-cost inference. OpenAI-compatible.",
|
||||
"Create a free API key at https://bazaarlink.ai — model 'auto:free' routes to zero-cost inference. All models use the provider/model-name format, e.g. xiaomi/mimo-v2.5-pro.",
|
||||
},
|
||||
xai: {
|
||||
id: "xai",
|
||||
@@ -1745,7 +1748,8 @@ export const APIKEY_PROVIDERS = {
|
||||
textIcon: "GLB",
|
||||
website: "https://opengateway.gitlawb.com",
|
||||
hasFree: false,
|
||||
freeNote: "Free MiMo (xiaomi/mimo-v2.5) revoked 2026-05 — Opengateway is now a pay-as-you-go credit gateway; no recurring free model.",
|
||||
freeNote:
|
||||
"Free MiMo (xiaomi/mimo-v2.5) revoked 2026-05 — Opengateway is now a pay-as-you-go credit gateway; no recurring free model.",
|
||||
apiHint: "Get your API key from Gitlawb Opengateway dashboard.",
|
||||
},
|
||||
"gitlawb-gmi": {
|
||||
@@ -1757,7 +1761,8 @@ export const APIKEY_PROVIDERS = {
|
||||
textIcon: "GMI",
|
||||
website: "https://opengateway.gitlawb.com",
|
||||
hasFree: false,
|
||||
freeNote: "Free Nemotron promo ended 2026-06 — the GMI Cloud route is now pay-as-you-go credit only.",
|
||||
freeNote:
|
||||
"Free Nemotron promo ended 2026-06 — the GMI Cloud route is now pay-as-you-go credit only.",
|
||||
apiHint: "Get your API key from Gitlawb Opengateway dashboard.",
|
||||
},
|
||||
"inference-net": {
|
||||
@@ -1974,7 +1979,8 @@ export const APIKEY_PROVIDERS = {
|
||||
textIcon: "CH",
|
||||
website: "https://chutes.ai",
|
||||
hasFree: false,
|
||||
freeNote: "No free tier as of 2026 — Chutes moved to pay-as-you-go (free Early Access ended 2026-03).",
|
||||
freeNote:
|
||||
"No free tier as of 2026 — Chutes moved to pay-as-you-go (free Early Access ended 2026-03).",
|
||||
authHint: "Bearer API key for the Chutes OpenAI-compatible gateway.",
|
||||
passthroughModels: true,
|
||||
},
|
||||
@@ -2082,7 +2088,8 @@ export const APIKEY_PROVIDERS = {
|
||||
textIcon: "IF",
|
||||
website: "https://xinghuo.xfyun.cn",
|
||||
hasFree: true,
|
||||
freeNote: "Spark Lite is free (2 QPS rate-limited), but iFlytek ToS §2.4(3) prohibits programmatic extraction and requires Chinese real-name auth — use with caution.",
|
||||
freeNote:
|
||||
"Spark Lite is free (2 QPS rate-limited), but iFlytek ToS §2.4(3) prohibits programmatic extraction and requires Chinese real-name auth — use with caution.",
|
||||
passthroughModels: true,
|
||||
authHint: "Get API key at console.xfyun.cn",
|
||||
},
|
||||
@@ -2108,7 +2115,8 @@ export const APIKEY_PROVIDERS = {
|
||||
textIcon: "YI",
|
||||
website: "https://01.ai",
|
||||
hasFree: false,
|
||||
freeNote: "No free API tier (2026) — Yi-Light retired; platform.01.ai is pay-as-you-go (Yi-Lightning paid). Open weights are download-only.",
|
||||
freeNote:
|
||||
"No free API tier (2026) — Yi-Light retired; platform.01.ai is pay-as-you-go (Yi-Lightning paid). Open weights are download-only.",
|
||||
passthroughModels: true,
|
||||
authHint: "Get API key at platform.lingyiwanwu.com",
|
||||
},
|
||||
@@ -2186,7 +2194,8 @@ export const APIKEY_PROVIDERS = {
|
||||
textIcon: "SD",
|
||||
website: "https://xinghuo.xfyun.cn",
|
||||
hasFree: true,
|
||||
freeNote: "Spark Lite free (alias for iflytek), but ToS restricts to personal/non-commercial use and prohibits relaying access to third parties — use with caution.",
|
||||
freeNote:
|
||||
"Spark Lite free (alias for iflytek), but ToS restricts to personal/non-commercial use and prohibits relaying access to third parties — use with caution.",
|
||||
passthroughModels: true,
|
||||
authHint: "Get API key at console.xfyun.cn",
|
||||
},
|
||||
@@ -2296,7 +2305,8 @@ export const APIKEY_PROVIDERS = {
|
||||
textIcon: "MA",
|
||||
website: "https://monsterapi.ai",
|
||||
hasFree: true,
|
||||
freeNote: "One-time signup trial credits for decentralized GPU inference (no recurring free plan). No credit card required.",
|
||||
freeNote:
|
||||
"One-time signup trial credits for decentralized GPU inference (no recurring free plan). No credit card required.",
|
||||
passthroughModels: true,
|
||||
authHint: "Get API key at monsterapi.ai",
|
||||
},
|
||||
@@ -2439,7 +2449,8 @@ export const APIKEY_PROVIDERS = {
|
||||
textIcon: "TK",
|
||||
website: "https://tokenrouter.com",
|
||||
hasFree: true,
|
||||
freeNote: "Free tier includes the MiniMax 3 model. Get your API key at https://tokenrouter.com.",
|
||||
freeNote:
|
||||
"Free tier includes the MiniMax 3 model. Get your API key at https://tokenrouter.com.",
|
||||
authHint:
|
||||
"Use your TokenRouter API key in Authorization: Bearer <key>. Fully OpenAI-compatible. API base URL: https://api.tokenrouter.com/v1.",
|
||||
apiHint:
|
||||
|
||||
76
tests/unit/bazaarlink-provider-integrity.test.ts
Normal file
76
tests/unit/bazaarlink-provider-integrity.test.ts
Normal file
@@ -0,0 +1,76 @@
|
||||
import { describe, it } from "node:test";
|
||||
import assert from "node:assert";
|
||||
|
||||
describe("bazaarlink provider entry in APIKEY_PROVIDERS", () => {
|
||||
it("exists with required fields", async () => {
|
||||
const { APIKEY_PROVIDERS } = await import("../../src/shared/constants/providers.ts");
|
||||
const p = (APIKEY_PROVIDERS as Record<string, Record<string, unknown>>)["bazaarlink"];
|
||||
assert.ok(p, "bazaarlink must exist in APIKEY_PROVIDERS");
|
||||
assert.equal(p.id, "bazaarlink");
|
||||
assert.equal(p.alias, "bzl");
|
||||
assert.equal(p.name, "BazaarLink");
|
||||
assert.equal(p.icon, "storefront");
|
||||
assert.equal(p.color, "#6366F1");
|
||||
assert.equal(p.textIcon, "BZ");
|
||||
assert.equal(p.website, "https://bazaarlink.ai");
|
||||
});
|
||||
|
||||
it("advertises the free tier and includes authHint", async () => {
|
||||
const { APIKEY_PROVIDERS } = await import("../../src/shared/constants/providers.ts");
|
||||
const p = (
|
||||
APIKEY_PROVIDERS as Record<
|
||||
string,
|
||||
{ hasFree?: boolean; authHint?: string; freeNote?: string; apiHint?: string }
|
||||
>
|
||||
)["bazaarlink"];
|
||||
assert.equal(p.hasFree, true, "bazaarlink should advertise a free tier");
|
||||
assert.ok(p.authHint, "bazaarlink must have an authHint field");
|
||||
assert.ok(p.authHint.includes("sk-bl-"), "authHint should mention the sk-bl- key prefix");
|
||||
assert.ok(p.freeNote, "bazaarlink must have a freeNote describing the free tier");
|
||||
assert.ok(p.apiHint, "bazaarlink must have an apiHint");
|
||||
assert.ok(p.apiHint.includes("bazaarlink.ai"), "apiHint should reference bazaarlink.ai");
|
||||
});
|
||||
|
||||
it("is registered in the execution registry", async () => {
|
||||
const { getRegistryEntry } = await import("../../open-sse/config/providerRegistry.ts");
|
||||
const entry = getRegistryEntry("bazaarlink");
|
||||
assert.ok(entry, "bazaarlink must have a registry entry");
|
||||
assert.equal(entry.format, "openai");
|
||||
assert.equal(entry.authType, "apikey");
|
||||
assert.ok(entry.baseUrl, "registry entry must have a baseUrl");
|
||||
assert.ok(entry.modelsUrl, "registry entry must have a modelsUrl");
|
||||
assert.ok(
|
||||
entry.models && entry.models.length > 0,
|
||||
"registry entry must list at least one model"
|
||||
);
|
||||
assert.ok(
|
||||
entry.models.some((m: { id: string }) => m.id === "auto:free"),
|
||||
"registry must include auto:free model"
|
||||
);
|
||||
assert.ok(
|
||||
entry.models.some((m: { id: string }) => m.id === "mimo-v2.5-pro"),
|
||||
"registry must include mimo-v2.5-pro"
|
||||
);
|
||||
});
|
||||
|
||||
it("is resolvable through the static catalog for managed connections", async () => {
|
||||
const { resolveStaticProviderCatalogEntry } =
|
||||
await import("../../src/lib/providers/catalog.ts");
|
||||
const entry = resolveStaticProviderCatalogEntry("bazaarlink");
|
||||
assert.ok(entry, "bazaarlink must resolve through the static provider catalog");
|
||||
assert.ok(entry.id, "bazaarlink", "resolved entry id must match");
|
||||
assert.equal(entry.category, "apikey", "bazaarlink must be in the apikey category");
|
||||
});
|
||||
|
||||
it("passes isManagedProviderConnectionId check so connections can be created", async () => {
|
||||
const { isManagedProviderConnectionId } = await import("../../src/lib/providers/catalog.ts");
|
||||
const result = isManagedProviderConnectionId("bazaarlink");
|
||||
assert.equal(result, true, "bazaarlink must pass isManagedProviderConnectionId");
|
||||
});
|
||||
|
||||
it("supports bulk API key add (not excluded)", async () => {
|
||||
const { supportsBulkApiKey } = await import("../../src/shared/constants/providers.ts");
|
||||
const result = supportsBulkApiKey("bazaarlink");
|
||||
assert.equal(result, true, "bazaarlink must support bulk API key add");
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user