mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-19 21:52:21 +03:00
fix(resilience): route remaining credential-selection call sites through quota preflight (#6686) (#6742)
* fix(resilience): route remaining credential-selection call sites through quota preflight (#6686) * chore(6742): re-sync onto release tip; CHANGELOG entry → changelog.d fragment (fragments-first)
This commit is contained in:
committed by
GitHub
parent
2ef88763e4
commit
249462d1ff
@@ -1,6 +1,9 @@
|
||||
import { handleAudioSpeech } from "@omniroute/open-sse/handlers/audioSpeech.ts";
|
||||
import { withInjectionGuard } from "@/middleware/promptInjectionGuard";
|
||||
import { getProviderCredentials, clearRecoveredProviderState } from "@/sse/services/auth";
|
||||
import {
|
||||
getProviderCredentialsWithQuotaPreflight,
|
||||
clearRecoveredProviderState,
|
||||
} from "@/sse/services/auth";
|
||||
import {
|
||||
parseSpeechModel,
|
||||
getSpeechProvider,
|
||||
@@ -95,7 +98,7 @@ async function postHandler(request, context) {
|
||||
// Get credentials — skip for local providers (authType: "none")
|
||||
let credentials = null;
|
||||
if (providerConfig && providerConfig.authType !== "none") {
|
||||
credentials = await getProviderCredentials(provider);
|
||||
credentials = await getProviderCredentialsWithQuotaPreflight(provider);
|
||||
if (!credentials) {
|
||||
return errorResponse(HTTP_STATUS.BAD_REQUEST, `No credentials for provider: ${provider}`);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
// Allow large audio/video file uploads — 5min for processing large files (up to 2GB)
|
||||
export const maxDuration = 300;
|
||||
import { handleAudioTranscription } from "@omniroute/open-sse/handlers/audioTranscription.ts";
|
||||
import { getProviderCredentials, clearRecoveredProviderState } from "@/sse/services/auth";
|
||||
import {
|
||||
getProviderCredentialsWithQuotaPreflight,
|
||||
clearRecoveredProviderState,
|
||||
} from "@/sse/services/auth";
|
||||
import {
|
||||
parseTranscriptionModel,
|
||||
getTranscriptionProvider,
|
||||
@@ -96,7 +99,7 @@ export async function POST(request) {
|
||||
// Get credentials — skip for local providers (authType: "none")
|
||||
let credentials = null;
|
||||
if (providerConfig && providerConfig.authType !== "none") {
|
||||
credentials = await getProviderCredentials(provider);
|
||||
credentials = await getProviderCredentialsWithQuotaPreflight(provider);
|
||||
if (!credentials) {
|
||||
return errorResponse(HTTP_STATUS.BAD_REQUEST, `No credentials for provider: ${provider}`);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
// Allow large audio/video file uploads — 5min for processing large files (up to 2GB)
|
||||
export const maxDuration = 300;
|
||||
import { handleAudioTranslation } from "@omniroute/open-sse/handlers/audioTranslation.ts";
|
||||
import { getProviderCredentials, clearRecoveredProviderState } from "@/sse/services/auth";
|
||||
import {
|
||||
getProviderCredentialsWithQuotaPreflight,
|
||||
clearRecoveredProviderState,
|
||||
} from "@/sse/services/auth";
|
||||
import {
|
||||
parseTranslationModel,
|
||||
getTranslationProvider,
|
||||
@@ -98,7 +101,7 @@ export async function POST(request) {
|
||||
// Get credentials — skip for local providers (authType: "none")
|
||||
let credentials = null;
|
||||
if (providerConfig && providerConfig.authType !== "none") {
|
||||
credentials = await getProviderCredentials(provider);
|
||||
credentials = await getProviderCredentialsWithQuotaPreflight(provider);
|
||||
if (!credentials) {
|
||||
return errorResponse(HTTP_STATUS.BAD_REQUEST, `No credentials for provider: ${provider}`);
|
||||
}
|
||||
|
||||
@@ -3,7 +3,10 @@ import {
|
||||
handleOpenAIImageEdit,
|
||||
} from "@omniroute/open-sse/handlers/imageGeneration.ts";
|
||||
import { withInjectionGuard } from "@/middleware/promptInjectionGuard";
|
||||
import { getProviderCredentials, clearRecoveredProviderState } from "@/sse/services/auth";
|
||||
import {
|
||||
getProviderCredentialsWithQuotaPreflight,
|
||||
clearRecoveredProviderState,
|
||||
} from "@/sse/services/auth";
|
||||
import { parseImageModel, getImageProvider } from "@omniroute/open-sse/config/imageRegistry.ts";
|
||||
import { errorResponse, unavailableResponse } from "@omniroute/open-sse/utils/error.ts";
|
||||
import { HTTP_STATUS } from "@omniroute/open-sse/config/constants.ts";
|
||||
@@ -172,7 +175,7 @@ async function postHandler(request: Request, context) {
|
||||
|
||||
// chatgpt-web keeps its conversation-continuation edit flow unchanged.
|
||||
if (providerConfig?.format === "chatgpt-web") {
|
||||
const credentials = await getProviderCredentials(
|
||||
const credentials = await getProviderCredentialsWithQuotaPreflight(
|
||||
parsed.provider,
|
||||
null,
|
||||
allowedConnections,
|
||||
@@ -241,7 +244,7 @@ async function postHandler(request: Request, context) {
|
||||
);
|
||||
}
|
||||
|
||||
const credentials = await getProviderCredentials(
|
||||
const credentials = await getProviderCredentialsWithQuotaPreflight(
|
||||
customProviderId,
|
||||
null,
|
||||
allowedConnections,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { handleImageGeneration } from "@omniroute/open-sse/handlers/imageGeneration.ts";
|
||||
import { withInjectionGuard } from "@/middleware/promptInjectionGuard";
|
||||
import {
|
||||
getProviderCredentials,
|
||||
getProviderCredentialsWithQuotaPreflight,
|
||||
clearRecoveredProviderState,
|
||||
extractApiKey,
|
||||
isValidApiKey,
|
||||
@@ -171,7 +171,7 @@ async function postHandler(request, context) {
|
||||
// Get credentials — skip for local providers (authType: "none")
|
||||
let credentials = null;
|
||||
if (providerConfig && providerConfig.authType !== "none") {
|
||||
credentials = await getProviderCredentials(provider);
|
||||
credentials = await getProviderCredentialsWithQuotaPreflight(provider);
|
||||
if (!credentials) {
|
||||
return errorResponse(
|
||||
HTTP_STATUS.BAD_REQUEST,
|
||||
@@ -187,7 +187,7 @@ async function postHandler(request, context) {
|
||||
);
|
||||
}
|
||||
} else if (isCustomModel) {
|
||||
credentials = await getProviderCredentials(provider);
|
||||
credentials = await getProviderCredentialsWithQuotaPreflight(provider);
|
||||
if (!credentials) {
|
||||
return errorResponse(
|
||||
HTTP_STATUS.BAD_REQUEST,
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
import { handleModeration } from "@omniroute/open-sse/handlers/moderations.ts";
|
||||
import { getProviderCredentials, clearRecoveredProviderState } from "@/sse/services/auth";
|
||||
import {
|
||||
getProviderCredentialsWithQuotaPreflight,
|
||||
clearRecoveredProviderState,
|
||||
} from "@/sse/services/auth";
|
||||
import { withInjectionGuard } from "@/middleware/promptInjectionGuard";
|
||||
import { parseModerationModel } from "@omniroute/open-sse/config/moderationRegistry.ts";
|
||||
import { errorResponse } from "@omniroute/open-sse/utils/error.ts";
|
||||
@@ -52,7 +55,7 @@ async function postHandler(request, context) {
|
||||
|
||||
// Default to openai if no provider prefix
|
||||
const resolvedProvider = provider || "openai";
|
||||
const credentials = await getProviderCredentials(resolvedProvider);
|
||||
const credentials = await getProviderCredentialsWithQuotaPreflight(resolvedProvider);
|
||||
if (!credentials) {
|
||||
return errorResponse(
|
||||
HTTP_STATUS.BAD_REQUEST,
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
import { handleMusicGeneration } from "@omniroute/open-sse/handlers/musicGeneration.ts";
|
||||
import { withInjectionGuard } from "@/middleware/promptInjectionGuard";
|
||||
import { getProviderCredentials, clearRecoveredProviderState } from "@/sse/services/auth";
|
||||
import {
|
||||
getProviderCredentialsWithQuotaPreflight,
|
||||
clearRecoveredProviderState,
|
||||
} from "@/sse/services/auth";
|
||||
import { parseMusicModel, getMusicProvider } from "@omniroute/open-sse/config/musicRegistry.ts";
|
||||
import { errorResponse } from "@omniroute/open-sse/utils/error.ts";
|
||||
import { HTTP_STATUS } from "@omniroute/open-sse/config/constants.ts";
|
||||
@@ -72,7 +75,7 @@ async function postHandler(request, context) {
|
||||
// Get credentials — skip for local providers (authType: "none")
|
||||
let credentials = null;
|
||||
if (providerConfig && providerConfig.authType !== "none") {
|
||||
credentials = await getProviderCredentials(provider);
|
||||
credentials = await getProviderCredentialsWithQuotaPreflight(provider);
|
||||
if (!credentials) {
|
||||
return errorResponse(
|
||||
HTTP_STATUS.BAD_REQUEST,
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
import { handleOcr } from "@omniroute/open-sse/handlers/ocr.ts";
|
||||
import { getProviderCredentials, clearRecoveredProviderState } from "@/sse/services/auth";
|
||||
import {
|
||||
getProviderCredentialsWithQuotaPreflight,
|
||||
clearRecoveredProviderState,
|
||||
} from "@/sse/services/auth";
|
||||
import { withInjectionGuard } from "@/middleware/promptInjectionGuard";
|
||||
import { parseOcrModel } from "@omniroute/open-sse/config/ocrRegistry.ts";
|
||||
import { errorResponse } from "@omniroute/open-sse/utils/error.ts";
|
||||
@@ -52,7 +55,7 @@ async function postHandler(request, context) {
|
||||
|
||||
// Default to mistral if no provider prefix
|
||||
const resolvedProvider = provider || "mistral";
|
||||
const credentials = await getProviderCredentials(resolvedProvider);
|
||||
const credentials = await getProviderCredentialsWithQuotaPreflight(resolvedProvider);
|
||||
if (!credentials) {
|
||||
return errorResponse(
|
||||
HTTP_STATUS.BAD_REQUEST,
|
||||
|
||||
@@ -2,7 +2,7 @@ import { errorResponse, unavailableResponse } from "@omniroute/open-sse/utils/er
|
||||
import { HTTP_STATUS } from "@omniroute/open-sse/config/constants.ts";
|
||||
import { getRegistryEntry } from "@omniroute/open-sse/config/providerRegistry.ts";
|
||||
import {
|
||||
getProviderCredentials,
|
||||
getProviderCredentialsWithQuotaPreflight,
|
||||
clearRecoveredProviderState,
|
||||
extractApiKey,
|
||||
isValidApiKey,
|
||||
@@ -71,7 +71,7 @@ export async function POST(request, { params }) {
|
||||
}
|
||||
}
|
||||
|
||||
const credentials = await getProviderCredentials(providerEntry.id);
|
||||
const credentials = await getProviderCredentialsWithQuotaPreflight(providerEntry.id);
|
||||
if (!credentials) {
|
||||
return errorResponse(HTTP_STATUS.BAD_REQUEST, `No credentials for provider: ${rawProvider}`);
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ import { handleImageGeneration } from "@omniroute/open-sse/handlers/imageGenerat
|
||||
import { errorResponse, unavailableResponse } from "@omniroute/open-sse/utils/error.ts";
|
||||
import { HTTP_STATUS } from "@omniroute/open-sse/config/constants.ts";
|
||||
import {
|
||||
getProviderCredentials,
|
||||
getProviderCredentialsWithQuotaPreflight,
|
||||
clearRecoveredProviderState,
|
||||
extractApiKey,
|
||||
isValidApiKey,
|
||||
@@ -68,7 +68,7 @@ export async function POST(request, { params }) {
|
||||
);
|
||||
}
|
||||
|
||||
const credentials = await getProviderCredentials(rawProvider);
|
||||
const credentials = await getProviderCredentialsWithQuotaPreflight(rawProvider);
|
||||
if (!credentials) {
|
||||
return errorResponse(
|
||||
HTTP_STATUS.BAD_REQUEST,
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
import { handleRerank } from "@omniroute/open-sse/handlers/rerank.ts";
|
||||
import { getProviderCredentials, clearRecoveredProviderState } from "@/sse/services/auth";
|
||||
import {
|
||||
getProviderCredentialsWithQuotaPreflight,
|
||||
clearRecoveredProviderState,
|
||||
} from "@/sse/services/auth";
|
||||
import { withInjectionGuard } from "@/middleware/promptInjectionGuard";
|
||||
import { parseRerankModel, getRerankProvider } from "@omniroute/open-sse/config/rerankRegistry.ts";
|
||||
import { errorResponse } from "@omniroute/open-sse/utils/error.ts";
|
||||
@@ -102,7 +105,7 @@ async function postHandler(request, context) {
|
||||
|
||||
if (provider) {
|
||||
// Cloud provider matched
|
||||
const credentials = await getProviderCredentials(provider);
|
||||
const credentials = await getProviderCredentialsWithQuotaPreflight(provider);
|
||||
if (!credentials) {
|
||||
return errorResponse(HTTP_STATUS.BAD_REQUEST, `No credentials for provider: ${provider}`);
|
||||
}
|
||||
@@ -132,7 +135,7 @@ async function postHandler(request, context) {
|
||||
const localProvider = localProviders.find((p) => p.id === prefix);
|
||||
|
||||
if (localProvider) {
|
||||
const credentials = await getProviderCredentials(localProvider.providerId);
|
||||
const credentials = await getProviderCredentialsWithQuotaPreflight(localProvider.providerId);
|
||||
if (!credentials) {
|
||||
return errorResponse(
|
||||
HTTP_STATUS.BAD_REQUEST,
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
import { handleSearch } from "@omniroute/open-sse/handlers/search.ts";
|
||||
import { getProviderCredentials, extractApiKey, isValidApiKey } from "@/sse/services/auth";
|
||||
import {
|
||||
getProviderCredentialsWithQuotaPreflight,
|
||||
extractApiKey,
|
||||
isValidApiKey,
|
||||
} from "@/sse/services/auth";
|
||||
import {
|
||||
getAllSearchProviders,
|
||||
getSearchProvider,
|
||||
@@ -64,13 +68,15 @@ type SearchCredentials = Record<string, any>;
|
||||
type SearchCredentialLookup = SearchCredentials | RateLimitedCredentials | null;
|
||||
|
||||
async function resolveSearchCredentials(providerId: string): Promise<SearchCredentialLookup> {
|
||||
const credentials = await getProviderCredentials(providerId).catch(() => null);
|
||||
const credentials = await getProviderCredentialsWithQuotaPreflight(providerId).catch(() => null);
|
||||
if (credentials && !isAllRateLimitedCredentials(credentials)) return credentials;
|
||||
|
||||
const fallbackId = SEARCH_CREDENTIAL_FALLBACKS[providerId];
|
||||
if (!fallbackId) return credentials;
|
||||
|
||||
const fallbackCredentials = await getProviderCredentials(fallbackId).catch(() => null);
|
||||
const fallbackCredentials = await getProviderCredentialsWithQuotaPreflight(fallbackId).catch(
|
||||
() => null
|
||||
);
|
||||
if (fallbackCredentials && !isAllRateLimitedCredentials(fallbackCredentials)) {
|
||||
return fallbackCredentials;
|
||||
}
|
||||
@@ -180,7 +186,9 @@ async function postHandler(request: Request, context: unknown) {
|
||||
// Sort by cost to find cheapest with credentials (fallback-only providers
|
||||
// are reached via the last-resort step below, never the primary pick).
|
||||
const sortedIds = Object.values(SEARCH_PROVIDERS)
|
||||
.filter((provider) => !provider.fallbackOnly && supportsSearchType(provider, body.search_type))
|
||||
.filter(
|
||||
(provider) => !provider.fallbackOnly && supportsSearchType(provider, body.search_type)
|
||||
)
|
||||
.sort((a, b) => a.costPerQuery - b.costPerQuery)
|
||||
.map((p) => p.id);
|
||||
|
||||
@@ -216,7 +224,9 @@ async function postHandler(request: Request, context: unknown) {
|
||||
// Find alternate for failover — must bind credentials to the matched provider.
|
||||
// Exclude fallback-only providers; they are only used by the last-resort step.
|
||||
const otherIds = Object.values(SEARCH_PROVIDERS)
|
||||
.filter((provider) => !provider.fallbackOnly && supportsSearchType(provider, body.search_type))
|
||||
.filter(
|
||||
(provider) => !provider.fallbackOnly && supportsSearchType(provider, body.search_type)
|
||||
)
|
||||
.sort((a, b) => a.costPerQuery - b.costPerQuery)
|
||||
.map((p) => p.id)
|
||||
.filter((id) => id !== providerConfig.id);
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
import { handleVideoGeneration } from "@omniroute/open-sse/handlers/videoGeneration.ts";
|
||||
import { resolveVideoCredentialProvider } from "@omniroute/open-sse/handlers/videoGeneration/googleFlow.ts";
|
||||
import { withInjectionGuard } from "@/middleware/promptInjectionGuard";
|
||||
import { getProviderCredentials, clearRecoveredProviderState } from "@/sse/services/auth";
|
||||
import {
|
||||
getProviderCredentialsWithQuotaPreflight,
|
||||
clearRecoveredProviderState,
|
||||
} from "@/sse/services/auth";
|
||||
import { parseVideoModel, getVideoProvider } from "@omniroute/open-sse/config/videoRegistry.ts";
|
||||
import { errorResponse } from "@omniroute/open-sse/utils/error.ts";
|
||||
import { HTTP_STATUS } from "@omniroute/open-sse/config/constants.ts";
|
||||
@@ -75,7 +78,9 @@ async function postHandler(request, context) {
|
||||
// OAuth credential (resolveVideoCredentialProvider maps googleflow → antigravity).
|
||||
let credentials = null;
|
||||
if (providerConfig && providerConfig.authType !== "none") {
|
||||
credentials = await getProviderCredentials(resolveVideoCredentialProvider(provider));
|
||||
credentials = await getProviderCredentialsWithQuotaPreflight(
|
||||
resolveVideoCredentialProvider(provider)
|
||||
);
|
||||
if (!credentials) {
|
||||
return errorResponse(
|
||||
HTTP_STATUS.BAD_REQUEST,
|
||||
|
||||
@@ -12,7 +12,11 @@ import { errorResponse } from "@omniroute/open-sse/utils/error.ts";
|
||||
import { HTTP_STATUS } from "@omniroute/open-sse/config/constants.ts";
|
||||
import { handleWebFetch } from "@omniroute/open-sse/handlers/webFetch.ts";
|
||||
import * as log from "@/sse/utils/logger";
|
||||
import { extractApiKey, isValidApiKey, getProviderCredentials } from "@/sse/services/auth";
|
||||
import {
|
||||
extractApiKey,
|
||||
isValidApiKey,
|
||||
getProviderCredentialsWithQuotaPreflight,
|
||||
} from "@/sse/services/auth";
|
||||
import { enforceApiKeyPolicy } from "@/shared/utils/apiKeyPolicy";
|
||||
import { isRequireApiKeyEnabled } from "@/shared/utils/featureFlags";
|
||||
import { v1WebFetchSchema } from "@/shared/validation/schemas";
|
||||
@@ -38,7 +42,7 @@ async function resolveCredentials(
|
||||
providerId: WebFetchProviderId
|
||||
): Promise<{ apiKey?: string } | null> {
|
||||
try {
|
||||
const creds = await getProviderCredentials(providerId);
|
||||
const creds = await getProviderCredentialsWithQuotaPreflight(providerId);
|
||||
return creds ?? null;
|
||||
} catch {
|
||||
return null;
|
||||
|
||||
Reference in New Issue
Block a user