refactor(cliproxy): extract shared auth utils and remove unused parameter

- Create auth-utils.ts with sanitizeEmail() and isTokenExpired()
- Remove duplicated functions from quota-fetcher-codex.ts
- Remove duplicated functions from quota-fetcher-gemini-cli.ts
- Remove unused _verbose parameter from displayAntigravityQuotaSection()
- Add descriptive comment to USER_AGENT constant

Addresses code review feedback on PR #395
This commit is contained in:
kaitranntt
2026-01-29 14:38:02 -05:00
parent 30e611fc28
commit e31d00f0b9
4 changed files with 35 additions and 44 deletions
+27
View File
@@ -0,0 +1,27 @@
/**
* Shared Authentication Utilities
*
* Common functions for OAuth token handling across quota fetchers.
*/
/**
* Sanitize email to match CLIProxyAPI auth file naming convention.
* Replaces @ and . with underscores for filesystem compatibility.
*/
export function sanitizeEmail(email: string): string {
return email.replace(/@/g, '_').replace(/\\./g, '_');
}
/**
* Check if token is expired based on the expired timestamp.
* Returns false if timestamp is missing or invalid (fail-open for quota display).
*/
export function isTokenExpired(expiredStr?: string): boolean {
if (!expiredStr) return false;
try {
const expiredDate = new Date(expiredStr);
return expiredDate.getTime() < Date.now();
} catch {
return false;
}
}
+5 -21
View File
@@ -9,12 +9,16 @@ import * as fs from 'node:fs';
import * as path from 'node:path';
import { getAuthDir } from './config-generator';
import { getProviderAccounts, getPausedDir } from './account-manager';
import { sanitizeEmail, isTokenExpired } from './auth-utils';
import type { CodexQuotaResult, CodexQuotaWindow } from './quota-types';
/** ChatGPT backend API base URL */
const CODEX_API_BASE = 'https://chatgpt.com/backend-api';
/** User agent matching Codex CLI */
/**
* User agent matching Codex CLI for API compatibility.
* Update when Codex CLI releases new versions to maintain compatibility.
*/
const USER_AGENT = 'codex_cli_rs/0.76.0 (Debian 13.0.0; x86_64) WindowsTerminal';
/** Auth data extracted from Codex auth file */
@@ -51,26 +55,6 @@ interface CodexWindowData {
resetAfterSeconds?: number | null;
}
/**
* Sanitize email to match CLIProxyAPI auth file naming convention
*/
function sanitizeEmail(email: string): string {
return email.replace(/@/g, '_').replace(/\./g, '_');
}
/**
* Check if token is expired based on the expired timestamp
*/
function isTokenExpired(expiredStr?: string): boolean {
if (!expiredStr) return false;
try {
const expiredDate = new Date(expiredStr);
return expiredDate.getTime() < Date.now();
} catch {
return false;
}
}
/**
* Read auth data from Codex auth file
*/
+1 -20
View File
@@ -9,6 +9,7 @@ import * as fs from 'node:fs';
import * as path from 'node:path';
import { getAuthDir } from './config-generator';
import { getProviderAccounts, getPausedDir } from './account-manager';
import { sanitizeEmail, isTokenExpired } from './auth-utils';
import type { GeminiCliQuotaResult, GeminiCliBucket } from './quota-types';
/** Google Cloud Code API endpoints */
@@ -81,26 +82,6 @@ function resolveGeminiCliProjectId(accountField: string): string | null {
return lastMatch;
}
/**
* Sanitize email to match CLIProxyAPI auth file naming convention
*/
function sanitizeEmail(email: string): string {
return email.replace(/@/g, '_').replace(/\./g, '_');
}
/**
* Check if token is expired based on the expired timestamp
*/
function isTokenExpired(expiredStr?: string): boolean {
if (!expiredStr) return false;
try {
const expiredDate = new Date(expiredStr);
return expiredDate.getTime() < Date.now();
} catch {
return false;
}
}
/**
* Read auth data from Gemini CLI auth file
*/
+2 -3
View File
@@ -1002,7 +1002,7 @@ async function handleQuotaStatus(
// Display Antigravity section
if (agyResults && agyResults.accounts.length > 0) {
displayAntigravityQuotaSection(agyResults, verbose);
displayAntigravityQuotaSection(agyResults);
} else if (shouldFetch.agy) {
console.log(subheader('Antigravity (0 accounts)'));
console.log(info('No Antigravity accounts configured'));
@@ -1035,8 +1035,7 @@ async function handleQuotaStatus(
* Display Antigravity quota section
*/
function displayAntigravityQuotaSection(
quotaResult: Awaited<ReturnType<typeof fetchAllProviderQuotas>>,
_verbose: boolean
quotaResult: Awaited<ReturnType<typeof fetchAllProviderQuotas>>
): void {
const provider: CLIProxyProvider = 'agy';
const accounts = getProviderAccounts(provider);