antigravity-claude-proxy 2.7.1 → 2.7.2
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/package.json +1 -1
- package/public/css/style.css +1 -1
- package/public/js/components/account-manager.js +9 -0
- package/public/js/components/server-config.js +32 -0
- package/public/js/config/constants.js +4 -0
- package/public/views/settings.html +58 -0
- package/src/account-manager/credentials.js +2 -2
- package/src/account-manager/index.js +24 -2
- package/src/account-manager/onboarding.js +2 -2
- package/src/account-manager/rate-limits.js +27 -1
- package/src/account-manager/storage.js +6 -3
- package/src/auth/oauth.js +5 -4
- package/src/cloudcode/message-handler.js +36 -3
- package/src/cloudcode/model-api.js +3 -2
- package/src/cloudcode/rate-limit-state.js +41 -0
- package/src/cloudcode/streaming-handler.js +38 -5
- package/src/config.js +2 -0
- package/src/errors.js +33 -0
- package/src/utils/helpers.js +18 -0
- package/src/webui/index.js +16 -1
package/src/errors.js
CHANGED
|
@@ -166,6 +166,37 @@ export class CapacityExhaustedError extends AntigravityError {
|
|
|
166
166
|
}
|
|
167
167
|
}
|
|
168
168
|
|
|
169
|
+
/**
|
|
170
|
+
* Account forbidden error (403 VALIDATION_REQUIRED / PERMISSION_DENIED)
|
|
171
|
+
* These are account-level errors where the account needs validation or has been
|
|
172
|
+
* disabled. Trying different endpoints won't help - need to rotate to another account.
|
|
173
|
+
*/
|
|
174
|
+
export class AccountForbiddenError extends AntigravityError {
|
|
175
|
+
/**
|
|
176
|
+
* @param {string} message - Error message
|
|
177
|
+
* @param {string} accountEmail - Email of the forbidden account
|
|
178
|
+
*/
|
|
179
|
+
constructor(message, accountEmail = null) {
|
|
180
|
+
super(message, 'ACCOUNT_FORBIDDEN', false, { accountEmail });
|
|
181
|
+
this.name = 'AccountForbiddenError';
|
|
182
|
+
this.accountEmail = accountEmail;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Check if an error is an account forbidden error (403 VALIDATION_REQUIRED / PERMISSION_DENIED)
|
|
188
|
+
* These errors indicate the account itself is blocked and need account rotation, not endpoint rotation.
|
|
189
|
+
* @param {Error} error - Error to check
|
|
190
|
+
* @returns {boolean}
|
|
191
|
+
*/
|
|
192
|
+
export function isAccountForbiddenError(error) {
|
|
193
|
+
if (error instanceof AccountForbiddenError) return true;
|
|
194
|
+
// Fallback string check only for errors that couldn't use the typed class
|
|
195
|
+
// (e.g., errors crossing module boundaries). Only match our own prefixed format.
|
|
196
|
+
const msg = (error.message || '');
|
|
197
|
+
return msg.startsWith('ACCOUNT_FORBIDDEN:');
|
|
198
|
+
}
|
|
199
|
+
|
|
169
200
|
/**
|
|
170
201
|
* Check if an error is a rate limit error
|
|
171
202
|
* Works with both custom error classes and legacy string-based errors
|
|
@@ -225,6 +256,7 @@ export default {
|
|
|
225
256
|
AntigravityError,
|
|
226
257
|
RateLimitError,
|
|
227
258
|
AuthError,
|
|
259
|
+
AccountForbiddenError,
|
|
228
260
|
NoAccountsError,
|
|
229
261
|
MaxRetriesError,
|
|
230
262
|
ApiError,
|
|
@@ -233,6 +265,7 @@ export default {
|
|
|
233
265
|
CapacityExhaustedError,
|
|
234
266
|
isRateLimitError,
|
|
235
267
|
isAuthError,
|
|
268
|
+
isAccountForbiddenError,
|
|
236
269
|
isEmptyResponseError,
|
|
237
270
|
isCapacityExhaustedError
|
|
238
271
|
};
|
package/src/utils/helpers.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { readFileSync } from 'fs';
|
|
2
2
|
import { fileURLToPath } from 'url';
|
|
3
3
|
import path from 'path';
|
|
4
|
+
import { config } from '../config.js';
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* Shared Utility Functions
|
|
@@ -71,6 +72,23 @@ export function isNetworkError(error) {
|
|
|
71
72
|
);
|
|
72
73
|
}
|
|
73
74
|
|
|
75
|
+
/**
|
|
76
|
+
* Throttled fetch that applies a configurable delay before each request
|
|
77
|
+
* Only applies delay when requestThrottlingEnabled is true
|
|
78
|
+
* @param {string|URL} url - The URL to fetch
|
|
79
|
+
* @param {RequestInit} [options] - Fetch options
|
|
80
|
+
* @returns {Promise<Response>} Fetch response
|
|
81
|
+
*/
|
|
82
|
+
export async function throttledFetch(url, options) {
|
|
83
|
+
if (config.requestThrottlingEnabled) {
|
|
84
|
+
const delayMs = config.requestDelayMs || 200;
|
|
85
|
+
if (delayMs > 0) {
|
|
86
|
+
await sleep(delayMs);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return fetch(url, options);
|
|
90
|
+
}
|
|
91
|
+
|
|
74
92
|
/**
|
|
75
93
|
* Generate random jitter for backoff timing (Thundering Herd Prevention)
|
|
76
94
|
* Prevents all clients from retrying at the exact same moment after errors.
|
package/src/webui/index.js
CHANGED
|
@@ -292,6 +292,15 @@ export function mountWebUI(app, dirname, accountManager) {
|
|
|
292
292
|
const { email } = req.params;
|
|
293
293
|
accountManager.clearTokenCache(email);
|
|
294
294
|
accountManager.clearProjectCache(email);
|
|
295
|
+
|
|
296
|
+
// For verification errors (403 VALIDATION_REQUIRED), clear isInvalid on refresh.
|
|
297
|
+
// The user has completed verification on Google's site and clicks Refresh to re-enable.
|
|
298
|
+
// Auth errors (no verifyUrl) still require OAuth re-auth via FIX button.
|
|
299
|
+
const account = accountManager.getAllAccounts().find(a => a.email === email);
|
|
300
|
+
if (account && account.isInvalid && account.verifyUrl) {
|
|
301
|
+
accountManager.clearInvalid(email);
|
|
302
|
+
}
|
|
303
|
+
|
|
295
304
|
res.json({
|
|
296
305
|
status: 'ok',
|
|
297
306
|
message: `Token cache cleared for ${email}`
|
|
@@ -644,7 +653,7 @@ export function mountWebUI(app, dirname, accountManager) {
|
|
|
644
653
|
*/
|
|
645
654
|
app.post('/api/config', async (req, res) => {
|
|
646
655
|
try {
|
|
647
|
-
const { debug, devMode, logLevel, persistTokenCache } = req.body;
|
|
656
|
+
const { debug, devMode, logLevel, persistTokenCache, requestThrottlingEnabled, requestDelayMs } = req.body;
|
|
648
657
|
|
|
649
658
|
// Validate tunable config fields via shared helper
|
|
650
659
|
const updates = validateConfigFields(req.body);
|
|
@@ -665,6 +674,12 @@ export function mountWebUI(app, dirname, accountManager) {
|
|
|
665
674
|
if (typeof persistTokenCache === 'boolean') {
|
|
666
675
|
updates.persistTokenCache = persistTokenCache;
|
|
667
676
|
}
|
|
677
|
+
if (typeof requestThrottlingEnabled === 'boolean') {
|
|
678
|
+
updates.requestThrottlingEnabled = requestThrottlingEnabled;
|
|
679
|
+
}
|
|
680
|
+
if (typeof requestDelayMs === 'number' && requestDelayMs >= 100 && requestDelayMs <= 5000) {
|
|
681
|
+
updates.requestDelayMs = requestDelayMs;
|
|
682
|
+
}
|
|
668
683
|
|
|
669
684
|
if (Object.keys(updates).length === 0) {
|
|
670
685
|
return res.status(400).json({
|