@blockrun/llm 2.11.1 → 2.13.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/dist/index.cjs CHANGED
@@ -39,6 +39,7 @@ __export(index_exports, {
39
39
  KNOWN_PROVIDERS: () => KNOWN_PROVIDERS,
40
40
  LLMClient: () => LLMClient,
41
41
  MusicClient: () => MusicClient,
42
+ NETWORK_ALIASES: () => NETWORK_ALIASES,
42
43
  OpenAI: () => OpenAI,
43
44
  PHONE_PRICES: () => PHONE_PRICES,
44
45
  PORTRAIT_ENROLLMENT_PRICE_USD: () => PORTRAIT_ENROLLMENT_PRICE_USD,
@@ -46,10 +47,14 @@ __export(index_exports, {
46
47
  PhoneClient: () => PhoneClient,
47
48
  PortraitClient: () => PortraitClient,
48
49
  PriceClient: () => PriceClient,
50
+ RPC_PRICE_USD: () => RPC_PRICE_USD,
51
+ RpcClient: () => RpcClient,
49
52
  SOLANA_NETWORK: () => SOLANA_NETWORK,
50
53
  SOLANA_WALLET_FILE_PATH: () => SOLANA_WALLET_FILE,
54
+ SUPPORTED_NETWORKS: () => SUPPORTED_NETWORKS,
51
55
  SearchClient: () => SearchClient,
52
56
  SolanaLLMClient: () => SolanaLLMClient,
57
+ SpeechClient: () => SpeechClient,
53
58
  SurfClient: () => SurfClient,
54
59
  USDC_BASE: () => USDC_BASE,
55
60
  USDC_BASE_CONTRACT: () => USDC_BASE_CONTRACT,
@@ -2398,11 +2403,210 @@ var MusicClient = class {
2398
2403
  }
2399
2404
  };
2400
2405
 
2401
- // src/video.ts
2406
+ // src/speech.ts
2402
2407
  var import_accounts5 = require("viem/accounts");
2403
2408
  var DEFAULT_API_URL4 = "https://blockrun.ai/api";
2404
- var DEFAULT_MODEL3 = "xai/grok-imagine-video";
2409
+ var DEFAULT_MODEL3 = "elevenlabs/flash-v2.5";
2410
+ var DEFAULT_SOUNDFX_MODEL = "elevenlabs/sound-effects";
2405
2411
  var DEFAULT_TIMEOUT4 = 12e4;
2412
+ var SpeechClient = class {
2413
+ account;
2414
+ privateKey;
2415
+ apiUrl;
2416
+ timeout;
2417
+ sessionTotalUsd = 0;
2418
+ sessionCalls = 0;
2419
+ constructor(options = {}) {
2420
+ const envKey = typeof process !== "undefined" && process.env ? process.env.BLOCKRUN_WALLET_KEY || process.env.BASE_CHAIN_WALLET_KEY : void 0;
2421
+ const privateKey = options.privateKey || envKey;
2422
+ if (!privateKey) {
2423
+ throw new Error(
2424
+ "Private key required. Pass privateKey in options or set BLOCKRUN_WALLET_KEY environment variable."
2425
+ );
2426
+ }
2427
+ validatePrivateKey(privateKey);
2428
+ this.privateKey = privateKey;
2429
+ this.account = (0, import_accounts5.privateKeyToAccount)(privateKey);
2430
+ const apiUrl = options.apiUrl || DEFAULT_API_URL4;
2431
+ validateApiUrl(apiUrl);
2432
+ this.apiUrl = apiUrl.replace(/\/$/, "");
2433
+ this.timeout = options.timeout || DEFAULT_TIMEOUT4;
2434
+ }
2435
+ /**
2436
+ * Synthesize speech from text (OpenAI-compatible TTS).
2437
+ *
2438
+ * Price scales with character count: (chars / 1000) x model rate,
2439
+ * minimum $0.001/request. Synthesis is synchronous.
2440
+ *
2441
+ * @param input - Text to synthesize. Per-model character caps apply
2442
+ * (flash/turbo 40k, multilingual-v2 10k, v3 5k).
2443
+ * @param options - Optional model / voice / format / speed
2444
+ * @returns SpeechResponse with audio URL, format, and character count
2445
+ *
2446
+ * @example
2447
+ * const result = await client.generate('Welcome to BlockRun.', { voice: 'george' });
2448
+ * console.log(result.data[0].url); // audio URL (mp3 by default)
2449
+ */
2450
+ async generate(input, options) {
2451
+ const body = {
2452
+ model: options?.model || DEFAULT_MODEL3,
2453
+ input
2454
+ };
2455
+ if (options?.voice) body.voice = options.voice;
2456
+ if (options?.responseFormat) body.response_format = options.responseFormat;
2457
+ if (options?.speed !== void 0) body.speed = options.speed;
2458
+ return this.requestWithPayment("/v1/audio/speech", body);
2459
+ }
2460
+ /** OpenAI-style alias for {@link generate}. */
2461
+ speak(input, options) {
2462
+ return this.generate(input, options);
2463
+ }
2464
+ /**
2465
+ * Generate a cinematic sound effect from a text prompt.
2466
+ *
2467
+ * Flat $0.05/generation, up to 22 seconds of audio.
2468
+ *
2469
+ * @param text - Sound effect description (max 1000 chars).
2470
+ * E.g. 'rain on a tin roof', 'sci-fi door whoosh'
2471
+ * @param options - Optional duration / prompt influence / format
2472
+ * @returns SpeechResponse with audio URL and format
2473
+ *
2474
+ * @example
2475
+ * const fx = await client.soundEffect('crackling campfire at night');
2476
+ * console.log(fx.data[0].url);
2477
+ */
2478
+ async soundEffect(text, options) {
2479
+ const body = {
2480
+ model: options?.model || DEFAULT_SOUNDFX_MODEL,
2481
+ text
2482
+ };
2483
+ if (options?.durationSeconds !== void 0) body.duration_seconds = options.durationSeconds;
2484
+ if (options?.promptInfluence !== void 0) body.prompt_influence = options.promptInfluence;
2485
+ if (options?.responseFormat) body.response_format = options.responseFormat;
2486
+ return this.requestWithPayment("/v1/audio/sound-effects", body);
2487
+ }
2488
+ /**
2489
+ * List available voices for TTS (free, rate-limited 60 req/min/IP).
2490
+ *
2491
+ * Pass a voice's `alias` (if present) or `voice_id` as the `voice`
2492
+ * option to {@link generate}.
2493
+ */
2494
+ async listVoices() {
2495
+ const response = await this.fetchWithTimeout(`${this.apiUrl}/v1/audio/voices`, {
2496
+ method: "GET"
2497
+ });
2498
+ if (!response.ok) {
2499
+ let errorBody;
2500
+ try {
2501
+ errorBody = await response.json();
2502
+ } catch {
2503
+ errorBody = { error: "Request failed" };
2504
+ }
2505
+ throw new APIError(`API error: ${response.status}`, response.status, sanitizeErrorResponse(errorBody));
2506
+ }
2507
+ const payload = await response.json();
2508
+ return payload.data || [];
2509
+ }
2510
+ async requestWithPayment(endpoint, body) {
2511
+ const url = `${this.apiUrl}${endpoint}`;
2512
+ const response = await this.fetchWithTimeout(url, {
2513
+ method: "POST",
2514
+ headers: { "Content-Type": "application/json" },
2515
+ body: JSON.stringify(body)
2516
+ });
2517
+ if (response.status === 402) {
2518
+ return this.handlePaymentAndRetry(url, endpoint, body, response);
2519
+ }
2520
+ if (!response.ok) {
2521
+ let errorBody;
2522
+ try {
2523
+ errorBody = await response.json();
2524
+ } catch {
2525
+ errorBody = { error: "Request failed" };
2526
+ }
2527
+ throw new APIError(`API error: ${response.status}`, response.status, sanitizeErrorResponse(errorBody));
2528
+ }
2529
+ return response.json();
2530
+ }
2531
+ async handlePaymentAndRetry(url, endpoint, body, response) {
2532
+ let paymentHeader = response.headers.get("payment-required");
2533
+ if (!paymentHeader) {
2534
+ try {
2535
+ const respBody = await response.json();
2536
+ if (respBody.x402 || respBody.accepts) {
2537
+ paymentHeader = btoa(JSON.stringify(respBody));
2538
+ }
2539
+ } catch {
2540
+ }
2541
+ }
2542
+ if (!paymentHeader) {
2543
+ throw new PaymentError("402 response but no payment requirements found");
2544
+ }
2545
+ const paymentRequired = parsePaymentRequired(paymentHeader);
2546
+ const details = extractPaymentDetails(paymentRequired);
2547
+ const paymentPayload = await createPaymentPayload(
2548
+ this.privateKey,
2549
+ this.account.address,
2550
+ details.recipient,
2551
+ details.amount,
2552
+ details.network || "eip155:8453",
2553
+ {
2554
+ resourceUrl: details.resource?.url || `${this.apiUrl}${endpoint}`,
2555
+ resourceDescription: details.resource?.description || "BlockRun Voice",
2556
+ maxTimeoutSeconds: details.maxTimeoutSeconds || 300,
2557
+ extra: details.extra
2558
+ }
2559
+ );
2560
+ const retryResponse = await this.fetchWithTimeout(url, {
2561
+ method: "POST",
2562
+ headers: {
2563
+ "Content-Type": "application/json",
2564
+ "PAYMENT-SIGNATURE": paymentPayload
2565
+ },
2566
+ body: JSON.stringify(body)
2567
+ });
2568
+ if (retryResponse.status === 402) {
2569
+ throw new PaymentError("Payment was rejected. Check your wallet balance.");
2570
+ }
2571
+ if (!retryResponse.ok) {
2572
+ let errorBody;
2573
+ try {
2574
+ errorBody = await retryResponse.json();
2575
+ } catch {
2576
+ errorBody = { error: "Request failed" };
2577
+ }
2578
+ throw new APIError(`API error after payment: ${retryResponse.status}`, retryResponse.status, sanitizeErrorResponse(errorBody));
2579
+ }
2580
+ const data = await retryResponse.json();
2581
+ this.sessionCalls++;
2582
+ const paidUsd = Number(details.amount) / 1e6;
2583
+ if (Number.isFinite(paidUsd)) this.sessionTotalUsd += paidUsd;
2584
+ const txHash = retryResponse.headers.get("x-payment-receipt") || retryResponse.headers.get("X-Payment-Receipt");
2585
+ if (txHash) data.txHash = txHash;
2586
+ return data;
2587
+ }
2588
+ async fetchWithTimeout(url, options) {
2589
+ const controller = new AbortController();
2590
+ const timeoutId = setTimeout(() => controller.abort(), this.timeout);
2591
+ try {
2592
+ return await fetch(url, { ...options, signal: controller.signal });
2593
+ } finally {
2594
+ clearTimeout(timeoutId);
2595
+ }
2596
+ }
2597
+ getWalletAddress() {
2598
+ return this.account.address;
2599
+ }
2600
+ getSpending() {
2601
+ return { totalUsd: this.sessionTotalUsd, calls: this.sessionCalls };
2602
+ }
2603
+ };
2604
+
2605
+ // src/video.ts
2606
+ var import_accounts6 = require("viem/accounts");
2607
+ var DEFAULT_API_URL5 = "https://blockrun.ai/api";
2608
+ var DEFAULT_MODEL4 = "xai/grok-imagine-video";
2609
+ var DEFAULT_TIMEOUT5 = 12e4;
2406
2610
  var POLL_INTERVAL_MS2 = 5e3;
2407
2611
  var DEFAULT_GENERATE_BUDGET_MS = 3e5;
2408
2612
  var MAX_TIMEOUT_SECONDS = 600;
@@ -2423,11 +2627,11 @@ var VideoClient = class {
2423
2627
  }
2424
2628
  validatePrivateKey(privateKey);
2425
2629
  this.privateKey = privateKey;
2426
- this.account = (0, import_accounts5.privateKeyToAccount)(privateKey);
2427
- const apiUrl = options.apiUrl || DEFAULT_API_URL4;
2630
+ this.account = (0, import_accounts6.privateKeyToAccount)(privateKey);
2631
+ const apiUrl = options.apiUrl || DEFAULT_API_URL5;
2428
2632
  validateApiUrl(apiUrl);
2429
2633
  this.apiUrl = apiUrl.replace(/\/$/, "");
2430
- this.timeout = options.timeout || DEFAULT_TIMEOUT4;
2634
+ this.timeout = options.timeout || DEFAULT_TIMEOUT5;
2431
2635
  }
2432
2636
  /**
2433
2637
  * Generate a short video clip from a text prompt (or text + image).
@@ -2450,11 +2654,33 @@ var VideoClient = class {
2450
2654
  "realFaceAssetId must be a Token360 asset id matching 'ta_[A-Za-z0-9]+' (e.g. 'ta_abc123xyz')"
2451
2655
  );
2452
2656
  }
2657
+ if (options?.lastFrameUrl && !options?.imageUrl) {
2658
+ throw new Error(
2659
+ "lastFrameUrl requires imageUrl: imageUrl seeds the FIRST frame and lastFrameUrl the FINAL frame \u2014 send both."
2660
+ );
2661
+ }
2662
+ if (options?.lastFrameUrl && options?.realFaceAssetId) {
2663
+ throw new Error(
2664
+ "lastFrameUrl and realFaceAssetId are mutually exclusive; first-and-last-frame uses imageUrl + lastFrameUrl."
2665
+ );
2666
+ }
2667
+ if (options?.referenceImageUrls?.length) {
2668
+ if (options.imageUrl || options.lastFrameUrl || options.realFaceAssetId) {
2669
+ throw new Error(
2670
+ "referenceImageUrls is mutually exclusive with imageUrl, lastFrameUrl, and realFaceAssetId."
2671
+ );
2672
+ }
2673
+ if (options.referenceImageUrls.length > 9) {
2674
+ throw new Error("referenceImageUrls accepts at most 9 images.");
2675
+ }
2676
+ }
2453
2677
  const body = {
2454
- model: options?.model || DEFAULT_MODEL3,
2678
+ model: options?.model || DEFAULT_MODEL4,
2455
2679
  prompt
2456
2680
  };
2457
2681
  if (options?.imageUrl) body.image_url = options.imageUrl;
2682
+ if (options?.lastFrameUrl) body.last_frame_url = options.lastFrameUrl;
2683
+ if (options?.referenceImageUrls?.length) body.reference_image_urls = options.referenceImageUrls;
2458
2684
  if (options?.realFaceAssetId) body.real_face_asset_id = options.realFaceAssetId;
2459
2685
  if (options?.durationSeconds !== void 0) body.duration_seconds = options.durationSeconds;
2460
2686
  if (options?.aspectRatio) body.aspect_ratio = options.aspectRatio;
@@ -2609,9 +2835,9 @@ var VideoClient = class {
2609
2835
  };
2610
2836
 
2611
2837
  // src/voice.ts
2612
- var import_accounts6 = require("viem/accounts");
2613
- var DEFAULT_API_URL5 = "https://blockrun.ai/api";
2614
- var DEFAULT_TIMEOUT5 = 6e4;
2838
+ var import_accounts7 = require("viem/accounts");
2839
+ var DEFAULT_API_URL6 = "https://blockrun.ai/api";
2840
+ var DEFAULT_TIMEOUT6 = 6e4;
2615
2841
  var CALL_PRICE_USD = 0.54;
2616
2842
  var VALID_MODELS = /* @__PURE__ */ new Set(["base", "enhanced", "turbo"]);
2617
2843
  var VoiceClient = class {
@@ -2631,11 +2857,11 @@ var VoiceClient = class {
2631
2857
  }
2632
2858
  validatePrivateKey(privateKey);
2633
2859
  this.privateKey = privateKey;
2634
- this.account = (0, import_accounts6.privateKeyToAccount)(privateKey);
2635
- const apiUrl = options.apiUrl || DEFAULT_API_URL5;
2860
+ this.account = (0, import_accounts7.privateKeyToAccount)(privateKey);
2861
+ const apiUrl = options.apiUrl || DEFAULT_API_URL6;
2636
2862
  validateApiUrl(apiUrl);
2637
2863
  this.apiUrl = apiUrl.replace(/\/$/, "");
2638
- this.timeout = options.timeout || DEFAULT_TIMEOUT5;
2864
+ this.timeout = options.timeout || DEFAULT_TIMEOUT6;
2639
2865
  }
2640
2866
  /**
2641
2867
  * Initiate an AI-powered outbound phone call.
@@ -2810,9 +3036,9 @@ var VoiceClient = class {
2810
3036
  };
2811
3037
 
2812
3038
  // src/phone.ts
2813
- var import_accounts7 = require("viem/accounts");
2814
- var DEFAULT_API_URL6 = "https://blockrun.ai/api";
2815
- var DEFAULT_TIMEOUT6 = 6e4;
3039
+ var import_accounts8 = require("viem/accounts");
3040
+ var DEFAULT_API_URL7 = "https://blockrun.ai/api";
3041
+ var DEFAULT_TIMEOUT7 = 6e4;
2816
3042
  var PHONE_PRICES = Object.freeze({
2817
3043
  lookup: 0.01,
2818
3044
  "lookup/fraud": 0.05,
@@ -2850,11 +3076,11 @@ var PhoneClient = class {
2850
3076
  }
2851
3077
  validatePrivateKey(privateKey);
2852
3078
  this.privateKey = privateKey;
2853
- this.account = (0, import_accounts7.privateKeyToAccount)(privateKey);
2854
- const apiUrl = options.apiUrl || DEFAULT_API_URL6;
3079
+ this.account = (0, import_accounts8.privateKeyToAccount)(privateKey);
3080
+ const apiUrl = options.apiUrl || DEFAULT_API_URL7;
2855
3081
  validateApiUrl(apiUrl);
2856
3082
  this.apiUrl = apiUrl.replace(/\/$/, "");
2857
- this.timeout = options.timeout || DEFAULT_TIMEOUT6;
3083
+ this.timeout = options.timeout || DEFAULT_TIMEOUT7;
2858
3084
  }
2859
3085
  /** EVM wallet address used for payments. */
2860
3086
  getWalletAddress() {
@@ -3029,9 +3255,9 @@ var PhoneClient = class {
3029
3255
  };
3030
3256
 
3031
3257
  // src/portrait.ts
3032
- var import_accounts8 = require("viem/accounts");
3033
- var DEFAULT_API_URL7 = "https://blockrun.ai/api";
3034
- var DEFAULT_TIMEOUT7 = 6e4;
3258
+ var import_accounts9 = require("viem/accounts");
3259
+ var DEFAULT_API_URL8 = "https://blockrun.ai/api";
3260
+ var DEFAULT_TIMEOUT8 = 6e4;
3035
3261
  var PORTRAIT_ENROLLMENT_PRICE_USD = 0.01;
3036
3262
  var PortraitClient = class {
3037
3263
  account;
@@ -3050,11 +3276,11 @@ var PortraitClient = class {
3050
3276
  }
3051
3277
  validatePrivateKey(privateKey);
3052
3278
  this.privateKey = privateKey;
3053
- this.account = (0, import_accounts8.privateKeyToAccount)(privateKey);
3054
- const apiUrl = options.apiUrl || DEFAULT_API_URL7;
3279
+ this.account = (0, import_accounts9.privateKeyToAccount)(privateKey);
3280
+ const apiUrl = options.apiUrl || DEFAULT_API_URL8;
3055
3281
  validateApiUrl(apiUrl);
3056
3282
  this.apiUrl = apiUrl.replace(/\/$/, "");
3057
- this.timeout = options.timeout || DEFAULT_TIMEOUT7;
3283
+ this.timeout = options.timeout || DEFAULT_TIMEOUT8;
3058
3284
  }
3059
3285
  /** EVM wallet address used for payments. */
3060
3286
  getWalletAddress() {
@@ -3183,9 +3409,9 @@ var PortraitClient = class {
3183
3409
  };
3184
3410
 
3185
3411
  // src/search.ts
3186
- var import_accounts9 = require("viem/accounts");
3187
- var DEFAULT_API_URL8 = "https://blockrun.ai/api";
3188
- var DEFAULT_TIMEOUT8 = 6e4;
3412
+ var import_accounts10 = require("viem/accounts");
3413
+ var DEFAULT_API_URL9 = "https://blockrun.ai/api";
3414
+ var DEFAULT_TIMEOUT9 = 6e4;
3189
3415
  var SearchClient = class {
3190
3416
  account;
3191
3417
  privateKey;
@@ -3201,11 +3427,11 @@ var SearchClient = class {
3201
3427
  }
3202
3428
  validatePrivateKey(privateKey);
3203
3429
  this.privateKey = privateKey;
3204
- this.account = (0, import_accounts9.privateKeyToAccount)(privateKey);
3205
- const apiUrl = options.apiUrl || DEFAULT_API_URL8;
3430
+ this.account = (0, import_accounts10.privateKeyToAccount)(privateKey);
3431
+ const apiUrl = options.apiUrl || DEFAULT_API_URL9;
3206
3432
  validateApiUrl(apiUrl);
3207
3433
  this.apiUrl = apiUrl.replace(/\/$/, "");
3208
- this.timeout = options.timeout || DEFAULT_TIMEOUT8;
3434
+ this.timeout = options.timeout || DEFAULT_TIMEOUT9;
3209
3435
  }
3210
3436
  async search(query, options) {
3211
3437
  if (!query || query.length > 1e3) {
@@ -3319,9 +3545,9 @@ var SearchClient = class {
3319
3545
  };
3320
3546
 
3321
3547
  // src/x-client.ts
3322
- var import_accounts10 = require("viem/accounts");
3323
- var DEFAULT_API_URL9 = "https://blockrun.ai/api";
3324
- var DEFAULT_TIMEOUT9 = 6e4;
3548
+ var import_accounts11 = require("viem/accounts");
3549
+ var DEFAULT_API_URL10 = "https://blockrun.ai/api";
3550
+ var DEFAULT_TIMEOUT10 = 6e4;
3325
3551
  var XClient = class _XClient {
3326
3552
  account;
3327
3553
  privateKey;
@@ -3344,11 +3570,11 @@ var XClient = class _XClient {
3344
3570
  }
3345
3571
  validatePrivateKey(privateKey);
3346
3572
  this.privateKey = privateKey;
3347
- this.account = (0, import_accounts10.privateKeyToAccount)(privateKey);
3348
- const apiUrl = options.apiUrl || DEFAULT_API_URL9;
3573
+ this.account = (0, import_accounts11.privateKeyToAccount)(privateKey);
3574
+ const apiUrl = options.apiUrl || DEFAULT_API_URL10;
3349
3575
  validateApiUrl(apiUrl);
3350
3576
  this.apiUrl = apiUrl.replace(/\/$/, "");
3351
- this.timeout = options.timeout || DEFAULT_TIMEOUT9;
3577
+ this.timeout = options.timeout || DEFAULT_TIMEOUT10;
3352
3578
  }
3353
3579
  // ───────── User endpoints ─────────
3354
3580
  userLookup(usernames) {
@@ -3526,9 +3752,9 @@ var XClient = class _XClient {
3526
3752
  };
3527
3753
 
3528
3754
  // src/price.ts
3529
- var import_accounts11 = require("viem/accounts");
3530
- var DEFAULT_API_URL10 = "https://blockrun.ai/api";
3531
- var DEFAULT_TIMEOUT10 = 3e4;
3755
+ var import_accounts12 = require("viem/accounts");
3756
+ var DEFAULT_API_URL11 = "https://blockrun.ai/api";
3757
+ var DEFAULT_TIMEOUT11 = 3e4;
3532
3758
  var PriceClient = class {
3533
3759
  account = null;
3534
3760
  privateKey = null;
@@ -3546,12 +3772,12 @@ var PriceClient = class {
3546
3772
  if (privateKey) {
3547
3773
  validatePrivateKey(privateKey);
3548
3774
  this.privateKey = privateKey;
3549
- this.account = (0, import_accounts11.privateKeyToAccount)(privateKey);
3775
+ this.account = (0, import_accounts12.privateKeyToAccount)(privateKey);
3550
3776
  }
3551
- const apiUrl = options.apiUrl || DEFAULT_API_URL10;
3777
+ const apiUrl = options.apiUrl || DEFAULT_API_URL11;
3552
3778
  validateApiUrl(apiUrl);
3553
3779
  this.apiUrl = apiUrl.replace(/\/$/, "");
3554
- this.timeout = options.timeout || DEFAULT_TIMEOUT10;
3780
+ this.timeout = options.timeout || DEFAULT_TIMEOUT11;
3555
3781
  }
3556
3782
  async price(category, symbol, options) {
3557
3783
  if (!symbol) throw new Error("symbol is required");
@@ -3730,9 +3956,9 @@ function buildUrl(base, query) {
3730
3956
  }
3731
3957
 
3732
3958
  // src/surf.ts
3733
- var import_accounts12 = require("viem/accounts");
3734
- var DEFAULT_API_URL11 = "https://blockrun.ai/api";
3735
- var DEFAULT_TIMEOUT11 = 6e4;
3959
+ var import_accounts13 = require("viem/accounts");
3960
+ var DEFAULT_API_URL12 = "https://blockrun.ai/api";
3961
+ var DEFAULT_TIMEOUT12 = 6e4;
3736
3962
  var SURF_PREFIX = "/v1/surf";
3737
3963
  var SurfClient = class {
3738
3964
  account;
@@ -3749,11 +3975,11 @@ var SurfClient = class {
3749
3975
  }
3750
3976
  validatePrivateKey(privateKey);
3751
3977
  this.privateKey = privateKey;
3752
- this.account = (0, import_accounts12.privateKeyToAccount)(privateKey);
3753
- const apiUrl = options.apiUrl || DEFAULT_API_URL11;
3978
+ this.account = (0, import_accounts13.privateKeyToAccount)(privateKey);
3979
+ const apiUrl = options.apiUrl || DEFAULT_API_URL12;
3754
3980
  validateApiUrl(apiUrl);
3755
3981
  this.apiUrl = apiUrl.replace(/\/$/, "");
3756
- this.timeout = options.timeout || DEFAULT_TIMEOUT11;
3982
+ this.timeout = options.timeout || DEFAULT_TIMEOUT12;
3757
3983
  }
3758
3984
  /**
3759
3985
  * GET a Surf endpoint. `path` is everything after `/v1/surf` (a leading
@@ -3884,10 +4110,263 @@ var SurfClient = class {
3884
4110
  }
3885
4111
  };
3886
4112
 
4113
+ // src/rpc.ts
4114
+ var import_accounts14 = require("viem/accounts");
4115
+ var DEFAULT_API_URL13 = "https://blockrun.ai/api";
4116
+ var DEFAULT_TIMEOUT13 = 6e4;
4117
+ var RPC_PRICE_USD = 2e-3;
4118
+ var SUPPORTED_NETWORKS = [
4119
+ // EVM
4120
+ "ethereum",
4121
+ "base",
4122
+ "arbitrum",
4123
+ "arbitrum-nova",
4124
+ "optimism",
4125
+ "polygon",
4126
+ "bsc",
4127
+ "avalanche",
4128
+ "fantom",
4129
+ "cronos",
4130
+ "celo",
4131
+ "gnosis",
4132
+ "zksync",
4133
+ "berachain",
4134
+ "unichain",
4135
+ "monad",
4136
+ "chiliz",
4137
+ "moonbeam",
4138
+ "aurora",
4139
+ "flare",
4140
+ "oasis",
4141
+ "kaia",
4142
+ "sonic",
4143
+ "xdc",
4144
+ "abstract",
4145
+ "hyperevm",
4146
+ "plume",
4147
+ "ronin",
4148
+ "rootstock",
4149
+ // Non-EVM (JSON-RPC-compatible)
4150
+ "solana",
4151
+ "bitcoin",
4152
+ "litecoin",
4153
+ "dogecoin",
4154
+ "bitcoin-cash",
4155
+ "near",
4156
+ "sui",
4157
+ "ripple",
4158
+ "polkadot",
4159
+ "kusama",
4160
+ "zcash"
4161
+ ];
4162
+ var NETWORK_ALIASES = {
4163
+ eth: "ethereum",
4164
+ arb: "arbitrum",
4165
+ "arbitrum-one": "arbitrum",
4166
+ "arb-one": "arbitrum",
4167
+ "arb-nova": "arbitrum-nova",
4168
+ op: "optimism",
4169
+ matic: "polygon",
4170
+ pol: "polygon",
4171
+ bnb: "bsc",
4172
+ binance: "bsc",
4173
+ "binance-smart-chain": "bsc",
4174
+ avax: "avalanche",
4175
+ ftm: "fantom",
4176
+ bera: "berachain",
4177
+ klaytn: "kaia",
4178
+ chz: "chiliz",
4179
+ hyperliquid: "hyperevm",
4180
+ rsk: "rootstock",
4181
+ sol: "solana",
4182
+ btc: "bitcoin",
4183
+ ltc: "litecoin",
4184
+ doge: "dogecoin",
4185
+ bch: "bitcoin-cash",
4186
+ xrp: "ripple",
4187
+ xrpl: "ripple",
4188
+ dot: "polkadot",
4189
+ zec: "zcash"
4190
+ };
4191
+ var RpcClient = class {
4192
+ account;
4193
+ privateKey;
4194
+ apiUrl;
4195
+ timeout;
4196
+ sessionTotalUsd = 0;
4197
+ sessionCalls = 0;
4198
+ constructor(options = {}) {
4199
+ const envKey = typeof process !== "undefined" && process.env ? process.env.BLOCKRUN_WALLET_KEY || process.env.BASE_CHAIN_WALLET_KEY : void 0;
4200
+ const privateKey = options.privateKey || envKey;
4201
+ if (!privateKey) {
4202
+ throw new Error(
4203
+ "Private key required. Pass privateKey in options or set BLOCKRUN_WALLET_KEY environment variable."
4204
+ );
4205
+ }
4206
+ validatePrivateKey(privateKey);
4207
+ this.privateKey = privateKey;
4208
+ this.account = (0, import_accounts14.privateKeyToAccount)(privateKey);
4209
+ const apiUrl = options.apiUrl || DEFAULT_API_URL13;
4210
+ validateApiUrl(apiUrl);
4211
+ this.apiUrl = apiUrl.replace(/\/$/, "");
4212
+ this.timeout = options.timeout || DEFAULT_TIMEOUT13;
4213
+ }
4214
+ /**
4215
+ * Make a single JSON-RPC 2.0 call. Flat $0.002.
4216
+ *
4217
+ * @param network - Chain name (e.g. "ethereum", "base", "solana") or a
4218
+ * common alias ("eth", "sol", "matic", ...). See
4219
+ * SUPPORTED_NETWORKS / NETWORK_ALIASES.
4220
+ * @param method - Chain RPC method, e.g. "eth_blockNumber", "eth_call",
4221
+ * "eth_getBalance" (EVM) or "getSlot", "getAccountInfo"
4222
+ * (Solana).
4223
+ * @param params - Method-specific params array (optional).
4224
+ * @returns RpcResponse with `result` (or JSON-RPC `error`), plus
4225
+ * `network`, `cacheHit` and `txHash` metadata.
4226
+ *
4227
+ * @example
4228
+ * const block = await client.call('ethereum', 'eth_blockNumber');
4229
+ * console.log(parseInt(block.result as string, 16));
4230
+ */
4231
+ async call(network, method, params) {
4232
+ const body = { jsonrpc: "2.0", id: 1, method };
4233
+ if (params !== void 0) body.params = params;
4234
+ const { data, headers } = await this.requestWithPayment(network, body);
4235
+ return this.toResponse(data, headers);
4236
+ }
4237
+ /**
4238
+ * Make a JSON-RPC 2.0 batch call. Priced per element ($0.002 x N).
4239
+ *
4240
+ * @param network - Chain name or alias (see {@link call}).
4241
+ * @param requests - Requests, each with a `method` and optional
4242
+ * `params` / `id`. `jsonrpc` and missing ids are
4243
+ * filled in automatically.
4244
+ * @returns Array of RpcResponse, in upstream order.
4245
+ *
4246
+ * @example
4247
+ * const out = await client.batch('base', [
4248
+ * { method: 'eth_blockNumber' },
4249
+ * { method: 'eth_gasPrice' },
4250
+ * ]);
4251
+ */
4252
+ async batch(network, requests) {
4253
+ if (!requests.length) {
4254
+ throw new Error("batch requires at least one request");
4255
+ }
4256
+ const body = requests.map((req, i) => {
4257
+ if (!req.method) throw new Error(`batch request ${i} is missing 'method'`);
4258
+ return { jsonrpc: "2.0", id: i + 1, ...req };
4259
+ });
4260
+ const { data, headers } = await this.requestWithPayment(network, body);
4261
+ const items = Array.isArray(data) ? data : [data];
4262
+ return items.map((item) => this.toResponse(item, headers));
4263
+ }
4264
+ toResponse(data, headers) {
4265
+ const base = data !== null && typeof data === "object" && !Array.isArray(data) ? { ...data } : { result: data };
4266
+ const network = headers.get("x-network");
4267
+ if (network) base.network = network;
4268
+ base.cacheHit = (headers.get("x-cache") || "").toUpperCase() === "HIT";
4269
+ const txHash = headers.get("x-payment-receipt") || headers.get("X-Payment-Receipt");
4270
+ if (txHash) base.txHash = txHash;
4271
+ return base;
4272
+ }
4273
+ async requestWithPayment(network, body) {
4274
+ const endpoint = `/v1/rpc/${network}`;
4275
+ const url = `${this.apiUrl}${endpoint}`;
4276
+ const response = await this.fetchWithTimeout(url, {
4277
+ method: "POST",
4278
+ headers: { "Content-Type": "application/json" },
4279
+ body: JSON.stringify(body)
4280
+ });
4281
+ if (response.status === 402) {
4282
+ return this.handlePaymentAndRetry(url, endpoint, body, response);
4283
+ }
4284
+ if (!response.ok) {
4285
+ let errorBody;
4286
+ try {
4287
+ errorBody = await response.json();
4288
+ } catch {
4289
+ errorBody = { error: "Request failed" };
4290
+ }
4291
+ throw new APIError(`API error: ${response.status}`, response.status, sanitizeErrorResponse(errorBody));
4292
+ }
4293
+ return { data: await response.json(), headers: response.headers };
4294
+ }
4295
+ async handlePaymentAndRetry(url, endpoint, body, response) {
4296
+ let paymentHeader = response.headers.get("payment-required");
4297
+ if (!paymentHeader) {
4298
+ try {
4299
+ const respBody = await response.json();
4300
+ if (respBody.x402 || respBody.accepts) {
4301
+ paymentHeader = btoa(JSON.stringify(respBody));
4302
+ }
4303
+ } catch {
4304
+ }
4305
+ }
4306
+ if (!paymentHeader) {
4307
+ throw new PaymentError("402 response but no payment requirements found");
4308
+ }
4309
+ const paymentRequired = parsePaymentRequired(paymentHeader);
4310
+ const details = extractPaymentDetails(paymentRequired);
4311
+ const paymentPayload = await createPaymentPayload(
4312
+ this.privateKey,
4313
+ this.account.address,
4314
+ details.recipient,
4315
+ details.amount,
4316
+ details.network || "eip155:8453",
4317
+ {
4318
+ resourceUrl: details.resource?.url || `${this.apiUrl}${endpoint}`,
4319
+ resourceDescription: details.resource?.description || "BlockRun Multi-chain RPC",
4320
+ maxTimeoutSeconds: details.maxTimeoutSeconds || 300,
4321
+ extra: details.extra
4322
+ }
4323
+ );
4324
+ const retryResponse = await this.fetchWithTimeout(url, {
4325
+ method: "POST",
4326
+ headers: {
4327
+ "Content-Type": "application/json",
4328
+ "PAYMENT-SIGNATURE": paymentPayload
4329
+ },
4330
+ body: JSON.stringify(body)
4331
+ });
4332
+ if (retryResponse.status === 402) {
4333
+ throw new PaymentError("Payment was rejected. Check your wallet balance.");
4334
+ }
4335
+ if (!retryResponse.ok) {
4336
+ let errorBody;
4337
+ try {
4338
+ errorBody = await retryResponse.json();
4339
+ } catch {
4340
+ errorBody = { error: "Request failed" };
4341
+ }
4342
+ throw new APIError(`API error after payment: ${retryResponse.status}`, retryResponse.status, sanitizeErrorResponse(errorBody));
4343
+ }
4344
+ this.sessionCalls++;
4345
+ const paidUsd = Number(details.amount) / 1e6;
4346
+ if (Number.isFinite(paidUsd)) this.sessionTotalUsd += paidUsd;
4347
+ return { data: await retryResponse.json(), headers: retryResponse.headers };
4348
+ }
4349
+ async fetchWithTimeout(url, options) {
4350
+ const controller = new AbortController();
4351
+ const timeoutId = setTimeout(() => controller.abort(), this.timeout);
4352
+ try {
4353
+ return await fetch(url, { ...options, signal: controller.signal });
4354
+ } finally {
4355
+ clearTimeout(timeoutId);
4356
+ }
4357
+ }
4358
+ getWalletAddress() {
4359
+ return this.account.address;
4360
+ }
4361
+ getSpending() {
4362
+ return { totalUsd: this.sessionTotalUsd, calls: this.sessionCalls };
4363
+ }
4364
+ };
4365
+
3887
4366
  // src/blockrun.ts
3888
- var import_accounts13 = require("viem/accounts");
3889
- var DEFAULT_API_URL12 = "https://blockrun.ai/api";
3890
- var DEFAULT_TIMEOUT12 = 6e4;
4367
+ var import_accounts15 = require("viem/accounts");
4368
+ var DEFAULT_API_URL14 = "https://blockrun.ai/api";
4369
+ var DEFAULT_TIMEOUT14 = 6e4;
3891
4370
  var DEFAULT_POLL_INTERVAL_MS = 5e3;
3892
4371
  var DEFAULT_POLL_BUDGET_MS = 3e5;
3893
4372
  var MAX_SIGNED_AUTH_SECONDS = 600;
@@ -3908,11 +4387,11 @@ var BlockrunClient = class {
3908
4387
  }
3909
4388
  validatePrivateKey(privateKey);
3910
4389
  this.privateKey = privateKey;
3911
- this.account = (0, import_accounts13.privateKeyToAccount)(privateKey);
3912
- const apiUrl = options.apiUrl || DEFAULT_API_URL12;
4390
+ this.account = (0, import_accounts15.privateKeyToAccount)(privateKey);
4391
+ const apiUrl = options.apiUrl || DEFAULT_API_URL14;
3913
4392
  validateApiUrl(apiUrl);
3914
4393
  this.apiUrl = apiUrl.replace(/\/$/, "");
3915
- this.timeout = options.timeout || DEFAULT_TIMEOUT12;
4394
+ this.timeout = options.timeout || DEFAULT_TIMEOUT14;
3916
4395
  }
3917
4396
  /**
3918
4397
  * GET a BlockRun endpoint. `path` is everything after `/api` (a leading
@@ -4263,7 +4742,7 @@ function sleep(ms) {
4263
4742
  }
4264
4743
 
4265
4744
  // src/wallet.ts
4266
- var import_accounts14 = require("viem/accounts");
4745
+ var import_accounts16 = require("viem/accounts");
4267
4746
  var fs2 = __toESM(require("fs"), 1);
4268
4747
  var path2 = __toESM(require("path"), 1);
4269
4748
  var os2 = __toESM(require("os"), 1);
@@ -4272,8 +4751,8 @@ var BASE_CHAIN_ID2 = "8453";
4272
4751
  var WALLET_DIR = path2.join(os2.homedir(), ".blockrun");
4273
4752
  var WALLET_FILE = path2.join(WALLET_DIR, ".session");
4274
4753
  function createWallet() {
4275
- const privateKey = (0, import_accounts14.generatePrivateKey)();
4276
- const account = (0, import_accounts14.privateKeyToAccount)(privateKey);
4754
+ const privateKey = (0, import_accounts16.generatePrivateKey)();
4755
+ const account = (0, import_accounts16.privateKeyToAccount)(privateKey);
4277
4756
  return {
4278
4757
  address: account.address,
4279
4758
  privateKey
@@ -4329,12 +4808,12 @@ function loadWallet() {
4329
4808
  function getOrCreateWallet() {
4330
4809
  const envKey = typeof process !== "undefined" && process.env ? process.env.BLOCKRUN_WALLET_KEY || process.env.BASE_CHAIN_WALLET_KEY : void 0;
4331
4810
  if (envKey) {
4332
- const account = (0, import_accounts14.privateKeyToAccount)(envKey);
4811
+ const account = (0, import_accounts16.privateKeyToAccount)(envKey);
4333
4812
  return { address: account.address, privateKey: envKey, isNew: false };
4334
4813
  }
4335
4814
  const fileKey = loadWallet();
4336
4815
  if (fileKey) {
4337
- const account = (0, import_accounts14.privateKeyToAccount)(fileKey);
4816
+ const account = (0, import_accounts16.privateKeyToAccount)(fileKey);
4338
4817
  return { address: account.address, privateKey: fileKey, isNew: false };
4339
4818
  }
4340
4819
  const { address, privateKey } = createWallet();
@@ -4344,11 +4823,11 @@ function getOrCreateWallet() {
4344
4823
  function getWalletAddress() {
4345
4824
  const envKey = typeof process !== "undefined" && process.env ? process.env.BLOCKRUN_WALLET_KEY || process.env.BASE_CHAIN_WALLET_KEY : void 0;
4346
4825
  if (envKey) {
4347
- return (0, import_accounts14.privateKeyToAccount)(envKey).address;
4826
+ return (0, import_accounts16.privateKeyToAccount)(envKey).address;
4348
4827
  }
4349
4828
  const fileKey = loadWallet();
4350
4829
  if (fileKey) {
4351
- return (0, import_accounts14.privateKeyToAccount)(fileKey).address;
4830
+ return (0, import_accounts16.privateKeyToAccount)(fileKey).address;
4352
4831
  }
4353
4832
  return null;
4354
4833
  }
@@ -4528,7 +5007,7 @@ async function getOrCreateSolanaWallet() {
4528
5007
  // src/solana-client.ts
4529
5008
  var SOLANA_API_URL = "https://sol.blockrun.ai/api";
4530
5009
  var DEFAULT_MAX_TOKENS2 = 1024;
4531
- var DEFAULT_TIMEOUT13 = 6e4;
5010
+ var DEFAULT_TIMEOUT15 = 6e4;
4532
5011
  var SDK_VERSION2 = "0.3.0";
4533
5012
  var USER_AGENT2 = `blockrun-ts/${SDK_VERSION2}`;
4534
5013
  var DEFAULT_SOLANA_RPC_URL = "https://sol.blockrun.ai/api/v1/solana/rpc";
@@ -4578,7 +5057,7 @@ var SolanaLLMClient = class {
4578
5057
  const rpc = resolveRpcConfig(options.rpcUrl, options.rpcHeaders);
4579
5058
  this.rpcUrl = rpc.url;
4580
5059
  this.rpcHeaders = rpc.headers;
4581
- this.timeout = options.timeout || DEFAULT_TIMEOUT13;
5060
+ this.timeout = options.timeout || DEFAULT_TIMEOUT15;
4582
5061
  }
4583
5062
  /** Get Solana wallet address (public key in base58). */
4584
5063
  async getWalletAddress() {
@@ -5492,7 +5971,7 @@ var OpenAI = class {
5492
5971
  };
5493
5972
 
5494
5973
  // src/anthropic-compat.ts
5495
- var import_accounts15 = require("viem/accounts");
5974
+ var import_accounts17 = require("viem/accounts");
5496
5975
  var AnthropicClient = class {
5497
5976
  _client = null;
5498
5977
  _clientPromise = null;
@@ -5505,7 +5984,7 @@ var AnthropicClient = class {
5505
5984
  const key = options.privateKey ?? wallet.privateKey;
5506
5985
  validatePrivateKey(key);
5507
5986
  this._privateKey = key;
5508
- this._account = (0, import_accounts15.privateKeyToAccount)(this._privateKey);
5987
+ this._account = (0, import_accounts17.privateKeyToAccount)(this._privateKey);
5509
5988
  const apiUrl = options.apiUrl ?? "https://blockrun.ai/api";
5510
5989
  validateApiUrl(apiUrl);
5511
5990
  this._apiUrl = apiUrl.replace(/\/$/, "");
@@ -5610,6 +6089,7 @@ var AnthropicClient = class {
5610
6089
  KNOWN_PROVIDERS,
5611
6090
  LLMClient,
5612
6091
  MusicClient,
6092
+ NETWORK_ALIASES,
5613
6093
  OpenAI,
5614
6094
  PHONE_PRICES,
5615
6095
  PORTRAIT_ENROLLMENT_PRICE_USD,
@@ -5617,10 +6097,14 @@ var AnthropicClient = class {
5617
6097
  PhoneClient,
5618
6098
  PortraitClient,
5619
6099
  PriceClient,
6100
+ RPC_PRICE_USD,
6101
+ RpcClient,
5620
6102
  SOLANA_NETWORK,
5621
6103
  SOLANA_WALLET_FILE_PATH,
6104
+ SUPPORTED_NETWORKS,
5622
6105
  SearchClient,
5623
6106
  SolanaLLMClient,
6107
+ SpeechClient,
5624
6108
  SurfClient,
5625
6109
  USDC_BASE,
5626
6110
  USDC_BASE_CONTRACT,