Skip to content

Commit 4803bec

Browse files
committed
Fix workspace reorder retry regressions
1 parent f1caab6 commit 4803bec

3 files changed

Lines changed: 83 additions & 7 deletions

File tree

index.ts

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -593,15 +593,22 @@ export const OpenAIOAuthPlugin: Plugin = async ({ client }: PluginInput) => {
593593
: newWs;
594594
})
595595
: existing.workspaces;
596+
const currentWorkspaceId =
597+
existing.workspaces?.[
598+
typeof existing.currentWorkspaceIndex === "number"
599+
? existing.currentWorkspaceIndex
600+
: 0
601+
]?.id;
596602
const nextCurrentWorkspaceIndex =
597603
mergedWorkspaces && mergedWorkspaces.length > 0
598604
? (() => {
599-
const currentIndex =
600-
typeof existing.currentWorkspaceIndex === "number"
601-
? existing.currentWorkspaceIndex
602-
: 0;
603-
if (currentIndex >= 0 && currentIndex < mergedWorkspaces.length) {
604-
return currentIndex;
605+
if (currentWorkspaceId) {
606+
const matchingWorkspaceIndex = mergedWorkspaces.findIndex(
607+
(workspace) => workspace.id === currentWorkspaceId,
608+
);
609+
if (matchingWorkspaceIndex >= 0) {
610+
return matchingWorkspaceIndex;
611+
}
605612
}
606613
const defaultWorkspaceIndex = mergedWorkspaces.findIndex(
607614
(workspace) => workspace.isDefault === true,

test/fetch-helpers.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -359,7 +359,7 @@ describe('isWorkspaceDisabledError', () => {
359359
expect(isWorkspaceDisabledError(403, 'usage_not_included', 'Not in your plan')).toBe(false);
360360
});
361361

362-
it('returns false for numeric error codes', () => {
362+
it('uses body text to classify numeric error codes', () => {
363363
expect(isWorkspaceDisabledError(403, 402, 'Workspace disabled')).toBe(true);
364364
expect(isWorkspaceDisabledError(403, 402, 'Billing failed for your subscription')).toBe(false);
365365
expect(isWorkspaceDisabledError(403, 0, '')).toBe(false);

test/index.test.ts

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2307,6 +2307,75 @@ describe("OpenAIOAuthPlugin persistAccountPool", () => {
23072307
]);
23082308
});
23092309

2310+
it("preserves the active workspace by id when refreshed workspace metadata is reordered", async () => {
2311+
process.env.CODEX_AUTH_ACCOUNT_ID = "shared-workspace";
2312+
mockStorage.accounts = [
2313+
{
2314+
accountId: "shared-workspace",
2315+
accountIdSource: "manual",
2316+
accountLabel: "Override [id:space]",
2317+
email: "user@example.com",
2318+
refreshToken: "refresh-a",
2319+
addedAt: Date.now() - 200000,
2320+
lastUsed: Date.now() - 200000,
2321+
workspaces: [
2322+
{ id: "workspace-a", name: "Workspace A", enabled: true },
2323+
{ id: "workspace-b", name: "Workspace B", enabled: false, disabledAt: 222, isDefault: true },
2324+
{ id: "workspace-c", name: "Workspace C", enabled: true },
2325+
],
2326+
currentWorkspaceIndex: 1,
2327+
},
2328+
];
2329+
2330+
const authModule = await import("../lib/auth/auth.js");
2331+
const accountsModule = await import("../lib/accounts.js");
2332+
vi.mocked(authModule.createAuthorizationFlow).mockResolvedValueOnce({
2333+
pkce: { verifier: "persist-reorder-workspaces", challenge: "persist-reorder-workspaces" },
2334+
state: "persist-reorder-workspaces",
2335+
url: "https://auth.openai.com/test?state=persist-reorder-workspaces",
2336+
});
2337+
vi.mocked(authModule.exchangeAuthorizationCode).mockResolvedValueOnce({
2338+
type: "success",
2339+
access: "access-token",
2340+
refresh: "refresh-updated",
2341+
expires: Date.now() + 3600_000,
2342+
idToken: undefined,
2343+
workspaces: [
2344+
{ id: "workspace-b", name: "Workspace B Renamed", enabled: true, isDefault: true },
2345+
{ id: "workspace-a", name: "Workspace A", enabled: true },
2346+
{ id: "workspace-c", name: "Workspace C", enabled: true },
2347+
],
2348+
});
2349+
vi.mocked(accountsModule.extractAccountEmail).mockReturnValueOnce("user@example.com");
2350+
vi.mocked(accountsModule.extractAccountId).mockReturnValueOnce("shared-workspace");
2351+
2352+
const mockClient = createMockClient();
2353+
const { OpenAIOAuthPlugin } = await import("../index.js");
2354+
const plugin =
2355+
(await OpenAIOAuthPlugin({
2356+
client: mockClient,
2357+
} as never)) as unknown as PluginType;
2358+
const manualMethod = plugin.auth.methods[1] as unknown as {
2359+
authorize: () => Promise<{
2360+
callback: (input: string) => Promise<{ type: string }>;
2361+
}>;
2362+
};
2363+
2364+
const flow = await manualMethod.authorize();
2365+
const result = await flow.callback(
2366+
"http://127.0.0.1:1455/auth/callback?code=abc123&state=persist-reorder-workspaces",
2367+
);
2368+
2369+
expect(result.type).toBe("success");
2370+
expect(mockStorage.accounts).toHaveLength(1);
2371+
expect(mockStorage.accounts[0]?.currentWorkspaceIndex).toBe(0);
2372+
expect(mockStorage.accounts[0]?.workspaces).toEqual([
2373+
{ id: "workspace-b", name: "Workspace B Renamed", enabled: false, disabledAt: 222, isDefault: true },
2374+
{ id: "workspace-a", name: "Workspace A", enabled: true },
2375+
{ id: "workspace-c", name: "Workspace C", enabled: true },
2376+
]);
2377+
});
2378+
23102379
it("preserves duplicate shared accountId entries when a login has no email claim", async () => {
23112380
process.env.CODEX_AUTH_ACCOUNT_ID = "shared-workspace";
23122381
mockStorage.accounts = [

0 commit comments

Comments
 (0)