@blockrun/llm 2.5.0 → 2.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +31 -2
- package/dist/index.cjs +464 -44
- package/dist/index.d.cts +329 -7
- package/dist/index.d.ts +329 -7
- package/dist/index.js +459 -43
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -40,7 +40,11 @@ __export(index_exports, {
|
|
|
40
40
|
LLMClient: () => LLMClient,
|
|
41
41
|
MusicClient: () => MusicClient,
|
|
42
42
|
OpenAI: () => OpenAI,
|
|
43
|
+
PHONE_PRICES: () => PHONE_PRICES,
|
|
44
|
+
PORTRAIT_ENROLLMENT_PRICE_USD: () => PORTRAIT_ENROLLMENT_PRICE_USD,
|
|
43
45
|
PaymentError: () => PaymentError,
|
|
46
|
+
PhoneClient: () => PhoneClient,
|
|
47
|
+
PortraitClient: () => PortraitClient,
|
|
44
48
|
PriceClient: () => PriceClient,
|
|
45
49
|
SOLANA_NETWORK: () => SOLANA_NETWORK,
|
|
46
50
|
SOLANA_WALLET_FILE_PATH: () => SOLANA_WALLET_FILE,
|
|
@@ -211,8 +215,8 @@ async function createSolanaPaymentPayload(secretKey, fromAddress, recipient, amo
|
|
|
211
215
|
const { Connection, PublicKey, TransactionMessage, VersionedTransaction, ComputeBudgetProgram } = await import("@solana/web3.js");
|
|
212
216
|
const { getAssociatedTokenAddress, createTransferCheckedInstruction, getMint } = await import("@solana/spl-token");
|
|
213
217
|
const { Keypair } = await import("@solana/web3.js");
|
|
214
|
-
const rpcUrl = options.rpcUrl || "https://
|
|
215
|
-
const connection = new Connection(rpcUrl);
|
|
218
|
+
const rpcUrl = options.rpcUrl || "https://sol.blockrun.ai/api/v1/solana/rpc";
|
|
219
|
+
const connection = options.rpcHeaders ? new Connection(rpcUrl, { httpHeaders: options.rpcHeaders }) : new Connection(rpcUrl);
|
|
216
220
|
const keypair = Keypair.fromSecretKey(secretKey);
|
|
217
221
|
const feePayerPubkey = new PublicKey(feePayer);
|
|
218
222
|
const ownerPubkey = keypair.publicKey;
|
|
@@ -2409,11 +2413,22 @@ var VideoClient = class {
|
|
|
2409
2413
|
* @param options - Optional generation parameters
|
|
2410
2414
|
*/
|
|
2411
2415
|
async generate(prompt, options) {
|
|
2416
|
+
if (options?.imageUrl && options?.realFaceAssetId) {
|
|
2417
|
+
throw new Error(
|
|
2418
|
+
"imageUrl and realFaceAssetId are mutually exclusive; pass at most one."
|
|
2419
|
+
);
|
|
2420
|
+
}
|
|
2421
|
+
if (options?.realFaceAssetId && !/^ta_[A-Za-z0-9]+$/.test(options.realFaceAssetId)) {
|
|
2422
|
+
throw new Error(
|
|
2423
|
+
"realFaceAssetId must be a Token360 asset id matching 'ta_[A-Za-z0-9]+' (e.g. 'ta_abc123xyz')"
|
|
2424
|
+
);
|
|
2425
|
+
}
|
|
2412
2426
|
const body = {
|
|
2413
2427
|
model: options?.model || DEFAULT_MODEL3,
|
|
2414
2428
|
prompt
|
|
2415
2429
|
};
|
|
2416
2430
|
if (options?.imageUrl) body.image_url = options.imageUrl;
|
|
2431
|
+
if (options?.realFaceAssetId) body.real_face_asset_id = options.realFaceAssetId;
|
|
2417
2432
|
if (options?.durationSeconds !== void 0) body.duration_seconds = options.durationSeconds;
|
|
2418
2433
|
if (options?.aspectRatio) body.aspect_ratio = options.aspectRatio;
|
|
2419
2434
|
if (options?.resolution) body.resolution = options.resolution;
|
|
@@ -2767,15 +2782,37 @@ var VoiceClient = class {
|
|
|
2767
2782
|
}
|
|
2768
2783
|
};
|
|
2769
2784
|
|
|
2770
|
-
// src/
|
|
2785
|
+
// src/phone.ts
|
|
2771
2786
|
var import_accounts7 = require("viem/accounts");
|
|
2772
2787
|
var DEFAULT_API_URL6 = "https://blockrun.ai/api";
|
|
2773
2788
|
var DEFAULT_TIMEOUT6 = 6e4;
|
|
2774
|
-
var
|
|
2789
|
+
var PHONE_PRICES = Object.freeze({
|
|
2790
|
+
lookup: 0.01,
|
|
2791
|
+
"lookup/fraud": 0.05,
|
|
2792
|
+
"numbers/buy": 5,
|
|
2793
|
+
"numbers/renew": 5,
|
|
2794
|
+
"numbers/list": 1e-3,
|
|
2795
|
+
"numbers/release": 0
|
|
2796
|
+
});
|
|
2797
|
+
function requireE164(value) {
|
|
2798
|
+
if (!value || typeof value !== "string") {
|
|
2799
|
+
throw new Error("phoneNumber is required (E.164 format, e.g. '+14155552671')");
|
|
2800
|
+
}
|
|
2801
|
+
const v = value.trim();
|
|
2802
|
+
if (!/^\+\d{7,15}$/.test(v)) {
|
|
2803
|
+
throw new Error(
|
|
2804
|
+
`phoneNumber must be E.164 (e.g. '+14155552671'), got ${JSON.stringify(value)}`
|
|
2805
|
+
);
|
|
2806
|
+
}
|
|
2807
|
+
return v;
|
|
2808
|
+
}
|
|
2809
|
+
var PhoneClient = class {
|
|
2775
2810
|
account;
|
|
2776
2811
|
privateKey;
|
|
2777
2812
|
apiUrl;
|
|
2778
2813
|
timeout;
|
|
2814
|
+
sessionTotalUsd = 0;
|
|
2815
|
+
sessionCalls = 0;
|
|
2779
2816
|
constructor(options = {}) {
|
|
2780
2817
|
const envKey = typeof process !== "undefined" && process.env ? process.env.BLOCKRUN_WALLET_KEY || process.env.BASE_CHAIN_WALLET_KEY : void 0;
|
|
2781
2818
|
const privateKey = options.privateKey || envKey;
|
|
@@ -2792,6 +2829,357 @@ var SearchClient = class {
|
|
|
2792
2829
|
this.apiUrl = apiUrl.replace(/\/$/, "");
|
|
2793
2830
|
this.timeout = options.timeout || DEFAULT_TIMEOUT6;
|
|
2794
2831
|
}
|
|
2832
|
+
/** EVM wallet address used for payments. */
|
|
2833
|
+
getWalletAddress() {
|
|
2834
|
+
return this.account.address;
|
|
2835
|
+
}
|
|
2836
|
+
/** Session-cumulative USD spend + call count across this client instance. */
|
|
2837
|
+
getSpending() {
|
|
2838
|
+
return { totalUsd: this.sessionTotalUsd, calls: this.sessionCalls };
|
|
2839
|
+
}
|
|
2840
|
+
// ─── Lookup ────────────────────────────────────────────────────────────
|
|
2841
|
+
/**
|
|
2842
|
+
* Carrier + line-type lookup. ~$0.01.
|
|
2843
|
+
*
|
|
2844
|
+
* @param phoneNumber E.164 number (e.g. "+14155552671").
|
|
2845
|
+
*/
|
|
2846
|
+
async lookup(phoneNumber) {
|
|
2847
|
+
const num = requireE164(phoneNumber);
|
|
2848
|
+
return this.request("lookup", { phoneNumber: num });
|
|
2849
|
+
}
|
|
2850
|
+
/**
|
|
2851
|
+
* Lookup + fraud signals (SIM swap, call forwarding). ~$0.05.
|
|
2852
|
+
*
|
|
2853
|
+
* @param phoneNumber E.164 number.
|
|
2854
|
+
*/
|
|
2855
|
+
async lookupFraud(phoneNumber) {
|
|
2856
|
+
const num = requireE164(phoneNumber);
|
|
2857
|
+
return this.request("lookup/fraud", { phoneNumber: num });
|
|
2858
|
+
}
|
|
2859
|
+
// ─── Provisioning ──────────────────────────────────────────────────────
|
|
2860
|
+
/**
|
|
2861
|
+
* Provision a dedicated phone number for 30 days. $5.00.
|
|
2862
|
+
*
|
|
2863
|
+
* Payment is settled only after Twilio confirms the purchase, so failed
|
|
2864
|
+
* buys never charge your wallet.
|
|
2865
|
+
*
|
|
2866
|
+
* @param options.country ISO country code, "US" or "CA" (default "US").
|
|
2867
|
+
* @param options.areaCode Optional 3-digit area-code hint. Availability is
|
|
2868
|
+
* not guaranteed — the backend falls back to any number in the country if
|
|
2869
|
+
* the area code can't be matched.
|
|
2870
|
+
*/
|
|
2871
|
+
async buyNumber(options = {}) {
|
|
2872
|
+
const country = options.country ?? "US";
|
|
2873
|
+
if (country !== "US" && country !== "CA") {
|
|
2874
|
+
throw new Error("country must be 'US' or 'CA'");
|
|
2875
|
+
}
|
|
2876
|
+
const body = { country };
|
|
2877
|
+
if (options.areaCode !== void 0) {
|
|
2878
|
+
const ac = options.areaCode;
|
|
2879
|
+
if (typeof ac !== "string" || !/^\d{3}$/.test(ac)) {
|
|
2880
|
+
throw new Error("areaCode must be a 3-digit string, e.g. '415'");
|
|
2881
|
+
}
|
|
2882
|
+
body.areaCode = ac;
|
|
2883
|
+
}
|
|
2884
|
+
const data = await this.request("numbers/buy", body);
|
|
2885
|
+
return data;
|
|
2886
|
+
}
|
|
2887
|
+
/**
|
|
2888
|
+
* Extend an existing provisioned number by 30 days. $5.00.
|
|
2889
|
+
*
|
|
2890
|
+
* @throws {APIError} 403 when the wallet doesn't own the number or it has expired.
|
|
2891
|
+
*/
|
|
2892
|
+
async renewNumber(phoneNumber) {
|
|
2893
|
+
const num = requireE164(phoneNumber);
|
|
2894
|
+
const data = await this.request("numbers/renew", {
|
|
2895
|
+
phoneNumber: num
|
|
2896
|
+
});
|
|
2897
|
+
return data;
|
|
2898
|
+
}
|
|
2899
|
+
/** List the wallet's active phone numbers. ~$0.001. */
|
|
2900
|
+
async listNumbers() {
|
|
2901
|
+
const data = await this.request("numbers/list", {});
|
|
2902
|
+
return data;
|
|
2903
|
+
}
|
|
2904
|
+
/**
|
|
2905
|
+
* Release a provisioned number back to the Twilio pool. Free, but still
|
|
2906
|
+
* flows through x402 so the backend can verify ownership.
|
|
2907
|
+
*/
|
|
2908
|
+
async releaseNumber(phoneNumber) {
|
|
2909
|
+
const num = requireE164(phoneNumber);
|
|
2910
|
+
const data = await this.request("numbers/release", {
|
|
2911
|
+
phoneNumber: num
|
|
2912
|
+
});
|
|
2913
|
+
return data;
|
|
2914
|
+
}
|
|
2915
|
+
// ─── Internals ─────────────────────────────────────────────────────────
|
|
2916
|
+
async request(path5, body) {
|
|
2917
|
+
const url = `${this.apiUrl}/v1/phone/${path5}`;
|
|
2918
|
+
const response = await this.fetchWithTimeout(url, {
|
|
2919
|
+
method: "POST",
|
|
2920
|
+
headers: { "Content-Type": "application/json" },
|
|
2921
|
+
body: JSON.stringify(body)
|
|
2922
|
+
});
|
|
2923
|
+
if (response.status === 402) {
|
|
2924
|
+
return this.handlePaymentAndRetry(url, body, response);
|
|
2925
|
+
}
|
|
2926
|
+
return this.unwrap(response, false);
|
|
2927
|
+
}
|
|
2928
|
+
async handlePaymentAndRetry(url, body, response) {
|
|
2929
|
+
let paymentHeader = response.headers.get("payment-required");
|
|
2930
|
+
if (!paymentHeader) {
|
|
2931
|
+
try {
|
|
2932
|
+
const rb = await response.json();
|
|
2933
|
+
if (rb.x402 || rb.accepts) paymentHeader = btoa(JSON.stringify(rb));
|
|
2934
|
+
} catch {
|
|
2935
|
+
}
|
|
2936
|
+
}
|
|
2937
|
+
if (!paymentHeader) {
|
|
2938
|
+
throw new PaymentError("402 response but no payment requirements found");
|
|
2939
|
+
}
|
|
2940
|
+
const paymentRequired = parsePaymentRequired(paymentHeader);
|
|
2941
|
+
const details = extractPaymentDetails(paymentRequired);
|
|
2942
|
+
const paymentPayload = await createPaymentPayload(
|
|
2943
|
+
this.privateKey,
|
|
2944
|
+
this.account.address,
|
|
2945
|
+
details.recipient,
|
|
2946
|
+
details.amount,
|
|
2947
|
+
details.network || "eip155:8453",
|
|
2948
|
+
{
|
|
2949
|
+
resourceUrl: details.resource?.url || url,
|
|
2950
|
+
resourceDescription: details.resource?.description || "BlockRun Phone",
|
|
2951
|
+
maxTimeoutSeconds: details.maxTimeoutSeconds || 300,
|
|
2952
|
+
extra: details.extra
|
|
2953
|
+
}
|
|
2954
|
+
);
|
|
2955
|
+
const retry = await this.fetchWithTimeout(url, {
|
|
2956
|
+
method: "POST",
|
|
2957
|
+
headers: {
|
|
2958
|
+
"Content-Type": "application/json",
|
|
2959
|
+
"PAYMENT-SIGNATURE": paymentPayload
|
|
2960
|
+
},
|
|
2961
|
+
body: JSON.stringify(body)
|
|
2962
|
+
});
|
|
2963
|
+
if (retry.status === 402) {
|
|
2964
|
+
throw new PaymentError("Payment was rejected. Check your wallet balance.");
|
|
2965
|
+
}
|
|
2966
|
+
const data = await this.unwrap(retry, true);
|
|
2967
|
+
const costUsd = Number.parseFloat(details.amount) / 1e6;
|
|
2968
|
+
this.sessionCalls += 1;
|
|
2969
|
+
this.sessionTotalUsd += costUsd;
|
|
2970
|
+
const txHash = retry.headers.get("x-payment-receipt") || retry.headers.get("X-Payment-Receipt");
|
|
2971
|
+
if (txHash && data && typeof data === "object" && !("txHash" in data)) {
|
|
2972
|
+
data.txHash = txHash;
|
|
2973
|
+
}
|
|
2974
|
+
return data;
|
|
2975
|
+
}
|
|
2976
|
+
async unwrap(response, afterPayment) {
|
|
2977
|
+
if (response.ok) {
|
|
2978
|
+
return response.json();
|
|
2979
|
+
}
|
|
2980
|
+
let errorBody;
|
|
2981
|
+
try {
|
|
2982
|
+
errorBody = await response.json();
|
|
2983
|
+
} catch {
|
|
2984
|
+
errorBody = { error: "Request failed" };
|
|
2985
|
+
}
|
|
2986
|
+
const prefix = afterPayment ? "API error after payment" : "API error";
|
|
2987
|
+
throw new APIError(
|
|
2988
|
+
`${prefix}: ${response.status}`,
|
|
2989
|
+
response.status,
|
|
2990
|
+
sanitizeErrorResponse(errorBody)
|
|
2991
|
+
);
|
|
2992
|
+
}
|
|
2993
|
+
async fetchWithTimeout(url, init) {
|
|
2994
|
+
const controller = new AbortController();
|
|
2995
|
+
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
|
|
2996
|
+
try {
|
|
2997
|
+
return await fetch(url, { ...init, signal: controller.signal });
|
|
2998
|
+
} finally {
|
|
2999
|
+
clearTimeout(timeoutId);
|
|
3000
|
+
}
|
|
3001
|
+
}
|
|
3002
|
+
};
|
|
3003
|
+
|
|
3004
|
+
// src/portrait.ts
|
|
3005
|
+
var import_accounts8 = require("viem/accounts");
|
|
3006
|
+
var DEFAULT_API_URL7 = "https://blockrun.ai/api";
|
|
3007
|
+
var DEFAULT_TIMEOUT7 = 6e4;
|
|
3008
|
+
var PORTRAIT_ENROLLMENT_PRICE_USD = 0.01;
|
|
3009
|
+
var PortraitClient = class {
|
|
3010
|
+
account;
|
|
3011
|
+
privateKey;
|
|
3012
|
+
apiUrl;
|
|
3013
|
+
timeout;
|
|
3014
|
+
sessionTotalUsd = 0;
|
|
3015
|
+
sessionCalls = 0;
|
|
3016
|
+
constructor(options = {}) {
|
|
3017
|
+
const envKey = typeof process !== "undefined" && process.env ? process.env.BLOCKRUN_WALLET_KEY || process.env.BASE_CHAIN_WALLET_KEY : void 0;
|
|
3018
|
+
const privateKey = options.privateKey || envKey;
|
|
3019
|
+
if (!privateKey) {
|
|
3020
|
+
throw new Error(
|
|
3021
|
+
"Private key required. Pass privateKey in options or set BLOCKRUN_WALLET_KEY environment variable."
|
|
3022
|
+
);
|
|
3023
|
+
}
|
|
3024
|
+
validatePrivateKey(privateKey);
|
|
3025
|
+
this.privateKey = privateKey;
|
|
3026
|
+
this.account = (0, import_accounts8.privateKeyToAccount)(privateKey);
|
|
3027
|
+
const apiUrl = options.apiUrl || DEFAULT_API_URL7;
|
|
3028
|
+
validateApiUrl(apiUrl);
|
|
3029
|
+
this.apiUrl = apiUrl.replace(/\/$/, "");
|
|
3030
|
+
this.timeout = options.timeout || DEFAULT_TIMEOUT7;
|
|
3031
|
+
}
|
|
3032
|
+
/** EVM wallet address used for payments. */
|
|
3033
|
+
getWalletAddress() {
|
|
3034
|
+
return this.account.address;
|
|
3035
|
+
}
|
|
3036
|
+
/** Session-cumulative USD spend + call count across this client instance. */
|
|
3037
|
+
getSpending() {
|
|
3038
|
+
return { totalUsd: this.sessionTotalUsd, calls: this.sessionCalls };
|
|
3039
|
+
}
|
|
3040
|
+
/**
|
|
3041
|
+
* Enroll a Virtual Portrait from a face image URL. $0.01 (promo).
|
|
3042
|
+
*
|
|
3043
|
+
* Payment is settled only after Token360 confirms the enrollment, so failed
|
|
3044
|
+
* enrollments never charge your wallet.
|
|
3045
|
+
*
|
|
3046
|
+
* @param options.name Display name (1–64 chars).
|
|
3047
|
+
* @param options.imageUrl Public HTTPS URL to a JPG/PNG/WEBP image (≤10 MB).
|
|
3048
|
+
* @returns The enrollment record, including `asset_id` (`ta_xxxxxx`).
|
|
3049
|
+
*/
|
|
3050
|
+
async enroll(options) {
|
|
3051
|
+
const name = typeof options?.name === "string" ? options.name.trim() : "";
|
|
3052
|
+
if (name.length < 1 || name.length > 64) {
|
|
3053
|
+
throw new Error("name is required and must be 1\u201364 characters");
|
|
3054
|
+
}
|
|
3055
|
+
const imageUrl = typeof options?.imageUrl === "string" ? options.imageUrl.trim() : "";
|
|
3056
|
+
if (!/^https?:\/\//i.test(imageUrl)) {
|
|
3057
|
+
throw new Error(
|
|
3058
|
+
"imageUrl must be a public http(s) URL to a JPG/PNG/WEBP image"
|
|
3059
|
+
);
|
|
3060
|
+
}
|
|
3061
|
+
const data = await this.request({
|
|
3062
|
+
name,
|
|
3063
|
+
image_url: imageUrl
|
|
3064
|
+
});
|
|
3065
|
+
return data;
|
|
3066
|
+
}
|
|
3067
|
+
// ─── Internals ─────────────────────────────────────────────────────────
|
|
3068
|
+
async request(body) {
|
|
3069
|
+
const url = `${this.apiUrl}/v1/portrait/enroll`;
|
|
3070
|
+
const response = await this.fetchWithTimeout(url, {
|
|
3071
|
+
method: "POST",
|
|
3072
|
+
headers: { "Content-Type": "application/json" },
|
|
3073
|
+
body: JSON.stringify(body)
|
|
3074
|
+
});
|
|
3075
|
+
if (response.status === 402) {
|
|
3076
|
+
return this.handlePaymentAndRetry(url, body, response);
|
|
3077
|
+
}
|
|
3078
|
+
return this.unwrap(response, false);
|
|
3079
|
+
}
|
|
3080
|
+
async handlePaymentAndRetry(url, body, response) {
|
|
3081
|
+
let paymentHeader = response.headers.get("payment-required");
|
|
3082
|
+
if (!paymentHeader) {
|
|
3083
|
+
try {
|
|
3084
|
+
const rb = await response.json();
|
|
3085
|
+
if (rb.x402 || rb.accepts) paymentHeader = btoa(JSON.stringify(rb));
|
|
3086
|
+
} catch {
|
|
3087
|
+
}
|
|
3088
|
+
}
|
|
3089
|
+
if (!paymentHeader) {
|
|
3090
|
+
throw new PaymentError("402 response but no payment requirements found");
|
|
3091
|
+
}
|
|
3092
|
+
const paymentRequired = parsePaymentRequired(paymentHeader);
|
|
3093
|
+
const details = extractPaymentDetails(paymentRequired);
|
|
3094
|
+
const paymentPayload = await createPaymentPayload(
|
|
3095
|
+
this.privateKey,
|
|
3096
|
+
this.account.address,
|
|
3097
|
+
details.recipient,
|
|
3098
|
+
details.amount,
|
|
3099
|
+
details.network || "eip155:8453",
|
|
3100
|
+
{
|
|
3101
|
+
resourceUrl: details.resource?.url || url,
|
|
3102
|
+
resourceDescription: details.resource?.description || "BlockRun Virtual Portrait",
|
|
3103
|
+
maxTimeoutSeconds: details.maxTimeoutSeconds || 300,
|
|
3104
|
+
extra: details.extra
|
|
3105
|
+
}
|
|
3106
|
+
);
|
|
3107
|
+
const retry = await this.fetchWithTimeout(url, {
|
|
3108
|
+
method: "POST",
|
|
3109
|
+
headers: {
|
|
3110
|
+
"Content-Type": "application/json",
|
|
3111
|
+
"PAYMENT-SIGNATURE": paymentPayload
|
|
3112
|
+
},
|
|
3113
|
+
body: JSON.stringify(body)
|
|
3114
|
+
});
|
|
3115
|
+
if (retry.status === 402) {
|
|
3116
|
+
throw new PaymentError("Payment was rejected. Check your wallet balance.");
|
|
3117
|
+
}
|
|
3118
|
+
const data = await this.unwrap(retry, true);
|
|
3119
|
+
const costUsd = Number.parseFloat(details.amount) / 1e6;
|
|
3120
|
+
this.sessionCalls += 1;
|
|
3121
|
+
this.sessionTotalUsd += costUsd;
|
|
3122
|
+
if (data && typeof data === "object" && !("txHash" in data)) {
|
|
3123
|
+
const settlement = data.settlement;
|
|
3124
|
+
if (settlement?.tx_hash) {
|
|
3125
|
+
data.txHash = settlement.tx_hash;
|
|
3126
|
+
}
|
|
3127
|
+
}
|
|
3128
|
+
return data;
|
|
3129
|
+
}
|
|
3130
|
+
async unwrap(response, afterPayment) {
|
|
3131
|
+
if (response.ok) {
|
|
3132
|
+
return response.json();
|
|
3133
|
+
}
|
|
3134
|
+
let errorBody;
|
|
3135
|
+
try {
|
|
3136
|
+
errorBody = await response.json();
|
|
3137
|
+
} catch {
|
|
3138
|
+
errorBody = { error: "Request failed" };
|
|
3139
|
+
}
|
|
3140
|
+
const prefix = afterPayment ? "API error after payment" : "API error";
|
|
3141
|
+
throw new APIError(
|
|
3142
|
+
`${prefix}: ${response.status}`,
|
|
3143
|
+
response.status,
|
|
3144
|
+
sanitizeErrorResponse(errorBody)
|
|
3145
|
+
);
|
|
3146
|
+
}
|
|
3147
|
+
async fetchWithTimeout(url, init) {
|
|
3148
|
+
const controller = new AbortController();
|
|
3149
|
+
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
|
|
3150
|
+
try {
|
|
3151
|
+
return await fetch(url, { ...init, signal: controller.signal });
|
|
3152
|
+
} finally {
|
|
3153
|
+
clearTimeout(timeoutId);
|
|
3154
|
+
}
|
|
3155
|
+
}
|
|
3156
|
+
};
|
|
3157
|
+
|
|
3158
|
+
// src/search.ts
|
|
3159
|
+
var import_accounts9 = require("viem/accounts");
|
|
3160
|
+
var DEFAULT_API_URL8 = "https://blockrun.ai/api";
|
|
3161
|
+
var DEFAULT_TIMEOUT8 = 6e4;
|
|
3162
|
+
var SearchClient = class {
|
|
3163
|
+
account;
|
|
3164
|
+
privateKey;
|
|
3165
|
+
apiUrl;
|
|
3166
|
+
timeout;
|
|
3167
|
+
constructor(options = {}) {
|
|
3168
|
+
const envKey = typeof process !== "undefined" && process.env ? process.env.BLOCKRUN_WALLET_KEY || process.env.BASE_CHAIN_WALLET_KEY : void 0;
|
|
3169
|
+
const privateKey = options.privateKey || envKey;
|
|
3170
|
+
if (!privateKey) {
|
|
3171
|
+
throw new Error(
|
|
3172
|
+
"Private key required. Pass privateKey in options or set BLOCKRUN_WALLET_KEY environment variable."
|
|
3173
|
+
);
|
|
3174
|
+
}
|
|
3175
|
+
validatePrivateKey(privateKey);
|
|
3176
|
+
this.privateKey = privateKey;
|
|
3177
|
+
this.account = (0, import_accounts9.privateKeyToAccount)(privateKey);
|
|
3178
|
+
const apiUrl = options.apiUrl || DEFAULT_API_URL8;
|
|
3179
|
+
validateApiUrl(apiUrl);
|
|
3180
|
+
this.apiUrl = apiUrl.replace(/\/$/, "");
|
|
3181
|
+
this.timeout = options.timeout || DEFAULT_TIMEOUT8;
|
|
3182
|
+
}
|
|
2795
3183
|
async search(query, options) {
|
|
2796
3184
|
if (!query || query.length > 1e3) {
|
|
2797
3185
|
throw new Error("query must be 1-1000 characters");
|
|
@@ -2904,9 +3292,9 @@ var SearchClient = class {
|
|
|
2904
3292
|
};
|
|
2905
3293
|
|
|
2906
3294
|
// src/x-client.ts
|
|
2907
|
-
var
|
|
2908
|
-
var
|
|
2909
|
-
var
|
|
3295
|
+
var import_accounts10 = require("viem/accounts");
|
|
3296
|
+
var DEFAULT_API_URL9 = "https://blockrun.ai/api";
|
|
3297
|
+
var DEFAULT_TIMEOUT9 = 6e4;
|
|
2910
3298
|
var XClient = class _XClient {
|
|
2911
3299
|
account;
|
|
2912
3300
|
privateKey;
|
|
@@ -2929,11 +3317,11 @@ var XClient = class _XClient {
|
|
|
2929
3317
|
}
|
|
2930
3318
|
validatePrivateKey(privateKey);
|
|
2931
3319
|
this.privateKey = privateKey;
|
|
2932
|
-
this.account = (0,
|
|
2933
|
-
const apiUrl = options.apiUrl ||
|
|
3320
|
+
this.account = (0, import_accounts10.privateKeyToAccount)(privateKey);
|
|
3321
|
+
const apiUrl = options.apiUrl || DEFAULT_API_URL9;
|
|
2934
3322
|
validateApiUrl(apiUrl);
|
|
2935
3323
|
this.apiUrl = apiUrl.replace(/\/$/, "");
|
|
2936
|
-
this.timeout = options.timeout ||
|
|
3324
|
+
this.timeout = options.timeout || DEFAULT_TIMEOUT9;
|
|
2937
3325
|
}
|
|
2938
3326
|
// ───────── User endpoints ─────────
|
|
2939
3327
|
userLookup(usernames) {
|
|
@@ -3111,9 +3499,9 @@ var XClient = class _XClient {
|
|
|
3111
3499
|
};
|
|
3112
3500
|
|
|
3113
3501
|
// src/price.ts
|
|
3114
|
-
var
|
|
3115
|
-
var
|
|
3116
|
-
var
|
|
3502
|
+
var import_accounts11 = require("viem/accounts");
|
|
3503
|
+
var DEFAULT_API_URL10 = "https://blockrun.ai/api";
|
|
3504
|
+
var DEFAULT_TIMEOUT10 = 3e4;
|
|
3117
3505
|
var PriceClient = class {
|
|
3118
3506
|
account = null;
|
|
3119
3507
|
privateKey = null;
|
|
@@ -3131,12 +3519,12 @@ var PriceClient = class {
|
|
|
3131
3519
|
if (privateKey) {
|
|
3132
3520
|
validatePrivateKey(privateKey);
|
|
3133
3521
|
this.privateKey = privateKey;
|
|
3134
|
-
this.account = (0,
|
|
3522
|
+
this.account = (0, import_accounts11.privateKeyToAccount)(privateKey);
|
|
3135
3523
|
}
|
|
3136
|
-
const apiUrl = options.apiUrl ||
|
|
3524
|
+
const apiUrl = options.apiUrl || DEFAULT_API_URL10;
|
|
3137
3525
|
validateApiUrl(apiUrl);
|
|
3138
3526
|
this.apiUrl = apiUrl.replace(/\/$/, "");
|
|
3139
|
-
this.timeout = options.timeout ||
|
|
3527
|
+
this.timeout = options.timeout || DEFAULT_TIMEOUT10;
|
|
3140
3528
|
}
|
|
3141
3529
|
async price(category, symbol, options) {
|
|
3142
3530
|
if (!symbol) throw new Error("symbol is required");
|
|
@@ -3315,9 +3703,9 @@ function buildUrl(base, query) {
|
|
|
3315
3703
|
}
|
|
3316
3704
|
|
|
3317
3705
|
// src/surf.ts
|
|
3318
|
-
var
|
|
3319
|
-
var
|
|
3320
|
-
var
|
|
3706
|
+
var import_accounts12 = require("viem/accounts");
|
|
3707
|
+
var DEFAULT_API_URL11 = "https://blockrun.ai/api";
|
|
3708
|
+
var DEFAULT_TIMEOUT11 = 6e4;
|
|
3321
3709
|
var SURF_PREFIX = "/v1/surf";
|
|
3322
3710
|
var SurfClient = class {
|
|
3323
3711
|
account;
|
|
@@ -3334,11 +3722,11 @@ var SurfClient = class {
|
|
|
3334
3722
|
}
|
|
3335
3723
|
validatePrivateKey(privateKey);
|
|
3336
3724
|
this.privateKey = privateKey;
|
|
3337
|
-
this.account = (0,
|
|
3338
|
-
const apiUrl = options.apiUrl ||
|
|
3725
|
+
this.account = (0, import_accounts12.privateKeyToAccount)(privateKey);
|
|
3726
|
+
const apiUrl = options.apiUrl || DEFAULT_API_URL11;
|
|
3339
3727
|
validateApiUrl(apiUrl);
|
|
3340
3728
|
this.apiUrl = apiUrl.replace(/\/$/, "");
|
|
3341
|
-
this.timeout = options.timeout ||
|
|
3729
|
+
this.timeout = options.timeout || DEFAULT_TIMEOUT11;
|
|
3342
3730
|
}
|
|
3343
3731
|
/**
|
|
3344
3732
|
* GET a Surf endpoint. `path` is everything after `/v1/surf` (a leading
|
|
@@ -3470,9 +3858,9 @@ var SurfClient = class {
|
|
|
3470
3858
|
};
|
|
3471
3859
|
|
|
3472
3860
|
// src/blockrun.ts
|
|
3473
|
-
var
|
|
3474
|
-
var
|
|
3475
|
-
var
|
|
3861
|
+
var import_accounts13 = require("viem/accounts");
|
|
3862
|
+
var DEFAULT_API_URL12 = "https://blockrun.ai/api";
|
|
3863
|
+
var DEFAULT_TIMEOUT12 = 6e4;
|
|
3476
3864
|
var DEFAULT_POLL_INTERVAL_MS = 5e3;
|
|
3477
3865
|
var DEFAULT_POLL_BUDGET_MS = 3e5;
|
|
3478
3866
|
var MAX_SIGNED_AUTH_SECONDS = 600;
|
|
@@ -3493,11 +3881,11 @@ var BlockrunClient = class {
|
|
|
3493
3881
|
}
|
|
3494
3882
|
validatePrivateKey(privateKey);
|
|
3495
3883
|
this.privateKey = privateKey;
|
|
3496
|
-
this.account = (0,
|
|
3497
|
-
const apiUrl = options.apiUrl ||
|
|
3884
|
+
this.account = (0, import_accounts13.privateKeyToAccount)(privateKey);
|
|
3885
|
+
const apiUrl = options.apiUrl || DEFAULT_API_URL12;
|
|
3498
3886
|
validateApiUrl(apiUrl);
|
|
3499
3887
|
this.apiUrl = apiUrl.replace(/\/$/, "");
|
|
3500
|
-
this.timeout = options.timeout ||
|
|
3888
|
+
this.timeout = options.timeout || DEFAULT_TIMEOUT12;
|
|
3501
3889
|
}
|
|
3502
3890
|
/**
|
|
3503
3891
|
* GET a BlockRun endpoint. `path` is everything after `/api` (a leading
|
|
@@ -3848,7 +4236,7 @@ function sleep(ms) {
|
|
|
3848
4236
|
}
|
|
3849
4237
|
|
|
3850
4238
|
// src/wallet.ts
|
|
3851
|
-
var
|
|
4239
|
+
var import_accounts14 = require("viem/accounts");
|
|
3852
4240
|
var fs2 = __toESM(require("fs"), 1);
|
|
3853
4241
|
var path2 = __toESM(require("path"), 1);
|
|
3854
4242
|
var os2 = __toESM(require("os"), 1);
|
|
@@ -3857,8 +4245,8 @@ var BASE_CHAIN_ID2 = "8453";
|
|
|
3857
4245
|
var WALLET_DIR = path2.join(os2.homedir(), ".blockrun");
|
|
3858
4246
|
var WALLET_FILE = path2.join(WALLET_DIR, ".session");
|
|
3859
4247
|
function createWallet() {
|
|
3860
|
-
const privateKey = (0,
|
|
3861
|
-
const account = (0,
|
|
4248
|
+
const privateKey = (0, import_accounts14.generatePrivateKey)();
|
|
4249
|
+
const account = (0, import_accounts14.privateKeyToAccount)(privateKey);
|
|
3862
4250
|
return {
|
|
3863
4251
|
address: account.address,
|
|
3864
4252
|
privateKey
|
|
@@ -3914,12 +4302,12 @@ function loadWallet() {
|
|
|
3914
4302
|
function getOrCreateWallet() {
|
|
3915
4303
|
const envKey = typeof process !== "undefined" && process.env ? process.env.BLOCKRUN_WALLET_KEY || process.env.BASE_CHAIN_WALLET_KEY : void 0;
|
|
3916
4304
|
if (envKey) {
|
|
3917
|
-
const account = (0,
|
|
4305
|
+
const account = (0, import_accounts14.privateKeyToAccount)(envKey);
|
|
3918
4306
|
return { address: account.address, privateKey: envKey, isNew: false };
|
|
3919
4307
|
}
|
|
3920
4308
|
const fileKey = loadWallet();
|
|
3921
4309
|
if (fileKey) {
|
|
3922
|
-
const account = (0,
|
|
4310
|
+
const account = (0, import_accounts14.privateKeyToAccount)(fileKey);
|
|
3923
4311
|
return { address: account.address, privateKey: fileKey, isNew: false };
|
|
3924
4312
|
}
|
|
3925
4313
|
const { address, privateKey } = createWallet();
|
|
@@ -3929,11 +4317,11 @@ function getOrCreateWallet() {
|
|
|
3929
4317
|
function getWalletAddress() {
|
|
3930
4318
|
const envKey = typeof process !== "undefined" && process.env ? process.env.BLOCKRUN_WALLET_KEY || process.env.BASE_CHAIN_WALLET_KEY : void 0;
|
|
3931
4319
|
if (envKey) {
|
|
3932
|
-
return (0,
|
|
4320
|
+
return (0, import_accounts14.privateKeyToAccount)(envKey).address;
|
|
3933
4321
|
}
|
|
3934
4322
|
const fileKey = loadWallet();
|
|
3935
4323
|
if (fileKey) {
|
|
3936
|
-
return (0,
|
|
4324
|
+
return (0, import_accounts14.privateKeyToAccount)(fileKey).address;
|
|
3937
4325
|
}
|
|
3938
4326
|
return null;
|
|
3939
4327
|
}
|
|
@@ -4113,14 +4501,37 @@ async function getOrCreateSolanaWallet() {
|
|
|
4113
4501
|
// src/solana-client.ts
|
|
4114
4502
|
var SOLANA_API_URL = "https://sol.blockrun.ai/api";
|
|
4115
4503
|
var DEFAULT_MAX_TOKENS2 = 1024;
|
|
4116
|
-
var
|
|
4504
|
+
var DEFAULT_TIMEOUT13 = 6e4;
|
|
4117
4505
|
var SDK_VERSION2 = "0.3.0";
|
|
4118
4506
|
var USER_AGENT2 = `blockrun-ts/${SDK_VERSION2}`;
|
|
4507
|
+
var DEFAULT_SOLANA_RPC_URL = "https://sol.blockrun.ai/api/v1/solana/rpc";
|
|
4508
|
+
function resolveRpcConfig(rpcUrl, rpcHeaders) {
|
|
4509
|
+
const env = typeof process !== "undefined" && process.env ? process.env : {};
|
|
4510
|
+
const url = rpcUrl || env.SOLANA_RPC_URL || DEFAULT_SOLANA_RPC_URL;
|
|
4511
|
+
let headers;
|
|
4512
|
+
if (rpcHeaders) {
|
|
4513
|
+
headers = { ...rpcHeaders };
|
|
4514
|
+
} else if (env.SOLANA_RPC_HEADERS) {
|
|
4515
|
+
try {
|
|
4516
|
+
const parsed = JSON.parse(env.SOLANA_RPC_HEADERS);
|
|
4517
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
4518
|
+
headers = Object.fromEntries(
|
|
4519
|
+
Object.entries(parsed).map(([k, v]) => [String(k), String(v)])
|
|
4520
|
+
);
|
|
4521
|
+
}
|
|
4522
|
+
} catch {
|
|
4523
|
+
}
|
|
4524
|
+
} else if (env.SOLANA_RPC_API_KEY) {
|
|
4525
|
+
headers = { "x-api-key": env.SOLANA_RPC_API_KEY };
|
|
4526
|
+
}
|
|
4527
|
+
return headers ? { url, headers } : { url };
|
|
4528
|
+
}
|
|
4119
4529
|
var SolanaLLMClient = class {
|
|
4120
4530
|
static SOLANA_API_URL = SOLANA_API_URL;
|
|
4121
4531
|
privateKey;
|
|
4122
4532
|
apiUrl;
|
|
4123
4533
|
rpcUrl;
|
|
4534
|
+
rpcHeaders;
|
|
4124
4535
|
timeout;
|
|
4125
4536
|
sessionTotalUsd = 0;
|
|
4126
4537
|
sessionCalls = 0;
|
|
@@ -4137,8 +4548,10 @@ var SolanaLLMClient = class {
|
|
|
4137
4548
|
const apiUrl = options.apiUrl || SOLANA_API_URL;
|
|
4138
4549
|
validateApiUrl(apiUrl);
|
|
4139
4550
|
this.apiUrl = apiUrl.replace(/\/$/, "");
|
|
4140
|
-
|
|
4141
|
-
this.
|
|
4551
|
+
const rpc = resolveRpcConfig(options.rpcUrl, options.rpcHeaders);
|
|
4552
|
+
this.rpcUrl = rpc.url;
|
|
4553
|
+
this.rpcHeaders = rpc.headers;
|
|
4554
|
+
this.timeout = options.timeout || DEFAULT_TIMEOUT13;
|
|
4142
4555
|
}
|
|
4143
4556
|
/** Get Solana wallet address (public key in base58). */
|
|
4144
4557
|
async getWalletAddress() {
|
|
@@ -4196,7 +4609,7 @@ var SolanaLLMClient = class {
|
|
|
4196
4609
|
try {
|
|
4197
4610
|
const response = await fetch(this.rpcUrl, {
|
|
4198
4611
|
method: "POST",
|
|
4199
|
-
headers: { "Content-Type": "application/json" },
|
|
4612
|
+
headers: { "Content-Type": "application/json", ...this.rpcHeaders ?? {} },
|
|
4200
4613
|
body: JSON.stringify({
|
|
4201
4614
|
jsonrpc: "2.0",
|
|
4202
4615
|
id: 1,
|
|
@@ -4447,7 +4860,8 @@ var SolanaLLMClient = class {
|
|
|
4447
4860
|
maxTimeoutSeconds: details.maxTimeoutSeconds || 300,
|
|
4448
4861
|
extra: details.extra,
|
|
4449
4862
|
extensions,
|
|
4450
|
-
rpcUrl: this.rpcUrl
|
|
4863
|
+
rpcUrl: this.rpcUrl,
|
|
4864
|
+
rpcHeaders: this.rpcHeaders
|
|
4451
4865
|
}
|
|
4452
4866
|
);
|
|
4453
4867
|
const retryResponse = await this.fetchWithTimeout(url, {
|
|
@@ -4538,7 +4952,8 @@ var SolanaLLMClient = class {
|
|
|
4538
4952
|
maxTimeoutSeconds: details.maxTimeoutSeconds || 300,
|
|
4539
4953
|
extra: details.extra,
|
|
4540
4954
|
extensions,
|
|
4541
|
-
rpcUrl: this.rpcUrl
|
|
4955
|
+
rpcUrl: this.rpcUrl,
|
|
4956
|
+
rpcHeaders: this.rpcHeaders
|
|
4542
4957
|
}
|
|
4543
4958
|
);
|
|
4544
4959
|
const retryResponse = await this.fetchWithTimeout(url, {
|
|
@@ -4629,7 +5044,8 @@ var SolanaLLMClient = class {
|
|
|
4629
5044
|
maxTimeoutSeconds: details.maxTimeoutSeconds || 300,
|
|
4630
5045
|
extra: details.extra,
|
|
4631
5046
|
extensions,
|
|
4632
|
-
rpcUrl: this.rpcUrl
|
|
5047
|
+
rpcUrl: this.rpcUrl,
|
|
5048
|
+
rpcHeaders: this.rpcHeaders
|
|
4633
5049
|
}
|
|
4634
5050
|
);
|
|
4635
5051
|
const query = params ? "?" + new URLSearchParams(params).toString() : "";
|
|
@@ -5045,7 +5461,7 @@ var OpenAI = class {
|
|
|
5045
5461
|
};
|
|
5046
5462
|
|
|
5047
5463
|
// src/anthropic-compat.ts
|
|
5048
|
-
var
|
|
5464
|
+
var import_accounts15 = require("viem/accounts");
|
|
5049
5465
|
var AnthropicClient = class {
|
|
5050
5466
|
_client = null;
|
|
5051
5467
|
_clientPromise = null;
|
|
@@ -5058,7 +5474,7 @@ var AnthropicClient = class {
|
|
|
5058
5474
|
const key = options.privateKey ?? wallet.privateKey;
|
|
5059
5475
|
validatePrivateKey(key);
|
|
5060
5476
|
this._privateKey = key;
|
|
5061
|
-
this._account = (0,
|
|
5477
|
+
this._account = (0, import_accounts15.privateKeyToAccount)(this._privateKey);
|
|
5062
5478
|
const apiUrl = options.apiUrl ?? "https://blockrun.ai/api";
|
|
5063
5479
|
validateApiUrl(apiUrl);
|
|
5064
5480
|
this._apiUrl = apiUrl.replace(/\/$/, "");
|
|
@@ -5164,7 +5580,11 @@ var AnthropicClient = class {
|
|
|
5164
5580
|
LLMClient,
|
|
5165
5581
|
MusicClient,
|
|
5166
5582
|
OpenAI,
|
|
5583
|
+
PHONE_PRICES,
|
|
5584
|
+
PORTRAIT_ENROLLMENT_PRICE_USD,
|
|
5167
5585
|
PaymentError,
|
|
5586
|
+
PhoneClient,
|
|
5587
|
+
PortraitClient,
|
|
5168
5588
|
PriceClient,
|
|
5169
5589
|
SOLANA_NETWORK,
|
|
5170
5590
|
SOLANA_WALLET_FILE_PATH,
|