@swype-org/react-sdk 0.1.329 → 0.1.339

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
@@ -838,6 +838,17 @@ declare function guestEntryMatchingRecommended(balances: GuestBalanceOptionInput
838
838
  tokenAddress: string;
839
839
  }): GuestTokenEntry | null;
840
840
 
841
+ /**
842
+ * Best-effort UI label for device biometrics (Face ID, Touch ID, Windows Hello, etc.).
843
+ * The web platform does not expose the exact modality; this uses coarse `userAgent`
844
+ * detection only — synchronous so it can run during render with no effects.
845
+ */
846
+ /**
847
+ * Returns short copy for passkey / biometric prompts based on the current environment.
848
+ * Does not call WebAuthn (no async); suitable for direct use in render.
849
+ */
850
+ declare function getDeviceBiometricUnlockText(): string;
851
+
841
852
  interface ScreenLayoutProps {
842
853
  children: ReactNode;
843
854
  /** Content pinned to the bottom of the screen (buttons, footer) */
@@ -958,8 +969,16 @@ interface PasskeyScreenProps {
958
969
  popupFallback?: boolean;
959
970
  /** Opens a pop-up window on the Blink domain for passkey registration. */
960
971
  onCreatePasskeyViaPopup?: () => void;
961
- }
962
- declare function PasskeyScreen({ onCreatePasskey, onBack, onLogout, creating, error, popupFallback, onCreatePasskeyViaPopup, }: PasskeyScreenProps): react_jsx_runtime.JSX.Element;
972
+ /** Creates a brand-new passkey on this device (for users who already have one on another device). */
973
+ onCreateNewPasskey?: () => void;
974
+ /** Popup fallback variant of onCreateNewPasskey. */
975
+ onCreateNewPasskeyViaPopup?: () => void;
976
+ /** When set, overrides `popupFallback` for the create-new link only. */
977
+ createNewPopupFallback?: boolean;
978
+ /** Loading state while a new passkey is being created. */
979
+ creatingNewPasskey?: boolean;
980
+ }
981
+ declare function PasskeyScreen({ onCreatePasskey, onBack, onLogout, creating, error, popupFallback, onCreatePasskeyViaPopup, onCreateNewPasskey, onCreateNewPasskeyViaPopup, createNewPopupFallback, creatingNewPasskey, }: PasskeyScreenProps): react_jsx_runtime.JSX.Element;
963
982
 
