import { describe, expect, it } from 'vitest'; import { CodexAccountAppServerClient } from '../CodexAccountAppServerClient'; import type { CodexAppServerSession, CodexAppServerSessionFactory, } from '@main/services/infrastructure/codexAppServer'; function createFactory(request: CodexAppServerSession['request']): { factory: CodexAppServerSessionFactory; requests: { method: string; params: unknown }[]; } { const requests: { method: string; params: unknown }[] = []; const session: CodexAppServerSession = { initializeResponse: { userAgent: 'codex-cli 0.117.0', codexHome: '/Users/me/.codex', platformFamily: 'macos', platformOs: 'darwin', }, request: async (method: string, params?: unknown, timeoutMs?: number) => { requests.push({ method, params }); return request(method, params, timeoutMs); }, notify: async () => undefined, onNotification: () => () => undefined, close: async () => undefined, }; const factory = { withSession: async ( _options: unknown, handler: (session: CodexAppServerSession) => Promise ): Promise => handler(session), } as unknown as CodexAppServerSessionFactory; return { factory, requests }; } describe('CodexAccountAppServerClient', () => { it('reads account and optional rate limits in one app-server session', async () => { let sessionCount = 0; const { factory, requests } = createFactory(async (method: string) => { if (method === 'account/read') { return { account: { type: 'chatgpt', email: 'user@example.com', planType: 'pro' }, requiresOpenaiAuth: true, } as TResult; } if (method === 'account/rateLimits/read') { return { rateLimits: { limitId: 'codex', limitName: null, primary: { usedPercent: 42, windowDurationMins: 300, resetsAt: null }, secondary: null, credits: null, planType: 'pro', }, rateLimitsByLimitId: null, } as TResult; } throw new Error(`Unexpected method ${method}`); }); const countedFactory = { withSession: async ( options: unknown, handler: (session: CodexAppServerSession) => Promise ): Promise => { sessionCount += 1; return factory.withSession(options as never, handler); }, } as unknown as CodexAppServerSessionFactory; const client = new CodexAccountAppServerClient(countedFactory); const result = await client.readAccountSnapshot({ binaryPath: '/usr/local/bin/codex', env: {}, refreshToken: true, includeRateLimits: true, }); expect(sessionCount).toBe(1); expect(result.account.account).toMatchObject({ type: 'chatgpt', email: 'user@example.com', }); expect(result.rateLimits).toMatchObject({ ok: true, payload: { rateLimits: { primary: { usedPercent: 42 }, }, }, }); expect(result.initialize.codexHome).toBe('/Users/me/.codex'); expect(requests).toEqual([ { method: 'account/read', params: { refreshToken: true } }, { method: 'account/rateLimits/read', params: undefined }, ]); }); it('keeps a successful account read when optional rate limits fail', async () => { const rateLimitError = new Error('rate limits failed'); const { factory } = createFactory(async (method: string) => { if (method === 'account/read') { return { account: { type: 'apiKey' }, requiresOpenaiAuth: false, } as TResult; } if (method === 'account/rateLimits/read') { throw rateLimitError; } throw new Error(`Unexpected method ${method}`); }); const client = new CodexAccountAppServerClient(factory); const result = await client.readAccountSnapshot({ binaryPath: '/usr/local/bin/codex', env: {}, includeRateLimits: true, }); expect(result.account).toEqual({ account: { type: 'apiKey' }, requiresOpenaiAuth: false, }); expect(result.rateLimits).toEqual({ ok: false, error: rateLimitError, }); }); it('surfaces account read failures without attempting rate limits', async () => { const requests: string[] = []; const { factory } = createFactory(async (method: string) => { requests.push(method); if (method === 'account/read') { throw new Error('account failed'); } return {} as TResult; }); const client = new CodexAccountAppServerClient(factory); await expect( client.readAccountSnapshot({ binaryPath: '/usr/local/bin/codex', env: {}, includeRateLimits: true, }) ).rejects.toThrow('account failed'); expect(requests).toEqual(['account/read']); }); });