@haven_ai/sdk 0.8.1-alpha.0 → 0.10.0-alpha.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.
Files changed (40) hide show
  1. package/README.md +1 -1
  2. package/dist/base64-CiR5BJhk.d.cts +1352 -0
  3. package/dist/base64-CxkinHPQ.d.ts +1352 -0
  4. package/dist/{chunk-HFOAYTD4.cjs → chunk-22FJ4JQO.cjs} +47 -35
  5. package/dist/chunk-22FJ4JQO.cjs.map +1 -0
  6. package/dist/chunk-6LEXYQ7J.cjs +106 -0
  7. package/dist/chunk-6LEXYQ7J.cjs.map +1 -0
  8. package/dist/chunk-EWTHDEIW.js +103 -0
  9. package/dist/chunk-EWTHDEIW.js.map +1 -0
  10. package/dist/{chunk-HX34HOW4.cjs → chunk-H37YVYZA.cjs} +6 -4
  11. package/dist/chunk-H37YVYZA.cjs.map +1 -0
  12. package/dist/{chunk-WDA3IGJP.js → chunk-MLUWABVT.js} +15 -6
  13. package/dist/chunk-MLUWABVT.js.map +1 -0
  14. package/dist/{chunk-H4APV67M.js → chunk-TD2PHUYP.js} +6 -4
  15. package/dist/chunk-TD2PHUYP.js.map +1 -0
  16. package/dist/edge.cjs +105 -89
  17. package/dist/edge.d.cts +4 -2
  18. package/dist/edge.d.ts +4 -2
  19. package/dist/edge.js +4 -4
  20. package/dist/index.cjs +1138 -500
  21. package/dist/index.cjs.map +1 -1
  22. package/dist/index.d.cts +128 -144
  23. package/dist/index.d.ts +128 -144
  24. package/dist/index.js +801 -199
  25. package/dist/index.js.map +1 -1
  26. package/dist/receipt-Cg9a5Seq.d.ts +130 -0
  27. package/dist/receipt-q7ez8Zb2.d.cts +130 -0
  28. package/dist/test-support.cjs +71 -18
  29. package/dist/test-support.cjs.map +1 -1
  30. package/dist/test-support.d.cts +21 -1
  31. package/dist/test-support.d.ts +21 -1
  32. package/dist/test-support.js +53 -3
  33. package/dist/test-support.js.map +1 -1
  34. package/dist/{base64-BjxHPgtC.d.cts → types-BKgqzvnk.d.cts} +238 -1307
  35. package/dist/{base64-BjxHPgtC.d.ts → types-BKgqzvnk.d.ts} +238 -1307
  36. package/package.json +1 -1
  37. package/dist/chunk-H4APV67M.js.map +0 -1
  38. package/dist/chunk-HFOAYTD4.cjs.map +0 -1
  39. package/dist/chunk-HX34HOW4.cjs.map +0 -1
  40. package/dist/chunk-WDA3IGJP.js.map +0 -1
package/dist/index.cjs CHANGED
@@ -1,7 +1,8 @@
1
1
  'use strict';
2
2
 
3
- var chunkHFOAYTD4_cjs = require('./chunk-HFOAYTD4.cjs');
4
- var chunkHX34HOW4_cjs = require('./chunk-HX34HOW4.cjs');
3
+ var chunk22FJ4JQO_cjs = require('./chunk-22FJ4JQO.cjs');
4
+ var chunk6LEXYQ7J_cjs = require('./chunk-6LEXYQ7J.cjs');
5
+ var chunkH37YVYZA_cjs = require('./chunk-H37YVYZA.cjs');
5
6
  var viem = require('viem');
6
7
  var ethers = require('ethers');
7
8
  var async_hooks = require('async_hooks');
