@swype-org/react-sdk 0.1.83 → 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.js CHANGED
@@ -713,7 +713,7 @@ function isSafari() {
713
713
  var POPUP_RESULT_TIMEOUT_MS = 12e4;
714
714
  var POPUP_CLOSED_POLL_MS = 500;
715
715
  var POPUP_CLOSED_GRACE_MS = 1e3;
716
- function createPasskeyViaPopup(options) {
716
+ function createPasskeyViaPopup(options, existingCredentialIds = []) {
717
717
  return new Promise((resolve, reject) => {
718
718
  const channelId = `swype-pk-${Date.now()}-${Math.random().toString(36).slice(2)}`;
719
719
  const payload = { ...options, channelId };
@@ -737,7 +737,19 @@ function createPasskeyViaPopup(options) {
737
737
  closedGraceTimer = setTimeout(() => {
738
738
  if (!settled) {
739
739
  cleanup();
740
- reject(new Error("Passkey setup window was closed before completing."));
740
+ checkServerForNewPasskey(
741
+ options.authToken,
742
+ options.apiBaseUrl,
743
+ existingCredentialIds
744
+ ).then((result) => {
745
+ if (result) {
746
+ resolve(result);
747
+ } else {
748
+ reject(new Error("Passkey setup window was closed before completing."));
749
+ }
750
+ }).catch(() => {
751
+ reject(new Error("Passkey setup window was closed before completing."));
752
+ });
741
753
  }
742
754
  }, POPUP_CLOSED_GRACE_MS);
743
755
  }
@@ -773,6 +785,78 @@ function createPasskeyViaPopup(options) {
773
785
  }
774
786
  });
775
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
+ }
848
+ async function checkServerForNewPasskey(authToken, apiBaseUrl, existingCredentialIds) {
849
+ if (!authToken || !apiBaseUrl) return null;
850
+ const res = await fetch(`${apiBaseUrl}/v1/users/config`, {
851
+ headers: { Authorization: `Bearer ${authToken}` }
852
+ });
853
+ if (!res.ok) return null;
854
+ const body = await res.json();
855
+ const passkeys = body.config.passkeys ?? [];
856
+ const existingSet = new Set(existingCredentialIds);
857
+ const newPasskey = passkeys.find((p) => !existingSet.has(p.credentialId));
858
+ return newPasskey ?? null;
859
+ }
776
860
 
777
861
  // src/hooks.ts
778
862
  var WALLET_CLIENT_MAX_ATTEMPTS = 15;
@@ -967,7 +1051,9 @@ function buildPasskeyPopupOptions(params) {
967
1051
  residentKey: "preferred",
968
1052
  userVerification: "required"
969
1053
  },
970
- timeout: 6e4
1054
+ timeout: 6e4,
1055
+ authToken: params.authToken,
1056
+ apiBaseUrl: params.apiBaseUrl
971
1057
  };
972
1058
  }
