@blockrun/llm 2.5.0 → 2.8.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.js CHANGED
@@ -112,8 +112,8 @@ async function createSolanaPaymentPayload(secretKey, fromAddress, recipient, amo
112
112
  const { Connection, PublicKey, TransactionMessage, VersionedTransaction, ComputeBudgetProgram } = await import("@solana/web3.js");
113
113
  const { getAssociatedTokenAddress, createTransferCheckedInstruction, getMint } = await import("@solana/spl-token");
114
114
  const { Keypair } = await import("@solana/web3.js");
115
- const rpcUrl = options.rpcUrl || "https://api.mainnet-beta.solana.com";
116
- const connection = new Connection(rpcUrl);
115
+ const rpcUrl = options.rpcUrl || "https://sol.blockrun.ai/api/v1/solana/rpc";
116
+ const connection = options.rpcHeaders ? new Connection(rpcUrl, { httpHeaders: options.rpcHeaders }) : new Connection(rpcUrl);
117
117
  const keypair = Keypair.fromSecretKey(secretKey);
118
118
  const feePayerPubkey = new PublicKey(feePayer);
119
119
  const ownerPubkey = keypair.publicKey;
@@ -2310,11 +2310,22 @@ var VideoClient = class {
2310
2310
  * @param options - Optional generation parameters
2311
2311
  */
2312
2312
  async generate(prompt, options) {
2313
+ if (options?.imageUrl && options?.realFaceAssetId) {
2314
+ throw new Error(
2315
+ "imageUrl and realFaceAssetId are mutually exclusive; pass at most one."
2316
+ );
2317
+ }
2318
+ if (options?.realFaceAssetId && !/^ta_[A-Za-z0-9]+$/.test(options.realFaceAssetId)) {
2319
+ throw new Error(
2320
+ "realFaceAssetId must be a Token360 asset id matching 'ta_[A-Za-z0-9]+' (e.g. 'ta_abc123xyz')"
2321
+ );
2322
+ }
2313
2323
  const body = {
2314
2324
  model: options?.model || DEFAULT_MODEL3,
2315
2325
  prompt
2316
2326
  };
2317
2327
  if (options?.imageUrl) body.image_url = options.imageUrl;
2328
+ if (options?.realFaceAssetId) body.real_face_asset_id = options.realFaceAssetId;
2318
2329
  if (options?.durationSeconds !== void 0) body.duration_seconds = options.durationSeconds;
2319
2330
  if (options?.aspectRatio) body.aspect_ratio = options.aspectRatio;
2320
2331
  if (options?.resolution) body.resolution = options.resolution;
@@ -2668,15 +2679,37 @@ var VoiceClient = class {
2668
2679
  }
2669
2680
  };
2670
2681
 
2671
- // src/search.ts
2682
+ // src/phone.ts
2672
2683
  import { privateKeyToAccount as privateKeyToAccount6 } from "viem/accounts";
2673
2684
  var DEFAULT_API_URL6 = "https://blockrun.ai/api";
2674
2685
  var DEFAULT_TIMEOUT6 = 6e4;
2675
- var SearchClient = class {
2686
+ var PHONE_PRICES = Object.freeze({
2687
+ lookup: 0.01,
2688
+ "lookup/fraud": 0.05,
2689
+ "numbers/buy": 5,
2690
+ "numbers/renew": 5,
2691
+ "numbers/list": 1e-3,
2692
+ "numbers/release": 0
2693
+ });
2694
+ function requireE164(value) {
2695
+ if (!value || typeof value !== "string") {
2696
+ throw new Error("phoneNumber is required (E.164 format, e.g. '+14155552671')");
2697
+ }
2698
+ const v = value.trim();
2699
+ if (!/^\+\d{7,15}$/.test(v)) {
2700
+ throw new Error(
2701
+ `phoneNumber must be E.164 (e.g. '+14155552671'), got ${JSON.stringify(value)}`
2702
+ );
2703
+ }
2704
+ return v;
2705
+ }
2706
+ var PhoneClient = class {
2676
2707
  account;
2677
2708
  privateKey;
2678
2709
  apiUrl;
2679
2710
  timeout;
2711
+ sessionTotalUsd = 0;
2712
+ sessionCalls = 0;
2680
2713
  constructor(options = {}) {
2681
2714
  const envKey = typeof process !== "undefined" && process.env ? process.env.BLOCKRUN_WALLET_KEY || process.env.BASE_CHAIN_WALLET_KEY : void 0;
2682
2715
  const privateKey = options.privateKey || envKey;
@@ -2693,6 +2726,357 @@ var SearchClient = class {
2693
2726
  this.apiUrl = apiUrl.replace(/\/$/, "");
2694
2727
  this.timeout = options.timeout || DEFAULT_TIMEOUT6;
2695
2728
  }
2729
+ /** EVM wallet address used for payments. */
2730
+ getWalletAddress() {
2731
+ return this.account.address;
2732
+ }
2733
+ /** Session-cumulative USD spend + call count across this client instance. */
2734
+ getSpending() {
2735
+ return { totalUsd: this.sessionTotalUsd, calls: this.sessionCalls };
2736
+ }
2737
+ // ─── Lookup ────────────────────────────────────────────────────────────
2738
+ /**
2739
+ * Carrier + line-type lookup. ~$0.01.
2740
+ *
2741
+ * @param phoneNumber E.164 number (e.g. "+14155552671").
2742
+ */
2743
+ async lookup(phoneNumber) {
2744
+ const num = requireE164(phoneNumber);
2745
+ return this.request("lookup", { phoneNumber: num });
2746
+ }
2747
+ /**
2748
+ * Lookup + fraud signals (SIM swap, call forwarding). ~$0.05.
2749
+ *
2750
+ * @param phoneNumber E.164 number.
2751
+ */
2752
+ async lookupFraud(phoneNumber) {
2753
+ const num = requireE164(phoneNumber);
2754
+ return this.request("lookup/fraud", { phoneNumber: num });
2755
+ }
2756
+ // ─── Provisioning ──────────────────────────────────────────────────────
2757
+ /**
2758
+ * Provision a dedicated phone number for 30 days. $5.00.
2759
+ *
2760
+ * Payment is settled only after Twilio confirms the purchase, so failed
2761
+ * buys never charge your wallet.
2762
+ *
2763
+ * @param options.country ISO country code, "US" or "CA" (default "US").
2764
+ * @param options.areaCode Optional 3-digit area-code hint. Availability is
2765
+ * not guaranteed — the backend falls back to any number in the country if
2766
+ * the area code can't be matched.
2767
+ */
2768
+ async buyNumber(options = {}) {
2769
+ const country = options.country ?? "US";
2770
+ if (country !== "US" && country !== "CA") {
2771
+ throw new Error("country must be 'US' or 'CA'");
2772
+ }
2773
+ const body = { country };
2774
+ if (options.areaCode !== void 0) {
2775
+ const ac = options.areaCode;
2776
+ if (typeof ac !== "string" || !/^\d{3}$/.test(ac)) {
2777
+ throw new Error("areaCode must be a 3-digit string, e.g. '415'");
2778
+ }
2779
+ body.areaCode = ac;
2780
+ }
2781
+ const data = await this.request("numbers/buy", body);
2782
+ return data;
2783
+ }
2784
+ /**
2785
+ * Extend an existing provisioned number by 30 days. $5.00.
2786
+ *
2787
+ * @throws {APIError} 403 when the wallet doesn't own the number or it has expired.
2788
+ */
2789
+ async renewNumber(phoneNumber) {
2790
+ const num = requireE164(phoneNumber);
2791
+ const data = await this.request("numbers/renew", {
2792
+ phoneNumber: num
2793
+ });
2794
+ return data;
2795
+ }
2796
+ /** List the wallet's active phone numbers. ~$0.001. */
2797
+ async listNumbers() {
2798
+ const data = await this.request("numbers/list", {});
2799
+ return data;
2800
+ }
2801
+ /**
2802
+ * Release a provisioned number back to the Twilio pool. Free, but still
2803
+ * flows through x402 so the backend can verify ownership.
2804
+ */
2805
+ async releaseNumber(phoneNumber) {
2806
+ const num = requireE164(phoneNumber);
2807
+ const data = await this.request("numbers/release", {
2808
+ phoneNumber: num
2809
+ });
2810
+ return data;
2811
+ }
2812
+ // ─── Internals ─────────────────────────────────────────────────────────
2813
+ async request(path5, body) {
2814
+ const url = `${this.apiUrl}/v1/phone/${path5}`;
2815
+ const response = await this.fetchWithTimeout(url, {
2816
+ method: "POST",
2817
+ headers: { "Content-Type": "application/json" },
2818
+ body: JSON.stringify(body)
2819
+ });
2820
+ if (response.status === 402) {
2821
+ return this.handlePaymentAndRetry(url, body, response);
2822
+ }
2823
+ return this.unwrap(response, false);
2824
+ }
2825
+ async handlePaymentAndRetry(url, body, response) {
2826
+ let paymentHeader = response.headers.get("payment-required");
2827
+ if (!paymentHeader) {
2828
+ try {
2829
+ const rb = await response.json();
2830
+ if (rb.x402 || rb.accepts) paymentHeader = btoa(JSON.stringify(rb));
2831
+ } catch {
2832
+ }
2833
+ }
2834
+ if (!paymentHeader) {
2835
+ throw new PaymentError("402 response but no payment requirements found");
2836
+ }
2837
+ const paymentRequired = parsePaymentRequired(paymentHeader);
2838
+ const details = extractPaymentDetails(paymentRequired);
2839
+ const paymentPayload = await createPaymentPayload(
2840
+ this.privateKey,
2841
+ this.account.address,
2842
+ details.recipient,
2843
+ details.amount,
2844
+ details.network || "eip155:8453",
2845
+ {
2846
+ resourceUrl: details.resource?.url || url,
2847
+ resourceDescription: details.resource?.description || "BlockRun Phone",
2848
+ maxTimeoutSeconds: details.maxTimeoutSeconds || 300,
2849
+ extra: details.extra
2850
+ }
2851
+ );
2852
+ const retry = await this.fetchWithTimeout(url, {
2853
+ method: "POST",
2854
+ headers: {
2855
+ "Content-Type": "application/json",
2856
+ "PAYMENT-SIGNATURE": paymentPayload
2857
+ },
2858
+ body: JSON.stringify(body)
2859
+ });
2860
+ if (retry.status === 402) {
2861
+ throw new PaymentError("Payment was rejected. Check your wallet balance.");
2862
+ }
2863
+ const data = await this.unwrap(retry, true);
2864
+ const costUsd = Number.parseFloat(details.amount) / 1e6;
2865
+ this.sessionCalls += 1;
2866
+ this.sessionTotalUsd += costUsd;
2867
+ const txHash = retry.headers.get("x-payment-receipt") || retry.headers.get("X-Payment-Receipt");
2868
+ if (txHash && data && typeof data === "object" && !("txHash" in data)) {
2869
+ data.txHash = txHash;
2870
+ }
2871
+ return data;
2872
+ }
2873
+ async unwrap(response, afterPayment) {
2874
+ if (response.ok) {
2875
+ return response.json();
2876
+ }
2877
+ let errorBody;
2878
+ try {
2879
+ errorBody = await response.json();
2880
+ } catch {
2881
+ errorBody = { error: "Request failed" };
2882
+ }
2883
+ const prefix = afterPayment ? "API error after payment" : "API error";
2884
+ throw new APIError(
2885
+ `${prefix}: ${response.status}`,
2886
+ response.status,
2887
+ sanitizeErrorResponse(errorBody)
2888
+ );
2889
+ }
2890
+ async fetchWithTimeout(url, init) {
2891
+ const controller = new AbortController();
2892
+ const timeoutId = setTimeout(() => controller.abort(), this.timeout);
2893
+ try {
2894
+ return await fetch(url, { ...init, signal: controller.signal });
2895
+ } finally {
2896
+ clearTimeout(timeoutId);
2897
+ }
2898
+ }
2899
+ };
2900
+
2901
+ // src/portrait.ts
2902
+ import { privateKeyToAccount as privateKeyToAccount7 } from "viem/accounts";
2903
+ var DEFAULT_API_URL7 = "https://blockrun.ai/api";
2904
+ var DEFAULT_TIMEOUT7 = 6e4;
2905
+ var PORTRAIT_ENROLLMENT_PRICE_USD = 0.01;
2906
+ var PortraitClient = class {
2907
+ account;
2908
+ privateKey;
2909
+ apiUrl;
2910
+ timeout;
2911
+ sessionTotalUsd = 0;
2912
+ sessionCalls = 0;
2913
+ constructor(options = {}) {
2914
+ const envKey = typeof process !== "undefined" && process.env ? process.env.BLOCKRUN_WALLET_KEY || process.env.BASE_CHAIN_WALLET_KEY : void 0;
2915
+ const privateKey = options.privateKey || envKey;
2916
+ if (!privateKey) {
2917
+ throw new Error(
2918
+ "Private key required. Pass privateKey in options or set BLOCKRUN_WALLET_KEY environment variable."
2919
+ );
2920
+ }
2921
+ validatePrivateKey(privateKey);
2922
+ this.privateKey = privateKey;
2923
+ this.account = privateKeyToAccount7(privateKey);
2924
+ const apiUrl = options.apiUrl || DEFAULT_API_URL7;
2925
+ validateApiUrl(apiUrl);
2926
+ this.apiUrl = apiUrl.replace(/\/$/, "");
2927
+ this.timeout = options.timeout || DEFAULT_TIMEOUT7;
2928
+ }
2929
+ /** EVM wallet address used for payments. */
2930
+ getWalletAddress() {
2931
+ return this.account.address;
2932
+ }
2933
+ /** Session-cumulative USD spend + call count across this client instance. */
2934
+ getSpending() {
2935
+ return { totalUsd: this.sessionTotalUsd, calls: this.sessionCalls };
2936
+ }
2937
+ /**
2938
+ * Enroll a Virtual Portrait from a face image URL. $0.01 (promo).
2939
+ *
2940
+ * Payment is settled only after Token360 confirms the enrollment, so failed
2941
+ * enrollments never charge your wallet.
2942
+ *
2943
+ * @param options.name Display name (1–64 chars).
2944
+ * @param options.imageUrl Public HTTPS URL to a JPG/PNG/WEBP image (≤10 MB).
2945
+ * @returns The enrollment record, including `asset_id` (`ta_xxxxxx`).
2946
+ */
2947
+ async enroll(options) {
2948
+ const name = typeof options?.name === "string" ? options.name.trim() : "";
2949
+ if (name.length < 1 || name.length > 64) {
2950
+ throw new Error("name is required and must be 1\u201364 characters");
2951
+ }
2952
+ const imageUrl = typeof options?.imageUrl === "string" ? options.imageUrl.trim() : "";
2953
+ if (!/^https?:\/\//i.test(imageUrl)) {
2954
+ throw new Error(
2955
+ "imageUrl must be a public http(s) URL to a JPG/PNG/WEBP image"
2956
+ );
2957
+ }
2958
+ const data = await this.request({
2959
+ name,
2960
+ image_url: imageUrl
2961
+ });
2962
+ return data;
2963
+ }
2964
+ // ─── Internals ─────────────────────────────────────────────────────────
2965
+ async request(body) {
2966
+ const url = `${this.apiUrl}/v1/portrait/enroll`;
2967
+ const response = await this.fetchWithTimeout(url, {
2968
+ method: "POST",
2969
+ headers: { "Content-Type": "application/json" },
2970
+ body: JSON.stringify(body)
2971
+ });
2972
+ if (response.status === 402) {
2973
+ return this.handlePaymentAndRetry(url, body, response);
2974
+ }
2975
+ return this.unwrap(response, false);
2976
+ }
2977
+ async handlePaymentAndRetry(url, body, response) {
2978
+ let paymentHeader = response.headers.get("payment-required");
2979
+ if (!paymentHeader) {
2980
+ try {
2981
+ const rb = await response.json();
2982
+ if (rb.x402 || rb.accepts) paymentHeader = btoa(JSON.stringify(rb));
2983
+ } catch {
2984
+ }
2985
+ }
2986
+ if (!paymentHeader) {
2987
+ throw new PaymentError("402 response but no payment requirements found");
2988
+ }
2989
+ const paymentRequired = parsePaymentRequired(paymentHeader);
2990
+ const details = extractPaymentDetails(paymentRequired);
2991
+ const paymentPayload = await createPaymentPayload(
2992
+ this.privateKey,
2993
+ this.account.address,
2994
+ details.recipient,
2995
+ details.amount,
2996
+ details.network || "eip155:8453",
2997
+ {
2998
+ resourceUrl: details.resource?.url || url,
2999
+ resourceDescription: details.resource?.description || "BlockRun Virtual Portrait",
3000
+ maxTimeoutSeconds: details.maxTimeoutSeconds || 300,
3001
+ extra: details.extra
3002
+ }
3003
+ );
3004
+ const retry = await this.fetchWithTimeout(url, {
3005
+ method: "POST",
3006
+ headers: {
3007
+ "Content-Type": "application/json",
3008
+ "PAYMENT-SIGNATURE": paymentPayload
3009
+ },
3010
+ body: JSON.stringify(body)
3011
+ });
3012
+ if (retry.status === 402) {
3013
+ throw new PaymentError("Payment was rejected. Check your wallet balance.");
3014
+ }
3015
+ const data = await this.unwrap(retry, true);
3016
+ const costUsd = Number.parseFloat(details.amount) / 1e6;
3017
+ this.sessionCalls += 1;
3018
+ this.sessionTotalUsd += costUsd;
3019
+ if (data && typeof data === "object" && !("txHash" in data)) {
3020
+ const settlement = data.settlement;
3021
+ if (settlement?.tx_hash) {
3022
+ data.txHash = settlement.tx_hash;
3023
+ }
3024
+ }
3025
+ return data;
3026
+ }
3027
+ async unwrap(response, afterPayment) {
3028
+ if (response.ok) {
3029
+ return response.json();
3030
+ }
3031
+ let errorBody;
3032
+ try {
3033
+ errorBody = await response.json();
3034
+ } catch {
3035
+ errorBody = { error: "Request failed" };
3036
+ }
3037
+ const prefix = afterPayment ? "API error after payment" : "API error";
3038
+ throw new APIError(
3039
+ `${prefix}: ${response.status}`,
3040
+ response.status,
3041
+ sanitizeErrorResponse(errorBody)
3042
+ );
3043
+ }
3044
+ async fetchWithTimeout(url, init) {
3045
+ const controller = new AbortController();
3046
+ const timeoutId = setTimeout(() => controller.abort(), this.timeout);
3047
+ try {
3048
+ return await fetch(url, { ...init, signal: controller.signal });
3049
+ } finally {
3050
+ clearTimeout(timeoutId);
3051
+ }
3052
+ }
3053
+ };
3054
+
3055
+ // src/search.ts
3056
+ import { privateKeyToAccount as privateKeyToAccount8 } from "viem/accounts";
3057
+ var DEFAULT_API_URL8 = "https://blockrun.ai/api";
3058
+ var DEFAULT_TIMEOUT8 = 6e4;
3059
+ var SearchClient = class {
3060
+ account;
3061
+ privateKey;
3062
+ apiUrl;
3063
+ timeout;
3064
+ constructor(options = {}) {
3065
+ const envKey = typeof process !== "undefined" && process.env ? process.env.BLOCKRUN_WALLET_KEY || process.env.BASE_CHAIN_WALLET_KEY : void 0;
3066
+ const privateKey = options.privateKey || envKey;
3067
+ if (!privateKey) {
3068
+ throw new Error(
3069
+ "Private key required. Pass privateKey in options or set BLOCKRUN_WALLET_KEY environment variable."
3070
+ );
3071
+ }
3072
+ validatePrivateKey(privateKey);
3073
+ this.privateKey = privateKey;
3074
+ this.account = privateKeyToAccount8(privateKey);
3075
+ const apiUrl = options.apiUrl || DEFAULT_API_URL8;
3076
+ validateApiUrl(apiUrl);
3077
+ this.apiUrl = apiUrl.replace(/\/$/, "");
3078
+ this.timeout = options.timeout || DEFAULT_TIMEOUT8;
3079
+ }
2696
3080
  async search(query, options) {
2697
3081
  if (!query || query.length > 1e3) {
2698
3082
  throw new Error("query must be 1-1000 characters");
@@ -2805,9 +3189,9 @@ var SearchClient = class {
2805
3189
  };
2806
3190
 
2807
3191
  // src/x-client.ts
2808
- import { privateKeyToAccount as privateKeyToAccount7 } from "viem/accounts";
2809
- var DEFAULT_API_URL7 = "https://blockrun.ai/api";
2810
- var DEFAULT_TIMEOUT7 = 6e4;
3192
+ import { privateKeyToAccount as privateKeyToAccount9 } from "viem/accounts";
3193
+ var DEFAULT_API_URL9 = "https://blockrun.ai/api";
3194
+ var DEFAULT_TIMEOUT9 = 6e4;
2811
3195
  var XClient = class _XClient {
2812
3196
  account;
2813
3197
  privateKey;
@@ -2830,11 +3214,11 @@ var XClient = class _XClient {
2830
3214
  }
2831
3215
  validatePrivateKey(privateKey);
2832
3216
  this.privateKey = privateKey;
2833
- this.account = privateKeyToAccount7(privateKey);
2834
- const apiUrl = options.apiUrl || DEFAULT_API_URL7;
3217
+ this.account = privateKeyToAccount9(privateKey);
3218
+ const apiUrl = options.apiUrl || DEFAULT_API_URL9;
2835
3219
  validateApiUrl(apiUrl);
2836
3220
  this.apiUrl = apiUrl.replace(/\/$/, "");
2837
- this.timeout = options.timeout || DEFAULT_TIMEOUT7;
3221
+ this.timeout = options.timeout || DEFAULT_TIMEOUT9;
2838
3222
  }
2839
3223
  // ───────── User endpoints ─────────
2840
3224
  userLookup(usernames) {
@@ -3012,9 +3396,9 @@ var XClient = class _XClient {
3012
3396
  };
3013
3397
 
3014
3398
  // src/price.ts
3015
- import { privateKeyToAccount as privateKeyToAccount8 } from "viem/accounts";
3016
- var DEFAULT_API_URL8 = "https://blockrun.ai/api";
3017
- var DEFAULT_TIMEOUT8 = 3e4;
3399
+ import { privateKeyToAccount as privateKeyToAccount10 } from "viem/accounts";
3400
+ var DEFAULT_API_URL10 = "https://blockrun.ai/api";
3401
+ var DEFAULT_TIMEOUT10 = 3e4;
3018
3402
  var PriceClient = class {
3019
3403
  account = null;
3020
3404
  privateKey = null;
@@ -3032,12 +3416,12 @@ var PriceClient = class {
3032
3416
  if (privateKey) {
3033
3417
  validatePrivateKey(privateKey);
3034
3418
  this.privateKey = privateKey;
3035
- this.account = privateKeyToAccount8(privateKey);
3419
+ this.account = privateKeyToAccount10(privateKey);
3036
3420
  }
3037
- const apiUrl = options.apiUrl || DEFAULT_API_URL8;
3421
+ const apiUrl = options.apiUrl || DEFAULT_API_URL10;
3038
3422
  validateApiUrl(apiUrl);
3039
3423
  this.apiUrl = apiUrl.replace(/\/$/, "");
3040
- this.timeout = options.timeout || DEFAULT_TIMEOUT8;
3424
+ this.timeout = options.timeout || DEFAULT_TIMEOUT10;
3041
3425
  }
3042
3426
  async price(category, symbol, options) {
3043
3427
  if (!symbol) throw new Error("symbol is required");
@@ -3216,9 +3600,9 @@ function buildUrl(base, query) {
3216
3600
  }
3217
3601
 
3218
3602
  // src/surf.ts
3219
- import { privateKeyToAccount as privateKeyToAccount9 } from "viem/accounts";
3220
- var DEFAULT_API_URL9 = "https://blockrun.ai/api";
3221
- var DEFAULT_TIMEOUT9 = 6e4;
3603
+ import { privateKeyToAccount as privateKeyToAccount11 } from "viem/accounts";
3604
+ var DEFAULT_API_URL11 = "https://blockrun.ai/api";
3605
+ var DEFAULT_TIMEOUT11 = 6e4;
3222
3606
  var SURF_PREFIX = "/v1/surf";
3223
3607
  var SurfClient = class {
3224
3608
  account;
@@ -3235,11 +3619,11 @@ var SurfClient = class {
3235
3619
  }
3236
3620
  validatePrivateKey(privateKey);
3237
3621
  this.privateKey = privateKey;
3238
- this.account = privateKeyToAccount9(privateKey);
3239
- const apiUrl = options.apiUrl || DEFAULT_API_URL9;
3622
+ this.account = privateKeyToAccount11(privateKey);
3623
+ const apiUrl = options.apiUrl || DEFAULT_API_URL11;
3240
3624
  validateApiUrl(apiUrl);
3241
3625
  this.apiUrl = apiUrl.replace(/\/$/, "");
3242
- this.timeout = options.timeout || DEFAULT_TIMEOUT9;
3626
+ this.timeout = options.timeout || DEFAULT_TIMEOUT11;
3243
3627
  }
3244
3628
  /**
3245
3629
  * GET a Surf endpoint. `path` is everything after `/v1/surf` (a leading
@@ -3371,9 +3755,9 @@ var SurfClient = class {
3371
3755
  };
3372
3756
 
3373
3757
  // src/blockrun.ts
3374
- import { privateKeyToAccount as privateKeyToAccount10 } from "viem/accounts";
3375
- var DEFAULT_API_URL10 = "https://blockrun.ai/api";
3376
- var DEFAULT_TIMEOUT10 = 6e4;
3758
+ import { privateKeyToAccount as privateKeyToAccount12 } from "viem/accounts";
3759
+ var DEFAULT_API_URL12 = "https://blockrun.ai/api";
3760
+ var DEFAULT_TIMEOUT12 = 6e4;
3377
3761
  var DEFAULT_POLL_INTERVAL_MS = 5e3;
3378
3762
  var DEFAULT_POLL_BUDGET_MS = 3e5;
3379
3763
  var MAX_SIGNED_AUTH_SECONDS = 600;
@@ -3394,11 +3778,11 @@ var BlockrunClient = class {
3394
3778
  }
3395
3779
  validatePrivateKey(privateKey);
3396
3780
  this.privateKey = privateKey;
3397
- this.account = privateKeyToAccount10(privateKey);
3398
- const apiUrl = options.apiUrl || DEFAULT_API_URL10;
3781
+ this.account = privateKeyToAccount12(privateKey);
3782
+ const apiUrl = options.apiUrl || DEFAULT_API_URL12;
3399
3783
  validateApiUrl(apiUrl);
3400
3784
  this.apiUrl = apiUrl.replace(/\/$/, "");
3401
- this.timeout = options.timeout || DEFAULT_TIMEOUT10;
3785
+ this.timeout = options.timeout || DEFAULT_TIMEOUT12;
3402
3786
  }
3403
3787
  /**
3404
3788
  * GET a BlockRun endpoint. `path` is everything after `/api` (a leading
@@ -3749,7 +4133,7 @@ function sleep(ms) {
3749
4133
  }
3750
4134
 
3751
4135
  // src/wallet.ts
3752
- import { privateKeyToAccount as privateKeyToAccount11, generatePrivateKey } from "viem/accounts";
4136
+ import { privateKeyToAccount as privateKeyToAccount13, generatePrivateKey } from "viem/accounts";
3753
4137
  import * as fs2 from "fs";
3754
4138
  import * as path2 from "path";
3755
4139
  import * as os2 from "os";
@@ -3759,7 +4143,7 @@ var WALLET_DIR = path2.join(os2.homedir(), ".blockrun");
3759
4143
  var WALLET_FILE = path2.join(WALLET_DIR, ".session");
3760
4144
  function createWallet() {
3761
4145
  const privateKey = generatePrivateKey();
3762
- const account = privateKeyToAccount11(privateKey);
4146
+ const account = privateKeyToAccount13(privateKey);
3763
4147
  return {
3764
4148
  address: account.address,
3765
4149
  privateKey
@@ -3815,12 +4199,12 @@ function loadWallet() {
3815
4199
  function getOrCreateWallet() {
3816
4200
  const envKey = typeof process !== "undefined" && process.env ? process.env.BLOCKRUN_WALLET_KEY || process.env.BASE_CHAIN_WALLET_KEY : void 0;
3817
4201
  if (envKey) {
3818
- const account = privateKeyToAccount11(envKey);
4202
+ const account = privateKeyToAccount13(envKey);
3819
4203
  return { address: account.address, privateKey: envKey, isNew: false };
3820
4204
  }
3821
4205
  const fileKey = loadWallet();
3822
4206
  if (fileKey) {
3823
- const account = privateKeyToAccount11(fileKey);
4207
+ const account = privateKeyToAccount13(fileKey);
3824
4208
  return { address: account.address, privateKey: fileKey, isNew: false };
3825
4209
  }
3826
4210
  const { address, privateKey } = createWallet();
@@ -3830,11 +4214,11 @@ function getOrCreateWallet() {
3830
4214
  function getWalletAddress() {
3831
4215
  const envKey = typeof process !== "undefined" && process.env ? process.env.BLOCKRUN_WALLET_KEY || process.env.BASE_CHAIN_WALLET_KEY : void 0;
3832
4216
  if (envKey) {
3833
- return privateKeyToAccount11(envKey).address;
4217
+ return privateKeyToAccount13(envKey).address;
3834
4218
  }
3835
4219
  const fileKey = loadWallet();
3836
4220
  if (fileKey) {
3837
- return privateKeyToAccount11(fileKey).address;
4221
+ return privateKeyToAccount13(fileKey).address;
3838
4222
  }
3839
4223
  return null;
3840
4224
  }
@@ -4014,14 +4398,37 @@ async function getOrCreateSolanaWallet() {
4014
4398
  // src/solana-client.ts
4015
4399
  var SOLANA_API_URL = "https://sol.blockrun.ai/api";
4016
4400
  var DEFAULT_MAX_TOKENS2 = 1024;
4017
- var DEFAULT_TIMEOUT11 = 6e4;
4401
+ var DEFAULT_TIMEOUT13 = 6e4;
4018
4402
  var SDK_VERSION2 = "0.3.0";
4019
4403
  var USER_AGENT2 = `blockrun-ts/${SDK_VERSION2}`;
4404
+ var DEFAULT_SOLANA_RPC_URL = "https://sol.blockrun.ai/api/v1/solana/rpc";
4405
+ function resolveRpcConfig(rpcUrl, rpcHeaders) {
4406
+ const env = typeof process !== "undefined" && process.env ? process.env : {};
4407
+ const url = rpcUrl || env.SOLANA_RPC_URL || DEFAULT_SOLANA_RPC_URL;
4408
+ let headers;
4409
+ if (rpcHeaders) {
4410
+ headers = { ...rpcHeaders };
4411
+ } else if (env.SOLANA_RPC_HEADERS) {
4412
+ try {
4413
+ const parsed = JSON.parse(env.SOLANA_RPC_HEADERS);
4414
+ if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
4415
+ headers = Object.fromEntries(
4416
+ Object.entries(parsed).map(([k, v]) => [String(k), String(v)])
4417
+ );
4418
+ }
4419
+ } catch {
4420
+ }
4421
+ } else if (env.SOLANA_RPC_API_KEY) {
4422
+ headers = { "x-api-key": env.SOLANA_RPC_API_KEY };
4423
+ }
4424
+ return headers ? { url, headers } : { url };
4425
+ }
4020
4426
  var SolanaLLMClient = class {
4021
4427
  static SOLANA_API_URL = SOLANA_API_URL;
4022
4428
  privateKey;
4023
4429
  apiUrl;
4024
4430
  rpcUrl;
4431
+ rpcHeaders;
4025
4432
  timeout;
4026
4433
  sessionTotalUsd = 0;
4027
4434
  sessionCalls = 0;
@@ -4038,8 +4445,10 @@ var SolanaLLMClient = class {
4038
4445
  const apiUrl = options.apiUrl || SOLANA_API_URL;
4039
4446
  validateApiUrl(apiUrl);
4040
4447
  this.apiUrl = apiUrl.replace(/\/$/, "");
4041
- this.rpcUrl = options.rpcUrl || "https://api.mainnet-beta.solana.com";
4042
- this.timeout = options.timeout || DEFAULT_TIMEOUT11;
4448
+ const rpc = resolveRpcConfig(options.rpcUrl, options.rpcHeaders);
4449
+ this.rpcUrl = rpc.url;
4450
+ this.rpcHeaders = rpc.headers;
4451
+ this.timeout = options.timeout || DEFAULT_TIMEOUT13;
4043
4452
  }
4044
4453
  /** Get Solana wallet address (public key in base58). */
4045
4454
  async getWalletAddress() {
@@ -4097,7 +4506,7 @@ var SolanaLLMClient = class {
4097
4506
  try {
4098
4507
  const response = await fetch(this.rpcUrl, {
4099
4508
  method: "POST",
4100
- headers: { "Content-Type": "application/json" },
4509
+ headers: { "Content-Type": "application/json", ...this.rpcHeaders ?? {} },
4101
4510
  body: JSON.stringify({
4102
4511
  jsonrpc: "2.0",
4103
4512
  id: 1,
@@ -4348,7 +4757,8 @@ var SolanaLLMClient = class {
4348
4757
  maxTimeoutSeconds: details.maxTimeoutSeconds || 300,
4349
4758
  extra: details.extra,
4350
4759
  extensions,
4351
- rpcUrl: this.rpcUrl
4760
+ rpcUrl: this.rpcUrl,
4761
+ rpcHeaders: this.rpcHeaders
4352
4762
  }
4353
4763
  );
4354
4764
  const retryResponse = await this.fetchWithTimeout(url, {
@@ -4439,7 +4849,8 @@ var SolanaLLMClient = class {
4439
4849
  maxTimeoutSeconds: details.maxTimeoutSeconds || 300,
4440
4850
  extra: details.extra,
4441
4851
  extensions,
4442
- rpcUrl: this.rpcUrl
4852
+ rpcUrl: this.rpcUrl,
4853
+ rpcHeaders: this.rpcHeaders
4443
4854
  }
4444
4855
  );
4445
4856
  const retryResponse = await this.fetchWithTimeout(url, {
@@ -4530,7 +4941,8 @@ var SolanaLLMClient = class {
4530
4941
  maxTimeoutSeconds: details.maxTimeoutSeconds || 300,
4531
4942
  extra: details.extra,
4532
4943
  extensions,
4533
- rpcUrl: this.rpcUrl
4944
+ rpcUrl: this.rpcUrl,
4945
+ rpcHeaders: this.rpcHeaders
4534
4946
  }
4535
4947
  );
4536
4948
  const query = params ? "?" + new URLSearchParams(params).toString() : "";
@@ -4946,7 +5358,7 @@ var OpenAI = class {
4946
5358
  };
4947
5359
 
4948
5360
  // src/anthropic-compat.ts
4949
- import { privateKeyToAccount as privateKeyToAccount12 } from "viem/accounts";
5361
+ import { privateKeyToAccount as privateKeyToAccount14 } from "viem/accounts";
4950
5362
  var AnthropicClient = class {
4951
5363
  _client = null;
4952
5364
  _clientPromise = null;
@@ -4959,7 +5371,7 @@ var AnthropicClient = class {
4959
5371
  const key = options.privateKey ?? wallet.privateKey;
4960
5372
  validatePrivateKey(key);
4961
5373
  this._privateKey = key;
4962
- this._account = privateKeyToAccount12(this._privateKey);
5374
+ this._account = privateKeyToAccount14(this._privateKey);
4963
5375
  const apiUrl = options.apiUrl ?? "https://blockrun.ai/api";
4964
5376
  validateApiUrl(apiUrl);
4965
5377
  this._apiUrl = apiUrl.replace(/\/$/, "");
@@ -5064,7 +5476,11 @@ export {
5064
5476
  LLMClient,
5065
5477
  MusicClient,
5066
5478
  OpenAI,
5479
+ PHONE_PRICES,
5480
+ PORTRAIT_ENROLLMENT_PRICE_USD,
5067
5481
  PaymentError,
5482
+ PhoneClient,
5483
+ PortraitClient,
5068
5484
  PriceClient,
5069
5485
  SOLANA_NETWORK,
5070
5486
  SOLANA_WALLET_FILE as SOLANA_WALLET_FILE_PATH,