@@ -14,7 +15,7 @@ function signHash(privateKey, hash) {
14
15
  const sig = signingKey.sign(hash);
15
16
  return sig.serialized;
16
17
  } catch (err) {
17
- throw new chunkHX34HOW4_cjs.HavenSigningError(
18
+ throw new chunkH37YVYZA_cjs.HavenSigningError(
18
19
  `Failed to sign hash: ${err instanceof Error ? err.message : String(err)}`
19
20
  );
20
21
  }
@@ -30,7 +31,7 @@ async function signTypedDataVerbatim(privateKey, typedData, label) {
30
31
  typedData.message
31
32
  );
32
33
  } catch (err) {
33
- throw new chunkHX34HOW4_cjs.HavenSigningError(
34
+ throw new chunkH37YVYZA_cjs.HavenSigningError(
34
35
  `Failed to sign ${label}: ${err instanceof Error ? err.message : String(err)}`
35
36
  );
36
37
  }
@@ -45,7 +46,7 @@ function addressFromKey(privateKey) {
45
46
  try {
46
47
  return new ethers.ethers.Wallet(privateKey).address;
47
48
  } catch (err) {
48
- throw new chunkHX34HOW4_cjs.HavenSigningError(
49
+ throw new chunkH37YVYZA_cjs.HavenSigningError(
49
50
  `Invalid private key: ${err instanceof Error ? err.message : String(err)}`
50
51
  );
51
52
  }
@@ -61,7 +62,7 @@ function verifySignature(hash, signature, expectedAddress) {
61
62
  var DEFAULT_BASE_URL = "http://localhost:3001";
62
63
  var DEFAULT_REQUEST_TIMEOUT = 3e4;
63
64
  function withoutClientHeader(headers) {
64
- const target = chunkHFOAYTD4_cjs.HAVEN_CLIENT_HEADER.toLowerCase();
65
+ const target = chunk22FJ4JQO_cjs.HAVEN_CLIENT_HEADER.toLowerCase();
65
66
  return Object.fromEntries(Object.entries(headers).filter(([name]) => name.toLowerCase() !== target));
66
67
  }
67
68
  var HavenApiTransport = class {
@@ -77,7 +78,7 @@ var HavenApiTransport = class {
77
78
  this.baseUrl = (config.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, "");
78
79
  this.requestTimeout = config.requestTimeout ?? DEFAULT_REQUEST_TIMEOUT;
79
80
  this.defaultHeaders = { ...config.defaultHeaders ?? {} };
80
- this.clientIdentity = config.clientIdentity ?? chunkHFOAYTD4_cjs.SDK_CLIENT_IDENTITY;
81
+ this.clientIdentity = config.clientIdentity ?? chunk22FJ4JQO_cjs.SDK_CLIENT_IDENTITY;
81
82
  }
82
83
  /**
83
84
  * The newest `client_update` the backend sent (#3303): inside a
@@ -90,7 +91,7 @@ var HavenApiTransport = class {
90
91
  }
91
92
  recordClientUpdate(data) {
92
93
  if (data === null || typeof data !== "object" || Array.isArray(data)) return;
93
- const hint = chunkHFOAYTD4_cjs.readClientUpdate(data.client_update);
94
+ const hint = chunk22FJ4JQO_cjs.readClientUpdate(data.client_update);
94
95
  if (!hint) return;
95
96
  this.lastClientUpdate = hint;
96
97
  const store = this.requestContext.getStore();
@@ -123,7 +124,7 @@ var HavenApiTransport = class {
123
124
  // JOIN `x-haven-client` and `X-Haven-Client` into one unparseable
124
125
  // value), so neither `defaultHeaders` nor a dispatch context can
125
126
  // misname the client; `clientIdentity` is the one way to set it.
126
- [chunkHFOAYTD4_cjs.HAVEN_CLIENT_HEADER]: this.clientIdentity
127
+ [chunk22FJ4JQO_cjs.HAVEN_CLIENT_HEADER]: this.clientIdentity
127
128
  },
128
129
  body: body ? JSON.stringify(body) : void 0,
129
130
  signal: controller.signal
@@ -136,15 +137,15 @@ var HavenApiTransport = class {
136
137
  const rawDetails = record.details ?? record.detail;
137
138
  const detailsText = typeof rawDetails === "string" ? rawDetails : rawDetails != null ? JSON.stringify(rawDetails) : void 0;
138
139
  const message = errorText && detailsText ? `${errorText}: ${detailsText}` : errorText ?? detailsText ?? "API request failed";
139
- throw new chunkHX34HOW4_cjs.HavenApiError(message, res.status, data);
140
+ throw new chunkH37YVYZA_cjs.HavenApiError(message, res.status, data);
140
141
  }
141
142
  return data;
142
143
  } catch (err) {
143
- if (err instanceof chunkHX34HOW4_cjs.HavenApiError) throw err;
144
+ if (err instanceof chunkH37YVYZA_cjs.HavenApiError) throw err;
144
145
  if (err instanceof Error && err.name === "AbortError") {
145
- throw new chunkHX34HOW4_cjs.HavenApiError(`Request to ${path} timed out`, 408);
146
+ throw new chunkH37YVYZA_cjs.HavenApiError(`Request to ${path} timed out`, 408);
146
147
  }
147
- throw new chunkHX34HOW4_cjs.HavenApiError(
148
+ throw new chunkH37YVYZA_cjs.HavenApiError(
148
149
  `Request to ${path} failed: ${err instanceof Error ? err.message : String(err)}`,
149
150
  0
150
151
  );
@@ -167,13 +168,13 @@ async function fetchUnsignedTaxDeclaration(client) {
167
168
  if (reason === "feature_disabled" || reason === "disabled" || reason === "no_company_details" || reason === "vies_not_valid") {
168
169
  return { available: false, reason };
169
170
  }
170
- throw new chunkHX34HOW4_cjs.HavenApiError(
171
+ throw new chunkH37YVYZA_cjs.HavenApiError(
171
172
  "The tax-declaration endpoint answered a body that is neither the \xA72.1 content nor a named unavailability reason.",
172
173
  502
173
174
  );
174
175
  }
175
176
  async function resolveTaxDeclarationHeader(client, input) {
176
- if (chunkHFOAYTD4_cjs.isErc7710Option(input.accepted)) {
177
+ if (chunk22FJ4JQO_cjs.isErc7710Option(input.accepted)) {
177
178
  return { header: void 0 };
178
179
  }
179
180
  let content;
@@ -185,7 +186,7 @@ async function resolveTaxDeclarationHeader(client, input) {
185
186
  if (!content.available) {
186
187
  return { header: void 0 };
187
188
  }
188
- const signed = chunkHFOAYTD4_cjs.buildSignedTaxDeclaration({
189
+ const signed = chunk22FJ4JQO_cjs.buildSignedTaxDeclaration({
189
190
  content: content.declaration,
190
191
  network: input.accepted.network,
191
192
  delegateKey: input.delegateKey
@@ -194,19 +195,19 @@ async function resolveTaxDeclarationHeader(client, input) {
194
195
  `[haven-sdk] signing x402 tax declaration taxId=${JSON.stringify(content.declaration.taxId)} jurisdiction=${JSON.stringify(content.declaration.jurisdiction)} principalId=${signed.declaration.principalId}
195
196
  `
196
197
  );
197
- return { header: chunkHFOAYTD4_cjs.encodeTaxDeclarationHeader(signed) };
198
+ return { header: chunk22FJ4JQO_cjs.encodeTaxDeclarationHeader(signed) };
198
199
  }
199
200
  function withTaxDeclarationHeader(init, header) {
200
201
  if (!header) {
201
- if (init?.headers && new Headers(init.headers).has(chunkHFOAYTD4_cjs.X_TAX_DECLARATION_HEADER)) {
202
+ if (init?.headers && new Headers(init.headers).has(chunk22FJ4JQO_cjs.X_TAX_DECLARATION_HEADER)) {
202
203
  const headers2 = new Headers(init.headers);
203
- headers2.delete(chunkHFOAYTD4_cjs.X_TAX_DECLARATION_HEADER);
204
+ headers2.delete(chunk22FJ4JQO_cjs.X_TAX_DECLARATION_HEADER);
204
205
  return { ...init, headers: headers2 };
205
206
  }
206
207
  return init ?? {};
207
208
  }
208
209
  const headers = new Headers(init?.headers);
209
- headers.set(chunkHFOAYTD4_cjs.X_TAX_DECLARATION_HEADER, header);
210
+ headers.set(chunk22FJ4JQO_cjs.X_TAX_DECLARATION_HEADER, header);
210
211
  return { ...init, headers };
211
212
  }
212
213
 
@@ -372,29 +373,29 @@ function paymentStateStatusCode(status, fallback = 502) {
372
373
  return PAYMENT_STATE_STATUS_CODES[status] ?? fallback;
373
374
  }
374
375
  function phaseForStatus(status) {
375
- if (status === "pending_signature") return chunkHX34HOW4_cjs.AgentPaymentPhase.AgentSignatureRequired;
376
- if (status === "submitted") return chunkHX34HOW4_cjs.AgentPaymentPhase.PaymentSubmitted;
377
- if (status === "confirmed") return chunkHX34HOW4_cjs.AgentPaymentPhase.PaymentConfirmed;
378
- if (status === "pending" || status === "pending_approval") return chunkHX34HOW4_cjs.AgentPaymentPhase.UserApprovalRequired;
379
- if (status === "approved") return chunkHX34HOW4_cjs.AgentPaymentPhase.UserExecutionRequired;
380
- if (status === "proposed") return chunkHX34HOW4_cjs.AgentPaymentPhase.WaitingForAdditionalApprovals;
381
- if (status === "executed") return chunkHX34HOW4_cjs.AgentPaymentPhase.FundingSent;
382
- if (status === "rejected") return chunkHX34HOW4_cjs.AgentPaymentPhase.Rejected;
383
- if (status === "expired") return chunkHX34HOW4_cjs.AgentPaymentPhase.Expired;
384
- if (status === "failed") return chunkHX34HOW4_cjs.AgentPaymentPhase.Failed;
376
+ if (status === "pending_signature") return chunkH37YVYZA_cjs.AgentPaymentPhase.AgentSignatureRequired;
377
+ if (status === "submitted") return chunkH37YVYZA_cjs.AgentPaymentPhase.PaymentSubmitted;
378
+ if (status === "confirmed") return chunkH37YVYZA_cjs.AgentPaymentPhase.PaymentConfirmed;
379
+ if (status === "pending" || status === "pending_approval") return chunkH37YVYZA_cjs.AgentPaymentPhase.UserApprovalRequired;
380
+ if (status === "approved") return chunkH37YVYZA_cjs.AgentPaymentPhase.UserExecutionRequired;
381
+ if (status === "proposed") return chunkH37YVYZA_cjs.AgentPaymentPhase.WaitingForAdditionalApprovals;
382
+ if (status === "executed") return chunkH37YVYZA_cjs.AgentPaymentPhase.FundingSent;
383
+ if (status === "rejected") return chunkH37YVYZA_cjs.AgentPaymentPhase.Rejected;
384
+ if (status === "expired") return chunkH37YVYZA_cjs.AgentPaymentPhase.Expired;
385
+ if (status === "failed") return chunkH37YVYZA_cjs.AgentPaymentPhase.Failed;
385
386
  return null;
386
387
  }
387
388
  function nextActionForStatus(status) {
388
- if (status === "pending_signature") return chunkHX34HOW4_cjs.AgentPaymentNextAction.SignAndSubmitPayment;
389
- if (status === "submitted") return chunkHX34HOW4_cjs.AgentPaymentNextAction.CheckStatusLater;
390
- if (status === "confirmed") return chunkHX34HOW4_cjs.AgentPaymentNextAction.None;
391
- if (status === "pending" || status === "pending_approval") return chunkHX34HOW4_cjs.AgentPaymentNextAction.StopAndTellUser;
392
- if (status === "approved") return chunkHX34HOW4_cjs.AgentPaymentNextAction.StopAndTellUser;
393
- if (status === "proposed") return chunkHX34HOW4_cjs.AgentPaymentNextAction.StopAndTellUser;
394
- if (status === "executed") return chunkHX34HOW4_cjs.AgentPaymentNextAction.StopAndTellUser;
395
- if (status === "rejected") return chunkHX34HOW4_cjs.AgentPaymentNextAction.StopAndTellUser;
396
- if (status === "expired") return chunkHX34HOW4_cjs.AgentPaymentNextAction.RequestAgainIfUserStillWantsIt;
397
- if (status === "failed") return chunkHX34HOW4_cjs.AgentPaymentNextAction.StopAndTellUser;
389
+ if (status === "pending_signature") return chunkH37YVYZA_cjs.AgentPaymentNextAction.SignAndSubmitPayment;
390
+ if (status === "submitted") return chunkH37YVYZA_cjs.AgentPaymentNextAction.CheckStatusLater;
391
+ if (status === "confirmed") return chunkH37YVYZA_cjs.AgentPaymentNextAction.None;
392
+ if (status === "pending" || status === "pending_approval") return chunkH37YVYZA_cjs.AgentPaymentNextAction.StopAndTellUser;
393
+ if (status === "approved") return chunkH37YVYZA_cjs.AgentPaymentNextAction.StopAndTellUser;
394
+ if (status === "proposed") return chunkH37YVYZA_cjs.AgentPaymentNextAction.StopAndTellUser;
395
+ if (status === "executed") return chunkH37YVYZA_cjs.AgentPaymentNextAction.StopAndTellUser;
396
+ if (status === "rejected") return chunkH37YVYZA_cjs.AgentPaymentNextAction.StopAndTellUser;
397
+ if (status === "expired") return chunkH37YVYZA_cjs.AgentPaymentNextAction.RequestAgainIfUserStillWantsIt;
398
+ if (status === "failed") return chunkH37YVYZA_cjs.AgentPaymentNextAction.StopAndTellUser;
398
399
  return null;
399
400
  }
400
401
  function messageForState(label, status, paymentId, nextAction) {
@@ -468,17 +469,17 @@ function throwPaymentStateError(label, raw) {
468
469
  const statusCode = paymentStateStatusCode(raw.status);
469
470
  const state = paymentStateFromRaw(label, raw);
470
471
  if (state) {
471
- throw new chunkHX34HOW4_cjs.HavenPaymentStateError(state.message, statusCode, state, raw);
472
+ throw new chunkH37YVYZA_cjs.HavenPaymentStateError(state.message, statusCode, state, raw);
472
473
  }
473
474
  if (raw.status === "pending_approval") {
474
- throw new chunkHX34HOW4_cjs.HavenApiError(
475
+ throw new chunkH37YVYZA_cjs.HavenApiError(
475
476
  `${label} exceeds the agent's on-chain budget and was declined; no approval is pending and none will arrive (payment_id: ${raw.payment_id}).`,
476
477
  statusCode,
477
478
  raw
478
479
  );
479
480
  }
480
481
  if (raw.status === "expired") {
481
- throw new chunkHX34HOW4_cjs.HavenApiError(
482
+ throw new chunkH37YVYZA_cjs.HavenApiError(
482
483
  `${label} expired before it could be completed (payment_id: ${raw.payment_id}).`,
483
484
  statusCode,
484
485
  raw
@@ -486,7 +487,7 @@ function throwPaymentStateError(label, raw) {
486
487
  }
487
488
  const paymentId = raw.payment_id ? ` (payment_id: ${raw.payment_id})` : "";
488
489
  const message = raw.error ?? `${label} ${raw.status}${paymentId}`;
489
- throw new chunkHX34HOW4_cjs.HavenApiError(message, statusCode, raw);
490
+ throw new chunkH37YVYZA_cjs.HavenApiError(message, statusCode, raw);
490
491
  }
491
492
 
492
493
  // src/x402-retry-target.ts
@@ -518,7 +519,7 @@ function isSecureX402RetryTarget(url) {
518
519
  return RESERVED_SUFFIXES.some((suffix) => host.endsWith(suffix));
519
520
  }
520
521
  var INSECURE_RETRY_TARGET_CODE = "INSECURE_RETRY_TARGET";
521
- var HavenInsecureRetryTargetError = class extends chunkHX34HOW4_cjs.HavenError {
522
+ var HavenInsecureRetryTargetError = class extends chunkH37YVYZA_cjs.HavenError {
522
523
  constructor(url) {
523
524
  super(
524
525
  `Refusing to send a payment header to ${url}: the paid x402 retry must go to an https URL (or a loopback / reserved test host). The merchant's challenge declared this resource URL; retry with the https URL you quoted (pass it as \`url\`), and report a merchant whose challenge downgrades the scheme.`,
@@ -534,6 +535,122 @@ function assertSecureX402RetryTarget(url) {
534
535
  if (!isSecureX402RetryTarget(url)) throw new HavenInsecureRetryTargetError(url);
535
536
  }
536
537
 
538
+ // src/merchant-egress.ts
539
+ var MERCHANT_EGRESS_REFUSED_CODE = "MERCHANT_EGRESS_REFUSED";
540
+ var MerchantEgressRefusedError = class extends chunkH37YVYZA_cjs.HavenError {
541
+ url;
542
+ refusal;
543
+ beforeRequest;
544
+ constructor(message, url, refusal, beforeRequest) {
545
+ super(message, MERCHANT_EGRESS_REFUSED_CODE, 400);
546
+ this.name = "MerchantEgressRefusedError";
547
+ this.url = url;
548
+ this.refusal = refusal;
549
+ this.beforeRequest = beforeRequest;
550
+ }
551
+ };
552
+ var MERCHANT_EGRESS_RESPONSE_CAP_CODE = "MERCHANT_EGRESS_RESPONSE_CAP";
553
+ var MerchantEgressResponseCapError = class extends chunkH37YVYZA_cjs.HavenError {
554
+ url;
555
+ limitBytes;
556
+ constructor(message, limitBytes, url) {
557
+ super(message, MERCHANT_EGRESS_RESPONSE_CAP_CODE, 400);
558
+ this.name = "MerchantEgressResponseCapError";
559
+ this.limitBytes = limitBytes;
560
+ this.url = url;
561
+ }
562
+ };
563
+ var INTERNAL_SUFFIXES = [".internal", ".local", ".localhost", ".test", ".invalid", ".example"];
564
+ function isPublicHttpsMerchantUrl(url) {
565
+ let parsed;
566
+ try {
567
+ parsed = new URL(url);
568
+ } catch {
569
+ return false;
570
+ }
571
+ if (parsed.protocol !== "https:") return false;
572
+ const host = parsed.hostname.toLowerCase().replace(/\.$/, "");
573
+ if (host.includes(":")) return false;
574
+ if (/^\d{1,3}(?:\.\d{1,3}){3}$/.test(host)) return false;
575
+ if (!host.includes(".")) return false;
576
+ return !INTERNAL_SUFFIXES.some((suffix) => host.endsWith(suffix));
577
+ }
578
+ function publicHttpsMerchantUrlRefusal(url) {
579
+ let parsed;
580
+ try {
581
+ parsed = new URL(url);
582
+ } catch {
583
+ return "it is not a valid URL";
584
+ }
585
+ if (parsed.protocol !== "https:") return `its scheme is ${parsed.protocol.replace(":", "")}, not https`;
586
+ const host = parsed.hostname.toLowerCase().replace(/\.$/, "");
587
+ if (host.includes(":")) return `${host} is an IP-literal host (IPv6)`;
588
+ if (/^\d{1,3}(?:\.\d{1,3}){3}$/.test(host)) return `${host} is an IP-literal host (IPv4)`;
589
+ if (!host.includes(".")) return `${host} is a single-label host`;
590
+ const suffix = INTERNAL_SUFFIXES.find((s) => host.endsWith(s));
591
+ if (suffix) return `${host} ends in the internal/reserved suffix ${suffix}`;
592
+ return "it is not a public https URL";
593
+ }
594
+ function assertPublicHttpsMerchantUrl(url) {
595
+ if (isPublicHttpsMerchantUrl(url)) return;
596
+ throw new MerchantEgressRefusedError(
597
+ `Hosted egress policy refuses ${url}: ${publicHttpsMerchantUrlRefusal(url)}. Hosted merchant requests go to public https hosts only \u2014 no IP literals, no localhost, no single-label or internal names. Re-quote the merchant at its public https URL.`,
598
+ url,
599
+ "url_not_allowed",
600
+ true
601
+ );
602
+ }
603
+ var HOSTED_DISCOVERY_TIMEOUT_MS = 5e3;
604
+ var HOSTED_EGRESS_TIMEOUTS = {
605
+ quote: 15e3,
606
+ mcpSession: 15e3,
607
+ discovery: HOSTED_DISCOVERY_TIMEOUT_MS,
608
+ // Today's DEFAULT_MERCHANT_TIMEOUT — stated here rather than imported to
609
+ // keep this module dependency-free in both directions.
610
+ delivery: 3e5
611
+ };
612
+ var HOSTED_RESPONSE_BYTE_CAPS = {
613
+ quote: 256 * 1024,
614
+ mcpSession: 256 * 1024,
615
+ discovery: 64 * 1024,
616
+ delivery: 5 * 1024 * 1024
617
+ };
618
+ var HOSTED_MAX_GET_REDIRECTS = 3;
619
+ function strictMerchantEgressPolicy() {
620
+ return {
621
+ assertUrl: assertPublicHttpsMerchantUrl,
622
+ maxResponseBytes: HOSTED_RESPONSE_BYTE_CAPS.delivery,
623
+ responseByteCaps: { ...HOSTED_RESPONSE_BYTE_CAPS },
624
+ maxGetRedirects: HOSTED_MAX_GET_REDIRECTS,
625
+ timeouts: { ...HOSTED_EGRESS_TIMEOUTS }
626
+ };
627
+ }
628
+ function isBodyPhaseTimeout(err) {
629
+ return err instanceof DOMException && err.name === "TimeoutError";
630
+ }
631
+ async function readBodyCapped(response, maxBytes) {
632
+ if (!response.body) return response.text();
633
+ const reader = response.body.getReader();
634
+ const decoder = new TextDecoder();
635
+ let text = "";
636
+ let total = 0;
637
+ while (true) {
638
+ const { done, value } = await reader.read();
639
+ if (done) break;
640
+ total += value.byteLength;
641
+ if (total > maxBytes) {
642
+ await reader.cancel().catch(() => {
643
+ });
644
+ throw new MerchantEgressResponseCapError(
645
+ `Merchant response exceeded the ${maxBytes}-byte cap while it was being read; the read was aborted.`,
646
+ maxBytes
647
+ );
648
+ }
649
+ text += decoder.decode(value, { stream: true });
650
+ }
651
+ return text + decoder.decode();
652
+ }
653
+
537
654
  // src/mcp-merchant-transport.ts
538
655
  var DEFAULT_MERCHANT_TIMEOUT = 3e5;
539
656
  var MCP_NOTIFICATION_TIMEOUT = 1e4;
@@ -547,24 +664,161 @@ var SESSION_NOT_FOUND_NEXT_ACTION = "reinitialize_then_retry_same_payment_header
547
664
  var McpMerchantTransport = class {
548
665
  merchantTimeout;
549
666
  fetchImpl;
667
+ egress;
550
668
  requestId = 0;
551
669
  constructor(options = {}) {
552
670
  this.merchantTimeout = options.merchantTimeout ?? DEFAULT_MERCHANT_TIMEOUT;
671
+ this.egress = options.egress;
553
672
  this.fetchImpl = options.fetch ?? ((input, init) => globalThis.fetch(input, init));
554
673
  }
674
+ /**
675
+ * #3747: the timeout a merchant use runs under. Without an egress policy
676
+ * this is always `merchantTimeout` — byte-identical to the pre-policy
677
+ * behaviour; with one, the effective deadline is
678
+ * `min(policy timeout for the use, merchantTimeout)` (spec review
679
+ * 2026-10-07) — a policy can only TIGHTEN `merchantTimeout`, never extend
680
+ * it.
681
+ */
682
+ budgetFor(use) {
683
+ const policyTimeout = this.egress?.timeouts?.[use];
684
+ return policyTimeout === void 0 ? this.merchantTimeout : Math.min(policyTimeout, this.merchantTimeout);
685
+ }
686
+ /** The per-use response byte cap (falls back to the policy's default). */
687
+ capFor(use) {
688
+ const egress = this.egress;
689
+ if (!egress) return void 0;
690
+ return egress.responseByteCaps?.[use] ?? egress.maxResponseBytes;
691
+ }
555
692
  /** Fetch a merchant with a settlement-sized timeout and caller cancellation. */
556
- async fetch(url, init = {}, timeoutMs = this.merchantTimeout) {
693
+ async fetch(url, init = {}, timeoutMs = this.merchantTimeout, maxBytes) {
694
+ if (!this.egress) {
695
+ const timeoutSignal = AbortSignal.timeout(timeoutMs);
696
+ const signal = init.signal ? AbortSignal.any([init.signal, timeoutSignal]) : timeoutSignal;
697
+ try {
698
+ return await this.fetchImpl(url, { ...init, signal });
699
+ } catch (err) {
700
+ if (timeoutSignal.aborted) {
701
+ throw new chunkH37YVYZA_cjs.MerchantTimeoutError(`Merchant request timed out after ${timeoutMs}ms: ${url}`);
702
+ }
703
+ throw err;
704
+ }
705
+ }
706
+ return this.fetchUnderPolicy(url, init, timeoutMs, maxBytes);
707
+ }
708
+ /**
709
+ * #3747: the policy path. Every URL — the initial request and each redirect
710
+ * hop — is `assertUrl`-checked BEFORE it connects; redirects run `manual`
711
+ * so nothing is ever followed un-checked; GET redirects are followed up to
712
+ * `maxGetRedirects` (a redirect on any other method is refused); response
713
+ * bodies are capped WHILE being read, not after buffering. The timeout
714
+ * signal spans the WHOLE redirect chain, and `MerchantTimeoutError`
715
+ * classification is preserved.
716
+ */
717
+ async fetchUnderPolicy(url, init, timeoutMs, maxBytes) {
718
+ const egress = this.egress;
719
+ try {
720
+ egress.assertUrl(url);
721
+ } catch (err) {
722
+ throw asRefusal(err, url, true);
723
+ }
724
+ const method = (init.method ?? "GET").toUpperCase();
557
725
  const timeoutSignal = AbortSignal.timeout(timeoutMs);
558
726
  const signal = init.signal ? AbortSignal.any([init.signal, timeoutSignal]) : timeoutSignal;
727
+ const maxRedirects = egress.maxGetRedirects ?? 0;
728
+ let currentUrl = url;
729
+ let hops = 0;
559
730
  try {
560
- return await this.fetchImpl(url, { ...init, signal });
731
+ while (true) {
732
+ const response = await this.fetchImpl(currentUrl, {
733
+ ...init,
734
+ redirect: init.redirect === "error" ? "error" : "manual",
735
+ signal
736
+ });
737
+ if (!isRedirectStatus(response.status)) return this.capResponse(response, currentUrl, maxBytes);
738
+ if (method !== "GET") {
739
+ throw new MerchantEgressRefusedError(
740
+ `Hosted egress policy refuses the ${response.status} redirect from ${currentUrl}: redirects are followed for GET requests only, and this was a ${method}. The request itself was already sent to the checked URL; nothing was sent to the redirect target.`,
741
+ currentUrl,
742
+ "redirect_on_non_get",
743
+ false
744
+ );
745
+ }
746
+ const location = response.headers.get("location");
747
+ if (!location) {
748
+ throw new MerchantEgressRefusedError(
749
+ `Hosted egress policy refuses the ${response.status} redirect from ${currentUrl}: it carries no Location header, so there is no checked target to follow.`,
750
+ currentUrl,
751
+ "redirect_missing_location",
752
+ false
753
+ );
754
+ }
755
+ let next;
756
+ try {
757
+ next = new URL(location, currentUrl).toString();
758
+ } catch {
759
+ throw new MerchantEgressRefusedError(
760
+ `Hosted egress policy refuses the redirect from ${currentUrl}: its Location header is not a resolvable URL.`,
761
+ currentUrl,
762
+ "redirect_invalid_location",
763
+ false
764
+ );
765
+ }
766
+ if (hops >= maxRedirects) {
767
+ throw new MerchantEgressRefusedError(
768
+ `Hosted egress policy refuses the redirect from ${currentUrl} to ${next}: the ${maxRedirects}-redirect budget for this request is spent.`,
769
+ next,
770
+ "redirect_budget_exceeded",
771
+ false
772
+ );
773
+ }
774
+ try {
775
+ egress.assertUrl(next);
776
+ } catch (err) {
777
+ throw asRefusal(err, next, false);
778
+ }
779
+ hops++;
780
+ currentUrl = next;
781
+ }
561
782
  } catch (err) {
562
783
  if (timeoutSignal.aborted) {
563
- throw new chunkHX34HOW4_cjs.MerchantTimeoutError(`Merchant request timed out after ${timeoutMs}ms: ${url}`);
784
+ throw new chunkH37YVYZA_cjs.MerchantTimeoutError(`Merchant request timed out after ${timeoutMs}ms: ${currentUrl}`);
564
785
  }
565
786
  throw err;
566
787
  }
567
788
  }
789
+ /**
790
+ * #3747: enforce `maxResponseBytes` at the STREAM, so every later read —
791
+ * `.text()`, `.json()`, `.clone().text()` — rejects mid-read the moment the
792
+ * cap is crossed. A body that never ends can never buffer past the cap.
793
+ */
794
+ capResponse(response, url, maxBytes) {
795
+ const cap = maxBytes ?? this.egress.maxResponseBytes;
796
+ if (!cap || !response.body) return response;
797
+ let total = 0;
798
+ const capped = response.body.pipeThrough(
799
+ new TransformStream({
800
+ transform(chunk, controller) {
801
+ total += chunk.byteLength;
802
+ if (total > cap) {
803
+ controller.error(
804
+ new MerchantEgressResponseCapError(
805
+ `Merchant response from ${url} exceeded the ${cap}-byte cap while it was being read; the read was aborted.`,
806
+ cap,
807
+ url
808
+ )
809
+ );
810
+ return;
811
+ }
812
+ controller.enqueue(chunk);
813
+ }
814
+ })
815
+ );
816
+ return new Response(capped, {
817
+ status: response.status,
818
+ statusText: response.statusText,
819
+ headers: response.headers
820
+ });
821
+ }
568
822
  /**
569
823
  * Establish an MCP Streamable-HTTP session. Any handshake failure degrades
570
824
  * to `undefined`, allowing the caller to fall back to plain x402.
@@ -588,7 +842,7 @@ var McpMerchantTransport = class {
588
842
  clientInfo: MCP_CLIENT_INFO
589
843
  }
590
844
  })
591
- });
845
+ }, this.budgetFor("mcpSession"), this.capFor("mcpSession"));
592
846
  if (!response.ok) return void 0;
593
847
  const sessionId = response.headers.get("mcp-session-id");
594
848
  if (!sessionId) return void 0;
@@ -596,7 +850,8 @@ var McpMerchantTransport = class {
596
850
  if (message && "error" in message) return void 0;
597
851
  await this.notifyInitialized(url, init, sessionId, wallet);
598
852
  return sessionId;
599
- } catch {
853
+ } catch (err) {
854
+ if (err instanceof MerchantEgressRefusedError || err instanceof MerchantEgressResponseCapError) throw err;
600
855
  return void 0;
601
856
  }
602
857
  }
@@ -612,7 +867,9 @@ var McpMerchantTransport = class {
612
867
  let text;
613
868
  try {
614
869
  text = await response.clone().text();
615
- } catch {
870
+ } catch (err) {
871
+ if (err instanceof MerchantEgressResponseCapError) throw err;
872
+ if (isBodyPhaseTimeout(err)) throw new chunkH37YVYZA_cjs.MerchantTimeoutError(`Merchant response body read timed out.`);
616
873
  return void 0;
617
874
  }
618
875
  if ((response.headers.get("content-type") ?? "").includes("text/event-stream")) {
@@ -635,7 +892,9 @@ var McpMerchantTransport = class {
635
892
  let text;
636
893
  try {
637
894
  text = await response.clone().text();
638
- } catch {
895
+ } catch (err) {
896
+ if (err instanceof MerchantEgressResponseCapError) throw err;
897
+ if (isBodyPhaseTimeout(err)) throw new chunkH37YVYZA_cjs.MerchantTimeoutError(`Merchant response body read timed out.`);
639
898
  return response;
640
899
  }
641
900
  const message = selectJsonRpcResult(parseSseJsonRpcMessages(text));
@@ -697,12 +956,12 @@ var McpMerchantTransport = class {
697
956
  async deliverPayment(url, init, paymentHeader) {
698
957
  assertSecureX402RetryTarget(url);
699
958
  const headers = new Headers(init?.headers);
700
- const send = chunkHFOAYTD4_cjs.x402PaymentHeaderNamesFor(paymentHeader);
701
- for (const name of chunkHFOAYTD4_cjs.X402_PAYMENT_HEADER_NAMES) {
959
+ const send = chunk22FJ4JQO_cjs.x402PaymentHeaderNamesFor(paymentHeader);
960
+ for (const name of chunk22FJ4JQO_cjs.X402_PAYMENT_HEADER_NAMES) {
702
961
  if (send.includes(name)) headers.set(name, paymentHeader);
703
962
  else headers.delete(name);
704
963
  }
705
- return this.fetch(url, withMcpPaymentMeta({ ...init, headers }, paymentHeader));
964
+ return this.fetch(url, withMcpPaymentMeta({ ...init, headers }, paymentHeader), this.budgetFor("delivery"), this.capFor("delivery"));
706
965
  }
707
966
  /**
708
967
  * #3171: deliver the payment; if the merchant answers its unknown-session
@@ -785,7 +1044,7 @@ function mcpToolResultOf(value) {
785
1044
  function extractMcpPaymentRequired(toolResult) {
786
1045
  if (toolResult.isError !== true) return void 0;
787
1046
  if (isRecord(toolResult.structuredContent)) {
788
- const parsed = chunkHFOAYTD4_cjs.normalizePaymentRequired(toolResult.structuredContent);
1047
+ const parsed = chunk22FJ4JQO_cjs.normalizePaymentRequired(toolResult.structuredContent);
789
1048
  if (parsed) return parsed;
790
1049
  }
791
1050
  if (Array.isArray(toolResult.content)) {
@@ -797,7 +1056,7 @@ function extractMcpPaymentRequired(toolResult) {
797
1056
  } catch {
798
1057
  continue;
799
1058
  }
800
- const parsed = chunkHFOAYTD4_cjs.normalizePaymentRequired(candidate);
1059
+ const parsed = chunk22FJ4JQO_cjs.normalizePaymentRequired(candidate);
801
1060
  if (parsed) return parsed;
802
1061
  }
803
1062
  }
@@ -821,7 +1080,7 @@ function withMcpPaymentMeta(init, paymentHeader) {
821
1080
  if (!request) return init;
822
1081
  let envelope;
823
1082
  try {
824
- envelope = chunkHFOAYTD4_cjs.decodeBase64Json(paymentHeader);
1083
+ envelope = chunk22FJ4JQO_cjs.decodeBase64Json(paymentHeader);
825
1084
  } catch {
826
1085
  return init;
827
1086
  }
@@ -837,7 +1096,7 @@ function withMcpPaymentMeta(init, paymentHeader) {
837
1096
  };
838
1097
  }
839
1098
  function encodeMcpSettlementReceipt(settlement) {
840
- return chunkHFOAYTD4_cjs.encodeBase64Json(settlement);
1099
+ return chunk22FJ4JQO_cjs.encodeBase64Json(settlement);
841
1100
  }
842
1101
  function parseJsonRpcToolsCall(body) {
843
1102
  if (typeof body !== "string") return void 0;
@@ -874,8 +1133,19 @@ function sessionNotFoundRecovery(body) {
874
1133
  function isRecord(value) {
875
1134
  return typeof value === "object" && value !== null && !Array.isArray(value);
876
1135
  }
1136
+ function isRedirectStatus(status) {
1137
+ return status === 301 || status === 302 || status === 303 || status === 307 || status === 308;
1138
+ }
1139
+ function asRefusal(err, url, beforeRequest) {
1140
+ if (!(err instanceof MerchantEgressRefusedError)) return err;
1141
+ if (err.beforeRequest === beforeRequest) return err;
1142
+ return new MerchantEgressRefusedError(err.message, url, err.refusal, beforeRequest);
1143
+ }
877
1144
  async function captureMerchantResponse(response) {
878
- const merchant_body = await response.text().catch(() => "");
1145
+ const merchant_body = await response.text().catch((err) => {
1146
+ if (err instanceof MerchantEgressResponseCapError) throw err;
1147
+ return "";
1148
+ });
879
1149
  return {
880
1150
  merchant_status: response.status,
881
1151
  merchant_status_text: response.statusText,
@@ -894,7 +1164,8 @@ async function responseHasBazaarExtension(response) {
894
1164
  try {
895
1165
  const body = await response.clone().json();
896
1166
  return body?.extensions?.bazaar != null;
897
- } catch {
1167
+ } catch (err) {
1168
+ if (err instanceof MerchantEgressResponseCapError) throw err;
898
1169
  return false;
899
1170
  }
900
1171
  }
@@ -922,95 +1193,6 @@ function parseSseJsonRpcMessages(text) {
922
1193
  function selectJsonRpcResult(messages) {
923
1194
  return messages.find((message) => "result" in message || "error" in message) ?? messages.at(-1);
924
1195
  }
925
- var RECEIPT_VERSION = "haven-receipt-1";
926
- var DELEGATION_MANAGER_CHAIN_IDS = /* @__PURE__ */ new Set([8453, 84532]);
927
- var EIP712_DOMAIN_TYPEHASH = viem.keccak256(
928
- viem.toBytes("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)")
929
- );
930
- function delegationDomainSeparator(chainId) {
931
- return viem.keccak256(
932
- viem.encodeAbiParameters(
933
- [{ type: "bytes32" }, { type: "bytes32" }, { type: "bytes32" }, { type: "uint256" }, { type: "address" }],
934
- [
935
- EIP712_DOMAIN_TYPEHASH,
936
- viem.keccak256(viem.toBytes("DelegationManager")),
937
- viem.keccak256(viem.toBytes("1")),
938
- BigInt(chainId),
939
- chunkHX34HOW4_cjs.DELEGATION_MANAGER
940
- ]
941
- )
942
- );
943
- }
944
- function delegationDigest(structHash, chainId) {
945
- return viem.keccak256(viem.concatHex(["0x1901", delegationDomainSeparator(chainId), structHash]));
946
- }
947
- function defaultRecover(hash, signature) {
948
- return ethers.ethers.recoverAddress(hash, signature);
949
- }
950
- var NOT_A_SIGNED_RECEIPT = { verified: false, reason: "not_a_signed_receipt" };
951
- function match(delegate, hash, signature, recover) {
952
- let recovered;
953
- try {
954
- recovered = recover(hash, signature);
955
- } catch {
956
- return { ok: false, reason: "bad_signature" };
957
- }
958
- if (recovered.toLowerCase() !== delegate.toLowerCase()) {
959
- return { ok: false, reason: "signer_mismatch", recoveredSigner: recovered };
960
- }
961
- return { ok: true, recoveredSigner: recovered };
962
- }
963
- function finish(result, verifiedOver) {
964
- if (result.ok) {
965
- return { verified: true, recoveredSigner: result.recoveredSigner, verifiedOver };
966
- }
967
- return result.recoveredSigner !== void 0 ? { verified: false, reason: result.reason, recoveredSigner: result.recoveredSigner } : { verified: false, reason: result.reason };
968
- }
969
- function verifyPaymentReceipt(receipt, recover = defaultRecover) {
970
- if (typeof receipt !== "object" || receipt === null) return NOT_A_SIGNED_RECEIPT;
971
- const source = receipt;
972
- if (typeof source.authorization !== "object" || source.authorization === null) {
973
- return NOT_A_SIGNED_RECEIPT;
974
- }
975
- const auth = source.authorization;
976
- const { delegate, signHash: signHash2, signature, signatureScheme } = auth;
977
- if (typeof delegate !== "string" || delegate === "" || typeof signHash2 !== "string" || signHash2 === "") {
978
- return NOT_A_SIGNED_RECEIPT;
979
- }
980
- if (typeof signature !== "string" || signature === "") {
981
- return { verified: false, reason: "missing_signature" };
982
- }
983
- const chainId = typeof source.onChain?.chainId === "number" ? source.onChain.chainId : void 0;
984
- const digestVerifiable = chainId !== void 0 && DELEGATION_MANAGER_CHAIN_IDS.has(chainId);
985
- if (signatureScheme === "eip712_userop") {
986
- return { verified: false, reason: "not_verifiable_offline" };
987
- }
988
- if (signatureScheme === "eip712_delegation") {
989
- if (!digestVerifiable) {
990
- return { verified: false, reason: "not_verifiable_offline" };
991
- }
992
- let digest;
993
- try {
994
- digest = delegationDigest(signHash2, chainId);
995
- } catch {
996
- return { verified: false, reason: "bad_signature" };
997
- }
998
- return finish(match(delegate, digest, signature, recover), "delegation_digest");
999
- }
1000
- const raw = match(delegate, signHash2, signature, recover);
1001
- if (raw.ok) return finish(raw, "sign_hash");
1002
- if (digestVerifiable) {
1003
- let digest;
1004
- try {
1005
- digest = delegationDigest(signHash2, chainId);
1006
- } catch {
1007
- return finish(raw, "sign_hash");
1008
- }
1009
- const delegated = match(delegate, digest, signature, recover);
1010
- if (delegated.ok) return finish(delegated, "delegation_digest");
1011
- }
1012
- return finish(raw, "sign_hash");
1013
- }
1014
1196
 
1015
1197
  // src/account-reads.ts
1016
1198
  function safeBigInt(value) {
@@ -1032,7 +1214,7 @@ function deriveReadiness(status, allowances) {
1032
1214
  return allowances.some((allowance) => safeBigInt(allowance.remainingAtomic) > 0n) ? "ready" : "needs_approval";
1033
1215
  }
1034
1216
  function formatRemainingDisplay(tokenAddress, tokenSymbol, remainingAtomic) {
1035
- const token = chunkHFOAYTD4_cjs.resolveTokenFromAddress(tokenAddress);
1217
+ const token = chunk22FJ4JQO_cjs.resolveTokenFromAddress(tokenAddress);
1036
1218
  return token ? `${formatAtomicAmount(safeBigInt(remainingAtomic), token.decimals)} ${tokenSymbol}` : `${remainingAtomic} ${tokenSymbol} (atomic; unknown decimals)`;
1037
1219
  }
1038
1220
  function formatTokenAmount(atomic, decimals) {
@@ -1043,6 +1225,19 @@ function formatTokenAmount(atomic, decimals) {
1043
1225
  const fracPart = digits.slice(digits.length - decimals).replace(/0+$/, "");
1044
1226
  return fracPart ? `${intPart}.${fracPart}` : intPart;
1045
1227
  }
1228
+ function mapSupersession(raw) {
1229
+ if (typeof raw !== "object" || raw === null) return null;
1230
+ const { agent_id: replacementAgentId, superseded_at: supersededAt } = raw;
1231
+ if (typeof replacementAgentId !== "string" || replacementAgentId === "") return null;
1232
+ if (typeof supersededAt !== "string" || supersededAt === "") return null;
1233
+ return {
1234
+ replacementAgentId,
1235
+ supersededAt,
1236
+ warning: `This agent was replaced on its machine by agent ${replacementAgentId} at ${supersededAt}. This session is still running as the old agent: restart the agent runtime so it loads the new agent, and ask the user to remove this agent on its Haven agent page if it is no longer used \u2014 it keeps any budget it still holds until then.`,
1237
+ nextAction: chunkH37YVYZA_cjs.AgentPaymentNextAction.StopAndTellUser,
1238
+ nextToolOmittedReason: "The next step is the user's: restart this session, and remove the superseded agent in the Haven dashboard. No Haven tool does either."
1239
+ };
1240
+ }
1046
1241
  function mapTaskBudget(raw) {
1047
1242
  return {
1048
1243
  id: raw.id,
@@ -1108,7 +1303,7 @@ function summarizePendingSubBudget(row) {
1108
1303
  };
1109
1304
  }
1110
1305
  function summarizeTaskBudget(taskBudget) {
1111
- const token = chunkHFOAYTD4_cjs.resolveTokenFromAddress(taskBudget.tokenAddress);
1306
+ const token = chunk22FJ4JQO_cjs.resolveTokenFromAddress(taskBudget.tokenAddress);
1112
1307
  const maxDisplay = token ? `${formatAtomicAmount(safeBigInt(taskBudget.maxAtomic), token.decimals)} ${token.symbol}` : `${taskBudget.maxAtomic} (atomic; unknown decimals)`;
1113
1308
  const spendDisplay = (atomic) => {
1114
1309
  if (atomic === null) return null;
@@ -1182,7 +1377,10 @@ var AccountReads = class {
1182
1377
  remainingDisplay: allowance.remainingDisplay,
1183
1378
  configuredAmount: allowance.configuredAmount,
1184
1379
  resetPeriodMin: allowance.resetPeriodMin,
1185
- isResetPending: allowance.onchain.isResetPending
1380
+ isResetPending: allowance.onchain.isResetPending,
1381
+ // #3731: same provenance as the detailed read's field — the compact
1382
+ // row is a projection of the same allowance, never a second source.
1383
+ fundsCoverRemaining: allowance.fundsCoverRemaining
1186
1384
  };
1187
1385
  });
1188
1386
  const readiness = deriveReadiness(agent.status, allowances);
@@ -1233,7 +1431,7 @@ var AccountReads = class {
1233
1431
  async listTaskBudgetsSummary() {
1234
1432
  try {
1235
1433
  const raw = await this.transport.get("/task-budgets?status=live").catch((error) => {
1236
- if (error instanceof chunkHX34HOW4_cjs.HavenApiError && error.statusCode === 400) {
1434
+ if (error instanceof chunkH37YVYZA_cjs.HavenApiError && error.statusCode === 400) {
1237
1435
  return this.transport.get("/task-budgets?status=all");
1238
1436
  }
1239
1437
  throw error;
@@ -1275,6 +1473,7 @@ var AccountReads = class {
1275
1473
  accountAddress: raw.account_address,
1276
1474
  delegateAddress: raw.delegate_address,
1277
1475
  chainId: raw.chain_id,
1476
+ supersededBy: mapSupersession(raw.superseded_by),
1278
1477
  allowances: raw.allowances.map((allowance) => ({
1279
1478
  id: allowance.id,
1280
1479
  tokenAddress: allowance.token_address,
@@ -1287,6 +1486,11 @@ var AccountReads = class {
1287
1486
  ...allowance.recipient_address !== void 0 ? { recipientAddress: allowance.recipient_address } : {},
1288
1487
  ...allowance.merchant_id !== void 0 ? { merchantId: allowance.merchant_id } : {},
1289
1488
  ...allowance.reserved_haven_atomic !== void 0 ? { reservedHavenAtomic: allowance.reserved_haven_atomic } : {},
1489
+ // #3731: boolean → itself; ANY other value (absent, string, null) →
1490
+ // null, never undefined — a malformed or empty body answers
1491
+ // "unverifiable", not a missing key. The key is absent on the wire
1492
+ // when the remaining is 0; that maps to null here too.
1493
+ fundsCoverRemaining: allowance.funds_cover_remaining === true || allowance.funds_cover_remaining === false ? allowance.funds_cover_remaining : null,
1290
1494
  remainingDisplay: formatRemainingDisplay(allowance.token_address, allowance.token_symbol, allowance.onchain.remaining),
1291
1495
  onchain: {
1292
1496
  amount: allowance.onchain.amount,
@@ -1335,7 +1539,7 @@ var AccountReads = class {
1335
1539
  payment: payment2,
1336
1540
  allowance: null,
1337
1541
  warnings: [{
1338
- code: chunkHX34HOW4_cjs.AgentPaymentWarningCode.AllowanceCheckUnavailable,
1542
+ code: chunkH37YVYZA_cjs.AgentPaymentWarningCode.AllowanceCheckUnavailable,
1339
1543
  message: `Could not read the post-purchase allowance/budget for payment ${paymentId} (${detail}). The payment itself succeeded \u2014 the on-chain policy remains the actual spend gate; this only affects the remaining-budget figure reported here.`
1340
1544
  }]
1341
1545
  });
@@ -1361,12 +1565,12 @@ var AccountReads = class {
1361
1565
  (allowance) => allowance.tokenAddress.toLowerCase() === tokenAddress.toLowerCase()
1362
1566
  );
1363
1567
  const payingHash = payment.budgetDelegationHash ?? null;
1364
- const match2 = payingHash ? tokenRows.find((allowance) => allowance.delegationHash === payingHash) ?? null : tokenRows[0] ?? null;
1365
- if (!match2 && payingHash) {
1568
+ const match = payingHash ? tokenRows.find((allowance) => allowance.delegationHash === payingHash) ?? null : tokenRows[0] ?? null;
1569
+ if (!match && payingHash) {
1366
1570
  return unavailable("the budget that paid is not one of this agent's own budgets", payment);
1367
1571
  }
1368
- if (!match2) return unavailable("no allowance/budget row matches the settled token", payment);
1369
- const remainingDisplay = formatRemainingDisplay(match2.tokenAddress, match2.tokenSymbol, match2.onchain.remaining);
1572
+ if (!match) return unavailable("no allowance/budget row matches the settled token", payment);
1573
+ const remainingDisplay = formatRemainingDisplay(match.tokenAddress, match.tokenSymbol, match.onchain.remaining);
1370
1574
  const rail = agentResult.value.executionRail;
1371
1575
  if (rail !== "delegation") {
1372
1576
  return unavailable(`the account's rail ('${rail}') cannot have a settled x402 payment`, payment);
@@ -1375,21 +1579,21 @@ var AccountReads = class {
1375
1579
  payment,
1376
1580
  allowance: {
1377
1581
  rail,
1378
- remaining_atomic: match2.onchain.remaining,
1582
+ remaining_atomic: match.onchain.remaining,
1379
1583
  // Deprecated spellings (#3464): kept for the deprecation window;
1380
1584
  // removal condition on the type's JSDoc.
1381
1585
  remaining_display: remainingDisplay,
1382
- token_symbol: match2.tokenSymbol,
1383
- token_address: match2.tokenAddress,
1384
- reset_period: match2.resetPeriodMin,
1586
+ token_symbol: match.tokenSymbol,
1587
+ token_address: match.tokenAddress,
1588
+ reset_period: match.resetPeriodMin,
1385
1589
  source: "active_delegations",
1386
1590
  // The canonical spellings — the SAME names and values
1387
1591
  // `haven_get_agent`'s allowances[] rows report.
1388
- remainingAtomic: match2.onchain.remaining,
1592
+ remainingAtomic: match.onchain.remaining,
1389
1593
  remainingDisplay,
1390
- resetPeriodMin: match2.resetPeriodMin,
1391
- tokenSymbol: match2.tokenSymbol,
1392
- tokenAddress: match2.tokenAddress
1594
+ resetPeriodMin: match.resetPeriodMin,
1595
+ tokenSymbol: match.tokenSymbol,
1596
+ tokenAddress: match.tokenAddress
1393
1597
  },
1394
1598
  warnings: []
1395
1599
  };
@@ -1420,9 +1624,15 @@ var AccountReads = class {
1420
1624
  nextCursor: typeof raw.next_cursor === "string" ? raw.next_cursor : null
1421
1625
  };
1422
1626
  }
1627
+ /**
1628
+ * #3723: the re-wrap is deliberate — this is the endpoint's own
1629
+ * `{ receipt, verification }` shape, and `verifyPaymentReceipt` accepts the
1630
+ * whole object or `.receipt` alone. The local `verification` is Haven's
1631
+ * self-check, not offline evidence.
1632
+ */
1423
1633
  async getReceipt(paymentId) {
1424
1634
  const { receipt } = await this.transport.get(`/payments/${paymentId}/receipt`);
1425
- return { receipt, verification: verifyPaymentReceipt(receipt) };
1635
+ return { receipt, verification: chunk6LEXYQ7J_cjs.verifyPaymentReceipt(receipt) };
1426
1636
  }
1427
1637
  async fetchAgent() {
1428
1638
  const raw = await this.transport.get("/machine-payments/agent");
@@ -1436,7 +1646,8 @@ var AccountReads = class {
1436
1646
  accountAddress: raw.account_address,
1437
1647
  delegateAddress: raw.delegate_address,
1438
1648
  chainId: raw.chain_id,
1439
- executionRail: raw.execution_rail === "delegation" ? "delegation" : "legacy"
1649
+ executionRail: raw.execution_rail === "delegation" ? "delegation" : "legacy",
1650
+ supersededBy: mapSupersession(raw.superseded_by)
1440
1651
  };
1441
1652
  }
1442
1653
  };
@@ -1457,7 +1668,7 @@ function isWaitTimeout(err) {
1457
1668
  async function waitForSweepTx(tx) {
1458
1669
  let receipt;
1459
1670
  try {
1460
- receipt = await tx.wait(1, chunkHX34HOW4_cjs.DEFAULT_CONFIRMATION_TIMEOUT_MS);
1671
+ receipt = await tx.wait(1, chunkH37YVYZA_cjs.DEFAULT_CONFIRMATION_TIMEOUT_MS);
1461
1672
  } catch (err) {
1462
1673
  if (!isWaitTimeout(err)) throw err;
1463
1674
  return { txHash: tx.hash, confirmation: "unconfirmed" };
@@ -1471,16 +1682,16 @@ var DelegateSweepApi = class {
1471
1682
  }
1472
1683
  options;
1473
1684
  async sweepDelegate() {
1474
- if (!this.options.delegateKey) throw new chunkHX34HOW4_cjs.HavenSigningError("delegateKey is required for sweepDelegate.");
1685
+ if (!this.options.delegateKey) throw new chunkH37YVYZA_cjs.HavenSigningError("delegateKey is required for sweepDelegate.");
1475
1686
  const agent = await this.options.getAgent();
1476
- if (!agent.delegateAddress) throw new chunkHX34HOW4_cjs.HavenApiError("Agent has no delegate address.", 422);
1687
+ if (!agent.delegateAddress) throw new chunkH37YVYZA_cjs.HavenApiError("Agent has no delegate address.", 422);
1477
1688
  const rpcUrl = this.options.chainRpcs[agent.chainId];
1478
- if (!rpcUrl) throw new chunkHX34HOW4_cjs.HavenApiError(`chainRpcs[${agent.chainId}] must be configured to sweep the delegate wallet.`, 422);
1689
+ if (!rpcUrl) throw new chunkH37YVYZA_cjs.HavenApiError(`chainRpcs[${agent.chainId}] must be configured to sweep the delegate wallet.`, 422);
1479
1690
  const provider = createJsonRpcProvider(rpcUrl);
1480
1691
  const wallet = createWallet(this.options.delegateKey, provider);
1481
1692
  const transfers = [];
1482
- if (chunkHFOAYTD4_cjs.isSweepableChain(agent.chainId)) {
1483
- const contract = createErc20Contract(chunkHFOAYTD4_cjs.sweepUsdcAddress(agent.chainId), ["function balanceOf(address) view returns (uint256)", "function transfer(address to, uint256 amount) returns (bool)"], wallet);
1693
+ if (chunk22FJ4JQO_cjs.isSweepableChain(agent.chainId)) {
1694
+ const contract = createErc20Contract(chunk22FJ4JQO_cjs.sweepUsdcAddress(agent.chainId), ["function balanceOf(address) view returns (uint256)", "function transfer(address to, uint256 amount) returns (bool)"], wallet);
1484
1695
  const balance2 = await contract.balanceOf(agent.delegateAddress);
1485
1696
  if (balance2 > 0n) {
1486
1697
  const tx = await contract.transfer(agent.accountAddress, balance2);
@@ -1568,7 +1779,7 @@ function snapshotRequestBody(body) {
1568
1779
  if (body == null) return void 0;
1569
1780
  if (typeof body === "string") return body;
1570
1781
  if (body instanceof URLSearchParams) return body.toString();
1571
- throw new chunkHX34HOW4_cjs.HavenApiError(
1782
+ throw new chunkH37YVYZA_cjs.HavenApiError(
1572
1783
  "Quote helpers can only capture resumable request bodies that are strings or URLSearchParams. For streams, blobs, or binary bodies, preserve the original request yourself and call the matching resume method with fresh init.",
1573
1784
  400
1574
1785
  );
@@ -1589,25 +1800,39 @@ function requestInitFromSnapshot(request) {
1589
1800
  };
1590
1801
  }
1591
1802
  function noCompatiblePaymentOptionError(accepts) {
1592
- const erc7710Only = chunkHFOAYTD4_cjs.selectErc7710PaymentOption(accepts) !== null;
1803
+ const erc7710Only = chunk22FJ4JQO_cjs.selectErc7710PaymentOption(accepts) !== null;
1593
1804
  const unsupportedOnly = !erc7710Only && accepts.some(
1594
- (opt) => opt !== null && typeof opt === "object" && !chunkHFOAYTD4_cjs.isErc7710Option(opt) && (chunkHFOAYTD4_cjs.x402AssetTransferMethod(opt) !== null || opt.extra?.paymentFlow !== void 0)
1805
+ (opt) => opt !== null && typeof opt === "object" && !chunk22FJ4JQO_cjs.isErc7710Option(opt) && (chunk22FJ4JQO_cjs.x402AssetTransferMethod(opt) !== null || opt.extra?.paymentFlow !== void 0)
1595
1806
  );
1596
- return new chunkHX34HOW4_cjs.HavenApiError(
1597
- "No compatible payment option found in x402 requirements. Haven supports standard x402 exact payments on Base USDC." + (erc7710Only ? " The only Haven-compatible option this merchant advertises is tagged extra.assetTransferMethod: 'erc7710' (direct settlement), which this EIP-3009 payment path cannot settle \u2014 the limitation is the settlement scheme, not the asset. Paying this merchant requires a delegation-rail erc7710 flow (settleX402Erc7710, or the hosted MCP purchase tools)." : unsupportedOnly ? " Every option this merchant advertises asks for a transfer method or payment flow Haven cannot construct (for example extra.assetTransferMethod: 'permit2', or an unrecognized extra.paymentFlow). No payment intent was created and no funds moved." : ""),
1807
+ const offeredSchemes = nonExactSchemesOnly(accepts);
1808
+ return new chunkH37YVYZA_cjs.HavenApiError(
1809
+ "No compatible payment option found in x402 requirements. Haven supports standard x402 exact payments on Base USDC." + (offeredSchemes ? ` The merchant offered only ${offeredSchemes}; Haven pays only the 'exact' scheme. For a request with a body, this often means the body or its Content-Type was missing or invalid: send the full request again (method, body, and Content-Type: application/json for a JSON API).` : erc7710Only ? " The only Haven-compatible option this merchant advertises is tagged extra.assetTransferMethod: 'erc7710' (direct settlement), which this EIP-3009 payment path cannot settle \u2014 the limitation is the settlement scheme, not the asset. Paying this merchant requires a delegation-rail erc7710 flow (settleX402Erc7710, or the hosted MCP purchase tools)." : unsupportedOnly ? " Every option this merchant advertises asks for a transfer method or payment flow Haven cannot construct (for example extra.assetTransferMethod: 'permit2', or an unrecognized extra.paymentFlow). No payment intent was created and no funds moved." : ""),
1598
1810
  400
1599
1811
  );
1600
1812
  }
1813
+ var SCHEME_ECHO_RE = /^[A-Za-z0-9_-]{1,32}$/;
1814
+ function nonExactSchemesOnly(accepts) {
1815
+ if (!Array.isArray(accepts) || accepts.length === 0) return null;
1816
+ const schemes = [];
1817
+ for (const opt of accepts) {
1818
+ if (opt === null || typeof opt !== "object") return null;
1819
+ const scheme = opt.scheme;
1820
+ if (typeof scheme !== "string" || scheme === "exact") return null;
1821
+ if (!SCHEME_ECHO_RE.test(scheme)) return null;
1822
+ if (!schemes.includes(scheme)) schemes.push(scheme);
1823
+ }
1824
+ return schemes.map((s) => `'${s}'`).join(", ");
1825
+ }
1601
1826
  function buildX402Quote(paymentRequired, request, idempotencyKey, mcpTransport) {
1602
- const standard = chunkHFOAYTD4_cjs.selectStandardPaymentOption(paymentRequired.accepts);
1603
- const option = standard ?? chunkHFOAYTD4_cjs.selectErc7710PaymentOption(paymentRequired.accepts);
1827
+ const standard = chunk22FJ4JQO_cjs.selectStandardPaymentOption(paymentRequired.accepts);
1828
+ const option = standard ?? chunk22FJ4JQO_cjs.selectErc7710PaymentOption(paymentRequired.accepts);
1604
1829
  if (!option) {
1605
1830
  throw noCompatiblePaymentOptionError(paymentRequired.accepts);
1606
1831
  }
1607
- const token = chunkHFOAYTD4_cjs.resolveTokenFromAddress(option.asset, option.network);
1832
+ const token = chunk22FJ4JQO_cjs.resolveTokenFromAddress(option.asset, option.network);
1608
1833
  return {
1609
1834
  rail: "x402",
1610
- idempotencyKey: idempotencyKey ?? chunkHFOAYTD4_cjs.buildX402IdempotencyKey(paymentRequired, option),
1835
+ idempotencyKey: idempotencyKey ?? chunk22FJ4JQO_cjs.buildX402IdempotencyKey(paymentRequired, option),
1611
1836
  paymentRequired,
1612
1837
  accepted: option,
1613
1838
  acceptedScheme: standard ? "standard" : "erc7710",
@@ -1621,8 +1846,8 @@ function buildX402Quote(paymentRequired, request, idempotencyKey, mcpTransport)
1621
1846
  resourceUrlDiffersFromRequest: paymentRequired.resource.url !== request.url,
1622
1847
  description: paymentRequired.resource.description ?? option.description ?? null,
1623
1848
  mimeType: paymentRequired.resource.mimeType ?? option.mimeType ?? null,
1624
- amountAtomic: chunkHFOAYTD4_cjs.x402AuthorizationAmount(option),
1625
- amount: decimalFromUsdcAtomic(chunkHFOAYTD4_cjs.x402AuthorizationAmount(option)),
1849
+ amountAtomic: chunk22FJ4JQO_cjs.x402AuthorizationAmount(option),
1850
+ amount: decimalFromUsdcAtomic(chunk22FJ4JQO_cjs.x402AuthorizationAmount(option)),
1626
1851
  token: token?.symbol ?? "USDC",
1627
1852
  // #1351: null when the asset is unrecognised on this network — the
1628
1853
  // `token` fallback above is a LABEL, not evidence of 6 decimals, and a
@@ -1661,7 +1886,7 @@ function buildX402Receipt(input) {
1661
1886
  payTo: input.merchantTo ?? input.accepted.payTo
1662
1887
  },
1663
1888
  x402: {
1664
- amount: chunkHFOAYTD4_cjs.x402AuthorizationAmount(input.accepted),
1889
+ amount: chunk22FJ4JQO_cjs.x402AuthorizationAmount(input.accepted),
1665
1890
  token: input.token,
1666
1891
  network: input.accepted.network,
1667
1892
  asset: input.accepted.asset,
@@ -1670,7 +1895,7 @@ function buildX402Receipt(input) {
1670
1895
  };
1671
1896
  }
1672
1897
  function buildX402ResumeState(input) {
1673
- const token = chunkHFOAYTD4_cjs.resolveTokenFromAddress(input.accepted.asset, input.accepted.network);
1898
+ const token = chunk22FJ4JQO_cjs.resolveTokenFromAddress(input.accepted.asset, input.accepted.network);
1674
1899
  return {
1675
1900
  rail: "x402",
1676
1901
  paymentId: input.paymentId,
@@ -1681,8 +1906,8 @@ function buildX402ResumeState(input) {
1681
1906
  request: input.request,
1682
1907
  resourceUrl: input.paymentRequired.resource.url,
1683
1908
  description: input.paymentRequired.resource.description ?? input.accepted.description ?? null,
1684
- amountAtomic: chunkHFOAYTD4_cjs.x402AuthorizationAmount(input.accepted),
1685
- amount: decimalFromUsdcAtomic(chunkHFOAYTD4_cjs.x402AuthorizationAmount(input.accepted)),
1909
+ amountAtomic: chunk22FJ4JQO_cjs.x402AuthorizationAmount(input.accepted),
1910
+ amount: decimalFromUsdcAtomic(chunk22FJ4JQO_cjs.x402AuthorizationAmount(input.accepted)),
1686
1911
  token: token?.symbol ?? "USDC",
1687
1912
  asset: input.accepted.asset,
1688
1913
  network: input.accepted.network,
@@ -1691,7 +1916,7 @@ function buildX402ResumeState(input) {
1691
1916
  };
1692
1917
  }
1693
1918
  function attachX402ResumeState(err, paymentRequired, accepted, idempotencyKey, request) {
1694
- if (!(err instanceof chunkHX34HOW4_cjs.HavenPaymentStateError)) return;
1919
+ if (!(err instanceof chunkH37YVYZA_cjs.HavenPaymentStateError)) return;
1695
1920
  if (err.state.rail !== "x402") return;
1696
1921
  err.resumeState = buildX402ResumeState({
1697
1922
  paymentId: err.state.paymentId,
@@ -1712,17 +1937,17 @@ function attachResumeState(err, input) {
1712
1937
  }
1713
1938
  function assertCanResumeX402(status, paymentRequired, option) {
1714
1939
  if (status.rail !== "x402") {
1715
- throw new chunkHX34HOW4_cjs.HavenPaymentStateError(
1940
+ throw new chunkH37YVYZA_cjs.HavenPaymentStateError(
1716
1941
  `Payment ${status.paymentId} is ${status.rail}, not x402.`,
1717
1942
  409,
1718
1943
  status
1719
1944
  );
1720
1945
  }
1721
- if (status.nextAction !== chunkHX34HOW4_cjs.AgentPaymentNextAction.RetryOriginalX402Request) {
1722
- throw new chunkHX34HOW4_cjs.HavenPaymentStateError(status.message, paymentStateStatusCode(status.status, 409), status);
1946
+ if (status.nextAction !== chunkH37YVYZA_cjs.AgentPaymentNextAction.RetryOriginalX402Request) {
1947
+ throw new chunkH37YVYZA_cjs.HavenPaymentStateError(status.message, paymentStateStatusCode(status.status, 409), status);
1723
1948
  }
1724
1949
  if (!status.txHash) {
1725
- throw new chunkHX34HOW4_cjs.HavenApiError(
1950
+ throw new chunkH37YVYZA_cjs.HavenApiError(
1726
1951
  `x402 payment ${status.paymentId} is ready to retry but has no Haven transaction hash.`,
1727
1952
  502,
1728
1953
  status,
@@ -1730,7 +1955,7 @@ function assertCanResumeX402(status, paymentRequired, option) {
1730
1955
  );
1731
1956
  }
1732
1957
  if (status.resourceUrl && status.resourceUrl !== paymentRequired.resource.url) {
1733
- throw new chunkHX34HOW4_cjs.HavenApiError(
1958
+ throw new chunkH37YVYZA_cjs.HavenApiError(
1734
1959
  "x402 resume request does not match the approved resource URL.",
1735
1960
  409,
1736
1961
  { status, paymentRequired },
@@ -1738,7 +1963,7 @@ function assertCanResumeX402(status, paymentRequired, option) {
1738
1963
  );
1739
1964
  }
1740
1965
  if (status.merchantAddress && !sameAddress(status.merchantAddress, option.payTo)) {
1741
- throw new chunkHX34HOW4_cjs.HavenApiError(
1966
+ throw new chunkH37YVYZA_cjs.HavenApiError(
1742
1967
  "x402 resume request does not match the approved merchant.",
1743
1968
  409,
1744
1969
  { status, selectedPayment: option },
@@ -1747,7 +1972,7 @@ function assertCanResumeX402(status, paymentRequired, option) {
1747
1972
  }
1748
1973
  const optionChainId = chainIdFromNetwork(option.network);
1749
1974
  if (status.chainId && optionChainId && status.chainId !== optionChainId) {
1750
- throw new chunkHX34HOW4_cjs.HavenApiError(
1975
+ throw new chunkH37YVYZA_cjs.HavenApiError(
1751
1976
  "x402 resume request does not match the approved network.",
1752
1977
  409,
1753
1978
  { status, selectedPayment: option },
@@ -1755,7 +1980,7 @@ function assertCanResumeX402(status, paymentRequired, option) {
1755
1980
  );
1756
1981
  }
1757
1982
  if (status.token && status.token !== "USDC") {
1758
- throw new chunkHX34HOW4_cjs.HavenApiError(
1983
+ throw new chunkH37YVYZA_cjs.HavenApiError(
1759
1984
  "x402 resume request does not match the approved token.",
1760
1985
  409,
1761
1986
  { status, selectedPayment: option },
@@ -1763,9 +1988,9 @@ function assertCanResumeX402(status, paymentRequired, option) {
1763
1988
  );
1764
1989
  }
1765
1990
  const approvedAmount = status.amount ? normalizeDecimal(status.amount) : "";
1766
- const requestedAmount = normalizeDecimal(decimalFromUsdcAtomic(chunkHFOAYTD4_cjs.x402AuthorizationAmount(option)));
1991
+ const requestedAmount = normalizeDecimal(decimalFromUsdcAtomic(chunk22FJ4JQO_cjs.x402AuthorizationAmount(option)));
1767
1992
  if (approvedAmount && approvedAmount !== requestedAmount) {
1768
- throw new chunkHX34HOW4_cjs.HavenApiError(
1993
+ throw new chunkH37YVYZA_cjs.HavenApiError(
1769
1994
  "x402 resume request does not match the approved amount.",
1770
1995
  409,
1771
1996
  { status, selectedPayment: option },
@@ -1821,7 +2046,7 @@ var X402FundingLeg = class {
1821
2046
  const cached = this.receiptCache.get(idempotencyKey);
1822
2047
  if (!cached || cached.expiresAt <= Date.now()) return void 0;
1823
2048
  if (!sameX402TaskBudget(cached.taskBudgetId, taskBudgetId) || !sameX402TaskBudget(cached.subBudgetId, subBudgetId)) {
1824
- throw new chunkHX34HOW4_cjs.X402TaskBudgetMismatchError(
2049
+ throw new chunkH37YVYZA_cjs.X402TaskBudgetMismatchError(
1825
2050
  `The x402 idempotency key '${idempotencyKey}' was already used under a different authorizing budget (task '${cached.taskBudgetId ?? "none"}' vs '${taskBudgetId ?? "none"}', sub '${cached.subBudgetId ?? "none"}' vs '${subBudgetId ?? "none"}'). Pass a new idempotencyKey to pay under this budget.`,
1826
2051
  idempotencyKey,
1827
2052
  cached.taskBudgetId,
@@ -1842,7 +2067,7 @@ var X402FundingLeg = class {
1842
2067
  url: paymentRequired.resource.url,
1843
2068
  payTo: this.delegateAddress,
1844
2069
  merchantPayTo: option.payTo,
1845
- amount: chunkHFOAYTD4_cjs.x402AuthorizationAmount(option),
2070
+ amount: chunk22FJ4JQO_cjs.x402AuthorizationAmount(option),
1846
2071
  asset: option.asset,
1847
2072
  network: option.network,
1848
2073
  description: paymentRequired.resource.description,
@@ -1861,41 +2086,41 @@ var X402FundingLeg = class {
1861
2086
  ...subBudgetId ? { subBudgetId } : {}
1862
2087
  });
1863
2088
  const state = paymentStateFromRaw("x402 payment", raw);
1864
- const executedReplay = raw.success && raw.tx_hash ? "idempotency-collision" : state?.nextAction === chunkHX34HOW4_cjs.AgentPaymentNextAction.RetryOriginalX402Request ? "approval-resume" : null;
2089
+ const executedReplay = raw.success && raw.tx_hash ? "idempotency-collision" : state?.nextAction === chunkH37YVYZA_cjs.AgentPaymentNextAction.RetryOriginalX402Request ? "approval-resume" : null;
1865
2090
  if (executedReplay) {
1866
2091
  const canFund = await this.delegateCanFund(
1867
2092
  raw.chain_id ?? state?.chainId ?? chainIdFromNetwork(option.network),
1868
2093
  option.asset,
1869
- chunkHFOAYTD4_cjs.x402AuthorizationAmount(option)
2094
+ chunk22FJ4JQO_cjs.x402AuthorizationAmount(option)
1870
2095
  );
1871
2096
  const refuse = executedReplay === "idempotency-collision" ? canFund !== true : canFund === false;
1872
2097
  if (refuse) {
1873
2098
  const settledReceipt = state && executedReplay === "approval-resume" ? this.receiptFromStatus(paymentRequired, option, void 0, state) : this.receiptFromAuthorization(paymentRequired, option, void 0, raw);
1874
- throw new chunkHX34HOW4_cjs.X402AlreadySettledError(
2099
+ throw new chunkH37YVYZA_cjs.X402AlreadySettledError(
1875
2100
  canFund === false ? "This x402 payment already settled \u2014 the delegate no longer holds the funds to authorize it again. To buy the same item a second time, pass a distinct `idempotencyKey`; the synthesised key intentionally collapses repeat calls for the same product within a 5-minute window so a retried request cannot pay twice." : "This x402 payment already settled, and whether the delegate can still fund a new authorization could not be verified (no `chainRpcs` entry for this chain). Refusing rather than issue an authorization that may be unfundable. To buy the same item a second time, pass a distinct `idempotencyKey`; to finish an interrupted payment, resume it by `paymentId`.",
1876
2101
  settledReceipt,
1877
2102
  canFund === false ? "settled" : "unverifiable"
1878
2103
  );
1879
2104
  }
1880
2105
  }
1881
- const paymentHeader = await this.createPaymentHeader(paymentRequired, option);
2106
+ const paymentHeader = await this.createPaymentHeader(paymentRequired, option, raw.payment_id ?? state?.paymentId);
1882
2107
  if (raw.success && raw.tx_hash) {
1883
2108
  const receipt2 = this.receiptFromAuthorization(paymentRequired, option, paymentHeader, raw);
1884
2109
  this.cacheReceipt(idempotencyKey, paymentHeader, receipt2, taskBudgetId, subBudgetId);
1885
2110
  return receipt2;
1886
2111
  }
1887
- if (state?.nextAction === chunkHX34HOW4_cjs.AgentPaymentNextAction.RetryOriginalX402Request) {
2112
+ if (state?.nextAction === chunkH37YVYZA_cjs.AgentPaymentNextAction.RetryOriginalX402Request) {
1888
2113
  const receipt2 = this.receiptFromStatus(paymentRequired, option, paymentHeader, state);
1889
2114
  this.cacheReceipt(idempotencyKey, paymentHeader, receipt2, taskBudgetId, subBudgetId);
1890
2115
  return receipt2;
1891
2116
  }
1892
2117
  this.assertSignableAuthorizationState("x402 payment", raw);
1893
2118
  if (!raw.sign_data?.hash) {
1894
- throw new chunkHX34HOW4_cjs.HavenApiError("No sign_hash returned from x402/authorize", 500, raw);
2119
+ throw new chunkH37YVYZA_cjs.HavenApiError("No sign_hash returned from x402/authorize", 500, raw);
1895
2120
  }
1896
2121
  const sig = await this.signForData(raw.sign_data, {
1897
2122
  asset: option.asset,
1898
- amount: chunkHFOAYTD4_cjs.x402AuthorizationAmount(option)
2123
+ amount: chunk22FJ4JQO_cjs.x402AuthorizationAmount(option)
1899
2124
  });
1900
2125
  const execResult = await this.post(
1901
2126
  `/payments/${raw.payment_id}/sign`,
@@ -1913,27 +2138,54 @@ var X402FundingLeg = class {
1913
2138
  return receipt;
1914
2139
  }
1915
2140
  // ── Header minting ───────────────────────────────────────────────
1916
- async createPaymentHeader(paymentRequired, option) {
2141
+ /**
2142
+ * Mint the merchant-facing X-PAYMENT header with the delegate key.
2143
+ *
2144
+ * #3888: when `paymentId` is given, the EIP-3009 nonce is the shared
2145
+ * derivation from that Haven payment id instead of the x402 library's
2146
+ * random draw — that is what lets the backend attribute the merchant's
2147
+ * `AuthorizationUsed(delegate, nonce)` settlement to this payment when the
2148
+ * agent never reports it, and what makes a resume/retry re-sign of a
2149
+ * settled payment carry the SAME nonce (the merchant refuses it as already
2150
+ * used, closing the #3475 re-pay hazard). The signed typed data stays the
2151
+ * library's own: the nonce only overwrites the field on the unsigned
2152
+ * payload `preparePaymentHeader` built. Without a payment id the library's
2153
+ * random nonce is kept — an install too old to name its payment behaves
2154
+ * exactly as before.
2155
+ */
2156
+ async createPaymentHeader(paymentRequired, option, paymentId) {
1917
2157
  if (!this.delegateKey) {
1918
- throw new chunkHX34HOW4_cjs.HavenSigningError("delegateKey is required to sign x402 payment headers.");
2158
+ throw new chunkH37YVYZA_cjs.HavenSigningError("delegateKey is required to sign x402 payment headers.");
1919
2159
  }
1920
2160
  const account = accounts.privateKeyToAccount(this.delegateKey);
1921
- const requirements = chunkHFOAYTD4_cjs.toStandardPaymentRequirements(paymentRequired, option);
1922
- const header = await schemes.exact.evm.createPaymentHeader(
1923
- account,
1924
- paymentRequired.x402Version,
1925
- requirements
1926
- );
2161
+ const requirements = chunk22FJ4JQO_cjs.toStandardPaymentRequirements(paymentRequired, option);
2162
+ let header;
2163
+ if (paymentId) {
2164
+ const unsigned = schemes.exact.evm.preparePaymentHeader(
2165
+ account.address,
2166
+ paymentRequired.x402Version,
2167
+ requirements
2168
+ );
2169
+ unsigned.payload.authorization.nonce = chunk22FJ4JQO_cjs.deriveX402PaymentNonce(paymentId);
2170
+ const signed = await schemes.exact.evm.signPaymentHeader(account, requirements, unsigned);
2171
+ header = schemes.exact.evm.encodePayment(signed);
2172
+ } else {
2173
+ header = await schemes.exact.evm.createPaymentHeader(
2174
+ account,
2175
+ paymentRequired.x402Version,
2176
+ requirements
2177
+ );
2178
+ }
1927
2179
  if (paymentRequired.x402Version < 2) return header;
1928
- const payment = chunkHFOAYTD4_cjs.decodeBase64Json(header);
1929
- return chunkHFOAYTD4_cjs.encodeBase64Json(chunkHFOAYTD4_cjs.x402V2PaymentEnvelope(paymentRequired, option, payment.payload));
2180
+ const payment = chunk22FJ4JQO_cjs.decodeBase64Json(header);
2181
+ return chunk22FJ4JQO_cjs.encodeBase64Json(chunk22FJ4JQO_cjs.x402V2PaymentEnvelope(paymentRequired, option, payment.payload));
1930
2182
  }
1931
2183
  // ── Receipt mapping ──────────────────────────────────────────────
1932
2184
  receiptFromAuthorization(paymentRequired, option, paymentHeader, raw, execResult) {
1933
2185
  const txHash = execResult?.tx_hash ?? raw.tx_hash ?? "";
1934
2186
  const chainId = execResult?.chain_id ?? raw.chain_id ?? chainIdFromNetwork(option.network);
1935
2187
  const token = execResult?.token ?? raw.token ?? "USDC";
1936
- const amount = execResult?.amount ?? raw.amount ?? decimalFromUsdcAtomic(chunkHFOAYTD4_cjs.x402AuthorizationAmount(option));
2188
+ const amount = execResult?.amount ?? raw.amount ?? decimalFromUsdcAtomic(chunk22FJ4JQO_cjs.x402AuthorizationAmount(option));
1937
2189
  const to = execResult?.to ?? raw.to ?? this.delegateAddress ?? "";
1938
2190
  const explorerUrl = execResult?.explorer_url ?? raw.explorer_url ?? explorerUrlOrEmpty(chainId, txHash);
1939
2191
  const merchantTo = execResult?.merchant_to ?? raw.merchant_to ?? option.payTo;
@@ -1955,7 +2207,7 @@ var X402FundingLeg = class {
1955
2207
  }
1956
2208
  receiptFromStatus(paymentRequired, option, paymentHeader, status) {
1957
2209
  if (!status.txHash) {
1958
- throw new chunkHX34HOW4_cjs.HavenApiError(
2210
+ throw new chunkH37YVYZA_cjs.HavenApiError(
1959
2211
  `x402 payment ${status.paymentId} is ready to retry but has no Haven transaction hash.`,
1960
2212
  502,
1961
2213
  status,
@@ -1966,7 +2218,7 @@ var X402FundingLeg = class {
1966
2218
  paymentId: status.paymentId,
1967
2219
  txHash: status.txHash,
1968
2220
  token: status.token || "USDC",
1969
- amount: status.amount || decimalFromUsdcAtomic(chunkHFOAYTD4_cjs.x402AuthorizationAmount(option)),
2221
+ amount: status.amount || decimalFromUsdcAtomic(chunk22FJ4JQO_cjs.x402AuthorizationAmount(option)),
1970
2222
  to: this.delegateAddress ?? "",
1971
2223
  resourceUrl: paymentRequired.resource.url,
1972
2224
  explorerUrl: explorerUrlOrEmpty(status.chainId, status.txHash),
@@ -1994,7 +2246,7 @@ var X402FundingLeg = class {
1994
2246
  const provider = createJsonRpcProvider(rpcUrl);
1995
2247
  const onChainReceipt = await provider.waitForTransaction(txHash, 1, timeoutMs);
1996
2248
  if (!onChainReceipt || onChainReceipt.status !== 1) {
1997
- throw new chunkHX34HOW4_cjs.HavenApiError(
2249
+ throw new chunkH37YVYZA_cjs.HavenApiError(
1998
2250
  "Funding tx did not confirm on-chain within the timeout window.",
1999
2251
  500,
2000
2252
  { txHash, chainId }
@@ -2043,7 +2295,7 @@ var X402FundingLeg = class {
2043
2295
  };
2044
2296
  function getPaymentHeaderValidBefore(paymentHeader) {
2045
2297
  try {
2046
- const payment = chunkHFOAYTD4_cjs.decodeBase64Json(
2298
+ const payment = chunk22FJ4JQO_cjs.decodeBase64Json(
2047
2299
  paymentHeader
2048
2300
  );
2049
2301
  const payload = payment.payload;
@@ -2098,7 +2350,7 @@ var X402Erc7710 = class {
2098
2350
  */
2099
2351
  async settle(paymentRequired, options = {}) {
2100
2352
  if (!this.delegateKey) {
2101
- throw new chunkHX34HOW4_cjs.HavenSigningError(
2353
+ throw new chunkH37YVYZA_cjs.HavenSigningError(
2102
2354
  "delegateKey is required for x402 payments. Pass it in the HavenClient config."
2103
2355
  );
2104
2356
  }
@@ -2123,21 +2375,21 @@ var X402Erc7710 = class {
2123
2375
  async prepare(paymentRequired, options = {}) {
2124
2376
  const delegationRail = options.delegationRail ?? (await this.getAgent()).executionRail === "delegation";
2125
2377
  if (!delegationRail) {
2126
- throw new chunkHX34HOW4_cjs.HavenApiError(
2378
+ throw new chunkH37YVYZA_cjs.HavenApiError(
2127
2379
  "erc7710 settlement requires a delegation-rail account; this one is not on it. Use authorizeX402() for the standard EIP-3009 path.",
2128
2380
  400
2129
2381
  );
2130
2382
  }
2131
- const selection = chunkHFOAYTD4_cjs.selectX402SettlementScheme(paymentRequired.accepts, { delegationRail });
2383
+ const selection = chunk22FJ4JQO_cjs.selectX402SettlementScheme(paymentRequired.accepts, { delegationRail });
2132
2384
  if (!selection || selection.scheme !== "erc7710") {
2133
- throw new chunkHX34HOW4_cjs.HavenApiError(
2385
+ throw new chunkH37YVYZA_cjs.HavenApiError(
2134
2386
  "This merchant does not advertise an erc7710 settlement option (no accepts[] entry carries extra.assetTransferMethod: 'erc7710'). Use authorizeX402() for the standard EIP-3009 path.",
2135
2387
  400
2136
2388
  );
2137
2389
  }
2138
2390
  const option = selection.option;
2139
2391
  const merchantPayTo = option.payTo;
2140
- const amountAtomic = chunkHFOAYTD4_cjs.x402AuthorizationAmount(option);
2392
+ const amountAtomic = chunk22FJ4JQO_cjs.x402AuthorizationAmount(option);
2141
2393
  const raw = await this.post("/x402", {
2142
2394
  url: options.resourceUrl ?? paymentRequired.resource?.url,
2143
2395
  // #2373: the full 402 challenge, persisted verbatim by the backend
@@ -2181,24 +2433,24 @@ var X402Erc7710 = class {
2181
2433
  ...options.subBudgetId ? { subBudgetId: options.subBudgetId } : {}
2182
2434
  });
2183
2435
  if (!raw.payment_id) {
2184
- throw new chunkHX34HOW4_cjs.HavenApiError("No payment_id returned from x402/authorize", 500, raw);
2436
+ throw new chunkH37YVYZA_cjs.HavenApiError("No payment_id returned from x402/authorize", 500, raw);
2185
2437
  }
2186
2438
  if (raw.status === "confirmed" && raw.tx_hash) {
2187
2439
  const requestedUrl = options.resourceUrl ?? paymentRequired.resource?.url;
2188
2440
  const samePurchase = typeof raw.to === "string" && raw.to.toLowerCase() === merchantPayTo.toLowerCase() && raw.resource_url === requestedUrl;
2189
2441
  if (!samePurchase) {
2190
- throw new chunkHX34HOW4_cjs.HavenApiError(
2442
+ throw new chunkH37YVYZA_cjs.HavenApiError(
2191
2443
  `Idempotency key already belongs to confirmed payment ${raw.payment_id}, which is not this erc7710 purchase (different payee or resource). Nothing was signed and nothing was charged. Check that payment's status before buying again: a funded but undelivered EIP-3009 payment is recovered, not paid twice. Otherwise use a new idempotency key for this purchase.`,
2192
2444
  409,
2193
2445
  raw,
2194
2446
  raw.payment_id
2195
2447
  );
2196
2448
  }
2197
- throw new chunkHX34HOW4_cjs.X402Erc7710AlreadySettledError(raw.payment_id, raw.tx_hash, raw);
2449
+ throw new chunkH37YVYZA_cjs.X402Erc7710AlreadySettledError(raw.payment_id, raw.tx_hash, raw);
2198
2450
  }
2199
2451
  const signData = raw.sign_data;
2200
2452
  if (signData?.signature_scheme !== "eip712_delegation" || !signData.typed_data) {
2201
- throw new chunkHX34HOW4_cjs.HavenApiError(
2453
+ throw new chunkH37YVYZA_cjs.HavenApiError(
2202
2454
  `x402/authorize did not return an erc7710 settlement child (signature_scheme was ${JSON.stringify(signData?.signature_scheme)}). Refusing to sign a payload this path did not ask for.`,
2203
2455
  500,
2204
2456
  raw
@@ -2230,9 +2482,9 @@ var X402Erc7710 = class {
2230
2482
  try {
2231
2483
  settled = await this.post(`/x402/${paymentId}/settle`, { signature });
2232
2484
  } catch (err) {
2233
- const body = err instanceof chunkHX34HOW4_cjs.HavenApiError ? err.body : void 0;
2234
- if (err instanceof chunkHX34HOW4_cjs.HavenApiError && err.statusCode === 409 && body?.code === "payment_already_settled" && typeof body.tx_hash === "string") {
2235
- throw new chunkHX34HOW4_cjs.X402Erc7710AlreadySettledError(
2485
+ const body = err instanceof chunkH37YVYZA_cjs.HavenApiError ? err.body : void 0;
2486
+ if (err instanceof chunkH37YVYZA_cjs.HavenApiError && err.statusCode === 409 && body?.code === "payment_already_settled" && typeof body.tx_hash === "string") {
2487
+ throw new chunkH37YVYZA_cjs.X402Erc7710AlreadySettledError(
2236
2488
  typeof body.payment_id === "string" ? body.payment_id : paymentId,
2237
2489
  body.tx_hash,
2238
2490
  body
@@ -2241,7 +2493,7 @@ var X402Erc7710 = class {
2241
2493
  throw err;
2242
2494
  }
2243
2495
  if (!settled.payment_header) {
2244
- throw new chunkHX34HOW4_cjs.HavenApiError(
2496
+ throw new chunkH37YVYZA_cjs.HavenApiError(
2245
2497
  "x402 settle returned no payment_header \u2014 the merchant cannot be retried.",
2246
2498
  500,
2247
2499
  settled
@@ -2251,9 +2503,9 @@ var X402Erc7710 = class {
2251
2503
  }
2252
2504
  };
2253
2505
  function settlementExpectationFromQuote(settlement) {
2254
- const chainId = chunkHX34HOW4_cjs.chainIdForNetwork(settlement.network);
2506
+ const chainId = chunkH37YVYZA_cjs.chainIdForNetwork(settlement.network);
2255
2507
  if (chainId === void 0) {
2256
- throw new chunkHX34HOW4_cjs.HavenSigningError(
2508
+ throw new chunkH37YVYZA_cjs.HavenSigningError(
2257
2509
  `Refusing to sign the x402 settlement child: the merchant's network ${JSON.stringify(settlement.network)} is not one this SDK can verify a settlement child on.`
2258
2510
  );
2259
2511
  }
@@ -2303,7 +2555,7 @@ function x402ToolReceipt(receipt) {
2303
2555
  };
2304
2556
  }
2305
2557
  function toolError(err) {
2306
- if (err instanceof chunkHX34HOW4_cjs.HavenPaymentStateError) {
2558
+ if (err instanceof chunkH37YVYZA_cjs.HavenPaymentStateError) {
2307
2559
  return {
2308
2560
  success: false,
2309
2561
  payment_id: err.state.paymentId,
@@ -2348,7 +2600,7 @@ function toolError(err) {
2348
2600
  error: err.message
2349
2601
  };
2350
2602
  }
2351
- if (err instanceof chunkHX34HOW4_cjs.HavenApiError) {
2603
+ if (err instanceof chunkH37YVYZA_cjs.HavenApiError) {
2352
2604
  return {
2353
2605
  success: false,
2354
2606
  status_code: err.statusCode,
@@ -2366,6 +2618,9 @@ function toolError(err) {
2366
2618
  var MERCHANT_BODY_SNIPPET_LIMIT = 1e3;
2367
2619
  var EVIDENCE_RETRY_DELAYS_MS = [1e3, 2e3, 4e3];
2368
2620
  var EVIDENCE_RETRYABLE_STATUS = 503;
2621
+ function isWellFormedSettlementTxHash(hash) {
2622
+ return typeof hash === "string" && /^0x[0-9a-fA-F]{64}$/.test(hash);
2623
+ }
2369
2624
  var MerchantCompletion = class {
2370
2625
  post;
2371
2626
  merchantTransport;
@@ -2389,14 +2644,14 @@ var MerchantCompletion = class {
2389
2644
  }
2390
2645
  async retryRequest(url, initialInit, paymentRequired, receipt) {
2391
2646
  if (!receipt.accepted) {
2392
- throw new chunkHX34HOW4_cjs.HavenApiError("No accepted x402 option was recorded for payment retry", 500);
2647
+ throw new chunkH37YVYZA_cjs.HavenApiError("No accepted x402 option was recorded for payment retry", 500);
2393
2648
  }
2394
2649
  if (!receipt.paymentHeader) {
2395
- throw new chunkHX34HOW4_cjs.HavenApiError("No x402 payment header was returned for payment retry", 500);
2650
+ throw new chunkH37YVYZA_cjs.HavenApiError("No x402 payment header was returned for payment retry", 500);
2396
2651
  }
2397
2652
  let retryInit = initialInit;
2398
2653
  if (this.getTaxDeclarationHeader && this.delegateKey) {
2399
- const scheme = chunkHFOAYTD4_cjs.x402PaymentHeaderNamesFor(receipt.paymentHeader);
2654
+ const scheme = chunk22FJ4JQO_cjs.x402PaymentHeaderNamesFor(receipt.paymentHeader);
2400
2655
  const isEip3009 = scheme.length > 1;
2401
2656
  if (isEip3009) {
2402
2657
  const resolved = await this.getTaxDeclarationHeader({
@@ -2431,7 +2686,7 @@ var MerchantCompletion = class {
2431
2686
  delegate_to: receipt.to
2432
2687
  }
2433
2688
  });
2434
- throw new chunkHX34HOW4_cjs.HavenApiError(
2689
+ throw new chunkH37YVYZA_cjs.HavenApiError(
2435
2690
  "x402 retry failed after Haven funded the delegate wallet; reconciliation may be required.",
2436
2691
  inBandRejection ? X402_RETRY_REJECTED_STATUS : merchant.merchant_status,
2437
2692
  {
@@ -2461,11 +2716,15 @@ var MerchantCompletion = class {
2461
2716
  merchantStatus: retryResponse.status,
2462
2717
  challengePayload: paymentRequired,
2463
2718
  selectedPayment: receipt.accepted,
2464
- paymentProofHeaderName: chunkHFOAYTD4_cjs.x402PaymentHeaderNamesSent(receipt.paymentHeader),
2719
+ paymentProofHeaderName: chunk22FJ4JQO_cjs.x402PaymentHeaderNamesSent(receipt.paymentHeader),
2465
2720
  paymentProofHeader: receipt.paymentHeader,
2466
2721
  protocolReceiptHeaderName,
2467
2722
  protocolReceiptHeader
2468
2723
  });
2724
+ const settlementCandidate = merchantSettlement.settlementTxHash;
2725
+ if (settlementCandidate && isWellFormedSettlementTxHash(settlementCandidate) && !isZeroSettlementTxHash(settlementCandidate) && settlementCandidate.toLowerCase() !== receipt.txHash.toLowerCase()) {
2726
+ await this.reportSettlementEvidenceOnce(receipt.paymentId, settlementCandidate);
2727
+ }
2469
2728
  await this.reportMerchantReceipt(receipt.paymentId, retryResponse);
2470
2729
  return retryResponse;
2471
2730
  }
@@ -2499,21 +2758,35 @@ var MerchantCompletion = class {
2499
2758
  } catch {
2500
2759
  }
2501
2760
  }
2761
+ /**
2762
+ * #3770: record the agent's evidence-only delivery verdict on a settled
2763
+ * payment — `ok`, `unusable` or `partial`, with a bounded note. Moves no
2764
+ * money and never changes `settled` or any money field; the receipt reads
2765
+ * (`haven_list_receipts` / `haven_get_receipt`) then carry it beside the
2766
+ * payment. Refuses another agent's payment (404) and an unsettled one
2767
+ * (409) — a report requires a delivery that already happened.
2768
+ */
2769
+ async reportDeliveryQuality(input) {
2770
+ return await this.post(`/machine-payments/${input.paymentId}/delivery-quality`, {
2771
+ quality: input.quality,
2772
+ ...input.note !== void 0 ? { note: input.note } : {}
2773
+ });
2774
+ }
2502
2775
  async resolveCompletionContext(input) {
2503
2776
  const status = await this.getPaymentStatus(input.paymentId);
2504
2777
  if (status.rail !== "x402") {
2505
- throw new chunkHX34HOW4_cjs.HavenPaymentStateError(
2778
+ throw new chunkH37YVYZA_cjs.HavenPaymentStateError(
2506
2779
  `Payment ${status.paymentId} is ${status.rail}, not x402.`,
2507
2780
  409,
2508
2781
  status
2509
2782
  );
2510
2783
  }
2511
- const readyForMerchantCompletion = input.noFundingLeg ? status.kind === "payment_intent" && status.status === "submitted" : status.nextAction === chunkHX34HOW4_cjs.AgentPaymentNextAction.RetryOriginalX402Request || status.kind === "payment_intent" && status.status === "confirmed" && status.phase === chunkHX34HOW4_cjs.AgentPaymentPhase.PaymentConfirmed && status.nextAction === chunkHX34HOW4_cjs.AgentPaymentNextAction.None;
2784
+ const readyForMerchantCompletion = input.noFundingLeg ? status.kind === "payment_intent" && status.status === "submitted" : status.nextAction === chunkH37YVYZA_cjs.AgentPaymentNextAction.RetryOriginalX402Request || status.kind === "payment_intent" && status.status === "confirmed" && status.phase === chunkH37YVYZA_cjs.AgentPaymentPhase.PaymentConfirmed && status.nextAction === chunkH37YVYZA_cjs.AgentPaymentNextAction.None;
2512
2785
  if (!readyForMerchantCompletion) {
2513
- throw new chunkHX34HOW4_cjs.HavenPaymentStateError(status.message, paymentStateStatusCode(status.status, 409), status);
2786
+ throw new chunkH37YVYZA_cjs.HavenPaymentStateError(status.message, paymentStateStatusCode(status.status, 409), status);
2514
2787
  }
2515
2788
  if (!input.noFundingLeg && !status.txHash) {
2516
- throw new chunkHX34HOW4_cjs.HavenApiError(
2789
+ throw new chunkH37YVYZA_cjs.HavenApiError(
2517
2790
  `x402 payment ${status.paymentId} is ready for merchant completion but has no Haven transaction hash.`,
2518
2791
  502,
2519
2792
  status,
@@ -2522,7 +2795,7 @@ var MerchantCompletion = class {
2522
2795
  }
2523
2796
  const approvedResourceUrl = status.resourceUrl ?? status.x402?.resourceUrl ?? null;
2524
2797
  if (approvedResourceUrl && approvedResourceUrl !== input.url) {
2525
- throw new chunkHX34HOW4_cjs.HavenApiError(
2798
+ throw new chunkH37YVYZA_cjs.HavenApiError(
2526
2799
  "x402 merchant completion does not match the approved resource URL.",
2527
2800
  409,
2528
2801
  { status, url: input.url },
@@ -2608,7 +2881,7 @@ var MerchantCompletion = class {
2608
2881
  */
2609
2882
  async reportMerchantOutcome(input) {
2610
2883
  if (!Number.isInteger(input.merchantStatus) || input.merchantStatus < 100 || input.merchantStatus > 599) {
2611
- throw new chunkHX34HOW4_cjs.HavenApiError(
2884
+ throw new chunkH37YVYZA_cjs.HavenApiError(
2612
2885
  `merchant_status must be an integer HTTP status from 100 to 599 (received ${input.merchantStatus}).`,
2613
2886
  400,
2614
2887
  void 0,
@@ -2617,7 +2890,7 @@ var MerchantCompletion = class {
2617
2890
  }
2618
2891
  const looksAccepted = input.merchantStatus >= 200 && input.merchantStatus < 300;
2619
2892
  if (looksAccepted !== (input.outcome === "accepted")) {
2620
- throw new chunkHX34HOW4_cjs.HavenApiError(
2893
+ throw new chunkH37YVYZA_cjs.HavenApiError(
2621
2894
  `outcome "${input.outcome}" contradicts merchant_status ${input.merchantStatus}: report "accepted" only for a 2xx and "rejected" only for a non-2xx.`,
2622
2895
  400,
2623
2896
  void 0,
@@ -2626,14 +2899,14 @@ var MerchantCompletion = class {
2626
2899
  }
2627
2900
  const status = await this.getPaymentStatus(input.paymentId);
2628
2901
  if (status.rail !== "x402") {
2629
- throw new chunkHX34HOW4_cjs.HavenPaymentStateError(
2902
+ throw new chunkH37YVYZA_cjs.HavenPaymentStateError(
2630
2903
  `Payment ${status.paymentId} is ${status.rail}, not x402 \u2014 there is no merchant retry to report.`,
2631
2904
  409,
2632
2905
  status
2633
2906
  );
2634
2907
  }
2635
2908
  if (status.status !== "confirmed" || !status.txHash) {
2636
- throw new chunkHX34HOW4_cjs.HavenPaymentStateError(
2909
+ throw new chunkH37YVYZA_cjs.HavenPaymentStateError(
2637
2910
  `Payment ${status.paymentId} has no confirmed Haven funding transaction to anchor a merchant report to (status ${status.status}). ${status.message}`,
2638
2911
  paymentStateStatusCode(status.status, 409),
2639
2912
  status
@@ -2641,7 +2914,7 @@ var MerchantCompletion = class {
2641
2914
  }
2642
2915
  const resourceUrl = status.resourceUrl ?? status.x402?.resourceUrl ?? null;
2643
2916
  if (!resourceUrl) {
2644
- throw new chunkHX34HOW4_cjs.HavenApiError(
2917
+ throw new chunkH37YVYZA_cjs.HavenApiError(
2645
2918
  `Payment ${status.paymentId} has no recorded resource URL, so a merchant report cannot be stored.`,
2646
2919
  409,
2647
2920
  status,
@@ -2670,7 +2943,10 @@ var MerchantCompletion = class {
2670
2943
  rail: "x402",
2671
2944
  txHash,
2672
2945
  resourceUrl,
2673
- merchantStatus: input.merchantStatus
2946
+ merchantStatus: input.merchantStatus,
2947
+ // #3778: accepted outcomes only — a rejection delivered nothing, so
2948
+ // there is no deliverable to point at.
2949
+ ...input.deliveryReference ? { deliveryReference: input.deliveryReference } : {}
2674
2950
  });
2675
2951
  return { paymentId: status.paymentId, outcome: "accepted", txHash, resourceUrl, recorded: "evidence" };
2676
2952
  }
@@ -2687,28 +2963,38 @@ var MerchantCompletion = class {
2687
2963
  paymentProofHeader: input.paymentProofHeader,
2688
2964
  protocolReceiptHeaderName: input.protocolReceiptHeaderName,
2689
2965
  protocolReceiptHeader: input.protocolReceiptHeader,
2690
- protocolReceiptPayload: input.protocolReceiptHeader ? parseProtocolReceiptHeader(input.protocolReceiptHeader) : void 0
2966
+ protocolReceiptPayload: input.protocolReceiptHeader ? parseProtocolReceiptHeader(input.protocolReceiptHeader) : void 0,
2967
+ ...input.deliveryReference ? { deliveryReference: input.deliveryReference } : {}
2691
2968
  };
2692
2969
  for (let attempt = 0; ; attempt += 1) {
2693
- try {
2694
- await this.post("/machine-payments/evidence", body);
2695
- return { outcome: "confirmed" };
2696
- } catch (err) {
2697
- const statusCode = err instanceof chunkHX34HOW4_cjs.HavenApiError ? err.statusCode : void 0;
2698
- const retryable = statusCode === EVIDENCE_RETRYABLE_STATUS;
2699
- if (!retryable) {
2700
- const reason = refusalReasonFromBody(err);
2701
- return {
2702
- outcome: "refused",
2703
- statusCode: statusCode ?? 0,
2704
- ...reason ? { reason } : {}
2705
- };
2706
- }
2707
- if (attempt >= EVIDENCE_RETRY_DELAYS_MS.length) {
2708
- return { outcome: "retryable", statusCode };
2709
- }
2710
- await this.sleep(EVIDENCE_RETRY_DELAYS_MS[attempt]);
2970
+ const result = await this.postEvidenceOnce(body);
2971
+ if (result.outcome !== "retryable" || attempt >= EVIDENCE_RETRY_DELAYS_MS.length) {
2972
+ return result;
2973
+ }
2974
+ await this.sleep(EVIDENCE_RETRY_DELAYS_MS[attempt]);
2975
+ }
2976
+ }
2977
+ /**
2978
+ * ONE evidence attempt — the body of `reportEvidence`'s loop above, and the
2979
+ * whole of the #3764 settlement report below. A 503 answers `retryable`
2980
+ * immediately; the caller decides whether to sleep and re-attempt
2981
+ * (`reportEvidence`) or hand the outcome to its consumer (#3764 D2).
2982
+ */
2983
+ async postEvidenceOnce(body) {
2984
+ try {
2985
+ await this.post("/machine-payments/evidence", body);
2986
+ return { outcome: "confirmed" };
2987
+ } catch (err) {
2988
+ const statusCode = err instanceof chunkH37YVYZA_cjs.HavenApiError ? err.statusCode : void 0;
2989
+ if (statusCode !== EVIDENCE_RETRYABLE_STATUS) {
2990
+ const reason = refusalReasonFromBody(err);
2991
+ return {
2992
+ outcome: "refused",
2993
+ statusCode: statusCode ?? 0,
2994
+ ...reason ? { reason } : {}
2995
+ };
2711
2996
  }
2997
+ return { outcome: "retryable", statusCode };
2712
2998
  }
2713
2999
  }
2714
3000
  /**
@@ -2745,7 +3031,7 @@ var MerchantCompletion = class {
2745
3031
  */
2746
3032
  async reportSettlementEvidence(paymentId, settlementTxHash) {
2747
3033
  if (isZeroSettlementTxHash(settlementTxHash)) {
2748
- throw new chunkHX34HOW4_cjs.HavenZeroSettlementHashError(paymentId);
3034
+ throw new chunkH37YVYZA_cjs.HavenZeroSettlementHashError(paymentId);
2749
3035
  }
2750
3036
  return this.reportEvidence({
2751
3037
  paymentId,
@@ -2753,9 +3039,30 @@ var MerchantCompletion = class {
2753
3039
  txHash: settlementTxHash
2754
3040
  });
2755
3041
  }
3042
+ /**
3043
+ * #3764: report the merchant's OWN EIP-3009 settlement transaction right
3044
+ * after a completed purchase — the second leg of a payment that already has
3045
+ * a funding-evidence row. Same endpoint and payload shape as
3046
+ * `reportSettlementEvidence` above, but with #3764's D2 budget: exactly ONE
3047
+ * attempt, no `EVIDENCE_RETRY_DELAYS_MS` backoff. The resource is already
3048
+ * paid for and delivered, so a retryable answer must not stretch the
3049
+ * completed purchase — the HOSTED tools hand the outcome to the agent
3050
+ * (`settlementEvidenceOutcome` → `haven_report_settlement_evidence`), and
3051
+ * the local caller swallows it by design (D1). Callers validate the hash
3052
+ * before this call (well-formed, non-zero, different from the funding hash
3053
+ * case-insensitively), so there is no client-side refusal here — the
3054
+ * backend verifies on-chain and is the only judge.
3055
+ */
3056
+ async reportSettlementEvidenceOnce(paymentId, settlementTxHash) {
3057
+ return this.postEvidenceOnce({
3058
+ paymentId,
3059
+ rail: "x402",
3060
+ txHash: settlementTxHash
3061
+ });
3062
+ }
2756
3063
  };
2757
3064
  function refusalReasonFromBody(err) {
2758
- if (!(err instanceof chunkHX34HOW4_cjs.HavenApiError)) return void 0;
3065
+ if (!(err instanceof chunkH37YVYZA_cjs.HavenApiError)) return void 0;
2759
3066
  const body = err.body;
2760
3067
  if (body === null || typeof body !== "object" || Array.isArray(body)) return void 0;
2761
3068
  const reason = body.reason;
@@ -2772,7 +3079,7 @@ function parseMerchantSettlement(header) {
2772
3079
  }
2773
3080
  function parseProtocolReceiptHeader(value) {
2774
3081
  try {
2775
- return chunkHFOAYTD4_cjs.decodeBase64Json(value);
3082
+ return chunk22FJ4JQO_cjs.decodeBase64Json(value);
2776
3083
  } catch {
2777
3084
  try {
2778
3085
  return JSON.parse(value);
@@ -2789,7 +3096,7 @@ function x402TypedDataDigest(typedData) {
2789
3096
  try {
2790
3097
  return viem.hashTypedData(typedData);
2791
3098
  } catch (err) {
2792
- throw new chunkHX34HOW4_cjs.HavenSigningError(
3099
+ throw new chunkH37YVYZA_cjs.HavenSigningError(
2793
3100
  `The x402 funding intent carried a sign_data.typed_data that is not a valid EIP-712 payload (needs domain, types, primaryType, message), so its digest cannot be derived and no signer could accept it. Underlying error: ${err instanceof Error ? err.message : String(err)}`
2794
3101
  );
2795
3102
  }
@@ -2805,10 +3112,23 @@ function mapCatalogEntry(entry) {
2805
3112
  protocol: entry.protocol,
2806
3113
  toolName: entry.tool_name,
2807
3114
  toolArguments: entry.tool_arguments ?? null,
3115
+ // #3769: call semantics. Conditional spread like `merchant` — a backend
3116
+ // predating #3769 leaves the fields absent, never null-but-present, so a
3117
+ // fixture's exact object shape does not grow keys. Present on the wire
3118
+ // means the row was read post-#3769 and null means "not declared".
3119
+ ...entry.tool_arguments_schema !== void 0 ? {
3120
+ toolArgumentsSchema: entry.tool_arguments_schema ?? null,
3121
+ httpMethod: entry.http_method ?? null,
3122
+ bodyType: entry.body_type ?? null,
3123
+ bodyExample: entry.body_example ?? null
3124
+ } : {},
2808
3125
  priceDisplay: entry.price_display,
2809
3126
  priceAtomic: entry.price_atomic,
2810
3127
  asset: entry.asset,
2811
3128
  network: entry.network,
3129
+ // #3839: conditional like `merchant` — absent (not null) when the backend
3130
+ // does not send the field, so an older backend's exact shape is unchanged.
3131
+ ...entry.asset_transfer_methods !== void 0 ? { assetTransferMethods: entry.asset_transfer_methods } : {},
2812
3132
  status: entry.status,
2813
3133
  verifiedAt: entry.verified_at,
2814
3134
  source: entry.source,
@@ -2833,6 +3153,7 @@ var HavenClient = class {
2833
3153
  accountReads;
2834
3154
  delegateSweep;
2835
3155
  x402Wallet;
3156
+ egressPolicy;
2836
3157
  merchantTransport;
2837
3158
  confirmationTimeout;
2838
3159
  pollingInterval;
@@ -2864,6 +3185,15 @@ var HavenClient = class {
2864
3185
  merchantCompletion;
2865
3186
  /** Delegate address derived from the private key (if provided) */
2866
3187
  delegateAddress;
3188
+ /**
3189
+ * #3747: the merchant-egress policy this client enforces on every merchant
3190
+ * request, or `undefined` when none was configured (default SDK behaviour).
3191
+ * Hosted tool seams read this to run the SAME policy at quote/prepare time,
3192
+ * so a bad target is refused before funding, not only at the wire.
3193
+ */
3194
+ get merchantEgress() {
3195
+ return this.egressPolicy;
3196
+ }
2867
3197
  constructor(config) {
2868
3198
  this.delegateKey = config.delegateKey;
2869
3199
  this.havenApi = new HavenApiTransport(config);
@@ -2879,8 +3209,9 @@ var HavenClient = class {
2879
3209
  buildExplorerUrl: (chainId, hash) => buildExplorerUrl(chainId, hash)
2880
3210
  });
2881
3211
  this.x402Wallet = config.x402Wallet;
2882
- this.merchantTransport = new McpMerchantTransport({ merchantTimeout: config.merchantTimeout });
2883
- this.confirmationTimeout = config.confirmationTimeout ?? chunkHX34HOW4_cjs.DEFAULT_CONFIRMATION_TIMEOUT_MS;
3212
+ this.egressPolicy = config.merchantEgress;
3213
+ this.merchantTransport = new McpMerchantTransport({ merchantTimeout: config.merchantTimeout, egress: config.merchantEgress });
3214
+ this.confirmationTimeout = config.confirmationTimeout ?? chunkH37YVYZA_cjs.DEFAULT_CONFIRMATION_TIMEOUT_MS;
2884
3215
  this.pollingInterval = config.pollingInterval ?? DEFAULT_POLLING_INTERVAL;
2885
3216
  this.chainRpcs = config.chainRpcs ?? {};
2886
3217
  if (this.delegateKey) {
@@ -2961,7 +3292,7 @@ var HavenClient = class {
2961
3292
  */
2962
3293
  async pay(request) {
2963
3294
  if (!this.delegateKey) {
2964
- throw new chunkHX34HOW4_cjs.HavenSigningError(
3295
+ throw new chunkH37YVYZA_cjs.HavenSigningError(
2965
3296
  "Cannot use pay() without a delegateKey. Use createIntent() + submitSignature() for manual signing."
2966
3297
  );
2967
3298
  }
@@ -3017,15 +3348,15 @@ var HavenClient = class {
3017
3348
  * on-chain allowance — there is nothing to sign until the user approves.
3018
3349
  */
3019
3350
  async createX402Intent(paymentRequired, options = {}) {
3020
- const option = chunkHFOAYTD4_cjs.selectStandardPaymentOption(paymentRequired.accepts);
3351
+ const option = chunk22FJ4JQO_cjs.selectStandardPaymentOption(paymentRequired.accepts);
3021
3352
  if (!option) {
3022
3353
  throw noCompatiblePaymentOptionError(paymentRequired.accepts);
3023
3354
  }
3024
3355
  const fundingTo = options.delegateAddress ?? (await this.getAgent()).delegateAddress;
3025
3356
  if (!fundingTo) {
3026
- throw new chunkHX34HOW4_cjs.HavenApiError("Authenticated agent has no delegate address registered.", 502);
3357
+ throw new chunkH37YVYZA_cjs.HavenApiError("Authenticated agent has no delegate address registered.", 502);
3027
3358
  }
3028
- const idempotencyKey = options.idempotencyKey ?? chunkHFOAYTD4_cjs.buildX402IdempotencyKey(paymentRequired, option);
3359
+ const idempotencyKey = options.idempotencyKey ?? chunk22FJ4JQO_cjs.buildX402IdempotencyKey(paymentRequired, option);
3029
3360
  const raw = await this.post("/x402", {
3030
3361
  url: paymentRequired.resource.url,
3031
3362
  payTo: fundingTo,
@@ -3036,7 +3367,7 @@ var HavenClient = class {
3036
3367
  // of a silent reroute to the erc7710 settlement branch (the #1358
3037
3368
  // review's open-budget misroute). Legacy-rail backends ignore the field.
3038
3369
  settlementScheme: "eip3009",
3039
- amount: chunkHFOAYTD4_cjs.x402AuthorizationAmount(option),
3370
+ amount: chunk22FJ4JQO_cjs.x402AuthorizationAmount(option),
3040
3371
  asset: option.asset,
3041
3372
  network: option.network,
3042
3373
  description: paymentRequired.resource.description,
@@ -3061,15 +3392,15 @@ var HavenClient = class {
3061
3392
  throwPaymentStateError("x402 payment", raw);
3062
3393
  }
3063
3394
  if (!raw.sign_data?.hash) {
3064
- throw new chunkHX34HOW4_cjs.HavenApiError("No sign_hash returned from x402/authorize", 500, raw);
3395
+ throw new chunkH37YVYZA_cjs.HavenApiError("No sign_hash returned from x402/authorize", 500, raw);
3065
3396
  }
3066
3397
  if (raw.sign_data.signature_scheme !== void 0 && !raw.sign_data.typed_data) {
3067
- throw new chunkHX34HOW4_cjs.HavenSigningError(
3398
+ throw new chunkH37YVYZA_cjs.HavenSigningError(
3068
3399
  `This account's x402 funding intent declares signature scheme '${raw.sign_data.signature_scheme}' but carried no typed_data to sign. Refusing to fall back to the bare hash \u2014 the account would reject that signature on-chain. This is a backend contract violation; report it rather than working around it.`
3069
3400
  );
3070
3401
  }
3071
3402
  if (!raw.x402_expected_auth) {
3072
- throw new chunkHX34HOW4_cjs.HavenApiError("No x402 expected-context binding returned from x402/authorize", 500, raw);
3403
+ throw new chunkH37YVYZA_cjs.HavenApiError("No x402 expected-context binding returned from x402/authorize", 500, raw);
3073
3404
  }
3074
3405
  return {
3075
3406
  paymentId: raw.payment_id,
@@ -3080,7 +3411,7 @@ var HavenClient = class {
3080
3411
  accepted: option,
3081
3412
  resourceUrl: paymentRequired.resource.url,
3082
3413
  merchantTo: raw.merchant_to ?? option.payTo,
3083
- amountAtomic: chunkHFOAYTD4_cjs.x402AuthorizationAmount(option),
3414
+ amountAtomic: chunk22FJ4JQO_cjs.x402AuthorizationAmount(option),
3084
3415
  asset: option.asset,
3085
3416
  network: option.network,
3086
3417
  expectedAuth: raw.x402_expected_auth,
@@ -3105,13 +3436,13 @@ var HavenClient = class {
3105
3436
  */
3106
3437
  sign(hash) {
3107
3438
  if (!this.delegateKey) {
3108
- throw new chunkHX34HOW4_cjs.HavenSigningError(
3439
+ throw new chunkH37YVYZA_cjs.HavenSigningError(
3109
3440
  "Cannot sign without a delegateKey. Pass the private key in HavenClient config, or sign externally."
3110
3441
  );
3111
3442
  }
3112
3443
  const signature = signHash(this.delegateKey, hash);
3113
3444
  if (!verifySignature(hash, signature, this.delegateAddress)) {
3114
- throw new chunkHX34HOW4_cjs.HavenSigningError(
3445
+ throw new chunkH37YVYZA_cjs.HavenSigningError(
3115
3446
  "Local signature verification failed \u2014 recovered address does not match delegate key."
3116
3447
  );
3117
3448
  }
@@ -3129,29 +3460,29 @@ var HavenClient = class {
3129
3460
  */
3130
3461
  async signForData(signData, settlementExpectation, fundingExpectation) {
3131
3462
  if (!this.delegateKey) {
3132
- throw new chunkHX34HOW4_cjs.HavenSigningError(
3463
+ throw new chunkH37YVYZA_cjs.HavenSigningError(
3133
3464
  "Cannot sign without a delegateKey. Pass the private key in HavenClient config, or sign externally."
3134
3465
  );
3135
3466
  }
3136
3467
  const scheme = signData.signature_scheme;
3137
3468
  if (scheme === "eip191_userop") {
3138
- throw new chunkHX34HOW4_cjs.HavenSigningError(
3469
+ throw new chunkH37YVYZA_cjs.HavenSigningError(
3139
3470
  "The session rail is retired \u2014 'eip191_userop' intents can no longer be signed. Re-onboard the account on the delegation rail."
3140
3471
  );
3141
3472
  }
3142
3473
  if (scheme === "eip712_userop") {
3143
3474
  if (!signData.typed_data) {
3144
- throw new chunkHX34HOW4_cjs.HavenSigningError(
3475
+ throw new chunkH37YVYZA_cjs.HavenSigningError(
3145
3476
  "sign_data.signature_scheme is eip712_userop but typed_data is missing \u2014 refusing to sign the bare hash (the account would reject it)."
3146
3477
  );
3147
3478
  }
3148
- chunkHX34HOW4_cjs.assertUserOpTypedDataBinding(signData.typed_data, signData.hash);
3149
- chunkHFOAYTD4_cjs.assertBoundDirectPaymentUserOp(
3479
+ chunkH37YVYZA_cjs.assertUserOpTypedDataBinding(signData.typed_data, signData.hash);
3480
+ chunk22FJ4JQO_cjs.assertBoundDirectPaymentUserOp(
3150
3481
  signData.typed_data,
3151
3482
  this.delegateAddress
3152
3483
  );
3153
3484
  if (fundingExpectation) {
3154
- chunkHFOAYTD4_cjs.assertFundingLegPaysDelegate(signData.typed_data, {
3485
+ chunk22FJ4JQO_cjs.assertFundingLegPaysDelegate(signData.typed_data, {
3155
3486
  delegateAddress: this.delegateAddress,
3156
3487
  asset: fundingExpectation.asset,
3157
3488
  amount: fundingExpectation.amount
@@ -3161,24 +3492,24 @@ var HavenClient = class {
3161
3492
  }
3162
3493
  if (scheme === "eip712_delegation") {
3163
3494
  if (!signData.typed_data) {
3164
- throw new chunkHX34HOW4_cjs.HavenSigningError(
3495
+ throw new chunkH37YVYZA_cjs.HavenSigningError(
3165
3496
  "sign_data.signature_scheme is eip712_delegation but typed_data is missing \u2014 refusing to sign the bare hash (the settlement would be rejected on redemption)."
3166
3497
  );
3167
3498
  }
3168
3499
  if (!settlementExpectation) {
3169
- throw new chunkHFOAYTD4_cjs.HavenTypedDataRefusedError(
3500
+ throw new chunk22FJ4JQO_cjs.HavenTypedDataRefusedError(
3170
3501
  "Refusing to sign an x402 settlement child without an independent expectation of what it must pay (the merchant's 402). Pay erc7710 merchants through settleX402Erc7710(), which supplies it."
3171
3502
  );
3172
3503
  }
3173
- chunkHFOAYTD4_cjs.assertOwnSettlementChild(signData.typed_data, settlementExpectation, this.delegateAddress);
3504
+ chunk22FJ4JQO_cjs.assertOwnSettlementChild(signData.typed_data, settlementExpectation, this.delegateAddress);
3174
3505
  return signSettlementDelegationTypedData(this.delegateKey, signData.typed_data);
3175
3506
  }
3176
3507
  if (scheme === void 0) {
3177
- throw new chunkHX34HOW4_cjs.HavenSigningError(
3508
+ throw new chunkH37YVYZA_cjs.HavenSigningError(
3178
3509
  "sign_data.signature_scheme is required \u2014 the legacy AllowanceModule rail that signed the bare hash is retired (#2850). Refusing to guess a signing scheme."
3179
3510
  );
3180
3511
  }
3181
- throw new chunkHX34HOW4_cjs.HavenSigningError(
3512
+ throw new chunkH37YVYZA_cjs.HavenSigningError(
3182
3513
  `Unknown sign_data.signature_scheme '${scheme}' \u2014 refusing to guess a signing scheme. Update @haven_ai/sdk.`
3183
3514
  );
3184
3515
  }
@@ -3368,7 +3699,7 @@ var HavenClient = class {
3368
3699
  */
3369
3700
  async getPaymentStatusWithPostPurchaseAllowance(paymentId) {
3370
3701
  const status = await this.getPaymentStatus(paymentId);
3371
- if (status.rail === chunkHX34HOW4_cjs.AgentPaymentRail.X402 && status.phase === chunkHX34HOW4_cjs.AgentPaymentPhase.PaymentConfirmed) {
3702
+ if (status.rail === chunkH37YVYZA_cjs.AgentPaymentRail.X402 && status.phase === chunkH37YVYZA_cjs.AgentPaymentPhase.PaymentConfirmed) {
3372
3703
  const { allowance, warnings } = await this.getPostPurchaseAllowanceSummary(paymentId);
3373
3704
  return { ...status, allowance, ...warnings.length > 0 ? { warnings } : {} };
3374
3705
  }
@@ -3455,6 +3786,9 @@ var HavenClient = class {
3455
3786
  * locally. The server's own verification is ignored — the receipt is verified
3456
3787
  * here (independently of Haven) by recovering the signer from the
3457
3788
  * authorisation, so the result is trustworthy even if the backend lied.
3789
+ * The returned `{ receipt, verification }` object is the same shape the
3790
+ * `GET /payments/{id}/receipt` endpoint returns, and `verifyPaymentReceipt`
3791
+ * (#3723) accepts either layer: pass this whole object or `.receipt` alone.
3458
3792
  */
3459
3793
  async getReceipt(paymentId) {
3460
3794
  return this.accountReads.getReceipt(paymentId);
@@ -3615,7 +3949,7 @@ var HavenClient = class {
3615
3949
  }
3616
3950
  await sleep(this.pollingInterval);
3617
3951
  }
3618
- throw new chunkHX34HOW4_cjs.HavenTimeoutError(paymentId);
3952
+ throw new chunkH37YVYZA_cjs.HavenTimeoutError(paymentId);
3619
3953
  }
3620
3954
  // ── x402 Protocol Support ────────────────────────────────────────
3621
3955
  /**
@@ -3629,24 +3963,24 @@ var HavenClient = class {
3629
3963
  */
3630
3964
  async authorizeX402(paymentRequired, options = {}) {
3631
3965
  if (!this.delegateKey) {
3632
- throw new chunkHX34HOW4_cjs.HavenSigningError(
3966
+ throw new chunkH37YVYZA_cjs.HavenSigningError(
3633
3967
  "delegateKey is required for x402 payments. Pass it in the HavenClient config."
3634
3968
  );
3635
3969
  }
3636
3970
  if (!this.delegateAddress) {
3637
- throw new chunkHX34HOW4_cjs.HavenSigningError("delegateAddress could not be derived from delegateKey.");
3971
+ throw new chunkH37YVYZA_cjs.HavenSigningError("delegateAddress could not be derived from delegateKey.");
3638
3972
  }
3639
- const option = chunkHFOAYTD4_cjs.selectStandardPaymentOption(paymentRequired.accepts);
3973
+ const option = chunk22FJ4JQO_cjs.selectStandardPaymentOption(paymentRequired.accepts);
3640
3974
  if (!option) {
3641
3975
  throw noCompatiblePaymentOptionError(paymentRequired.accepts);
3642
3976
  }
3643
- const idempotencyKey = options.idempotencyKey ?? chunkHFOAYTD4_cjs.buildX402IdempotencyKey(paymentRequired, option);
3977
+ const idempotencyKey = options.idempotencyKey ?? chunk22FJ4JQO_cjs.buildX402IdempotencyKey(paymentRequired, option);
3644
3978
  const cached = this.fundingLeg.cachedReceipt(idempotencyKey, options.taskBudgetId, options.subBudgetId);
3645
3979
  if (cached) return cached;
3646
3980
  const inFlight = this.inFlightX402.get(idempotencyKey);
3647
3981
  if (inFlight) {
3648
3982
  if (!sameX402TaskBudget(this.inFlightX402TaskBudget.get(idempotencyKey), options.taskBudgetId) || !sameX402TaskBudget(this.inFlightX402SubBudget.get(idempotencyKey), options.subBudgetId)) {
3649
- throw new chunkHX34HOW4_cjs.X402TaskBudgetMismatchError(
3983
+ throw new chunkH37YVYZA_cjs.X402TaskBudgetMismatchError(
3650
3984
  `The x402 idempotency key '${idempotencyKey}' has an in-flight payment created under a different authorizing budget (task '${this.inFlightX402TaskBudget.get(idempotencyKey) ?? "none"}' vs '${options.taskBudgetId ?? "none"}', sub '${this.inFlightX402SubBudget.get(idempotencyKey) ?? "none"}' vs '${options.subBudgetId ?? "none"}'). Pass a new idempotencyKey to pay under this budget.`,
3651
3985
  idempotencyKey,
3652
3986
  this.inFlightX402TaskBudget.get(idempotencyKey),
@@ -3687,7 +4021,7 @@ var HavenClient = class {
3687
4021
  async quoteX402(url, init, options = {}) {
3688
4022
  const initialInit = withX402Wallet(init, x402PayerAddress(this.delegateAddress, this.x402Wallet));
3689
4023
  const request = snapshotX402Request(url, initialInit);
3690
- const response = await this.merchantTransport.fetch(url, initialInit);
4024
+ const response = await this.merchantTransport.fetch(url, initialInit, this.merchantTransport.budgetFor("quote"), this.merchantTransport.capFor("quote"));
3691
4025
  if (response.status !== 402) {
3692
4026
  const toolResultChallenge = await this.merchantTransport.extractToolResultChallenge(response, initialInit);
3693
4027
  if (toolResultChallenge) {
@@ -3697,19 +4031,20 @@ var HavenClient = class {
3697
4031
  let body;
3698
4032
  try {
3699
4033
  body = await response.clone().json();
3700
- } catch {
4034
+ } catch (err) {
4035
+ if (err instanceof MerchantEgressResponseCapError) throw err;
3701
4036
  body = void 0;
3702
4037
  }
3703
- throw new chunkHX34HOW4_cjs.X402UnexpectedStatusError(
4038
+ throw new chunkH37YVYZA_cjs.X402UnexpectedStatusError(
3704
4039
  `Expected an x402 quote response with HTTP 402, got HTTP ${response.status}.`,
3705
4040
  response.status || 400,
3706
4041
  body
3707
4042
  );
3708
4043
  }
3709
4044
  if (response.headers.get("MACHINE-PAYMENT-CHALLENGE")) {
3710
- throw new chunkHX34HOW4_cjs.HavenApiError("quoteX402 only supports standard x402 Payment Required responses.", 400);
4045
+ throw new chunkH37YVYZA_cjs.HavenApiError("quoteX402 only supports standard x402 Payment Required responses.", 400);
3711
4046
  }
3712
- const paymentRequired = await chunkHFOAYTD4_cjs.parsePaymentRequiredResponse(response);
4047
+ const paymentRequired = await chunk22FJ4JQO_cjs.parsePaymentRequiredResponse(response);
3713
4048
  const mcpTransport = await this.merchantTransport.detect(url, paymentRequired, response);
3714
4049
  return buildX402Quote(paymentRequired, request, options.idempotencyKey, mcpTransport);
3715
4050
  }
@@ -3727,7 +4062,7 @@ var HavenClient = class {
3727
4062
  const wallet = await this.merchantCompletion.resolveWalletForMerchantCall();
3728
4063
  const sessionId = await this.merchantTransport.initialize(url, init, wallet);
3729
4064
  if (!sessionId) {
3730
- throw new chunkHX34HOW4_cjs.HavenApiError(
4065
+ throw new chunkH37YVYZA_cjs.HavenApiError(
3731
4066
  "The merchant did not establish an MCP session before the x402 quote. No payment was created.",
3732
4067
  502,
3733
4068
  { mcpSessionNotEstablished: true }
@@ -3801,18 +4136,18 @@ var HavenClient = class {
3801
4136
  }
3802
4137
  async resumeAuthorizedX402(input) {
3803
4138
  if (!this.delegateKey) {
3804
- throw new chunkHX34HOW4_cjs.HavenSigningError(
4139
+ throw new chunkH37YVYZA_cjs.HavenSigningError(
3805
4140
  "delegateKey is required for x402 payments. Pass it in the HavenClient config."
3806
4141
  );
3807
4142
  }
3808
4143
  if (!this.delegateAddress) {
3809
- throw new chunkHX34HOW4_cjs.HavenSigningError("delegateAddress could not be derived from delegateKey.");
4144
+ throw new chunkH37YVYZA_cjs.HavenSigningError("delegateAddress could not be derived from delegateKey.");
3810
4145
  }
3811
- const option = chunkHFOAYTD4_cjs.selectStandardPaymentOption(input.paymentRequired.accepts);
4146
+ const option = chunk22FJ4JQO_cjs.selectStandardPaymentOption(input.paymentRequired.accepts);
3812
4147
  if (!option) {
3813
4148
  throw noCompatiblePaymentOptionError(input.paymentRequired.accepts);
3814
4149
  }
3815
- const idempotencyKey = input.idempotencyKey ?? chunkHFOAYTD4_cjs.buildX402IdempotencyKey(input.paymentRequired, option);
4150
+ const idempotencyKey = input.idempotencyKey ?? chunk22FJ4JQO_cjs.buildX402IdempotencyKey(input.paymentRequired, option);
3816
4151
  const cached = this.fundingLeg.cachedReceipt(idempotencyKey, input.taskBudgetId);
3817
4152
  if (cached) return cached;
3818
4153
  const status = await this.getPaymentStatus(input.paymentId);
@@ -3820,16 +4155,16 @@ var HavenClient = class {
3820
4155
  const canFund = await this.fundingLeg.delegateCanFund(
3821
4156
  status.chainId ?? chainIdFromNetwork(option.network),
3822
4157
  option.asset,
3823
- chunkHFOAYTD4_cjs.x402AuthorizationAmount(option)
4158
+ chunk22FJ4JQO_cjs.x402AuthorizationAmount(option)
3824
4159
  );
3825
4160
  if (canFund === false) {
3826
- throw new chunkHX34HOW4_cjs.X402AlreadySettledError(
4161
+ throw new chunkH37YVYZA_cjs.X402AlreadySettledError(
3827
4162
  `x402 payment ${status.paymentId} has already settled \u2014 the delegate no longer holds the funds to authorize it again, so there is nothing left to resume.`,
3828
4163
  this.fundingLeg.receiptFromStatus(input.paymentRequired, option, void 0, status),
3829
4164
  "settled"
3830
4165
  );
3831
4166
  }
3832
- const paymentHeader = await this.fundingLeg.createPaymentHeader(input.paymentRequired, option);
4167
+ const paymentHeader = await this.fundingLeg.createPaymentHeader(input.paymentRequired, option, status.paymentId);
3833
4168
  const receipt = this.fundingLeg.receiptFromStatus(input.paymentRequired, option, paymentHeader, status);
3834
4169
  this.fundingLeg.cacheReceipt(idempotencyKey, paymentHeader, receipt, input.taskBudgetId);
3835
4170
  return receipt;
@@ -3844,13 +4179,13 @@ var HavenClient = class {
3844
4179
  const url = input.url ?? input.request?.url;
3845
4180
  if (!paymentRequired) {
3846
4181
  if (!url) {
3847
- throw new chunkHX34HOW4_cjs.HavenApiError("x402 resume requires the original URL or a captured request snapshot.", 400);
4182
+ throw new chunkH37YVYZA_cjs.HavenApiError("x402 resume requires the original URL or a captured request snapshot.", 400);
3848
4183
  }
3849
- const response = await this.merchantTransport.fetch(url, initialInit);
4184
+ const response = await this.merchantTransport.fetch(url, initialInit, this.merchantTransport.budgetFor("quote"), this.merchantTransport.capFor("quote"));
3850
4185
  if (response.status !== 402) {
3851
- throw new chunkHX34HOW4_cjs.HavenApiError("Expected the original x402 request to return HTTP 402 before resuming.", 400);
4186
+ throw new chunkH37YVYZA_cjs.HavenApiError("Expected the original x402 request to return HTTP 402 before resuming.", 400);
3852
4187
  }
3853
- paymentRequired = await chunkHFOAYTD4_cjs.parsePaymentRequiredResponse(response);
4188
+ paymentRequired = await chunk22FJ4JQO_cjs.parsePaymentRequiredResponse(response);
3854
4189
  }
3855
4190
  const receipt = await this.resumeAuthorizedX402({
3856
4191
  paymentId: input.paymentId,
@@ -3891,7 +4226,7 @@ var HavenClient = class {
3891
4226
  }
3892
4227
  let requestInit = withX402Wallet(init, x402PayerAddress(this.delegateAddress, this.x402Wallet));
3893
4228
  if (mcpSessionId) requestInit = this.merchantTransport.withSessionHeaders(requestInit, mcpSessionId);
3894
- const response = await this.merchantTransport.fetch(url, requestInit);
4229
+ const response = await this.merchantTransport.fetch(url, requestInit, this.merchantTransport.budgetFor("quote"), this.merchantTransport.capFor("quote"));
3895
4230
  let paymentRequired;
3896
4231
  let nativeChallenge = false;
3897
4232
  if (response.status !== 402) {
@@ -3903,8 +4238,9 @@ var HavenClient = class {
3903
4238
  nativeChallenge = true;
3904
4239
  } else {
3905
4240
  try {
3906
- paymentRequired = await chunkHFOAYTD4_cjs.parsePaymentRequiredResponse(response);
3907
- } catch {
4241
+ paymentRequired = await chunk22FJ4JQO_cjs.parsePaymentRequiredResponse(response);
4242
+ } catch (err) {
4243
+ if (err instanceof MerchantEgressResponseCapError) throw err;
3908
4244
  return response;
3909
4245
  }
3910
4246
  }
@@ -3913,8 +4249,8 @@ var HavenClient = class {
3913
4249
  if (mcpSessionId) requestInit = this.merchantTransport.withSessionHeaders(requestInit, mcpSessionId);
3914
4250
  }
3915
4251
  const request = snapshotX402Request(url, requestInit);
3916
- const option = chunkHFOAYTD4_cjs.selectStandardPaymentOption(paymentRequired.accepts);
3917
- const idempotencyKey = options.idempotencyKey ?? (option ? chunkHFOAYTD4_cjs.buildX402IdempotencyKey(paymentRequired, option) : void 0);
4252
+ const option = chunk22FJ4JQO_cjs.selectStandardPaymentOption(paymentRequired.accepts);
4253
+ const idempotencyKey = options.idempotencyKey ?? (option ? chunk22FJ4JQO_cjs.buildX402IdempotencyKey(paymentRequired, option) : void 0);
3918
4254
  let receipt;
3919
4255
  try {
3920
4256
  receipt = await this.authorizeX402(paymentRequired, options);
@@ -4013,6 +4349,7 @@ var HavenClient = class {
4013
4349
  const settlement = parseMerchantSettlement(protocolReceiptHeader ?? null);
4014
4350
  const merchantAccepted = surfaced.ok && inBandChallenge === void 0 && metaSettlement?.success !== false;
4015
4351
  let evidenceOutcome;
4352
+ let settlementEvidenceOutcome;
4016
4353
  if (!merchantAccepted) {
4017
4354
  if (!input.noFundingLeg && fundingTxHash) {
4018
4355
  await this.merchantCompletion.recordRetryRejected({
@@ -4041,12 +4378,24 @@ var HavenClient = class {
4041
4378
  txHash: evidenceTxHash,
4042
4379
  resourceUrl: evidenceContext.resourceUrl,
4043
4380
  merchantStatus: surfaced.status,
4044
- paymentProofHeaderName: chunkHFOAYTD4_cjs.x402PaymentHeaderNamesSent(input.paymentHeader),
4381
+ paymentProofHeaderName: chunk22FJ4JQO_cjs.x402PaymentHeaderNamesSent(input.paymentHeader),
4045
4382
  paymentProofHeader: input.paymentHeader,
4046
4383
  protocolReceiptHeaderName,
4047
- protocolReceiptHeader
4384
+ protocolReceiptHeader,
4385
+ // #3778: the delivery pointer rides the accepted arm's evidence
4386
+ // report — a rejection delivered nothing to point at.
4387
+ ...input.deliveryReference ? { deliveryReference: input.deliveryReference } : {}
4048
4388
  });
4049
4389
  }
4390
+ if (!input.noFundingLeg) {
4391
+ const settlementCandidate = settlement.settlementTxHash;
4392
+ if (settlementCandidate && isWellFormedSettlementTxHash(settlementCandidate) && !isZeroSettlementTxHash(settlementCandidate) && fundingTxHash && settlementCandidate.toLowerCase() !== fundingTxHash.toLowerCase()) {
4393
+ settlementEvidenceOutcome = await this.merchantCompletion.reportSettlementEvidenceOnce(
4394
+ evidenceContext.paymentId,
4395
+ settlementCandidate
4396
+ );
4397
+ }
4398
+ }
4050
4399
  await this.merchantCompletion.reportMerchantReceipt(evidenceContext.paymentId, surfaced);
4051
4400
  }
4052
4401
  return {
@@ -4055,7 +4404,8 @@ var HavenClient = class {
4055
4404
  body,
4056
4405
  // #3155 review S3: a transaction beside a rejection is not a settlement.
4057
4406
  settlementTxHash: merchantAccepted ? settlement.settlementTxHash ?? void 0 : void 0,
4058
- evidenceOutcome
4407
+ evidenceOutcome,
4408
+ settlementEvidenceOutcome
4059
4409
  };
4060
4410
  }
4061
4411
  /**
@@ -4090,13 +4440,26 @@ var HavenClient = class {
4090
4440
  async reportSettlementEvidence(paymentId, settlementTxHash) {
4091
4441
  return await this.merchantCompletion.reportSettlementEvidence(paymentId, settlementTxHash);
4092
4442
  }
4443
+ /**
4444
+ * #3770: record the agent's evidence-only delivery verdict on a settled
4445
+ * payment — `ok`, `unusable` or `partial`, with a bounded note. The
4446
+ * receipt reads (`haven_list_receipts` / `haven_get_receipt`) then carry
4447
+ * it beside the payment. Moves no money and never changes `settled`;
4448
+ * another agent's payment is refused (404), an unsettled one refused
4449
+ * (409).
4450
+ */
4451
+ async reportDeliveryQuality(input) {
4452
+ return await this.merchantCompletion.reportDeliveryQuality(input);
4453
+ }
4093
4454
  /**
4094
4455
  * GET /x402/:id/merchant-call-context — the settle-leg twin of #1263's
4095
4456
  * sign-context fetch (#1307). Re-serves the stored merchant MCP-tool call
4096
- * context (merchant_url, tool_name, arguments, mcp_transport) recorded at
4097
- * quote time, so `haven_settle_mcp_tool` / `haven_complete_mcp_tool` can
4098
- * omit those fields and let Haven rehydrate them by payment_id instead of
4099
- * the caller re-threading them. Throws `HavenApiError` (404 unknown/foreign
4457
+ * context (merchant_url, tool_name, arguments, mcp_transport — and the
4458
+ * catalog row name #3781 added, when the purchase came from a catalog
4459
+ * entry) recorded at quote time, so `haven_settle_mcp_tool` /
4460
+ * `haven_complete_mcp_tool` can omit those fields and let Haven rehydrate
4461
+ * them by payment_id instead of the caller re-threading them. Throws
4462
+ * `HavenApiError` (404 unknown/foreign
4100
4463
  * payment_id, 409 no stored context, 410 expired) — the caller decides the
4101
4464
  * fallback (re-send the full context explicitly).
4102
4465
  */
@@ -4109,6 +4472,9 @@ var HavenClient = class {
4109
4472
  merchantUrl: raw.merchant_url,
4110
4473
  toolName: raw.tool_name,
4111
4474
  arguments: raw.arguments ?? {},
4475
+ // #3781: the catalog row name rides the same blob; absent on a direct
4476
+ // haven_pay_mcp_tool purchase.
4477
+ ...raw.catalog_name ? { catalogName: raw.catalog_name } : {},
4112
4478
  ...raw.mcp_transport ? {
4113
4479
  mcpTransport: {
4114
4480
  handshakeRequired: raw.mcp_transport.handshake_required,
@@ -4117,6 +4483,36 @@ var HavenClient = class {
4117
4483
  } : {}
4118
4484
  };
4119
4485
  }
4486
+ /**
4487
+ * GET /x402/by-idempotency-key/:key — read-only, agent-scoped lookup of the
4488
+ * caller's own x402 intent for an idempotency key (#3739). A hosted pay tool
4489
+ * calls it BEFORE re-probing a merchant, so a replay never depends on the
4490
+ * merchant still answering. Writes nothing (a stale pending intent is
4491
+ * reported with `windowOpen: false`, never expired here). Returns `null`
4492
+ * when there is no such intent (a 404: unknown and not-yours are the same
4493
+ * answer); any other failure throws `HavenApiError`.
4494
+ */
4495
+ async findX402IntentByIdempotencyKey(key) {
4496
+ let raw;
4497
+ try {
4498
+ raw = await this.get(`/x402/by-idempotency-key/${encodeURIComponent(key)}`);
4499
+ } catch (err) {
4500
+ if (err instanceof chunkH37YVYZA_cjs.HavenApiError && err.statusCode === 404) return null;
4501
+ throw err;
4502
+ }
4503
+ return {
4504
+ paymentId: raw.payment_id,
4505
+ status: raw.status,
4506
+ settlementScheme: raw.settlement_scheme ?? null,
4507
+ resourceUrl: raw.resource_url ?? null,
4508
+ expiresAt: raw.expires_at ?? null,
4509
+ windowOpen: raw.window_open === true,
4510
+ taskBudgetId: raw.task_budget_id ?? null,
4511
+ amountAtomic: raw.amount_atomic,
4512
+ asset: raw.asset ?? null,
4513
+ network: raw.network
4514
+ };
4515
+ }
4120
4516
  /**
4121
4517
  * Wait for a funding tx to be mined with ≥1 confirmation before the
4122
4518
  * merchant retry, eliminating the race where the merchant's
@@ -4236,6 +4632,7 @@ function sleep(ms) {
4236
4632
  function composeDescription(d) {
4237
4633
  return [d.summary, d.selectionGuidance, d.behavior, d.nextActionGuidance].filter(Boolean).join(" ");
4238
4634
  }
4635
+ var FUNDING_LEG_DISCOVERY_GUIDANCE = `funding_leg_expected is a catalog hint: among equivalent entries prefer false (erc7710, no funding leg); "unknown" is no preference; never hide true entries. A recipient-pinned budget can pay erc7710 merchants only. The quote's expected_funding_leg is authoritative.`;
4239
4636
  var toolDescriptions = {
4240
4637
  quoteX402: {
4241
4638
  summary: "Inspect an HTTP 402 x402 paid resource without creating a Haven payment, signature, approval, or on-chain transaction.",
@@ -4275,14 +4672,14 @@ var toolDescriptions = {
4275
4672
  },
4276
4673
  getAgent: {
4277
4674
  summary: "Return the authenticated agent identity AND its live spend authority in one call: Haven wallet, delegate, chain, raw status, spend_authority_readiness, per-token remaining allowance (atomic + human-readable). The recommended first call in a new session.",
4278
- selectionGuidance: "Use this as the session bootstrap, or to confirm identity together with whether the agent can spend right now. For per-token detail (configured vs spent vs reset window) use haven_get_allowances.",
4279
- behavior: 'Reads identity plus the live spend-authority snapshot \u2014 the active on-chain budget delegation. spend_authority_readiness (readiness is a deprecated alias, same value) is "ready" when at least one token has remaining spend authority, "needs_approval" when the agent is active but has none, and "revoked" when the credential is not active. It covers hosted identity + on-chain spend authority ONLY \u2014 the hosted server cannot see the LOCAL signer, so "ready" does not mean the signer can start; verify the signer with a signer tool call or connect --doctor. An over-budget payment is declined before any money moves; there is no approval queue \u2014 ask the owner to grant or raise the budget in Haven. allowances[] carries id, tokenAddress, remainingAtomic, remainingDisplay per token. taskBudgets[] rows carry maxAtomic/maxDisplay plus spentAtomic/remainingAtomic/remainingDisplay \u2014 what the chain still allows that budget \u2014 and remainingIsFromChain: false marks a failed read (figures null, never the full cap); only live rows are listed (closed and expired omitted), each with its status (pending | open | closing) and isExpired, so a closing budget stays visible. pendingSubBudgetSignatures[] lists sub-budget rows awaiting YOUR signature, each with its haven_sign next step. Identity fields: id, name, status, accountAddress, delegateAddress, chainId.',
4675
+ selectionGuidance: "Use this as the session bootstrap, or to confirm identity together with whether the agent has spend authority right now. For per-token detail (configured vs spent vs reset window) use haven_get_allowances.",
4676
+ behavior: `Reads identity plus the live spend-authority snapshot \u2014 the active on-chain budget delegation. spend_authority_readiness (readiness is a deprecated alias, same value) is "ready" when at least one token has remaining spend authority, "needs_approval" when the agent is active but has none, and "revoked" when the credential is not active. Readiness is AUTHORITY: it says a budget is live, not that the account holds funds. Each allowances[] row carries fundsCoverRemaining: false when the account's balance cannot back that row's whole remaining budget \u2014 a heads-up to mention to the user, not a refusal (budgets above the balance are a normal setup; an owner may top up weekly) \u2014 and null when the coverage read failed or the remaining figure was not read live; the key is absent when the remaining is 0, and rows for one token are compared alone. It covers hosted identity + on-chain spend authority ONLY \u2014 the hosted server cannot see the LOCAL signer, so "ready" does not mean the signer can start; verify the signer with a signer tool call or connect --doctor. An over-budget payment is declined before any money moves; there is no approval queue \u2014 ask the owner to grant or raise the budget in Haven. allowances[] carries id, tokenAddress, remainingAtomic, remainingDisplay per token. taskBudgets[] rows carry maxAtomic/maxDisplay plus spentAtomic/remainingAtomic/remainingDisplay \u2014 what the chain still allows that budget \u2014 and remainingIsFromChain: false marks a failed read (figures null, never the full cap); only live rows are listed (closed and expired omitted), each with its status (pending | open | closing) and isExpired, so a closing budget stays visible. pendingSubBudgetSignatures[] lists sub-budget rows awaiting YOUR signature, each with its haven_sign next step. Identity fields: id, name, status, accountAddress, delegateAddress, chainId.`,
4280
4677
  nextActionGuidance: ""
4281
4678
  },
4282
4679
  getAllowances: {
4283
4680
  summary: "Return configured and on-chain allowance state for the authenticated agent. On-chain allowance is the real spend gate.",
4284
- selectionGuidance: "Use this when the user asks about allowance, budget, spend limit, remaining amount, remaining allowance, remaining budget, daily limit, reset period, what can I spend, or what the agent can still spend. For whether the account actually HOLDS funds behind the budget use haven_check_funds.",
4285
- behavior: "Returns the per-token spend authority for the account: the active budget delegation (remaining = the period budget, which re-arms natively at the period boundary), each with id, onchain.remaining, remainingDisplay, delegationHash, recipientAddress (null = open; a pinned budget pays only that recipient), merchantId (set only on a merchant-locked budget), and reservedHavenAtomic \u2014 Haven-side task- and sub-budget reservations summed beside, never folded into, the on-chain figure. An over-budget payment is declined before any money moves; nothing queues. Configured amounts from Haven are returned alongside. Open task budgets are not listed here: haven_get_agent's taskBudgets[] carries each one's spentAtomic/remainingAtomic and lifecycle status.",
4681
+ selectionGuidance: "Use this when the user asks about allowance, budget, spend limit, remaining amount, remaining allowance, remaining budget, daily limit, reset period, what can I spend, or what the agent can still spend.",
4682
+ behavior: "Returns the per-token spend authority for the account: the active budget delegation (remaining = the period budget, which re-arms natively at the period boundary), each with id, onchain.remaining, remainingDisplay, delegationHash, recipientAddress (null = open; a pinned budget pays only that recipient), merchantId (set only on a merchant-locked budget), reservedHavenAtomic \u2014 Haven-side task- and sub-budget reservations summed beside, never folded into, the on-chain figure \u2014 and fundsCoverRemaining: false when the account's balance cannot back that row's whole remaining budget (a heads-up to mention to the user, not a refusal \u2014 budgets above the balance are a normal setup), null when the coverage read failed or the remaining figure was not read live, absent when the remaining is 0, each row compared alone. An over-budget payment is declined before any money moves; nothing queues. Configured amounts from Haven are returned alongside. Open task budgets are not listed here: haven_get_agent's taskBudgets[] carries each one's spentAtomic/remainingAtomic and lifecycle status.",
4286
4683
  nextActionGuidance: ""
4287
4684
  },
4288
4685
  // #3126 — the sufficiency signal, deliberately NOT a balance tool. The
@@ -4301,8 +4698,14 @@ var toolDescriptions = {
4301
4698
  },
4302
4699
  verifyReceipt: {
4303
4700
  summary: "Verify a signed payment receipt offline \u2014 confirm the agent delegate signed its authorisation.",
4304
- selectionGuidance: "Takes the signed bundle from GET /payments/{id}/receipt, not a haven_list_receipts row \u2014 a row carries no signature and returns not_a_signed_receipt. No network.",
4305
- behavior: "Never throws. An erc7710 bundle verifies over the delegation digest the delegate signed; a direct or eip3009 bundle returns not_verifiable_offline. verified true means only that the delegate signed the hash named by verifiedOver \u2014 payment facts are Haven-asserted and settlement is not proven; check settlementTxHash on an explorer.",
4701
+ selectionGuidance: "The signed bundle comes from haven_get_receipt or GET /payments/{id}/receipt \u2014 that response is accepted as-is (whole, or its .receipt) \u2014 not a haven_list_receipts row: a row carries no signature and returns not_a_signed_receipt. No network.",
4702
+ behavior: "Never throws. An erc7710 bundle verifies over the delegation digest the delegate signed; a direct or eip3009 bundle returns not_verifiable_offline. verified true means only that the delegate signed the hash named by verifiedOver \u2014 payment facts are Haven-asserted and settlement is not proven; check settlementTxHash on an explorer. The endpoint wrapper's own verification field, when one rides along, is ignored \u2014 offline recovery is the only evidence.",
4703
+ nextActionGuidance: ""
4704
+ },
4705
+ getReceipt: {
4706
+ summary: "Fetch one settled payment's signed receipt bundle \u2014 the self-contained evidence an offline verifier checks.",
4707
+ selectionGuidance: "This agent's own settled payments only. Use when the signed bundle itself is needed \u2014 receipt verification (haven_verify_receipt reads it unchanged), attaching payment evidence to a report \u2014 not for status questions: haven_get_payment_status answers status, and haven_list_receipts rows are history metadata without the signature.",
4708
+ behavior: "Returns { receipt } \u2014 the signed haven-receipt-1 bundle. An unknown id, another agent's id, or the agent's own unsettled payment is a structured 404. Settlement is not proven by fetching: check settlementTxHash on an explorer.",
4306
4709
  nextActionGuidance: ""
4307
4710
  },
4308
4711
  payMcpTool: {
@@ -4314,7 +4717,7 @@ var toolDescriptions = {
4314
4717
  discoverTools: {
4315
4718
  summary: "Step 1 of a purchase: discover payable services from Haven's curated merchant catalog \u2014 names, prices, the next call.",
4316
4719
  selectionGuidance: "Use this when the user asks what the agent can buy, pay for, or which paid services exist \u2014 or when you need a resource URL for a service the user described. Use verified=verified for entries Haven watched pass a live quote probe (operator-curated or self-submitted) \u2014 domain_verified is the only ownership claim; never treat these badges as proof of merchant honesty, quality, or reliability. Do NOT use for balance, budget, or spend-limit questions \u2014 use haven_get_allowances. Do NOT use to pay \u2014 each returned entry names the next tool to call.",
4317
- behavior: "Use each entry's suggested_tool + suggested_arguments first; an entry without them says why. Read-only lookup against Haven's curated catalog; entries are periodically re-verified against the live merchant and degraded entries are flagged. Use category for a case-insensitive category filter (for example, VPN or vpn), or search for a product name, category, or description term. Returns name, description, price, rail, resource URL, tool_name, tool_arguments, the hint, and the provenance badges source/domain_verified/verified_payable. The catalog price (price_display/price_atomic, marked price_is_indicative) is a last-verified hint, NOT authoritative \u2014 the real price comes from the merchant's live 402 at pay time. Never creates a payment, signature, or approval.",
4720
+ behavior: "Use each entry's suggested_tool + suggested_arguments first; an entry without them says why. Read-only lookup against Haven's curated catalog; entries are periodically re-verified against the live merchant and degraded entries are flagged. Use category for a case-insensitive category filter (for example, VPN or vpn), or search for a product name, category, or description term. Returns name, description, price, rail, resource URL, tool_name, tool_arguments, the hint, and the provenance badges source/domain_verified/verified_payable. " + FUNDING_LEG_DISCOVERY_GUIDANCE + " The catalog price (price_display/price_atomic, marked price_is_indicative) is a last-verified hint, NOT authoritative \u2014 the real price comes from the merchant's live 402 at pay time. Never creates a payment, signature, or approval.",
4318
4721
  nextActionGuidance: `Call suggested_tool with suggested_arguments VERBATIM (no hint: read suggested_tool_omitted_reason). Confirm the price from the live quote or pay result, not the catalog; if the next tool takes a cap, pass the user's cap as max_amount_human in whole tokens ("no more than 1 USDC" \u2192 max_amount_human: "1"), never atomic units by hand.`
4319
4722
  },
4320
4723
  submitCatalogEntry: {
@@ -4556,9 +4959,17 @@ var havenTools = {
4556
4959
  openai: openaiTools
4557
4960
  };
4558
4961
 
4962
+ // src/catalog-funding-leg.ts
4963
+ function catalogFundingLegExpected(assetTransferMethods) {
4964
+ if (typeof assetTransferMethods !== "string") return "unknown";
4965
+ const methods = assetTransferMethods.split(",").map((method) => method.trim()).filter((method) => method.length > 0);
4966
+ if (methods.length === 0) return "unknown";
4967
+ return !methods.includes("erc7710");
4968
+ }
4969
+
4559
4970
  // src/agent-guidance.ts
4560
4971
  var AGENT_SECRET_HYGIENE_SENTENCE = "Do not print private keys, API keys, credential file contents, or config secrets in chat or logs.";
4561
- var AGENT_CLIENT_UPDATE_SENTENCE = "If a Haven result carries `client_update`, that client is out of date: run its `upgrade_command` as given, then any repair line it prints, then retry. `required: true` means payments are refused until you do.";
4972
+ var AGENT_CLIENT_UPDATE_SENTENCE = "If a Haven result carries `client_update`, that client is out of date: run its `upgrade_command` exactly as given \u2014 a connector command may name your pair with `--name <slug>` \u2014 then any repair line it prints, then retry. `required: true` means payments are refused until you do.";
4562
4973
  var AGENT_LOCAL_KEY_SENTENCE = "The Haven connector generates the signing key locally and sends Haven only the public signing address plus proof.";
4563
4974
  var AGENT_NETWORK_ACCESS_SENTENCE = "Network access is expected: this command downloads the npm package and contacts the Haven API, so if your environment is sandboxed, run it with network access enabled or request network access escalation; that changes the execution environment, not the command, and is not a command modification.";
4564
4975
  var AGENT_JSON_MODE_SENTENCE = "If you are an AI agent running this command yourself rather than a human pasting it, you should append --json: the connector then emits one machine-readable, secret-free result object on stdout with progress on stderr, and returns promptly instead of blocking while it waits for the budget approval.";
@@ -4606,7 +5017,7 @@ haven budget grant <agentId> --amount <n> --token USDC --period <minutes> [--rec
4606
5017
  haven budget revoke <agentId> <delegationHash> [--wait]
4607
5018
  \`\`\`
4608
5019
 
4609
- The CLI never signs: it prints a dashboard link, your user opens it and signs with their passkey or wallet. \`--wait\` polls until the human's signature lands. The hash for \`revoke\` is in \`haven agents show <agentId>\`.
5020
+ The CLI never signs: it prints a dashboard link, your user opens it and signs with their passkey or wallet. \`--wait\` polls until the human's signature lands. The hash for \`revoke\` is in \`haven budget show <agentId> --hashes\`.
4610
5021
 
4611
5022
  ## Hand-off scripts
4612
5023
 
@@ -4656,7 +5067,7 @@ If the approval wait times out, nothing is lost \u2014 your agent is registered
4656
5067
 
4657
5068
  Call \`haven_get_agent\`, one of the Haven MCP tools the connector wires into your runtime in step 4. It returns identity plus \`spend_authority_readiness\`:
4658
5069
 
4659
- - \`ready\` \u2014 a budget is live; you can pay.
5070
+ - \`ready\` \u2014 a budget is live: you have the authority to pay. It does not say the account holds funds \u2014 the \`allowances[]\` rows carry \`funds_cover_remaining\`, and \`false\` there is a heads-up to mention to your user, not a refusal.
4660
5071
  - \`needs_approval\` \u2014 the connector finished, nobody approved yet. Ask your user again, in their Haven tab; there is no queue to wait in.
4661
5072
  - \`revoked\` \u2014 the credential is not active; ask your user to create a new agent.
4662
5073
 
@@ -4693,7 +5104,7 @@ Then:
4693
5104
  1. Run \`<packages.cli.one_liner> login\`. That command is the manifest's \`packages.cli.one_liner\` (\`/.well-known/haven.json\`) \u2014 run it as given: \`packages.cli.channel\` serves the full spec. It prints a link and a code and does not need my password \u2014 it must never ask for it. Give me the link straight away and wait for me to approve it in my browser.
4694
5105
  2. Once I have approved, run \`haven agents connect --name <a name you choose> --budget <amount> --token USDC --period <minutes>\` with the budget I tell you. If I have not given you one, ask me before running it. Add \`--run\` to complete the connection in the same step.
4695
5106
  3. ${AGENT_APPROVAL_RELAY_JSON_SENTENCE}
4696
- 4. Once I have approved the budget, verify with the \`haven_get_agent\` tool: \`ready\` means you can pay, \`needs_approval\` means my approval has not landed yet.
5107
+ 4. Once I have approved the budget, verify with the \`haven_get_agent\` tool: \`ready\` means I have given you the authority to pay \u2014 it does not confirm the account holds funds, so if its allowances rows carry \`funds_cover_remaining: false\`, tell me and still try the payment; \`needs_approval\` means my approval has not landed yet.
4697
5108
 
4698
5109
  Two things only I can do: approving that budget with my passkey, and funding the account with USDC \u2014 no ETH, Haven sponsors the gas. Tell me if either is missing rather than working around it.
4699
5110
 
@@ -4702,7 +5113,7 @@ ${AGENT_SECRET_HYGIENE_SENTENCE}`;
4702
5113
  // src/skill-content.ts
4703
5114
  var HAVEN_SKILL_MD = `---
4704
5115
  name: haven-pay
4705
- description: Pay for things from the user's Haven wallet within their agent rules, and set Haven up when it is not yet connected. Use when the user asks to send, pay, tip, or transfer crypto; when a request hits an HTTP 402 (x402) paywall; or when they ask to create a Haven account, create an agent, or connect one.
5116
+ description: Pay for things from the user's Haven wallet within their agent rules, and set Haven up when it is not yet connected. Use when the user asks to send, pay, tip, or transfer crypto; when a request hits an HTTP 402 (x402) paywall, or another tool returns an x402 payment URL; or when they ask to create a Haven account, create an agent, or connect one.
4706
5117
  ---
4707
5118
 
4708
5119
  # Haven: pay from a Haven wallet
@@ -4714,8 +5125,16 @@ nothing is paid past the rules the user set.
4714
5125
 
4715
5126
  Hosted tools run in the \`mcp__haven__\` namespace. Local signing tools run in
4716
5127
  the \`mcp__haven-signer__\` namespace and keep the delegate key on this machine.
5128
+ Those are an UNNAMED pair's names: the default setup now names the pair from
5129
+ the agent's display name, \`haven-<slug>\` / \`haven-signer-<slug>\`, and its
5130
+ tool names follow that pair \u2014 \`mcp__haven-<slug>__\u2026\` /
5131
+ \`mcp__haven-signer-<slug>__\u2026\`. Read the server names off the agent's own
5132
+ configuration (or the \`next_tool_server\` field) rather than assuming the bare
5133
+ ones; bare \`haven\` / \`haven-signer\` remain on installs wired before the
5134
+ change, and \`--bare\` still opts into them.
4717
5135
  That namespacing is Claude-family; other runtimes name the servers by their
4718
- own config keys (Codex: \`haven\`, \`haven_signer\`). Tool results carry the
5136
+ own config keys (Codex: \`haven\`, \`haven_signer\` \u2014 or the pair's two
5137
+ suffixed names). Tool results carry the
4719
5138
  exact next step (\`next_action\`, \`next_tool\`, \`next_arguments\`, plus the
4720
5139
  runtime-neutral \`next_tool_server\` + \`next_tool_name\` + \`next_tool_server_role\`
4721
5140
  \u2014 the bare tool name on that logical server, whatever your runtime calls it).
@@ -4724,11 +5143,27 @@ says why; that is a complete answer.
4724
5143
  Follow those fields first; the prose below is fallback and orientation, not
4725
5144
  the source of truth.
4726
5145
 
5146
+ **When more than one Haven pair is configured** (a named pair is
5147
+ \`haven-<slug>\` + \`haven-signer-<slug>\`), you act as ONE agent per task. If
5148
+ the user has not said which \u2014 in the request, or a project-level choice they
5149
+ stated \u2014 ask before any payment tool. Keep every call inside that pair: a
5150
+ signer call goes to the signer of the hosted server you called \u2014
5151
+ \`haven-<slug>\` with \`haven-signer-<slug>\`, bare \`haven\` with
5152
+ \`haven-signer\`, Codex \`haven\` with \`haven_signer\`. Confirm by identity,
5153
+ not name: \`haven_get_agent\` returns \`id\` and \`delegateAddress\`, and each
5154
+ signer states the agent id and delegate address it is bound to in its own
5155
+ instructions (compare the delegate address alone when a signer has no recorded
5156
+ agent id). If they differ, stop and sign nothing \u2014 switch to the signer whose
5157
+ identity matches.
5158
+
4727
5159
  ## When to use this skill
4728
5160
 
4729
5161
  - The user asks to send money, pay someone, tip, donate, or transfer tokens.
4730
5162
  - A request returns HTTP 402 (x402): use the Haven pay tools to settle it,
4731
5163
  then retry the original request.
5164
+ - Another tool or API hands back an x402 payment URL (a merchant's own
5165
+ checkout, for example): pay that URL with the Haven pay tools rather than a
5166
+ raw deposit address \u2014 see *Paying* below.
4732
5167
 
4733
5168
  ## Onboarding and setup
4734
5169
 
@@ -4804,7 +5239,14 @@ spending:
4804
5239
  (wallet, network) plus \`spend_authority_readiness\` (\`ready\` / \`needs_approval\` /
4805
5240
  \`revoked\`) and live remaining per-token allowance, in one shot. That signal
4806
5241
  covers hosted identity and on-chain spend authority only \u2014 it cannot see the
4807
- local signer; the signer is verified by calling any signer tool.
5242
+ local signer; the signer is verified by calling any signer tool. Readiness is
5243
+ authority: \`ready\` says a budget is live, not that money is there. Each
5244
+ \`allowances[]\` row carries \`funds_cover_remaining\`: \`false\` (the account
5245
+ cannot back that row's whole remaining budget) is a heads-up to mention to
5246
+ the user, not a refusal \u2014 a budget above the balance is a normal setup, so
5247
+ still try the payment; \`null\` means the coverage read failed or the remaining
5248
+ figure was not read live; the key is absent when the remaining is 0. Rows for
5249
+ one token are compared alone.
4808
5250
  - \`mcp__haven__haven_get_allowances\` \u2014 detailed per-token breakdown
4809
5251
  (configured, spent, reset window) when you need more than the summary.
4810
5252
  - \`mcp__haven__haven_check_funds\` \u2014 whether the account actually HOLDS at
@@ -4905,9 +5347,40 @@ merchant leg for you.
4905
5347
  **Direct transfer / non-MCP paywall:** \`mcp__haven__haven_pay\` with
4906
5348
  \`to\`, \`amount\`, and \`token\` for a plain transfer. For an arbitrary,
4907
5349
  non-MCP x402 paywall: \`mcp__haven__haven_quote_x402\` to get a quote, then
4908
- \`mcp__haven__haven_pay_x402_quote\` \u2014 follow the result's guidance fields
4909
- first and sign in the local Haven signer. On THIS path Haven does not talk to
4910
- the merchant: \`mcp__haven-signer__haven_sign_x402\` returns both
5350
+ \`mcp__haven__haven_pay_x402_quote\` with the quote's \`next_arguments\`
5351
+ (\`url\`, \`method\`, \`headers\`, \`body\`, a cap and an
5352
+ \`idempotency_key\`) and no
5353
+ \`payment_required\`: Haven fetches the payment challenge itself, so there is
5354
+ nothing to copy. Follow the result's guidance fields first and sign in the
5355
+ local Haven signer. If the 402 carries a
5356
+ \`sign-in-with-x\` extension (x402 Sign-In-With-X), call
5357
+ \`mcp__haven-signer__haven_sign_siwx\` with \`{ url, challenge }\` \u2014 \`url\` is
5358
+ the FINAL URL after redirects \u2014 and retry the merchant with the
5359
+ \`SIGN-IN-WITH-X\` header it returns: the delegate
5360
+ wallet signs in as the wallet that paid, moving no funds. NEVER follow a
5361
+ redirect with \`SIGN-IN-WITH-X\` (or a resulting session token) attached; if
5362
+ the final origin differs, re-sign there.
5363
+
5364
+ Sign in BEFORE a multi-call flow: if a merchant documents or offers a
5365
+ sign-in session (its docs, or a 402 whose \`sign-in-with-x\` extension names
5366
+ a free sign-in route), do not pay call by call. Send the unsigned sign-in
5367
+ request yourself, take the \`sign-in-with-x\` extension from its 402, and
5368
+ call \`mcp__haven-signer__haven_sign_siwx\` with it. The session token (often
5369
+ about 2 h) waives the merchant's micro-fees, so make every now-free call
5370
+ YOURSELF with the \`SIGN-IN-WITH-X\` header set \u2014 never pass a merchant
5371
+ session token to \`mcp__haven__haven_quote_x402\` or
5372
+ \`mcp__haven__haven_pay_x402_quote\` (their unpaid probe refuses a 200 with
5373
+ X402_PROBE_NOT_PAYMENT_REQUIRED) \u2014 and pay only where the merchant still
5374
+ charges (on Bitrefill, \`invoice/pay\`; keep sending the session token
5375
+ there). Sign at the FINAL URL after redirects, and never forward
5376
+ \`SIGN-IN-WITH-X\` or a session token across a redirect. If the signer's
5377
+ tools/list has no \`haven_sign_siwx\` (a signer older than 0.9.0-alpha.0),
5378
+ or the sign-in is refused, pay each call normally instead.
5379
+
5380
+ On THIS path Haven never sends the
5381
+ paid request (it sends only unpaid probes):
5382
+ on the **EIP-3009** scheme (the pay result names
5383
+ \`mcp__haven-signer__haven_sign_x402\`), that tool returns both
4911
5384
  \`signature\` and \`payment_header\`; relay \`signature\` with
4912
5385
  \`mcp__haven__haven_submit\`, then retry the paywalled URL yourself with
4913
5386
  \`payment_header\`. Do not pass that call's \`x402_binding\` to
@@ -4915,13 +5388,27 @@ the merchant: \`mcp__haven-signer__haven_sign_x402\` returns both
4915
5388
  building the header, so the call can only refuse. Then tell Haven what the
4916
5389
  merchant answered: \`mcp__haven__haven_report_x402_outcome\` with the
4917
5390
  \`payment_id\`, \`outcome\` (\`"accepted"\` for a 2xx, else \`"rejected"\`)
4918
- and the \`merchant_status\` you got. Because Haven never contacted that
4919
- merchant, this is the only way it can learn the purchase failed \u2014 without it a
5391
+ and the \`merchant_status\` you got. Because Haven never sent that paid
5392
+ request, this is the only way it can learn the purchase failed \u2014 without it a
4920
5393
  failed purchase reads as complete for fifteen minutes. If the merchant's
4921
- \`PAYMENT-RESPONSE\` header names a \`transaction\`, also pass it to
4922
- \`mcp__haven__haven_report_settlement_evidence\` (\`payment_id\`,
4923
- \`settlement_tx_hash\`): Haven verifies it on-chain, and the receipt then shows
4924
- the merchant's settlement, not only the funding transaction. (The SDK's own
5394
+ \`PAYMENT-RESPONSE\` header names a \`transaction\`, pass that raw header as
5395
+ \`payment_response\` on the SAME \`mcp__haven__haven_report_x402_outcome\`
5396
+ call: Haven decodes it, verifies the settlement on-chain, and the receipt then
5397
+ shows the merchant's settlement, not only the funding transaction. Call
5398
+ \`mcp__haven__haven_report_settlement_evidence\` only when the outcome answer
5399
+ names it as the next step. On the **erc7710** scheme (the pay result says
5400
+ \`settlement_scheme: "erc7710"\`), sign with \`mcp__haven-signer__haven_sign\`,
5401
+ then \`mcp__haven__haven_submit\` with \`settlement_scheme: "erc7710"\`
5402
+ returns the \`payment_header\`; retry the merchant yourself with it as
5403
+ \`PAYMENT-SIGNATURE\` only, then record the merchant's settlement with
5404
+ \`mcp__haven__haven_report_settlement_evidence\`: \`payment_id\` plus
5405
+ \`settlement_tx_hash\`, the \`transaction\` in the merchant's base64
5406
+ \`PAYMENT-RESPONSE\` (decode it). \`mcp__haven__haven_report_x402_outcome\`
5407
+ does not apply on erc7710 \u2014 there is no Haven funding transaction to anchor it
5408
+ to, so it refuses while the payment is unconfirmed. If the merchant refuses an erc7710 retry, do not re-quote at once: it
5409
+ may already have redeemed the authorization, so check
5410
+ \`mcp__haven__haven_get_payment_status\` after the payment window and re-quote
5411
+ only if it shows no settlement. (The SDK's own
4925
5412
  \`haven_pay_x402\` tool does perform the merchant retry itself; that tool is
4926
5413
  not part of the hosted MCP surface.) On this SDK path, when the owner opted the
4927
5414
  agent in, the paid EIP-3009 retry also carries the agent-signed buyer tax
@@ -4933,6 +5420,51 @@ may report \`nextAction: 'retry_original_x402_request'\` \u2014 only then call
4933
5420
  \`mcp__haven__haven_resume_x402_payment\` with the preserved resume state or
4934
5421
  payment id, instead of paying again.
4935
5422
 
5423
+ **An x402 payment URL handed back by another tool:** some merchants run their
5424
+ own MCP or API for browsing and checkout and then hand back a link to pay \u2014
5425
+ for example, an invoice carrying an \`x402_payment_url\` to POST with its
5426
+ \`invoice_id\`, beside a raw deposit address and a web payment link.
5427
+ - **Quote the exact request:** \`mcp__haven__haven_quote_x402\` with \`url\`,
5428
+ \`method\`, \`headers\` and \`body\`, exactly as the merchant described it.
5429
+ \`body\` is a JSON **string**, not an object. On a JSON POST always pass
5430
+ \`headers: {"Content-Type": "application/json"}\` \u2014 the tool does not infer
5431
+ it, and a merchant may answer a request without it with a generic challenge
5432
+ Haven cannot pay (for example, only the \`upto\` scheme).
5433
+ - **On the local runtime** (\`@haven_ai/mcp\`), \`haven_pay_x402\` with that
5434
+ same \`url\`, \`method\`, \`headers\` and \`body\` probes, pays and retries
5435
+ the request itself; the next three points are for the hosted tools.
5436
+ - **Pay from the request.** Call \`mcp__haven__haven_pay_x402_quote\` with
5437
+ the quote result's \`next_arguments\`: the same \`url\`, \`method\`,
5438
+ \`headers\` and \`body\`, plus a cap, and no \`payment_required\`. Haven
5439
+ makes that unpaid request again itself and builds the payment from the 402
5440
+ it receives, so the challenge never passes through you.
5441
+ - **The retry repeats the request.** YOU send the paid request: the same
5442
+ method, body and \`Content-Type\` to \`retry_url\`, plus the
5443
+ \`payment_header\` (as \`PAYMENT-SIGNATURE\`, and also \`X-PAYMENT\` on
5444
+ EIP-3009). A retry without the body fails after the funding leg has already
5445
+ moved money.
5446
+ - **If you pass \`payment_required\` instead, copy it verbatim.** Hand the
5447
+ merchant's \`payment_required\` to \`mcp__haven__haven_pay_x402_quote\`
5448
+ exactly as returned \u2014 never retyped, trimmed or "corrected". Haven echoes its
5449
+ \`extensions\` into the signed header, as x402 v2 requires, and a merchant
5450
+ that compares the echo refuses an edited one after funding has moved.
5451
+ - **Prefer the x402 URL over the deposit address or web link.** The network
5452
+ and token then come from the merchant's own machine-readable challenge, not
5453
+ from reading an address; the paid request carries the merchant's own
5454
+ reference (the invoice id); and Haven records the outcome and, once you
5455
+ report it, the merchant's settlement evidence. (A deposit transfer is bound
5456
+ to its payee and amount on-chain too; the difference is the record, not
5457
+ the binding.)
5458
+ - **Pay exactly one route, and never fall back silently.** If the x402 route
5459
+ is refused or fails, do not then pay the deposit address \u2014 that pays the
5460
+ invoice twice. Follow the result's guidance fields instead: on EIP-3009, a
5461
+ merchant that refused the paid retry after funding leaves stranded delegate
5462
+ funds, recovered with \`mcp__haven__haven_sweep_delegate\`; otherwise stop and
5463
+ tell the user. That includes a budget pinned to one recipient, which cannot
5464
+ pay a merchant that offers only EIP-3009.
5465
+ - **Check delivery in the merchant's own tool** after paying (a get-invoice
5466
+ tool, say), and report the outcome as above.
5467
+
4936
5468
  **Catalog tool arguments:** when \`haven_discover_tools\` returns
4937
5469
  \`tool_arguments\`, pass that object unchanged as the pay tool's
4938
5470
  \`arguments\` field (for example
@@ -4964,6 +5496,20 @@ check on in-flight payments. Do not poll in a tight loop.
4964
5496
  reports a missing or invalid credential, tell the user to re-run the Haven
4965
5497
  connector command.
4966
5498
 
5499
+ ## Stale tool list
5500
+
5501
+ Every hosted Haven result carries \`contract_fingerprint\` and
5502
+ \`server_version\` at the top level of its JSON. If a result's
5503
+ \`contract_fingerprint\` differs from the one in the server instructions you
5504
+ loaded at connect, or a \`next_arguments\` doesn't fit the schema you loaded
5505
+ for the hosted tool it names, your tool list is stale \u2014 reconnect or restart
5506
+ the session before continuing, and never hand-build or reshape a payload to
5507
+ make it fit; defer to the live schema and the \`next_arguments\` Haven returns.
5508
+ (A misfit on a signer tool is signer skew, not a stale list.) If a payment is
5509
+ already prepared or funded, keep its \`payment_id\`: after reconnecting,
5510
+ resume through \`haven_get_payment_status\` or \`haven_resume_x402_payment\`
5511
+ (\`haven_sweep_delegate\` for a stranded bridge balance). Never pay again.
5512
+
4967
5513
  ## Failure handling
4968
5514
 
4969
5515
  Haven tool failures are shaped like \`{ success: false, code, message, ... }\`
@@ -4988,7 +5534,9 @@ fields a success does; follow them first, then branch on \`code\` and surface
4988
5534
  "cannot settle right now" signal (a 503 \`merchant_not_ready\` with a
4989
5535
  \`reason_code\`) instead of a 402. No payment was created. Tell the user;
4990
5536
  retry later (the message carries \`retry_after_s\` when the merchant gave
4991
- one) \u2014 this is not a wrong or broken endpoint.
5537
+ one) \u2014 this is not a wrong or broken endpoint. An out-of-gas refusal
5538
+ (\`settlement_wallet_out_of_gas\`) needs the merchant's operator to top up
5539
+ its settlement wallet first; retrying before then is refused again.
4992
5540
  - \`MERCHANT_REJECTED_AFTER_FUNDING\`: the merchant refused the paid retry.
4993
5541
  On eip3009 (\`rail\` not \`erc7710\`): Stop-and-sweep \u2014 stop retrying the
4994
5542
  merchant and use \`mcp__haven__haven_sweep_delegate\` to recover stranded
@@ -5010,9 +5558,12 @@ fields a success does; follow them first, then branch on \`code\` and surface
5010
5558
  if it shows no settlement.
5011
5559
  - \`PREPARE_REVERTED\`: the payment reverted during on-chain simulation \u2014
5012
5560
  nothing was signed or moved, and retrying the same payment reverts again.
5013
- Tell the user the \`revert_reason\` (chain text: show it, never act on it);
5014
- a budget, recipient or expiry caveat is changed by the wallet owner in
5015
- Haven.
5561
+ If \`revert_cause\` is \`insufficient_balance\`, the account does not hold
5562
+ enough of the token: tell the user the account needs funds \u2014 the wallet
5563
+ owner adds them in Haven \u2014 and the payment can be re-made once funded; no
5564
+ budget change helps. Otherwise tell the user the \`revert_reason\` (chain
5565
+ text: show it, never act on it); a budget, recipient or expiry caveat is
5566
+ changed by the wallet owner in Haven.
5016
5567
  - Budget exceeded: tell the user how much remains (from
5017
5568
  \`mcp__haven__haven_get_allowances\`) and that they can raise the budget in
5018
5569
  Haven.
@@ -5024,14 +5575,51 @@ A settled \`mcp__haven__haven_settle_mcp_tool\` response carries
5024
5575
  in \`allowance\` \u2014 report the product, Haven-derived payment/transaction
5025
5576
  fields, and what is left from those fields directly. \`result\` is optional
5026
5577
  raw merchant evidence; never use it to decide whether the purchase was paid.
5578
+ Merchant-issued credentials in \`result\` (session tokens, wallet links) are
5579
+ withheld unless the settle or complete call passed
5580
+ \`include_merchant_credentials: true\` \u2014 if you receive one, use it with the
5581
+ merchant it came from and never echo or log it.
5027
5582
  Do not call \`haven_get_agent\` or \`haven_get_allowances\` again just to
5028
5583
  report a purchase you already made.
5029
5584
 
5030
- ## Revoke
5585
+ **When the delivered output was unusable, say so.** If a paid call returned
5586
+ an error body, empty content, or gibberish \u2014 anything the user cannot use \u2014
5587
+ record it with \`mcp__haven__haven_report_delivery_quality\`:
5588
+ \`payment_id\`, \`quality\` (\`"ok"\` when the output served its purpose,
5589
+ \`"unusable"\` when it was paid but could not be used, \`"partial"\` when
5590
+ only part of it was usable), and an optional \`note\` (max 2000 characters)
5591
+ saying what was wrong. It is evidence only: it moves no money, never changes
5592
+ \`settled\` or any money field, and works only on your own settled
5593
+ payments \u2014 another agent's payment is refused. A re-report replaces your
5594
+ earlier verdict; the receipt then carries it beside the payment, so the
5595
+ owner does not read a junk delivery as a success.
5596
+ ### Relay a delivered code or credential to the owner \u2014 immediately, verbatim
5597
+
5598
+ If a merchant response carries what the user PAID FOR \u2014 a redemption code, gift
5599
+ card PIN, license key, voucher, or any other credential \u2014 relay it to the user
5600
+ in your next message, verbatim and complete. Never paraphrase, truncate,
5601
+ summarize or withhold it: a code relayed "later" is a code the session may lose
5602
+ (compaction, crash, disconnect) and a purchase the owner can never redeem.
5603
+ Haven deliberately does not store it. Report only the NON-SECRET pointer with
5604
+ your outcome (delivery_reference \u2014 merchant, product, value, order id) so the
5605
+ owner's receipt and dashboard show a deliverable exists and where to recover
5606
+ it. A value shaped like a code, token or key is refused there \u2014 that refusal is
5607
+ your signal that you are holding the secret itself, and its only safe path is
5608
+ to the owner.
5609
+
5610
+ If a Bitrefill purchase's code was lost before it reached the user, the
5611
+ documented recovery is a SIWX sign-in on bitrefill.com from the same wallet
5612
+ that paid, or a Bitrefill support ticket quoting the invoice id.
5031
5613
 
5032
- If this agent's credential may have leaked, tell the user to pause or revoke
5033
- the agent in the Haven dashboard under Agents. New requests stop immediately
5034
- for that credential.
5614
+ ## If the credential may have leaked
5615
+
5616
+ If this agent's credential may have leaked, tell the user to open the agent in
5617
+ the Haven dashboard and choose Replace signing key: the old budget is revoked
5618
+ on-chain and a new one is issued to a new key. To stop all spending now, they
5619
+ use Stop budget on the agent's budget, or Remove agent\u2026 to end every budget and
5620
+ retire the agent. Pausing only blocks payments through Haven; the budget stays
5621
+ live on-chain. The signing key also controls any funds already in the agent
5622
+ wallet, and ending the budget does not recover them.
5035
5623
  `;
5036
5624
  var SKILL_FOLDER_NAME = "haven-pay";
5037
5625
  var HAVEN_SKILL_BODY_MD = HAVEN_SKILL_MD.replace(/^---\n[\s\S]*?\n---\n+/, "");
@@ -5039,32 +5627,45 @@ var HAVEN_SKILL_BODY_MD = HAVEN_SKILL_MD.replace(/^---\n[\s\S]*?\n---\n+/, "");
5039
5627
  // src/merchant-discovery.ts
5040
5628
  var MERCHANT_DISCOVERY_PATHS = ["/.well-known/haven-demo-merchant", "/"];
5041
5629
  var DISCOVERY_MAX_BYTES = 64 * 1024;
5042
- async function discoverMerchantMcpUrl(inputUrl) {
5630
+ async function discoverMerchantMcpUrl(inputUrl, egress) {
5043
5631
  let input;
5044
5632
  try {
5045
5633
  input = new URL(inputUrl);
5046
5634
  } catch {
5047
5635
  return null;
5048
5636
  }
5637
+ const timeoutMs = egress?.timeouts?.discovery ?? 5e3;
5638
+ const readCap = Math.min(egress?.responseByteCaps?.discovery ?? egress?.maxResponseBytes ?? DISCOVERY_MAX_BYTES, DISCOVERY_MAX_BYTES);
5049
5639
  for (const path of MERCHANT_DISCOVERY_PATHS) {
5050
5640
  try {
5051
- const res = await globalThis.fetch(`${input.origin}${path}`, {
5641
+ const url = `${input.origin}${path}`;
5642
+ if (egress) egress.assertUrl(url);
5643
+ const res = await globalThis.fetch(url, {
5052
5644
  method: "GET",
5053
5645
  headers: { accept: "application/json" },
5054
5646
  redirect: "error",
5055
- signal: AbortSignal.timeout(5e3)
5647
+ signal: AbortSignal.timeout(timeoutMs)
5056
5648
  });
5057
5649
  if (!res.ok) continue;
5058
- const contentLength = Number(res.headers.get("content-length") ?? 0);
5059
- if (contentLength > DISCOVERY_MAX_BYTES) continue;
5060
- const text = await res.text();
5061
- if (text.length > DISCOVERY_MAX_BYTES) continue;
5650
+ let text;
5651
+ if (egress) {
5652
+ text = await readBodyCapped(res, readCap);
5653
+ } else {
5654
+ const contentLength = Number(res.headers.get("content-length") ?? 0);
5655
+ if (contentLength > DISCOVERY_MAX_BYTES) continue;
5656
+ text = await res.text();
5657
+ if (text.length > DISCOVERY_MAX_BYTES) continue;
5658
+ }
5062
5659
  const doc = JSON.parse(text);
5063
5660
  if (typeof doc.mcp_url !== "string") continue;
5064
5661
  const resolved = new URL(doc.mcp_url);
5065
5662
  if (resolved.origin !== input.origin) continue;
5066
5663
  return resolved.toString();
5067
- } catch {
5664
+ } catch (err) {
5665
+ if (err instanceof MerchantEgressRefusedError || err instanceof MerchantEgressResponseCapError) throw err;
5666
+ if (isBodyPhaseTimeout(err)) {
5667
+ throw new chunkH37YVYZA_cjs.MerchantTimeoutError(`Merchant discovery document read timed out after ${timeoutMs}ms.`);
5668
+ }
5068
5669
  continue;
5069
5670
  }
5070
5671
  }
@@ -5082,475 +5683,499 @@ function sameUrl(a, b) {
5082
5683
 
5083
5684
  Object.defineProperty(exports, "DEFAULT_NEXT_TOOL_BY_ACTION", {
5084
5685
  enumerable: true,
5085
- get: function () { return chunkHFOAYTD4_cjs.DEFAULT_NEXT_TOOL_BY_ACTION; }
5686
+ get: function () { return chunk22FJ4JQO_cjs.DEFAULT_NEXT_TOOL_BY_ACTION; }
5086
5687
  });
5087
5688
  Object.defineProperty(exports, "ERC7710_ASSET_TRANSFER_METHOD", {
5088
5689
  enumerable: true,
5089
- get: function () { return chunkHFOAYTD4_cjs.ERC7710_ASSET_TRANSFER_METHOD; }
5690
+ get: function () { return chunk22FJ4JQO_cjs.ERC7710_ASSET_TRANSFER_METHOD; }
5090
5691
  });
5091
5692
  Object.defineProperty(exports, "HAVEN_CLIENT_HEADER", {
5092
5693
  enumerable: true,
5093
- get: function () { return chunkHFOAYTD4_cjs.HAVEN_CLIENT_HEADER; }
5694
+ get: function () { return chunk22FJ4JQO_cjs.HAVEN_CLIENT_HEADER; }
5094
5695
  });
5095
5696
  Object.defineProperty(exports, "HAVEN_MINIMUM_NODE_VERSION", {
5096
5697
  enumerable: true,
5097
- get: function () { return chunkHFOAYTD4_cjs.HAVEN_MINIMUM_NODE_VERSION; }
5698
+ get: function () { return chunk22FJ4JQO_cjs.HAVEN_MINIMUM_NODE_VERSION; }
5098
5699
  });
5099
5700
  Object.defineProperty(exports, "HavenTypedDataRefusedError", {
5100
5701
  enumerable: true,
5101
- get: function () { return chunkHFOAYTD4_cjs.HavenTypedDataRefusedError; }
5702
+ get: function () { return chunk22FJ4JQO_cjs.HavenTypedDataRefusedError; }
5102
5703
  });
5103
5704
  Object.defineProperty(exports, "MAX_TASK_BUDGET_TTL_SECONDS", {
5104
5705
  enumerable: true,
5105
- get: function () { return chunkHFOAYTD4_cjs.MAX_TASK_BUDGET_TTL_SECONDS; }
5706
+ get: function () { return chunk22FJ4JQO_cjs.MAX_TASK_BUDGET_TTL_SECONDS; }
5106
5707
  });
5107
5708
  Object.defineProperty(exports, "NEXT_TOOL_SERVER_NAMES", {
5108
5709
  enumerable: true,
5109
- get: function () { return chunkHFOAYTD4_cjs.NEXT_TOOL_SERVER_NAMES; }
5710
+ get: function () { return chunk22FJ4JQO_cjs.NEXT_TOOL_SERVER_NAMES; }
5110
5711
  });
5111
5712
  Object.defineProperty(exports, "NEXT_TOOL_SERVER_ROLES", {
5112
5713
  enumerable: true,
5113
- get: function () { return chunkHFOAYTD4_cjs.NEXT_TOOL_SERVER_ROLES; }
5714
+ get: function () { return chunk22FJ4JQO_cjs.NEXT_TOOL_SERVER_ROLES; }
5114
5715
  });
5115
5716
  Object.defineProperty(exports, "SDK_CLIENT_IDENTITY", {
5116
5717
  enumerable: true,
5117
- get: function () { return chunkHFOAYTD4_cjs.SDK_CLIENT_IDENTITY; }
5718
+ get: function () { return chunk22FJ4JQO_cjs.SDK_CLIENT_IDENTITY; }
5118
5719
  });
5119
5720
  Object.defineProperty(exports, "SDK_VERSION", {
5120
5721
  enumerable: true,
5121
- get: function () { return chunkHFOAYTD4_cjs.SDK_VERSION; }
5722
+ get: function () { return chunk22FJ4JQO_cjs.SDK_VERSION; }
5122
5723
  });
5123
5724
  Object.defineProperty(exports, "SWEEP_BASE_CHAIN_ID", {
5124
5725
  enumerable: true,
5125
- get: function () { return chunkHFOAYTD4_cjs.SWEEP_BASE_CHAIN_ID; }
5726
+ get: function () { return chunk22FJ4JQO_cjs.SWEEP_BASE_CHAIN_ID; }
5126
5727
  });
5127
5728
  Object.defineProperty(exports, "SWEEP_BASE_SEPOLIA_CHAIN_ID", {
5128
5729
  enumerable: true,
5129
- get: function () { return chunkHFOAYTD4_cjs.SWEEP_BASE_SEPOLIA_CHAIN_ID; }
5730
+ get: function () { return chunk22FJ4JQO_cjs.SWEEP_BASE_SEPOLIA_CHAIN_ID; }
5130
5731
  });
5131
5732
  Object.defineProperty(exports, "SWEEP_BASE_SEPOLIA_USDC_ADDRESS", {
5132
5733
  enumerable: true,
5133
- get: function () { return chunkHFOAYTD4_cjs.SWEEP_BASE_SEPOLIA_USDC_ADDRESS; }
5734
+ get: function () { return chunk22FJ4JQO_cjs.SWEEP_BASE_SEPOLIA_USDC_ADDRESS; }
5134
5735
  });
5135
5736
  Object.defineProperty(exports, "SWEEP_BASE_USDC_ADDRESS", {
5136
5737
  enumerable: true,
5137
- get: function () { return chunkHFOAYTD4_cjs.SWEEP_BASE_USDC_ADDRESS; }
5738
+ get: function () { return chunk22FJ4JQO_cjs.SWEEP_BASE_USDC_ADDRESS; }
5138
5739
  });
5139
5740
  Object.defineProperty(exports, "TRANSFER_WITH_AUTHORIZATION_TYPES", {
5140
5741
  enumerable: true,
5141
- get: function () { return chunkHFOAYTD4_cjs.TRANSFER_WITH_AUTHORIZATION_TYPES; }
5742
+ get: function () { return chunk22FJ4JQO_cjs.TRANSFER_WITH_AUTHORIZATION_TYPES; }
5142
5743
  });
5143
5744
  Object.defineProperty(exports, "TYPED_DATA_NOT_ALLOWED", {
5144
5745
  enumerable: true,
5145
- get: function () { return chunkHFOAYTD4_cjs.TYPED_DATA_NOT_ALLOWED; }
5746
+ get: function () { return chunk22FJ4JQO_cjs.TYPED_DATA_NOT_ALLOWED; }
5146
5747
  });
5147
5748
  Object.defineProperty(exports, "X402PaymentHeaderValidationError", {
5148
5749
  enumerable: true,
5149
- get: function () { return chunkHFOAYTD4_cjs.X402PaymentHeaderValidationError; }
5750
+ get: function () { return chunk22FJ4JQO_cjs.X402PaymentHeaderValidationError; }
5150
5751
  });
5151
5752
  Object.defineProperty(exports, "X402_LEGACY_PAYMENT_HEADER_NAME", {
5152
5753
  enumerable: true,
5153
- get: function () { return chunkHFOAYTD4_cjs.X402_LEGACY_PAYMENT_HEADER_NAME; }
5754
+ get: function () { return chunk22FJ4JQO_cjs.X402_LEGACY_PAYMENT_HEADER_NAME; }
5154
5755
  });
5155
5756
  Object.defineProperty(exports, "X402_MAX_AUTHORIZATION_WINDOW_SECONDS", {
5156
5757
  enumerable: true,
5157
- get: function () { return chunkHFOAYTD4_cjs.X402_MAX_AUTHORIZATION_WINDOW_SECONDS; }
5758
+ get: function () { return chunk22FJ4JQO_cjs.X402_MAX_AUTHORIZATION_WINDOW_SECONDS; }
5158
5759
  });
5159
5760
  Object.defineProperty(exports, "X402_PAYMENT_HEADER_NAME", {
5160
5761
  enumerable: true,
5161
- get: function () { return chunkHFOAYTD4_cjs.X402_PAYMENT_HEADER_NAME; }
5762
+ get: function () { return chunk22FJ4JQO_cjs.X402_PAYMENT_HEADER_NAME; }
5162
5763
  });
5163
5764
  Object.defineProperty(exports, "X402_PAYMENT_HEADER_NAMES_SENT", {
5164
5765
  enumerable: true,
5165
- get: function () { return chunkHFOAYTD4_cjs.X402_PAYMENT_HEADER_NAMES_SENT; }
5766
+ get: function () { return chunk22FJ4JQO_cjs.X402_PAYMENT_HEADER_NAMES_SENT; }
5767
+ });
5768
+ Object.defineProperty(exports, "X402_PAYMENT_NONCE_TAG", {
5769
+ enumerable: true,
5770
+ get: function () { return chunk22FJ4JQO_cjs.X402_PAYMENT_NONCE_TAG; }
5166
5771
  });
5167
5772
  Object.defineProperty(exports, "X402_PAYMENT_REQUIRED_HEADER_NAME", {
5168
5773
  enumerable: true,
5169
- get: function () { return chunkHFOAYTD4_cjs.X402_PAYMENT_REQUIRED_HEADER_NAME; }
5774
+ get: function () { return chunk22FJ4JQO_cjs.X402_PAYMENT_REQUIRED_HEADER_NAME; }
5170
5775
  });
5171
5776
  Object.defineProperty(exports, "X402_PAYMENT_RESPONSE_HEADER_NAME", {
5172
5777
  enumerable: true,
5173
- get: function () { return chunkHFOAYTD4_cjs.X402_PAYMENT_RESPONSE_HEADER_NAME; }
5778
+ get: function () { return chunk22FJ4JQO_cjs.X402_PAYMENT_RESPONSE_HEADER_NAME; }
5174
5779
  });
5175
5780
  Object.defineProperty(exports, "X402_SETTLEMENT_FORWARD_MARGIN_SECONDS", {
5176
5781
  enumerable: true,
5177
- get: function () { return chunkHFOAYTD4_cjs.X402_SETTLEMENT_FORWARD_MARGIN_SECONDS; }
5782
+ get: function () { return chunk22FJ4JQO_cjs.X402_SETTLEMENT_FORWARD_MARGIN_SECONDS; }
5178
5783
  });
5179
5784
  Object.defineProperty(exports, "assertBoundDirectPaymentUserOp", {
5180
5785
  enumerable: true,
5181
- get: function () { return chunkHFOAYTD4_cjs.assertBoundDirectPaymentUserOp; }
5786
+ get: function () { return chunk22FJ4JQO_cjs.assertBoundDirectPaymentUserOp; }
5182
5787
  });
5183
5788
  Object.defineProperty(exports, "assertOwnTaskBudgetCloseUserOp", {
5184
5789
  enumerable: true,
5185
- get: function () { return chunkHFOAYTD4_cjs.assertOwnTaskBudgetCloseUserOp; }
5790
+ get: function () { return chunk22FJ4JQO_cjs.assertOwnTaskBudgetCloseUserOp; }
5186
5791
  });
5187
5792
  Object.defineProperty(exports, "assertOwnTaskChild", {
5188
5793
  enumerable: true,
5189
- get: function () { return chunkHFOAYTD4_cjs.assertOwnTaskChild; }
5794
+ get: function () { return chunk22FJ4JQO_cjs.assertOwnTaskChild; }
5190
5795
  });
5191
5796
  Object.defineProperty(exports, "buildSweepAuthorizationMessage", {
5192
5797
  enumerable: true,
5193
- get: function () { return chunkHFOAYTD4_cjs.buildSweepAuthorizationMessage; }
5798
+ get: function () { return chunk22FJ4JQO_cjs.buildSweepAuthorizationMessage; }
5194
5799
  });
5195
5800
  Object.defineProperty(exports, "buildSweepTypedData", {
5196
5801
  enumerable: true,
5197
- get: function () { return chunkHFOAYTD4_cjs.buildSweepTypedData; }
5802
+ get: function () { return chunk22FJ4JQO_cjs.buildSweepTypedData; }
5198
5803
  });
5199
5804
  Object.defineProperty(exports, "buildX402ExpectedMessage", {
5200
5805
  enumerable: true,
5201
- get: function () { return chunkHFOAYTD4_cjs.buildX402ExpectedMessage; }
5806
+ get: function () { return chunk22FJ4JQO_cjs.buildX402ExpectedMessage; }
5202
5807
  });
5203
5808
  Object.defineProperty(exports, "compareNodeVersions", {
5204
5809
  enumerable: true,
5205
- get: function () { return chunkHFOAYTD4_cjs.compareNodeVersions; }
5810
+ get: function () { return chunk22FJ4JQO_cjs.compareNodeVersions; }
5206
5811
  });
5207
5812
  Object.defineProperty(exports, "createNextStepBuilder", {
5208
5813
  enumerable: true,
5209
- get: function () { return chunkHFOAYTD4_cjs.createNextStepBuilder; }
5814
+ get: function () { return chunk22FJ4JQO_cjs.createNextStepBuilder; }
5210
5815
  });
5211
5816
  Object.defineProperty(exports, "decodeBase64Json", {
5212
5817
  enumerable: true,
5213
- get: function () { return chunkHFOAYTD4_cjs.decodeBase64Json; }
5818
+ get: function () { return chunk22FJ4JQO_cjs.decodeBase64Json; }
5214
5819
  });
5215
5820
  Object.defineProperty(exports, "decodeBase64Utf8", {
5216
5821
  enumerable: true,
5217
- get: function () { return chunkHFOAYTD4_cjs.decodeBase64Utf8; }
5822
+ get: function () { return chunk22FJ4JQO_cjs.decodeBase64Utf8; }
5218
5823
  });
5219
5824
  Object.defineProperty(exports, "defaultNextToolFor", {
5220
5825
  enumerable: true,
5221
- get: function () { return chunkHFOAYTD4_cjs.defaultNextToolFor; }
5826
+ get: function () { return chunk22FJ4JQO_cjs.defaultNextToolFor; }
5827
+ });
5828
+ Object.defineProperty(exports, "deriveX402PaymentNonce", {
5829
+ enumerable: true,
5830
+ get: function () { return chunk22FJ4JQO_cjs.deriveX402PaymentNonce; }
5222
5831
  });
5223
5832
  Object.defineProperty(exports, "encodeBase64Json", {
5224
5833
  enumerable: true,
5225
- get: function () { return chunkHFOAYTD4_cjs.encodeBase64Json; }
5834
+ get: function () { return chunk22FJ4JQO_cjs.encodeBase64Json; }
5226
5835
  });
5227
5836
  Object.defineProperty(exports, "encodeBase64Utf8", {
5228
5837
  enumerable: true,
5229
- get: function () { return chunkHFOAYTD4_cjs.encodeBase64Utf8; }
5838
+ get: function () { return chunk22FJ4JQO_cjs.encodeBase64Utf8; }
5230
5839
  });
5231
5840
  Object.defineProperty(exports, "encodePaymentProof", {
5232
5841
  enumerable: true,
5233
- get: function () { return chunkHFOAYTD4_cjs.encodePaymentProof; }
5842
+ get: function () { return chunk22FJ4JQO_cjs.encodePaymentProof; }
5234
5843
  });
5235
5844
  Object.defineProperty(exports, "hashDelegation", {
5236
5845
  enumerable: true,
5237
- get: function () { return chunkHFOAYTD4_cjs.hashDelegation; }
5846
+ get: function () { return chunk22FJ4JQO_cjs.hashDelegation; }
5238
5847
  });
5239
5848
  Object.defineProperty(exports, "havenClientIdentity", {
5240
5849
  enumerable: true,
5241
- get: function () { return chunkHFOAYTD4_cjs.havenClientIdentity; }
5850
+ get: function () { return chunk22FJ4JQO_cjs.havenClientIdentity; }
5242
5851
  });
5243
5852
  Object.defineProperty(exports, "isErc7710Option", {
5244
5853
  enumerable: true,
5245
- get: function () { return chunkHFOAYTD4_cjs.isErc7710Option; }
5854
+ get: function () { return chunk22FJ4JQO_cjs.isErc7710Option; }
5246
5855
  });
5247
5856
  Object.defineProperty(exports, "isSupportedNodeVersion", {
5248
5857
  enumerable: true,
5249
- get: function () { return chunkHFOAYTD4_cjs.isSupportedNodeVersion; }
5858
+ get: function () { return chunk22FJ4JQO_cjs.isSupportedNodeVersion; }
5250
5859
  });
5251
5860
  Object.defineProperty(exports, "isSweepableChain", {
5252
5861
  enumerable: true,
5253
- get: function () { return chunkHFOAYTD4_cjs.isSweepableChain; }
5862
+ get: function () { return chunk22FJ4JQO_cjs.isSweepableChain; }
5254
5863
  });
5255
5864
  Object.defineProperty(exports, "isTaskChildTypedData", {
5256
5865
  enumerable: true,
5257
- get: function () { return chunkHFOAYTD4_cjs.isTaskChildTypedData; }
5866
+ get: function () { return chunk22FJ4JQO_cjs.isTaskChildTypedData; }
5258
5867
  });
5259
5868
  Object.defineProperty(exports, "normalizePaymentRequired", {
5260
5869
  enumerable: true,
5261
- get: function () { return chunkHFOAYTD4_cjs.normalizePaymentRequired; }
5870
+ get: function () { return chunk22FJ4JQO_cjs.normalizePaymentRequired; }
5262
5871
  });
5263
5872
  Object.defineProperty(exports, "parseNextTool", {
5264
5873
  enumerable: true,
5265
- get: function () { return chunkHFOAYTD4_cjs.parseNextTool; }
5874
+ get: function () { return chunk22FJ4JQO_cjs.parseNextTool; }
5266
5875
  });
5267
5876
  Object.defineProperty(exports, "parsePaymentRequired", {
5268
5877
  enumerable: true,
5269
- get: function () { return chunkHFOAYTD4_cjs.parsePaymentRequired; }
5878
+ get: function () { return chunk22FJ4JQO_cjs.parsePaymentRequired; }
5270
5879
  });
5271
5880
  Object.defineProperty(exports, "parsePaymentRequiredResponse", {
5272
5881
  enumerable: true,
5273
- get: function () { return chunkHFOAYTD4_cjs.parsePaymentRequiredResponse; }
5882
+ get: function () { return chunk22FJ4JQO_cjs.parsePaymentRequiredResponse; }
5274
5883
  });
5275
5884
  Object.defineProperty(exports, "readClientUpdate", {
5276
5885
  enumerable: true,
5277
- get: function () { return chunkHFOAYTD4_cjs.readClientUpdate; }
5886
+ get: function () { return chunk22FJ4JQO_cjs.readClientUpdate; }
5278
5887
  });
5279
5888
  Object.defineProperty(exports, "renderNextTool", {
5280
5889
  enumerable: true,
5281
- get: function () { return chunkHFOAYTD4_cjs.renderNextTool; }
5890
+ get: function () { return chunk22FJ4JQO_cjs.renderNextTool; }
5282
5891
  });
5283
5892
  Object.defineProperty(exports, "resolveTokenBySymbol", {
5284
5893
  enumerable: true,
5285
- get: function () { return chunkHFOAYTD4_cjs.resolveTokenBySymbol; }
5894
+ get: function () { return chunk22FJ4JQO_cjs.resolveTokenBySymbol; }
5286
5895
  });
5287
5896
  Object.defineProperty(exports, "resolveTokenFromAddress", {
5288
5897
  enumerable: true,
5289
- get: function () { return chunkHFOAYTD4_cjs.resolveTokenFromAddress; }
5898
+ get: function () { return chunk22FJ4JQO_cjs.resolveTokenFromAddress; }
5290
5899
  });
5291
5900
  Object.defineProperty(exports, "selectErc7710PaymentOption", {
5292
5901
  enumerable: true,
5293
- get: function () { return chunkHFOAYTD4_cjs.selectErc7710PaymentOption; }
5902
+ get: function () { return chunk22FJ4JQO_cjs.selectErc7710PaymentOption; }
5294
5903
  });
5295
5904
  Object.defineProperty(exports, "selectPaymentOption", {
5296
5905
  enumerable: true,
5297
- get: function () { return chunkHFOAYTD4_cjs.selectPaymentOption; }
5906
+ get: function () { return chunk22FJ4JQO_cjs.selectPaymentOption; }
5298
5907
  });
5299
5908
  Object.defineProperty(exports, "selectStandardPaymentOption", {
5300
5909
  enumerable: true,
5301
- get: function () { return chunkHFOAYTD4_cjs.selectStandardPaymentOption; }
5910
+ get: function () { return chunk22FJ4JQO_cjs.selectStandardPaymentOption; }
5302
5911
  });
5303
5912
  Object.defineProperty(exports, "selectX402SettlementScheme", {
5304
5913
  enumerable: true,
5305
- get: function () { return chunkHFOAYTD4_cjs.selectX402SettlementScheme; }
5914
+ get: function () { return chunk22FJ4JQO_cjs.selectX402SettlementScheme; }
5306
5915
  });
5307
5916
  Object.defineProperty(exports, "sweepUsdcAddress", {
5308
5917
  enumerable: true,
5309
- get: function () { return chunkHFOAYTD4_cjs.sweepUsdcAddress; }
5918
+ get: function () { return chunk22FJ4JQO_cjs.sweepUsdcAddress; }
5310
5919
  });
5311
5920
  Object.defineProperty(exports, "sweepUsdcDomain", {
5312
5921
  enumerable: true,
5313
- get: function () { return chunkHFOAYTD4_cjs.sweepUsdcDomain; }
5922
+ get: function () { return chunk22FJ4JQO_cjs.sweepUsdcDomain; }
5314
5923
  });
5315
5924
  Object.defineProperty(exports, "toStandardPaymentRequirements", {
5316
5925
  enumerable: true,
5317
- get: function () { return chunkHFOAYTD4_cjs.toStandardPaymentRequirements; }
5926
+ get: function () { return chunk22FJ4JQO_cjs.toStandardPaymentRequirements; }
5318
5927
  });
5319
5928
  Object.defineProperty(exports, "unsupportedNodeVersionMessage", {
5320
5929
  enumerable: true,
5321
- get: function () { return chunkHFOAYTD4_cjs.unsupportedNodeVersionMessage; }
5930
+ get: function () { return chunk22FJ4JQO_cjs.unsupportedNodeVersionMessage; }
5322
5931
  });
5323
5932
  Object.defineProperty(exports, "validateStandardX402PaymentHeader", {
5324
5933
  enumerable: true,
5325
- get: function () { return chunkHFOAYTD4_cjs.validateStandardX402PaymentHeader; }
5934
+ get: function () { return chunk22FJ4JQO_cjs.validateStandardX402PaymentHeader; }
5326
5935
  });
5327
5936
  Object.defineProperty(exports, "x402AssetTransferMethod", {
5328
5937
  enumerable: true,
5329
- get: function () { return chunkHFOAYTD4_cjs.x402AssetTransferMethod; }
5938
+ get: function () { return chunk22FJ4JQO_cjs.x402AssetTransferMethod; }
5330
5939
  });
5331
5940
  Object.defineProperty(exports, "x402AuthorizationAmount", {
5332
5941
  enumerable: true,
5333
- get: function () { return chunkHFOAYTD4_cjs.x402AuthorizationAmount; }
5942
+ get: function () { return chunk22FJ4JQO_cjs.x402AuthorizationAmount; }
5334
5943
  });
5335
5944
  Object.defineProperty(exports, "x402FacilitatorAddresses", {
5336
5945
  enumerable: true,
5337
- get: function () { return chunkHFOAYTD4_cjs.x402FacilitatorAddresses; }
5946
+ get: function () { return chunk22FJ4JQO_cjs.x402FacilitatorAddresses; }
5947
+ });
5948
+ Object.defineProperty(exports, "x402PaymentHeaderNamesFor", {
5949
+ enumerable: true,
5950
+ get: function () { return chunk22FJ4JQO_cjs.x402PaymentHeaderNamesFor; }
5951
+ });
5952
+ Object.defineProperty(exports, "x402RetryHeadersFor", {
5953
+ enumerable: true,
5954
+ get: function () { return chunk22FJ4JQO_cjs.x402RetryHeadersFor; }
5338
5955
  });
5339
5956
  Object.defineProperty(exports, "x402V2PaymentEnvelope", {
5340
5957
  enumerable: true,
5341
- get: function () { return chunkHFOAYTD4_cjs.x402V2PaymentEnvelope; }
5958
+ get: function () { return chunk22FJ4JQO_cjs.x402V2PaymentEnvelope; }
5959
+ });
5960
+ Object.defineProperty(exports, "RECEIPT_VERSION", {
5961
+ enumerable: true,
5962
+ get: function () { return chunk6LEXYQ7J_cjs.RECEIPT_VERSION; }
5963
+ });
5964
+ Object.defineProperty(exports, "verifyPaymentReceipt", {
5965
+ enumerable: true,
5966
+ get: function () { return chunk6LEXYQ7J_cjs.verifyPaymentReceipt; }
5342
5967
  });
5343
5968
  Object.defineProperty(exports, "AGENT_PAYMENT_FAILURE_CODE_VALUES", {
5344
5969
  enumerable: true,
5345
- get: function () { return chunkHX34HOW4_cjs.AGENT_PAYMENT_FAILURE_CODE_VALUES; }
5970
+ get: function () { return chunkH37YVYZA_cjs.AGENT_PAYMENT_FAILURE_CODE_VALUES; }
5346
5971
  });
5347
5972
  Object.defineProperty(exports, "AGENT_PAYMENT_NEXT_ACTION_VALUES", {
5348
5973
  enumerable: true,
5349
- get: function () { return chunkHX34HOW4_cjs.AGENT_PAYMENT_NEXT_ACTION_VALUES; }
5974
+ get: function () { return chunkH37YVYZA_cjs.AGENT_PAYMENT_NEXT_ACTION_VALUES; }
5350
5975
  });
5351
5976
  Object.defineProperty(exports, "AGENT_PAYMENT_PHASE_VALUES", {
5352
5977
  enumerable: true,
5353
- get: function () { return chunkHX34HOW4_cjs.AGENT_PAYMENT_PHASE_VALUES; }
5978
+ get: function () { return chunkH37YVYZA_cjs.AGENT_PAYMENT_PHASE_VALUES; }
5354
5979
  });
5355
5980
  Object.defineProperty(exports, "AGENT_PAYMENT_RAIL_VALUES", {
5356
5981
  enumerable: true,
5357
- get: function () { return chunkHX34HOW4_cjs.AGENT_PAYMENT_RAIL_VALUES; }
5982
+ get: function () { return chunkH37YVYZA_cjs.AGENT_PAYMENT_RAIL_VALUES; }
5358
5983
  });
5359
5984
  Object.defineProperty(exports, "AgentPaymentFailureCode", {
5360
5985
  enumerable: true,
5361
- get: function () { return chunkHX34HOW4_cjs.AgentPaymentFailureCode; }
5986
+ get: function () { return chunkH37YVYZA_cjs.AgentPaymentFailureCode; }
5362
5987
  });
5363
5988
  Object.defineProperty(exports, "AgentPaymentFailureCodeDescriptions", {
5364
5989
  enumerable: true,
5365
- get: function () { return chunkHX34HOW4_cjs.AgentPaymentFailureCodeDescriptions; }
5990
+ get: function () { return chunkH37YVYZA_cjs.AgentPaymentFailureCodeDescriptions; }
5366
5991
  });
5367
5992
  Object.defineProperty(exports, "AgentPaymentFailureCodeSchema", {
5368
5993
  enumerable: true,
5369
- get: function () { return chunkHX34HOW4_cjs.AgentPaymentFailureCodeSchema; }
5994
+ get: function () { return chunkH37YVYZA_cjs.AgentPaymentFailureCodeSchema; }
5370
5995
  });
5371
5996
  Object.defineProperty(exports, "AgentPaymentNextAction", {
5372
5997
  enumerable: true,
5373
- get: function () { return chunkHX34HOW4_cjs.AgentPaymentNextAction; }
5998
+ get: function () { return chunkH37YVYZA_cjs.AgentPaymentNextAction; }
5374
5999
  });
5375
6000
  Object.defineProperty(exports, "AgentPaymentNextActionDescriptions", {
5376
6001
  enumerable: true,
5377
- get: function () { return chunkHX34HOW4_cjs.AgentPaymentNextActionDescriptions; }
6002
+ get: function () { return chunkH37YVYZA_cjs.AgentPaymentNextActionDescriptions; }
5378
6003
  });
5379
6004
  Object.defineProperty(exports, "AgentPaymentNextActionSchema", {
5380
6005
  enumerable: true,
5381
- get: function () { return chunkHX34HOW4_cjs.AgentPaymentNextActionSchema; }
6006
+ get: function () { return chunkH37YVYZA_cjs.AgentPaymentNextActionSchema; }
5382
6007
  });
5383
6008
  Object.defineProperty(exports, "AgentPaymentPhase", {
5384
6009
  enumerable: true,
5385
- get: function () { return chunkHX34HOW4_cjs.AgentPaymentPhase; }
6010
+ get: function () { return chunkH37YVYZA_cjs.AgentPaymentPhase; }
5386
6011
  });
5387
6012
  Object.defineProperty(exports, "AgentPaymentPhaseDescriptions", {
5388
6013
  enumerable: true,
5389
- get: function () { return chunkHX34HOW4_cjs.AgentPaymentPhaseDescriptions; }
6014
+ get: function () { return chunkH37YVYZA_cjs.AgentPaymentPhaseDescriptions; }
5390
6015
  });
5391
6016
  Object.defineProperty(exports, "AgentPaymentPhaseSchema", {
5392
6017
  enumerable: true,
5393
- get: function () { return chunkHX34HOW4_cjs.AgentPaymentPhaseSchema; }
6018
+ get: function () { return chunkH37YVYZA_cjs.AgentPaymentPhaseSchema; }
5394
6019
  });
5395
6020
  Object.defineProperty(exports, "AgentPaymentRail", {
5396
6021
  enumerable: true,
5397
- get: function () { return chunkHX34HOW4_cjs.AgentPaymentRail; }
6022
+ get: function () { return chunkH37YVYZA_cjs.AgentPaymentRail; }
5398
6023
  });
5399
6024
  Object.defineProperty(exports, "AgentPaymentRailDescriptions", {
5400
6025
  enumerable: true,
5401
- get: function () { return chunkHX34HOW4_cjs.AgentPaymentRailDescriptions; }
6026
+ get: function () { return chunkH37YVYZA_cjs.AgentPaymentRailDescriptions; }
5402
6027
  });
5403
6028
  Object.defineProperty(exports, "AgentPaymentRailSchema", {
5404
6029
  enumerable: true,
5405
- get: function () { return chunkHX34HOW4_cjs.AgentPaymentRailSchema; }
6030
+ get: function () { return chunkH37YVYZA_cjs.AgentPaymentRailSchema; }
5406
6031
  });
5407
6032
  Object.defineProperty(exports, "AgentPaymentWarningCode", {
5408
6033
  enumerable: true,
5409
- get: function () { return chunkHX34HOW4_cjs.AgentPaymentWarningCode; }
6034
+ get: function () { return chunkH37YVYZA_cjs.AgentPaymentWarningCode; }
5410
6035
  });
5411
6036
  Object.defineProperty(exports, "CONNECTOR_PACKAGE_NAME", {
5412
6037
  enumerable: true,
5413
- get: function () { return chunkHX34HOW4_cjs.CONNECTOR_PACKAGE_NAME; }
6038
+ get: function () { return chunkH37YVYZA_cjs.CONNECTOR_PACKAGE_NAME; }
5414
6039
  });
5415
6040
  Object.defineProperty(exports, "DEFAULT_CONFIRMATION_TIMEOUT_MS", {
5416
6041
  enumerable: true,
5417
- get: function () { return chunkHX34HOW4_cjs.DEFAULT_CONFIRMATION_TIMEOUT_MS; }
6042
+ get: function () { return chunkH37YVYZA_cjs.DEFAULT_CONFIRMATION_TIMEOUT_MS; }
5418
6043
  });
5419
6044
  Object.defineProperty(exports, "DIRECT_SIGN_CONTEXT_VERSION", {
5420
6045
  enumerable: true,
5421
- get: function () { return chunkHX34HOW4_cjs.DIRECT_SIGN_CONTEXT_VERSION; }
6046
+ get: function () { return chunkH37YVYZA_cjs.DIRECT_SIGN_CONTEXT_VERSION; }
5422
6047
  });
5423
6048
  Object.defineProperty(exports, "ENTRY_POINT_V07", {
5424
6049
  enumerable: true,
5425
- get: function () { return chunkHX34HOW4_cjs.ENTRY_POINT_V07; }
6050
+ get: function () { return chunkH37YVYZA_cjs.ENTRY_POINT_V07; }
5426
6051
  });
5427
6052
  Object.defineProperty(exports, "HAVEN_CONNECTOR_CHANNEL", {
5428
6053
  enumerable: true,
5429
- get: function () { return chunkHX34HOW4_cjs.HAVEN_CONNECTOR_CHANNEL; }
6054
+ get: function () { return chunkH37YVYZA_cjs.HAVEN_CONNECTOR_CHANNEL; }
5430
6055
  });
5431
6056
  Object.defineProperty(exports, "HYBRID_DELEGATOR_DOMAIN_NAME", {
5432
6057
  enumerable: true,
5433
- get: function () { return chunkHX34HOW4_cjs.HYBRID_DELEGATOR_DOMAIN_NAME; }
6058
+ get: function () { return chunkH37YVYZA_cjs.HYBRID_DELEGATOR_DOMAIN_NAME; }
5434
6059
  });
5435
6060
  Object.defineProperty(exports, "HYBRID_DELEGATOR_DOMAIN_VERSION", {
5436
6061
  enumerable: true,
5437
- get: function () { return chunkHX34HOW4_cjs.HYBRID_DELEGATOR_DOMAIN_VERSION; }
6062
+ get: function () { return chunkH37YVYZA_cjs.HYBRID_DELEGATOR_DOMAIN_VERSION; }
5438
6063
  });
5439
6064
  Object.defineProperty(exports, "HavenApiError", {
5440
6065
  enumerable: true,
5441
- get: function () { return chunkHX34HOW4_cjs.HavenApiError; }
6066
+ get: function () { return chunkH37YVYZA_cjs.HavenApiError; }
5442
6067
  });
5443
6068
  Object.defineProperty(exports, "HavenError", {
5444
6069
  enumerable: true,
5445
- get: function () { return chunkHX34HOW4_cjs.HavenError; }
6070
+ get: function () { return chunkH37YVYZA_cjs.HavenError; }
5446
6071
  });
5447
6072
  Object.defineProperty(exports, "HavenPaymentStateError", {
5448
6073
  enumerable: true,
5449
- get: function () { return chunkHX34HOW4_cjs.HavenPaymentStateError; }
6074
+ get: function () { return chunkH37YVYZA_cjs.HavenPaymentStateError; }
5450
6075
  });
5451
6076
  Object.defineProperty(exports, "HavenSigningError", {
5452
6077
  enumerable: true,
5453
- get: function () { return chunkHX34HOW4_cjs.HavenSigningError; }
6078
+ get: function () { return chunkH37YVYZA_cjs.HavenSigningError; }
5454
6079
  });
5455
6080
  Object.defineProperty(exports, "HavenTimeoutError", {
5456
6081
  enumerable: true,
5457
- get: function () { return chunkHX34HOW4_cjs.HavenTimeoutError; }
6082
+ get: function () { return chunkH37YVYZA_cjs.HavenTimeoutError; }
5458
6083
  });
5459
6084
  Object.defineProperty(exports, "HavenUnsupportedSignerVersionError", {
5460
6085
  enumerable: true,
5461
- get: function () { return chunkHX34HOW4_cjs.HavenUnsupportedSignerVersionError; }
6086
+ get: function () { return chunkH37YVYZA_cjs.HavenUnsupportedSignerVersionError; }
5462
6087
  });
5463
6088
  Object.defineProperty(exports, "HavenUserOpBindingError", {
5464
6089
  enumerable: true,
5465
- get: function () { return chunkHX34HOW4_cjs.HavenUserOpBindingError; }
6090
+ get: function () { return chunkH37YVYZA_cjs.HavenUserOpBindingError; }
5466
6091
  });
5467
6092
  Object.defineProperty(exports, "HavenZeroSettlementHashError", {
5468
6093
  enumerable: true,
5469
- get: function () { return chunkHX34HOW4_cjs.HavenZeroSettlementHashError; }
6094
+ get: function () { return chunkH37YVYZA_cjs.HavenZeroSettlementHashError; }
5470
6095
  });
5471
6096
  Object.defineProperty(exports, "MerchantTimeoutError", {
5472
6097
  enumerable: true,
5473
- get: function () { return chunkHX34HOW4_cjs.MerchantTimeoutError; }
6098
+ get: function () { return chunkH37YVYZA_cjs.MerchantTimeoutError; }
5474
6099
  });
5475
6100
  Object.defineProperty(exports, "PACKED_USER_OPERATION_FIELDS", {
5476
6101
  enumerable: true,
5477
- get: function () { return chunkHX34HOW4_cjs.PACKED_USER_OPERATION_FIELDS; }
6102
+ get: function () { return chunkH37YVYZA_cjs.PACKED_USER_OPERATION_FIELDS; }
5478
6103
  });
5479
6104
  Object.defineProperty(exports, "ROOT_AUTHORITY", {
5480
6105
  enumerable: true,
5481
- get: function () { return chunkHX34HOW4_cjs.ROOT_AUTHORITY; }
6106
+ get: function () { return chunkH37YVYZA_cjs.ROOT_AUTHORITY; }
5482
6107
  });
5483
6108
  Object.defineProperty(exports, "SIGNER_UPDATE_FALLBACK", {
5484
6109
  enumerable: true,
5485
- get: function () { return chunkHX34HOW4_cjs.SIGNER_UPDATE_FALLBACK; }
6110
+ get: function () { return chunkH37YVYZA_cjs.SIGNER_UPDATE_FALLBACK; }
5486
6111
  });
5487
6112
  Object.defineProperty(exports, "SignerRefusalCode", {
5488
6113
  enumerable: true,
5489
- get: function () { return chunkHX34HOW4_cjs.SignerRefusalCode; }
6114
+ get: function () { return chunkH37YVYZA_cjs.SignerRefusalCode; }
5490
6115
  });
5491
6116
  Object.defineProperty(exports, "TASK_SIGN_CONTEXT_VERSION", {
5492
6117
  enumerable: true,
5493
- get: function () { return chunkHX34HOW4_cjs.TASK_SIGN_CONTEXT_VERSION; }
6118
+ get: function () { return chunkH37YVYZA_cjs.TASK_SIGN_CONTEXT_VERSION; }
5494
6119
  });
5495
6120
  Object.defineProperty(exports, "X402AlreadySettledError", {
5496
6121
  enumerable: true,
5497
- get: function () { return chunkHX34HOW4_cjs.X402AlreadySettledError; }
6122
+ get: function () { return chunkH37YVYZA_cjs.X402AlreadySettledError; }
5498
6123
  });
5499
6124
  Object.defineProperty(exports, "X402Erc7710AlreadySettledError", {
5500
6125
  enumerable: true,
5501
- get: function () { return chunkHX34HOW4_cjs.X402Erc7710AlreadySettledError; }
6126
+ get: function () { return chunkH37YVYZA_cjs.X402Erc7710AlreadySettledError; }
5502
6127
  });
5503
6128
  Object.defineProperty(exports, "X402TaskBudgetMismatchError", {
5504
6129
  enumerable: true,
5505
- get: function () { return chunkHX34HOW4_cjs.X402TaskBudgetMismatchError; }
6130
+ get: function () { return chunkH37YVYZA_cjs.X402TaskBudgetMismatchError; }
5506
6131
  });
5507
6132
  Object.defineProperty(exports, "X402UnexpectedStatusError", {
5508
6133
  enumerable: true,
5509
- get: function () { return chunkHX34HOW4_cjs.X402UnexpectedStatusError; }
6134
+ get: function () { return chunkH37YVYZA_cjs.X402UnexpectedStatusError; }
5510
6135
  });
5511
6136
  Object.defineProperty(exports, "assertUserOpTypedDataBinding", {
5512
6137
  enumerable: true,
5513
- get: function () { return chunkHX34HOW4_cjs.assertUserOpTypedDataBinding; }
6138
+ get: function () { return chunkH37YVYZA_cjs.assertUserOpTypedDataBinding; }
5514
6139
  });
5515
6140
  Object.defineProperty(exports, "connectorRerunCommand", {
5516
6141
  enumerable: true,
5517
- get: function () { return chunkHX34HOW4_cjs.connectorRerunCommand; }
6142
+ get: function () { return chunkH37YVYZA_cjs.connectorRerunCommand; }
5518
6143
  });
5519
6144
  Object.defineProperty(exports, "connectorSpec", {
5520
6145
  enumerable: true,
5521
- get: function () { return chunkHX34HOW4_cjs.connectorSpec; }
6146
+ get: function () { return chunkH37YVYZA_cjs.connectorSpec; }
5522
6147
  });
5523
6148
  Object.defineProperty(exports, "connectorUpgradeCommand", {
5524
6149
  enumerable: true,
5525
- get: function () { return chunkHX34HOW4_cjs.connectorUpgradeCommand; }
6150
+ get: function () { return chunkH37YVYZA_cjs.connectorUpgradeCommand; }
5526
6151
  });
5527
6152
  Object.defineProperty(exports, "deriveDelegateAccountAddress", {
5528
6153
  enumerable: true,
5529
- get: function () { return chunkHX34HOW4_cjs.deriveDelegateAccountAddress; }
6154
+ get: function () { return chunkH37YVYZA_cjs.deriveDelegateAccountAddress; }
5530
6155
  });
5531
6156
  Object.defineProperty(exports, "isConnectorChannel", {
5532
6157
  enumerable: true,
5533
- get: function () { return chunkHX34HOW4_cjs.isConnectorChannel; }
6158
+ get: function () { return chunkH37YVYZA_cjs.isConnectorChannel; }
5534
6159
  });
5535
6160
  Object.defineProperty(exports, "isPackedUserOperationTypedData", {
5536
6161
  enumerable: true,
5537
- get: function () { return chunkHX34HOW4_cjs.isPackedUserOperationTypedData; }
6162
+ get: function () { return chunkH37YVYZA_cjs.isPackedUserOperationTypedData; }
5538
6163
  });
5539
6164
  Object.defineProperty(exports, "packedUserOperationHash", {
5540
6165
  enumerable: true,
5541
- get: function () { return chunkHX34HOW4_cjs.packedUserOperationHash; }
6166
+ get: function () { return chunkH37YVYZA_cjs.packedUserOperationHash; }
5542
6167
  });
5543
6168
  Object.defineProperty(exports, "resolveConnectorChannel", {
5544
6169
  enumerable: true,
5545
- get: function () { return chunkHX34HOW4_cjs.resolveConnectorChannel; }
6170
+ get: function () { return chunkH37YVYZA_cjs.resolveConnectorChannel; }
5546
6171
  });
5547
6172
  Object.defineProperty(exports, "signerUpdateFallback", {
5548
6173
  enumerable: true,
5549
- get: function () { return chunkHX34HOW4_cjs.signerUpdateFallback; }
6174
+ get: function () { return chunkH37YVYZA_cjs.signerUpdateFallback; }
5550
6175
  });
5551
6176
  Object.defineProperty(exports, "verifySettlementChild", {
5552
6177
  enumerable: true,
5553
- get: function () { return chunkHX34HOW4_cjs.verifySettlementChild; }
6178
+ get: function () { return chunkH37YVYZA_cjs.verifySettlementChild; }
5554
6179
  });
5555
6180
  exports.AGENT_APPROVAL_RELAY_JSON_SENTENCE = AGENT_APPROVAL_RELAY_JSON_SENTENCE;
5556
6181
  exports.AGENT_APPROVAL_RELAY_PROSE_SENTENCE = AGENT_APPROVAL_RELAY_PROSE_SENTENCE;
@@ -5566,27 +6191,40 @@ exports.DISCOVERY_MAX_BYTES = DISCOVERY_MAX_BYTES;
5566
6191
  exports.HAVEN_AGENT_RUNBOOK_MD = HAVEN_AGENT_RUNBOOK_MD;
5567
6192
  exports.HAVEN_SKILL_BODY_MD = HAVEN_SKILL_BODY_MD;
5568
6193
  exports.HAVEN_SKILL_MD = HAVEN_SKILL_MD;
6194
+ exports.HOSTED_DISCOVERY_TIMEOUT_MS = HOSTED_DISCOVERY_TIMEOUT_MS;
6195
+ exports.HOSTED_EGRESS_TIMEOUTS = HOSTED_EGRESS_TIMEOUTS;
6196
+ exports.HOSTED_MAX_GET_REDIRECTS = HOSTED_MAX_GET_REDIRECTS;
6197
+ exports.HOSTED_RESPONSE_BYTE_CAPS = HOSTED_RESPONSE_BYTE_CAPS;
5569
6198
  exports.HavenClient = HavenClient;
5570
6199
  exports.HavenInsecureRetryTargetError = HavenInsecureRetryTargetError;
5571
6200
  exports.INSECURE_RETRY_TARGET_CODE = INSECURE_RETRY_TARGET_CODE;
5572
6201
  exports.MERCHANT_DISCOVERY_PATHS = MERCHANT_DISCOVERY_PATHS;
5573
- exports.RECEIPT_VERSION = RECEIPT_VERSION;
6202
+ exports.MERCHANT_EGRESS_REFUSED_CODE = MERCHANT_EGRESS_REFUSED_CODE;
6203
+ exports.MERCHANT_EGRESS_RESPONSE_CAP_CODE = MERCHANT_EGRESS_RESPONSE_CAP_CODE;
6204
+ exports.MerchantEgressRefusedError = MerchantEgressRefusedError;
6205
+ exports.MerchantEgressResponseCapError = MerchantEgressResponseCapError;
5574
6206
  exports.SKILL_FOLDER_NAME = SKILL_FOLDER_NAME;
5575
6207
  exports.addressFromKey = addressFromKey;
6208
+ exports.assertPublicHttpsMerchantUrl = assertPublicHttpsMerchantUrl;
5576
6209
  exports.assertSecureX402RetryTarget = assertSecureX402RetryTarget;
6210
+ exports.catalogFundingLegExpected = catalogFundingLegExpected;
5577
6211
  exports.composeDescription = composeDescription;
5578
6212
  exports.discoverMerchantMcpUrl = discoverMerchantMcpUrl;
5579
6213
  exports.formatTokenAmount = formatTokenAmount;
5580
6214
  exports.havenTools = havenTools;
6215
+ exports.isPublicHttpsMerchantUrl = isPublicHttpsMerchantUrl;
5581
6216
  exports.isSecureX402RetryTarget = isSecureX402RetryTarget;
5582
6217
  exports.isZeroSettlementTxHash = isZeroSettlementTxHash;
6218
+ exports.parseMerchantSettlement = parseMerchantSettlement;
6219
+ exports.publicHttpsMerchantUrlRefusal = publicHttpsMerchantUrlRefusal;
6220
+ exports.readBodyCapped = readBodyCapped;
5583
6221
  exports.readX402ReceiptPayer = readX402ReceiptPayer;
5584
6222
  exports.resolveX402RetryTarget = resolveX402RetryTarget;
5585
6223
  exports.sameUrl = sameUrl;
5586
6224
  exports.signHash = signHash;
5587
6225
  exports.signUserOpTypedDataForDelegation = signUserOpTypedDataForDelegation;
6226
+ exports.strictMerchantEgressPolicy = strictMerchantEgressPolicy;
5588
6227
  exports.toolDescriptions = toolDescriptions;
5589
- exports.verifyPaymentReceipt = verifyPaymentReceipt;
5590
6228
  exports.verifySignature = verifySignature;
5591
6229
  //# sourceMappingURL=index.cjs.map
5592
6230
  //# sourceMappingURL=index.cjs.map