maxpool 1.5.53 → 1.5.55
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/index.js +19 -0
- package/src/server.js +17 -6
package/package.json
CHANGED
package/src/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
+
import net from 'node:net';
|
|
3
4
|
import { spawn, spawnSync } from 'node:child_process';
|
|
4
5
|
import { createInterface } from 'node:readline';
|
|
5
6
|
import { loadOrCreateConfig, loadConfig, saveConfig, atomicConfigUpdate, getConfigPath, loadState, saveState, getStatePath, getLogPath, readGeneration, flushConfigWrites, flushStateWrites } from './config.js';
|
|
@@ -7,6 +8,24 @@ import { setEventLogPath, installConsoleMirror, setConsoleStdoutSuppressed } fro
|
|
|
7
8
|
import { SleepGuard } from './sleep-guard.js';
|
|
8
9
|
import { AccountManager } from './account-manager.js';
|
|
9
10
|
import { createProxyServer, REQUEST_IDLE_MAX_MS } from './server.js';
|
|
11
|
+
|
|
12
|
+
// ── Happy Eyeballs: stop racing a dead IPv6 leg ────────────────────────────────
|
|
13
|
+
// Node 20 resolves both families and, 250ms after starting the IPv4 connect, races an
|
|
14
|
+
// IPv6 one (autoSelectFamily, autoSelectFamilyAttemptTimeout=250). On a machine whose
|
|
15
|
+
// resolver returns an AAAA that BLACKHOLES — a VPN advertising IPv6 it cannot carry is
|
|
16
|
+
// the common case — that second leg never completes and takes the whole connect down
|
|
17
|
+
// with it, surfacing as UND_ERR_CONNECT_TIMEOUT / ETIMEDOUT on a network that is
|
|
18
|
+
// otherwise fine (curl, which falls back cleanly, succeeds in the same second).
|
|
19
|
+
//
|
|
20
|
+
// Measured 2026-08-01 on this fleet: 6,848 connect failures in one day; A/B over 14
|
|
21
|
+
// requests gave 12/14 at the 250ms default vs 14/14 with the timeout raised. Raising it
|
|
22
|
+
// is preferred over disabling the race outright: real IPv6 still wins where it works,
|
|
23
|
+
// and a blackholed leg simply loses instead of poisoning the attempt. `dns
|
|
24
|
+
// setDefaultResultOrder('ipv4first')` was ALSO measured and is NOT reliable (6 of 14 in a
|
|
25
|
+
// degraded window) — it reorders preference but still starts the doomed leg.
|
|
26
|
+
net.setDefaultAutoSelectFamilyAttemptTimeout(
|
|
27
|
+
Math.max(1000, Number(process.env.MAXPOOL_FAMILY_ATTEMPT_TIMEOUT_MS) || 5000),
|
|
28
|
+
);
|
|
10
29
|
import { Prober } from './prober.js';
|
|
11
30
|
import { loginOAuth, fetchProfile, refreshAccessToken, isTokenExpiringSoon, tokenFingerprint } from './oauth.js';
|
|
12
31
|
import { TUI } from './tui.js';
|
package/src/server.js
CHANGED
|
@@ -1446,11 +1446,18 @@ function unavailableMessage(accountManager, requestInfo = {}, retryAfter, willRe
|
|
|
1446
1446
|
}
|
|
1447
1447
|
|
|
1448
1448
|
const claudeCount = accountManager.accounts.filter(a => a.type !== 'provider').length;
|
|
1449
|
-
// Only name the providers when this pool
|
|
1450
|
-
//
|
|
1451
|
-
//
|
|
1452
|
-
|
|
1449
|
+
// Only name the providers when this pool HAS them AND they are actually allowed to
|
|
1450
|
+
// serve this request. With crossProviderFallbackPolicy 'never' (the default) they are
|
|
1451
|
+
// barred by POLICY, not saturated — saying they are "at their limit" is a lie that
|
|
1452
|
+
// hides the real, one-keypress fix. Name the switch instead.
|
|
1453
|
+
const providerAccounts = accountManager.accounts.filter(a => a.type === 'provider');
|
|
1454
|
+
const providersUsable = providerAccounts.some(a => a.enabled !== false
|
|
1455
|
+
&& accountManager._claudeFallbackFor?.(a.provider) !== 'never');
|
|
1456
|
+
const providersClause = providerAccounts.length && providersUsable
|
|
1453
1457
|
? ' and the GLM/Kimi providers' : '';
|
|
1458
|
+
const providersBarredHint = providerAccounts.length && !providersUsable
|
|
1459
|
+
? ' GLM and Kimi are switched off for Claude sessions — turn one on with m then g if you want them to cover this.'
|
|
1460
|
+
: '';
|
|
1454
1461
|
|
|
1455
1462
|
// No route is expected to recover within the queue window — i.e. every Claude
|
|
1456
1463
|
// account is at its own 5h/weekly limit. A short "retry in Ns" would be a lie;
|
|
@@ -1459,10 +1466,14 @@ function unavailableMessage(accountManager, requestInfo = {}, retryAfter, willRe
|
|
|
1459
1466
|
const eta = Number.isFinite(retryAfter) && retryAfter > 0
|
|
1460
1467
|
? ` Soonest reset in ~${formatRetryDuration(retryAfter)}, beyond the hold window.`
|
|
1461
1468
|
: '';
|
|
1462
|
-
return `No account can take this request — all ${claudeCount} Claude accounts${providersClause} are at their limit.${eta} Add another Claude account or wait for a quota reset
|
|
1469
|
+
return `No account can take this request — all ${claudeCount} Claude accounts${providersClause} are at their limit.${eta} Add another Claude account or wait for a quota reset.${providersBarredHint}`;
|
|
1463
1470
|
}
|
|
1464
1471
|
|
|
1465
|
-
|
|
1472
|
+
// "momentarily ... Retry in 2282s" was two bugs in one breath: 2282 seconds is 38
|
|
1473
|
+
// MINUTES (not momentary), and raw seconds are unreadable. Scale the wording to the
|
|
1474
|
+
// actual wait and render it in human units, the way every other branch already does.
|
|
1475
|
+
const waitLong = Number.isFinite(retryAfter) && retryAfter >= 120;
|
|
1476
|
+
return `No account can take this request right now — all ${claudeCount} Claude accounts${providersClause} are ${waitLong ? 'at their limit' : 'momentarily at their limit'}. Retry in ~${formatRetryDuration(retryAfter)}.${providersBarredHint}`;
|
|
1466
1477
|
}
|
|
1467
1478
|
|
|
1468
1479
|
// A provider (GLM/Kimi) rejecting a request whose token count exceeds its context
|