maxpool 1.24.29 → 1.24.30
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/prober.js +9 -2
- package/src/zai-reset-cards.js +9 -5
package/package.json
CHANGED
package/src/prober.js
CHANGED
|
@@ -219,16 +219,23 @@ export class Prober {
|
|
|
219
219
|
* the backoff; the idempotent requestId keeps any overlapping attempt single-spend. */
|
|
220
220
|
async _redeemZaiCard(account, act) {
|
|
221
221
|
try {
|
|
222
|
-
const key = `${account.
|
|
222
|
+
const key = `${account.name}:${act.card.recordId}`; // name, not index: index shifts on account removal
|
|
223
223
|
const now = Date.now();
|
|
224
224
|
const until = this._cardRetryUntil?.get(key);
|
|
225
225
|
if (until && until > now) return; // still backing off
|
|
226
226
|
const q = account.quota || {};
|
|
227
227
|
this.log(`[reset-card] ${account.name}: redeeming ${act.resetType} card ${act.card.recordId} (${act.reason}; ses=${q.providerSes ?? '?'} wk=${q.providerWk ?? '?'})`);
|
|
228
|
-
|
|
228
|
+
let r = await this._withTimeout(redeemResetCard(account.credential, act.card.recordId, act.resetType, { grantType: act.card.grantType, accountKey: account.name }));
|
|
229
|
+
// grantType-less listing + "unavailable" is the exact 2026-10-22 outage shape; GLOBAL
|
|
230
|
+
// is the only grantType z.ai has ever issued and a wrong one answers 400 no-spend
|
|
231
|
+
// (measured, src/zai-reset-cards.js header) — so one fallback retry is safe.
|
|
232
|
+
if (!r?.ok && !act.card.grantType && /unavailable/i.test(r?.error || '')) {
|
|
233
|
+
r = await this._withTimeout(redeemResetCard(account.credential, act.card.recordId, act.resetType, { grantType: 'GLOBAL', accountKey: account.name }));
|
|
234
|
+
}
|
|
229
235
|
if (r?.ok) {
|
|
230
236
|
if (!this._cardRetryUntil) this._cardRetryUntil = new Map();
|
|
231
237
|
this._cardRetryUntil.set(key, 0); // success clears any backoff
|
|
238
|
+
this._cardTries?.set(key, 0); // ...and the failure count (red-team 2026-10-23)
|
|
232
239
|
this.log(`[reset-card] ${account.name}: card ${act.card.recordId} redeemed`);
|
|
233
240
|
if (this.am.applyResetCards) {
|
|
234
241
|
const fresh = await this._withTimeout(listResetCards(account.credential));
|
package/src/zai-reset-cards.js
CHANGED
|
@@ -85,15 +85,19 @@ export async function listResetCards(token, { signal, fetchImpl = fetch } = {})
|
|
|
85
85
|
}
|
|
86
86
|
|
|
87
87
|
/** Deterministic requestId for a card: retries of the SAME redeem are idempotent
|
|
88
|
-
* server-side, so a network blip mid-redeem can never double-spend.
|
|
89
|
-
|
|
90
|
-
|
|
88
|
+
* server-side, so a network blip mid-redeem can never double-spend. The account
|
|
89
|
+
* key scopes it too — recordIds collide across z.ai accounts (card 9 on max+1 AND
|
|
90
|
+
* glm4, 2026-10-23); z.ai idempotency measured per-account, but scoping keeps the
|
|
91
|
+
* two accounts' keys distinct even if that assumption ever changes (red-team).
|
|
92
|
+
* accountKey never changes semantics for a given account, so retries stay stable. */
|
|
93
|
+
function requestIdFor(recordId, accountKey = '') {
|
|
94
|
+
const h = createHash('sha256').update(`maxpool-zai-card-${accountKey}-${recordId}`).digest('hex').slice(0, 24);
|
|
91
95
|
return `maxpool-${h}`;
|
|
92
96
|
}
|
|
93
97
|
|
|
94
98
|
/** Redeem one card. NEVER retries on the wire here (the idempotency key makes a
|
|
95
99
|
* caller-level retry safe). Returns { ok:true, recordId } | { ok:false, error, code }. */
|
|
96
|
-
export async function redeemResetCard(token, recordId, resetType, { grantType, signal, fetchImpl = fetch } = {}) {
|
|
100
|
+
export async function redeemResetCard(token, recordId, resetType, { grantType, accountKey = '', signal, fetchImpl = fetch } = {}) {
|
|
97
101
|
if (resetType !== 'WEEK' && resetType !== 'FIVE_HOUR') {
|
|
98
102
|
return { ok: false, error: `invalid resetType ${resetType}` };
|
|
99
103
|
}
|
|
@@ -105,7 +109,7 @@ export async function redeemResetCard(token, recordId, resetType, { grantType, s
|
|
|
105
109
|
// grantType answers "Unsupported coupon grant type" without spending anything.
|
|
106
110
|
const body = {
|
|
107
111
|
recordId, targetType: 'PERSONAL', resetType,
|
|
108
|
-
requestId: requestIdFor(recordId),
|
|
112
|
+
requestId: requestIdFor(recordId, accountKey),
|
|
109
113
|
};
|
|
110
114
|
if (grantType) body.grantType = grantType;
|
|
111
115
|
const res = await fetchImpl(USE_URL, {
|