@haven_ai/sdk 0.10.0-alpha.0 → 0.11.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 (36) hide show
  1. package/README.md +8 -5
  2. package/dist/{base64-CiR5BJhk.d.cts → base64-D4VZhgUg.d.ts} +2 -2
  3. package/dist/{base64-CxkinHPQ.d.ts → base64-DR4Gl8cD.d.cts} +2 -2
  4. package/dist/{chunk-EWTHDEIW.js → chunk-34YJQFCM.js} +3 -3
  5. package/dist/{chunk-EWTHDEIW.js.map → chunk-34YJQFCM.js.map} +1 -1
  6. package/dist/{chunk-6LEXYQ7J.cjs → chunk-DXBAN4SN.cjs} +4 -4
  7. package/dist/{chunk-6LEXYQ7J.cjs.map → chunk-DXBAN4SN.cjs.map} +1 -1
  8. package/dist/{chunk-TD2PHUYP.js → chunk-I7SL4A6X.js} +19 -3
  9. package/dist/chunk-I7SL4A6X.js.map +1 -0
  10. package/dist/{chunk-22FJ4JQO.cjs → chunk-IKQIIMM6.cjs} +35 -35
  11. package/dist/{chunk-22FJ4JQO.cjs.map → chunk-IKQIIMM6.cjs.map} +1 -1
  12. package/dist/{chunk-H37YVYZA.cjs → chunk-MZKLAHBK.cjs} +19 -3
  13. package/dist/chunk-MZKLAHBK.cjs.map +1 -0
  14. package/dist/{chunk-MLUWABVT.js → chunk-ZDJ55LR7.js} +4 -4
  15. package/dist/{chunk-MLUWABVT.js.map → chunk-ZDJ55LR7.js.map} +1 -1
  16. package/dist/edge.cjs +93 -93
  17. package/dist/edge.d.cts +4 -4
  18. package/dist/edge.d.ts +4 -4
  19. package/dist/edge.js +4 -4
  20. package/dist/index.cjs +755 -450
  21. package/dist/index.cjs.map +1 -1
  22. package/dist/index.d.cts +55 -26
  23. package/dist/index.d.ts +55 -26
  24. package/dist/index.js +439 -134
  25. package/dist/index.js.map +1 -1
  26. package/dist/{receipt-Cg9a5Seq.d.ts → receipt-CbD8L0WL.d.ts} +1 -1
  27. package/dist/{receipt-q7ez8Zb2.d.cts → receipt-_bWCELEH.d.cts} +1 -1
  28. package/dist/test-support.cjs +21 -21
  29. package/dist/test-support.d.cts +2 -2
  30. package/dist/test-support.d.ts +2 -2
  31. package/dist/test-support.js +2 -2
  32. package/dist/{types-BKgqzvnk.d.cts → types-DKmvjXK6.d.cts} +65 -10
  33. package/dist/{types-BKgqzvnk.d.ts → types-DKmvjXK6.d.ts} +65 -10
  34. package/package.json +1 -1
  35. package/dist/chunk-H37YVYZA.cjs.map +0 -1
  36. package/dist/chunk-TD2PHUYP.js.map +0 -1
@@ -1,4 +1,4 @@
1
- import { aW as RawPaymentParties } from './types-BKgqzvnk.js';
1
+ import { aW as RawPaymentParties } from './types-DKmvjXK6.js';
2
2
 
