@blockrun/llm 3.13.5 → 3.14.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
@@ -31,6 +31,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
31
31
  var index_exports = {};
32
32
  __export(index_exports, {
33
33
  APIError: () => APIError,
34
+ API_KEY_URL: () => API_KEY_URL,
34
35
  AnthropicClient: () => AnthropicClient,
35
36
  BASE_CHAIN_ID: () => BASE_CHAIN_ID,
36
37
  BlockrunClient: () => BlockrunClient,
@@ -42,6 +43,7 @@ __export(index_exports, {
42
43
  NETWORK_ALIASES: () => NETWORK_ALIASES,
43
44
  OpenAI: () => OpenAI,
44
45
  PHONE_PRICES: () => PHONE_PRICES,
46
+ PORTAL_URL: () => PORTAL_URL,
45
47
  PORTRAIT_ENROLLMENT_PRICE_USD: () => PORTRAIT_ENROLLMENT_PRICE_USD,
46
48
  PaymentError: () => PaymentError,
47
49
  PhoneClient: () => PhoneClient,
@@ -99,6 +101,7 @@ __export(index_exports, {
99
101
  scanSolanaWallets: () => scanSolanaWallets,
100
102
  scanWallets: () => scanWallets2,
101
103
  setCache: () => setCache,
104
+ setupAgentClient: () => setupAgentClient,
102
105
  setupAgentSolanaWallet: () => setupAgentSolanaWallet,
103
106
  setupAgentWallet: () => setupAgentWallet,
104
107
  solanaClient: () => solanaClient,
@@ -112,9 +115,6 @@ __export(index_exports, {
112
115
  });
113
116
  module.exports = __toCommonJS(index_exports);
114
117
 
115
- // src/client.ts
116
- var import_accounts2 = require("viem/accounts");
117
-
118
118
  // src/types.ts
119
119
  var BlockrunError = class extends Error {
120
120
  constructor(message) {
@@ -136,6 +136,8 @@ var PaymentError = class extends BlockrunError {
136
136
  };
137
137
  var APIError = class extends BlockrunError {
138
138
  statusCode;
139
+ /** Retry-After header returned by the account API. */
140
+ retryAfter;
139
141
  response;
140
142
  constructor(message, statusCode, response) {
141
143
  super(message);
@@ -145,7 +147,249 @@ var APIError = class extends BlockrunError {
145
147
  }
146
148
  };
147
149
 
148
- // node_modules/.pnpm/@blockrun+router-core@https+++codeload.github.com+BlockRunAI+router-core+tar.gz+5d911879d7f1e_fbldkf3f3jmlwtwu53ftq2mj24/node_modules/@blockrun/router-core/dist/index.js
150
+ // src/validation.ts
151
+ var LOCALHOST_DOMAINS = ["localhost", "127.0.0.1"];
152
+ var KNOWN_PROVIDERS = /* @__PURE__ */ new Set([
153
+ "openai",
154
+ "anthropic",
155
+ "google",
156
+ "deepseek",
157
+ "mistralai",
158
+ "meta-llama",
159
+ "together",
160
+ "xai",
161
+ "moonshot",
162
+ "nvidia",
163
+ "minimax",
164
+ "zai"
165
+ ]);
166
+ function validateModel(model) {
167
+ if (!model || typeof model !== "string") {
168
+ throw new Error("Model must be a non-empty string");
169
+ }
170
+ }
171
+ function validateMaxTokens(maxTokens) {
172
+ if (maxTokens === void 0 || maxTokens === null) {
173
+ return;
174
+ }
175
+ if (typeof maxTokens !== "number" || !Number.isInteger(maxTokens)) {
176
+ throw new Error("maxTokens must be an integer");
177
+ }
178
+ if (maxTokens < 1) {
179
+ throw new Error("maxTokens must be positive (minimum: 1)");
180
+ }
181
+ }
182
+ function validateTemperature(temperature) {
183
+ if (temperature === void 0 || temperature === null) {
184
+ return;
185
+ }
186
+ if (typeof temperature !== "number") {
187
+ throw new Error("temperature must be a number");
188
+ }
189
+ if (temperature < 0 || temperature > 2) {
190
+ throw new Error("temperature must be between 0 and 2");
191
+ }
192
+ }
193
+ function validateTopP(topP) {
194
+ if (topP === void 0 || topP === null) {
195
+ return;
196
+ }
197
+ if (typeof topP !== "number") {
198
+ throw new Error("topP must be a number");
199
+ }
200
+ if (topP < 0 || topP > 1) {
201
+ throw new Error("topP must be between 0 and 1");
202
+ }
203
+ }
204
+ function validatePrivateKey(key) {
205
+ if (typeof key !== "string") {
206
+ throw new Error("Private key must be a string");
207
+ }
208
+ if (!key.startsWith("0x")) {
209
+ throw new Error("Private key must start with 0x");
210
+ }
211
+ if (key.length !== 66) {
212
+ throw new Error(
213
+ "Private key must be 66 characters (0x + 64 hexadecimal characters)"
214
+ );
215
+ }
216
+ if (!/^0x[0-9a-fA-F]{64}$/.test(key)) {
217
+ throw new Error(
218
+ "Private key must contain only hexadecimal characters (0-9, a-f, A-F)"
219
+ );
220
+ }
221
+ }
222
+ function validateApiUrl(url) {
223
+ let parsed;
224
+ try {
225
+ parsed = new URL(url);
226
+ } catch {
227
+ throw new Error("Invalid API URL format");
228
+ }
229
+ if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
230
+ throw new Error(
231
+ `Invalid protocol: ${parsed.protocol}. Use http:// or https://`
232
+ );
233
+ }
234
+ const isLocalhost = LOCALHOST_DOMAINS.includes(parsed.hostname);
235
+ if (parsed.protocol !== "https:" && !isLocalhost) {
236
+ throw new Error(
237
+ `API URL must use HTTPS for non-localhost endpoints. Use https:// instead of ${parsed.protocol}//`
238
+ );
239
+ }
240
+ }
241
+ function sanitizeErrorResponse(errorBody) {
242
+ if (typeof errorBody !== "object" || errorBody === null) {
243
+ return { message: "API request failed" };
244
+ }
245
+ const body = errorBody;
246
+ return {
247
+ message: typeof body.error === "string" ? body.error : "API request failed",
248
+ code: typeof body.code === "string" ? body.code : void 0
249
+ };
250
+ }
251
+ function validateResourceUrl(url, baseUrl) {
252
+ try {
253
+ const parsed = new URL(url);
254
+ const baseParsed = new URL(baseUrl);
255
+ if (parsed.hostname !== baseParsed.hostname) {
256
+ console.warn(
257
+ `Resource URL hostname mismatch: ${parsed.hostname} vs ${baseParsed.hostname}. Using safe default instead.`
258
+ );
259
+ return `${baseUrl}/v1/chat/completions`;
260
+ }
261
+ if (parsed.protocol !== baseParsed.protocol) {
262
+ console.warn(
263
+ `Resource URL protocol mismatch: ${parsed.protocol} vs ${baseParsed.protocol}. Using safe default instead.`
264
+ );
265
+ return `${baseUrl}/v1/chat/completions`;
266
+ }
267
+ return url;
268
+ } catch {
269
+ console.warn(`Invalid resource URL format: ${url}. Using safe default.`);
270
+ return `${baseUrl}/v1/chat/completions`;
271
+ }
272
+ }
273
+
274
+ // src/api-key.ts
275
+ var TRANSIENT_STATUS = /* @__PURE__ */ new Set([502, 503, 504, 522, 524]);
276
+ var TRANSIENT_RETRIES = 2;
277
+ var TRANSIENT_BACKOFF_MS = 1e3;
278
+ var API_KEY_URL = "https://api.blockrun.ai";
279
+ var PORTAL_URL = "https://user.blockrun.ai";
280
+ function resolveApiKeyAuth(options) {
281
+ if (options.apiKey !== void 0 && options.privateKey !== void 0) {
282
+ throw new Error("Pass either apiKey or privateKey, not both.");
283
+ }
284
+ const key = options.apiKey ?? (options.privateKey === void 0 && typeof process !== "undefined" ? process.env?.BLOCKRUN_API_KEY : void 0);
285
+ if (key === void 0) return void 0;
286
+ if (!/^brk_[A-Za-z0-9_-]+$/.test(key.trim())) {
287
+ throw new Error(`Invalid BlockRun API key. Create one at ${PORTAL_URL}/dashboard/keys.`);
288
+ }
289
+ const base = options.apiUrl ?? (typeof process !== "undefined" ? process.env?.BLOCKRUN_API_BASE_URL : void 0) ?? API_KEY_URL;
290
+ return new ApiKeyAuth(key.trim(), base);
291
+ }
292
+ function requireWallet(value) {
293
+ if (value === void 0) throw new Error("This operation requires a wallet; the client uses API key account billing.");
294
+ return value;
295
+ }
296
+ var ApiKeyAuth = class {
297
+ apiUrl;
298
+ #key;
299
+ constructor(key, base) {
300
+ validateApiUrl(base);
301
+ const url = new URL(base);
302
+ if (url.username || url.password || url.search || url.hash) {
303
+ throw new Error("API base URL must not contain credentials, a query, or a fragment.");
304
+ }
305
+ this.apiUrl = base.replace(/\/+$/, "").replace(/\/v1$/, "");
306
+ this.#key = key;
307
+ }
308
+ /** Resolve gateway poll paths without forwarding credentials to another origin. */
309
+ resolveUrl(path6) {
310
+ const url = new URL(path6, this.apiUrl + "/");
311
+ if (url.origin !== new URL(this.apiUrl).origin || url.username || url.password) {
312
+ throw new Error("Refusing to send a BlockRun API key to a different origin.");
313
+ }
314
+ if (new URL(this.apiUrl).pathname === "/" && url.pathname.startsWith("/api/v1/")) url.pathname = url.pathname.slice(4);
315
+ return url.href;
316
+ }
317
+ async fetch(input, init, raiseErrors = true) {
318
+ const request = input instanceof Request ? input : void 0;
319
+ const url = this.resolveUrl(request?.url ?? String(input));
320
+ const headers = new Headers(init?.headers ?? request?.headers);
321
+ for (const name of [...headers.keys()]) {
322
+ if (name.toLowerCase().includes("payment") || name.toLowerCase() === "x-api-key") headers.delete(name);
323
+ }
324
+ headers.set("authorization", `Bearer ${this.#key}`);
325
+ const method = (init?.method ?? request?.method ?? "GET").toUpperCase();
326
+ const retries = method === "GET" || method === "HEAD" ? TRANSIENT_RETRIES : 0;
327
+ let response;
328
+ for (let attempt = 0; ; attempt++) {
329
+ response = await globalThis.fetch(request ? new Request(url, request) : url, {
330
+ ...init,
331
+ headers,
332
+ redirect: "error"
333
+ });
334
+ if (attempt >= retries || !TRANSIENT_STATUS.has(response.status)) break;
335
+ await new Promise((resolve) => setTimeout(resolve, TRANSIENT_BACKOFF_MS * (attempt + 1)));
336
+ }
337
+ if (raiseErrors && !response.ok) {
338
+ let body;
339
+ try {
340
+ body = await response.json();
341
+ } catch {
342
+ body = void 0;
343
+ }
344
+ const outer = body && typeof body === "object" ? body : {};
345
+ const detail = outer.error && typeof outer.error === "object" ? outer.error : outer;
346
+ const safe = Object.fromEntries(["message", "code", "type", "param"].flatMap((name) => typeof detail[name] === "string" ? [[name, detail[name].split(this.#key).join("[REDACTED]")]] : []));
347
+ const hint = response.status === 402 ? ` Top up at ${PORTAL_URL}/dashboard/credits.` : response.status === 401 ? ` Check your key at ${PORTAL_URL}/dashboard/keys.` : "";
348
+ const error = new APIError(`BlockRun account API error: ${response.status}.${hint}`, response.status, safe);
349
+ error.retryAfter = response.headers.get("retry-after") ?? void 0;
350
+ throw error;
351
+ }
352
+ return response;
353
+ }
354
+ /** Poll an account-owned async job without ever entering the x402 signing path. */
355
+ async poll(response, timeout, interval) {
356
+ const deadline = Date.now() + timeout;
357
+ let data = await response.json();
358
+ if (["failed", "cancelled", "canceled"].includes(String(data.status))) {
359
+ throw new APIError("Account API job failed or was cancelled", 502);
360
+ }
361
+ const pollPath = data.poll_url;
362
+ if (typeof pollPath !== "string") {
363
+ if (response.status === 202 || ["queued", "in_progress", "processing"].includes(String(data.status))) {
364
+ throw new APIError("Async response missing poll_url", response.status);
365
+ }
366
+ return data;
367
+ }
368
+ const url = this.resolveUrl(pollPath);
369
+ while (Date.now() < deadline) {
370
+ if (data.status === "completed") return data;
371
+ if (["failed", "cancelled", "canceled"].includes(String(data.status))) {
372
+ throw new APIError("Account API job failed or was cancelled", 502, sanitizeErrorResponse(data));
373
+ }
374
+ await new Promise((resolve) => setTimeout(resolve, Math.min(interval, Math.max(0, deadline - Date.now()))));
375
+ const remaining = deadline - Date.now();
376
+ if (remaining <= 0) break;
377
+ try {
378
+ const res = await this.fetch(url, { signal: AbortSignal.timeout(remaining) });
379
+ data = await res.json();
380
+ } catch (err) {
381
+ if (!(err instanceof APIError) || !TRANSIENT_STATUS.has(err.statusCode)) throw err;
382
+ }
383
+ }
384
+ if (data.status === "completed") return data;
385
+ throw new APIError("Account API job polling timed out; check the job before submitting again.", 504, { poll_url: url });
386
+ }
387
+ };
388
+
389
+ // src/client.ts
390
+ var import_accounts2 = require("viem/accounts");
391
+
392
+ // node_modules/.pnpm/@blockrun+router-core@https+++codeload.github.com+BlockRunAI+router-core+tar.gz+814fd3b6bc788_xq5fkcckbb2p7dtp6dodey4yri/node_modules/@blockrun/router-core/dist/index.js
149
393
  function scoreTokenCount(estimatedTokens, thresholds) {
150
394
  if (estimatedTokens < thresholds.simple) {
151
395
  return { name: "tokenCount", score: -1, signal: `short (${estimatedTokens} tokens)` };
@@ -668,6 +912,13 @@ var DEFAULT_MODEL_CAPABILITIES = Object.freeze({
668
912
  supportsTools: true,
669
913
  supportsVision: true
670
914
  },
915
+ "cohere/north-mini-code": {
916
+ // supportsTools: not probed — fails closed
917
+ contextWindow: 256e3,
918
+ maxOutputTokens: 16384,
919
+ supportsTools: false,
920
+ supportsVision: false
921
+ },
671
922
  "deepseek/deepseek-chat": {
672
923
  contextWindow: 1048576,
673
924
  maxOutputTokens: 65536,
@@ -758,8 +1009,15 @@ var DEFAULT_MODEL_CAPABILITIES = Object.freeze({
758
1009
  supportsTools: true,
759
1010
  supportsVision: true
760
1011
  },
761
- "nvidia/mistral-nemotron": {
762
- // supportsTools: gateway unavailable at probe time — fails closed
1012
+ "nvidia/llama-3.2-11b-vision": {
1013
+ // supportsTools: not probed — fails closed
1014
+ contextWindow: 128e3,
1015
+ maxOutputTokens: 16384,
1016
+ supportsTools: false,
1017
+ supportsVision: true
1018
+ },
1019
+ "nvidia/nemotron-3-nano-30b": {
1020
+ // supportsTools: not probed — fails closed
763
1021
  contextWindow: 131072,
764
1022
  maxOutputTokens: 16384,
765
1023
  supportsTools: false,
@@ -771,21 +1029,16 @@ var DEFAULT_MODEL_CAPABILITIES = Object.freeze({
771
1029
  supportsTools: false,
772
1030
  supportsVision: true
773
1031
  },
774
- "nvidia/nemotron-nano-12b-v2-vl": {
775
- // supportsTools: gateway unavailable at probe time — fails closed
776
- contextWindow: 131072,
777
- maxOutputTokens: 16384,
778
- supportsTools: false,
779
- supportsVision: true
780
- },
781
- "nvidia/nemotron-nano-9b-v2": {
782
- contextWindow: 131072,
1032
+ "nvidia/nemotron-3-ultra-550b": {
1033
+ // supportsTools: not probed — fails closed
1034
+ contextWindow: 1e6,
783
1035
  maxOutputTokens: 16384,
784
1036
  supportsTools: false,
785
1037
  supportsVision: false
786
1038
  },
787
- "nvidia/step-3.7-flash": {
788
- contextWindow: 131072,
1039
+ "nvidia/nemotron-3.5-lightning": {
1040
+ // supportsTools: not probed — fails closed
1041
+ contextWindow: 1e6,
789
1042
  maxOutputTokens: 16384,
790
1043
  supportsTools: false,
791
1044
  supportsVision: false
@@ -845,13 +1098,6 @@ var DEFAULT_MODEL_CAPABILITIES = Object.freeze({
845
1098
  supportsTools: false,
846
1099
  supportsVision: true
847
1100
  },
848
- "openai/gpt-5.3": {
849
- // supportsTools: gateway unavailable at probe time — fails closed
850
- contextWindow: 128e3,
851
- maxOutputTokens: 128e3,
852
- supportsTools: false,
853
- supportsVision: true
854
- },
855
1101
  "openai/gpt-5.3-codex": {
856
1102
  // supportsTools: gateway unavailable at probe time — fails closed; override: 2026-08-29 probe: every request (6 plain + 3 tool attempts) returned a gateway 500, so the probe measured an incident, not the model. Codex's function calling is established by the 2026-07 Terminal-Bench / tau2 calibration trajectories in portfolio.ts. Hosts observing the 500s should drop it with RouterOptions.unavailableModels rather than this snapshot claiming the model cannot call tools.
857
1103
  contextWindow: 4e5,
@@ -957,6 +1203,13 @@ var DEFAULT_MODEL_CAPABILITIES = Object.freeze({
957
1203
  supportsTools: true,
958
1204
  supportsVision: false
959
1205
  },
1206
+ "poolside/laguna-xs-2.1": {
1207
+ // supportsTools: not probed — fails closed
1208
+ contextWindow: 131072,
1209
+ maxOutputTokens: 16384,
1210
+ supportsTools: false,
1211
+ supportsVision: false
1212
+ },
960
1213
  "qwen/qwen3.7-flash": {
961
1214
  contextWindow: 1e6,
962
1215
  maxOutputTokens: 65536,
@@ -3498,8 +3751,8 @@ var DEFAULT_ROUTING_CONFIG = {
3498
3751
  // $0.20/$1.25, 1M ctx
3499
3752
  "google/gemini-2.5-flash-lite",
3500
3753
  // $0.10/$0.40
3501
- "nvidia/step-3.7-flash"
3502
- // FREE backstop — NVIDIA free tier (probed 2026-08-21)
3754
+ "nvidia/nemotron-3.5-lightning"
3755
+ // FREE backstop — NVIDIA free tier (probed 2026-08-30)
3503
3756
  ]
3504
3757
  },
3505
3758
  MEDIUM: {
@@ -3588,15 +3841,19 @@ var DEFAULT_ROUTING_CONFIG = {
3588
3841
  // Eco tier configs - absolute cheapest (blockrun/eco)
3589
3842
  ecoTiers: {
3590
3843
  SIMPLE: {
3591
- primary: "nvidia/step-3.7-flash",
3592
- // FREE — NVIDIA free tier flagship
3844
+ primary: "nvidia/nemotron-3.5-lightning",
3845
+ // FREE — NVIDIA free tier flagship, 1M ctx
3593
3846
  fallback: [
3594
- "nvidia/nemotron-nano-9b-v2",
3595
- // FREE — compact + fast, high-volume light tasks
3847
+ "nvidia/nemotron-3-nano-30b",
3848
+ // FREE — fastest free model (~121 tok/s)
3596
3849
  // The free head keeps rotting with NVIDIA's hosting (deepseek-v4-flash
3597
3850
  // 410 2026-08-12, seed-oss-36b 410 2026-08-03, gpt-oss-120b/20b 400
3598
- // 2026-08-21). Each retirement retargets the two free rungs to the
3599
- // current free tier; the paid rungs below never move.
3851
+ // 2026-08-21, and on 2026-08-30 FOUR of the five visible free models at
3852
+ // once — step-3.7-flash, nemotron-nano-9b-v2 and nemotron-nano-12b-v2-vl
3853
+ // all 410, mistral-nemotron hung). Each retirement retargets the two
3854
+ // free rungs to the current free tier; the paid rungs below never move.
3855
+ // The head follows blockrun's own redirect of the model it replaces, so
3856
+ // the router and the gateway never name different models.
3600
3857
  "google/gemini-2.5-flash-lite",
3601
3858
  // $0.10/$0.40 — cheapest paid rung
3602
3859
  "zai/glm-5.3-flash",
@@ -3740,7 +3997,7 @@ var DEFAULT_ROUTING_CONFIG = {
3740
3997
  // strongest open-weight reasoner
3741
3998
  "deepseek/deepseek-chat",
3742
3999
  // Cheap, reliable
3743
- "nvidia/step-3.7-flash"
4000
+ "nvidia/nemotron-3.5-lightning"
3744
4001
  // NVIDIA free ultimate backstop
3745
4002
  ]
3746
4003
  },
@@ -3844,7 +4101,7 @@ var DEFAULT_ROUTING_CONFIG = {
3844
4101
  // retail high-risk 3/3
3845
4102
  "deepseek/deepseek-chat",
3846
4103
  // cheap, reliable
3847
- "nvidia/step-3.7-flash"
4104
+ "nvidia/nemotron-3.5-lightning"
3848
4105
  // NVIDIA free ultimate backstop
3849
4106
  ]
3850
4107
  },
@@ -4262,9 +4519,11 @@ function parsePaymentRequired(headerValue) {
4262
4519
  if (error.message.includes("Invalid payment required structure")) {
4263
4520
  throw error;
4264
4521
  }
4265
- throw new Error("Failed to parse payment required header: invalid format");
4522
+ throw new Error("Failed to parse payment required header: invalid format", {
4523
+ cause: error
4524
+ });
4266
4525
  }
4267
- throw new Error("Failed to parse payment required header");
4526
+ throw new Error("Failed to parse payment required header", { cause: error });
4268
4527
  }
4269
4528
  }
4270
4529
  function extractPaymentDetails(paymentRequired, preferredNetwork) {
@@ -4295,130 +4554,6 @@ function extractPaymentDetails(paymentRequired, preferredNetwork) {
4295
4554
  };
4296
4555
  }
4297
4556
 
4298
- // src/validation.ts
4299
- var LOCALHOST_DOMAINS = ["localhost", "127.0.0.1"];
4300
- var KNOWN_PROVIDERS = /* @__PURE__ */ new Set([
4301
- "openai",
4302
- "anthropic",
4303
- "google",
4304
- "deepseek",
4305
- "mistralai",
4306
- "meta-llama",
4307
- "together",
4308
- "xai",
4309
- "moonshot",
4310
- "nvidia",
4311
- "minimax",
4312
- "zai"
4313
- ]);
4314
- function validateModel(model) {
4315
- if (!model || typeof model !== "string") {
4316
- throw new Error("Model must be a non-empty string");
4317
- }
4318
- }
4319
- function validateMaxTokens(maxTokens) {
4320
- if (maxTokens === void 0 || maxTokens === null) {
4321
- return;
4322
- }
4323
- if (typeof maxTokens !== "number" || !Number.isInteger(maxTokens)) {
4324
- throw new Error("maxTokens must be an integer");
4325
- }
4326
- if (maxTokens < 1) {
4327
- throw new Error("maxTokens must be positive (minimum: 1)");
4328
- }
4329
- }
4330
- function validateTemperature(temperature) {
4331
- if (temperature === void 0 || temperature === null) {
4332
- return;
4333
- }
4334
- if (typeof temperature !== "number") {
4335
- throw new Error("temperature must be a number");
4336
- }
4337
- if (temperature < 0 || temperature > 2) {
4338
- throw new Error("temperature must be between 0 and 2");
4339
- }
4340
- }
4341
- function validateTopP(topP) {
4342
- if (topP === void 0 || topP === null) {
4343
- return;
4344
- }
4345
- if (typeof topP !== "number") {
4346
- throw new Error("topP must be a number");
4347
- }
4348
- if (topP < 0 || topP > 1) {
4349
- throw new Error("topP must be between 0 and 1");
4350
- }
4351
- }
4352
- function validatePrivateKey(key) {
4353
- if (typeof key !== "string") {
4354
- throw new Error("Private key must be a string");
4355
- }
4356
- if (!key.startsWith("0x")) {
4357
- throw new Error("Private key must start with 0x");
4358
- }
4359
- if (key.length !== 66) {
4360
- throw new Error(
4361
- "Private key must be 66 characters (0x + 64 hexadecimal characters)"
4362
- );
4363
- }
4364
- if (!/^0x[0-9a-fA-F]{64}$/.test(key)) {
4365
- throw new Error(
4366
- "Private key must contain only hexadecimal characters (0-9, a-f, A-F)"
4367
- );
4368
- }
4369
- }
4370
- function validateApiUrl(url) {
4371
- let parsed;
4372
- try {
4373
- parsed = new URL(url);
4374
- } catch {
4375
- throw new Error("Invalid API URL format");
4376
- }
4377
- if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
4378
- throw new Error(
4379
- `Invalid protocol: ${parsed.protocol}. Use http:// or https://`
4380
- );
4381
- }
4382
- const isLocalhost = LOCALHOST_DOMAINS.includes(parsed.hostname);
4383
- if (parsed.protocol !== "https:" && !isLocalhost) {
4384
- throw new Error(
4385
- `API URL must use HTTPS for non-localhost endpoints. Use https:// instead of ${parsed.protocol}//`
4386
- );
4387
- }
4388
- }
4389
- function sanitizeErrorResponse(errorBody) {
4390
- if (typeof errorBody !== "object" || errorBody === null) {
4391
- return { message: "API request failed" };
4392
- }
4393
- const body = errorBody;
4394
- return {
4395
- message: typeof body.error === "string" ? body.error : "API request failed",
4396
- code: typeof body.code === "string" ? body.code : void 0
4397
- };
4398
- }
4399
- function validateResourceUrl(url, baseUrl) {
4400
- try {
4401
- const parsed = new URL(url);
4402
- const baseParsed = new URL(baseUrl);
4403
- if (parsed.hostname !== baseParsed.hostname) {
4404
- console.warn(
4405
- `Resource URL hostname mismatch: ${parsed.hostname} vs ${baseParsed.hostname}. Using safe default instead.`
4406
- );
4407
- return `${baseUrl}/v1/chat/completions`;
4408
- }
4409
- if (parsed.protocol !== baseParsed.protocol) {
4410
- console.warn(
4411
- `Resource URL protocol mismatch: ${parsed.protocol} vs ${baseParsed.protocol}. Using safe default instead.`
4412
- );
4413
- return `${baseUrl}/v1/chat/completions`;
4414
- }
4415
- return url;
4416
- } catch {
4417
- console.warn(`Invalid resource URL format: ${url}. Using safe default.`);
4418
- return `${baseUrl}/v1/chat/completions`;
4419
- }
4420
- }
4421
-
4422
4557
  // src/cost-log.ts
4423
4558
  var fs = __toESM(require("fs"), 1);
4424
4559
  var path = __toESM(require("path"), 1);
@@ -4465,7 +4600,7 @@ function getCostSummary() {
4465
4600
  }
4466
4601
 
4467
4602
  // src/version.ts
4468
- var SDK_VERSION = "3.13.5";
4603
+ var SDK_VERSION = "3.14.0";
4469
4604
  var USER_AGENT = `blockrun-ts/${SDK_VERSION}`;
4470
4605
 
4471
4606
  // src/client.ts
@@ -4513,8 +4648,19 @@ function resolveDefaultTimeout() {
4513
4648
  var DEFAULT_TIMEOUT = resolveDefaultTimeout();
4514
4649
  var LLMClient = class _LLMClient {
4515
4650
  static DEFAULT_API_URL = DEFAULT_API_URL;
4516
- account;
4517
- privateKey;
4651
+ _account;
4652
+ get account() {
4653
+ return requireWallet(this._account);
4654
+ }
4655
+ apiAuth;
4656
+ /** Active billing mode. */
4657
+ get authMode() {
4658
+ return this.apiAuth ? "api-key" : "wallet";
4659
+ }
4660
+ _privateKey;
4661
+ get privateKey() {
4662
+ return requireWallet(this._privateKey);
4663
+ }
4518
4664
  apiUrl;
4519
4665
  timeout;
4520
4666
  sessionTotalUsd = 0;
@@ -4532,17 +4678,20 @@ var LLMClient = class _LLMClient {
4532
4678
  * @param options - Client configuration options (optional if BASE_CHAIN_WALLET_KEY env var is set)
4533
4679
  */
4534
4680
  constructor(options = {}) {
4535
- const envKey = typeof process !== "undefined" && process.env ? process.env.BASE_CHAIN_WALLET_KEY : void 0;
4536
- const privateKey = options.privateKey || envKey;
4537
- if (!privateKey) {
4538
- throw new Error(
4539
- "Private key required. Pass privateKey in options or set BASE_CHAIN_WALLET_KEY environment variable."
4540
- );
4681
+ this.apiAuth = resolveApiKeyAuth(options);
4682
+ if (!this.apiAuth) {
4683
+ const envKey = typeof process !== "undefined" && process.env ? process.env.BASE_CHAIN_WALLET_KEY : void 0;
4684
+ const privateKey = options.privateKey || envKey;
4685
+ if (!privateKey) {
4686
+ throw new Error(
4687
+ "Private key required. Pass privateKey in options or set BASE_CHAIN_WALLET_KEY environment variable."
4688
+ );
4689
+ }
4690
+ validatePrivateKey(privateKey);
4691
+ this._privateKey = privateKey;
4692
+ this._account = (0, import_accounts2.privateKeyToAccount)(privateKey);
4541
4693
  }
4542
- validatePrivateKey(privateKey);
4543
- this.privateKey = privateKey;
4544
- this.account = (0, import_accounts2.privateKeyToAccount)(privateKey);
4545
- const apiUrl = options.apiUrl || DEFAULT_API_URL;
4694
+ const apiUrl = this.apiAuth?.apiUrl || options.apiUrl || DEFAULT_API_URL;
4546
4695
  validateApiUrl(apiUrl);
4547
4696
  this.apiUrl = apiUrl.replace(/\/$/, "");
4548
4697
  this.timeout = options.timeout || DEFAULT_TIMEOUT;
@@ -4583,7 +4732,7 @@ var LLMClient = class _LLMClient {
4583
4732
  systemPrompt,
4584
4733
  maxOutputTokens,
4585
4734
  await this.getModelPricing(),
4586
- { ...options, minimumPaymentUsd: BASE_MINIMUM_PAYMENT_USD }
4735
+ { ...options, minimumPaymentUsd: this.apiAuth ? 0 : BASE_MINIMUM_PAYMENT_USD }
4587
4736
  );
4588
4737
  }
4589
4738
  /**
@@ -5169,6 +5318,7 @@ var LLMClient = class _LLMClient {
5169
5318
  sanitizeErrorResponse(errorBody)
5170
5319
  );
5171
5320
  }
5321
+ if (this.apiAuth && endpoint.startsWith("/v1/images/")) return this.apiAuth.poll(response, this.timeout, 2e3);
5172
5322
  return response.json();
5173
5323
  }
5174
5324
  /**
@@ -5421,7 +5571,7 @@ var LLMClient = class _LLMClient {
5421
5571
  const controller = new AbortController();
5422
5572
  const timeoutId = setTimeout(() => controller.abort(), this.timeout);
5423
5573
  try {
5424
- const response = await fetch(url, {
5574
+ const response = await (this.apiAuth ? this.apiAuth.fetch.bind(this.apiAuth) : fetch)(url, {
5425
5575
  ...options,
5426
5576
  signal: controller.signal
5427
5577
  });
@@ -5922,6 +6072,7 @@ var LLMClient = class _LLMClient {
5922
6072
  * console.log(`Spent $${spending.totalUsd.toFixed(4)} across ${spending.calls} calls`);
5923
6073
  */
5924
6074
  getSpending() {
6075
+ if (this.apiAuth) throw new Error("Account usage is available at https://user.blockrun.ai/dashboard; getSpending() tracks x402 settlements only.");
5925
6076
  return {
5926
6077
  totalUsd: this.sessionTotalUsd,
5927
6078
  calls: this.sessionCalls
@@ -5945,8 +6096,19 @@ var DEFAULT_TIMEOUT2 = 2e5;
5945
6096
  var POLL_INTERVAL_MS = 3e3;
5946
6097
  var POLL_MAX_DURATION_MS = 3e5;
5947
6098
  var ImageClient = class {
5948
- account;
5949
- privateKey;
6099
+ _account;
6100
+ get account() {
6101
+ return requireWallet(this._account);
6102
+ }
6103
+ apiAuth;
6104
+ /** Active billing mode. */
6105
+ get authMode() {
6106
+ return this.apiAuth ? "api-key" : "wallet";
6107
+ }
6108
+ _privateKey;
6109
+ get privateKey() {
6110
+ return requireWallet(this._privateKey);
6111
+ }
5950
6112
  apiUrl;
5951
6113
  timeout;
5952
6114
  sessionTotalUsd = 0;
@@ -5957,17 +6119,20 @@ var ImageClient = class {
5957
6119
  * @param options - Client configuration options
5958
6120
  */
5959
6121
  constructor(options = {}) {
5960
- const envKey = typeof process !== "undefined" && process.env ? process.env.BLOCKRUN_WALLET_KEY || process.env.BASE_CHAIN_WALLET_KEY : void 0;
5961
- const privateKey = options.privateKey || envKey;
5962
- if (!privateKey) {
5963
- throw new Error(
5964
- "Private key required. Pass privateKey in options or set BLOCKRUN_WALLET_KEY environment variable."
5965
- );
6122
+ this.apiAuth = resolveApiKeyAuth(options);
6123
+ if (!this.apiAuth) {
6124
+ const envKey = typeof process !== "undefined" && process.env ? process.env.BLOCKRUN_WALLET_KEY || process.env.BASE_CHAIN_WALLET_KEY : void 0;
6125
+ const privateKey = options.privateKey || envKey;
6126
+ if (!privateKey) {
6127
+ throw new Error(
6128
+ "Private key required. Pass privateKey in options or set BLOCKRUN_WALLET_KEY environment variable."
6129
+ );
6130
+ }
6131
+ validatePrivateKey(privateKey);
6132
+ this._privateKey = privateKey;
6133
+ this._account = (0, import_accounts3.privateKeyToAccount)(privateKey);
5966
6134
  }
5967
- validatePrivateKey(privateKey);
5968
- this.privateKey = privateKey;
5969
- this.account = (0, import_accounts3.privateKeyToAccount)(privateKey);
5970
- const apiUrl = options.apiUrl || DEFAULT_API_URL2;
6135
+ const apiUrl = this.apiAuth?.apiUrl || options.apiUrl || DEFAULT_API_URL2;
5971
6136
  validateApiUrl(apiUrl);
5972
6137
  this.apiUrl = apiUrl.replace(/\/$/, "");
5973
6138
  this.timeout = options.timeout || DEFAULT_TIMEOUT2;
@@ -6094,6 +6259,7 @@ var ImageClient = class {
6094
6259
  sanitizeErrorResponse(errorBody)
6095
6260
  );
6096
6261
  }
6262
+ if (this.apiAuth) return this.apiAuth.poll(response, POLL_MAX_DURATION_MS, POLL_INTERVAL_MS);
6097
6263
  return response.json();
6098
6264
  }
6099
6265
  /**
@@ -6231,7 +6397,7 @@ var ImageClient = class {
6231
6397
  const controller = new AbortController();
6232
6398
  const timeoutId = setTimeout(() => controller.abort(), this.timeout);
6233
6399
  try {
6234
- const response = await fetch(url, {
6400
+ const response = await (this.apiAuth ? this.apiAuth.fetch.bind(this.apiAuth) : fetch)(url, {
6235
6401
  ...options,
6236
6402
  signal: controller.signal
6237
6403
  });
@@ -6250,6 +6416,7 @@ var ImageClient = class {
6250
6416
  * Get session spending information.
6251
6417
  */
6252
6418
  getSpending() {
6419
+ if (this.apiAuth) throw new Error("Account usage is available at https://user.blockrun.ai/dashboard; getSpending() tracks x402 settlements only.");
6253
6420
  return {
6254
6421
  totalUsd: this.sessionTotalUsd,
6255
6422
  calls: this.sessionCalls
@@ -6263,24 +6430,38 @@ var DEFAULT_API_URL3 = "https://blockrun.ai/api";
6263
6430
  var DEFAULT_MODEL2 = "minimax/music-2.5+";
6264
6431
  var DEFAULT_TIMEOUT3 = 21e4;
6265
6432
  var MusicClient = class {
6266
- account;
6267
- privateKey;
6433
+ _account;
6434
+ get account() {
6435
+ return requireWallet(this._account);
6436
+ }
6437
+ apiAuth;
6438
+ /** Active billing mode. */
6439
+ get authMode() {
6440
+ return this.apiAuth ? "api-key" : "wallet";
6441
+ }
6442
+ _privateKey;
6443
+ get privateKey() {
6444
+ return requireWallet(this._privateKey);
6445
+ }
6268
6446
  apiUrl;
6269
6447
  timeout;
6270
6448
  sessionTotalUsd = 0;
6271
6449
  sessionCalls = 0;
6272
6450
  constructor(options = {}) {
6273
- const envKey = typeof process !== "undefined" && process.env ? process.env.BLOCKRUN_WALLET_KEY || process.env.BASE_CHAIN_WALLET_KEY : void 0;
6274
- const privateKey = options.privateKey || envKey;
6275
- if (!privateKey) {
6276
- throw new Error(
6277
- "Private key required. Pass privateKey in options or set BLOCKRUN_WALLET_KEY environment variable."
6278
- );
6451
+ this.apiAuth = resolveApiKeyAuth(options);
6452
+ if (!this.apiAuth) {
6453
+ const envKey = typeof process !== "undefined" && process.env ? process.env.BLOCKRUN_WALLET_KEY || process.env.BASE_CHAIN_WALLET_KEY : void 0;
6454
+ const privateKey = options.privateKey || envKey;
6455
+ if (!privateKey) {
6456
+ throw new Error(
6457
+ "Private key required. Pass privateKey in options or set BLOCKRUN_WALLET_KEY environment variable."
6458
+ );
6459
+ }
6460
+ validatePrivateKey(privateKey);
6461
+ this._privateKey = privateKey;
6462
+ this._account = (0, import_accounts4.privateKeyToAccount)(privateKey);
6279
6463
  }
6280
- validatePrivateKey(privateKey);
6281
- this.privateKey = privateKey;
6282
- this.account = (0, import_accounts4.privateKeyToAccount)(privateKey);
6283
- const apiUrl = options.apiUrl || DEFAULT_API_URL3;
6464
+ const apiUrl = this.apiAuth?.apiUrl || options.apiUrl || DEFAULT_API_URL3;
6284
6465
  validateApiUrl(apiUrl);
6285
6466
  this.apiUrl = apiUrl.replace(/\/$/, "");
6286
6467
  this.timeout = options.timeout || DEFAULT_TIMEOUT3;
@@ -6337,6 +6518,7 @@ var MusicClient = class {
6337
6518
  }
6338
6519
  throw new APIError(`API error: ${response.status}`, response.status, sanitizeErrorResponse(errorBody));
6339
6520
  }
6521
+ if (this.apiAuth) return this.apiAuth.poll(response, this.timeout, 5e3);
6340
6522
  return response.json();
6341
6523
  }
6342
6524
  async handlePaymentAndRetry(url, body, response) {
@@ -6399,7 +6581,7 @@ var MusicClient = class {
6399
6581
  const controller = new AbortController();
6400
6582
  const timeoutId = setTimeout(() => controller.abort(), this.timeout);
6401
6583
  try {
6402
- return await fetch(url, { ...options, signal: controller.signal });
6584
+ return await (this.apiAuth ? this.apiAuth.fetch.bind(this.apiAuth) : fetch)(url, { ...options, signal: controller.signal });
6403
6585
  } finally {
6404
6586
  clearTimeout(timeoutId);
6405
6587
  }
@@ -6408,6 +6590,7 @@ var MusicClient = class {
6408
6590
  return this.account.address;
6409
6591
  }
6410
6592
  getSpending() {
6593
+ if (this.apiAuth) throw new Error("Account usage is available at https://user.blockrun.ai/dashboard; getSpending() tracks x402 settlements only.");
6411
6594
  return { totalUsd: this.sessionTotalUsd, calls: this.sessionCalls };
6412
6595
  }
6413
6596
  };
@@ -6419,24 +6602,38 @@ var DEFAULT_MODEL3 = "elevenlabs/flash-v2.5";
6419
6602
  var DEFAULT_SOUNDFX_MODEL = "elevenlabs/sound-effects";
6420
6603
  var DEFAULT_TIMEOUT4 = 12e4;
6421
6604
  var SpeechClient = class {
6422
- account;
6423
- privateKey;
6605
+ _account;
6606
+ get account() {
6607
+ return requireWallet(this._account);
6608
+ }
6609
+ apiAuth;
6610
+ /** Active billing mode. */
6611
+ get authMode() {
6612
+ return this.apiAuth ? "api-key" : "wallet";
6613
+ }
6614
+ _privateKey;
6615
+ get privateKey() {
6616
+ return requireWallet(this._privateKey);
6617
+ }
6424
6618
  apiUrl;
6425
6619
  timeout;
6426
6620
  sessionTotalUsd = 0;
6427
6621
  sessionCalls = 0;
6428
6622
  constructor(options = {}) {
6429
- const envKey = typeof process !== "undefined" && process.env ? process.env.BLOCKRUN_WALLET_KEY || process.env.BASE_CHAIN_WALLET_KEY : void 0;
6430
- const privateKey = options.privateKey || envKey;
6431
- if (!privateKey) {
6432
- throw new Error(
6433
- "Private key required. Pass privateKey in options or set BLOCKRUN_WALLET_KEY environment variable."
6434
- );
6623
+ this.apiAuth = resolveApiKeyAuth(options);
6624
+ if (!this.apiAuth) {
6625
+ const envKey = typeof process !== "undefined" && process.env ? process.env.BLOCKRUN_WALLET_KEY || process.env.BASE_CHAIN_WALLET_KEY : void 0;
6626
+ const privateKey = options.privateKey || envKey;
6627
+ if (!privateKey) {
6628
+ throw new Error(
6629
+ "Private key required. Pass privateKey in options or set BLOCKRUN_WALLET_KEY environment variable."
6630
+ );
6631
+ }
6632
+ validatePrivateKey(privateKey);
6633
+ this._privateKey = privateKey;
6634
+ this._account = (0, import_accounts5.privateKeyToAccount)(privateKey);
6435
6635
  }
6436
- validatePrivateKey(privateKey);
6437
- this.privateKey = privateKey;
6438
- this.account = (0, import_accounts5.privateKeyToAccount)(privateKey);
6439
- const apiUrl = options.apiUrl || DEFAULT_API_URL4;
6636
+ const apiUrl = this.apiAuth?.apiUrl || options.apiUrl || DEFAULT_API_URL4;
6440
6637
  validateApiUrl(apiUrl);
6441
6638
  this.apiUrl = apiUrl.replace(/\/$/, "");
6442
6639
  this.timeout = options.timeout || DEFAULT_TIMEOUT4;
@@ -6598,7 +6795,7 @@ var SpeechClient = class {
6598
6795
  const controller = new AbortController();
6599
6796
  const timeoutId = setTimeout(() => controller.abort(), this.timeout);
6600
6797
  try {
6601
- return await fetch(url, { ...options, signal: controller.signal });
6798
+ return await (this.apiAuth ? this.apiAuth.fetch.bind(this.apiAuth) : fetch)(url, { ...options, signal: controller.signal });
6602
6799
  } finally {
6603
6800
  clearTimeout(timeoutId);
6604
6801
  }
@@ -6607,6 +6804,7 @@ var SpeechClient = class {
6607
6804
  return this.account.address;
6608
6805
  }
6609
6806
  getSpending() {
6807
+ if (this.apiAuth) throw new Error("Account usage is available at https://user.blockrun.ai/dashboard; getSpending() tracks x402 settlements only.");
6610
6808
  return { totalUsd: this.sessionTotalUsd, calls: this.sessionCalls };
6611
6809
  }
6612
6810
  };
@@ -6621,24 +6819,38 @@ var DEFAULT_GENERATE_BUDGET_MS = 9e5;
6621
6819
  var MAX_TIMEOUT_SECONDS = 600;
6622
6820
  var MAX_POLL_RESIGNS = 2;
6623
6821
  var VideoClient = class {
6624
- account;
6625
- privateKey;
6822
+ _account;
6823
+ get account() {
6824
+ return requireWallet(this._account);
6825
+ }
6826
+ apiAuth;
6827
+ /** Active billing mode. */
6828
+ get authMode() {
6829
+ return this.apiAuth ? "api-key" : "wallet";
6830
+ }
6831
+ _privateKey;
6832
+ get privateKey() {
6833
+ return requireWallet(this._privateKey);
6834
+ }
6626
6835
  apiUrl;
6627
6836
  timeout;
6628
6837
  sessionTotalUsd = 0;
6629
6838
  sessionCalls = 0;
6630
6839
  constructor(options = {}) {
6631
- const envKey = typeof process !== "undefined" && process.env ? process.env.BLOCKRUN_WALLET_KEY || process.env.BASE_CHAIN_WALLET_KEY : void 0;
6632
- const privateKey = options.privateKey || envKey;
6633
- if (!privateKey) {
6634
- throw new Error(
6635
- "Private key required. Pass privateKey in options or set BLOCKRUN_WALLET_KEY environment variable."
6636
- );
6840
+ this.apiAuth = resolveApiKeyAuth(options);
6841
+ if (!this.apiAuth) {
6842
+ const envKey = typeof process !== "undefined" && process.env ? process.env.BLOCKRUN_WALLET_KEY || process.env.BASE_CHAIN_WALLET_KEY : void 0;
6843
+ const privateKey = options.privateKey || envKey;
6844
+ if (!privateKey) {
6845
+ throw new Error(
6846
+ "Private key required. Pass privateKey in options or set BLOCKRUN_WALLET_KEY environment variable."
6847
+ );
6848
+ }
6849
+ validatePrivateKey(privateKey);
6850
+ this._privateKey = privateKey;
6851
+ this._account = (0, import_accounts6.privateKeyToAccount)(privateKey);
6637
6852
  }
6638
- validatePrivateKey(privateKey);
6639
- this.privateKey = privateKey;
6640
- this.account = (0, import_accounts6.privateKeyToAccount)(privateKey);
6641
- const apiUrl = options.apiUrl || DEFAULT_API_URL5;
6853
+ const apiUrl = this.apiAuth?.apiUrl || options.apiUrl || DEFAULT_API_URL5;
6642
6854
  validateApiUrl(apiUrl);
6643
6855
  this.apiUrl = apiUrl.replace(/\/$/, "");
6644
6856
  this.timeout = options.timeout || DEFAULT_TIMEOUT5;
@@ -6764,6 +6976,7 @@ var VideoClient = class {
6764
6976
  headers: { "Content-Type": "application/json" },
6765
6977
  body: JSON.stringify(body)
6766
6978
  });
6979
+ if (this.apiAuth) return this.apiAuth.poll(resp402, budgetMs, POLL_INTERVAL_MS2);
6767
6980
  if (resp402.status !== 402) {
6768
6981
  await this.throwApiError(resp402, "Expected 402 on first POST");
6769
6982
  }
@@ -6911,7 +7124,7 @@ var VideoClient = class {
6911
7124
  const controller = new AbortController();
6912
7125
  const timeoutId = setTimeout(() => controller.abort(), this.timeout);
6913
7126
  try {
6914
- return await fetch(url, { ...options, signal: controller.signal });
7127
+ return await (this.apiAuth ? this.apiAuth.fetch.bind(this.apiAuth) : fetch)(url, { ...options, signal: controller.signal });
6915
7128
  } finally {
6916
7129
  clearTimeout(timeoutId);
6917
7130
  }
@@ -6920,6 +7133,7 @@ var VideoClient = class {
6920
7133
  return this.account.address;
6921
7134
  }
6922
7135
  getSpending() {
7136
+ if (this.apiAuth) throw new Error("Account usage is available at https://user.blockrun.ai/dashboard; getSpending() tracks x402 settlements only.");
6923
7137
  return { totalUsd: this.sessionTotalUsd, calls: this.sessionCalls };
6924
7138
  }
6925
7139
  };
@@ -6931,24 +7145,38 @@ var DEFAULT_TIMEOUT6 = 6e4;
6931
7145
  var CALL_PRICE_USD = 0.54;
6932
7146
  var VALID_MODELS = /* @__PURE__ */ new Set(["base", "enhanced", "turbo"]);
6933
7147
  var VoiceClient = class {
6934
- account;
6935
- privateKey;
7148
+ _account;
7149
+ get account() {
7150
+ return requireWallet(this._account);
7151
+ }
7152
+ apiAuth;
7153
+ /** Active billing mode. */
7154
+ get authMode() {
7155
+ return this.apiAuth ? "api-key" : "wallet";
7156
+ }
7157
+ _privateKey;
7158
+ get privateKey() {
7159
+ return requireWallet(this._privateKey);
7160
+ }
6936
7161
  apiUrl;
6937
7162
  timeout;
6938
7163
  sessionTotalUsd = 0;
6939
7164
  sessionCalls = 0;
6940
7165
  constructor(options = {}) {
6941
- const envKey = typeof process !== "undefined" && process.env ? process.env.BLOCKRUN_WALLET_KEY || process.env.BASE_CHAIN_WALLET_KEY : void 0;
6942
- const privateKey = options.privateKey || envKey;
6943
- if (!privateKey) {
6944
- throw new Error(
6945
- "Private key required. Pass privateKey in options or set BLOCKRUN_WALLET_KEY environment variable."
6946
- );
7166
+ this.apiAuth = resolveApiKeyAuth(options);
7167
+ if (!this.apiAuth) {
7168
+ const envKey = typeof process !== "undefined" && process.env ? process.env.BLOCKRUN_WALLET_KEY || process.env.BASE_CHAIN_WALLET_KEY : void 0;
7169
+ const privateKey = options.privateKey || envKey;
7170
+ if (!privateKey) {
7171
+ throw new Error(
7172
+ "Private key required. Pass privateKey in options or set BLOCKRUN_WALLET_KEY environment variable."
7173
+ );
7174
+ }
7175
+ validatePrivateKey(privateKey);
7176
+ this._privateKey = privateKey;
7177
+ this._account = (0, import_accounts7.privateKeyToAccount)(privateKey);
6947
7178
  }
6948
- validatePrivateKey(privateKey);
6949
- this.privateKey = privateKey;
6950
- this.account = (0, import_accounts7.privateKeyToAccount)(privateKey);
6951
- const apiUrl = options.apiUrl || DEFAULT_API_URL6;
7179
+ const apiUrl = this.apiAuth?.apiUrl || options.apiUrl || DEFAULT_API_URL6;
6952
7180
  validateApiUrl(apiUrl);
6953
7181
  this.apiUrl = apiUrl.replace(/\/$/, "");
6954
7182
  this.timeout = options.timeout || DEFAULT_TIMEOUT6;
@@ -7112,7 +7340,7 @@ var VoiceClient = class {
7112
7340
  const controller = new AbortController();
7113
7341
  const timeoutId = setTimeout(() => controller.abort(), this.timeout);
7114
7342
  try {
7115
- return await fetch(url, { ...options, signal: controller.signal });
7343
+ return await (this.apiAuth ? this.apiAuth.fetch.bind(this.apiAuth) : fetch)(url, { ...options, signal: controller.signal });
7116
7344
  } finally {
7117
7345
  clearTimeout(timeoutId);
7118
7346
  }
@@ -7121,6 +7349,7 @@ var VoiceClient = class {
7121
7349
  return this.account.address;
7122
7350
  }
7123
7351
  getSpending() {
7352
+ if (this.apiAuth) throw new Error("Account usage is available at https://user.blockrun.ai/dashboard; getSpending() tracks x402 settlements only.");
7124
7353
  return { totalUsd: this.sessionTotalUsd, calls: this.sessionCalls };
7125
7354
  }
7126
7355
  };
@@ -7150,24 +7379,38 @@ function requireE164(value) {
7150
7379
  return v;
7151
7380
  }
7152
7381
  var PhoneClient = class {
7153
- account;
7154
- privateKey;
7382
+ _account;
7383
+ get account() {
7384
+ return requireWallet(this._account);
7385
+ }
7386
+ apiAuth;
7387
+ /** Active billing mode. */
7388
+ get authMode() {
7389
+ return this.apiAuth ? "api-key" : "wallet";
7390
+ }
7391
+ _privateKey;
7392
+ get privateKey() {
7393
+ return requireWallet(this._privateKey);
7394
+ }
7155
7395
  apiUrl;
7156
7396
  timeout;
7157
7397
  sessionTotalUsd = 0;
7158
7398
  sessionCalls = 0;
7159
7399
  constructor(options = {}) {
7160
- const envKey = typeof process !== "undefined" && process.env ? process.env.BLOCKRUN_WALLET_KEY || process.env.BASE_CHAIN_WALLET_KEY : void 0;
7161
- const privateKey = options.privateKey || envKey;
7162
- if (!privateKey) {
7163
- throw new Error(
7164
- "Private key required. Pass privateKey in options or set BLOCKRUN_WALLET_KEY environment variable."
7165
- );
7400
+ this.apiAuth = resolveApiKeyAuth(options);
7401
+ if (!this.apiAuth) {
7402
+ const envKey = typeof process !== "undefined" && process.env ? process.env.BLOCKRUN_WALLET_KEY || process.env.BASE_CHAIN_WALLET_KEY : void 0;
7403
+ const privateKey = options.privateKey || envKey;
7404
+ if (!privateKey) {
7405
+ throw new Error(
7406
+ "Private key required. Pass privateKey in options or set BLOCKRUN_WALLET_KEY environment variable."
7407
+ );
7408
+ }
7409
+ validatePrivateKey(privateKey);
7410
+ this._privateKey = privateKey;
7411
+ this._account = (0, import_accounts8.privateKeyToAccount)(privateKey);
7166
7412
  }
7167
- validatePrivateKey(privateKey);
7168
- this.privateKey = privateKey;
7169
- this.account = (0, import_accounts8.privateKeyToAccount)(privateKey);
7170
- const apiUrl = options.apiUrl || DEFAULT_API_URL7;
7413
+ const apiUrl = this.apiAuth?.apiUrl || options.apiUrl || DEFAULT_API_URL7;
7171
7414
  validateApiUrl(apiUrl);
7172
7415
  this.apiUrl = apiUrl.replace(/\/$/, "");
7173
7416
  this.timeout = options.timeout || DEFAULT_TIMEOUT7;
@@ -7178,6 +7421,7 @@ var PhoneClient = class {
7178
7421
  }
7179
7422
  /** Session-cumulative USD spend + call count across this client instance. */
7180
7423
  getSpending() {
7424
+ if (this.apiAuth) throw new Error("Account usage is available at https://user.blockrun.ai/dashboard; getSpending() tracks x402 settlements only.");
7181
7425
  return { totalUsd: this.sessionTotalUsd, calls: this.sessionCalls };
7182
7426
  }
7183
7427
  // ─── Lookup ────────────────────────────────────────────────────────────
@@ -7337,7 +7581,7 @@ var PhoneClient = class {
7337
7581
  const controller = new AbortController();
7338
7582
  const timeoutId = setTimeout(() => controller.abort(), this.timeout);
7339
7583
  try {
7340
- return await fetch(url, { ...init, signal: controller.signal });
7584
+ return await (this.apiAuth ? this.apiAuth.fetch.bind(this.apiAuth) : fetch)(url, { ...init, signal: controller.signal });
7341
7585
  } finally {
7342
7586
  clearTimeout(timeoutId);
7343
7587
  }
@@ -7350,24 +7594,38 @@ var DEFAULT_API_URL8 = "https://blockrun.ai/api";
7350
7594
  var DEFAULT_TIMEOUT8 = 6e4;
7351
7595
  var PORTRAIT_ENROLLMENT_PRICE_USD = 0.01;
7352
7596
  var PortraitClient = class {
7353
- account;
7354
- privateKey;
7597
+ _account;
7598
+ get account() {
7599
+ return requireWallet(this._account);
7600
+ }
7601
+ apiAuth;
7602
+ /** Active billing mode. */
7603
+ get authMode() {
7604
+ return this.apiAuth ? "api-key" : "wallet";
7605
+ }
7606
+ _privateKey;
7607
+ get privateKey() {
7608
+ return requireWallet(this._privateKey);
7609
+ }
7355
7610
  apiUrl;
7356
7611
  timeout;
7357
7612
  sessionTotalUsd = 0;
7358
7613
  sessionCalls = 0;
7359
7614
  constructor(options = {}) {
7360
- const envKey = typeof process !== "undefined" && process.env ? process.env.BLOCKRUN_WALLET_KEY || process.env.BASE_CHAIN_WALLET_KEY : void 0;
7361
- const privateKey = options.privateKey || envKey;
7362
- if (!privateKey) {
7363
- throw new Error(
7364
- "Private key required. Pass privateKey in options or set BLOCKRUN_WALLET_KEY environment variable."
7365
- );
7615
+ this.apiAuth = resolveApiKeyAuth(options);
7616
+ if (!this.apiAuth) {
7617
+ const envKey = typeof process !== "undefined" && process.env ? process.env.BLOCKRUN_WALLET_KEY || process.env.BASE_CHAIN_WALLET_KEY : void 0;
7618
+ const privateKey = options.privateKey || envKey;
7619
+ if (!privateKey) {
7620
+ throw new Error(
7621
+ "Private key required. Pass privateKey in options or set BLOCKRUN_WALLET_KEY environment variable."
7622
+ );
7623
+ }
7624
+ validatePrivateKey(privateKey);
7625
+ this._privateKey = privateKey;
7626
+ this._account = (0, import_accounts9.privateKeyToAccount)(privateKey);
7366
7627
  }
7367
- validatePrivateKey(privateKey);
7368
- this.privateKey = privateKey;
7369
- this.account = (0, import_accounts9.privateKeyToAccount)(privateKey);
7370
- const apiUrl = options.apiUrl || DEFAULT_API_URL8;
7628
+ const apiUrl = this.apiAuth?.apiUrl || options.apiUrl || DEFAULT_API_URL8;
7371
7629
  validateApiUrl(apiUrl);
7372
7630
  this.apiUrl = apiUrl.replace(/\/$/, "");
7373
7631
  this.timeout = options.timeout || DEFAULT_TIMEOUT8;
@@ -7378,6 +7636,7 @@ var PortraitClient = class {
7378
7636
  }
7379
7637
  /** Session-cumulative USD spend + call count across this client instance. */
7380
7638
  getSpending() {
7639
+ if (this.apiAuth) throw new Error("Account usage is available at https://user.blockrun.ai/dashboard; getSpending() tracks x402 settlements only.");
7381
7640
  return { totalUsd: this.sessionTotalUsd, calls: this.sessionCalls };
7382
7641
  }
7383
7642
  /**
@@ -7491,7 +7750,7 @@ var PortraitClient = class {
7491
7750
  const controller = new AbortController();
7492
7751
  const timeoutId = setTimeout(() => controller.abort(), this.timeout);
7493
7752
  try {
7494
- return await fetch(url, { ...init, signal: controller.signal });
7753
+ return await (this.apiAuth ? this.apiAuth.fetch.bind(this.apiAuth) : fetch)(url, { ...init, signal: controller.signal });
7495
7754
  } finally {
7496
7755
  clearTimeout(timeoutId);
7497
7756
  }
@@ -7503,22 +7762,36 @@ var import_accounts10 = require("viem/accounts");
7503
7762
  var DEFAULT_API_URL9 = "https://blockrun.ai/api";
7504
7763
  var DEFAULT_TIMEOUT9 = 6e4;
7505
7764
  var SearchClient = class {
7506
- account;
7507
- privateKey;
7765
+ _account;
7766
+ get account() {
7767
+ return requireWallet(this._account);
7768
+ }
7769
+ apiAuth;
7770
+ /** Active billing mode. */
7771
+ get authMode() {
7772
+ return this.apiAuth ? "api-key" : "wallet";
7773
+ }
7774
+ _privateKey;
7775
+ get privateKey() {
7776
+ return requireWallet(this._privateKey);
7777
+ }
7508
7778
  apiUrl;
7509
7779
  timeout;
7510
7780
  constructor(options = {}) {
7511
- const envKey = typeof process !== "undefined" && process.env ? process.env.BLOCKRUN_WALLET_KEY || process.env.BASE_CHAIN_WALLET_KEY : void 0;
7512
- const privateKey = options.privateKey || envKey;
7513
- if (!privateKey) {
7514
- throw new Error(
7515
- "Private key required. Pass privateKey in options or set BLOCKRUN_WALLET_KEY environment variable."
7516
- );
7781
+ this.apiAuth = resolveApiKeyAuth(options);
7782
+ if (!this.apiAuth) {
7783
+ const envKey = typeof process !== "undefined" && process.env ? process.env.BLOCKRUN_WALLET_KEY || process.env.BASE_CHAIN_WALLET_KEY : void 0;
7784
+ const privateKey = options.privateKey || envKey;
7785
+ if (!privateKey) {
7786
+ throw new Error(
7787
+ "Private key required. Pass privateKey in options or set BLOCKRUN_WALLET_KEY environment variable."
7788
+ );
7789
+ }
7790
+ validatePrivateKey(privateKey);
7791
+ this._privateKey = privateKey;
7792
+ this._account = (0, import_accounts10.privateKeyToAccount)(privateKey);
7517
7793
  }
7518
- validatePrivateKey(privateKey);
7519
- this.privateKey = privateKey;
7520
- this.account = (0, import_accounts10.privateKeyToAccount)(privateKey);
7521
- const apiUrl = options.apiUrl || DEFAULT_API_URL9;
7794
+ const apiUrl = this.apiAuth?.apiUrl || options.apiUrl || DEFAULT_API_URL9;
7522
7795
  validateApiUrl(apiUrl);
7523
7796
  this.apiUrl = apiUrl.replace(/\/$/, "");
7524
7797
  this.timeout = options.timeout || DEFAULT_TIMEOUT9;
@@ -7624,7 +7897,7 @@ var SearchClient = class {
7624
7897
  const controller = new AbortController();
7625
7898
  const timeoutId = setTimeout(() => controller.abort(), this.timeout);
7626
7899
  try {
7627
- return await fetch(url, { ...init, signal: controller.signal });
7900
+ return await (this.apiAuth ? this.apiAuth.fetch.bind(this.apiAuth) : fetch)(url, { ...init, signal: controller.signal });
7628
7901
  } finally {
7629
7902
  clearTimeout(timeoutId);
7630
7903
  }
@@ -7639,15 +7912,20 @@ var import_accounts11 = require("viem/accounts");
7639
7912
  var DEFAULT_API_URL10 = "https://blockrun.ai/api";
7640
7913
  var DEFAULT_TIMEOUT10 = 3e4;
7641
7914
  var PriceClient = class {
7915
+ apiAuth;
7916
+ get authMode() {
7917
+ return this.apiAuth ? "api-key" : "wallet";
7918
+ }
7642
7919
  account = null;
7643
7920
  privateKey = null;
7644
7921
  apiUrl;
7645
7922
  timeout;
7646
7923
  constructor(options = {}) {
7924
+ this.apiAuth = resolveApiKeyAuth(options);
7647
7925
  const envKey = typeof process !== "undefined" && process.env ? process.env.BLOCKRUN_WALLET_KEY || process.env.BASE_CHAIN_WALLET_KEY : void 0;
7648
- const privateKey = options.privateKey || envKey;
7649
- const requireWallet = options.requireWallet ?? true;
7650
- if (!privateKey && requireWallet) {
7926
+ const privateKey = this.apiAuth ? void 0 : options.privateKey || envKey;
7927
+ const requireWallet2 = options.requireWallet ?? true;
7928
+ if (!this.apiAuth && !privateKey && requireWallet2) {
7651
7929
  throw new Error(
7652
7930
  "Private key required for paid endpoints. Pass privateKey in options, set BLOCKRUN_WALLET_KEY, or pass requireWallet: false for free-only usage."
7653
7931
  );
@@ -7657,7 +7935,7 @@ var PriceClient = class {
7657
7935
  this.privateKey = privateKey;
7658
7936
  this.account = (0, import_accounts11.privateKeyToAccount)(privateKey);
7659
7937
  }
7660
- const apiUrl = options.apiUrl || DEFAULT_API_URL10;
7938
+ const apiUrl = this.apiAuth?.apiUrl || options.apiUrl || DEFAULT_API_URL10;
7661
7939
  validateApiUrl(apiUrl);
7662
7940
  this.apiUrl = apiUrl.replace(/\/$/, "");
7663
7941
  this.timeout = options.timeout || DEFAULT_TIMEOUT10;
@@ -7810,7 +8088,7 @@ var PriceClient = class {
7810
8088
  const controller = new AbortController();
7811
8089
  const timeoutId = setTimeout(() => controller.abort(), this.timeout);
7812
8090
  try {
7813
- return await fetch(url, { ...init, signal: controller.signal });
8091
+ return await (this.apiAuth ? this.apiAuth.fetch.bind(this.apiAuth) : fetch)(url, { ...init, signal: controller.signal });
7814
8092
  } finally {
7815
8093
  clearTimeout(timeoutId);
7816
8094
  }
@@ -7844,22 +8122,36 @@ var DEFAULT_API_URL11 = "https://blockrun.ai/api";
7844
8122
  var DEFAULT_TIMEOUT11 = 6e4;
7845
8123
  var SURF_PREFIX = "/v1/surf";
7846
8124
  var SurfClient = class {
7847
- account;
7848
- privateKey;
8125
+ _account;
8126
+ get account() {
8127
+ return requireWallet(this._account);
8128
+ }
8129
+ apiAuth;
8130
+ /** Active billing mode. */
8131
+ get authMode() {
8132
+ return this.apiAuth ? "api-key" : "wallet";
8133
+ }
8134
+ _privateKey;
8135
+ get privateKey() {
8136
+ return requireWallet(this._privateKey);
8137
+ }
7849
8138
  apiUrl;
7850
8139
  timeout;
7851
8140
  constructor(options = {}) {
7852
- const envKey = typeof process !== "undefined" && process.env ? process.env.BLOCKRUN_WALLET_KEY || process.env.BASE_CHAIN_WALLET_KEY : void 0;
7853
- const privateKey = options.privateKey || envKey;
7854
- if (!privateKey) {
7855
- throw new Error(
7856
- "Private key required. Pass privateKey in options or set BLOCKRUN_WALLET_KEY environment variable."
7857
- );
8141
+ this.apiAuth = resolveApiKeyAuth(options);
8142
+ if (!this.apiAuth) {
8143
+ const envKey = typeof process !== "undefined" && process.env ? process.env.BLOCKRUN_WALLET_KEY || process.env.BASE_CHAIN_WALLET_KEY : void 0;
8144
+ const privateKey = options.privateKey || envKey;
8145
+ if (!privateKey) {
8146
+ throw new Error(
8147
+ "Private key required. Pass privateKey in options or set BLOCKRUN_WALLET_KEY environment variable."
8148
+ );
8149
+ }
8150
+ validatePrivateKey(privateKey);
8151
+ this._privateKey = privateKey;
8152
+ this._account = (0, import_accounts12.privateKeyToAccount)(privateKey);
7858
8153
  }
7859
- validatePrivateKey(privateKey);
7860
- this.privateKey = privateKey;
7861
- this.account = (0, import_accounts12.privateKeyToAccount)(privateKey);
7862
- const apiUrl = options.apiUrl || DEFAULT_API_URL11;
8154
+ const apiUrl = this.apiAuth?.apiUrl || options.apiUrl || DEFAULT_API_URL11;
7863
8155
  validateApiUrl(apiUrl);
7864
8156
  this.apiUrl = apiUrl.replace(/\/$/, "");
7865
8157
  this.timeout = options.timeout || DEFAULT_TIMEOUT11;
@@ -7983,7 +8275,7 @@ var SurfClient = class {
7983
8275
  const controller = new AbortController();
7984
8276
  const timeoutId = setTimeout(() => controller.abort(), this.timeout);
7985
8277
  try {
7986
- return await fetch(url, { ...init, signal: controller.signal });
8278
+ return await (this.apiAuth ? this.apiAuth.fetch.bind(this.apiAuth) : fetch)(url, { ...init, signal: controller.signal });
7987
8279
  } finally {
7988
8280
  clearTimeout(timeoutId);
7989
8281
  }
@@ -8072,24 +8364,38 @@ var NETWORK_ALIASES = {
8072
8364
  zec: "zcash"
8073
8365
  };
8074
8366
  var RpcClient = class {
8075
- account;
8076
- privateKey;
8367
+ _account;
8368
+ get account() {
8369
+ return requireWallet(this._account);
8370
+ }
8371
+ apiAuth;
8372
+ /** Active billing mode. */
8373
+ get authMode() {
8374
+ return this.apiAuth ? "api-key" : "wallet";
8375
+ }
8376
+ _privateKey;
8377
+ get privateKey() {
8378
+ return requireWallet(this._privateKey);
8379
+ }
8077
8380
  apiUrl;
8078
8381
  timeout;
8079
8382
  sessionTotalUsd = 0;
8080
8383
  sessionCalls = 0;
8081
8384
  constructor(options = {}) {
8082
- const envKey = typeof process !== "undefined" && process.env ? process.env.BLOCKRUN_WALLET_KEY || process.env.BASE_CHAIN_WALLET_KEY : void 0;
8083
- const privateKey = options.privateKey || envKey;
8084
- if (!privateKey) {
8085
- throw new Error(
8086
- "Private key required. Pass privateKey in options or set BLOCKRUN_WALLET_KEY environment variable."
8087
- );
8385
+ this.apiAuth = resolveApiKeyAuth(options);
8386
+ if (!this.apiAuth) {
8387
+ const envKey = typeof process !== "undefined" && process.env ? process.env.BLOCKRUN_WALLET_KEY || process.env.BASE_CHAIN_WALLET_KEY : void 0;
8388
+ const privateKey = options.privateKey || envKey;
8389
+ if (!privateKey) {
8390
+ throw new Error(
8391
+ "Private key required. Pass privateKey in options or set BLOCKRUN_WALLET_KEY environment variable."
8392
+ );
8393
+ }
8394
+ validatePrivateKey(privateKey);
8395
+ this._privateKey = privateKey;
8396
+ this._account = (0, import_accounts13.privateKeyToAccount)(privateKey);
8088
8397
  }
8089
- validatePrivateKey(privateKey);
8090
- this.privateKey = privateKey;
8091
- this.account = (0, import_accounts13.privateKeyToAccount)(privateKey);
8092
- const apiUrl = options.apiUrl || DEFAULT_API_URL12;
8398
+ const apiUrl = this.apiAuth?.apiUrl || options.apiUrl || DEFAULT_API_URL12;
8093
8399
  validateApiUrl(apiUrl);
8094
8400
  this.apiUrl = apiUrl.replace(/\/$/, "");
8095
8401
  this.timeout = options.timeout || DEFAULT_TIMEOUT12;
@@ -8233,7 +8539,7 @@ var RpcClient = class {
8233
8539
  const controller = new AbortController();
8234
8540
  const timeoutId = setTimeout(() => controller.abort(), this.timeout);
8235
8541
  try {
8236
- return await fetch(url, { ...options, signal: controller.signal });
8542
+ return await (this.apiAuth ? this.apiAuth.fetch.bind(this.apiAuth) : fetch)(url, { ...options, signal: controller.signal });
8237
8543
  } finally {
8238
8544
  clearTimeout(timeoutId);
8239
8545
  }
@@ -8242,6 +8548,7 @@ var RpcClient = class {
8242
8548
  return this.account.address;
8243
8549
  }
8244
8550
  getSpending() {
8551
+ if (this.apiAuth) throw new Error("Account usage is available at https://user.blockrun.ai/dashboard; getSpending() tracks x402 settlements only.");
8245
8552
  return { totalUsd: this.sessionTotalUsd, calls: this.sessionCalls };
8246
8553
  }
8247
8554
  };
@@ -8254,24 +8561,38 @@ var DEFAULT_POLL_INTERVAL_MS = 5e3;
8254
8561
  var DEFAULT_POLL_BUDGET_MS = 3e5;
8255
8562
  var MAX_SIGNED_AUTH_SECONDS = 600;
8256
8563
  var BlockrunClient = class {
8257
- account;
8258
- privateKey;
8564
+ _account;
8565
+ get account() {
8566
+ return requireWallet(this._account);
8567
+ }
8568
+ apiAuth;
8569
+ /** Active billing mode. */
8570
+ get authMode() {
8571
+ return this.apiAuth ? "api-key" : "wallet";
8572
+ }
8573
+ _privateKey;
8574
+ get privateKey() {
8575
+ return requireWallet(this._privateKey);
8576
+ }
8259
8577
  apiUrl;
8260
8578
  timeout;
8261
8579
  sessionTotalUsd = 0;
8262
8580
  sessionCalls = 0;
8263
8581
  constructor(options = {}) {
8264
- const envKey = typeof process !== "undefined" && process.env ? process.env.BLOCKRUN_WALLET_KEY || process.env.BASE_CHAIN_WALLET_KEY : void 0;
8265
- const privateKey = options.privateKey || envKey;
8266
- if (!privateKey) {
8267
- throw new Error(
8268
- "Private key required. Pass privateKey in options or set BLOCKRUN_WALLET_KEY environment variable."
8269
- );
8582
+ this.apiAuth = resolveApiKeyAuth(options);
8583
+ if (!this.apiAuth) {
8584
+ const envKey = typeof process !== "undefined" && process.env ? process.env.BLOCKRUN_WALLET_KEY || process.env.BASE_CHAIN_WALLET_KEY : void 0;
8585
+ const privateKey = options.privateKey || envKey;
8586
+ if (!privateKey) {
8587
+ throw new Error(
8588
+ "Private key required. Pass privateKey in options or set BLOCKRUN_WALLET_KEY environment variable."
8589
+ );
8590
+ }
8591
+ validatePrivateKey(privateKey);
8592
+ this._privateKey = privateKey;
8593
+ this._account = (0, import_accounts14.privateKeyToAccount)(privateKey);
8270
8594
  }
8271
- validatePrivateKey(privateKey);
8272
- this.privateKey = privateKey;
8273
- this.account = (0, import_accounts14.privateKeyToAccount)(privateKey);
8274
- const apiUrl = options.apiUrl || DEFAULT_API_URL13;
8595
+ const apiUrl = this.apiAuth?.apiUrl || options.apiUrl || DEFAULT_API_URL13;
8275
8596
  validateApiUrl(apiUrl);
8276
8597
  this.apiUrl = apiUrl.replace(/\/$/, "");
8277
8598
  this.timeout = options.timeout || DEFAULT_TIMEOUT13;
@@ -8313,6 +8634,7 @@ var BlockrunClient = class {
8313
8634
  headers: { "Content-Type": "application/json" },
8314
8635
  body: JSON.stringify(body ?? {})
8315
8636
  });
8637
+ if (this.apiAuth) return this.apiAuth.poll(resp402, budgetMs, intervalMs);
8316
8638
  if (resp402.status === 200) {
8317
8639
  return resp402.json();
8318
8640
  }
@@ -8605,7 +8927,7 @@ var BlockrunClient = class {
8605
8927
  const controller = new AbortController();
8606
8928
  const timeoutId = setTimeout(() => controller.abort(), this.timeout);
8607
8929
  try {
8608
- return await fetch(url, { ...init, signal: controller.signal });
8930
+ return await (this.apiAuth ? this.apiAuth.fetch.bind(this.apiAuth) : fetch)(url, { ...init, signal: controller.signal });
8609
8931
  } finally {
8610
8932
  clearTimeout(timeoutId);
8611
8933
  }
@@ -8617,6 +8939,7 @@ var BlockrunClient = class {
8617
8939
  return this.account.address;
8618
8940
  }
8619
8941
  getSpending() {
8942
+ if (this.apiAuth) throw new Error("Account usage is available at https://user.blockrun.ai/dashboard; getSpending() tracks x402 settlements only.");
8620
8943
  return { totalUsd: this.sessionTotalUsd, calls: this.sessionCalls };
8621
8944
  }
8622
8945
  };
@@ -8627,7 +8950,7 @@ function sleep(ms) {
8627
8950
  // src/wallet.ts
8628
8951
  var import_accounts16 = require("viem/accounts");
8629
8952
 
8630
- // node_modules/.pnpm/@blockrun+core@0.1.1_bufferutil@4.1.0_typescript@5.9.3_utf-8-validate@6.0.6_zod@3.25.76/node_modules/@blockrun/core/dist/config.js
8953
+ // node_modules/.pnpm/@blockrun+core@0.1.1_bufferutil@4.1.0_typescript@6.0.3_utf-8-validate@6.0.6_zod@3.25.76/node_modules/@blockrun/core/dist/config.js
8631
8954
  var fs2 = __toESM(require("fs"), 1);
8632
8955
  var os2 = __toESM(require("os"), 1);
8633
8956
  var path2 = __toESM(require("path"), 1);
@@ -8649,7 +8972,7 @@ function paths() {
8649
8972
  };
8650
8973
  }
8651
8974
 
8652
- // node_modules/.pnpm/@blockrun+core@0.1.1_bufferutil@4.1.0_typescript@5.9.3_utf-8-validate@6.0.6_zod@3.25.76/node_modules/@blockrun/core/dist/wallet.js
8975
+ // node_modules/.pnpm/@blockrun+core@0.1.1_bufferutil@4.1.0_typescript@6.0.3_utf-8-validate@6.0.6_zod@3.25.76/node_modules/@blockrun/core/dist/wallet.js
8653
8976
  var fs3 = __toESM(require("fs"), 1);
8654
8977
  var path3 = __toESM(require("path"), 1);
8655
8978
  var import_accounts15 = require("viem/accounts");
@@ -8945,7 +9268,8 @@ async function solanaKeyToBytes(privateKey) {
8945
9268
  } catch (err) {
8946
9269
  const msg = err instanceof Error ? err.message : String(err);
8947
9270
  throw new Error(
8948
- `Invalid Solana private key: ${msg}. Expected a base58-encoded 64-byte key (standard Solana format), a 64-byte hex string, or a Solana CLI JSON byte array.`
9271
+ `Invalid Solana private key: ${msg}. Expected a base58-encoded 64-byte key (standard Solana format), a 64-byte hex string, or a Solana CLI JSON byte array.`,
9272
+ { cause: err }
8949
9273
  );
8950
9274
  }
8951
9275
  }
@@ -9091,7 +9415,7 @@ async function solanaPublicKeyFrom(privateKey, source) {
9091
9415
  return await solanaPublicKey(privateKey);
9092
9416
  } catch (err) {
9093
9417
  const msg = err instanceof Error ? err.message : String(err);
9094
- throw new Error(`${msg} (key loaded from ${source})`);
9418
+ throw new Error(`${msg} (key loaded from ${source})`, { cause: err });
9095
9419
  }
9096
9420
  }
9097
9421
  async function getOrCreateSolanaWallet() {
@@ -9205,7 +9529,14 @@ function resolveRpcConfig(rpcUrl, rpcHeaders) {
9205
9529
  }
9206
9530
  var SolanaLLMClient = class {
9207
9531
  static SOLANA_API_URL = SOLANA_API_URL;
9208
- privateKey;
9532
+ apiAuth;
9533
+ get authMode() {
9534
+ return this.apiAuth ? "api-key" : "wallet";
9535
+ }
9536
+ _privateKey;
9537
+ get privateKey() {
9538
+ return requireWallet(this._privateKey);
9539
+ }
9209
9540
  apiUrl;
9210
9541
  rpcUrl;
9211
9542
  rpcHeaders;
@@ -9216,15 +9547,18 @@ var SolanaLLMClient = class {
9216
9547
  modelPricingCache = null;
9217
9548
  modelPricingPromise = null;
9218
9549
  constructor(options = {}) {
9219
- const envKey = typeof process !== "undefined" && process.env ? process.env.SOLANA_WALLET_KEY : void 0;
9220
- const privateKey = options.privateKey || envKey;
9221
- if (!privateKey) {
9222
- throw new Error(
9223
- "Private key required. Pass privateKey in options or set SOLANA_WALLET_KEY environment variable."
9224
- );
9550
+ this.apiAuth = resolveApiKeyAuth(options);
9551
+ if (!this.apiAuth) {
9552
+ const envKey = typeof process !== "undefined" && process.env ? process.env.SOLANA_WALLET_KEY : void 0;
9553
+ const privateKey = options.privateKey || envKey;
9554
+ if (!privateKey) {
9555
+ throw new Error(
9556
+ "Private key required. Pass privateKey in options or set SOLANA_WALLET_KEY environment variable."
9557
+ );
9558
+ }
9559
+ this._privateKey = privateKey;
9225
9560
  }
9226
- this.privateKey = privateKey;
9227
- const apiUrl = options.apiUrl || SOLANA_API_URL;
9561
+ const apiUrl = this.apiAuth?.apiUrl || options.apiUrl || SOLANA_API_URL;
9228
9562
  validateApiUrl(apiUrl);
9229
9563
  this.apiUrl = apiUrl.replace(/\/$/, "");
9230
9564
  const rpc = resolveRpcConfig(options.rpcUrl, options.rpcHeaders);
@@ -9337,7 +9671,7 @@ var SolanaLLMClient = class {
9337
9671
  {
9338
9672
  routingProfile: options?.routingProfile,
9339
9673
  requiresStructuredOutput: options?.responseFormat !== void 0,
9340
- minimumPaymentUsd: SOLANA_MINIMUM_PAYMENT_USD
9674
+ minimumPaymentUsd: this.apiAuth ? 0 : SOLANA_MINIMUM_PAYMENT_USD
9341
9675
  }
9342
9676
  );
9343
9677
  }
@@ -9366,7 +9700,7 @@ var SolanaLLMClient = class {
9366
9700
  toolChoice: options.toolChoice,
9367
9701
  conversationChars,
9368
9702
  hasVision,
9369
- minimumPaymentUsd: SOLANA_MINIMUM_PAYMENT_USD
9703
+ minimumPaymentUsd: this.apiAuth ? 0 : SOLANA_MINIMUM_PAYMENT_USD
9370
9704
  }
9371
9705
  );
9372
9706
  const response = await this.chatCompletion(decision.model, messages, {
@@ -9619,6 +9953,7 @@ var SolanaLLMClient = class {
9619
9953
  }
9620
9954
  /** Get session spending. */
9621
9955
  getSpending() {
9956
+ if (this.apiAuth) throw new Error("Account usage is available at https://user.blockrun.ai/dashboard; getSpending() tracks x402 settlements only.");
9622
9957
  return { totalUsd: this.sessionTotalUsd, calls: this.sessionCalls };
9623
9958
  }
9624
9959
  /** True if using sol.blockrun.ai. */
@@ -9755,6 +10090,7 @@ var SolanaLLMClient = class {
9755
10090
  }
9756
10091
  throw new APIError(`API error: ${response.status}`, response.status, sanitizeErrorResponse(errorBody));
9757
10092
  }
10093
+ if (this.apiAuth && endpoint.startsWith("/v1/images/")) return this.apiAuth.poll(response, this.timeout, 2e3);
9758
10094
  return response.json();
9759
10095
  }
9760
10096
  }
@@ -9941,7 +10277,7 @@ var SolanaLLMClient = class {
9941
10277
  const controller = new AbortController();
9942
10278
  const timeoutId = setTimeout(() => controller.abort(), this.timeout);
9943
10279
  try {
9944
- return await fetch(url, { ...options, signal: controller.signal });
10280
+ return await (this.apiAuth ? this.apiAuth.fetch.bind(this.apiAuth) : fetch)(url, { ...options, signal: controller.signal });
9945
10281
  } finally {
9946
10282
  clearTimeout(timeoutId);
9947
10283
  }
@@ -10140,6 +10476,9 @@ function getCostLogSummary() {
10140
10476
  }
10141
10477
 
10142
10478
  // src/setup.ts
10479
+ var import_node_fs = require("fs");
10480
+ var import_node_os = require("os");
10481
+ var import_node_path = require("path");
10143
10482
  function setupAgentWallet(options) {
10144
10483
  const { address, privateKey, isNew } = getOrCreateWallet();
10145
10484
  if (isNew) {
@@ -10182,6 +10521,24 @@ async function status() {
10182
10521
  console.log(`Balance: $${balance.toFixed(2)} USDC`);
10183
10522
  return { address, balance };
10184
10523
  }
10524
+ async function setupAgentClient(options = {}) {
10525
+ if (resolveApiKeyAuth(options)) return new LLMClient({ apiKey: options.apiKey });
10526
+ let chain = options.chain;
10527
+ if (!chain) {
10528
+ for (const file of ["payment-chain", ".chain"]) {
10529
+ try {
10530
+ const saved = (0, import_node_fs.readFileSync)((0, import_node_path.join)((0, import_node_os.homedir)(), ".blockrun", file), "utf8").trim();
10531
+ if (saved === "solana" || saved === "base") {
10532
+ chain = saved;
10533
+ break;
10534
+ }
10535
+ } catch {
10536
+ }
10537
+ }
10538
+ }
10539
+ chain ??= !loadSolanaWallet() && loadWallet() ? "base" : "solana";
10540
+ return chain === "solana" ? setupAgentSolanaWallet(options) : setupAgentWallet(options);
10541
+ }
10185
10542
 
10186
10543
  // src/openai-compat.ts
10187
10544
  var StreamingResponse = class {
@@ -10313,13 +10670,17 @@ var Chat = class {
10313
10670
  };
10314
10671
  var OpenAI = class {
10315
10672
  chat;
10673
+ get authMode() {
10674
+ return this.client.authMode;
10675
+ }
10316
10676
  client;
10317
10677
  constructor(options = {}) {
10318
10678
  const privateKey = options.walletKey || options.privateKey;
10319
- const apiUrl = options.baseURL || "https://blockrun.ai/api";
10679
+ const apiUrl = resolveApiKeyAuth({ apiKey: options.apiKey, privateKey, apiUrl: options.baseURL })?.apiUrl ?? options.baseURL ?? "https://blockrun.ai/api";
10320
10680
  const timeout = options.timeout ?? DEFAULT_TIMEOUT;
10321
10681
  this.client = new LLMClient({
10322
10682
  privateKey,
10683
+ apiKey: options.apiKey,
10323
10684
  apiUrl,
10324
10685
  timeout
10325
10686
  });
@@ -10338,17 +10699,29 @@ var import_accounts17 = require("viem/accounts");
10338
10699
  var AnthropicClient = class {
10339
10700
  _client = null;
10340
10701
  _clientPromise = null;
10341
- _privateKey;
10342
- _account;
10702
+ apiAuth;
10703
+ get authMode() {
10704
+ return this.apiAuth ? "api-key" : "wallet";
10705
+ }
10706
+ walletKey;
10707
+ get _privateKey() {
10708
+ return requireWallet(this.walletKey);
10709
+ }
10710
+ walletAccount;
10711
+ get _account() {
10712
+ return requireWallet(this.walletAccount);
10713
+ }
10343
10714
  _apiUrl;
10344
10715
  _timeout;
10345
10716
  constructor(options = {}) {
10346
- const wallet = getOrCreateWallet();
10347
- const key = options.privateKey ?? wallet.privateKey;
10348
- validatePrivateKey(key);
10349
- this._privateKey = key;
10350
- this._account = (0, import_accounts17.privateKeyToAccount)(this._privateKey);
10351
- const apiUrl = options.apiUrl ?? "https://blockrun.ai/api";
10717
+ this.apiAuth = resolveApiKeyAuth(options);
10718
+ if (!this.apiAuth) {
10719
+ const key = options.privateKey ?? getOrCreateWallet().privateKey;
10720
+ validatePrivateKey(key);
10721
+ this.walletKey = key;
10722
+ this.walletAccount = (0, import_accounts17.privateKeyToAccount)(this.walletKey);
10723
+ }
10724
+ const apiUrl = this.apiAuth?.apiUrl ?? options.apiUrl ?? "https://blockrun.ai/api";
10352
10725
  validateApiUrl(apiUrl);
10353
10726
  this._apiUrl = apiUrl.replace(/\/$/, "");
10354
10727
  this._timeout = options.timeout ?? DEFAULT_TIMEOUT;
@@ -10372,6 +10745,7 @@ var AnthropicClient = class {
10372
10745
  const timeoutId = setTimeout(() => controller.abort(), this._timeout);
10373
10746
  try {
10374
10747
  const mergedInit = { ...init, signal: controller.signal };
10748
+ if (this.apiAuth) return await this.apiAuth.fetch(input, mergedInit, false);
10375
10749
  let response = await globalThis.fetch(input, mergedInit);
10376
10750
  if (response.status === 402) {
10377
10751
  let paymentHeader = response.headers.get("payment-required");
@@ -10444,6 +10818,7 @@ var AnthropicClient = class {
10444
10818
  // Annotate the CommonJS export names for ESM import in node:
10445
10819
  0 && (module.exports = {
10446
10820
  APIError,
10821
+ API_KEY_URL,
10447
10822
  AnthropicClient,
10448
10823
  BASE_CHAIN_ID,
10449
10824
  BlockrunClient,
@@ -10455,6 +10830,7 @@ var AnthropicClient = class {
10455
10830
  NETWORK_ALIASES,
10456
10831
  OpenAI,
10457
10832
  PHONE_PRICES,
10833
+ PORTAL_URL,
10458
10834
  PORTRAIT_ENROLLMENT_PRICE_USD,
10459
10835
  PaymentError,
10460
10836
  PhoneClient,
@@ -10511,6 +10887,7 @@ var AnthropicClient = class {
10511
10887
  scanSolanaWallets,
10512
10888
  scanWallets,
10513
10889
  setCache,
10890
+ setupAgentClient,
10514
10891
  setupAgentSolanaWallet,
10515
10892
  setupAgentWallet,
10516
10893
  solanaClient,