codex-multi-auth 1.2.1 → 1.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.
Files changed (151) hide show
  1. package/README.md +3 -3
  2. package/dist/index.d.ts.map +1 -1
  3. package/dist/index.js +55 -21
  4. package/dist/index.js.map +1 -1
  5. package/dist/lib/accounts.d.ts +11 -0
  6. package/dist/lib/accounts.d.ts.map +1 -1
  7. package/dist/lib/accounts.js +320 -70
  8. package/dist/lib/accounts.js.map +1 -1
  9. package/dist/lib/circuit-breaker.d.ts +4 -0
  10. package/dist/lib/circuit-breaker.d.ts.map +1 -1
  11. package/dist/lib/circuit-breaker.js +33 -1
  12. package/dist/lib/circuit-breaker.js.map +1 -1
  13. package/dist/lib/codex-manager/commands/forecast.d.ts +2 -1
  14. package/dist/lib/codex-manager/commands/forecast.d.ts.map +1 -1
  15. package/dist/lib/codex-manager/commands/forecast.js +92 -2
  16. package/dist/lib/codex-manager/commands/forecast.js.map +1 -1
  17. package/dist/lib/codex-manager/commands/report.d.ts +3 -1
  18. package/dist/lib/codex-manager/commands/report.d.ts.map +1 -1
  19. package/dist/lib/codex-manager/commands/report.js +102 -12
  20. package/dist/lib/codex-manager/commands/report.js.map +1 -1
  21. package/dist/lib/codex-manager.d.ts.map +1 -1
  22. package/dist/lib/codex-manager.js +50 -40
  23. package/dist/lib/codex-manager.js.map +1 -1
  24. package/dist/lib/config.d.ts.map +1 -1
  25. package/dist/lib/config.js +172 -17
  26. package/dist/lib/config.js.map +1 -1
  27. package/dist/lib/forecast.d.ts.map +1 -1
  28. package/dist/lib/forecast.js +1 -19
  29. package/dist/lib/forecast.js.map +1 -1
  30. package/dist/lib/health.d.ts +1 -0
  31. package/dist/lib/health.d.ts.map +1 -1
  32. package/dist/lib/health.js +6 -2
  33. package/dist/lib/health.js.map +1 -1
  34. package/dist/lib/parallel-probe.d.ts +1 -1
  35. package/dist/lib/parallel-probe.d.ts.map +1 -1
  36. package/dist/lib/parallel-probe.js +5 -2
  37. package/dist/lib/parallel-probe.js.map +1 -1
  38. package/dist/lib/preemptive-quota-scheduler.d.ts.map +1 -1
  39. package/dist/lib/preemptive-quota-scheduler.js +6 -3
  40. package/dist/lib/preemptive-quota-scheduler.js.map +1 -1
  41. package/dist/lib/proactive-refresh.d.ts +1 -1
  42. package/dist/lib/proactive-refresh.d.ts.map +1 -1
  43. package/dist/lib/proactive-refresh.js +14 -5
  44. package/dist/lib/proactive-refresh.js.map +1 -1
  45. package/dist/lib/refresh-guardian.d.ts +3 -0
  46. package/dist/lib/refresh-guardian.d.ts.map +1 -1
  47. package/dist/lib/refresh-guardian.js +142 -52
  48. package/dist/lib/refresh-guardian.js.map +1 -1
  49. package/dist/lib/request/fetch-helpers.d.ts.map +1 -1
  50. package/dist/lib/request/fetch-helpers.js +180 -43
  51. package/dist/lib/request/fetch-helpers.js.map +1 -1
  52. package/dist/lib/rotation.d.ts +14 -11
  53. package/dist/lib/rotation.d.ts.map +1 -1
  54. package/dist/lib/rotation.js +36 -30
  55. package/dist/lib/rotation.js.map +1 -1
  56. package/dist/lib/runtime/account-check.d.ts +4 -0
  57. package/dist/lib/runtime/account-check.d.ts.map +1 -1
  58. package/dist/lib/runtime/account-check.js +15 -10
  59. package/dist/lib/runtime/account-check.js.map +1 -1
  60. package/dist/lib/runtime/account-state.d.ts +1 -12
  61. package/dist/lib/runtime/account-state.d.ts.map +1 -1
  62. package/dist/lib/runtime/account-state.js +1 -37
  63. package/dist/lib/runtime/account-state.js.map +1 -1
  64. package/dist/lib/runtime/verify-flagged.d.ts +4 -0
  65. package/dist/lib/runtime/verify-flagged.d.ts.map +1 -1
  66. package/dist/lib/runtime/verify-flagged.js +32 -23
  67. package/dist/lib/runtime/verify-flagged.js.map +1 -1
  68. package/dist/lib/storage/flagged-load-entry.d.ts +2 -0
  69. package/dist/lib/storage/flagged-load-entry.d.ts.map +1 -1
  70. package/dist/lib/storage/flagged-load-entry.js +1 -0
  71. package/dist/lib/storage/flagged-load-entry.js.map +1 -1
  72. package/dist/lib/storage/flagged-storage-file.d.ts +4 -0
  73. package/dist/lib/storage/flagged-storage-file.d.ts.map +1 -1
  74. package/dist/lib/storage/flagged-storage-file.js +1 -1
  75. package/dist/lib/storage/flagged-storage-file.js.map +1 -1
  76. package/dist/lib/storage/flagged-storage-io.d.ts +1 -0
  77. package/dist/lib/storage/flagged-storage-io.d.ts.map +1 -1
  78. package/dist/lib/storage/flagged-storage-io.js +130 -5
  79. package/dist/lib/storage/flagged-storage-io.js.map +1 -1
  80. package/dist/lib/storage/identity.d.ts +6 -0
  81. package/dist/lib/storage/identity.d.ts.map +1 -1
  82. package/dist/lib/storage/identity.js +14 -3
  83. package/dist/lib/storage/identity.js.map +1 -1
  84. package/dist/lib/storage/path-state.d.ts +1 -0
  85. package/dist/lib/storage/path-state.d.ts.map +1 -1
  86. package/dist/lib/storage/path-state.js +3 -0
  87. package/dist/lib/storage/path-state.js.map +1 -1
  88. package/dist/lib/storage/paths.d.ts.map +1 -1
  89. package/dist/lib/storage/paths.js +3 -2
  90. package/dist/lib/storage/paths.js.map +1 -1
  91. package/dist/lib/storage.d.ts.map +1 -1
  92. package/dist/lib/storage.js +7 -0
  93. package/dist/lib/storage.js.map +1 -1
  94. package/dist/lib/unified-settings.d.ts.map +1 -1
  95. package/dist/lib/unified-settings.js +226 -28
  96. package/dist/lib/unified-settings.js.map +1 -1
  97. package/package.json +8 -3
  98. package/scripts/codex-bin-resolver.js +99 -0
  99. package/scripts/codex.js +709 -81
  100. package/dist/lib/codex-manager/best.d.ts +0 -26
  101. package/dist/lib/codex-manager/best.d.ts.map +0 -1
  102. package/dist/lib/codex-manager/best.js +0 -249
  103. package/dist/lib/codex-manager/best.js.map +0 -1
  104. package/dist/lib/codex-manager/config-explain.d.ts +0 -2
  105. package/dist/lib/codex-manager/config-explain.d.ts.map +0 -1
  106. package/dist/lib/codex-manager/config-explain.js +0 -62
  107. package/dist/lib/codex-manager/config-explain.js.map +0 -1
  108. package/dist/lib/codex-manager/config-template.d.ts +0 -2
  109. package/dist/lib/codex-manager/config-template.d.ts.map +0 -1
  110. package/dist/lib/codex-manager/config-template.js +0 -112
  111. package/dist/lib/codex-manager/config-template.js.map +0 -1
  112. package/dist/lib/codex-manager/debug-bundle.d.ts +0 -2
  113. package/dist/lib/codex-manager/debug-bundle.d.ts.map +0 -1
  114. package/dist/lib/codex-manager/debug-bundle.js +0 -128
  115. package/dist/lib/codex-manager/debug-bundle.js.map +0 -1
  116. package/dist/lib/codex-manager/doctor.d.ts +0 -20
  117. package/dist/lib/codex-manager/doctor.d.ts.map +0 -1
  118. package/dist/lib/codex-manager/doctor.js +0 -546
  119. package/dist/lib/codex-manager/doctor.js.map +0 -1
  120. package/dist/lib/codex-manager/fix.d.ts +0 -26
  121. package/dist/lib/codex-manager/fix.d.ts.map +0 -1
  122. package/dist/lib/codex-manager/fix.js +0 -366
  123. package/dist/lib/codex-manager/fix.js.map +0 -1
  124. package/dist/lib/codex-manager/forecast.d.ts +0 -26
  125. package/dist/lib/codex-manager/forecast.d.ts.map +0 -1
  126. package/dist/lib/codex-manager/forecast.js +0 -218
  127. package/dist/lib/codex-manager/forecast.js.map +0 -1
  128. package/dist/lib/codex-manager/info.d.ts +0 -11
  129. package/dist/lib/codex-manager/info.d.ts.map +0 -1
  130. package/dist/lib/codex-manager/info.js +0 -91
  131. package/dist/lib/codex-manager/info.js.map +0 -1
  132. package/dist/lib/codex-manager/login.d.ts +0 -40
  133. package/dist/lib/codex-manager/login.d.ts.map +0 -1
  134. package/dist/lib/codex-manager/login.js +0 -1041
  135. package/dist/lib/codex-manager/login.js.map +0 -1
  136. package/dist/lib/codex-manager/report.d.ts +0 -39
  137. package/dist/lib/codex-manager/report.d.ts.map +0 -1
  138. package/dist/lib/codex-manager/report.js +0 -243
  139. package/dist/lib/codex-manager/report.js.map +0 -1
  140. package/dist/lib/codex-manager/switch.d.ts +0 -31
  141. package/dist/lib/codex-manager/switch.d.ts.map +0 -1
  142. package/dist/lib/codex-manager/switch.js +0 -103
  143. package/dist/lib/codex-manager/switch.js.map +0 -1
  144. package/dist/lib/codex-manager/verify-flagged.d.ts +0 -20
  145. package/dist/lib/codex-manager/verify-flagged.d.ts.map +0 -1
  146. package/dist/lib/codex-manager/verify-flagged.js +0 -316
  147. package/dist/lib/codex-manager/verify-flagged.js.map +0 -1
  148. package/dist/lib/request/trace-mode.d.ts +0 -9
  149. package/dist/lib/request/trace-mode.d.ts.map +0 -1
  150. package/dist/lib/request/trace-mode.js +0 -14
  151. package/dist/lib/request/trace-mode.js.map +0 -1