973
1059
  async function deviceHasPasskey(credentialId) {
@@ -2744,6 +2830,72 @@ var errorBannerStyle2 = (tokens) => ({
2744
2830
  width: "100%",
2745
2831
  textAlign: "left"
2746
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
+ });
2747
2899
  var WALLET_EMOJIS = {
2748
2900
  rabby: "\u{1F430}",
2749
2901
  ora: "\u2666\uFE0F",
@@ -2786,8 +2938,8 @@ function WalletPickerScreen({
2786
2938
  children: [
2787
2939
  /* @__PURE__ */ jsx(ScreenHeader, { title: "Set up Swype", onBack }),
2788
2940
  hasPending && /* @__PURE__ */ jsxs(Fragment, { children: [
2789
- /* @__PURE__ */ jsx("h2", { style: headingStyle4(tokens.text), children: "Continue where you left off" }),
2790
- /* @__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" }),
2791
2943
  /* @__PURE__ */ jsx("div", { style: pendingListStyle, children: pendingConnections.map((acct) => {
2792
2944
  const wallet = acct.wallets[0];
2793
2945
  const address = wallet ? truncateAddress(wallet.name) : void 0;
@@ -2827,8 +2979,8 @@ function WalletPickerScreen({
2827
2979
  /* @__PURE__ */ jsx("div", { style: dividerStyle2(tokens.border), children: /* @__PURE__ */ jsx("span", { style: dividerTextStyle(tokens.textMuted), children: "Or connect a new wallet" }) })
2828
2980
  ] }),
2829
2981
  !hasPending && /* @__PURE__ */ jsxs(Fragment, { children: [
2830
- /* @__PURE__ */ jsx("h2", { style: headingStyle4(tokens.text), children: "Where are your stablecoins?" }),
2831
- /* @__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" })
2832
2984
  ] }),
2833
2985
  /* @__PURE__ */ jsxs("div", { style: gridStyle, children: [
2834
2986
  displayProviders.map((p) => {
@@ -2881,14 +3033,14 @@ function WalletPickerScreen({
2881
3033
  }
2882
3034
  );
2883
3035
  }
2884
- var headingStyle4 = (color) => ({
3036
+ var headingStyle5 = (color) => ({
2885
3037
  fontSize: "1.35rem",
2886
3038
  fontWeight: 700,
2887
3039
  letterSpacing: "-0.02em",
2888
3040
  color,
2889
3041
  margin: "8px 0 4px"
2890
3042
  });
2891
- var subtitleStyle4 = (color) => ({
3043
+ var subtitleStyle5 = (color) => ({
2892
3044
  fontSize: "0.88rem",
2893
3045
  color,
2894
3046
  margin: "0 0 24px"
@@ -3064,9 +3216,9 @@ function SetupScreen({
3064
3216
  ] }),
3065
3217
  children: [
3066
3218
  /* @__PURE__ */ jsx(ScreenHeader, { title: "Swype Setup", onBack, right: /* @__PURE__ */ jsx(SettingsMenu, { onLogout }) }),
3067
- /* @__PURE__ */ jsx("h2", { style: headingStyle5(tokens.text), children: "Set up One-Tap deposits" }),
3068
- /* @__PURE__ */ jsx("p", { style: subtitleStyle5(tokens.textSecondary), children: "Set your limit for instant deposits. Like a contactless card \u2014 you choose the max." }),
3069
- 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 }),
3070
3222
  /* @__PURE__ */ jsxs("div", { style: balanceRowStyle, children: [
3071
3223
  /* @__PURE__ */ jsxs("div", { style: balanceLeftStyle, children: [
3072
3224
  /* @__PURE__ */ jsx("div", { style: coinIconStyle(tokens.accent), children: /* @__PURE__ */ jsxs("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", children: [
@@ -3144,20 +3296,20 @@ function SetupScreen({
3144
3296
  }
3145
3297
  );
3146
3298
  }
3147
- var headingStyle5 = (color) => ({
3299
+ var headingStyle6 = (color) => ({
3148
3300
  fontSize: "1.3rem",
3149
3301
  fontWeight: 700,
3150
3302
  letterSpacing: "-0.02em",
3151
3303
  color,
3152
3304
  margin: "8px 0 4px"
3153
3305
  });
3154
- var subtitleStyle5 = (color) => ({
3306
+ var subtitleStyle6 = (color) => ({
3155
3307
  fontSize: "0.86rem",
3156
3308
  color,
3157
3309
  margin: "0 0 24px",
3158
3310
  lineHeight: 1.5
3159
3311
  });
3160
- var errorBannerStyle3 = (tokens) => ({
3312
+ var errorBannerStyle4 = (tokens) => ({
3161
3313
  background: tokens.errorBg,
3162
3314
  border: `1px solid ${tokens.error}66`,
3163
3315
  borderRadius: 16,
@@ -3425,7 +3577,7 @@ function DepositScreen({
3425
3577
  "%)"
3426
3578
  ] }) : /* @__PURE__ */ jsx("div", { style: detailRowStyle(tokens.textMuted), children: "Fees calculated at time of transfer" })
3427
3579
  ] }),
3428
- error && /* @__PURE__ */ jsx("div", { style: errorBannerStyle4(tokens), children: error })
3580
+ error && /* @__PURE__ */ jsx("div", { style: errorBannerStyle5(tokens), children: error })
3429
3581
  ]
3430
3582
  }
3431
3583
  );
@@ -3493,7 +3645,7 @@ var detailRowStyle = (color) => ({
3493
3645
  color,
3494
3646
  marginBottom: 4
3495
3647
  });
3496
- var errorBannerStyle4 = (tokens) => ({
3648
+ var errorBannerStyle5 = (tokens) => ({
3497
3649
  background: tokens.errorBg,
3498
3650
  border: `1px solid ${tokens.error}66`,
3499
3651
  borderRadius: 16,
@@ -3592,22 +3744,22 @@ function SuccessScreen({
3592
3744
  right: /* @__PURE__ */ jsx(SettingsMenu, { onLogout })
3593
3745
  }
3594
3746
  ),
3595
- /* @__PURE__ */ jsxs("div", { style: contentStyle4, children: [
3747
+ /* @__PURE__ */ jsxs("div", { style: contentStyle5, children: [
3596
3748
  succeeded ? /* @__PURE__ */ jsxs(Fragment, { children: [
3597
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 }) }) }),
3598
- /* @__PURE__ */ jsxs("h2", { style: headingStyle6(tokens.text), children: [
3750
+ /* @__PURE__ */ jsxs("h2", { style: headingStyle7(tokens.text), children: [
3599
3751
  "$",
3600
3752
  amount.toFixed(2),
3601
3753
  " deposited"
3602
3754
  ] }),
3603
- merchantName && /* @__PURE__ */ jsxs("p", { style: subtitleStyle6(tokens.textSecondary), children: [
3755
+ merchantName && /* @__PURE__ */ jsxs("p", { style: subtitleStyle7(tokens.textSecondary), children: [
3604
3756
  "to ",
3605
3757
  merchantName
3606
3758
  ] })
3607
3759
  ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
3608
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 }) }) }),
3609
- /* @__PURE__ */ jsx("h2", { style: headingStyle6(tokens.text), children: "Transfer failed" }),
3610
- 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 })
3611
3763
  ] }),
3612
3764
  /* @__PURE__ */ jsxs("div", { style: summaryCardStyle(tokens), children: [
3613
3765
  sourceName && /* @__PURE__ */ jsxs("div", { style: summaryRowStyle, children: [
@@ -3639,21 +3791,21 @@ function SuccessScreen({
3639
3791
  }
3640
3792
  );
3641
3793
  }
3642
- var contentStyle4 = {
3794
+ var contentStyle5 = {
3643
3795
  flex: 1,
3644
3796
  display: "flex",
3645
3797
  flexDirection: "column",
3646
3798
  alignItems: "center",
3647
3799
  paddingTop: 16
3648
3800
  };
3649
- var headingStyle6 = (color) => ({
3801
+ var headingStyle7 = (color) => ({
3650
3802
  fontSize: "1.5rem",
3651
3803
  fontWeight: 700,
3652
3804
  letterSpacing: "-0.02em",
3653
3805
  color,
3654
3806
  margin: "20px 0 4px"
3655
3807
  });
3656
- var subtitleStyle6 = (color) => ({
3808
+ var subtitleStyle7 = (color) => ({
3657
3809
  fontSize: "0.9rem",
3658
3810
  color,
3659
3811
  margin: "0 0 20px"
@@ -3759,7 +3911,7 @@ function SelectSourceScreen({
3759
3911
  right: /* @__PURE__ */ jsx(SettingsMenu, { onLogout })
3760
3912
  }
3761
3913
  ),
3762
- /* @__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." }),
3763
3915
  /* @__PURE__ */ jsx("label", { style: labelStyle2(tokens.textSecondary), children: "Chain" }),
3764
3916
  /* @__PURE__ */ jsx("div", { style: optionListStyle, children: choices.map((chain) => {
3765
3917
  const isSelected = chain.chainName === selectedChainName;
@@ -3816,7 +3968,7 @@ function SelectSourceScreen({
3816
3968
  }
3817
3969
  );
3818
3970
  }
3819
- var subtitleStyle7 = (color) => ({
3971
+ var subtitleStyle8 = (color) => ({
3820
3972
  fontSize: "0.85rem",
3821
3973
  color,
3822
3974
  margin: "0 0 20px",
@@ -3931,8 +4083,8 @@ function AdvancedSourceScreen({
3931
4083
  right: /* @__PURE__ */ jsx("span", { style: advancedBadgeStyle(tokens.accent), children: "Advanced" })
3932
4084
  }
3933
4085
  ),
3934
- /* @__PURE__ */ jsx("h2", { style: headingStyle7(tokens.text), children: "Set up One-Tap deposits" }),
3935
- /* @__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." }),
3936
4088
  /* @__PURE__ */ jsx("label", { style: labelStyle3(tokens.textSecondary), children: "Select tokens to approve" }),
3937
4089
  /* @__PURE__ */ jsx("div", { style: chainListStyle, children: choices.map((chain) => {
3938
4090
  const isExpanded = expandedChain === chain.chainName;
@@ -3995,14 +4147,14 @@ var advancedBadgeStyle = (color) => ({
3995
4147
  padding: "3px 10px",
3996
4148
  letterSpacing: "0.02em"
3997
4149
  });
3998
- var headingStyle7 = (color) => ({
4150
+ var headingStyle8 = (color) => ({
3999
4151
  fontSize: "1.3rem",
4000
4152
  fontWeight: 700,
4001
4153
  letterSpacing: "-0.02em",
4002
4154
  color,
4003
4155
  margin: "8px 0 4px"
4004
4156
  });
4005
- var subtitleStyle8 = (color) => ({
4157
+ var subtitleStyle9 = (color) => ({
4006
4158
  fontSize: "0.86rem",
4007
4159
  color,
4008
4160
  margin: "0 0 20px",
@@ -4130,16 +4282,16 @@ function TransferStatusScreen({
4130
4282
  const steps = buildSteps(phase);
4131
4283
  return /* @__PURE__ */ jsxs(ScreenLayout, { children: [
4132
4284
  /* @__PURE__ */ jsx(ScreenHeader, { right: /* @__PURE__ */ jsx(SettingsMenu, { onLogout }) }),
4133
- /* @__PURE__ */ jsxs("div", { style: contentStyle5, children: [
4285
+ /* @__PURE__ */ jsxs("div", { style: contentStyle6, children: [
4134
4286
  /* @__PURE__ */ jsx(Spinner, { size: 48 }),
4135
- /* @__PURE__ */ jsx("h2", { style: headingStyle8(tokens.text), children: "Processing Transfer..." }),
4136
- 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 }),
4137
4289
  /* @__PURE__ */ jsx("div", { style: stepsWrapStyle, children: /* @__PURE__ */ jsx(StepList, { steps }) }),
4138
4290
  /* @__PURE__ */ jsx("p", { style: waitHintStyle(tokens.textMuted), children: "Usually takes a few seconds" })
4139
4291
  ] })
4140
4292
  ] });
4141
4293
  }
4142
- var contentStyle5 = {
4294
+ var contentStyle6 = {
4143
4295
  flex: 1,
4144
4296
  display: "flex",
4145
4297
  flexDirection: "column",
@@ -4148,14 +4300,14 @@ var contentStyle5 = {
4148
4300
  textAlign: "center",
4149
4301
  padding: "0 24px"
4150
4302
  };
4151
- var headingStyle8 = (color) => ({
4303
+ var headingStyle9 = (color) => ({
4152
4304
  fontSize: "1.45rem",
4153
4305
  fontWeight: 700,
4154
4306
  letterSpacing: "-0.02em",
4155
4307
  color,
4156
4308
  margin: "20px 0 16px"
4157
4309
  });
4158
- var errorBannerStyle5 = (tokens) => ({
4310
+ var errorBannerStyle6 = (tokens) => ({
4159
4311
  background: tokens.errorBg,
4160
4312
  border: `1px solid ${tokens.error}66`,
4161
4313
  borderRadius: 16,
@@ -4215,10 +4367,10 @@ function OpenWalletScreen({
4215
4367
  ] }),
4216
4368
  children: [
4217
4369
  /* @__PURE__ */ jsx(ScreenHeader, { right: /* @__PURE__ */ jsx(SettingsMenu, { onLogout }) }),
4218
- /* @__PURE__ */ jsxs("div", { style: contentStyle6, children: [
4370
+ /* @__PURE__ */ jsxs("div", { style: contentStyle7, children: [
4219
4371
  logoSrc ? /* @__PURE__ */ jsx("img", { src: logoSrc, alt: displayName, style: logoStyle }) : /* @__PURE__ */ jsx(Spinner, { size: 48 }),
4220
- /* @__PURE__ */ jsx("h2", { style: headingStyle9(tokens.text), children: loading ? "Connecting..." : `Open ${displayName}` }),
4221
- /* @__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.` }),
4222
4374
  !loading && /* @__PURE__ */ jsxs("div", { style: waitingBadgeStyle(tokens), children: [
4223
4375
  /* @__PURE__ */ jsx(Spinner, { size: 14 }),
4224
4376
  /* @__PURE__ */ jsx("span", { children: "Waiting for authorization..." })
@@ -4228,7 +4380,7 @@ function OpenWalletScreen({
4228
4380
  }
4229
4381
  );
4230
4382
  }
4231
- var contentStyle6 = {
4383
+ var contentStyle7 = {
4232
4384
  flex: 1,
4233
4385
  display: "flex",
4234
4386
  flexDirection: "column",
@@ -4248,14 +4400,14 @@ var logoStyle = {
4248
4400
  borderRadius: 14,
4249
4401
  objectFit: "contain"
4250
4402
  };
4251
- var headingStyle9 = (color) => ({
4403
+ var headingStyle10 = (color) => ({
4252
4404
  fontSize: "1.45rem",
4253
4405
  fontWeight: 700,
4254
4406
  letterSpacing: "-0.02em",
4255
4407
  color,
4256
4408
  margin: "20px 0 8px"
4257
4409
  });
4258
- var subtitleStyle9 = (color) => ({
4410
+ var subtitleStyle10 = (color) => ({
4259
4411
  fontSize: "0.9rem",
4260
4412
  color,
4261
4413
  margin: "0 0 24px",
@@ -4299,10 +4451,10 @@ function ConfirmSignScreen({
4299
4451
  ] }),
4300
4452
  children: [
4301
4453
  /* @__PURE__ */ jsx(ScreenHeader, { right: /* @__PURE__ */ jsx(SettingsMenu, { onLogout }) }),
4302
- /* @__PURE__ */ jsxs("div", { style: contentStyle7, children: [
4454
+ /* @__PURE__ */ jsxs("div", { style: contentStyle8, children: [
4303
4455
  logoSrc ? /* @__PURE__ */ jsx("img", { src: logoSrc, alt: displayName, style: logoStyle2 }) : /* @__PURE__ */ jsx(Spinner, { size: 48 }),
4304
- /* @__PURE__ */ jsx("h2", { style: headingStyle10(tokens.text), children: "Wallet authorized" }),
4305
- /* @__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: [
4306
4458
  displayName,
4307
4459
  " approved the connection. Tap below to confirm your payment."
4308
4460
  ] }),
@@ -4315,7 +4467,7 @@ function ConfirmSignScreen({
4315
4467
  }
4316
4468
  );
4317
4469
  }
4318
- var contentStyle7 = {
4470
+ var contentStyle8 = {
4319
4471
  flex: 1,
4320
4472
  display: "flex",
4321
4473
  flexDirection: "column",
@@ -4330,14 +4482,14 @@ var logoStyle2 = {
4330
4482
  borderRadius: 14,
4331
4483
  objectFit: "contain"
4332
4484
  };
4333
- var headingStyle10 = (color) => ({
4485
+ var headingStyle11 = (color) => ({
4334
4486
  fontSize: "1.45rem",
4335
4487
  fontWeight: 700,
4336
4488
  letterSpacing: "-0.02em",
4337
4489
  color,
4338
4490
  margin: "20px 0 8px"
4339
4491
  });
4340
- var subtitleStyle10 = (color) => ({
4492
+ var subtitleStyle11 = (color) => ({
4341
4493
  fontSize: "0.9rem",
4342
4494
  color,
4343
4495
  margin: "0 0 24px",
@@ -4396,7 +4548,7 @@ var PaymentErrorBoundary = class extends Component {
4396
4548
  /* @__PURE__ */ jsx("path", { d: "M12 8v5", stroke: "#ef4444", strokeWidth: "1.5", strokeLinecap: "round" }),
4397
4549
  /* @__PURE__ */ jsx("circle", { cx: "12", cy: "16", r: "0.75", fill: "#ef4444" })
4398
4550
  ] }) }),
4399
- /* @__PURE__ */ jsx("h2", { style: headingStyle11, children: "Something went wrong" }),
4551
+ /* @__PURE__ */ jsx("h2", { style: headingStyle12, children: "Something went wrong" }),
4400
4552
  /* @__PURE__ */ jsx("p", { style: messageStyle, children: "An unexpected error occurred. Please try again." }),
4401
4553
  /* @__PURE__ */ jsx("button", { type: "button", onClick: this.handleReset, style: buttonStyle3, children: "Try again" })
4402
4554
  ] });
@@ -4416,7 +4568,7 @@ var containerStyle8 = {
4416
4568
  var iconStyle4 = {
4417
4569
  marginBottom: 20
4418
4570
  };
4419
- var headingStyle11 = {
4571
+ var headingStyle12 = {
4420
4572
  fontSize: "1.25rem",
4421
4573
  fontWeight: 700,
4422
4574
  color: "#1a1a1a",
@@ -4579,6 +4731,7 @@ function SwypePaymentInner({
4579
4731
  const [transfer, setTransfer] = useState(null);
4580
4732
  const [creatingTransfer, setCreatingTransfer] = useState(false);
4581
4733
  const [registeringPasskey, setRegisteringPasskey] = useState(false);
4734
+ const [verifyingPasskeyPopup, setVerifyingPasskeyPopup] = useState(false);
4582
4735
  const [passkeyPopupNeeded, setPasskeyPopupNeeded] = useState(
4583
4736
  () => isSafari() && isInCrossOriginIframe()
4584
4737
  );
@@ -4586,6 +4739,7 @@ function SwypePaymentInner({
4586
4739
  if (typeof window === "undefined") return null;
4587
4740
  return window.localStorage.getItem(ACTIVE_CREDENTIAL_STORAGE_KEY);
4588
4741
  });
4742
+ const [knownCredentialIds, setKnownCredentialIds] = useState([]);
4589
4743
  const [authInput, setAuthInput] = useState("");
4590
4744
  const [verificationTarget, setVerificationTarget] = useState(null);
4591
4745
  const [otpCode, setOtpCode] = useState("");
@@ -4875,6 +5029,7 @@ function SwypePaymentInner({
4875
5029
  setOneTapLimit(config.defaultAllowance);
4876
5030
  }
4877
5031
  const allPasskeys = config.passkeys ?? (config.passkey ? [config.passkey] : []);
5032
+ setKnownCredentialIds(allPasskeys.map((p) => p.credentialId));
4878
5033
  if (allPasskeys.length === 0) {
4879
5034
  setStep("create-passkey");
4880
5035
  return;
@@ -4885,6 +5040,10 @@ function SwypePaymentInner({
4885
5040
  }
4886
5041
  if (cancelled) return;
4887
5042
  const credentialIds = allPasskeys.map((p) => p.credentialId);
5043
+ if (isSafari() && isInCrossOriginIframe()) {
5044
+ setStep("verify-passkey");
5045
+ return;
5046
+ }
4888
5047
  const matched = await findDevicePasskey(credentialIds);
4889
5048
  if (cancelled) return;
4890
5049
  if (matched) {
@@ -5391,12 +5550,18 @@ function SwypePaymentInner({
5391
5550
  setRegisteringPasskey(true);
5392
5551
  setError(null);
5393
5552
  try {
5553
+ const token = await getAccessToken();
5394
5554
  const passkeyDisplayName = user?.email?.address ?? user?.google?.name ?? user?.id ?? "Swype User";
5395
5555
  const popupOptions = buildPasskeyPopupOptions({
5396
5556
  userId: user?.id ?? "unknown",
5397
- displayName: passkeyDisplayName
5557
+ displayName: passkeyDisplayName,
5558
+ authToken: token ?? void 0,
5559
+ apiBaseUrl
5398
5560
  });
5399
- const { credentialId, publicKey } = await createPasskeyViaPopup(popupOptions);
5561
+ const { credentialId, publicKey } = await createPasskeyViaPopup(
5562
+ popupOptions,
5563
+ knownCredentialIds
5564
+ );
5400
5565
  await completePasskeyRegistration(credentialId, publicKey);
5401
5566
  } catch (err) {
5402
5567
  captureException(err);
@@ -5404,7 +5569,28 @@ function SwypePaymentInner({
5404
5569
  } finally {
5405
5570
  setRegisteringPasskey(false);
5406
5571
  }
5407
- }, [user, completePasskeyRegistration]);
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]);
5408
5594
  const handleSelectProvider = useCallback((providerId) => {
5409
5595
  setSelectedProviderId(providerId);
5410
5596
  setSelectedAccountId(null);
@@ -5536,6 +5722,17 @@ function SwypePaymentInner({
5536
5722
  if ((step === "login" || step === "otp-verify") && authenticated) {
5537
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..." }) }) });
5538
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
+ }
5539
5736
  if (step === "create-passkey") {
5540
5737
  return /* @__PURE__ */ jsx(
5541
5738
  CreatePasskeyScreen,
@@ -5697,6 +5894,6 @@ function SwypePaymentInner({
5697
5894
  return null;
5698
5895
  }
5699
5896
 
5700
- 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 };
5701
5898
  //# sourceMappingURL=index.js.map
5702
5899
  //# sourceMappingURL=index.js.map