@t402/react 2.3.1 → 2.4.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/README.md +27 -36
- package/dist/cjs/index.cjs +259 -0
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/index.d.cts +305 -1
- package/dist/esm/index.d.ts +305 -1
- package/dist/esm/index.js +257 -1
- package/dist/esm/index.js.map +1 -1
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -11,24 +11,24 @@ npm install @t402/react
|
|
|
11
11
|
## Quick Start
|
|
12
12
|
|
|
13
13
|
```tsx
|
|
14
|
-
import { PaymentProvider, PaymentButton, usePaymentRequired } from
|
|
14
|
+
import { PaymentProvider, PaymentButton, usePaymentRequired } from '@t402/react'
|
|
15
15
|
|
|
16
16
|
function App() {
|
|
17
17
|
return (
|
|
18
18
|
<PaymentProvider>
|
|
19
19
|
<ProtectedContent />
|
|
20
20
|
</PaymentProvider>
|
|
21
|
-
)
|
|
21
|
+
)
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
function ProtectedContent() {
|
|
25
|
-
const { paymentRequired, requirements, pay, status } = usePaymentRequired(
|
|
25
|
+
const { paymentRequired, requirements, pay, status } = usePaymentRequired('/api/data')
|
|
26
26
|
|
|
27
27
|
if (paymentRequired) {
|
|
28
|
-
return <PaymentButton requirements={requirements} onPay={pay} status={status}
|
|
28
|
+
return <PaymentButton requirements={requirements} onPay={pay} status={status} />
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
-
return <div>Premium content loaded!</div
|
|
31
|
+
return <div>Premium content loaded!</div>
|
|
32
32
|
}
|
|
33
33
|
```
|
|
34
34
|
|
|
@@ -39,13 +39,8 @@ function ProtectedContent() {
|
|
|
39
39
|
Renders a payment action button with loading and status states.
|
|
40
40
|
|
|
41
41
|
```tsx
|
|
42
|
-
import { PaymentButton } from
|
|
43
|
-
|
|
44
|
-
<PaymentButton
|
|
45
|
-
requirements={requirements}
|
|
46
|
-
onPay={handlePay}
|
|
47
|
-
status={status}
|
|
48
|
-
/>
|
|
42
|
+
import { PaymentButton } from '@t402/react'
|
|
43
|
+
;<PaymentButton requirements={requirements} onPay={handlePay} status={status} />
|
|
49
44
|
```
|
|
50
45
|
|
|
51
46
|
### PaymentDetails
|
|
@@ -53,9 +48,8 @@ import { PaymentButton } from "@t402/react";
|
|
|
53
48
|
Displays payment requirements (amount, network, recipient).
|
|
54
49
|
|
|
55
50
|
```tsx
|
|
56
|
-
import { PaymentDetails } from
|
|
57
|
-
|
|
58
|
-
<PaymentDetails requirements={requirements} />
|
|
51
|
+
import { PaymentDetails } from '@t402/react'
|
|
52
|
+
;<PaymentDetails requirements={requirements} />
|
|
59
53
|
```
|
|
60
54
|
|
|
61
55
|
### PaymentStatusDisplay
|
|
@@ -63,9 +57,8 @@ import { PaymentDetails } from "@t402/react";
|
|
|
63
57
|
Shows the current payment status with appropriate UI feedback.
|
|
64
58
|
|
|
65
59
|
```tsx
|
|
66
|
-
import { PaymentStatusDisplay } from
|
|
67
|
-
|
|
68
|
-
<PaymentStatusDisplay status={status} />
|
|
60
|
+
import { PaymentStatusDisplay } from '@t402/react'
|
|
61
|
+
;<PaymentStatusDisplay status={status} />
|
|
69
62
|
```
|
|
70
63
|
|
|
71
64
|
### AddressDisplay
|
|
@@ -73,9 +66,8 @@ import { PaymentStatusDisplay } from "@t402/react";
|
|
|
73
66
|
Renders a blockchain address with truncation and copy functionality.
|
|
74
67
|
|
|
75
68
|
```tsx
|
|
76
|
-
import { AddressDisplay } from
|
|
77
|
-
|
|
78
|
-
<AddressDisplay address="0x1234...5678" />
|
|
69
|
+
import { AddressDisplay } from '@t402/react'
|
|
70
|
+
;<AddressDisplay address="0x1234...5678" />
|
|
79
71
|
```
|
|
80
72
|
|
|
81
73
|
## Hooks
|
|
@@ -86,11 +78,11 @@ Detects 402 responses and extracts payment requirements.
|
|
|
86
78
|
|
|
87
79
|
```tsx
|
|
88
80
|
const {
|
|
89
|
-
paymentRequired,
|
|
90
|
-
requirements,
|
|
91
|
-
pay,
|
|
92
|
-
status,
|
|
93
|
-
} = usePaymentRequired(url, options)
|
|
81
|
+
paymentRequired, // boolean - whether payment is needed
|
|
82
|
+
requirements, // PaymentRequirements[] from 402 response
|
|
83
|
+
pay, // () => Promise<void> - trigger payment
|
|
84
|
+
status, // PaymentStatus - current state
|
|
85
|
+
} = usePaymentRequired(url, options)
|
|
94
86
|
```
|
|
95
87
|
|
|
96
88
|
### usePaymentStatus
|
|
@@ -98,7 +90,7 @@ const {
|
|
|
98
90
|
Tracks the lifecycle of a payment (idle, pending, confirming, complete, error).
|
|
99
91
|
|
|
100
92
|
```tsx
|
|
101
|
-
const { status, error, reset } = usePaymentStatus()
|
|
93
|
+
const { status, error, reset } = usePaymentStatus()
|
|
102
94
|
```
|
|
103
95
|
|
|
104
96
|
### useAsyncPayment
|
|
@@ -106,7 +98,7 @@ const { status, error, reset } = usePaymentStatus();
|
|
|
106
98
|
Manages async payment flows with automatic retry and status tracking.
|
|
107
99
|
|
|
108
100
|
```tsx
|
|
109
|
-
const { execute, status, error } = useAsyncPayment(paymentFn)
|
|
101
|
+
const { execute, status, error } = useAsyncPayment(paymentFn)
|
|
110
102
|
```
|
|
111
103
|
|
|
112
104
|
## Provider
|
|
@@ -116,9 +108,8 @@ const { execute, status, error } = useAsyncPayment(paymentFn);
|
|
|
116
108
|
Wraps your app to provide payment context to all child components.
|
|
117
109
|
|
|
118
110
|
```tsx
|
|
119
|
-
import { PaymentProvider } from
|
|
120
|
-
|
|
121
|
-
<PaymentProvider>
|
|
111
|
+
import { PaymentProvider } from '@t402/react'
|
|
112
|
+
;<PaymentProvider>
|
|
122
113
|
<App />
|
|
123
114
|
</PaymentProvider>
|
|
124
115
|
```
|
|
@@ -136,15 +127,15 @@ import {
|
|
|
136
127
|
truncateAddress,
|
|
137
128
|
formatTokenAmount,
|
|
138
129
|
choosePaymentRequirement,
|
|
139
|
-
} from
|
|
130
|
+
} from '@t402/react'
|
|
140
131
|
|
|
141
132
|
// Network detection
|
|
142
|
-
isEvmNetwork(
|
|
133
|
+
isEvmNetwork('eip155:8453') // true
|
|
143
134
|
|
|
144
135
|
// Display helpers
|
|
145
|
-
getNetworkDisplayName(
|
|
146
|
-
truncateAddress(
|
|
147
|
-
formatTokenAmount(1500000n, 6)
|
|
136
|
+
getNetworkDisplayName('eip155:8453') // "Base"
|
|
137
|
+
truncateAddress('0x1234567890abcdef') // "0x1234...cdef"
|
|
138
|
+
formatTokenAmount(1500000n, 6) // "1.50"
|
|
148
139
|
```
|
|
149
140
|
|
|
150
141
|
## Peer Dependencies
|
package/dist/cjs/index.cjs
CHANGED
|
@@ -628,6 +628,262 @@ function useAsyncPayment(options) {
|
|
|
628
628
|
reset
|
|
629
629
|
};
|
|
630
630
|
}
|
|
631
|
+
function useGaslessPayment(options) {
|
|
632
|
+
const { payFn, onSuccess, onError, autoWait = true } = options;
|
|
633
|
+
const [status, setStatus] = react.useState("idle");
|
|
634
|
+
const [userOpHash, setUserOpHash] = react.useState(null);
|
|
635
|
+
const [txHash, setTxHash] = react.useState(null);
|
|
636
|
+
const [sponsored, setSponsored] = react.useState(null);
|
|
637
|
+
const [error, setError] = react.useState(null);
|
|
638
|
+
const isMountedRef = react.useRef(true);
|
|
639
|
+
const pay = react.useCallback(
|
|
640
|
+
async (params) => {
|
|
641
|
+
setStatus("loading");
|
|
642
|
+
setError(null);
|
|
643
|
+
setUserOpHash(null);
|
|
644
|
+
setTxHash(null);
|
|
645
|
+
setSponsored(null);
|
|
646
|
+
try {
|
|
647
|
+
const result = await payFn(params);
|
|
648
|
+
if (isMountedRef.current) {
|
|
649
|
+
setUserOpHash(result.userOpHash);
|
|
650
|
+
setSponsored(result.sponsored);
|
|
651
|
+
}
|
|
652
|
+
if (autoWait) {
|
|
653
|
+
const receipt = await result.wait();
|
|
654
|
+
if (isMountedRef.current) {
|
|
655
|
+
setTxHash(receipt.txHash);
|
|
656
|
+
setStatus("success");
|
|
657
|
+
onSuccess?.(receipt);
|
|
658
|
+
}
|
|
659
|
+
} else {
|
|
660
|
+
if (isMountedRef.current) {
|
|
661
|
+
setStatus("success");
|
|
662
|
+
onSuccess?.({ txHash: result.userOpHash, success: true });
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
} catch (err) {
|
|
666
|
+
const errorMessage = err instanceof Error ? err.message : "Gasless payment failed";
|
|
667
|
+
if (isMountedRef.current) {
|
|
668
|
+
setError(errorMessage);
|
|
669
|
+
setStatus("error");
|
|
670
|
+
}
|
|
671
|
+
onError?.(err instanceof Error ? err : new Error(errorMessage));
|
|
672
|
+
}
|
|
673
|
+
},
|
|
674
|
+
[payFn, onSuccess, onError, autoWait]
|
|
675
|
+
);
|
|
676
|
+
const reset = react.useCallback(() => {
|
|
677
|
+
setStatus("idle");
|
|
678
|
+
setUserOpHash(null);
|
|
679
|
+
setTxHash(null);
|
|
680
|
+
setSponsored(null);
|
|
681
|
+
setError(null);
|
|
682
|
+
}, []);
|
|
683
|
+
return {
|
|
684
|
+
pay,
|
|
685
|
+
status,
|
|
686
|
+
userOpHash,
|
|
687
|
+
txHash,
|
|
688
|
+
sponsored,
|
|
689
|
+
error,
|
|
690
|
+
isLoading: status === "loading",
|
|
691
|
+
isSuccess: status === "success",
|
|
692
|
+
isError: status === "error",
|
|
693
|
+
reset
|
|
694
|
+
};
|
|
695
|
+
}
|
|
696
|
+
function useBridgePayment(options) {
|
|
697
|
+
const { bridgeFn, autoBridgeFn, onSuccess, onError, autoWaitForDelivery = false } = options;
|
|
698
|
+
const [status, setStatus] = react.useState("idle");
|
|
699
|
+
const [txHash, setTxHash] = react.useState(null);
|
|
700
|
+
const [messageGuid, setMessageGuid] = react.useState(null);
|
|
701
|
+
const [dstTxHash, setDstTxHash] = react.useState(null);
|
|
702
|
+
const [error, setError] = react.useState(null);
|
|
703
|
+
const isMountedRef = react.useRef(true);
|
|
704
|
+
const executeBridge = react.useCallback(
|
|
705
|
+
async (bridgeCall) => {
|
|
706
|
+
setStatus("bridging");
|
|
707
|
+
setError(null);
|
|
708
|
+
setTxHash(null);
|
|
709
|
+
setMessageGuid(null);
|
|
710
|
+
setDstTxHash(null);
|
|
711
|
+
try {
|
|
712
|
+
const result = await bridgeCall();
|
|
713
|
+
if (isMountedRef.current) {
|
|
714
|
+
setTxHash(result.txHash);
|
|
715
|
+
setMessageGuid(result.messageGuid);
|
|
716
|
+
}
|
|
717
|
+
if (autoWaitForDelivery) {
|
|
718
|
+
if (isMountedRef.current) setStatus("waiting");
|
|
719
|
+
const delivery = await result.waitForDelivery();
|
|
720
|
+
if (isMountedRef.current) {
|
|
721
|
+
if (delivery.dstTxHash) setDstTxHash(delivery.dstTxHash);
|
|
722
|
+
setStatus("success");
|
|
723
|
+
onSuccess?.({
|
|
724
|
+
txHash: result.txHash,
|
|
725
|
+
dstTxHash: delivery.dstTxHash,
|
|
726
|
+
fromChain: result.fromChain,
|
|
727
|
+
toChain: result.toChain
|
|
728
|
+
});
|
|
729
|
+
}
|
|
730
|
+
} else {
|
|
731
|
+
if (isMountedRef.current) {
|
|
732
|
+
setStatus("success");
|
|
733
|
+
onSuccess?.({
|
|
734
|
+
txHash: result.txHash,
|
|
735
|
+
fromChain: result.fromChain,
|
|
736
|
+
toChain: result.toChain
|
|
737
|
+
});
|
|
738
|
+
}
|
|
739
|
+
}
|
|
740
|
+
} catch (err) {
|
|
741
|
+
const errorMessage = err instanceof Error ? err.message : "Bridge operation failed";
|
|
742
|
+
if (isMountedRef.current) {
|
|
743
|
+
setError(errorMessage);
|
|
744
|
+
setStatus("error");
|
|
745
|
+
}
|
|
746
|
+
onError?.(err instanceof Error ? err : new Error(errorMessage));
|
|
747
|
+
}
|
|
748
|
+
},
|
|
749
|
+
[onSuccess, onError, autoWaitForDelivery]
|
|
750
|
+
);
|
|
751
|
+
const bridge = react.useCallback(
|
|
752
|
+
async (params) => {
|
|
753
|
+
await executeBridge(() => bridgeFn(params));
|
|
754
|
+
},
|
|
755
|
+
[bridgeFn, executeBridge]
|
|
756
|
+
);
|
|
757
|
+
const autoBridge = react.useCallback(
|
|
758
|
+
async (params) => {
|
|
759
|
+
const fn = autoBridgeFn ?? (() => {
|
|
760
|
+
throw new Error("autoBridgeFn not provided");
|
|
761
|
+
});
|
|
762
|
+
await executeBridge(() => fn(params));
|
|
763
|
+
},
|
|
764
|
+
[autoBridgeFn, executeBridge]
|
|
765
|
+
);
|
|
766
|
+
const reset = react.useCallback(() => {
|
|
767
|
+
setStatus("idle");
|
|
768
|
+
setTxHash(null);
|
|
769
|
+
setMessageGuid(null);
|
|
770
|
+
setDstTxHash(null);
|
|
771
|
+
setError(null);
|
|
772
|
+
}, []);
|
|
773
|
+
return {
|
|
774
|
+
bridge,
|
|
775
|
+
autoBridge,
|
|
776
|
+
status,
|
|
777
|
+
txHash,
|
|
778
|
+
messageGuid,
|
|
779
|
+
dstTxHash,
|
|
780
|
+
error,
|
|
781
|
+
isLoading: status === "bridging" || status === "quoting" || status === "waiting",
|
|
782
|
+
isSuccess: status === "success",
|
|
783
|
+
isError: status === "error",
|
|
784
|
+
reset
|
|
785
|
+
};
|
|
786
|
+
}
|
|
787
|
+
function useMultiSigPayment(options) {
|
|
788
|
+
const { initiateFn, submitFn, onSuccess, onError, autoWait = true } = options;
|
|
789
|
+
const [status, setStatus] = react.useState("idle");
|
|
790
|
+
const [requestId, setRequestId] = react.useState(null);
|
|
791
|
+
const [userOpHash, setUserOpHash] = react.useState(null);
|
|
792
|
+
const [txHash, setTxHash] = react.useState(null);
|
|
793
|
+
const [threshold, setThreshold] = react.useState(0);
|
|
794
|
+
const [collectedCount, setCollectedCount] = react.useState(0);
|
|
795
|
+
const [isReady, setIsReady] = react.useState(false);
|
|
796
|
+
const [error, setError] = react.useState(null);
|
|
797
|
+
const isMountedRef = react.useRef(true);
|
|
798
|
+
const initiate = react.useCallback(
|
|
799
|
+
async (params) => {
|
|
800
|
+
setStatus("initiating");
|
|
801
|
+
setError(null);
|
|
802
|
+
setRequestId(null);
|
|
803
|
+
setUserOpHash(null);
|
|
804
|
+
setTxHash(null);
|
|
805
|
+
try {
|
|
806
|
+
const result = await initiateFn(params);
|
|
807
|
+
if (isMountedRef.current) {
|
|
808
|
+
setRequestId(result.requestId);
|
|
809
|
+
setUserOpHash(result.userOpHash);
|
|
810
|
+
setThreshold(result.threshold);
|
|
811
|
+
setCollectedCount(result.collectedCount);
|
|
812
|
+
setIsReady(result.isReady);
|
|
813
|
+
setStatus("collecting");
|
|
814
|
+
}
|
|
815
|
+
} catch (err) {
|
|
816
|
+
const errorMessage = err instanceof Error ? err.message : "Failed to initiate multi-sig payment";
|
|
817
|
+
if (isMountedRef.current) {
|
|
818
|
+
setError(errorMessage);
|
|
819
|
+
setStatus("error");
|
|
820
|
+
}
|
|
821
|
+
onError?.(err instanceof Error ? err : new Error(errorMessage));
|
|
822
|
+
}
|
|
823
|
+
},
|
|
824
|
+
[initiateFn, onError]
|
|
825
|
+
);
|
|
826
|
+
const submit = react.useCallback(async () => {
|
|
827
|
+
if (!requestId) {
|
|
828
|
+
const err = new Error("No active request to submit");
|
|
829
|
+
setError(err.message);
|
|
830
|
+
setStatus("error");
|
|
831
|
+
onError?.(err);
|
|
832
|
+
return;
|
|
833
|
+
}
|
|
834
|
+
setStatus("submitting");
|
|
835
|
+
setError(null);
|
|
836
|
+
try {
|
|
837
|
+
const result = await submitFn(requestId);
|
|
838
|
+
if (autoWait) {
|
|
839
|
+
const receipt = await result.wait();
|
|
840
|
+
if (isMountedRef.current) {
|
|
841
|
+
setTxHash(receipt.txHash);
|
|
842
|
+
setStatus("success");
|
|
843
|
+
onSuccess?.(receipt);
|
|
844
|
+
}
|
|
845
|
+
} else {
|
|
846
|
+
if (isMountedRef.current) {
|
|
847
|
+
setStatus("success");
|
|
848
|
+
onSuccess?.({ txHash: result.userOpHash, success: true });
|
|
849
|
+
}
|
|
850
|
+
}
|
|
851
|
+
} catch (err) {
|
|
852
|
+
const errorMessage = err instanceof Error ? err.message : "Failed to submit multi-sig transaction";
|
|
853
|
+
if (isMountedRef.current) {
|
|
854
|
+
setError(errorMessage);
|
|
855
|
+
setStatus("error");
|
|
856
|
+
}
|
|
857
|
+
onError?.(err instanceof Error ? err : new Error(errorMessage));
|
|
858
|
+
}
|
|
859
|
+
}, [requestId, submitFn, onSuccess, onError, autoWait]);
|
|
860
|
+
const reset = react.useCallback(() => {
|
|
861
|
+
setStatus("idle");
|
|
862
|
+
setRequestId(null);
|
|
863
|
+
setUserOpHash(null);
|
|
864
|
+
setTxHash(null);
|
|
865
|
+
setThreshold(0);
|
|
866
|
+
setCollectedCount(0);
|
|
867
|
+
setIsReady(false);
|
|
868
|
+
setError(null);
|
|
869
|
+
}, []);
|
|
870
|
+
return {
|
|
871
|
+
initiate,
|
|
872
|
+
submit,
|
|
873
|
+
status,
|
|
874
|
+
requestId,
|
|
875
|
+
userOpHash,
|
|
876
|
+
txHash,
|
|
877
|
+
threshold,
|
|
878
|
+
collectedCount,
|
|
879
|
+
isReady,
|
|
880
|
+
error,
|
|
881
|
+
isLoading: status === "initiating" || status === "submitting",
|
|
882
|
+
isSuccess: status === "success",
|
|
883
|
+
isError: status === "error",
|
|
884
|
+
reset
|
|
885
|
+
};
|
|
886
|
+
}
|
|
631
887
|
var initialState = {
|
|
632
888
|
status: "idle",
|
|
633
889
|
error: null,
|
|
@@ -738,6 +994,9 @@ exports.isTronNetwork = isTronNetwork;
|
|
|
738
994
|
exports.normalizePaymentRequirements = normalizePaymentRequirements;
|
|
739
995
|
exports.truncateAddress = truncateAddress;
|
|
740
996
|
exports.useAsyncPayment = useAsyncPayment;
|
|
997
|
+
exports.useBridgePayment = useBridgePayment;
|
|
998
|
+
exports.useGaslessPayment = useGaslessPayment;
|
|
999
|
+
exports.useMultiSigPayment = useMultiSigPayment;
|
|
741
1000
|
exports.usePaymentContext = usePaymentContext;
|
|
742
1001
|
exports.usePaymentRequired = usePaymentRequired;
|
|
743
1002
|
exports.usePaymentStatus = usePaymentStatus;
|