@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 +45 -74
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +20 -23
- package/dist/index.d.ts +20 -23
- package/dist/index.js +45 -74
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
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
|
|
731
|
+
function createPasskeyViaPopup(options) {
|
|
732
732
|
return new Promise((resolve, reject) => {
|
|
733
|
-
const
|
|
734
|
-
const payload = { ...options,
|
|
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
|
-
|
|
750
|
+
setTimeout(() => {
|
|
753
751
|
if (!settled) {
|
|
752
|
+
settled = true;
|
|
754
753
|
cleanup();
|
|
755
|
-
|
|
754
|
+
checkServerForPasskeyByToken(
|
|
756
755
|
options.authToken,
|
|
757
756
|
options.apiBaseUrl,
|
|
758
|
-
|
|
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
|
|
807
|
-
const payload = {
|
|
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
|
-
|
|
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
|
|
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
|
|
872
|
-
|
|
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
|
|
5579
|
-
|
|
5580
|
-
|
|
5581
|
-
);
|
|
5582
|
-
|
|
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,
|
|
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
|
});
|