maxpool 1.5.20 → 1.5.21
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 +41 -0
- package/src/index.js +18 -1
package/package.json
CHANGED
package/src/account-manager.js
CHANGED
|
@@ -2438,6 +2438,47 @@ export class AccountManager {
|
|
|
2438
2438
|
return idx;
|
|
2439
2439
|
}
|
|
2440
2440
|
|
|
2441
|
+
/**
|
|
2442
|
+
* Serialize runtime (client-supplied) PROVIDER accounts so they survive a
|
|
2443
|
+
* restart. They're created lazily from `cc all` request headers
|
|
2444
|
+
* (prepareRuntimeProviders), NOT from config — so without persistence a cold boot
|
|
2445
|
+
* / reload shows only the config OAuth accounts until the next `cc all` request
|
|
2446
|
+
* re-sends the tokens. Persisted to state.json (0600, same protection as the
|
|
2447
|
+
* OAuth-token-bearing config) alongside quota.
|
|
2448
|
+
*/
|
|
2449
|
+
exportRuntimeProviders() {
|
|
2450
|
+
return this.accounts
|
|
2451
|
+
.filter(a => a.runtime && a.type === 'provider' && a.credential)
|
|
2452
|
+
.map(a => ({
|
|
2453
|
+
name: a.name,
|
|
2454
|
+
type: a.type,
|
|
2455
|
+
provider: a.provider,
|
|
2456
|
+
authToken: a.credential,
|
|
2457
|
+
upstream: a.upstream,
|
|
2458
|
+
authHeader: a.authHeader,
|
|
2459
|
+
profiles: a.profiles,
|
|
2460
|
+
priority: a.priority,
|
|
2461
|
+
model: a.model,
|
|
2462
|
+
modelMap: a.modelMap,
|
|
2463
|
+
stripBetaHeaders: a.stripBetaHeaders,
|
|
2464
|
+
}));
|
|
2465
|
+
}
|
|
2466
|
+
|
|
2467
|
+
/**
|
|
2468
|
+
* Restore persisted runtime providers on boot, via the SAME upsert the header
|
|
2469
|
+
* path uses (so a restored provider is byte-identical to a header-created one). A
|
|
2470
|
+
* live `cc all` request refreshes the token before routing (prepareRuntimeProviders
|
|
2471
|
+
* runs ahead of account selection), so a stale restored token never serves a
|
|
2472
|
+
* request. Idempotent — upsertRuntimeAccount matches by name.
|
|
2473
|
+
*/
|
|
2474
|
+
restoreRuntimeProviders(list) {
|
|
2475
|
+
if (!Array.isArray(list)) return;
|
|
2476
|
+
for (const p of list) {
|
|
2477
|
+
if (!p || !p.name || !(p.authToken || p.credential)) continue;
|
|
2478
|
+
this.upsertRuntimeAccount({ ...p, authToken: p.authToken || p.credential });
|
|
2479
|
+
}
|
|
2480
|
+
}
|
|
2481
|
+
|
|
2441
2482
|
/**
|
|
2442
2483
|
* Remove an account by index.
|
|
2443
2484
|
*/
|
package/src/index.js
CHANGED
|
@@ -528,6 +528,15 @@ async function serverWorkerCommand() {
|
|
|
528
528
|
// lease holder); a cold/direct worker reads the on-disk state file.
|
|
529
529
|
const savedState = await loadState();
|
|
530
530
|
if (savedState?.quota) accountManager.restoreQuotaState(savedState.quota);
|
|
531
|
+
// Runtime fallback providers (glm-fallback/kimi-fallback) are created lazily from
|
|
532
|
+
// `cc all` request headers, not config — so without restoring them here a restart
|
|
533
|
+
// shows only the config OAuth accounts until the next `cc all` request re-sends the
|
|
534
|
+
// tokens. NOTE: a SEAMLESS reload worker reads state at spawn (before the outgoing
|
|
535
|
+
// worker's final flush), so a provider created <60s before that reload (not yet
|
|
536
|
+
// interval-flushed) is missed until the next `cc all` request — the same
|
|
537
|
+
// self-healing window as an abrupt SIGKILL. A cold restart reads the clean-shutdown
|
|
538
|
+
// final flush and restores fully (the reported zero-request case).
|
|
539
|
+
if (savedState?.runtimeProviders) accountManager.restoreRuntimeProviders(savedState.runtimeProviders);
|
|
531
540
|
// Track the state-file generation we last observed so a stale flush is refused.
|
|
532
541
|
let stateGeneration = Number(savedState?._generation) || 0;
|
|
533
542
|
|
|
@@ -550,7 +559,15 @@ async function serverWorkerCommand() {
|
|
|
550
559
|
// flush REFUSED (dropping the final quota snapshot). The guard only exists to
|
|
551
560
|
// serialize CROSS-worker writes; the final flush is provably intra-worker.
|
|
552
561
|
const expectedGeneration = force ? null : stateGeneration;
|
|
553
|
-
return saveState(
|
|
562
|
+
return saveState(
|
|
563
|
+
{
|
|
564
|
+
quota: accountManager.exportQuotaState(),
|
|
565
|
+
// Runtime providers so glm-fallback/kimi-fallback survive a restart (they're
|
|
566
|
+
// header-derived, not in config). Empty [] when none — harmless.
|
|
567
|
+
runtimeProviders: accountManager.exportRuntimeProviders(),
|
|
568
|
+
},
|
|
569
|
+
{ expectedGeneration },
|
|
570
|
+
)
|
|
554
571
|
.then(written => { if (written != null) stateGeneration = written; })
|
|
555
572
|
.catch(() => {});
|
|
556
573
|
};
|