@kaitranntt/ccs 7.30.1-dev.1 → 7.31.0-dev.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cliproxy/auth/gemini-token-refresh.d.ts +4 -0
- package/dist/cliproxy/auth/gemini-token-refresh.d.ts.map +1 -1
- package/dist/cliproxy/auth/gemini-token-refresh.js +153 -18
- package/dist/cliproxy/auth/gemini-token-refresh.js.map +1 -1
- package/dist/cliproxy/auth-utils.d.ts +16 -0
- package/dist/cliproxy/auth-utils.d.ts.map +1 -0
- package/dist/cliproxy/auth-utils.js +33 -0
- package/dist/cliproxy/auth-utils.js.map +1 -0
- package/dist/cliproxy/quota-fetcher-codex.d.ts +66 -0
- package/dist/cliproxy/quota-fetcher-codex.d.ts.map +1 -0
- package/dist/cliproxy/quota-fetcher-codex.js +310 -0
- package/dist/cliproxy/quota-fetcher-codex.js.map +1 -0
- package/dist/cliproxy/quota-fetcher-gemini-cli.d.ts +51 -0
- package/dist/cliproxy/quota-fetcher-gemini-cli.d.ts.map +1 -0
- package/dist/cliproxy/quota-fetcher-gemini-cli.js +372 -0
- package/dist/cliproxy/quota-fetcher-gemini-cli.js.map +1 -0
- package/dist/cliproxy/quota-fetcher.d.ts.map +1 -1
- package/dist/cliproxy/quota-fetcher.js +4 -24
- package/dist/cliproxy/quota-fetcher.js.map +1 -1
- package/dist/cliproxy/quota-types.d.ts +78 -0
- package/dist/cliproxy/quota-types.d.ts.map +1 -0
- package/dist/cliproxy/quota-types.js +9 -0
- package/dist/cliproxy/quota-types.js.map +1 -0
- package/dist/commands/cliproxy-command.d.ts.map +1 -1
- package/dist/commands/cliproxy-command.js +192 -21
- package/dist/commands/cliproxy-command.js.map +1 -1
- package/package.json +1 -1
|
@@ -3,6 +3,10 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Handles proactive token validation and refresh for Gemini OAuth tokens.
|
|
5
5
|
* Prevents UND_ERR_SOCKET errors by ensuring tokens are valid before use.
|
|
6
|
+
*
|
|
7
|
+
* Token sources (priority order):
|
|
8
|
+
* 1. CLIProxy auth dir (~/.ccs/cliproxy/auth/) - CCS-managed tokens
|
|
9
|
+
* 2. Standard Gemini CLI (~/.gemini/oauth_creds.json) - backward compatibility
|
|
6
10
|
*/
|
|
7
11
|
/**
|
|
8
12
|
* Get path to Gemini OAuth credentials file
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gemini-token-refresh.d.ts","sourceRoot":"","sources":["../../../src/cliproxy/auth/gemini-token-refresh.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"gemini-token-refresh.d.ts","sourceRoot":"","sources":["../../../src/cliproxy/auth/gemini-token-refresh.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAkEH;;GAEG;AACH,wBAAgB,kBAAkB,IAAI,MAAM,CAE3C;AAwKD;;GAEG;AACH,wBAAgB,yBAAyB,IAAI,OAAO,CAUnD;AAED;;;GAGG;AACH,wBAAsB,kBAAkB,IAAI,OAAO,CAAC;IAClD,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC,CA4DD;AAED;;;;GAIG;AACH,wBAAsB,sBAAsB,CAAC,OAAO,UAAQ,GAAG,OAAO,CAAC;IACrE,KAAK,EAAE,OAAO,CAAC;IACf,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC,CAwBD"}
|
|
@@ -4,6 +4,10 @@
|
|
|
4
4
|
*
|
|
5
5
|
* Handles proactive token validation and refresh for Gemini OAuth tokens.
|
|
6
6
|
* Prevents UND_ERR_SOCKET errors by ensuring tokens are valid before use.
|
|
7
|
+
*
|
|
8
|
+
* Token sources (priority order):
|
|
9
|
+
* 1. CLIProxy auth dir (~/.ccs/cliproxy/auth/) - CCS-managed tokens
|
|
10
|
+
* 2. Standard Gemini CLI (~/.gemini/oauth_creds.json) - backward compatibility
|
|
7
11
|
*/
|
|
8
12
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
9
13
|
if (k2 === undefined) k2 = k;
|
|
@@ -33,6 +37,9 @@ exports.ensureGeminiTokenValid = exports.refreshGeminiToken = exports.isGeminiTo
|
|
|
33
37
|
const fs = __importStar(require("fs"));
|
|
34
38
|
const path = __importStar(require("path"));
|
|
35
39
|
const os = __importStar(require("os"));
|
|
40
|
+
const config_generator_1 = require("../config-generator");
|
|
41
|
+
const account_manager_1 = require("../account-manager");
|
|
42
|
+
const token_manager_1 = require("./token-manager");
|
|
36
43
|
/**
|
|
37
44
|
* Gemini OAuth credentials - PUBLIC from official Gemini CLI source code
|
|
38
45
|
* These are not secrets - they're public OAuth client credentials that Google
|
|
@@ -55,34 +62,161 @@ function getGeminiOAuthPath() {
|
|
|
55
62
|
return path.join(os.homedir(), '.gemini', 'oauth_creds.json');
|
|
56
63
|
}
|
|
57
64
|
exports.getGeminiOAuthPath = getGeminiOAuthPath;
|
|
65
|
+
/**
|
|
66
|
+
* Map CLIProxyAPI token format to internal GeminiOAuthCreds format
|
|
67
|
+
*/
|
|
68
|
+
function mapCliproxyToGeminiCreds(cliproxy) {
|
|
69
|
+
return {
|
|
70
|
+
access_token: cliproxy.token.access_token,
|
|
71
|
+
refresh_token: cliproxy.token.refresh_token,
|
|
72
|
+
expiry_date: cliproxy.token.expiry,
|
|
73
|
+
token_type: 'Bearer',
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Validate CLIProxyAPI token structure has required fields
|
|
78
|
+
*/
|
|
79
|
+
function isValidCliproxyToken(data) {
|
|
80
|
+
if (typeof data !== 'object' || data === null)
|
|
81
|
+
return false;
|
|
82
|
+
const obj = data;
|
|
83
|
+
if (obj.type !== 'gemini')
|
|
84
|
+
return false;
|
|
85
|
+
if (typeof obj.token !== 'object' || obj.token === null)
|
|
86
|
+
return false;
|
|
87
|
+
const token = obj.token;
|
|
88
|
+
return typeof token.access_token === 'string';
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Read Gemini token from CLIProxy auth directory
|
|
92
|
+
* Returns credentials with source path, or null if no valid token found
|
|
93
|
+
*/
|
|
94
|
+
function readCliproxyGeminiCreds() {
|
|
95
|
+
const authDir = (0, config_generator_1.getProviderAuthDir)('gemini');
|
|
96
|
+
if (!fs.existsSync(authDir))
|
|
97
|
+
return null;
|
|
98
|
+
// Try to find default account's token file
|
|
99
|
+
const defaultAccount = (0, account_manager_1.getDefaultAccount)('gemini');
|
|
100
|
+
let tokenPath = null;
|
|
101
|
+
if (defaultAccount) {
|
|
102
|
+
tokenPath = path.join(authDir, defaultAccount.tokenFile);
|
|
103
|
+
if (!fs.existsSync(tokenPath))
|
|
104
|
+
tokenPath = null;
|
|
105
|
+
}
|
|
106
|
+
// Fallback: find any gemini token file by prefix or type
|
|
107
|
+
if (!tokenPath) {
|
|
108
|
+
const accounts = (0, account_manager_1.getProviderAccounts)('gemini');
|
|
109
|
+
if (accounts.length > 0) {
|
|
110
|
+
tokenPath = path.join(authDir, accounts[0].tokenFile);
|
|
111
|
+
if (!fs.existsSync(tokenPath))
|
|
112
|
+
tokenPath = null;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
// Last fallback: scan directory for gemini token files
|
|
116
|
+
if (!tokenPath) {
|
|
117
|
+
try {
|
|
118
|
+
const files = fs.readdirSync(authDir).filter((f) => f.endsWith('.json'));
|
|
119
|
+
for (const file of files) {
|
|
120
|
+
const filePath = path.join(authDir, file);
|
|
121
|
+
if (file.startsWith('gemini-') || (0, token_manager_1.isTokenFileForProvider)(filePath, 'gemini')) {
|
|
122
|
+
tokenPath = filePath;
|
|
123
|
+
break;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
catch {
|
|
128
|
+
// Directory read failed - continue to return null
|
|
129
|
+
return null;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
if (!tokenPath)
|
|
133
|
+
return null;
|
|
134
|
+
try {
|
|
135
|
+
const content = fs.readFileSync(tokenPath, 'utf8');
|
|
136
|
+
const data = JSON.parse(content);
|
|
137
|
+
// Validate CLIProxyAPI format with proper type checking
|
|
138
|
+
if (isValidCliproxyToken(data)) {
|
|
139
|
+
return {
|
|
140
|
+
creds: mapCliproxyToGeminiCreds(data),
|
|
141
|
+
sourcePath: tokenPath,
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
return null;
|
|
145
|
+
}
|
|
146
|
+
catch {
|
|
147
|
+
return null;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
58
150
|
/**
|
|
59
151
|
* Read Gemini OAuth credentials
|
|
152
|
+
* Priority: CLIProxy auth dir first, then ~/.gemini/oauth_creds.json
|
|
153
|
+
* Returns credentials with source path for correct write-back
|
|
60
154
|
*/
|
|
61
155
|
function readGeminiCreds() {
|
|
156
|
+
// 1. Try CLIProxy auth directory first (CCS-managed tokens)
|
|
157
|
+
const cliproxyResult = readCliproxyGeminiCreds();
|
|
158
|
+
if (cliproxyResult) {
|
|
159
|
+
return cliproxyResult;
|
|
160
|
+
}
|
|
161
|
+
// 2. Fall back to standard Gemini CLI location
|
|
62
162
|
const oauthPath = getGeminiOAuthPath();
|
|
63
163
|
if (!fs.existsSync(oauthPath)) {
|
|
64
164
|
return null;
|
|
65
165
|
}
|
|
66
166
|
try {
|
|
67
167
|
const content = fs.readFileSync(oauthPath, 'utf8');
|
|
68
|
-
return
|
|
168
|
+
return {
|
|
169
|
+
creds: JSON.parse(content),
|
|
170
|
+
sourcePath: oauthPath,
|
|
171
|
+
};
|
|
69
172
|
}
|
|
70
173
|
catch {
|
|
71
174
|
return null;
|
|
72
175
|
}
|
|
73
176
|
}
|
|
177
|
+
/**
|
|
178
|
+
* Write updated credentials to CLIProxy token file
|
|
179
|
+
* Preserves existing fields (email, project_id), only updates token subfields
|
|
180
|
+
*/
|
|
181
|
+
function writeCliproxyGeminiCreds(tokenPath, creds) {
|
|
182
|
+
try {
|
|
183
|
+
const existing = JSON.parse(fs.readFileSync(tokenPath, 'utf8'));
|
|
184
|
+
const updated = {
|
|
185
|
+
...existing,
|
|
186
|
+
token: {
|
|
187
|
+
...existing.token,
|
|
188
|
+
access_token: creds.access_token,
|
|
189
|
+
refresh_token: creds.refresh_token,
|
|
190
|
+
expiry: creds.expiry_date,
|
|
191
|
+
},
|
|
192
|
+
};
|
|
193
|
+
fs.writeFileSync(tokenPath, JSON.stringify(updated, null, 2), { mode: 0o600 });
|
|
194
|
+
return undefined;
|
|
195
|
+
}
|
|
196
|
+
catch (err) {
|
|
197
|
+
return err instanceof Error ? err.message : 'Failed to write credentials';
|
|
198
|
+
}
|
|
199
|
+
}
|
|
74
200
|
/**
|
|
75
201
|
* Write Gemini OAuth credentials
|
|
202
|
+
* Writes back to the specified source location (CLIProxy or ~/.gemini)
|
|
203
|
+
* @param creds - The credentials to write
|
|
204
|
+
* @param sourcePath - The path where credentials were originally read from
|
|
76
205
|
* @returns error message if write failed, undefined on success
|
|
77
206
|
*/
|
|
78
|
-
function writeGeminiCreds(creds) {
|
|
79
|
-
const
|
|
80
|
-
|
|
207
|
+
function writeGeminiCreds(creds, sourcePath) {
|
|
208
|
+
const geminiOAuthPath = getGeminiOAuthPath();
|
|
209
|
+
// If source is not the standard Gemini path, write to CLIProxy format
|
|
210
|
+
if (sourcePath !== geminiOAuthPath) {
|
|
211
|
+
return writeCliproxyGeminiCreds(sourcePath, creds);
|
|
212
|
+
}
|
|
213
|
+
// Otherwise write to standard Gemini CLI location
|
|
214
|
+
const dir = path.dirname(geminiOAuthPath);
|
|
81
215
|
try {
|
|
82
216
|
if (!fs.existsSync(dir)) {
|
|
83
217
|
fs.mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
84
218
|
}
|
|
85
|
-
fs.writeFileSync(
|
|
219
|
+
fs.writeFileSync(geminiOAuthPath, JSON.stringify(creds, null, 2), { mode: 0o600 });
|
|
86
220
|
return undefined;
|
|
87
221
|
}
|
|
88
222
|
catch (err) {
|
|
@@ -93,14 +227,14 @@ function writeGeminiCreds(creds) {
|
|
|
93
227
|
* Check if Gemini token is expired or expiring soon
|
|
94
228
|
*/
|
|
95
229
|
function isGeminiTokenExpiringSoon() {
|
|
96
|
-
const
|
|
97
|
-
if (!
|
|
230
|
+
const result = readGeminiCreds();
|
|
231
|
+
if (!result || !result.creds.access_token) {
|
|
98
232
|
return true; // No token = needs auth
|
|
99
233
|
}
|
|
100
|
-
if (!creds.expiry_date) {
|
|
234
|
+
if (!result.creds.expiry_date) {
|
|
101
235
|
return false; // No expiry info = assume valid
|
|
102
236
|
}
|
|
103
|
-
const expiresIn = creds.expiry_date - Date.now();
|
|
237
|
+
const expiresIn = result.creds.expiry_date - Date.now();
|
|
104
238
|
return expiresIn < REFRESH_LEAD_TIME_MS;
|
|
105
239
|
}
|
|
106
240
|
exports.isGeminiTokenExpiringSoon = isGeminiTokenExpiringSoon;
|
|
@@ -109,10 +243,11 @@ exports.isGeminiTokenExpiringSoon = isGeminiTokenExpiringSoon;
|
|
|
109
243
|
* @returns Result with success status, optional error, and expiry time
|
|
110
244
|
*/
|
|
111
245
|
async function refreshGeminiToken() {
|
|
112
|
-
const
|
|
113
|
-
if (!
|
|
246
|
+
const result = readGeminiCreds();
|
|
247
|
+
if (!result || !result.creds.refresh_token) {
|
|
114
248
|
return { success: false, error: 'No refresh token available' };
|
|
115
249
|
}
|
|
250
|
+
const { creds, sourcePath } = result;
|
|
116
251
|
const controller = new AbortController();
|
|
117
252
|
const timeoutId = setTimeout(() => controller.abort(), 10000);
|
|
118
253
|
try {
|
|
@@ -124,7 +259,7 @@ async function refreshGeminiToken() {
|
|
|
124
259
|
},
|
|
125
260
|
body: new URLSearchParams({
|
|
126
261
|
grant_type: 'refresh_token',
|
|
127
|
-
refresh_token: creds.refresh_token,
|
|
262
|
+
refresh_token: creds.refresh_token, // Already validated above
|
|
128
263
|
client_id: GEMINI_CLIENT_ID,
|
|
129
264
|
client_secret: GEMINI_CLIENT_SECRET,
|
|
130
265
|
}).toString(),
|
|
@@ -147,7 +282,7 @@ async function refreshGeminiToken() {
|
|
|
147
282
|
access_token: data.access_token,
|
|
148
283
|
expiry_date: expiresAt,
|
|
149
284
|
};
|
|
150
|
-
const writeError = writeGeminiCreds(updatedCreds);
|
|
285
|
+
const writeError = writeGeminiCreds(updatedCreds, sourcePath);
|
|
151
286
|
if (writeError) {
|
|
152
287
|
return { success: false, error: `Token refreshed but failed to save: ${writeError}` };
|
|
153
288
|
}
|
|
@@ -168,8 +303,8 @@ exports.refreshGeminiToken = refreshGeminiToken;
|
|
|
168
303
|
* @returns true if token is valid (or was refreshed), false if refresh failed
|
|
169
304
|
*/
|
|
170
305
|
async function ensureGeminiTokenValid(verbose = false) {
|
|
171
|
-
const
|
|
172
|
-
if (!
|
|
306
|
+
const result = readGeminiCreds();
|
|
307
|
+
if (!result || !result.creds.access_token) {
|
|
173
308
|
return { valid: false, refreshed: false, error: 'No Gemini credentials found' };
|
|
174
309
|
}
|
|
175
310
|
if (!isGeminiTokenExpiringSoon()) {
|
|
@@ -179,14 +314,14 @@ async function ensureGeminiTokenValid(verbose = false) {
|
|
|
179
314
|
if (verbose) {
|
|
180
315
|
console.log('[i] Gemini token expired or expiring soon, refreshing...');
|
|
181
316
|
}
|
|
182
|
-
const
|
|
183
|
-
if (
|
|
317
|
+
const refreshResult = await refreshGeminiToken();
|
|
318
|
+
if (refreshResult.success) {
|
|
184
319
|
if (verbose) {
|
|
185
320
|
console.log('[OK] Gemini token refreshed successfully');
|
|
186
321
|
}
|
|
187
322
|
return { valid: true, refreshed: true };
|
|
188
323
|
}
|
|
189
|
-
return { valid: false, refreshed: false, error:
|
|
324
|
+
return { valid: false, refreshed: false, error: refreshResult.error };
|
|
190
325
|
}
|
|
191
326
|
exports.ensureGeminiTokenValid = ensureGeminiTokenValid;
|
|
192
327
|
//# sourceMappingURL=gemini-token-refresh.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gemini-token-refresh.js","sourceRoot":"","sources":["../../../src/cliproxy/auth/gemini-token-refresh.ts"],"names":[],"mappings":";AAAA
|
|
1
|
+
{"version":3,"file":"gemini-token-refresh.js","sourceRoot":"","sources":["../../../src/cliproxy/auth/gemini-token-refresh.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared Authentication Utilities
|
|
3
|
+
*
|
|
4
|
+
* Common functions for OAuth token handling across quota fetchers.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Sanitize email to match CLIProxyAPI auth file naming convention.
|
|
8
|
+
* Replaces @ and . with underscores for filesystem compatibility.
|
|
9
|
+
*/
|
|
10
|
+
export declare function sanitizeEmail(email: string): string;
|
|
11
|
+
/**
|
|
12
|
+
* Check if token is expired based on the expired timestamp.
|
|
13
|
+
* Returns false if timestamp is missing or invalid (fail-open for quota display).
|
|
14
|
+
*/
|
|
15
|
+
export declare function isTokenExpired(expiredStr?: string): boolean;
|
|
16
|
+
//# sourceMappingURL=auth-utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth-utils.d.ts","sourceRoot":"","sources":["../../src/cliproxy/auth-utils.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;GAGG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEnD;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAQ3D"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Shared Authentication Utilities
|
|
4
|
+
*
|
|
5
|
+
* Common functions for OAuth token handling across quota fetchers.
|
|
6
|
+
*/
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.isTokenExpired = exports.sanitizeEmail = void 0;
|
|
9
|
+
/**
|
|
10
|
+
* Sanitize email to match CLIProxyAPI auth file naming convention.
|
|
11
|
+
* Replaces @ and . with underscores for filesystem compatibility.
|
|
12
|
+
*/
|
|
13
|
+
function sanitizeEmail(email) {
|
|
14
|
+
return email.replace(/@/g, '_').replace(/\./g, '_');
|
|
15
|
+
}
|
|
16
|
+
exports.sanitizeEmail = sanitizeEmail;
|
|
17
|
+
/**
|
|
18
|
+
* Check if token is expired based on the expired timestamp.
|
|
19
|
+
* Returns false if timestamp is missing or invalid (fail-open for quota display).
|
|
20
|
+
*/
|
|
21
|
+
function isTokenExpired(expiredStr) {
|
|
22
|
+
if (!expiredStr)
|
|
23
|
+
return false;
|
|
24
|
+
try {
|
|
25
|
+
const expiredDate = new Date(expiredStr);
|
|
26
|
+
return expiredDate.getTime() < Date.now();
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
exports.isTokenExpired = isTokenExpired;
|
|
33
|
+
//# sourceMappingURL=auth-utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth-utils.js","sourceRoot":"","sources":["../../src/cliproxy/auth-utils.ts"],"names":[],"mappings":";AAAA;;;;GAIG;;;AAEH;;;GAGG;AACH,SAAgB,aAAa,CAAC,KAAa;IACzC,OAAO,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;AACtD,CAAC;AAFD,sCAEC;AAED;;;GAGG;AACH,SAAgB,cAAc,CAAC,UAAmB;IAChD,IAAI,CAAC,UAAU;QAAE,OAAO,KAAK,CAAC;IAC9B,IAAI,CAAC;QACH,MAAM,WAAW,GAAG,IAAI,IAAI,CAAC,UAAU,CAAC,CAAC;QACzC,OAAO,WAAW,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAC5C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AARD,wCAQC"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Quota Fetcher for Codex (ChatGPT) Accounts
|
|
3
|
+
*
|
|
4
|
+
* Fetches quota information from ChatGPT backend API.
|
|
5
|
+
* Used for displaying rate limit windows and reset times.
|
|
6
|
+
*/
|
|
7
|
+
import type { CodexQuotaResult, CodexQuotaWindow } from './quota-types';
|
|
8
|
+
/** Auth data extracted from Codex auth file */
|
|
9
|
+
interface CodexAuthData {
|
|
10
|
+
accessToken: string;
|
|
11
|
+
accountId: string;
|
|
12
|
+
isExpired: boolean;
|
|
13
|
+
expiresAt: string | null;
|
|
14
|
+
}
|
|
15
|
+
/** Raw API response structure */
|
|
16
|
+
interface CodexUsageResponse {
|
|
17
|
+
plan_type?: string;
|
|
18
|
+
planType?: string;
|
|
19
|
+
rate_limit?: CodexRateLimitWindow;
|
|
20
|
+
rateLimit?: CodexRateLimitWindow;
|
|
21
|
+
code_review_rate_limit?: CodexRateLimitWindow;
|
|
22
|
+
codeReviewRateLimit?: CodexRateLimitWindow;
|
|
23
|
+
}
|
|
24
|
+
/** Rate limit window from API */
|
|
25
|
+
interface CodexRateLimitWindow {
|
|
26
|
+
primary_window?: CodexWindowData;
|
|
27
|
+
primaryWindow?: CodexWindowData;
|
|
28
|
+
secondary_window?: CodexWindowData;
|
|
29
|
+
secondaryWindow?: CodexWindowData;
|
|
30
|
+
}
|
|
31
|
+
/** Individual window data */
|
|
32
|
+
interface CodexWindowData {
|
|
33
|
+
used_percent?: number;
|
|
34
|
+
usedPercent?: number;
|
|
35
|
+
reset_after_seconds?: number | null;
|
|
36
|
+
resetAfterSeconds?: number | null;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Read auth data from Codex auth file
|
|
40
|
+
*/
|
|
41
|
+
declare function readCodexAuthData(accountId: string): CodexAuthData | null;
|
|
42
|
+
/**
|
|
43
|
+
* Build CodexQuotaWindow array from API response
|
|
44
|
+
* Handles both snake_case and camelCase field names
|
|
45
|
+
*/
|
|
46
|
+
declare function buildCodexQuotaWindows(payload: CodexUsageResponse): CodexQuotaWindow[];
|
|
47
|
+
/**
|
|
48
|
+
* Fetch quota for a single Codex account
|
|
49
|
+
*
|
|
50
|
+
* @param accountId - Account identifier (email)
|
|
51
|
+
* @param verbose - Show detailed diagnostics
|
|
52
|
+
* @returns Quota result with windows and percentages
|
|
53
|
+
*/
|
|
54
|
+
export declare function fetchCodexQuota(accountId: string, verbose?: boolean): Promise<CodexQuotaResult>;
|
|
55
|
+
/**
|
|
56
|
+
* Fetch quota for all Codex accounts
|
|
57
|
+
*
|
|
58
|
+
* @param verbose - Show detailed diagnostics
|
|
59
|
+
* @returns Array of account quotas
|
|
60
|
+
*/
|
|
61
|
+
export declare function fetchAllCodexQuotas(verbose?: boolean): Promise<{
|
|
62
|
+
account: string;
|
|
63
|
+
quota: CodexQuotaResult;
|
|
64
|
+
}[]>;
|
|
65
|
+
export { readCodexAuthData, buildCodexQuotaWindows };
|
|
66
|
+
//# sourceMappingURL=quota-fetcher-codex.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"quota-fetcher-codex.d.ts","sourceRoot":"","sources":["../../src/cliproxy/quota-fetcher-codex.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAOH,OAAO,KAAK,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAWxE,+CAA+C;AAC/C,UAAU,aAAa;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,OAAO,CAAC;IACnB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED,iCAAiC;AACjC,UAAU,kBAAkB;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,oBAAoB,CAAC;IAClC,SAAS,CAAC,EAAE,oBAAoB,CAAC;IACjC,sBAAsB,CAAC,EAAE,oBAAoB,CAAC;IAC9C,mBAAmB,CAAC,EAAE,oBAAoB,CAAC;CAC5C;AAED,iCAAiC;AACjC,UAAU,oBAAoB;IAC5B,cAAc,CAAC,EAAE,eAAe,CAAC;IACjC,aAAa,CAAC,EAAE,eAAe,CAAC;IAChC,gBAAgB,CAAC,EAAE,eAAe,CAAC;IACnC,eAAe,CAAC,EAAE,eAAe,CAAC;CACnC;AAED,6BAA6B;AAC7B,UAAU,eAAe;IACvB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,mBAAmB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACpC,iBAAiB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACnC;AAED;;GAEG;AACH,iBAAS,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI,CAkDlE;AAED;;;GAGG;AACH,iBAAS,sBAAsB,CAAC,OAAO,EAAE,kBAAkB,GAAG,gBAAgB,EAAE,CAmD/E;AAED;;;;;;GAMG;AACH,wBAAsB,eAAe,CACnC,SAAS,EAAE,MAAM,EACjB,OAAO,UAAQ,GACd,OAAO,CAAC,gBAAgB,CAAC,CAoJ3B;AAED;;;;;GAKG;AACH,wBAAsB,mBAAmB,CACvC,OAAO,UAAQ,GACd,OAAO,CAAC;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,gBAAgB,CAAA;CAAE,EAAE,CAAC,CAezD;AAGD,OAAO,EAAE,iBAAiB,EAAE,sBAAsB,EAAE,CAAC"}
|