maxpool 1.20.4 → 1.21.0
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/src/account-manager.js +18 -1
- package/src/prober.js +5 -0
- package/src/server.js +10 -0
- package/src/tui.js +5 -1
package/package.json
CHANGED
package/src/account-manager.js
CHANGED
|
@@ -830,6 +830,9 @@ export class AccountManager {
|
|
|
830
830
|
_isAvailable(account, options = {}) {
|
|
831
831
|
if (!account) return false;
|
|
832
832
|
if (!account.enabled) return false;
|
|
833
|
+
// Subscription latched gone (org-disabled 403): benched until re-subscribed. The
|
|
834
|
+
// clear path is a successful re-auth (updateAccountTokens) after re-purchasing.
|
|
835
|
+
if (account.subscriptionGone) return false;
|
|
833
836
|
const now = options.now ?? Date.now();
|
|
834
837
|
|
|
835
838
|
// Check rate limit expiry
|
|
@@ -3135,6 +3138,19 @@ export class AccountManager {
|
|
|
3135
3138
|
// worth having; the diagnosis that motivated it was wrong.)
|
|
3136
3139
|
q.consecutiveProbeFailures = (q.consecutiveProbeFailures || 0) + 1;
|
|
3137
3140
|
const n = q.consecutiveProbeFailures;
|
|
3141
|
+
// A SUSTAINED ORG-403 is the subscription being gone (canceled Max plan lapsing
|
|
3142
|
+
// server-side — measured 2026-09-18/20: "OAuth authentication is currently not
|
|
3143
|
+
// allowed for this organization" on 2solarmax@ and privacy@, both canceled Sep 16).
|
|
3144
|
+
// The quota endpoint refuses before any quota question is answered, so probing is
|
|
3145
|
+
// pure waste. Latch subscriptionGone (3 strikes, like the 401 rule): the prober
|
|
3146
|
+
// skips the account, the TUI says why, and routing treats it as unavailable. A
|
|
3147
|
+
// successful re-auth clears it (updateAccountTokens).
|
|
3148
|
+
if (status === 403
|
|
3149
|
+
&& /not allowed for this organization|disabled.*subscription|subscription.*disabled|organization has disabled/i.test(String(message))
|
|
3150
|
+
&& n >= 3 && !account.subscriptionGone) {
|
|
3151
|
+
account.subscriptionGone = true;
|
|
3152
|
+
console.error(`[Maxpool] "${account.name}" subscription disabled at the organization (HTTP 403 x${n}) — benching it. Re-enable after re-subscribing, or remove the account (a → d).`);
|
|
3153
|
+
}
|
|
3138
3154
|
// A SUSTAINED 401 is dead credentials, not a blip. Latch refreshDead so (a) the
|
|
3139
3155
|
// prober stops re-POSTing a rejected token every 60s forever — measured 2026-08-10:
|
|
3140
3156
|
// 8 disabled accounts each past 20 consecutive 401s, hammering Anthropic's OAuth
|
|
@@ -3717,7 +3733,7 @@ export class AccountManager {
|
|
|
3717
3733
|
// A dead refresh token (invalid_grant) is PERMANENT until browser re-auth —
|
|
3718
3734
|
// never auto-retry it. Without this the prober re-POSTs the rejected token every
|
|
3719
3735
|
// ~60s forever (hammering Anthropic's OAuth endpoint). Cleared on re-login.
|
|
3720
|
-
if (account.refreshDead) return false;
|
|
3736
|
+
if (account.refreshDead || account.subscriptionGone) return false;
|
|
3721
3737
|
|
|
3722
3738
|
// A DISABLED account never spends its single-use refresh token. The prober still
|
|
3723
3739
|
// READS its quota by design (you disable an exhausted account and still want to
|
|
@@ -3831,6 +3847,7 @@ export class AccountManager {
|
|
|
3831
3847
|
if (refreshToken) account.refreshToken = refreshToken;
|
|
3832
3848
|
account.expiresAt = expiresAt;
|
|
3833
3849
|
account.refreshDead = false; // fresh tokens from re-auth revive a dead-refresh account
|
|
3850
|
+
account.subscriptionGone = false; // a working re-auth means the org accepts OAuth again
|
|
3834
3851
|
if (account.status === 'error') account.status = 'active';
|
|
3835
3852
|
console.log(`[Maxpool] Updated tokens for account "${account.name}"`);
|
|
3836
3853
|
this._onTokenRefresh?.(accountIndex, {
|
package/src/prober.js
CHANGED
|
@@ -187,6 +187,11 @@ export class Prober {
|
|
|
187
187
|
* than silently swallowed — a swallowed failing probe is what let a stale
|
|
188
188
|
* weekly look fresh. Never throws. */
|
|
189
189
|
async probeOne(account) {
|
|
190
|
+
// Subscription latched org-disabled (account-manager recordProbeError): the quota
|
|
191
|
+
// endpoint 403s before answering anything, so probing is pure waste until the org
|
|
192
|
+
// accepts OAuth again. Skipping also stops the every-60s hammer that ran 700+ times
|
|
193
|
+
// on 2solarmax@ between 2026-09-18 and 09-20.
|
|
194
|
+
if (account.subscriptionGone) return { ok: false, status: 403 };
|
|
190
195
|
try {
|
|
191
196
|
await this.am.ensureTokenFresh(account.index);
|
|
192
197
|
let usage = await this._withTimeout(this.probeFn(account.credential));
|
package/src/server.js
CHANGED
|
@@ -1054,6 +1054,16 @@ async function forwardRequest(
|
|
|
1054
1054
|
try { return JSON.parse(errorBody)?.error?.message || errorBody; } catch { return errorBody; }
|
|
1055
1055
|
})();
|
|
1056
1056
|
console.log(`[Maxpool] ${upstreamRes.status} from "${account.name}": ${String(why).slice(0, 300)}`);
|
|
1057
|
+
// ORG-DISABLED SUBSCRIPTION (2026-09-20): "OAuth authentication is currently not
|
|
1058
|
+
// allowed for this organization" means the plan is GONE server-side (canceled
|
|
1059
|
+
// subscription lapsed). Fail-over handles this request, but without a latch every
|
|
1060
|
+
// later request would pick the account again. recordProbeError latches
|
|
1061
|
+
// subscriptionGone on 3 strikes — the request path strikes once per hit, so this
|
|
1062
|
+
// converges after three routed attempts and benches it exactly like the probe path.
|
|
1063
|
+
if (account.type !== 'provider' && upstreamRes.status === 403
|
|
1064
|
+
&& /not allowed for this organization|organization has disabled/i.test(String(why))) {
|
|
1065
|
+
accountManager.recordProbeError?.(account.index, String(why).slice(0, 160), 403);
|
|
1066
|
+
}
|
|
1057
1067
|
// Providers answer with a code and no field name, so record what WE sent.
|
|
1058
1068
|
if (account.type === 'provider') {
|
|
1059
1069
|
console.log(`[Maxpool] request shape: ${describeBodyShape(upstreamBody || body).slice(0, 600)}`);
|
package/src/tui.js
CHANGED
|
@@ -2022,6 +2022,9 @@ export class TUI {
|
|
|
2022
2022
|
// broken account. Reported 2026-08-10 with all 8 disabled accounts sitting on dead
|
|
2023
2023
|
// credentials (HTTP 401) and no way to see it.
|
|
2024
2024
|
if (a.refreshDead) effectiveStatus = a.enabled === false ? 'disabled-reauth' : 'reauth';
|
|
2025
|
+
// Subscription gone (org-disabled 403): a DISTINCT state from reauth — re-logging in
|
|
2026
|
+
// will NOT fix it until the subscription is re-purchased. Says the actionable thing.
|
|
2027
|
+
else if (a.subscriptionGone) effectiveStatus = 'no sub';
|
|
2025
2028
|
switch (effectiveStatus) {
|
|
2026
2029
|
case 'active': status = isCur ? green('active') : 'active'; break;
|
|
2027
2030
|
case 'reauth': status = yellow('reauth'); break;
|
|
@@ -2033,6 +2036,7 @@ export class TUI {
|
|
|
2033
2036
|
// Disabled AND needs re-login — both facts matter: it won't serve because you
|
|
2034
2037
|
// switched it off, and it CAN'T serve until you log in again.
|
|
2035
2038
|
case 'disabled-reauth': status = red('✕ reauth'); break;
|
|
2039
|
+
case 'no sub': status = red('✕ no sub'); break;
|
|
2036
2040
|
case 'throttled': {
|
|
2037
2041
|
// A transient auto-recovering cooldown — show the remaining time (from
|
|
2038
2042
|
// rateLimitedUntil) so it reads as "recovering in Ns", not stuck.
|
|
@@ -2128,7 +2132,7 @@ export class TUI {
|
|
|
2128
2132
|
// "stale·probe 401" here is just the perpetual echo of the 401 that killed it.
|
|
2129
2133
|
// Only annotate probe-staleness for LIVE accounts, where a failing probe
|
|
2130
2134
|
// (e.g. a 429) is a real, actionable signal.
|
|
2131
|
-
if (a?.refreshDead || a?.enabled === false) return '';
|
|
2135
|
+
if (a?.refreshDead || a?.subscriptionGone || a?.enabled === false) return '';
|
|
2132
2136
|
if (!this.am._quotaProbeStale?.(a)) return ''; // probe fresh (or off) → nothing to flag; interval>0 after this
|
|
2133
2137
|
// The background probe IS stale — but only flag it if something DISPLAYED is
|
|
2134
2138
|
// actually stale. An OAuth account's Ses/Wk bars come from unified5h/7d, which
|