@superlogic/spree-pay 0.1.4 → 0.1.6

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 CHANGED
@@ -17,9 +17,9 @@ import { SpreePay, SpreePayProvider, useSpreePay } from '@superlogic/spree-pay';
17
17
 
18
18
  const spreeEnv = {
19
19
  tenantId: 'moca' // Keep moca for crypto payments on BASE network
20
- environment: 'dev',
21
- accessToken: 'eyJhbGciOiJSUzI1NiIs...', // Use user JWT token
20
+ environment: 'dev' as const,
22
21
  redirect3dsURI: '/3ds' // Any valid URI in your app that captures 3ds redirect
22
+ ssoPageURI: '/silent-check-sso.html' // Any valid URI in your app that will handle keyklock SSO (example below)
23
23
  };
24
24
 
25
25
  function Checkout() {
@@ -70,3 +70,18 @@ export default function ThreeDSRedirectPage() {
70
70
  }
71
71
 
72
72
  ```
73
+
74
+ ## Keyklock SSO page example (/silent-check-sso.html)
75
+
76
+ ```html
77
+ <!doctype html>
78
+ <html>
79
+ <body>
80
+ <script>
81
+ try {
82
+ parent.postMessage(location.href, location.origin);
83
+ } catch (e) {}
84
+ </script>
85
+ </body>
86
+ </html>
87
+ ```
package/build/index.cjs CHANGED
@@ -38,7 +38,7 @@ __export(index_exports, {
38
38
  module.exports = __toCommonJS(index_exports);
39
39
 
40
40
  // src/SpreePay.tsx
41
- var import_react11 = require("react");
41
+ var import_react12 = require("react");
42
42
  var import_nice_modal_react6 = __toESM(require("@ebay/nice-modal-react"), 1);
43
43
  var import_swr4 = require("swr");
44
44
 
@@ -5648,7 +5648,8 @@ var cardPayment = async ({ card, hash, redirect3dsURI }) => {
5648
5648
  }
5649
5649
  }
5650
5650
  return {
5651
- status: paymentResData.status
5651
+ status: paymentResData.status,
5652
+ paymentId: paymentResData.id
5652
5653
  };
5653
5654
  };
5654
5655
 
@@ -6643,31 +6644,171 @@ var import_react_query = require("@tanstack/react-query");
6643
6644
  var import_nice_modal_react5 = __toESM(require("@ebay/nice-modal-react"), 1);
6644
6645
  var import_rainbowkit2 = require("@rainbow-me/rainbowkit");
6645
6646
  var import_styles = require("@rainbow-me/rainbowkit/styles.css");
6646
- var import_wagmi4 = require("wagmi");
6647
+ var import_wallets = require("@rainbow-me/rainbowkit/wallets");
6648
+ var import_wagmi5 = require("wagmi");
6647
6649
  var import_chains = require("wagmi/chains");
6648
6650
 
6649
6651
  // src/components/CryptoTab/Crypto/Crypto.tsx
6650
6652
  var import_react10 = require("react");
6651
- var import_wagmi3 = require("wagmi");
6653
+ var import_wagmi4 = require("wagmi");
6652
6654
 
6653
- // src/services/cryptoPayment.ts
6654
- var cryptoPayment = async (params) => {
6655
- const { publicKey, coinSymbol, hash, sendTransaction } = params;
6656
- const paymentRes = await SlapiPaymentService.createPayment({
6657
- type: "CRYPTO" /* CRYPTO */,
6658
- hash,
6659
- crypto: {
6660
- token: coinSymbol,
6661
- publicKey,
6662
- slippageType: "fixed",
6663
- slippageBps: 0.5 * 100
6655
+ // ../../node_modules/@wagmi/core/dist/esm/utils/getAction.js
6656
+ function getAction(client, actionFn, name) {
6657
+ const action_implicit = client[actionFn.name];
6658
+ if (typeof action_implicit === "function")
6659
+ return action_implicit;
6660
+ const action_explicit = client[name];
6661
+ if (typeof action_explicit === "function")
6662
+ return action_explicit;
6663
+ return (params) => actionFn(client, params);
6664
+ }
6665
+
6666
+ // ../../node_modules/@wagmi/core/dist/esm/actions/readContract.js
6667
+ var import_actions = require("viem/actions");
6668
+ function readContract(config2, parameters) {
6669
+ const { chainId, ...rest } = parameters;
6670
+ const client = config2.getClient({ chainId });
6671
+ const action = getAction(client, import_actions.readContract, "readContract");
6672
+ return action(rest);
6673
+ }
6674
+
6675
+ // ../../node_modules/@wagmi/core/dist/esm/actions/waitForTransactionReceipt.js
6676
+ var import_viem = require("viem");
6677
+ var import_actions2 = require("viem/actions");
6678
+ async function waitForTransactionReceipt(config2, parameters) {
6679
+ const { chainId, timeout = 0, ...rest } = parameters;
6680
+ const client = config2.getClient({ chainId });
6681
+ const action = getAction(client, import_actions2.waitForTransactionReceipt, "waitForTransactionReceipt");
6682
+ const receipt = await action({ ...rest, timeout });
6683
+ if (receipt.status === "reverted") {
6684
+ const action_getTransaction = getAction(client, import_actions2.getTransaction, "getTransaction");
6685
+ const txn = await action_getTransaction({ hash: receipt.transactionHash });
6686
+ const action_call = getAction(client, import_actions2.call, "call");
6687
+ const code = await action_call({
6688
+ ...txn,
6689
+ data: txn.input,
6690
+ gasPrice: txn.type !== "eip1559" ? txn.gasPrice : void 0,
6691
+ maxFeePerGas: txn.type === "eip1559" ? txn.maxFeePerGas : void 0,
6692
+ maxPriorityFeePerGas: txn.type === "eip1559" ? txn.maxPriorityFeePerGas : void 0
6693
+ });
6694
+ const reason = code?.data ? (0, import_viem.hexToString)(`0x${code.data.substring(138)}`) : "unknown reason";
6695
+ throw new Error(reason);
6696
+ }
6697
+ return {
6698
+ ...receipt,
6699
+ chainId: client.chain.id
6700
+ };
6701
+ }
6702
+
6703
+ // ../../node_modules/@wagmi/core/dist/esm/exports/index.js
6704
+ var import_viem2 = require("viem");
6705
+
6706
+ // src/hooks/useCryptoPayment.ts
6707
+ var import_viem3 = require("viem");
6708
+ var import_wagmi = require("wagmi");
6709
+
6710
+ // src/config/baseTokens.ts
6711
+ var BASE_CHAIN_ID = 8453;
6712
+ var BASE_TOKENS = [
6713
+ {
6714
+ address: "0x2b11834ed1feaed4b4b3a86a6f571315e25a884d",
6715
+ chainId: BASE_CHAIN_ID,
6716
+ decimals: 18,
6717
+ symbol: "MOCA" /* MOCA */,
6718
+ name: "Moca",
6719
+ logoURI: "https://assets.coingecko.com/coins/images/30046/standard/moca.png"
6720
+ },
6721
+ {
6722
+ address: "0x833589fCD6eDb6E08f4c7C32D4f71b54bDA02913",
6723
+ chainId: BASE_CHAIN_ID,
6724
+ decimals: 6,
6725
+ symbol: "USDC" /* USDC */,
6726
+ name: "USD Coin",
6727
+ logoURI: "https://cryptologos.cc/logos/usd-coin-usdc-logo.png"
6728
+ },
6729
+ {
6730
+ address: "0x4200000000000000000000000000000000000006",
6731
+ chainId: BASE_CHAIN_ID,
6732
+ decimals: 18,
6733
+ symbol: "WETH" /* WETH */,
6734
+ name: "Wrapped Ether",
6735
+ logoURI: "https://static.cdnlogo.com/logos/e/84/ethereum-eth_thumb.png"
6736
+ },
6737
+ {
6738
+ address: "0xfde4c96c8593536e31f229ea8f37b2ada2699bb2",
6739
+ chainId: BASE_CHAIN_ID,
6740
+ decimals: 6,
6741
+ symbol: "USDT" /* USDT */,
6742
+ name: "Tether USD",
6743
+ logoURI: "https://cryptologos.cc/logos/tether-usdt-logo.png"
6744
+ }
6745
+ ];
6746
+
6747
+ // src/hooks/useCryptoPayment.ts
6748
+ var MAX_UINT256 = BigInt(2) ** BigInt(256) - BigInt(1);
6749
+ var ONE_INCH_AGGREGATION_ROUTER_V6 = "0x111111125421ca6dc452d289314280a0f8842a65";
6750
+ var useCryptoPayment = () => {
6751
+ const { data: walletClient } = (0, import_wagmi.useWalletClient)();
6752
+ const config2 = (0, import_wagmi.useConfig)();
6753
+ const { selectedPaymentMethod } = useSpreePaymentMethod();
6754
+ const cryptoPayment = async ({ hash }) => {
6755
+ if (!walletClient) {
6756
+ throw new Error("Wallet not connected");
6664
6757
  }
6665
- });
6666
- const encodedTX = paymentRes.data.encodedTx;
6667
- const parsedTX = JSON.parse(encodedTX);
6668
- const txHash = await sendTransaction(parsedTX);
6669
- const res = await SlapiPaymentService.baseVerify({ id: paymentRes.data.txId, txHash });
6670
- return { status: res.verified ? "AUTHORIZED" /* AUTHORIZED */ : "FAILED" /* FAILED */ };
6758
+ if (selectedPaymentMethod.type !== "CRYPTO" /* CRYPTO */ || !selectedPaymentMethod.method?.symbol) {
6759
+ throw new Error("Unsupported payment method");
6760
+ }
6761
+ const TOKEN = selectedPaymentMethod.method.symbol;
6762
+ if (["MOCA" /* MOCA */, "WETH" /* WETH */, "USDC" /* USDC */, "USDT" /* USDT */].includes(TOKEN)) {
6763
+ const tokenAddress = selectedPaymentMethod.method.address;
6764
+ if (!tokenAddress) {
6765
+ throw new Error("Token address not found");
6766
+ }
6767
+ const allowance = await readContract(config2, {
6768
+ address: tokenAddress,
6769
+ abi: import_viem3.erc20Abi,
6770
+ functionName: "allowance",
6771
+ args: [walletClient.account.address, ONE_INCH_AGGREGATION_ROUTER_V6]
6772
+ });
6773
+ if (allowance <= 0n) {
6774
+ const result = await walletClient.writeContract({
6775
+ address: tokenAddress,
6776
+ abi: import_viem3.erc20Abi,
6777
+ functionName: "approve",
6778
+ args: [ONE_INCH_AGGREGATION_ROUTER_V6, MAX_UINT256]
6779
+ });
6780
+ await waitForTransactionReceipt(config2, {
6781
+ hash: result,
6782
+ confirmations: 1
6783
+ // You can change the number of block confirmations as per your requirement
6784
+ });
6785
+ }
6786
+ }
6787
+ const paymentRes = await SlapiPaymentService.createPayment({
6788
+ type: "CRYPTO" /* CRYPTO */,
6789
+ hash,
6790
+ crypto: {
6791
+ token: TOKEN,
6792
+ publicKey: walletClient.account.address,
6793
+ slippageType: "fixed",
6794
+ slippageBps: 0.5 * 100
6795
+ }
6796
+ });
6797
+ const parsedTX = JSON.parse(paymentRes.data.encodedTx);
6798
+ const txHash = await walletClient.sendTransaction({
6799
+ account: walletClient.account.address,
6800
+ to: parsedTX.to,
6801
+ data: parsedTX.data,
6802
+ value: parsedTX.value
6803
+ });
6804
+ const res = await SlapiPaymentService.baseVerify({ id: paymentRes.data.txId, txHash });
6805
+ return {
6806
+ txHash,
6807
+ paymentId: paymentRes.data.txId,
6808
+ status: res.verified ? "AUTHORIZED" /* AUTHORIZED */ : "FAILED" /* FAILED */
6809
+ };
6810
+ };
6811
+ return { cryptoPayment };
6671
6812
  };
6672
6813
 
6673
6814
  // src/components/CryptoTab/Crypto/ConnectButton.tsx
@@ -6830,50 +6971,12 @@ var import_nice_modal_react3 = __toESM(require("@ebay/nice-modal-react"), 1);
6830
6971
 
6831
6972
  // src/hooks/useBaseERC20Token.ts
6832
6973
  var React30 = __toESM(require("react"), 1);
6833
- var import_viem = require("viem");
6834
- var import_wagmi = require("wagmi");
6835
-
6836
- // src/config/baseTokens.ts
6837
- var BASE_TOKENS = [
6838
- {
6839
- address: "0x2b11834ed1feaed4b4b3a86a6f571315e25a884d",
6840
- chainId: 8453,
6841
- decimals: 18,
6842
- symbol: "MOCA",
6843
- name: "Moca",
6844
- logoURI: "https://assets.coingecko.com/coins/images/30046/standard/moca.png"
6845
- },
6846
- {
6847
- address: "0x833589fCD6eDb6E08f4c7C32D4f71b54bDA02913",
6848
- chainId: 8453,
6849
- decimals: 6,
6850
- symbol: "USDC",
6851
- name: "USD Coin",
6852
- logoURI: "https://cryptologos.cc/logos/usd-coin-usdc-logo.png"
6853
- },
6854
- {
6855
- address: "0x4200000000000000000000000000000000000006",
6856
- chainId: 8453,
6857
- decimals: 18,
6858
- symbol: "WETH",
6859
- name: "Wrapped Ether",
6860
- logoURI: "https://static.cdnlogo.com/logos/e/84/ethereum-eth_thumb.png"
6861
- },
6862
- {
6863
- address: "0xfde4c96c8593536e31f229ea8f37b2ada2699bb2",
6864
- chainId: 8453,
6865
- decimals: 6,
6866
- symbol: "USDT",
6867
- name: "Tether USD",
6868
- logoURI: "https://cryptologos.cc/logos/tether-usdt-logo.png"
6869
- }
6870
- ];
6871
-
6872
- // src/hooks/useBaseERC20Token.ts
6974
+ var import_viem4 = require("viem");
6975
+ var import_wagmi2 = require("wagmi");
6873
6976
  function useBaseERC20Token() {
6874
- const { address } = (0, import_wagmi.useAccount)();
6875
- const baseClient = (0, import_wagmi.usePublicClient)({ chainId: 8453 });
6876
- const defaultClient = (0, import_wagmi.usePublicClient)();
6977
+ const { address } = (0, import_wagmi2.useAccount)();
6978
+ const baseClient = (0, import_wagmi2.usePublicClient)({ chainId: BASE_CHAIN_ID });
6979
+ const defaultClient = (0, import_wagmi2.usePublicClient)();
6877
6980
  const [rows, setRows] = React30.useState([]);
6878
6981
  const [isLoading, setLoading] = React30.useState(false);
6879
6982
  const [error, setError] = React30.useState(null);
@@ -6890,7 +6993,7 @@ function useBaseERC20Token() {
6890
6993
  const normalizedTokens = [];
6891
6994
  for (const t of BASE_TOKENS) {
6892
6995
  try {
6893
- const addr = (0, import_viem.getAddress)(t.address);
6996
+ const addr = (0, import_viem4.getAddress)(t.address);
6894
6997
  normalizedTokens.push({ ...t, address: addr });
6895
6998
  } catch {
6896
6999
  }
@@ -6899,7 +7002,7 @@ function useBaseERC20Token() {
6899
7002
  allowFailure: true,
6900
7003
  contracts: normalizedTokens.map((t) => ({
6901
7004
  address: t.address,
6902
- abi: import_viem.erc20Abi,
7005
+ abi: import_viem4.erc20Abi,
6903
7006
  functionName: "balanceOf",
6904
7007
  args: [address]
6905
7008
  }))
@@ -6910,14 +7013,16 @@ function useBaseERC20Token() {
6910
7013
  const t = normalizedTokens[idx];
6911
7014
  if (r2.status === "success") {
6912
7015
  const raw = r2.result;
6913
- if (raw > 0n) acc.push({ ...t, raw, formatted: (0, import_viem.formatUnits)(raw, t.decimals) });
7016
+ if (raw > 0n) acc.push({ ...t, raw, formatted: (0, import_viem4.formatUnits)(raw, t.decimals) });
6914
7017
  }
6915
7018
  }
6916
7019
  if (!cancelled) setRows(acc);
6917
7020
  } catch (e) {
6918
7021
  if (!cancelled) {
6919
7022
  const msg = e instanceof Error ? e.message : "Multicall failed";
6920
- setError(baseClient ? msg : "Base client unavailable. Ensure Base (8453) is configured in Wagmi.");
7023
+ setError(
7024
+ baseClient ? msg : `Base client unavailable. Ensure Base (${BASE_CHAIN_ID}) is configured in Wagmi.`
7025
+ );
6921
7026
  }
6922
7027
  } finally {
6923
7028
  if (!cancelled) setLoading(false);
@@ -6932,16 +7037,15 @@ function useBaseERC20Token() {
6932
7037
  }
6933
7038
 
6934
7039
  // src/hooks/useBaseNativeToken.ts
6935
- var import_wagmi2 = require("wagmi");
7040
+ var import_wagmi3 = require("wagmi");
6936
7041
  function useBaseNativeToken() {
6937
- const { address } = (0, import_wagmi2.useAccount)();
6938
- const { data, isLoading, error } = (0, import_wagmi2.useBalance)({
7042
+ const { address } = (0, import_wagmi3.useAccount)();
7043
+ const { data, isLoading, error } = (0, import_wagmi3.useBalance)({
6939
7044
  address,
6940
- chainId: 8453,
6941
- // Base
7045
+ chainId: BASE_CHAIN_ID,
6942
7046
  query: { enabled: !!address }
6943
7047
  });
6944
- const nativeBalance = data ? { ...data, logoURI: "https://static.cdnlogo.com/logos/e/84/ethereum-eth_thumb.png" } : void 0;
7048
+ const nativeBalance = data ? { ...data, symbol: "ETH" /* ETH */, logoURI: "https://static.cdnlogo.com/logos/e/84/ethereum-eth_thumb.png" } : void 0;
6945
7049
  return {
6946
7050
  isLoadingNative: isLoading,
6947
7051
  nativeError: error?.message ?? null,
@@ -7009,7 +7113,6 @@ var CryptoSelectModal = import_nice_modal_react3.default.create(() => {
7009
7113
  return /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(
7010
7114
  "button",
7011
7115
  {
7012
- disabled: true,
7013
7116
  className: "flex h-11 w-full items-center justify-between gap-4 rounded-sm px-1.5 hover:bg-gray-100 disabled:cursor-not-allowed disabled:opacity-50",
7014
7117
  onClick: () => handleSelect(coin),
7015
7118
  children: [
@@ -7069,41 +7172,24 @@ var SelectedCoin = (props) => {
7069
7172
  // src/components/CryptoTab/Crypto/Crypto.tsx
7070
7173
  var import_jsx_runtime31 = require("react/jsx-runtime");
7071
7174
  var Crypto = () => {
7072
- const { address } = (0, import_wagmi3.useAccount)();
7073
- const { data: walletClient } = (0, import_wagmi3.useWalletClient)();
7175
+ const { address } = (0, import_wagmi4.useAccount)();
7074
7176
  const { selectedPaymentMethod } = useSpreePaymentMethod();
7177
+ const { cryptoPayment } = useCryptoPayment();
7075
7178
  const isWalletConnected = Boolean(address);
7076
7179
  const { register } = useSpreePayRegister();
7077
7180
  const handlePay = (0, import_react10.useCallback)(
7078
7181
  async (data) => {
7079
7182
  try {
7080
- if (selectedPaymentMethod.type === "CRYPTO" /* CRYPTO */ && selectedPaymentMethod.method) {
7081
- if (!walletClient || !address) throw new Error("Wallet not connected");
7082
- const sendTransaction = (encodedTx) => {
7083
- return walletClient.sendTransaction({
7084
- account: address,
7085
- to: encodedTx.to,
7086
- data: encodedTx.data,
7087
- value: encodedTx.value
7088
- });
7089
- };
7090
- const res = await cryptoPayment({
7091
- hash: data.hash,
7092
- coinSymbol: selectedPaymentMethod.method.symbol,
7093
- publicKey: address,
7094
- sendTransaction
7095
- });
7096
- if (["AUTHORIZED" /* AUTHORIZED */, "CAPTURED" /* CAPTURED */].includes(res.status)) {
7097
- return Promise.resolve(res);
7098
- }
7099
- return Promise.reject(new PaymentError("Crypto payment failed", res.status));
7183
+ const res = await cryptoPayment({ hash: data.hash });
7184
+ if (["AUTHORIZED" /* AUTHORIZED */, "CAPTURED" /* CAPTURED */].includes(res.status)) {
7185
+ return Promise.resolve(res);
7100
7186
  }
7101
- return Promise.reject(new PaymentError("Unsupported payment method", "FAILED" /* FAILED */));
7187
+ return Promise.reject(new PaymentError("Crypto payment failed", res.status));
7102
7188
  } catch (_) {
7103
7189
  return Promise.reject(new PaymentError("Payment failed", "FAILED" /* FAILED */));
7104
7190
  }
7105
7191
  },
7106
- [selectedPaymentMethod, address, walletClient]
7192
+ [cryptoPayment]
7107
7193
  );
7108
7194
  (0, import_react10.useEffect)(() => {
7109
7195
  register(handlePay);
@@ -7131,14 +7217,23 @@ var Crypto = () => {
7131
7217
  // src/components/CryptoTab/Crypto/CryptoWrapper.tsx
7132
7218
  var import_jsx_runtime32 = require("react/jsx-runtime");
7133
7219
  var queryClient = new import_react_query.QueryClient();
7134
- var config = (0, import_rainbowkit2.getDefaultConfig)({
7135
- appName: "Spree Pay",
7136
- projectId: "YOUR_PROJECT_ID",
7220
+ var connectors = (0, import_rainbowkit2.connectorsForWallets)(
7221
+ [
7222
+ {
7223
+ groupName: "Supported",
7224
+ wallets: [import_wallets.injectedWallet, import_wallets.walletConnectWallet]
7225
+ }
7226
+ ],
7227
+ { appName: "Spree Pay", projectId: "YOUR_PROJECT_ID" }
7228
+ );
7229
+ var config = (0, import_wagmi5.createConfig)({
7137
7230
  chains: [import_chains.base],
7231
+ connectors,
7232
+ transports: { [import_chains.base.id]: (0, import_wagmi5.http)() },
7138
7233
  ssr: true
7139
7234
  });
7140
7235
  var CryptoWrapper = () => {
7141
- return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_wagmi4.WagmiProvider, { config, children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_react_query.QueryClientProvider, { client: queryClient, children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_rainbowkit2.RainbowKitProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_nice_modal_react5.default.Provider, { children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(Crypto, {}) }) }) }) });
7236
+ return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_wagmi5.WagmiProvider, { config, children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_react_query.QueryClientProvider, { client: queryClient, children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_rainbowkit2.RainbowKitProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_nice_modal_react5.default.Provider, { children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(Crypto, {}) }) }) }) });
7142
7237
  };
7143
7238
 
7144
7239
  // src/components/CryptoTab/CryptoTab.tsx
@@ -7213,7 +7308,7 @@ var Tabs = () => {
7213
7308
  const { selectedPaymentMethod, setSelectedPaymentMethod } = useSpreePaymentMethod();
7214
7309
  return /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("div", { className: "mb-4 rounded-2xl border border-black/25 bg-white", children: [
7215
7310
  /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("div", { className: "flex w-full flex-col gap-4 border-b-1 border-black/7 px-7 py-6", children: [
7216
- /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("h2", { className: "text-primary text-2xl font-semibold", children: "Choose a 123Payment Method" }),
7311
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("h2", { className: "text-primary text-2xl font-semibold", children: "Choose a Payment Method" }),
7217
7312
  /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(TabButtons, { value: selectedPaymentMethod.type, onChange: setSelectedPaymentMethod })
7218
7313
  ] }),
7219
7314
  selectedPaymentMethod.type === "CREDIT_CARD" /* CREDIT_CARD */ && /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(CreditCardTab, {}),
@@ -7224,32 +7319,151 @@ var Tabs = () => {
7224
7319
  // src/SpreePayContent.tsx
7225
7320
  var import_jsx_runtime36 = require("react/jsx-runtime");
7226
7321
  var SpreePayContent = (props) => {
7227
- const { className, amount, onProcess } = props;
7228
- return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("div", { className: cn("sl-spreepay", className), children: /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("div", { className: "w-full", children: [
7322
+ const { amount, onProcess } = props;
7323
+ return /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("div", { className: "w-full", children: [
7229
7324
  /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(Tabs, {}),
7230
7325
  /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(CheckoutButton, { onCheckout: onProcess, amount }),
7231
7326
  /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(SpreeLegal, {})
7232
- ] }) });
7327
+ ] });
7233
7328
  };
7234
7329
 
7330
+ // src/hooks/useKeycloakSSO.ts
7331
+ var import_react11 = require("react");
7332
+ var import_keycloak_js = __toESM(require("keycloak-js"), 1);
7333
+ var refreshAheadSeconds = 60;
7334
+ function useKeycloakSSO(config2) {
7335
+ const { url, realm, clientId, ssoPageURI, enabled } = config2;
7336
+ const initRef = (0, import_react11.useRef)(false);
7337
+ const kcRef = (0, import_react11.useRef)(null);
7338
+ const refreshTimerRef = (0, import_react11.useRef)(null);
7339
+ const [error, setError] = (0, import_react11.useState)(null);
7340
+ const [isChecking, setIsChecking] = (0, import_react11.useState)(false);
7341
+ const [accessToken, setAccessToken] = (0, import_react11.useState)(null);
7342
+ const scheduleRefresh = (0, import_react11.useCallback)(() => {
7343
+ const kc = kcRef.current;
7344
+ if (!kc || !kc.tokenParsed || !kc.tokenParsed.exp) {
7345
+ return;
7346
+ }
7347
+ const expSeconds = kc.tokenParsed.exp;
7348
+ const nowSeconds = Math.floor(Date.now() / 1e3);
7349
+ const delaySeconds = Math.max(expSeconds - nowSeconds - refreshAheadSeconds, 5);
7350
+ const delayMs = delaySeconds * 1e3;
7351
+ if (refreshTimerRef.current) clearTimeout(refreshTimerRef.current);
7352
+ refreshTimerRef.current = setTimeout(() => {
7353
+ kc.updateToken(refreshAheadSeconds).then((refreshed) => {
7354
+ if (refreshed) {
7355
+ setAccessToken(kc.token ?? null);
7356
+ scheduleRefresh();
7357
+ }
7358
+ }).catch((_) => {
7359
+ kc.login().catch(console.error);
7360
+ });
7361
+ }, delayMs);
7362
+ }, []);
7363
+ (0, import_react11.useEffect)(() => {
7364
+ if (initRef.current || !enabled) return;
7365
+ initRef.current = true;
7366
+ setIsChecking(true);
7367
+ const kc = new import_keycloak_js.default({ url, realm, clientId });
7368
+ kcRef.current = kc;
7369
+ kc.onTokenExpired = () => {
7370
+ kc.updateToken(refreshAheadSeconds).then((refreshed) => {
7371
+ if (refreshed) {
7372
+ setAccessToken(kc.token ?? null);
7373
+ scheduleRefresh();
7374
+ }
7375
+ }).catch((err) => {
7376
+ console.error("[Keycloak] onTokenExpired refresh failed", err);
7377
+ });
7378
+ };
7379
+ kc.init({
7380
+ onLoad: "check-sso",
7381
+ silentCheckSsoRedirectUri: `${window.location.origin}${ssoPageURI}`,
7382
+ silentCheckSsoFallback: true
7383
+ }).then((auth) => {
7384
+ console.log("[Keycloak] init success, authenticated=", auth);
7385
+ setAccessToken(kc.token ?? null);
7386
+ if (auth) scheduleRefresh();
7387
+ }).catch((err) => {
7388
+ setError(err);
7389
+ }).finally(() => setIsChecking(false));
7390
+ return () => {
7391
+ if (refreshTimerRef.current) clearTimeout(refreshTimerRef.current);
7392
+ };
7393
+ }, [ssoPageURI, scheduleRefresh, clientId, url, realm]);
7394
+ return { isChecking, accessToken, error };
7395
+ }
7396
+
7235
7397
  // src/SpreePay.tsx
7236
7398
  var import_jsx_runtime37 = require("react/jsx-runtime");
7237
7399
  var envConfig = {
7238
- dev: { slapiUrl: "https://slapi.dev.superlogic.com" },
7239
- stg: { slapiUrl: "https://slapi.dev.superlogic.com" },
7240
- prod: { slapiUrl: "https://slapi.dev.superlogic.com" }
7400
+ dev: {
7401
+ bookit: {
7402
+ slapiUrl: "https://slapi.dev.superlogic.com",
7403
+ keyklockUrl: "https://auth.dev.join.bookit.com",
7404
+ keyklockClientId: "oneof-next"
7405
+ },
7406
+ moca: {
7407
+ slapiUrl: "https://slapi.dev.air.shop",
7408
+ keyklockUrl: "https://login.dev.air.shop",
7409
+ keyklockClientId: "oneof-next"
7410
+ }
7411
+ },
7412
+ stg: {
7413
+ bookit: {
7414
+ slapiUrl: "https://slapi.stg.superlogic.com",
7415
+ keyklockUrl: "https://auth.stg.join.bookit.com",
7416
+ keyklockClientId: "oneof-next"
7417
+ },
7418
+ moca: {
7419
+ slapiUrl: "https://slapi.stg.superlogic.com",
7420
+ keyklockUrl: "https://login.stg.air.shop",
7421
+ keyklockClientId: "oneof-next"
7422
+ }
7423
+ },
7424
+ prod: {
7425
+ bookit: {
7426
+ slapiUrl: "https://slapi.superlogic.com",
7427
+ keyklockUrl: "https://auth.join.bookit.com",
7428
+ keyklockClientId: "oneof-next"
7429
+ },
7430
+ moca: {
7431
+ slapiUrl: "https://slapi.superlogic.com",
7432
+ keyklockUrl: "https://login.air.shop",
7433
+ keyklockClientId: "oneof-next"
7434
+ }
7435
+ }
7241
7436
  };
7242
- var SpreePay = (props) => {
7437
+ var SpreePay = ({ className, ...rest }) => {
7243
7438
  const { env } = useSpreePayEnv();
7244
- const slapiFetcher = (0, import_react11.useMemo)(
7245
- () => registerApi({
7246
- tenantId: env.tenantId,
7247
- accessToken: env.accessToken,
7248
- baseUrl: envConfig[env.environment].slapiUrl
7249
- }),
7250
- [env]
7251
- );
7252
- return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
7439
+ const environment = env?.environment || "dev";
7440
+ const tenantId = env?.tenantId || "bookit";
7441
+ const { isChecking, accessToken, error } = useKeycloakSSO({
7442
+ realm: env.tenantId,
7443
+ url: envConfig[environment][tenantId].keyklockUrl,
7444
+ clientId: envConfig[environment][tenantId].keyklockClientId,
7445
+ ssoPageURI: env.ssoPageURI,
7446
+ enabled: !env.accessToken
7447
+ });
7448
+ const slapiFetcher = (0, import_react12.useMemo)(() => {
7449
+ if (accessToken || env.accessToken) {
7450
+ return registerApi({
7451
+ accessToken: env.accessToken || accessToken,
7452
+ tenantId,
7453
+ baseUrl: envConfig[environment][tenantId].slapiUrl
7454
+ });
7455
+ }
7456
+ }, [env.accessToken, environment, tenantId, accessToken]);
7457
+ if (isChecking) {
7458
+ return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("div", { className: cn("sl-spreepay", className), children: /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("p", { className: "w-full text-center text-sm", children: "Loading..." }) });
7459
+ }
7460
+ if (error) {
7461
+ return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("div", { className: cn("sl-spreepay", className), children: /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("p", { className: "w-full text-center text-sm", children: [
7462
+ "Error: ",
7463
+ error.message
7464
+ ] }) });
7465
+ }
7466
+ return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("div", { className: cn("sl-spreepay", className), children: /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
7253
7467
  import_swr4.SWRConfig,
7254
7468
  {
7255
7469
  value: {
@@ -7258,15 +7472,15 @@ var SpreePay = (props) => {
7258
7472
  revalidateIfStale: false,
7259
7473
  revalidateOnReconnect: false
7260
7474
  },
7261
- children: /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(import_nice_modal_react6.default.Provider, { children: /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(SpreePayContent, { ...props }) })
7475
+ children: /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(import_nice_modal_react6.default.Provider, { children: /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(SpreePayContent, { ...rest }) })
7262
7476
  }
7263
- );
7477
+ ) });
7264
7478
  };
7265
7479
 
7266
7480
  // src/hooks/useCapture3DS.ts
7267
- var import_react12 = require("react");
7481
+ var import_react13 = require("react");
7268
7482
  var useCapture3DS = (searchParams) => {
7269
- (0, import_react12.useEffect)(() => {
7483
+ (0, import_react13.useEffect)(() => {
7270
7484
  if (window?.parent && searchParams?.paymentIntent) {
7271
7485
  window.parent.SP_EVENT_BUS?.emit("paymentIntent", { paymentIntent: searchParams.paymentIntent });
7272
7486
  }