964
983
  interface VerifyPasskeyScreenProps {
965
984
  onVerify: () => void;
@@ -1172,7 +1191,7 @@ interface SuccessScreenProps {
1172
1191
  merchantName?: string;
1173
1192
  sourceName?: string;
1174
1193
  remainingLimit?: number | null;
1175
- onDone: () => void;
1194
+ onDone?: () => void;
1176
1195
  onLogout?: () => void;
1177
1196
  onIncreaseLimits?: () => void;
1178
1197
  onManageAccount?: () => void;
@@ -1322,4 +1341,4 @@ declare const BLINK_LOGO: string;
1322
1341
  /** @deprecated Use BLINK_LOGO instead. Kept for backward compatibility. */
1323
1342
  declare const BLINK_MASCOT: string;
1324
1343
 
1325
- export { type Account, type ActionExecutionResult, type AdvancedSettings, AdvancedSourceScreen, type Amount, type AuthorizationAction, type AuthorizationSession, AuthorizationSessionCancelledError, type AuthorizationSessionDetail, BLINK_LOGO, BLINK_MASCOT, BlinkLoadingScreen, BlinkPayment, type BlinkPaymentProps, BlinkProvider, type BlinkProviderProps, type Chain, ConfirmSignScreen, DepositScreen, type Destination, type ErrorResponse, type FlowPhase, FlowPhaseProvider, type GuestBalanceOptionInput, GuestPreauthLinkingScreen, GuestPreauthSetupCompleteScreen, type GuestTokenEntry, GuestTokenPickerScreen, type GuestTransferFee, IconCircle, InfoBanner, type ListResponse, LoginScreen, type MerchantAuthorization, type MerchantPublicKey, type MobileFlowState, OpenWalletScreen, OtpVerifyScreen, OutlineButton, PasskeyIframeBlockedError, PasskeyScreen, type PaymentPhase, PoweredByFooter, type PreciseMoney, PrimaryButton, type Provider, ScreenHeader, ScreenLayout, type ScreenName, SelectSourceScreen, SettingsMenu, SetupScreen, SetupStatusScreen, type SetupTokenOption, type SourceOption, type SourceSelection, type SourceType, Spinner, type StepItem, StepList, SuccessScreen, type ThemeMode, type ThemeTokens, type TokenBalance, TokenPickerScreen, type Transfer, type TransferDestination, type TransferPhase, TransferStatusScreen, type UserConfig, VerifyPasskeyScreen, type Wallet, WalletPickerScreen, type WalletSource, type WalletToken, api as blinkApi, buildPasskeyPopupOptions, createPasskeyCredential, createPasskeyViaPopup, darkTheme, deviceHasPasskey, findDevicePasskey, findDevicePasskeyViaPopup, getTheme, guestEntryMatchingRecommended, isAuthorizationSessionCancelled, isUserDismissedAuthorizationError, lightTheme, mapGuestPickerEntries, resolvePasskeyRpId, screenForPhase, useAuthorizationExecutor, useBlinkConfig, useBlinkDepositAmount, useTransferPolling, useTransferSigning };
1344
+ export { type Account, type ActionExecutionResult, type AdvancedSettings, AdvancedSourceScreen, type Amount, type AuthorizationAction, type AuthorizationSession, AuthorizationSessionCancelledError, type AuthorizationSessionDetail, BLINK_LOGO, BLINK_MASCOT, BlinkLoadingScreen, BlinkPayment, type BlinkPaymentProps, BlinkProvider, type BlinkProviderProps, type Chain, ConfirmSignScreen, DepositScreen, type Destination, type ErrorResponse, type FlowPhase, FlowPhaseProvider, type GuestBalanceOptionInput, GuestPreauthLinkingScreen, GuestPreauthSetupCompleteScreen, type GuestTokenEntry, GuestTokenPickerScreen, type GuestTransferFee, IconCircle, InfoBanner, type ListResponse, LoginScreen, type MerchantAuthorization, type MerchantPublicKey, type MobileFlowState, OpenWalletScreen, OtpVerifyScreen, OutlineButton, PasskeyIframeBlockedError, PasskeyScreen, type PaymentPhase, PoweredByFooter, type PreciseMoney, PrimaryButton, type Provider, ScreenHeader, ScreenLayout, type ScreenName, SelectSourceScreen, SettingsMenu, SetupScreen, SetupStatusScreen, type SetupTokenOption, type SourceOption, type SourceSelection, type SourceType, Spinner, type StepItem, StepList, SuccessScreen, type ThemeMode, type ThemeTokens, type TokenBalance, TokenPickerScreen, type Transfer, type TransferDestination, type TransferPhase, TransferStatusScreen, type UserConfig, VerifyPasskeyScreen, type Wallet, WalletPickerScreen, type WalletSource, type WalletToken, api as blinkApi, buildPasskeyPopupOptions, createPasskeyCredential, createPasskeyViaPopup, darkTheme, deviceHasPasskey, findDevicePasskey, findDevicePasskeyViaPopup, getDeviceBiometricUnlockText, getTheme, guestEntryMatchingRecommended, isAuthorizationSessionCancelled, isUserDismissedAuthorizationError, lightTheme, mapGuestPickerEntries, resolvePasskeyRpId, screenForPhase, useAuthorizationExecutor, useBlinkConfig, useBlinkDepositAmount, useTransferPolling, useTransferSigning };
package/dist/index.d.ts CHANGED
@@ -838,6 +838,17 @@ declare function guestEntryMatchingRecommended(balances: GuestBalanceOptionInput
838
838
  tokenAddress: string;
839
839
  }): GuestTokenEntry | null;
840
840
 
841
+ /**
842
+ * Best-effort UI label for device biometrics (Face ID, Touch ID, Windows Hello, etc.).
843
+ * The web platform does not expose the exact modality; this uses coarse `userAgent`
844
+ * detection only — synchronous so it can run during render with no effects.
845
+ */
846
+ /**
847
+ * Returns short copy for passkey / biometric prompts based on the current environment.
848
+ * Does not call WebAuthn (no async); suitable for direct use in render.
849
+ */
850
+ declare function getDeviceBiometricUnlockText(): string;
851
+
841
852
  interface ScreenLayoutProps {
842
853
  children: ReactNode;
843
854
  /** Content pinned to the bottom of the screen (buttons, footer) */
@@ -958,8 +969,16 @@ interface PasskeyScreenProps {
958
969
  popupFallback?: boolean;
959
970
  /** Opens a pop-up window on the Blink domain for passkey registration. */
960
971
  onCreatePasskeyViaPopup?: () => void;
961
- }
962
- declare function PasskeyScreen({ onCreatePasskey, onBack, onLogout, creating, error, popupFallback, onCreatePasskeyViaPopup, }: PasskeyScreenProps): react_jsx_runtime.JSX.Element;
972
+ /** Creates a brand-new passkey on this device (for users who already have one on another device). */
973
+ onCreateNewPasskey?: () => void;
974
+ /** Popup fallback variant of onCreateNewPasskey. */
975
+ onCreateNewPasskeyViaPopup?: () => void;
976
+ /** When set, overrides `popupFallback` for the create-new link only. */
977
+ createNewPopupFallback?: boolean;
978
+ /** Loading state while a new passkey is being created. */
979
+ creatingNewPasskey?: boolean;
980
+ }
981
+ declare function PasskeyScreen({ onCreatePasskey, onBack, onLogout, creating, error, popupFallback, onCreatePasskeyViaPopup, onCreateNewPasskey, onCreateNewPasskeyViaPopup, createNewPopupFallback, creatingNewPasskey, }: PasskeyScreenProps): react_jsx_runtime.JSX.Element;
963
982
 
964
983
  interface VerifyPasskeyScreenProps {
965
984
  onVerify: () => void;
@@ -1172,7 +1191,7 @@ interface SuccessScreenProps {
1172
1191
  merchantName?: string;
1173
1192
  sourceName?: string;
1174
1193
  remainingLimit?: number | null;
1175
- onDone: () => void;
1194
+ onDone?: () => void;
1176
1195
  onLogout?: () => void;
1177
1196
  onIncreaseLimits?: () => void;
1178
1197
  onManageAccount?: () => void;
@@ -1322,4 +1341,4 @@ declare const BLINK_LOGO: string;
1322
1341
  /** @deprecated Use BLINK_LOGO instead. Kept for backward compatibility. */
1323
1342
  declare const BLINK_MASCOT: string;
1324
1343
 
1325
- export { type Account, type ActionExecutionResult, type AdvancedSettings, AdvancedSourceScreen, type Amount, type AuthorizationAction, type AuthorizationSession, AuthorizationSessionCancelledError, type AuthorizationSessionDetail, BLINK_LOGO, BLINK_MASCOT, BlinkLoadingScreen, BlinkPayment, type BlinkPaymentProps, BlinkProvider, type BlinkProviderProps, type Chain, ConfirmSignScreen, DepositScreen, type Destination, type ErrorResponse, type FlowPhase, FlowPhaseProvider, type GuestBalanceOptionInput, GuestPreauthLinkingScreen, GuestPreauthSetupCompleteScreen, type GuestTokenEntry, GuestTokenPickerScreen, type GuestTransferFee, IconCircle, InfoBanner, type ListResponse, LoginScreen, type MerchantAuthorization, type MerchantPublicKey, type MobileFlowState, OpenWalletScreen, OtpVerifyScreen, OutlineButton, PasskeyIframeBlockedError, PasskeyScreen, type PaymentPhase, PoweredByFooter, type PreciseMoney, PrimaryButton, type Provider, ScreenHeader, ScreenLayout, type ScreenName, SelectSourceScreen, SettingsMenu, SetupScreen, SetupStatusScreen, type SetupTokenOption, type SourceOption, type SourceSelection, type SourceType, Spinner, type StepItem, StepList, SuccessScreen, type ThemeMode, type ThemeTokens, type TokenBalance, TokenPickerScreen, type Transfer, type TransferDestination, type TransferPhase, TransferStatusScreen, type UserConfig, VerifyPasskeyScreen, type Wallet, WalletPickerScreen, type WalletSource, type WalletToken, api as blinkApi, buildPasskeyPopupOptions, createPasskeyCredential, createPasskeyViaPopup, darkTheme, deviceHasPasskey, findDevicePasskey, findDevicePasskeyViaPopup, getTheme, guestEntryMatchingRecommended, isAuthorizationSessionCancelled, isUserDismissedAuthorizationError, lightTheme, mapGuestPickerEntries, resolvePasskeyRpId, screenForPhase, useAuthorizationExecutor, useBlinkConfig, useBlinkDepositAmount, useTransferPolling, useTransferSigning };
1344
+ export { type Account, type ActionExecutionResult, type AdvancedSettings, AdvancedSourceScreen, type Amount, type AuthorizationAction, type AuthorizationSession, AuthorizationSessionCancelledError, type AuthorizationSessionDetail, BLINK_LOGO, BLINK_MASCOT, BlinkLoadingScreen, BlinkPayment, type BlinkPaymentProps, BlinkProvider, type BlinkProviderProps, type Chain, ConfirmSignScreen, DepositScreen, type Destination, type ErrorResponse, type FlowPhase, FlowPhaseProvider, type GuestBalanceOptionInput, GuestPreauthLinkingScreen, GuestPreauthSetupCompleteScreen, type GuestTokenEntry, GuestTokenPickerScreen, type GuestTransferFee, IconCircle, InfoBanner, type ListResponse, LoginScreen, type MerchantAuthorization, type MerchantPublicKey, type MobileFlowState, OpenWalletScreen, OtpVerifyScreen, OutlineButton, PasskeyIframeBlockedError, PasskeyScreen, type PaymentPhase, PoweredByFooter, type PreciseMoney, PrimaryButton, type Provider, ScreenHeader, ScreenLayout, type ScreenName, SelectSourceScreen, SettingsMenu, SetupScreen, SetupStatusScreen, type SetupTokenOption, type SourceOption, type SourceSelection, type SourceType, Spinner, type StepItem, StepList, SuccessScreen, type ThemeMode, type ThemeTokens, type TokenBalance, TokenPickerScreen, type Transfer, type TransferDestination, type TransferPhase, TransferStatusScreen, type UserConfig, VerifyPasskeyScreen, type Wallet, WalletPickerScreen, type WalletSource, type WalletToken, api as blinkApi, buildPasskeyPopupOptions, createPasskeyCredential, createPasskeyViaPopup, darkTheme, deviceHasPasskey, findDevicePasskey, findDevicePasskeyViaPopup, getDeviceBiometricUnlockText, getTheme, guestEntryMatchingRecommended, isAuthorizationSessionCancelled, isUserDismissedAuthorizationError, lightTheme, mapGuestPickerEntries, resolvePasskeyRpId, screenForPhase, useAuthorizationExecutor, useBlinkConfig, useBlinkDepositAmount, useTransferPolling, useTransferSigning };
package/dist/index.js CHANGED
@@ -1948,7 +1948,7 @@ function resolvePhase(state) {
1948
1948
  const isFundingSourceSubflow = !state.loginRequested && (currentPhase.step === "token-picker" || currentPhase.step === "one-tap-setup" || currentPhase.step === "select-source" || currentPhase.step === "confirm-sign" || currentPhase.step === "guest-token-picker" && guestTokenPickerEligible);
1949
1949
  const walletPickerSwitchEligible = currentPhase.step === "wallet-picker" && currentPhase.reason === "switch" && !state.creatingTransfer && !(state.mobileFlow && state.deeplinkUri);
1950
1950
  const missingActivePasskeyCredential = state.passkeyConfigLoaded && !state.activeCredentialId;
1951
- const shouldPromptPasskeyVerification = missingActivePasskeyCredential && state.knownCredentialIds.length > 0 && state.passkeyPopupNeeded;
1951
+ const shouldPromptPasskeyVerification = missingActivePasskeyCredential && state.knownCredentialIds.length > 0;
1952
1952
  const guestPreauthClaimPending = state.guestPreauthAccountId != null && state.guestSessionToken != null && state.privyAuthenticated && state.activeCredentialId != null && !state.guestPreauthSetupCompletePending && !state.error;
1953
1953
  const branchGuestSetupComplete = state.guestPreauthSetupCompletePending && state.privyReady && state.privyAuthenticated;
1954
1954
  const branchKeepGuestPreauthPin = !branchGuestSetupComplete && guestPreauthPinsCurrentPhase;
@@ -3757,16 +3757,33 @@ function PasskeyScreen({
3757
3757
  creating,
3758
3758
  error,
3759
3759
  popupFallback = false,
3760
- onCreatePasskeyViaPopup
3760
+ onCreatePasskeyViaPopup,
3761
+ onCreateNewPasskey,
3762
+ onCreateNewPasskeyViaPopup,
3763
+ createNewPopupFallback,
3764
+ creatingNewPasskey
3761
3765
  }) {
3762
3766
  const { tokens } = useBlinkConfig();
3763
3767
  const handleCreate = popupFallback && onCreatePasskeyViaPopup ? onCreatePasskeyViaPopup : onCreatePasskey;
3764
3768
  const buttonLabel = popupFallback ? "Open Passkey Window" : "Verify Passkey";
3769
+ const showCreateNewLink = onCreateNewPasskey != null;
3770
+ const usePopupForNew = createNewPopupFallback ?? popupFallback;
3771
+ const handleCreateNew = usePopupForNew && onCreateNewPasskeyViaPopup ? onCreateNewPasskeyViaPopup : onCreateNewPasskey;
3765
3772
  return /* @__PURE__ */ jsxs(
3766
3773
  ScreenLayout,
3767
3774
  {
3768
3775
  footer: /* @__PURE__ */ jsxs(Fragment, { children: [
3769
- /* @__PURE__ */ jsx(PrimaryButton, { onClick: handleCreate, disabled: creating, loading: creating, children: buttonLabel }),
3776
+ /* @__PURE__ */ jsx(PrimaryButton, { onClick: handleCreate, disabled: creating || creatingNewPasskey, loading: creating, children: buttonLabel }),
3777
+ showCreateNewLink && /* @__PURE__ */ jsx(
3778
+ "button",
3779
+ {
3780
+ type: "button",
3781
+ onClick: handleCreateNew,
3782
+ disabled: creatingNewPasskey || creating,
3783
+ style: createNewLinkStyle(tokens.textMuted),
3784
+ children: creatingNewPasskey ? "Creating passkey\u2026" : "Create a new passkey for this device"
3785
+ }
3786
+ ),
3770
3787
  /* @__PURE__ */ jsx(PoweredByFooter, {})
3771
3788
  ] }),
3772
3789
  children: [
@@ -3801,6 +3818,17 @@ var subtitleStyle3 = (color) => ({
3801
3818
  margin: "0 0 20px",
3802
3819
  lineHeight: 1.5
3803
3820
  });
3821
+ var createNewLinkStyle = (color) => ({
3822
+ background: "none",
3823
+ border: "none",
3824
+ color,
3825
+ fontSize: "0.85rem",
3826
+ cursor: "pointer",
3827
+ padding: "8px 16px",
3828
+ textDecoration: "underline",
3829
+ fontFamily: "inherit",
3830
+ width: "100%"
3831
+ });
3804
3832
  var errorBannerStyle2 = (tokens) => ({
3805
3833
  background: tokens.errorBg,
3806
3834
  border: `1px solid ${tokens.error}66`,
@@ -4014,7 +4042,7 @@ function WalletPickerScreen({
4014
4042
  },
4015
4043
  loading: connecting || preparing,
4016
4044
  disabled: preparing,
4017
- children: preparing ? "Preparing..." : `Open ${selectedProvider.name} to Link`
4045
+ children: preparing ? "Preparing..." : `Open ${selectedProvider.name} to Deposit`
4018
4046
  }
4019
4047
  ),
4020
4048
  /* @__PURE__ */ jsx(PoweredByFooter, {})
@@ -4888,8 +4916,7 @@ function isPreciseMoneyNonPositive(fee) {
4888
4916
  return Number.isFinite(n) && n <= 0;
4889
4917
  }
4890
4918
  function formatNonPositiveFeeDisplay(fee) {
4891
- if (fee.currency === "USD") return "Under $0.01";
4892
- return `Less than 0.01 ${fee.currency}`;
4919
+ return "< $0.01";
4893
4920
  }
4894
4921
  function formatPreciseMoneyForDisplay(fee) {
4895
4922
  const raw = fee.value.trim();
@@ -4984,13 +5011,14 @@ function DepositScreen({
4984
5011
  const selectedProviderLogo = KNOWN_LOGOS[selectedProviderName.toLowerCase()];
4985
5012
  const totalAccountBalance = selectedAccount ? selectedAccount.wallets.reduce((sum, w) => sum + w.balance.available.amount, 0) : availableBalance;
4986
5013
  const isLowBalance = availableBalance < minDepositFloor;
5014
+ const insufficientFunds = availableBalance < amount;
4987
5015
  const exceedsLimit = remainingLimit != null && amount > remainingLimit && !isLowBalance;
4988
- const canDeposit = amount >= minDepositFloor && !exceedsLimit && !isLowBalance && !processing;
5016
+ const canDeposit = amount >= minDepositFloor && !exceedsLimit && !isLowBalance && !insufficientFunds && !processing;
4989
5017
  return /* @__PURE__ */ jsxs(
4990
5018
  ScreenLayout,
4991
5019
  {
4992
5020
  footer: /* @__PURE__ */ jsxs(Fragment, { children: [
4993
- !accountPickerOpen && !tokenPickerOpen && (exceedsLimit && onIncreaseLimit ? /* @__PURE__ */ jsx(PrimaryButton, { onClick: onIncreaseLimit, loading: increasingLimit, children: "Increase limit" }) : /* @__PURE__ */ jsx(PrimaryButton, { onClick: () => onDeposit(amount), disabled: !canDeposit, loading: processing, children: "Confirm" })),
5021
+ !accountPickerOpen && !tokenPickerOpen && (exceedsLimit && onIncreaseLimit ? /* @__PURE__ */ jsx(PrimaryButton, { onClick: onIncreaseLimit, loading: increasingLimit, children: "Increase limit" }) : /* @__PURE__ */ jsx(PrimaryButton, { onClick: () => onDeposit(amount), disabled: !canDeposit, loading: processing, children: insufficientFunds ? "Insufficient Funds" : "Confirm" })),
4994
5022
  /* @__PURE__ */ jsx(PoweredByFooter, {})
4995
5023
  ] }),
4996
5024
  children: [
@@ -5070,7 +5098,7 @@ function DepositScreen({
5070
5098
  return /* @__PURE__ */ jsx("div", { style: feeRowContainerStyle, "aria-live": "polite", children: /* @__PURE__ */ jsx("span", { style: feeRowLabelStyle(tokens.textMuted), children: "Getting fee estimate\u2026" }) });
5071
5099
  }
5072
5100
  if (quoteFee) {
5073
- const feeText = isPreciseMoneyNonPositive(quoteFee) ? formatNonPositiveFeeDisplay(quoteFee) : formatPreciseMoneyForDisplay(quoteFee);
5101
+ const feeText = isPreciseMoneyNonPositive(quoteFee) ? formatNonPositiveFeeDisplay() : formatPreciseMoneyForDisplay(quoteFee);
5074
5102
  return /* @__PURE__ */ jsxs("div", { style: feeRowContainerStyle, "aria-live": "polite", children: [
5075
5103
  /* @__PURE__ */ jsx("span", { style: feeRowLabelStyle(tokens.textMuted), children: "Fee estimate: " }),
5076
5104
  /* @__PURE__ */ jsx("span", { style: feeRowAmountStyle(tokens.textSecondary), children: feeText })
@@ -5511,6 +5539,25 @@ var feeRowAmountStyle = (color) => ({
5511
5539
  color,
5512
5540
  fontVariantNumeric: "tabular-nums"
5513
5541
  });
5542
+
5543
+ // src/deviceBiometricUnlockText.ts
5544
+ var FALLBACK = "Biometric verification";
5545
+ function getDeviceBiometricUnlockText() {
5546
+ const ua = typeof navigator !== "undefined" && typeof navigator.userAgent === "string" ? navigator.userAgent : "";
5547
+ if (/iPhone|iPad|iPod/i.test(ua)) {
5548
+ return "Face ID or Touch ID";
5549
+ }
5550
+ if (/Android/i.test(ua)) {
5551
+ return "Fingerprint or face unlock";
5552
+ }
5553
+ if (/Windows NT/i.test(ua)) {
5554
+ return "Windows Hello";
5555
+ }
5556
+ if (/Macintosh|Mac OS X/i.test(ua)) {
5557
+ return "Touch ID";
5558
+ }
5559
+ return FALLBACK;
5560
+ }
5514
5561
  function SuccessScreen({
5515
5562
  amount,
5516
5563
  currency: _currency,
@@ -5532,9 +5579,9 @@ function SuccessScreen({
5532
5579
  {
5533
5580
  footer: /* @__PURE__ */ jsxs(Fragment, { children: [
5534
5581
  isGuestDepositSuccess ? /* @__PURE__ */ jsxs(Fragment, { children: [
5535
- /* @__PURE__ */ jsx(PrimaryButton, { onClick: onPreauthorize, children: "Set up one tap" }),
5536
- /* @__PURE__ */ jsx("button", { type: "button", onClick: onDone, style: skipButtonStyle(tokens.textMuted), children: "Return to app" })
5537
- ] }) : /* @__PURE__ */ jsx(PrimaryButton, { onClick: onDone, children: succeeded ? "Done" : "Try again" }),
5582
+ /* @__PURE__ */ jsx(PrimaryButton, { onClick: onPreauthorize, children: "Setup" }),
5583
+ onDone && /* @__PURE__ */ jsx("button", { type: "button", onClick: onDone, style: skipButtonStyle(tokens.textMuted), children: "Return to app" })
5584
+ ] }) : onDone ? /* @__PURE__ */ jsx(PrimaryButton, { onClick: onDone, children: succeeded ? "Done" : "Try again" }) : null,
5538
5585
  onManageAccount && /* @__PURE__ */ jsx("button", { type: "button", onClick: onManageAccount, style: manageStyle(tokens.textMuted), children: "Manage Blink account \u2192" }),
5539
5586
  /* @__PURE__ */ jsx(PoweredByFooter, {})
5540
5587
  ] }),
@@ -5542,13 +5589,17 @@ function SuccessScreen({
5542
5589
  /* @__PURE__ */ jsx(ScreenHeader, { onLogout }),
5543
5590
  /* @__PURE__ */ jsxs("div", { style: screenContentStyle, children: [
5544
5591
  isGuestDepositSuccess ? /* @__PURE__ */ jsxs("div", { style: contentStyleCompact, children: [
5545
- /* @__PURE__ */ jsxs("h2", { style: headingStyle7(tokens.text), children: [
5546
- "$",
5547
- amount.toFixed(2),
5548
- " deposited"
5592
+ /* @__PURE__ */ jsx("p", { style: subtitleStyle7(tokens.text), children: "Success" }),
5593
+ /* @__PURE__ */ jsxs("p", { style: headingStyle7(tokens.text), children: [
5594
+ "Make next time ",
5595
+ /* @__PURE__ */ jsx("br", {}),
5596
+ " faster \u2014 and free"
5549
5597
  ] }),
5550
- /* @__PURE__ */ jsx("p", { style: { ...subtitleStyle7(tokens.text), fontWeight: 600, margin: "0 0 8px" }, children: "Next time, do it in one tap" }),
5551
- /* @__PURE__ */ jsx("p", { style: subtitleStyle7(tokens.textSecondary), children: "Set up one tap for this wallet and skip the extra steps." })
5598
+ /* @__PURE__ */ jsxs("p", { style: subtitleStyle7(tokens.textSecondary), children: [
5599
+ "Future deposits are just ",
5600
+ getDeviceBiometricUnlockText(),
5601
+ " and go."
5602
+ ] })
5552
5603
  ] }) : succeeded ? /* @__PURE__ */ jsxs("div", { style: contentStyleCompact, children: [
5553
5604
  /* @__PURE__ */ jsxs("h2", { style: headingStyle7(tokens.text), children: [
5554
5605
  "$",
@@ -6708,7 +6759,7 @@ function GuestTokenPickerScreen({
6708
6759
  return /* @__PURE__ */ jsx("div", { style: feeRowContainerStyle2, "aria-live": "polite", children: /* @__PURE__ */ jsx("span", { style: feeRowLabelStyle2(t.textMuted), children: "Getting fee estimate\u2026" }) });
6709
6760
  }
6710
6761
  if (quoteFee) {
6711
- const feeText = isPreciseMoneyNonPositive(quoteFee) ? formatNonPositiveFeeDisplay(quoteFee) : formatPreciseMoneyForDisplay(quoteFee);
6762
+ const feeText = isPreciseMoneyNonPositive(quoteFee) ? formatNonPositiveFeeDisplay() : formatPreciseMoneyForDisplay(quoteFee);
6712
6763
  return /* @__PURE__ */ jsxs("div", { style: feeRowContainerStyle2, "aria-live": "polite", children: [
6713
6764
  /* @__PURE__ */ jsx("span", { style: feeRowLabelStyle2(t.textMuted), children: "Fee estimate: " }),
6714
6765
  /* @__PURE__ */ jsx("span", { style: feeRowAmountStyle2(t.textSecondary), children: feeText })
@@ -7308,13 +7359,15 @@ function StepRendererContent({
7308
7359
  return /* @__PURE__ */ jsx(
7309
7360
  PasskeyScreen,
7310
7361
  {
7311
- onCreatePasskey: handlers.onRegisterPasskey,
7362
+ onCreatePasskey: handlers.onVerifyPasskey,
7312
7363
  onBack: handlers.onLogout,
7313
7364
  onLogout: handlers.onLogout,
7314
- creating: state.verifyingPasskeyPopup,
7365
+ creating: state.registeringPasskey,
7315
7366
  error: state.error,
7316
- popupFallback: true,
7317
- onCreatePasskeyViaPopup: handlers.onVerifyPasskeyViaPopup
7367
+ onCreateNewPasskey: handlers.onCreateNewPasskey,
7368
+ onCreateNewPasskeyViaPopup: handlers.onCreateNewPasskeyViaPopup,
7369
+ createNewPopupFallback: state.passkeyPopupNeeded,
7370
+ creatingNewPasskey: state.registeringPasskey
7318
7371
  }
7319
7372
  );
7320
7373
  case "wallet-picker": {
@@ -7864,6 +7917,53 @@ function usePasskeyHandlers(dispatch, apiBaseUrl, accounts, knownCredentialIds)
7864
7917
  dispatch({ type: "SET_REGISTERING_PASSKEY", value: false });
7865
7918
  }
7866
7919
  }, [user, knownCredentialIds, activateExistingCredential, completePasskeyRegistration, dispatch]);
7920
+ const handleVerifyPasskey = useCallback(async () => {
7921
+ dispatch({ type: "SET_REGISTERING_PASSKEY", value: true });
7922
+ dispatch({ type: "SET_ERROR", error: null });
7923
+ try {
7924
+ const matched = await findDevicePasskey(knownCredentialIds);
7925
+ if (matched) {
7926
+ await activateExistingCredential(matched);
7927
+ } else {
7928
+ dispatch({
7929
+ type: "SET_ERROR",
7930
+ error: "No matching passkey found on this device. Please try again."
7931
+ });
7932
+ }
7933
+ } catch (err) {
7934
+ captureException(err);
7935
+ dispatch({
7936
+ type: "SET_ERROR",
7937
+ error: err instanceof Error ? err.message : "Passkey verification failed."
7938
+ });
7939
+ } finally {
7940
+ dispatch({ type: "SET_REGISTERING_PASSKEY", value: false });
7941
+ }
7942
+ }, [knownCredentialIds, activateExistingCredential, dispatch]);
7943
+ const handleCreateNewPasskey = useCallback(async () => {
7944
+ dispatch({ type: "SET_REGISTERING_PASSKEY", value: true });
7945
+ dispatch({ type: "SET_ERROR", error: null });
7946
+ try {
7947
+ const passkeyDisplayName = user?.email?.address ?? user?.google?.name ?? user?.id ?? "Blink User";
7948
+ const { credentialId, publicKey } = await createPasskeyCredential({
7949
+ userId: user?.id ?? "unknown",
7950
+ displayName: passkeyDisplayName
7951
+ });
7952
+ await completePasskeyRegistration(credentialId, publicKey);
7953
+ } catch (err) {
7954
+ if (err instanceof PasskeyIframeBlockedError) {
7955
+ dispatch({ type: "SET_PASSKEY_POPUP_NEEDED", needed: true });
7956
+ } else {
7957
+ captureException(err);
7958
+ dispatch({
7959
+ type: "SET_ERROR",
7960
+ error: err instanceof Error ? err.message : "Failed to register passkey"
7961
+ });
7962
+ }
7963
+ } finally {
7964
+ dispatch({ type: "SET_REGISTERING_PASSKEY", value: false });
7965
+ }
7966
+ }, [user, completePasskeyRegistration, dispatch]);
7867
7967
  const handleCreatePasskeyViaPopup = useCallback(async () => {
7868
7968
  dispatch({ type: "SET_REGISTERING_PASSKEY", value: true });
7869
7969
  dispatch({ type: "SET_ERROR", error: null });
@@ -7910,6 +8010,35 @@ function usePasskeyHandlers(dispatch, apiBaseUrl, accounts, knownCredentialIds)
7910
8010
  dispatch({ type: "SET_REGISTERING_PASSKEY", value: false });
7911
8011
  }
7912
8012
  }, [user, knownCredentialIds, getAccessToken, apiBaseUrl, activateExistingCredential, dispatch]);
8013
+ const handleCreateNewPasskeyViaPopup = useCallback(async () => {
8014
+ dispatch({ type: "SET_REGISTERING_PASSKEY", value: true });
8015
+ dispatch({ type: "SET_ERROR", error: null });
8016
+ try {
8017
+ const token = await getAccessToken();
8018
+ const passkeyDisplayName = user?.email?.address ?? user?.google?.name ?? user?.id ?? "Blink User";
8019
+ const popupOptions = buildPasskeyPopupOptions({
8020
+ userId: user?.id ?? "unknown",
8021
+ displayName: passkeyDisplayName,
8022
+ authToken: token ?? void 0,
8023
+ apiBaseUrl
8024
+ });
8025
+ const { credentialId, publicKey } = await createPasskeyViaPopup(popupOptions);
8026
+ dispatch({ type: "PASSKEY_ACTIVATED", credentialId, publicKey });
8027
+ localStorage.setItem(ACTIVE_CREDENTIAL_STORAGE_KEY, credentialId);
8028
+ if (token) {
8029
+ reportPasskeyActivity(apiBaseUrl, token, credentialId).catch(() => {
8030
+ });
8031
+ }
8032
+ } catch (err) {
8033
+ captureException(err);
8034
+ dispatch({
8035
+ type: "SET_ERROR",
8036
+ error: err instanceof Error ? err.message : "Failed to register passkey"
8037
+ });
8038
+ } finally {
8039
+ dispatch({ type: "SET_REGISTERING_PASSKEY", value: false });
8040
+ }
8041
+ }, [user, getAccessToken, apiBaseUrl, dispatch]);
7913
8042
  const handleVerifyPasskeyViaPopup = useCallback(async () => {
7914
8043
  dispatch({ type: "SET_VERIFYING_PASSKEY", value: true });
7915
8044
  dispatch({ type: "SET_ERROR", error: null });
@@ -7952,7 +8081,10 @@ function usePasskeyHandlers(dispatch, apiBaseUrl, accounts, knownCredentialIds)
7952
8081
  }, [knownCredentialIds, getAccessToken, apiBaseUrl, dispatch]);
7953
8082
  return {
7954
8083
  handleRegisterPasskey,
8084
+ handleVerifyPasskey,
8085
+ handleCreateNewPasskey,
7955
8086
  handleCreatePasskeyViaPopup,
8087
+ handleCreateNewPasskeyViaPopup,
7956
8088
  handleVerifyPasskeyViaPopup,
7957
8089
  checkingPasskeyRef
7958
8090
  };
@@ -9570,28 +9702,6 @@ function usePasskeyCheckEffect(deps) {
9570
9702
  await restoreState(activeCredentialId, token);
9571
9703
  return;
9572
9704
  }
9573
- if (cancelled) return;
9574
- const credentialIds = allPasskeys.map((p) => p.credentialId);
9575
- let matched = null;
9576
- if (isSafari() && isInCrossOriginIframe()) {
9577
- matched = await findDevicePasskeyViaPopup({
9578
- credentialIds,
9579
- rpId: resolvePasskeyRpId(),
9580
- authToken: token ?? void 0,
9581
- apiBaseUrl
9582
- });
9583
- } else {
9584
- matched = await findDevicePasskey(credentialIds);
9585
- }
9586
- if (cancelled) return;
9587
- if (matched) {
9588
- const publicKey = allPasskeys.find((p) => p.credentialId === matched)?.publicKey;
9589
- dispatch({ type: "PASSKEY_ACTIVATED", credentialId: matched, publicKey });
9590
- window.localStorage.setItem(ACTIVE_CREDENTIAL_STORAGE_KEY, matched);
9591
- reportPasskeyActivity(apiBaseUrl, token, matched).catch(() => {
9592
- });
9593
- await restoreState(matched, token);
9594
- }
9595
9705
  } catch (err) {
9596
9706
  dispatch({
9597
9707
  type: "PASSKEY_CONFIG_LOADED",
@@ -10654,7 +10764,7 @@ function BlinkPaymentInner({
10654
10764
  paymentReducer,
10655
10765
  {
10656
10766
  depositAmount,
10657
- passkeyPopupNeeded: isSafari() && isInCrossOriginIframe(),
10767
+ passkeyPopupNeeded: isSafari() && isInCrossOriginIframe() && !isDesktop,
10658
10768
  activeCredentialId: typeof window === "undefined" ? null : window.localStorage.getItem(ACTIVE_CREDENTIAL_STORAGE_KEY)
10659
10769
  },
10660
10770
  createInitialState
@@ -11010,7 +11120,10 @@ function BlinkPaymentInner({
11010
11120
  dispatch({ type: "BACK_TO_LOGIN" });
11011
11121
  },
11012
11122
  onRegisterPasskey: passkey.handleRegisterPasskey,
11123
+ onVerifyPasskey: passkey.handleVerifyPasskey,
11124
+ onCreateNewPasskey: passkey.handleCreateNewPasskey,
11013
11125
  onCreatePasskeyViaPopup: passkey.handleCreatePasskeyViaPopup,
11126
+ onCreateNewPasskeyViaPopup: passkey.handleCreateNewPasskeyViaPopup,
11014
11127
  onVerifyPasskeyViaPopup: passkey.handleVerifyPasskeyViaPopup,
11015
11128
  onPrepareProvider: provider.handlePrepareProvider,
11016
11129
  onSelectProvider: provider.handleSelectProvider,
@@ -11122,6 +11235,6 @@ function BlinkPaymentInner({
11122
11235
  );
11123
11236
  }
11124
11237
 
11125
- export { AdvancedSourceScreen, AuthorizationSessionCancelledError, BLINK_LOGO, BLINK_MASCOT, BlinkLoadingScreen, BlinkPayment, BlinkProvider, ConfirmSignScreen, DepositScreen, FlowPhaseProvider, GuestPreauthLinkingScreen, GuestPreauthSetupCompleteScreen, GuestTokenPickerScreen, IconCircle, InfoBanner, LoginScreen, OpenWalletScreen, OtpVerifyScreen, OutlineButton, PasskeyIframeBlockedError, PasskeyScreen, PoweredByFooter, PrimaryButton, ScreenHeader, ScreenLayout, SelectSourceScreen, SettingsMenu, SetupScreen, SetupStatusScreen, Spinner, StepList, SuccessScreen, TokenPickerScreen, TransferStatusScreen, VerifyPasskeyScreen, WalletPickerScreen, api_exports as blinkApi, buildPasskeyPopupOptions, createPasskeyCredential, createPasskeyViaPopup, darkTheme, deviceHasPasskey, findDevicePasskey, findDevicePasskeyViaPopup, getTheme, guestEntryMatchingRecommended, isAuthorizationSessionCancelled, isUserDismissedAuthorizationError, lightTheme, mapGuestPickerEntries, resolvePasskeyRpId, screenForPhase, useAuthorizationExecutor, useBlinkConfig, useBlinkDepositAmount, useTransferPolling, useTransferSigning };
11238
+ export { AdvancedSourceScreen, AuthorizationSessionCancelledError, BLINK_LOGO, BLINK_MASCOT, BlinkLoadingScreen, BlinkPayment, BlinkProvider, ConfirmSignScreen, DepositScreen, FlowPhaseProvider, GuestPreauthLinkingScreen, GuestPreauthSetupCompleteScreen, GuestTokenPickerScreen, IconCircle, InfoBanner, LoginScreen, OpenWalletScreen, OtpVerifyScreen, OutlineButton, PasskeyIframeBlockedError, PasskeyScreen, PoweredByFooter, PrimaryButton, ScreenHeader, ScreenLayout, SelectSourceScreen, SettingsMenu, SetupScreen, SetupStatusScreen, Spinner, StepList, SuccessScreen, TokenPickerScreen, TransferStatusScreen, VerifyPasskeyScreen, WalletPickerScreen, api_exports as blinkApi, buildPasskeyPopupOptions, createPasskeyCredential, createPasskeyViaPopup, darkTheme, deviceHasPasskey, findDevicePasskey, findDevicePasskeyViaPopup, getDeviceBiometricUnlockText, getTheme, guestEntryMatchingRecommended, isAuthorizationSessionCancelled, isUserDismissedAuthorizationError, lightTheme, mapGuestPickerEntries, resolvePasskeyRpId, screenForPhase, useAuthorizationExecutor, useBlinkConfig, useBlinkDepositAmount, useTransferPolling, useTransferSigning };
11126
11239
  //# sourceMappingURL=index.js.map
11127
11240
  //# sourceMappingURL=index.js.map