@blockrun/llm 2.3.0 → 2.5.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
@@ -3215,8 +3215,541 @@ function buildUrl(base, query) {
3215
3215
  return `${base}?${qs}`;
3216
3216
  }
3217
3217
 
3218
+ // 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;
3222
+ var SURF_PREFIX = "/v1/surf";
3223
+ var SurfClient = class {
3224
+ account;
3225
+ privateKey;
3226
+ apiUrl;
3227
+ timeout;
3228
+ constructor(options = {}) {
3229
+ const envKey = typeof process !== "undefined" && process.env ? process.env.BLOCKRUN_WALLET_KEY || process.env.BASE_CHAIN_WALLET_KEY : void 0;
3230
+ const privateKey = options.privateKey || envKey;
3231
+ if (!privateKey) {
3232
+ throw new Error(
3233
+ "Private key required. Pass privateKey in options or set BLOCKRUN_WALLET_KEY environment variable."
3234
+ );
3235
+ }
3236
+ validatePrivateKey(privateKey);
3237
+ this.privateKey = privateKey;
3238
+ this.account = privateKeyToAccount9(privateKey);
3239
+ const apiUrl = options.apiUrl || DEFAULT_API_URL9;
3240
+ validateApiUrl(apiUrl);
3241
+ this.apiUrl = apiUrl.replace(/\/$/, "");
3242
+ this.timeout = options.timeout || DEFAULT_TIMEOUT9;
3243
+ }
3244
+ /**
3245
+ * GET a Surf endpoint. `path` is everything after `/v1/surf` (a leading
3246
+ * `/v1/surf` is tolerated and stripped). Query params are URL-encoded;
3247
+ * arrays become repeated keys (`?a=1&a=2`).
3248
+ */
3249
+ async get(path5, params) {
3250
+ const url = this.buildUrl(path5, params);
3251
+ return this.requestWithPayment(url, "GET");
3252
+ }
3253
+ /**
3254
+ * POST a Surf endpoint with a JSON body. Same path normalization as `get`.
3255
+ */
3256
+ async post(path5, body) {
3257
+ const url = this.buildUrl(path5);
3258
+ return this.requestWithPayment(url, "POST", body);
3259
+ }
3260
+ buildUrl(path5, params) {
3261
+ let normalized = path5.startsWith("/") ? path5 : `/${path5}`;
3262
+ if (!normalized.startsWith(SURF_PREFIX)) {
3263
+ normalized = `${SURF_PREFIX}${normalized}`;
3264
+ }
3265
+ const base = `${this.apiUrl}${normalized}`;
3266
+ if (!params) return base;
3267
+ const qs = new URLSearchParams();
3268
+ for (const [key, value] of Object.entries(params)) {
3269
+ if (value === void 0 || value === null) continue;
3270
+ if (Array.isArray(value)) {
3271
+ for (const v of value) {
3272
+ if (v === void 0 || v === null) continue;
3273
+ qs.append(key, String(v));
3274
+ }
3275
+ } else {
3276
+ qs.append(key, String(value));
3277
+ }
3278
+ }
3279
+ const query = qs.toString();
3280
+ return query ? `${base}?${query}` : base;
3281
+ }
3282
+ async requestWithPayment(url, method, body) {
3283
+ const init = { method };
3284
+ if (method === "POST") {
3285
+ init.headers = { "Content-Type": "application/json" };
3286
+ init.body = JSON.stringify(body ?? {});
3287
+ }
3288
+ const response = await this.fetchWithTimeout(url, init);
3289
+ if (response.status === 402) {
3290
+ return this.handlePaymentAndRetry(url, method, body, response);
3291
+ }
3292
+ if (!response.ok) {
3293
+ await this.throwApiError(response, `Surf request failed (${method} ${url})`);
3294
+ }
3295
+ return response.json();
3296
+ }
3297
+ async handlePaymentAndRetry(url, method, body, response) {
3298
+ let paymentHeader = response.headers.get("payment-required");
3299
+ if (!paymentHeader) {
3300
+ try {
3301
+ const respBody = await response.json();
3302
+ if (respBody.x402Version !== void 0 || respBody.accepts !== void 0) {
3303
+ paymentHeader = btoa(JSON.stringify(respBody));
3304
+ }
3305
+ } catch {
3306
+ }
3307
+ }
3308
+ if (!paymentHeader) {
3309
+ throw new PaymentError("402 response but no payment requirements found");
3310
+ }
3311
+ const paymentRequired = parsePaymentRequired(paymentHeader);
3312
+ const details = extractPaymentDetails(paymentRequired);
3313
+ const paymentPayload = await createPaymentPayload(
3314
+ this.privateKey,
3315
+ this.account.address,
3316
+ details.recipient,
3317
+ details.amount,
3318
+ details.network || "eip155:8453",
3319
+ {
3320
+ resourceUrl: details.resource?.url || url,
3321
+ resourceDescription: details.resource?.description || "BlockRun Surf",
3322
+ maxTimeoutSeconds: details.maxTimeoutSeconds || 300,
3323
+ extra: details.extra
3324
+ }
3325
+ );
3326
+ const retryInit = {
3327
+ method,
3328
+ headers: { "PAYMENT-SIGNATURE": paymentPayload }
3329
+ };
3330
+ if (method === "POST") {
3331
+ retryInit.headers = {
3332
+ ...retryInit.headers,
3333
+ "Content-Type": "application/json"
3334
+ };
3335
+ retryInit.body = JSON.stringify(body ?? {});
3336
+ }
3337
+ const retry = await this.fetchWithTimeout(url, retryInit);
3338
+ if (retry.status === 402) {
3339
+ throw new PaymentError("Payment was rejected. Check your wallet balance.");
3340
+ }
3341
+ if (!retry.ok) {
3342
+ await this.throwApiError(retry, `Surf request failed after payment (${method} ${url})`);
3343
+ }
3344
+ return retry.json();
3345
+ }
3346
+ async throwApiError(resp, prefix) {
3347
+ let errorBody;
3348
+ try {
3349
+ errorBody = await resp.json();
3350
+ } catch {
3351
+ errorBody = { error: "Request failed" };
3352
+ }
3353
+ throw new APIError(
3354
+ `${prefix}: HTTP ${resp.status}`,
3355
+ resp.status,
3356
+ sanitizeErrorResponse(errorBody)
3357
+ );
3358
+ }
3359
+ async fetchWithTimeout(url, init) {
3360
+ const controller = new AbortController();
3361
+ const timeoutId = setTimeout(() => controller.abort(), this.timeout);
3362
+ try {
3363
+ return await fetch(url, { ...init, signal: controller.signal });
3364
+ } finally {
3365
+ clearTimeout(timeoutId);
3366
+ }
3367
+ }
3368
+ getWalletAddress() {
3369
+ return this.account.address;
3370
+ }
3371
+ };
3372
+
3373
+ // 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;
3377
+ var DEFAULT_POLL_INTERVAL_MS = 5e3;
3378
+ var DEFAULT_POLL_BUDGET_MS = 3e5;
3379
+ var MAX_SIGNED_AUTH_SECONDS = 600;
3380
+ var BlockrunClient = class {
3381
+ account;
3382
+ privateKey;
3383
+ apiUrl;
3384
+ timeout;
3385
+ sessionTotalUsd = 0;
3386
+ sessionCalls = 0;
3387
+ constructor(options = {}) {
3388
+ const envKey = typeof process !== "undefined" && process.env ? process.env.BLOCKRUN_WALLET_KEY || process.env.BASE_CHAIN_WALLET_KEY : void 0;
3389
+ const privateKey = options.privateKey || envKey;
3390
+ if (!privateKey) {
3391
+ throw new Error(
3392
+ "Private key required. Pass privateKey in options or set BLOCKRUN_WALLET_KEY environment variable."
3393
+ );
3394
+ }
3395
+ validatePrivateKey(privateKey);
3396
+ this.privateKey = privateKey;
3397
+ this.account = privateKeyToAccount10(privateKey);
3398
+ const apiUrl = options.apiUrl || DEFAULT_API_URL10;
3399
+ validateApiUrl(apiUrl);
3400
+ this.apiUrl = apiUrl.replace(/\/$/, "");
3401
+ this.timeout = options.timeout || DEFAULT_TIMEOUT10;
3402
+ }
3403
+ /**
3404
+ * GET a BlockRun endpoint. `path` is everything after `/api` (a leading
3405
+ * `/api` is tolerated and stripped). Query params are URL-encoded; arrays
3406
+ * become repeated keys (`?a=1&a=2`); undefined/null are dropped.
3407
+ */
3408
+ async get(path5, params) {
3409
+ const url = this.buildUrl(path5, params);
3410
+ return this.requestWithPayment(url, "GET");
3411
+ }
3412
+ /**
3413
+ * POST a BlockRun endpoint with a JSON body.
3414
+ */
3415
+ async post(path5, body) {
3416
+ const url = this.buildUrl(path5);
3417
+ return this.requestWithPayment(url, "POST", body);
3418
+ }
3419
+ /**
3420
+ * Submit a long-running job and poll until it completes.
3421
+ *
3422
+ * Pattern: submit → 402 → sign → 202 `{ id, poll_url, status }` → loop GET
3423
+ * the poll_url with the SAME `PAYMENT-SIGNATURE` until status=completed (or
3424
+ * deadline exceeded). Settlement happens only when upstream returns 200 +
3425
+ * completed — upstream failure or caller giving up = no charge.
3426
+ *
3427
+ * If the gateway returns 200 directly on submit (no async surface), this
3428
+ * short-circuits and returns the body. Most long-running endpoints (image,
3429
+ * video, music, voice) return 202 with a poll_url.
3430
+ */
3431
+ async poll(path5, body, options) {
3432
+ const submitUrl = this.buildUrl(path5);
3433
+ const budgetMs = options?.budgetMs ?? DEFAULT_POLL_BUDGET_MS;
3434
+ const intervalMs = options?.intervalMs ?? DEFAULT_POLL_INTERVAL_MS;
3435
+ const resp402 = await this.fetchWithTimeout(submitUrl, {
3436
+ method: "POST",
3437
+ headers: { "Content-Type": "application/json" },
3438
+ body: JSON.stringify(body ?? {})
3439
+ });
3440
+ if (resp402.status === 200) {
3441
+ return resp402.json();
3442
+ }
3443
+ if (resp402.status !== 402) {
3444
+ await this.throwApiError(resp402, `poll submit failed (${submitUrl})`);
3445
+ }
3446
+ const paymentPayload = await this.signFrom402(resp402, submitUrl, {
3447
+ description: "BlockRun async job",
3448
+ maxTimeoutSeconds: MAX_SIGNED_AUTH_SECONDS
3449
+ });
3450
+ const submitResp = await this.fetchWithTimeout(submitUrl, {
3451
+ method: "POST",
3452
+ headers: {
3453
+ "Content-Type": "application/json",
3454
+ "PAYMENT-SIGNATURE": paymentPayload
3455
+ },
3456
+ body: JSON.stringify(body ?? {})
3457
+ });
3458
+ if (submitResp.status === 402) {
3459
+ throw new PaymentError("Payment was rejected. Check your wallet balance.");
3460
+ }
3461
+ if (submitResp.status !== 200 && submitResp.status !== 202) {
3462
+ await this.throwApiError(submitResp, `poll submit failed (${submitUrl})`);
3463
+ }
3464
+ if (submitResp.status === 200) {
3465
+ this.recordSpending();
3466
+ return submitResp.json();
3467
+ }
3468
+ const submitData = await submitResp.json();
3469
+ if (!submitData.id || !submitData.poll_url) {
3470
+ throw new APIError(
3471
+ "Async submit response missing id/poll_url",
3472
+ submitResp.status,
3473
+ { response: submitData }
3474
+ );
3475
+ }
3476
+ const pollUrl = this.absolute(submitData.poll_url);
3477
+ const deadline = Date.now() + budgetMs;
3478
+ let lastStatus = submitData.status || "queued";
3479
+ while (Date.now() < deadline) {
3480
+ await sleep(intervalMs);
3481
+ const pollResp = await this.fetchWithTimeout(pollUrl, {
3482
+ method: "GET",
3483
+ headers: { "PAYMENT-SIGNATURE": paymentPayload }
3484
+ });
3485
+ let pollData = {};
3486
+ try {
3487
+ pollData = await pollResp.json();
3488
+ } catch {
3489
+ }
3490
+ lastStatus = pollData.status || lastStatus;
3491
+ if (pollResp.status === 202 && (lastStatus === "queued" || lastStatus === "in_progress")) {
3492
+ continue;
3493
+ }
3494
+ if (lastStatus === "failed") {
3495
+ throw new APIError(
3496
+ `Upstream job failed: ${pollData.error || "unknown"}`,
3497
+ pollResp.status,
3498
+ sanitizeErrorResponse(pollData)
3499
+ );
3500
+ }
3501
+ if (pollResp.status === 200 && lastStatus === "completed") {
3502
+ this.recordSpending();
3503
+ return pollData;
3504
+ }
3505
+ if (pollResp.status !== 200 && pollResp.status !== 202 && pollResp.status !== 504) {
3506
+ await this.throwApiError(pollResp, `poll failed (${pollUrl})`);
3507
+ }
3508
+ }
3509
+ throw new APIError(
3510
+ `Job did not complete within ${Math.round(budgetMs / 1e3)}s (last status: ${lastStatus}). No payment was taken.`,
3511
+ 504,
3512
+ { id: submitData.id, last_status: lastStatus }
3513
+ );
3514
+ }
3515
+ /**
3516
+ * Stream a Server-Sent Events endpoint.
3517
+ *
3518
+ * Yields each `data: …` line parsed as JSON. Stops when the upstream emits
3519
+ * `data: [DONE]` or closes the connection. Caller is responsible for typing
3520
+ * the chunk shape; pass a generic for typed yields.
3521
+ *
3522
+ * Example — streaming chat:
3523
+ * for await (const chunk of br.stream<ChatChunk>("/v1/chat/completions", {
3524
+ * model: "anthropic/claude-sonnet-4-6",
3525
+ * messages: [{ role: "user", content: "Hi" }],
3526
+ * stream: true,
3527
+ * })) {
3528
+ * process.stdout.write(chunk.choices?.[0]?.delta?.content ?? "");
3529
+ * }
3530
+ */
3531
+ async *stream(path5, body) {
3532
+ const url = this.buildUrl(path5);
3533
+ const requestBody = JSON.stringify(body ?? {});
3534
+ const resp402 = await this.fetchWithTimeout(url, {
3535
+ method: "POST",
3536
+ headers: { "Content-Type": "application/json" },
3537
+ body: requestBody
3538
+ });
3539
+ let streamResp;
3540
+ if (resp402.status === 200) {
3541
+ streamResp = resp402;
3542
+ } else if (resp402.status === 402) {
3543
+ const paymentPayload = await this.signFrom402(resp402, url, {
3544
+ description: "BlockRun stream"
3545
+ });
3546
+ streamResp = await this.fetchWithTimeout(url, {
3547
+ method: "POST",
3548
+ headers: {
3549
+ "Content-Type": "application/json",
3550
+ "PAYMENT-SIGNATURE": paymentPayload
3551
+ },
3552
+ body: requestBody
3553
+ });
3554
+ if (streamResp.status === 402) {
3555
+ throw new PaymentError(
3556
+ "Payment was rejected. Check your wallet balance."
3557
+ );
3558
+ }
3559
+ if (!streamResp.ok) {
3560
+ await this.throwApiError(streamResp, `stream failed after payment (${url})`);
3561
+ }
3562
+ this.recordSpending();
3563
+ } else {
3564
+ await this.throwApiError(resp402, `stream failed (${url})`);
3565
+ return;
3566
+ }
3567
+ if (!streamResp.body) {
3568
+ throw new APIError("Stream response has no body", streamResp.status, {});
3569
+ }
3570
+ const reader = streamResp.body.getReader();
3571
+ const decoder = new TextDecoder();
3572
+ let buffer = "";
3573
+ try {
3574
+ while (true) {
3575
+ const { done, value } = await reader.read();
3576
+ if (done) break;
3577
+ buffer += decoder.decode(value, { stream: true });
3578
+ const lines = buffer.split("\n");
3579
+ buffer = lines.pop() || "";
3580
+ for (const line of lines) {
3581
+ const trimmed = line.trim();
3582
+ if (!trimmed || !trimmed.startsWith("data: ")) continue;
3583
+ const data = trimmed.slice(6);
3584
+ if (data === "[DONE]") return;
3585
+ try {
3586
+ yield JSON.parse(data);
3587
+ } catch {
3588
+ }
3589
+ }
3590
+ }
3591
+ } finally {
3592
+ reader.releaseLock();
3593
+ }
3594
+ }
3595
+ // --------------------------------------------------------------------
3596
+ // Internal: shared infrastructure
3597
+ // --------------------------------------------------------------------
3598
+ buildUrl(path5, params) {
3599
+ let normalized = path5.startsWith("/") ? path5 : `/${path5}`;
3600
+ if (normalized.startsWith("/api/")) {
3601
+ normalized = normalized.slice(4);
3602
+ }
3603
+ const base = `${this.apiUrl}${normalized}`;
3604
+ if (!params) return base;
3605
+ const qs = new URLSearchParams();
3606
+ for (const [key, value] of Object.entries(params)) {
3607
+ if (value === void 0 || value === null) continue;
3608
+ if (Array.isArray(value)) {
3609
+ for (const v of value) {
3610
+ if (v === void 0 || v === null) continue;
3611
+ qs.append(key, String(v));
3612
+ }
3613
+ } else {
3614
+ qs.append(key, String(value));
3615
+ }
3616
+ }
3617
+ const query = qs.toString();
3618
+ return query ? `${base}?${query}` : base;
3619
+ }
3620
+ absolute(url) {
3621
+ if (url.startsWith("http://") || url.startsWith("https://")) return url;
3622
+ const base = this.apiUrl.endsWith("/api") ? this.apiUrl.slice(0, -"/api".length) : this.apiUrl;
3623
+ return `${base}${url}`;
3624
+ }
3625
+ async requestWithPayment(url, method, body) {
3626
+ const init = { method };
3627
+ if (method === "POST") {
3628
+ init.headers = { "Content-Type": "application/json" };
3629
+ init.body = JSON.stringify(body ?? {});
3630
+ }
3631
+ const response = await this.fetchWithTimeout(url, init);
3632
+ if (response.status === 402) {
3633
+ return this.handlePaymentAndRetry(url, method, body, response);
3634
+ }
3635
+ if (!response.ok) {
3636
+ await this.throwApiError(response, `${method} ${url} failed`);
3637
+ }
3638
+ return response.json();
3639
+ }
3640
+ async handlePaymentAndRetry(url, method, body, response) {
3641
+ const paymentPayload = await this.signFrom402(response, url, {
3642
+ description: "BlockRun"
3643
+ });
3644
+ const retryInit = {
3645
+ method,
3646
+ headers: { "PAYMENT-SIGNATURE": paymentPayload }
3647
+ };
3648
+ if (method === "POST") {
3649
+ retryInit.headers = {
3650
+ ...retryInit.headers,
3651
+ "Content-Type": "application/json"
3652
+ };
3653
+ retryInit.body = JSON.stringify(body ?? {});
3654
+ }
3655
+ const retry = await this.fetchWithTimeout(url, retryInit);
3656
+ if (retry.status === 402) {
3657
+ throw new PaymentError(
3658
+ "Payment was rejected. Check your wallet balance."
3659
+ );
3660
+ }
3661
+ if (!retry.ok) {
3662
+ await this.throwApiError(retry, `${method} ${url} failed after payment`);
3663
+ }
3664
+ this.recordSpending();
3665
+ return retry.json();
3666
+ }
3667
+ /**
3668
+ * Read a 402 response's payment requirements (header or body), then sign and
3669
+ * return the base64 PAYMENT-SIGNATURE payload. Also records the cost-to-be
3670
+ * onto the response context (settled on `recordSpending`).
3671
+ */
3672
+ async signFrom402(response, url, opts) {
3673
+ let paymentHeader = response.headers.get("payment-required");
3674
+ if (!paymentHeader) {
3675
+ try {
3676
+ const respBody = await response.json();
3677
+ if (respBody.x402Version !== void 0 || respBody.accepts !== void 0) {
3678
+ paymentHeader = btoa(JSON.stringify(respBody));
3679
+ }
3680
+ } catch {
3681
+ }
3682
+ }
3683
+ if (!paymentHeader) {
3684
+ throw new PaymentError("402 response but no payment requirements found");
3685
+ }
3686
+ const paymentRequired = parsePaymentRequired(paymentHeader);
3687
+ const details = extractPaymentDetails(paymentRequired);
3688
+ this.pendingCostUsd = parseFloat(details.amount) / 1e6;
3689
+ return createPaymentPayload(
3690
+ this.privateKey,
3691
+ this.account.address,
3692
+ details.recipient,
3693
+ details.amount,
3694
+ details.network || "eip155:8453",
3695
+ {
3696
+ resourceUrl: details.resource?.url || url,
3697
+ resourceDescription: details.resource?.description || opts.description,
3698
+ maxTimeoutSeconds: Math.max(
3699
+ details.maxTimeoutSeconds || 0,
3700
+ opts.maxTimeoutSeconds || 300
3701
+ ),
3702
+ extra: details.extra
3703
+ }
3704
+ );
3705
+ }
3706
+ /** Accumulates the most-recent pending cost; settled by recordSpending. */
3707
+ pendingCostUsd = 0;
3708
+ recordSpending() {
3709
+ if (this.pendingCostUsd > 0) {
3710
+ this.sessionCalls += 1;
3711
+ this.sessionTotalUsd += this.pendingCostUsd;
3712
+ this.pendingCostUsd = 0;
3713
+ }
3714
+ }
3715
+ async throwApiError(resp, prefix) {
3716
+ let errorBody;
3717
+ try {
3718
+ errorBody = await resp.json();
3719
+ } catch {
3720
+ errorBody = { error: "Request failed" };
3721
+ }
3722
+ throw new APIError(
3723
+ `${prefix}: HTTP ${resp.status}`,
3724
+ resp.status,
3725
+ sanitizeErrorResponse(errorBody)
3726
+ );
3727
+ }
3728
+ async fetchWithTimeout(url, init) {
3729
+ const controller = new AbortController();
3730
+ const timeoutId = setTimeout(() => controller.abort(), this.timeout);
3731
+ try {
3732
+ return await fetch(url, { ...init, signal: controller.signal });
3733
+ } finally {
3734
+ clearTimeout(timeoutId);
3735
+ }
3736
+ }
3737
+ // --------------------------------------------------------------------
3738
+ // Public surface: wallet + spending
3739
+ // --------------------------------------------------------------------
3740
+ getWalletAddress() {
3741
+ return this.account.address;
3742
+ }
3743
+ getSpending() {
3744
+ return { totalUsd: this.sessionTotalUsd, calls: this.sessionCalls };
3745
+ }
3746
+ };
3747
+ function sleep(ms) {
3748
+ return new Promise((r) => setTimeout(r, ms));
3749
+ }
3750
+
3218
3751
  // src/wallet.ts
