97 lines
3.0 KiB
JavaScript
97 lines
3.0 KiB
JavaScript
/**
|
|
* Centralized proxy decision logic.
|
|
*
|
|
* Determines whether to use a CORS proxy for LLM API requests based on:
|
|
* - Provider name
|
|
* - API key pattern (for providers where it matters)
|
|
*/
|
|
/**
|
|
* Check if a provider/API key combination requires a CORS proxy.
|
|
*
|
|
* @param provider - Provider name (e.g., "anthropic", "openai", "zai")
|
|
* @param apiKey - API key for the provider
|
|
* @returns true if proxy is required, false otherwise
|
|
*/
|
|
export function shouldUseProxyForProvider(provider, apiKey) {
|
|
switch (provider.toLowerCase()) {
|
|
case "zai":
|
|
// Z-AI always requires proxy
|
|
return true;
|
|
case "anthropic":
|
|
// Anthropic OAuth tokens (sk-ant-oat-*) require proxy
|
|
// Regular API keys (sk-ant-api-*) do NOT require proxy
|
|
return apiKey.startsWith("sk-ant-oat");
|
|
// These providers work without proxy
|
|
case "openai":
|
|
case "google":
|
|
case "groq":
|
|
case "openrouter":
|
|
case "cerebras":
|
|
case "xai":
|
|
case "ollama":
|
|
case "lmstudio":
|
|
return false;
|
|
// Unknown providers - assume no proxy needed
|
|
// This allows new providers to work by default
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
/**
|
|
* Apply CORS proxy to a model's baseUrl if needed.
|
|
*
|
|
* @param model - The model to potentially proxy
|
|
* @param apiKey - API key for the provider
|
|
* @param proxyUrl - CORS proxy URL (e.g., "https://proxy.mariozechner.at/proxy")
|
|
* @returns Model with modified baseUrl if proxy is needed, otherwise original model
|
|
*/
|
|
export function applyProxyIfNeeded(model, apiKey, proxyUrl) {
|
|
// If no proxy URL configured, return original model
|
|
if (!proxyUrl) {
|
|
return model;
|
|
}
|
|
// If model has no baseUrl, can't proxy it
|
|
if (!model.baseUrl) {
|
|
return model;
|
|
}
|
|
// Check if this provider/key needs proxy
|
|
if (!shouldUseProxyForProvider(model.provider, apiKey)) {
|
|
return model;
|
|
}
|
|
// Apply proxy to baseUrl
|
|
return {
|
|
...model,
|
|
baseUrl: `${proxyUrl}/?url=${encodeURIComponent(model.baseUrl)}`,
|
|
};
|
|
}
|
|
/**
|
|
* Check if an error is likely a CORS error.
|
|
*
|
|
* CORS errors in browsers typically manifest as:
|
|
* - TypeError with message "Failed to fetch"
|
|
* - NetworkError
|
|
*
|
|
* @param error - The error to check
|
|
* @returns true if error is likely a CORS error
|
|
*/
|
|
export function isCorsError(error) {
|
|
if (!(error instanceof Error)) {
|
|
return false;
|
|
}
|
|
// Check for common CORS error patterns
|
|
const message = error.message.toLowerCase();
|
|
// "Failed to fetch" is the standard CORS error in most browsers
|
|
if (error.name === "TypeError" && message.includes("failed to fetch")) {
|
|
return true;
|
|
}
|
|
// Some browsers report "NetworkError"
|
|
if (error.name === "NetworkError") {
|
|
return true;
|
|
}
|
|
// CORS-specific messages
|
|
if (message.includes("cors") || message.includes("cross-origin")) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
//# sourceMappingURL=proxy-utils.js.map
|