Files
OmniRoute/src/lib/providers/imageValidation.ts
Paijo 76d697bb88 chore: remove 9 dead/unreachable free providers (#3054)
* chore: remove 9 dead/unreachable free providers

Verified via HTTP probe — API endpoints return 000/404/empty:
- freetheai, enally, replicate, lepton, poolside, nomic
- astraflow, petals, nanobanana (phantom: catalog but no registry)

Also removed from: providerRegistry.ts, validation.ts,
staticModels.ts, imageValidation.ts, open-sse/config/petals.ts

* chore: remove dead astraflow providers

Remove astraflow and astraflow-cn (UCloud) — API endpoints unreachable.
Remaining dead providers (enally, freetheai, nanobanana, replicate,
lepton, petals, poolside, nomic) have working main sites but dead API
endpoints — need API keys. Will remove in follow-up.

* chore: remove 9 dead/unreachable free providers

Removed: freetheai, enally, replicate, lepton, poolside, nomic,
astraflow, petals, nanobanana

All verified as dead via live API probes (000/404/empty responses).
Cleaned from providers.ts, providerRegistry.ts, validation.ts,
staticModels.ts, and imageValidation.ts.

---------

Co-authored-by: oyi77 <oyi77@users.noreply.github.com>
2026-06-01 22:29:30 -03:00

161 lines
4.2 KiB
TypeScript

import { getImageProvider } from "@omniroute/open-sse/config/imageRegistry";
import { getProviderOutboundGuard } from "@/shared/network/outboundUrlGuard";
import {
SAFE_OUTBOUND_FETCH_PRESETS,
SafeOutboundFetchError,
getSafeOutboundFetchErrorStatus,
safeOutboundFetch,
} from "@/shared/network/safeOutboundFetch";
const IMAGE_PROVIDER_VALIDATION_ENDPOINTS: Record<
string,
{ baseUrl?: string; path: string; method?: string }
> = {
"fal-ai": {
baseUrl: "https://api.fal.ai",
path: "/v1/models?limit=1",
},
"stability-ai": {
path: "/v1/user/account",
},
"black-forest-labs": {
path: "/v1/credits",
},
recraft: {
path: "/v1/users/me",
},
topaz: {
path: "/account/v1/credits/balance",
},
};
function normalizeBaseUrl(baseUrl: string) {
return (baseUrl || "").trim().replace(/\/$/, "");
}
function applyCustomUserAgent(headers: Record<string, string>, providerSpecificData: any = {}) {
const customUserAgent =
typeof providerSpecificData?.customUserAgent === "string"
? providerSpecificData.customUserAgent.trim()
: "";
if (customUserAgent) {
headers["user-agent"] = customUserAgent;
}
return headers;
}
function toValidationErrorResult(error: unknown) {
const message = error instanceof Error ? error.message : String(error || "Validation failed");
const statusCode = getSafeOutboundFetchErrorStatus(error);
return {
valid: false,
error: message || "Validation failed",
unsupported: false,
...(statusCode ? { statusCode } : {}),
...(error instanceof SafeOutboundFetchError && error.code === "TIMEOUT"
? { timeout: true }
: {}),
...(statusCode === 400 ? { securityBlocked: true } : {}),
};
}
function buildImageProviderValidationHeaders(
imageProvider: any,
apiKey: string,
providerSpecificData: any = {}
) {
const headers: Record<string, string> = {
Accept: "application/json",
};
if (apiKey) {
switch (String(imageProvider?.authHeader || "").toLowerCase()) {
case "bearer":
headers.Authorization = `Bearer ${apiKey}`;
break;
case "key":
headers.Authorization = `Key ${apiKey}`;
break;
case "x-key":
headers["x-key"] = apiKey;
break;
case "x-api-key":
headers["X-API-Key"] = apiKey;
break;
case "none":
break;
default:
headers.Authorization = `Bearer ${apiKey}`;
break;
}
}
return applyCustomUserAgent(headers, providerSpecificData);
}
async function validationRead(url: string, init: RequestInit) {
return safeOutboundFetch(url, {
...SAFE_OUTBOUND_FETCH_PRESETS.validationRead,
guard: getProviderOutboundGuard(),
...init,
});
}
export async function validateImageProviderApiKey({
provider,
apiKey,
providerSpecificData = {},
}: any) {
const imageProvider = getImageProvider(provider);
const validationConfig = IMAGE_PROVIDER_VALIDATION_ENDPOINTS[provider];
if (!imageProvider || !validationConfig) {
return { valid: false, error: "Provider validation not supported", unsupported: true };
}
try {
const baseUrl = normalizeBaseUrl(
providerSpecificData?.baseUrl || validationConfig.baseUrl || imageProvider.baseUrl
);
const url = `${baseUrl}${validationConfig.path}`;
const response = await validationRead(url, {
method: validationConfig.method || "GET",
headers: buildImageProviderValidationHeaders(imageProvider, apiKey, providerSpecificData),
});
if (response.ok) {
return { valid: true, error: null, method: "image-provider" };
}
if (response.status === 401 || response.status === 403) {
return { valid: false, error: "Invalid API key", method: "image-provider" };
}
if (response.status === 429) {
return {
valid: false,
error: "Validation rate limited (429)",
method: "image-provider",
};
}
if (response.status >= 500) {
return {
valid: false,
error: `Provider unavailable (${response.status})`,
method: "image-provider",
};
}
return {
valid: false,
error: `Validation failed: ${response.status}`,
method: "image-provider",
};
} catch (error: any) {
return toValidationErrorResult(error);
}
}