@blockrun/llm 1.6.2 → 1.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.cjs CHANGED
@@ -37,16 +37,20 @@ __export(index_exports, {
37
37
  ImageClient: () => ImageClient,
38
38
  KNOWN_PROVIDERS: () => KNOWN_PROVIDERS,
39
39
  LLMClient: () => LLMClient,
40
+ MusicClient: () => MusicClient,
40
41
  OpenAI: () => OpenAI,
41
42
  PaymentError: () => PaymentError,
43
+ PriceClient: () => PriceClient,
42
44
  SOLANA_NETWORK: () => SOLANA_NETWORK,
43
45
  SOLANA_WALLET_FILE_PATH: () => SOLANA_WALLET_FILE,
46
+ SearchClient: () => SearchClient,
44
47
  SolanaLLMClient: () => SolanaLLMClient,
45
48
  USDC_BASE: () => USDC_BASE,
46
49
  USDC_BASE_CONTRACT: () => USDC_BASE_CONTRACT,
47
50
  USDC_SOLANA: () => USDC_SOLANA,
48
51
  WALLET_DIR_PATH: () => WALLET_DIR_PATH,
49
52
  WALLET_FILE_PATH: () => WALLET_FILE_PATH,
53
+ XClient: () => XClient,
50
54
  clearCache: () => clearCache,
51
55
  createPaymentPayload: () => createPaymentPayload,
52
56
  createSolanaPaymentPayload: () => createSolanaPaymentPayload,
@@ -1228,7 +1232,10 @@ var LLMClient = class _LLMClient {
1228
1232
  contextWindow: m.contextWindow ?? m.context_window ?? 0,
1229
1233
  maxOutput: m.maxOutput ?? m.max_output ?? 0,
1230
1234
  categories: m.categories || [],
1231
- available: true
1235
+ available: true,
1236
+ billingMode: m.billingMode ?? m.billing_mode,
1237
+ flatPrice: m.flatPrice ?? m.flat_price ?? m.pricing?.flat,
1238
+ hidden: m.hidden
1232
1239
  }));
1233
1240
  }
