@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.js CHANGED
@@ -1,6 +1,3 @@
1
- // src/client.ts
2
- import { privateKeyToAccount } from "viem/accounts";
3
-
4
1
  // src/types.ts
5
2
  var BlockrunError = class extends Error {
6
3
  constructor(message) {
@@ -22,6 +19,8 @@ var PaymentError = class extends BlockrunError {
22
19
  };
23
20
  var APIError = class extends BlockrunError {
24
21
  statusCode;
22
+ /** Retry-After header returned by the account API. */
23
+ retryAfter;
25
24
  response;
26
25
  constructor(message, statusCode, response) {
27
26
  super(message);
@@ -31,7 +30,249 @@ var APIError = class extends BlockrunError {
31
30
  }
32
31
  };
33
32
 
34
- // 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
33
+ // src/validation.ts
34
+ var LOCALHOST_DOMAINS = ["localhost", "127.0.0.1"];
35
+ var KNOWN_PROVIDERS = /* @__PURE__ */ new Set([
36
+ "openai",
37
+ "anthropic",
38
+ "google",
39
+ "deepseek",
40
+ "mistralai",
41
+ "meta-llama",
42
+ "together",
43
+ "xai",
44
+ "moonshot",
45
+ "nvidia",
46
+ "minimax",
47
+ "zai"
48
+ ]);
49
+ function validateModel(model) {
50
+ if (!model || typeof model !== "string") {
51
+ throw new Error("Model must be a non-empty string");
52
+ }
53
+ }
54
+ function validateMaxTokens(maxTokens) {
55
+ if (maxTokens === void 0 || maxTokens === null) {
56
+ return;
57
+ }
58
+ if (typeof maxTokens !== "number" || !Number.isInteger(maxTokens)) {
59
+ throw new Error("maxTokens must be an integer");
60
+ }
61
+ if (maxTokens < 1) {
62
+ throw new Error("maxTokens must be positive (minimum: 1)");
63
+ }
64
+ }
65
+ function validateTemperature(temperature) {
66
+ if (temperature === void 0 || temperature === null) {
67
+ return;
68
+ }
69
+ if (typeof temperature !== "number") {
70
+ throw new Error("temperature must be a number");
71
+ }
72
+ if (temperature < 0 || temperature > 2) {
73
+ throw new Error("temperature must be between 0 and 2");
74
+ }
75
+ }
76
+ function validateTopP(topP) {
77
+ if (topP === void 0 || topP === null) {
78
+ return;
79
+ }
80
+ if (typeof topP !== "number") {
81
+ throw new Error("topP must be a number");
82
+ }
83
+ if (topP < 0 || topP > 1) {
84
+ throw new Error("topP must be between 0 and 1");
85
+ }
86
+ }
87
+ function validatePrivateKey(key) {
88
+ if (typeof key !== "string") {
89
+ throw new Error("Private key must be a string");
90
+ }
91
+ if (!key.startsWith("0x")) {
92
+ throw new Error("Private key must start with 0x");
93
+ }
94
+ if (key.length !== 66) {
95
+ throw new Error(
96
+ "Private key must be 66 characters (0x + 64 hexadecimal characters)"
97
+ );
98
+ }
99
+ if (!/^0x[0-9a-fA-F]{64}$/.test(key)) {
100
+ throw new Error(
101
+ "Private key must contain only hexadecimal characters (0-9, a-f, A-F)"
102
+ );
103
+ }
104
+ }
105
+ function validateApiUrl(url) {
106
+ let parsed;
107
+ try {
108
+ parsed = new URL(url);
109
+ } catch {
110
+ throw new Error("Invalid API URL format");
111
+ }
112
+ if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
113
+ throw new Error(
114
+ `Invalid protocol: ${parsed.protocol}. Use http:// or https://`
115
+ );
116
+ }
117
+ const isLocalhost = LOCALHOST_DOMAINS.includes(parsed.hostname);
118
+ if (parsed.protocol !== "https:" && !isLocalhost) {
119
+ throw new Error(
120
+ `API URL must use HTTPS for non-localhost endpoints. Use https:// instead of ${parsed.protocol}//`
121
+ );
122
+ }
123
+ }
124
+ function sanitizeErrorResponse(errorBody) {
125
+ if (typeof errorBody !== "object" || errorBody === null) {
126
+ return { message: "API request failed" };
127
+ }
128
+ const body = errorBody;
129
+ return {
130
+ message: typeof body.error === "string" ? body.error : "API request failed",
131
+ code: typeof body.code === "string" ? body.code : void 0
132
+ };
133
+ }
134
+ function validateResourceUrl(url, baseUrl) {
135
+ try {
136
+ const parsed = new URL(url);
137
+ const baseParsed = new URL(baseUrl);
138
+ if (parsed.hostname !== baseParsed.hostname) {
139
+ console.warn(
140
+ `Resource URL hostname mismatch: ${parsed.hostname} vs ${baseParsed.hostname}. Using safe default instead.`
141
+ );
142
+ return `${baseUrl}/v1/chat/completions`;
143
+ }
144
+ if (parsed.protocol !== baseParsed.protocol) {
145
+ console.warn(
146
+ `Resource URL protocol mismatch: ${parsed.protocol} vs ${baseParsed.protocol}. Using safe default instead.`
147
+ );
148
+ return `${baseUrl}/v1/chat/completions`;
149
+ }
150
+ return url;
151
+ } catch {
152
+ console.warn(`Invalid resource URL format: ${url}. Using safe default.`);
153
+ return `${baseUrl}/v1/chat/completions`;
154
+ }
155
+ }
156
+
157
+ // src/api-key.ts
158
+ var TRANSIENT_STATUS = /* @__PURE__ */ new Set([502, 503, 504, 522, 524]);
159
+ var TRANSIENT_RETRIES = 2;
160
+ var TRANSIENT_BACKOFF_MS = 1e3;
161
+ var API_KEY_URL = "https://api.blockrun.ai";
162
+ var PORTAL_URL = "https://user.blockrun.ai";
163
+ function resolveApiKeyAuth(options) {
164
+ if (options.apiKey !== void 0 && options.privateKey !== void 0) {
165
+ throw new Error("Pass either apiKey or privateKey, not both.");
166
+ }
167
+ const key = options.apiKey ?? (options.privateKey === void 0 && typeof process !== "undefined" ? process.env?.BLOCKRUN_API_KEY : void 0);
168
+ if (key === void 0) return void 0;
169
+ if (!/^brk_[A-Za-z0-9_-]+$/.test(key.trim())) {
170
+ throw new Error(`Invalid BlockRun API key. Create one at ${PORTAL_URL}/dashboard/keys.`);
171
+ }
172
+ const base = options.apiUrl ?? (typeof process !== "undefined" ? process.env?.BLOCKRUN_API_BASE_URL : void 0) ?? API_KEY_URL;
173
+ return new ApiKeyAuth(key.trim(), base);
174
+ }
175
+ function requireWallet(value) {
176
+ if (value === void 0) throw new Error("This operation requires a wallet; the client uses API key account billing.");
177
+ return value;
178
+ }
179
+ var ApiKeyAuth = class {
180
+ apiUrl;
181
+ #key;
182
+ constructor(key, base) {
183
+ validateApiUrl(base);
184
+ const url = new URL(base);
185
+ if (url.username || url.password || url.search || url.hash) {
186
+ throw new Error("API base URL must not contain credentials, a query, or a fragment.");
187
+ }
188
+ this.apiUrl = base.replace(/\/+$/, "").replace(/\/v1$/, "");
189
+ this.#key = key;
190
+ }
191
+ /** Resolve gateway poll paths without forwarding credentials to another origin. */
192
+ resolveUrl(path6) {
193
+ const url = new URL(path6, this.apiUrl + "/");
194
+ if (url.origin !== new URL(this.apiUrl).origin || url.username || url.password) {
195
+ throw new Error("Refusing to send a BlockRun API key to a different origin.");
196
+ }
197
+ if (new URL(this.apiUrl).pathname === "/" && url.pathname.startsWith("/api/v1/")) url.pathname = url.pathname.slice(4);
198
+ return url.href;
199
+ }
200
+ async fetch(input, init, raiseErrors = true) {
201
+ const request = input instanceof Request ? input : void 0;
202
+ const url = this.resolveUrl(request?.url ?? String(input));
203
+ const headers = new Headers(init?.headers ?? request?.headers);
204
+ for (const name of [...headers.keys()]) {
205
+ if (name.toLowerCase().includes("payment") || name.toLowerCase() === "x-api-key") headers.delete(name);
206
+ }
207
+ headers.set("authorization", `Bearer ${this.#key}`);
208
+ const method = (init?.method ?? request?.method ?? "GET").toUpperCase();
209
+ const retries = method === "GET" || method === "HEAD" ? TRANSIENT_RETRIES : 0;
210
+ let response;
211
+ for (let attempt = 0; ; attempt++) {
212
+ response = await globalThis.fetch(request ? new Request(url, request) : url, {
213
+ ...init,
214
+ headers,
215
+ redirect: "error"
216
+ });
217
+ if (attempt >= retries || !TRANSIENT_STATUS.has(response.status)) break;
218
+ await new Promise((resolve) => setTimeout(resolve, TRANSIENT_BACKOFF_MS * (attempt + 1)));
219
+ }
220
+ if (raiseErrors && !response.ok) {
221
+ let body;
222
+ try {
223
+ body = await response.json();
224
+ } catch {
225
+ body = void 0;
226
+ }
227
+ const outer = body && typeof body === "object" ? body : {};
228
+ const detail = outer.error && typeof outer.error === "object" ? outer.error : outer;
229
+ const safe = Object.fromEntries(["message", "code", "type", "param"].flatMap((name) => typeof detail[name] === "string" ? [[name, detail[name].split(this.#key).join("[REDACTED]")]] : []));
230
+ const hint = response.status === 402 ? ` Top up at ${PORTAL_URL}/dashboard/credits.` : response.status === 401 ? ` Check your key at ${PORTAL_URL}/dashboard/keys.` : "";
231
+ const error = new APIError(`BlockRun account API error: ${response.status}.${hint}`, response.status, safe);
232
+ error.retryAfter = response.headers.get("retry-after") ?? void 0;
233
+ throw error;
234
+ }
235
+ return response;
236
+ }
237
+ /** Poll an account-owned async job without ever entering the x402 signing path. */
238
+ async poll(response, timeout, interval) {
239
+ const deadline = Date.now() + timeout;
240
+ let data = await response.json();
241
+ if (["failed", "cancelled", "canceled"].includes(String(data.status))) {
242
+ throw new APIError("Account API job failed or was cancelled", 502);
243
+ }
244
+ const pollPath = data.poll_url;
245
+ if (typeof pollPath !== "string") {
246
+ if (response.status === 202 || ["queued", "in_progress", "processing"].includes(String(data.status))) {
247
+ throw new APIError("Async response missing poll_url", response.status);
248
+ }
249
+ return data;
250
+ }
251
+ const url = this.resolveUrl(pollPath);
252
+ while (Date.now() < deadline) {
253
+ if (data.status === "completed") return data;
254
+ if (["failed", "cancelled", "canceled"].includes(String(data.status))) {
255
+ throw new APIError("Account API job failed or was cancelled", 502, sanitizeErrorResponse(data));
256
+ }
257
+ await new Promise((resolve) => setTimeout(resolve, Math.min(interval, Math.max(0, deadline - Date.now()))));
258
+ const remaining = deadline - Date.now();
259
+ if (remaining <= 0) break;
260
+ try {
261
+ const res = await this.fetch(url, { signal: AbortSignal.timeout(remaining) });
262
+ data = await res.json();
263
+ } catch (err) {
264
+ if (!(err instanceof APIError) || !TRANSIENT_STATUS.has(err.statusCode)) throw err;
265
+ }
266
+ }
267
+ if (data.status === "completed") return data;
268
+ throw new APIError("Account API job polling timed out; check the job before submitting again.", 504, { poll_url: url });
269
+ }
270
+ };
271
+
272
+ // src/client.ts
273
+ import { privateKeyToAccount } from "viem/accounts";
274
+
275
+ // 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
35
276
  function scoreTokenCount(estimatedTokens, thresholds) {
36
277
  if (estimatedTokens < thresholds.simple) {
37
278
  return { name: "tokenCount", score: -1, signal: `short (${estimatedTokens} tokens)` };
@@ -554,6 +795,13 @@ var DEFAULT_MODEL_CAPABILITIES = Object.freeze({
554
795
  supportsTools: true,
555
796
  supportsVision: true
556
797
  },
798
+ "cohere/north-mini-code": {
799
+ // supportsTools: not probed — fails closed
800
+ contextWindow: 256e3,
801
+ maxOutputTokens: 16384,
802
+ supportsTools: false,
803
+ supportsVision: false
804
+ },
557
805
  "deepseek/deepseek-chat": {
558
806
  contextWindow: 1048576,
559
807
  maxOutputTokens: 65536,
@@ -644,8 +892,15 @@ var DEFAULT_MODEL_CAPABILITIES = Object.freeze({
644
892
  supportsTools: true,
645
893
  supportsVision: true
646
894
  },
647
- "nvidia/mistral-nemotron": {
648
- // supportsTools: gateway unavailable at probe time — fails closed
895
+ "nvidia/llama-3.2-11b-vision": {
896
+ // supportsTools: not probed — fails closed
897
+ contextWindow: 128e3,
898
+ maxOutputTokens: 16384,
899
+ supportsTools: false,
900
+ supportsVision: true
901
+ },
902
+ "nvidia/nemotron-3-nano-30b": {
903
+ // supportsTools: not probed — fails closed
649
904
  contextWindow: 131072,
650
905
  maxOutputTokens: 16384,
651
906
  supportsTools: false,
@@ -657,21 +912,16 @@ var DEFAULT_MODEL_CAPABILITIES = Object.freeze({
657
912
  supportsTools: false,
658
913
  supportsVision: true
659
914
  },
660
- "nvidia/nemotron-nano-12b-v2-vl": {
661
- // supportsTools: gateway unavailable at probe time — fails closed
662
- contextWindow: 131072,
663
- maxOutputTokens: 16384,
664
- supportsTools: false,
665
- supportsVision: true
666
- },
667
- "nvidia/nemotron-nano-9b-v2": {
668
- contextWindow: 131072,
915
+ "nvidia/nemotron-3-ultra-550b": {
916
+ // supportsTools: not probed — fails closed
917
+ contextWindow: 1e6,
669
918
  maxOutputTokens: 16384,
670
919
  supportsTools: false,
671
920
  supportsVision: false
672
921
  },
673
- "nvidia/step-3.7-flash": {
674
- contextWindow: 131072,
922
+ "nvidia/nemotron-3.5-lightning": {
923
+ // supportsTools: not probed — fails closed
924
+ contextWindow: 1e6,
675
925
  maxOutputTokens: 16384,
676
926
  supportsTools: false,
677
927
  supportsVision: false
@@ -731,13 +981,6 @@ var DEFAULT_MODEL_CAPABILITIES = Object.freeze({
731
981
  supportsTools: false,
732
982
  supportsVision: true
733
983
  },
734
- "openai/gpt-5.3": {
735
- // supportsTools: gateway unavailable at probe time — fails closed
736
- contextWindow: 128e3,
737
- maxOutputTokens: 128e3,
738
- supportsTools: false,
739
- supportsVision: true
740
- },
741
984
  "openai/gpt-5.3-codex": {
742
985
  // 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.
743
986
  contextWindow: 4e5,
@@ -843,6 +1086,13 @@ var DEFAULT_MODEL_CAPABILITIES = Object.freeze({
843
1086
  supportsTools: true,
844
1087
  supportsVision: false
845
1088
  },
1089
+ "poolside/laguna-xs-2.1": {
1090
+ // supportsTools: not probed — fails closed
1091
+ contextWindow: 131072,
1092
+ maxOutputTokens: 16384,
1093
+ supportsTools: false,
1094
+ supportsVision: false
1095
+ },
846
1096
  "qwen/qwen3.7-flash": {
847
1097
  contextWindow: 1e6,
848
1098
  maxOutputTokens: 65536,
@@ -3384,8 +3634,8 @@ var DEFAULT_ROUTING_CONFIG = {
3384
3634
  // $0.20/$1.25, 1M ctx
3385
3635
  "google/gemini-2.5-flash-lite",
3386
3636
  // $0.10/$0.40
3387
- "nvidia/step-3.7-flash"
3388
- // FREE backstop — NVIDIA free tier (probed 2026-08-21)
3637
+ "nvidia/nemotron-3.5-lightning"
3638
+ // FREE backstop — NVIDIA free tier (probed 2026-08-30)
3389
3639
  ]
3390
3640
  },
3391
3641
  MEDIUM: {
@@ -3474,15 +3724,19 @@ var DEFAULT_ROUTING_CONFIG = {
3474
3724
  // Eco tier configs - absolute cheapest (blockrun/eco)
3475
3725
  ecoTiers: {
3476
3726
  SIMPLE: {
3477
- primary: "nvidia/step-3.7-flash",
3478
- // FREE — NVIDIA free tier flagship
3727
+ primary: "nvidia/nemotron-3.5-lightning",
3728
+ // FREE — NVIDIA free tier flagship, 1M ctx
3479
3729
  fallback: [
3480
- "nvidia/nemotron-nano-9b-v2",
3481
- // FREE — compact + fast, high-volume light tasks
3730
+ "nvidia/nemotron-3-nano-30b",
3731
+ // FREE — fastest free model (~121 tok/s)
3482
3732
  // The free head keeps rotting with NVIDIA's hosting (deepseek-v4-flash
3483
3733
  // 410 2026-08-12, seed-oss-36b 410 2026-08-03, gpt-oss-120b/20b 400
3484
- // 2026-08-21). Each retirement retargets the two free rungs to the
3485
- // current free tier; the paid rungs below never move.
3734
+ // 2026-08-21, and on 2026-08-30 FOUR of the five visible free models at
3735
+ // once — step-3.7-flash, nemotron-nano-9b-v2 and nemotron-nano-12b-v2-vl
3736
+ // all 410, mistral-nemotron hung). Each retirement retargets the two
3737
+ // free rungs to the current free tier; the paid rungs below never move.
3738
+ // The head follows blockrun's own redirect of the model it replaces, so
3739
+ // the router and the gateway never name different models.
3486
3740
  "google/gemini-2.5-flash-lite",
3487
3741
  // $0.10/$0.40 — cheapest paid rung
3488
3742
  "zai/glm-5.3-flash",
@@ -3626,7 +3880,7 @@ var DEFAULT_ROUTING_CONFIG = {
3626
3880
  // strongest open-weight reasoner
3627
3881
  "deepseek/deepseek-chat",
3628
3882
  // Cheap, reliable
3629
- "nvidia/step-3.7-flash"
3883
+ "nvidia/nemotron-3.5-lightning"
3630
3884
  // NVIDIA free ultimate backstop
3631
3885
  ]
3632
3886
  },
@@ -3730,7 +3984,7 @@ var DEFAULT_ROUTING_CONFIG = {
3730
3984
  // retail high-risk 3/3
3731
3985
  "deepseek/deepseek-chat",
3732
3986
  // cheap, reliable
3733
- "nvidia/step-3.7-flash"
3987
+ "nvidia/nemotron-3.5-lightning"
3734
3988
  // NVIDIA free ultimate backstop
3735
3989
  ]
3736
3990
  },
@@ -4148,9 +4402,11 @@ function parsePaymentRequired(headerValue) {
4148
4402
  if (error.message.includes("Invalid payment required structure")) {
4149
4403
  throw error;
4150
4404
  }
4151
- throw new Error("Failed to parse payment required header: invalid format");
4405
+ throw new Error("Failed to parse payment required header: invalid format", {
4406
+ cause: error
4407
+ });
4152
4408
  }
4153
- throw new Error("Failed to parse payment required header");
4409
+ throw new Error("Failed to parse payment required header", { cause: error });
4154
4410
  }
4155
4411
  }
4156
4412
  function extractPaymentDetails(paymentRequired, preferredNetwork) {
@@ -4181,130 +4437,6 @@ function extractPaymentDetails(paymentRequired, preferredNetwork) {
4181
4437
  };
4182
4438
  }
4183
4439
 
4184
- // src/validation.ts
4185
- var LOCALHOST_DOMAINS = ["localhost", "127.0.0.1"];
4186
- var KNOWN_PROVIDERS = /* @__PURE__ */ new Set([
4187
- "openai",
4188
- "anthropic",
4189
- "google",
4190
- "deepseek",
4191
- "mistralai",
4192
- "meta-llama",
4193
- "together",
4194
- "xai",
4195
- "moonshot",
4196
- "nvidia",
4197
- "minimax",
4198
- "zai"
4199
- ]);
4200
- function validateModel(model) {
4201
- if (!model || typeof model !== "string") {
4202
- throw new Error("Model must be a non-empty string");
4203
- }
4204
- }
4205
- function validateMaxTokens(maxTokens) {
4206
- if (maxTokens === void 0 || maxTokens === null) {
4207
- return;
4208
- }
4209
- if (typeof maxTokens !== "number" || !Number.isInteger(maxTokens)) {
4210
- throw new Error("maxTokens must be an integer");
4211
- }
4212
- if (maxTokens < 1) {
4213
- throw new Error("maxTokens must be positive (minimum: 1)");
4214
- }
4215
- }
4216
- function validateTemperature(temperature) {
4217
- if (temperature === void 0 || temperature === null) {
4218
- return;
4219
- }
4220
- if (typeof temperature !== "number") {
4221
- throw new Error("temperature must be a number");
4222
- }
4223
- if (temperature < 0 || temperature > 2) {
4224
- throw new Error("temperature must be between 0 and 2");
4225
- }
4226
- }
4227
- function validateTopP(topP) {
4228
- if (topP === void 0 || topP === null) {
4229
- return;
4230
- }
4231
- if (typeof topP !== "number") {
4232
- throw new Error("topP must be a number");
4233
- }
4234
- if (topP < 0 || topP > 1) {
4235
- throw new Error("topP must be between 0 and 1");
4236
- }
4237
- }
4238
- function validatePrivateKey(key) {
4239
- if (typeof key !== "string") {
4240
- throw new Error("Private key must be a string");
4241
- }
4242
- if (!key.startsWith("0x")) {
4243
- throw new Error("Private key must start with 0x");
4244
- }
4245
- if (key.length !== 66) {
4246
- throw new Error(
4247
- "Private key must be 66 characters (0x + 64 hexadecimal characters)"
4248
- );
4249
- }
4250
- if (!/^0x[0-9a-fA-F]{64}$/.test(key)) {
4251
- throw new Error(
4252
- "Private key must contain only hexadecimal characters (0-9, a-f, A-F)"
4253
- );
4254
- }
4255
- }
4256
- function validateApiUrl(url) {
4257
- let parsed;
4258
- try {
4259
- parsed = new URL(url);
4260
- } catch {
4261
- throw new Error("Invalid API URL format");
4262
- }
4263
- if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
4264
- throw new Error(
4265
- `Invalid protocol: ${parsed.protocol}. Use http:// or https://`
4266
- );
4267
- }
4268
- const isLocalhost = LOCALHOST_DOMAINS.includes(parsed.hostname);
4269
- if (parsed.protocol !== "https:" && !isLocalhost) {
4270
- throw new Error(
4271
- `API URL must use HTTPS for non-localhost endpoints. Use https:// instead of ${parsed.protocol}//`
4272
- );
4273
- }
4274
- }
4275
- function sanitizeErrorResponse(errorBody) {
4276
- if (typeof errorBody !== "object" || errorBody === null) {
4277
- return { message: "API request failed" };
4278
- }
4279
- const body = errorBody;
4280
- return {
4281
- message: typeof body.error === "string" ? body.error : "API request failed",
4282
- code: typeof body.code === "string" ? body.code : void 0
4283
- };
4284
- }
4285
- function validateResourceUrl(url, baseUrl) {
4286
- try {
4287
- const parsed = new URL(url);
4288
- const baseParsed = new URL(baseUrl);
4289
- if (parsed.hostname !== baseParsed.hostname) {
4290
- console.warn(
4291
- `Resource URL hostname mismatch: ${parsed.hostname} vs ${baseParsed.hostname}. Using safe default instead.`
4292
- );
4293
- return `${baseUrl}/v1/chat/completions`;
4294
- }
4295
- if (parsed.protocol !== baseParsed.protocol) {
4296
- console.warn(
4297
- `Resource URL protocol mismatch: ${parsed.protocol} vs ${baseParsed.protocol}. Using safe default instead.`
4298
- );
4299
- return `${baseUrl}/v1/chat/completions`;
4300
- }
4301
- return url;
4302
- } catch {
4303
- console.warn(`Invalid resource URL format: ${url}. Using safe default.`);
4304
- return `${baseUrl}/v1/chat/completions`;
4305
- }
4306
- }
4307
-
4308
4440
  // src/cost-log.ts
4309
4441
  import * as fs from "fs";
4310
4442
  import * as path from "path";
@@ -4351,7 +4483,7 @@ function getCostSummary() {
4351
4483
  }
4352
4484
 
4353
4485
  // src/version.ts
4354
- var SDK_VERSION = "3.13.5";
4486
+ var SDK_VERSION = "3.14.0";
4355
4487
  var USER_AGENT = `blockrun-ts/${SDK_VERSION}`;
4356
4488
 
4357
4489
  // src/client.ts
@@ -4399,8 +4531,19 @@ function resolveDefaultTimeout() {
4399
4531
  var DEFAULT_TIMEOUT = resolveDefaultTimeout();
4400
4532
  var LLMClient = class _LLMClient {
4401
4533
  static DEFAULT_API_URL = DEFAULT_API_URL;
4402
- account;
4403
- privateKey;
4534
+ _account;
4535
+ get account() {
4536
+ return requireWallet(this._account);
4537
+ }
4538
+ apiAuth;
4539
+ /** Active billing mode. */
4540
+ get authMode() {
4541
+ return this.apiAuth ? "api-key" : "wallet";
4542
+ }
4543
+ _privateKey;
4544
+ get privateKey() {
4545
+ return requireWallet(this._privateKey);
4546
+ }
4404
4547
  apiUrl;
4405
4548
  timeout;
4406
4549
  sessionTotalUsd = 0;
@@ -4418,17 +4561,20 @@ var LLMClient = class _LLMClient {
4418
4561
  * @param options - Client configuration options (optional if BASE_CHAIN_WALLET_KEY env var is set)
4419
4562
  */
4420
4563
  constructor(options = {}) {
4421
- const envKey = typeof process !== "undefined" && process.env ? process.env.BASE_CHAIN_WALLET_KEY : void 0;
4422
- const privateKey = options.privateKey || envKey;
4423
- if (!privateKey) {
4424
- throw new Error(
4425
- "Private key required. Pass privateKey in options or set BASE_CHAIN_WALLET_KEY environment variable."
4426
- );
4564
+ this.apiAuth = resolveApiKeyAuth(options);
4565
+ if (!this.apiAuth) {
4566
+ const envKey = typeof process !== "undefined" && process.env ? process.env.BASE_CHAIN_WALLET_KEY : void 0;
4567
+ const privateKey = options.privateKey || envKey;
4568
+ if (!privateKey) {
4569
+ throw new Error(
4570
+ "Private key required. Pass privateKey in options or set BASE_CHAIN_WALLET_KEY environment variable."
4571
+ );
4572
+ }
4573
+ validatePrivateKey(privateKey);
4574
+ this._privateKey = privateKey;
4575
+ this._account = privateKeyToAccount(privateKey);
4427
4576
  }
4428
- validatePrivateKey(privateKey);
4429
- this.privateKey = privateKey;
4430
- this.account = privateKeyToAccount(privateKey);
4431
- const apiUrl = options.apiUrl || DEFAULT_API_URL;
4577
+ const apiUrl = this.apiAuth?.apiUrl || options.apiUrl || DEFAULT_API_URL;
4432
4578
  validateApiUrl(apiUrl);
4433
4579
  this.apiUrl = apiUrl.replace(/\/$/, "");
4434
4580
  this.timeout = options.timeout || DEFAULT_TIMEOUT;
@@ -4469,7 +4615,7 @@ var LLMClient = class _LLMClient {
4469
4615
  systemPrompt,
4470
4616
  maxOutputTokens,
4471
4617
  await this.getModelPricing(),
4472
- { ...options, minimumPaymentUsd: BASE_MINIMUM_PAYMENT_USD }
4618
+ { ...options, minimumPaymentUsd: this.apiAuth ? 0 : BASE_MINIMUM_PAYMENT_USD }
4473
4619
  );
4474
4620
  }
4475
4621
  /**
@@ -5055,6 +5201,7 @@ var LLMClient = class _LLMClient {
5055
5201
  sanitizeErrorResponse(errorBody)
5056
5202
  );
5057
5203
  }
5204
+ if (this.apiAuth && endpoint.startsWith("/v1/images/")) return this.apiAuth.poll(response, this.timeout, 2e3);
5058
5205
  return response.json();
5059
5206
  }
5060
5207
  /**
@@ -5307,7 +5454,7 @@ var LLMClient = class _LLMClient {
5307
5454
  const controller = new AbortController();
5308
5455
  const timeoutId = setTimeout(() => controller.abort(), this.timeout);
5309
5456
  try {
5310
- const response = await fetch(url, {
5457
+ const response = await (this.apiAuth ? this.apiAuth.fetch.bind(this.apiAuth) : fetch)(url, {
5311
5458
  ...options,
5312
5459
  signal: controller.signal
5313
5460
  });
@@ -5808,6 +5955,7 @@ var LLMClient = class _LLMClient {
5808
5955
  * console.log(`Spent $${spending.totalUsd.toFixed(4)} across ${spending.calls} calls`);
5809
5956
  */
5810
5957
  getSpending() {
5958
+ if (this.apiAuth) throw new Error("Account usage is available at https://user.blockrun.ai/dashboard; getSpending() tracks x402 settlements only.");
5811
5959
  return {
5812
5960
  totalUsd: this.sessionTotalUsd,
5813
5961
  calls: this.sessionCalls
@@ -5831,8 +5979,19 @@ var DEFAULT_TIMEOUT2 = 2e5;
5831
5979
  var POLL_INTERVAL_MS = 3e3;
5832
5980
  var POLL_MAX_DURATION_MS = 3e5;
5833
5981
  var ImageClient = class {
5834
- account;
5835
- privateKey;
5982
+ _account;
5983
+ get account() {
5984
+ return requireWallet(this._account);
5985
+ }
5986
+ apiAuth;
5987
+ /** Active billing mode. */
5988
+ get authMode() {
5989
+ return this.apiAuth ? "api-key" : "wallet";
5990
+ }
5991
+ _privateKey;
5992
+ get privateKey() {
5993
+ return requireWallet(this._privateKey);
5994
+ }
5836
5995
  apiUrl;
5837
5996
  timeout;
5838
5997
  sessionTotalUsd = 0;
@@ -5843,17 +6002,20 @@ var ImageClient = class {
5843
6002
  * @param options - Client configuration options
5844
6003
  */
5845
6004
  constructor(options = {}) {
5846
- const envKey = typeof process !== "undefined" && process.env ? process.env.BLOCKRUN_WALLET_KEY || process.env.BASE_CHAIN_WALLET_KEY : void 0;
5847
- const privateKey = options.privateKey || envKey;
5848
- if (!privateKey) {
5849
- throw new Error(
5850
- "Private key required. Pass privateKey in options or set BLOCKRUN_WALLET_KEY environment variable."
5851
- );
6005
+ this.apiAuth = resolveApiKeyAuth(options);
6006
+ if (!this.apiAuth) {
6007
+ const envKey = typeof process !== "undefined" && process.env ? process.env.BLOCKRUN_WALLET_KEY || process.env.BASE_CHAIN_WALLET_KEY : void 0;
6008
+ const privateKey = options.privateKey || envKey;
6009
+ if (!privateKey) {
6010
+ throw new Error(
6011
+ "Private key required. Pass privateKey in options or set BLOCKRUN_WALLET_KEY environment variable."
6012
+ );
6013
+ }
6014
+ validatePrivateKey(privateKey);
6015
+ this._privateKey = privateKey;
6016
+ this._account = privateKeyToAccount2(privateKey);
5852
6017
  }
5853
- validatePrivateKey(privateKey);
5854
- this.privateKey = privateKey;
5855
- this.account = privateKeyToAccount2(privateKey);
5856
- const apiUrl = options.apiUrl || DEFAULT_API_URL2;
6018
+ const apiUrl = this.apiAuth?.apiUrl || options.apiUrl || DEFAULT_API_URL2;
5857
6019
  validateApiUrl(apiUrl);
5858
6020
  this.apiUrl = apiUrl.replace(/\/$/, "");
5859
6021
  this.timeout = options.timeout || DEFAULT_TIMEOUT2;
@@ -5980,6 +6142,7 @@ var ImageClient = class {
5980
6142
  sanitizeErrorResponse(errorBody)
5981
6143
  );
5982
6144
  }
6145
+ if (this.apiAuth) return this.apiAuth.poll(response, POLL_MAX_DURATION_MS, POLL_INTERVAL_MS);
5983
6146
  return response.json();
5984
6147
  }
5985
6148
  /**
@@ -6117,7 +6280,7 @@ var ImageClient = class {
6117
6280
  const controller = new AbortController();
6118
6281
  const timeoutId = setTimeout(() => controller.abort(), this.timeout);
6119
6282
  try {
6120
- const response = await fetch(url, {
6283
+ const response = await (this.apiAuth ? this.apiAuth.fetch.bind(this.apiAuth) : fetch)(url, {
6121
6284
  ...options,
6122
6285
  signal: controller.signal
6123
6286
  });
@@ -6136,6 +6299,7 @@ var ImageClient = class {
6136
6299
  * Get session spending information.
6137
6300
  */
6138
6301
  getSpending() {
6302
+ if (this.apiAuth) throw new Error("Account usage is available at https://user.blockrun.ai/dashboard; getSpending() tracks x402 settlements only.");
6139
6303
  return {
6140
6304
  totalUsd: this.sessionTotalUsd,
6141
6305
  calls: this.sessionCalls
@@ -6149,24 +6313,38 @@ var DEFAULT_API_URL3 = "https://blockrun.ai/api";
6149
6313
  var DEFAULT_MODEL2 = "minimax/music-2.5+";
6150
6314
  var DEFAULT_TIMEOUT3 = 21e4;
6151
6315
  var MusicClient = class {
6152
- account;
6153
- privateKey;
6316
+ _account;
6317
+ get account() {
6318
+ return requireWallet(this._account);
6319
+ }
6320
+ apiAuth;
6321
+ /** Active billing mode. */
6322
+ get authMode() {
6323
+ return this.apiAuth ? "api-key" : "wallet";
6324
+ }
6325
+ _privateKey;
6326
+ get privateKey() {
6327
+ return requireWallet(this._privateKey);
6328
+ }
6154
6329
  apiUrl;
6155
6330
  timeout;
6156
6331
  sessionTotalUsd = 0;
6157
6332
  sessionCalls = 0;
6158
6333
  constructor(options = {}) {
6159
- const envKey = typeof process !== "undefined" && process.env ? process.env.BLOCKRUN_WALLET_KEY || process.env.BASE_CHAIN_WALLET_KEY : void 0;
6160
- const privateKey = options.privateKey || envKey;
6161
- if (!privateKey) {
6162
- throw new Error(
6163
- "Private key required. Pass privateKey in options or set BLOCKRUN_WALLET_KEY environment variable."
6164
- );
6334
+ this.apiAuth = resolveApiKeyAuth(options);
6335
+ if (!this.apiAuth) {
6336
+ const envKey = typeof process !== "undefined" && process.env ? process.env.BLOCKRUN_WALLET_KEY || process.env.BASE_CHAIN_WALLET_KEY : void 0;
6337
+ const privateKey = options.privateKey || envKey;
6338
+ if (!privateKey) {
6339
+ throw new Error(
6340
+ "Private key required. Pass privateKey in options or set BLOCKRUN_WALLET_KEY environment variable."
6341
+ );
6342
+ }
6343
+ validatePrivateKey(privateKey);
6344
+ this._privateKey = privateKey;
6345
+ this._account = privateKeyToAccount3(privateKey);
6165
6346
  }
6166
- validatePrivateKey(privateKey);
6167
- this.privateKey = privateKey;
6168
- this.account = privateKeyToAccount3(privateKey);
6169
- const apiUrl = options.apiUrl || DEFAULT_API_URL3;
6347
+ const apiUrl = this.apiAuth?.apiUrl || options.apiUrl || DEFAULT_API_URL3;
6170
6348
  validateApiUrl(apiUrl);
6171
6349
  this.apiUrl = apiUrl.replace(/\/$/, "");
6172
6350
  this.timeout = options.timeout || DEFAULT_TIMEOUT3;
@@ -6223,6 +6401,7 @@ var MusicClient = class {
6223
6401
  }
6224
6402
  throw new APIError(`API error: ${response.status}`, response.status, sanitizeErrorResponse(errorBody));
6225
6403
  }
6404
+ if (this.apiAuth) return this.apiAuth.poll(response, this.timeout, 5e3);
6226
6405
  return response.json();
6227
6406
  }
6228
6407
  async handlePaymentAndRetry(url, body, response) {
@@ -6285,7 +6464,7 @@ var MusicClient = class {
6285
6464
  const controller = new AbortController();
6286
6465
  const timeoutId = setTimeout(() => controller.abort(), this.timeout);
6287
6466
  try {
6288
- return await fetch(url, { ...options, signal: controller.signal });
6467
+ return await (this.apiAuth ? this.apiAuth.fetch.bind(this.apiAuth) : fetch)(url, { ...options, signal: controller.signal });
6289
6468
  } finally {
6290
6469
  clearTimeout(timeoutId);
6291
6470
  }
@@ -6294,6 +6473,7 @@ var MusicClient = class {
6294
6473
  return this.account.address;
6295
6474
  }
6296
6475
  getSpending() {
6476
+ if (this.apiAuth) throw new Error("Account usage is available at https://user.blockrun.ai/dashboard; getSpending() tracks x402 settlements only.");
6297
6477
  return { totalUsd: this.sessionTotalUsd, calls: this.sessionCalls };
6298
6478
  }
6299
6479
  };
@@ -6305,24 +6485,38 @@ var DEFAULT_MODEL3 = "elevenlabs/flash-v2.5";
6305
6485
  var DEFAULT_SOUNDFX_MODEL = "elevenlabs/sound-effects";
6306
6486
  var DEFAULT_TIMEOUT4 = 12e4;
6307
6487
  var SpeechClient = class {
6308
- account;
6309
- privateKey;
6488
+ _account;
6489
+ get account() {
6490
+ return requireWallet(this._account);
6491
+ }
6492
+ apiAuth;
6493
+ /** Active billing mode. */
6494
+ get authMode() {
6495
+ return this.apiAuth ? "api-key" : "wallet";
6496
+ }
6497
+ _privateKey;
6498
+ get privateKey() {
6499
+ return requireWallet(this._privateKey);
6500
+ }
6310
6501
  apiUrl;
6311
6502
  timeout;
6312
6503
  sessionTotalUsd = 0;
6313
6504
  sessionCalls = 0;
6314
6505
  constructor(options = {}) {
6315
- const envKey = typeof process !== "undefined" && process.env ? process.env.BLOCKRUN_WALLET_KEY || process.env.BASE_CHAIN_WALLET_KEY : void 0;
6316
- const privateKey = options.privateKey || envKey;
6317
- if (!privateKey) {
6318
- throw new Error(
6319
- "Private key required. Pass privateKey in options or set BLOCKRUN_WALLET_KEY environment variable."
6320
- );
6506
+ this.apiAuth = resolveApiKeyAuth(options);
6507
+ if (!this.apiAuth) {
6508
+ const envKey = typeof process !== "undefined" && process.env ? process.env.BLOCKRUN_WALLET_KEY || process.env.BASE_CHAIN_WALLET_KEY : void 0;
6509
+ const privateKey = options.privateKey || envKey;
6510
+ if (!privateKey) {
6511
+ throw new Error(
6512
+ "Private key required. Pass privateKey in options or set BLOCKRUN_WALLET_KEY environment variable."
6513
+ );
6514
+ }
6515
+ validatePrivateKey(privateKey);
6516
+ this._privateKey = privateKey;
6517
+ this._account = privateKeyToAccount4(privateKey);
6321
6518
  }
6322
- validatePrivateKey(privateKey);
6323
- this.privateKey = privateKey;
6324
- this.account = privateKeyToAccount4(privateKey);
6325
- const apiUrl = options.apiUrl || DEFAULT_API_URL4;
6519
+ const apiUrl = this.apiAuth?.apiUrl || options.apiUrl || DEFAULT_API_URL4;
6326
6520
  validateApiUrl(apiUrl);
6327
6521
  this.apiUrl = apiUrl.replace(/\/$/, "");
6328
6522
  this.timeout = options.timeout || DEFAULT_TIMEOUT4;
@@ -6484,7 +6678,7 @@ var SpeechClient = class {
6484
6678
  const controller = new AbortController();
6485
6679
  const timeoutId = setTimeout(() => controller.abort(), this.timeout);
6486
6680
  try {
6487
- return await fetch(url, { ...options, signal: controller.signal });
6681
+ return await (this.apiAuth ? this.apiAuth.fetch.bind(this.apiAuth) : fetch)(url, { ...options, signal: controller.signal });
6488
6682
  } finally {
6489
6683
  clearTimeout(timeoutId);
6490
6684
  }
@@ -6493,6 +6687,7 @@ var SpeechClient = class {
6493
6687
  return this.account.address;
6494
6688
  }
6495
6689
  getSpending() {
6690
+ if (this.apiAuth) throw new Error("Account usage is available at https://user.blockrun.ai/dashboard; getSpending() tracks x402 settlements only.");
6496
6691
  return { totalUsd: this.sessionTotalUsd, calls: this.sessionCalls };
6497
6692
  }
6498
6693
  };
@@ -6507,24 +6702,38 @@ var DEFAULT_GENERATE_BUDGET_MS = 9e5;
6507
6702
  var MAX_TIMEOUT_SECONDS = 600;
6508
6703
  var MAX_POLL_RESIGNS = 2;
6509
6704
  var VideoClient = class {
6510
- account;
6511
- privateKey;
6705
+ _account;
6706
+ get account() {
6707
+ return requireWallet(this._account);
6708
+ }
6709
+ apiAuth;
6710
+ /** Active billing mode. */
6711
+ get authMode() {
6712
+ return this.apiAuth ? "api-key" : "wallet";
6713
+ }
6714
+ _privateKey;
6715
+ get privateKey() {
6716
+ return requireWallet(this._privateKey);
6717
+ }
6512
6718
  apiUrl;
6513
6719
  timeout;
6514
6720
  sessionTotalUsd = 0;
6515
6721
  sessionCalls = 0;
6516
6722
  constructor(options = {}) {
6517
- const envKey = typeof process !== "undefined" && process.env ? process.env.BLOCKRUN_WALLET_KEY || process.env.BASE_CHAIN_WALLET_KEY : void 0;
6518
- const privateKey = options.privateKey || envKey;
6519
- if (!privateKey) {
6520
- throw new Error(
6521
- "Private key required. Pass privateKey in options or set BLOCKRUN_WALLET_KEY environment variable."
6522
- );
6723
+ this.apiAuth = resolveApiKeyAuth(options);
6724
+ if (!this.apiAuth) {
6725
+ const envKey = typeof process !== "undefined" && process.env ? process.env.BLOCKRUN_WALLET_KEY || process.env.BASE_CHAIN_WALLET_KEY : void 0;
6726
+ const privateKey = options.privateKey || envKey;
6727
+ if (!privateKey) {
6728
+ throw new Error(
6729
+ "Private key required. Pass privateKey in options or set BLOCKRUN_WALLET_KEY environment variable."
6730
+ );
6731
+ }
6732
+ validatePrivateKey(privateKey);
6733
+ this._privateKey = privateKey;
6734
+ this._account = privateKeyToAccount5(privateKey);
6523
6735
  }
6524
- validatePrivateKey(privateKey);
6525
- this.privateKey = privateKey;
6526
- this.account = privateKeyToAccount5(privateKey);
6527
- const apiUrl = options.apiUrl || DEFAULT_API_URL5;
6736
+ const apiUrl = this.apiAuth?.apiUrl || options.apiUrl || DEFAULT_API_URL5;
6528
6737
  validateApiUrl(apiUrl);
6529
6738
  this.apiUrl = apiUrl.replace(/\/$/, "");
6530
6739
  this.timeout = options.timeout || DEFAULT_TIMEOUT5;
@@ -6650,6 +6859,7 @@ var VideoClient = class {
6650
6859
  headers: { "Content-Type": "application/json" },
6651
6860
  body: JSON.stringify(body)
6652
6861
  });
6862
+ if (this.apiAuth) return this.apiAuth.poll(resp402, budgetMs, POLL_INTERVAL_MS2);
6653
6863
  if (resp402.status !== 402) {
6654
6864
  await this.throwApiError(resp402, "Expected 402 on first POST");
6655
6865
  }
@@ -6797,7 +7007,7 @@ var VideoClient = class {
6797
7007
  const controller = new AbortController();
6798
7008
  const timeoutId = setTimeout(() => controller.abort(), this.timeout);
6799
7009
  try {
6800
- return await fetch(url, { ...options, signal: controller.signal });
7010
+ return await (this.apiAuth ? this.apiAuth.fetch.bind(this.apiAuth) : fetch)(url, { ...options, signal: controller.signal });
6801
7011
  } finally {
6802
7012
  clearTimeout(timeoutId);
6803
7013
  }
@@ -6806,6 +7016,7 @@ var VideoClient = class {
6806
7016
  return this.account.address;
6807
7017
  }
6808
7018
  getSpending() {
7019
+ if (this.apiAuth) throw new Error("Account usage is available at https://user.blockrun.ai/dashboard; getSpending() tracks x402 settlements only.");
6809
7020
  return { totalUsd: this.sessionTotalUsd, calls: this.sessionCalls };
6810
7021
  }
6811
7022
  };
@@ -6817,24 +7028,38 @@ var DEFAULT_TIMEOUT6 = 6e4;
6817
7028
  var CALL_PRICE_USD = 0.54;
6818
7029
  var VALID_MODELS = /* @__PURE__ */ new Set(["base", "enhanced", "turbo"]);
6819
7030
  var VoiceClient = class {
6820
- account;
6821
- privateKey;
7031
+ _account;
7032
+ get account() {
7033
+ return requireWallet(this._account);
7034
+ }
7035
+ apiAuth;
7036
+ /** Active billing mode. */
7037
+ get authMode() {
7038
+ return this.apiAuth ? "api-key" : "wallet";
7039
+ }
7040
+ _privateKey;
7041
+ get privateKey() {
7042
+ return requireWallet(this._privateKey);
7043
+ }
6822
7044
  apiUrl;
6823
7045
  timeout;
6824
7046
  sessionTotalUsd = 0;
6825
7047
  sessionCalls = 0;
6826
7048
  constructor(options = {}) {
6827
- const envKey = typeof process !== "undefined" && process.env ? process.env.BLOCKRUN_WALLET_KEY || process.env.BASE_CHAIN_WALLET_KEY : void 0;
6828
- const privateKey = options.privateKey || envKey;
6829
- if (!privateKey) {
6830
- throw new Error(
6831
- "Private key required. Pass privateKey in options or set BLOCKRUN_WALLET_KEY environment variable."
6832
- );
7049
+ this.apiAuth = resolveApiKeyAuth(options);
7050
+ if (!this.apiAuth) {
7051
+ const envKey = typeof process !== "undefined" && process.env ? process.env.BLOCKRUN_WALLET_KEY || process.env.BASE_CHAIN_WALLET_KEY : void 0;
7052
+ const privateKey = options.privateKey || envKey;
7053
+ if (!privateKey) {
7054
+ throw new Error(
7055
+ "Private key required. Pass privateKey in options or set BLOCKRUN_WALLET_KEY environment variable."
7056
+ );
7057
+ }
7058
+ validatePrivateKey(privateKey);
7059
+ this._privateKey = privateKey;
7060
+ this._account = privateKeyToAccount6(privateKey);
6833
7061
  }
6834
- validatePrivateKey(privateKey);
6835
- this.privateKey = privateKey;
6836
- this.account = privateKeyToAccount6(privateKey);
6837
- const apiUrl = options.apiUrl || DEFAULT_API_URL6;
7062
+ const apiUrl = this.apiAuth?.apiUrl || options.apiUrl || DEFAULT_API_URL6;
6838
7063
  validateApiUrl(apiUrl);
6839
7064
  this.apiUrl = apiUrl.replace(/\/$/, "");
6840
7065
  this.timeout = options.timeout || DEFAULT_TIMEOUT6;
@@ -6998,7 +7223,7 @@ var VoiceClient = class {
6998
7223
  const controller = new AbortController();
6999
7224
  const timeoutId = setTimeout(() => controller.abort(), this.timeout);
7000
7225
  try {
7001
- return await fetch(url, { ...options, signal: controller.signal });
7226
+ return await (this.apiAuth ? this.apiAuth.fetch.bind(this.apiAuth) : fetch)(url, { ...options, signal: controller.signal });
7002
7227
  } finally {
7003
7228
  clearTimeout(timeoutId);
7004
7229
  }
@@ -7007,6 +7232,7 @@ var VoiceClient = class {
7007
7232
  return this.account.address;
7008
7233
  }
7009
7234
  getSpending() {
7235
+ if (this.apiAuth) throw new Error("Account usage is available at https://user.blockrun.ai/dashboard; getSpending() tracks x402 settlements only.");
7010
7236
  return { totalUsd: this.sessionTotalUsd, calls: this.sessionCalls };
7011
7237
  }
7012
7238
  };
@@ -7036,24 +7262,38 @@ function requireE164(value) {
7036
7262
  return v;
7037
7263
  }
7038
7264
  var PhoneClient = class {
7039
- account;
7040
- privateKey;
7265
+ _account;
7266
+ get account() {
7267
+ return requireWallet(this._account);
7268
+ }
7269
+ apiAuth;
7270
+ /** Active billing mode. */
7271
+ get authMode() {
7272
+ return this.apiAuth ? "api-key" : "wallet";
7273
+ }
7274
+ _privateKey;
7275
+ get privateKey() {
7276
+ return requireWallet(this._privateKey);
7277
+ }
7041
7278
  apiUrl;
7042
7279
  timeout;
7043
7280
  sessionTotalUsd = 0;
7044
7281
  sessionCalls = 0;
7045
7282
  constructor(options = {}) {
7046
- const envKey = typeof process !== "undefined" && process.env ? process.env.BLOCKRUN_WALLET_KEY || process.env.BASE_CHAIN_WALLET_KEY : void 0;
7047
- const privateKey = options.privateKey || envKey;
7048
- if (!privateKey) {
7049
- throw new Error(
7050
- "Private key required. Pass privateKey in options or set BLOCKRUN_WALLET_KEY environment variable."
7051
- );
7283
+ this.apiAuth = resolveApiKeyAuth(options);
7284
+ if (!this.apiAuth) {
7285
+ const envKey = typeof process !== "undefined" && process.env ? process.env.BLOCKRUN_WALLET_KEY || process.env.BASE_CHAIN_WALLET_KEY : void 0;
7286
+ const privateKey = options.privateKey || envKey;
7287
+ if (!privateKey) {
7288
+ throw new Error(
7289
+ "Private key required. Pass privateKey in options or set BLOCKRUN_WALLET_KEY environment variable."
7290
+ );
7291
+ }
7292
+ validatePrivateKey(privateKey);
7293
+ this._privateKey = privateKey;
7294
+ this._account = privateKeyToAccount7(privateKey);
7052
7295
  }
7053
- validatePrivateKey(privateKey);
7054
- this.privateKey = privateKey;
7055
- this.account = privateKeyToAccount7(privateKey);
7056
- const apiUrl = options.apiUrl || DEFAULT_API_URL7;
7296
+ const apiUrl = this.apiAuth?.apiUrl || options.apiUrl || DEFAULT_API_URL7;
7057
7297
  validateApiUrl(apiUrl);
7058
7298
  this.apiUrl = apiUrl.replace(/\/$/, "");
7059
7299
  this.timeout = options.timeout || DEFAULT_TIMEOUT7;
@@ -7064,6 +7304,7 @@ var PhoneClient = class {
7064
7304
  }
7065
7305
  /** Session-cumulative USD spend + call count across this client instance. */
7066
7306
  getSpending() {
7307
+ if (this.apiAuth) throw new Error("Account usage is available at https://user.blockrun.ai/dashboard; getSpending() tracks x402 settlements only.");
7067
7308
  return { totalUsd: this.sessionTotalUsd, calls: this.sessionCalls };
7068
7309
  }
7069
7310
  // ─── Lookup ────────────────────────────────────────────────────────────
@@ -7223,7 +7464,7 @@ var PhoneClient = class {
7223
7464
  const controller = new AbortController();
7224
7465
  const timeoutId = setTimeout(() => controller.abort(), this.timeout);
7225
7466
  try {
7226
- return await fetch(url, { ...init, signal: controller.signal });
7467
+ return await (this.apiAuth ? this.apiAuth.fetch.bind(this.apiAuth) : fetch)(url, { ...init, signal: controller.signal });
7227
7468
  } finally {
7228
7469
  clearTimeout(timeoutId);
7229
7470
  }
@@ -7236,24 +7477,38 @@ var DEFAULT_API_URL8 = "https://blockrun.ai/api";
7236
7477
  var DEFAULT_TIMEOUT8 = 6e4;
7237
7478
  var PORTRAIT_ENROLLMENT_PRICE_USD = 0.01;
7238
7479
  var PortraitClient = class {
7239
- account;
7240
- privateKey;
7480
+ _account;
7481
+ get account() {
7482
+ return requireWallet(this._account);
7483
+ }
7484
+ apiAuth;
7485
+ /** Active billing mode. */
7486
+ get authMode() {
7487
+ return this.apiAuth ? "api-key" : "wallet";
7488
+ }
7489
+ _privateKey;
7490
+ get privateKey() {
7491
+ return requireWallet(this._privateKey);
7492
+ }
7241
7493
  apiUrl;
7242
7494
  timeout;
7243
7495
  sessionTotalUsd = 0;
7244
7496
  sessionCalls = 0;
7245
7497
  constructor(options = {}) {
7246
- const envKey = typeof process !== "undefined" && process.env ? process.env.BLOCKRUN_WALLET_KEY || process.env.BASE_CHAIN_WALLET_KEY : void 0;
7247
- const privateKey = options.privateKey || envKey;
7248
- if (!privateKey) {
7249
- throw new Error(
7250
- "Private key required. Pass privateKey in options or set BLOCKRUN_WALLET_KEY environment variable."
7251
- );
7498
+ this.apiAuth = resolveApiKeyAuth(options);
7499
+ if (!this.apiAuth) {
7500
+ const envKey = typeof process !== "undefined" && process.env ? process.env.BLOCKRUN_WALLET_KEY || process.env.BASE_CHAIN_WALLET_KEY : void 0;
7501
+ const privateKey = options.privateKey || envKey;
7502
+ if (!privateKey) {
7503
+ throw new Error(
7504
+ "Private key required. Pass privateKey in options or set BLOCKRUN_WALLET_KEY environment variable."
7505
+ );
7506
+ }
7507
+ validatePrivateKey(privateKey);
7508
+ this._privateKey = privateKey;
7509
+ this._account = privateKeyToAccount8(privateKey);
7252
7510
  }
7253
- validatePrivateKey(privateKey);
7254
- this.privateKey = privateKey;
7255
- this.account = privateKeyToAccount8(privateKey);
7256
- const apiUrl = options.apiUrl || DEFAULT_API_URL8;
7511
+ const apiUrl = this.apiAuth?.apiUrl || options.apiUrl || DEFAULT_API_URL8;
7257
7512
  validateApiUrl(apiUrl);
7258
7513
  this.apiUrl = apiUrl.replace(/\/$/, "");
7259
7514
  this.timeout = options.timeout || DEFAULT_TIMEOUT8;
@@ -7264,6 +7519,7 @@ var PortraitClient = class {
7264
7519
  }
7265
7520
  /** Session-cumulative USD spend + call count across this client instance. */
7266
7521
  getSpending() {
7522
+ if (this.apiAuth) throw new Error("Account usage is available at https://user.blockrun.ai/dashboard; getSpending() tracks x402 settlements only.");
7267
7523
  return { totalUsd: this.sessionTotalUsd, calls: this.sessionCalls };
7268
7524
  }
7269
7525
  /**
@@ -7377,7 +7633,7 @@ var PortraitClient = class {
7377
7633
  const controller = new AbortController();
7378
7634
  const timeoutId = setTimeout(() => controller.abort(), this.timeout);
7379
7635
  try {
7380
- return await fetch(url, { ...init, signal: controller.signal });
7636
+ return await (this.apiAuth ? this.apiAuth.fetch.bind(this.apiAuth) : fetch)(url, { ...init, signal: controller.signal });
7381
7637
  } finally {
7382
7638
  clearTimeout(timeoutId);
7383
7639
  }
@@ -7389,22 +7645,36 @@ import { privateKeyToAccount as privateKeyToAccount9 } from "viem/accounts";
7389
7645
  var DEFAULT_API_URL9 = "https://blockrun.ai/api";
7390
7646
  var DEFAULT_TIMEOUT9 = 6e4;
7391
7647
  var SearchClient = class {
7392
- account;
7393
- privateKey;
7648
+ _account;
7649
+ get account() {
7650
+ return requireWallet(this._account);
7651
+ }
7652
+ apiAuth;
7653
+ /** Active billing mode. */
7654
+ get authMode() {
7655
+ return this.apiAuth ? "api-key" : "wallet";
7656
+ }
7657
+ _privateKey;
7658
+ get privateKey() {
7659
+ return requireWallet(this._privateKey);
7660
+ }
7394
7661
  apiUrl;
7395
7662
  timeout;
7396
7663
  constructor(options = {}) {
7397
- const envKey = typeof process !== "undefined" && process.env ? process.env.BLOCKRUN_WALLET_KEY || process.env.BASE_CHAIN_WALLET_KEY : void 0;
7398
- const privateKey = options.privateKey || envKey;
7399
- if (!privateKey) {
7400
- throw new Error(
7401
- "Private key required. Pass privateKey in options or set BLOCKRUN_WALLET_KEY environment variable."
7402
- );
7664
+ this.apiAuth = resolveApiKeyAuth(options);
7665
+ if (!this.apiAuth) {
7666
+ const envKey = typeof process !== "undefined" && process.env ? process.env.BLOCKRUN_WALLET_KEY || process.env.BASE_CHAIN_WALLET_KEY : void 0;
7667
+ const privateKey = options.privateKey || envKey;
7668
+ if (!privateKey) {
7669
+ throw new Error(
7670
+ "Private key required. Pass privateKey in options or set BLOCKRUN_WALLET_KEY environment variable."
7671
+ );
7672
+ }
7673
+ validatePrivateKey(privateKey);
7674
+ this._privateKey = privateKey;
7675
+ this._account = privateKeyToAccount9(privateKey);
7403
7676
  }
7404
- validatePrivateKey(privateKey);
7405
- this.privateKey = privateKey;
7406
- this.account = privateKeyToAccount9(privateKey);
7407
- const apiUrl = options.apiUrl || DEFAULT_API_URL9;
7677
+ const apiUrl = this.apiAuth?.apiUrl || options.apiUrl || DEFAULT_API_URL9;
7408
7678
  validateApiUrl(apiUrl);
7409
7679
  this.apiUrl = apiUrl.replace(/\/$/, "");
7410
7680
  this.timeout = options.timeout || DEFAULT_TIMEOUT9;
@@ -7510,7 +7780,7 @@ var SearchClient = class {
7510
7780
  const controller = new AbortController();
7511
7781
  const timeoutId = setTimeout(() => controller.abort(), this.timeout);
7512
7782
  try {
7513
- return await fetch(url, { ...init, signal: controller.signal });
7783
+ return await (this.apiAuth ? this.apiAuth.fetch.bind(this.apiAuth) : fetch)(url, { ...init, signal: controller.signal });
7514
7784
  } finally {
7515
7785
  clearTimeout(timeoutId);
7516
7786
  }
@@ -7525,15 +7795,20 @@ import { privateKeyToAccount as privateKeyToAccount10 } from "viem/accounts";
7525
7795
  var DEFAULT_API_URL10 = "https://blockrun.ai/api";
7526
7796
  var DEFAULT_TIMEOUT10 = 3e4;
7527
7797
  var PriceClient = class {
7798
+ apiAuth;
7799
+ get authMode() {
7800
+ return this.apiAuth ? "api-key" : "wallet";
7801
+ }
7528
7802
  account = null;
7529
7803
  privateKey = null;
7530
7804
  apiUrl;
7531
7805
  timeout;
7532
7806
  constructor(options = {}) {
7807
+ this.apiAuth = resolveApiKeyAuth(options);
7533
7808
  const envKey = typeof process !== "undefined" && process.env ? process.env.BLOCKRUN_WALLET_KEY || process.env.BASE_CHAIN_WALLET_KEY : void 0;
7534
- const privateKey = options.privateKey || envKey;
7535
- const requireWallet = options.requireWallet ?? true;
7536
- if (!privateKey && requireWallet) {
7809
+ const privateKey = this.apiAuth ? void 0 : options.privateKey || envKey;
7810
+ const requireWallet2 = options.requireWallet ?? true;
7811
+ if (!this.apiAuth && !privateKey && requireWallet2) {
7537
7812
  throw new Error(
7538
7813
  "Private key required for paid endpoints. Pass privateKey in options, set BLOCKRUN_WALLET_KEY, or pass requireWallet: false for free-only usage."
7539
7814
  );
@@ -7543,7 +7818,7 @@ var PriceClient = class {
7543
7818
  this.privateKey = privateKey;
7544
7819
  this.account = privateKeyToAccount10(privateKey);
7545
7820
  }
7546
- const apiUrl = options.apiUrl || DEFAULT_API_URL10;
7821
+ const apiUrl = this.apiAuth?.apiUrl || options.apiUrl || DEFAULT_API_URL10;
7547
7822
  validateApiUrl(apiUrl);
7548
7823
  this.apiUrl = apiUrl.replace(/\/$/, "");
7549
7824
  this.timeout = options.timeout || DEFAULT_TIMEOUT10;
@@ -7696,7 +7971,7 @@ var PriceClient = class {
7696
7971
  const controller = new AbortController();
7697
7972
  const timeoutId = setTimeout(() => controller.abort(), this.timeout);
7698
7973
  try {
7699
- return await fetch(url, { ...init, signal: controller.signal });
7974
+ return await (this.apiAuth ? this.apiAuth.fetch.bind(this.apiAuth) : fetch)(url, { ...init, signal: controller.signal });
7700
7975
  } finally {
7701
7976
  clearTimeout(timeoutId);
7702
7977
  }
@@ -7730,22 +8005,36 @@ var DEFAULT_API_URL11 = "https://blockrun.ai/api";
7730
8005
  var DEFAULT_TIMEOUT11 = 6e4;
7731
8006
  var SURF_PREFIX = "/v1/surf";
7732
8007
  var SurfClient = class {
7733
- account;
7734
- privateKey;
8008
+ _account;
8009
+ get account() {
8010
+ return requireWallet(this._account);
8011
+ }
8012
+ apiAuth;
8013
+ /** Active billing mode. */
8014
+ get authMode() {
8015
+ return this.apiAuth ? "api-key" : "wallet";
8016
+ }
8017
+ _privateKey;
8018
+ get privateKey() {
8019
+ return requireWallet(this._privateKey);
8020
+ }
7735
8021
  apiUrl;
7736
8022
  timeout;
7737
8023
  constructor(options = {}) {
7738
- const envKey = typeof process !== "undefined" && process.env ? process.env.BLOCKRUN_WALLET_KEY || process.env.BASE_CHAIN_WALLET_KEY : void 0;
7739
- const privateKey = options.privateKey || envKey;
7740
- if (!privateKey) {
7741
- throw new Error(
7742
- "Private key required. Pass privateKey in options or set BLOCKRUN_WALLET_KEY environment variable."
7743
- );
8024
+ this.apiAuth = resolveApiKeyAuth(options);
8025
+ if (!this.apiAuth) {
8026
+ const envKey = typeof process !== "undefined" && process.env ? process.env.BLOCKRUN_WALLET_KEY || process.env.BASE_CHAIN_WALLET_KEY : void 0;
8027
+ const privateKey = options.privateKey || envKey;
8028
+ if (!privateKey) {
8029
+ throw new Error(
8030
+ "Private key required. Pass privateKey in options or set BLOCKRUN_WALLET_KEY environment variable."
8031
+ );
8032
+ }
8033
+ validatePrivateKey(privateKey);
8034
+ this._privateKey = privateKey;
8035
+ this._account = privateKeyToAccount11(privateKey);
7744
8036
  }
7745
- validatePrivateKey(privateKey);
7746
- this.privateKey = privateKey;
7747
- this.account = privateKeyToAccount11(privateKey);
7748
- const apiUrl = options.apiUrl || DEFAULT_API_URL11;
8037
+ const apiUrl = this.apiAuth?.apiUrl || options.apiUrl || DEFAULT_API_URL11;
7749
8038
  validateApiUrl(apiUrl);
7750
8039
  this.apiUrl = apiUrl.replace(/\/$/, "");
7751
8040
  this.timeout = options.timeout || DEFAULT_TIMEOUT11;
@@ -7869,7 +8158,7 @@ var SurfClient = class {
7869
8158
  const controller = new AbortController();
7870
8159
  const timeoutId = setTimeout(() => controller.abort(), this.timeout);
7871
8160
  try {
7872
- return await fetch(url, { ...init, signal: controller.signal });
8161
+ return await (this.apiAuth ? this.apiAuth.fetch.bind(this.apiAuth) : fetch)(url, { ...init, signal: controller.signal });
7873
8162
  } finally {
7874
8163
  clearTimeout(timeoutId);
7875
8164
  }
@@ -7958,24 +8247,38 @@ var NETWORK_ALIASES = {
7958
8247
  zec: "zcash"
7959
8248
  };
7960
8249
  var RpcClient = class {
7961
- account;
7962
- privateKey;
8250
+ _account;
8251
+ get account() {
8252
+ return requireWallet(this._account);
8253
+ }
8254
+ apiAuth;
8255
+ /** Active billing mode. */
8256
+ get authMode() {
8257
+ return this.apiAuth ? "api-key" : "wallet";
8258
+ }
8259
+ _privateKey;
8260
+ get privateKey() {
8261
+ return requireWallet(this._privateKey);
8262
+ }
7963
8263
  apiUrl;
7964
8264
  timeout;
7965
8265
  sessionTotalUsd = 0;
7966
8266
  sessionCalls = 0;
7967
8267
  constructor(options = {}) {
7968
- const envKey = typeof process !== "undefined" && process.env ? process.env.BLOCKRUN_WALLET_KEY || process.env.BASE_CHAIN_WALLET_KEY : void 0;
7969
- const privateKey = options.privateKey || envKey;
7970
- if (!privateKey) {
7971
- throw new Error(
7972
- "Private key required. Pass privateKey in options or set BLOCKRUN_WALLET_KEY environment variable."
7973
- );
8268
+ this.apiAuth = resolveApiKeyAuth(options);
8269
+ if (!this.apiAuth) {
8270
+ const envKey = typeof process !== "undefined" && process.env ? process.env.BLOCKRUN_WALLET_KEY || process.env.BASE_CHAIN_WALLET_KEY : void 0;
8271
+ const privateKey = options.privateKey || envKey;
8272
+ if (!privateKey) {
8273
+ throw new Error(
8274
+ "Private key required. Pass privateKey in options or set BLOCKRUN_WALLET_KEY environment variable."
8275
+ );
8276
+ }
8277
+ validatePrivateKey(privateKey);
8278
+ this._privateKey = privateKey;
8279
+ this._account = privateKeyToAccount12(privateKey);
7974
8280
  }
7975
- validatePrivateKey(privateKey);
7976
- this.privateKey = privateKey;
7977
- this.account = privateKeyToAccount12(privateKey);
7978
- const apiUrl = options.apiUrl || DEFAULT_API_URL12;
8281
+ const apiUrl = this.apiAuth?.apiUrl || options.apiUrl || DEFAULT_API_URL12;
7979
8282
  validateApiUrl(apiUrl);
7980
8283
  this.apiUrl = apiUrl.replace(/\/$/, "");
7981
8284
  this.timeout = options.timeout || DEFAULT_TIMEOUT12;
@@ -8119,7 +8422,7 @@ var RpcClient = class {
8119
8422
  const controller = new AbortController();
8120
8423
  const timeoutId = setTimeout(() => controller.abort(), this.timeout);
8121
8424
  try {
8122
- return await fetch(url, { ...options, signal: controller.signal });
8425
+ return await (this.apiAuth ? this.apiAuth.fetch.bind(this.apiAuth) : fetch)(url, { ...options, signal: controller.signal });
8123
8426
  } finally {
8124
8427
  clearTimeout(timeoutId);
8125
8428
  }
@@ -8128,6 +8431,7 @@ var RpcClient = class {
8128
8431
  return this.account.address;
8129
8432
  }
8130
8433
  getSpending() {
8434
+ if (this.apiAuth) throw new Error("Account usage is available at https://user.blockrun.ai/dashboard; getSpending() tracks x402 settlements only.");
8131
8435
  return { totalUsd: this.sessionTotalUsd, calls: this.sessionCalls };
8132
8436
  }
8133
8437
  };
@@ -8140,24 +8444,38 @@ var DEFAULT_POLL_INTERVAL_MS = 5e3;
8140
8444
  var DEFAULT_POLL_BUDGET_MS = 3e5;
8141
8445
  var MAX_SIGNED_AUTH_SECONDS = 600;
8142
8446
  var BlockrunClient = class {
8143
- account;
8144
- privateKey;
8447
+ _account;
8448
+ get account() {
8449
+ return requireWallet(this._account);
8450
+ }
8451
+ apiAuth;
8452
+ /** Active billing mode. */
8453
+ get authMode() {
8454
+ return this.apiAuth ? "api-key" : "wallet";
8455
+ }
8456
+ _privateKey;
8457
+ get privateKey() {
8458
+ return requireWallet(this._privateKey);
8459
+ }
8145
8460
  apiUrl;
8146
8461
  timeout;
8147
8462
  sessionTotalUsd = 0;
8148
8463
  sessionCalls = 0;
8149
8464
  constructor(options = {}) {
8150
- const envKey = typeof process !== "undefined" && process.env ? process.env.BLOCKRUN_WALLET_KEY || process.env.BASE_CHAIN_WALLET_KEY : void 0;
8151
- const privateKey = options.privateKey || envKey;
8152
- if (!privateKey) {
8153
- throw new Error(
8154
- "Private key required. Pass privateKey in options or set BLOCKRUN_WALLET_KEY environment variable."
8155
- );
8465
+ this.apiAuth = resolveApiKeyAuth(options);
8466
+ if (!this.apiAuth) {
8467
+ const envKey = typeof process !== "undefined" && process.env ? process.env.BLOCKRUN_WALLET_KEY || process.env.BASE_CHAIN_WALLET_KEY : void 0;
8468
+ const privateKey = options.privateKey || envKey;
8469
+ if (!privateKey) {
8470
+ throw new Error(
8471
+ "Private key required. Pass privateKey in options or set BLOCKRUN_WALLET_KEY environment variable."
8472
+ );
8473
+ }
8474
+ validatePrivateKey(privateKey);
8475
+ this._privateKey = privateKey;
8476
+ this._account = privateKeyToAccount13(privateKey);
8156
8477
  }
8157
- validatePrivateKey(privateKey);
8158
- this.privateKey = privateKey;
8159
- this.account = privateKeyToAccount13(privateKey);
8160
- const apiUrl = options.apiUrl || DEFAULT_API_URL13;
8478
+ const apiUrl = this.apiAuth?.apiUrl || options.apiUrl || DEFAULT_API_URL13;
8161
8479
  validateApiUrl(apiUrl);
8162
8480
  this.apiUrl = apiUrl.replace(/\/$/, "");
8163
8481
  this.timeout = options.timeout || DEFAULT_TIMEOUT13;
@@ -8199,6 +8517,7 @@ var BlockrunClient = class {
8199
8517
  headers: { "Content-Type": "application/json" },
8200
8518
  body: JSON.stringify(body ?? {})
8201
8519
  });
8520
+ if (this.apiAuth) return this.apiAuth.poll(resp402, budgetMs, intervalMs);
8202
8521
  if (resp402.status === 200) {
8203
8522
  return resp402.json();
8204
8523
  }
@@ -8491,7 +8810,7 @@ var BlockrunClient = class {
8491
8810
  const controller = new AbortController();
8492
8811
  const timeoutId = setTimeout(() => controller.abort(), this.timeout);
8493
8812
  try {
8494
- return await fetch(url, { ...init, signal: controller.signal });
8813
+ return await (this.apiAuth ? this.apiAuth.fetch.bind(this.apiAuth) : fetch)(url, { ...init, signal: controller.signal });
8495
8814
  } finally {
8496
8815
  clearTimeout(timeoutId);
8497
8816
  }
@@ -8503,6 +8822,7 @@ var BlockrunClient = class {
8503
8822
  return this.account.address;
8504
8823
  }
8505
8824
  getSpending() {
8825
+ if (this.apiAuth) throw new Error("Account usage is available at https://user.blockrun.ai/dashboard; getSpending() tracks x402 settlements only.");
8506
8826
  return { totalUsd: this.sessionTotalUsd, calls: this.sessionCalls };
8507
8827
  }
8508
8828
  };
@@ -8513,7 +8833,7 @@ function sleep(ms) {
8513
8833
  // src/wallet.ts
8514
8834
  import { privateKeyToAccount as privateKeyToAccount15, generatePrivateKey as generatePrivateKey2 } from "viem/accounts";
8515
8835
 
8516
- // 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
8836
+ // 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
8517
8837
  import * as fs2 from "fs";
8518
8838
  import * as os2 from "os";
8519
8839
  import * as path2 from "path";
@@ -8535,7 +8855,7 @@ function paths() {
8535
8855
  };
8536
8856
  }
8537
8857
 
8538
- // 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
8858
+ // 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
8539
8859
  import * as fs3 from "fs";
8540
8860
  import * as path3 from "path";
8541
8861
  import { privateKeyToAccount as privateKeyToAccount14, generatePrivateKey } from "viem/accounts";
@@ -8831,7 +9151,8 @@ async function solanaKeyToBytes(privateKey) {
8831
9151
  } catch (err) {
8832
9152
  const msg = err instanceof Error ? err.message : String(err);
8833
9153
  throw new Error(
8834
- `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.`
9154
+ `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.`,
9155
+ { cause: err }
8835
9156
  );
8836
9157
  }
8837
9158
  }
@@ -8977,7 +9298,7 @@ async function solanaPublicKeyFrom(privateKey, source) {
8977
9298
  return await solanaPublicKey(privateKey);
8978
9299
  } catch (err) {
8979
9300
  const msg = err instanceof Error ? err.message : String(err);
8980
- throw new Error(`${msg} (key loaded from ${source})`);
9301
+ throw new Error(`${msg} (key loaded from ${source})`, { cause: err });
8981
9302
  }
8982
9303
  }
8983
9304
  async function getOrCreateSolanaWallet() {
@@ -9091,7 +9412,14 @@ function resolveRpcConfig(rpcUrl, rpcHeaders) {
9091
9412
  }
9092
9413
  var SolanaLLMClient = class {
9093
9414
  static SOLANA_API_URL = SOLANA_API_URL;
9094
- privateKey;
9415
+ apiAuth;
9416
+ get authMode() {
9417
+ return this.apiAuth ? "api-key" : "wallet";
9418
+ }
9419
+ _privateKey;
9420
+ get privateKey() {
9421
+ return requireWallet(this._privateKey);
9422
+ }
9095
9423
  apiUrl;
9096
9424
  rpcUrl;
9097
9425
  rpcHeaders;
@@ -9102,15 +9430,18 @@ var SolanaLLMClient = class {
9102
9430
  modelPricingCache = null;
9103
9431
  modelPricingPromise = null;
9104
9432
  constructor(options = {}) {
9105
- const envKey = typeof process !== "undefined" && process.env ? process.env.SOLANA_WALLET_KEY : void 0;
9106
- const privateKey = options.privateKey || envKey;
9107
- if (!privateKey) {
9108
- throw new Error(
9109
- "Private key required. Pass privateKey in options or set SOLANA_WALLET_KEY environment variable."
9110
- );
9433
+ this.apiAuth = resolveApiKeyAuth(options);
9434
+ if (!this.apiAuth) {
9435
+ const envKey = typeof process !== "undefined" && process.env ? process.env.SOLANA_WALLET_KEY : void 0;
9436
+ const privateKey = options.privateKey || envKey;
9437
+ if (!privateKey) {
9438
+ throw new Error(
9439
+ "Private key required. Pass privateKey in options or set SOLANA_WALLET_KEY environment variable."
9440
+ );
9441
+ }
9442
+ this._privateKey = privateKey;
9111
9443
  }
9112
- this.privateKey = privateKey;
9113
- const apiUrl = options.apiUrl || SOLANA_API_URL;
9444
+ const apiUrl = this.apiAuth?.apiUrl || options.apiUrl || SOLANA_API_URL;
9114
9445
  validateApiUrl(apiUrl);
9115
9446
  this.apiUrl = apiUrl.replace(/\/$/, "");
9116
9447
  const rpc = resolveRpcConfig(options.rpcUrl, options.rpcHeaders);
@@ -9223,7 +9554,7 @@ var SolanaLLMClient = class {
9223
9554
  {
9224
9555
  routingProfile: options?.routingProfile,
9225
9556
  requiresStructuredOutput: options?.responseFormat !== void 0,
9226
- minimumPaymentUsd: SOLANA_MINIMUM_PAYMENT_USD
9557
+ minimumPaymentUsd: this.apiAuth ? 0 : SOLANA_MINIMUM_PAYMENT_USD
9227
9558
  }
9228
9559
  );
9229
9560
  }
@@ -9252,7 +9583,7 @@ var SolanaLLMClient = class {
9252
9583
  toolChoice: options.toolChoice,
9253
9584
  conversationChars,
9254
9585
  hasVision,
9255
- minimumPaymentUsd: SOLANA_MINIMUM_PAYMENT_USD
9586
+ minimumPaymentUsd: this.apiAuth ? 0 : SOLANA_MINIMUM_PAYMENT_USD
9256
9587
  }
9257
9588
  );
9258
9589
  const response = await this.chatCompletion(decision.model, messages, {
@@ -9505,6 +9836,7 @@ var SolanaLLMClient = class {
9505
9836
  }
9506
9837
  /** Get session spending. */
9507
9838
  getSpending() {
9839
+ if (this.apiAuth) throw new Error("Account usage is available at https://user.blockrun.ai/dashboard; getSpending() tracks x402 settlements only.");
9508
9840
  return { totalUsd: this.sessionTotalUsd, calls: this.sessionCalls };
9509
9841
  }
9510
9842
  /** True if using sol.blockrun.ai. */
@@ -9641,6 +9973,7 @@ var SolanaLLMClient = class {
9641
9973
  }
9642
9974
  throw new APIError(`API error: ${response.status}`, response.status, sanitizeErrorResponse(errorBody));
9643
9975
  }
9976
+ if (this.apiAuth && endpoint.startsWith("/v1/images/")) return this.apiAuth.poll(response, this.timeout, 2e3);
9644
9977
  return response.json();
9645
9978
  }
9646
9979
  }
@@ -9827,7 +10160,7 @@ var SolanaLLMClient = class {
9827
10160
  const controller = new AbortController();
9828
10161
  const timeoutId = setTimeout(() => controller.abort(), this.timeout);
9829
10162
  try {
9830
- return await fetch(url, { ...options, signal: controller.signal });
10163
+ return await (this.apiAuth ? this.apiAuth.fetch.bind(this.apiAuth) : fetch)(url, { ...options, signal: controller.signal });
9831
10164
  } finally {
9832
10165
  clearTimeout(timeoutId);
9833
10166
  }
@@ -10026,6 +10359,9 @@ function getCostLogSummary() {
10026
10359
  }
10027
10360
 
10028
10361
  // src/setup.ts
10362
+ import { readFileSync as readFileSync6 } from "fs";
10363
+ import { homedir as homedir5 } from "os";
10364
+ import { join as join6 } from "path";
10029
10365
  function setupAgentWallet(options) {
10030
10366
  const { address, privateKey, isNew } = getOrCreateWallet();
10031
10367
  if (isNew) {
@@ -10068,6 +10404,24 @@ async function status() {
10068
10404
  console.log(`Balance: $${balance.toFixed(2)} USDC`);
10069
10405
  return { address, balance };
10070
10406
  }
10407
+ async function setupAgentClient(options = {}) {
10408
+ if (resolveApiKeyAuth(options)) return new LLMClient({ apiKey: options.apiKey });
10409
+ let chain = options.chain;
10410
+ if (!chain) {
10411
+ for (const file of ["payment-chain", ".chain"]) {
10412
+ try {
10413
+ const saved = readFileSync6(join6(homedir5(), ".blockrun", file), "utf8").trim();
10414
+ if (saved === "solana" || saved === "base") {
10415
+ chain = saved;
10416
+ break;
10417
+ }
10418
+ } catch {
10419
+ }
10420
+ }
10421
+ }
10422
+ chain ??= !loadSolanaWallet() && loadWallet() ? "base" : "solana";
10423
+ return chain === "solana" ? setupAgentSolanaWallet(options) : setupAgentWallet(options);
10424
+ }
10071
10425
 
10072
10426
  // src/openai-compat.ts
10073
10427
  var StreamingResponse = class {
@@ -10199,13 +10553,17 @@ var Chat = class {
10199
10553
  };
10200
10554
  var OpenAI = class {
10201
10555
  chat;
10556
+ get authMode() {
10557
+ return this.client.authMode;
10558
+ }
10202
10559
  client;
10203
10560
  constructor(options = {}) {
10204
10561
  const privateKey = options.walletKey || options.privateKey;
10205
- const apiUrl = options.baseURL || "https://blockrun.ai/api";
10562
+ const apiUrl = resolveApiKeyAuth({ apiKey: options.apiKey, privateKey, apiUrl: options.baseURL })?.apiUrl ?? options.baseURL ?? "https://blockrun.ai/api";
10206
10563
  const timeout = options.timeout ?? DEFAULT_TIMEOUT;
10207
10564
  this.client = new LLMClient({
10208
10565
  privateKey,
10566
+ apiKey: options.apiKey,
10209
10567
  apiUrl,
10210
10568
  timeout
10211
10569
  });
@@ -10224,17 +10582,29 @@ import { privateKeyToAccount as privateKeyToAccount16 } from "viem/accounts";
10224
10582
  var AnthropicClient = class {
10225
10583
  _client = null;
10226
10584
  _clientPromise = null;
10227
- _privateKey;
10228
- _account;
10585
+ apiAuth;
10586
+ get authMode() {
10587
+ return this.apiAuth ? "api-key" : "wallet";
10588
+ }
10589
+ walletKey;
10590
+ get _privateKey() {
10591
+ return requireWallet(this.walletKey);
10592
+ }
10593
+ walletAccount;
10594
+ get _account() {
10595
+ return requireWallet(this.walletAccount);
10596
+ }
10229
10597
  _apiUrl;
10230
10598
  _timeout;
10231
10599
  constructor(options = {}) {
10232
- const wallet = getOrCreateWallet();
10233
- const key = options.privateKey ?? wallet.privateKey;
10234
- validatePrivateKey(key);
10235
- this._privateKey = key;
10236
- this._account = privateKeyToAccount16(this._privateKey);
10237
- const apiUrl = options.apiUrl ?? "https://blockrun.ai/api";
10600
+ this.apiAuth = resolveApiKeyAuth(options);
10601
+ if (!this.apiAuth) {
10602
+ const key = options.privateKey ?? getOrCreateWallet().privateKey;
10603
+ validatePrivateKey(key);
10604
+ this.walletKey = key;
10605
+ this.walletAccount = privateKeyToAccount16(this.walletKey);
10606
+ }
10607
+ const apiUrl = this.apiAuth?.apiUrl ?? options.apiUrl ?? "https://blockrun.ai/api";
10238
10608
  validateApiUrl(apiUrl);
10239
10609
  this._apiUrl = apiUrl.replace(/\/$/, "");
10240
10610
  this._timeout = options.timeout ?? DEFAULT_TIMEOUT;
@@ -10258,6 +10628,7 @@ var AnthropicClient = class {
10258
10628
  const timeoutId = setTimeout(() => controller.abort(), this._timeout);
10259
10629
  try {
10260
10630
  const mergedInit = { ...init, signal: controller.signal };
10631
+ if (this.apiAuth) return await this.apiAuth.fetch(input, mergedInit, false);
10261
10632
  let response = await globalThis.fetch(input, mergedInit);
10262
10633
  if (response.status === 402) {
10263
10634
  let paymentHeader = response.headers.get("payment-required");
@@ -10329,6 +10700,7 @@ var AnthropicClient = class {
10329
10700
  };
10330
10701
  export {
10331
10702
  APIError,
10703
+ API_KEY_URL,
10332
10704
  AnthropicClient,
10333
10705
  BASE_CHAIN_ID,
10334
10706
  BlockrunClient,
@@ -10340,6 +10712,7 @@ export {
10340
10712
  NETWORK_ALIASES,
10341
10713
  OpenAI,
10342
10714
  PHONE_PRICES,
10715
+ PORTAL_URL,
10343
10716
  PORTRAIT_ENROLLMENT_PRICE_USD,
10344
10717
  PaymentError,
10345
10718
  PhoneClient,
@@ -10397,6 +10770,7 @@ export {
10397
10770
  scanSolanaWallets,
10398
10771
  scanWallets2 as scanWallets,
10399
10772
  setCache,
10773
+ setupAgentClient,
10400
10774
  setupAgentSolanaWallet,
10401
10775
  setupAgentWallet,
10402
10776
  solanaClient,