feat(proxy): propagate account-level proxy across all surfaces
- chatSurface/openAiResponsesSurface: extract channelProxyUrl once and pass to withSiteRecordProxyRequestInit - geminiSurface: switch from withSiteProxyRequestInit to withSiteRecordProxyRequestInit with channelProxyUrl - balanceService: pass accountProxyUrl to sub2api token refresh requests - siteProxy: fix isAccountOverride to only be true when account proxy differs from site proxy - Accounts.tsx: use parseAccountExtraConfig helper for proxy badge display
This commit is contained in:
@@ -204,6 +204,7 @@ export async function handleChatSurfaceRequest(
|
||||
runtime: endpointRequest.runtime,
|
||||
};
|
||||
};
|
||||
const channelProxyUrl = resolveChannelProxyUrl(selected.site, selected.account.extraConfig);
|
||||
const dispatchRequest = (
|
||||
compatibilityRequest: BuiltEndpointRequest,
|
||||
targetUrl?: string,
|
||||
@@ -216,7 +217,7 @@ export async function handleChatSurfaceRequest(
|
||||
method: 'POST',
|
||||
headers: requestForFetch.headers,
|
||||
body: JSON.stringify(requestForFetch.body),
|
||||
}),
|
||||
}, channelProxyUrl),
|
||||
})
|
||||
);
|
||||
const endpointStrategy = downstreamTransformer.compatibility.createEndpointStrategy({
|
||||
@@ -265,7 +266,6 @@ export async function handleChatSurfaceRequest(
|
||||
try {
|
||||
const endpointResult = await executeEndpointFlow({
|
||||
siteUrl: selected.site.url,
|
||||
proxyUrl: resolveChannelProxyUrl(selected.site, selected.account.extraConfig),
|
||||
endpointCandidates,
|
||||
buildRequest: (endpoint) => buildEndpointRequest(endpoint),
|
||||
dispatchRequest,
|
||||
|
||||
@@ -9,7 +9,7 @@ import { isModelAllowedByPolicyOrAllowedRoutes } from '../../services/downstream
|
||||
import { tokenRouter } from '../../services/tokenRouter.js';
|
||||
import { buildOauthProviderHeaders } from '../../services/oauth/service.js';
|
||||
import { getOauthInfoFromExtraConfig } from '../../services/oauth/oauthAccount.js';
|
||||
import { withSiteProxyRequestInit } from '../../services/siteProxy.js';
|
||||
import { resolveChannelProxyUrl, withSiteRecordProxyRequestInit } from '../../services/siteProxy.js';
|
||||
import { refreshModelsAndRebuildRoutes } from '../../services/modelService.js';
|
||||
import { getDownstreamRoutingPolicy } from '../../routes/proxy/downstreamPolicy.js';
|
||||
import { executeEndpointFlow, type BuiltEndpointRequest } from '../../routes/proxy/endpointFlow.js';
|
||||
@@ -470,6 +470,7 @@ export async function geminiProxyRoute(app: FastifyInstance) {
|
||||
selected.tokenValue,
|
||||
query,
|
||||
);
|
||||
const channelProxyUrl = resolveChannelProxyUrl(selected.site, selected.account.extraConfig);
|
||||
const upstream = isInternalGemini
|
||||
? await dispatchRuntimeRequest({
|
||||
siteUrl: selected.site.url,
|
||||
@@ -489,11 +490,11 @@ export async function geminiProxyRoute(app: FastifyInstance) {
|
||||
: (isStreamAction ? 'streamGenerateContent' : 'generateContent'),
|
||||
},
|
||||
},
|
||||
buildInit: async (requestUrl, requestForFetch) => withSiteProxyRequestInit(requestUrl, {
|
||||
buildInit: async (_requestUrl, requestForFetch) => withSiteRecordProxyRequestInit(selected.site, {
|
||||
method: 'POST',
|
||||
headers: requestForFetch.headers,
|
||||
body: JSON.stringify(requestForFetch.body),
|
||||
}),
|
||||
}, channelProxyUrl),
|
||||
})
|
||||
: await fetch(targetUrl, {
|
||||
method: 'POST',
|
||||
@@ -741,16 +742,17 @@ export async function geminiProxyRoute(app: FastifyInstance) {
|
||||
runtime: endpointRequest.runtime,
|
||||
};
|
||||
};
|
||||
const channelProxyUrl = resolveChannelProxyUrl(selected.site, selected.account.extraConfig);
|
||||
const dispatchRequest = (compatibilityRequest: BuiltEndpointRequest, targetUrl?: string) => (
|
||||
dispatchRuntimeRequest({
|
||||
siteUrl: selected.site.url,
|
||||
targetUrl,
|
||||
request: compatibilityRequest,
|
||||
buildInit: async (requestUrl, requestForFetch) => withSiteProxyRequestInit(requestUrl, {
|
||||
buildInit: async (_requestUrl, requestForFetch) => withSiteRecordProxyRequestInit(selected.site, {
|
||||
method: 'POST',
|
||||
headers: requestForFetch.headers,
|
||||
body: JSON.stringify(requestForFetch.body),
|
||||
}),
|
||||
}, channelProxyUrl),
|
||||
})
|
||||
);
|
||||
const endpointStrategy = createChatEndpointStrategy({
|
||||
|
||||
@@ -304,6 +304,7 @@ export async function handleOpenAiResponsesSurfaceRequest(
|
||||
runtime: endpointRequest.runtime,
|
||||
};
|
||||
};
|
||||
const channelProxyUrl = resolveChannelProxyUrl(selected.site, selected.account.extraConfig);
|
||||
const dispatchRequest = (compatibilityRequest: BuiltEndpointRequest, targetUrl?: string) => (
|
||||
dispatchRuntimeRequest({
|
||||
siteUrl: selected.site.url,
|
||||
@@ -313,7 +314,7 @@ export async function handleOpenAiResponsesSurfaceRequest(
|
||||
method: 'POST',
|
||||
headers: requestForFetch.headers,
|
||||
body: JSON.stringify(requestForFetch.body),
|
||||
}),
|
||||
}, channelProxyUrl),
|
||||
})
|
||||
);
|
||||
const endpointStrategy = openAiResponsesTransformer.compatibility.createEndpointStrategy({
|
||||
@@ -355,7 +356,6 @@ export async function handleOpenAiResponsesSurfaceRequest(
|
||||
try {
|
||||
const endpointResult = await executeEndpointFlow({
|
||||
siteUrl: selected.site.url,
|
||||
proxyUrl: resolveChannelProxyUrl(selected.site, selected.account.extraConfig),
|
||||
endpointCandidates,
|
||||
buildRequest: (endpoint) => buildEndpointRequest(endpoint),
|
||||
dispatchRequest,
|
||||
|
||||
@@ -201,7 +201,7 @@ async function refreshSub2ApiManagedSession(params: {
|
||||
method: 'POST',
|
||||
headers,
|
||||
body: JSON.stringify({ refresh_token: refreshToken }),
|
||||
}));
|
||||
}, getProxyUrlFromExtraConfig(params.account.extraConfig)));
|
||||
payload = await response.json().catch(() => null);
|
||||
} catch (err: any) {
|
||||
throw new Error(err?.message || 'sub2api token refresh request failed');
|
||||
@@ -382,23 +382,23 @@ export async function refreshBalance(accountId: number) {
|
||||
let activeExtraConfig = account.extraConfig;
|
||||
let balanceInfo: BalanceInfo | null = null;
|
||||
|
||||
const accountProxyUrl = getProxyUrlFromExtraConfig(account.extraConfig);
|
||||
|
||||
if (isSub2ApiPlatform(site.platform)) {
|
||||
const managedAuth = getSub2ApiAuthFromExtraConfig(activeExtraConfig);
|
||||
if (managedAuth?.refreshToken && isNearTokenExpiry(managedAuth.tokenExpiresAt)) {
|
||||
try {
|
||||
const refreshed = await refreshSub2ApiManagedSession({
|
||||
const refreshed = await withAccountProxyOverride(accountProxyUrl, () => refreshSub2ApiManagedSession({
|
||||
account,
|
||||
site,
|
||||
currentAccessToken: activeAccessToken,
|
||||
currentExtraConfig: activeExtraConfig,
|
||||
});
|
||||
}));
|
||||
activeAccessToken = refreshed.accessToken;
|
||||
activeExtraConfig = refreshed.extraConfig;
|
||||
} catch {}
|
||||
}
|
||||
}
|
||||
|
||||
const accountProxyUrl = getProxyUrlFromExtraConfig(account.extraConfig);
|
||||
const readBalance = async (token: string) => withAccountProxyOverride(accountProxyUrl,
|
||||
() => adapter.getBalance(site.url, token, platformUserId));
|
||||
const handleBalanceError = async (err: any) => {
|
||||
|
||||
@@ -470,8 +470,10 @@ export function withSiteRecordProxyRequestInit(
|
||||
nextOptions.headers = mergedHeaders;
|
||||
}
|
||||
const accountNormalized = normalizeSiteProxyUrl(accountProxyUrl);
|
||||
const proxyUrl = accountNormalized || resolveProxyUrlForSite(site);
|
||||
return withExplicitProxyRequestInit(proxyUrl, nextOptions, !!accountNormalized);
|
||||
const siteProxyUrl = resolveProxyUrlForSite(site);
|
||||
const proxyUrl = accountNormalized || siteProxyUrl;
|
||||
const isAccountOverride = !!accountNormalized && accountNormalized !== siteProxyUrl;
|
||||
return withExplicitProxyRequestInit(proxyUrl, nextOptions, isAccountOverride);
|
||||
}
|
||||
|
||||
export function resolveChannelProxyUrl(
|
||||
|
||||
Reference in New Issue
Block a user