package/README.md CHANGED
@@ -308,9 +308,9 @@ codex auth doctor --json
308
308
 
309
309
  ## Release Notes
310
310
 
311
- - Current stable: [docs/releases/v1.1.10.md](docs/releases/v1.1.10.md)
312
- - Previous stable: [docs/releases/v0.1.9.md](docs/releases/v0.1.9.md)
313
- - Earlier stable: [docs/releases/v0.1.8.md](docs/releases/v0.1.8.md)
311
+ - Current stable: [docs/releases/v1.2.4.md](docs/releases/v1.2.4.md)
312
+ - Previous stable: [docs/releases/v1.2.2.md](docs/releases/v1.2.2.md)
313
+ - Earlier stable: [docs/releases/v1.2.1.md](docs/releases/v1.2.1.md)
314
314
  - Archived prerelease: [docs/releases/v0.1.0-beta.0.md](docs/releases/v0.1.0-beta.0.md)
315
315
 
316
316
  ## License
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAe,MAAM,kBAAkB,CAAC;AAmQ5D;;;;;;;;;;;;;;;GAeG;AAEH,eAAO,MAAM,iBAAiB,EAAE,MAyqH/B,CAAC;AAEF,eAAO,MAAM,gBAAgB,KAAoB,CAAC;AAElD,eAAe,iBAAiB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAe,MAAM,kBAAkB,CAAC;AAqQ5D;;;;;;;;;;;;;;;GAeG;AAEH,eAAO,MAAM,iBAAiB,EAAE,MAgvH/B,CAAC;AAEF,eAAO,MAAM,gBAAgB,KAAoB,CAAC;AAElD,eAAe,iBAAiB,CAAC"}
package/dist/index.js CHANGED
@@ -51,6 +51,7 @@ import { normalizeRequestInit, parseRequestBodyFromInit, } from "./lib/request/r
51
51
  import { applyFastSessionDefaults } from "./lib/request/request-transformer.js";
