@blockrun/llm 3.24.9 → 3.25.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -2
- package/dist/index.cjs +146 -10
- package/dist/index.d.cts +73 -3
- package/dist/index.d.ts +73 -3
- package/dist/index.js +144 -10
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -635,7 +635,10 @@ console.log(res.costUsd, res.settlement); // what you paid, and the tx
|
|
|
635
635
|
```
|
|
636
636
|
|
|
637
637
|
`costUsd`, `settlement` and the per-call `timeout` work the same on `LLMClient`
|
|
638
|
-
(Base / Arc).
|
|
638
|
+
(Base / Arc). Both clients default to a 600 s request timeout
|
|
639
|
+
(`BLOCKRUN_CHAT_TIMEOUT`, in seconds, overrides it; the `timeout` option, in
|
|
640
|
+
ms, overrides both): a call aborted after its payment was sent may already be
|
|
641
|
+
charged, so a batch payment ends unresolved rather than paid again. `costUsd` is what the call added to `getSpending()`: the signed
|
|
639
642
|
price under `exact`, the metered `extra.chargedAmount` under batch settlement,
|
|
640
643
|
`0` for a free model; it is undefined in API-key mode (billed to the account).
|
|
641
644
|
When the gateway answers a paid request from a free fallback model it skips
|
|
@@ -720,6 +723,7 @@ await client.closeBatchChannel();
|
|
|
720
723
|
- **Never pays twice.** Anything that goes wrong before a batch payment is sent falls back to `exact`. Once one is sent, a call whose payment may have been charged throws `BatchPaymentUnresolvedError` and is never paid again (no new payment, no `exact`, no fallback model).
|
|
721
724
|
- **Non-streaming chat only.** `chat`, `chatCompletion`, `smartChat` and `smartChatCompletion` use batch; `stream()` and media jobs pay `exact`.
|
|
722
725
|
- **One channel per wallet.** All clients for a wallet share one channel, saved to `~/.blockrun/solana-batch/<wallet>.json` (mode `0600`) so a restart reuses it.
|
|
726
|
+
- **One process per wallet.** The process that opens the channel holds its store's lock until it exits. Other processes on that wallet (worker pools, PM2/cluster workers, parallel runs) pay `exact`, reported as `channel_store_locked`. Give each worker its own wallet, or route calls through one process. `batch.onLocked: "wait"` waits up to `batch.lockWaitMs` (default 60 s) for the lock, and `"throw"` raises `BatchChannelLockedError` (unpaid, nothing signed) instead of paying `exact`.
|
|
723
727
|
- **Observable.** Every fallback, backoff, recovery and re-read writes one stderr line; `batch.onEvent` and `client.getBatchStats()` expose the same events and counters.
|
|
724
728
|
|
|
725
729
|
The full runtime contract (the answer-by-answer table, payment-identifier
|
|
@@ -1695,7 +1699,7 @@ const configured = new LLMClient({
|
|
|
1695
1699
|
| `SOLANA_RPC_URL` | Solana RPC for payments and balance (also `rpcUrl`) |
|
|
1696
1700
|
| `SOLANA_RPC_API_KEY` / `SOLANA_RPC_HEADERS` | Header auth for that RPC (also `rpcHeaders`) |
|
|
1697
1701
|
| `BASE_RPC_URL` | Base RPC tried first by `LLMClient.getBalance()` |
|
|
1698
|
-
| `BLOCKRUN_CHAT_TIMEOUT` | `LLMClient` default timeout, in **seconds** (default 600) |
|
|
1702
|
+
| `BLOCKRUN_CHAT_TIMEOUT` | `LLMClient` and `SolanaLLMClient` default timeout, in **seconds** (default 600) |
|
|
1699
1703
|
| `BLOCKRUN_HOME` | Base directory for the Base wallet files (security-sensitive, see [Wallets](#one-wallet-across-every-blockrun-product)) |
|
|
1700
1704
|
|
|
1701
1705
|
`BLOCKRUN_SOL_OPERATOR` is **not** an environment variable or a secret. It is
|
package/dist/index.cjs
CHANGED
|
@@ -36,11 +36,13 @@ __export(index_exports, {
|
|
|
36
36
|
AnthropicClient: () => AnthropicClient,
|
|
37
37
|
BASE_CHAIN_ID: () => BASE_CHAIN_ID,
|
|
38
38
|
BLOCKRUN_SOL_OPERATOR: () => BLOCKRUN_SOL_OPERATOR,
|
|
39
|
+
BatchChannelLockedError: () => BatchChannelLockedError,
|
|
39
40
|
BatchCloseDeferredError: () => BatchCloseDeferredError,
|
|
40
41
|
BatchPaymentUnresolvedError: () => BatchPaymentUnresolvedError,
|
|
41
42
|
BlockrunClient: () => BlockrunClient,
|
|
42
43
|
BlockrunError: () => BlockrunError,
|
|
43
44
|
DEFAULT_BATCH_IN_DOUBT: () => DEFAULT_BATCH_IN_DOUBT,
|
|
45
|
+
DEFAULT_BATCH_LOCK_WAIT_MS: () => DEFAULT_BATCH_LOCK_WAIT_MS,
|
|
44
46
|
DEFAULT_BATCH_RATE_LIMIT: () => DEFAULT_BATCH_RATE_LIMIT,
|
|
45
47
|
EVM_NETWORKS: () => EVM_NETWORKS,
|
|
46
48
|
ImageClient: () => ImageClient,
|
|
@@ -5120,7 +5122,7 @@ function getCostSummary() {
|
|
|
5120
5122
|
}
|
|
5121
5123
|
|
|
5122
5124
|
// src/version.ts
|
|
5123
|
-
var SDK_VERSION = "3.
|
|
5125
|
+
var SDK_VERSION = "3.25.0";
|
|
5124
5126
|
var USER_AGENT = `blockrun-ts/${SDK_VERSION}`;
|
|
5125
5127
|
|
|
5126
5128
|
// src/client.ts
|
|
@@ -10222,6 +10224,8 @@ var BATCH_SCHEME = "batch-settlement";
|
|
|
10222
10224
|
var BLOCKRUN_SOL_OPERATOR = "5YKPQUFjw5WQqhSUkEGKNNfYYVqnRRNbpYyL71qQ1vm3";
|
|
10223
10225
|
var DEFAULT_BATCH_RATE_LIMIT = { maxAttempts: 3, maxWaitMs: 6e4 };
|
|
10224
10226
|
var DEFAULT_BATCH_IN_DOUBT = { maxWaitMs: 3e5 };
|
|
10227
|
+
var DEFAULT_BATCH_LOCK_WAIT_MS = 6e4;
|
|
10228
|
+
var LOCK_POLL_MS = 500;
|
|
10225
10229
|
var BatchPaymentUnresolvedError = class extends PaymentError {
|
|
10226
10230
|
/** The {@link SolanaBatchEvent.reason} of the `unresolved` event reported with it. */
|
|
10227
10231
|
reason;
|
|
@@ -10267,6 +10271,22 @@ var BatchCloseDeferredError = class extends BlockrunError {
|
|
|
10267
10271
|
this.channelIds = init.channelIds ?? [];
|
|
10268
10272
|
}
|
|
10269
10273
|
};
|
|
10274
|
+
var BatchChannelLockedError = class extends BlockrunError {
|
|
10275
|
+
/** The paying wallet's address. */
|
|
10276
|
+
wallet;
|
|
10277
|
+
/** The live owner's pid, when the SDK knows it. */
|
|
10278
|
+
ownerPid;
|
|
10279
|
+
/** How long this call waited for the lock, in ms (0 unless `onLocked` is `"wait"`). */
|
|
10280
|
+
waitedMs;
|
|
10281
|
+
constructor(init) {
|
|
10282
|
+
super(`batch-settlement unavailable for wallet ${init.wallet}: ${init.detail}`);
|
|
10283
|
+
this.name = "BatchChannelLockedError";
|
|
10284
|
+
this.wallet = init.wallet;
|
|
10285
|
+
if (init.ownerPid !== void 0) this.ownerPid = init.ownerPid;
|
|
10286
|
+
this.waitedMs = init.waitedMs;
|
|
10287
|
+
withDisposition(this, "unpaid");
|
|
10288
|
+
}
|
|
10289
|
+
};
|
|
10270
10290
|
var INSTALL_HINT2 = "npm install @x402/core@~2.28.0 @x402/svm@~2.28.0 @solana/kit";
|
|
10271
10291
|
async function load(pkg, importer) {
|
|
10272
10292
|
try {
|
|
@@ -10902,6 +10922,38 @@ function withoutClientSignedBatch(paymentRequired) {
|
|
|
10902
10922
|
const accepts = paymentRequired.accepts ?? [];
|
|
10903
10923
|
return accepts.some(clientSignedBatch) ? { ...paymentRequired, accepts: accepts.filter((accept) => !clientSignedBatch(accept)) } : paymentRequired;
|
|
10904
10924
|
}
|
|
10925
|
+
var DEPOSIT_BLOCKHASH_TTL_MS = 1e4;
|
|
10926
|
+
var MAX_DEPOSIT_BLOCKHASH_ENDPOINTS = 8;
|
|
10927
|
+
var depositBlockhashes = /* @__PURE__ */ new Map();
|
|
10928
|
+
async function finalizedBlockhash(rpcUrl, rpcHeaders) {
|
|
10929
|
+
const cached = depositBlockhashes.get(rpcUrl);
|
|
10930
|
+
if (cached && Date.now() - cached.fetchedAt < DEPOSIT_BLOCKHASH_TTL_MS) return cached;
|
|
10931
|
+
const result = await rpcRequest(rpcUrl, "getLatestBlockhash", [{ commitment: "finalized" }], rpcHeaders);
|
|
10932
|
+
const blockhash = result.value?.blockhash;
|
|
10933
|
+
if (typeof blockhash !== "string" || !blockhash) throw new Error("getLatestBlockhash returned no blockhash");
|
|
10934
|
+
const entry = {
|
|
10935
|
+
blockhash,
|
|
10936
|
+
lastValidBlockHeight: rpcInteger(result.value?.lastValidBlockHeight, "getLatestBlockhash lastValidBlockHeight"),
|
|
10937
|
+
fetchedAt: Date.now()
|
|
10938
|
+
};
|
|
10939
|
+
depositBlockhashes.delete(rpcUrl);
|
|
10940
|
+
depositBlockhashes.set(rpcUrl, entry);
|
|
10941
|
+
while (depositBlockhashes.size > MAX_DEPOSIT_BLOCKHASH_ENDPOINTS) {
|
|
10942
|
+
depositBlockhashes.delete(depositBlockhashes.keys().next().value);
|
|
10943
|
+
}
|
|
10944
|
+
return entry;
|
|
10945
|
+
}
|
|
10946
|
+
function withDepositBlockhash(paymentRequired, blockhash) {
|
|
10947
|
+
const accepts = paymentRequired.accepts ?? [];
|
|
10948
|
+
const lacking = (accept) => accept.scheme === BATCH_SCHEME && !accept.extra?.recentBlockhash;
|
|
10949
|
+
if (!accepts.some(lacking)) return paymentRequired;
|
|
10950
|
+
return {
|
|
10951
|
+
...paymentRequired,
|
|
10952
|
+
accepts: accepts.map(
|
|
10953
|
+
(accept) => lacking(accept) ? { ...accept, extra: { ...accept.extra, recentBlockhash: blockhash.blockhash, lastValidBlockHeight: blockhash.lastValidBlockHeight } } : accept
|
|
10954
|
+
)
|
|
10955
|
+
};
|
|
10956
|
+
}
|
|
10905
10957
|
var PAYMENT_IDENTIFIER = "payment-identifier";
|
|
10906
10958
|
function withPaymentIdentifier(paymentRequired) {
|
|
10907
10959
|
const declared = paymentRequired.extensions?.[PAYMENT_IDENTIFIER];
|
|
@@ -11299,12 +11351,22 @@ var SolanaBatchPayer = class {
|
|
|
11299
11351
|
if (!Number.isFinite(this.inDoubtMaxWaitMs) || this.inDoubtMaxWaitMs < 0) {
|
|
11300
11352
|
throw new Error("batch.inDoubt.maxWaitMs must be a finite number of ms >= 0");
|
|
11301
11353
|
}
|
|
11354
|
+
this.onLocked = init.options.onLocked ?? "exact";
|
|
11355
|
+
if (this.onLocked !== "exact" && this.onLocked !== "wait" && this.onLocked !== "throw") {
|
|
11356
|
+
throw new Error('batch.onLocked must be "exact", "wait" or "throw"');
|
|
11357
|
+
}
|
|
11358
|
+
this.lockWaitMs = init.options.lockWaitMs ?? DEFAULT_BATCH_LOCK_WAIT_MS;
|
|
11359
|
+
if (!Number.isFinite(this.lockWaitMs) || this.lockWaitMs < 0) {
|
|
11360
|
+
throw new Error("batch.lockWaitMs must be a finite number of ms >= 0");
|
|
11361
|
+
}
|
|
11302
11362
|
}
|
|
11303
11363
|
init;
|
|
11304
11364
|
state;
|
|
11305
11365
|
maxAttempts;
|
|
11306
11366
|
maxWaitMs;
|
|
11307
11367
|
inDoubtMaxWaitMs;
|
|
11368
|
+
onLocked;
|
|
11369
|
+
lockWaitMs;
|
|
11308
11370
|
counters = {
|
|
11309
11371
|
fallbacks: 0,
|
|
11310
11372
|
fallbacksByReason: {},
|
|
@@ -11353,6 +11415,7 @@ var SolanaBatchPayer = class {
|
|
|
11353
11415
|
if (owner !== void 0) {
|
|
11354
11416
|
return {
|
|
11355
11417
|
reason: "channel_store_locked",
|
|
11418
|
+
ownerPid: owner,
|
|
11356
11419
|
detail: owner === process.pid ? `channel store ${file} is in use by another copy of @blockrun/llm in this process (or by a process that had this pid and died: remove ${file}.lock if nothing uses it)` : `channel store ${file} is in use by process ${owner}`
|
|
11357
11420
|
};
|
|
11358
11421
|
}
|
|
@@ -11698,12 +11761,23 @@ var SolanaBatchPayer = class {
|
|
|
11698
11761
|
const unavailable = batchUnavailable(paymentRequired);
|
|
11699
11762
|
if (unavailable) return this.fallback(unavailable);
|
|
11700
11763
|
let wallet;
|
|
11764
|
+
let waitedMs = 0;
|
|
11701
11765
|
try {
|
|
11702
11766
|
wallet = await this.wallet();
|
|
11767
|
+
if ("reason" in wallet && wallet.reason === "channel_store_locked" && this.onLocked === "wait") {
|
|
11768
|
+
const started = Date.now();
|
|
11769
|
+
wallet = await this.waitForLock(wallet);
|
|
11770
|
+
waitedMs = Date.now() - started;
|
|
11771
|
+
}
|
|
11703
11772
|
} catch (err) {
|
|
11704
11773
|
return this.fallback(creationFailure(err));
|
|
11705
11774
|
}
|
|
11706
|
-
if ("reason" in wallet)
|
|
11775
|
+
if ("reason" in wallet) {
|
|
11776
|
+
if (wallet.reason === "channel_store_locked" && this.onLocked !== "exact") {
|
|
11777
|
+
return this.lockedOut(wallet.detail, wallet.ownerPid, waitedMs);
|
|
11778
|
+
}
|
|
11779
|
+
return this.fallback({ reason: wallet.reason, detail: wallet.detail });
|
|
11780
|
+
}
|
|
11707
11781
|
if (closesAtStart !== void 0 && wallet.closes !== closesAtStart) {
|
|
11708
11782
|
return this.fallback({
|
|
11709
11783
|
reason: "closed_during_call",
|
|
@@ -11720,6 +11794,40 @@ var SolanaBatchPayer = class {
|
|
|
11720
11794
|
wallet.active -= 1;
|
|
11721
11795
|
}
|
|
11722
11796
|
}
|
|
11797
|
+
/**
|
|
11798
|
+
* `onLocked: "wait"`: try the wallet's channel store again every
|
|
11799
|
+
* {@link LOCK_POLL_MS} until its owner lets go of it or `lockWaitMs` runs
|
|
11800
|
+
* out. Reported once as a `backoff` event (`channel_store_locked`).
|
|
11801
|
+
*/
|
|
11802
|
+
async waitForLock(refusal) {
|
|
11803
|
+
const deadline = Date.now() + this.lockWaitMs;
|
|
11804
|
+
let current = refusal;
|
|
11805
|
+
if (this.lockWaitMs > 0) {
|
|
11806
|
+
await this.report({
|
|
11807
|
+
type: "backoff",
|
|
11808
|
+
reason: "channel_store_locked",
|
|
11809
|
+
retryAfterMs: this.lockWaitMs,
|
|
11810
|
+
detail: refusal.detail
|
|
11811
|
+
});
|
|
11812
|
+
}
|
|
11813
|
+
while ("reason" in current && current.reason === "channel_store_locked") {
|
|
11814
|
+
const left = deadline - Date.now();
|
|
11815
|
+
if (left <= 0) break;
|
|
11816
|
+
await sleep2(Math.min(LOCK_POLL_MS, left));
|
|
11817
|
+
current = await this.wallet();
|
|
11818
|
+
}
|
|
11819
|
+
return current;
|
|
11820
|
+
}
|
|
11821
|
+
/** `onLocked` other than `"exact"`: the call's `"unpaid"` error, nothing signed. */
|
|
11822
|
+
async lockedOut(detail, ownerPid, waitedMs) {
|
|
11823
|
+
const error = new BatchChannelLockedError({
|
|
11824
|
+
wallet: await this.init.address(),
|
|
11825
|
+
detail,
|
|
11826
|
+
waitedMs,
|
|
11827
|
+
...ownerPid !== void 0 ? { ownerPid } : {}
|
|
11828
|
+
});
|
|
11829
|
+
return { kind: "failed", error };
|
|
11830
|
+
}
|
|
11723
11831
|
/**
|
|
11724
11832
|
* The close fence for a call about to send its first request: how many
|
|
11725
11833
|
* closes this wallet has completed so far, to hand to {@link pay}.
|
|
@@ -11810,11 +11918,9 @@ var SolanaBatchPayer = class {
|
|
|
11810
11918
|
}
|
|
11811
11919
|
if (wallet.busy) return fallback({ reason: "channel_busy", attempt: budget.attempt });
|
|
11812
11920
|
if (wallet.file && !holdsChannelFile(wallet.file)) {
|
|
11813
|
-
|
|
11814
|
-
|
|
11815
|
-
|
|
11816
|
-
detail: `this process no longer holds the lock on ${wallet.file}; another owner may be paying into its channels`
|
|
11817
|
-
});
|
|
11921
|
+
const detail = `this process no longer holds the lock on ${wallet.file}; another owner may be paying into its channels`;
|
|
11922
|
+
if (this.onLocked !== "exact") return this.lockedOut(detail, void 0, 0);
|
|
11923
|
+
return fallback({ reason: "channel_store_locked", attempt: budget.attempt, detail });
|
|
11818
11924
|
}
|
|
11819
11925
|
wallet.busy = true;
|
|
11820
11926
|
holding = true;
|
|
@@ -12391,7 +12497,8 @@ var SolanaBatchPayer = class {
|
|
|
12391
12497
|
const http = (await this.build(wallet)).http;
|
|
12392
12498
|
try {
|
|
12393
12499
|
await this.prepareTopUp(wallet, paymentRequired);
|
|
12394
|
-
|
|
12500
|
+
const required = await this.withDepositBlockhash(wallet, withoutClientSignedBatch(paymentRequired));
|
|
12501
|
+
return { http, payload: await http.createPaymentPayload(withPaymentIdentifier(required)) };
|
|
12395
12502
|
} catch (err) {
|
|
12396
12503
|
if (pass > 0 || !isResyncRequired(err) || wallet.resyncs.size === 0) throw err;
|
|
12397
12504
|
} finally {
|
|
@@ -12399,6 +12506,34 @@ var SolanaBatchPayer = class {
|
|
|
12399
12506
|
}
|
|
12400
12507
|
}
|
|
12401
12508
|
}
|
|
12509
|
+
/**
|
|
12510
|
+
* The 402 to build this payment from: with a finalized blockhash
|
|
12511
|
+
* ({@link withDepositBlockhash}) when the payment will likely carry a
|
|
12512
|
+
* deposit (no usable record for the trusted accept's channel, so an open,
|
|
12513
|
+
* or a top-up {@link prepareTopUp} just sized). An authorization signs no
|
|
12514
|
+
* transaction and costs no RPC read. Best effort: a failed read leaves the
|
|
12515
|
+
* 402 as it is, and `@x402/svm` fetches its own blockhash.
|
|
12516
|
+
*/
|
|
12517
|
+
async withDepositBlockhash(wallet, paymentRequired) {
|
|
12518
|
+
const accept = trustedBatchAccept(paymentRequired, this.init.options.operators);
|
|
12519
|
+
const key = accept ? channelKeyOf(accept) : void 0;
|
|
12520
|
+
if (!accept || accept.extra?.recentBlockhash) return paymentRequired;
|
|
12521
|
+
let deposit = wallet.topUp !== void 0;
|
|
12522
|
+
if (!deposit) {
|
|
12523
|
+
try {
|
|
12524
|
+
const record = key ? await wallet.book.base.get(key) : void 0;
|
|
12525
|
+
deposit = !record || typeof record.channelId !== "string" || record.pending !== void 0;
|
|
12526
|
+
} catch {
|
|
12527
|
+
deposit = true;
|
|
12528
|
+
}
|
|
12529
|
+
}
|
|
12530
|
+
if (!deposit) return paymentRequired;
|
|
12531
|
+
try {
|
|
12532
|
+
return withDepositBlockhash(paymentRequired, await finalizedBlockhash(this.init.rpcUrl, this.init.rpcHeaders));
|
|
12533
|
+
} catch {
|
|
12534
|
+
return paymentRequired;
|
|
12535
|
+
}
|
|
12536
|
+
}
|
|
12402
12537
|
/**
|
|
12403
12538
|
* Queue a re-read of a stored channel whose account is gone at finalized
|
|
12404
12539
|
* and at confirmed commitment (closed, its account reclaimed), anchored at
|
|
@@ -12705,7 +12840,6 @@ var SolanaBatchPayer = class {
|
|
|
12705
12840
|
// src/solana-client.ts
|
|
12706
12841
|
var SOLANA_API_URL = "https://sol.blockrun.ai/api";
|
|
12707
12842
|
var DEFAULT_MAX_TOKENS2 = 1024;
|
|
12708
|
-
var DEFAULT_TIMEOUT14 = 6e4;
|
|
12709
12843
|
var STALE_BLOCKHASH_RETRY_BACKOFFS_MS = [500, 2e3];
|
|
12710
12844
|
var MAX_PAYMENT_FAILURE_BYTES = 64 * 1024;
|
|
12711
12845
|
var DEFAULT_VIDEO_MODEL = "xai/grok-imagine-video";
|
|
@@ -12873,7 +13007,7 @@ var SolanaLLMClient = class {
|
|
|
12873
13007
|
const rpc = resolveRpcConfig(options.rpcUrl, options.rpcHeaders);
|
|
12874
13008
|
this.rpcUrl = rpc.url;
|
|
12875
13009
|
this.rpcHeaders = rpc.headers;
|
|
12876
|
-
this.timeout = options.timeout ||
|
|
13010
|
+
this.timeout = options.timeout || DEFAULT_TIMEOUT;
|
|
12877
13011
|
if (options.batch && !this.apiAuth) {
|
|
12878
13012
|
this.batchPayer = new SolanaBatchPayer({
|
|
12879
13013
|
options: options.batch,
|
|
@@ -14641,11 +14775,13 @@ var AnthropicClient = class {
|
|
|
14641
14775
|
AnthropicClient,
|
|
14642
14776
|
BASE_CHAIN_ID,
|
|
14643
14777
|
BLOCKRUN_SOL_OPERATOR,
|
|
14778
|
+
BatchChannelLockedError,
|
|
14644
14779
|
BatchCloseDeferredError,
|
|
14645
14780
|
BatchPaymentUnresolvedError,
|
|
14646
14781
|
BlockrunClient,
|
|
14647
14782
|
BlockrunError,
|
|
14648
14783
|
DEFAULT_BATCH_IN_DOUBT,
|
|
14784
|
+
DEFAULT_BATCH_LOCK_WAIT_MS,
|
|
14649
14785
|
DEFAULT_BATCH_RATE_LIMIT,
|
|
14650
14786
|
EVM_NETWORKS,
|
|
14651
14787
|
ImageClient,
|
package/dist/index.d.cts
CHANGED
|
@@ -2923,6 +2923,27 @@ interface SolanaBatchOptions {
|
|
|
2923
2923
|
* by scanning the chain for it.
|
|
2924
2924
|
*/
|
|
2925
2925
|
channelStore?: string | false;
|
|
2926
|
+
/**
|
|
2927
|
+
* What a call does when another live process owns this wallet's channel
|
|
2928
|
+
* store (`channel_store_locked`). One process per wallet pays with batch:
|
|
2929
|
+
* it holds the store's lock until it exits, so worker pools, PM2/cluster
|
|
2930
|
+
* workers or parallel runs on one wallet must each use their own wallet
|
|
2931
|
+
* (or route their calls through one process).
|
|
2932
|
+
* - `"exact"` (default): the call pays with `exact`, as before.
|
|
2933
|
+
* - `"wait"`: the call waits up to {@link lockWaitMs} for the lock (the
|
|
2934
|
+
* owner has to exit), then pays with batch, or raises
|
|
2935
|
+
* {@link BatchChannelLockedError} once the wait runs out.
|
|
2936
|
+
* - `"throw"`: the call raises {@link BatchChannelLockedError} at once.
|
|
2937
|
+
*
|
|
2938
|
+
* The error is raised before anything is signed, so it is `"unpaid"`:
|
|
2939
|
+
* `fallbackModels` (and `smartChat()`'s chain) may move on, and will meet
|
|
2940
|
+
* the same lock. A process that loses its lock to another owner raises it
|
|
2941
|
+
* too unless `onLocked` is `"exact"` (waiting cannot give it back).
|
|
2942
|
+
* Locks between clients of one process do not apply: they share a channel.
|
|
2943
|
+
*/
|
|
2944
|
+
onLocked?: "exact" | "wait" | "throw";
|
|
2945
|
+
/** Most time, in ms, one call waits for the lock under `onLocked: "wait"`. Default 60000. */
|
|
2946
|
+
lockWaitMs?: number;
|
|
2926
2947
|
/**
|
|
2927
2948
|
* How a call rides out an HTTP 429 (rate limited, or channel capacity
|
|
2928
2949
|
* exhausted) on a batch payment before it pays with `exact`. The call waits
|
|
@@ -2982,6 +3003,8 @@ declare const DEFAULT_BATCH_RATE_LIMIT: {
|
|
|
2982
3003
|
declare const DEFAULT_BATCH_IN_DOUBT: {
|
|
2983
3004
|
readonly maxWaitMs: 300000;
|
|
2984
3005
|
};
|
|
3006
|
+
/** Default {@link SolanaBatchOptions.lockWaitMs}. */
|
|
3007
|
+
declare const DEFAULT_BATCH_LOCK_WAIT_MS = 60000;
|
|
2985
3008
|
/**
|
|
2986
3009
|
* One observable batch-settlement event.
|
|
2987
3010
|
*
|
|
@@ -2996,7 +3019,10 @@ declare const DEFAULT_BATCH_IN_DOUBT: {
|
|
|
2996
3019
|
* (`reason: "rate_limited"`) or because another call for the wallet hit one
|
|
2997
3020
|
* (`reason: "cooldown"`), or before each replay of a payment in doubt that
|
|
2998
3021
|
* carries a payment identifier (`reason: "in_doubt"`, or `rate_limited`
|
|
2999
|
-
* after a 429), with the answer's `status` and the wait in `retryAfterMs
|
|
3022
|
+
* after a 429), with the answer's `status` and the wait in `retryAfterMs`;
|
|
3023
|
+
* or, once, when a call starts waiting up to `lockWaitMs` for another
|
|
3024
|
+
* process's channel store lock (`reason: "channel_store_locked"`,
|
|
3025
|
+
* `onLocked: "wait"`).
|
|
3000
3026
|
* - `recovered`: a call that backed off was then paid with batch (`reason:
|
|
3001
3027
|
* "in_doubt"` when the replay of a payment in doubt resolved it), or its
|
|
3002
3028
|
* fresh challenge after the wait was served without a payment (`reason:
|
|
@@ -3167,6 +3193,26 @@ declare class BatchCloseDeferredError extends BlockrunError {
|
|
|
3167
3193
|
detail: string;
|
|
3168
3194
|
});
|
|
3169
3195
|
}
|
|
3196
|
+
/**
|
|
3197
|
+
* Batch is on, another owner holds this wallet's channel store, and the
|
|
3198
|
+
* client's `batch.onLocked` is `"wait"` (the wait ran out) or `"throw"`.
|
|
3199
|
+
* Raised before anything is signed: nothing was paid for the call, and its
|
|
3200
|
+
* {@link RetryDisposition} is `"unpaid"`.
|
|
3201
|
+
*/
|
|
3202
|
+
declare class BatchChannelLockedError extends BlockrunError {
|
|
3203
|
+
/** The paying wallet's address. */
|
|
3204
|
+
readonly wallet: string;
|
|
3205
|
+
/** The live owner's pid, when the SDK knows it. */
|
|
3206
|
+
readonly ownerPid?: number;
|
|
3207
|
+
/** How long this call waited for the lock, in ms (0 unless `onLocked` is `"wait"`). */
|
|
3208
|
+
readonly waitedMs: number;
|
|
3209
|
+
constructor(init: {
|
|
3210
|
+
wallet: string;
|
|
3211
|
+
detail: string;
|
|
3212
|
+
ownerPid?: number;
|
|
3213
|
+
waitedMs: number;
|
|
3214
|
+
});
|
|
3215
|
+
}
|
|
3170
3216
|
/**
|
|
3171
3217
|
* The outcome of one batch attempt.
|
|
3172
3218
|
*
|
|
@@ -3270,6 +3316,8 @@ declare class SolanaBatchPayer {
|
|
|
3270
3316
|
private readonly maxAttempts;
|
|
3271
3317
|
private readonly maxWaitMs;
|
|
3272
3318
|
private readonly inDoubtMaxWaitMs;
|
|
3319
|
+
private readonly onLocked;
|
|
3320
|
+
private readonly lockWaitMs;
|
|
3273
3321
|
private readonly counters;
|
|
3274
3322
|
private readonly hooks;
|
|
3275
3323
|
constructor(init: SolanaBatchPayerInit);
|
|
@@ -3387,6 +3435,14 @@ declare class SolanaBatchPayer {
|
|
|
3387
3435
|
* open a channel the caller believes is closed.
|
|
3388
3436
|
*/
|
|
3389
3437
|
pay(paymentRequired: PaymentRequired, send: (headers: Record<string, string>) => Promise<Response>, rechallenge: () => Promise<Rechallenge>, closesAtStart?: number): Promise<BatchAttempt>;
|
|
3438
|
+
/**
|
|
3439
|
+
* `onLocked: "wait"`: try the wallet's channel store again every
|
|
3440
|
+
* {@link LOCK_POLL_MS} until its owner lets go of it or `lockWaitMs` runs
|
|
3441
|
+
* out. Reported once as a `backoff` event (`channel_store_locked`).
|
|
3442
|
+
*/
|
|
3443
|
+
private waitForLock;
|
|
3444
|
+
/** `onLocked` other than `"exact"`: the call's `"unpaid"` error, nothing signed. */
|
|
3445
|
+
private lockedOut;
|
|
3390
3446
|
/**
|
|
3391
3447
|
* The close fence for a call about to send its first request: how many
|
|
3392
3448
|
* closes this wallet has completed so far, to hand to {@link pay}.
|
|
@@ -3508,6 +3564,15 @@ declare class SolanaBatchPayer {
|
|
|
3508
3564
|
* once.
|
|
3509
3565
|
*/
|
|
3510
3566
|
private createPayload;
|
|
3567
|
+
/**
|
|
3568
|
+
* The 402 to build this payment from: with a finalized blockhash
|
|
3569
|
+
* ({@link withDepositBlockhash}) when the payment will likely carry a
|
|
3570
|
+
* deposit (no usable record for the trusted accept's channel, so an open,
|
|
3571
|
+
* or a top-up {@link prepareTopUp} just sized). An authorization signs no
|
|
3572
|
+
* transaction and costs no RPC read. Best effort: a failed read leaves the
|
|
3573
|
+
* 402 as it is, and `@x402/svm` fetches its own blockhash.
|
|
3574
|
+
*/
|
|
3575
|
+
private withDepositBlockhash;
|
|
3511
3576
|
/**
|
|
3512
3577
|
* Queue a re-read of a stored channel whose account is gone at finalized
|
|
3513
3578
|
* and at confirmed commitment (closed, its account reclaimed), anchored at
|
|
@@ -3647,7 +3712,12 @@ interface SolanaLLMClientOptions extends ApiKeyOptions {
|
|
|
3647
3712
|
* (shortcut for `{ "x-api-key": "..." }`) env vars when omitted.
|
|
3648
3713
|
*/
|
|
3649
3714
|
rpcHeaders?: Record<string, string>;
|
|
3650
|
-
/**
|
|
3715
|
+
/**
|
|
3716
|
+
* Request timeout in milliseconds. Default: `BLOCKRUN_CHAT_TIMEOUT` (in
|
|
3717
|
+
* seconds) when set, else 600000, the same as `LLMClient`: a reasoning
|
|
3718
|
+
* model's long turn can take minutes, and a batch payment whose call is
|
|
3719
|
+
* aborted after it was sent ends unresolved.
|
|
3720
|
+
*/
|
|
3651
3721
|
timeout?: number;
|
|
3652
3722
|
/**
|
|
3653
3723
|
* Opt in to x402 batch-settlement (metered billing) for chat completions.
|
|
@@ -4476,4 +4546,4 @@ declare function readSettlement(response: Response, quotedUsd: number, scheme: S
|
|
|
4476
4546
|
settlement: Settlement;
|
|
4477
4547
|
};
|
|
4478
4548
|
|
|
4479
|
-
export { APIError, API_KEY_URL, ARC_CHAIN_ID, AnthropicClient, type AnyTool, type ApiKeyOptions, type AudioModel, type AudioTrack, BASE_CHAIN_ID, BLOCKRUN_SOL_OPERATOR, type BarResolution, type BatchAttempt, BatchCloseDeferredError, type BatchPayloadKind, BatchPaymentUnresolvedError, type BatchUnresolvedReason, type BlockRunAnthropicOptions, BlockrunClient, type BlockrunClientOptions, BlockrunError, type CallInitiatedResponse, type CallModel, type CallOptions, type CallStatusResponse, type ChatChoice, type ChatCompletionOptions, type ChatMessage, type ChatOptions, type ChatResponse, type ChatResponseWithCost, type ChatUsage, type CostEntry, type CostEstimate, type CreatePaymentOptions, DEFAULT_BATCH_IN_DOUBT, DEFAULT_BATCH_RATE_LIMIT, EVM_NETWORKS, type EvmNetwork, type FunctionCall, type FunctionDefinition, type HistoryOptions, ImageClient, type ImageClientOptions, type ImageData, type ImageEditOptions, type ImageGenerateOptions, type ImageModel, type ImageResponse, KNOWN_PROVIDERS, LLMClient, type LLMClientOptions, type ListOptions, type MarketSession, type Model, MusicClient, type MusicClientOptions, type MusicGenerateOptions, type MusicResponse, NETWORK_ALIASES, type NewsSearchSource, OpenAI, type OpenAIChatCompletionChoice, type OpenAIChatCompletionChunk, type OpenAIChatCompletionParams, type OpenAIChatCompletionResponse, type OpenAIClientOptions, PHONE_PRICES, PORTAL_URL, PORTRAIT_ENROLLMENT_PRICE_USD, PaymentError, type PaymentLinks, type PhoneBuyOptions, type PhoneBuyResponse, PhoneClient, type PhoneClientOptions, type PhoneListResponse, type PhoneLookupResponse, type PhoneNumberRecord, type PhoneReleaseResponse, type PhoneRenewResponse, type PollOptions, PortraitClient, type PortraitClientOptions, type PortraitEnrollOptions, type PortraitEnrollResponse, type PriceBar, type PriceCategory, PriceClient, type PriceClientOptions, type PriceHistoryResponse, type PriceOptions, type PricePoint, RPC_PRICE_USD, type Rechallenge, type ResponseFormat, RetiredEndpointError, type RetryDisposition, type RoutingDecision, type RoutingProfile, type RoutingTaskType, type RoutingTier, type RoutingTierConfig, type RpcBatchRequest, RpcClient, type RpcClientOptions, type RpcError, type RpcNetwork, type RpcResponse, type RssSearchSource, SOLANA_NETWORK, SOLANA_WALLET_FILE as SOLANA_WALLET_FILE_PATH, SUPPORTED_NETWORKS, SearchClient, type SearchClientOptions, type SearchOptions, type SearchParameters, type SearchResult, type SearchSource, type SearchUsage, type Settlement, type SmartChatCompletionOptions, type SmartChatCompletionResponse, type SmartChatOptions, type SmartChatResponse, type SolanaBatchEvent, type SolanaBatchOptions, SolanaBatchPayer, type SolanaBatchPayerInit, type SolanaBatchStats, SolanaLLMClient, type SolanaLLMClientOptions, type SolanaWalletInfo, type SoundEffectOptions, type SpeechAudio, SpeechClient, type SpeechClientOptions, type SpeechGenerateOptions, type SpeechModel, type SpeechResponse, type SpeechVoice, type Spending, type SpendingReport, type StockMarket, SurfClient, type SurfClientOptions, type SymbolListResponse, type Tool, type ToolCall, type ToolChoice, USDC_ARC, USDC_BASE, USDC_BASE_CONTRACT, USDC_SOLANA, type UrlCitation, VideoClient, type VideoClientOptions, type VideoClip, type VideoGenerateOptions, type VideoModel, type VideoResponse, VoiceClient, type VoiceClientOptions, type VoiceInfo, type VoicePreset, WALLET_DIR_PATH, WALLET_FILE_PATH, type WalletInfo, type WebSearchSource, type WebSearchTool, type X402ClientLike, type X402HookContext, type XSearchSource, type XSearchTool, clearCache, createPaymentPayload, createSolanaPaymentPayload, createSolanaWallet, createWallet, LLMClient as default, evmNetwork, extractPaymentDetails, formatFundingMessageCompact, formatNeedsFundingMessage, formatSolanaWalletMigrationNotice, formatWalletCreatedMessage, formatWalletMigrationNotice, getCached, getCachedByRequest, getCostLogSummary, getCostSummary, getEip681Uri, getOrCreateSolanaWallet, getOrCreateWallet, getPaymentLinks, getWalletAddress, importSolanaWallet, importWallet, listDiscoveredSolanaWallets, listDiscoveredWallets, loadSolanaWallet, loadWallet, logCost, parsePaymentRequired, readSettlement, retryDisposition, saveSolanaWallet, saveToCache, saveWallet, scanSolanaWallets, scanWallets, setCache, setupAgentClient, setupAgentSolanaWallet, setupAgentWallet, solanaClient, solanaKeyToBytes, solanaPublicKey, status, toWireSearchParameters, toWireTools, validateMaxTokens, validateModel, validateTemperature, validateTopP };
|
|
4549
|
+
export { APIError, API_KEY_URL, ARC_CHAIN_ID, AnthropicClient, type AnyTool, type ApiKeyOptions, type AudioModel, type AudioTrack, BASE_CHAIN_ID, BLOCKRUN_SOL_OPERATOR, type BarResolution, type BatchAttempt, BatchChannelLockedError, BatchCloseDeferredError, type BatchPayloadKind, BatchPaymentUnresolvedError, type BatchUnresolvedReason, type BlockRunAnthropicOptions, BlockrunClient, type BlockrunClientOptions, BlockrunError, type CallInitiatedResponse, type CallModel, type CallOptions, type CallStatusResponse, type ChatChoice, type ChatCompletionOptions, type ChatMessage, type ChatOptions, type ChatResponse, type ChatResponseWithCost, type ChatUsage, type CostEntry, type CostEstimate, type CreatePaymentOptions, DEFAULT_BATCH_IN_DOUBT, DEFAULT_BATCH_LOCK_WAIT_MS, DEFAULT_BATCH_RATE_LIMIT, EVM_NETWORKS, type EvmNetwork, type FunctionCall, type FunctionDefinition, type HistoryOptions, ImageClient, type ImageClientOptions, type ImageData, type ImageEditOptions, type ImageGenerateOptions, type ImageModel, type ImageResponse, KNOWN_PROVIDERS, LLMClient, type LLMClientOptions, type ListOptions, type MarketSession, type Model, MusicClient, type MusicClientOptions, type MusicGenerateOptions, type MusicResponse, NETWORK_ALIASES, type NewsSearchSource, OpenAI, type OpenAIChatCompletionChoice, type OpenAIChatCompletionChunk, type OpenAIChatCompletionParams, type OpenAIChatCompletionResponse, type OpenAIClientOptions, PHONE_PRICES, PORTAL_URL, PORTRAIT_ENROLLMENT_PRICE_USD, PaymentError, type PaymentLinks, type PhoneBuyOptions, type PhoneBuyResponse, PhoneClient, type PhoneClientOptions, type PhoneListResponse, type PhoneLookupResponse, type PhoneNumberRecord, type PhoneReleaseResponse, type PhoneRenewResponse, type PollOptions, PortraitClient, type PortraitClientOptions, type PortraitEnrollOptions, type PortraitEnrollResponse, type PriceBar, type PriceCategory, PriceClient, type PriceClientOptions, type PriceHistoryResponse, type PriceOptions, type PricePoint, RPC_PRICE_USD, type Rechallenge, type ResponseFormat, RetiredEndpointError, type RetryDisposition, type RoutingDecision, type RoutingProfile, type RoutingTaskType, type RoutingTier, type RoutingTierConfig, type RpcBatchRequest, RpcClient, type RpcClientOptions, type RpcError, type RpcNetwork, type RpcResponse, type RssSearchSource, SOLANA_NETWORK, SOLANA_WALLET_FILE as SOLANA_WALLET_FILE_PATH, SUPPORTED_NETWORKS, SearchClient, type SearchClientOptions, type SearchOptions, type SearchParameters, type SearchResult, type SearchSource, type SearchUsage, type Settlement, type SmartChatCompletionOptions, type SmartChatCompletionResponse, type SmartChatOptions, type SmartChatResponse, type SolanaBatchEvent, type SolanaBatchOptions, SolanaBatchPayer, type SolanaBatchPayerInit, type SolanaBatchStats, SolanaLLMClient, type SolanaLLMClientOptions, type SolanaWalletInfo, type SoundEffectOptions, type SpeechAudio, SpeechClient, type SpeechClientOptions, type SpeechGenerateOptions, type SpeechModel, type SpeechResponse, type SpeechVoice, type Spending, type SpendingReport, type StockMarket, SurfClient, type SurfClientOptions, type SymbolListResponse, type Tool, type ToolCall, type ToolChoice, USDC_ARC, USDC_BASE, USDC_BASE_CONTRACT, USDC_SOLANA, type UrlCitation, VideoClient, type VideoClientOptions, type VideoClip, type VideoGenerateOptions, type VideoModel, type VideoResponse, VoiceClient, type VoiceClientOptions, type VoiceInfo, type VoicePreset, WALLET_DIR_PATH, WALLET_FILE_PATH, type WalletInfo, type WebSearchSource, type WebSearchTool, type X402ClientLike, type X402HookContext, type XSearchSource, type XSearchTool, clearCache, createPaymentPayload, createSolanaPaymentPayload, createSolanaWallet, createWallet, LLMClient as default, evmNetwork, extractPaymentDetails, formatFundingMessageCompact, formatNeedsFundingMessage, formatSolanaWalletMigrationNotice, formatWalletCreatedMessage, formatWalletMigrationNotice, getCached, getCachedByRequest, getCostLogSummary, getCostSummary, getEip681Uri, getOrCreateSolanaWallet, getOrCreateWallet, getPaymentLinks, getWalletAddress, importSolanaWallet, importWallet, listDiscoveredSolanaWallets, listDiscoveredWallets, loadSolanaWallet, loadWallet, logCost, parsePaymentRequired, readSettlement, retryDisposition, saveSolanaWallet, saveToCache, saveWallet, scanSolanaWallets, scanWallets, setCache, setupAgentClient, setupAgentSolanaWallet, setupAgentWallet, solanaClient, solanaKeyToBytes, solanaPublicKey, status, toWireSearchParameters, toWireTools, validateMaxTokens, validateModel, validateTemperature, validateTopP };
|
package/dist/index.d.ts
CHANGED
|
@@ -2923,6 +2923,27 @@ interface SolanaBatchOptions {
|
|
|
2923
2923
|
* by scanning the chain for it.
|
|
2924
2924
|
*/
|
|
2925
2925
|
channelStore?: string | false;
|
|
2926
|
+
/**
|
|
2927
|
+
* What a call does when another live process owns this wallet's channel
|
|
2928
|
+
* store (`channel_store_locked`). One process per wallet pays with batch:
|
|
2929
|
+
* it holds the store's lock until it exits, so worker pools, PM2/cluster
|
|
2930
|
+
* workers or parallel runs on one wallet must each use their own wallet
|
|
2931
|
+
* (or route their calls through one process).
|
|
2932
|
+
* - `"exact"` (default): the call pays with `exact`, as before.
|
|
2933
|
+
* - `"wait"`: the call waits up to {@link lockWaitMs} for the lock (the
|
|
2934
|
+
* owner has to exit), then pays with batch, or raises
|
|
2935
|
+
* {@link BatchChannelLockedError} once the wait runs out.
|
|
2936
|
+
* - `"throw"`: the call raises {@link BatchChannelLockedError} at once.
|
|
2937
|
+
*
|
|
2938
|
+
* The error is raised before anything is signed, so it is `"unpaid"`:
|
|
2939
|
+
* `fallbackModels` (and `smartChat()`'s chain) may move on, and will meet
|
|
2940
|
+
* the same lock. A process that loses its lock to another owner raises it
|
|
2941
|
+
* too unless `onLocked` is `"exact"` (waiting cannot give it back).
|
|
2942
|
+
* Locks between clients of one process do not apply: they share a channel.
|
|
2943
|
+
*/
|
|
2944
|
+
onLocked?: "exact" | "wait" | "throw";
|
|
2945
|
+
/** Most time, in ms, one call waits for the lock under `onLocked: "wait"`. Default 60000. */
|
|
2946
|
+
lockWaitMs?: number;
|
|
2926
2947
|
/**
|
|
2927
2948
|
* How a call rides out an HTTP 429 (rate limited, or channel capacity
|
|
2928
2949
|
* exhausted) on a batch payment before it pays with `exact`. The call waits
|
|
@@ -2982,6 +3003,8 @@ declare const DEFAULT_BATCH_RATE_LIMIT: {
|
|
|
2982
3003
|
declare const DEFAULT_BATCH_IN_DOUBT: {
|
|
2983
3004
|
readonly maxWaitMs: 300000;
|
|
2984
3005
|
};
|
|
3006
|
+
/** Default {@link SolanaBatchOptions.lockWaitMs}. */
|
|
3007
|
+
declare const DEFAULT_BATCH_LOCK_WAIT_MS = 60000;
|
|
2985
3008
|
/**
|
|
2986
3009
|
* One observable batch-settlement event.
|
|
2987
3010
|
*
|
|
@@ -2996,7 +3019,10 @@ declare const DEFAULT_BATCH_IN_DOUBT: {
|
|
|
2996
3019
|
* (`reason: "rate_limited"`) or because another call for the wallet hit one
|
|
2997
3020
|
* (`reason: "cooldown"`), or before each replay of a payment in doubt that
|
|
2998
3021
|
* carries a payment identifier (`reason: "in_doubt"`, or `rate_limited`
|
|
2999
|
-
* after a 429), with the answer's `status` and the wait in `retryAfterMs
|
|
3022
|
+
* after a 429), with the answer's `status` and the wait in `retryAfterMs`;
|
|
3023
|
+
* or, once, when a call starts waiting up to `lockWaitMs` for another
|
|
3024
|
+
* process's channel store lock (`reason: "channel_store_locked"`,
|
|
3025
|
+
* `onLocked: "wait"`).
|
|
3000
3026
|
* - `recovered`: a call that backed off was then paid with batch (`reason:
|
|
3001
3027
|
* "in_doubt"` when the replay of a payment in doubt resolved it), or its
|
|
3002
3028
|
* fresh challenge after the wait was served without a payment (`reason:
|
|
@@ -3167,6 +3193,26 @@ declare class BatchCloseDeferredError extends BlockrunError {
|
|
|
3167
3193
|
detail: string;
|
|
3168
3194
|
});
|
|
3169
3195
|
}
|
|
3196
|
+
/**
|
|
3197
|
+
* Batch is on, another owner holds this wallet's channel store, and the
|
|
3198
|
+
* client's `batch.onLocked` is `"wait"` (the wait ran out) or `"throw"`.
|
|
3199
|
+
* Raised before anything is signed: nothing was paid for the call, and its
|
|
3200
|
+
* {@link RetryDisposition} is `"unpaid"`.
|
|
3201
|
+
*/
|
|
3202
|
+
declare class BatchChannelLockedError extends BlockrunError {
|
|
3203
|
+
/** The paying wallet's address. */
|
|
3204
|
+
readonly wallet: string;
|
|
3205
|
+
/** The live owner's pid, when the SDK knows it. */
|
|
3206
|
+
readonly ownerPid?: number;
|
|
3207
|
+
/** How long this call waited for the lock, in ms (0 unless `onLocked` is `"wait"`). */
|
|
3208
|
+
readonly waitedMs: number;
|
|
3209
|
+
constructor(init: {
|
|
3210
|
+
wallet: string;
|
|
3211
|
+
detail: string;
|
|
3212
|
+
ownerPid?: number;
|
|
3213
|
+
waitedMs: number;
|
|
3214
|
+
});
|
|
3215
|
+
}
|
|
3170
3216
|
/**
|
|
3171
3217
|
* The outcome of one batch attempt.
|
|
3172
3218
|
*
|
|
@@ -3270,6 +3316,8 @@ declare class SolanaBatchPayer {
|
|
|
3270
3316
|
private readonly maxAttempts;
|
|
3271
3317
|
private readonly maxWaitMs;
|
|
3272
3318
|
private readonly inDoubtMaxWaitMs;
|
|
3319
|
+
private readonly onLocked;
|
|
3320
|
+
private readonly lockWaitMs;
|
|
3273
3321
|
private readonly counters;
|
|
3274
3322
|
private readonly hooks;
|
|
3275
3323
|
constructor(init: SolanaBatchPayerInit);
|
|
@@ -3387,6 +3435,14 @@ declare class SolanaBatchPayer {
|
|
|
3387
3435
|
* open a channel the caller believes is closed.
|
|
3388
3436
|
*/
|
|
3389
3437
|
pay(paymentRequired: PaymentRequired, send: (headers: Record<string, string>) => Promise<Response>, rechallenge: () => Promise<Rechallenge>, closesAtStart?: number): Promise<BatchAttempt>;
|
|
3438
|
+
/**
|
|
3439
|
+
* `onLocked: "wait"`: try the wallet's channel store again every
|
|
3440
|
+
* {@link LOCK_POLL_MS} until its owner lets go of it or `lockWaitMs` runs
|
|
3441
|
+
* out. Reported once as a `backoff` event (`channel_store_locked`).
|
|
3442
|
+
*/
|
|
3443
|
+
private waitForLock;
|
|
3444
|
+
/** `onLocked` other than `"exact"`: the call's `"unpaid"` error, nothing signed. */
|
|
3445
|
+
private lockedOut;
|
|
3390
3446
|
/**
|
|
3391
3447
|
* The close fence for a call about to send its first request: how many
|
|
3392
3448
|
* closes this wallet has completed so far, to hand to {@link pay}.
|
|
@@ -3508,6 +3564,15 @@ declare class SolanaBatchPayer {
|
|
|
3508
3564
|
* once.
|
|
3509
3565
|
*/
|
|
3510
3566
|
private createPayload;
|
|
3567
|
+
/**
|
|
3568
|
+
* The 402 to build this payment from: with a finalized blockhash
|
|
3569
|
+
* ({@link withDepositBlockhash}) when the payment will likely carry a
|
|
3570
|
+
* deposit (no usable record for the trusted accept's channel, so an open,
|
|
3571
|
+
* or a top-up {@link prepareTopUp} just sized). An authorization signs no
|
|
3572
|
+
* transaction and costs no RPC read. Best effort: a failed read leaves the
|
|
3573
|
+
* 402 as it is, and `@x402/svm` fetches its own blockhash.
|
|
3574
|
+
*/
|
|
3575
|
+
private withDepositBlockhash;
|
|
3511
3576
|
/**
|
|
3512
3577
|
* Queue a re-read of a stored channel whose account is gone at finalized
|
|
3513
3578
|
* and at confirmed commitment (closed, its account reclaimed), anchored at
|
|
@@ -3647,7 +3712,12 @@ interface SolanaLLMClientOptions extends ApiKeyOptions {
|
|
|
3647
3712
|
* (shortcut for `{ "x-api-key": "..." }`) env vars when omitted.
|
|
3648
3713
|
*/
|
|
3649
3714
|
rpcHeaders?: Record<string, string>;
|
|
3650
|
-
/**
|
|
3715
|
+
/**
|
|
3716
|
+
* Request timeout in milliseconds. Default: `BLOCKRUN_CHAT_TIMEOUT` (in
|
|
3717
|
+
* seconds) when set, else 600000, the same as `LLMClient`: a reasoning
|
|
3718
|
+
* model's long turn can take minutes, and a batch payment whose call is
|
|
3719
|
+
* aborted after it was sent ends unresolved.
|
|
3720
|
+
*/
|
|
3651
3721
|
timeout?: number;
|
|
3652
3722
|
/**
|
|
3653
3723
|
* Opt in to x402 batch-settlement (metered billing) for chat completions.
|
|
@@ -4476,4 +4546,4 @@ declare function readSettlement(response: Response, quotedUsd: number, scheme: S
|
|
|
4476
4546
|
settlement: Settlement;
|
|
4477
4547
|
};
|
|
4478
4548
|
|
|
4479
|
-
export { APIError, API_KEY_URL, ARC_CHAIN_ID, AnthropicClient, type AnyTool, type ApiKeyOptions, type AudioModel, type AudioTrack, BASE_CHAIN_ID, BLOCKRUN_SOL_OPERATOR, type BarResolution, type BatchAttempt, BatchCloseDeferredError, type BatchPayloadKind, BatchPaymentUnresolvedError, type BatchUnresolvedReason, type BlockRunAnthropicOptions, BlockrunClient, type BlockrunClientOptions, BlockrunError, type CallInitiatedResponse, type CallModel, type CallOptions, type CallStatusResponse, type ChatChoice, type ChatCompletionOptions, type ChatMessage, type ChatOptions, type ChatResponse, type ChatResponseWithCost, type ChatUsage, type CostEntry, type CostEstimate, type CreatePaymentOptions, DEFAULT_BATCH_IN_DOUBT, DEFAULT_BATCH_RATE_LIMIT, EVM_NETWORKS, type EvmNetwork, type FunctionCall, type FunctionDefinition, type HistoryOptions, ImageClient, type ImageClientOptions, type ImageData, type ImageEditOptions, type ImageGenerateOptions, type ImageModel, type ImageResponse, KNOWN_PROVIDERS, LLMClient, type LLMClientOptions, type ListOptions, type MarketSession, type Model, MusicClient, type MusicClientOptions, type MusicGenerateOptions, type MusicResponse, NETWORK_ALIASES, type NewsSearchSource, OpenAI, type OpenAIChatCompletionChoice, type OpenAIChatCompletionChunk, type OpenAIChatCompletionParams, type OpenAIChatCompletionResponse, type OpenAIClientOptions, PHONE_PRICES, PORTAL_URL, PORTRAIT_ENROLLMENT_PRICE_USD, PaymentError, type PaymentLinks, type PhoneBuyOptions, type PhoneBuyResponse, PhoneClient, type PhoneClientOptions, type PhoneListResponse, type PhoneLookupResponse, type PhoneNumberRecord, type PhoneReleaseResponse, type PhoneRenewResponse, type PollOptions, PortraitClient, type PortraitClientOptions, type PortraitEnrollOptions, type PortraitEnrollResponse, type PriceBar, type PriceCategory, PriceClient, type PriceClientOptions, type PriceHistoryResponse, type PriceOptions, type PricePoint, RPC_PRICE_USD, type Rechallenge, type ResponseFormat, RetiredEndpointError, type RetryDisposition, type RoutingDecision, type RoutingProfile, type RoutingTaskType, type RoutingTier, type RoutingTierConfig, type RpcBatchRequest, RpcClient, type RpcClientOptions, type RpcError, type RpcNetwork, type RpcResponse, type RssSearchSource, SOLANA_NETWORK, SOLANA_WALLET_FILE as SOLANA_WALLET_FILE_PATH, SUPPORTED_NETWORKS, SearchClient, type SearchClientOptions, type SearchOptions, type SearchParameters, type SearchResult, type SearchSource, type SearchUsage, type Settlement, type SmartChatCompletionOptions, type SmartChatCompletionResponse, type SmartChatOptions, type SmartChatResponse, type SolanaBatchEvent, type SolanaBatchOptions, SolanaBatchPayer, type SolanaBatchPayerInit, type SolanaBatchStats, SolanaLLMClient, type SolanaLLMClientOptions, type SolanaWalletInfo, type SoundEffectOptions, type SpeechAudio, SpeechClient, type SpeechClientOptions, type SpeechGenerateOptions, type SpeechModel, type SpeechResponse, type SpeechVoice, type Spending, type SpendingReport, type StockMarket, SurfClient, type SurfClientOptions, type SymbolListResponse, type Tool, type ToolCall, type ToolChoice, USDC_ARC, USDC_BASE, USDC_BASE_CONTRACT, USDC_SOLANA, type UrlCitation, VideoClient, type VideoClientOptions, type VideoClip, type VideoGenerateOptions, type VideoModel, type VideoResponse, VoiceClient, type VoiceClientOptions, type VoiceInfo, type VoicePreset, WALLET_DIR_PATH, WALLET_FILE_PATH, type WalletInfo, type WebSearchSource, type WebSearchTool, type X402ClientLike, type X402HookContext, type XSearchSource, type XSearchTool, clearCache, createPaymentPayload, createSolanaPaymentPayload, createSolanaWallet, createWallet, LLMClient as default, evmNetwork, extractPaymentDetails, formatFundingMessageCompact, formatNeedsFundingMessage, formatSolanaWalletMigrationNotice, formatWalletCreatedMessage, formatWalletMigrationNotice, getCached, getCachedByRequest, getCostLogSummary, getCostSummary, getEip681Uri, getOrCreateSolanaWallet, getOrCreateWallet, getPaymentLinks, getWalletAddress, importSolanaWallet, importWallet, listDiscoveredSolanaWallets, listDiscoveredWallets, loadSolanaWallet, loadWallet, logCost, parsePaymentRequired, readSettlement, retryDisposition, saveSolanaWallet, saveToCache, saveWallet, scanSolanaWallets, scanWallets, setCache, setupAgentClient, setupAgentSolanaWallet, setupAgentWallet, solanaClient, solanaKeyToBytes, solanaPublicKey, status, toWireSearchParameters, toWireTools, validateMaxTokens, validateModel, validateTemperature, validateTopP };
|
|
4549
|
+
export { APIError, API_KEY_URL, ARC_CHAIN_ID, AnthropicClient, type AnyTool, type ApiKeyOptions, type AudioModel, type AudioTrack, BASE_CHAIN_ID, BLOCKRUN_SOL_OPERATOR, type BarResolution, type BatchAttempt, BatchChannelLockedError, BatchCloseDeferredError, type BatchPayloadKind, BatchPaymentUnresolvedError, type BatchUnresolvedReason, type BlockRunAnthropicOptions, BlockrunClient, type BlockrunClientOptions, BlockrunError, type CallInitiatedResponse, type CallModel, type CallOptions, type CallStatusResponse, type ChatChoice, type ChatCompletionOptions, type ChatMessage, type ChatOptions, type ChatResponse, type ChatResponseWithCost, type ChatUsage, type CostEntry, type CostEstimate, type CreatePaymentOptions, DEFAULT_BATCH_IN_DOUBT, DEFAULT_BATCH_LOCK_WAIT_MS, DEFAULT_BATCH_RATE_LIMIT, EVM_NETWORKS, type EvmNetwork, type FunctionCall, type FunctionDefinition, type HistoryOptions, ImageClient, type ImageClientOptions, type ImageData, type ImageEditOptions, type ImageGenerateOptions, type ImageModel, type ImageResponse, KNOWN_PROVIDERS, LLMClient, type LLMClientOptions, type ListOptions, type MarketSession, type Model, MusicClient, type MusicClientOptions, type MusicGenerateOptions, type MusicResponse, NETWORK_ALIASES, type NewsSearchSource, OpenAI, type OpenAIChatCompletionChoice, type OpenAIChatCompletionChunk, type OpenAIChatCompletionParams, type OpenAIChatCompletionResponse, type OpenAIClientOptions, PHONE_PRICES, PORTAL_URL, PORTRAIT_ENROLLMENT_PRICE_USD, PaymentError, type PaymentLinks, type PhoneBuyOptions, type PhoneBuyResponse, PhoneClient, type PhoneClientOptions, type PhoneListResponse, type PhoneLookupResponse, type PhoneNumberRecord, type PhoneReleaseResponse, type PhoneRenewResponse, type PollOptions, PortraitClient, type PortraitClientOptions, type PortraitEnrollOptions, type PortraitEnrollResponse, type PriceBar, type PriceCategory, PriceClient, type PriceClientOptions, type PriceHistoryResponse, type PriceOptions, type PricePoint, RPC_PRICE_USD, type Rechallenge, type ResponseFormat, RetiredEndpointError, type RetryDisposition, type RoutingDecision, type RoutingProfile, type RoutingTaskType, type RoutingTier, type RoutingTierConfig, type RpcBatchRequest, RpcClient, type RpcClientOptions, type RpcError, type RpcNetwork, type RpcResponse, type RssSearchSource, SOLANA_NETWORK, SOLANA_WALLET_FILE as SOLANA_WALLET_FILE_PATH, SUPPORTED_NETWORKS, SearchClient, type SearchClientOptions, type SearchOptions, type SearchParameters, type SearchResult, type SearchSource, type SearchUsage, type Settlement, type SmartChatCompletionOptions, type SmartChatCompletionResponse, type SmartChatOptions, type SmartChatResponse, type SolanaBatchEvent, type SolanaBatchOptions, SolanaBatchPayer, type SolanaBatchPayerInit, type SolanaBatchStats, SolanaLLMClient, type SolanaLLMClientOptions, type SolanaWalletInfo, type SoundEffectOptions, type SpeechAudio, SpeechClient, type SpeechClientOptions, type SpeechGenerateOptions, type SpeechModel, type SpeechResponse, type SpeechVoice, type Spending, type SpendingReport, type StockMarket, SurfClient, type SurfClientOptions, type SymbolListResponse, type Tool, type ToolCall, type ToolChoice, USDC_ARC, USDC_BASE, USDC_BASE_CONTRACT, USDC_SOLANA, type UrlCitation, VideoClient, type VideoClientOptions, type VideoClip, type VideoGenerateOptions, type VideoModel, type VideoResponse, VoiceClient, type VoiceClientOptions, type VoiceInfo, type VoicePreset, WALLET_DIR_PATH, WALLET_FILE_PATH, type WalletInfo, type WebSearchSource, type WebSearchTool, type X402ClientLike, type X402HookContext, type XSearchSource, type XSearchTool, clearCache, createPaymentPayload, createSolanaPaymentPayload, createSolanaWallet, createWallet, LLMClient as default, evmNetwork, extractPaymentDetails, formatFundingMessageCompact, formatNeedsFundingMessage, formatSolanaWalletMigrationNotice, formatWalletCreatedMessage, formatWalletMigrationNotice, getCached, getCachedByRequest, getCostLogSummary, getCostSummary, getEip681Uri, getOrCreateSolanaWallet, getOrCreateWallet, getPaymentLinks, getWalletAddress, importSolanaWallet, importWallet, listDiscoveredSolanaWallets, listDiscoveredWallets, loadSolanaWallet, loadWallet, logCost, parsePaymentRequired, readSettlement, retryDisposition, saveSolanaWallet, saveToCache, saveWallet, scanSolanaWallets, scanWallets, setCache, setupAgentClient, setupAgentSolanaWallet, setupAgentWallet, solanaClient, solanaKeyToBytes, solanaPublicKey, status, toWireSearchParameters, toWireTools, validateMaxTokens, validateModel, validateTemperature, validateTopP };
|
package/dist/index.js
CHANGED
|
@@ -4989,7 +4989,7 @@ function getCostSummary() {
|
|
|
4989
4989
|
}
|
|
4990
4990
|
|
|
4991
4991
|
// src/version.ts
|
|
4992
|
-
var SDK_VERSION = "3.
|
|
4992
|
+
var SDK_VERSION = "3.25.0";
|
|
4993
4993
|
var USER_AGENT = `blockrun-ts/${SDK_VERSION}`;
|
|
4994
4994
|
|
|
4995
4995
|
// src/client.ts
|
|
@@ -10091,6 +10091,8 @@ var BATCH_SCHEME = "batch-settlement";
|
|
|
10091
10091
|
var BLOCKRUN_SOL_OPERATOR = "5YKPQUFjw5WQqhSUkEGKNNfYYVqnRRNbpYyL71qQ1vm3";
|
|
10092
10092
|
var DEFAULT_BATCH_RATE_LIMIT = { maxAttempts: 3, maxWaitMs: 6e4 };
|
|
10093
10093
|
var DEFAULT_BATCH_IN_DOUBT = { maxWaitMs: 3e5 };
|
|
10094
|
+
var DEFAULT_BATCH_LOCK_WAIT_MS = 6e4;
|
|
10095
|
+
var LOCK_POLL_MS = 500;
|
|
10094
10096
|
var BatchPaymentUnresolvedError = class extends PaymentError {
|
|
10095
10097
|
/** The {@link SolanaBatchEvent.reason} of the `unresolved` event reported with it. */
|
|
10096
10098
|
reason;
|
|
@@ -10136,6 +10138,22 @@ var BatchCloseDeferredError = class extends BlockrunError {
|
|
|
10136
10138
|
this.channelIds = init.channelIds ?? [];
|
|
10137
10139
|
}
|
|
10138
10140
|
};
|
|
10141
|
+
var BatchChannelLockedError = class extends BlockrunError {
|
|
10142
|
+
/** The paying wallet's address. */
|
|
10143
|
+
wallet;
|
|
10144
|
+
/** The live owner's pid, when the SDK knows it. */
|
|
10145
|
+
ownerPid;
|
|
10146
|
+
/** How long this call waited for the lock, in ms (0 unless `onLocked` is `"wait"`). */
|
|
10147
|
+
waitedMs;
|
|
10148
|
+
constructor(init) {
|
|
10149
|
+
super(`batch-settlement unavailable for wallet ${init.wallet}: ${init.detail}`);
|
|
10150
|
+
this.name = "BatchChannelLockedError";
|
|
10151
|
+
this.wallet = init.wallet;
|
|
10152
|
+
if (init.ownerPid !== void 0) this.ownerPid = init.ownerPid;
|
|
10153
|
+
this.waitedMs = init.waitedMs;
|
|
10154
|
+
withDisposition(this, "unpaid");
|
|
10155
|
+
}
|
|
10156
|
+
};
|
|
10139
10157
|
var INSTALL_HINT2 = "npm install @x402/core@~2.28.0 @x402/svm@~2.28.0 @solana/kit";
|
|
10140
10158
|
async function load(pkg, importer) {
|
|
10141
10159
|
try {
|
|
@@ -10771,6 +10789,38 @@ function withoutClientSignedBatch(paymentRequired) {
|
|
|
10771
10789
|
const accepts = paymentRequired.accepts ?? [];
|
|
10772
10790
|
return accepts.some(clientSignedBatch) ? { ...paymentRequired, accepts: accepts.filter((accept) => !clientSignedBatch(accept)) } : paymentRequired;
|
|
10773
10791
|
}
|
|
10792
|
+
var DEPOSIT_BLOCKHASH_TTL_MS = 1e4;
|
|
10793
|
+
var MAX_DEPOSIT_BLOCKHASH_ENDPOINTS = 8;
|
|
10794
|
+
var depositBlockhashes = /* @__PURE__ */ new Map();
|
|
10795
|
+
async function finalizedBlockhash(rpcUrl, rpcHeaders) {
|
|
10796
|
+
const cached = depositBlockhashes.get(rpcUrl);
|
|
10797
|
+
if (cached && Date.now() - cached.fetchedAt < DEPOSIT_BLOCKHASH_TTL_MS) return cached;
|
|
10798
|
+
const result = await rpcRequest(rpcUrl, "getLatestBlockhash", [{ commitment: "finalized" }], rpcHeaders);
|
|
10799
|
+
const blockhash = result.value?.blockhash;
|
|
10800
|
+
if (typeof blockhash !== "string" || !blockhash) throw new Error("getLatestBlockhash returned no blockhash");
|
|
10801
|
+
const entry = {
|
|
10802
|
+
blockhash,
|
|
10803
|
+
lastValidBlockHeight: rpcInteger(result.value?.lastValidBlockHeight, "getLatestBlockhash lastValidBlockHeight"),
|
|
10804
|
+
fetchedAt: Date.now()
|
|
10805
|
+
};
|
|
10806
|
+
depositBlockhashes.delete(rpcUrl);
|
|
10807
|
+
depositBlockhashes.set(rpcUrl, entry);
|
|
10808
|
+
while (depositBlockhashes.size > MAX_DEPOSIT_BLOCKHASH_ENDPOINTS) {
|
|
10809
|
+
depositBlockhashes.delete(depositBlockhashes.keys().next().value);
|
|
10810
|
+
}
|
|
10811
|
+
return entry;
|
|
10812
|
+
}
|
|
10813
|
+
function withDepositBlockhash(paymentRequired, blockhash) {
|
|
10814
|
+
const accepts = paymentRequired.accepts ?? [];
|
|
10815
|
+
const lacking = (accept) => accept.scheme === BATCH_SCHEME && !accept.extra?.recentBlockhash;
|
|
10816
|
+
if (!accepts.some(lacking)) return paymentRequired;
|
|
10817
|
+
return {
|
|
10818
|
+
...paymentRequired,
|
|
10819
|
+
accepts: accepts.map(
|
|
10820
|
+
(accept) => lacking(accept) ? { ...accept, extra: { ...accept.extra, recentBlockhash: blockhash.blockhash, lastValidBlockHeight: blockhash.lastValidBlockHeight } } : accept
|
|
10821
|
+
)
|
|
10822
|
+
};
|
|
10823
|
+
}
|
|
10774
10824
|
var PAYMENT_IDENTIFIER = "payment-identifier";
|
|
10775
10825
|
function withPaymentIdentifier(paymentRequired) {
|
|
10776
10826
|
const declared = paymentRequired.extensions?.[PAYMENT_IDENTIFIER];
|
|
@@ -11168,12 +11218,22 @@ var SolanaBatchPayer = class {
|
|
|
11168
11218
|
if (!Number.isFinite(this.inDoubtMaxWaitMs) || this.inDoubtMaxWaitMs < 0) {
|
|
11169
11219
|
throw new Error("batch.inDoubt.maxWaitMs must be a finite number of ms >= 0");
|
|
11170
11220
|
}
|
|
11221
|
+
this.onLocked = init.options.onLocked ?? "exact";
|
|
11222
|
+
if (this.onLocked !== "exact" && this.onLocked !== "wait" && this.onLocked !== "throw") {
|
|
11223
|
+
throw new Error('batch.onLocked must be "exact", "wait" or "throw"');
|
|
11224
|
+
}
|
|
11225
|
+
this.lockWaitMs = init.options.lockWaitMs ?? DEFAULT_BATCH_LOCK_WAIT_MS;
|
|
11226
|
+
if (!Number.isFinite(this.lockWaitMs) || this.lockWaitMs < 0) {
|
|
11227
|
+
throw new Error("batch.lockWaitMs must be a finite number of ms >= 0");
|
|
11228
|
+
}
|
|
11171
11229
|
}
|
|
11172
11230
|
init;
|
|
11173
11231
|
state;
|
|
11174
11232
|
maxAttempts;
|
|
11175
11233
|
maxWaitMs;
|
|
11176
11234
|
inDoubtMaxWaitMs;
|
|
11235
|
+
onLocked;
|
|
11236
|
+
lockWaitMs;
|
|
11177
11237
|
counters = {
|
|
11178
11238
|
fallbacks: 0,
|
|
11179
11239
|
fallbacksByReason: {},
|
|
@@ -11222,6 +11282,7 @@ var SolanaBatchPayer = class {
|
|
|
11222
11282
|
if (owner !== void 0) {
|
|
11223
11283
|
return {
|
|
11224
11284
|
reason: "channel_store_locked",
|
|
11285
|
+
ownerPid: owner,
|
|
11225
11286
|
detail: owner === process.pid ? `channel store ${file} is in use by another copy of @blockrun/llm in this process (or by a process that had this pid and died: remove ${file}.lock if nothing uses it)` : `channel store ${file} is in use by process ${owner}`
|
|
11226
11287
|
};
|
|
11227
11288
|
}
|
|
@@ -11567,12 +11628,23 @@ var SolanaBatchPayer = class {
|
|
|
11567
11628
|
const unavailable = batchUnavailable(paymentRequired);
|
|
11568
11629
|
if (unavailable) return this.fallback(unavailable);
|
|
11569
11630
|
let wallet;
|
|
11631
|
+
let waitedMs = 0;
|
|
11570
11632
|
try {
|
|
11571
11633
|
wallet = await this.wallet();
|
|
11634
|
+
if ("reason" in wallet && wallet.reason === "channel_store_locked" && this.onLocked === "wait") {
|
|
11635
|
+
const started = Date.now();
|
|
11636
|
+
wallet = await this.waitForLock(wallet);
|
|
11637
|
+
waitedMs = Date.now() - started;
|
|
11638
|
+
}
|
|
11572
11639
|
} catch (err) {
|
|
11573
11640
|
return this.fallback(creationFailure(err));
|
|
11574
11641
|
}
|
|
11575
|
-
if ("reason" in wallet)
|
|
11642
|
+
if ("reason" in wallet) {
|
|
11643
|
+
if (wallet.reason === "channel_store_locked" && this.onLocked !== "exact") {
|
|
11644
|
+
return this.lockedOut(wallet.detail, wallet.ownerPid, waitedMs);
|
|
11645
|
+
}
|
|
11646
|
+
return this.fallback({ reason: wallet.reason, detail: wallet.detail });
|
|
11647
|
+
}
|
|
11576
11648
|
if (closesAtStart !== void 0 && wallet.closes !== closesAtStart) {
|
|
11577
11649
|
return this.fallback({
|
|
11578
11650
|
reason: "closed_during_call",
|
|
@@ -11589,6 +11661,40 @@ var SolanaBatchPayer = class {
|
|
|
11589
11661
|
wallet.active -= 1;
|
|
11590
11662
|
}
|
|
11591
11663
|
}
|
|
11664
|
+
/**
|
|
11665
|
+
* `onLocked: "wait"`: try the wallet's channel store again every
|
|
11666
|
+
* {@link LOCK_POLL_MS} until its owner lets go of it or `lockWaitMs` runs
|
|
11667
|
+
* out. Reported once as a `backoff` event (`channel_store_locked`).
|
|
11668
|
+
*/
|
|
11669
|
+
async waitForLock(refusal) {
|
|
11670
|
+
const deadline = Date.now() + this.lockWaitMs;
|
|
11671
|
+
let current = refusal;
|
|
11672
|
+
if (this.lockWaitMs > 0) {
|
|
11673
|
+
await this.report({
|
|
11674
|
+
type: "backoff",
|
|
11675
|
+
reason: "channel_store_locked",
|
|
11676
|
+
retryAfterMs: this.lockWaitMs,
|
|
11677
|
+
detail: refusal.detail
|
|
11678
|
+
});
|
|
11679
|
+
}
|
|
11680
|
+
while ("reason" in current && current.reason === "channel_store_locked") {
|
|
11681
|
+
const left = deadline - Date.now();
|
|
11682
|
+
if (left <= 0) break;
|
|
11683
|
+
await sleep2(Math.min(LOCK_POLL_MS, left));
|
|
11684
|
+
current = await this.wallet();
|
|
11685
|
+
}
|
|
11686
|
+
return current;
|
|
11687
|
+
}
|
|
11688
|
+
/** `onLocked` other than `"exact"`: the call's `"unpaid"` error, nothing signed. */
|
|
11689
|
+
async lockedOut(detail, ownerPid, waitedMs) {
|
|
11690
|
+
const error = new BatchChannelLockedError({
|
|
11691
|
+
wallet: await this.init.address(),
|
|
11692
|
+
detail,
|
|
11693
|
+
waitedMs,
|
|
11694
|
+
...ownerPid !== void 0 ? { ownerPid } : {}
|
|
11695
|
+
});
|
|
11696
|
+
return { kind: "failed", error };
|
|
11697
|
+
}
|
|
11592
11698
|
/**
|
|
11593
11699
|
* The close fence for a call about to send its first request: how many
|
|
11594
11700
|
* closes this wallet has completed so far, to hand to {@link pay}.
|
|
@@ -11679,11 +11785,9 @@ var SolanaBatchPayer = class {
|
|
|
11679
11785
|
}
|
|
11680
11786
|
if (wallet.busy) return fallback({ reason: "channel_busy", attempt: budget.attempt });
|
|
11681
11787
|
if (wallet.file && !holdsChannelFile(wallet.file)) {
|
|
11682
|
-
|
|
11683
|
-
|
|
11684
|
-
|
|
11685
|
-
detail: `this process no longer holds the lock on ${wallet.file}; another owner may be paying into its channels`
|
|
11686
|
-
});
|
|
11788
|
+
const detail = `this process no longer holds the lock on ${wallet.file}; another owner may be paying into its channels`;
|
|
11789
|
+
if (this.onLocked !== "exact") return this.lockedOut(detail, void 0, 0);
|
|
11790
|
+
return fallback({ reason: "channel_store_locked", attempt: budget.attempt, detail });
|
|
11687
11791
|
}
|
|
11688
11792
|
wallet.busy = true;
|
|
11689
11793
|
holding = true;
|
|
@@ -12260,7 +12364,8 @@ var SolanaBatchPayer = class {
|
|
|
12260
12364
|
const http = (await this.build(wallet)).http;
|
|
12261
12365
|
try {
|
|
12262
12366
|
await this.prepareTopUp(wallet, paymentRequired);
|
|
12263
|
-
|
|
12367
|
+
const required = await this.withDepositBlockhash(wallet, withoutClientSignedBatch(paymentRequired));
|
|
12368
|
+
return { http, payload: await http.createPaymentPayload(withPaymentIdentifier(required)) };
|
|
12264
12369
|
} catch (err) {
|
|
12265
12370
|
if (pass > 0 || !isResyncRequired(err) || wallet.resyncs.size === 0) throw err;
|
|
12266
12371
|
} finally {
|
|
@@ -12268,6 +12373,34 @@ var SolanaBatchPayer = class {
|
|
|
12268
12373
|
}
|
|
12269
12374
|
}
|
|
12270
12375
|
}
|
|
12376
|
+
/**
|
|
12377
|
+
* The 402 to build this payment from: with a finalized blockhash
|
|
12378
|
+
* ({@link withDepositBlockhash}) when the payment will likely carry a
|
|
12379
|
+
* deposit (no usable record for the trusted accept's channel, so an open,
|
|
12380
|
+
* or a top-up {@link prepareTopUp} just sized). An authorization signs no
|
|
12381
|
+
* transaction and costs no RPC read. Best effort: a failed read leaves the
|
|
12382
|
+
* 402 as it is, and `@x402/svm` fetches its own blockhash.
|
|
12383
|
+
*/
|
|
12384
|
+
async withDepositBlockhash(wallet, paymentRequired) {
|
|
12385
|
+
const accept = trustedBatchAccept(paymentRequired, this.init.options.operators);
|
|
12386
|
+
const key = accept ? channelKeyOf(accept) : void 0;
|
|
12387
|
+
if (!accept || accept.extra?.recentBlockhash) return paymentRequired;
|
|
12388
|
+
let deposit = wallet.topUp !== void 0;
|
|
12389
|
+
if (!deposit) {
|
|
12390
|
+
try {
|
|
12391
|
+
const record = key ? await wallet.book.base.get(key) : void 0;
|
|
12392
|
+
deposit = !record || typeof record.channelId !== "string" || record.pending !== void 0;
|
|
12393
|
+
} catch {
|
|
12394
|
+
deposit = true;
|
|
12395
|
+
}
|
|
12396
|
+
}
|
|
12397
|
+
if (!deposit) return paymentRequired;
|
|
12398
|
+
try {
|
|
12399
|
+
return withDepositBlockhash(paymentRequired, await finalizedBlockhash(this.init.rpcUrl, this.init.rpcHeaders));
|
|
12400
|
+
} catch {
|
|
12401
|
+
return paymentRequired;
|
|
12402
|
+
}
|
|
12403
|
+
}
|
|
12271
12404
|
/**
|
|
12272
12405
|
* Queue a re-read of a stored channel whose account is gone at finalized
|
|
12273
12406
|
* and at confirmed commitment (closed, its account reclaimed), anchored at
|
|
@@ -12574,7 +12707,6 @@ var SolanaBatchPayer = class {
|
|
|
12574
12707
|
// src/solana-client.ts
|
|
12575
12708
|
var SOLANA_API_URL = "https://sol.blockrun.ai/api";
|
|
12576
12709
|
var DEFAULT_MAX_TOKENS2 = 1024;
|
|
12577
|
-
var DEFAULT_TIMEOUT14 = 6e4;
|
|
12578
12710
|
var STALE_BLOCKHASH_RETRY_BACKOFFS_MS = [500, 2e3];
|
|
12579
12711
|
var MAX_PAYMENT_FAILURE_BYTES = 64 * 1024;
|
|
12580
12712
|
var DEFAULT_VIDEO_MODEL = "xai/grok-imagine-video";
|
|
@@ -12742,7 +12874,7 @@ var SolanaLLMClient = class {
|
|
|
12742
12874
|
const rpc = resolveRpcConfig(options.rpcUrl, options.rpcHeaders);
|
|
12743
12875
|
this.rpcUrl = rpc.url;
|
|
12744
12876
|
this.rpcHeaders = rpc.headers;
|
|
12745
|
-
this.timeout = options.timeout ||
|
|
12877
|
+
this.timeout = options.timeout || DEFAULT_TIMEOUT;
|
|
12746
12878
|
if (options.batch && !this.apiAuth) {
|
|
12747
12879
|
this.batchPayer = new SolanaBatchPayer({
|
|
12748
12880
|
options: options.batch,
|
|
@@ -14509,11 +14641,13 @@ export {
|
|
|
14509
14641
|
AnthropicClient,
|
|
14510
14642
|
BASE_CHAIN_ID,
|
|
14511
14643
|
BLOCKRUN_SOL_OPERATOR,
|
|
14644
|
+
BatchChannelLockedError,
|
|
14512
14645
|
BatchCloseDeferredError,
|
|
14513
14646
|
BatchPaymentUnresolvedError,
|
|
14514
14647
|
BlockrunClient,
|
|
14515
14648
|
BlockrunError,
|
|
14516
14649
|
DEFAULT_BATCH_IN_DOUBT,
|
|
14650
|
+
DEFAULT_BATCH_LOCK_WAIT_MS,
|
|
14517
14651
|
DEFAULT_BATCH_RATE_LIMIT,
|
|
14518
14652
|
EVM_NETWORKS,
|
|
14519
14653
|
ImageClient,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@blockrun/llm",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.25.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "TypeScript SDK for BlockRun - every frontier model behind one OpenAI-compatible client. Pay with a BlockRun API key or per-call in USDC. Smart routing picks the cheapest capable model. No rate limits.",
|
|
6
6
|
"main": "dist/index.cjs",
|