@blockrun/clawrouter 0.8.11 → 0.8.12

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/dist/index.js CHANGED
@@ -2362,6 +2362,42 @@ var HEALTH_CHECK_TIMEOUT_MS = 2e3;
2362
2362
  var RATE_LIMIT_COOLDOWN_MS = 6e4;
2363
2363
  var PORT_RETRY_ATTEMPTS = 5;
2364
2364
  var PORT_RETRY_DELAY_MS = 1e3;
2365
+ function transformPaymentError(errorBody) {
2366
+ try {
2367
+ const parsed = JSON.parse(errorBody);
2368
+ if (parsed.error === "Payment verification failed" && parsed.details) {
2369
+ const match = parsed.details.match(/Verification failed:\s*(\{.*\})/s);
2370
+ if (match) {
2371
+ const innerJson = JSON.parse(match[1]);
2372
+ if (innerJson.invalidReason === "insufficient_funds" && innerJson.invalidMessage) {
2373
+ const balanceMatch = innerJson.invalidMessage.match(
2374
+ /insufficient balance:\s*(\d+)\s*<\s*(\d+)/i
2375
+ );
2376
+ if (balanceMatch) {
2377
+ const currentMicros = parseInt(balanceMatch[1], 10);
2378
+ const requiredMicros = parseInt(balanceMatch[2], 10);
2379
+ const currentUSD = (currentMicros / 1e6).toFixed(6);
2380
+ const requiredUSD = (requiredMicros / 1e6).toFixed(6);
2381
+ const wallet = innerJson.payer || "unknown";
2382
+ const shortWallet = wallet.length > 12 ? `${wallet.slice(0, 6)}...${wallet.slice(-4)}` : wallet;
2383
+ return JSON.stringify({
2384
+ error: {
2385
+ message: `Insufficient USDC balance. Current: $${currentUSD}, Required: ~$${requiredUSD}`,
2386
+ type: "insufficient_funds",
2387
+ wallet,
2388
+ current_balance_usd: currentUSD,
2389
+ required_usd: requiredUSD,
2390
+ help: `Fund wallet ${shortWallet} with USDC on Base, or use free model: /model free`
2391
+ }
2392
+ });
2393
+ }
2394
+ }
2395
+ }
2396
+ }
2397
+ } catch {
2398
+ }
2399
+ return errorBody;
2400
+ }
2365
2401
  var rateLimitedModels = /* @__PURE__ */ new Map();
2366
2402
  function isRateLimited(modelId) {
2367
2403
  const hitTime = rateLimitedModels.get(modelId);
@@ -3230,10 +3266,18 @@ async function proxyRequest(req, res, apiBase, payFetch, options, routerOpts, de
3230
3266
  options.onRouted?.(routingDecision);
3231
3267
  }
3232
3268
  if (!upstream) {
3233
- const errBody = lastError?.body || "All models in fallback chain failed";
3269
+ const rawErrBody = lastError?.body || "All models in fallback chain failed";
3234
3270
  const errStatus = lastError?.status || 502;
3271
+ const transformedErr = transformPaymentError(rawErrBody);
3235
3272
  if (headersSentEarly) {
3236
- const errEvent = `data: ${JSON.stringify({ error: { message: errBody, type: "provider_error", status: errStatus } })}
3273
+ let errPayload;
3274
+ try {
3275
+ const parsed = JSON.parse(transformedErr);
3276
+ errPayload = JSON.stringify(parsed);
3277
+ } catch {
3278
+ errPayload = JSON.stringify({ error: { message: rawErrBody, type: "provider_error", status: errStatus } });
3279
+ }
3280
+ const errEvent = `data: ${errPayload}
3237
3281
 
3238
3282
  `;
3239
3283
  safeWrite(res, errEvent);
@@ -3248,17 +3292,11 @@ async function proxyRequest(req, res, apiBase, payFetch, options, routerOpts, de
3248
3292
  });
3249
3293
  } else {
3250
3294
  res.writeHead(errStatus, { "Content-Type": "application/json" });
3251
- res.end(
3252
- JSON.stringify({
3253
- error: { message: errBody, type: "provider_error" }
3254
- })
3255
- );
3295
+ res.end(transformedErr);
3256
3296
  deduplicator.complete(dedupKey, {
3257
3297
  status: errStatus,
3258
3298
  headers: { "content-type": "application/json" },
3259
- body: Buffer.from(
3260
- JSON.stringify({ error: { message: errBody, type: "provider_error" } })
3261
- ),
3299
+ body: Buffer.from(transformedErr),
3262
3300
  completedAt: Date.now()
3263
3301
  });
3264
3302
  }