@blockrun/llm 3.23.0 → 3.23.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -4833,7 +4833,7 @@ function getCostSummary() {
4833
4833
  }
4834
4834
 
4835
4835
  // src/version.ts
4836
- var SDK_VERSION = "3.23.0";
4836
+ var SDK_VERSION = "3.23.1";
4837
4837
  var USER_AGENT = `blockrun-ts/${SDK_VERSION}`;
4838
4838
 
4839
4839
  // src/client.ts
@@ -10861,6 +10861,38 @@ function capOutstandingEscrow(scheme, wallet) {
10861
10861
  return original.call(this, requirements, requestAmount, needed, context, widened, existingDeposit);
10862
10862
  };
10863
10863
  }
10864
+ var payScope = new import_async_hooks.AsyncLocalStorage();
10865
+ function registerHookDispatchers(client) {
10866
+ client.onBeforePaymentCreation(async (context) => {
10867
+ for (const hook of payScope.getStore()?.hooks.before ?? []) {
10868
+ const result = await hook(context);
10869
+ if (result && typeof result === "object" && result.abort) return result;
10870
+ }
10871
+ return void 0;
10872
+ });
10873
+ client.onAfterPaymentCreation(async (context) => {
10874
+ const scope = payScope.getStore();
10875
+ for (const hook of scope?.hooks.after ?? []) {
10876
+ try {
10877
+ await hook(context);
10878
+ } catch (error) {
10879
+ if (scope && !scope.afterError) scope.afterError = { error };
10880
+ }
10881
+ }
10882
+ });
10883
+ client.onPaymentCreationFailure(async (context) => {
10884
+ await runFailureHooks(payScope.getStore(), context);
10885
+ return void 0;
10886
+ });
10887
+ }
10888
+ async function runFailureHooks(scope, context) {
10889
+ for (const hook of scope?.hooks.failure ?? []) {
10890
+ try {
10891
+ await hook(context);
10892
+ } catch {
10893
+ }
10894
+ }
10895
+ }
10864
10896
  var RPC_SCOPE_STORE = /* @__PURE__ */ Symbol.for("@blockrun/llm/batch-rpc-scope/v1");
10865
10897
  var RPC_HEADER_HOOK = /* @__PURE__ */ Symbol.for("@blockrun/llm/batch-rpc-headers/v1");
10866
10898
  var sharedGlobal = globalThis;