3
3
  /**
4
4
  * Verifiable payment receipts.
@@ -1,4 +1,4 @@
1
- import { aW as RawPaymentParties } from './types-BKgqzvnk.cjs';
1
+ import { aW as RawPaymentParties } from './types-DKmvjXK6.cjs';
2
2
 
3
3
  /**
4
4
  * Verifiable payment receipts.
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
- var chunk6LEXYQ7J_cjs = require('./chunk-6LEXYQ7J.cjs');
4
- var chunkH37YVYZA_cjs = require('./chunk-H37YVYZA.cjs');
3
+ var chunkDXBAN4SN_cjs = require('./chunk-DXBAN4SN.cjs');
4
+ var chunkMZKLAHBK_cjs = require('./chunk-MZKLAHBK.cjs');
5
5
  var viem = require('viem');
6
6
  var ethers = require('ethers');
7
7
 
@@ -9,7 +9,7 @@ var ZERO_BYTES32 = `0x${"00".repeat(32)}`;
9
9
  var ROOT_AUTHORITY = `0x${"ff".repeat(32)}`;
10
10
  var DEFAULT_DELEGATOR = "0x98989898989898989898989898989898989898De";
11
11
  var DELEGATION_ARRAY_PARAM = [
12
- { type: "tuple[]", components: chunkH37YVYZA_cjs.DELEGATION_TUPLE_COMPONENTS }
12
+ { type: "tuple[]", components: chunkMZKLAHBK_cjs.DELEGATION_TUPLE_COMPONENTS }
13
13
  ];
14
14
  var EXECUTE_ABI = [
15
15
  {
@@ -85,16 +85,16 @@ function buildBoundRedeemDelegationsCallData(options) {
85
85
  10000n
86
86
  );
87
87
  return viem.encodeFunctionData({
88
- abi: chunkH37YVYZA_cjs.REDEEM_DELEGATIONS_ABI,
88
+ abi: chunkMZKLAHBK_cjs.REDEEM_DELEGATIONS_ABI,
89
89
  functionName: "redeemDelegations",
90
- args: [[permissionContext], [chunkH37YVYZA_cjs.SINGLE_DEFAULT_MODE], [executionCallData]]
90
+ args: [[permissionContext], [chunkMZKLAHBK_cjs.SINGLE_DEFAULT_MODE], [executionCallData]]
91
91
  });
92
92
  }
93
93
  function buildEmptyPermissionContextRedemption(selfCallCallData) {
94
94
  return viem.encodeFunctionData({
95
- abi: chunkH37YVYZA_cjs.REDEEM_DELEGATIONS_ABI,
95
+ abi: chunkMZKLAHBK_cjs.REDEEM_DELEGATIONS_ABI,
96
96
  functionName: "redeemDelegations",
97
- args: [[buildEmptyPermissionContext()], [chunkH37YVYZA_cjs.SINGLE_DEFAULT_MODE], [selfCallCallData]]
97
+ args: [[buildEmptyPermissionContext()], [chunkMZKLAHBK_cjs.SINGLE_DEFAULT_MODE], [selfCallCallData]]
98
98
  });
99
99
  }
100
100
  function buildExecuteCallData(target, value, innerCallData) {
@@ -106,20 +106,20 @@ function buildExecuteCallData(target, value, innerCallData) {
106
106
  }
107
107
  function buildBoundDirectUserOp(options) {
108
108
  const chainId = options.chainId ?? 84532;
109
- const sender = options.sender ?? chunkH37YVYZA_cjs.deriveDelegateAccountAddress(options.delegate);
109
+ const sender = options.sender ?? chunkMZKLAHBK_cjs.deriveDelegateAccountAddress(options.delegate);
110
110
  const callData = options.callData ?? buildExecuteCallData(
111
- options.target ?? chunkH37YVYZA_cjs.DELEGATION_MANAGER,
111
+ options.target ?? chunkMZKLAHBK_cjs.DELEGATION_MANAGER,
112
112
  options.value ?? 0n,
113
113
  buildBoundRedeemDelegationsCallData({ delegate: sender, delegator: options.delegator })
114
114
  );
115
115
  const typedData = {
116
116
  domain: {
117
- name: chunkH37YVYZA_cjs.HYBRID_DELEGATOR_DOMAIN_NAME,
118
- version: chunkH37YVYZA_cjs.HYBRID_DELEGATOR_DOMAIN_VERSION,
117
+ name: chunkMZKLAHBK_cjs.HYBRID_DELEGATOR_DOMAIN_NAME,
118
+ version: chunkMZKLAHBK_cjs.HYBRID_DELEGATOR_DOMAIN_VERSION,
119
119
  chainId,
120
120
  verifyingContract: sender
121
121
  },
122
- types: { PackedUserOperation: chunkH37YVYZA_cjs.PACKED_USER_OPERATION_FIELDS.map((field) => ({ ...field })) },
122
+ types: { PackedUserOperation: chunkMZKLAHBK_cjs.PACKED_USER_OPERATION_FIELDS.map((field) => ({ ...field })) },
123
123
  primaryType: "PackedUserOperation",
124
124
  message: {
125
125
  sender,
@@ -130,10 +130,10 @@ function buildBoundDirectUserOp(options) {
130
130
  preVerificationGas: "0",
131
131
  gasFees: ZERO_BYTES32,
132
132
  paymasterAndData: "0x",
133
- entryPoint: chunkH37YVYZA_cjs.ENTRY_POINT_V07
133
+ entryPoint: chunkMZKLAHBK_cjs.ENTRY_POINT_V07
134
134
  }
135
135
  };
136
- const payloadHash = chunkH37YVYZA_cjs.packedUserOperationHash(typedData);
136
+ const payloadHash = chunkMZKLAHBK_cjs.packedUserOperationHash(typedData);
137
137
  return { typedData, payloadHash, sender };
138
138
  }
139
139
  function buildSelfCallCallData(sender) {
@@ -151,7 +151,7 @@ function rebuildDirectUserOpForSender(fixtureTypedData, newSender) {
151
151
  const originalCallData = fixtureTypedData.message.callData;
152
152
  const { args: executeArgs } = viem.decodeFunctionData({ abi: EXECUTE_ABI, data: originalCallData });
153
153
  const execution = executeArgs[0];
154
- const { args: redeemArgs } = viem.decodeFunctionData({ abi: chunkH37YVYZA_cjs.REDEEM_DELEGATIONS_ABI, data: execution.callData });
154
+ const { args: redeemArgs } = viem.decodeFunctionData({ abi: chunkMZKLAHBK_cjs.REDEEM_DELEGATIONS_ABI, data: execution.callData });
155
155
  const [permissionContexts, modes, executionCallDatas] = redeemArgs;
156
156
  const [delegations] = viem.decodeAbiParameters(DELEGATION_ARRAY_PARAM, permissionContexts[0]);
157
157
  const adjustedDelegations = delegations.map(
@@ -159,7 +159,7 @@ function rebuildDirectUserOpForSender(fixtureTypedData, newSender) {
159
159
  );
160
160
  const adjustedPermissionContext = viem.encodeAbiParameters(DELEGATION_ARRAY_PARAM, [adjustedDelegations]);
161
161
  const adjustedRedeemCallData = viem.encodeFunctionData({
162
- abi: chunkH37YVYZA_cjs.REDEEM_DELEGATIONS_ABI,
162
+ abi: chunkMZKLAHBK_cjs.REDEEM_DELEGATIONS_ABI,
163
163
  functionName: "redeemDelegations",
164
164
  args: [[adjustedPermissionContext], modes, executionCallDatas]
165
165
  });
@@ -173,13 +173,13 @@ function rebuildDirectUserOpForSender(fixtureTypedData, newSender) {
173
173
  domain: { ...fixtureTypedData.domain, verifyingContract: newSender },
174
174
  message: { ...fixtureTypedData.message, sender: newSender, callData: adjustedCallData }
175
175
  };
176
- const payloadHash = chunkH37YVYZA_cjs.packedUserOperationHash(typedData);
176
+ const payloadHash = chunkMZKLAHBK_cjs.packedUserOperationHash(typedData);
177
177
  return { typedData, payloadHash };
178
178
  }
179
179
  function buildFundingLegUserOp(options) {
180
- const sender = chunkH37YVYZA_cjs.deriveDelegateAccountAddress(options.delegate);
180
+ const sender = chunkMZKLAHBK_cjs.deriveDelegateAccountAddress(options.delegate);
181
181
  const callData = buildExecuteCallData(
182
- chunkH37YVYZA_cjs.DELEGATION_MANAGER,
182
+ chunkMZKLAHBK_cjs.DELEGATION_MANAGER,
183
183
  0n,
184
184
  buildBoundRedeemDelegationsCallData({
185
185
  delegate: sender,
@@ -212,7 +212,7 @@ function delegationDigest(signHash, chainId) {
212
212
  viem.keccak256(viem.toBytes("DelegationManager")),
213
213
  viem.keccak256(viem.toBytes("1")),
214
214
  BigInt(chainId),
215
- chunkH37YVYZA_cjs.DELEGATION_MANAGER
215
+ chunkMZKLAHBK_cjs.DELEGATION_MANAGER
216
216
  ]
217
217
  )
218
218
  );
@@ -224,7 +224,7 @@ function signedErc7710Receipt(options = {}) {
224
224
  const delegate = new ethers.Wallet(options.delegateKey ?? RECEIPT_DELEGATE_KEY);
225
225
  const signature = delegate.signingKey.sign(delegationDigest(signHash, chainId)).serialized;
226
226
  return {
227
- version: chunk6LEXYQ7J_cjs.RECEIPT_VERSION,
227
+ version: chunkDXBAN4SN_cjs.RECEIPT_VERSION,
228
228
  paymentId: options.paymentId ?? "pay_3723",
229
229
  payment: {
230
230
  token: "USDC",
@@ -1,6 +1,6 @@
1
1
  import { Address, Hex } from 'viem';
2
- import { P as PaymentReceipt } from './receipt-q7ez8Zb2.cjs';
3
- import './types-BKgqzvnk.cjs';
2
+ import { P as PaymentReceipt } from './receipt-_bWCELEH.cjs';
3
+ import './types-DKmvjXK6.cjs';
4
4
 
5
5
  /**
6
6
  * #3272 — a real-shaped, BOUND direct-payment `PackedUserOperation` for
@@ -1,6 +1,6 @@
1
1
  import { Address, Hex } from 'viem';
2
- import { P as PaymentReceipt } from './receipt-Cg9a5Seq.js';
3
- import './types-BKgqzvnk.js';
2
+ import { P as PaymentReceipt } from './receipt-CbD8L0WL.js';
3
+ import './types-DKmvjXK6.js';
4
4
 
5
5
  /**
6
6
  * #3272 — a real-shaped, BOUND direct-payment `PackedUserOperation` for
@@ -1,5 +1,5 @@
1
- import { RECEIPT_VERSION } from './chunk-EWTHDEIW.js';
2
- import { DELEGATION_TUPLE_COMPONENTS, SINGLE_DEFAULT_MODE, REDEEM_DELEGATIONS_ABI, deriveDelegateAccountAddress, DELEGATION_MANAGER, PACKED_USER_OPERATION_FIELDS, packedUserOperationHash, ENTRY_POINT_V07, HYBRID_DELEGATOR_DOMAIN_VERSION, HYBRID_DELEGATOR_DOMAIN_NAME } from './chunk-TD2PHUYP.js';
1
+ import { RECEIPT_VERSION } from './chunk-34YJQFCM.js';
2
+ import { DELEGATION_TUPLE_COMPONENTS, SINGLE_DEFAULT_MODE, REDEEM_DELEGATIONS_ABI, deriveDelegateAccountAddress, DELEGATION_MANAGER, PACKED_USER_OPERATION_FIELDS, packedUserOperationHash, ENTRY_POINT_V07, HYBRID_DELEGATOR_DOMAIN_VERSION, HYBRID_DELEGATOR_DOMAIN_NAME } from './chunk-I7SL4A6X.js';
3
3
  import { keccak256, toBytes, encodeAbiParameters, encodePacked, encodeFunctionData, decodeFunctionData, decodeAbiParameters, hashTypedData, concatHex } from 'viem';
4
4
  import { Wallet } from 'ethers';
5
5
 
@@ -14,9 +14,14 @@
14
14
  * it is a string check. A public host name whose DNS ANSWER points at
15
15
  * private space is NOT blocked here — that needs the resolution-time
16
16
  * checks parked in #3742–#3744 (owner-accepted residual, 2026-10-07).
17
- * - Without `merchantEgress`, NOTHING in the SDK changes: no `redirect:
18
- * 'manual'`, no body capping, no extra refusals. SDK, local-MCP and
19
- * embedder callers keep today's behaviour byte for byte.
17
+ * - Without `merchantEgress` there is no URL check, no body capping and no
18
+ * per-use budget. Redirects are still followed by the transport (#4257),
19
+ * under the platform's rules (20 hops, the Fetch spec's method/body
20
+ * rewrite), plus the one rule both paths share: a hop to another origin
21
+ * carries only the cross-origin header allow-list. A paid request (the
22
+ * delivery, or a body with an x402 payment in `_meta`) is never re-sent
23
+ * to another origin by a redirect that keeps the body (307/308, or 301/302
24
+ * on a method other than POST); any other request follows as before.
20
25
  * - The policy is network policy, not spend control. It never gates a
21
26
  * payment's authority — the on-chain allowance stays the real control
22
27
  * (CASP: off-chain policy is never the spend control).
@@ -48,7 +53,10 @@ interface MerchantEgressPolicy {
48
53
  /**
49
54
  * How many GET redirects may be followed; EVERY hop is re-asserted against
50
55
  * `assertUrl` before it connects. A redirect on any other method is
51
- * refused outright. `undefined` = no redirect following.
56
+ * refused outright. A hop to a different origin carries only the
57
+ * transport's cross-origin header allow-list (#4244): credentials and other
58
+ * caller headers stay with the origin they were sent to.
59
+ * `undefined` = no redirect following.
52
60
  */
