chore: prepare fork docker deployment

This commit is contained in:
MUH. IQRAM BAHRING
2026-08-06 03:11:31 +08:00
parent eca3b9c3dc
commit d05b84d377
16 changed files with 397 additions and 1597 deletions
+1 -1
View File
@@ -8,7 +8,7 @@ on:
env:
GHCR_IMAGE: ghcr.io/${{ github.repository }}
DOCKERHUB_IMAGE: decolua/9router
DOCKERHUB_IMAGE: mhiqrambhrng/9router-mibp-version
jobs:
build-and-push:
+35 -1512
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -1,6 +1,6 @@
services:
9router:
image: decolua/9router:latest
image: mhiqrambhrng/9router-mibp-version:latest
container_name: 9router
restart: always
ports:
+1 -1
View File
@@ -34,7 +34,7 @@ export default {
website: "https://freebuff.com",
notice: {
signupUrl: "https://freebuff.com",
text: "Free ad-supported coding agent by Codebuff. Sign in with your Freebuff/Codebuff account via browser login. Free tier is ad-supported and limited in some regions (limited mode: 6 x 1-hour sessions/day); full mode runs in select countries.",
text: "Free ad-supported coding agent by Codebuff. Sign in with your Freebuff/Codebuff account via browser login. Free tier is ad-supported and limited in some regions (limited mode: 6 x 1-hour sessions/day); full mode runs in select countries. ⚠️ One account has ONE active session locked to ONE model — requesting a different model while a session is active returns 'model_locked' (409); use a separate account per model, or wait for the session to expire.",
},
},
category: "free",
@@ -9,27 +9,72 @@ import CooldownTimer from "./CooldownTimer";
export default function ConnectionRow({ connection, proxyPools, isOAuth, isFirst, isLast, onMoveUp, onMoveDown, onToggleActive, onUpdateProxy, onEdit, onDelete, oneByOneStatus = null, autoPing = null }) {
const [showProxyDropdown, setShowProxyDropdown] = useState(false);
const [updatingProxy, setUpdatingProxy] = useState(false);
const [selectedProxyIds, setSelectedProxyIds] = useState([]);
const [rotationStrategy, setRotationStrategy] = useState("none");
const proxyDropdownRef = useRef(null);
// Initialize proxy state from connection
useEffect(() => {
const proxyPoolIds = connection.providerSpecificData?.proxyPoolIds || [];
const legacyProxyPoolId = connection.providerSpecificData?.proxyPoolId;
// Migrate legacy single proxy to array format
if (legacyProxyPoolId && proxyPoolIds.length === 0) {
setSelectedProxyIds([legacyProxyPoolId]);
} else {
setSelectedProxyIds(proxyPoolIds);
}
setRotationStrategy(connection.providerSpecificData?.proxyRotationStrategy || "none");
}, [connection]);
const proxyPoolMap = new Map((proxyPools || []).map((pool) => [pool.id, pool]));
const boundProxyPoolId = connection.providerSpecificData?.proxyPoolId || null;
const boundProxyPool = boundProxyPoolId ? proxyPoolMap.get(boundProxyPoolId) : null;
// Display logic - support both new (multi-proxy) and legacy (single proxy) formats
const hasLegacyProxy = connection.providerSpecificData?.connectionProxyEnabled === true && !!connection.providerSpecificData?.connectionProxyUrl;
const hasAnyProxy = !!boundProxyPoolId || hasLegacyProxy;
const proxyDisplayText = boundProxyPool
? `Pool: ${boundProxyPool.name}`
: boundProxyPoolId
? `Pool: ${boundProxyPoolId} (inactive/missing)`
: hasLegacyProxy
? `Legacy: ${connection.providerSpecificData?.connectionProxyUrl}`
: "";
const hasAnyProxy = selectedProxyIds.length > 0 || hasLegacyProxy;
const getProxyDisplayText = () => {
if (selectedProxyIds.length === 0 && !hasLegacyProxy) return "";
if (selectedProxyIds.length === 1) {
const pool = proxyPoolMap.get(selectedProxyIds[0]);
return pool ? `Pool: ${pool.name}` : `Pool: ${selectedProxyIds[0]} (inactive/missing)`;
}
if (selectedProxyIds.length > 1) {
const strategyLabel = rotationStrategy === "random" ? "Random" : rotationStrategy === "round-robin" ? "Round Robin" : rotationStrategy === "failover" ? "Failover" : "Multiple";
return `${selectedProxyIds.length} pools (${strategyLabel})`;
}
if (hasLegacyProxy) {
return `Legacy: ${connection.providerSpecificData?.connectionProxyUrl}`;
}
return "";
};
const proxyDisplayText = getProxyDisplayText();
const autoPingTooltip = autoPing?.provider === "codex"
? "Auto-starts the next 5h Codex window after reset by sending a tiny gpt-5.5 request. Consumes a small amount of quota."
: "When your 5h quota runs out, auto-sends a request the moment it resets so a new window starts right away.";
let maskedProxyUrl = "";
if (boundProxyPool?.proxyUrl || connection.providerSpecificData?.connectionProxyUrl) {
const rawProxyUrl = boundProxyPool?.proxyUrl || connection.providerSpecificData?.connectionProxyUrl;
if (selectedProxyIds.length > 0) {
const selectedPools = selectedProxyIds.map(id => proxyPoolMap.get(id)).filter(Boolean);
if (selectedPools.length > 0) {
try {
const parsed = new URL(selectedPools[0].proxyUrl);
maskedProxyUrl = `${parsed.protocol}//${parsed.hostname}${parsed.port ? `:${parsed.port}` : ""}`;
if (selectedPools.length > 1) {
maskedProxyUrl += ` (+${selectedPools.length - 1} more)`;
}
} catch {
maskedProxyUrl = selectedPools[0].proxyUrl;
}
}
} else if (connection.providerSpecificData?.connectionProxyUrl) {
const rawProxyUrl = connection.providerSpecificData?.connectionProxyUrl;
try {
const parsed = new URL(rawProxyUrl);
maskedProxyUrl = `${parsed.protocol}//${parsed.hostname}${parsed.port ? `:${parsed.port}` : ""}`;
@@ -38,12 +83,15 @@ export default function ConnectionRow({ connection, proxyPools, isOAuth, isFirst
}
}
const noProxyText = boundProxyPool?.noProxy || connection.providerSpecificData?.connectionNoProxy || "";
const noProxyText = selectedProxyIds.length > 0
? proxyPoolMap.get(selectedProxyIds[0])?.noProxy || ""
: connection.providerSpecificData?.connectionNoProxy || "";
let proxyBadgeVariant = "default";
if (boundProxyPool?.isActive === true) {
proxyBadgeVariant = "success";
} else if (boundProxyPoolId || hasLegacyProxy) {
if (selectedProxyIds.length > 0) {
const allActive = selectedProxyIds.every(id => proxyPoolMap.get(id)?.isActive === true);
proxyBadgeVariant = allActive ? "success" : "error";
} else if (hasLegacyProxy) {
proxyBadgeVariant = "error";
}
@@ -59,10 +107,54 @@ export default function ConnectionRow({ connection, proxyPools, isOAuth, isFirst
return () => document.removeEventListener("mousedown", handler);
}, [showProxyDropdown]);
const handleSelectProxy = async (poolId) => {
const handleToggleProxySelection = (poolId) => {
setSelectedProxyIds(prev => {
if (prev.includes(poolId)) {
return prev.filter(id => id !== poolId);
} else {
return [...prev, poolId];
}
});
};
const handleStrategyChange = (strategy) => {
setRotationStrategy(strategy);
// Auto-select all active proxy pools when switching to rotation strategies
if (strategy !== "none" && selectedProxyIds.length === 0) {
const activePoolIds = (proxyPools || [])
.filter(pool => pool.isActive === true)
.map(pool => pool.id);
setSelectedProxyIds(activePoolIds);
}
// Reset to single proxy when switching to "none"
if (strategy === "none" && selectedProxyIds.length > 1) {
setSelectedProxyIds(selectedProxyIds.slice(0, 1));
}
};
const handleApplyProxyChanges = async () => {
setUpdatingProxy(true);
try {
await onUpdateProxy(poolId === "__none__" ? null : poolId);
await onUpdateProxy({
proxyPoolIds: selectedProxyIds,
proxyRotationStrategy: rotationStrategy,
});
setShowProxyDropdown(false);
} finally {
setUpdatingProxy(false);
}
};
const handleSelectProxy = async (poolId) => {
// Legacy single-proxy mode (backwards compatibility)
setUpdatingProxy(true);
try {
await onUpdateProxy({
proxyPoolIds: poolId === "__none__" ? [] : [poolId],
proxyRotationStrategy: "none",
});
} finally {
setUpdatingProxy(false);
setShowProxyDropdown(false);
@@ -226,22 +318,117 @@ export default function ConnectionRow({ connection, proxyPools, isOAuth, isFirst
<span className="text-[10px] leading-tight">Proxy</span>
</button>
{showProxyDropdown && (
<div className="absolute right-0 top-full z-50 mt-1 max-w-[78vw] min-w-[160px] rounded-lg border border-border bg-bg py-1 shadow-lg">
<button
onClick={() => handleSelectProxy("__none__")}
className={`w-full text-left px-3 py-1.5 text-sm hover:bg-black/5 dark:hover:bg-white/5 ${!boundProxyPoolId ? "text-primary font-medium" : "text-text-main"}`}
>
None
</button>
{(proxyPools || []).map((pool) => (
<button
key={pool.id}
onClick={() => handleSelectProxy(pool.id)}
className={`w-full text-left px-3 py-1.5 text-sm hover:bg-black/5 dark:hover:bg-white/5 ${boundProxyPoolId === pool.id ? "text-primary font-medium" : "text-text-main"}`}
<div className="absolute right-0 top-full z-50 mt-1 max-w-[90vw] min-w-[280px] rounded-lg border border-border bg-bg shadow-lg">
{/* Rotation Strategy Selector */}
<div className="border-b border-border p-3">
<label className="block text-xs font-medium text-text-muted mb-2">Rotation Strategy</label>
<select
value={rotationStrategy}
onChange={(e) => handleStrategyChange(e.target.value)}
className="w-full rounded border border-border bg-bg px-2 py-1.5 text-sm text-text-main focus:border-primary focus:outline-none"
>
{pool.name}
<option value="none">None (Single Proxy)</option>
<option value="random">Random</option>
<option value="round-robin">Round Robin</option>
<option value="failover">Failover</option>
</select>
{rotationStrategy !== "none" && (
<p className="mt-1 text-[10px] text-text-muted">
{rotationStrategy === "random" && "Randomly select proxy on each request"}
{rotationStrategy === "round-robin" && "Rotate proxies in order across requests"}
{rotationStrategy === "failover" && "Try next proxy on failure"}
</p>
)}
</div>
{/* Proxy Pool Selection */}
<div className="max-h-[60vh] overflow-y-auto py-1">
<button
onClick={() => {
setSelectedProxyIds([]);
setRotationStrategy("none");
}}
className={`w-full text-left px-3 py-2 text-sm hover:bg-black/5 dark:hover:bg-white/5 ${selectedProxyIds.length === 0 ? "text-primary font-medium" : "text-text-main"}`}
>
<div className="flex items-center gap-2">
<span className="material-symbols-outlined text-[16px]">
{selectedProxyIds.length === 0 ? "check_box" : "check_box_outline_blank"}
</span>
<span>None</span>
</div>
</button>
))}
{/* Select All Button (only for rotation strategies) */}
{rotationStrategy !== "none" && (
<button
onClick={() => {
const activePoolIds = (proxyPools || [])
.filter(pool => pool.isActive === true)
.map(pool => pool.id);
const allSelected = activePoolIds.length > 0 && activePoolIds.every(id => selectedProxyIds.includes(id));
if (allSelected) {
setSelectedProxyIds([]);
} else {
setSelectedProxyIds(activePoolIds);
}
}}
className={`w-full text-left px-3 py-2 text-sm border-b border-border hover:bg-black/5 dark:hover:bg-white/5 ${selectedProxyIds.length === (proxyPools || []).filter(p => p.isActive).length ? "bg-black/5 dark:bg-white/5" : ""}`}
>
<div className="flex items-center gap-2">
<span className="material-symbols-outlined text-[16px]">
{selectedProxyIds.length === (proxyPools || []).filter(p => p.isActive).length && selectedProxyIds.length > 0
? "check_box"
: "check_box_outline_blank"
}
</span>
<span className="font-medium">Select All Active</span>
</div>
</button>
)}
{(proxyPools || []).map((pool) => {
const isSelected = selectedProxyIds.includes(pool.id);
const isActive = pool.isActive === true;
return (
<button
key={pool.id}
onClick={() => {
if (rotationStrategy === "none") {
setSelectedProxyIds([pool.id]);
} else {
handleToggleProxySelection(pool.id);
}
}}
className={`w-full text-left px-3 py-2 text-sm hover:bg-black/5 dark:hover:bg-white/5 ${isSelected ? "bg-black/5 dark:bg-white/5" : ""}`}
>
<div className="flex items-center gap-2">
<span className="material-symbols-outlined text-[16px]">
{rotationStrategy === "none"
? (isSelected ? "radio_button_checked" : "radio_button_unchecked")
: (isSelected ? "check_box" : "check_box_outline_blank")
}
</span>
<span className={isSelected ? "text-primary font-medium" : "text-text-main"}>{pool.name}</span>
{!isActive && (
<span className="ml-auto text-[10px] text-red-500">(inactive)</span>
)}
</div>
</button>
);
})}
</div>
{/* Apply Button */}
<div className="border-t border-border p-2">
<button
onClick={handleApplyProxyChanges}
disabled={updatingProxy}
className="w-full rounded bg-primary px-3 py-2 text-sm font-medium text-white hover:bg-primary/90 disabled:opacity-50 disabled:cursor-not-allowed"
>
{updatingProxy ? "Applying..." : "Apply"}
</button>
</div>
</div>
)}
</div>
@@ -968,17 +968,39 @@ export default function ProviderDetailPage() {
onToggle: (on) => handleAutoPingConnection(conn.id, on),
provider: providerId,
} : null}
onUpdateProxy={async (proxyPoolId) => {
onUpdateProxy={async (proxyConfig) => {
try {
// Support both new format (object) and legacy format (string/null)
const updatePayload = typeof proxyConfig === 'object' && proxyConfig !== null
? {
proxyPoolIds: proxyConfig.proxyPoolIds || [],
proxyRotationStrategy: proxyConfig.proxyRotationStrategy || "none",
}
: {
// Legacy single-proxy format
proxyPoolId: proxyConfig || null,
};
const res = await fetch(`/api/providers/${conn.id}`, {
method: "PUT",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ proxyPoolId: proxyPoolId || null }),
body: JSON.stringify(updatePayload),
});
if (res.ok) {
setConnections(prev => prev.map(c =>
c.id === conn.id
? { ...c, providerSpecificData: { ...c.providerSpecificData, proxyPoolId: proxyPoolId || null } }
? {
...c,
providerSpecificData: {
...c.providerSpecificData,
...(updatePayload.proxyPoolIds !== undefined ? {
proxyPoolIds: updatePayload.proxyPoolIds,
proxyRotationStrategy: updatePayload.proxyRotationStrategy,
} : {
proxyPoolId: updatePayload.proxyPoolId,
})
}
}
: c
));
}
@@ -215,6 +215,7 @@ export async function GET(request, { params }) {
"codebuddy-intl",
"qoder",
"grok-cli",
"freebuff",
];
let deviceData;
if (noPkceDeviceProviders.includes(provider)) {
+1 -1
View File
@@ -391,7 +391,7 @@ const PROVIDER_MODELS_CONFIG = {
},
"grok-cli": {
customResolver: async (connection) => {
const proxy = await resolveConnectionProxyConfig(connection.providerSpecificData || {});
const proxy = await resolveConnectionProxyConfig(connection.providerSpecificData || {}, connection.id);
const result = await resolveGrokCliModels({
...connection,
connectionId: connection.id,
+37 -4
View File
@@ -33,7 +33,31 @@ function normalizeProxyConfig(body = {}) {
};
}
async function normalizeProxyPoolUpdate(proxyPoolIdInput) {
async function normalizeProxyPoolUpdate(body) {
// Handle new multi-proxy format
if (body.proxyPoolIds !== undefined) {
const proxyPoolIds = Array.isArray(body.proxyPoolIds) ? body.proxyPoolIds : [];
const proxyRotationStrategy = body.proxyRotationStrategy || "none";
// Validate all proxy pool IDs exist
for (const poolId of proxyPoolIds) {
if (poolId) {
const pool = await getProxyPoolById(poolId);
if (!pool) {
return { hasProxyPoolField: true, error: `Proxy pool ${poolId} not found` };
}
}
}
return {
hasProxyPoolField: true,
proxyPoolIds: proxyPoolIds.filter(Boolean),
proxyRotationStrategy,
};
}
// Handle legacy single proxy format
const proxyPoolIdInput = body.proxyPoolId;
if (proxyPoolIdInput === undefined) {
return { hasProxyPoolField: false, proxyPoolId: null };
}
@@ -111,7 +135,7 @@ export async function PUT(request, { params }) {
return NextResponse.json({ error: proxyConfig.error }, { status: 400 });
}
const proxyPoolResult = await normalizeProxyPoolUpdate(body.proxyPoolId);
const proxyPoolResult = await normalizeProxyPoolUpdate(body);
if (proxyPoolResult.error) {
return NextResponse.json({ error: proxyPoolResult.error }, { status: 400 });
}
@@ -147,10 +171,19 @@ export async function PUT(request, { params }) {
}
if (proxyPoolResult.hasProxyPoolField) {
if (proxyPoolResult.proxyPoolId === null) {
// Handle new multi-proxy format
if (proxyPoolResult.proxyPoolIds !== undefined) {
updateData.providerSpecificData.proxyPoolIds = proxyPoolResult.proxyPoolIds;
updateData.providerSpecificData.proxyRotationStrategy = proxyPoolResult.proxyRotationStrategy;
// Clear legacy field
delete updateData.providerSpecificData.proxyPoolId;
} else {
updateData.providerSpecificData.proxyPoolId = proxyPoolResult.proxyPoolId;
// Handle legacy single-proxy format
if (proxyPoolResult.proxyPoolId === null) {
delete updateData.providerSpecificData.proxyPoolId;
} else {
updateData.providerSpecificData.proxyPoolId = proxyPoolResult.proxyPoolId;
}
}
}
}
+1 -1
View File
@@ -803,7 +803,7 @@ export async function testSingleConnection(id) {
const connection = await getProviderConnectionById(id);
if (!connection) return { valid: false, error: "Connection not found", latencyMs: 0, testedAt: new Date().toISOString() };
const effectiveProxy = await resolveConnectionProxyConfig(connection.providerSpecificData || {});
const effectiveProxy = await resolveConnectionProxyConfig(connection.providerSpecificData || {}, connection.id);
if (effectiveProxy.connectionProxyEnabled && effectiveProxy.connectionProxyUrl && !effectiveProxy.vercelRelayUrl) {
const proxyResult = await testProxyUrl({ proxyUrl: effectiveProxy.connectionProxyUrl });
+1 -1
View File
@@ -145,7 +145,7 @@ export async function GET(request, { params }) {
}
// Resolve connection proxy config; force strictProxy=false so quota/refresh fall back to direct on failure
const proxyConfig = await resolveConnectionProxyConfig(connection.providerSpecificData);
const proxyConfig = await resolveConnectionProxyConfig(connection.providerSpecificData, connection.id);
const proxyOptions = {
connectionProxyEnabled: proxyConfig.connectionProxyEnabled === true,
connectionProxyUrl: proxyConfig.connectionProxyUrl || "",
+1 -1
View File
@@ -77,7 +77,7 @@ const LIVE_MODEL_RESOLVERS = {
return result?.models?.length ? { models: result.models } : null;
},
"grok-cli": async (conn) => {
const proxy = await resolveConnectionProxyConfig(conn.providerSpecificData || {});
const proxy = await resolveConnectionProxyConfig(conn.providerSpecificData || {}, conn.id);
const result = await resolveGrokCliModels({
...conn,
connectionId: conn.id,
+1
View File
@@ -8,6 +8,7 @@ const OPTIONAL_FIELDS = [
"scope", "projectId", "apiKey", "testStatus",
"lastTested", "lastError", "lastErrorAt", "rateLimitedUntil", "expiresIn", "errorCode",
"consecutiveUseCount", "idToken", "lastRefreshAt",
"proxyRotationStrategy", "proxyPoolIds",
];
function rowToConn(row) {
+70 -38
View File
@@ -59,75 +59,107 @@ function normalizeLegacyProxy(providerSpecificData = {}) {
* Resolve final proxy configuration.
*
* Priority:
* 1. Proxy Pool
* 2. Legacy Proxy
* 3. No Proxy
* 1. Multi-Proxy Pool (new format with rotation)
* 2. Single Proxy Pool (legacy)
* 3. Legacy Proxy
* 4. No Proxy
*/
export async function resolveConnectionProxyConfig(
providerSpecificData = {}
providerSpecificData = {},
connectionId = null
) {
try {
const proxyPoolIdRaw = normalizeString(
providerSpecificData?.proxyPoolId
);
// "__none__" means explicitly disabled
const proxyPoolId =
proxyPoolIdRaw === "__none__" ? "" : proxyPoolIdRaw;
// Handle new multi-proxy format
const proxyPoolIds = providerSpecificData?.proxyPoolIds || [];
const proxyRotationStrategy = providerSpecificData?.proxyRotationStrategy || "none";
// Handle legacy single-proxy format
const legacyProxyPoolId = normalizeString(providerSpecificData?.proxyPoolId);
const proxyPoolIdRaw = legacyProxyPoolId === "__none__" ? "" : legacyProxyPoolId;
const legacy = normalizeLegacyProxy(providerSpecificData);
/**
* -----------------------------
* Proxy Pool Resolution
* Multi-Proxy Pool Resolution (NEW)
* -----------------------------
*/
if (proxyPoolId) {
const proxyPool = await getProxyPoolById(proxyPoolId);
if (proxyPoolIds.length > 0) {
const selectedPoolId = pickProxyPoolId(proxyPoolIds, proxyRotationStrategy, connectionId);
if (selectedPoolId) {
const proxyPool = await getProxyPoolById(selectedPoolId);
const proxyUrl = normalizeString(proxyPool?.proxyUrl);
const noProxy = normalizeString(proxyPool?.noProxy);
const isValidPool = proxyPool && proxyPool.isActive === true && proxyUrl;
if (isValidPool) {
/**
* Vercel/Cloudflare relay proxies use base URL rewriting
* instead of HTTP_PROXY environment variables.
*/
if (proxyPool.type === "vercel" || proxyPool.type === "cloudflare" || proxyPool.type === "deno") {
return {
source: proxyPool.type,
proxyPoolId: selectedPoolId,
proxyPool,
connectionProxyEnabled: false,
connectionProxyUrl: "",
connectionNoProxy: noProxy,
strictProxy: proxyPool.strictProxy === true,
vercelRelayUrl: proxyUrl,
};
}
/**
* Standard proxy pool
*/
return {
source: "pool",
proxyPoolId: selectedPoolId,
proxyPool,
connectionProxyEnabled: true,
connectionProxyUrl: proxyUrl,
connectionNoProxy: noProxy,
strictProxy: proxyPool.strictProxy === true,
};
}
}
}
/**
* -----------------------------
* Single Proxy Pool Resolution (LEGACY)
* -----------------------------
*/
if (proxyPoolIdRaw) {
const proxyPool = await getProxyPoolById(proxyPoolIdRaw);
const proxyUrl = normalizeString(proxyPool?.proxyUrl);
const noProxy = normalizeString(proxyPool?.noProxy);
const isValidPool =
proxyPool &&
proxyPool.isActive === true &&
proxyUrl;
const isValidPool = proxyPool && proxyPool.isActive === true && proxyUrl;
if (isValidPool) {
/**
* Vercel/Cloudflare relay proxies use base URL rewriting
* instead of HTTP_PROXY environment variables.
*/
if (proxyPool.type === "vercel" || proxyPool.type === "cloudflare" || proxyPool.type === "deno") {
return {
source: proxyPool.type,
proxyPoolId,
proxyPoolId: proxyPoolIdRaw,
proxyPool,
connectionProxyEnabled: false,
connectionProxyUrl: "",
connectionNoProxy: noProxy,
strictProxy: proxyPool.strictProxy === true,
vercelRelayUrl: proxyUrl, // Still mapped to vercelRelayUrl in the unified payload since they use the exact same header spec
vercelRelayUrl: proxyUrl,
};
}
/**
* Standard proxy pool
*/
return {
source: "pool",
proxyPoolId,
proxyPoolId: proxyPoolIdRaw,
proxyPool,
connectionProxyEnabled: true,
connectionProxyUrl: proxyUrl,
connectionNoProxy: noProxy,
strictProxy: proxyPool.strictProxy === true,
};
}
@@ -145,7 +177,7 @@ export async function resolveConnectionProxyConfig(
return {
source: "legacy",
proxyPoolId: proxyPoolId || null,
proxyPoolId: proxyPoolIdRaw || null,
proxyPool: null,
...legacy,
@@ -160,7 +192,7 @@ export async function resolveConnectionProxyConfig(
return {
source: "none",
proxyPoolId: proxyPoolId || null,
proxyPoolId: proxyPoolIdRaw || null,
proxyPool: null,
...legacy,
+1
View File
@@ -234,6 +234,7 @@ export default function OAuthModal({ isOpen, provider, providerInfo, onSuccess,
"codebuddy-intl",
"qoder",
"grok-cli",
"freebuff",
];
if (deviceCodeProviders.includes(provider)) {
setIsDeviceCode(true);
+1 -1
View File
@@ -172,7 +172,7 @@ export async function getProviderCredentials(provider, excludeConnectionIds = nu
connection = availableConnections[0];
}
const resolvedProxy = await resolveConnectionProxyConfig(connection.providerSpecificData || {});
const resolvedProxy = await resolveConnectionProxyConfig(connection.providerSpecificData || {}, connection.id);
return {
authType: connection.authType,