52
52
  import { applyResponseCompaction } from "./lib/request/response-compaction.js";
53
53
  import { isEmptyResponse } from "./lib/request/response-handler.js";
54
+ import { CodexAuthError } from "./lib/errors.js";
54
55
  import { parseRetryAfterHintMs, sanitizeResponseHeadersForLog, } from "./lib/request/response-metadata.js";
55
56
  import { withStreamingFailover } from "./lib/request/stream-failover.js";
56
57
  import { createAbortableSleep, sleepWithCountdown, } from "./lib/request/wait-utils.js";
@@ -80,7 +81,7 @@ import { applyUiRuntimeFromConfig, getStatusMarker, } from "./lib/runtime/ui-run
80
81
  import { verifyRuntimeFlaggedAccounts } from "./lib/runtime/verify-flagged.js";
81
82
  import { SessionAffinityStore } from "./lib/session-affinity.js";
82
83
  import { registerCleanup } from "./lib/shutdown.js";
83
- import { clearAccounts, clearFlaggedAccounts, exportAccounts, findMatchingAccountIndex, formatStorageErrorHint, getStoragePath, importAccounts, loadAccounts, loadFlaggedAccounts, StorageError, saveAccounts, saveFlaggedAccounts, setStorageBackupEnabled, setStoragePath, withAccountStorageTransaction, } from "./lib/storage.js";
84
+ import { clearAccounts, clearFlaggedAccounts, exportAccounts, findMatchingAccountIndex, formatStorageErrorHint, getStoragePath, importAccounts, loadAccounts, loadFlaggedAccounts, StorageError, saveAccounts, saveFlaggedAccounts, setStorageBackupEnabled, setStoragePath, withAccountAndFlaggedStorageTransaction, withAccountStorageTransaction, } from "./lib/storage.js";
84
85
  import { buildTableHeader, buildTableRow, } from "./lib/table-formatter.js";