53
61
  maxGetRedirects?: number;
54
62
  /** Per-use timeouts (ms). The effective deadline is `min(this, merchantTimeout)`. */
@@ -59,7 +67,14 @@ interface MerchantEgressPolicy {
59
67
  */
60
68
  responseByteCaps?: Partial<Record<MerchantEgressUse, number>>;
61
69
  }
62
- type MerchantEgressRefusalReason = 'url_not_allowed' | 'redirect_on_non_get' | 'redirect_missing_location' | 'redirect_invalid_location' | 'redirect_budget_exceeded';
70
+ type MerchantEgressRefusalReason = 'url_not_allowed' | 'redirect_on_non_get' | 'redirect_missing_location' | 'redirect_invalid_location' | 'redirect_budget_exceeded'
71
+ /**
72
+ * #4257: a redirect that keeps the body (307/308, or 301/302 on a method
73
+ * other than POST) would re-send it to another origin. Under a
74
+ * policy (GET only) this is unreachable; without one it fires for a paid
75
+ * delivery, or a body carrying an x402 payment in `_meta`.
76
+ */
77
+ | 'redirect_cross_origin_body';
63
78
  declare const MERCHANT_EGRESS_REFUSED_CODE = "MERCHANT_EGRESS_REFUSED";
64
79
  /**
65
80
  * The policy refused a merchant request. `beforeRequest` is true when the
@@ -73,7 +88,27 @@ declare class MerchantEgressRefusedError extends HavenError {
73
88
  readonly url: string;
74
89
  readonly refusal: MerchantEgressRefusalReason;
75
90
  readonly beforeRequest: boolean;
76
- constructor(message: string, url: string, refusal: MerchantEgressRefusalReason, beforeRequest: boolean);
91
+ /** #4257: the redirect status that was not followed, when a redirect was refused. */
92
+ readonly redirectStatus?: number;
93
+ /**
94
+ * #4257: set only when `url` IS the redirect target (a cross-origin body
95
+ * re-send, a spent hop budget, a hop `assertUrl` refused). A refusal that
96
+ * stopped at the answering URL itself (a non-GET redirect, a missing or
97
+ * unresolvable Location) leaves it unset, and `url` is that answering URL.
98
+ */
99
+ readonly redirectTarget?: string;
100
+ /**
101
+ * #4257: set when the refusal interrupted a PAID delivery and the local
102
+ * completion has re-thrown it with the payment it belongs to — the funded,
103
+ * undelivered state, never "nothing happened".
104
+ */
105
+ readonly settlementScheme?: 'eip3009' | 'erc7710';
106
+ constructor(message: string, url: string, refusal: MerchantEgressRefusalReason, beforeRequest: boolean, extra?: {
107
+ redirectStatus?: number;
108
+ redirectTarget?: string;
109
+ paymentId?: string;
110
+ settlementScheme?: 'eip3009' | 'erc7710';
111
+ });
77
112
  }
