Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- **fix(providers):** lazily load `chatgpt-web-codex` admin helpers in `PUT /api/providers/[id]`, mirroring #12355's exact pattern for the sibling `POST` route — a source-inspection test pins the import-graph invariant, since Turbopack's client-bundle boundary can't be exercised from the test harness directly ([#13071](https://github.com/diegosouzapw/OmniRoute/pull/13071)).
20 changes: 15 additions & 5 deletions src/app/api/providers/[id]/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,16 @@ import {
enableRateLimitProtection,
disableRateLimitProtection,
} from "@/../open-sse/services/rateLimitManager";
import {
finalizeValidatedChatGptWebCodexSecrets,
decodeChatGptWebCodexSecrets,
encodeChatGptWebCodexSecrets,
} from "@omniroute/open-sse/services/chatgptWebCodexAdmin.ts";
// Dynamically imported below, inside the one `provider === "chatgpt-web-codex"`
// branch that needs it -- same fix as #12355 (src/app/api/providers/route.ts),
// which missed this identical pattern in the by-id route. 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. A static top-level import evaluates that whole
// chain on EVERY PUT to this route regardless of provider, turning an
// unrelated-provider bundling bug into a route-wide 500 (observed live: PUT
// on a plain openai-compatible connection's rename failed with "Missing
// tiktoken_bg.wasm" after 17-50s, never touching chatgpt-web-codex at all).
import { rejectRetiredCommonChatGptWebProvider } from "@/lib/providers/chatgptWebRetirementResponse";

function normalizeCodexLimitPolicy(
Expand Down Expand Up @@ -178,6 +183,11 @@ export async function PUT(request: Request, { params }: { params: Promise<{ id:
? incomingPsd.validationId
: "";
try {
const {
finalizeValidatedChatGptWebCodexSecrets,
decodeChatGptWebCodexSecrets,
encodeChatGptWebCodexSecrets,
} = await import("@omniroute/open-sse/services/chatgptWebCodexAdmin.ts");
const incomingSecrets = decodeChatGptWebCodexSecrets(apiKey);
const existingSecrets = decodeChatGptWebCodexSecrets(existing.apiKey || "");
const encoded = encodeChatGptWebCodexSecrets({
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// #12355 fixed a static top-level import of chatgptWebCodexAdmin.ts in
// src/app/api/providers/route.ts: that module's transitive chain (the vendor
// ChatGPT-Web browser adapter -> token-estimate.ts -> tiktoken's WASM
// tokenizer) fails to bundle under Turbopack dev mode even with tiktoken
// listed in serverExternalPackages, so a static import evaluated that whole
// chain on EVERY request to the route regardless of provider, turning one
// unrelated provider's bundling bug into a route-wide 500 for everyone.
//
// #12355 only touched the collection route (POST /api/providers) and missed
// the identical pattern in the by-id route (PUT /api/providers/[id]) --
// observed live: renaming a plain openai-compatible connection failed with
// "Missing tiktoken_bg.wasm" after 17-50s, having never touched
// chatgpt-web-codex at all. #12355 also shipped with no regression test,
// which is exactly how the sibling instance went unnoticed.
//
// This pins BOTH general provider routes to stay lazy, and confirms the one
// legitimately-static import (the chatgpt-web-codex-only "doctor" diagnostic
// route, where every request already is for that provider) is left alone --
// this is a source-inspection test, matching
// tests/unit/instrumentation-import-graph-12074.test.ts's own pattern for
// import-graph invariants that can't be exercised by actually bundling under
// Turbopack from this harness.

import assert from "node:assert/strict";
import fs from "node:fs";
import path from "node:path";
import test from "node:test";

const STATIC_IMPORT_RE = /^import\s+[\s\S]*?from\s+["']@omniroute\/open-sse\/services\/chatgptWebCodexAdmin\.ts["'];?\s*$/m;
const DYNAMIC_IMPORT_RE = /await import\(["']@omniroute\/open-sse\/services\/chatgptWebCodexAdmin\.ts["']\)/;

function readSource(relativePath: string): string {
return fs.readFileSync(path.join(process.cwd(), relativePath), "utf8");
}

for (const routePath of [
"src/app/api/providers/route.ts",
"src/app/api/providers/[id]/route.ts",
]) {
test(`${routePath} does not statically import chatgptWebCodexAdmin.ts`, () => {
const source = readSource(routePath);
assert.doesNotMatch(
source,
STATIC_IMPORT_RE,
`${routePath} handles every provider, not just chatgpt-web-codex -- a static import here ` +
"evaluates tiktoken's bundling-fragile chain on every request regardless of provider"
);
assert.match(
source,
DYNAMIC_IMPORT_RE,
`${routePath} must still load chatgptWebCodexAdmin.ts lazily where it's actually needed`
);
});
}

test("the chatgpt-web-codex-doctor route is intentionally exempt (every request there already is that provider)", () => {
const source = readSource(
"src/app/api/providers/[id]/chatgpt-web-codex-doctor/route.ts"
);
assert.match(
source,
STATIC_IMPORT_RE,
"this route only ever serves chatgpt-web-codex connections -- a static import here is correct, " +
"not the #12355 bug; if this assertion starts failing because the import was lazily moved, that's " +
"fine too, just update this test to match"
);
});
Loading