@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.cjs
CHANGED
|
@@ -65,12 +65,18 @@ var loadCollectJs = (tokenizationKey) => {
|
|
|
65
65
|
if (existing) return;
|
|
66
66
|
const script = document.createElement("script");
|
|
67
67
|
script.src = SCRIPT_SRC;
|
|
68
|
-
script.setAttribute("data-tokenization-key",
|
|
68
|
+
script.setAttribute("data-tokenization-key", trimmed);
|
|
69
69
|
script.setAttribute("data-field-ccnumber-placeholder", "0000 0000 0000 0000");
|
|
70
70
|
script.setAttribute("data-field-ccexp-placeholder", "10 / 25");
|
|
71
71
|
script.setAttribute("data-field-cvv-placeholder", "123");
|
|
72
72
|
script.setAttribute("data-variant", "inline");
|
|
73
73
|
script.async = true;
|
|
74
|
+
script.addEventListener("load", () => {
|
|
75
|
+
console.log("payments-ui: Collect.js loaded");
|
|
76
|
+
});
|
|
77
|
+
script.addEventListener("error", (event) => {
|
|
78
|
+
console.error("payments-ui: failed to load Collect.js", event);
|
|
79
|
+
});
|
|
74
80
|
document.head.appendChild(script);
|
|
75
81
|
};
|
|
76
82
|
|
|
@@ -106,20 +112,31 @@ var createApiClient = (paymentConfig, baseUrl, fetcher, resolveAuthToken) => {
|
|
|
106
112
|
if (token) {
|
|
107
113
|
headers.Authorization = `Bearer ${token}`;
|
|
108
114
|
}
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
115
|
+
try {
|
|
116
|
+
const response = await fetcher(url, {
|
|
117
|
+
method,
|
|
118
|
+
headers,
|
|
119
|
+
body: options?.body ? JSON.stringify(options.body) : void 0
|
|
120
|
+
});
|
|
121
|
+
if (!response.ok) {
|
|
122
|
+
const message = await response.text();
|
|
123
|
+
console.error("payments-ui: API request failed", {
|
|
124
|
+
url,
|
|
125
|
+
method,
|
|
126
|
+
status: response.status,
|
|
127
|
+
message
|
|
128
|
+
});
|
|
129
|
+
throw new Error(message || `Request failed with status ${response.status}`);
|
|
130
|
+
}
|
|
131
|
+
if (response.status === 204) {
|
|
132
|
+
return void 0;
|
|
133
|
+
}
|
|
134
|
+
const data = await response.json();
|
|
135
|
+
return data;
|
|
136
|
+
} catch (error) {
|
|
137
|
+
console.error("payments-ui: API request error", { url, method, error });
|
|
138
|
+
throw error;
|
|
120
139
|
}
|
|
121
|
-
const data = await response.json();
|
|
122
|
-
return data;
|
|
123
140
|
};
|
|
124
141
|
return {
|
|
125
142
|
request,
|
|
@@ -1595,8 +1612,16 @@ var useSolanaDirectPayment = (options) => {
|
|
|
1595
1612
|
const balance = balanceInfo?.balance || 0;
|
|
1596
1613
|
const hasBalanceFlag = hasSufficientBalance(balance, tokenAmount);
|
|
1597
1614
|
setTokenBalance({ balance, hasBalance: hasBalanceFlag });
|
|
1615
|
+
console.log("payments-ui: Solana wallet balance", {
|
|
1616
|
+
token: selectedToken.symbol,
|
|
1617
|
+
balance,
|
|
1618
|
+
required: tokenAmount
|
|
1619
|
+
});
|
|
1598
1620
|
} catch (error) {
|
|
1599
|
-
console.error("Failed to fetch token balance:",
|
|
1621
|
+
console.error("Failed to fetch token balance:", {
|
|
1622
|
+
token: selectedToken?.symbol,
|
|
1623
|
+
error
|
|
1624
|
+
});
|
|
1600
1625
|
setTokenBalance({ balance: 0, hasBalance: false });
|
|
1601
1626
|
} finally {
|
|
1602
1627
|
setIsBalanceLoading(false);
|
|
@@ -1660,30 +1685,49 @@ var useSolanaDirectPayment = (options) => {
|
|
|
1660
1685
|
return;
|
|
1661
1686
|
}
|
|
1662
1687
|
if (!tokenBalance?.hasBalance) {
|
|
1688
|
+
console.warn("payments-ui: insufficient balance for Solana direct payment", {
|
|
1689
|
+
token: selectedToken.symbol
|
|
1690
|
+
});
|
|
1663
1691
|
onError("Insufficient balance for this token");
|
|
1664
1692
|
return;
|
|
1665
1693
|
}
|
|
1666
1694
|
try {
|
|
1667
1695
|
setIsProcessing(true);
|
|
1668
1696
|
onStart();
|
|
1697
|
+
console.log("payments-ui: initiating Solana direct payment", {
|
|
1698
|
+
priceId,
|
|
1699
|
+
token: selectedToken.symbol
|
|
1700
|
+
});
|
|
1669
1701
|
const paymentData = await solanaService.generatePayment(
|
|
1670
1702
|
priceId,
|
|
1671
1703
|
selectedToken.symbol,
|
|
1672
1704
|
publicKey.toBase58()
|
|
1673
1705
|
);
|
|
1706
|
+
console.log("payments-ui: Solana payment intent created", {
|
|
1707
|
+
intentId: paymentData.intent_id
|
|
1708
|
+
});
|
|
1674
1709
|
const transactionToSign = decodeTransaction(paymentData.transaction);
|
|
1710
|
+
console.log("payments-ui: requesting Solana wallet signature");
|
|
1675
1711
|
const signedTx = await signWithWallet(transactionToSign);
|
|
1676
1712
|
const signedSerialized = buffer.Buffer.from(signedTx.serialize()).toString("base64");
|
|
1677
1713
|
onConfirming();
|
|
1714
|
+
console.log("payments-ui: submitting signed Solana transaction");
|
|
1678
1715
|
const result = await solanaService.submitPayment(
|
|
1679
1716
|
signedSerialized,
|
|
1680
1717
|
priceId,
|
|
1681
1718
|
paymentData.intent_id,
|
|
1682
1719
|
`Payment for subscription - ${selectedToken.symbol}`
|
|
1683
1720
|
);
|
|
1721
|
+
console.log("payments-ui: Solana direct payment confirmed", {
|
|
1722
|
+
transactionId: result.transaction_id
|
|
1723
|
+
});
|
|
1684
1724
|
onSuccess(result, result.transaction_id);
|
|
1685
1725
|
} catch (err) {
|
|
1686
|
-
console.error("
|
|
1726
|
+
console.error("Solana direct payment failed:", {
|
|
1727
|
+
priceId,
|
|
1728
|
+
token: selectedToken.symbol,
|
|
1729
|
+
error: err
|
|
1730
|
+
});
|
|
1687
1731
|
let errorMessage = "Payment failed. Please try again.";
|
|
1688
1732
|
const message = err instanceof Error ? err.message : typeof err === "string" ? err : "";
|
|
1689
1733
|
if (message.includes("User rejected")) {
|
|
@@ -1775,11 +1819,15 @@ var DirectPayment = ({
|
|
|
1775
1819
|
var useSolanaQrPayment = (options) => {
|
|
1776
1820
|
const { priceId, selectedToken, onSuccess, onError } = options;
|
|
1777
1821
|
const solanaService = useSolanaService();
|
|
1822
|
+
const tokenSymbol = selectedToken?.symbol ?? null;
|
|
1823
|
+
const onSuccessRef = React3.useRef(onSuccess);
|
|
1824
|
+
const onErrorRef = React3.useRef(onError);
|
|
1778
1825
|
const [intent, setIntent] = React3.useState(null);
|
|
1779
1826
|
const [qrDataUri, setQrDataUri] = React3.useState(null);
|
|
1780
1827
|
const [isLoading, setIsLoading] = React3.useState(false);
|
|
1781
1828
|
const [error, setError] = React3.useState(null);
|
|
1782
1829
|
const [timeRemaining, setTimeRemaining] = React3.useState(0);
|
|
1830
|
+
const [refreshNonce, setRefreshNonce] = React3.useState(0);
|
|
1783
1831
|
const pollRef = React3.useRef(null);
|
|
1784
1832
|
const countdownRef = React3.useRef(null);
|
|
1785
1833
|
const clearTimers = React3.useCallback(() => {
|
|
@@ -1797,27 +1845,47 @@ var useSolanaQrPayment = (options) => {
|
|
|
1797
1845
|
clearTimers();
|
|
1798
1846
|
};
|
|
1799
1847
|
}, [clearTimers]);
|
|
1848
|
+
const resetState = React3.useCallback(
|
|
1849
|
+
(message) => {
|
|
1850
|
+
clearTimers();
|
|
1851
|
+
setIntent((prev) => prev ? null : prev);
|
|
1852
|
+
setQrDataUri((prev) => prev ? null : prev);
|
|
1853
|
+
setTimeRemaining((prev) => prev !== 0 ? 0 : prev);
|
|
1854
|
+
setError((prev) => {
|
|
1855
|
+
const next = message === void 0 ? null : message;
|
|
1856
|
+
return prev === next ? prev : next;
|
|
1857
|
+
});
|
|
1858
|
+
},
|
|
1859
|
+
[clearTimers]
|
|
1860
|
+
);
|
|
1861
|
+
React3.useEffect(() => {
|
|
1862
|
+
onSuccessRef.current = onSuccess;
|
|
1863
|
+
}, [onSuccess]);
|
|
1864
|
+
React3.useEffect(() => {
|
|
1865
|
+
onErrorRef.current = onError;
|
|
1866
|
+
}, [onError]);
|
|
1800
1867
|
const handleError = React3.useCallback(
|
|
1801
1868
|
(message, notifyParent = false) => {
|
|
1869
|
+
console.error("[payments-ui] Solana Pay QR error:", message);
|
|
1802
1870
|
clearTimers();
|
|
1803
|
-
|
|
1804
|
-
setIntent(null);
|
|
1805
|
-
setQrDataUri(null);
|
|
1806
|
-
setTimeRemaining(0);
|
|
1871
|
+
resetState(message);
|
|
1807
1872
|
if (notifyParent) {
|
|
1808
|
-
|
|
1873
|
+
onErrorRef.current?.(message);
|
|
1809
1874
|
}
|
|
1810
1875
|
},
|
|
1811
|
-
[clearTimers,
|
|
1876
|
+
[clearTimers, resetState]
|
|
1812
1877
|
);
|
|
1813
1878
|
const handleSuccess = React3.useCallback(
|
|
1814
1879
|
(status) => {
|
|
1815
1880
|
clearTimers();
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1881
|
+
resetState(null);
|
|
1882
|
+
console.log("[payments-ui] Solana Pay QR confirmed", {
|
|
1883
|
+
paymentId: status.payment_id,
|
|
1884
|
+
intentId: status.intent_id
|
|
1885
|
+
});
|
|
1886
|
+
onSuccessRef.current?.(status.payment_id, status.transaction || "");
|
|
1819
1887
|
},
|
|
1820
|
-
[clearTimers,
|
|
1888
|
+
[clearTimers, resetState]
|
|
1821
1889
|
);
|
|
1822
1890
|
const pollStatus = React3.useCallback(
|
|
1823
1891
|
async (reference) => {
|
|
@@ -1869,57 +1937,75 @@ var useSolanaQrPayment = (options) => {
|
|
|
1869
1937
|
handleError("Unable to render QR code");
|
|
1870
1938
|
}
|
|
1871
1939
|
}, [handleError]);
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
setQrDataUri(null);
|
|
1876
|
-
setError(null);
|
|
1940
|
+
React3.useEffect(() => {
|
|
1941
|
+
let cancelled = false;
|
|
1942
|
+
const generateIntent = async () => {
|
|
1877
1943
|
clearTimers();
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1944
|
+
if (!tokenSymbol || !priceId) {
|
|
1945
|
+
resetState(null);
|
|
1946
|
+
setIsLoading((prev) => prev ? false : prev);
|
|
1947
|
+
return;
|
|
1948
|
+
}
|
|
1949
|
+
try {
|
|
1950
|
+
setIsLoading(true);
|
|
1951
|
+
setError(null);
|
|
1952
|
+
console.log("[payments-ui] Requesting Solana Pay QR intent", {
|
|
1953
|
+
priceId,
|
|
1954
|
+
token: tokenSymbol
|
|
1955
|
+
});
|
|
1956
|
+
const nextIntent = await solanaService.generateQRCode(
|
|
1957
|
+
priceId,
|
|
1958
|
+
tokenSymbol
|
|
1959
|
+
);
|
|
1960
|
+
if (cancelled) return;
|
|
1961
|
+
setIntent(nextIntent);
|
|
1962
|
+
setTimeRemaining(
|
|
1963
|
+
Math.max(0, Math.floor(nextIntent.expires_at - Date.now() / 1e3))
|
|
1964
|
+
);
|
|
1965
|
+
await renderQr(nextIntent);
|
|
1966
|
+
console.log("[payments-ui] Solana Pay QR ready", {
|
|
1967
|
+
reference: nextIntent.reference
|
|
1968
|
+
});
|
|
1969
|
+
startCountdown(nextIntent.expires_at, nextIntent.reference);
|
|
1970
|
+
pollStatus(nextIntent.reference);
|
|
1971
|
+
} catch (err) {
|
|
1972
|
+
if (cancelled) return;
|
|
1973
|
+
console.error("Failed to generate Solana Pay QR intent:", err);
|
|
1974
|
+
const message = err instanceof Error ? err.message : "Unable to create Solana Pay QR code";
|
|
1975
|
+
handleError(message);
|
|
1976
|
+
} finally {
|
|
1977
|
+
if (!cancelled) {
|
|
1978
|
+
setIsLoading(false);
|
|
1979
|
+
}
|
|
1980
|
+
}
|
|
1981
|
+
};
|
|
1982
|
+
void generateIntent();
|
|
1983
|
+
return () => {
|
|
1984
|
+
cancelled = true;
|
|
1884
1985
|
clearTimers();
|
|
1885
|
-
|
|
1886
|
-
priceId,
|
|
1887
|
-
selectedToken.symbol
|
|
1888
|
-
);
|
|
1889
|
-
setIntent(nextIntent);
|
|
1890
|
-
setTimeRemaining(
|
|
1891
|
-
Math.max(0, Math.floor(nextIntent.expires_at - Date.now() / 1e3))
|
|
1892
|
-
);
|
|
1893
|
-
await renderQr(nextIntent);
|
|
1894
|
-
startCountdown(nextIntent.expires_at, nextIntent.reference);
|
|
1895
|
-
pollStatus(nextIntent.reference);
|
|
1896
|
-
} catch (err) {
|
|
1897
|
-
console.error("Failed to generate Solana Pay QR intent:", err);
|
|
1898
|
-
const message = err instanceof Error ? err.message : "Unable to create Solana Pay QR code";
|
|
1899
|
-
handleError(message);
|
|
1900
|
-
} finally {
|
|
1901
|
-
setIsLoading(false);
|
|
1902
|
-
}
|
|
1986
|
+
};
|
|
1903
1987
|
}, [
|
|
1904
1988
|
clearTimers,
|
|
1905
1989
|
handleError,
|
|
1906
1990
|
pollStatus,
|
|
1907
1991
|
priceId,
|
|
1908
|
-
|
|
1992
|
+
renderQr,
|
|
1993
|
+
resetState,
|
|
1909
1994
|
solanaService,
|
|
1910
1995
|
startCountdown,
|
|
1911
|
-
|
|
1996
|
+
tokenSymbol,
|
|
1997
|
+
refreshNonce
|
|
1912
1998
|
]);
|
|
1913
|
-
React3.
|
|
1914
|
-
|
|
1915
|
-
}, [
|
|
1999
|
+
const refresh = React3.useCallback(() => {
|
|
2000
|
+
setRefreshNonce((value) => value + 1);
|
|
2001
|
+
}, []);
|
|
1916
2002
|
return {
|
|
1917
2003
|
intent,
|
|
1918
2004
|
qrDataUri,
|
|
1919
2005
|
isLoading,
|
|
1920
2006
|
error,
|
|
1921
2007
|
timeRemaining,
|
|
1922
|
-
refresh
|
|
2008
|
+
refresh
|
|
1923
2009
|
};
|
|
1924
2010
|
};
|
|
1925
2011
|
var QRCodePayment = ({
|
|
@@ -2042,11 +2128,15 @@ var useSupportedTokens = () => {
|
|
|
2042
2128
|
setIsLoading(true);
|
|
2043
2129
|
setError(null);
|
|
2044
2130
|
try {
|
|
2131
|
+
console.log("payments-ui: fetching supported Solana tokens");
|
|
2045
2132
|
const tokens2 = await solanaService.getSupportedTokens();
|
|
2046
2133
|
const sortedTokens = [...tokens2].sort(
|
|
2047
2134
|
(a, b) => a.symbol.localeCompare(b.symbol)
|
|
2048
2135
|
);
|
|
2049
2136
|
setTokens(sortedTokens);
|
|
2137
|
+
console.log("payments-ui: loaded supported tokens", {
|
|
2138
|
+
count: sortedTokens.length
|
|
2139
|
+
});
|
|
2050
2140
|
setLastFetched(Date.now());
|
|
2051
2141
|
return sortedTokens;
|
|
2052
2142
|
} catch (error2) {
|
|
@@ -2892,7 +2982,10 @@ var usePaymentStatus = (options = {}) => {
|
|
|
2892
2982
|
error: err ? `Transaction failed: ${err}` : void 0
|
|
2893
2983
|
};
|
|
2894
2984
|
} catch (error2) {
|
|
2895
|
-
console.error("Failed to check transaction status:",
|
|
2985
|
+
console.error("Failed to check transaction status:", {
|
|
2986
|
+
signature,
|
|
2987
|
+
error: error2
|
|
2988
|
+
});
|
|
2896
2989
|
return {
|
|
2897
2990
|
signature,
|
|
2898
2991
|
confirmationStatus: "failed",
|
|
@@ -2914,7 +3007,10 @@ var usePaymentStatus = (options = {}) => {
|
|
|
2914
3007
|
if (error2?.status === 404) {
|
|
2915
3008
|
return null;
|
|
2916
3009
|
}
|
|
2917
|
-
console.error("Failed to check payment status:",
|
|
3010
|
+
console.error("Failed to check payment status:", {
|
|
3011
|
+
purchaseId: id,
|
|
3012
|
+
error: error2
|
|
3013
|
+
});
|
|
2918
3014
|
return null;
|
|
2919
3015
|
}
|
|
2920
3016
|
},
|
|
@@ -2977,7 +3073,11 @@ var usePaymentStatus = (options = {}) => {
|
|
|
2977
3073
|
return;
|
|
2978
3074
|
}
|
|
2979
3075
|
} catch (error2) {
|
|
2980
|
-
console.error("Error monitoring payment:",
|
|
3076
|
+
console.error("Error monitoring payment:", {
|
|
3077
|
+
transactionId,
|
|
3078
|
+
purchaseId,
|
|
3079
|
+
error: error2
|
|
3080
|
+
});
|
|
2981
3081
|
setRetryCount((prev) => prev + 1);
|
|
2982
3082
|
if (retryCount >= maxRetries) {
|
|
2983
3083
|
if (intervalRef.current) {
|
|
@@ -3027,6 +3127,11 @@ var usePaymentStatus = (options = {}) => {
|
|
|
3027
3127
|
} catch (error2) {
|
|
3028
3128
|
const errorMessage = error2 instanceof Error ? error2.message : "Failed to check status";
|
|
3029
3129
|
setError(errorMessage);
|
|
3130
|
+
console.error("Failed to check payment status:", {
|
|
3131
|
+
transactionId,
|
|
3132
|
+
purchaseId,
|
|
3133
|
+
error: error2
|
|
3134
|
+
});
|
|
3030
3135
|
} finally {
|
|
3031
3136
|
setIsLoading(false);
|
|
3032
3137
|
}
|