@swype-org/react-sdk 0.1.82 → 0.1.84

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.cjs CHANGED
@@ -715,7 +715,8 @@ function isSafari() {
715
715
  }
716
716
  var POPUP_RESULT_TIMEOUT_MS = 12e4;
717
717
  var POPUP_CLOSED_POLL_MS = 500;
718
- function createPasskeyViaPopup(options) {
718
+ var POPUP_CLOSED_GRACE_MS = 1e3;
719
+ function createPasskeyViaPopup(options, existingCredentialIds = []) {
719
720
  return new Promise((resolve, reject) => {
720
721
  const channelId = `swype-pk-${Date.now()}-${Math.random().toString(36).slice(2)}`;
721
722
  const payload = { ...options, channelId };
@@ -732,10 +733,28 @@ function createPasskeyViaPopup(options) {
732
733
  cleanup();
733
734
  reject(new Error("Passkey creation timed out. Please try again."));
734
735
  }, POPUP_RESULT_TIMEOUT_MS);
736
+ let closedGraceTimer = null;
735
737
  const closedPoll = setInterval(() => {
736
738
  if (popup.closed) {
737
- cleanup();
738
- reject(new Error("Passkey setup window was closed before completing."));
739
+ clearInterval(closedPoll);
740
+ closedGraceTimer = setTimeout(() => {
741
+ if (!settled) {
742
+ cleanup();
743
+ checkServerForNewPasskey(
744
+ options.authToken,
745
+ options.apiBaseUrl,
746
+ existingCredentialIds
747
+ ).then((result) => {
748
+ if (result) {
749
+ resolve(result);
750
+ } else {
751
+ reject(new Error("Passkey setup window was closed before completing."));
752
+ }
753
+ }).catch(() => {
754
+ reject(new Error("Passkey setup window was closed before completing."));
755
+ });
756
+ }
757
+ }, POPUP_CLOSED_GRACE_MS);
739
758
  }
740
759
  }, POPUP_CLOSED_POLL_MS);
741
760
  function handleResult(data) {
@@ -763,11 +782,24 @@ function createPasskeyViaPopup(options) {
763
782
  function cleanup() {
764
783
  clearTimeout(timer);
765
784
  clearInterval(closedPoll);
785
+ if (closedGraceTimer) clearTimeout(closedGraceTimer);
766
786
  window.removeEventListener("message", postMessageHandler);
767
787
  channel?.close();
768
788
  }
769
789
  });
770
790
  }
791
+ async function checkServerForNewPasskey(authToken, apiBaseUrl, existingCredentialIds) {
792
+ if (!authToken || !apiBaseUrl) return null;
793
+ const res = await fetch(`${apiBaseUrl}/v1/users/config`, {
794
+ headers: { Authorization: `Bearer ${authToken}` }
795
+ });
796
+ if (!res.ok) return null;
797
+ const body = await res.json();
798
+ const passkeys = body.config.passkeys ?? [];
799
+ const existingSet = new Set(existingCredentialIds);
800
+ const newPasskey = passkeys.find((p) => !existingSet.has(p.credentialId));
801
+ return newPasskey ?? null;
802
+ }
771
803
 
772
804
  // src/hooks.ts
773
805
  var WALLET_CLIENT_MAX_ATTEMPTS = 15;
@@ -962,7 +994,9 @@ function buildPasskeyPopupOptions(params) {
962
994
  residentKey: "preferred",
963
995
  userVerification: "required"
964
996
  },
965
- timeout: 6e4
997
+ timeout: 6e4,
998
+ authToken: params.authToken,
999
+ apiBaseUrl: params.apiBaseUrl
966
1000
  };
967
1001
  }
968
1002
  async function deviceHasPasskey(credentialId) {
@@ -4581,6 +4615,7 @@ function SwypePaymentInner({
4581
4615
  if (typeof window === "undefined") return null;
4582
4616
  return window.localStorage.getItem(ACTIVE_CREDENTIAL_STORAGE_KEY);
4583
4617
  });
4618
+ const [knownCredentialIds, setKnownCredentialIds] = react.useState([]);
4584
4619
  const [authInput, setAuthInput] = react.useState("");
4585
4620
  const [verificationTarget, setVerificationTarget] = react.useState(null);
4586
4621
  const [otpCode, setOtpCode] = react.useState("");
@@ -4870,6 +4905,7 @@ function SwypePaymentInner({
4870
4905
  setOneTapLimit(config.defaultAllowance);
4871
4906
  }
4872
4907
  const allPasskeys = config.passkeys ?? (config.passkey ? [config.passkey] : []);
4908
+ setKnownCredentialIds(allPasskeys.map((p) => p.credentialId));
4873
4909
  if (allPasskeys.length === 0) {
4874
4910
  setStep("create-passkey");
4875
4911
  return;
@@ -5386,12 +5422,18 @@ function SwypePaymentInner({
5386
5422
  setRegisteringPasskey(true);
5387
5423
  setError(null);
5388
5424
  try {
5425
+ const token = await getAccessToken();
5389
5426
  const passkeyDisplayName = user?.email?.address ?? user?.google?.name ?? user?.id ?? "Swype User";
5390
5427
  const popupOptions = buildPasskeyPopupOptions({
5391
5428
  userId: user?.id ?? "unknown",
5392
- displayName: passkeyDisplayName
5429
+ displayName: passkeyDisplayName,
5430
+ authToken: token ?? void 0,
5431
+ apiBaseUrl
5393
5432
  });
5394
- const { credentialId, publicKey } = await createPasskeyViaPopup(popupOptions);
5433
+ const { credentialId, publicKey } = await createPasskeyViaPopup(
5434
+ popupOptions,
5435
+ knownCredentialIds
5436
+ );
5395
5437
  await completePasskeyRegistration(credentialId, publicKey);
5396
5438
  } catch (err) {
5397
5439
  captureException(err);
@@ -5399,7 +5441,7 @@ function SwypePaymentInner({
5399
5441
  } finally {
5400
5442
  setRegisteringPasskey(false);
5401
5443
  }
5402
- }, [user, completePasskeyRegistration]);
5444
+ }, [user, completePasskeyRegistration, getAccessToken, apiBaseUrl, knownCredentialIds]);
5403
5445
  const handleSelectProvider = react.useCallback((providerId) => {
5404
5446
  setSelectedProviderId(providerId);
5405
5447
  setSelectedAccountId(null);