1234
1241
  /**
@@ -1898,8 +1905,703 @@ var ImageClient = class {
1898
1905
  }
1899
1906
  };
1900
1907
 
1901
- // src/wallet.ts
1908
+ // src/music.ts
1902
1909
  var import_accounts4 = require("viem/accounts");
1910
+ var DEFAULT_API_URL3 = "https://blockrun.ai/api";
1911
+ var DEFAULT_MODEL2 = "minimax/music-2.5+";
1912
+ var DEFAULT_TIMEOUT3 = 21e4;
1913
+ var MusicClient = class {
1914
+ account;
1915
+ privateKey;
1916
+ apiUrl;
1917
+ timeout;
1918
+ sessionTotalUsd = 0;
1919
+ sessionCalls = 0;
1920
+ constructor(options = {}) {
1921
+ const envKey = typeof process !== "undefined" && process.env ? process.env.BLOCKRUN_WALLET_KEY || process.env.BASE_CHAIN_WALLET_KEY : void 0;
1922
+ const privateKey = options.privateKey || envKey;
1923
+ if (!privateKey) {
1924
+ throw new Error(
1925
+ "Private key required. Pass privateKey in options or set BLOCKRUN_WALLET_KEY environment variable."
1926
+ );
1927
+ }
1928
+ validatePrivateKey(privateKey);
1929
+ this.privateKey = privateKey;
1930
+ this.account = (0, import_accounts4.privateKeyToAccount)(privateKey);
1931
+ const apiUrl = options.apiUrl || DEFAULT_API_URL3;
1932
+ validateApiUrl(apiUrl);
1933
+ this.apiUrl = apiUrl.replace(/\/$/, "");
1934
+ this.timeout = options.timeout || DEFAULT_TIMEOUT3;
1935
+ }
1936
+ /**
1937
+ * Generate a music track from a text prompt.
1938
+ *
1939
+ * Takes 1-3 minutes. Returns a CDN URL valid for ~24h.
1940
+ *
1941
+ * @param prompt - Music style, mood, or description
1942
+ * @param options - Optional generation parameters
1943
+ * @returns MusicResponse with track URL and metadata
1944
+ *
1945
+ * @example
1946
+ * const result = await client.generate('chill lo-fi beats with piano');
1947
+ * console.log(result.data[0].url); // Download this URL — expires in 24h
1948
+ *
1949
+ * @example With lyrics
1950
+ * const result = await client.generate('upbeat pop song', {
1951
+ * instrumental: false,
1952
+ * lyrics: 'Hello world, this is my song...'
1953
+ * });
1954
+ */
1955
+ async generate(prompt, options) {
1956
+ const instrumental = options?.instrumental ?? true;
1957
+ const lyrics = options?.lyrics?.trim();
1958
+ if (instrumental && lyrics) {
1959
+ throw new Error("Cannot specify lyrics when instrumental is true");
1960
+ }
1961
+ const body = {
1962
+ model: options?.model || DEFAULT_MODEL2,
1963
+ prompt,
1964
+ instrumental
1965
+ };
1966
+ if (lyrics) body.lyrics = lyrics;
1967
+ return this.requestWithPayment("/v1/audio/generations", body);
1968
+ }
1969
+ async requestWithPayment(endpoint, body) {
1970
+ const url = `${this.apiUrl}${endpoint}`;
1971
+ const response = await this.fetchWithTimeout(url, {
1972
+ method: "POST",
1973
+ headers: { "Content-Type": "application/json" },
1974
+ body: JSON.stringify(body)
1975
+ });
1976
+ if (response.status === 402) {
1977
+ return this.handlePaymentAndRetry(url, body, response);
1978
+ }
1979
+ if (!response.ok) {
1980
+ let errorBody;
1981
+ try {
1982
+ errorBody = await response.json();
1983
+ } catch {
1984
+ errorBody = { error: "Request failed" };
1985
+ }
1986
+ throw new APIError(`API error: ${response.status}`, response.status, sanitizeErrorResponse(errorBody));
1987
+ }
1988
+ return response.json();
1989
+ }
1990
+ async handlePaymentAndRetry(url, body, response) {
1991
+ let paymentHeader = response.headers.get("payment-required");
1992
+ if (!paymentHeader) {
1993
+ try {
1994
+ const respBody = await response.json();
1995
+ if (respBody.x402 || respBody.accepts) {
1996
+ paymentHeader = btoa(JSON.stringify(respBody));
1997
+ }
1998
+ } catch {
1999
+ }
2000
+ }
2001
+ if (!paymentHeader) {
2002
+ throw new PaymentError("402 response but no payment requirements found");
2003
+ }
2004
+ const paymentRequired = parsePaymentRequired(paymentHeader);
2005
+ const details = extractPaymentDetails(paymentRequired);
2006
+ const paymentPayload = await createPaymentPayload(
2007
+ this.privateKey,
2008
+ this.account.address,
2009
+ details.recipient,
2010
+ details.amount,
2011
+ details.network || "eip155:8453",
2012
+ {
2013
+ resourceUrl: details.resource?.url || `${this.apiUrl}/v1/audio/generations`,
2014
+ resourceDescription: details.resource?.description || "BlockRun Music Generation",
2015
+ maxTimeoutSeconds: details.maxTimeoutSeconds || 300,
2016
+ extra: details.extra
2017
+ }
2018
+ );
2019
+ const retryResponse = await this.fetchWithTimeout(url, {
2020
+ method: "POST",
2021
+ headers: {
2022
+ "Content-Type": "application/json",
2023
+ "PAYMENT-SIGNATURE": paymentPayload
2024
+ },
2025
+ body: JSON.stringify(body)
2026
+ });
2027
+ if (retryResponse.status === 402) {
2028
+ throw new PaymentError("Payment was rejected. Check your wallet balance.");
2029
+ }
2030
+ if (!retryResponse.ok) {
2031
+ let errorBody;
2032
+ try {
2033
+ errorBody = await retryResponse.json();
2034
+ } catch {
2035
+ errorBody = { error: "Request failed" };
2036
+ }
2037
+ throw new APIError(`API error after payment: ${retryResponse.status}`, retryResponse.status, sanitizeErrorResponse(errorBody));
2038
+ }
2039
+ const data = await retryResponse.json();
2040
+ this.sessionCalls++;
2041
+ this.sessionTotalUsd += 0.1575;
2042
+ const txHash = retryResponse.headers.get("x-payment-receipt") || retryResponse.headers.get("X-Payment-Receipt");
2043
+ if (txHash) data.txHash = txHash;
2044
+ return data;
2045
+ }
2046
+ async fetchWithTimeout(url, options) {
2047
+ const controller = new AbortController();
2048
+ const timeoutId = setTimeout(() => controller.abort(), this.timeout);
2049
+ try {
2050
+ return await fetch(url, { ...options, signal: controller.signal });
2051
+ } finally {
2052
+ clearTimeout(timeoutId);
2053
+ }
2054
+ }
2055
+ getWalletAddress() {
2056
+ return this.account.address;
2057
+ }
2058
+ getSpending() {
2059
+ return { totalUsd: this.sessionTotalUsd, calls: this.sessionCalls };
2060
+ }
2061
+ };
2062
+
2063
+ // src/search.ts
2064
+ var import_accounts5 = require("viem/accounts");
2065
+ var DEFAULT_API_URL4 = "https://blockrun.ai/api";
2066
+ var DEFAULT_TIMEOUT4 = 6e4;
2067
+ var SearchClient = class {
2068
+ account;
2069
+ privateKey;
2070
+ apiUrl;
2071
+ timeout;
2072
+ constructor(options = {}) {
2073
+ const envKey = typeof process !== "undefined" && process.env ? process.env.BLOCKRUN_WALLET_KEY || process.env.BASE_CHAIN_WALLET_KEY : void 0;
2074
+ const privateKey = options.privateKey || envKey;
2075
+ if (!privateKey) {
2076
+ throw new Error(
2077
+ "Private key required. Pass privateKey in options or set BLOCKRUN_WALLET_KEY environment variable."
2078
+ );
2079
+ }
2080
+ validatePrivateKey(privateKey);
2081
+ this.privateKey = privateKey;
2082
+ this.account = (0, import_accounts5.privateKeyToAccount)(privateKey);
2083
+ const apiUrl = options.apiUrl || DEFAULT_API_URL4;
2084
+ validateApiUrl(apiUrl);
2085
+ this.apiUrl = apiUrl.replace(/\/$/, "");
2086
+ this.timeout = options.timeout || DEFAULT_TIMEOUT4;
2087
+ }
2088
+ async search(query, options) {
2089
+ if (!query || query.length > 1e3) {
2090
+ throw new Error("query must be 1-1000 characters");
2091
+ }
2092
+ const maxResults = options?.maxResults ?? 10;
2093
+ if (maxResults < 1 || maxResults > 50) {
2094
+ throw new Error("maxResults must be between 1 and 50");
2095
+ }
2096
+ const body = {
2097
+ query,
2098
+ max_results: maxResults
2099
+ };
2100
+ if (options?.sources) body.sources = options.sources;
2101
+ if (options?.fromDate) body.from_date = options.fromDate;
2102
+ if (options?.toDate) body.to_date = options.toDate;
2103
+ return this.requestWithPayment("/v1/search", body);
2104
+ }
2105
+ async requestWithPayment(endpoint, body) {
2106
+ const url = `${this.apiUrl}${endpoint}`;
2107
+ const response = await this.fetchWithTimeout(url, {
2108
+ method: "POST",
2109
+ headers: { "Content-Type": "application/json" },
2110
+ body: JSON.stringify(body)
2111
+ });
2112
+ if (response.status === 402) {
2113
+ return this.handlePaymentAndRetry(url, body, response);
2114
+ }
2115
+ if (!response.ok) {
2116
+ let errorBody;
2117
+ try {
2118
+ errorBody = await response.json();
2119
+ } catch {
2120
+ errorBody = { error: "Request failed" };
2121
+ }
2122
+ throw new APIError(
2123
+ `API error: ${response.status}`,
2124
+ response.status,
2125
+ sanitizeErrorResponse(errorBody)
2126
+ );
2127
+ }
2128
+ return response.json();
2129
+ }
2130
+ async handlePaymentAndRetry(url, body, response) {
2131
+ let paymentHeader = response.headers.get("payment-required");
2132
+ if (!paymentHeader) {
2133
+ try {
2134
+ const respBody = await response.json();
2135
+ if (respBody.x402 || respBody.accepts) {
2136
+ paymentHeader = btoa(JSON.stringify(respBody));
2137
+ }
2138
+ } catch {
2139
+ }
2140
+ }
2141
+ if (!paymentHeader) {
2142
+ throw new PaymentError("402 response but no payment requirements found");
2143
+ }
2144
+ const paymentRequired = parsePaymentRequired(paymentHeader);
2145
+ const details = extractPaymentDetails(paymentRequired);
2146
+ const paymentPayload = await createPaymentPayload(
2147
+ this.privateKey,
2148
+ this.account.address,
2149
+ details.recipient,
2150
+ details.amount,
2151
+ details.network || "eip155:8453",
2152
+ {
2153
+ resourceUrl: details.resource?.url || url,
2154
+ resourceDescription: details.resource?.description || "BlockRun Search",
2155
+ maxTimeoutSeconds: details.maxTimeoutSeconds || 300,
2156
+ extra: details.extra
2157
+ }
2158
+ );
2159
+ const retry = await this.fetchWithTimeout(url, {
2160
+ method: "POST",
2161
+ headers: {
2162
+ "Content-Type": "application/json",
2163
+ "PAYMENT-SIGNATURE": paymentPayload
2164
+ },
2165
+ body: JSON.stringify(body)
2166
+ });
2167
+ if (retry.status === 402) {
2168
+ throw new PaymentError("Payment was rejected. Check your wallet balance.");
2169
+ }
2170
+ if (!retry.ok) {
2171
+ let errorBody;
2172
+ try {
2173
+ errorBody = await retry.json();
2174
+ } catch {
2175
+ errorBody = { error: "Request failed" };
2176
+ }
2177
+ throw new APIError(
2178
+ `API error after payment: ${retry.status}`,
2179
+ retry.status,
2180
+ sanitizeErrorResponse(errorBody)
2181
+ );
2182
+ }
2183
+ return retry.json();
2184
+ }
2185
+ async fetchWithTimeout(url, init) {
2186
+ const controller = new AbortController();
2187
+ const timeoutId = setTimeout(() => controller.abort(), this.timeout);
2188
+ try {
2189
+ return await fetch(url, { ...init, signal: controller.signal });
2190
+ } finally {
2191
+ clearTimeout(timeoutId);
2192
+ }
2193
+ }
2194
+ getWalletAddress() {
2195
+ return this.account.address;
2196
+ }
2197
+ };
2198
+
2199
+ // src/x-client.ts
2200
+ var import_accounts6 = require("viem/accounts");
2201
+ var DEFAULT_API_URL5 = "https://blockrun.ai/api";
2202
+ var DEFAULT_TIMEOUT5 = 6e4;
2203
+ var XClient = class {
2204
+ account;
2205
+ privateKey;
2206
+ apiUrl;
2207
+ timeout;
2208
+ constructor(options = {}) {
2209
+ const envKey = typeof process !== "undefined" && process.env ? process.env.BLOCKRUN_WALLET_KEY || process.env.BASE_CHAIN_WALLET_KEY : void 0;
2210
+ const privateKey = options.privateKey || envKey;
2211
+ if (!privateKey) {
2212
+ throw new Error(
2213
+ "Private key required. Pass privateKey in options or set BLOCKRUN_WALLET_KEY environment variable."
2214
+ );
2215
+ }
2216
+ validatePrivateKey(privateKey);
2217
+ this.privateKey = privateKey;
2218
+ this.account = (0, import_accounts6.privateKeyToAccount)(privateKey);
2219
+ const apiUrl = options.apiUrl || DEFAULT_API_URL5;
2220
+ validateApiUrl(apiUrl);
2221
+ this.apiUrl = apiUrl.replace(/\/$/, "");
2222
+ this.timeout = options.timeout || DEFAULT_TIMEOUT5;
2223
+ }
2224
+ // ───────── User endpoints ─────────
2225
+ userLookup(usernames) {
2226
+ return this.post("/v1/x/users/lookup", { usernames });
2227
+ }
2228
+ userInfo(username) {
2229
+ return this.post("/v1/x/users/info", { username });
2230
+ }
2231
+ followers(username, cursor) {
2232
+ const body = { username };
2233
+ if (cursor) body.cursor = cursor;
2234
+ return this.post("/v1/x/users/followers", body);
2235
+ }
2236
+ /** `/v1/x/users/following` (singular path variant). */
2237
+ following(username, cursor) {
2238
+ const body = { username };
2239
+ if (cursor) body.cursor = cursor;
2240
+ return this.post("/v1/x/users/following", body);
2241
+ }
2242
+ /** `/v1/x/users/followings` (plural path variant). */
2243
+ followings(username, cursor) {
2244
+ const body = { username };
2245
+ if (cursor) body.cursor = cursor;
2246
+ return this.post("/v1/x/users/followings", body);
2247
+ }
2248
+ verifiedFollowers(userId, cursor) {
2249
+ const body = { userId };
2250
+ if (cursor) body.cursor = cursor;
2251
+ return this.post(
2252
+ "/v1/x/users/verified-followers",
2253
+ body
2254
+ );
2255
+ }
2256
+ userTweets(options) {
2257
+ if (!options.username && !options.userId) {
2258
+ throw new Error("Either username or userId is required");
2259
+ }
2260
+ const body = {};
2261
+ if (options.username) body.username = options.username;
2262
+ if (options.userId) body.userId = options.userId;
2263
+ if (options.cursor) body.cursor = options.cursor;
2264
+ if (options.includeReplies !== void 0) body.includeReplies = options.includeReplies;
2265
+ return this.post("/v1/x/users/tweets", body);
2266
+ }
2267
+ mentions(username, options) {
2268
+ const body = { username };
2269
+ if (options?.sinceTime) body.sinceTime = options.sinceTime;
2270
+ if (options?.untilTime) body.untilTime = options.untilTime;
2271
+ if (options?.cursor) body.cursor = options.cursor;
2272
+ return this.post("/v1/x/users/mentions", body);
2273
+ }
2274
+ // ───────── Tweet endpoints ─────────
2275
+ tweetLookup(tweetIds) {
2276
+ return this.post("/v1/x/tweets/lookup", {
2277
+ tweet_ids: tweetIds
2278
+ });
2279
+ }
2280
+ tweetReplies(tweetId, options) {
2281
+ const body = { tweetId };
2282
+ if (options?.cursor) body.cursor = options.cursor;
2283
+ if (options?.queryType) body.queryType = options.queryType;
2284
+ return this.post("/v1/x/tweets/replies", body);
2285
+ }
2286
+ tweetThread(tweetId, cursor) {
2287
+ const body = { tweetId };
2288
+ if (cursor) body.cursor = cursor;
2289
+ return this.post("/v1/x/tweets/thread", body);
2290
+ }
2291
+ // ───────── Search & discovery ─────────
2292
+ search(query, options) {
2293
+ const body = { query };
2294
+ if (options?.queryType) body.queryType = options.queryType;
2295
+ if (options?.cursor) body.cursor = options.cursor;
2296
+ return this.post("/v1/x/search", body);
2297
+ }
2298
+ trending() {
2299
+ return this.post("/v1/x/trending", {});
2300
+ }
2301
+ articlesRising() {
2302
+ return this.post("/v1/x/articles/rising", {});
2303
+ }
2304
+ // ───────── Internals ─────────
2305
+ async post(endpoint, body) {
2306
+ const url = `${this.apiUrl}${endpoint}`;
2307
+ const response = await this.fetchWithTimeout(url, {
2308
+ method: "POST",
2309
+ headers: { "Content-Type": "application/json" },
2310
+ body: JSON.stringify(body)
2311
+ });
2312
+ if (response.status === 402) {
2313
+ return this.payAndRetry(url, body, response);
2314
+ }
2315
+ if (!response.ok) {
2316
+ let errorBody;
2317
+ try {
2318
+ errorBody = await response.json();
2319
+ } catch {
2320
+ errorBody = { error: "Request failed" };
2321
+ }
2322
+ throw new APIError(
2323
+ `API error: ${response.status}`,
2324
+ response.status,
2325
+ sanitizeErrorResponse(errorBody)
2326
+ );
2327
+ }
2328
+ return response.json();
2329
+ }
2330
+ async payAndRetry(url, body, response) {
2331
+ let paymentHeader = response.headers.get("payment-required");
2332
+ if (!paymentHeader) {
2333
+ try {
2334
+ const respBody = await response.json();
2335
+ if (respBody.x402 || respBody.accepts) {
2336
+ paymentHeader = btoa(JSON.stringify(respBody));
2337
+ }
2338
+ } catch {
2339
+ }
2340
+ }
2341
+ if (!paymentHeader) {
2342
+ throw new PaymentError("402 response but no payment requirements found");
2343
+ }
2344
+ const paymentRequired = parsePaymentRequired(paymentHeader);
2345
+ const details = extractPaymentDetails(paymentRequired);
2346
+ const paymentPayload = await createPaymentPayload(
2347
+ this.privateKey,
2348
+ this.account.address,
2349
+ details.recipient,
2350
+ details.amount,
2351
+ details.network || "eip155:8453",
2352
+ {
2353
+ resourceUrl: details.resource?.url || url,
2354
+ resourceDescription: details.resource?.description || "BlockRun X API",
2355
+ maxTimeoutSeconds: details.maxTimeoutSeconds || 300,
2356
+ extra: details.extra
2357
+ }
2358
+ );
2359
+ const retry = await this.fetchWithTimeout(url, {
2360
+ method: "POST",
2361
+ headers: {
2362
+ "Content-Type": "application/json",
2363
+ "PAYMENT-SIGNATURE": paymentPayload
2364
+ },
2365
+ body: JSON.stringify(body)
2366
+ });
2367
+ if (retry.status === 402) {
2368
+ throw new PaymentError("Payment was rejected. Check your wallet balance.");
2369
+ }
2370
+ if (!retry.ok) {
2371
+ let errorBody;
2372
+ try {
2373
+ errorBody = await retry.json();
2374
+ } catch {
2375
+ errorBody = { error: "Request failed" };
2376
+ }
2377
+ throw new APIError(
2378
+ `API error after payment: ${retry.status}`,
2379
+ retry.status,
2380
+ sanitizeErrorResponse(errorBody)
2381
+ );
2382
+ }
2383
+ return retry.json();
2384
+ }
2385
+ async fetchWithTimeout(url, init) {
2386
+ const controller = new AbortController();
2387
+ const timeoutId = setTimeout(() => controller.abort(), this.timeout);
2388
+ try {
2389
+ return await fetch(url, { ...init, signal: controller.signal });
2390
+ } finally {
2391
+ clearTimeout(timeoutId);
2392
+ }
2393
+ }
2394
+ getWalletAddress() {
2395
+ return this.account.address;
2396
+ }
2397
+ };
2398
+
2399
+ // src/price.ts
2400
+ var import_accounts7 = require("viem/accounts");
2401
+ var DEFAULT_API_URL6 = "https://blockrun.ai/api";
2402
+ var DEFAULT_TIMEOUT6 = 3e4;
2403
+ var PriceClient = class {
2404
+ account = null;
2405
+ privateKey = null;
2406
+ apiUrl;
2407
+ timeout;
2408
+ constructor(options = {}) {
2409
+ const envKey = typeof process !== "undefined" && process.env ? process.env.BLOCKRUN_WALLET_KEY || process.env.BASE_CHAIN_WALLET_KEY : void 0;
2410
+ const privateKey = options.privateKey || envKey;
2411
+ const requireWallet = options.requireWallet ?? true;
2412
+ if (!privateKey && requireWallet) {
2413
+ throw new Error(
2414
+ "Private key required for paid endpoints. Pass privateKey in options, set BLOCKRUN_WALLET_KEY, or pass requireWallet: false for free-only usage."
2415
+ );
2416
+ }
2417
+ if (privateKey) {
2418
+ validatePrivateKey(privateKey);
2419
+ this.privateKey = privateKey;
2420
+ this.account = (0, import_accounts7.privateKeyToAccount)(privateKey);
2421
+ }
2422
+ const apiUrl = options.apiUrl || DEFAULT_API_URL6;
2423
+ validateApiUrl(apiUrl);
2424
+ this.apiUrl = apiUrl.replace(/\/$/, "");
2425
+ this.timeout = options.timeout || DEFAULT_TIMEOUT6;
2426
+ }
2427
+ async price(category, symbol, options) {
2428
+ if (!symbol) throw new Error("symbol is required");
2429
+ const path5 = categoryPath(category, options?.market, "price", symbol);
2430
+ const query = {};
2431
+ if (options?.session) query.session = options.session;
2432
+ const data = await this.getWithPayment(path5, query);
2433
+ return {
2434
+ symbol: data.symbol ?? symbol.toUpperCase(),
2435
+ price: data.price,
2436
+ publishTime: data.publishTime,
2437
+ confidence: data.confidence,
2438
+ feedId: data.feedId,
2439
+ timestamp: data.timestamp,
2440
+ assetType: data.assetType,
2441
+ category: data.category,
2442
+ source: data.source,
2443
+ free: data.free
2444
+ };
2445
+ }
2446
+ async history(category, symbol, options) {
2447
+ if (!symbol) throw new Error("symbol is required");
2448
+ if (!options.from || options.from <= 0) {
2449
+ throw new Error("history requires options.from (unix seconds)");
2450
+ }
2451
+ const path5 = categoryPath(category, options.market, "history", symbol);
2452
+ const query = {
2453
+ resolution: options.resolution ?? "D",
2454
+ from: String(options.from)
2455
+ };
2456
+ if (options.to) query.to = String(options.to);
2457
+ if (options.session) query.session = options.session;
2458
+ const data = await this.getWithPayment(path5, query);
2459
+ return {
2460
+ symbol: data.symbol ?? symbol.toUpperCase(),
2461
+ resolution: data.resolution ?? (options.resolution ?? "D"),
2462
+ from: data.from,
2463
+ to: data.to,
2464
+ bars: data.bars ?? [],
2465
+ source: data.source,
2466
+ category: data.category
2467
+ };
2468
+ }
2469
+ async listSymbols(category, options) {
2470
+ const path5 = categoryPath(category, options?.market, "list");
2471
+ const query = {
2472
+ limit: String(options?.limit && options.limit > 0 ? options.limit : 100)
2473
+ };
2474
+ if (options?.query) query.q = options.query;
2475
+ const data = await this.getWithPayment(path5, query);
2476
+ if (Array.isArray(data)) {
2477
+ return { symbols: data, count: data.length };
2478
+ }
2479
+ const obj = data;
2480
+ const symbols = obj.symbols ?? obj.feeds ?? [];
2481
+ return {
2482
+ symbols,
2483
+ count: obj.count ?? symbols.length
2484
+ };
2485
+ }
2486
+ getWalletAddress() {
2487
+ return this.account?.address ?? null;
2488
+ }
2489
+ async getWithPayment(endpoint, query) {
2490
+ const url = buildUrl(`${this.apiUrl}${endpoint}`, query);
2491
+ const response = await this.fetchWithTimeout(url, { method: "GET" });
2492
+ if (response.status === 402) {
2493
+ if (!this.privateKey || !this.account) {
2494
+ throw new PaymentError(
2495
+ `${endpoint} returned 402 Payment Required but no wallet is configured.`
2496
+ );
2497
+ }
2498
+ return this.payAndRetry(url, response);
2499
+ }
2500
+ if (!response.ok) {
2501
+ let errorBody;
2502
+ try {
2503
+ errorBody = await response.json();
2504
+ } catch {
2505
+ errorBody = { error: "Request failed" };
2506
+ }
2507
+ throw new APIError(
2508
+ `API error: ${response.status}`,
2509
+ response.status,
2510
+ sanitizeErrorResponse(errorBody)
2511
+ );
2512
+ }
2513
+ return response.json();
2514
+ }
2515
+ async payAndRetry(url, response) {
2516
+ if (!this.privateKey || !this.account) {
2517
+ throw new PaymentError("Wallet required to sign payment.");
2518
+ }
2519
+ let paymentHeader = response.headers.get("payment-required");
2520
+ if (!paymentHeader) {
2521
+ try {
2522
+ const respBody = await response.json();
2523
+ if (respBody.x402) {
2524
+ paymentHeader = btoa(JSON.stringify(respBody.x402));
2525
+ } else if (respBody.accepts) {
2526
+ paymentHeader = btoa(JSON.stringify(respBody));
2527
+ }
2528
+ } catch {
2529
+ }
2530
+ }
2531
+ if (!paymentHeader) {
2532
+ throw new PaymentError("402 response but no payment requirements found");
2533
+ }
2534
+ const paymentRequired = parsePaymentRequired(paymentHeader);
2535
+ const details = extractPaymentDetails(paymentRequired);
2536
+ const paymentPayload = await createPaymentPayload(
2537
+ this.privateKey,
2538
+ this.account.address,
2539
+ details.recipient,
2540
+ details.amount,
2541
+ details.network || "eip155:8453",
2542
+ {
2543
+ resourceUrl: details.resource?.url || url,
2544
+ resourceDescription: details.resource?.description || "BlockRun Price Data",
2545
+ maxTimeoutSeconds: details.maxTimeoutSeconds || 300,
2546
+ extra: details.extra
2547
+ }
2548
+ );
2549
+ const retry = await this.fetchWithTimeout(url, {
2550
+ method: "GET",
2551
+ headers: { "PAYMENT-SIGNATURE": paymentPayload }
2552
+ });
2553
+ if (retry.status === 402) {
2554
+ throw new PaymentError("Payment was rejected. Check your wallet balance.");
2555
+ }
2556
+ if (!retry.ok) {
2557
+ let errorBody;
2558
+ try {
2559
+ errorBody = await retry.json();
2560
+ } catch {
2561
+ errorBody = { error: "Request failed" };
2562
+ }
2563
+ throw new APIError(
2564
+ `API error after payment: ${retry.status}`,
2565
+ retry.status,
2566
+ sanitizeErrorResponse(errorBody)
2567
+ );
2568
+ }
2569
+ return retry.json();
2570
+ }
2571
+ async fetchWithTimeout(url, init) {
2572
+ const controller = new AbortController();
2573
+ const timeoutId = setTimeout(() => controller.abort(), this.timeout);
2574
+ try {
2575
+ return await fetch(url, { ...init, signal: controller.signal });
2576
+ } finally {
2577
+ clearTimeout(timeoutId);
2578
+ }
2579
+ }
2580
+ };
2581
+ function categoryPath(category, market, kind, symbol) {
2582
+ let base;
2583
+ if (category === "stocks") {
2584
+ if (!market) {
2585
+ throw new Error("market is required when category === 'stocks'");
2586
+ }
2587
+ base = `/v1/stocks/${market}`;
2588
+ } else if (["crypto", "fx", "commodity", "usstock"].includes(category)) {
2589
+ base = `/v1/${category}`;
2590
+ } else {
2591
+ throw new Error(`unknown category: ${category}`);
2592
+ }
2593
+ if (!symbol) return `${base}/${kind}`;
2594
+ return `${base}/${kind}/${encodeURIComponent(symbol.toUpperCase())}`;
2595
+ }
2596
+ function buildUrl(base, query) {
2597
+ const params = Object.entries(query);
2598
+ if (params.length === 0) return base;
2599
+ const qs = params.map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(v)}`).join("&");
2600
+ return `${base}?${qs}`;
2601
+ }
2602
+
2603
+ // src/wallet.ts
2604
+ var import_accounts8 = require("viem/accounts");
1903
2605
  var fs = __toESM(require("fs"), 1);
1904
2606
  var path = __toESM(require("path"), 1);
1905
2607
  var os = __toESM(require("os"), 1);
@@ -1908,8 +2610,8 @@ var BASE_CHAIN_ID2 = "8453";
1908
2610
  var WALLET_DIR = path.join(os.homedir(), ".blockrun");
1909
2611
  var WALLET_FILE = path.join(WALLET_DIR, ".session");
1910
2612
  function createWallet() {
1911
- const privateKey = (0, import_accounts4.generatePrivateKey)();
1912
- const account = (0, import_accounts4.privateKeyToAccount)(privateKey);
2613
+ const privateKey = (0, import_accounts8.generatePrivateKey)();
2614
+ const account = (0, import_accounts8.privateKeyToAccount)(privateKey);
1913
2615
  return {
1914
2616
  address: account.address,
1915
2617
  privateKey
@@ -1965,12 +2667,12 @@ function loadWallet() {
1965
2667
  function getOrCreateWallet() {
1966
2668
  const envKey = typeof process !== "undefined" && process.env ? process.env.BLOCKRUN_WALLET_KEY || process.env.BASE_CHAIN_WALLET_KEY : void 0;
1967
2669
  if (envKey) {
1968
- const account = (0, import_accounts4.privateKeyToAccount)(envKey);
2670
+ const account = (0, import_accounts8.privateKeyToAccount)(envKey);
1969
2671
  return { address: account.address, privateKey: envKey, isNew: false };
1970
2672
  }
1971
2673
  const fileKey = loadWallet();
1972
2674
  if (fileKey) {
1973
- const account = (0, import_accounts4.privateKeyToAccount)(fileKey);
2675
+ const account = (0, import_accounts8.privateKeyToAccount)(fileKey);
1974
2676
  return { address: account.address, privateKey: fileKey, isNew: false };
1975
2677
  }
1976
2678
  const { address, privateKey } = createWallet();
@@ -1980,11 +2682,11 @@ function getOrCreateWallet() {
1980
2682
  function getWalletAddress() {
1981
2683
  const envKey = typeof process !== "undefined" && process.env ? process.env.BLOCKRUN_WALLET_KEY || process.env.BASE_CHAIN_WALLET_KEY : void 0;
1982
2684
  if (envKey) {
1983
- return (0, import_accounts4.privateKeyToAccount)(envKey).address;
2685
+ return (0, import_accounts8.privateKeyToAccount)(envKey).address;
1984
2686
  }
1985
2687
  const fileKey = loadWallet();
1986
2688
  if (fileKey) {
1987
- return (0, import_accounts4.privateKeyToAccount)(fileKey).address;
2689
+ return (0, import_accounts8.privateKeyToAccount)(fileKey).address;
1988
2690
  }
1989
2691
  return null;
1990
2692
  }
@@ -2164,7 +2866,7 @@ async function getOrCreateSolanaWallet() {
2164
2866
  // src/solana-client.ts
2165
2867
  var SOLANA_API_URL = "https://sol.blockrun.ai/api";
2166
2868
  var DEFAULT_MAX_TOKENS2 = 1024;
2167
- var DEFAULT_TIMEOUT3 = 6e4;
2869
+ var DEFAULT_TIMEOUT7 = 6e4;
2168
2870
  var SDK_VERSION2 = "0.3.0";
2169
2871
  var USER_AGENT2 = `blockrun-ts/${SDK_VERSION2}`;
2170
2872
  var SolanaLLMClient = class {
@@ -2189,7 +2891,7 @@ var SolanaLLMClient = class {
2189
2891
  validateApiUrl(apiUrl);
2190
2892
  this.apiUrl = apiUrl.replace(/\/$/, "");
2191
2893
  this.rpcUrl = options.rpcUrl || "https://api.mainnet-beta.solana.com";
2192
- this.timeout = options.timeout || DEFAULT_TIMEOUT3;
2894
+ this.timeout = options.timeout || DEFAULT_TIMEOUT7;
2193
2895
  }
2194
2896
  /** Get Solana wallet address (public key in base58). */
2195
2897
  async getWalletAddress() {
@@ -3134,7 +3836,7 @@ var OpenAI = class {
3134
3836
  };
3135
3837
 
3136
3838
  // src/anthropic-compat.ts
3137
- var import_accounts5 = require("viem/accounts");
3839
+ var import_accounts9 = require("viem/accounts");
3138
3840
  var AnthropicClient = class {
3139
3841
  _client = null;
3140
3842
  _clientPromise = null;
@@ -3147,7 +3849,7 @@ var AnthropicClient = class {
3147
3849
  const key = options.privateKey ?? wallet.privateKey;
3148
3850
  validatePrivateKey(key);
3149
3851
  this._privateKey = key;
3150
- this._account = (0, import_accounts5.privateKeyToAccount)(this._privateKey);
3852
+ this._account = (0, import_accounts9.privateKeyToAccount)(this._privateKey);
3151
3853
  const apiUrl = options.apiUrl ?? "https://blockrun.ai/api";
3152
3854
  validateApiUrl(apiUrl);
3153
3855
  this._apiUrl = apiUrl.replace(/\/$/, "");
@@ -3250,16 +3952,20 @@ var AnthropicClient = class {
3250
3952
  ImageClient,
3251
3953
  KNOWN_PROVIDERS,
3252
3954
  LLMClient,
3955
+ MusicClient,
3253
3956
  OpenAI,
3254
3957
  PaymentError,
3958
+ PriceClient,
3255
3959
  SOLANA_NETWORK,
3256
3960
  SOLANA_WALLET_FILE_PATH,
3961
+ SearchClient,
3257
3962
  SolanaLLMClient,
3258
3963
  USDC_BASE,
3259
3964
  USDC_BASE_CONTRACT,
3260
3965
  USDC_SOLANA,
3261
3966
  WALLET_DIR_PATH,
3262
3967
  WALLET_FILE_PATH,
3968
+ XClient,
3263
3969
  clearCache,
3264
3970
  createPaymentPayload,
3265
3971
  createSolanaPaymentPayload,