@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.d.cts CHANGED
@@ -1758,8 +1758,18 @@ declare class HavenClient {
1758
1758
  * balance — otherwise it rejects with "Payment verification failed". The
1759
1759
  * SDK's local path already does this (see authorizeStandardX402); the hosted
1760
1760
  * split flow regressed when the 5→3 collapse removed the incidental
1761
- * inter-call latency that used to mask it. No-op when the funding tx hash or
1762
- * a chain RPC (chainRpcs[chainId]) is unavailable.
1761
+ * inter-call latency that used to mask it.
1762
+ *
1763
+ * **NOT a no-op when the funding tx hash is absent** (#1508). The WAIT is
1764
+ * skipped without a hash or a chain RPC, but the `GET /payments/:id` read
1765
+ * below runs UNCONDITIONALLY — it is how the fallback hash and the chainId
1766
+ * are obtained. That distinction is load-bearing: this method must never be
1767
+ * called on a scheme with no funding leg, because the read itself fails once
1768
+ * the intent reaches a status the backend maps to a non-2xx (`submitted` is a
1769
+ * 409), turning a settled payment into a reported error. The previous wording
1770
+ * here said "No-op when the funding tx hash ... is unavailable", and the
1771
+ * hosted erc7710 path was written against that promise — see
1772
+ * `deliverMerchantPayment`'s `noFundingLeg` option.
1763
1773
  */
1764
1774
  ensureFundingConfirmed(paymentId: string, fundingTxHash?: string): Promise<void>;
1765
1775
  completeX402MerchantCall(input: {
@@ -1768,6 +1778,16 @@ declare class HavenClient {
1768
1778
  paymentId: string;
1769
1779
  paymentHeader: string;
1770
1780
  mcpTransport?: X402McpTransport;
1781
+ /**
1782
+ * #1508: the payment settles with NO funding leg (erc7710). This method was
1783
+ * written for EIP-3009 and encodes that lifecycle in two places — the
1784
+ * readiness gate wants `confirmed`, and a Haven funding tx hash is
1785
+ * mandatory. Neither is reachable on a scheme where the MERCHANT redeems
1786
+ * the delegation chain: the intent sits at `submitted` by design, and there
1787
+ * is no Haven-submitted transaction at all. Set this to take the
1788
+ * no-funding-leg path through both.
1789
+ */
1790
+ noFundingLeg?: boolean;
1771
1791
  }): Promise<{
1772
1792
  status: number;
1773
1793
  ok: boolean;
package/dist/index.d.ts CHANGED
@@ -1758,8 +1758,18 @@ declare class HavenClient {
1758
1758
  * balance — otherwise it rejects with "Payment verification failed". The
1759
1759
  * SDK's local path already does this (see authorizeStandardX402); the hosted
1760
1760
  * split flow regressed when the 5→3 collapse removed the incidental
1761
- * inter-call latency that used to mask it. No-op when the funding tx hash or
1762
- * a chain RPC (chainRpcs[chainId]) is unavailable.
1761
+ * inter-call latency that used to mask it.
1762
+ *
1763
+ * **NOT a no-op when the funding tx hash is absent** (#1508). The WAIT is
1764
+ * skipped without a hash or a chain RPC, but the `GET /payments/:id` read
1765
+ * below runs UNCONDITIONALLY — it is how the fallback hash and the chainId
1766
+ * are obtained. That distinction is load-bearing: this method must never be
1767
+ * called on a scheme with no funding leg, because the read itself fails once
1768
+ * the intent reaches a status the backend maps to a non-2xx (`submitted` is a
1769
+ * 409), turning a settled payment into a reported error. The previous wording
1770
+ * here said "No-op when the funding tx hash ... is unavailable", and the
1771
+ * hosted erc7710 path was written against that promise — see
1772
+ * `deliverMerchantPayment`'s `noFundingLeg` option.
1763
1773
  */
1764
1774
  ensureFundingConfirmed(paymentId: string, fundingTxHash?: string): Promise<void>;
1765
1775
  completeX402MerchantCall(input: {
@@ -1768,6 +1778,16 @@ declare class HavenClient {
1768
1778
  paymentId: string;
1769
1779
  paymentHeader: string;
1770
1780
  mcpTransport?: X402McpTransport;
1781
+ /**
1782
+ * #1508: the payment settles with NO funding leg (erc7710). This method was
1783
+ * written for EIP-3009 and encodes that lifecycle in two places — the
1784
+ * readiness gate wants `confirmed`, and a Haven funding tx hash is
1785
+ * mandatory. Neither is reachable on a scheme where the MERCHANT redeems
1786
+ * the delegation chain: the intent sits at `submitted` by design, and there
1787
+ * is no Haven-submitted transaction at all. Set this to take the
1788
+ * no-funding-leg path through both.
1789
+ */
1790
+ noFundingLeg?: boolean;
1771
1791
  }): Promise<{
1772
1792
  status: number;
1773
1793
  ok: boolean;
package/dist/index.js CHANGED
@@ -2463,8 +2463,18 @@ var HavenClient = class {
2463
2463
  * balance — otherwise it rejects with "Payment verification failed". The
2464
2464
  * SDK's local path already does this (see authorizeStandardX402); the hosted
2465
2465
  * split flow regressed when the 5→3 collapse removed the incidental
2466
- * inter-call latency that used to mask it. No-op when the funding tx hash or
2467
- * a chain RPC (chainRpcs[chainId]) is unavailable.
2466
+ * inter-call latency that used to mask it.
2467
+ *
2468
+ * **NOT a no-op when the funding tx hash is absent** (#1508). The WAIT is
2469
+ * skipped without a hash or a chain RPC, but the `GET /payments/:id` read
2470
+ * below runs UNCONDITIONALLY — it is how the fallback hash and the chainId
2471
+ * are obtained. That distinction is load-bearing: this method must never be
2472
+ * called on a scheme with no funding leg, because the read itself fails once
2473
+ * the intent reaches a status the backend maps to a non-2xx (`submitted` is a
2474
+ * 409), turning a settled payment into a reported error. The previous wording
2475
+ * here said "No-op when the funding tx hash ... is unavailable", and the
2476
+ * hosted erc7710 path was written against that promise — see
2477
+ * `deliverMerchantPayment`'s `noFundingLeg` option.
2468
2478
  */
2469
2479
  async ensureFundingConfirmed(paymentId, fundingTxHash) {
2470
2480
  const status = await this.getPaymentStatus(paymentId);
@@ -2473,8 +2483,10 @@ var HavenClient = class {
2473
2483
  async completeX402MerchantCall(input) {
2474
2484
  const evidenceContext = await this.resolveX402MerchantCompletionContext({
2475
2485
  paymentId: input.paymentId,
2476
- url: input.url
2486
+ url: input.url,
2487
+ noFundingLeg: input.noFundingLeg === true
2477
2488
  });
2489
+ const fundingTxHash = evidenceContext.txHash;
2478
2490
  const shouldHandshakeMcp = isMcpUrl(input.url) || input.mcpTransport?.handshakeRequired === true;
2479
2491
  const x402Wallet = shouldHandshakeMcp ? await this.resolveX402WalletForMerchantCall() : this.x402PayerAddress();
2480
2492
  let mcpSessionId;
@@ -2498,33 +2510,37 @@ var HavenClient = class {
2498
2510
  body = text;
2499
2511
  }
2500
2512
  if (!surfaced.ok) {
2501
- await this.recordMerchantRetryRejected({
2502
- rail: "x402",
2503
- paymentId: evidenceContext.paymentId,
2504
- txHash: evidenceContext.txHash,
2505
- resourceUrl: evidenceContext.resourceUrl,
2506
- merchant: {
2507
- merchant_status: surfaced.status,
2508
- merchant_status_text: surfaced.statusText,
2509
- merchant_headers: Object.fromEntries(surfaced.headers.entries()),
2510
- merchant_body: text
2511
- },
2512
- details: {
2513
- merchant_to: evidenceContext.merchantAddress
2514
- }
2515
- });
2513
+ if (!input.noFundingLeg && fundingTxHash) {
2514
+ await this.recordMerchantRetryRejected({
2515
+ rail: "x402",
2516
+ paymentId: evidenceContext.paymentId,
2517
+ txHash: fundingTxHash,
2518
+ resourceUrl: evidenceContext.resourceUrl,
2519
+ merchant: {
2520
+ merchant_status: surfaced.status,
2521
+ merchant_status_text: surfaced.statusText,
2522
+ merchant_headers: Object.fromEntries(surfaced.headers.entries()),
2523
+ merchant_body: text
2524
+ },
2525
+ details: {
2526
+ merchant_to: evidenceContext.merchantAddress
2527
+ }
2528
+ });
2529
+ }
2516
2530
  } else {
2517
- await this.reportMachinePaymentEvidence({
2518
- paymentId: evidenceContext.paymentId,
2519
- rail: "x402",
2520
- txHash: evidenceContext.txHash,
2521
- resourceUrl: evidenceContext.resourceUrl,
2522
- merchantStatus: surfaced.status,
2523
- paymentProofHeaderName: "X-PAYMENT",
2524
- paymentProofHeader: input.paymentHeader,
2525
- protocolReceiptHeaderName: protocolReceiptHeader ? "PAYMENT-RESPONSE" : void 0,
2526
- protocolReceiptHeader
2527
- });
2531
+ if (!input.noFundingLeg && fundingTxHash) {
2532
+ await this.reportMachinePaymentEvidence({
2533
+ paymentId: evidenceContext.paymentId,
2534
+ rail: "x402",
2535
+ txHash: fundingTxHash,
2536
+ resourceUrl: evidenceContext.resourceUrl,
2537
+ merchantStatus: surfaced.status,
2538
+ paymentProofHeaderName: "X-PAYMENT",
2539
+ paymentProofHeader: input.paymentHeader,
2540
+ protocolReceiptHeaderName: protocolReceiptHeader ? "PAYMENT-RESPONSE" : void 0,
2541
+ protocolReceiptHeader
2542
+ });
2543
+ }
2528
2544
  await this.reportMerchantReceipt(evidenceContext.paymentId, surfaced);
2529
2545
  }
2530
2546
  return {
@@ -2570,11 +2586,11 @@ var HavenClient = class {
2570
2586
  status
2571
2587
  );
2572
2588
  }
2573
- const readyForMerchantCompletion = status.nextAction === AgentPaymentNextAction.RetryOriginalX402Request || status.kind === "payment_intent" && status.status === "confirmed" && status.phase === AgentPaymentPhase.PaymentConfirmed && status.nextAction === AgentPaymentNextAction.None;
2589
+ 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;
2574
2590
  if (!readyForMerchantCompletion) {
2575
2591
  throw new HavenPaymentStateError(status.message, PAYMENT_STATE_STATUS_CODES[status.status] ?? 409, status);
2576
2592
  }
2577
- if (!status.txHash) {
2593
+ if (!input.noFundingLeg && !status.txHash) {
2578
2594
  throw new HavenApiError(
2579
2595
  `x402 payment ${status.paymentId} is ready for merchant completion but has no Haven transaction hash.`,
2580
2596
  502,