@haven_ai/sdk 0.1.24-alpha.0 → 0.1.25-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.
package/dist/index.cjs CHANGED
@@ -2465,8 +2465,18 @@ var HavenClient = class {
2465
2465
  * balance — otherwise it rejects with "Payment verification failed". The
2466
2466
  * SDK's local path already does this (see authorizeStandardX402); the hosted
2467
2467
  * split flow regressed when the 5→3 collapse removed the incidental
2468
- * inter-call latency that used to mask it. No-op when the funding tx hash or
2469
- * a chain RPC (chainRpcs[chainId]) is unavailable.
2468
+ * inter-call latency that used to mask it.
2469
+ *
2470
+ * **NOT a no-op when the funding tx hash is absent** (#1508). The WAIT is
2471
+ * skipped without a hash or a chain RPC, but the `GET /payments/:id` read
2472
+ * below runs UNCONDITIONALLY — it is how the fallback hash and the chainId
2473
+ * are obtained. That distinction is load-bearing: this method must never be
2474
+ * called on a scheme with no funding leg, because the read itself fails once
2475
+ * the intent reaches a status the backend maps to a non-2xx (`submitted` is a
2476
+ * 409), turning a settled payment into a reported error. The previous wording
2477
+ * here said "No-op when the funding tx hash ... is unavailable", and the
2478
+ * hosted erc7710 path was written against that promise — see
2479
+ * `deliverMerchantPayment`'s `noFundingLeg` option.
2470
2480
  */
2471
2481
  async ensureFundingConfirmed(paymentId, fundingTxHash) {
2472
2482
  const status = await this.getPaymentStatus(paymentId);
@@ -2475,8 +2485,10 @@ var HavenClient = class {
2475
2485
  async completeX402MerchantCall(input) {
2476
2486
  const evidenceContext = await this.resolveX402MerchantCompletionContext({
2477
2487
  paymentId: input.paymentId,
2478
- url: input.url
2488
+ url: input.url,
2489
+ noFundingLeg: input.noFundingLeg === true
2479
2490
  });
2491
+ const fundingTxHash = evidenceContext.txHash;
2480
2492
  const shouldHandshakeMcp = isMcpUrl(input.url) || input.mcpTransport?.handshakeRequired === true;
2481
2493
  const x402Wallet = shouldHandshakeMcp ? await this.resolveX402WalletForMerchantCall() : this.x402PayerAddress();
2482
2494
  let mcpSessionId;
@@ -2500,33 +2512,37 @@ var HavenClient = class {
2500
2512
  body = text;
2501
2513
  }
2502
2514
  if (!surfaced.ok) {
2503
- await this.recordMerchantRetryRejected({
2504
- rail: "x402",
2505
- paymentId: evidenceContext.paymentId,
2506
- txHash: evidenceContext.txHash,
2507
- resourceUrl: evidenceContext.resourceUrl,
2508
- merchant: {
2509
- merchant_status: surfaced.status,
2510
- merchant_status_text: surfaced.statusText,
2511
- merchant_headers: Object.fromEntries(surfaced.headers.entries()),
2512
- merchant_body: text
2513
- },
2514
- details: {
2515
- merchant_to: evidenceContext.merchantAddress
2516
- }
2517
- });
2515
+ if (!input.noFundingLeg && fundingTxHash) {
2516
+ await this.recordMerchantRetryRejected({
2517
+ rail: "x402",
2518
+ paymentId: evidenceContext.paymentId,
2519
+ txHash: fundingTxHash,
2520
+ resourceUrl: evidenceContext.resourceUrl,
2521
+ merchant: {
2522
+ merchant_status: surfaced.status,
2523
+ merchant_status_text: surfaced.statusText,
2524
+ merchant_headers: Object.fromEntries(surfaced.headers.entries()),
2525
+ merchant_body: text
2526
+ },
2527
+ details: {
2528
+ merchant_to: evidenceContext.merchantAddress
2529
+ }
2530
+ });
2531
+ }
2518
2532
  } else {
2519
- await this.reportMachinePaymentEvidence({
2520
- paymentId: evidenceContext.paymentId,
2521
- rail: "x402",
2522
- txHash: evidenceContext.txHash,
2523
- resourceUrl: evidenceContext.resourceUrl,
2524
- merchantStatus: surfaced.status,
2525
- paymentProofHeaderName: "X-PAYMENT",
2526
- paymentProofHeader: input.paymentHeader,
2527
- protocolReceiptHeaderName: protocolReceiptHeader ? "PAYMENT-RESPONSE" : void 0,
2528
- protocolReceiptHeader
2529
- });
2533
+ if (!input.noFundingLeg && fundingTxHash) {
2534
+ await this.reportMachinePaymentEvidence({
2535
+ paymentId: evidenceContext.paymentId,
2536
+ rail: "x402",
2537
+ txHash: fundingTxHash,
2538
+ resourceUrl: evidenceContext.resourceUrl,
2539
+ merchantStatus: surfaced.status,
2540
+ paymentProofHeaderName: "X-PAYMENT",
2541
+ paymentProofHeader: input.paymentHeader,
2542
+ protocolReceiptHeaderName: protocolReceiptHeader ? "PAYMENT-RESPONSE" : void 0,
2543
+ protocolReceiptHeader
2544
+ });
2545
+ }
2530
2546
  await this.reportMerchantReceipt(evidenceContext.paymentId, surfaced);
2531
2547
  }
2532
2548
  return {
@@ -2572,11 +2588,11 @@ var HavenClient = class {
2572
2588
  status
2573
2589
  );
2574
2590
  }
2575
- const readyForMerchantCompletion = status.nextAction === AgentPaymentNextAction.RetryOriginalX402Request || status.kind === "payment_intent" && status.status === "confirmed" && status.phase === AgentPaymentPhase.PaymentConfirmed && status.nextAction === AgentPaymentNextAction.None;
2591
+ const readyForMerchantCompletion = input.noFundingLeg ? status.kind === "payment_intent" && status.status === "submitted" : status.nextAction === AgentPaymentNextAction.RetryOriginalX402Request || status.kind === "payment_intent" && status.status === "confirmed" && status.phase === AgentPaymentPhase.PaymentConfirmed && status.nextAction === AgentPaymentNextAction.None;
2576
2592
  if (!readyForMerchantCompletion) {
2577
2593
  throw new HavenPaymentStateError(status.message, PAYMENT_STATE_STATUS_CODES[status.status] ?? 409, status);
2578
2594
  }
2579
- if (!status.txHash) {
2595
+ if (!input.noFundingLeg && !status.txHash) {
2580
2596
  throw new HavenApiError(
2581
2597
  `x402 payment ${status.paymentId} is ready for merchant completion but has no Haven transaction hash.`,
2582
2598
  502,