3219
- import { privateKeyToAccount as privateKeyToAccount9, generatePrivateKey } from "viem/accounts";
3752
+ import { privateKeyToAccount as privateKeyToAccount11, generatePrivateKey } from "viem/accounts";
3220
3753
  import * as fs2 from "fs";
3221
3754
  import * as path2 from "path";
3222
3755
  import * as os2 from "os";
@@ -3226,7 +3759,7 @@ var WALLET_DIR = path2.join(os2.homedir(), ".blockrun");
3226
3759
  var WALLET_FILE = path2.join(WALLET_DIR, ".session");
3227
3760
  function createWallet() {
3228
3761
  const privateKey = generatePrivateKey();
3229
- const account = privateKeyToAccount9(privateKey);
3762
+ const account = privateKeyToAccount11(privateKey);
3230
3763
  return {
3231
3764
  address: account.address,
3232
3765
  privateKey
@@ -3282,12 +3815,12 @@ function loadWallet() {
3282
3815
  function getOrCreateWallet() {
3283
3816
  const envKey = typeof process !== "undefined" && process.env ? process.env.BLOCKRUN_WALLET_KEY || process.env.BASE_CHAIN_WALLET_KEY : void 0;
3284
3817
  if (envKey) {
3285
- const account = privateKeyToAccount9(envKey);
3818
+ const account = privateKeyToAccount11(envKey);
3286
3819
  return { address: account.address, privateKey: envKey, isNew: false };
3287
3820
  }
3288
3821
  const fileKey = loadWallet();
3289
3822
  if (fileKey) {
3290
- const account = privateKeyToAccount9(fileKey);
3823
+ const account = privateKeyToAccount11(fileKey);
3291
3824
  return { address: account.address, privateKey: fileKey, isNew: false };
3292
3825
  }
3293
3826
  const { address, privateKey } = createWallet();
@@ -3297,11 +3830,11 @@ function getOrCreateWallet() {
3297
3830
  function getWalletAddress() {
3298
3831
  const envKey = typeof process !== "undefined" && process.env ? process.env.BLOCKRUN_WALLET_KEY || process.env.BASE_CHAIN_WALLET_KEY : void 0;
3299
3832
  if (envKey) {
3300
- return privateKeyToAccount9(envKey).address;
3833
+ return privateKeyToAccount11(envKey).address;
3301
3834
  }
3302
3835
  const fileKey = loadWallet();
3303
3836
  if (fileKey) {
3304
- return privateKeyToAccount9(fileKey).address;
3837
+ return privateKeyToAccount11(fileKey).address;
3305
3838
  }
3306
3839
  return null;
3307
3840
  }
@@ -3481,7 +4014,7 @@ async function getOrCreateSolanaWallet() {
3481
4014
  // src/solana-client.ts
3482
4015
  var SOLANA_API_URL = "https://sol.blockrun.ai/api";
3483
4016
  var DEFAULT_MAX_TOKENS2 = 1024;
3484
- var DEFAULT_TIMEOUT9 = 6e4;
4017
+ var DEFAULT_TIMEOUT11 = 6e4;
3485
4018
  var SDK_VERSION2 = "0.3.0";
3486
4019
  var USER_AGENT2 = `blockrun-ts/${SDK_VERSION2}`;
3487
4020
  var SolanaLLMClient = class {
@@ -3506,7 +4039,7 @@ var SolanaLLMClient = class {
3506
4039
  validateApiUrl(apiUrl);
3507
4040
  this.apiUrl = apiUrl.replace(/\/$/, "");
3508
4041
  this.rpcUrl = options.rpcUrl || "https://api.mainnet-beta.solana.com";
3509
- this.timeout = options.timeout || DEFAULT_TIMEOUT9;
4042
+ this.timeout = options.timeout || DEFAULT_TIMEOUT11;
3510
4043
  }
3511
4044
  /** Get Solana wallet address (public key in base58). */
3512
4045
  async getWalletAddress() {
@@ -4413,7 +4946,7 @@ var OpenAI = class {
4413
4946
  };
4414
4947
 
4415
4948
  // src/anthropic-compat.ts
4416
- import { privateKeyToAccount as privateKeyToAccount10 } from "viem/accounts";
4949
+ import { privateKeyToAccount as privateKeyToAccount12 } from "viem/accounts";
4417
4950
  var AnthropicClient = class {
4418
4951
  _client = null;
4419
4952
  _clientPromise = null;
@@ -4426,7 +4959,7 @@ var AnthropicClient = class {
4426
4959
  const key = options.privateKey ?? wallet.privateKey;
4427
4960
  validatePrivateKey(key);
4428
4961
  this._privateKey = key;
4429
- this._account = privateKeyToAccount10(this._privateKey);
4962
+ this._account = privateKeyToAccount12(this._privateKey);
4430
4963
  const apiUrl = options.apiUrl ?? "https://blockrun.ai/api";
4431
4964
  validateApiUrl(apiUrl);
4432
4965
  this._apiUrl = apiUrl.replace(/\/$/, "");
@@ -4524,6 +5057,7 @@ export {
4524
5057
  APIError,
4525
5058
  AnthropicClient,
4526
5059
  BASE_CHAIN_ID,
5060
+ BlockrunClient,
4527
5061
  BlockrunError,
4528
5062
  ImageClient,
4529
5063
  KNOWN_PROVIDERS,
@@ -4536,6 +5070,7 @@ export {
4536
5070
  SOLANA_WALLET_FILE as SOLANA_WALLET_FILE_PATH,
4537
5071
  SearchClient,
4538
5072
  SolanaLLMClient,
5073
+ SurfClient,
4539
5074
  USDC_BASE,
4540
5075
  USDC_BASE_CONTRACT,
4541
5076
  USDC_SOLANA,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blockrun/llm",
3
- "version": "2.3.0",
3
+ "version": "2.5.0",
4
4
  "type": "module",
5
5
  "description": "BlockRun SDK - Pay-per-request AI (LLM, Image, Video, Music, Voice) via x402 on Base and Solana",
6
6
  "main": "dist/index.cjs",