@haven_ai/sdk 0.0.0-dev.202609180723.d49b927 → 0.0.0-dev.202609180817.b16be14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +60 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +57 -3
- package/dist/index.d.ts +57 -3
- package/dist/index.js +56 -5
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1420,6 +1420,51 @@ function throwPaymentStateError(label, raw) {
|
|
|
1420
1420
|
throw new HavenApiError(message, statusCode, raw);
|
|
1421
1421
|
}
|
|
1422
1422
|
|
|
1423
|
+
// src/x402-retry-target.ts
|
|
1424
|
+
function resolveX402RetryTarget(input) {
|
|
1425
|
+
const requestUrl = input.requestUrl?.trim() || void 0;
|
|
1426
|
+
if (requestUrl) {
|
|
1427
|
+
return {
|
|
1428
|
+
url: requestUrl,
|
|
1429
|
+
source: "request",
|
|
1430
|
+
resourceUrlDiffersFromRequest: requestUrl !== input.resourceUrl
|
|
1431
|
+
};
|
|
1432
|
+
}
|
|
1433
|
+
return { url: input.resourceUrl, source: "resource" };
|
|
1434
|
+
}
|
|
1435
|
+
var LOOPBACK_HOSTS = /* @__PURE__ */ new Set(["localhost", "::1", "[::1]"]);
|
|
1436
|
+
var RESERVED_SUFFIXES = [".test", ".localhost", ".invalid", ".example"];
|
|
1437
|
+
var IPV4_LOOPBACK = /^127(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}$/;
|
|
1438
|
+
function isSecureX402RetryTarget(url) {
|
|
1439
|
+
let parsed;
|
|
1440
|
+
try {
|
|
1441
|
+
parsed = new URL(url);
|
|
1442
|
+
} catch {
|
|
1443
|
+
return false;
|
|
1444
|
+
}
|
|
1445
|
+
if (parsed.protocol === "https:") return true;
|
|
1446
|
+
if (parsed.protocol !== "http:") return false;
|
|
1447
|
+
const host = parsed.hostname.toLowerCase();
|
|
1448
|
+
if (LOOPBACK_HOSTS.has(host) || IPV4_LOOPBACK.test(host)) return true;
|
|
1449
|
+
return RESERVED_SUFFIXES.some((suffix) => host.endsWith(suffix));
|
|
1450
|
+
}
|
|
1451
|
+
var INSECURE_RETRY_TARGET_CODE = "INSECURE_RETRY_TARGET";
|
|
1452
|
+
var HavenInsecureRetryTargetError = class extends HavenError {
|
|
1453
|
+
constructor(url) {
|
|
1454
|
+
super(
|
|
1455
|
+
`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.`,
|
|
1456
|
+
INSECURE_RETRY_TARGET_CODE,
|
|
1457
|
+
400
|
|
1458
|
+
);
|
|
1459
|
+
this.url = url;
|
|
1460
|
+
this.name = "HavenInsecureRetryTargetError";
|
|
1461
|
+
}
|
|
1462
|
+
url;
|
|
1463
|
+
};
|
|
1464
|
+
function assertSecureX402RetryTarget(url) {
|
|
1465
|
+
if (!isSecureX402RetryTarget(url)) throw new HavenInsecureRetryTargetError(url);
|
|
1466
|
+
}
|
|
1467
|
+
|
|
1423
1468
|
// src/mcp-merchant-transport.ts
|
|
1424
1469
|
var DEFAULT_MERCHANT_TIMEOUT = 3e5;
|
|
1425
1470
|
var MCP_NOTIFICATION_TIMEOUT = 1e4;
|
|
@@ -1577,6 +1622,7 @@ var McpMerchantTransport = class {
|
|
|
1577
1622
|
* overwrite, which is worse than the duplicate this change removes.
|
|
1578
1623
|
*/
|
|
1579
1624
|
async deliverPayment(url, init, paymentHeader) {
|
|
1625
|
+
assertSecureX402RetryTarget(url);
|
|
1580
1626
|
const headers = new Headers(init?.headers);
|
|
1581
1627
|
const send = x402PaymentHeaderNamesFor(paymentHeader);
|
|
1582
1628
|
for (const name of X402_PAYMENT_HEADER_NAMES) {
|
|
@@ -2006,6 +2052,11 @@ function buildX402Quote(paymentRequired, request, idempotencyKey, mcpTransport)
|
|
|
2006
2052
|
request,
|
|
2007
2053
|
...mcpTransport ? { mcpTransport } : {},
|
|
2008
2054
|
resourceUrl: paymentRequired.resource.url,
|
|
2055
|
+
// #3097: the merchant's declaration vs the URL the caller quoted. The
|
|
2056
|
+
// paid retry goes to the caller's URL; a quote that says the two disagree
|
|
2057
|
+
// is how an agent sees a challenge that downgrades the scheme or moves
|
|
2058
|
+
// the host before it pays.
|
|
2059
|
+
resourceUrlDiffersFromRequest: paymentRequired.resource.url !== request.url,
|
|
2009
2060
|
description: paymentRequired.resource.description ?? option.description ?? null,
|
|
2010
2061
|
mimeType: paymentRequired.resource.mimeType ?? option.mimeType ?? null,
|
|
2011
2062
|
amountAtomic: x402AuthorizationAmount(option),
|
|
@@ -4289,10 +4340,10 @@ var toolDescriptions = {
|
|
|
4289
4340
|
nextActionGuidance: "On a decline, report the reason to the user and ask them to raise the budget in Haven \u2014 there is no approval queue to wait on. This tool retries the merchant itself while it runs, so do not wait on a signal mid-call. If the process crashes after payment, a later haven_get_payment_status call may report nextAction=retry_original_x402_request \u2014 resume via haven_resume_x402_payment instead of paying again."
|
|
4290
4341
|
},
|
|
4291
4342
|
discoverTools: {
|
|
4292
|
-
summary: "Step 1 of a purchase: discover payable services from Haven's curated merchant catalog \u2014 names, prices,
|
|
4293
|
-
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
|
|
4294
|
-
behavior: "Use each entry's suggested_tool
|
|
4295
|
-
nextActionGuidance: `
|
|
4343
|
+
summary: "Step 1 of a purchase: discover payable services from Haven's curated merchant catalog \u2014 names, prices, the next call.",
|
|
4344
|
+
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.",
|
|
4345
|
+
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.",
|
|
4346
|
+
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.`
|
|
4296
4347
|
},
|
|
4297
4348
|
submitCatalogEntry: {
|
|
4298
4349
|
summary: "Submit a merchant's payable (x402/MCP) endpoint to Haven's Verified Payable Directory for verification and listing.",
|
|
@@ -5087,11 +5138,13 @@ exports.HAVEN_SKILL_MD = HAVEN_SKILL_MD;
|
|
|
5087
5138
|
exports.HavenApiError = HavenApiError;
|
|
5088
5139
|
exports.HavenClient = HavenClient;
|
|
5089
5140
|
exports.HavenError = HavenError;
|
|
5141
|
+
exports.HavenInsecureRetryTargetError = HavenInsecureRetryTargetError;
|
|
5090
5142
|
exports.HavenPaymentStateError = HavenPaymentStateError;
|
|
5091
5143
|
exports.HavenSigningError = HavenSigningError;
|
|
5092
5144
|
exports.HavenTimeoutError = HavenTimeoutError;
|
|
5093
5145
|
exports.HavenUnsupportedSignerVersionError = HavenUnsupportedSignerVersionError;
|
|
5094
5146
|
exports.HavenZeroSettlementHashError = HavenZeroSettlementHashError;
|
|
5147
|
+
exports.INSECURE_RETRY_TARGET_CODE = INSECURE_RETRY_TARGET_CODE;
|
|
5095
5148
|
exports.MERCHANT_DISCOVERY_PATHS = MERCHANT_DISCOVERY_PATHS;
|
|
5096
5149
|
exports.MerchantTimeoutError = MerchantTimeoutError;
|
|
5097
5150
|
exports.RECEIPT_VERSION = RECEIPT_VERSION;
|
|
@@ -5114,6 +5167,7 @@ exports.X402_PAYMENT_REQUIRED_HEADER_NAME = X402_PAYMENT_REQUIRED_HEADER_NAME;
|
|
|
5114
5167
|
exports.X402_PAYMENT_RESPONSE_HEADER_NAME = X402_PAYMENT_RESPONSE_HEADER_NAME;
|
|
5115
5168
|
exports.X402_SETTLEMENT_FORWARD_MARGIN_SECONDS = X402_SETTLEMENT_FORWARD_MARGIN_SECONDS;
|
|
5116
5169
|
exports.addressFromKey = addressFromKey;
|
|
5170
|
+
exports.assertSecureX402RetryTarget = assertSecureX402RetryTarget;
|
|
5117
5171
|
exports.buildSweepAuthorizationMessage = buildSweepAuthorizationMessage;
|
|
5118
5172
|
exports.buildSweepTypedData = buildSweepTypedData;
|
|
5119
5173
|
exports.buildX402ExpectedMessage = buildX402ExpectedMessage;
|
|
@@ -5130,6 +5184,7 @@ exports.encodePaymentProof = encodePaymentProof;
|
|
|
5130
5184
|
exports.havenTools = havenTools;
|
|
5131
5185
|
exports.isConnectorChannel = isConnectorChannel;
|
|
5132
5186
|
exports.isErc7710Option = isErc7710Option;
|
|
5187
|
+
exports.isSecureX402RetryTarget = isSecureX402RetryTarget;
|
|
5133
5188
|
exports.isSupportedNodeVersion = isSupportedNodeVersion;
|
|
5134
5189
|
exports.isSweepableChain = isSweepableChain;
|
|
5135
5190
|
exports.isZeroSettlementTxHash = isZeroSettlementTxHash;
|
|
@@ -5139,6 +5194,7 @@ exports.parsePaymentRequiredResponse = parsePaymentRequiredResponse;
|
|
|
5139
5194
|
exports.readX402ReceiptPayer = readX402ReceiptPayer;
|
|
5140
5195
|
exports.resolveConnectorChannel = resolveConnectorChannel;
|
|
5141
5196
|
exports.resolveTokenFromAddress = resolveTokenFromAddress;
|
|
5197
|
+
exports.resolveX402RetryTarget = resolveX402RetryTarget;
|
|
5142
5198
|
exports.sameUrl = sameUrl;
|
|
5143
5199
|
exports.selectErc7710PaymentOption = selectErc7710PaymentOption;
|
|
5144
5200
|
exports.selectPaymentOption = selectPaymentOption;
|