@benji-money/connect-sdk 1.1.4-beta.3 → 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.3" ? String("1.1.4-beta.3") : "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,6 +724,80 @@ 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
+ }
735
+ function sourceOpenerIsHost(source) {
736
+ try {
737
+ if (!isMessageWindow(source)) return false;
738
+ return source.opener === window;
739
+ } catch {
740
+ return false;
741
+ }
742
+ }
743
+ function isPopupOriginatedAuth(event, loginPopup, iframeWindow, connectOrigin) {
744
+ if (iframeWindow && event.source === iframeWindow) {
745
+ return false;
746
+ }
747
+ if (loginPopup && event.source === loginPopup) {
748
+ return true;
749
+ }
750
+ if (sourceOpenerIsHost(event.source)) {
751
+ return true;
752
+ }
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";
800
+ }
726
801
  function isConnectMessageType(data2) {
727
802
  if (!data2 || typeof data2 !== "object") return false;
728
803
  const type = data2.type;
@@ -842,6 +917,7 @@ var ConnectSDK = (() => {
842
917
  };
843
918
 
844
919
  // src/router/message.ts
920
+ var IFRAME_DELIVERABILITY_POLL_MS = 100;
845
921
  var _MessageRouter = class _MessageRouter {
846
922
  static configureMessageRouter(config) {
847
923
  this.onSuccess = config.onSuccess;
@@ -857,8 +933,10 @@ var ConnectSDK = (() => {
857
933
  this.loginPopup = context.loginPopup;
858
934
  this.mode = context.mode;
859
935
  this.connectOrigin = new URL(Endpoints.benji_connect_auth_url).origin;
860
- if (this.isIframeReady) {
936
+ if (this.canDeliverToConnectIframe()) {
861
937
  this.flushPendingPopupAuth();
938
+ } else {
939
+ this.startIframeDeliverabilityPoll();
862
940
  }
863
941
  }
864
942
  static resetIframeReady() {
@@ -866,6 +944,9 @@ var ConnectSDK = (() => {
866
944
  }
867
945
  static setMode(mode) {
868
946
  this.mode = mode;
947
+ if (mode !== 5 /* LOGIN */) {
948
+ this.stopIframeDeliverabilityPoll();
949
+ }
869
950
  }
870
951
  static addEventListeners() {
871
952
  if (this.configuredListeners) return;
@@ -878,6 +959,7 @@ var ConnectSDK = (() => {
878
959
  window.removeEventListener("error", this.errorEventHandler);
879
960
  window.removeEventListener("unhandledrejection", this.errorEventHandler);
880
961
  window.removeEventListener("message", this.messageEventHandler);
962
+ this.stopIframeDeliverabilityPoll();
881
963
  this.configuredListeners = false;
882
964
  this.iframe = null;
883
965
  this.loginPopup = null;
@@ -885,6 +967,7 @@ var ConnectSDK = (() => {
885
967
  this.connectOrigin = "";
886
968
  this.isIframeReady = false;
887
969
  this.pendingPopupAuth = [];
970
+ this.lastVerifiedPopupSource = null;
888
971
  }
889
972
  static handleErrorMessage(event) {
890
973
  switch (event.type) {
@@ -904,35 +987,148 @@ var ConnectSDK = (() => {
904
987
  }
905
988
  }
906
989
  }
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.
907
1013
  static relayToIframe(event) {
908
1014
  var _a;
1015
+ const type = authMessageType(event.data);
1016
+ const deliverable = this.canDeliverToConnectIframe();
909
1017
  const iframeWindow = (_a = this.iframe) == null ? void 0 : _a.contentWindow;
910
- if (!this.isIframeReady || !iframeWindow) {
1018
+ if (!iframeWindow || !deliverable) {
911
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
+ });
912
1028
  return;
913
1029
  }
1030
+ if (this.pendingPopupAuth.length > 0) {
1031
+ this.flushPendingPopupAuth();
1032
+ }
914
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
+ });
915
1041
  }
916
1042
  static markIframeReady(iframe) {
917
1043
  if (this.iframe !== iframe) return;
918
1044
  this.isIframeReady = true;
1045
+ console.debug("[Benji Connect SDK] LOGIN iframe_load");
919
1046
  this.flushPendingPopupAuth();
920
1047
  }
921
1048
  static flushPendingPopupAuth() {
922
- if (!this.isIframeReady || !this.pendingPopupAuth.length) return;
923
- const queued = this.pendingPopupAuth;
924
- this.pendingPopupAuth = [];
1049
+ var _a, _b;
1050
+ const iframeWindow = (_b = (_a = this.iframe) == null ? void 0 : _a.contentWindow) != null ? _b : null;
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 = [];
925
1073
  for (const event of queued) {
926
- this.relayToIframe(event);
1074
+ if (!isPopupOriginatedAuth(
1075
+ event,
1076
+ this.loginPopup,
1077
+ iframeWindow,
1078
+ expectedOrigin
1079
+ )) {
1080
+ skippedNotOriginated += 1;
1081
+ continue;
1082
+ }
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();
927
1095
  }
1096
+ console.debug("[Benji Connect SDK] LOGIN flushPendingPopupAuth", {
1097
+ pendingCount: queued.length,
1098
+ flushedCount,
1099
+ skippedNotOriginated,
1100
+ remainingCount: this.pendingPopupAuth.length
1101
+ });
928
1102
  }
929
1103
  static relayToPopup(payload) {
930
- if (!this.loginPopup) {
931
- 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
+ });
932
1122
  return;
933
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
+ });
934
1130
  try {
935
- this.loginPopup.postMessage(payload, "*");
1131
+ target.postMessage(payload, "*");
936
1132
  } catch (error) {
937
1133
  console.error("[Benji Connect SDK] Failed to forward login auth message to popup", error);
938
1134
  }
@@ -942,14 +1138,7 @@ var ConnectSDK = (() => {
942
1138
  if (shouldRelayMessage(this.mode, event.data)) {
943
1139
  const expectedOrigin2 = this.connectOrigin || new URL(Endpoints.benji_connect_auth_url).origin;
944
1140
  const iframeWindow = (_a = this.iframe) == null ? void 0 : _a.contentWindow;
945
- if (this.loginPopup && event.source === this.loginPopup) {
946
- this.relayToIframe(event);
947
- return;
948
- }
949
- if (!this.loginPopup && event.source instanceof Window && event.source !== iframeWindow) {
950
- this.pendingPopupAuth.push(event);
951
- return;
952
- }
1141
+ const type = authMessageType(event.data);
953
1142
  if (iframeWindow && event.source === iframeWindow) {
954
1143
  if (event.origin !== expectedOrigin2) {
955
1144
  console.warn(
@@ -959,9 +1148,30 @@ var ConnectSDK = (() => {
959
1148
  );
960
1149
  return;
961
1150
  }
1151
+ console.debug("[Benji Connect SDK] LOGIN auth relay", {
1152
+ type,
1153
+ origin: event.origin,
1154
+ direction: "iframe_to_popup"
1155
+ });
962
1156
  this.relayToPopup(event.data);
963
1157
  return;
964
1158
  }
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
+ });
1168
+ this.relayToIframe(event);
1169
+ return;
1170
+ }
1171
+ console.warn("[Benji Connect SDK] LOGIN auth relay unclassified", {
1172
+ type,
1173
+ origin: event.origin
1174
+ });
965
1175
  return;
966
1176
  }
967
1177
  if (!isConnectMessageType(event.data)) return;
@@ -1038,6 +1248,8 @@ var ConnectSDK = (() => {
1038
1248
  _MessageRouter.connectOrigin = "";
1039
1249
  _MessageRouter.isIframeReady = false;
1040
1250
  _MessageRouter.pendingPopupAuth = [];
1251
+ _MessageRouter.lastVerifiedPopupSource = null;
1252
+ _MessageRouter.iframeDeliverabilityPoll = null;
1041
1253
  _MessageRouter.errorEventHandler = (event) => {
1042
1254
  return _MessageRouter.handleErrorMessage(event);
1043
1255
  };
@@ -1131,7 +1343,7 @@ var ConnectSDK = (() => {
1131
1343
  const popupUrl = preparedLink ? appendLoginPopupFlag(preparedLink) : "about:blank";
1132
1344
  this.loginPopup = window.open(
1133
1345
  popupUrl,
1134
- "benji_partner_auth",
1346
+ LOGIN_PARTNER_POPUP_NAME,
1135
1347
  buildLoginPopupFeatures(position)
1136
1348
  );
1137
1349
  if (!this.loginPopup) {
@@ -1158,6 +1370,15 @@ var ConnectSDK = (() => {
1158
1370
  var _a, _b, _c;
1159
1371
  if (this.isClosing) return;
1160
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");
1161
1382
  (_c = (_b = this.sdkConfig).onExit) == null ? void 0 : _c.call(_b, {
1162
1383
  context: buildContext(),
1163
1384
  trigger: "POPUP_CLOSED" /* POPUP_CLOSED */