@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 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", "8u8B78-23Z347-c2svF3-pbEb7G");
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
- const response = await fetcher(url, {
110
- method,
111
- headers,
112
- body: options?.body ? JSON.stringify(options.body) : void 0
113
- });
114
- if (!response.ok) {
115
- const message = await response.text();
116
- throw new Error(message || `Request failed with status ${response.status}`);
117
- }
118
- if (response.status === 204) {
119
- return void 0;
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:", error);
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("Payment failed:", err);
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
- setError(message);
1804
- setIntent(null);
1805
- setQrDataUri(null);
1806
- setTimeRemaining(0);
1871
+ resetState(message);
1807
1872
  if (notifyParent) {
1808
- onError(message);
1873
+ onErrorRef.current?.(message);
1809
1874
  }
1810
1875
  },
1811
- [clearTimers, onError]
1876
+ [clearTimers, resetState]
1812
1877
  );
1813
1878
  const handleSuccess = React3.useCallback(
1814
1879
  (status) => {
1815
1880
  clearTimers();
1816
- setTimeRemaining(0);
1817
- setIntent(null);
1818
- onSuccess(status.payment_id, status.transaction || "");
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, onSuccess]
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
- const fetchIntent = React3.useCallback(async () => {
1873
- if (!selectedToken) {
1874
- setIntent(null);
1875
- setQrDataUri(null);
1876
- setError(null);
1940
+ React3.useEffect(() => {
1941
+ let cancelled = false;
1942
+ const generateIntent = async () => {
1877
1943
  clearTimers();
1878
- setTimeRemaining(0);
1879
- return;
1880
- }
1881
- try {
1882
- setIsLoading(true);
1883
- setError(null);
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
- const nextIntent = await solanaService.generateQRCode(
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
- selectedToken,
1992
+ renderQr,
1993
+ resetState,
1909
1994
  solanaService,
1910
1995
  startCountdown,
1911
- renderQr
1996
+ tokenSymbol,
1997
+ refreshNonce
1912
1998
  ]);
1913
- React3.useEffect(() => {
1914
- void fetchIntent();
1915
- }, [fetchIntent]);
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: fetchIntent
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:", error2);
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:", error2);
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:", error2);
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
  }