@blockrun/llm 2.3.0 → 2.4.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/README.md +44 -0
- package/dist/index.cjs +168 -11
- package/dist/index.d.cts +74 -1
- package/dist/index.d.ts +74 -1
- package/dist/index.js +166 -10
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -455,6 +455,50 @@ const results = await x.search('x402 micropayments', { queryType: 'Latest' });
|
|
|
455
455
|
const tweets = await x.userTweets({ username: 'vitalikbuterin', includeReplies: false });
|
|
456
456
|
```
|
|
457
457
|
|
|
458
|
+
### Surf Crypto Data
|
|
459
|
+
|
|
460
|
+
`SurfClient` exposes the full `/v1/surf/*` catalog — 84+ pay-per-call
|
|
461
|
+
endpoints across CEX/DEX market data, on-chain SQL, wallet intelligence,
|
|
462
|
+
prediction markets (Polymarket + Kalshi), social analytics, news, VC fund
|
|
463
|
+
data, and an OpenAI-compatible chat surface. Flat pricing per call:
|
|
464
|
+
|
|
465
|
+
| Tier | Price/call | Examples |
|
|
466
|
+
|------|-----------|----------|
|
|
467
|
+
| 1 | $0.001 | `/market/price`, `/market/ranking`, `/news/feed`, prediction-market reads, social tweets |
|
|
468
|
+
| 2 | $0.005 | `/exchange/depth`, `/exchange/klines`, `/wallet/detail`, `/search/*`, `/social/ranking` |
|
|
469
|
+
| 3 | $0.020 | `/onchain/sql`, `/onchain/query`, `/onchain/schema`, `/chat/completions` |
|
|
470
|
+
|
|
471
|
+
Because the catalog is broad and evolving, the client deliberately ships a
|
|
472
|
+
generic `get` / `post` pair instead of 84 typed wrappers. Pass the path
|
|
473
|
+
(with or without the `/v1/surf` prefix), query params, or a JSON body —
|
|
474
|
+
type the response via a generic if you want.
|
|
475
|
+
|
|
476
|
+
```ts
|
|
477
|
+
import { SurfClient } from '@blockrun/llm';
|
|
478
|
+
|
|
479
|
+
const surf = new SurfClient();
|
|
480
|
+
|
|
481
|
+
// Tier 1 — token price ($0.001)
|
|
482
|
+
const btc = await surf.get('/market/price', { symbol: 'BTC' });
|
|
483
|
+
|
|
484
|
+
// Tier 2 — order book depth ($0.005)
|
|
485
|
+
const book = await surf.get('/exchange/depth', {
|
|
486
|
+
exchange: 'binance',
|
|
487
|
+
symbol: 'BTC-USDT',
|
|
488
|
+
});
|
|
489
|
+
|
|
490
|
+
// Tier 3 — raw on-chain SQL against 80+ ClickHouse tables ($0.020)
|
|
491
|
+
const rows = await surf.post('/onchain/sql', {
|
|
492
|
+
query: 'SELECT block_number FROM ethereum.blocks ORDER BY block_number DESC LIMIT 5',
|
|
493
|
+
});
|
|
494
|
+
|
|
495
|
+
// Typed response via generic
|
|
496
|
+
type Price = { symbol: string; price: number; timestamp: string };
|
|
497
|
+
const eth = await surf.get<Price>('/market/price', { symbol: 'ETH' });
|
|
498
|
+
```
|
|
499
|
+
|
|
500
|
+
Full endpoint inventory: <https://blockrun.ai/marketplace/surf>.
|
|
501
|
+
|
|
458
502
|
Methods: `userLookup`, `userInfo`, `followers`, `following`, `followings`,
|
|
459
503
|
`verifiedFollowers`, `userTweets`, `mentions`, `tweetLookup`, `tweetReplies`,
|
|
460
504
|
`tweetThread`, `search`, `trending`, `articlesRising`.
|
package/dist/index.cjs
CHANGED
|
@@ -45,6 +45,7 @@ __export(index_exports, {
|
|
|
45
45
|
SOLANA_WALLET_FILE_PATH: () => SOLANA_WALLET_FILE,
|
|
46
46
|
SearchClient: () => SearchClient,
|
|
47
47
|
SolanaLLMClient: () => SolanaLLMClient,
|
|
48
|
+
SurfClient: () => SurfClient,
|
|
48
49
|
USDC_BASE: () => USDC_BASE,
|
|
49
50
|
USDC_BASE_CONTRACT: () => USDC_BASE_CONTRACT,
|
|
50
51
|
USDC_SOLANA: () => USDC_SOLANA,
|
|
@@ -3312,8 +3313,163 @@ function buildUrl(base, query) {
|
|
|
3312
3313
|
return `${base}?${qs}`;
|
|
3313
3314
|
}
|
|
3314
3315
|
|
|
3315
|
-
// src/
|
|
3316
|
+
// src/surf.ts
|
|
3316
3317
|
var import_accounts10 = require("viem/accounts");
|
|
3318
|
+
var DEFAULT_API_URL9 = "https://blockrun.ai/api";
|
|
3319
|
+
var DEFAULT_TIMEOUT9 = 6e4;
|
|
3320
|
+
var SURF_PREFIX = "/v1/surf";
|
|
3321
|
+
var SurfClient = class {
|
|
3322
|
+
account;
|
|
3323
|
+
privateKey;
|
|
3324
|
+
apiUrl;
|
|
3325
|
+
timeout;
|
|
3326
|
+
constructor(options = {}) {
|
|
3327
|
+
const envKey = typeof process !== "undefined" && process.env ? process.env.BLOCKRUN_WALLET_KEY || process.env.BASE_CHAIN_WALLET_KEY : void 0;
|
|
3328
|
+
const privateKey = options.privateKey || envKey;
|
|
3329
|
+
if (!privateKey) {
|
|
3330
|
+
throw new Error(
|
|
3331
|
+
"Private key required. Pass privateKey in options or set BLOCKRUN_WALLET_KEY environment variable."
|
|
3332
|
+
);
|
|
3333
|
+
}
|
|
3334
|
+
validatePrivateKey(privateKey);
|
|
3335
|
+
this.privateKey = privateKey;
|
|
3336
|
+
this.account = (0, import_accounts10.privateKeyToAccount)(privateKey);
|
|
3337
|
+
const apiUrl = options.apiUrl || DEFAULT_API_URL9;
|
|
3338
|
+
validateApiUrl(apiUrl);
|
|
3339
|
+
this.apiUrl = apiUrl.replace(/\/$/, "");
|
|
3340
|
+
this.timeout = options.timeout || DEFAULT_TIMEOUT9;
|
|
3341
|
+
}
|
|
3342
|
+
/**
|
|
3343
|
+
* GET a Surf endpoint. `path` is everything after `/v1/surf` (a leading
|
|
3344
|
+
* `/v1/surf` is tolerated and stripped). Query params are URL-encoded;
|
|
3345
|
+
* arrays become repeated keys (`?a=1&a=2`).
|
|
3346
|
+
*/
|
|
3347
|
+
async get(path5, params) {
|
|
3348
|
+
const url = this.buildUrl(path5, params);
|
|
3349
|
+
return this.requestWithPayment(url, "GET");
|
|
3350
|
+
}
|
|
3351
|
+
/**
|
|
3352
|
+
* POST a Surf endpoint with a JSON body. Same path normalization as `get`.
|
|
3353
|
+
*/
|
|
3354
|
+
async post(path5, body) {
|
|
3355
|
+
const url = this.buildUrl(path5);
|
|
3356
|
+
return this.requestWithPayment(url, "POST", body);
|
|
3357
|
+
}
|
|
3358
|
+
buildUrl(path5, params) {
|
|
3359
|
+
let normalized = path5.startsWith("/") ? path5 : `/${path5}`;
|
|
3360
|
+
if (!normalized.startsWith(SURF_PREFIX)) {
|
|
3361
|
+
normalized = `${SURF_PREFIX}${normalized}`;
|
|
3362
|
+
}
|
|
3363
|
+
const base = `${this.apiUrl}${normalized}`;
|
|
3364
|
+
if (!params) return base;
|
|
3365
|
+
const qs = new URLSearchParams();
|
|
3366
|
+
for (const [key, value] of Object.entries(params)) {
|
|
3367
|
+
if (value === void 0 || value === null) continue;
|
|
3368
|
+
if (Array.isArray(value)) {
|
|
3369
|
+
for (const v of value) {
|
|
3370
|
+
if (v === void 0 || v === null) continue;
|
|
3371
|
+
qs.append(key, String(v));
|
|
3372
|
+
}
|
|
3373
|
+
} else {
|
|
3374
|
+
qs.append(key, String(value));
|
|
3375
|
+
}
|
|
3376
|
+
}
|
|
3377
|
+
const query = qs.toString();
|
|
3378
|
+
return query ? `${base}?${query}` : base;
|
|
3379
|
+
}
|
|
3380
|
+
async requestWithPayment(url, method, body) {
|
|
3381
|
+
const init = { method };
|
|
3382
|
+
if (method === "POST") {
|
|
3383
|
+
init.headers = { "Content-Type": "application/json" };
|
|
3384
|
+
init.body = JSON.stringify(body ?? {});
|
|
3385
|
+
}
|
|
3386
|
+
const response = await this.fetchWithTimeout(url, init);
|
|
3387
|
+
if (response.status === 402) {
|
|
3388
|
+
return this.handlePaymentAndRetry(url, method, body, response);
|
|
3389
|
+
}
|
|
3390
|
+
if (!response.ok) {
|
|
3391
|
+
await this.throwApiError(response, `Surf request failed (${method} ${url})`);
|
|
3392
|
+
}
|
|
3393
|
+
return response.json();
|
|
3394
|
+
}
|
|
3395
|
+
async handlePaymentAndRetry(url, method, body, response) {
|
|
3396
|
+
let paymentHeader = response.headers.get("payment-required");
|
|
3397
|
+
if (!paymentHeader) {
|
|
3398
|
+
try {
|
|
3399
|
+
const respBody = await response.json();
|
|
3400
|
+
if (respBody.x402Version !== void 0 || respBody.accepts !== void 0) {
|
|
3401
|
+
paymentHeader = btoa(JSON.stringify(respBody));
|
|
3402
|
+
}
|
|
3403
|
+
} catch {
|
|
3404
|
+
}
|
|
3405
|
+
}
|
|
3406
|
+
if (!paymentHeader) {
|
|
3407
|
+
throw new PaymentError("402 response but no payment requirements found");
|
|
3408
|
+
}
|
|
3409
|
+
const paymentRequired = parsePaymentRequired(paymentHeader);
|
|
3410
|
+
const details = extractPaymentDetails(paymentRequired);
|
|
3411
|
+
const paymentPayload = await createPaymentPayload(
|
|
3412
|
+
this.privateKey,
|
|
3413
|
+
this.account.address,
|
|
3414
|
+
details.recipient,
|
|
3415
|
+
details.amount,
|
|
3416
|
+
details.network || "eip155:8453",
|
|
3417
|
+
{
|
|
3418
|
+
resourceUrl: details.resource?.url || url,
|
|
3419
|
+
resourceDescription: details.resource?.description || "BlockRun Surf",
|
|
3420
|
+
maxTimeoutSeconds: details.maxTimeoutSeconds || 300,
|
|
3421
|
+
extra: details.extra
|
|
3422
|
+
}
|
|
3423
|
+
);
|
|
3424
|
+
const retryInit = {
|
|
3425
|
+
method,
|
|
3426
|
+
headers: { "PAYMENT-SIGNATURE": paymentPayload }
|
|
3427
|
+
};
|
|
3428
|
+
if (method === "POST") {
|
|
3429
|
+
retryInit.headers = {
|
|
3430
|
+
...retryInit.headers,
|
|
3431
|
+
"Content-Type": "application/json"
|
|
3432
|
+
};
|
|
3433
|
+
retryInit.body = JSON.stringify(body ?? {});
|
|
3434
|
+
}
|
|
3435
|
+
const retry = await this.fetchWithTimeout(url, retryInit);
|
|
3436
|
+
if (retry.status === 402) {
|
|
3437
|
+
throw new PaymentError("Payment was rejected. Check your wallet balance.");
|
|
3438
|
+
}
|
|
3439
|
+
if (!retry.ok) {
|
|
3440
|
+
await this.throwApiError(retry, `Surf request failed after payment (${method} ${url})`);
|
|
3441
|
+
}
|
|
3442
|
+
return retry.json();
|
|
3443
|
+
}
|
|
3444
|
+
async throwApiError(resp, prefix) {
|
|
3445
|
+
let errorBody;
|
|
3446
|
+
try {
|
|
3447
|
+
errorBody = await resp.json();
|
|
3448
|
+
} catch {
|
|
3449
|
+
errorBody = { error: "Request failed" };
|
|
3450
|
+
}
|
|
3451
|
+
throw new APIError(
|
|
3452
|
+
`${prefix}: HTTP ${resp.status}`,
|
|
3453
|
+
resp.status,
|
|
3454
|
+
sanitizeErrorResponse(errorBody)
|
|
3455
|
+
);
|
|
3456
|
+
}
|
|
3457
|
+
async fetchWithTimeout(url, init) {
|
|
3458
|
+
const controller = new AbortController();
|
|
3459
|
+
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
|
|
3460
|
+
try {
|
|
3461
|
+
return await fetch(url, { ...init, signal: controller.signal });
|
|
3462
|
+
} finally {
|
|
3463
|
+
clearTimeout(timeoutId);
|
|
3464
|
+
}
|
|
3465
|
+
}
|
|
3466
|
+
getWalletAddress() {
|
|
3467
|
+
return this.account.address;
|
|
3468
|
+
}
|
|
3469
|
+
};
|
|
3470
|
+
|
|
3471
|
+
// src/wallet.ts
|
|
3472
|
+
var import_accounts11 = require("viem/accounts");
|
|
3317
3473
|
var fs2 = __toESM(require("fs"), 1);
|
|
3318
3474
|
var path2 = __toESM(require("path"), 1);
|
|
3319
3475
|
var os2 = __toESM(require("os"), 1);
|
|
@@ -3322,8 +3478,8 @@ var BASE_CHAIN_ID2 = "8453";
|
|
|
3322
3478
|
var WALLET_DIR = path2.join(os2.homedir(), ".blockrun");
|
|
3323
3479
|
var WALLET_FILE = path2.join(WALLET_DIR, ".session");
|
|
3324
3480
|
function createWallet() {
|
|
3325
|
-
const privateKey = (0,
|
|
3326
|
-
const account = (0,
|
|
3481
|
+
const privateKey = (0, import_accounts11.generatePrivateKey)();
|
|
3482
|
+
const account = (0, import_accounts11.privateKeyToAccount)(privateKey);
|
|
3327
3483
|
return {
|
|
3328
3484
|
address: account.address,
|
|
3329
3485
|
privateKey
|
|
@@ -3379,12 +3535,12 @@ function loadWallet() {
|
|
|
3379
3535
|
function getOrCreateWallet() {
|
|
3380
3536
|
const envKey = typeof process !== "undefined" && process.env ? process.env.BLOCKRUN_WALLET_KEY || process.env.BASE_CHAIN_WALLET_KEY : void 0;
|
|
3381
3537
|
if (envKey) {
|
|
3382
|
-
const account = (0,
|
|
3538
|
+
const account = (0, import_accounts11.privateKeyToAccount)(envKey);
|
|
3383
3539
|
return { address: account.address, privateKey: envKey, isNew: false };
|
|
3384
3540
|
}
|
|
3385
3541
|
const fileKey = loadWallet();
|
|
3386
3542
|
if (fileKey) {
|
|
3387
|
-
const account = (0,
|
|
3543
|
+
const account = (0, import_accounts11.privateKeyToAccount)(fileKey);
|
|
3388
3544
|
return { address: account.address, privateKey: fileKey, isNew: false };
|
|
3389
3545
|
}
|
|
3390
3546
|
const { address, privateKey } = createWallet();
|
|
@@ -3394,11 +3550,11 @@ function getOrCreateWallet() {
|
|
|
3394
3550
|
function getWalletAddress() {
|
|
3395
3551
|
const envKey = typeof process !== "undefined" && process.env ? process.env.BLOCKRUN_WALLET_KEY || process.env.BASE_CHAIN_WALLET_KEY : void 0;
|
|
3396
3552
|
if (envKey) {
|
|
3397
|
-
return (0,
|
|
3553
|
+
return (0, import_accounts11.privateKeyToAccount)(envKey).address;
|
|
3398
3554
|
}
|
|
3399
3555
|
const fileKey = loadWallet();
|
|
3400
3556
|
if (fileKey) {
|
|
3401
|
-
return (0,
|
|
3557
|
+
return (0, import_accounts11.privateKeyToAccount)(fileKey).address;
|
|
3402
3558
|
}
|
|
3403
3559
|
return null;
|
|
3404
3560
|
}
|
|
@@ -3578,7 +3734,7 @@ async function getOrCreateSolanaWallet() {
|
|
|
3578
3734
|
// src/solana-client.ts
|
|
3579
3735
|
var SOLANA_API_URL = "https://sol.blockrun.ai/api";
|
|
3580
3736
|
var DEFAULT_MAX_TOKENS2 = 1024;
|
|
3581
|
-
var
|
|
3737
|
+
var DEFAULT_TIMEOUT10 = 6e4;
|
|
3582
3738
|
var SDK_VERSION2 = "0.3.0";
|
|
3583
3739
|
var USER_AGENT2 = `blockrun-ts/${SDK_VERSION2}`;
|
|
3584
3740
|
var SolanaLLMClient = class {
|
|
@@ -3603,7 +3759,7 @@ var SolanaLLMClient = class {
|
|
|
3603
3759
|
validateApiUrl(apiUrl);
|
|
3604
3760
|
this.apiUrl = apiUrl.replace(/\/$/, "");
|
|
3605
3761
|
this.rpcUrl = options.rpcUrl || "https://api.mainnet-beta.solana.com";
|
|
3606
|
-
this.timeout = options.timeout ||
|
|
3762
|
+
this.timeout = options.timeout || DEFAULT_TIMEOUT10;
|
|
3607
3763
|
}
|
|
3608
3764
|
/** Get Solana wallet address (public key in base58). */
|
|
3609
3765
|
async getWalletAddress() {
|
|
@@ -4510,7 +4666,7 @@ var OpenAI = class {
|
|
|
4510
4666
|
};
|
|
4511
4667
|
|
|
4512
4668
|
// src/anthropic-compat.ts
|
|
4513
|
-
var
|
|
4669
|
+
var import_accounts12 = require("viem/accounts");
|
|
4514
4670
|
var AnthropicClient = class {
|
|
4515
4671
|
_client = null;
|
|
4516
4672
|
_clientPromise = null;
|
|
@@ -4523,7 +4679,7 @@ var AnthropicClient = class {
|
|
|
4523
4679
|
const key = options.privateKey ?? wallet.privateKey;
|
|
4524
4680
|
validatePrivateKey(key);
|
|
4525
4681
|
this._privateKey = key;
|
|
4526
|
-
this._account = (0,
|
|
4682
|
+
this._account = (0, import_accounts12.privateKeyToAccount)(this._privateKey);
|
|
4527
4683
|
const apiUrl = options.apiUrl ?? "https://blockrun.ai/api";
|
|
4528
4684
|
validateApiUrl(apiUrl);
|
|
4529
4685
|
this._apiUrl = apiUrl.replace(/\/$/, "");
|
|
@@ -4634,6 +4790,7 @@ var AnthropicClient = class {
|
|
|
4634
4790
|
SOLANA_WALLET_FILE_PATH,
|
|
4635
4791
|
SearchClient,
|
|
4636
4792
|
SolanaLLMClient,
|
|
4793
|
+
SurfClient,
|
|
4637
4794
|
USDC_BASE,
|
|
4638
4795
|
USDC_BASE_CONTRACT,
|
|
4639
4796
|
USDC_SOLANA,
|
package/dist/index.d.cts
CHANGED
|
@@ -785,6 +785,11 @@ interface PriceClientOptions {
|
|
|
785
785
|
/** If false, construction succeeds without a wallet (free endpoints only). */
|
|
786
786
|
requireWallet?: boolean;
|
|
787
787
|
}
|
|
788
|
+
interface SurfClientOptions {
|
|
789
|
+
privateKey?: `0x${string}` | string;
|
|
790
|
+
apiUrl?: string;
|
|
791
|
+
timeout?: number;
|
|
792
|
+
}
|
|
788
793
|
declare class BlockrunError extends Error {
|
|
789
794
|
constructor(message: string);
|
|
790
795
|
}
|
|
@@ -1713,6 +1718,74 @@ declare class PriceClient {
|
|
|
1713
1718
|
private fetchWithTimeout;
|
|
1714
1719
|
}
|
|
1715
1720
|
|
|
1721
|
+
/**
|
|
1722
|
+
* BlockRun Surf Client — pay-per-call crypto data via x402 micropayments.
|
|
1723
|
+
*
|
|
1724
|
+
* Surf aggregates 84+ endpoints across CEX/DEX market data, on-chain SQL,
|
|
1725
|
+
* wallet intelligence, prediction markets, social analytics, and news under
|
|
1726
|
+
* a single OpenAPI surface mounted at `/api/v1/surf/*`.
|
|
1727
|
+
*
|
|
1728
|
+
* Pricing tiers (flat per-call, USDC on Base):
|
|
1729
|
+
* Tier 1 — $0.001/call (prices, rankings, lists, news, simple reads)
|
|
1730
|
+
* Tier 2 — $0.005/call (order books, candles, search, wallet details)
|
|
1731
|
+
* Tier 3 — $0.020/call (on-chain SQL, schema introspection, chat)
|
|
1732
|
+
*
|
|
1733
|
+
* Because the catalog is large and evolving, this client deliberately
|
|
1734
|
+
* exposes a thin `get` / `post` pair instead of 84 typed wrappers. Pass the
|
|
1735
|
+
* path (with or without the `/v1/surf` prefix) and either query params or a
|
|
1736
|
+
* JSON body. The full endpoint inventory lives at
|
|
1737
|
+
* https://blockrun.ai/marketplace/surf.
|
|
1738
|
+
*
|
|
1739
|
+
* Usage:
|
|
1740
|
+
* import { SurfClient } from "@blockrun/llm";
|
|
1741
|
+
*
|
|
1742
|
+
* const surf = new SurfClient({ privateKey: "0x..." });
|
|
1743
|
+
*
|
|
1744
|
+
* // Tier 1 — token price ($0.001)
|
|
1745
|
+
* const btc = await surf.get("/market/price", { symbol: "BTC" });
|
|
1746
|
+
*
|
|
1747
|
+
* // Tier 2 — order book ($0.005)
|
|
1748
|
+
* const book = await surf.get("/exchange/depth", {
|
|
1749
|
+
* exchange: "binance",
|
|
1750
|
+
* symbol: "BTC-USDT",
|
|
1751
|
+
* });
|
|
1752
|
+
*
|
|
1753
|
+
* // Tier 3 — raw on-chain SQL ($0.020)
|
|
1754
|
+
* const rows = await surf.post("/onchain/sql", {
|
|
1755
|
+
* query: "SELECT block_number FROM ethereum.blocks ORDER BY block_number DESC LIMIT 5",
|
|
1756
|
+
* });
|
|
1757
|
+
*
|
|
1758
|
+
* // Typed responses via generic
|
|
1759
|
+
* type Price = { symbol: string; price: number; timestamp: string };
|
|
1760
|
+
* const typed = await surf.get<Price>("/market/price", { symbol: "ETH" });
|
|
1761
|
+
*/
|
|
1762
|
+
|
|
1763
|
+
type QueryValue = string | number | boolean | null | undefined;
|
|
1764
|
+
type QueryParams = Record<string, QueryValue | QueryValue[]>;
|
|
1765
|
+
declare class SurfClient {
|
|
1766
|
+
private account;
|
|
1767
|
+
private privateKey;
|
|
1768
|
+
private apiUrl;
|
|
1769
|
+
private timeout;
|
|
1770
|
+
constructor(options?: SurfClientOptions);
|
|
1771
|
+
/**
|
|
1772
|
+
* GET a Surf endpoint. `path` is everything after `/v1/surf` (a leading
|
|
1773
|
+
* `/v1/surf` is tolerated and stripped). Query params are URL-encoded;
|
|
1774
|
+
* arrays become repeated keys (`?a=1&a=2`).
|
|
1775
|
+
*/
|
|
1776
|
+
get<T = unknown>(path: string, params?: QueryParams): Promise<T>;
|
|
1777
|
+
/**
|
|
1778
|
+
* POST a Surf endpoint with a JSON body. Same path normalization as `get`.
|
|
1779
|
+
*/
|
|
1780
|
+
post<T = unknown>(path: string, body?: Record<string, unknown>): Promise<T>;
|
|
1781
|
+
private buildUrl;
|
|
1782
|
+
private requestWithPayment;
|
|
1783
|
+
private handlePaymentAndRetry;
|
|
1784
|
+
private throwApiError;
|
|
1785
|
+
private fetchWithTimeout;
|
|
1786
|
+
getWalletAddress(): string;
|
|
1787
|
+
}
|
|
1788
|
+
|
|
1716
1789
|
/**
|
|
1717
1790
|
* x402 Payment Protocol v2 Implementation for BlockRun.
|
|
1718
1791
|
*
|
|
@@ -2356,4 +2429,4 @@ declare function validateTemperature(temperature?: number): void;
|
|
|
2356
2429
|
*/
|
|
2357
2430
|
declare function validateTopP(topP?: number): void;
|
|
2358
2431
|
|
|
2359
|
-
export { APIError, AnthropicClient, type AudioModel, type AudioTrack, BASE_CHAIN_ID, type BarResolution, type BlockRunAnthropicOptions, BlockrunError, type CallInitiatedResponse, type CallModel, type CallOptions, type CallStatusResponse, type ChatChoice, type ChatCompletionOptions, type ChatMessage, type ChatOptions, type ChatResponse, type ChatResponseWithCost, type ChatUsage, type CostEntry, type CostEstimate, type CreatePaymentOptions, type FunctionCall, type FunctionDefinition, type HistoryOptions, ImageClient, type ImageClientOptions, type ImageData, type ImageEditOptions, type ImageGenerateOptions, type ImageModel, type ImageResponse, KNOWN_PROVIDERS, LLMClient, type LLMClientOptions, type ListOptions, type MarketSession, type Model, MusicClient, type MusicClientOptions, type MusicGenerateOptions, type MusicResponse, type NewsSearchSource, OpenAI, type OpenAIChatCompletionChoice, type OpenAIChatCompletionChunk, type OpenAIChatCompletionParams, type OpenAIChatCompletionResponse, type OpenAIClientOptions, PaymentError, type PaymentLinks, type PriceBar, type PriceCategory, PriceClient, type PriceClientOptions, type PriceHistoryResponse, type PriceOptions, type PricePoint, type RoutingDecision, type RoutingProfile, type RoutingTier, type RssSearchSource, SOLANA_NETWORK, SOLANA_WALLET_FILE as SOLANA_WALLET_FILE_PATH, SearchClient, type SearchClientOptions, type SearchOptions, type SearchParameters, type SearchResult, type SearchSource, type SearchUsage, type SmartChatOptions, type SmartChatResponse, SolanaLLMClient, type SolanaLLMClientOptions, type SolanaWalletInfo, type Spending, type SpendingReport, type StockMarket, type SymbolListResponse, type Tool, type ToolCall, type ToolChoice, USDC_BASE, USDC_BASE_CONTRACT, USDC_SOLANA, VideoClient, type VideoClientOptions, type VideoClip, type VideoGenerateOptions, type VideoModel, type VideoResponse, VoiceClient, type VoiceClientOptions, type VoicePreset, WALLET_DIR_PATH, WALLET_FILE_PATH, type WalletInfo, type WebSearchSource, type XArticlesRisingResponse, type XAuthorAnalyticsResponse, XClient, type XClientOptions, type XCompareAuthorsResponse, type XFollower, type XFollowersResponse, type XFollowingsResponse, type XMentionsOptions, type XMentionsResponse, type XSearchOptions, type XSearchResponse, type XSearchSource, type XTrendingResponse, type XTweet, type XTweetLookupResponse, type XTweetRepliesOptions, type XTweetRepliesResponse, type XTweetThreadResponse, type XTweetsResponse, type XUser, type XUserInfoResponse, type XUserLookupResponse, type XUserTweetsOptions, type XVerifiedFollowersResponse, clearCache, createPaymentPayload, createSolanaPaymentPayload, createSolanaWallet, createWallet, LLMClient as default, extractPaymentDetails, formatFundingMessageCompact, formatNeedsFundingMessage, formatWalletCreatedMessage, getCached, getCachedByRequest, getCostLogSummary, getCostSummary, getEip681Uri, getOrCreateSolanaWallet, getOrCreateWallet, getPaymentLinks, getWalletAddress, loadSolanaWallet, loadWallet, logCost, parsePaymentRequired, saveSolanaWallet, saveToCache, saveWallet, scanSolanaWallets, scanWallets, setCache, setupAgentSolanaWallet, setupAgentWallet, solanaClient, solanaKeyToBytes, solanaPublicKey, status, validateMaxTokens, validateModel, validateTemperature, validateTopP };
|
|
2432
|
+
export { APIError, AnthropicClient, type AudioModel, type AudioTrack, BASE_CHAIN_ID, type BarResolution, type BlockRunAnthropicOptions, BlockrunError, type CallInitiatedResponse, type CallModel, type CallOptions, type CallStatusResponse, type ChatChoice, type ChatCompletionOptions, type ChatMessage, type ChatOptions, type ChatResponse, type ChatResponseWithCost, type ChatUsage, type CostEntry, type CostEstimate, type CreatePaymentOptions, type FunctionCall, type FunctionDefinition, type HistoryOptions, ImageClient, type ImageClientOptions, type ImageData, type ImageEditOptions, type ImageGenerateOptions, type ImageModel, type ImageResponse, KNOWN_PROVIDERS, LLMClient, type LLMClientOptions, type ListOptions, type MarketSession, type Model, MusicClient, type MusicClientOptions, type MusicGenerateOptions, type MusicResponse, type NewsSearchSource, OpenAI, type OpenAIChatCompletionChoice, type OpenAIChatCompletionChunk, type OpenAIChatCompletionParams, type OpenAIChatCompletionResponse, type OpenAIClientOptions, PaymentError, type PaymentLinks, type PriceBar, type PriceCategory, PriceClient, type PriceClientOptions, type PriceHistoryResponse, type PriceOptions, type PricePoint, type RoutingDecision, type RoutingProfile, type RoutingTier, type RssSearchSource, SOLANA_NETWORK, SOLANA_WALLET_FILE as SOLANA_WALLET_FILE_PATH, SearchClient, type SearchClientOptions, type SearchOptions, type SearchParameters, type SearchResult, type SearchSource, type SearchUsage, type SmartChatOptions, type SmartChatResponse, SolanaLLMClient, type SolanaLLMClientOptions, type SolanaWalletInfo, type Spending, type SpendingReport, type StockMarket, SurfClient, type SurfClientOptions, type SymbolListResponse, type Tool, type ToolCall, type ToolChoice, USDC_BASE, USDC_BASE_CONTRACT, USDC_SOLANA, VideoClient, type VideoClientOptions, type VideoClip, type VideoGenerateOptions, type VideoModel, type VideoResponse, VoiceClient, type VoiceClientOptions, type VoicePreset, WALLET_DIR_PATH, WALLET_FILE_PATH, type WalletInfo, type WebSearchSource, type XArticlesRisingResponse, type XAuthorAnalyticsResponse, XClient, type XClientOptions, type XCompareAuthorsResponse, type XFollower, type XFollowersResponse, type XFollowingsResponse, type XMentionsOptions, type XMentionsResponse, type XSearchOptions, type XSearchResponse, type XSearchSource, type XTrendingResponse, type XTweet, type XTweetLookupResponse, type XTweetRepliesOptions, type XTweetRepliesResponse, type XTweetThreadResponse, type XTweetsResponse, type XUser, type XUserInfoResponse, type XUserLookupResponse, type XUserTweetsOptions, type XVerifiedFollowersResponse, clearCache, createPaymentPayload, createSolanaPaymentPayload, createSolanaWallet, createWallet, LLMClient as default, extractPaymentDetails, formatFundingMessageCompact, formatNeedsFundingMessage, formatWalletCreatedMessage, getCached, getCachedByRequest, getCostLogSummary, getCostSummary, getEip681Uri, getOrCreateSolanaWallet, getOrCreateWallet, getPaymentLinks, getWalletAddress, loadSolanaWallet, loadWallet, logCost, parsePaymentRequired, saveSolanaWallet, saveToCache, saveWallet, scanSolanaWallets, scanWallets, setCache, setupAgentSolanaWallet, setupAgentWallet, solanaClient, solanaKeyToBytes, solanaPublicKey, status, validateMaxTokens, validateModel, validateTemperature, validateTopP };
|
package/dist/index.d.ts
CHANGED
|
@@ -785,6 +785,11 @@ interface PriceClientOptions {
|
|
|
785
785
|
/** If false, construction succeeds without a wallet (free endpoints only). */
|
|
786
786
|
requireWallet?: boolean;
|
|
787
787
|
}
|
|
788
|
+
interface SurfClientOptions {
|
|
789
|
+
privateKey?: `0x${string}` | string;
|
|
790
|
+
apiUrl?: string;
|
|
791
|
+
timeout?: number;
|
|
792
|
+
}
|
|
788
793
|
declare class BlockrunError extends Error {
|
|
789
794
|
constructor(message: string);
|
|
790
795
|
}
|
|
@@ -1713,6 +1718,74 @@ declare class PriceClient {
|
|
|
1713
1718
|
private fetchWithTimeout;
|
|
1714
1719
|
}
|
|
1715
1720
|
|
|
1721
|
+
/**
|
|
1722
|
+
* BlockRun Surf Client — pay-per-call crypto data via x402 micropayments.
|
|
1723
|
+
*
|
|
1724
|
+
* Surf aggregates 84+ endpoints across CEX/DEX market data, on-chain SQL,
|
|
1725
|
+
* wallet intelligence, prediction markets, social analytics, and news under
|
|
1726
|
+
* a single OpenAPI surface mounted at `/api/v1/surf/*`.
|
|
1727
|
+
*
|
|
1728
|
+
* Pricing tiers (flat per-call, USDC on Base):
|
|
1729
|
+
* Tier 1 — $0.001/call (prices, rankings, lists, news, simple reads)
|
|
1730
|
+
* Tier 2 — $0.005/call (order books, candles, search, wallet details)
|
|
1731
|
+
* Tier 3 — $0.020/call (on-chain SQL, schema introspection, chat)
|
|
1732
|
+
*
|
|
1733
|
+
* Because the catalog is large and evolving, this client deliberately
|
|
1734
|
+
* exposes a thin `get` / `post` pair instead of 84 typed wrappers. Pass the
|
|
1735
|
+
* path (with or without the `/v1/surf` prefix) and either query params or a
|
|
1736
|
+
* JSON body. The full endpoint inventory lives at
|
|
1737
|
+
* https://blockrun.ai/marketplace/surf.
|
|
1738
|
+
*
|
|
1739
|
+
* Usage:
|
|
1740
|
+
* import { SurfClient } from "@blockrun/llm";
|
|
1741
|
+
*
|
|
1742
|
+
* const surf = new SurfClient({ privateKey: "0x..." });
|
|
1743
|
+
*
|
|
1744
|
+
* // Tier 1 — token price ($0.001)
|
|
1745
|
+
* const btc = await surf.get("/market/price", { symbol: "BTC" });
|
|
1746
|
+
*
|
|
1747
|
+
* // Tier 2 — order book ($0.005)
|
|
1748
|
+
* const book = await surf.get("/exchange/depth", {
|
|
1749
|
+
* exchange: "binance",
|
|
1750
|
+
* symbol: "BTC-USDT",
|
|
1751
|
+
* });
|
|
1752
|
+
*
|
|
1753
|
+
* // Tier 3 — raw on-chain SQL ($0.020)
|
|
1754
|
+
* const rows = await surf.post("/onchain/sql", {
|
|
1755
|
+
* query: "SELECT block_number FROM ethereum.blocks ORDER BY block_number DESC LIMIT 5",
|
|
1756
|
+
* });
|
|
1757
|
+
*
|
|
1758
|
+
* // Typed responses via generic
|
|
1759
|
+
* type Price = { symbol: string; price: number; timestamp: string };
|
|
1760
|
+
* const typed = await surf.get<Price>("/market/price", { symbol: "ETH" });
|
|
1761
|
+
*/
|
|
1762
|
+
|
|
1763
|
+
type QueryValue = string | number | boolean | null | undefined;
|
|
1764
|
+
type QueryParams = Record<string, QueryValue | QueryValue[]>;
|
|
1765
|
+
declare class SurfClient {
|
|
1766
|
+
private account;
|
|
1767
|
+
private privateKey;
|
|
1768
|
+
private apiUrl;
|
|
1769
|
+
private timeout;
|
|
1770
|
+
constructor(options?: SurfClientOptions);
|
|
1771
|
+
/**
|
|
1772
|
+
* GET a Surf endpoint. `path` is everything after `/v1/surf` (a leading
|
|
1773
|
+
* `/v1/surf` is tolerated and stripped). Query params are URL-encoded;
|
|
1774
|
+
* arrays become repeated keys (`?a=1&a=2`).
|
|
1775
|
+
*/
|
|
1776
|
+
get<T = unknown>(path: string, params?: QueryParams): Promise<T>;
|
|
1777
|
+
/**
|
|
1778
|
+
* POST a Surf endpoint with a JSON body. Same path normalization as `get`.
|
|
1779
|
+
*/
|
|
1780
|
+
post<T = unknown>(path: string, body?: Record<string, unknown>): Promise<T>;
|
|
1781
|
+
private buildUrl;
|
|
1782
|
+
private requestWithPayment;
|
|
1783
|
+
private handlePaymentAndRetry;
|
|
1784
|
+
private throwApiError;
|
|
1785
|
+
private fetchWithTimeout;
|
|
1786
|
+
getWalletAddress(): string;
|
|
1787
|
+
}
|
|
1788
|
+
|
|
1716
1789
|
/**
|
|
1717
1790
|
* x402 Payment Protocol v2 Implementation for BlockRun.
|
|
1718
1791
|
*
|
|
@@ -2356,4 +2429,4 @@ declare function validateTemperature(temperature?: number): void;
|
|
|
2356
2429
|
*/
|
|
2357
2430
|
declare function validateTopP(topP?: number): void;
|
|
2358
2431
|
|
|
2359
|
-
export { APIError, AnthropicClient, type AudioModel, type AudioTrack, BASE_CHAIN_ID, type BarResolution, type BlockRunAnthropicOptions, BlockrunError, type CallInitiatedResponse, type CallModel, type CallOptions, type CallStatusResponse, type ChatChoice, type ChatCompletionOptions, type ChatMessage, type ChatOptions, type ChatResponse, type ChatResponseWithCost, type ChatUsage, type CostEntry, type CostEstimate, type CreatePaymentOptions, type FunctionCall, type FunctionDefinition, type HistoryOptions, ImageClient, type ImageClientOptions, type ImageData, type ImageEditOptions, type ImageGenerateOptions, type ImageModel, type ImageResponse, KNOWN_PROVIDERS, LLMClient, type LLMClientOptions, type ListOptions, type MarketSession, type Model, MusicClient, type MusicClientOptions, type MusicGenerateOptions, type MusicResponse, type NewsSearchSource, OpenAI, type OpenAIChatCompletionChoice, type OpenAIChatCompletionChunk, type OpenAIChatCompletionParams, type OpenAIChatCompletionResponse, type OpenAIClientOptions, PaymentError, type PaymentLinks, type PriceBar, type PriceCategory, PriceClient, type PriceClientOptions, type PriceHistoryResponse, type PriceOptions, type PricePoint, type RoutingDecision, type RoutingProfile, type RoutingTier, type RssSearchSource, SOLANA_NETWORK, SOLANA_WALLET_FILE as SOLANA_WALLET_FILE_PATH, SearchClient, type SearchClientOptions, type SearchOptions, type SearchParameters, type SearchResult, type SearchSource, type SearchUsage, type SmartChatOptions, type SmartChatResponse, SolanaLLMClient, type SolanaLLMClientOptions, type SolanaWalletInfo, type Spending, type SpendingReport, type StockMarket, type SymbolListResponse, type Tool, type ToolCall, type ToolChoice, USDC_BASE, USDC_BASE_CONTRACT, USDC_SOLANA, VideoClient, type VideoClientOptions, type VideoClip, type VideoGenerateOptions, type VideoModel, type VideoResponse, VoiceClient, type VoiceClientOptions, type VoicePreset, WALLET_DIR_PATH, WALLET_FILE_PATH, type WalletInfo, type WebSearchSource, type XArticlesRisingResponse, type XAuthorAnalyticsResponse, XClient, type XClientOptions, type XCompareAuthorsResponse, type XFollower, type XFollowersResponse, type XFollowingsResponse, type XMentionsOptions, type XMentionsResponse, type XSearchOptions, type XSearchResponse, type XSearchSource, type XTrendingResponse, type XTweet, type XTweetLookupResponse, type XTweetRepliesOptions, type XTweetRepliesResponse, type XTweetThreadResponse, type XTweetsResponse, type XUser, type XUserInfoResponse, type XUserLookupResponse, type XUserTweetsOptions, type XVerifiedFollowersResponse, clearCache, createPaymentPayload, createSolanaPaymentPayload, createSolanaWallet, createWallet, LLMClient as default, extractPaymentDetails, formatFundingMessageCompact, formatNeedsFundingMessage, formatWalletCreatedMessage, getCached, getCachedByRequest, getCostLogSummary, getCostSummary, getEip681Uri, getOrCreateSolanaWallet, getOrCreateWallet, getPaymentLinks, getWalletAddress, loadSolanaWallet, loadWallet, logCost, parsePaymentRequired, saveSolanaWallet, saveToCache, saveWallet, scanSolanaWallets, scanWallets, setCache, setupAgentSolanaWallet, setupAgentWallet, solanaClient, solanaKeyToBytes, solanaPublicKey, status, validateMaxTokens, validateModel, validateTemperature, validateTopP };
|
|
2432
|
+
export { APIError, AnthropicClient, type AudioModel, type AudioTrack, BASE_CHAIN_ID, type BarResolution, type BlockRunAnthropicOptions, BlockrunError, type CallInitiatedResponse, type CallModel, type CallOptions, type CallStatusResponse, type ChatChoice, type ChatCompletionOptions, type ChatMessage, type ChatOptions, type ChatResponse, type ChatResponseWithCost, type ChatUsage, type CostEntry, type CostEstimate, type CreatePaymentOptions, type FunctionCall, type FunctionDefinition, type HistoryOptions, ImageClient, type ImageClientOptions, type ImageData, type ImageEditOptions, type ImageGenerateOptions, type ImageModel, type ImageResponse, KNOWN_PROVIDERS, LLMClient, type LLMClientOptions, type ListOptions, type MarketSession, type Model, MusicClient, type MusicClientOptions, type MusicGenerateOptions, type MusicResponse, type NewsSearchSource, OpenAI, type OpenAIChatCompletionChoice, type OpenAIChatCompletionChunk, type OpenAIChatCompletionParams, type OpenAIChatCompletionResponse, type OpenAIClientOptions, PaymentError, type PaymentLinks, type PriceBar, type PriceCategory, PriceClient, type PriceClientOptions, type PriceHistoryResponse, type PriceOptions, type PricePoint, type RoutingDecision, type RoutingProfile, type RoutingTier, type RssSearchSource, SOLANA_NETWORK, SOLANA_WALLET_FILE as SOLANA_WALLET_FILE_PATH, SearchClient, type SearchClientOptions, type SearchOptions, type SearchParameters, type SearchResult, type SearchSource, type SearchUsage, type SmartChatOptions, type SmartChatResponse, SolanaLLMClient, type SolanaLLMClientOptions, type SolanaWalletInfo, type Spending, type SpendingReport, type StockMarket, SurfClient, type SurfClientOptions, type SymbolListResponse, type Tool, type ToolCall, type ToolChoice, USDC_BASE, USDC_BASE_CONTRACT, USDC_SOLANA, VideoClient, type VideoClientOptions, type VideoClip, type VideoGenerateOptions, type VideoModel, type VideoResponse, VoiceClient, type VoiceClientOptions, type VoicePreset, WALLET_DIR_PATH, WALLET_FILE_PATH, type WalletInfo, type WebSearchSource, type XArticlesRisingResponse, type XAuthorAnalyticsResponse, XClient, type XClientOptions, type XCompareAuthorsResponse, type XFollower, type XFollowersResponse, type XFollowingsResponse, type XMentionsOptions, type XMentionsResponse, type XSearchOptions, type XSearchResponse, type XSearchSource, type XTrendingResponse, type XTweet, type XTweetLookupResponse, type XTweetRepliesOptions, type XTweetRepliesResponse, type XTweetThreadResponse, type XTweetsResponse, type XUser, type XUserInfoResponse, type XUserLookupResponse, type XUserTweetsOptions, type XVerifiedFollowersResponse, clearCache, createPaymentPayload, createSolanaPaymentPayload, createSolanaWallet, createWallet, LLMClient as default, extractPaymentDetails, formatFundingMessageCompact, formatNeedsFundingMessage, formatWalletCreatedMessage, getCached, getCachedByRequest, getCostLogSummary, getCostSummary, getEip681Uri, getOrCreateSolanaWallet, getOrCreateWallet, getPaymentLinks, getWalletAddress, loadSolanaWallet, loadWallet, logCost, parsePaymentRequired, saveSolanaWallet, saveToCache, saveWallet, scanSolanaWallets, scanWallets, setCache, setupAgentSolanaWallet, setupAgentWallet, solanaClient, solanaKeyToBytes, solanaPublicKey, status, validateMaxTokens, validateModel, validateTemperature, validateTopP };
|
package/dist/index.js
CHANGED
|
@@ -3215,8 +3215,163 @@ 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
|
+
|
|
3218
3373
|
// src/wallet.ts
|
|
3219
|
-
import { privateKeyToAccount as
|
|
3374
|
+
import { privateKeyToAccount as privateKeyToAccount10, generatePrivateKey } from "viem/accounts";
|
|
3220
3375
|
import * as fs2 from "fs";
|
|
3221
3376
|
import * as path2 from "path";
|
|
3222
3377
|
import * as os2 from "os";
|
|
@@ -3226,7 +3381,7 @@ var WALLET_DIR = path2.join(os2.homedir(), ".blockrun");
|
|
|
3226
3381
|
var WALLET_FILE = path2.join(WALLET_DIR, ".session");
|
|
3227
3382
|
function createWallet() {
|
|
3228
3383
|
const privateKey = generatePrivateKey();
|
|
3229
|
-
const account =
|
|
3384
|
+
const account = privateKeyToAccount10(privateKey);
|
|
3230
3385
|
return {
|
|
3231
3386
|
address: account.address,
|
|
3232
3387
|
privateKey
|
|
@@ -3282,12 +3437,12 @@ function loadWallet() {
|
|
|
3282
3437
|
function getOrCreateWallet() {
|
|
3283
3438
|
const envKey = typeof process !== "undefined" && process.env ? process.env.BLOCKRUN_WALLET_KEY || process.env.BASE_CHAIN_WALLET_KEY : void 0;
|
|
3284
3439
|
if (envKey) {
|
|
3285
|
-
const account =
|
|
3440
|
+
const account = privateKeyToAccount10(envKey);
|
|
3286
3441
|
return { address: account.address, privateKey: envKey, isNew: false };
|
|
3287
3442
|
}
|
|
3288
3443
|
const fileKey = loadWallet();
|
|
3289
3444
|
if (fileKey) {
|
|
3290
|
-
const account =
|
|
3445
|
+
const account = privateKeyToAccount10(fileKey);
|
|
3291
3446
|
return { address: account.address, privateKey: fileKey, isNew: false };
|
|
3292
3447
|
}
|
|
3293
3448
|
const { address, privateKey } = createWallet();
|
|
@@ -3297,11 +3452,11 @@ function getOrCreateWallet() {
|
|
|
3297
3452
|
function getWalletAddress() {
|
|
3298
3453
|
const envKey = typeof process !== "undefined" && process.env ? process.env.BLOCKRUN_WALLET_KEY || process.env.BASE_CHAIN_WALLET_KEY : void 0;
|
|
3299
3454
|
if (envKey) {
|
|
3300
|
-
return
|
|
3455
|
+
return privateKeyToAccount10(envKey).address;
|
|
3301
3456
|
}
|
|
3302
3457
|
const fileKey = loadWallet();
|
|
3303
3458
|
if (fileKey) {
|
|
3304
|
-
return
|
|
3459
|
+
return privateKeyToAccount10(fileKey).address;
|
|
3305
3460
|
}
|
|
3306
3461
|
return null;
|
|
3307
3462
|
}
|
|
@@ -3481,7 +3636,7 @@ async function getOrCreateSolanaWallet() {
|
|
|
3481
3636
|
// src/solana-client.ts
|
|
3482
3637
|
var SOLANA_API_URL = "https://sol.blockrun.ai/api";
|
|
3483
3638
|
var DEFAULT_MAX_TOKENS2 = 1024;
|
|
3484
|
-
var
|
|
3639
|
+
var DEFAULT_TIMEOUT10 = 6e4;
|
|
3485
3640
|
var SDK_VERSION2 = "0.3.0";
|
|
3486
3641
|
var USER_AGENT2 = `blockrun-ts/${SDK_VERSION2}`;
|
|
3487
3642
|
var SolanaLLMClient = class {
|
|
@@ -3506,7 +3661,7 @@ var SolanaLLMClient = class {
|
|
|
3506
3661
|
validateApiUrl(apiUrl);
|
|
3507
3662
|
this.apiUrl = apiUrl.replace(/\/$/, "");
|
|
3508
3663
|
this.rpcUrl = options.rpcUrl || "https://api.mainnet-beta.solana.com";
|
|
3509
|
-
this.timeout = options.timeout ||
|
|
3664
|
+
this.timeout = options.timeout || DEFAULT_TIMEOUT10;
|
|
3510
3665
|
}
|
|
3511
3666
|
/** Get Solana wallet address (public key in base58). */
|
|
3512
3667
|
async getWalletAddress() {
|
|
@@ -4413,7 +4568,7 @@ var OpenAI = class {
|
|
|
4413
4568
|
};
|
|
4414
4569
|
|
|
4415
4570
|
// src/anthropic-compat.ts
|
|
4416
|
-
import { privateKeyToAccount as
|
|
4571
|
+
import { privateKeyToAccount as privateKeyToAccount11 } from "viem/accounts";
|
|
4417
4572
|
var AnthropicClient = class {
|
|
4418
4573
|
_client = null;
|
|
4419
4574
|
_clientPromise = null;
|
|
@@ -4426,7 +4581,7 @@ var AnthropicClient = class {
|
|
|
4426
4581
|
const key = options.privateKey ?? wallet.privateKey;
|
|
4427
4582
|
validatePrivateKey(key);
|
|
4428
4583
|
this._privateKey = key;
|
|
4429
|
-
this._account =
|
|
4584
|
+
this._account = privateKeyToAccount11(this._privateKey);
|
|
4430
4585
|
const apiUrl = options.apiUrl ?? "https://blockrun.ai/api";
|
|
4431
4586
|
validateApiUrl(apiUrl);
|
|
4432
4587
|
this._apiUrl = apiUrl.replace(/\/$/, "");
|
|
@@ -4536,6 +4691,7 @@ export {
|
|
|
4536
4691
|
SOLANA_WALLET_FILE as SOLANA_WALLET_FILE_PATH,
|
|
4537
4692
|
SearchClient,
|
|
4538
4693
|
SolanaLLMClient,
|
|
4694
|
+
SurfClient,
|
|
4539
4695
|
USDC_BASE,
|
|
4540
4696
|
USDC_BASE_CONTRACT,
|
|
4541
4697
|
USDC_SOLANA,
|