78
113
  declare const MERCHANT_EGRESS_RESPONSE_CAP_CODE = "MERCHANT_EGRESS_RESPONSE_CAP";
79
114
  /**
@@ -1107,9 +1142,9 @@ interface HavenSubBudgetCloseSignData {
1107
1142
  /** #3506: `POST /sub-budgets/:id/close`. */
1108
1143
  interface CloseSubBudgetResult {
1109
1144
  subBudget: HavenSubBudget;
1110
- /** `closed` on a trivial close (never signed, or already expired); absent when a close signature is pending. */
1145
+ /** `closed` on a trivial close (never signed, or `open` and already expired) or when the chain already shows it disabled; absent when a close signature is pending. */
1111
1146
  status?: 'closed';
1112
- /** Present only when the close needed a signature (a live child). */
1147
+ /** Present only when the close needed a signature (a live child, or any `closing` row — #3923). */
1113
1148
  signData?: HavenSubBudgetCloseSignData;
1114
1149
  nextAction?: string;
1115
1150
  }
@@ -1145,6 +1180,8 @@ interface HavenTaskBudget {
1145
1180
  status: HavenTaskBudgetStatus;
1146
1181
  expiresAt: number;
1147
1182
  isExpired: boolean;
1183
+ /** #3922: camelCase `is_live`; absent when the backend predates it (presence preserved). */
1184
+ isLive?: boolean;
1148
1185
  createdAt: string;
1149
1186
  openedAt: string | null;
1150
1187
  closedAt: string | null;
@@ -1793,6 +1830,22 @@ declare const AgentPaymentWarningCode: {
1793
1830
  * settlement can no longer land at all.
1794
1831
  */
1795
1832
  readonly SettlementUnconfirmed: "SETTLEMENT_UNCONFIRMED";
1833
+ /**
1834
+ * #3967: the quote-time budget pre-check decided the quoted amount does NOT
1835
+ * fit the agent's remaining delegation budget — the same server-side compare
1836
+ * the payment path runs before funding. Travels beside
1837
+ * `budget_check.sufficient: false` and, on `haven_quote_x402`,
1838
+ * `safe_to_continue: false` with no prefilled cap. The on-chain policy
1839
+ * remains the actual gate either way.
1840
+ */
1841
+ readonly QuoteExceedsRemainingBudget: "QUOTE_EXCEEDS_REMAINING_BUDGET";
1842
+ /**
1843
+ * #3967: the MERCHANT reported a denial on one of its x402 payment options —
1844
+ * a known denial key (starting with `issuanceDenied`) in `accepts[].extra`.
1845
+ * Strictly informational: it flips neither `safe_to_continue` nor
1846
+ * `expected_settleable`; the agent should surface it to the user.
1847
+ */
1848
+ readonly MerchantReportedDenial: "MERCHANT_REPORTED_DENIAL";
1796
1849
  };
1797
1850
  type AgentPaymentWarningCode = (typeof AgentPaymentWarningCode)[keyof typeof AgentPaymentWarningCode];
1798
1851
  interface AgentPaymentWarning {
@@ -2053,9 +2106,11 @@ interface HavenCatalogEntry {
2053
2106
  * (the operator vouches for the listing; the catalog refresh probe still
2054
2107
  * checks the endpoint, see `verifiedPayable`). `ingestion` = submitted
2055
2108
  * through the Verified Payable Directory and passed domain-ownership proof
2056
- * plus the read-only quote probe.
2109
+ * plus the read-only quote probe. `bazaar` = written by the x402 Bazaar
2110
+ * discovery cron (#4245): seller-chosen name and description, no operator
2111
+ * review, no ownership proof.
2057
2112
  */
2058
- source: 'operator' | 'ingestion';
2113
+ source: 'operator' | 'ingestion' | 'bazaar';
2059
2114
  /** True only for `ingestion` entries — the one ownership claim. See the epic's trust claim (never merchant honesty or quality). */
2060
2115
  domainVerified: boolean;
2061
2116
  /**
@@ -14,9 +14,14 @@
14
14
  * it is a string check. A public host name whose DNS ANSWER points at
15
15
  * private space is NOT blocked here — that needs the resolution-time
16
16
  * checks parked in #3742–#3744 (owner-accepted residual, 2026-10-07).
17
- * - Without `merchantEgress`, NOTHING in the SDK changes: no `redirect:
18
- * 'manual'`, no body capping, no extra refusals. SDK, local-MCP and
19
- * embedder callers keep today's behaviour byte for byte.
17
+ * - Without `merchantEgress` there is no URL check, no body capping and no
18
+ * per-use budget. Redirects are still followed by the transport (#4257),
19
+ * under the platform's rules (20 hops, the Fetch spec's method/body
20
+ * rewrite), plus the one rule both paths share: a hop to another origin
21
+ * carries only the cross-origin header allow-list. A paid request (the
22
+ * delivery, or a body with an x402 payment in `_meta`) is never re-sent
23
+ * to another origin by a redirect that keeps the body (307/308, or 301/302
24
+ * on a method other than POST); any other request follows as before.
20
25
  * - The policy is network policy, not spend control. It never gates a
21
26
  * payment's authority — the on-chain allowance stays the real control
22
27
  * (CASP: off-chain policy is never the spend control).
@@ -48,7 +53,10 @@ interface MerchantEgressPolicy {
48
53
  /**
49
54
  * How many GET redirects may be followed; EVERY hop is re-asserted against
50
55
  * `assertUrl` before it connects. A redirect on any other method is
51
- * refused outright. `undefined` = no redirect following.
56
+ * refused outright. A hop to a different origin carries only the
57
+ * transport's cross-origin header allow-list (#4244): credentials and other
58
+ * caller headers stay with the origin they were sent to.
59
+ * `undefined` = no redirect following.
52
60
  */
53
61
  maxGetRedirects?: number;
54
62
  /** Per-use timeouts (ms). The effective deadline is `min(this, merchantTimeout)`. */
@@ -59,7 +67,14 @@ interface MerchantEgressPolicy {
59
67
  */
60
68
  responseByteCaps?: Partial<Record<MerchantEgressUse, number>>;
61
69
  }
62
- type MerchantEgressRefusalReason = 'url_not_allowed' | 'redirect_on_non_get' | 'redirect_missing_location' | 'redirect_invalid_location' | 'redirect_budget_exceeded';
70
+ type MerchantEgressRefusalReason = 'url_not_allowed' | 'redirect_on_non_get' | 'redirect_missing_location' | 'redirect_invalid_location' | 'redirect_budget_exceeded'
71
+ /**
72
+ * #4257: a redirect that keeps the body (307/308, or 301/302 on a method
73
+ * other than POST) would re-send it to another origin. Under a
74
+ * policy (GET only) this is unreachable; without one it fires for a paid
75
+ * delivery, or a body carrying an x402 payment in `_meta`.
76
+ */
77
+ | 'redirect_cross_origin_body';
63
78
  declare const MERCHANT_EGRESS_REFUSED_CODE = "MERCHANT_EGRESS_REFUSED";
64
79
  /**
65
80
  * The policy refused a merchant request. `beforeRequest` is true when the
@@ -73,7 +88,27 @@ declare class MerchantEgressRefusedError extends HavenError {
73
88
  readonly url: string;
74
89
  readonly refusal: MerchantEgressRefusalReason;
75
90
  readonly beforeRequest: boolean;
76
- constructor(message: string, url: string, refusal: MerchantEgressRefusalReason, beforeRequest: boolean);
91
+ /** #4257: the redirect status that was not followed, when a redirect was refused. */
92
+ readonly redirectStatus?: number;
93
+ /**
94
+ * #4257: set only when `url` IS the redirect target (a cross-origin body
95
+ * re-send, a spent hop budget, a hop `assertUrl` refused). A refusal that
96
+ * stopped at the answering URL itself (a non-GET redirect, a missing or
97
+ * unresolvable Location) leaves it unset, and `url` is that answering URL.
98
+ */
99
+ readonly redirectTarget?: string;
100
+ /**
101
+ * #4257: set when the refusal interrupted a PAID delivery and the local
102
+ * completion has re-thrown it with the payment it belongs to — the funded,
103
+ * undelivered state, never "nothing happened".
104
+ */
105
+ readonly settlementScheme?: 'eip3009' | 'erc7710';
106
+ constructor(message: string, url: string, refusal: MerchantEgressRefusalReason, beforeRequest: boolean, extra?: {
107
+ redirectStatus?: number;
108
+ redirectTarget?: string;
109
+ paymentId?: string;
110
+ settlementScheme?: 'eip3009' | 'erc7710';
111
+ });
77
112
  }
78
113
  declare const MERCHANT_EGRESS_RESPONSE_CAP_CODE = "MERCHANT_EGRESS_RESPONSE_CAP";
79
114
  /**
@@ -1107,9 +1142,9 @@ interface HavenSubBudgetCloseSignData {
1107
1142
  /** #3506: `POST /sub-budgets/:id/close`. */
1108
1143
  interface CloseSubBudgetResult {
1109
1144
  subBudget: HavenSubBudget;
1110
- /** `closed` on a trivial close (never signed, or already expired); absent when a close signature is pending. */
1145
+ /** `closed` on a trivial close (never signed, or `open` and already expired) or when the chain already shows it disabled; absent when a close signature is pending. */
1111
1146
  status?: 'closed';
1112
- /** Present only when the close needed a signature (a live child). */
1147
+ /** Present only when the close needed a signature (a live child, or any `closing` row — #3923). */
1113
1148
  signData?: HavenSubBudgetCloseSignData;
1114
1149
  nextAction?: string;
1115
1150
  }
@@ -1145,6 +1180,8 @@ interface HavenTaskBudget {
1145
1180
  status: HavenTaskBudgetStatus;
1146
1181
  expiresAt: number;
1147
1182
  isExpired: boolean;
1183
+ /** #3922: camelCase `is_live`; absent when the backend predates it (presence preserved). */
1184
+ isLive?: boolean;
1148
1185
  createdAt: string;
1149
1186
  openedAt: string | null;
1150
1187
  closedAt: string | null;
@@ -1793,6 +1830,22 @@ declare const AgentPaymentWarningCode: {
1793
1830
  * settlement can no longer land at all.
1794
1831
  */
1795
1832
  readonly SettlementUnconfirmed: "SETTLEMENT_UNCONFIRMED";
1833
+ /**
1834
+ * #3967: the quote-time budget pre-check decided the quoted amount does NOT
1835
+ * fit the agent's remaining delegation budget — the same server-side compare
1836
+ * the payment path runs before funding. Travels beside
1837
+ * `budget_check.sufficient: false` and, on `haven_quote_x402`,
1838
+ * `safe_to_continue: false` with no prefilled cap. The on-chain policy
1839
+ * remains the actual gate either way.
1840
+ */
1841
+ readonly QuoteExceedsRemainingBudget: "QUOTE_EXCEEDS_REMAINING_BUDGET";
1842
+ /**
1843
+ * #3967: the MERCHANT reported a denial on one of its x402 payment options —
1844
+ * a known denial key (starting with `issuanceDenied`) in `accepts[].extra`.
1845
+ * Strictly informational: it flips neither `safe_to_continue` nor
1846
+ * `expected_settleable`; the agent should surface it to the user.
1847
+ */
1848
+ readonly MerchantReportedDenial: "MERCHANT_REPORTED_DENIAL";
1796
1849
  };
1797
1850
  type AgentPaymentWarningCode = (typeof AgentPaymentWarningCode)[keyof typeof AgentPaymentWarningCode];
1798
1851
  interface AgentPaymentWarning {
@@ -2053,9 +2106,11 @@ interface HavenCatalogEntry {
2053
2106
  * (the operator vouches for the listing; the catalog refresh probe still
2054
2107
  * checks the endpoint, see `verifiedPayable`). `ingestion` = submitted
2055
2108
  * through the Verified Payable Directory and passed domain-ownership proof
2056
- * plus the read-only quote probe.
2109
+ * plus the read-only quote probe. `bazaar` = written by the x402 Bazaar
2110
+ * discovery cron (#4245): seller-chosen name and description, no operator
2111
+ * review, no ownership proof.
2057
2112
  */
2058
- source: 'operator' | 'ingestion';
2113
+ source: 'operator' | 'ingestion' | 'bazaar';
2059
2114
  /** True only for `ingestion` entries — the one ownership claim. See the epic's trust claim (never merchant honesty or quality). */
2060
2115
  domainVerified: boolean;
2061
2116
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@haven_ai/sdk",
3
- "version": "0.10.0-alpha.0",
3
+ "version": "0.11.0-alpha.0",
4
4
  "description": "TypeScript SDK for Haven — give AI agents budgeted, non-custodial payment ability. Pay x402 (HTTP 402) APIs in USDC within on-chain-enforced spending limits; the agent never holds funds or keys.",
5
5
  "engines": {
6
6
  "node": ">=22"