bsv-x402 0.6.0 → 0.7.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
@@ -544,6 +544,8 @@ async function constructBrc105Proof(challenge, wallet, origin) {
544
544
  })
545
545
  }],
546
546
  options: {
547
+ returnTXIDOnly: false,
548
+ noSend: true,
547
549
  randomizeOutputs: false
548
550
  }
549
551
  });
@@ -555,13 +557,21 @@ async function constructBrc105Proof(challenge, wallet, origin) {
555
557
  } else {
556
558
  throw new Error("Wallet returned no transaction data (neither tx nor rawTx)");
557
559
  }
558
- return {
560
+ const proof = {
559
561
  derivationPrefix: challenge.derivationPrefix,
560
562
  derivationSuffix,
561
563
  transaction: transactionBase64,
562
564
  clientIdentityKey,
563
565
  txid: result.txid
564
566
  };
567
+ const abort = wallet.abortAction ? async () => {
568
+ try {
569
+ await wallet.abortAction({ reference: result.txid });
570
+ } catch (err) {
571
+ console.warn("[x402] abortAction failed:", err);
572
+ }
573
+ } : void 0;
574
+ return { proof, abort };
565
575
  }
566
576
 
567
577
  // src/challenge.ts
@@ -597,6 +607,22 @@ function parseChallenge(header) {
597
607
  }
598
608
 
599
609
  // src/x402-fetch.ts
610
+ function bytesToBase642(bytes) {
611
+ let binary = "";
612
+ for (const b of bytes) binary += String.fromCharCode(b);
613
+ return btoa(binary);
614
+ }
615
+ function numberArrayToBase642(arr) {
616
+ return bytesToBase642(new Uint8Array(arr));
617
+ }
618
+ function hexToBytes2(hex) {
619
+ if (hex.length % 2 !== 0) throw new Error("Hex string must have even length");
620
+ const bytes = new Uint8Array(hex.length / 2);
621
+ for (let i = 0; i < hex.length; i += 2) {
622
+ bytes[i / 2] = parseInt(hex.slice(i, i + 2), 16);
623
+ }
624
+ return bytes;
625
+ }
600
626
  var BASE58_ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
