@swype-org/react-sdk 0.1.84 → 0.1.86

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
@@ -164,6 +164,7 @@ __export(api_exports, {
164
164
  fetchUserConfig: () => fetchUserConfig,
165
165
  registerPasskey: () => registerPasskey,
166
166
  reportActionCompletion: () => reportActionCompletion,
167
+ reportPasskeyActivity: () => reportPasskeyActivity,
167
168
  signTransfer: () => signTransfer,
168
169
  updateUserConfig: () => updateUserConfig,
169
170
  updateUserConfigBySession: () => updateUserConfigBySession
@@ -286,6 +287,17 @@ async function registerPasskey(apiBaseUrl, token, credentialId, publicKey) {
286
287
  });
287
288
  if (!res.ok) await throwApiError(res);
288
289
  }
290
+ async function reportPasskeyActivity(apiBaseUrl, token, credentialId) {
291
+ const res = await fetch(`${apiBaseUrl}/v1/users/config/passkey`, {
292
+ method: "PATCH",
293
+ headers: {
294
+ "Content-Type": "application/json",
295
+ Authorization: `Bearer ${token}`
296
+ },
297
+ body: JSON.stringify({ credentialId })
298
+ });
299
+ if (!res.ok) await throwApiError(res);
300
+ }
289
301
  async function fetchUserConfig(apiBaseUrl, token) {
290
302
  const res = await fetch(`${apiBaseUrl}/v1/users/config`, {
291
303
  headers: { Authorization: `Bearer ${token}` }
@@ -785,6 +797,66 @@ function createPasskeyViaPopup(options, existingCredentialIds = []) {
785
797
  }
786
798
  });
787
799
  }
