@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.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", "8u8B78-23Z347-c2svF3-pbEb7G");
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
- const response = await fetcher(url, {
80
- method,
81
- headers,
82
- body: options?.body ? JSON.stringify(options.body) : void 0
83
- });
84
- if (!response.ok) {
85
- const message = await response.text();
86
- throw new Error(message || `Request failed with status ${response.status}`);
87
- }
88
- if (response.status === 204) {
89
- return void 0;
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:", error);
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("Payment failed:", err);
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
- setError(message);
1774
- setIntent(null);
1775
- setQrDataUri(null);
1776
- setTimeRemaining(0);
1841
+ resetState(message);
1777
1842
  if (notifyParent) {
1778
- onError(message);
1843
+ onErrorRef.current?.(message);
1779
1844
  }
1780
1845
  },
1781
- [clearTimers, onError]
1846
+ [clearTimers, resetState]
1782
1847
  );
1783
1848
  const handleSuccess = useCallback(
1784
1849
  (status) => {
1785
1850
  clearTimers();
1786
- setTimeRemaining(0);
1787
- setIntent(null);
1788
- onSuccess(status.payment_id, status.transaction || "");
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, onSuccess]
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
- const fetchIntent = useCallback(async () => {
1843
- if (!selectedToken) {
1844
- setIntent(null);
1845
- setQrDataUri(null);
1846
- setError(null);
1910
+ useEffect(() => {
1911
+ let cancelled = false;
1912
+ const generateIntent = async () => {
1847
1913
  clearTimers();
1848
- setTimeRemaining(0);
1849
- return;
1850
- }
1851
- try {
1852
- setIsLoading(true);
1853
- setError(null);
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
- const nextIntent = await solanaService.generateQRCode(
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
- selectedToken,
1962
+ renderQr,
1963
+ resetState,
1879
1964
  solanaService,
1880
1965
  startCountdown,
1881
- renderQr
1966
+ tokenSymbol,
1967
+ refreshNonce
1882
1968
  ]);
1883
- useEffect(() => {
1884
- void fetchIntent();
1885
- }, [fetchIntent]);
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: fetchIntent
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:", error2);
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:", error2);
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:", error2);
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
  }