601
627
  function base58DecodeCheck(address) {
602
628
  let leadingZeros = 0;
@@ -660,12 +686,17 @@ async function defaultConstructProof(challenge) {
660
686
  if (!result || !result.txid) {
661
687
  throw new Error("Wallet declined payment or returned invalid result");
662
688
  }
663
- if (!result.rawTx || typeof result.rawTx !== "string" || result.rawTx.length === 0) {
664
- throw new Error("Wallet did not return raw transaction");
689
+ let beef;
690
+ if (result.tx && Array.isArray(result.tx) && result.tx.length > 0) {
691
+ beef = numberArrayToBase642(result.tx);
692
+ } else if (result.rawTx && typeof result.rawTx === "string" && result.rawTx.length > 0) {
693
+ beef = bytesToBase642(hexToBytes2(result.rawTx));
694
+ } else {
695
+ throw new Error("Wallet returned no transaction data (neither tx nor rawTx)");
665
696
  }
666
697
  return {
667
698
  txid: result.txid,
668
- rawTx: result.rawTx
699
+ beef
669
700
  };
670
701
  }
671
702
  function createX402Fetch(config = {}) {
@@ -706,11 +737,16 @@ function createX402Fetch(config = {}) {
706
737
  return response;
707
738
  }
708
739
  let proof;
740
+ let abort;
709
741
  try {
710
742
  if (brc105ProofConstructor) {
711
- proof = await brc105ProofConstructor(brc105Challenge);
743
+ const result = await brc105ProofConstructor(brc105Challenge);
744
+ proof = result.proof;
745
+ abort = result.abort;
712
746
  } else {
713
- proof = await constructBrc105Proof(brc105Challenge, brc105Wallet, origin);
747
+ const result = await constructBrc105Proof(brc105Challenge, brc105Wallet, origin);
748
+ proof = result.proof;
749
+ abort = result.abort;
714
750
  }
715
751
  } catch (err) {
716
752
  console.error("[x402] Proof construction failed (brc105):", err);
@@ -720,7 +756,21 @@ function createX402Fetch(config = {}) {
720
756
  const headers = new Headers(init?.headers);
721
757
  headers.set("x-bsv-payment", JSON.stringify(proof));
722
758
  headers.set("x-bsv-auth-identity-key", proof.clientIdentityKey);
723
- return fetch(input, { ...init, headers });
759
+ let retryResponse;
760
+ try {
761
+ retryResponse = await fetch(input, { ...init, headers });
762
+ } catch (err) {
763
+ if (abort) {
764
+ await abort();
765
+ console.warn("[x402] BRC-105 retry fetch failed, UTXOs released via abortAction");
766
+ }
767
+ throw err;
768
+ }
769
+ if (!retryResponse.ok && abort) {
770
+ await abort();
771
+ console.warn("[x402] Server rejected BRC-105 payment, UTXOs released via abortAction");
772
+ }
773
+ return retryResponse;
724
774
  }
725
775
  return response;
726
776
  };
package/dist/index.d.cts CHANGED
@@ -6,7 +6,7 @@ interface Challenge {
6
6
  }
7
7
  interface Proof {
8
8
  txid: string;
9
- rawTx: string;
9
+ beef: string;
10
10
  }
11
11
  interface Brc105Challenge {
12
12
  version: string;
@@ -37,6 +37,11 @@ interface Brc105Wallet {
37
37
  hmac: number[];
38
38
  }>;
39
39
  createAction(params: CWICreateActionParams): Promise<CWICreateActionResult>;
40
+ abortAction?: (args: {
41
+ reference: string;
42
+ }) => Promise<{
43
+ aborted: boolean;
44
+ }>;
40
45
  }
41
46
  interface Brc105Proof {
42
47
  derivationPrefix: string;
@@ -45,7 +50,11 @@ interface Brc105Proof {
45
50
  clientIdentityKey: string;
46
51
  txid: string;
47
52
  }
48
- type Brc105ProofConstructor = (challenge: Brc105Challenge) => Promise<Brc105Proof>;
53
+ interface Brc105ProofResult {
54
+ proof: Brc105Proof;
55
+ abort?: () => Promise<void>;
56
+ }
57
+ type Brc105ProofConstructor = (challenge: Brc105Challenge) => Promise<Brc105ProofResult>;
49
58
  type PaymentProtocol = 'x402' | 'brc105';
50
59
  interface PaymentRequest {
51
60
  amount: number;
@@ -118,7 +127,7 @@ declare function parseBrc105Challenge(response: Response): Brc105Challenge;
118
127
  * 4. Call wallet.createAction with the locking script and custom instructions
119
128
  * 5. Convert transaction to base64
120
129
  */
121
- declare function constructBrc105Proof(challenge: Brc105Challenge, wallet: Brc105Wallet, origin?: string): Promise<Brc105Proof>;
130
+ declare function constructBrc105Proof(challenge: Brc105Challenge, wallet: Brc105Wallet, origin?: string): Promise<Brc105ProofResult>;
122
131
 
123
132
  /**
124
133
  * Autospend balance cap per tier (max sats that can be auto-spent without confirmation).
package/dist/index.d.ts CHANGED
@@ -6,7 +6,7 @@ interface Challenge {
6
6
  }
7
7
  interface Proof {
8
8
  txid: string;
9
- rawTx: string;
9
+ beef: string;
10
10
  }
11
11
  interface Brc105Challenge {
12
12
  version: string;
@@ -37,6 +37,11 @@ interface Brc105Wallet {
37
37
  hmac: number[];
38
38
  }>;
39
39
  createAction(params: CWICreateActionParams): Promise<CWICreateActionResult>;
40
+ abortAction?: (args: {
41
+ reference: string;
42
+ }) => Promise<{
43
+ aborted: boolean;
44
+ }>;
40
45
  }
41
46
  interface Brc105Proof {
42
47
  derivationPrefix: string;
@@ -45,7 +50,11 @@ interface Brc105Proof {
45
50
  clientIdentityKey: string;
46
51
  txid: string;
47
52
  }
48
- type Brc105ProofConstructor = (challenge: Brc105Challenge) => Promise<Brc105Proof>;
53
+ interface Brc105ProofResult {
54
+ proof: Brc105Proof;
55
+ abort?: () => Promise<void>;
56
+ }
57
+ type Brc105ProofConstructor = (challenge: Brc105Challenge) => Promise<Brc105ProofResult>;
49
58
  type PaymentProtocol = 'x402' | 'brc105';
50
59
  interface PaymentRequest {
51
60
  amount: number;
@@ -118,7 +127,7 @@ declare function parseBrc105Challenge(response: Response): Brc105Challenge;
118
127
  * 4. Call wallet.createAction with the locking script and custom instructions
119
128
  * 5. Convert transaction to base64
120
129
  */
121
- declare function constructBrc105Proof(challenge: Brc105Challenge, wallet: Brc105Wallet, origin?: string): Promise<Brc105Proof>;
130
+ declare function constructBrc105Proof(challenge: Brc105Challenge, wallet: Brc105Wallet, origin?: string): Promise<Brc105ProofResult>;
122
131
 
123
132
  /**
124
133
  * Autospend balance cap per tier (max sats that can be auto-spent without confirmation).
package/dist/index.js CHANGED
@@ -506,6 +506,8 @@ async function constructBrc105Proof(challenge, wallet, origin) {
506
506
  })
507
507
  }],
508
508
  options: {
509
+ returnTXIDOnly: false,
510
+ noSend: true,
509
511
  randomizeOutputs: false
510
512
  }
511
513
  });
@@ -517,13 +519,21 @@ async function constructBrc105Proof(challenge, wallet, origin) {
517
519
  } else {
518
520
  throw new Error("Wallet returned no transaction data (neither tx nor rawTx)");
519
521
  }
520
- return {
522
+ const proof = {
521
523
  derivationPrefix: challenge.derivationPrefix,
522
524
  derivationSuffix,
523
525
  transaction: transactionBase64,
524
526
  clientIdentityKey,
525
527
  txid: result.txid
526
528
  };
529
+ const abort = wallet.abortAction ? async () => {
530
+ try {
531
+ await wallet.abortAction({ reference: result.txid });
532
+ } catch (err) {
533
+ console.warn("[x402] abortAction failed:", err);
534
+ }
535
+ } : void 0;
536
+ return { proof, abort };
527
537
  }
528
538
 
529
539
  // src/challenge.ts
@@ -559,6 +569,22 @@ function parseChallenge(header) {
559
569
  }
560
570
 
561
571
  // src/x402-fetch.ts
572
+ function bytesToBase642(bytes) {
573
+ let binary = "";
574
+ for (const b of bytes) binary += String.fromCharCode(b);
575
+ return btoa(binary);
576
+ }
577
+ function numberArrayToBase642(arr) {
578
+ return bytesToBase642(new Uint8Array(arr));
579
+ }
580
+ function hexToBytes2(hex) {
581
+ if (hex.length % 2 !== 0) throw new Error("Hex string must have even length");
582
+ const bytes = new Uint8Array(hex.length / 2);
583
+ for (let i = 0; i < hex.length; i += 2) {
584
+ bytes[i / 2] = parseInt(hex.slice(i, i + 2), 16);
585
+ }
586
+ return bytes;
587
+ }
562
588
  var BASE58_ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
563
589
  function base58DecodeCheck(address) {
564
590
  let leadingZeros = 0;
@@ -622,12 +648,17 @@ async function defaultConstructProof(challenge) {
622
648
  if (!result || !result.txid) {
623
649
  throw new Error("Wallet declined payment or returned invalid result");
624
650
  }
625
- if (!result.rawTx || typeof result.rawTx !== "string" || result.rawTx.length === 0) {
626
- throw new Error("Wallet did not return raw transaction");
651
+ let beef;
652
+ if (result.tx && Array.isArray(result.tx) && result.tx.length > 0) {
653
+ beef = numberArrayToBase642(result.tx);
654
+ } else if (result.rawTx && typeof result.rawTx === "string" && result.rawTx.length > 0) {
655
+ beef = bytesToBase642(hexToBytes2(result.rawTx));
656
+ } else {
657
+ throw new Error("Wallet returned no transaction data (neither tx nor rawTx)");
627
658
  }
628
659
  return {
629
660
  txid: result.txid,
630
- rawTx: result.rawTx
661
+ beef
631
662
  };
632
663
  }
633
664
  function createX402Fetch(config = {}) {
@@ -668,11 +699,16 @@ function createX402Fetch(config = {}) {
668
699
  return response;
669
700
  }
670
701
  let proof;
702
+ let abort;
671
703
  try {
672
704
  if (brc105ProofConstructor) {
673
- proof = await brc105ProofConstructor(brc105Challenge);
705
+ const result = await brc105ProofConstructor(brc105Challenge);
706
+ proof = result.proof;
707
+ abort = result.abort;
674
708
  } else {
675
- proof = await constructBrc105Proof(brc105Challenge, brc105Wallet, origin);
709
+ const result = await constructBrc105Proof(brc105Challenge, brc105Wallet, origin);
710
+ proof = result.proof;
711
+ abort = result.abort;
676
712
  }
677
713
  } catch (err) {
678
714
  console.error("[x402] Proof construction failed (brc105):", err);
@@ -682,7 +718,21 @@ function createX402Fetch(config = {}) {
682
718
  const headers = new Headers(init?.headers);
683
719
  headers.set("x-bsv-payment", JSON.stringify(proof));
684
720
  headers.set("x-bsv-auth-identity-key", proof.clientIdentityKey);
685
- return fetch(input, { ...init, headers });
721
+ let retryResponse;
722
+ try {
723
+ retryResponse = await fetch(input, { ...init, headers });
724
+ } catch (err) {
725
+ if (abort) {
726
+ await abort();
727
+ console.warn("[x402] BRC-105 retry fetch failed, UTXOs released via abortAction");
728
+ }
729
+ throw err;
730
+ }
731
+ if (!retryResponse.ok && abort) {
732
+ await abort();
733
+ console.warn("[x402] Server rejected BRC-105 payment, UTXOs released via abortAction");
734
+ }
735
+ return retryResponse;
686
736
  }
687
737
  return response;
688
738
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bsv-x402",
3
- "version": "0.6.0",
3
+ "version": "0.7.0",
4
4
  "description": "x402 payment protocol client — a fetch() wrapper that handles 402 payment flows transparently",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",
@@ -34,7 +34,7 @@
34
34
  "url": "git+https://github.com/sgbett/bsv-x402.git"
35
35
  },
36
36
  "devDependencies": {
37
- "@bsv/wallet-toolbox-client": "^2.1.17",
37
+ "@bsv/wallet-toolbox-client": "npm:@sgbett/wallet-toolbox-client@2.1.19-fix.1",
38
38
  "@types/chrome": "^0.1.38",
39
39
  "@types/express": "^5.0.6",
40
40
  "express": "^5.2.1",