@swype-org/react-sdk 0.1.84 → 0.1.85

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.d.cts CHANGED
@@ -199,7 +199,7 @@ interface UserConfig {
199
199
  /** Theme mode */
200
200
  type ThemeMode = 'light' | 'dark';
201
201
  /** Steps in the payment flow */
202
- type PaymentStep = 'login' | 'otp-verify' | 'create-passkey' | 'wallet-picker' | 'open-wallet' | 'confirm-sign' | 'deposit' | 'low-balance' | 'processing' | 'select-source' | 'success';
202
+ type PaymentStep = 'login' | 'otp-verify' | 'create-passkey' | 'verify-passkey' | 'wallet-picker' | 'open-wallet' | 'confirm-sign' | 'deposit' | 'low-balance' | 'processing' | 'select-source' | 'success';
203
203
  /** User-selected advanced settings for chain/asset override */
204
204
  interface AdvancedSettings {
205
205
  /** Override asset (e.g. 'USDC', 'USDT'). Null = let backend decide. */
@@ -453,8 +453,30 @@ declare function createPasskeyViaPopup(options: PasskeyPopupOptions, existingCre
453
453
  credentialId: string;
454
454
  publicKey: string;
455
455
  }>;
456
+ interface PasskeyVerifyPopupOptions {
457
+ credentialIds: string[];
458
+ rpId: string;
459
+ /** Populated by `findDevicePasskeyViaPopup`; not set by callers. */
460
+ channelId?: string;
461
+ }
462
+ /**
463
+ * Opens a same-origin pop-up window on the Swype domain to check whether
464
+ * any of the given passkey credential IDs exist on this device.
465
+ *
466
+ * Used as a fallback when Safari blocks `navigator.credentials.get()`
467
+ * inside a cross-origin iframe. The popup runs on the Swype domain where
468
+ * the rpId matches, so WebAuthn works.
469
+ *
470
+ * Must be called from a user-gesture handler (e.g. button click) to
471
+ * avoid the browser's pop-up blocker.
472
+ *
473
+ * @returns The matching credential ID, or `null` if none matched or the
474
+ * popup was closed before completing.
475
+ */
476
+ declare function findDevicePasskeyViaPopup(options: PasskeyVerifyPopupOptions): Promise<string | null>;
456
477
 
457
478
  type AccessTokenGetter = () => Promise<string | null | undefined>;
479
+ declare function resolvePasskeyRpId(): string;
458
480
  /**
459
481
  * Creates a WebAuthn passkey credential.
460
482
  * Used for upfront passkey registration before the authorization flow.
@@ -726,4 +748,4 @@ interface AdvancedSourceScreenProps {
726
748
  }
727
749
  declare function AdvancedSourceScreen({ choices, selectedChainName, selectedTokenSymbol, onSelectSource, onBack, }: AdvancedSourceScreenProps): react_jsx_runtime.JSX.Element;
728
750
 
729
- export { type Account, type ActionExecutionResult, type AdvancedSettings, AdvancedSourceScreen, type Amount, type AuthorizationAction, type AuthorizationSession, type AuthorizationSessionDetail, type Chain, CreatePasskeyScreen, type Destination, type ErrorResponse, IconCircle, InfoBanner, type ListResponse, type MerchantAuthorization, type MerchantPublicKey, OutlineButton, PasskeyIframeBlockedError, type PaymentStep, PoweredByFooter, PrimaryButton, type Provider, ScreenHeader, ScreenLayout, SelectSourceScreen, SettingsMenu, SetupScreen, type SourceOption, type SourceSelection, type SourceType, Spinner, type StepItem, StepList, SwypePayment, type SwypePaymentProps, SwypeProvider, type SwypeProviderProps, type ThemeMode, type ThemeTokens, type TokenBalance, type Transfer, type TransferDestination, type UserConfig, type Wallet, type WalletSource, type WalletToken, buildPasskeyPopupOptions, createPasskeyCredential, createPasskeyViaPopup, darkTheme, deviceHasPasskey, findDevicePasskey, getTheme, lightTheme, api as swypeApi, useAuthorizationExecutor, useSwypeConfig, useSwypeDepositAmount, useTransferPolling, useTransferSigning };
751
+ export { type Account, type ActionExecutionResult, type AdvancedSettings, AdvancedSourceScreen, type Amount, type AuthorizationAction, type AuthorizationSession, type AuthorizationSessionDetail, type Chain, CreatePasskeyScreen, type Destination, type ErrorResponse, IconCircle, InfoBanner, type ListResponse, type MerchantAuthorization, type MerchantPublicKey, OutlineButton, PasskeyIframeBlockedError, type PaymentStep, PoweredByFooter, PrimaryButton, type Provider, ScreenHeader, ScreenLayout, SelectSourceScreen, SettingsMenu, SetupScreen, type SourceOption, type SourceSelection, type SourceType, Spinner, type StepItem, StepList, SwypePayment, type SwypePaymentProps, SwypeProvider, type SwypeProviderProps, type ThemeMode, type ThemeTokens, type TokenBalance, type Transfer, type TransferDestination, type UserConfig, type Wallet, type WalletSource, type WalletToken, buildPasskeyPopupOptions, createPasskeyCredential, createPasskeyViaPopup, darkTheme, deviceHasPasskey, findDevicePasskey, findDevicePasskeyViaPopup, getTheme, lightTheme, resolvePasskeyRpId, api as swypeApi, useAuthorizationExecutor, useSwypeConfig, useSwypeDepositAmount, useTransferPolling, useTransferSigning };
package/dist/index.d.ts CHANGED
@@ -199,7 +199,7 @@ interface UserConfig {
199
199
  /** Theme mode */
200
200
  type ThemeMode = 'light' | 'dark';
201
201
  /** Steps in the payment flow */
202
- type PaymentStep = 'login' | 'otp-verify' | 'create-passkey' | 'wallet-picker' | 'open-wallet' | 'confirm-sign' | 'deposit' | 'low-balance' | 'processing' | 'select-source' | 'success';
202
+ type PaymentStep = 'login' | 'otp-verify' | 'create-passkey' | 'verify-passkey' | 'wallet-picker' | 'open-wallet' | 'confirm-sign' | 'deposit' | 'low-balance' | 'processing' | 'select-source' | 'success';
203
203
  /** User-selected advanced settings for chain/asset override */
204
204
  interface AdvancedSettings {
205
205
  /** Override asset (e.g. 'USDC', 'USDT'). Null = let backend decide. */
@@ -453,8 +453,30 @@ declare function createPasskeyViaPopup(options: PasskeyPopupOptions, existingCre
453
453
  credentialId: string;
454
454
  publicKey: string;
455
455
  }>;
456
+ interface PasskeyVerifyPopupOptions {
457
+ credentialIds: string[];
458
+ rpId: string;
459
+ /** Populated by `findDevicePasskeyViaPopup`; not set by callers. */
460
+ channelId?: string;
461
+ }
462
+ /**
463
+ * Opens a same-origin pop-up window on the Swype domain to check whether
464
+ * any of the given passkey credential IDs exist on this device.
465
+ *
466
+ * Used as a fallback when Safari blocks `navigator.credentials.get()`
467
+ * inside a cross-origin iframe. The popup runs on the Swype domain where
468
+ * the rpId matches, so WebAuthn works.
469
+ *
470
+ * Must be called from a user-gesture handler (e.g. button click) to
471
+ * avoid the browser's pop-up blocker.
472
+ *
473
+ * @returns The matching credential ID, or `null` if none matched or the
474
+ * popup was closed before completing.
475
+ */
476
+ declare function findDevicePasskeyViaPopup(options: PasskeyVerifyPopupOptions): Promise<string | null>;
456
477
 
457
478
  type AccessTokenGetter = () => Promise<string | null | undefined>;
479
+ declare function resolvePasskeyRpId(): string;
458
480
  /**
459
481
  * Creates a WebAuthn passkey credential.
460
482
  * Used for upfront passkey registration before the authorization flow.
@@ -726,4 +748,4 @@ interface AdvancedSourceScreenProps {
726
748
  }
727
749
  declare function AdvancedSourceScreen({ choices, selectedChainName, selectedTokenSymbol, onSelectSource, onBack, }: AdvancedSourceScreenProps): react_jsx_runtime.JSX.Element;
728
750
 
729
- export { type Account, type ActionExecutionResult, type AdvancedSettings, AdvancedSourceScreen, type Amount, type AuthorizationAction, type AuthorizationSession, type AuthorizationSessionDetail, type Chain, CreatePasskeyScreen, type Destination, type ErrorResponse, IconCircle, InfoBanner, type ListResponse, type MerchantAuthorization, type MerchantPublicKey, OutlineButton, PasskeyIframeBlockedError, type PaymentStep, PoweredByFooter, PrimaryButton, type Provider, ScreenHeader, ScreenLayout, SelectSourceScreen, SettingsMenu, SetupScreen, type SourceOption, type SourceSelection, type SourceType, Spinner, type StepItem, StepList, SwypePayment, type SwypePaymentProps, SwypeProvider, type SwypeProviderProps, type ThemeMode, type ThemeTokens, type TokenBalance, type Transfer, type TransferDestination, type UserConfig, type Wallet, type WalletSource, type WalletToken, buildPasskeyPopupOptions, createPasskeyCredential, createPasskeyViaPopup, darkTheme, deviceHasPasskey, findDevicePasskey, getTheme, lightTheme, api as swypeApi, useAuthorizationExecutor, useSwypeConfig, useSwypeDepositAmount, useTransferPolling, useTransferSigning };
751
+ export { type Account, type ActionExecutionResult, type AdvancedSettings, AdvancedSourceScreen, type Amount, type AuthorizationAction, type AuthorizationSession, type AuthorizationSessionDetail, type Chain, CreatePasskeyScreen, type Destination, type ErrorResponse, IconCircle, InfoBanner, type ListResponse, type MerchantAuthorization, type MerchantPublicKey, OutlineButton, PasskeyIframeBlockedError, type PaymentStep, PoweredByFooter, PrimaryButton, type Provider, ScreenHeader, ScreenLayout, SelectSourceScreen, SettingsMenu, SetupScreen, type SourceOption, type SourceSelection, type SourceType, Spinner, type StepItem, StepList, SwypePayment, type SwypePaymentProps, SwypeProvider, type SwypeProviderProps, type ThemeMode, type ThemeTokens, type TokenBalance, type Transfer, type TransferDestination, type UserConfig, type Wallet, type WalletSource, type WalletToken, buildPasskeyPopupOptions, createPasskeyCredential, createPasskeyViaPopup, darkTheme, deviceHasPasskey, findDevicePasskey, findDevicePasskeyViaPopup, getTheme, lightTheme, resolvePasskeyRpId, api as swypeApi, useAuthorizationExecutor, useSwypeConfig, useSwypeDepositAmount, useTransferPolling, useTransferSigning };
package/dist/index.js CHANGED
@@ -785,6 +785,66 @@ function createPasskeyViaPopup(options, existingCredentialIds = []) {
785
785
  }
786
786
  });
787
787
  }
788
+ var VERIFY_POPUP_TIMEOUT_MS = 6e4;
789
+ function findDevicePasskeyViaPopup(options) {
790
+ return new Promise((resolve, reject) => {
791
+ const channelId = `swype-pv-${Date.now()}-${Math.random().toString(36).slice(2)}`;
792
+ const payload = { ...options, channelId };
793
+ const encoded = btoa(JSON.stringify(payload));
794
+ const popupUrl = `${window.location.origin}/passkey-verify#${encoded}`;
795
+ const popup = window.open(popupUrl, "swype-passkey-verify");
796
+ if (!popup) {
797
+ reject(new Error("Pop-up blocked. Please allow pop-ups for this site and try again."));
798
+ return;
799
+ }
800
+ let settled = false;
801
+ const channel = typeof BroadcastChannel !== "undefined" ? new BroadcastChannel(channelId) : null;
802
+ const timer = setTimeout(() => {
803
+ cleanup();
804
+ resolve(null);
805
+ }, VERIFY_POPUP_TIMEOUT_MS);
806
+ const closedPoll = setInterval(() => {
807
+ if (popup.closed && !settled) {
808
+ clearInterval(closedPoll);
809
+ setTimeout(() => {
810
+ if (!settled) {
811
+ cleanup();
812
+ resolve(null);
813
+ }
814
+ }, POPUP_CLOSED_GRACE_MS);
815
+ }
816
+ }, POPUP_CLOSED_POLL_MS);
817
+ function handleResult(data) {
818
+ if (settled) return;
819
+ if (!data || typeof data !== "object") return;
820
+ if (data.type !== "swype:passkey-verify-result") return;
821
+ settled = true;
822
+ cleanup();
823
+ if (data.error) {
824
+ resolve(null);
825
+ } else if (data.result && typeof data.result === "object") {
826
+ const result = data.result;
827
+ resolve(result.credentialId ?? null);
828
+ } else {
829
+ resolve(null);
830
+ }
831
+ }
832
+ if (channel) {
833
+ channel.onmessage = (event) => handleResult(event.data);
834
+ }
835
+ const postMessageHandler = (event) => {
836
+ if (event.source !== popup) return;
837
+ handleResult(event.data);
838
+ };
839
+ window.addEventListener("message", postMessageHandler);
840
+ function cleanup() {
841
+ clearTimeout(timer);
842
+ clearInterval(closedPoll);
843
+ window.removeEventListener("message", postMessageHandler);
844
+ channel?.close();
845
+ }
846
+ });
847
+ }
788
848
  async function checkServerForNewPasskey(authToken, apiBaseUrl, existingCredentialIds) {
789
849
  if (!authToken || !apiBaseUrl) return null;
790
850
  const res = await fetch(`${apiBaseUrl}/v1/users/config`, {
@@ -2770,6 +2830,72 @@ var errorBannerStyle2 = (tokens) => ({
2770
2830
  width: "100%",
2771
2831
  textAlign: "left"
2772
2832
  });
2833
+ function VerifyPasskeyScreen({
2834
+ onVerify,
2835
+ onBack,
2836
+ verifying,
2837
+ error
2838
+ }) {
2839
+ const { tokens } = useSwypeConfig();
2840
+ return /* @__PURE__ */ jsxs(
2841
+ ScreenLayout,
2842
+ {
2843
+ footer: /* @__PURE__ */ jsxs(Fragment, { children: [
2844
+ /* @__PURE__ */ jsx(PrimaryButton, { onClick: onVerify, disabled: verifying, loading: verifying, children: "Verify passkey" }),
2845
+ /* @__PURE__ */ jsx(PoweredByFooter, {})
2846
+ ] }),
2847
+ children: [
2848
+ /* @__PURE__ */ jsx(ScreenHeader, { onBack }),
2849
+ /* @__PURE__ */ jsxs("div", { style: contentStyle4, children: [
2850
+ /* @__PURE__ */ jsx(IconCircle, { variant: "accent", size: 64, children: /* @__PURE__ */ jsxs("svg", { width: "36", height: "36", viewBox: "0 0 24 24", fill: "none", children: [
2851
+ /* @__PURE__ */ jsx("rect", { x: "4", y: "4", width: "16", height: "16", rx: "3", stroke: tokens.accent, strokeWidth: "1.5", strokeDasharray: "3 2" }),
2852
+ /* @__PURE__ */ jsx("circle", { cx: "9", cy: "10", r: "1", fill: tokens.accent }),
2853
+ /* @__PURE__ */ jsx("circle", { cx: "15", cy: "10", r: "1", fill: tokens.accent }),
2854
+ /* @__PURE__ */ jsx("path", { d: "M9 14c0 1.5 1.34 2.5 3 2.5s3-1 3-2.5", stroke: tokens.accent, strokeWidth: "1.2", strokeLinecap: "round" })
2855
+ ] }) }),
2856
+ /* @__PURE__ */ jsx("h2", { style: headingStyle4(tokens.text), children: "Verify your passkey" }),
2857
+ /* @__PURE__ */ jsx("p", { style: subtitleStyle4(tokens.textSecondary), children: "Your browser requires a separate window to verify your passkey. Tap the button below to continue." }),
2858
+ error && /* @__PURE__ */ jsx("div", { style: errorBannerStyle3(tokens), children: error }),
2859
+ /* @__PURE__ */ jsx(InfoBanner, { children: "Your passkey is stored securely on your device. Swype never sees your biometric data." })
2860
+ ] })
2861
+ ]
2862
+ }
2863
+ );
2864
+ }
2865
+ var contentStyle4 = {
2866
+ textAlign: "center",
2867
+ flex: 1,
2868
+ display: "flex",
2869
+ flexDirection: "column",
2870
+ alignItems: "center",
2871
+ paddingTop: 32
2872
+ };
2873
+ var headingStyle4 = (color) => ({
2874
+ fontSize: "1.45rem",
2875
+ fontWeight: 700,
2876
+ letterSpacing: "-0.02em",
2877
+ color,
2878
+ margin: "24px 0 8px"
2879
+ });
2880
+ var subtitleStyle4 = (color) => ({
2881
+ fontSize: "0.9rem",
2882
+ color,
2883
+ margin: "0 0 28px",
2884
+ lineHeight: 1.5,
2885
+ maxWidth: 280
2886
+ });
2887
+ var errorBannerStyle3 = (tokens) => ({
2888
+ background: tokens.errorBg,
2889
+ border: `1px solid ${tokens.error}66`,
2890
+ borderRadius: 16,
2891
+ padding: "11px 14px",
2892
+ color: tokens.error,
2893
+ fontSize: "0.84rem",
2894
+ marginBottom: 14,
2895
+ lineHeight: 1.5,
2896
+ width: "100%",
2897
+ textAlign: "left"
2898
+ });
2773
2899
  var WALLET_EMOJIS = {
2774
2900
  rabby: "\u{1F430}",
2775
2901
  ora: "\u2666\uFE0F",
@@ -2812,8 +2938,8 @@ function WalletPickerScreen({
2812
2938
  children: [
2813
2939
  /* @__PURE__ */ jsx(ScreenHeader, { title: "Set up Swype", onBack }),
2814
2940
  hasPending && /* @__PURE__ */ jsxs(Fragment, { children: [
2815
- /* @__PURE__ */ jsx("h2", { style: headingStyle4(tokens.text), children: "Continue where you left off" }),
2816
- /* @__PURE__ */ jsx("p", { style: subtitleStyle4(tokens.textSecondary), children: "You have a wallet that still needs setup" }),
2941
+ /* @__PURE__ */ jsx("h2", { style: headingStyle5(tokens.text), children: "Continue where you left off" }),
2942
+ /* @__PURE__ */ jsx("p", { style: subtitleStyle5(tokens.textSecondary), children: "You have a wallet that still needs setup" }),
2817
2943
  /* @__PURE__ */ jsx("div", { style: pendingListStyle, children: pendingConnections.map((acct) => {
2818
2944
  const wallet = acct.wallets[0];
2819
2945
  const address = wallet ? truncateAddress(wallet.name) : void 0;
@@ -2853,8 +2979,8 @@ function WalletPickerScreen({
2853
2979
  /* @__PURE__ */ jsx("div", { style: dividerStyle2(tokens.border), children: /* @__PURE__ */ jsx("span", { style: dividerTextStyle(tokens.textMuted), children: "Or connect a new wallet" }) })
2854
2980
  ] }),
2855
2981
  !hasPending && /* @__PURE__ */ jsxs(Fragment, { children: [
2856
- /* @__PURE__ */ jsx("h2", { style: headingStyle4(tokens.text), children: "Where are your stablecoins?" }),
2857
- /* @__PURE__ */ jsx("p", { style: subtitleStyle4(tokens.textSecondary), children: "Select the wallet you want to deposit from" })
2982
+ /* @__PURE__ */ jsx("h2", { style: headingStyle5(tokens.text), children: "Where are your stablecoins?" }),
2983
+ /* @__PURE__ */ jsx("p", { style: subtitleStyle5(tokens.textSecondary), children: "Select the wallet you want to deposit from" })
2858
2984
  ] }),
2859
2985
  /* @__PURE__ */ jsxs("div", { style: gridStyle, children: [
2860
2986
  displayProviders.map((p) => {
@@ -2907,14 +3033,14 @@ function WalletPickerScreen({
2907
3033
  }
2908
3034
  );
2909
3035
  }
2910
- var headingStyle4 = (color) => ({
3036
+ var headingStyle5 = (color) => ({
2911
3037
  fontSize: "1.35rem",
2912
3038
  fontWeight: 700,
2913
3039
  letterSpacing: "-0.02em",
2914
3040
  color,
2915
3041
  margin: "8px 0 4px"
2916
3042
  });
2917
- var subtitleStyle4 = (color) => ({
3043
+ var subtitleStyle5 = (color) => ({
2918
3044
  fontSize: "0.88rem",
2919
3045
  color,
2920
3046
  margin: "0 0 24px"
@@ -3090,9 +3216,9 @@ function SetupScreen({
3090
3216
  ] }),
3091
3217
  children: [
3092
3218
  /* @__PURE__ */ jsx(ScreenHeader, { title: "Swype Setup", onBack, right: /* @__PURE__ */ jsx(SettingsMenu, { onLogout }) }),
3093
- /* @__PURE__ */ jsx("h2", { style: headingStyle5(tokens.text), children: "Set up One-Tap deposits" }),
3094
- /* @__PURE__ */ jsx("p", { style: subtitleStyle5(tokens.textSecondary), children: "Set your limit for instant deposits. Like a contactless card \u2014 you choose the max." }),
3095
- error && /* @__PURE__ */ jsx("div", { style: errorBannerStyle3(tokens), children: error }),
3219
+ /* @__PURE__ */ jsx("h2", { style: headingStyle6(tokens.text), children: "Set up One-Tap deposits" }),
3220
+ /* @__PURE__ */ jsx("p", { style: subtitleStyle6(tokens.textSecondary), children: "Set your limit for instant deposits. Like a contactless card \u2014 you choose the max." }),
3221
+ error && /* @__PURE__ */ jsx("div", { style: errorBannerStyle4(tokens), children: error }),
3096
3222
  /* @__PURE__ */ jsxs("div", { style: balanceRowStyle, children: [
3097
3223
  /* @__PURE__ */ jsxs("div", { style: balanceLeftStyle, children: [
3098
3224
  /* @__PURE__ */ jsx("div", { style: coinIconStyle(tokens.accent), children: /* @__PURE__ */ jsxs("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", children: [
@@ -3170,20 +3296,20 @@ function SetupScreen({
3170
3296
  }
3171
3297
  );
3172
3298
  }
3173
- var headingStyle5 = (color) => ({
3299
+ var headingStyle6 = (color) => ({
3174
3300
  fontSize: "1.3rem",
3175
3301
  fontWeight: 700,
3176
3302
  letterSpacing: "-0.02em",
3177
3303
  color,
3178
3304
  margin: "8px 0 4px"
3179
3305
  });
3180
- var subtitleStyle5 = (color) => ({
3306
+ var subtitleStyle6 = (color) => ({
3181
3307
  fontSize: "0.86rem",
3182
3308
  color,
3183
3309
  margin: "0 0 24px",
3184
3310
  lineHeight: 1.5
3185
3311
  });
3186
- var errorBannerStyle3 = (tokens) => ({
3312
+ var errorBannerStyle4 = (tokens) => ({
3187
3313
  background: tokens.errorBg,
3188
3314
  border: `1px solid ${tokens.error}66`,
3189
3315
  borderRadius: 16,
@@ -3451,7 +3577,7 @@ function DepositScreen({
3451
3577
  "%)"
3452
3578
  ] }) : /* @__PURE__ */ jsx("div", { style: detailRowStyle(tokens.textMuted), children: "Fees calculated at time of transfer" })
3453
3579
  ] }),
3454
- error && /* @__PURE__ */ jsx("div", { style: errorBannerStyle4(tokens), children: error })
3580
+ error && /* @__PURE__ */ jsx("div", { style: errorBannerStyle5(tokens), children: error })
3455
3581
  ]
3456
3582
  }
3457
3583
  );
@@ -3519,7 +3645,7 @@ var detailRowStyle = (color) => ({
3519
3645
  color,
3520
3646
  marginBottom: 4
3521
3647
  });
3522
- var errorBannerStyle4 = (tokens) => ({
3648
+ var errorBannerStyle5 = (tokens) => ({
3523
3649
  background: tokens.errorBg,
3524
3650
  border: `1px solid ${tokens.error}66`,
3525
3651
  borderRadius: 16,
@@ -3618,22 +3744,22 @@ function SuccessScreen({
3618
3744
  right: /* @__PURE__ */ jsx(SettingsMenu, { onLogout })
3619
3745
  }
3620
3746
  ),
3621
- /* @__PURE__ */ jsxs("div", { style: contentStyle4, children: [
3747
+ /* @__PURE__ */ jsxs("div", { style: contentStyle5, children: [
3622
3748
  succeeded ? /* @__PURE__ */ jsxs(Fragment, { children: [
3623
3749
  /* @__PURE__ */ jsx(IconCircle, { variant: "success", size: 64, children: /* @__PURE__ */ jsx("svg", { width: "32", height: "32", viewBox: "0 0 24 24", fill: "none", children: /* @__PURE__ */ jsx("path", { d: "M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41L9 16.17z", fill: tokens.success }) }) }),
3624
- /* @__PURE__ */ jsxs("h2", { style: headingStyle6(tokens.text), children: [
3750
+ /* @__PURE__ */ jsxs("h2", { style: headingStyle7(tokens.text), children: [
3625
3751
  "$",
3626
3752
  amount.toFixed(2),
3627
3753
  " deposited"
3628
3754
  ] }),
3629
- merchantName && /* @__PURE__ */ jsxs("p", { style: subtitleStyle6(tokens.textSecondary), children: [
3755
+ merchantName && /* @__PURE__ */ jsxs("p", { style: subtitleStyle7(tokens.textSecondary), children: [
3630
3756
  "to ",
3631
3757
  merchantName
3632
3758
  ] })
3633
3759
  ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
3634
3760
  /* @__PURE__ */ jsx(IconCircle, { variant: "error", size: 64, children: /* @__PURE__ */ jsx("svg", { width: "32", height: "32", viewBox: "0 0 24 24", fill: "none", children: /* @__PURE__ */ jsx("path", { d: "M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-2h2v2zm0-4h-2V7h2v6z", fill: tokens.error }) }) }),
3635
- /* @__PURE__ */ jsx("h2", { style: headingStyle6(tokens.text), children: "Transfer failed" }),
3636
- error && /* @__PURE__ */ jsx("p", { style: subtitleStyle6(tokens.error), children: error })
3761
+ /* @__PURE__ */ jsx("h2", { style: headingStyle7(tokens.text), children: "Transfer failed" }),
3762
+ error && /* @__PURE__ */ jsx("p", { style: subtitleStyle7(tokens.error), children: error })
3637
3763
  ] }),
3638
3764
  /* @__PURE__ */ jsxs("div", { style: summaryCardStyle(tokens), children: [
3639
3765
  sourceName && /* @__PURE__ */ jsxs("div", { style: summaryRowStyle, children: [
@@ -3665,21 +3791,21 @@ function SuccessScreen({
3665
3791
  }
3666
3792
  );
3667
3793
  }
3668
- var contentStyle4 = {
3794
+ var contentStyle5 = {
3669
3795
  flex: 1,
3670
3796
  display: "flex",
3671
3797
  flexDirection: "column",
3672
3798
  alignItems: "center",
3673
3799
  paddingTop: 16
3674
3800
  };
3675
- var headingStyle6 = (color) => ({
3801
+ var headingStyle7 = (color) => ({
3676
3802
  fontSize: "1.5rem",
3677
3803
  fontWeight: 700,
3678
3804
  letterSpacing: "-0.02em",
3679
3805
  color,
3680
3806
  margin: "20px 0 4px"
3681
3807
  });
3682
- var subtitleStyle6 = (color) => ({
3808
+ var subtitleStyle7 = (color) => ({
3683
3809
  fontSize: "0.9rem",
3684
3810
  color,
3685
3811
  margin: "0 0 20px"
@@ -3785,7 +3911,7 @@ function SelectSourceScreen({
3785
3911
  right: /* @__PURE__ */ jsx(SettingsMenu, { onLogout })
3786
3912
  }
3787
3913
  ),
3788
- /* @__PURE__ */ jsx("p", { style: subtitleStyle7(tokens.textMuted), children: "Choose which chain and token to pay from." }),
3914
+ /* @__PURE__ */ jsx("p", { style: subtitleStyle8(tokens.textMuted), children: "Choose which chain and token to pay from." }),
3789
3915
  /* @__PURE__ */ jsx("label", { style: labelStyle2(tokens.textSecondary), children: "Chain" }),
3790
3916
  /* @__PURE__ */ jsx("div", { style: optionListStyle, children: choices.map((chain) => {
3791
3917
  const isSelected = chain.chainName === selectedChainName;
@@ -3842,7 +3968,7 @@ function SelectSourceScreen({
3842
3968
  }
3843
3969
  );
3844
3970
  }
3845
- var subtitleStyle7 = (color) => ({
3971
+ var subtitleStyle8 = (color) => ({
3846
3972
  fontSize: "0.85rem",
3847
3973
  color,
3848
3974
  margin: "0 0 20px",
@@ -3957,8 +4083,8 @@ function AdvancedSourceScreen({
3957
4083
  right: /* @__PURE__ */ jsx("span", { style: advancedBadgeStyle(tokens.accent), children: "Advanced" })
3958
4084
  }
3959
4085
  ),
3960
- /* @__PURE__ */ jsx("h2", { style: headingStyle7(tokens.text), children: "Set up One-Tap deposits" }),
3961
- /* @__PURE__ */ jsx("p", { style: subtitleStyle8(tokens.textSecondary), children: "Select a token source for your One-Tap deposits." }),
4086
+ /* @__PURE__ */ jsx("h2", { style: headingStyle8(tokens.text), children: "Set up One-Tap deposits" }),
4087
+ /* @__PURE__ */ jsx("p", { style: subtitleStyle9(tokens.textSecondary), children: "Select a token source for your One-Tap deposits." }),
3962
4088
  /* @__PURE__ */ jsx("label", { style: labelStyle3(tokens.textSecondary), children: "Select tokens to approve" }),
3963
4089
  /* @__PURE__ */ jsx("div", { style: chainListStyle, children: choices.map((chain) => {
3964
4090
  const isExpanded = expandedChain === chain.chainName;
@@ -4021,14 +4147,14 @@ var advancedBadgeStyle = (color) => ({
4021
4147
  padding: "3px 10px",
4022
4148
  letterSpacing: "0.02em"
4023
4149
  });
4024
- var headingStyle7 = (color) => ({
4150
+ var headingStyle8 = (color) => ({
4025
4151
  fontSize: "1.3rem",
4026
4152
  fontWeight: 700,
4027
4153
  letterSpacing: "-0.02em",
4028
4154
  color,
4029
4155
  margin: "8px 0 4px"
4030
4156
  });
4031
- var subtitleStyle8 = (color) => ({
4157
+ var subtitleStyle9 = (color) => ({
4032
4158
  fontSize: "0.86rem",
4033
4159
  color,
4034
4160
  margin: "0 0 20px",
@@ -4156,16 +4282,16 @@ function TransferStatusScreen({
4156
4282
  const steps = buildSteps(phase);
4157
4283
  return /* @__PURE__ */ jsxs(ScreenLayout, { children: [
4158
4284
  /* @__PURE__ */ jsx(ScreenHeader, { right: /* @__PURE__ */ jsx(SettingsMenu, { onLogout }) }),
4159
- /* @__PURE__ */ jsxs("div", { style: contentStyle5, children: [
4285
+ /* @__PURE__ */ jsxs("div", { style: contentStyle6, children: [
4160
4286
  /* @__PURE__ */ jsx(Spinner, { size: 48 }),
4161
- /* @__PURE__ */ jsx("h2", { style: headingStyle8(tokens.text), children: "Processing Transfer..." }),
4162
- error && /* @__PURE__ */ jsx("div", { style: errorBannerStyle5(tokens), children: error }),
4287
+ /* @__PURE__ */ jsx("h2", { style: headingStyle9(tokens.text), children: "Processing Transfer..." }),
4288
+ error && /* @__PURE__ */ jsx("div", { style: errorBannerStyle6(tokens), children: error }),
4163
4289
  /* @__PURE__ */ jsx("div", { style: stepsWrapStyle, children: /* @__PURE__ */ jsx(StepList, { steps }) }),
4164
4290
  /* @__PURE__ */ jsx("p", { style: waitHintStyle(tokens.textMuted), children: "Usually takes a few seconds" })
4165
4291
  ] })
4166
4292
  ] });
4167
4293
  }
4168
- var contentStyle5 = {
4294
+ var contentStyle6 = {
4169
4295
  flex: 1,
4170
4296
  display: "flex",
4171
4297
  flexDirection: "column",
@@ -4174,14 +4300,14 @@ var contentStyle5 = {
4174
4300
  textAlign: "center",
4175
4301
  padding: "0 24px"
4176
4302
  };
4177
- var headingStyle8 = (color) => ({
4303
+ var headingStyle9 = (color) => ({
4178
4304
  fontSize: "1.45rem",
4179
4305
  fontWeight: 700,
4180
4306
  letterSpacing: "-0.02em",
4181
4307
  color,
4182
4308
  margin: "20px 0 16px"
4183
4309
  });
4184
- var errorBannerStyle5 = (tokens) => ({
4310
+ var errorBannerStyle6 = (tokens) => ({
4185
4311
  background: tokens.errorBg,
4186
4312
  border: `1px solid ${tokens.error}66`,
4187
4313
  borderRadius: 16,
@@ -4241,10 +4367,10 @@ function OpenWalletScreen({
4241
4367
  ] }),
4242
4368
  children: [
4243
4369
  /* @__PURE__ */ jsx(ScreenHeader, { right: /* @__PURE__ */ jsx(SettingsMenu, { onLogout }) }),
4244
- /* @__PURE__ */ jsxs("div", { style: contentStyle6, children: [
4370
+ /* @__PURE__ */ jsxs("div", { style: contentStyle7, children: [
4245
4371
  logoSrc ? /* @__PURE__ */ jsx("img", { src: logoSrc, alt: displayName, style: logoStyle }) : /* @__PURE__ */ jsx(Spinner, { size: 48 }),
4246
- /* @__PURE__ */ jsx("h2", { style: headingStyle9(tokens.text), children: loading ? "Connecting..." : `Open ${displayName}` }),
4247
- /* @__PURE__ */ jsx("p", { style: subtitleStyle9(tokens.textSecondary), children: loading ? "Creating transfer and preparing your wallet link..." : `Continue in ${displayName} to authorize this connection.` }),
4372
+ /* @__PURE__ */ jsx("h2", { style: headingStyle10(tokens.text), children: loading ? "Connecting..." : `Open ${displayName}` }),
4373
+ /* @__PURE__ */ jsx("p", { style: subtitleStyle10(tokens.textSecondary), children: loading ? "Creating transfer and preparing your wallet link..." : `Continue in ${displayName} to authorize this connection.` }),
4248
4374
  !loading && /* @__PURE__ */ jsxs("div", { style: waitingBadgeStyle(tokens), children: [
4249
4375
  /* @__PURE__ */ jsx(Spinner, { size: 14 }),
4250
4376
  /* @__PURE__ */ jsx("span", { children: "Waiting for authorization..." })
@@ -4254,7 +4380,7 @@ function OpenWalletScreen({
4254
4380
  }
4255
4381
  );
4256
4382
  }
4257
- var contentStyle6 = {
4383
+ var contentStyle7 = {
4258
4384
  flex: 1,
4259
4385
  display: "flex",
4260
4386
  flexDirection: "column",
@@ -4274,14 +4400,14 @@ var logoStyle = {
4274
4400
  borderRadius: 14,
4275
4401
  objectFit: "contain"
4276
4402
  };
4277
- var headingStyle9 = (color) => ({
4403
+ var headingStyle10 = (color) => ({
4278
4404
  fontSize: "1.45rem",
4279
4405
  fontWeight: 700,
4280
4406
  letterSpacing: "-0.02em",
4281
4407
  color,
4282
4408
  margin: "20px 0 8px"
4283
4409
  });
4284
- var subtitleStyle9 = (color) => ({
4410
+ var subtitleStyle10 = (color) => ({
4285
4411
  fontSize: "0.9rem",
4286
4412
  color,
4287
4413
  margin: "0 0 24px",
@@ -4325,10 +4451,10 @@ function ConfirmSignScreen({
4325
4451
  ] }),
4326
4452
  children: [
4327
4453
  /* @__PURE__ */ jsx(ScreenHeader, { right: /* @__PURE__ */ jsx(SettingsMenu, { onLogout }) }),
4328
- /* @__PURE__ */ jsxs("div", { style: contentStyle7, children: [
4454
+ /* @__PURE__ */ jsxs("div", { style: contentStyle8, children: [
4329
4455
  logoSrc ? /* @__PURE__ */ jsx("img", { src: logoSrc, alt: displayName, style: logoStyle2 }) : /* @__PURE__ */ jsx(Spinner, { size: 48 }),
4330
- /* @__PURE__ */ jsx("h2", { style: headingStyle10(tokens.text), children: "Wallet authorized" }),
4331
- /* @__PURE__ */ jsxs("p", { style: subtitleStyle10(tokens.textSecondary), children: [
4456
+ /* @__PURE__ */ jsx("h2", { style: headingStyle11(tokens.text), children: "Wallet authorized" }),
4457
+ /* @__PURE__ */ jsxs("p", { style: subtitleStyle11(tokens.textSecondary), children: [
4332
4458
  displayName,
4333
4459
  " approved the connection. Tap below to confirm your payment."
4334
4460
  ] }),
@@ -4341,7 +4467,7 @@ function ConfirmSignScreen({
4341
4467
  }
4342
4468
  );
4343
4469
  }
4344
- var contentStyle7 = {
4470
+ var contentStyle8 = {
4345
4471
  flex: 1,
4346
4472
  display: "flex",
4347
4473
  flexDirection: "column",
@@ -4356,14 +4482,14 @@ var logoStyle2 = {
4356
4482
  borderRadius: 14,
4357
4483
  objectFit: "contain"
4358
4484
  };
4359
- var headingStyle10 = (color) => ({
4485
+ var headingStyle11 = (color) => ({
4360
4486
  fontSize: "1.45rem",
4361
4487
  fontWeight: 700,
4362
4488
  letterSpacing: "-0.02em",
4363
4489
  color,
4364
4490
  margin: "20px 0 8px"
4365
4491
  });
4366
- var subtitleStyle10 = (color) => ({
4492
+ var subtitleStyle11 = (color) => ({
4367
4493
  fontSize: "0.9rem",
4368
4494
  color,
4369
4495
  margin: "0 0 24px",
@@ -4422,7 +4548,7 @@ var PaymentErrorBoundary = class extends Component {
4422
4548
  /* @__PURE__ */ jsx("path", { d: "M12 8v5", stroke: "#ef4444", strokeWidth: "1.5", strokeLinecap: "round" }),
4423
4549
  /* @__PURE__ */ jsx("circle", { cx: "12", cy: "16", r: "0.75", fill: "#ef4444" })
4424
4550
  ] }) }),
4425
- /* @__PURE__ */ jsx("h2", { style: headingStyle11, children: "Something went wrong" }),
4551
+ /* @__PURE__ */ jsx("h2", { style: headingStyle12, children: "Something went wrong" }),
4426
4552
  /* @__PURE__ */ jsx("p", { style: messageStyle, children: "An unexpected error occurred. Please try again." }),
4427
4553
  /* @__PURE__ */ jsx("button", { type: "button", onClick: this.handleReset, style: buttonStyle3, children: "Try again" })
4428
4554
  ] });
@@ -4442,7 +4568,7 @@ var containerStyle8 = {
4442
4568
  var iconStyle4 = {
4443
4569
  marginBottom: 20
4444
4570
  };
4445
- var headingStyle11 = {
4571
+ var headingStyle12 = {
4446
4572
  fontSize: "1.25rem",
4447
4573
  fontWeight: 700,
4448
4574
  color: "#1a1a1a",
@@ -4605,6 +4731,7 @@ function SwypePaymentInner({
4605
4731
  const [transfer, setTransfer] = useState(null);
4606
4732
  const [creatingTransfer, setCreatingTransfer] = useState(false);
4607
4733
  const [registeringPasskey, setRegisteringPasskey] = useState(false);
4734
+ const [verifyingPasskeyPopup, setVerifyingPasskeyPopup] = useState(false);
4608
4735
  const [passkeyPopupNeeded, setPasskeyPopupNeeded] = useState(
4609
4736
  () => isSafari() && isInCrossOriginIframe()
4610
4737
  );
@@ -4913,6 +5040,10 @@ function SwypePaymentInner({
4913
5040
  }
4914
5041
  if (cancelled) return;
4915
5042
  const credentialIds = allPasskeys.map((p) => p.credentialId);
5043
+ if (isSafari() && isInCrossOriginIframe()) {
5044
+ setStep("verify-passkey");
5045
+ return;
5046
+ }
4916
5047
  const matched = await findDevicePasskey(credentialIds);
4917
5048
  if (cancelled) return;
4918
5049
  if (matched) {
@@ -5439,6 +5570,27 @@ function SwypePaymentInner({
5439
5570
  setRegisteringPasskey(false);
5440
5571
  }
5441
5572
  }, [user, completePasskeyRegistration, getAccessToken, apiBaseUrl, knownCredentialIds]);
5573
+ const handleVerifyPasskeyViaPopup = useCallback(async () => {
5574
+ setVerifyingPasskeyPopup(true);
5575
+ setError(null);
5576
+ try {
5577
+ const matched = await findDevicePasskeyViaPopup({
5578
+ credentialIds: knownCredentialIds,
5579
+ rpId: resolvePasskeyRpId()
5580
+ });
5581
+ if (matched) {
5582
+ setActiveCredentialId(matched);
5583
+ window.localStorage.setItem(ACTIVE_CREDENTIAL_STORAGE_KEY, matched);
5584
+ setStep("login");
5585
+ } else {
5586
+ setStep("create-passkey");
5587
+ }
5588
+ } catch {
5589
+ setStep("create-passkey");
5590
+ } finally {
5591
+ setVerifyingPasskeyPopup(false);
5592
+ }
5593
+ }, [knownCredentialIds]);
5442
5594
  const handleSelectProvider = useCallback((providerId) => {
5443
5595
  setSelectedProviderId(providerId);
5444
5596
  setSelectedAccountId(null);
@@ -5570,6 +5722,17 @@ function SwypePaymentInner({
5570
5722
  if ((step === "login" || step === "otp-verify") && authenticated) {
5571
5723
  return /* @__PURE__ */ jsx(ScreenLayout, { children: /* @__PURE__ */ jsx("div", { style: { textAlign: "center", padding: "48px 0", flex: 1, display: "flex", alignItems: "center", justifyContent: "center" }, children: /* @__PURE__ */ jsx(Spinner, { label: "Verifying your passkey..." }) }) });
5572
5724
  }
5725
+ if (step === "verify-passkey") {
5726
+ return /* @__PURE__ */ jsx(
5727
+ VerifyPasskeyScreen,
5728
+ {
5729
+ onVerify: handleVerifyPasskeyViaPopup,
5730
+ onBack: handleLogout,
5731
+ verifying: verifyingPasskeyPopup,
5732
+ error
5733
+ }
5734
+ );
5735
+ }
5573
5736
  if (step === "create-passkey") {
5574
5737
  return /* @__PURE__ */ jsx(
5575
5738
  CreatePasskeyScreen,
@@ -5731,6 +5894,6 @@ function SwypePaymentInner({
5731
5894
  return null;
5732
5895
  }
5733
5896
 
5734
- export { AdvancedSourceScreen, CreatePasskeyScreen, IconCircle, InfoBanner, OutlineButton, PasskeyIframeBlockedError, PoweredByFooter, PrimaryButton, ScreenHeader, ScreenLayout, SelectSourceScreen, SettingsMenu, SetupScreen, Spinner, StepList, SwypePayment, SwypeProvider, buildPasskeyPopupOptions, createPasskeyCredential, createPasskeyViaPopup, darkTheme, deviceHasPasskey, findDevicePasskey, getTheme, lightTheme, api_exports as swypeApi, useAuthorizationExecutor, useSwypeConfig, useSwypeDepositAmount, useTransferPolling, useTransferSigning };
5897
+ export { AdvancedSourceScreen, CreatePasskeyScreen, IconCircle, InfoBanner, OutlineButton, PasskeyIframeBlockedError, PoweredByFooter, PrimaryButton, ScreenHeader, ScreenLayout, SelectSourceScreen, SettingsMenu, SetupScreen, Spinner, StepList, SwypePayment, SwypeProvider, buildPasskeyPopupOptions, createPasskeyCredential, createPasskeyViaPopup, darkTheme, deviceHasPasskey, findDevicePasskey, findDevicePasskeyViaPopup, getTheme, lightTheme, resolvePasskeyRpId, api_exports as swypeApi, useAuthorizationExecutor, useSwypeConfig, useSwypeDepositAmount, useTransferPolling, useTransferSigning };
5735
5898
  //# sourceMappingURL=index.js.map
5736
5899
  //# sourceMappingURL=index.js.map