@swype-org/react-sdk 0.1.80 → 0.1.81

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
@@ -389,7 +389,8 @@ declare function SwypePayment(props: SwypePaymentProps): react_jsx_runtime.JSX.E
389
389
  * call (works in Chrome/Firefox with the iframe permissions policy). If
390
390
  * that fails (Safari), we open a same-origin pop-up window on the Swype
391
391
  * domain to perform the ceremony, then relay the result back via
392
- * `postMessage`.
392
+ * `BroadcastChannel` (Safari strips `window.opener` from popups opened
393
+ * by cross-origin iframes, so `postMessage` via opener doesn't work).
393
394
  *
394
395
  * Passkey *assertion* (`navigator.credentials.get`) still delegates to
395
396
  * the parent page via postMessage as before.
@@ -419,12 +420,19 @@ interface PasskeyPopupOptions {
419
420
  userVerification?: string;
420
421
  };
421
422
  timeout?: number;
423
+ /** Populated by `createPasskeyViaPopup`; not set by callers. */
424
+ channelId?: string;
422
425
  }
423
426
  /**
424
427
  * Opens a same-origin pop-up window on the Swype domain to perform
425
428
  * passkey creation. Used as a fallback when Safari blocks
426
429
  * `navigator.credentials.create()` inside a cross-origin iframe.
427
430
  *
431
+ * Communication uses `BroadcastChannel` because Safari strips
432
+ * `window.opener` from popups opened by cross-origin iframes.
433
+ * Falls back to `window.postMessage` for browsers that preserve the
434
+ * opener reference.
435
+ *
428
436
  * Must be called from a user-gesture handler (e.g. button click) to
429
437
  * avoid the browser's pop-up blocker.
430
438
  */
package/dist/index.d.ts CHANGED
@@ -389,7 +389,8 @@ declare function SwypePayment(props: SwypePaymentProps): react_jsx_runtime.JSX.E
389
389
  * call (works in Chrome/Firefox with the iframe permissions policy). If
390
390
  * that fails (Safari), we open a same-origin pop-up window on the Swype
391
391
  * domain to perform the ceremony, then relay the result back via
392
- * `postMessage`.
392
+ * `BroadcastChannel` (Safari strips `window.opener` from popups opened
393
+ * by cross-origin iframes, so `postMessage` via opener doesn't work).
393
394
  *
394
395
  * Passkey *assertion* (`navigator.credentials.get`) still delegates to
395
396
  * the parent page via postMessage as before.
@@ -419,12 +420,19 @@ interface PasskeyPopupOptions {
419
420
  userVerification?: string;
420
421
  };
421
422
  timeout?: number;
423
+ /** Populated by `createPasskeyViaPopup`; not set by callers. */
424
+ channelId?: string;
422
425
  }
423
426
  /**
424
427
  * Opens a same-origin pop-up window on the Swype domain to perform
425
428
  * passkey creation. Used as a fallback when Safari blocks
426
429
  * `navigator.credentials.create()` inside a cross-origin iframe.
427
430
  *
431
+ * Communication uses `BroadcastChannel` because Safari strips
432
+ * `window.opener` from popups opened by cross-origin iframes.
433
+ * Falls back to `window.postMessage` for browsers that preserve the
434
+ * opener reference.
435
+ *
428
436
  * Must be called from a user-gesture handler (e.g. button click) to
429
437
  * avoid the browser's pop-up blocker.
430
438
  */
package/dist/index.js CHANGED
@@ -698,13 +698,17 @@ var POPUP_RESULT_TIMEOUT_MS = 12e4;
698
698
  var POPUP_CLOSED_POLL_MS = 500;
699
699
  function createPasskeyViaPopup(options) {
700
700
  return new Promise((resolve, reject) => {
701
- const encoded = btoa(JSON.stringify(options));
701
+ const channelId = `swype-pk-${Date.now()}-${Math.random().toString(36).slice(2)}`;
702
+ const payload = { ...options, channelId };
703
+ const encoded = btoa(JSON.stringify(payload));
702
704
  const popupUrl = `${window.location.origin}/passkey-register#${encoded}`;
703
705
  const popup = window.open(popupUrl, "swype-passkey");
704
706
  if (!popup) {
705
707
  reject(new Error("Pop-up blocked. Please allow pop-ups for this site and try again."));
706
708
  return;
707
709
  }
710
+ let settled = false;
711
+ const channel = typeof BroadcastChannel !== "undefined" ? new BroadcastChannel(channelId) : null;
708
712
  const timer = setTimeout(() => {
709
713
  cleanup();
710
714
  reject(new Error("Passkey creation timed out. Please try again."));
@@ -715,11 +719,11 @@ function createPasskeyViaPopup(options) {
715
719
  reject(new Error("Passkey setup window was closed before completing."));
716
720
  }
717
721
  }, POPUP_CLOSED_POLL_MS);
718
- const handler = (event) => {
719
- if (event.source !== popup) return;
720
- const data = event.data;
722
+ function handleResult(data) {
723
+ if (settled) return;
721
724
  if (!data || typeof data !== "object") return;
722
725
  if (data.type !== "swype:passkey-popup-result") return;
726
+ settled = true;
723
727
  cleanup();
724
728
  if (data.error) {
725
729
  reject(new Error(data.error));
@@ -728,13 +732,21 @@ function createPasskeyViaPopup(options) {
728
732
  } else {
729
733
  reject(new Error("Invalid passkey popup response."));
730
734
  }
735
+ }
736
+ if (channel) {
737
+ channel.onmessage = (event) => handleResult(event.data);
738
+ }
739
+ const postMessageHandler = (event) => {
740
+ if (event.source !== popup) return;
741
+ handleResult(event.data);
731
742
  };
743
+ window.addEventListener("message", postMessageHandler);
732
744
  function cleanup() {
733
745
  clearTimeout(timer);
734
746
  clearInterval(closedPoll);
735
- window.removeEventListener("message", handler);
747
+ window.removeEventListener("message", postMessageHandler);
748
+ channel?.close();
736
749
  }
737
- window.addEventListener("message", handler);
738
750
  });
739
751
  }
740
752