[URGENT] fix(dev): reduce instrumentation executor fan-out (phase 3) (#12078)

* fix(dev): reduce instrumentation executor fan-out

* fix(ci): reduce credential refresh complexity

---------

Co-authored-by: backryun <backryun@daonlab.local>
This commit is contained in:
backryun
2026-09-01 02:13:46 +09:00
committed by GitHub
parent 2fbd0f5c25
commit e12fb110f9
14 changed files with 393 additions and 167 deletions

View File

@@ -0,0 +1,54 @@
import { assertCommonChatGptWebProviderAvailable } from "@/shared/constants/chatgptWebRetirement";
import { assertMicrosoftDesignerWebProviderAvailable } from "@/shared/constants/designerWebRetirement";
import { assertRuntimeProviderAvailable } from "@/shared/constants/providerRetirement";
import type { BaseExecutor } from "./base.ts";
import { getDefaultExecutor } from "./defaultResolver.ts";
type CredentialExecutorLoader = () => Promise<BaseExecutor>;
const specializedCredentialExecutors: Record<string, CredentialExecutorLoader> = {
antigravity: () => import("./antigravity.ts").then((m) => new m.AntigravityExecutor()),
agy: () => import("./antigravity.ts").then((m) => new m.AntigravityExecutor()),
github: () => import("./github.ts").then((m) => new m.GithubExecutor()),
"ghe-copilot": () => import("./ghe-copilot.ts").then((m) => new m.GheCopilotExecutor()),
kiro: () => import("./kiro.ts").then((m) => new m.KiroExecutor()),
"amazon-q": () => import("./kiro.ts").then((m) => new m.KiroExecutor("amazon-q")),
codex: () => import("./codex.ts").then((m) => new m.CodexExecutor()),
cursor: () => import("./cursor.ts").then((m) => new m.CursorExecutor()),
cu: () => import("./cursor.ts").then((m) => new m.CursorExecutor()),
"cursor-api": () => import("./cursor.ts").then((m) => new m.CursorExecutor("cursor-api")),
cua: () => import("./cursor.ts").then((m) => new m.CursorExecutor("cursor-api")),
trae: () => import("./trae.ts").then((m) => new m.TraeExecutor()),
gitlab: () => import("./gitlab.ts").then((m) => new m.GitlabExecutor()),
"gitlab-duo": () => import("./gitlab.ts").then((m) => new m.GitlabExecutor("gitlab-duo")),
"zed-hosted": () => import("./zed-hosted.ts").then((m) => new m.ZedHostedExecutor()),
"grok-cli": () => import("./grok-cli.ts").then((m) => new m.GrokCliExecutor()),
gc: () => import("./grok-cli.ts").then((m) => new m.GrokCliExecutor()),
auggie: () => import("./auggie.ts").then((m) => new m.AuggieExecutor()),
xai: () => import("./xai.ts").then((m) => new m.XaiExecutor()),
"xai-oauth": () => import("./xai.ts").then((m) => new m.XaiExecutor("xai-oauth")),
xao: () => import("./xai.ts").then((m) => new m.XaiExecutor("xai-oauth")),
};
const credentialExecutorCache = new Map<string, Promise<BaseExecutor>>();
/** Resolve only executors with credential-refresh behavior, without loading the chat registry. */
export async function getCredentialRefreshExecutor(provider: string): Promise<BaseExecutor> {
assertMicrosoftDesignerWebProviderAvailable(provider);
assertRuntimeProviderAvailable(provider);
assertCommonChatGptWebProviderAvailable(provider);
let executor = credentialExecutorCache.get(provider);
if (!executor) {
const specializedLoader = specializedCredentialExecutors[provider];
executor = specializedLoader
? specializedLoader()
: Promise.resolve(getDefaultExecutor(provider));
executor = executor.catch((error) => {
credentialExecutorCache.delete(provider);
throw error;
});
credentialExecutorCache.set(provider, executor);
}
return executor;
}

View File

@@ -0,0 +1,13 @@
import { DefaultExecutor } from "./default.ts";
const defaultExecutorCache = new Map<string, DefaultExecutor>();
/** Resolve the shared fallback executor without initializing the specialized executor registry. */
export function getDefaultExecutor(provider: string): DefaultExecutor {
let executor = defaultExecutorCache.get(provider);
if (!executor) {
executor = new DefaultExecutor(provider);
defaultExecutorCache.set(provider, executor);
}
return executor;
}

View File

@@ -9,7 +9,7 @@ import {
} from "./registry.ts";
// Type-only: pulls no runtime code, keeps DefaultExecutor the only eager class.
import type { BaseExecutor } from "./base.ts";
import { DefaultExecutor } from "./default.ts";
import { getDefaultExecutor } from "./defaultResolver.ts";
// R0.3 — declarative built-in table, made LAZY by #11220.
//
@@ -207,8 +207,6 @@ for (const [alias, load] of Object.entries(lazyExecutors)) {
registerLazyExecutor(alias, load);
}
const defaultCache = new Map();
// #6699 — providers that exist ONLY as Cloud Agent task-API entries
// (CLOUD_AGENT_PROVIDERS / staticModels "Available Models" catalog) and have no
// chat-completions REGISTRY entry anywhere in open-sse/. Without this guard,
@@ -251,8 +249,7 @@ export async function getExecutor(provider: string): Promise<BaseExecutor> {
(err as Error & { status?: number }).status = 400;
throw err;
}
if (!defaultCache.has(provider)) defaultCache.set(provider, new DefaultExecutor(provider));
return defaultCache.get(provider)!;
return getDefaultExecutor(provider);
}
export function hasSpecializedExecutor(provider: string): boolean {

View File

@@ -319,7 +319,7 @@ export async function registerNodejs(): Promise<void> {
process.title = renameProcessTitle(process.title);
// Initialize proxy fetch patch FIRST (before any HTTP requests)
await import("@omniroute/open-sse/index.ts");
await import("@omniroute/open-sse/utils/proxyFetch.ts");
console.log("[STARTUP] Global fetch proxy patch initialized");
// Register quota fetchers early so combo routing can use real quota-aware

View File

@@ -9,6 +9,7 @@ import {
joinClaudeCodeCompatibleUrl,
joinBaseUrlAndPath,
} from "@omniroute/open-sse/services/claudeCodeCompatible.ts";
import { getDefaultExecutor } from "@omniroute/open-sse/executors/defaultResolver.ts";
import {
addModelsSuffix,
normalizeAnthropicBaseUrl,
@@ -137,8 +138,7 @@ export async function validateClaudeOAuthInline({
typeof override === "string" && override ? override : modelId || "claude-haiku-4-5-20251001";
try {
const { getExecutor } = await import("@omniroute/open-sse/executors/index.ts");
const executed = await (await getExecutor("claude")).execute({
const executed = await getDefaultExecutor("claude").execute({
model: testModelId,
body: {
model: testModelId,

View File

@@ -22,13 +22,12 @@
import { logger } from "@omniroute/open-sse/utils/logger.ts";
import { sanitizeErrorMessage } from "@omniroute/open-sse/utils/error.ts";
import { getExecutor } from "@omniroute/open-sse/executors/index.ts";
import type { BaseExecutor } from "@omniroute/open-sse/executors/base";
import { getCodexUsage } from "@omniroute/open-sse/services/usage/codex.ts";
import { getSettings } from "@/lib/db/settings";
import { getProviderConnections, updateProviderConnection } from "@/lib/db/providers";
import { isConnectionUnavailableToAuxiliaryActivity } from "@/lib/exclusiveLeaseIsolation";
import { refreshAndUpdateCredentials } from "@/lib/usage/providerLimits";
import { refreshAndUpdateCredentialsWithResolver } from "@/lib/usage/providerLimits/credentialRefresh";
import { getCircuitBreaker } from "@/shared/utils/circuitBreaker";
import {
QUOTA_AUTOPING_FAILURE_COOLDOWN_MS,
@@ -63,8 +62,11 @@ export interface QuotaAutoPingDeps {
refreshAndUpdateCredentials: (
connection: QuotaAutoPingConnection
) => Promise<{ connection: QuotaAutoPingConnection }>;
getCodexUsage: (accessToken?: string, providerSpecificData?: JsonRecord) => Promise<JsonRecord>;
getExecutor: (provider: string) => Promise<BaseExecutor>;
getCodexUsage: (
accessToken?: string,
providerSpecificData?: JsonRecord
) => Promise<JsonRecord>;
getExecutor: (provider: "codex") => Promise<BaseExecutor>;
canExecuteProvider: (provider: string) => boolean;
isConnectionUnavailableToAuxiliaryActivity: (connectionId: string) => Promise<boolean>;
}
@@ -79,15 +81,33 @@ export function createQuotaAutoPingState(): QuotaAutoPingState {
return { running: false, resetCache: {}, failureCache: {} };
}
let codexExecutorPromise: Promise<BaseExecutor> | null = null;
async function loadQuotaAutoPingExecutor(provider: string): Promise<BaseExecutor> {
if (provider !== "codex") {
throw new Error(`Quota auto-ping does not support provider "${provider}"`);
}
try {
codexExecutorPromise ??= import("@omniroute/open-sse/executors/codex.ts").then(
({ CodexExecutor }) => new CodexExecutor()
);
return await codexExecutorPromise;
} catch (error) {
codexExecutorPromise = null;
throw error;
}
}
export function createDefaultQuotaAutoPingDeps(): QuotaAutoPingDeps {
return {
getSettings,
getProviderConnections,
updateProviderConnection,
refreshAndUpdateCredentials: async (connection) =>
refreshAndUpdateCredentials(connection as never),
refreshAndUpdateCredentialsWithResolver(connection, loadQuotaAutoPingExecutor),
getCodexUsage,
getExecutor,
getExecutor: loadQuotaAutoPingExecutor,
canExecuteProvider: (provider) => getCircuitBreaker(provider).canExecute(),
isConnectionUnavailableToAuxiliaryActivity,
};

View File

@@ -18,13 +18,10 @@ import { clearRecoveredProviderState } from "@/sse/services/auth";
import { getMachineId } from "@/shared/utils/machine";
import { USAGE_SUPPORTED_PROVIDERS } from "@/shared/constants/providers";
import { mergeProviderLimitsCacheEntry, toProviderLimitsCacheEntry } from "./providerLimitsCache";
import { getExecutor } from "@omniroute/open-sse/executors/index.ts";
import { getCredentialRefreshExecutor } from "@omniroute/open-sse/executors/credential.ts";
import { getUsageForProvider } from "@omniroute/open-sse/services/usage.ts";
import { cooldownUntilMs } from "@omniroute/open-sse/services/accountFallback.ts";
import {
rotationGroupFor,
serializeRefresh,
} from "@omniroute/open-sse/services/refreshSerializer.ts";
import { rotationGroupFor } from "@omniroute/open-sse/services/refreshSerializer.ts";
import {
extractCodeAssistOnboardTierId,
extractCodeAssistSubscriptionTier,
@@ -42,29 +39,15 @@ import {
sanitizeUsageQuotasForProvider,
} from "./providerLimits/quotaNormalize";
import { syncInChunksWithSpacing } from "./providerLimits/chunkedSpacingSync";
import {
refreshAndUpdateCredentialsWithResolver,
type CredentialRefreshOptions,
type ProviderConnectionLike,
} from "./providerLimits/credentialRefresh";
export { shouldAttemptRotatingRefresh } from "./providerLimits/credentialRefresh";
type JsonRecord = Record<string, unknown>;
type SyncSource = "manual" | "scheduled";
interface ProviderConnectionLike {
id: string;
provider: string;
authType?: string;
accessToken?: string;
refreshToken?: string;
expiresAt?: string;
tokenExpiresAt?: string;
providerSpecificData?: JsonRecord;
testStatus?: string;
isActive?: boolean;
lastError?: string | null;
lastErrorAt?: string | null;
lastErrorType?: string | null;
lastErrorSource?: string | null;
errorCode?: string | number | null;
rateLimitedUntil?: string | null;
backoffLevel?: number;
}
const PROVIDER_LIMITS_APIKEY_PROVIDERS = new Set([
"glm",
"glm-cn",
@@ -218,122 +201,15 @@ async function syncToCloudIfEnabled() {
}
}
/**
* Whether the quota path may refresh this provider's token. Exported for testing.
*
* Rotating-refresh providers (Codex/OpenAI share one Auth0 client_id, etc.) mint a
* single-use refresh_token on every refresh. The BULK quota-sync path runs many
* connections concurrently; refreshing sibling accounts in parallel makes Auth0
* revoke the whole token family (openai/codex#9648) and kills every account but
* the last (#3019). So the bulk path never refreshes rotating providers
* (`allowRotatingRefresh` falsy). The on-demand, per-connection path opts in and
* is made safe by `serializeRefresh` (one token mint at a time per rotation group,
* so even N concurrent per-account requests can never refresh siblings in
* parallel). Non-rotating providers are always eligible.
*/
export function shouldAttemptRotatingRefresh(
provider: string,
allowRotatingRefresh: boolean | undefined
): boolean {
if (rotationGroupFor(provider) === null) return true;
return allowRotatingRefresh === true;
}
export async function refreshAndUpdateCredentials(
connection: ProviderConnectionLike,
opts: { allowRotatingRefresh?: boolean; force?: boolean } = {}
opts: CredentialRefreshOptions = {}
) {
if (!shouldAttemptRotatingRefresh(connection.provider, opts.allowRotatingRefresh)) {
return { connection, refreshed: false };
}
const executor = await getExecutor(connection.provider);
const credentials = {
connectionId: connection.id,
accessToken: connection.accessToken,
refreshToken: connection.refreshToken,
expiresAt: connection.tokenExpiresAt || connection.expiresAt || null,
providerSpecificData: connection.providerSpecificData,
copilotToken: connection.providerSpecificData?.copilotToken,
copilotTokenExpiresAt: connection.providerSpecificData?.copilotTokenExpiresAt,
};
// `force` is used ONLY on the reactive 401 recovery path (a usage fetch came
// back unauthorized) — it bypasses the proactive `needsRefresh` heuristic so
// imported accounts (expiresAt=null, where needsRefresh is always false) can
// still re-mint. The mint stays serialized per rotation group; this never
// refreshes proactively from the bulk path (#3019 guard above is unchanged).
if (!opts.force && !executor.needsRefresh(credentials)) {
return { connection, refreshed: false };
}
// Serialize the actual token mint per rotation group so two sibling accounts
// never hit Auth0 concurrently (passthrough for non-rotating providers).
const refreshResult = (await serializeRefresh(connection.provider, () =>
executor.refreshCredentials(credentials, console)
)) as
| (JsonRecord & {
accessToken?: string;
refreshToken?: string;
expiresIn?: number;
expiresAt?: string;
copilotToken?: string;
copilotTokenExpiresAt?: string;
})
| null;
if (!refreshResult) {
// Refresh failed but we still have an accessToken — fall back to the
// existing token for ANY OAuth provider (graceful degradation) instead of
// hard-failing. Previously this was qualified to `provider === "github"`,
// which left every other provider stuck on a transient refresh failure even
// when a usable access token was still on hand.
if (connection.accessToken) {
return { connection, refreshed: false };
}
throw withStatus(
new Error("Failed to refresh credentials. Please re-authorize the connection."),
401
);
}
const updateData: JsonRecord = {
updatedAt: new Date().toISOString(),
};
if (refreshResult.accessToken) {
updateData.accessToken = refreshResult.accessToken;
}
if (refreshResult.refreshToken) {
updateData.refreshToken = refreshResult.refreshToken;
}
if (refreshResult.expiresIn) {
const expiresAt = new Date(Date.now() + refreshResult.expiresIn * 1000).toISOString();
updateData.expiresAt = expiresAt;
updateData.tokenExpiresAt = expiresAt;
} else if (refreshResult.expiresAt) {
updateData.expiresAt = refreshResult.expiresAt;
updateData.tokenExpiresAt = refreshResult.expiresAt;
}
if (refreshResult.copilotToken || refreshResult.copilotTokenExpiresAt) {
updateData.providerSpecificData = {
...(connection.providerSpecificData || {}),
copilotToken: refreshResult.copilotToken,
copilotTokenExpiresAt: refreshResult.copilotTokenExpiresAt,
};
}
await updateProviderConnection(connection.id, updateData);
return {
connection: {
...connection,
...updateData,
providerSpecificData:
(updateData.providerSpecificData as JsonRecord | undefined) ||
connection.providerSpecificData,
},
refreshed: true,
};
return refreshAndUpdateCredentialsWithResolver(
connection,
getCredentialRefreshExecutor,
opts
);
}
function isUsageAuthError(message: unknown): boolean {

View File

@@ -0,0 +1,150 @@
import { updateProviderConnection } from "@/lib/db/providers";
import type { BaseExecutor } from "@omniroute/open-sse/executors/base";
import {
rotationGroupFor,
serializeRefresh,
} from "@omniroute/open-sse/services/refreshSerializer.ts";
type JsonRecord = Record<string, unknown>;
type CredentialRefreshResult = JsonRecord & {
accessToken?: string;
refreshToken?: string;
expiresIn?: number;
expiresAt?: string;
copilotToken?: string;
copilotTokenExpiresAt?: string;
};
export interface ProviderConnectionLike {
id: string;
provider: string;
authType?: string;
accessToken?: string;
refreshToken?: string;
expiresAt?: string | null;
tokenExpiresAt?: string | null;
providerSpecificData?: JsonRecord;
testStatus?: string;
isActive?: boolean;
lastError?: string | null;
lastErrorAt?: string | null;
lastErrorType?: string | null;
lastErrorSource?: string | null;
errorCode?: string | number | null;
rateLimitedUntil?: string | null;
backoffLevel?: number;
}
export interface CredentialRefreshOptions {
allowRotatingRefresh?: boolean;
force?: boolean;
}
export type CredentialExecutorResolver = (provider: string) => Promise<BaseExecutor>;
function withStatus(error: Error, status: number): Error & { status: number } {
return Object.assign(error, { status });
}
/**
* Whether the quota path may refresh this provider's token.
*
* Rotating-refresh providers mint a single-use refresh token on every refresh,
* so bulk quota sync must not refresh siblings concurrently. The on-demand path
* explicitly opts in and remains serialized per rotation group.
*/
export function shouldAttemptRotatingRefresh(
provider: string,
allowRotatingRefresh: boolean | undefined
): boolean {
if (rotationGroupFor(provider) === null) return true;
return allowRotatingRefresh === true;
}
function buildCredentialUpdateData(
connection: ProviderConnectionLike,
refreshResult: CredentialRefreshResult
): JsonRecord {
const updateData: JsonRecord = {
updatedAt: new Date().toISOString(),
};
if (refreshResult.accessToken) {
updateData.accessToken = refreshResult.accessToken;
}
if (refreshResult.refreshToken) {
updateData.refreshToken = refreshResult.refreshToken;
}
if (refreshResult.expiresIn) {
const expiresAt = new Date(Date.now() + refreshResult.expiresIn * 1000).toISOString();
updateData.expiresAt = expiresAt;
updateData.tokenExpiresAt = expiresAt;
} else if (refreshResult.expiresAt) {
updateData.expiresAt = refreshResult.expiresAt;
updateData.tokenExpiresAt = refreshResult.expiresAt;
}
if (refreshResult.copilotToken || refreshResult.copilotTokenExpiresAt) {
updateData.providerSpecificData = {
...(connection.providerSpecificData || {}),
copilotToken: refreshResult.copilotToken,
copilotTokenExpiresAt: refreshResult.copilotTokenExpiresAt,
};
}
return updateData;
}
/** Refresh and persist credentials using a caller-supplied executor resolver. */
export async function refreshAndUpdateCredentialsWithResolver(
connection: ProviderConnectionLike,
resolveExecutor: CredentialExecutorResolver,
opts: CredentialRefreshOptions = {}
) {
if (!shouldAttemptRotatingRefresh(connection.provider, opts.allowRotatingRefresh)) {
return { connection, refreshed: false };
}
const executor = await resolveExecutor(connection.provider);
const credentials = {
connectionId: connection.id,
accessToken: connection.accessToken,
refreshToken: connection.refreshToken,
expiresAt: connection.tokenExpiresAt || connection.expiresAt || null,
providerSpecificData: connection.providerSpecificData,
copilotToken: connection.providerSpecificData?.copilotToken,
copilotTokenExpiresAt: connection.providerSpecificData?.copilotTokenExpiresAt,
};
if (!opts.force && !executor.needsRefresh(credentials)) {
return { connection, refreshed: false };
}
const refreshResult = (await serializeRefresh(connection.provider, () =>
executor.refreshCredentials(credentials, console)
)) as CredentialRefreshResult | null;
if (!refreshResult) {
if (connection.accessToken) {
return { connection, refreshed: false };
}
throw withStatus(
new Error("Failed to refresh credentials. Please re-authorize the connection."),
401
);
}
const updateData = buildCredentialUpdateData(connection, refreshResult);
await updateProviderConnection(connection.id, updateData);
return {
connection: {
...connection,
...updateData,
providerSpecificData:
(updateData.providerSpecificData as JsonRecord | undefined) ||
connection.providerSpecificData,
},
refreshed: true,
};
}

View File

@@ -27,11 +27,12 @@ import path from "node:path";
process.env.DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-codex-quota-"));
const { getExecutor } = await import("../../open-sse/executors/index.ts");
const { getCredentialRefreshExecutor } =
await import("../../open-sse/executors/credential.ts");
const { refreshAndUpdateCredentials } = await import("../../src/lib/usage/providerLimits.ts");
test("codex: quota-sync must NOT proactively rotate the refresh_token (Auth0 family-revocation cascade guard)", async () => {
const exec = await getExecutor("codex");
const exec = await getCredentialRefreshExecutor("codex");
const origNeeds = exec.needsRefresh;
const origRefresh = exec.refreshCredentials;
let refreshCalls = 0;
@@ -68,7 +69,7 @@ test("codex: quota-sync must NOT proactively rotate the refresh_token (Auth0 fam
});
test("non-rotating OAuth provider is still refreshed proactively from quota-sync (gate is not over-broad)", async () => {
const exec = await getExecutor("cursor");
const exec = await getCredentialRefreshExecutor("cursor");
const origNeeds = exec.needsRefresh;
const origRefresh = exec.refreshCredentials;
let refreshCalls = 0;

View File

@@ -15,6 +15,7 @@ const { registerExecutor, getRegisteredExecutor, hasRegisteredExecutor, listExec
await import("../../open-sse/executors/registry.ts");
const { getExecutor, hasSpecializedExecutor, BaseExecutor, DefaultExecutor } =
await import("../../open-sse/executors/index.ts");
const { getDefaultExecutor } = await import("../../open-sse/executors/defaultResolver.ts");
test.after(() => {
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 });
@@ -54,3 +55,9 @@ test("registry lookup is exact — Object.prototype names are not executors", as
assert.ok((await getExecutor(name)) instanceof DefaultExecutor, name);
}
});
test("the registry and leaf resolver share fallback executor instances", async () => {
const provider = "default-resolver-test-provider";
assert.equal(await getExecutor(provider), getDefaultExecutor(provider));
assert.equal(getDefaultExecutor(provider), getDefaultExecutor(provider));
});

View File

@@ -0,0 +1,107 @@
import assert from "node:assert/strict";
import fs from "node:fs";
import path from "node:path";
import test from "node:test";
const instrumentationPath = path.join(process.cwd(), "src/instrumentation-node.ts");
const quotaAutoPingPath = path.join(process.cwd(), "src/lib/services/quotaAutoPing.ts");
const credentialRefreshPath = path.join(
process.cwd(),
"src/lib/usage/providerLimits/credentialRefresh.ts"
);
const providerLimitsPath = path.join(process.cwd(), "src/lib/usage/providerLimits.ts");
const credentialExecutorPath = path.join(process.cwd(), "open-sse/executors/credential.ts");
const executorDirectory = path.join(process.cwd(), "open-sse/executors");
const anthropicValidationPath = path.join(
process.cwd(),
"src/lib/providers/validation/anthropicFormat.ts"
);
const defaultExecutorResolverPath = path.join(
process.cwd(),
"open-sse/executors/defaultResolver.ts"
);
test("node instrumentation loads the proxy patch leaf before quota registration", () => {
const source = fs.readFileSync(instrumentationPath, "utf8");
const proxyPatchImport = 'await import("@omniroute/open-sse/utils/proxyFetch.ts")';
const proxyPatchIndex = source.indexOf(proxyPatchImport);
const quotaRegistrationIndex = source.indexOf("await registerQuotaFetchers()");
assert.ok(proxyPatchIndex >= 0, "startup must load the proxyFetch side-effect leaf");
assert.ok(quotaRegistrationIndex > proxyPatchIndex, "proxy patch must run before quota setup");
assert.doesNotMatch(source, /import\("@omniroute\/open-sse\/index\.ts"\)/);
});
test("quota auto-ping lazily loads only the Codex executor", () => {
const source = fs.readFileSync(quotaAutoPingPath, "utf8");
const credentialRefreshSource = fs.readFileSync(credentialRefreshPath, "utf8");
assert.doesNotMatch(source, /open-sse\/executors\/index(?:\.ts)?/);
assert.doesNotMatch(source, /@\/lib\/usage\/providerLimits["']/);
assert.match(source, /import\("@omniroute\/open-sse\/executors\/codex\.ts"\)/);
assert.match(source, /@\/lib\/usage\/providerLimits\/credentialRefresh/);
assert.match(source, /getExecutor: loadQuotaAutoPingExecutor/);
assert.doesNotMatch(credentialRefreshSource, /open-sse\/executors\/index(?:\.ts)?/);
});
test("startup still registers bespoke, batch, and generic quota fetchers", async () => {
const [{ registerQuotaFetchers }, { getQuotaFetcher }] = await Promise.all([
import("../../src/instrumentation-node.ts"),
import("../../open-sse/services/quotaPreflight.ts"),
]);
await registerQuotaFetchers();
for (const provider of [
"agentrouter",
"codex",
"bailian-coding-plan",
"qwen-cloud-token-plan",
"crof",
"deepseek",
"openrouter",
"opencode-go",
"grok-web",
"antigravity",
]) {
assert.equal(typeof getQuotaFetcher(provider), "function", `${provider} quota fetcher missing`);
}
});
test("provider-limit startup uses the refresh-only executor resolver", () => {
const providerLimitsSource = fs.readFileSync(providerLimitsPath, "utf8");
const credentialExecutorSource = fs.readFileSync(credentialExecutorPath, "utf8");
assert.doesNotMatch(providerLimitsSource, /open-sse\/executors\/index(?:\.ts)?/);
assert.match(providerLimitsSource, /open-sse\/executors\/credential\.ts/);
assert.doesNotMatch(credentialExecutorSource, /\.\/index(?:\.ts)?/);
assert.match(credentialExecutorSource, /export async function getCredentialRefreshExecutor/);
});
test("credential resolver covers every executor with custom refresh behavior", () => {
const credentialExecutorSource = fs.readFileSync(credentialExecutorPath, "utf8");
const refreshOverrideFiles = fs
.readdirSync(executorDirectory)
.filter((file) => file.endsWith(".ts") && !["base.ts", "default.ts"].includes(file))
.filter((file) => {
const source = fs.readFileSync(path.join(executorDirectory, file), "utf8");
return /^\s*(?:async\s+)?(?:needsRefresh|refreshCredentials)\s*\(/m.test(source);
});
for (const file of refreshOverrideFiles) {
assert.ok(
credentialExecutorSource.includes(`import("./${file}")`),
`${file} must be registered in the refresh-only resolver`
);
}
});
test("Claude OAuth validation resolves the default executor without the chat registry", () => {
const validationSource = fs.readFileSync(anthropicValidationPath, "utf8");
const resolverSource = fs.readFileSync(defaultExecutorResolverPath, "utf8");
assert.doesNotMatch(validationSource, /open-sse\/executors\/index(?:\.ts)?/);
assert.match(validationSource, /open-sse\/executors\/defaultResolver\.ts/);
assert.doesNotMatch(resolverSource, /\.\/index(?:\.ts)?/);
assert.match(resolverSource, /export function getDefaultExecutor/);
});

View File

@@ -22,7 +22,8 @@ process.env.DATA_DIR = fs.mkdtempSync(
path.join(os.tmpdir(), "omniroute-accesstoken-fallback-")
);
const { getExecutor } = await import("../../open-sse/executors/index.ts");
const { getCredentialRefreshExecutor } =
await import("../../open-sse/executors/credential.ts");
const { refreshAndUpdateCredentials } = await import("../../src/lib/usage/providerLimits.ts");
// `gemini` is a non-rotating (no rotation lock group), non-github OAuth provider,
@@ -39,7 +40,7 @@ function geminiConnection() {
}
test("falls back to the existing accessToken for a non-github provider when refreshCredentials returns null", async () => {
const exec = await getExecutor("gemini");
const exec = await getCredentialRefreshExecutor("gemini");
const origNeeds = exec.needsRefresh;
const origRefresh = exec.refreshCredentials;
exec.needsRefresh = () => true; // force the refresh attempt
@@ -65,7 +66,7 @@ test("falls back to the existing accessToken for a non-github provider when refr
});
test("still throws when refresh fails AND there is no accessToken to fall back on", async () => {
const exec = await getExecutor("gemini");
const exec = await getCredentialRefreshExecutor("gemini");
const origNeeds = exec.needsRefresh;
const origRefresh = exec.refreshCredentials;
exec.needsRefresh = () => true;

View File

@@ -18,7 +18,8 @@ import path from "node:path";
process.env.DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-force-refresh-imported-"));
const { getExecutor } = await import("../../open-sse/executors/index.ts");
const { getCredentialRefreshExecutor } =
await import("../../open-sse/executors/credential.ts");
const { refreshAndUpdateCredentials } = await import("../../src/lib/usage/providerLimits.ts");
function importedCodexConnection() {
@@ -33,7 +34,7 @@ function importedCodexConnection() {
}
test("force re-mints an imported rotating account that needsRefresh would skip (#3019 reactive)", async () => {
const exec = await getExecutor("codex");
const exec = await getCredentialRefreshExecutor("codex");
const origNeeds = exec.needsRefresh;
const origRefresh = exec.refreshCredentials;
let refreshCalls = 0;
@@ -65,7 +66,7 @@ test("force re-mints an imported rotating account that needsRefresh would skip (
});
test("force does NOT override the bulk #3019 guard (no allowRotatingRefresh → no mint)", async () => {
const exec = await getExecutor("codex");
const exec = await getCredentialRefreshExecutor("codex");
const origNeeds = exec.needsRefresh;
const origRefresh = exec.refreshCredentials;
let refreshCalls = 0;

View File

@@ -9,8 +9,8 @@ import { dirname, join } from "node:path";
// top-level IIFE at *require time* — merely importing the `playwright` package crashes,
// no browser needs to be launched. `claudeTurnstileSolver.ts` used to `import { chromium }
// from "playwright"` statically, and that module is unconditionally reachable from the
// Next.js instrumentation hook on every boot via open-sse/executors/index.ts, so any
// unsupported platform crashed the whole server at startup regardless of configured provider.
// Next.js instrumentation hook used to reach it on every boot via open-sse/executors/index.ts,
// so any unsupported platform crashed the whole server regardless of configured provider.
const HERE = dirname(fileURLToPath(import.meta.url));
const SOLVER = join(HERE, "../../open-sse/services/claudeTurnstileSolver.ts");
@@ -28,10 +28,9 @@ test("importing the real executor chain does not throw on an unsupported process
Object.defineProperty(process, "platform", { value: "android", configurable: true });
try {
// This is the exact reachability chain from the Next.js instrumentation hook:
// instrumentation-node.ts -> open-sse/index.ts -> executors/index.ts -> claude-web*.ts
// -> claudeTurnstileSolver.ts. Before the fix, this threw
// "Unsupported platform: android" purely from the static playwright import.
// Keep the executor-registry import safe for direct runtime consumers. Before the
// original fix, this threw "Unsupported platform: android" purely from the static
// playwright import; instrumentation no longer imports this graph at boot (#12074).
await import("../../open-sse/executors/index.ts");
} finally {
Object.defineProperty(process, "platform", originalDescriptor);