85
86
  import { createHashlineEditTool, createHashlineReadTool, } from "./lib/tools/hashline-tools.js";
86
87
  import { formatUiBadge, formatUiHeader, formatUiItem, formatUiKeyValue, formatUiSection, paintUiText, } from "./lib/ui/format.js";
@@ -168,6 +169,20 @@ export const OpenAIOAuthPlugin = async ({ client }) => {
168
169
  findMatchingAccountIndex,
169
170
  modelFamilies: MODEL_FAMILIES,
170
171
  });
172
+ const persistAccountPoolAndFlagged = async (results, flaggedStorage, replaceAll = false) => withAccountAndFlaggedStorageTransaction(async (loadedStorage, persist) => {
173
+ await persistAccountPoolResults({
174
+ results,
175
+ replaceAll,
176
+ modelFamilies: MODEL_FAMILIES,
177
+ withAccountStorageTransaction: async (handler) => handler(loadedStorage, async (storage) => {
178
+ await persist(storage, flaggedStorage);
179
+ }),
180
+ findMatchingAccountIndex,
181
+ extractAccountId,
182
+ extractAccountEmail,
183
+ sanitizeEmail,
184
+ });
185
+ });
171
186
  const accountManagerCacheInvalidationDeps = {
172
187
  setCachedAccountManager: (value) => {
173
188
  cachedAccountManager = value;
@@ -585,9 +600,7 @@ export const OpenAIOAuthPlugin = async ({ client }) => {
585
600
  try {
586
601
  if (shouldRefreshToken(accountAuth, tokenRefreshSkewMs)) {
587
602
  accountAuth = (await refreshAndUpdateToken(accountAuth, client));
588
- accountManager.updateFromAuth(account, accountAuth);
589
- accountManager.clearAuthFailures(account);
590
- accountManager.saveToDiskDebounced();
603
+ await accountManager.commitRefreshedAuth(account, accountAuth);
591
604
  }
592
605
  }
593
606
  catch (err) {
@@ -597,13 +610,27 @@ export const OpenAIOAuthPlugin = async ({ client }) => {
597
610
  runtimeMetrics.accountRotations++;
598
611
  runtimeMetrics.lastError =
599
612
  err?.message ?? String(err);
600
- const failures = accountManager.incrementAuthFailures(account);
613
+ const isRetryableRefreshError = err instanceof CodexAuthError && err.retryable;
601
614
  const accountLabel = formatAccountLabel(account, account.index);
615
+ sessionAffinityStore?.forgetSession(sessionAffinityKey);
616
+ if (isRetryableRefreshError) {
617
+ runtimeMetrics.networkErrors++;
618
+ const retryableRefreshPolicy = evaluateFailurePolicy({ kind: "network", failoverMode }, { networkCooldownMs: networkErrorCooldownMs });
619
+ if (retryableRefreshPolicy.recordFailure) {
620
+ accountManager.recordFailure(account, modelFamily, model);
621
+ }
622
+ if (typeof retryableRefreshPolicy.cooldownMs === "number" &&
623
+ retryableRefreshPolicy.cooldownReason) {
624
+ accountManager.markAccountCoolingDown(account, retryableRefreshPolicy.cooldownMs, retryableRefreshPolicy.cooldownReason);
625
+ accountManager.saveToDiskDebounced();
626
+ }
627
+ continue;
628
+ }
629
+ const failures = accountManager.incrementAuthFailures(account);
602
630
  const authFailurePolicy = evaluateFailurePolicy({
603
631
  kind: "auth-refresh",
604
632
  consecutiveAuthFailures: failures,
605
633
  });
606
- sessionAffinityStore?.forgetSession(sessionAffinityKey);
607
634
  if (authFailurePolicy.removeAccount) {
608
635
  const removedIndex = account.index;
609
636
  sessionAffinityStore?.forgetAccount(removedIndex);
@@ -1045,20 +1072,22 @@ export const OpenAIOAuthPlugin = async ({ client }) => {
1045
1072
  sessionAffinityStore?.forgetSession(sessionAffinityKey);
1046
1073
  break;
1047
1074
  }
1048
- if (rateLimit) {
1075
+ if (response.status === 429) {
1049
1076
  runtimeMetrics.rateLimitedResponses++;
1050
- const { attempt, delayMs } = getRateLimitBackoff(account.index, quotaKey, rateLimit.retryAfterMs);
1051
- preemptiveQuotaScheduler.markRateLimited(quotaScheduleKey, delayMs);
1052
- const waitLabel = formatWaitTime(delayMs);
1053
- if (delayMs <= RATE_LIMIT_SHORT_RETRY_THRESHOLD_MS) {
1077
+ const retryAfterMs = rateLimit?.retryAfterMs ?? 60_000;
1078
+ const { attempt, delayMs } = getRateLimitBackoff(account.index, quotaKey, retryAfterMs);
1079
+ const cooldownMs = Math.max(delayMs, retryAfterMs);
1080
+ preemptiveQuotaScheduler.markRateLimited(quotaScheduleKey, cooldownMs);
1081
+ const waitLabel = formatWaitTime(cooldownMs);
1082
+ if (cooldownMs <= RATE_LIMIT_SHORT_RETRY_THRESHOLD_MS) {
1054
1083
  if (accountManager.shouldShowAccountToast(account.index, rateLimitToastDebounceMs)) {
1055
1084
  await showRuntimeToast(client, `Rate limited. Retrying in ${waitLabel} (attempt ${attempt})...`, "warning", { duration: toastDurationMs });
1056
1085
  accountManager.markToastShown(account.index);
1057
1086
  }
1058
- await sleep(addJitter(Math.max(MIN_BACKOFF_MS, delayMs), 0.2));
1087
+ await sleep(addJitter(Math.max(MIN_BACKOFF_MS, cooldownMs), 0.2));
1059
1088
  continue;
1060
1089
  }
1061
- accountManager.markRateLimitedWithReason(account, delayMs, modelFamily, parseRateLimitReason(rateLimit.code), model);
1090
+ accountManager.markRateLimitedWithReason(account, cooldownMs, modelFamily, parseRateLimitReason(rateLimit?.code), model);
1062
1091
  accountManager.recordRateLimit(account, modelFamily, model);
1063
1092
  account.lastSwitchReason = "rate-limit";
1064
1093
  sessionAffinityStore?.forgetSession(sessionAffinityKey);
@@ -1111,9 +1140,7 @@ export const OpenAIOAuthPlugin = async ({ client }) => {
1111
1140
  try {
1112
1141
  if (shouldRefreshToken(fallbackAuth, tokenRefreshSkewMs)) {
1113
1142
  fallbackAuth = (await refreshAndUpdateToken(fallbackAuth, client));
1114
- accountManager.updateFromAuth(fallbackAccount, fallbackAuth);
1115
- accountManager.clearAuthFailures(fallbackAccount);
1116
- accountManager.saveToDiskDebounced();
1143
+ await accountManager.commitRefreshedAuth(fallbackAccount, fallbackAuth);
1117
1144
  }
1118
1145
  }
1119
1146
  catch (refreshError) {
@@ -1195,21 +1222,27 @@ export const OpenAIOAuthPlugin = async ({ client }) => {
1195
1222
  preemptiveQuotaScheduler.update(`${fallbackEntitlementAccountKey}:${model ?? modelFamily}`, fallbackSnapshot);
1196
1223
  }
1197
1224
  if (!fallbackResponse.ok) {
1225
+ const { response: handledFallbackResponse, rateLimit: fallbackRateLimit } = await handleErrorResponse(fallbackResponse);
1198
1226
  try {
1199
1227
  await fallbackResponse.body?.cancel();
1200
1228
  }
1201
1229
  catch {
1202
- // Best effort cleanup before trying next fallback account.
1230
+ // Best-effort only; the error body has already been read.
1203
1231
  }
1204
- if (fallbackResponse.status === 429) {
1205
- const retryAfterMs = parseRetryAfterHintMs(fallbackResponse.headers) ?? 60_000;
1206
- accountManager.markRateLimitedWithReason(fallbackAccount, retryAfterMs, modelFamily, "quota", model);
1232
+ if (handledFallbackResponse.status === 429) {
1233
+ const retryAfterMs = fallbackRateLimit?.retryAfterMs ?? 60_000;
1234
+ const fallbackQuotaKey = model ? `${modelFamily}:${model}` : modelFamily;
1235
+ const { delayMs } = getRateLimitBackoff(fallbackAccount.index, fallbackQuotaKey, retryAfterMs);
1236
+ const cooldownMs = Math.max(delayMs, retryAfterMs);
1237
+ preemptiveQuotaScheduler.markRateLimited(`${fallbackEntitlementAccountKey}:${model ?? modelFamily}`, cooldownMs);
1238
+ accountManager.markRateLimitedWithReason(fallbackAccount, cooldownMs, modelFamily, "quota", model);
1207
1239
  accountManager.recordRateLimit(fallbackAccount, modelFamily, model);
1240
+ accountManager.saveToDiskDebounced();
1208
1241
  }
1209
1242
  else {
1210
1243
  accountManager.recordFailure(fallbackAccount, modelFamily, model);
1244
+ capabilityPolicyStore.recordFailure(fallbackEntitlementAccountKey, capabilityModelKey);
1211
1245
  }
1212
- capabilityPolicyStore.recordFailure(fallbackEntitlementAccountKey, capabilityModelKey);
1213
1246
  continue;
1214
1247
  }
1215
1248
  successAccountForResponse = fallbackAccount;
@@ -1521,6 +1554,7 @@ export const OpenAIOAuthPlugin = async ({ client }) => {
1521
1554
  queuedRefresh,
1522
1555
  resolveTokenSuccessAccount,
1523
1556
  persistAccounts: persistAccountPool,
1557
+ persistAccountsAndFlagged: persistAccountPoolAndFlagged,
1524
1558
  invalidateAccountManagerCache: () => invalidateRuntimeAccountManagerCache(accountManagerCacheInvalidationDeps),
1525
1559
  saveFlaggedAccounts,
1526
1560
  showLine: (message) => console.log(message),