@swype-org/react-sdk 0.1.86 → 0.1.88

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
@@ -728,10 +728,10 @@ function isSafari() {
728
728
  var POPUP_RESULT_TIMEOUT_MS = 12e4;
729
729
  var POPUP_CLOSED_POLL_MS = 500;
730
730
  var POPUP_CLOSED_GRACE_MS = 1e3;
731
- function createPasskeyViaPopup(options, existingCredentialIds = []) {
731
+ function createPasskeyViaPopup(options) {
732
732
  return new Promise((resolve, reject) => {
733
- const channelId = `swype-pk-${Date.now()}-${Math.random().toString(36).slice(2)}`;
734
- const payload = { ...options, channelId };
733
+ const verificationToken = crypto.randomUUID();
734
+ const payload = { ...options, verificationToken };
735
735
  const encoded = btoa(JSON.stringify(payload));
736
736
  const popupUrl = `${window.location.origin}/passkey-register#${encoded}`;
737
737
  const popup = window.open(popupUrl, "swype-passkey");
@@ -740,22 +740,21 @@ function createPasskeyViaPopup(options, existingCredentialIds = []) {
740
740
  return;
741
741
  }
742
742
  let settled = false;
743
- const channel = typeof BroadcastChannel !== "undefined" ? new BroadcastChannel(channelId) : null;
744
743
  const timer = setTimeout(() => {
745
744
  cleanup();
746
745
  reject(new Error("Passkey creation timed out. Please try again."));
747
746
  }, POPUP_RESULT_TIMEOUT_MS);
748
- let closedGraceTimer = null;
749
747
  const closedPoll = setInterval(() => {
750
748
  if (popup.closed) {
751
749
  clearInterval(closedPoll);
752
- closedGraceTimer = setTimeout(() => {
750
+ setTimeout(() => {
753
751
  if (!settled) {
752
+ settled = true;
754
753
  cleanup();
755
- checkServerForNewPasskey(
754
+ checkServerForPasskeyByToken(
756
755
  options.authToken,
757
756
  options.apiBaseUrl,
758
- existingCredentialIds
757
+ verificationToken
759
758
  ).then((result) => {
760
759
  if (result) {
761
760
  resolve(result);
@@ -769,42 +768,20 @@ function createPasskeyViaPopup(options, existingCredentialIds = []) {
769
768
  }, POPUP_CLOSED_GRACE_MS);
770
769
  }
771
770
  }, POPUP_CLOSED_POLL_MS);
772
- function handleResult(data) {
773
- if (settled) return;
774
- if (!data || typeof data !== "object") return;
775
- if (data.type !== "swype:passkey-popup-result") return;
776
- settled = true;
777
- cleanup();
778
- if (data.error) {
779
- reject(new Error(data.error));
780
- } else if (data.result) {
781
- resolve(data.result);
782
- } else {
783
- reject(new Error("Invalid passkey popup response."));
784
- }
785
- }
786
- if (channel) {
787
- channel.onmessage = (event) => handleResult(event.data);
788
- }
789
- const postMessageHandler = (event) => {
790
- if (event.source !== popup) return;
791
- handleResult(event.data);
792
- };
793
- window.addEventListener("message", postMessageHandler);
794
771
  function cleanup() {
795
772
  clearTimeout(timer);
796
773
  clearInterval(closedPoll);
797
- if (closedGraceTimer) clearTimeout(closedGraceTimer);
798
- window.removeEventListener("message", postMessageHandler);
799
- channel?.close();
800
774
  }
801
775
  });
802
776
  }
803
777
  var VERIFY_POPUP_TIMEOUT_MS = 6e4;
804
778
  function findDevicePasskeyViaPopup(options) {
805
779
  return new Promise((resolve, reject) => {
806
- const channelId = `swype-pv-${Date.now()}-${Math.random().toString(36).slice(2)}`;
807
- const payload = { ...options, channelId };
780
+ const verificationToken = crypto.randomUUID();
781
+ const payload = {
782
+ ...options,
783
+ verificationToken
784
+ };
808
785
  const encoded = btoa(JSON.stringify(payload));
809
786
  const popupUrl = `${window.location.origin}/passkey-verify#${encoded}`;
810
787
  const popup = window.open(popupUrl, "swype-passkey-verify");
@@ -813,7 +790,6 @@ function findDevicePasskeyViaPopup(options) {
813
790
  return;
814
791
  }
815
792
  let settled = false;
816
- const channel = typeof BroadcastChannel !== "undefined" ? new BroadcastChannel(channelId) : null;
817
793
  const timer = setTimeout(() => {
818
794
  cleanup();
819
795
  resolve(null);
@@ -823,44 +799,28 @@ function findDevicePasskeyViaPopup(options) {
823
799
  clearInterval(closedPoll);
824
800
  setTimeout(() => {
825
801
  if (!settled) {
802
+ settled = true;
826
803
  cleanup();
827
- resolve(null);
804
+ checkServerForPasskeyByToken(
805
+ options.authToken,
806
+ options.apiBaseUrl,
807
+ verificationToken
808
+ ).then((result) => {
809
+ resolve(result?.credentialId ?? null);
810
+ }).catch(() => {
811
+ resolve(null);
812
+ });
828
813
  }
829
814
  }, POPUP_CLOSED_GRACE_MS);
830
815
  }
831
816
  }, POPUP_CLOSED_POLL_MS);
832
- function handleResult(data) {
833
- if (settled) return;
834
- if (!data || typeof data !== "object") return;
835
- if (data.type !== "swype:passkey-verify-result") return;
836
- settled = true;
837
- cleanup();
838
- if (data.error) {
839
- resolve(null);
840
- } else if (data.result && typeof data.result === "object") {
841
- const result = data.result;
842
- resolve(result.credentialId ?? null);
843
- } else {
844
- resolve(null);
845
- }
846
- }
847
- if (channel) {
848
- channel.onmessage = (event) => handleResult(event.data);
849
- }
850
- const postMessageHandler = (event) => {
851
- if (event.source !== popup) return;
852
- handleResult(event.data);
853
- };
854
- window.addEventListener("message", postMessageHandler);
855
817
  function cleanup() {
856
818
  clearTimeout(timer);
857
819
  clearInterval(closedPoll);
858
- window.removeEventListener("message", postMessageHandler);
859
- channel?.close();
860
820
  }
861
821
  });
862
822
  }
863
- async function checkServerForNewPasskey(authToken, apiBaseUrl, existingCredentialIds) {
823
+ async function checkServerForPasskeyByToken(authToken, apiBaseUrl, verificationToken) {
864
824
  if (!authToken || !apiBaseUrl) return null;
865
825
  const res = await fetch(`${apiBaseUrl}/v1/users/config`, {
866
826
  headers: { Authorization: `Bearer ${authToken}` }
@@ -868,9 +828,8 @@ async function checkServerForNewPasskey(authToken, apiBaseUrl, existingCredentia
868
828
  if (!res.ok) return null;
869
829
  const body = await res.json();
870
830
  const passkeys = body.config.passkeys ?? [];
871
- const existingSet = new Set(existingCredentialIds);
872
- const newPasskey = passkeys.find((p) => !existingSet.has(p.credentialId));
873
- return newPasskey ?? null;
831
+ const matched = passkeys.find((p) => p.lastVerificationToken === verificationToken);
832
+ return matched ? { credentialId: matched.credentialId, publicKey: matched.publicKey } : null;
874
833
  }
875
834
 
876
835
  // src/hooks.ts
@@ -5575,30 +5534,42 @@ function SwypePaymentInner({
5575
5534
  authToken: token ?? void 0,
5576
5535
  apiBaseUrl
5577
5536
  });
5578
- const { credentialId, publicKey } = await createPasskeyViaPopup(
5579
- popupOptions,
5580
- knownCredentialIds
5581
- );
5582
- await completePasskeyRegistration(credentialId, publicKey);
5537
+ const { credentialId } = await createPasskeyViaPopup(popupOptions);
5538
+ setActiveCredentialId(credentialId);
5539
+ localStorage.setItem(ACTIVE_CREDENTIAL_STORAGE_KEY, credentialId);
5540
+ setPasskeyPopupNeeded(false);
5541
+ const resolved = resolvePostAuthStep({
5542
+ hasPasskey: true,
5543
+ accounts,
5544
+ persistedMobileFlow: loadMobileFlowState(),
5545
+ mobileSetupInProgress: mobileSetupFlowRef.current,
5546
+ connectingNewAccount
5547
+ });
5548
+ if (resolved.clearPersistedFlow) {
5549
+ clearMobileFlowState();
5550
+ }
5551
+ setStep(resolved.step);
5583
5552
  } catch (err) {
5584
5553
  captureException(err);
5585
5554
  setError(err instanceof Error ? err.message : "Failed to register passkey");
5586
5555
  } finally {
5587
5556
  setRegisteringPasskey(false);
5588
5557
  }
5589
- }, [user, completePasskeyRegistration, getAccessToken, apiBaseUrl, knownCredentialIds]);
5558
+ }, [user, getAccessToken, apiBaseUrl, accounts, connectingNewAccount]);
5590
5559
  const handleVerifyPasskeyViaPopup = react.useCallback(async () => {
5591
5560
  setVerifyingPasskeyPopup(true);
5592
5561
  setError(null);
5593
5562
  try {
5563
+ const token = await getAccessToken();
5594
5564
  const matched = await findDevicePasskeyViaPopup({
5595
5565
  credentialIds: knownCredentialIds,
5596
- rpId: resolvePasskeyRpId()
5566
+ rpId: resolvePasskeyRpId(),
5567
+ authToken: token ?? void 0,
5568
+ apiBaseUrl
5597
5569
  });
5598
5570
  if (matched) {
5599
5571
  setActiveCredentialId(matched);
5600
5572
  window.localStorage.setItem(ACTIVE_CREDENTIAL_STORAGE_KEY, matched);
5601
- const token = await getAccessToken();
5602
5573
  if (token) {
5603
5574
  reportPasskeyActivity(apiBaseUrl, token, matched).catch(() => {
5604
5575
  });