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
57 changes: 48 additions & 9 deletions src/providers/codex.ts
Original file line number Diff line number Diff line change
Expand Up @@ -676,14 +676,21 @@ async function appServerRequestResult(input: {
}
if (input.method === "account/chatgptAuthTokens/refresh") {
const bridge = requireCodexHostAuthBridge();
const refreshed = await bridge.refreshAuthTokens({
previousAccountId: typeof input.params.previousAccountId === "string"
? input.params.previousAccountId
: null,
reason: typeof input.params.reason === "string" && input.params.reason
? input.params.reason
: "account/chatgptAuthTokens/refresh",
});
let refreshed: CodexChatgptAuthTokens;
try {
refreshed = await bridge.refreshAuthTokens({
previousAccountId: typeof input.params.previousAccountId === "string"
? input.params.previousAccountId
: null,
reason: typeof input.params.reason === "string" && input.params.reason
? input.params.reason
: "account/chatgptAuthTokens/refresh",
});
} catch (error) {
return {
error: appServerHostRequestFailure(error),
};
}
return {
result: {
accessToken: refreshed.accessToken,
Expand All @@ -701,6 +708,18 @@ async function appServerRequestResult(input: {
};
}

function appServerHostRequestFailure(error: unknown): {
code: number;
message: string;
} {
return {
code: -32000,
message: error instanceof Error && error.message
? error.message
: String(error),
};
}

async function bootstrapCodexExternalAuth(input: {
request: (
method: string,
Expand Down Expand Up @@ -1257,7 +1276,14 @@ async function defaultAppServerTurnRunner(
method,
params: safeJsonObjectFromRecord(params),
});
const response = await appServerRequestResult({ method, params });
let response: Awaited<ReturnType<typeof appServerRequestResult>>;
try {
response = await appServerRequestResult({ method, params });
} catch (error) {
response = {
error: appServerHostRequestFailure(error),
};
}
logCodexAppServerDebug("message:host_response", {
method,
requestId,
Expand Down Expand Up @@ -2561,6 +2587,19 @@ export function safeJsonForTest(text: string): Record<string, JSONValue> {
return safeJsonObject(text);
}

export async function appServerRequestResultForTest(input: {
method: string;
params: Record<string, unknown>;
}): Promise<{
result?: Record<string, JSONValue>;
error?: {
code: number;
message: string;
};
}> {
return await appServerRequestResult(input);
}

export function sanitizeCodexSpawnArgsForTest(
args: Array<string>,
): Array<string> {
Expand Down
35 changes: 35 additions & 0 deletions src/providers/codex_app_server.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { assertEquals } from "@std/assert";
import {
appServerRequestResultForTest,
setCodexHostAuthBridgeForTests,
} from "./codex.ts";

Deno.test("codex app-server refresh host failures are returned as RPC errors", async () => {
setCodexHostAuthBridgeForTests({
readAuthTokens: () => {
throw new Error("not expected");
},
refreshAuthTokens: () => {
throw new SyntaxError("Unexpected end of JSON input");
},
});

try {
const response = await appServerRequestResultForTest({
method: "account/chatgptAuthTokens/refresh",
params: {
previousAccountId: "acct-test",
reason: "account/chatgptAuthTokens/refresh",
},
});

assertEquals(response, {
error: {
code: -32000,
message: "Unexpected end of JSON input",
},
});
} finally {
setCodexHostAuthBridgeForTests(null);
}
});
Loading