@doujins/payments-ui 0.0.6 → 0.0.8
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 +169 -64
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +169 -64
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -35,12 +35,18 @@ var loadCollectJs = (tokenizationKey) => {
|
|
|
35
35
|
if (existing) return;
|
|
36
36
|
const script = document.createElement("script");
|
|
37
37
|
script.src = SCRIPT_SRC;
|
|
38
|
-
script.setAttribute("data-tokenization-key",
|
|
38
|
+
script.setAttribute("data-tokenization-key", trimmed);
|
|
39
39
|
script.setAttribute("data-field-ccnumber-placeholder", "0000 0000 0000 0000");
|
|
40
40
|
script.setAttribute("data-field-ccexp-placeholder", "10 / 25");
|
|
41
41
|
script.setAttribute("data-field-cvv-placeholder", "123");
|
|
42
42
|
script.setAttribute("data-variant", "inline");
|
|
43
43
|
script.async = true;
|
|
44
|
+
script.addEventListener("load", () => {
|
|
45
|
+
console.log("payments-ui: Collect.js loaded");
|
|
46
|
+
});
|
|
47
|
+
script.addEventListener("error", (event) => {
|
|
48
|
+
console.error("payments-ui: failed to load Collect.js", event);
|
|
49
|
+
});
|
|
44
50
|
document.head.appendChild(script);
|
|
45
51
|
};
|
|
46
52
|
|
|
@@ -76,20 +82,31 @@ var createApiClient = (paymentConfig, baseUrl, fetcher, resolveAuthToken) => {
|
|
|
76
82
|
if (token) {
|
|
77
83
|
headers.Authorization = `Bearer ${token}`;
|
|
78
84
|
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
85
|
+
try {
|
|
86
|
+
const response = await fetcher(url, {
|
|
87
|
+
method,
|
|
88
|
+
headers,
|
|
89
|
+
body: options?.body ? JSON.stringify(options.body) : void 0
|
|
90
|
+
});
|
|
91
|
+
if (!response.ok) {
|
|
92
|
+
const message = await response.text();
|
|
93
|
+
console.error("payments-ui: API request failed", {
|
|
94
|
+
url,
|
|
95
|
+
method,
|
|
96
|
+
status: response.status,
|
|
97
|
+
message
|
|
98
|
+
});
|
|
99
|
+
throw new Error(message || `Request failed with status ${response.status}`);
|
|
100
|
+
}
|
|
101
|
+
if (response.status === 204) {
|
|
102
|
+
return void 0;
|
|
103
|
+
}
|
|
104
|
+
const data = await response.json();
|
|
105
|
+
return data;
|
|
106
|
+
} catch (error) {
|
|
107
|
+
console.error("payments-ui: API request error", { url, method, error });
|
|
108
|
+
throw error;
|
|
90
109
|
}
|
|
91
|
-
const data = await response.json();
|
|
92
|
-
return data;
|
|
93
110
|
};
|
|
94
111
|
return {
|
|
95
112
|
request,
|
|
@@ -1565,8 +1582,16 @@ var useSolanaDirectPayment = (options) => {
|
|
|
1565
1582
|
const balance = balanceInfo?.balance || 0;
|
|
1566
1583
|
const hasBalanceFlag = hasSufficientBalance(balance, tokenAmount);
|
|
1567
1584
|
setTokenBalance({ balance, hasBalance: hasBalanceFlag });
|
|
1585
|
+
console.log("payments-ui: Solana wallet balance", {
|
|
1586
|
+
token: selectedToken.symbol,
|
|
1587
|
+
balance,
|
|
1588
|
+
required: tokenAmount
|
|
1589
|
+
});
|
|
1568
1590
|
} catch (error) {
|
|
1569
|
-
console.error("Failed to fetch token balance:",
|
|
1591
|
+
console.error("Failed to fetch token balance:", {
|
|
1592
|
+
token: selectedToken?.symbol,
|
|
1593
|
+
error
|
|
1594
|
+
});
|
|
1570
1595
|
setTokenBalance({ balance: 0, hasBalance: false });
|
|
1571
1596
|
} finally {
|
|
1572
1597
|
setIsBalanceLoading(false);
|
|
@@ -1630,30 +1655,49 @@ var useSolanaDirectPayment = (options) => {
|
|
|
1630
1655
|
return;
|
|
1631
1656
|
}
|
|
1632
1657
|
if (!tokenBalance?.hasBalance) {
|
|
1658
|
+
console.warn("payments-ui: insufficient balance for Solana direct payment", {
|
|
1659
|
+
token: selectedToken.symbol
|
|
1660
|
+
});
|
|
1633
1661
|
onError("Insufficient balance for this token");
|
|
1634
1662
|
return;
|
|
1635
1663
|
}
|
|
1636
1664
|
try {
|
|
1637
1665
|
setIsProcessing(true);
|
|
1638
1666
|
onStart();
|
|
1667
|
+
console.log("payments-ui: initiating Solana direct payment", {
|
|
1668
|
+
priceId,
|
|
1669
|
+
token: selectedToken.symbol
|
|
1670
|
+
});
|
|
1639
1671
|
const paymentData = await solanaService.generatePayment(
|
|
1640
1672
|
priceId,
|
|
1641
1673
|
selectedToken.symbol,
|
|
1642
1674
|
publicKey.toBase58()
|
|
1643
1675
|
);
|
|
1676
|
+
console.log("payments-ui: Solana payment intent created", {
|
|
1677
|
+
intentId: paymentData.intent_id
|
|
1678
|
+
});
|
|
1644
1679
|
const transactionToSign = decodeTransaction(paymentData.transaction);
|
|
1680
|
+
console.log("payments-ui: requesting Solana wallet signature");
|
|
1645
1681
|
const signedTx = await signWithWallet(transactionToSign);
|
|
1646
1682
|
const signedSerialized = Buffer.from(signedTx.serialize()).toString("base64");
|
|
1647
1683
|
onConfirming();
|
|
1684
|
+
console.log("payments-ui: submitting signed Solana transaction");
|
|
1648
1685
|
const result = await solanaService.submitPayment(
|
|
1649
1686
|
signedSerialized,
|
|
1650
1687
|
priceId,
|
|
1651
1688
|
paymentData.intent_id,
|
|
1652
1689
|
`Payment for subscription - ${selectedToken.symbol}`
|
|
1653
1690
|
);
|
|
1691
|
+
console.log("payments-ui: Solana direct payment confirmed", {
|
|
1692
|
+
transactionId: result.transaction_id
|
|
1693
|
+
});
|
|
1654
1694
|
onSuccess(result, result.transaction_id);
|
|
1655
1695
|
} catch (err) {
|
|
1656
|
-
console.error("
|
|
1696
|
+
console.error("Solana direct payment failed:", {
|
|
1697
|
+
priceId,
|
|
1698
|
+
token: selectedToken.symbol,
|
|
1699
|
+
error: err
|
|
1700
|
+
});
|
|
1657
1701
|
let errorMessage = "Payment failed. Please try again.";
|
|
1658
1702
|
const message = err instanceof Error ? err.message : typeof err === "string" ? err : "";
|
|
1659
1703
|
if (message.includes("User rejected")) {
|
|
@@ -1745,11 +1789,15 @@ var DirectPayment = ({
|
|
|
1745
1789
|
var useSolanaQrPayment = (options) => {
|
|
1746
1790
|
const { priceId, selectedToken, onSuccess, onError } = options;
|
|
1747
1791
|
const solanaService = useSolanaService();
|
|
1792
|
+
const tokenSymbol = selectedToken?.symbol ?? null;
|
|
1793
|
+
const onSuccessRef = useRef(onSuccess);
|
|
1794
|
+
const onErrorRef = useRef(onError);
|
|
1748
1795
|
const [intent, setIntent] = useState(null);
|
|
1749
1796
|
const [qrDataUri, setQrDataUri] = useState(null);
|
|
1750
1797
|
const [isLoading, setIsLoading] = useState(false);
|
|
1751
1798
|
const [error, setError] = useState(null);
|
|
1752
1799
|
const [timeRemaining, setTimeRemaining] = useState(0);
|
|
1800
|
+
const [refreshNonce, setRefreshNonce] = useState(0);
|
|
1753
1801
|
const pollRef = useRef(null);
|
|
1754
1802
|
const countdownRef = useRef(null);
|
|
1755
1803
|
const clearTimers = useCallback(() => {
|
|
@@ -1767,27 +1815,47 @@ var useSolanaQrPayment = (options) => {
|
|
|
1767
1815
|
clearTimers();
|
|
1768
1816
|
};
|
|
1769
1817
|
}, [clearTimers]);
|
|
1818
|
+
const resetState = useCallback(
|
|
1819
|
+
(message) => {
|
|
1820
|
+
clearTimers();
|
|
1821
|
+
setIntent((prev) => prev ? null : prev);
|
|
1822
|
+
setQrDataUri((prev) => prev ? null : prev);
|
|
1823
|
+
setTimeRemaining((prev) => prev !== 0 ? 0 : prev);
|
|
1824
|
+
setError((prev) => {
|
|
1825
|
+
const next = message === void 0 ? null : message;
|
|
1826
|
+
return prev === next ? prev : next;
|
|
1827
|
+
});
|
|
1828
|
+
},
|
|
1829
|
+
[clearTimers]
|
|
1830
|
+
);
|
|
1831
|
+
useEffect(() => {
|
|
1832
|
+
onSuccessRef.current = onSuccess;
|
|
1833
|
+
}, [onSuccess]);
|
|
1834
|
+
useEffect(() => {
|
|
1835
|
+
onErrorRef.current = onError;
|
|
1836
|
+
}, [onError]);
|
|
1770
1837
|
const handleError = useCallback(
|
|
1771
1838
|
(message, notifyParent = false) => {
|
|
1839
|
+
console.error("[payments-ui] Solana Pay QR error:", message);
|
|
1772
1840
|
clearTimers();
|
|
1773
|
-
|
|
1774
|
-
setIntent(null);
|
|
1775
|
-
setQrDataUri(null);
|
|
1776
|
-
setTimeRemaining(0);
|
|
1841
|
+
resetState(message);
|
|
1777
1842
|
if (notifyParent) {
|
|
1778
|
-
|
|
1843
|
+
onErrorRef.current?.(message);
|
|
1779
1844
|
}
|
|
1780
1845
|
},
|
|
1781
|
-
[clearTimers,
|
|
1846
|
+
[clearTimers, resetState]
|
|
1782
1847
|
);
|
|
1783
1848
|
const handleSuccess = useCallback(
|
|
1784
1849
|
(status) => {
|
|
1785
1850
|
clearTimers();
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1851
|
+
resetState(null);
|
|
1852
|
+
console.log("[payments-ui] Solana Pay QR confirmed", {
|
|
1853
|
+
paymentId: status.payment_id,
|
|
1854
|
+
intentId: status.intent_id
|
|
1855
|
+
});
|
|
1856
|
+
onSuccessRef.current?.(status.payment_id, status.transaction || "");
|
|
1789
1857
|
},
|
|
1790
|
-
[clearTimers,
|
|
1858
|
+
[clearTimers, resetState]
|
|
1791
1859
|
);
|
|
1792
1860
|
const pollStatus = useCallback(
|
|
1793
1861
|
async (reference) => {
|
|
@@ -1839,57 +1907,75 @@ var useSolanaQrPayment = (options) => {
|
|
|
1839
1907
|
handleError("Unable to render QR code");
|
|
1840
1908
|
}
|
|
1841
1909
|
}, [handleError]);
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
setQrDataUri(null);
|
|
1846
|
-
setError(null);
|
|
1910
|
+
useEffect(() => {
|
|
1911
|
+
let cancelled = false;
|
|
1912
|
+
const generateIntent = async () => {
|
|
1847
1913
|
clearTimers();
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1914
|
+
if (!tokenSymbol || !priceId) {
|
|
1915
|
+
resetState(null);
|
|
1916
|
+
setIsLoading((prev) => prev ? false : prev);
|
|
1917
|
+
return;
|
|
1918
|
+
}
|
|
1919
|
+
try {
|
|
1920
|
+
setIsLoading(true);
|
|
1921
|
+
setError(null);
|
|
1922
|
+
console.log("[payments-ui] Requesting Solana Pay QR intent", {
|
|
1923
|
+
priceId,
|
|
1924
|
+
token: tokenSymbol
|
|
1925
|
+
});
|
|
1926
|
+
const nextIntent = await solanaService.generateQRCode(
|
|
1927
|
+
priceId,
|
|
1928
|
+
tokenSymbol
|
|
1929
|
+
);
|
|
1930
|
+
if (cancelled) return;
|
|
1931
|
+
setIntent(nextIntent);
|
|
1932
|
+
setTimeRemaining(
|
|
1933
|
+
Math.max(0, Math.floor(nextIntent.expires_at - Date.now() / 1e3))
|
|
1934
|
+
);
|
|
1935
|
+
await renderQr(nextIntent);
|
|
1936
|
+
console.log("[payments-ui] Solana Pay QR ready", {
|
|
1937
|
+
reference: nextIntent.reference
|
|
1938
|
+
});
|
|
1939
|
+
startCountdown(nextIntent.expires_at, nextIntent.reference);
|
|
1940
|
+
pollStatus(nextIntent.reference);
|
|
1941
|
+
} catch (err) {
|
|
1942
|
+
if (cancelled) return;
|
|
1943
|
+
console.error("Failed to generate Solana Pay QR intent:", err);
|
|
1944
|
+
const message = err instanceof Error ? err.message : "Unable to create Solana Pay QR code";
|
|
1945
|
+
handleError(message);
|
|
1946
|
+
} finally {
|
|
1947
|
+
if (!cancelled) {
|
|
1948
|
+
setIsLoading(false);
|
|
1949
|
+
}
|
|
1950
|
+
}
|
|
1951
|
+
};
|
|
1952
|
+
void generateIntent();
|
|
1953
|
+
return () => {
|
|
1954
|
+
cancelled = true;
|
|
1854
1955
|
clearTimers();
|
|
1855
|
-
|
|
1856
|
-
priceId,
|
|
1857
|
-
selectedToken.symbol
|
|
1858
|
-
);
|
|
1859
|
-
setIntent(nextIntent);
|
|
1860
|
-
setTimeRemaining(
|
|
1861
|
-
Math.max(0, Math.floor(nextIntent.expires_at - Date.now() / 1e3))
|
|
1862
|
-
);
|
|
1863
|
-
await renderQr(nextIntent);
|
|
1864
|
-
startCountdown(nextIntent.expires_at, nextIntent.reference);
|
|
1865
|
-
pollStatus(nextIntent.reference);
|
|
1866
|
-
} catch (err) {
|
|
1867
|
-
console.error("Failed to generate Solana Pay QR intent:", err);
|
|
1868
|
-
const message = err instanceof Error ? err.message : "Unable to create Solana Pay QR code";
|
|
1869
|
-
handleError(message);
|
|
1870
|
-
} finally {
|
|
1871
|
-
setIsLoading(false);
|
|
1872
|
-
}
|
|
1956
|
+
};
|
|
1873
1957
|
}, [
|
|
1874
1958
|
clearTimers,
|
|
1875
1959
|
handleError,
|
|
1876
1960
|
pollStatus,
|
|
1877
1961
|
priceId,
|
|
1878
|
-
|
|
1962
|
+
renderQr,
|
|
1963
|
+
resetState,
|
|
1879
1964
|
solanaService,
|
|
1880
1965
|
startCountdown,
|
|
1881
|
-
|
|
1966
|
+
tokenSymbol,
|
|
1967
|
+
refreshNonce
|
|
1882
1968
|
]);
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
}, [
|
|
1969
|
+
const refresh = useCallback(() => {
|
|
1970
|
+
setRefreshNonce((value) => value + 1);
|
|
1971
|
+
}, []);
|
|
1886
1972
|
return {
|
|
1887
1973
|
intent,
|
|
1888
1974
|
qrDataUri,
|
|
1889
1975
|
isLoading,
|
|
1890
1976
|
error,
|
|
1891
1977
|
timeRemaining,
|
|
1892
|
-
refresh
|
|
1978
|
+
refresh
|
|
1893
1979
|
};
|
|
1894
1980
|
};
|
|
1895
1981
|
var QRCodePayment = ({
|
|
@@ -2012,11 +2098,15 @@ var useSupportedTokens = () => {
|
|
|
2012
2098
|
setIsLoading(true);
|
|
2013
2099
|
setError(null);
|
|
2014
2100
|
try {
|
|
2101
|
+
console.log("payments-ui: fetching supported Solana tokens");
|
|
2015
2102
|
const tokens2 = await solanaService.getSupportedTokens();
|
|
2016
2103
|
const sortedTokens = [...tokens2].sort(
|
|
2017
2104
|
(a, b) => a.symbol.localeCompare(b.symbol)
|
|
2018
2105
|
);
|
|
2019
2106
|
setTokens(sortedTokens);
|
|
2107
|
+
console.log("payments-ui: loaded supported tokens", {
|
|
2108
|
+
count: sortedTokens.length
|
|
2109
|
+
});
|
|
2020
2110
|
setLastFetched(Date.now());
|
|
2021
2111
|
return sortedTokens;
|
|
2022
2112
|
} catch (error2) {
|
|
@@ -2862,7 +2952,10 @@ var usePaymentStatus = (options = {}) => {
|
|
|
2862
2952
|
error: err ? `Transaction failed: ${err}` : void 0
|
|
2863
2953
|
};
|
|
2864
2954
|
} catch (error2) {
|
|
2865
|
-
console.error("Failed to check transaction status:",
|
|
2955
|
+
console.error("Failed to check transaction status:", {
|
|
2956
|
+
signature,
|
|
2957
|
+
error: error2
|
|
2958
|
+
});
|
|
2866
2959
|
return {
|
|
2867
2960
|
signature,
|
|
2868
2961
|
confirmationStatus: "failed",
|
|
@@ -2884,7 +2977,10 @@ var usePaymentStatus = (options = {}) => {
|
|
|
2884
2977
|
if (error2?.status === 404) {
|
|
2885
2978
|
return null;
|
|
2886
2979
|
}
|
|
2887
|
-
console.error("Failed to check payment status:",
|
|
2980
|
+
console.error("Failed to check payment status:", {
|
|
2981
|
+
purchaseId: id,
|
|
2982
|
+
error: error2
|
|
2983
|
+
});
|
|
2888
2984
|
return null;
|
|
2889
2985
|
}
|
|
2890
2986
|
},
|
|
@@ -2947,7 +3043,11 @@ var usePaymentStatus = (options = {}) => {
|
|
|
2947
3043
|
return;
|
|
2948
3044
|
}
|
|
2949
3045
|
} catch (error2) {
|
|
2950
|
-
console.error("Error monitoring payment:",
|
|
3046
|
+
console.error("Error monitoring payment:", {
|
|
3047
|
+
transactionId,
|
|
3048
|
+
purchaseId,
|
|
3049
|
+
error: error2
|
|
3050
|
+
});
|
|
2951
3051
|
setRetryCount((prev) => prev + 1);
|
|
2952
3052
|
if (retryCount >= maxRetries) {
|
|
2953
3053
|
if (intervalRef.current) {
|
|
@@ -2997,6 +3097,11 @@ var usePaymentStatus = (options = {}) => {
|
|
|
2997
3097
|
} catch (error2) {
|
|
2998
3098
|
const errorMessage = error2 instanceof Error ? error2.message : "Failed to check status";
|
|
2999
3099
|
setError(errorMessage);
|
|
3100
|
+
console.error("Failed to check payment status:", {
|
|
3101
|
+
transactionId,
|
|
3102
|
+
purchaseId,
|
|
3103
|
+
error: error2
|
|
3104
|
+
});
|
|
3000
3105
|
} finally {
|
|
3001
3106
|
setIsLoading(false);
|
|
3002
3107
|
}
|