800
+ var VERIFY_POPUP_TIMEOUT_MS = 6e4;
801
+ function findDevicePasskeyViaPopup(options) {
802
+ return new Promise((resolve, reject) => {
803
+ const channelId = `swype-pv-${Date.now()}-${Math.random().toString(36).slice(2)}`;
804
+ const payload = { ...options, channelId };
805
+ const encoded = btoa(JSON.stringify(payload));
806
+ const popupUrl = `${window.location.origin}/passkey-verify#${encoded}`;
807
+ const popup = window.open(popupUrl, "swype-passkey-verify");
808
+ if (!popup) {
809
+ reject(new Error("Pop-up blocked. Please allow pop-ups for this site and try again."));
810
+ return;
811
+ }
812
+ let settled = false;
813
+ const channel = typeof BroadcastChannel !== "undefined" ? new BroadcastChannel(channelId) : null;
814
+ const timer = setTimeout(() => {
815
+ cleanup();
816
+ resolve(null);
817
+ }, VERIFY_POPUP_TIMEOUT_MS);
818
+ const closedPoll = setInterval(() => {
819
+ if (popup.closed && !settled) {
820
+ clearInterval(closedPoll);
821
+ setTimeout(() => {
822
+ if (!settled) {
823
+ cleanup();
824
+ resolve(null);
825
+ }
826
+ }, POPUP_CLOSED_GRACE_MS);
827
+ }
828
+ }, POPUP_CLOSED_POLL_MS);
829
+ function handleResult(data) {
830
+ if (settled) return;
831
+ if (!data || typeof data !== "object") return;
832
+ if (data.type !== "swype:passkey-verify-result") return;
833
+ settled = true;
834
+ cleanup();
835
+ if (data.error) {
836
+ resolve(null);
837
+ } else if (data.result && typeof data.result === "object") {
838
+ const result = data.result;
839
+ resolve(result.credentialId ?? null);
840
+ } else {
841
+ resolve(null);
842
+ }
843
+ }
844
+ if (channel) {
845
+ channel.onmessage = (event) => handleResult(event.data);
846
+ }
847
+ const postMessageHandler = (event) => {
848
+ if (event.source !== popup) return;
849
+ handleResult(event.data);
850
+ };
851
+ window.addEventListener("message", postMessageHandler);
852
+ function cleanup() {
853
+ clearTimeout(timer);
854
+ clearInterval(closedPoll);
855
+ window.removeEventListener("message", postMessageHandler);
856
+ channel?.close();
857
+ }
858
+ });
859
+ }
788
860
  async function checkServerForNewPasskey(authToken, apiBaseUrl, existingCredentialIds) {
789
861
  if (!authToken || !apiBaseUrl) return null;
790
862
  const res = await fetch(`${apiBaseUrl}/v1/users/config`, {
@@ -2770,6 +2842,72 @@ var errorBannerStyle2 = (tokens) => ({
2770
2842
  width: "100%",
2771
2843
  textAlign: "left"
2772
2844
  });
2845
+ function VerifyPasskeyScreen({
2846
+ onVerify,
2847
+ onBack,
2848
+ verifying,
2849
+ error
2850
+ }) {
2851
+ const { tokens } = useSwypeConfig();
2852
+ return /* @__PURE__ */ jsxs(
2853
+ ScreenLayout,
2854
+ {
2855
+ footer: /* @__PURE__ */ jsxs(Fragment, { children: [
2856
+ /* @__PURE__ */ jsx(PrimaryButton, { onClick: onVerify, disabled: verifying, loading: verifying, children: "Verify passkey" }),
2857
+ /* @__PURE__ */ jsx(PoweredByFooter, {})
2858
+ ] }),
2859
+ children: [
2860
+ /* @__PURE__ */ jsx(ScreenHeader, { onBack }),
2861
+ /* @__PURE__ */ jsxs("div", { style: contentStyle4, children: [
2862
+ /* @__PURE__ */ jsx(IconCircle, { variant: "accent", size: 64, children: /* @__PURE__ */ jsxs("svg", { width: "36", height: "36", viewBox: "0 0 24 24", fill: "none", children: [
2863
+ /* @__PURE__ */ jsx("rect", { x: "4", y: "4", width: "16", height: "16", rx: "3", stroke: tokens.accent, strokeWidth: "1.5", strokeDasharray: "3 2" }),
2864
+ /* @__PURE__ */ jsx("circle", { cx: "9", cy: "10", r: "1", fill: tokens.accent }),
2865
+ /* @__PURE__ */ jsx("circle", { cx: "15", cy: "10", r: "1", fill: tokens.accent }),
2866
+ /* @__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" })
2867
+ ] }) }),
2868
+ /* @__PURE__ */ jsx("h2", { style: headingStyle4(tokens.text), children: "Verify your passkey" }),
2869
+ /* @__PURE__ */ jsx("p", { style: subtitleStyle4(tokens.textSecondary), children: "Your browser requires a separate window to verify your passkey. Tap the button below to continue." }),
2870
+ error && /* @__PURE__ */ jsx("div", { style: errorBannerStyle3(tokens), children: error }),
2871
+ /* @__PURE__ */ jsx(InfoBanner, { children: "Your passkey is stored securely on your device. Swype never sees your biometric data." })
2872
+ ] })
2873
+ ]
2874
+ }
2875
+ );
2876
+ }
2877
+ var contentStyle4 = {
2878
+ textAlign: "center",
2879
+ flex: 1,
2880
+ display: "flex",
2881
+ flexDirection: "column",
2882
+ alignItems: "center",
2883
+ paddingTop: 32
2884
+ };
2885
+ var headingStyle4 = (color) => ({
2886
+ fontSize: "1.45rem",
2887
+ fontWeight: 700,
2888
+ letterSpacing: "-0.02em",
2889
+ color,
2890
+ margin: "24px 0 8px"
2891
+ });
2892
+ var subtitleStyle4 = (color) => ({
2893
+ fontSize: "0.9rem",
2894
+ color,
2895
+ margin: "0 0 28px",
2896
+ lineHeight: 1.5,
2897
+ maxWidth: 280
2898
+ });
2899
+ var errorBannerStyle3 = (tokens) => ({
2900
+ background: tokens.errorBg,
2901
+ border: `1px solid ${tokens.error}66`,
2902
+ borderRadius: 16,
2903
+ padding: "11px 14px",
2904
+ color: tokens.error,
2905
+ fontSize: "0.84rem",
2906
+ marginBottom: 14,
2907
+ lineHeight: 1.5,
2908
+ width: "100%",
2909
+ textAlign: "left"
2910
+ });
2773
2911
  var WALLET_EMOJIS = {
2774
2912
  rabby: "\u{1F430}",
2775
2913
  ora: "\u2666\uFE0F",
@@ -2812,8 +2950,8 @@ function WalletPickerScreen({
2812
2950
  children: [
2813
2951
  /* @__PURE__ */ jsx(ScreenHeader, { title: "Set up Swype", onBack }),
2814
2952
  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" }),
2953
+ /* @__PURE__ */ jsx("h2", { style: headingStyle5(tokens.text), children: "Continue where you left off" }),
2954
+ /* @__PURE__ */ jsx("p", { style: subtitleStyle5(tokens.textSecondary), children: "You have a wallet that still needs setup" }),
2817
2955
  /* @__PURE__ */ jsx("div", { style: pendingListStyle, children: pendingConnections.map((acct) => {
2818
2956
  const wallet = acct.wallets[0];
2819
2957
  const address = wallet ? truncateAddress(wallet.name) : void 0;
@@ -2853,8 +2991,8 @@ function WalletPickerScreen({
2853
2991
  /* @__PURE__ */ jsx("div", { style: dividerStyle2(tokens.border), children: /* @__PURE__ */ jsx("span", { style: dividerTextStyle(tokens.textMuted), children: "Or connect a new wallet" }) })
2854
2992
  ] }),
2855
2993
  !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" })
2994
+ /* @__PURE__ */ jsx("h2", { style: headingStyle5(tokens.text), children: "Where are your stablecoins?" }),
2995
+ /* @__PURE__ */ jsx("p", { style: subtitleStyle5(tokens.textSecondary), children: "Select the wallet you want to deposit from" })
2858
2996
  ] }),
2859
2997
  /* @__PURE__ */ jsxs("div", { style: gridStyle, children: [
2860
2998
  displayProviders.map((p) => {
@@ -2907,14 +3045,14 @@ function WalletPickerScreen({
2907
3045
  }
2908
3046
  );
2909
3047
  }
2910
- var headingStyle4 = (color) => ({
3048
+ var headingStyle5 = (color) => ({
2911
3049
  fontSize: "1.35rem",
2912
3050
  fontWeight: 700,
2913
3051
  letterSpacing: "-0.02em",
2914
3052
  color,
2915
3053
  margin: "8px 0 4px"
2916
3054
  });
2917
- var subtitleStyle4 = (color) => ({
3055
+ var subtitleStyle5 = (color) => ({
2918
3056
  fontSize: "0.88rem",
2919
3057
  color,
2920
3058
  margin: "0 0 24px"
@@ -3090,9 +3228,9 @@ function SetupScreen({
3090
3228
  ] }),
3091
3229
  children: [
3092
3230
  /* @__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 }),
3231
+ /* @__PURE__ */ jsx("h2", { style: headingStyle6(tokens.text), children: "Set up One-Tap deposits" }),
3232
+ /* @__PURE__ */ jsx("p", { style: subtitleStyle6(tokens.textSecondary), children: "Set your limit for instant deposits. Like a contactless card \u2014 you choose the max." }),
3233
+ error && /* @__PURE__ */ jsx("div", { style: errorBannerStyle4(tokens), children: error }),
3096
3234
  /* @__PURE__ */ jsxs("div", { style: balanceRowStyle, children: [
3097
3235
  /* @__PURE__ */ jsxs("div", { style: balanceLeftStyle, children: [
3098
3236
  /* @__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 +3308,20 @@ function SetupScreen({
3170
3308
  }
3171
3309
  );
3172
3310
  }
3173
- var headingStyle5 = (color) => ({
3311
+ var headingStyle6 = (color) => ({
3174
3312
  fontSize: "1.3rem",
3175
3313
  fontWeight: 700,
3176
3314
  letterSpacing: "-0.02em",
3177
3315
  color,
3178
3316
  margin: "8px 0 4px"
3179
3317
  });
3180
- var subtitleStyle5 = (color) => ({
3318
+ var subtitleStyle6 = (color) => ({
3181
3319
  fontSize: "0.86rem",
3182
3320
  color,
3183
3321
  margin: "0 0 24px",
3184
3322
  lineHeight: 1.5
3185
3323
  });
3186
- var errorBannerStyle3 = (tokens) => ({
3324
+ var errorBannerStyle4 = (tokens) => ({
3187
3325
  background: tokens.errorBg,
3188
3326
  border: `1px solid ${tokens.error}66`,
3189
3327
  borderRadius: 16,
@@ -3451,7 +3589,7 @@ function DepositScreen({
3451
3589
  "%)"
3452
3590
  ] }) : /* @__PURE__ */ jsx("div", { style: detailRowStyle(tokens.textMuted), children: "Fees calculated at time of transfer" })
3453
3591
  ] }),
3454
- error && /* @__PURE__ */ jsx("div", { style: errorBannerStyle4(tokens), children: error })
3592
+ error && /* @__PURE__ */ jsx("div", { style: errorBannerStyle5(tokens), children: error })
3455
3593
  ]
3456
3594
  }
3457
3595
  );
@@ -3519,7 +3657,7 @@ var detailRowStyle = (color) => ({
3519
3657
  color,
3520
3658
  marginBottom: 4
3521
3659
  });
3522
- var errorBannerStyle4 = (tokens) => ({
3660
+ var errorBannerStyle5 = (tokens) => ({
3523
3661
  background: tokens.errorBg,
3524
3662
  border: `1px solid ${tokens.error}66`,
3525
3663
  borderRadius: 16,
@@ -3618,22 +3756,22 @@ function SuccessScreen({
3618
3756
  right: /* @__PURE__ */ jsx(SettingsMenu, { onLogout })
3619
3757
  }
3620
3758
  ),
3621
- /* @__PURE__ */ jsxs("div", { style: contentStyle4, children: [
3759
+ /* @__PURE__ */ jsxs("div", { style: contentStyle5, children: [
3622
3760
  succeeded ? /* @__PURE__ */ jsxs(Fragment, { children: [
3623
3761
  /* @__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: [
3762
+ /* @__PURE__ */ jsxs("h2", { style: headingStyle7(tokens.text), children: [
3625
3763
  "$",
3626
3764
  amount.toFixed(2),
3627
3765
  " deposited"
3628
3766
  ] }),
3629
- merchantName && /* @__PURE__ */ jsxs("p", { style: subtitleStyle6(tokens.textSecondary), children: [
3767
+ merchantName && /* @__PURE__ */ jsxs("p", { style: subtitleStyle7(tokens.textSecondary), children: [
3630
3768
  "to ",
3631
3769
  merchantName
3632
3770
  ] })
3633
3771
  ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
3634
3772
  /* @__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 })
3773
+ /* @__PURE__ */ jsx("h2", { style: headingStyle7(tokens.text), children: "Transfer failed" }),
3774
+ error && /* @__PURE__ */ jsx("p", { style: subtitleStyle7(tokens.error), children: error })
3637
3775
  ] }),
3638
3776
  /* @__PURE__ */ jsxs("div", { style: summaryCardStyle(tokens), children: [
3639
3777
  sourceName && /* @__PURE__ */ jsxs("div", { style: summaryRowStyle, children: [
@@ -3665,21 +3803,21 @@ function SuccessScreen({
3665
3803
  }
3666
3804
  );
3667
3805
  }
3668
- var contentStyle4 = {
3806
+ var contentStyle5 = {
3669
3807
  flex: 1,
3670
3808
  display: "flex",
3671
3809
  flexDirection: "column",
3672
3810
  alignItems: "center",
3673
3811
  paddingTop: 16
3674
3812
  };
3675
- var headingStyle6 = (color) => ({
3813
+ var headingStyle7 = (color) => ({
3676
3814
  fontSize: "1.5rem",
3677
3815
  fontWeight: 700,
3678
3816
  letterSpacing: "-0.02em",
3679
3817
  color,
3680
3818
  margin: "20px 0 4px"
3681
3819
  });
3682
- var subtitleStyle6 = (color) => ({
3820
+ var subtitleStyle7 = (color) => ({
3683
3821
  fontSize: "0.9rem",
3684
3822
  color,
3685
3823
  margin: "0 0 20px"
@@ -3785,7 +3923,7 @@ function SelectSourceScreen({
3785
3923
  right: /* @__PURE__ */ jsx(SettingsMenu, { onLogout })
3786
3924
  }
3787
3925
  ),
3788
- /* @__PURE__ */ jsx("p", { style: subtitleStyle7(tokens.textMuted), children: "Choose which chain and token to pay from." }),
3926
+ /* @__PURE__ */ jsx("p", { style: subtitleStyle8(tokens.textMuted), children: "Choose which chain and token to pay from." }),
3789
3927
  /* @__PURE__ */ jsx("label", { style: labelStyle2(tokens.textSecondary), children: "Chain" }),
3790
3928
  /* @__PURE__ */ jsx("div", { style: optionListStyle, children: choices.map((chain) => {
3791
3929
  const isSelected = chain.chainName === selectedChainName;
@@ -3842,7 +3980,7 @@ function SelectSourceScreen({
3842
3980
  }
3843
3981
  );
3844
3982
  }
3845
- var subtitleStyle7 = (color) => ({
3983
+ var subtitleStyle8 = (color) => ({
3846
3984
  fontSize: "0.85rem",
3847
3985
  color,
3848
3986
  margin: "0 0 20px",
@@ -3957,8 +4095,8 @@ function AdvancedSourceScreen({
3957
4095
  right: /* @__PURE__ */ jsx("span", { style: advancedBadgeStyle(tokens.accent), children: "Advanced" })
3958
4096
  }
3959
4097
  ),
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." }),
4098
+ /* @__PURE__ */ jsx("h2", { style: headingStyle8(tokens.text), children: "Set up One-Tap deposits" }),
4099
+ /* @__PURE__ */ jsx("p", { style: subtitleStyle9(tokens.textSecondary), children: "Select a token source for your One-Tap deposits." }),
3962
4100
  /* @__PURE__ */ jsx("label", { style: labelStyle3(tokens.textSecondary), children: "Select tokens to approve" }),
3963
4101
  /* @__PURE__ */ jsx("div", { style: chainListStyle, children: choices.map((chain) => {
3964
4102
  const isExpanded = expandedChain === chain.chainName;
@@ -4021,14 +4159,14 @@ var advancedBadgeStyle = (color) => ({
4021
4159
  padding: "3px 10px",
4022
4160
  letterSpacing: "0.02em"
4023
4161
  });
4024
- var headingStyle7 = (color) => ({
4162
+ var headingStyle8 = (color) => ({
4025
4163
  fontSize: "1.3rem",
4026
4164
  fontWeight: 700,
4027
4165
  letterSpacing: "-0.02em",
4028
4166
  color,
4029
4167
  margin: "8px 0 4px"
4030
4168
  });
4031
- var subtitleStyle8 = (color) => ({
4169
+ var subtitleStyle9 = (color) => ({
4032
4170
  fontSize: "0.86rem",
4033
4171
  color,
4034
4172
  margin: "0 0 20px",
@@ -4156,16 +4294,16 @@ function TransferStatusScreen({
4156
4294
  const steps = buildSteps(phase);
4157
4295
  return /* @__PURE__ */ jsxs(ScreenLayout, { children: [
4158
4296
  /* @__PURE__ */ jsx(ScreenHeader, { right: /* @__PURE__ */ jsx(SettingsMenu, { onLogout }) }),
4159
- /* @__PURE__ */ jsxs("div", { style: contentStyle5, children: [
4297
+ /* @__PURE__ */ jsxs("div", { style: contentStyle6, children: [
4160
4298
  /* @__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 }),
4299
+ /* @__PURE__ */ jsx("h2", { style: headingStyle9(tokens.text), children: "Processing Transfer..." }),
4300
+ error && /* @__PURE__ */ jsx("div", { style: errorBannerStyle6(tokens), children: error }),
4163
4301
  /* @__PURE__ */ jsx("div", { style: stepsWrapStyle, children: /* @__PURE__ */ jsx(StepList, { steps }) }),
4164
4302
  /* @__PURE__ */ jsx("p", { style: waitHintStyle(tokens.textMuted), children: "Usually takes a few seconds" })
4165
4303
  ] })
4166
4304
  ] });
4167
4305
  }
4168
- var contentStyle5 = {
4306
+ var contentStyle6 = {
4169
4307
  flex: 1,
4170
4308
  display: "flex",
4171
4309
  flexDirection: "column",
@@ -4174,14 +4312,14 @@ var contentStyle5 = {
4174
4312
  textAlign: "center",
4175
4313
  padding: "0 24px"
4176
4314
  };
4177
- var headingStyle8 = (color) => ({
4315
+ var headingStyle9 = (color) => ({
4178
4316
  fontSize: "1.45rem",
4179
4317
  fontWeight: 700,
4180
4318
  letterSpacing: "-0.02em",
4181
4319
  color,
4182
4320
  margin: "20px 0 16px"
4183
4321
  });
4184
- var errorBannerStyle5 = (tokens) => ({
4322
+ var errorBannerStyle6 = (tokens) => ({
4185
4323
  background: tokens.errorBg,
4186
4324
  border: `1px solid ${tokens.error}66`,
4187
4325
  borderRadius: 16,
@@ -4241,10 +4379,10 @@ function OpenWalletScreen({
4241
4379
  ] }),
4242
4380
  children: [
4243
4381
  /* @__PURE__ */ jsx(ScreenHeader, { right: /* @__PURE__ */ jsx(SettingsMenu, { onLogout }) }),
4244
- /* @__PURE__ */ jsxs("div", { style: contentStyle6, children: [
4382
+ /* @__PURE__ */ jsxs("div", { style: contentStyle7, children: [
4245
4383
  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.` }),
4384
+ /* @__PURE__ */ jsx("h2", { style: headingStyle10(tokens.text), children: loading ? "Connecting..." : `Open ${displayName}` }),
4385
+ /* @__PURE__ */ jsx("p", { style: subtitleStyle10(tokens.textSecondary), children: loading ? "Creating transfer and preparing your wallet link..." : `Continue in ${displayName} to authorize this connection.` }),
4248
4386
  !loading && /* @__PURE__ */ jsxs("div", { style: waitingBadgeStyle(tokens), children: [
4249
4387
  /* @__PURE__ */ jsx(Spinner, { size: 14 }),
4250
4388
  /* @__PURE__ */ jsx("span", { children: "Waiting for authorization..." })
@@ -4254,7 +4392,7 @@ function OpenWalletScreen({
4254
4392
  }
4255
4393
  );
4256
4394
  }
4257
- var contentStyle6 = {
4395
+ var contentStyle7 = {
4258
4396
  flex: 1,
4259
4397
  display: "flex",
4260
4398
  flexDirection: "column",
@@ -4274,14 +4412,14 @@ var logoStyle = {
4274
4412
  borderRadius: 14,
4275
4413
  objectFit: "contain"
4276
4414
  };
4277
- var headingStyle9 = (color) => ({
4415
+ var headingStyle10 = (color) => ({
4278
4416
  fontSize: "1.45rem",
4279
4417
  fontWeight: 700,
4280
4418
  letterSpacing: "-0.02em",
4281
4419
  color,
4282
4420
  margin: "20px 0 8px"
4283
4421
  });
4284
- var subtitleStyle9 = (color) => ({
4422
+ var subtitleStyle10 = (color) => ({
4285
4423
  fontSize: "0.9rem",
4286
4424
  color,
4287
4425
  margin: "0 0 24px",
@@ -4325,10 +4463,10 @@ function ConfirmSignScreen({
4325
4463
  ] }),
4326
4464
  children: [
4327
4465
  /* @__PURE__ */ jsx(ScreenHeader, { right: /* @__PURE__ */ jsx(SettingsMenu, { onLogout }) }),
4328
- /* @__PURE__ */ jsxs("div", { style: contentStyle7, children: [
4466
+ /* @__PURE__ */ jsxs("div", { style: contentStyle8, children: [
4329
4467
  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: [
4468
+ /* @__PURE__ */ jsx("h2", { style: headingStyle11(tokens.text), children: "Wallet authorized" }),
4469
+ /* @__PURE__ */ jsxs("p", { style: subtitleStyle11(tokens.textSecondary), children: [
4332
4470
  displayName,
4333
4471
  " approved the connection. Tap below to confirm your payment."
4334
4472
  ] }),
@@ -4341,7 +4479,7 @@ function ConfirmSignScreen({
4341
4479
  }
4342
4480
  );
4343
4481
  }
4344
- var contentStyle7 = {
4482
+ var contentStyle8 = {
4345
4483
  flex: 1,
4346
4484
  display: "flex",
4347
4485
  flexDirection: "column",
@@ -4356,14 +4494,14 @@ var logoStyle2 = {
4356
4494
  borderRadius: 14,
4357
4495
  objectFit: "contain"
4358
4496
  };
4359
- var headingStyle10 = (color) => ({
4497
+ var headingStyle11 = (color) => ({
4360
4498
  fontSize: "1.45rem",
4361
4499
  fontWeight: 700,
4362
4500
  letterSpacing: "-0.02em",
4363
4501
  color,
4364
4502
  margin: "20px 0 8px"
4365
4503
  });
4366
- var subtitleStyle10 = (color) => ({
4504
+ var subtitleStyle11 = (color) => ({
4367
4505
  fontSize: "0.9rem",
4368
4506
  color,
4369
4507
  margin: "0 0 24px",
@@ -4422,7 +4560,7 @@ var PaymentErrorBoundary = class extends Component {
4422
4560
  /* @__PURE__ */ jsx("path", { d: "M12 8v5", stroke: "#ef4444", strokeWidth: "1.5", strokeLinecap: "round" }),
4423
4561
  /* @__PURE__ */ jsx("circle", { cx: "12", cy: "16", r: "0.75", fill: "#ef4444" })
4424
4562
  ] }) }),
4425
- /* @__PURE__ */ jsx("h2", { style: headingStyle11, children: "Something went wrong" }),
4563
+ /* @__PURE__ */ jsx("h2", { style: headingStyle12, children: "Something went wrong" }),
4426
4564
  /* @__PURE__ */ jsx("p", { style: messageStyle, children: "An unexpected error occurred. Please try again." }),
4427
4565
  /* @__PURE__ */ jsx("button", { type: "button", onClick: this.handleReset, style: buttonStyle3, children: "Try again" })
4428
4566
  ] });
@@ -4442,7 +4580,7 @@ var containerStyle8 = {
4442
4580
  var iconStyle4 = {
4443
4581
  marginBottom: 20
4444
4582
  };
4445
- var headingStyle11 = {
4583
+ var headingStyle12 = {
4446
4584
  fontSize: "1.25rem",
4447
4585
  fontWeight: 700,
4448
4586
  color: "#1a1a1a",
@@ -4605,6 +4743,7 @@ function SwypePaymentInner({
4605
4743
  const [transfer, setTransfer] = useState(null);
4606
4744
  const [creatingTransfer, setCreatingTransfer] = useState(false);
4607
4745
  const [registeringPasskey, setRegisteringPasskey] = useState(false);
4746
+ const [verifyingPasskeyPopup, setVerifyingPasskeyPopup] = useState(false);
4608
4747
  const [passkeyPopupNeeded, setPasskeyPopupNeeded] = useState(
4609
4748
  () => isSafari() && isInCrossOriginIframe()
4610
4749
  );
@@ -4913,11 +5052,17 @@ function SwypePaymentInner({
4913
5052
  }
4914
5053
  if (cancelled) return;
4915
5054
  const credentialIds = allPasskeys.map((p) => p.credentialId);
5055
+ if (isSafari() && isInCrossOriginIframe()) {
5056
+ setStep("verify-passkey");
5057
+ return;
5058
+ }
4916
5059
  const matched = await findDevicePasskey(credentialIds);
4917
5060
  if (cancelled) return;
4918
5061
  if (matched) {
4919
5062
  setActiveCredentialId(matched);
4920
5063
  window.localStorage.setItem(ACTIVE_CREDENTIAL_STORAGE_KEY, matched);
5064
+ reportPasskeyActivity(apiBaseUrl, token, matched).catch(() => {
5065
+ });
4921
5066
  await restoreOrDeposit(matched, token);
4922
5067
  return;
4923
5068
  }
@@ -5439,6 +5584,32 @@ function SwypePaymentInner({
5439
5584
  setRegisteringPasskey(false);
5440
5585
  }
5441
5586
  }, [user, completePasskeyRegistration, getAccessToken, apiBaseUrl, knownCredentialIds]);
5587
+ const handleVerifyPasskeyViaPopup = useCallback(async () => {
5588
+ setVerifyingPasskeyPopup(true);
5589
+ setError(null);
5590
+ try {
5591
+ const matched = await findDevicePasskeyViaPopup({
5592
+ credentialIds: knownCredentialIds,
5593
+ rpId: resolvePasskeyRpId()
5594
+ });
5595
+ if (matched) {
5596
+ setActiveCredentialId(matched);
5597
+ window.localStorage.setItem(ACTIVE_CREDENTIAL_STORAGE_KEY, matched);
5598
+ const token = await getAccessToken();
5599
+ if (token) {
5600
+ reportPasskeyActivity(apiBaseUrl, token, matched).catch(() => {
5601
+ });
5602
+ }
5603
+ setStep("login");
5604
+ } else {
5605
+ setStep("create-passkey");
5606
+ }
5607
+ } catch {
5608
+ setStep("create-passkey");
5609
+ } finally {
5610
+ setVerifyingPasskeyPopup(false);
5611
+ }
5612
+ }, [knownCredentialIds, getAccessToken, apiBaseUrl]);
5442
5613
  const handleSelectProvider = useCallback((providerId) => {
5443
5614
  setSelectedProviderId(providerId);
5444
5615
  setSelectedAccountId(null);
@@ -5570,6 +5741,17 @@ function SwypePaymentInner({
5570
5741
  if ((step === "login" || step === "otp-verify") && authenticated) {
5571
5742
  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
5743
  }
5744
+ if (step === "verify-passkey") {
5745
+ return /* @__PURE__ */ jsx(
5746
+ VerifyPasskeyScreen,
5747
+ {
5748
+ onVerify: handleVerifyPasskeyViaPopup,
5749
+ onBack: handleLogout,
5750
+ verifying: verifyingPasskeyPopup,
5751
+ error
5752
+ }
5753
+ );
5754
+ }
5573
5755
  if (step === "create-passkey") {
5574
5756
  return /* @__PURE__ */ jsx(
5575
5757
  CreatePasskeyScreen,
@@ -5731,6 +5913,6 @@ function SwypePaymentInner({
5731
5913
  return null;
5732
5914
  }
5733
5915
 
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 };
5916
+ 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
5917
  //# sourceMappingURL=index.js.map
5736
5918
  //# sourceMappingURL=index.js.map