mirror of
https://github.com/tiennm99/ccs.git
synced 2026-09-02 10:19:37 +00:00
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:
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -9,12 +9,16 @@ import * as fs from 'node:fs';
|
|||||||
import * as path from 'node:path';
|
import * as path from 'node:path';
|
||||||
import { getAuthDir } from './config-generator';
|
import { getAuthDir } from './config-generator';
|
||||||
import { getProviderAccounts, getPausedDir } from './account-manager';
|
import { getProviderAccounts, getPausedDir } from './account-manager';
|
||||||
|
import { sanitizeEmail, isTokenExpired } from './auth-utils';
|
||||||
import type { CodexQuotaResult, CodexQuotaWindow } from './quota-types';
|
import type { CodexQuotaResult, CodexQuotaWindow } from './quota-types';
|
||||||
|
|
||||||
/** ChatGPT backend API base URL */
|
/** ChatGPT backend API base URL */
|
||||||
const CODEX_API_BASE = 'https://chatgpt.com/backend-api';
|
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';
|
const USER_AGENT = 'codex_cli_rs/0.76.0 (Debian 13.0.0; x86_64) WindowsTerminal';
|
||||||
|
|
||||||
/** Auth data extracted from Codex auth file */
|
/** Auth data extracted from Codex auth file */
|
||||||
@@ -51,26 +55,6 @@ interface CodexWindowData {
|
|||||||
resetAfterSeconds?: number | null;
|
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
|
* Read auth data from Codex auth file
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import * as fs from 'node:fs';
|
|||||||
import * as path from 'node:path';
|
import * as path from 'node:path';
|
||||||
import { getAuthDir } from './config-generator';
|
import { getAuthDir } from './config-generator';
|
||||||
import { getProviderAccounts, getPausedDir } from './account-manager';
|
import { getProviderAccounts, getPausedDir } from './account-manager';
|
||||||
|
import { sanitizeEmail, isTokenExpired } from './auth-utils';
|
||||||
import type { GeminiCliQuotaResult, GeminiCliBucket } from './quota-types';
|
import type { GeminiCliQuotaResult, GeminiCliBucket } from './quota-types';
|
||||||
|
|
||||||
/** Google Cloud Code API endpoints */
|
/** Google Cloud Code API endpoints */
|
||||||
@@ -81,26 +82,6 @@ function resolveGeminiCliProjectId(accountField: string): string | null {
|
|||||||
return lastMatch;
|
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
|
* Read auth data from Gemini CLI auth file
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -1002,7 +1002,7 @@ async function handleQuotaStatus(
|
|||||||
|
|
||||||
// Display Antigravity section
|
// Display Antigravity section
|
||||||
if (agyResults && agyResults.accounts.length > 0) {
|
if (agyResults && agyResults.accounts.length > 0) {
|
||||||
displayAntigravityQuotaSection(agyResults, verbose);
|
displayAntigravityQuotaSection(agyResults);
|
||||||
} else if (shouldFetch.agy) {
|
} else if (shouldFetch.agy) {
|
||||||
console.log(subheader('Antigravity (0 accounts)'));
|
console.log(subheader('Antigravity (0 accounts)'));
|
||||||
console.log(info('No Antigravity accounts configured'));
|
console.log(info('No Antigravity accounts configured'));
|
||||||
@@ -1035,8 +1035,7 @@ async function handleQuotaStatus(
|
|||||||
* Display Antigravity quota section
|
* Display Antigravity quota section
|
||||||
*/
|
*/
|
||||||
function displayAntigravityQuotaSection(
|
function displayAntigravityQuotaSection(
|
||||||
quotaResult: Awaited<ReturnType<typeof fetchAllProviderQuotas>>,
|
quotaResult: Awaited<ReturnType<typeof fetchAllProviderQuotas>>
|
||||||
_verbose: boolean
|
|
||||||
): void {
|
): void {
|
||||||
const provider: CLIProxyProvider = 'agy';
|
const provider: CLIProxyProvider = 'agy';
|
||||||
const accounts = getProviderAccounts(provider);
|
const accounts = getProviderAccounts(provider);
|
||||||
|
|||||||
Reference in New Issue
Block a user