@benji-money/connect-sdk 1.1.4-beta.4 → 1.1.4-beta.5

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.
@@ -110,7 +110,7 @@ var ConnectSDK = (() => {
110
110
  // src/utils/config.ts
111
111
  var buildContext = () => ({
112
112
  namespace: "benji-connect-sdk" ? "benji-connect-sdk" : "benji-connect-sdk",
113
- version: "1.1.4-beta.4" ? String("1.1.4-beta.4") : "0.0.0"
113
+ version: "1.1.4-beta.5" ? String("1.1.4-beta.5") : "0.0.0"
114
114
  });
115
115
  function isBenjiConnectEnvironment(environment) {
116
116
  return environment === "local" /* LOCAL */ || environment === "development" /* DEVELOPMENT */ || environment === "sandbox" /* SANDBOX */ || environment === "production" /* PRODUCTION */;
@@ -711,10 +711,11 @@ var ConnectSDK = (() => {
711
711
  "request_code_exchange",
712
712
  "request_code_with_login",
713
713
  "request_code_with_phone",
714
- "request_loyalty_verification",
715
- "request_phone_verification"
714
+ "request_phone_verification",
715
+ "request_loyalty_verification"
716
716
  ]);
717
717
  var CONNECT_MESSAGE_TYPES = new Set(Object.values(BenjiConnectEventType));
718
+ var LOGIN_PARTNER_POPUP_NAME = "benji_partner_auth";
718
719
  function isAuthMessageType(data2) {
719
720
  if (!data2 || typeof data2 !== "object") return false;
720
721
  const type = data2.type;
@@ -723,9 +724,18 @@ var ConnectSDK = (() => {
723
724
  function shouldRelayMessage(mode, data2) {
724
725
  return mode === 5 /* LOGIN */ && isAuthMessageType(data2);
725
726
  }
727
+ function isMessageWindow(source) {
728
+ if (!source || typeof source !== "object") return false;
729
+ try {
730
+ return typeof source.closed === "boolean";
731
+ } catch {
732
+ return false;
733
+ }
734
+ }
726
735
  function sourceOpenerIsHost(source) {
727
736
  try {
728
- return source instanceof Window && source.opener === window;
737
+ if (!isMessageWindow(source)) return false;
738
+ return source.opener === window;
729
739
  } catch {
730
740
  return false;
731
741
  }
@@ -740,7 +750,53 @@ var ConnectSDK = (() => {
740
750
  if (sourceOpenerIsHost(event.source)) {
741
751
  return true;
742
752
  }
743
- return event.source instanceof Window && event.origin === connectOrigin && event.source !== iframeWindow;
753
+ return isMessageWindow(event.source) && event.origin === connectOrigin && event.source !== iframeWindow;
754
+ }
755
+ function canDeliverAuthToConnectIframe(iframe) {
756
+ var _a;
757
+ const iframeWindow = (_a = iframe == null ? void 0 : iframe.contentWindow) != null ? _a : null;
758
+ if (!iframeWindow) return false;
759
+ try {
760
+ const href = iframeWindow.location.href;
761
+ return Boolean(href) && href !== "about:blank" && href !== "";
762
+ } catch {
763
+ return true;
764
+ }
765
+ }
766
+ function authMessageType(data2) {
767
+ if (!data2 || typeof data2 !== "object") return void 0;
768
+ const type = data2.type;
769
+ return typeof type === "string" ? type : void 0;
770
+ }
771
+ function resolveLoginPartnerWindow(loginPopup, lastVerifiedPopupSource) {
772
+ var _a;
773
+ const candidates = [];
774
+ if (lastVerifiedPopupSource && !lastVerifiedPopupSource.closed) {
775
+ candidates.push(lastVerifiedPopupSource);
776
+ }
777
+ if (loginPopup && !loginPopup.closed && loginPopup !== lastVerifiedPopupSource) {
778
+ candidates.push(loginPopup);
779
+ }
780
+ if (candidates.length === 0) {
781
+ try {
782
+ const named = window.open("", LOGIN_PARTNER_POPUP_NAME);
783
+ if (named && !named.closed) {
784
+ console.debug("[Benji Connect SDK] LOGIN named_reacquire", { success: true });
785
+ candidates.push(named);
786
+ } else {
787
+ console.debug("[Benji Connect SDK] LOGIN named_reacquire", { success: false });
788
+ }
789
+ } catch {
790
+ console.debug("[Benji Connect SDK] LOGIN named_reacquire", { success: false });
791
+ }
792
+ }
793
+ return (_a = candidates[0]) != null ? _a : null;
794
+ }
795
+ function describeLoginPartnerWindowTarget(target, loginPopup, lastVerifiedPopupSource) {
796
+ if (!target) return "none";
797
+ if (target === lastVerifiedPopupSource) return "lastVerified";
798
+ if (target === loginPopup) return "loginPopup";
799
+ return "named";
744
800
  }
745
801
  function isConnectMessageType(data2) {
746
802
  if (!data2 || typeof data2 !== "object") return false;
@@ -861,6 +917,7 @@ var ConnectSDK = (() => {
861
917
  };
862
918
 
863
919
  // src/router/message.ts
920
+ var IFRAME_DELIVERABILITY_POLL_MS = 100;
864
921
  var _MessageRouter = class _MessageRouter {
865
922
  static configureMessageRouter(config) {
866
923
  this.onSuccess = config.onSuccess;
@@ -876,8 +933,10 @@ var ConnectSDK = (() => {
876
933
  this.loginPopup = context.loginPopup;
877
934
  this.mode = context.mode;
878
935
  this.connectOrigin = new URL(Endpoints.benji_connect_auth_url).origin;
879
- if (this.isIframeReady) {
936
+ if (this.canDeliverToConnectIframe()) {
880
937
  this.flushPendingPopupAuth();
938
+ } else {
939
+ this.startIframeDeliverabilityPoll();
881
940
  }
882
941
  }
883
942
  static resetIframeReady() {
@@ -885,6 +944,9 @@ var ConnectSDK = (() => {
885
944
  }
886
945
  static setMode(mode) {
887
946
  this.mode = mode;
947
+ if (mode !== 5 /* LOGIN */) {
948
+ this.stopIframeDeliverabilityPoll();
949
+ }
888
950
  }
889
951
  static addEventListeners() {
890
952
  if (this.configuredListeners) return;
@@ -897,6 +959,7 @@ var ConnectSDK = (() => {
897
959
  window.removeEventListener("error", this.errorEventHandler);
898
960
  window.removeEventListener("unhandledrejection", this.errorEventHandler);
899
961
  window.removeEventListener("message", this.messageEventHandler);
962
+ this.stopIframeDeliverabilityPoll();
900
963
  this.configuredListeners = false;
901
964
  this.iframe = null;
902
965
  this.loginPopup = null;
@@ -904,6 +967,7 @@ var ConnectSDK = (() => {
904
967
  this.connectOrigin = "";
905
968
  this.isIframeReady = false;
906
969
  this.pendingPopupAuth = [];
970
+ this.lastVerifiedPopupSource = null;
907
971
  }
908
972
  static handleErrorMessage(event) {
909
973
  switch (event.type) {
@@ -923,29 +987,89 @@ var ConnectSDK = (() => {
923
987
  }
924
988
  }
925
989
  }
926
- // Forward popup/tab auth payloads into Connect. Queue until the iframe has loaded;
927
- // otherwise fast SSO (Safari or already-authenticated) can arrive before contentWindow is usable.
990
+ static canDeliverToConnectIframe() {
991
+ return canDeliverAuthToConnectIframe(this.iframe);
992
+ }
993
+ static startIframeDeliverabilityPoll() {
994
+ if (this.iframeDeliverabilityPoll !== null || this.mode !== 5 /* LOGIN */ || this.pendingPopupAuth.length === 0) {
995
+ return;
996
+ }
997
+ this.iframeDeliverabilityPoll = window.setInterval(() => {
998
+ if (this.mode !== 5 /* LOGIN */ || this.pendingPopupAuth.length === 0) {
999
+ this.stopIframeDeliverabilityPoll();
1000
+ return;
1001
+ }
1002
+ if (this.canDeliverToConnectIframe()) {
1003
+ this.flushPendingPopupAuth();
1004
+ }
1005
+ }, IFRAME_DELIVERABILITY_POLL_MS);
1006
+ }
1007
+ static stopIframeDeliverabilityPoll() {
1008
+ if (this.iframeDeliverabilityPoll === null) return;
1009
+ window.clearInterval(this.iframeDeliverabilityPoll);
1010
+ this.iframeDeliverabilityPoll = null;
1011
+ }
1012
+ // Forward popup/tab auth payloads into Connect. Queue until deliverable.
928
1013
  static relayToIframe(event) {
929
1014
  var _a;
1015
+ const type = authMessageType(event.data);
1016
+ const deliverable = this.canDeliverToConnectIframe();
930
1017
  const iframeWindow = (_a = this.iframe) == null ? void 0 : _a.contentWindow;
931
- if (!this.isIframeReady || !iframeWindow) {
1018
+ if (!iframeWindow || !deliverable) {
932
1019
  this.pendingPopupAuth.push(event);
1020
+ this.startIframeDeliverabilityPoll();
1021
+ console.debug("[Benji Connect SDK] LOGIN relayToIframe queued", {
1022
+ type,
1023
+ queued: true,
1024
+ pendingCount: this.pendingPopupAuth.length,
1025
+ isIframeReady: this.isIframeReady,
1026
+ deliverable
1027
+ });
933
1028
  return;
934
1029
  }
1030
+ if (this.pendingPopupAuth.length > 0) {
1031
+ this.flushPendingPopupAuth();
1032
+ }
935
1033
  iframeWindow.postMessage(event.data, this.connectOrigin);
1034
+ console.debug("[Benji Connect SDK] LOGIN relayToIframe posted", {
1035
+ type,
1036
+ queued: false,
1037
+ pendingCount: this.pendingPopupAuth.length,
1038
+ isIframeReady: this.isIframeReady,
1039
+ deliverable
1040
+ });
936
1041
  }
937
1042
  static markIframeReady(iframe) {
938
1043
  if (this.iframe !== iframe) return;
939
1044
  this.isIframeReady = true;
1045
+ console.debug("[Benji Connect SDK] LOGIN iframe_load");
940
1046
  this.flushPendingPopupAuth();
941
1047
  }
942
1048
  static flushPendingPopupAuth() {
943
1049
  var _a, _b;
944
- if (!this.isIframeReady || !this.pendingPopupAuth.length) return;
945
- const expectedOrigin = this.connectOrigin || new URL(Endpoints.benji_connect_auth_url).origin;
946
1050
  const iframeWindow = (_b = (_a = this.iframe) == null ? void 0 : _a.contentWindow) != null ? _b : null;
947
- const queued = this.pendingPopupAuth;
948
- this.pendingPopupAuth = [];
1051
+ if (!this.pendingPopupAuth.length) {
1052
+ this.stopIframeDeliverabilityPoll();
1053
+ return;
1054
+ }
1055
+ if (!iframeWindow) {
1056
+ this.startIframeDeliverabilityPoll();
1057
+ return;
1058
+ }
1059
+ if (!this.canDeliverToConnectIframe()) {
1060
+ this.startIframeDeliverabilityPoll();
1061
+ console.debug("[Benji Connect SDK] LOGIN flushPendingPopupAuth skipped", {
1062
+ pendingCount: this.pendingPopupAuth.length,
1063
+ isIframeReady: this.isIframeReady,
1064
+ deliverable: false
1065
+ });
1066
+ return;
1067
+ }
1068
+ const expectedOrigin = this.connectOrigin || new URL(Endpoints.benji_connect_auth_url).origin;
1069
+ const queued = [...this.pendingPopupAuth];
1070
+ let flushedCount = 0;
1071
+ let skippedNotOriginated = 0;
1072
+ const remaining = [];
949
1073
  for (const event of queued) {
950
1074
  if (!isPopupOriginatedAuth(
951
1075
  event,
@@ -953,18 +1077,58 @@ var ConnectSDK = (() => {
953
1077
  iframeWindow,
954
1078
  expectedOrigin
955
1079
  )) {
1080
+ skippedNotOriginated += 1;
956
1081
  continue;
957
1082
  }
958
- this.relayToIframe(event);
1083
+ if (!this.canDeliverToConnectIframe()) {
1084
+ remaining.push(event);
1085
+ continue;
1086
+ }
1087
+ iframeWindow.postMessage(event.data, this.connectOrigin);
1088
+ flushedCount += 1;
1089
+ }
1090
+ this.pendingPopupAuth = remaining;
1091
+ if (this.pendingPopupAuth.length === 0) {
1092
+ this.stopIframeDeliverabilityPoll();
1093
+ } else {
1094
+ this.startIframeDeliverabilityPoll();
959
1095
  }
1096
+ console.debug("[Benji Connect SDK] LOGIN flushPendingPopupAuth", {
1097
+ pendingCount: queued.length,
1098
+ flushedCount,
1099
+ skippedNotOriginated,
1100
+ remainingCount: this.pendingPopupAuth.length
1101
+ });
960
1102
  }
961
1103
  static relayToPopup(payload) {
962
- if (!this.loginPopup) {
963
- console.warn("[Benji Connect SDK] Skipping login auth relay, no login popup");
1104
+ var _a, _b, _c, _d, _e, _f, _g, _h;
1105
+ const type = authMessageType(payload);
1106
+ const target = resolveLoginPartnerWindow(
1107
+ this.loginPopup,
1108
+ this.lastVerifiedPopupSource
1109
+ );
1110
+ const targetLabel = describeLoginPartnerWindowTarget(
1111
+ target,
1112
+ this.loginPopup,
1113
+ this.lastVerifiedPopupSource
1114
+ );
1115
+ if (!target) {
1116
+ console.warn("[Benji Connect SDK] Skipping login auth relay, no live partner window", {
1117
+ type,
1118
+ target: targetLabel,
1119
+ loginPopupClosed: (_b = (_a = this.loginPopup) == null ? void 0 : _a.closed) != null ? _b : true,
1120
+ lastVerifiedClosed: (_d = (_c = this.lastVerifiedPopupSource) == null ? void 0 : _c.closed) != null ? _d : true
1121
+ });
964
1122
  return;
965
1123
  }
1124
+ console.debug("[Benji Connect SDK] LOGIN relayToPopup", {
1125
+ type,
1126
+ target: targetLabel,
1127
+ loginPopupClosed: (_f = (_e = this.loginPopup) == null ? void 0 : _e.closed) != null ? _f : true,
1128
+ lastVerifiedClosed: (_h = (_g = this.lastVerifiedPopupSource) == null ? void 0 : _g.closed) != null ? _h : true
1129
+ });
966
1130
  try {
967
- this.loginPopup.postMessage(payload, "*");
1131
+ target.postMessage(payload, "*");
968
1132
  } catch (error) {
969
1133
  console.error("[Benji Connect SDK] Failed to forward login auth message to popup", error);
970
1134
  }
@@ -974,6 +1138,7 @@ var ConnectSDK = (() => {
974
1138
  if (shouldRelayMessage(this.mode, event.data)) {
975
1139
  const expectedOrigin2 = this.connectOrigin || new URL(Endpoints.benji_connect_auth_url).origin;
976
1140
  const iframeWindow = (_a = this.iframe) == null ? void 0 : _a.contentWindow;
1141
+ const type = authMessageType(event.data);
977
1142
  if (iframeWindow && event.source === iframeWindow) {
978
1143
  if (event.origin !== expectedOrigin2) {
979
1144
  console.warn(
@@ -983,13 +1148,30 @@ var ConnectSDK = (() => {
983
1148
  );
984
1149
  return;
985
1150
  }
1151
+ console.debug("[Benji Connect SDK] LOGIN auth relay", {
1152
+ type,
1153
+ origin: event.origin,
1154
+ direction: "iframe_to_popup"
1155
+ });
986
1156
  this.relayToPopup(event.data);
987
1157
  return;
988
1158
  }
989
1159
  if (isPopupOriginatedAuth(event, this.loginPopup, iframeWindow != null ? iframeWindow : null, expectedOrigin2)) {
1160
+ if (isMessageWindow(event.source)) {
1161
+ this.lastVerifiedPopupSource = event.source;
1162
+ }
1163
+ console.debug("[Benji Connect SDK] LOGIN auth relay", {
1164
+ type,
1165
+ origin: event.origin,
1166
+ direction: "popup_to_iframe"
1167
+ });
990
1168
  this.relayToIframe(event);
991
1169
  return;
992
1170
  }
1171
+ console.warn("[Benji Connect SDK] LOGIN auth relay unclassified", {
1172
+ type,
1173
+ origin: event.origin
1174
+ });
993
1175
  return;
994
1176
  }
995
1177
  if (!isConnectMessageType(event.data)) return;
@@ -1066,6 +1248,8 @@ var ConnectSDK = (() => {
1066
1248
  _MessageRouter.connectOrigin = "";
1067
1249
  _MessageRouter.isIframeReady = false;
1068
1250
  _MessageRouter.pendingPopupAuth = [];
1251
+ _MessageRouter.lastVerifiedPopupSource = null;
1252
+ _MessageRouter.iframeDeliverabilityPoll = null;
1069
1253
  _MessageRouter.errorEventHandler = (event) => {
1070
1254
  return _MessageRouter.handleErrorMessage(event);
1071
1255
  };
@@ -1159,7 +1343,7 @@ var ConnectSDK = (() => {
1159
1343
  const popupUrl = preparedLink ? appendLoginPopupFlag(preparedLink) : "about:blank";
1160
1344
  this.loginPopup = window.open(
1161
1345
  popupUrl,
1162
- "benji_partner_auth",
1346
+ LOGIN_PARTNER_POPUP_NAME,
1163
1347
  buildLoginPopupFeatures(position)
1164
1348
  );
1165
1349
  if (!this.loginPopup) {
@@ -1186,6 +1370,15 @@ var ConnectSDK = (() => {
1186
1370
  var _a, _b, _c;
1187
1371
  if (this.isClosing) return;
1188
1372
  if ((_a = this.loginPopup) == null ? void 0 : _a.closed) {
1373
+ const live = resolveLoginPartnerWindow(
1374
+ this.loginPopup,
1375
+ MessageRouter.lastVerifiedPopupSource
1376
+ );
1377
+ if (live) {
1378
+ console.debug("[Benji Connect SDK] LOGIN popup_closed_poll skipped, live partner window remains");
1379
+ return;
1380
+ }
1381
+ console.debug("[Benji Connect SDK] LOGIN popup_closed_poll exit, no live partner window");
1189
1382
  (_c = (_b = this.sdkConfig).onExit) == null ? void 0 : _c.call(_b, {
1190
1383
  context: buildContext(),
1191
1384
  trigger: "POPUP_CLOSED" /* POPUP_CLOSED */