opencode-codex-multi-account 0.2.3 → 0.2.4
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/index.js +173 -107
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -84,6 +84,23 @@ var PluginConfigSchema = v.object({
|
|
|
84
84
|
quiet_mode: v.optional(v.boolean(), false),
|
|
85
85
|
debug: v.optional(v.boolean(), false)
|
|
86
86
|
});
|
|
87
|
+
var TokenRefreshError = class _TokenRefreshError extends Error {
|
|
88
|
+
status;
|
|
89
|
+
permanent;
|
|
90
|
+
constructor(permanent, status) {
|
|
91
|
+
super(status === void 0 ? "Token refresh failed" : `Token refresh failed: ${status}`);
|
|
92
|
+
this.name = "TokenRefreshError";
|
|
93
|
+
this.status = status;
|
|
94
|
+
this.permanent = permanent;
|
|
95
|
+
Object.setPrototypeOf(this, _TokenRefreshError.prototype);
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
function isTokenRefreshError(error) {
|
|
99
|
+
if (error instanceof TokenRefreshError) return true;
|
|
100
|
+
if (!(error instanceof Error)) return false;
|
|
101
|
+
const candidate = error;
|
|
102
|
+
return candidate.name === "TokenRefreshError" && typeof candidate.permanent === "boolean" && (candidate.status === void 0 || typeof candidate.status === "number");
|
|
103
|
+
}
|
|
87
104
|
|
|
88
105
|
// ../multi-account-core/src/config.ts
|
|
89
106
|
var DEFAULT_CONFIG_FILENAME = "multiauth-config.json";
|
|
@@ -224,6 +241,14 @@ function createMinimalClient() {
|
|
|
224
241
|
}
|
|
225
242
|
};
|
|
226
243
|
}
|
|
244
|
+
function getClearedOAuthBody() {
|
|
245
|
+
return {
|
|
246
|
+
type: "oauth",
|
|
247
|
+
refresh: "",
|
|
248
|
+
access: "",
|
|
249
|
+
expires: 0
|
|
250
|
+
};
|
|
251
|
+
}
|
|
227
252
|
|
|
228
253
|
// ../multi-account-core/src/claims.ts
|
|
229
254
|
var CLAIMS_FILENAME = "multiauth-claims.json";
|
|
@@ -647,13 +672,7 @@ function createAccountManagerForProvider(dependencies) {
|
|
|
647
672
|
});
|
|
648
673
|
}
|
|
649
674
|
async markRevoked(uuid) {
|
|
650
|
-
await this.
|
|
651
|
-
account.isAuthDisabled = true;
|
|
652
|
-
account.authDisabledReason = "OAuth token revoked (403)";
|
|
653
|
-
account.accessToken = void 0;
|
|
654
|
-
account.expiresAt = void 0;
|
|
655
|
-
});
|
|
656
|
-
this.runtimeFactory?.invalidate(uuid);
|
|
675
|
+
await this.removeAccountByUuid(uuid);
|
|
657
676
|
}
|
|
658
677
|
async markSuccess(uuid) {
|
|
659
678
|
this.last429Map.delete(uuid);
|
|
@@ -676,15 +695,32 @@ function createAccountManagerForProvider(dependencies) {
|
|
|
676
695
|
}).catch(() => {
|
|
677
696
|
});
|
|
678
697
|
}
|
|
698
|
+
async clearOpenCodeAuthIfNoAccountsRemain() {
|
|
699
|
+
if (!this.client) return;
|
|
700
|
+
const storage = await this.store.load();
|
|
701
|
+
if (storage.accounts.length > 0) return;
|
|
702
|
+
await this.client.auth.set({
|
|
703
|
+
path: { id: providerAuthId },
|
|
704
|
+
body: getClearedOAuthBody()
|
|
705
|
+
}).catch(() => {
|
|
706
|
+
});
|
|
707
|
+
}
|
|
708
|
+
async removeAccountByUuid(uuid) {
|
|
709
|
+
const removed = await this.store.removeAccount(uuid);
|
|
710
|
+
if (!removed) return;
|
|
711
|
+
this.last429Map.delete(uuid);
|
|
712
|
+
this.runtimeFactory?.invalidate(uuid);
|
|
713
|
+
await this.refresh();
|
|
714
|
+
await this.clearOpenCodeAuthIfNoAccountsRemain();
|
|
715
|
+
}
|
|
679
716
|
async markAuthFailure(uuid, result) {
|
|
717
|
+
if (!result.ok && result.permanent) {
|
|
718
|
+
await this.removeAccountByUuid(uuid);
|
|
719
|
+
return;
|
|
720
|
+
}
|
|
680
721
|
await this.store.mutateStorage((storage) => {
|
|
681
722
|
const account = storage.accounts.find((entry) => entry.uuid === uuid);
|
|
682
723
|
if (!account) return;
|
|
683
|
-
if (!result.ok && result.permanent) {
|
|
684
|
-
account.isAuthDisabled = true;
|
|
685
|
-
account.authDisabledReason = "Token permanently rejected (400/401/403)";
|
|
686
|
-
return;
|
|
687
|
-
}
|
|
688
724
|
account.consecutiveAuthFailures = (account.consecutiveAuthFailures ?? 0) + 1;
|
|
689
725
|
const maxFailures = getConfig().max_consecutive_auth_failures;
|
|
690
726
|
const usableCount = storage.accounts.filter(
|
|
@@ -781,11 +817,21 @@ function createAccountManagerForProvider(dependencies) {
|
|
|
781
817
|
this.cached = [];
|
|
782
818
|
this.activeAccountUuid = void 0;
|
|
783
819
|
}
|
|
784
|
-
async addAccount(auth) {
|
|
820
|
+
async addAccount(auth, email) {
|
|
785
821
|
if (!auth.refresh) return;
|
|
786
|
-
const
|
|
787
|
-
if (
|
|
822
|
+
const existingByToken = this.cached.find((account) => account.refreshToken === auth.refresh);
|
|
823
|
+
if (existingByToken) return;
|
|
824
|
+
if (email) {
|
|
825
|
+
const existingByEmail = this.cached.find(
|
|
826
|
+
(account) => account.email && account.email === email
|
|
827
|
+
);
|
|
828
|
+
if (existingByEmail?.uuid) {
|
|
829
|
+
await this.replaceAccountCredentials(existingByEmail.uuid, auth);
|
|
830
|
+
return;
|
|
831
|
+
}
|
|
832
|
+
}
|
|
788
833
|
const newAccount = this.createNewAccount(auth, Date.now());
|
|
834
|
+
if (email) newAccount.email = email;
|
|
789
835
|
await this.store.addAccount(newAccount);
|
|
790
836
|
this.activeAccountUuid = newAccount.uuid;
|
|
791
837
|
await this.store.setActiveUuid(newAccount.uuid);
|
|
@@ -1111,7 +1157,6 @@ var MAX_SERVER_RETRIES_PER_ATTEMPT = 2;
|
|
|
1111
1157
|
var MAX_RESOLVE_ATTEMPTS = 10;
|
|
1112
1158
|
var SERVER_RETRY_BASE_MS = 1e3;
|
|
1113
1159
|
var SERVER_RETRY_MAX_MS = 4e3;
|
|
1114
|
-
var PERMANENT_AUTH_FAILURE_STATUSES = /* @__PURE__ */ new Set([400, 401, 403]);
|
|
1115
1160
|
function isAbortError(error) {
|
|
1116
1161
|
return error instanceof Error && error.name === "AbortError";
|
|
1117
1162
|
}
|
|
@@ -1125,80 +1170,49 @@ function createExecutorForProvider(providerName, dependencies) {
|
|
|
1125
1170
|
} = dependencies;
|
|
1126
1171
|
async function executeWithAccountRotation2(manager, runtimeFactory, client, input, init) {
|
|
1127
1172
|
const maxRetries = Math.max(MIN_MAX_RETRIES, manager.getAccountCount() * RETRIES_PER_ACCOUNT);
|
|
1128
|
-
let retries = 0;
|
|
1129
1173
|
let previousAccountUuid;
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
);
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
let response;
|
|
1146
|
-
try {
|
|
1147
|
-
runtime = await runtimeFactory.getRuntime(accountUuid);
|
|
1148
|
-
response = await runtime.fetch(input, init);
|
|
1149
|
-
} catch (error) {
|
|
1150
|
-
if (isAbortError(error)) throw error;
|
|
1151
|
-
if (await handleRuntimeFetchFailure(manager, runtimeFactory, client, account, error)) {
|
|
1152
|
-
continue;
|
|
1174
|
+
async function retryServerErrors(account, runtime) {
|
|
1175
|
+
for (let attempt = 0; attempt < MAX_SERVER_RETRIES_PER_ATTEMPT; attempt++) {
|
|
1176
|
+
const backoff = Math.min(SERVER_RETRY_BASE_MS * 2 ** attempt, SERVER_RETRY_MAX_MS);
|
|
1177
|
+
const jitteredBackoff = backoff * (0.5 + Math.random() * 0.5);
|
|
1178
|
+
await sleep2(jitteredBackoff);
|
|
1179
|
+
let retryResponse;
|
|
1180
|
+
try {
|
|
1181
|
+
retryResponse = await runtime.fetch(input, init);
|
|
1182
|
+
} catch (error) {
|
|
1183
|
+
if (isAbortError(error)) throw error;
|
|
1184
|
+
if (await handleRuntimeFetchFailure(manager, runtimeFactory, client, account, error)) {
|
|
1185
|
+
return null;
|
|
1186
|
+
}
|
|
1187
|
+
void showToast2(client, `${getAccountLabel2(account)} network error \u2014 switching`, "warning");
|
|
1188
|
+
return null;
|
|
1153
1189
|
}
|
|
1154
|
-
|
|
1155
|
-
continue;
|
|
1190
|
+
if (retryResponse.status < 500) return retryResponse;
|
|
1156
1191
|
}
|
|
1192
|
+
return null;
|
|
1193
|
+
}
|
|
1194
|
+
const dispatchResponseStatus = async (account, accountUuid, runtime, response, allow401Retry, from401RefreshRetry) => {
|
|
1157
1195
|
if (response.status >= 500) {
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1196
|
+
const recovered = await retryServerErrors(account, runtime);
|
|
1197
|
+
if (recovered === null) {
|
|
1198
|
+
return { type: "retryOuter" };
|
|
1199
|
+
}
|
|
1200
|
+
response = recovered;
|
|
1201
|
+
}
|
|
1202
|
+
if (response.status === 401) {
|
|
1203
|
+
if (allow401Retry) {
|
|
1204
|
+
runtimeFactory.invalidate(accountUuid);
|
|
1165
1205
|
try {
|
|
1166
|
-
|
|
1206
|
+
const retryRuntime = await runtimeFactory.getRuntime(accountUuid);
|
|
1207
|
+
const retryResponse = await retryRuntime.fetch(input, init);
|
|
1208
|
+
return dispatchResponseStatus(account, accountUuid, retryRuntime, retryResponse, false, true);
|
|
1167
1209
|
} catch (error) {
|
|
1168
1210
|
if (isAbortError(error)) throw error;
|
|
1169
1211
|
if (await handleRuntimeFetchFailure(manager, runtimeFactory, client, account, error)) {
|
|
1170
|
-
|
|
1171
|
-
break;
|
|
1212
|
+
return { type: "retryOuter" };
|
|
1172
1213
|
}
|
|
1173
|
-
|
|
1174
|
-
void showToast2(client, `${getAccountLabel2(account)} network error \u2014 switching`, "warning");
|
|
1175
|
-
break;
|
|
1214
|
+
return { type: "retryOuter" };
|
|
1176
1215
|
}
|
|
1177
|
-
if (serverResponse.status < 500) break;
|
|
1178
|
-
}
|
|
1179
|
-
if (authFailureDuringServerRetry) {
|
|
1180
|
-
continue;
|
|
1181
|
-
}
|
|
1182
|
-
if (networkErrorDuringServerRetry || serverResponse.status >= 500) {
|
|
1183
|
-
continue;
|
|
1184
|
-
}
|
|
1185
|
-
response = serverResponse;
|
|
1186
|
-
}
|
|
1187
|
-
if (response.status === 401) {
|
|
1188
|
-
runtimeFactory.invalidate(accountUuid);
|
|
1189
|
-
try {
|
|
1190
|
-
const retryRuntime = await runtimeFactory.getRuntime(accountUuid);
|
|
1191
|
-
const retryResponse = await retryRuntime.fetch(input, init);
|
|
1192
|
-
if (retryResponse.status !== 401) {
|
|
1193
|
-
await manager.markSuccess(accountUuid);
|
|
1194
|
-
return retryResponse;
|
|
1195
|
-
}
|
|
1196
|
-
} catch (error) {
|
|
1197
|
-
if (isAbortError(error)) throw error;
|
|
1198
|
-
if (await handleRuntimeFetchFailure(manager, runtimeFactory, client, account, error)) {
|
|
1199
|
-
continue;
|
|
1200
|
-
}
|
|
1201
|
-
continue;
|
|
1202
1216
|
}
|
|
1203
1217
|
await manager.markAuthFailure(accountUuid, { ok: false, permanent: false });
|
|
1204
1218
|
await manager.refresh();
|
|
@@ -1209,7 +1223,7 @@ function createExecutorForProvider(providerName, dependencies) {
|
|
|
1209
1223
|
);
|
|
1210
1224
|
}
|
|
1211
1225
|
void showToast2(client, `${getAccountLabel2(account)} auth failed \u2014 switching to next account.`, "warning");
|
|
1212
|
-
|
|
1226
|
+
return { type: "retryOuter" };
|
|
1213
1227
|
}
|
|
1214
1228
|
if (response.status === 403) {
|
|
1215
1229
|
const revoked = await isRevokedTokenResponse(response);
|
|
@@ -1226,26 +1240,62 @@ function createExecutorForProvider(providerName, dependencies) {
|
|
|
1226
1240
|
`All ${providerName} accounts have been revoked or disabled. Re-authenticate with \`opencode auth login\`.`
|
|
1227
1241
|
);
|
|
1228
1242
|
}
|
|
1229
|
-
|
|
1243
|
+
return { type: "retryOuter" };
|
|
1244
|
+
}
|
|
1245
|
+
if (from401RefreshRetry) {
|
|
1246
|
+
return { type: "handled", response };
|
|
1230
1247
|
}
|
|
1231
1248
|
}
|
|
1232
1249
|
if (response.status === 429) {
|
|
1233
1250
|
await handleRateLimitResponse2(manager, client, account, response);
|
|
1251
|
+
return { type: "handled" };
|
|
1252
|
+
}
|
|
1253
|
+
return { type: "success", response };
|
|
1254
|
+
};
|
|
1255
|
+
for (let retries = 1; retries <= maxRetries; retries++) {
|
|
1256
|
+
await manager.refresh();
|
|
1257
|
+
const account = await resolveAccount(manager, client);
|
|
1258
|
+
const accountUuid = account.uuid;
|
|
1259
|
+
if (!accountUuid) continue;
|
|
1260
|
+
if (previousAccountUuid && accountUuid !== previousAccountUuid && manager.getAccountCount() > 1) {
|
|
1261
|
+
void showToast2(client, `Switched to ${getAccountLabel2(account)}`, "info");
|
|
1262
|
+
}
|
|
1263
|
+
previousAccountUuid = accountUuid;
|
|
1264
|
+
let runtime;
|
|
1265
|
+
let response;
|
|
1266
|
+
try {
|
|
1267
|
+
runtime = await runtimeFactory.getRuntime(accountUuid);
|
|
1268
|
+
response = await runtime.fetch(input, init);
|
|
1269
|
+
} catch (error) {
|
|
1270
|
+
if (isAbortError(error)) throw error;
|
|
1271
|
+
if (await handleRuntimeFetchFailure(manager, runtimeFactory, client, account, error)) {
|
|
1272
|
+
continue;
|
|
1273
|
+
}
|
|
1274
|
+
void showToast2(client, `${getAccountLabel2(account)} network error \u2014 switching`, "warning");
|
|
1275
|
+
continue;
|
|
1276
|
+
}
|
|
1277
|
+
const transition = await dispatchResponseStatus(account, accountUuid, runtime, response, true, false);
|
|
1278
|
+
if (transition.type === "retryOuter" || transition.type === "handled") {
|
|
1279
|
+
if (transition.type === "handled" && transition.response) {
|
|
1280
|
+
return transition.response;
|
|
1281
|
+
}
|
|
1234
1282
|
continue;
|
|
1235
1283
|
}
|
|
1236
1284
|
await manager.markSuccess(accountUuid);
|
|
1237
|
-
return response;
|
|
1285
|
+
return transition.response;
|
|
1238
1286
|
}
|
|
1287
|
+
throw new Error(
|
|
1288
|
+
`Exhausted ${maxRetries} retries across all accounts. All attempts failed due to auth errors, rate limits, or token issues.`
|
|
1289
|
+
);
|
|
1239
1290
|
}
|
|
1240
1291
|
async function handleRuntimeFetchFailure(manager, runtimeFactory, client, account, error) {
|
|
1241
|
-
|
|
1242
|
-
if (refreshFailureStatus === void 0) return false;
|
|
1292
|
+
if (!isTokenRefreshError(error)) return false;
|
|
1243
1293
|
if (!account.uuid) return false;
|
|
1244
1294
|
const accountUuid = account.uuid;
|
|
1245
1295
|
runtimeFactory.invalidate(accountUuid);
|
|
1246
1296
|
await manager.markAuthFailure(accountUuid, {
|
|
1247
1297
|
ok: false,
|
|
1248
|
-
permanent:
|
|
1298
|
+
permanent: error.permanent
|
|
1249
1299
|
});
|
|
1250
1300
|
await manager.refresh();
|
|
1251
1301
|
if (!manager.hasAnyUsableAccount()) {
|
|
@@ -1290,13 +1340,6 @@ function createExecutorForProvider(providerName, dependencies) {
|
|
|
1290
1340
|
executeWithAccountRotation: executeWithAccountRotation2
|
|
1291
1341
|
};
|
|
1292
1342
|
}
|
|
1293
|
-
function getRefreshFailureStatus(error) {
|
|
1294
|
-
if (!(error instanceof Error)) return void 0;
|
|
1295
|
-
const matched = error.message.match(/Token refresh failed:\s*(\d{3})/);
|
|
1296
|
-
if (!matched) return void 0;
|
|
1297
|
-
const status = Number(matched[1]);
|
|
1298
|
-
return Number.isFinite(status) ? status : void 0;
|
|
1299
|
-
}
|
|
1300
1343
|
async function isRevokedTokenResponse(response) {
|
|
1301
1344
|
try {
|
|
1302
1345
|
const cloned = response.clone();
|
|
@@ -1311,6 +1354,7 @@ async function isRevokedTokenResponse(response) {
|
|
|
1311
1354
|
var INITIAL_DELAY_MS = 5e3;
|
|
1312
1355
|
function createProactiveRefreshQueueForProvider(dependencies) {
|
|
1313
1356
|
const {
|
|
1357
|
+
providerAuthId,
|
|
1314
1358
|
getConfig: getConfig2,
|
|
1315
1359
|
refreshToken: refreshToken2,
|
|
1316
1360
|
isTokenExpired: isTokenExpired2,
|
|
@@ -1329,6 +1373,10 @@ function createProactiveRefreshQueueForProvider(dependencies) {
|
|
|
1329
1373
|
const config = getConfig2();
|
|
1330
1374
|
if (!config.proactive_refresh) return;
|
|
1331
1375
|
this.runToken++;
|
|
1376
|
+
if (this.timeoutHandle) {
|
|
1377
|
+
clearTimeout(this.timeoutHandle);
|
|
1378
|
+
this.timeoutHandle = null;
|
|
1379
|
+
}
|
|
1332
1380
|
this.scheduleNext(this.runToken, INITIAL_DELAY_MS);
|
|
1333
1381
|
debugLog2(this.client, "Proactive refresh started", {
|
|
1334
1382
|
intervalSeconds: config.proactive_refresh_interval_seconds,
|
|
@@ -1403,23 +1451,41 @@ function createProactiveRefreshQueueForProvider(dependencies) {
|
|
|
1403
1451
|
}
|
|
1404
1452
|
async persistFailure(account, permanent) {
|
|
1405
1453
|
try {
|
|
1406
|
-
|
|
1407
|
-
|
|
1454
|
+
const accountUuid = account.uuid;
|
|
1455
|
+
if (!accountUuid) return;
|
|
1456
|
+
if (permanent) {
|
|
1457
|
+
const removed = await this.store.removeAccount(accountUuid);
|
|
1458
|
+
if (!removed) return;
|
|
1459
|
+
this.onInvalidate?.(accountUuid);
|
|
1460
|
+
await this.clearOpenCodeAuthIfNoAccountsRemain();
|
|
1461
|
+
return;
|
|
1462
|
+
}
|
|
1463
|
+
await this.store.mutateStorage((storage) => {
|
|
1464
|
+
const target = storage.accounts.find((entry) => entry.uuid === accountUuid);
|
|
1465
|
+
if (!target) return;
|
|
1466
|
+
target.consecutiveAuthFailures = (target.consecutiveAuthFailures ?? 0) + 1;
|
|
1467
|
+
const maxFailures = getConfig2().max_consecutive_auth_failures;
|
|
1468
|
+
const usableCount = storage.accounts.filter(
|
|
1469
|
+
(entry) => entry.enabled && !entry.isAuthDisabled && entry.uuid !== accountUuid
|
|
1470
|
+
).length;
|
|
1471
|
+
if (target.consecutiveAuthFailures >= maxFailures && usableCount > 0) {
|
|
1408
1472
|
target.isAuthDisabled = true;
|
|
1409
|
-
target.authDisabledReason =
|
|
1410
|
-
} else {
|
|
1411
|
-
target.consecutiveAuthFailures = (target.consecutiveAuthFailures ?? 0) + 1;
|
|
1412
|
-
const maxFailures = getConfig2().max_consecutive_auth_failures;
|
|
1413
|
-
if (target.consecutiveAuthFailures >= maxFailures) {
|
|
1414
|
-
target.isAuthDisabled = true;
|
|
1415
|
-
target.authDisabledReason = `${maxFailures} consecutive auth failures (proactive refresh)`;
|
|
1416
|
-
}
|
|
1473
|
+
target.authDisabledReason = `${maxFailures} consecutive auth failures (proactive refresh)`;
|
|
1417
1474
|
}
|
|
1418
1475
|
});
|
|
1419
1476
|
} catch {
|
|
1420
1477
|
debugLog2(this.client, `Failed to persist auth failure for ${account.uuid}`);
|
|
1421
1478
|
}
|
|
1422
1479
|
}
|
|
1480
|
+
async clearOpenCodeAuthIfNoAccountsRemain() {
|
|
1481
|
+
const storage = await this.store.load();
|
|
1482
|
+
if (storage.accounts.length > 0) return;
|
|
1483
|
+
await this.client.auth.set({
|
|
1484
|
+
path: { id: providerAuthId },
|
|
1485
|
+
body: getClearedOAuthBody()
|
|
1486
|
+
}).catch(() => {
|
|
1487
|
+
});
|
|
1488
|
+
}
|
|
1423
1489
|
};
|
|
1424
1490
|
}
|
|
1425
1491
|
|
|
@@ -1769,6 +1835,8 @@ var openAIOAuthAdapter = {
|
|
|
1769
1835
|
oauthBetaHeader: "",
|
|
1770
1836
|
requestBetaHeader: "",
|
|
1771
1837
|
cliUserAgent: "opencode/1.1.53",
|
|
1838
|
+
cliVersion: "",
|
|
1839
|
+
billingSalt: "",
|
|
1772
1840
|
toolPrefix: "mcp_",
|
|
1773
1841
|
accountStorageFilename: "openai-multi-account-accounts.json",
|
|
1774
1842
|
transform: {
|
|
@@ -2993,6 +3061,7 @@ Retrying authentication for ${label}...
|
|
|
2993
3061
|
|
|
2994
3062
|
// src/proactive-refresh.ts
|
|
2995
3063
|
var ProactiveRefreshQueue = createProactiveRefreshQueueForProvider({
|
|
3064
|
+
providerAuthId: "openai",
|
|
2996
3065
|
getConfig,
|
|
2997
3066
|
isTokenExpired,
|
|
2998
3067
|
refreshToken,
|
|
@@ -3103,10 +3172,7 @@ var AccountRuntimeFactory = class {
|
|
|
3103
3172
|
if (!accessToken || !expiresAt || isTokenExpired({ accessToken, expiresAt })) {
|
|
3104
3173
|
const refreshed = await refreshToken(storedAccount.refreshToken, uuid, this.client);
|
|
3105
3174
|
if (!refreshed.ok) {
|
|
3106
|
-
|
|
3107
|
-
throw new Error(`Token refresh failed: ${refreshed.status}`);
|
|
3108
|
-
}
|
|
3109
|
-
throw new Error("Token refresh failed");
|
|
3175
|
+
throw new TokenRefreshError(refreshed.permanent, refreshed.status);
|
|
3110
3176
|
}
|
|
3111
3177
|
accessToken = refreshed.patch.accessToken;
|
|
3112
3178
|
expiresAt = refreshed.patch.expiresAt;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opencode-codex-multi-account",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.4",
|
|
4
4
|
"description": "OpenCode plugin for Codex (OpenAI) multi-account management with automatic rate limit switching",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
"directory": "packages/codex-multi-account"
|
|
41
41
|
},
|
|
42
42
|
"dependencies": {
|
|
43
|
-
"opencode-multi-account-core": "^0.2.
|
|
43
|
+
"opencode-multi-account-core": "^0.2.4",
|
|
44
44
|
"valibot": "^1.2.0"
|
|
45
45
|
},
|
|
46
46
|
"devDependencies": {
|