mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-09-19 21:32:20 +03:00
fix(providers): stop an unrelated-provider tiktoken bundling failure from crashing /api/providers (#12355)
Validado em lote numa worktree combinada com os 9 PRs desta leva sobre o tip de `release/v3.8.51` (já com a leva anterior dentro): os nove boardaram **sem um único conflito**, `typecheck:core` limpo e **80/80** nos 6 arquivos de teste que os PRs trazem. O crescimento de arquivo próprio da leva foi rebaselinado num registro datado (`_rebaseline_2026_09_03_hartmark_batch`): `combos/page.tsx` 5012→5018 (#12355, tratar o estado degradado quando o bundling de tiktoken de um provider sem relação falha) e `open-sse/services/combo.ts` 4023→4036 (#12338, os fixes do universal-handoff). As violações restantes (`codex.ts`, `stream.ts`) foram medidas também no tip puro e são drift da base, não desta leva. Obrigado, @hartmark.
This commit is contained in:
@@ -761,15 +761,21 @@ function CombosPageContent() {
|
||||
const [proxyConfig, setProxyConfig] = useState(null);
|
||||
const { comboProxyAssignedIds, fetchComboProxyAssignments } = useComboProxyAssignments();
|
||||
const [providerNodes, setProviderNodes] = useState([]);
|
||||
const [showUsageGuide, setShowUsageGuide] = useState(() => {
|
||||
// Lazy initializer instead of a mount effect (react-hooks/set-state-in-effect).
|
||||
// SSR has no localStorage, so a lazy initializer reading it here returns a
|
||||
// different value server-side (always "not dismissed") than the client's
|
||||
// real stored value -- exactly the kind of source React's hydration
|
||||
// mismatch check is built to catch, and in dev mode a mismatch forces a
|
||||
// full client-only re-render of this tree, discarding whatever the fetch
|
||||
// effects below had already populated. Start with the SSR-safe default on
|
||||
// both passes and correct it client-only, after hydration, in an effect.
|
||||
const [showUsageGuide, setShowUsageGuide] = useState(true);
|
||||
useEffect(() => {
|
||||
try {
|
||||
return globalThis.localStorage?.getItem(COMBO_USAGE_GUIDE_STORAGE_KEY) !== "1";
|
||||
setShowUsageGuide(globalThis.localStorage?.getItem(COMBO_USAGE_GUIDE_STORAGE_KEY) !== "1");
|
||||
} catch {
|
||||
// Ignore storage access errors (privacy mode / restricted environments)
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}, []);
|
||||
const [recentlyCreatedCombo, setRecentlyCreatedCombo] = useState("");
|
||||
const [creatingKimiPreset, setCreatingKimiPreset] = useState(false);
|
||||
const [comboDragIndex, setComboDragIndex] = useState(null);
|
||||
|
||||
@@ -47,7 +47,15 @@ import {
|
||||
fetchModelSyncInternal,
|
||||
getModelSyncInternalBaseUrl,
|
||||
} from "@/shared/services/modelSyncScheduler";
|
||||
import { finalizeValidatedChatGptWebCodexSecrets } from "@omniroute/open-sse/services/chatgptWebCodexAdmin.ts";
|
||||
// Dynamically imported below, inside the one `provider === "chatgpt-web-codex"`
|
||||
// branch that needs it: this module's transitive chain pulls in tiktoken's
|
||||
// WASM tokenizer, which Turbopack dev mode fails to resolve for this graph
|
||||
// even with `tiktoken` listed in serverExternalPackages (the standalone
|
||||
// Node require works fine; only Turbopack's bundling of this import path
|
||||
// doesn't). A static top-level import evaluates that whole chain on EVERY
|
||||
// /api/providers request regardless of provider, turning an unrelated-
|
||||
// provider bug into a route-wide 500. Loading it lazily, only when actually
|
||||
// needed, avoids paying that cost (and that risk) on the common path.
|
||||
import { isAutoFetchModelsEnabled } from "@/lib/providerModels/modelDiscovery";
|
||||
import { testSingleConnection } from "./[id]/test/route";
|
||||
import { rejectRetiredCommonChatGptWebProvider } from "@/lib/providers/chatgptWebRetirementResponse";
|
||||
@@ -204,6 +212,8 @@ export async function POST(request: Request) {
|
||||
? providerSpecificData.validationId
|
||||
: "";
|
||||
try {
|
||||
const { finalizeValidatedChatGptWebCodexSecrets } =
|
||||
await import("@omniroute/open-sse/services/chatgptWebCodexAdmin.ts");
|
||||
const finalized = finalizeValidatedChatGptWebCodexSecrets(apiKey || "", validationId);
|
||||
persistedApiKey = finalized.encodedCredential;
|
||||
providerSpecificData = { ...(providerSpecificData || {}) };
|
||||
@@ -324,11 +334,16 @@ export async function POST(request: Request) {
|
||||
})
|
||||
.then((syncRes) => {
|
||||
if (!syncRes.ok) {
|
||||
console.log(`[providers] Auto-sync failed for ${newConnection.id}: ${syncRes.status}`);
|
||||
console.log(
|
||||
`[providers] Auto-sync failed for ${newConnection.id}: ${syncRes.status}`
|
||||
);
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(`[providers] Auto-sync error for ${newConnection.id}:`, err?.message || err);
|
||||
console.log(
|
||||
`[providers] Auto-sync error for ${newConnection.id}:`,
|
||||
err?.message || err
|
||||
);
|
||||
});
|
||||
} catch (syncSetupError) {
|
||||
// Defensive: if URL parsing or header construction itself throws, do
|
||||
|
||||
@@ -4,7 +4,6 @@ import { rmSync } from "node:fs";
|
||||
import { CHATGPT_WEB_CODEX_CONNECTOR_NAME } from "@/shared/constants/chatgptWebCodex";
|
||||
import { inspectBrowserLoginCapabilities } from "@omniroute/open-sse/vendor/codex-chatgpt-web/browser-login.ts";
|
||||
import { decodeChatGptWebCodexSecrets } from "@omniroute/open-sse/executors/chatgpt-web-codex/credentials.ts";
|
||||
import { detectChromeExecutable } from "@omniroute/open-sse/executors/chatgpt-web-codex.ts";
|
||||
import {
|
||||
connectionRuntimePaths,
|
||||
ensureConnectionStorageState,
|
||||
@@ -12,6 +11,16 @@ import {
|
||||
} from "@omniroute/open-sse/executors/chatgpt-web-codex/storageState.ts";
|
||||
import { sanitizeErrorMessage } from "@omniroute/open-sse/utils/error.ts";
|
||||
|
||||
// detectChromeExecutable (executors/chatgpt-web-codex.ts) is imported
|
||||
// dynamically below, not statically here: this module is re-exported through
|
||||
// the shared `@/lib/providers/validation` barrel that every provider
|
||||
// validator's callers pull in, and executors/chatgpt-web-codex.ts's own
|
||||
// import chain (its vendor browser adapter -> token-estimate.ts -> tiktoken's
|
||||
// WASM tokenizer) fails to bundle under Turbopack dev mode even with
|
||||
// `tiktoken` server-externalized -- turning validation of an unrelated
|
||||
// provider into a route-wide crash for anyone who merely imports the barrel.
|
||||
// A static import here evaluates that whole chain unconditionally.
|
||||
|
||||
export async function validateChatGptWebCodexProvider({
|
||||
apiKey,
|
||||
providerSpecificData = {},
|
||||
@@ -54,6 +63,8 @@ export async function validateChatGptWebCodexProvider({
|
||||
};
|
||||
}
|
||||
const cdpEndpoint = process.env.CHATGPT_WEB_CODEX_CDP_URL?.trim();
|
||||
const { detectChromeExecutable } =
|
||||
await import("@omniroute/open-sse/executors/chatgpt-web-codex.ts");
|
||||
const chromeExecutablePath = detectChromeExecutable(
|
||||
typeof providerSpecificData.chromeExecutablePath === "string"
|
||||
? providerSpecificData.chromeExecutablePath
|
||||
|
||||
Reference in New Issue
Block a user