@swype-org/react-sdk 0.1.27 → 0.1.29

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
@@ -1,5 +1,5 @@
1
- import { createContext, useRef, useEffect, useState, useCallback, useMemo, useContext } from 'react';
2
- import { PrivyProvider, usePrivy } from '@privy-io/react-auth';
1
+ import { createContext, useRef, useState, useCallback, useMemo, useContext, useEffect } from 'react';
2
+ import { PrivyProvider, usePrivy, useLoginWithEmail, useLoginWithSms } from '@privy-io/react-auth';
3
3
  import { createConfig, http, WagmiProvider, useConfig, useConnect, useSwitchChain } from 'wagmi';
4
4
  import { mainnet, arbitrum, base } from 'wagmi/chains';
5
5
  import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
@@ -25,9 +25,9 @@ var darkTheme = {
25
25
  textMuted: "#7fa4b0",
26
26
  textInverse: "#052027",
27
27
  border: "#2b4551",
28
- borderFocus: "#2ec4cf",
29
- accent: "#2eb6c2",
30
- accentHover: "#239ba6",
28
+ borderFocus: "#28b67a",
29
+ accent: "#28b67a",
30
+ accentHover: "#219866",
31
31
  accentText: "#ffffff",
32
32
  success: "#0f9d73",
33
33
  successBg: "#0f2f2a",
@@ -49,9 +49,9 @@ var lightTheme = {
49
49
  textMuted: "#7d97a1",
50
50
  textInverse: "#ffffff",
51
51
  border: "#d2e4ea",
52
- borderFocus: "#2eb6c2",
53
- accent: "#2eb6c2",
54
- accentHover: "#259da7",
52
+ borderFocus: "#28b67a",
53
+ accent: "#28b67a",
54
+ accentHover: "#219866",
55
55
  accentText: "#ffffff",
56
56
  success: "#0f9d73",
57
57
  successBg: "#e6f7f1",
@@ -74,26 +74,6 @@ var wagmiConfig = createConfig({
74
74
  [base.id]: http()
75
75
  }
76
76
  });
77
- var PRIVY_MODAL_CENTER_CSS = `
78
- @media (max-width: 440px) {
79
- #privy-dialog [data-headlessui-state] {
80
- position: static !important;
81
- bottom: auto !important;
82
- margin: auto !important;
83
- width: 360px !important;
84
- max-width: calc(100vw - 32px) !important;
85
- box-shadow: 0px 8px 36px rgba(55, 65, 81, 0.15) !important;
86
- border-radius: var(--privy-border-radius-lg) !important;
87
- transform: none !important;
88
- transition: opacity 100ms ease-in !important;
89
- }
90
- #privy-dialog [data-headlessui-state].entering,
91
- #privy-dialog [data-headlessui-state].leaving {
92
- opacity: 0 !important;
93
- transform: none !important;
94
- }
95
- }
96
- `;
97
77
  var SwypeContext = createContext(null);
98
78
  function SwypeProvider({
99
79
  apiBaseUrl,
@@ -104,15 +84,6 @@ function SwypeProvider({
104
84
  if (!queryClientRef.current) {
105
85
  queryClientRef.current = new QueryClient();
106
86
  }
107
- useEffect(() => {
108
- const style = document.createElement("style");
109
- style.setAttribute("data-swype", "privy-modal-center");
110
- style.textContent = PRIVY_MODAL_CENTER_CSS;
111
- document.head.appendChild(style);
112
- return () => {
113
- style.remove();
114
- };
115
- }, []);
116
87
  const [depositAmount, setDepositAmountRaw] = useState(null);
117
88
  const setDepositAmount = useCallback((amount) => {
118
89
  setDepositAmountRaw(amount);
@@ -135,6 +106,12 @@ function SwypeProvider({
135
106
  appearance: {
136
107
  theme,
137
108
  accentColor: getTheme(theme).accent
109
+ },
110
+ intl: {
111
+ defaultCountry: "US"
112
+ },
113
+ embeddedWallets: {
114
+ showWalletUIs: false
138
115
  }
139
116
  },
140
117
  children: /* @__PURE__ */ jsx(SwypeContext.Provider, { value, children })
@@ -173,6 +150,7 @@ __export(api_exports, {
173
150
  fetchAccounts: () => fetchAccounts,
174
151
  fetchAuthorizationSession: () => fetchAuthorizationSession,
175
152
  fetchChains: () => fetchChains,
153
+ fetchMerchantPublicKey: () => fetchMerchantPublicKey,
176
154
  fetchProviders: () => fetchProviders,
177
155
  fetchTransfer: () => fetchTransfer,
178
156
  fetchUserConfig: () => fetchUserConfig,
@@ -215,9 +193,13 @@ async function fetchAccounts(apiBaseUrl, token, credentialId) {
215
193
  return data.items;
216
194
  }
217
195
  async function createTransfer(apiBaseUrl, token, params) {
196
+ if (!params.merchantAuthorization) {
197
+ throw new Error("merchantAuthorization is required for transfer creation.");
198
+ }
218
199
  const body = {
219
- id: crypto.randomUUID(),
200
+ id: params.id ?? crypto.randomUUID(),
220
201
  credentialId: params.credentialId,
202
+ merchantAuthorization: params.merchantAuthorization,
221
203
  sources: [{ [params.sourceType]: params.sourceId }],
222
204
  destinations: [
223
205
  {
@@ -242,6 +224,13 @@ async function createTransfer(apiBaseUrl, token, params) {
242
224
  if (!res.ok) await throwApiError(res);
243
225
  return await res.json();
244
226
  }
227
+ async function fetchMerchantPublicKey(apiBaseUrl, merchantId) {
228
+ const res = await fetch(
229
+ `${apiBaseUrl}/v1/merchants/${encodeURIComponent(merchantId)}/public-key`
230
+ );
231
+ if (!res.ok) await throwApiError(res);
232
+ return await res.json();
233
+ }
245
234
  async function fetchTransfer(apiBaseUrl, token, transferId, authorizationSessionToken) {
246
235
  if (!token && !authorizationSessionToken) {
247
236
  throw new Error("Missing auth credentials for transfer fetch.");
@@ -813,6 +802,11 @@ async function createPasskeyCredential(params) {
813
802
  };
814
803
  }
815
804
  async function deviceHasPasskey(credentialId) {
805
+ const found = await findDevicePasskey([credentialId]);
806
+ return found != null;
807
+ }
808
+ async function findDevicePasskey(credentialIds) {
809
+ if (credentialIds.length === 0) return null;
816
810
  try {
817
811
  const challenge = new Uint8Array(32);
818
812
  crypto.getRandomValues(challenge);
@@ -821,17 +815,18 @@ async function deviceHasPasskey(credentialId) {
821
815
  publicKey: {
822
816
  challenge,
823
817
  rpId: resolvePasskeyRpId(),
824
- allowCredentials: [{
818
+ allowCredentials: credentialIds.map((id) => ({
825
819
  type: "public-key",
826
- id: base64ToBytes(credentialId)
827
- }],
820
+ id: base64ToBytes(id)
821
+ })),
828
822
  userVerification: "discouraged",
829
823
  timeout: 3e4
830
824
  }
831
825
  });
832
- return assertion != null;
826
+ if (!assertion) return null;
827
+ return toBase64(assertion.rawId);
833
828
  } catch {
834
- return false;
829
+ return null;
835
830
  }
836
831
  }
837
832
  function useTransferPolling(intervalMs = 3e3) {
@@ -2091,6 +2086,46 @@ function AdvancedSettings({
2091
2086
  ] });
2092
2087
  }
2093
2088
 
2089
+ // src/auth.ts
2090
+ var EMAIL_PATTERN = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
2091
+ var PHONE_DIGIT_PATTERN = /^\d{7,15}$/;
2092
+ function normalizePhoneNumber(rawValue) {
2093
+ const trimmed = rawValue.trim();
2094
+ if (!trimmed) return null;
2095
+ const hasExplicitCountryCode = trimmed.startsWith("+");
2096
+ const digits = trimmed.replace(/\D/g, "");
2097
+ if (!PHONE_DIGIT_PATTERN.test(digits)) return null;
2098
+ return hasExplicitCountryCode ? `+${digits}` : digits;
2099
+ }
2100
+ function normalizeAuthIdentifier(rawValue) {
2101
+ const trimmed = rawValue.trim();
2102
+ if (!trimmed) return null;
2103
+ if (EMAIL_PATTERN.test(trimmed)) {
2104
+ return {
2105
+ kind: "email",
2106
+ value: trimmed.toLowerCase()
2107
+ };
2108
+ }
2109
+ const normalizedPhoneNumber = normalizePhoneNumber(trimmed);
2110
+ if (normalizedPhoneNumber) {
2111
+ return {
2112
+ kind: "phone",
2113
+ value: normalizedPhoneNumber
2114
+ };
2115
+ }
2116
+ return null;
2117
+ }
2118
+ function maskAuthIdentifier(identifier) {
2119
+ if (identifier.kind === "email") {
2120
+ const [localPart, domain = ""] = identifier.value.split("@");
2121
+ const localPrefix = localPart.slice(0, 2);
2122
+ return `${localPrefix}${"*".repeat(Math.max(localPart.length - 2, 0))}@${domain}`;
2123
+ }
2124
+ const digits = identifier.value.replace(/\D/g, "");
2125
+ const visibleSuffix = digits.slice(-4);
2126
+ return `***-***-${visibleSuffix}`;
2127
+ }
2128
+
2094
2129
  // src/processingStatus.ts
2095
2130
  var PROCESSING_TIMEOUT_MS = 18e4;
2096
2131
  function resolvePreferredTransfer(polledTransfer, localTransfer) {
@@ -2196,10 +2231,22 @@ function SwypePayment({
2196
2231
  destination,
2197
2232
  onComplete,
2198
2233
  onError,
2199
- useWalletConnector
2234
+ useWalletConnector,
2235
+ idempotencyKey,
2236
+ merchantAuthorization
2200
2237
  }) {
2201
2238
  const { apiBaseUrl, tokens, depositAmount } = useSwypeConfig();
2202
- const { ready, authenticated, user, login, logout, getAccessToken } = usePrivy();
2239
+ const { ready, authenticated, user, logout, getAccessToken } = usePrivy();
2240
+ const {
2241
+ sendCode: sendEmailCode,
2242
+ loginWithCode: loginWithEmailCode,
2243
+ state: emailLoginState
2244
+ } = useLoginWithEmail();
2245
+ const {
2246
+ sendCode: sendSmsCode,
2247
+ loginWithCode: loginWithSmsCode,
2248
+ state: smsLoginState
2249
+ } = useLoginWithSms();
2203
2250
  const [step, setStep] = useState("login");
2204
2251
  const [error, setError] = useState(null);
2205
2252
  const [providers, setProviders] = useState([]);
@@ -2224,6 +2271,11 @@ function SwypePayment({
2224
2271
  if (typeof window === "undefined") return null;
2225
2272
  return window.localStorage.getItem(ACTIVE_CREDENTIAL_STORAGE_KEY);
2226
2273
  });
2274
+ const [authInput, setAuthInput] = useState("");
2275
+ const [verificationTarget, setVerificationTarget] = useState(
2276
+ null
2277
+ );
2278
+ const [otpCode, setOtpCode] = useState("");
2227
2279
  const [mobileFlow, setMobileFlow] = useState(false);
2228
2280
  const pollingTransferIdRef = useRef(null);
2229
2281
  const mobileSigningTransferIdRef = useRef(null);
@@ -2241,9 +2293,81 @@ function SwypePayment({
2241
2293
  setAmount(depositAmount.toString());
2242
2294
  }
2243
2295
  }, [depositAmount]);
2296
+ const resetHeadlessLogin = useCallback(() => {
2297
+ setAuthInput("");
2298
+ setVerificationTarget(null);
2299
+ setOtpCode("");
2300
+ }, []);
2301
+ const activeOtpStatus = verificationTarget?.kind === "email" ? emailLoginState.status : verificationTarget?.kind === "phone" ? smsLoginState.status : "initial";
2302
+ const activeOtpErrorMessage = verificationTarget?.kind === "email" && emailLoginState.status === "error" ? emailLoginState.error?.message ?? "Failed to continue with email." : verificationTarget?.kind === "phone" && smsLoginState.status === "error" ? smsLoginState.error?.message ?? "Failed to continue with phone number." : null;
2303
+ useEffect(() => {
2304
+ if (activeOtpErrorMessage) {
2305
+ setError(activeOtpErrorMessage);
2306
+ }
2307
+ }, [activeOtpErrorMessage]);
2308
+ const handleSendLoginCode = useCallback(async () => {
2309
+ const normalizedIdentifier = normalizeAuthIdentifier(authInput);
2310
+ if (!normalizedIdentifier) {
2311
+ setError("Enter a valid email address or phone number.");
2312
+ return;
2313
+ }
2314
+ setError(null);
2315
+ setOtpCode("");
2316
+ try {
2317
+ if (normalizedIdentifier.kind === "email") {
2318
+ await sendEmailCode({ email: normalizedIdentifier.value });
2319
+ } else {
2320
+ await sendSmsCode({ phoneNumber: normalizedIdentifier.value });
2321
+ }
2322
+ setVerificationTarget(normalizedIdentifier);
2323
+ } catch (err) {
2324
+ const msg = err instanceof Error ? err.message : "Failed to send verification code";
2325
+ setError(msg);
2326
+ }
2327
+ }, [authInput, sendEmailCode, sendSmsCode]);
2328
+ const handleVerifyLoginCode = useCallback(async () => {
2329
+ if (!verificationTarget) return;
2330
+ const trimmedCode = otpCode.trim();
2331
+ if (!/^\d{6}$/.test(trimmedCode)) {
2332
+ setError("Enter the 6-digit verification code.");
2333
+ return;
2334
+ }
2335
+ setError(null);
2336
+ try {
2337
+ if (verificationTarget.kind === "email") {
2338
+ await loginWithEmailCode({ code: trimmedCode });
2339
+ } else {
2340
+ await loginWithSmsCode({ code: trimmedCode });
2341
+ }
2342
+ } catch (err) {
2343
+ const msg = err instanceof Error ? err.message : "Failed to verify code";
2344
+ setError(msg);
2345
+ }
2346
+ }, [verificationTarget, otpCode, loginWithEmailCode, loginWithSmsCode]);
2347
+ const handleResendLoginCode = useCallback(async () => {
2348
+ if (!verificationTarget) return;
2349
+ setError(null);
2350
+ try {
2351
+ if (verificationTarget.kind === "email") {
2352
+ await sendEmailCode({ email: verificationTarget.value });
2353
+ } else {
2354
+ await sendSmsCode({ phoneNumber: verificationTarget.value });
2355
+ }
2356
+ } catch (err) {
2357
+ const msg = err instanceof Error ? err.message : "Failed to resend code";
2358
+ setError(msg);
2359
+ }
2360
+ }, [verificationTarget, sendEmailCode, sendSmsCode]);
2361
+ const handleEditIdentifier = useCallback(() => {
2362
+ setError(null);
2363
+ setVerificationTarget(null);
2364
+ setOtpCode("");
2365
+ }, []);
2244
2366
  useEffect(() => {
2245
2367
  if (!ready || !authenticated || step !== "login") return;
2246
2368
  let cancelled = false;
2369
+ setError(null);
2370
+ resetHeadlessLogin();
2247
2371
  const checkPasskey = async () => {
2248
2372
  try {
2249
2373
  const token = await getAccessToken();
@@ -2263,20 +2387,20 @@ function SwypePayment({
2263
2387
  }
2264
2388
  return;
2265
2389
  }
2266
- for (const pk of allPasskeys) {
2267
- if (cancelled) return;
2268
- if (await deviceHasPasskey(pk.credentialId)) {
2269
- setActiveCredentialId(pk.credentialId);
2270
- window.localStorage.setItem(ACTIVE_CREDENTIAL_STORAGE_KEY, pk.credentialId);
2271
- if (depositAmount != null && depositAmount > 0) {
2272
- setStep("ready");
2273
- } else {
2274
- setStep("enter-amount");
2275
- }
2276
- return;
2390
+ if (cancelled) return;
2391
+ const credentialIds = allPasskeys.map((p) => p.credentialId);
2392
+ const matched = await findDevicePasskey(credentialIds);
2393
+ if (cancelled) return;
2394
+ if (matched) {
2395
+ setActiveCredentialId(matched);
2396
+ window.localStorage.setItem(ACTIVE_CREDENTIAL_STORAGE_KEY, matched);
2397
+ if (depositAmount != null && depositAmount > 0) {
2398
+ setStep("ready");
2399
+ } else {
2400
+ setStep("enter-amount");
2277
2401
  }
2402
+ return;
2278
2403
  }
2279
- if (cancelled) return;
2280
2404
  setStep("register-passkey");
2281
2405
  } catch {
2282
2406
  if (!cancelled) {
@@ -2292,7 +2416,16 @@ function SwypePayment({
2292
2416
  return () => {
2293
2417
  cancelled = true;
2294
2418
  };
2295
- }, [ready, authenticated, step, depositAmount, apiBaseUrl, getAccessToken, activeCredentialId]);
2419
+ }, [
2420
+ ready,
2421
+ authenticated,
2422
+ step,
2423
+ depositAmount,
2424
+ apiBaseUrl,
2425
+ getAccessToken,
2426
+ activeCredentialId,
2427
+ resetHeadlessLogin
2428
+ ]);
2296
2429
  const loadingDataRef = useRef(false);
2297
2430
  useEffect(() => {
2298
2431
  if (!authenticated) return;
@@ -2510,7 +2643,9 @@ function SwypePayment({
2510
2643
  }
2511
2644
  }
2512
2645
  const t = await createTransfer(apiBaseUrl, token, {
2646
+ id: idempotencyKey,
2513
2647
  credentialId: activeCredentialId,
2648
+ merchantAuthorization,
2514
2649
  sourceType: effectiveSourceType,
2515
2650
  sourceId: effectiveSourceId,
2516
2651
  destination,
@@ -2600,7 +2735,8 @@ function SwypePayment({
2600
2735
  processingStartedAtRef.current = null;
2601
2736
  pollingTransferIdRef.current = null;
2602
2737
  mobileSigningTransferIdRef.current = null;
2603
- }, [logout, polling, depositAmount]);
2738
+ resetHeadlessLogin();
2739
+ }, [logout, polling, depositAmount, resetHeadlessLogin]);
2604
2740
  const handleConnectNewAccount = (providerId) => {
2605
2741
  setSelectedProviderId(providerId);
2606
2742
  setSelectedAccountId(null);
@@ -2637,7 +2773,7 @@ function SwypePayment({
2637
2773
  cursor: "pointer",
2638
2774
  transition: "filter 0.15s ease, transform 0.15s ease",
2639
2775
  fontFamily: "inherit",
2640
- boxShadow: "0 8px 18px rgba(46, 182, 194, 0.28)"
2776
+ boxShadow: "0 8px 18px rgba(40, 182, 122, 0.28)"
2641
2777
  };
2642
2778
  const btnDisabled = {
2643
2779
  ...btnPrimary,
@@ -2649,6 +2785,33 @@ function SwypePayment({
2649
2785
  background: tokens.bgCard,
2650
2786
  color: tokens.textSecondary,
2651
2787
  border: `1px solid ${tokens.border}`});
2788
+ const textFieldStyle = {
2789
+ width: "100%",
2790
+ padding: "15px 16px",
2791
+ borderRadius: "16px",
2792
+ border: `1px solid ${tokens.border}`,
2793
+ background: tokens.bgInput,
2794
+ color: tokens.text,
2795
+ fontSize: "0.98rem",
2796
+ fontFamily: "inherit",
2797
+ outline: "none",
2798
+ boxSizing: "border-box"
2799
+ };
2800
+ const authCaptionStyle = {
2801
+ fontSize: "0.84rem",
2802
+ color: tokens.textSecondary,
2803
+ margin: 0,
2804
+ lineHeight: 1.5
2805
+ };
2806
+ const authTertiaryButtonStyle = {
2807
+ background: "transparent",
2808
+ border: "none",
2809
+ color: tokens.textMuted,
2810
+ cursor: "pointer",
2811
+ fontFamily: "inherit",
2812
+ fontSize: "0.84rem",
2813
+ padding: 0
2814
+ };
2652
2815
  const errorStyle = {
2653
2816
  background: tokens.errorBg,
2654
2817
  border: `1px solid ${tokens.error}66`,
@@ -2709,6 +2872,7 @@ function SwypePayment({
2709
2872
  ]
2710
2873
  }
2711
2874
  );
2875
+ const placeholderProviders = ["A", "B", "C", "D", "E"];
2712
2876
  const displayedSelectSourceChoices = selectSourceChoices.length > 0 ? selectSourceChoices : [
2713
2877
  {
2714
2878
  chainName: "Base",
@@ -2744,43 +2908,186 @@ function SwypePayment({
2744
2908
  return /* @__PURE__ */ jsx("div", { style: cardStyle, children: /* @__PURE__ */ jsx("div", { style: { textAlign: "center", padding: "24px 0" }, children: /* @__PURE__ */ jsx(Spinner, { label: "Initializing..." }) }) });
2745
2909
  }
2746
2910
  if (step === "login" && !authenticated) {
2911
+ const isAwaitingOtp = verificationTarget !== null;
2912
+ const isSendingCode = activeOtpStatus === "sending-code";
2913
+ const isSubmittingCode = activeOtpStatus === "submitting-code";
2914
+ const continueDisabled = authInput.trim().length === 0 || isSendingCode || isSubmittingCode;
2915
+ const verifyDisabled = otpCode.trim().length !== 6 || isSubmittingCode;
2747
2916
  return /* @__PURE__ */ jsx("div", { style: cardStyle, children: /* @__PURE__ */ jsxs("div", { style: { textAlign: "center" }, children: [
2748
- /* @__PURE__ */ jsxs(
2749
- "svg",
2917
+ /* @__PURE__ */ jsx(
2918
+ "div",
2750
2919
  {
2751
- width: "48",
2752
- height: "48",
2753
- viewBox: "0 0 48 48",
2754
- fill: "none",
2755
- style: { margin: "0 auto 16px" },
2756
- children: [
2757
- /* @__PURE__ */ jsx("rect", { width: "48", height: "48", rx: "12", fill: tokens.accent + "20" }),
2758
- /* @__PURE__ */ jsx(
2759
- "path",
2760
- {
2761
- d: "M24 14v20M14 24h20",
2762
- stroke: tokens.accent,
2763
- strokeWidth: "2.5",
2764
- strokeLinecap: "round"
2765
- }
2766
- )
2767
- ]
2920
+ style: {
2921
+ width: 56,
2922
+ height: 56,
2923
+ borderRadius: 14,
2924
+ background: tokens.accent,
2925
+ color: tokens.accentText,
2926
+ display: "flex",
2927
+ alignItems: "center",
2928
+ justifyContent: "center",
2929
+ fontWeight: 700,
2930
+ fontSize: "1.35rem",
2931
+ margin: "0 auto 24px",
2932
+ boxShadow: "0 10px 20px rgba(40, 182, 122, 0.22)"
2933
+ },
2934
+ children: "S"
2935
+ }
2936
+ ),
2937
+ /* @__PURE__ */ jsx(
2938
+ "h2",
2939
+ {
2940
+ style: {
2941
+ ...headingStyle,
2942
+ fontSize: "2.05rem",
2943
+ lineHeight: 1.15,
2944
+ marginBottom: "10px",
2945
+ whiteSpace: "pre-line"
2946
+ },
2947
+ children: isAwaitingOtp ? "Enter your code." : "One-time setup.\nOne-tap deposits after."
2768
2948
  }
2769
2949
  ),
2770
- /* @__PURE__ */ jsx("h2", { style: { ...headingStyle, marginBottom: "8px" }, children: "Pay with Swype" }),
2771
2950
  /* @__PURE__ */ jsx(
2772
2951
  "p",
2773
2952
  {
2774
2953
  style: {
2775
- fontSize: "0.875rem",
2776
- color: tokens.textSecondary,
2777
- margin: "0 0 24px 0",
2778
- lineHeight: 1.5
2954
+ ...authCaptionStyle,
2955
+ margin: "0 0 26px 0",
2956
+ whiteSpace: "pre-line"
2779
2957
  },
2780
- children: "Connect your account to continue"
2958
+ children: isAwaitingOtp ? `We sent a 6-digit code to ${maskAuthIdentifier(verificationTarget)}.` : "Protected by Face ID."
2781
2959
  }
2782
2960
  ),
2783
- /* @__PURE__ */ jsx("button", { style: btnPrimary, onClick: login, children: "Connect to Swype" })
2961
+ error && /* @__PURE__ */ jsx("div", { style: errorStyle, children: error }),
2962
+ isAwaitingOtp ? /* @__PURE__ */ jsxs(Fragment, { children: [
2963
+ /* @__PURE__ */ jsx(
2964
+ "input",
2965
+ {
2966
+ id: "swype-login-code",
2967
+ type: "text",
2968
+ inputMode: "numeric",
2969
+ autoComplete: "one-time-code",
2970
+ placeholder: "Verification code",
2971
+ value: otpCode,
2972
+ onChange: (event) => {
2973
+ setOtpCode(event.target.value.replace(/\D/g, "").slice(0, 6));
2974
+ },
2975
+ style: {
2976
+ ...textFieldStyle,
2977
+ textAlign: "center",
2978
+ letterSpacing: "0.24em",
2979
+ marginBottom: "14px"
2980
+ }
2981
+ }
2982
+ ),
2983
+ /* @__PURE__ */ jsx(
2984
+ "button",
2985
+ {
2986
+ style: verifyDisabled ? btnDisabled : btnPrimary,
2987
+ disabled: verifyDisabled,
2988
+ onClick: handleVerifyLoginCode,
2989
+ children: isSubmittingCode ? "Verifying..." : "Continue"
2990
+ }
2991
+ ),
2992
+ /* @__PURE__ */ jsxs(
2993
+ "div",
2994
+ {
2995
+ style: {
2996
+ display: "flex",
2997
+ justifyContent: "space-between",
2998
+ gap: "12px",
2999
+ marginTop: "14px"
3000
+ },
3001
+ children: [
3002
+ /* @__PURE__ */ jsx("button", { type: "button", style: authTertiaryButtonStyle, onClick: handleEditIdentifier, children: "Use a different email or phone" }),
3003
+ /* @__PURE__ */ jsx(
3004
+ "button",
3005
+ {
3006
+ type: "button",
3007
+ style: authTertiaryButtonStyle,
3008
+ onClick: handleResendLoginCode,
3009
+ disabled: isSendingCode || isSubmittingCode,
3010
+ children: isSendingCode ? "Sending..." : "Resend code"
3011
+ }
3012
+ )
3013
+ ]
3014
+ }
3015
+ )
3016
+ ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
3017
+ /* @__PURE__ */ jsx(
3018
+ "input",
3019
+ {
3020
+ id: "swype-login-identifier",
3021
+ type: "text",
3022
+ inputMode: "text",
3023
+ autoComplete: "username",
3024
+ placeholder: "Email or phone number",
3025
+ value: authInput,
3026
+ onChange: (event) => setAuthInput(event.target.value),
3027
+ style: { ...textFieldStyle, marginBottom: "14px" }
3028
+ }
3029
+ ),
3030
+ /* @__PURE__ */ jsx(
3031
+ "button",
3032
+ {
3033
+ style: continueDisabled ? btnDisabled : btnPrimary,
3034
+ disabled: continueDisabled,
3035
+ onClick: handleSendLoginCode,
3036
+ children: isSendingCode ? "Sending code..." : "Continue"
3037
+ }
3038
+ ),
3039
+ /* @__PURE__ */ jsxs(
3040
+ "div",
3041
+ {
3042
+ style: {
3043
+ display: "flex",
3044
+ alignItems: "center",
3045
+ gap: "10px",
3046
+ margin: "22px 0 14px",
3047
+ color: tokens.textMuted,
3048
+ fontSize: "0.82rem"
3049
+ },
3050
+ children: [
3051
+ /* @__PURE__ */ jsx("div", { style: { flex: 1, height: 1, background: tokens.border } }),
3052
+ /* @__PURE__ */ jsx("span", { children: "works with" }),
3053
+ /* @__PURE__ */ jsx("div", { style: { flex: 1, height: 1, background: tokens.border } })
3054
+ ]
3055
+ }
3056
+ ),
3057
+ /* @__PURE__ */ jsx(
3058
+ "div",
3059
+ {
3060
+ "aria-label": "Works with placeholder providers",
3061
+ style: {
3062
+ display: "flex",
3063
+ justifyContent: "center",
3064
+ gap: "12px",
3065
+ marginBottom: "18px"
3066
+ },
3067
+ children: placeholderProviders.map((providerLabel) => /* @__PURE__ */ jsx(
3068
+ "div",
3069
+ {
3070
+ style: {
3071
+ width: 34,
3072
+ height: 34,
3073
+ borderRadius: 999,
3074
+ border: `1px solid ${tokens.border}`,
3075
+ background: tokens.bgInput,
3076
+ color: tokens.textMuted,
3077
+ display: "flex",
3078
+ alignItems: "center",
3079
+ justifyContent: "center",
3080
+ fontSize: "0.78rem",
3081
+ fontWeight: 600
3082
+ },
3083
+ children: providerLabel
3084
+ },
3085
+ providerLabel
3086
+ ))
3087
+ }
3088
+ ),
3089
+ /* @__PURE__ */ jsx("p", { style: { ...authCaptionStyle, color: tokens.textMuted }, children: "Powered by Swype. Non-custodial." })
3090
+ ] })
2784
3091
  ] }) });
2785
3092
  }
2786
3093
  if (step === "register-passkey") {
@@ -3543,6 +3850,6 @@ function SwypePayment({
3543
3850
  return null;
3544
3851
  }
3545
3852
 
3546
- export { SwypePayment, SwypeProvider, createPasskeyCredential, darkTheme, deviceHasPasskey, getTheme, lightTheme, api_exports as swypeApi, useAuthorizationExecutor, useSwypeConfig, useSwypeDepositAmount, useTransferPolling, useTransferSigning };
3853
+ export { SwypePayment, SwypeProvider, createPasskeyCredential, darkTheme, deviceHasPasskey, findDevicePasskey, getTheme, lightTheme, api_exports as swypeApi, useAuthorizationExecutor, useSwypeConfig, useSwypeDepositAmount, useTransferPolling, useTransferSigning };
3547
3854
  //# sourceMappingURL=index.js.map
3548
3855
  //# sourceMappingURL=index.js.map