@@ -10912,6 +10944,11 @@ function intentTarget(intent) {
10912
10944
  var SolanaBatchPayer = class {
10913
10945
  constructor(init) {
10914
10946
  this.init = init;
10947
+ init.configureClient?.({
10948
+ onBeforePaymentCreation: (hook) => void this.hooks.before.push(hook),
10949
+ onAfterPaymentCreation: (hook) => void this.hooks.after.push(hook),
10950
+ onPaymentCreationFailure: (hook) => void this.hooks.failure.push(hook)
10951
+ });
10915
10952
  const { operators, rateLimit, inDoubt } = init.options;
10916
10953
  if (!Array.isArray(operators) || operators.length === 0 || operators.some((o) => typeof o !== "string" || !o)) {
10917
10954
  throw new Error("batch.operators must list at least one base58 operator public key");
@@ -10944,6 +10981,7 @@ var SolanaBatchPayer = class {
10944
10981
  unresolved: 0,
10945
10982
  unresolvedByReason: {}
10946
10983
  };
10984
+ hooks = { before: [], after: [], failure: [] };
10947
10985
  /** A copy of this client's batch counters. */
10948
10986
  stats() {
10949
10987
  return {
@@ -11046,7 +11084,7 @@ var SolanaBatchPayer = class {
11046
11084
  capOutstandingEscrow(scheme, wallet);
11047
11085
  const client = new core.x402Client().register("solana:*", scheme).registerPolicy(scheme.paymentPolicy);
11048
11086
  client.setSpendControls({ maxAmountPerPayment: false });
11049
- this.init.configureClient?.(client);
11087
+ registerHookDispatchers(client);
11050
11088
  const raw = new core.x402HTTPClient(client);
11051
11089
  const http = {
11052
11090
  getPaymentSettleResponse: (getHeader) => raw.getPaymentSettleResponse(getHeader),
@@ -11340,7 +11378,10 @@ var SolanaBatchPayer = class {
11340
11378
  }
11341
11379
  wallet.active += 1;
11342
11380
  try {
11343
- return await this.payWith(wallet, paymentRequired, send, rechallenge, closesAtStart ?? wallet.closes);
11381
+ return await payScope.run(
11382
+ { hooks: this.hooks },
11383
+ () => this.payWith(wallet, paymentRequired, send, rechallenge, closesAtStart ?? wallet.closes)
11384
+ );
11344
11385
  } finally {
11345
11386
  wallet.active -= 1;
11346
11387
  }
@@ -11752,6 +11793,18 @@ var SolanaBatchPayer = class {
11752
11793
  /** Build a new batch payment for a 402: the payload, its headers and its kind. */
11753
11794
  async buildPayment(wallet, paymentRequired) {
11754
11795
  const { http, payload } = await this.createPayload(wallet, paymentRequired);
11796
+ const scope = payScope.getStore();
11797
+ if (scope?.afterError) {
11798
+ const { error } = scope.afterError;
11799
+ scope.afterError = void 0;
11800
+ await this.settle(http, payload, () => null, 0);
11801
+ await runFailureHooks(scope, {
11802
+ paymentRequired,
11803
+ selectedRequirements: payload.accepted,
11804
+ error
11805
+ });
11806
+ throw error;
11807
+ }
11755
11808
  const headers = http.encodePaymentSignatureHeader(payload);
11756
11809
  const channelId = payloadChannelId(payload);
11757
11810
  const known = channelId ? wallet.book.find(channelId) : void 0;
package/dist/index.d.cts CHANGED
@@ -3194,14 +3194,20 @@ interface SolanaBatchPayerInit {
3194
3194
  /** Headers the exact path sends to `rpcUrl` (`rpcHeaders`, `SOLANA_RPC_HEADERS`, `SOLANA_RPC_API_KEY`). */
3195
3195
  rpcHeaders?: Record<string, string>;
3196
3196
  /**
3197
- * Called once with the batch scheme's `x402Client`, after the scheme and its
3198
- * policy are registered and before anything is signed. An embedder that
3199
- * enforces its own spend rules registers its payment-creation hooks here, so
3200
- * they see every batch payment this payer signs (each one's
3201
- * `selectedRequirements.amount` is the per-call ceiling, not the channel
3202
- * deposit) exactly as they see the embedder's own `exact` payments. A
3203
- * before-hook that throws refuses the payment: nothing is signed or sent,
3204
- * and `pay()` reports a fallback.
3197
+ * Called once, when the payer is constructed, with a registrar for x402
3198
+ * payment-creation hooks. An embedder that enforces its own spend rules
3199
+ * registers its hooks here, so they see every batch payment THIS payer signs
3200
+ * (each one's `selectedRequirements.amount` is the per-call ceiling, not the
3201
+ * channel deposit) exactly as they see the embedder's own `exact` payments.
3202
+ *
3203
+ * The hooks are this payer's own: payers that share a wallet (and so its
3204
+ * channel and scheme client) never run each other's hooks. A before-hook
3205
+ * that throws refuses the payment: nothing is signed or sent, and `pay()`
3206
+ * reports a fallback. An after-hook that throws does the same: the payment
3207
+ * was signed but is rolled back unsent, so the channel is not left pending,
3208
+ * and the failure hooks are told. Failure hooks are notifications only: a
3209
+ * payload one returns as `recovered` is ignored, since a batch payment is
3210
+ * never replaced by a payment built outside the batch scheme.
3205
3211
  */
3206
3212
  configureClient?: (client: X402ClientLike) => void;
3207
3213
  }
@@ -3242,6 +3248,7 @@ declare class SolanaBatchPayer {
3242
3248
  private readonly maxWaitMs;
3243
3249
  private readonly inDoubtMaxWaitMs;
3244
3250
  private readonly counters;
3251
+ private readonly hooks;
3245
3252
  constructor(init: SolanaBatchPayerInit);
3246
3253
  /** A copy of this client's batch counters. */
3247
3254
  stats(): SolanaBatchStats;
package/dist/index.d.ts CHANGED
@@ -3194,14 +3194,20 @@ interface SolanaBatchPayerInit {
3194
3194
  /** Headers the exact path sends to `rpcUrl` (`rpcHeaders`, `SOLANA_RPC_HEADERS`, `SOLANA_RPC_API_KEY`). */
3195
3195
  rpcHeaders?: Record<string, string>;
3196
3196
  /**
3197
- * Called once with the batch scheme's `x402Client`, after the scheme and its
3198
- * policy are registered and before anything is signed. An embedder that
3199
- * enforces its own spend rules registers its payment-creation hooks here, so
3200
- * they see every batch payment this payer signs (each one's
3201
- * `selectedRequirements.amount` is the per-call ceiling, not the channel
3202
- * deposit) exactly as they see the embedder's own `exact` payments. A
3203
- * before-hook that throws refuses the payment: nothing is signed or sent,
3204
- * and `pay()` reports a fallback.
3197
+ * Called once, when the payer is constructed, with a registrar for x402
3198
+ * payment-creation hooks. An embedder that enforces its own spend rules
3199
+ * registers its hooks here, so they see every batch payment THIS payer signs
3200
+ * (each one's `selectedRequirements.amount` is the per-call ceiling, not the
3201
+ * channel deposit) exactly as they see the embedder's own `exact` payments.
3202
+ *
3203
+ * The hooks are this payer's own: payers that share a wallet (and so its
3204
+ * channel and scheme client) never run each other's hooks. A before-hook
3205
+ * that throws refuses the payment: nothing is signed or sent, and `pay()`
3206
+ * reports a fallback. An after-hook that throws does the same: the payment
3207
+ * was signed but is rolled back unsent, so the channel is not left pending,
3208
+ * and the failure hooks are told. Failure hooks are notifications only: a
3209
+ * payload one returns as `recovered` is ignored, since a batch payment is
3210
+ * never replaced by a payment built outside the batch scheme.
3205
3211
  */
3206
3212
  configureClient?: (client: X402ClientLike) => void;
3207
3213
  }
@@ -3242,6 +3248,7 @@ declare class SolanaBatchPayer {
3242
3248
  private readonly maxWaitMs;
3243
3249
  private readonly inDoubtMaxWaitMs;
3244
3250
  private readonly counters;
3251
+ private readonly hooks;
3245
3252
  constructor(init: SolanaBatchPayerInit);
3246
3253
  /** A copy of this client's batch counters. */
3247
3254
  stats(): SolanaBatchStats;
package/dist/index.js CHANGED
@@ -4702,7 +4702,7 @@ function getCostSummary() {
4702
4702
  }
4703
4703
 
4704
4704
  // src/version.ts
4705
- var SDK_VERSION = "3.23.0";
4705
+ var SDK_VERSION = "3.23.1";
4706
4706
  var USER_AGENT = `blockrun-ts/${SDK_VERSION}`;
4707
4707
 
4708
4708
  // src/client.ts
@@ -10730,6 +10730,38 @@ function capOutstandingEscrow(scheme, wallet) {
10730
10730
  return original.call(this, requirements, requestAmount, needed, context, widened, existingDeposit);
10731
10731
  };
10732
10732
  }
10733
+ var payScope = new AsyncLocalStorage();
10734
+ function registerHookDispatchers(client) {
10735
+ client.onBeforePaymentCreation(async (context) => {
10736
+ for (const hook of payScope.getStore()?.hooks.before ?? []) {
10737
+ const result = await hook(context);
10738
+ if (result && typeof result === "object" && result.abort) return result;
10739
+ }
10740
+ return void 0;
10741
+ });
10742
+ client.onAfterPaymentCreation(async (context) => {
10743
+ const scope = payScope.getStore();
10744
+ for (const hook of scope?.hooks.after ?? []) {
10745
+ try {
10746
+ await hook(context);
10747
+ } catch (error) {
10748
+ if (scope && !scope.afterError) scope.afterError = { error };
10749
+ }
10750
+ }
10751
+ });
10752
+ client.onPaymentCreationFailure(async (context) => {
10753
+ await runFailureHooks(payScope.getStore(), context);
10754
+ return void 0;
10755
+ });
10756
+ }
10757
+ async function runFailureHooks(scope, context) {
10758
+ for (const hook of scope?.hooks.failure ?? []) {
10759
+ try {
10760
+ await hook(context);
10761
+ } catch {
10762
+ }
10763
+ }
10764
+ }
10733
10765
  var RPC_SCOPE_STORE = /* @__PURE__ */ Symbol.for("@blockrun/llm/batch-rpc-scope/v1");
10734
10766
  var RPC_HEADER_HOOK = /* @__PURE__ */ Symbol.for("@blockrun/llm/batch-rpc-headers/v1");
10735
10767
  var sharedGlobal = globalThis;
@@ -10781,6 +10813,11 @@ function intentTarget(intent) {
10781
10813
  var SolanaBatchPayer = class {
10782
10814
  constructor(init) {
10783
10815
  this.init = init;
10816
+ init.configureClient?.({
10817
+ onBeforePaymentCreation: (hook) => void this.hooks.before.push(hook),
10818
+ onAfterPaymentCreation: (hook) => void this.hooks.after.push(hook),
10819
+ onPaymentCreationFailure: (hook) => void this.hooks.failure.push(hook)
10820
+ });
10784
10821
  const { operators, rateLimit, inDoubt } = init.options;
10785
10822
  if (!Array.isArray(operators) || operators.length === 0 || operators.some((o) => typeof o !== "string" || !o)) {
10786
10823
  throw new Error("batch.operators must list at least one base58 operator public key");
@@ -10813,6 +10850,7 @@ var SolanaBatchPayer = class {
10813
10850
  unresolved: 0,
10814
10851
  unresolvedByReason: {}
10815
10852
  };
10853
+ hooks = { before: [], after: [], failure: [] };
10816
10854
  /** A copy of this client's batch counters. */
10817
10855
  stats() {
10818
10856
  return {
@@ -10915,7 +10953,7 @@ var SolanaBatchPayer = class {
10915
10953
  capOutstandingEscrow(scheme, wallet);
10916
10954
  const client = new core.x402Client().register("solana:*", scheme).registerPolicy(scheme.paymentPolicy);
10917
10955
  client.setSpendControls({ maxAmountPerPayment: false });
10918
- this.init.configureClient?.(client);
10956
+ registerHookDispatchers(client);
10919
10957
  const raw = new core.x402HTTPClient(client);
10920
10958
  const http = {
10921
10959
  getPaymentSettleResponse: (getHeader) => raw.getPaymentSettleResponse(getHeader),
@@ -11209,7 +11247,10 @@ var SolanaBatchPayer = class {
11209
11247
  }
11210
11248
  wallet.active += 1;
11211
11249
  try {
11212
- return await this.payWith(wallet, paymentRequired, send, rechallenge, closesAtStart ?? wallet.closes);
11250
+ return await payScope.run(
11251
+ { hooks: this.hooks },
11252
+ () => this.payWith(wallet, paymentRequired, send, rechallenge, closesAtStart ?? wallet.closes)
11253
+ );
11213
11254
  } finally {
11214
11255
  wallet.active -= 1;
11215
11256
  }
@@ -11621,6 +11662,18 @@ var SolanaBatchPayer = class {
11621
11662
  /** Build a new batch payment for a 402: the payload, its headers and its kind. */
11622
11663
  async buildPayment(wallet, paymentRequired) {
11623
11664
  const { http, payload } = await this.createPayload(wallet, paymentRequired);
11665
+ const scope = payScope.getStore();
11666
+ if (scope?.afterError) {
11667
+ const { error } = scope.afterError;
11668
+ scope.afterError = void 0;
11669
+ await this.settle(http, payload, () => null, 0);
11670
+ await runFailureHooks(scope, {
11671
+ paymentRequired,
11672
+ selectedRequirements: payload.accepted,
11673
+ error
11674
+ });
11675
+ throw error;
11676
+ }
11624
11677
  const headers = http.encodePaymentSignatureHeader(payload);
11625
11678
  const channelId = payloadChannelId(payload);
11626
11679
  const known = channelId ? wallet.book.find(channelId) : void 0;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blockrun/llm",
3
- "version": "3.23.0",
3
+ "version": "3.23.1",
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",