@benji-money/connect-sdk 1.1.4-beta.5 → 1.1.4-beta.6
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/connect-sdk.umd.global.js +356 -7
- package/dist/connect-sdk.umd.global.js.map +1 -1
- package/dist/index.cjs +431 -24
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +44 -1
- package/dist/index.d.ts +44 -1
- package/dist/index.js +425 -23
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/connect-sdk.umd.d.ts +0 -14
|
@@ -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.
|
|
113
|
+
version: "1.1.4-beta.6" ? String("1.1.4-beta.6") : "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 */;
|
|
@@ -247,6 +247,150 @@ var ConnectSDK = (() => {
|
|
|
247
247
|
return ensureAuthLinkStateNonce(url, nonce);
|
|
248
248
|
}
|
|
249
249
|
|
|
250
|
+
// src/utils/verifyAppUrl.ts
|
|
251
|
+
var DEFAULT_LOCAL_VERIFY_ORIGIN = "http://localhost:3000";
|
|
252
|
+
var REMOTE_VERIFY_ORIGINS = [
|
|
253
|
+
"https://verifyapp-staging.withbenji.com",
|
|
254
|
+
"https://verifyapp-dev.withbenji.com",
|
|
255
|
+
"https://verifyapp.withbenji.com"
|
|
256
|
+
];
|
|
257
|
+
function rewriteVerifyAppUrlForLocalConnect(partnerLoginLink, localOrigin = DEFAULT_LOCAL_VERIFY_ORIGIN) {
|
|
258
|
+
if (!partnerLoginLink) {
|
|
259
|
+
return partnerLoginLink;
|
|
260
|
+
}
|
|
261
|
+
let url = partnerLoginLink;
|
|
262
|
+
for (const remote of REMOTE_VERIFY_ORIGINS) {
|
|
263
|
+
url = url.replaceAll(remote, localOrigin);
|
|
264
|
+
url = url.replaceAll(
|
|
265
|
+
remote.replace(/^https:\/\//, "https%3A//"),
|
|
266
|
+
localOrigin.replace(/^http:\/\//, "http%3A//")
|
|
267
|
+
);
|
|
268
|
+
url = url.replaceAll(encodeURIComponent(remote), encodeURIComponent(localOrigin));
|
|
269
|
+
}
|
|
270
|
+
return url;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
// src/utils/loginTransport.ts
|
|
274
|
+
var LOGIN_PENDING_STORAGE_KEY = "benji_login_pending";
|
|
275
|
+
var LOGIN_FORCE_REDIRECT_STORAGE_KEY = "benji_force_login_redirect";
|
|
276
|
+
var LOGIN_RESUME_QUERY_FLAG = "login_resume";
|
|
277
|
+
var LOGIN_RETURN_STATE_SEPARATOR = ".benji_return.";
|
|
278
|
+
function isIosSafari(userAgent, maxTouchPoints) {
|
|
279
|
+
const isIos = /iPhone|iPad|iPod/.test(userAgent) || userAgent.includes("Macintosh") && maxTouchPoints > 1;
|
|
280
|
+
const isSafari = /Safari/.test(userAgent) && !/CriOS|FxiOS|EdgiOS|OPiOS|Chrome/.test(userAgent);
|
|
281
|
+
return isIos && isSafari;
|
|
282
|
+
}
|
|
283
|
+
function shouldUseSameTabLogin(args) {
|
|
284
|
+
if (!args.isNonDummyLogin) return false;
|
|
285
|
+
if (args.forceRedirect) return true;
|
|
286
|
+
return isIosSafari(args.userAgent, args.maxTouchPoints);
|
|
287
|
+
}
|
|
288
|
+
function isNonDummyLogin(mode, authType) {
|
|
289
|
+
return mode === 5 /* LOGIN */ && authType != null && authType !== 0 /* DUMMY */;
|
|
290
|
+
}
|
|
291
|
+
function isLocalForceRedirectEnabled(environment, storage) {
|
|
292
|
+
if (environment !== "local" /* LOCAL */) return false;
|
|
293
|
+
if (!storage) return false;
|
|
294
|
+
return storage.getItem(LOGIN_FORCE_REDIRECT_STORAGE_KEY) === "1";
|
|
295
|
+
}
|
|
296
|
+
function canStampLoginReturnState(partnerAuthLink, configToken) {
|
|
297
|
+
try {
|
|
298
|
+
const state = new URL(partnerAuthLink).searchParams.get("state");
|
|
299
|
+
return !state || state === configToken;
|
|
300
|
+
} catch {
|
|
301
|
+
return false;
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
function writeLoginPending(storage, payload) {
|
|
305
|
+
storage.setItem(LOGIN_PENDING_STORAGE_KEY, JSON.stringify(payload));
|
|
306
|
+
}
|
|
307
|
+
function buildRequestCodeExchangeMessage(args) {
|
|
308
|
+
const { configToken } = decodeLoginReturnState(args.token);
|
|
309
|
+
return {
|
|
310
|
+
type: "request_code_exchange",
|
|
311
|
+
data: {
|
|
312
|
+
partnerId: args.partnerId,
|
|
313
|
+
code: args.code,
|
|
314
|
+
token: configToken,
|
|
315
|
+
redirect_uri: args.redirectUri
|
|
316
|
+
}
|
|
317
|
+
};
|
|
318
|
+
}
|
|
319
|
+
function toBase64Url(value) {
|
|
320
|
+
const bytes = new TextEncoder().encode(value);
|
|
321
|
+
let binary = "";
|
|
322
|
+
for (const byte of bytes) {
|
|
323
|
+
binary += String.fromCharCode(byte);
|
|
324
|
+
}
|
|
325
|
+
return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/g, "");
|
|
326
|
+
}
|
|
327
|
+
function fromBase64Url(value) {
|
|
328
|
+
try {
|
|
329
|
+
const padded = value.replace(/-/g, "+").replace(/_/g, "/");
|
|
330
|
+
const pad = padded.length % 4 === 0 ? "" : "=".repeat(4 - padded.length % 4);
|
|
331
|
+
const binary = atob(padded + pad);
|
|
332
|
+
const bytes = Uint8Array.from(binary, (ch) => ch.charCodeAt(0));
|
|
333
|
+
return new TextDecoder().decode(bytes);
|
|
334
|
+
} catch {
|
|
335
|
+
return null;
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
function encodeLoginReturnState(configToken, returnOrigin) {
|
|
339
|
+
return `${configToken}${LOGIN_RETURN_STATE_SEPARATOR}${toBase64Url(returnOrigin)}`;
|
|
340
|
+
}
|
|
341
|
+
function decodeLoginReturnState(state) {
|
|
342
|
+
const separatorIndex = state.indexOf(LOGIN_RETURN_STATE_SEPARATOR);
|
|
343
|
+
if (separatorIndex <= 0) {
|
|
344
|
+
return { configToken: state };
|
|
345
|
+
}
|
|
346
|
+
const configToken = state.slice(0, separatorIndex);
|
|
347
|
+
const encodedOrigin = state.slice(
|
|
348
|
+
separatorIndex + LOGIN_RETURN_STATE_SEPARATOR.length
|
|
349
|
+
);
|
|
350
|
+
if (!configToken || !encodedOrigin) {
|
|
351
|
+
return { configToken: state };
|
|
352
|
+
}
|
|
353
|
+
const returnOrigin = fromBase64Url(encodedOrigin);
|
|
354
|
+
if (!returnOrigin) {
|
|
355
|
+
return { configToken: state };
|
|
356
|
+
}
|
|
357
|
+
return { configToken, returnOrigin };
|
|
358
|
+
}
|
|
359
|
+
function stampLoginReturnState(url, configToken, returnOrigin) {
|
|
360
|
+
if (!canStampLoginReturnState(url, configToken)) {
|
|
361
|
+
throw new Error("Partner sign-in URL contains incompatible OAuth state.");
|
|
362
|
+
}
|
|
363
|
+
const state = encodeLoginReturnState(configToken, returnOrigin);
|
|
364
|
+
try {
|
|
365
|
+
const parsed = new URL(url);
|
|
366
|
+
parsed.searchParams.set("state", state);
|
|
367
|
+
return parsed.toString();
|
|
368
|
+
} catch {
|
|
369
|
+
if (url.includes("state=")) {
|
|
370
|
+
return url.replace(
|
|
371
|
+
/([?&]state=)[^&]*/,
|
|
372
|
+
`$1${encodeURIComponent(state)}`
|
|
373
|
+
);
|
|
374
|
+
}
|
|
375
|
+
const separator = url.includes("?") ? "&" : "?";
|
|
376
|
+
return `${url}${separator}state=${encodeURIComponent(state)}`;
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
function buildSameTabPartnerAuthUrl(args) {
|
|
380
|
+
let prepared = args.configToken ? preparePartnerAuthUrl(args.partnerAuthLink, args.configToken) : args.partnerAuthLink;
|
|
381
|
+
if (args.configToken && args.returnOrigin) {
|
|
382
|
+
prepared = stampLoginReturnState(
|
|
383
|
+
prepared,
|
|
384
|
+
args.configToken,
|
|
385
|
+
args.returnOrigin
|
|
386
|
+
);
|
|
387
|
+
}
|
|
388
|
+
if (!args.rewriteForLocalConnect) {
|
|
389
|
+
return prepared;
|
|
390
|
+
}
|
|
391
|
+
return rewriteVerifyAppUrlForLocalConnect(prepared);
|
|
392
|
+
}
|
|
393
|
+
|
|
250
394
|
// src/utils/placement.ts
|
|
251
395
|
var IFRAME_WIDTH = 400;
|
|
252
396
|
var IFRAME_HEIGHT = 645;
|
|
@@ -918,6 +1062,7 @@ var ConnectSDK = (() => {
|
|
|
918
1062
|
|
|
919
1063
|
// src/router/message.ts
|
|
920
1064
|
var IFRAME_DELIVERABILITY_POLL_MS = 100;
|
|
1065
|
+
var HOST_AUTH_REDELIVERY_MS = 500;
|
|
921
1066
|
var _MessageRouter = class _MessageRouter {
|
|
922
1067
|
static configureMessageRouter(config) {
|
|
923
1068
|
this.onSuccess = config.onSuccess;
|
|
@@ -934,6 +1079,7 @@ var ConnectSDK = (() => {
|
|
|
934
1079
|
this.mode = context.mode;
|
|
935
1080
|
this.connectOrigin = new URL(Endpoints.benji_connect_auth_url).origin;
|
|
936
1081
|
if (this.canDeliverToConnectIframe()) {
|
|
1082
|
+
this.flushPendingHostAuth();
|
|
937
1083
|
this.flushPendingPopupAuth();
|
|
938
1084
|
} else {
|
|
939
1085
|
this.startIframeDeliverabilityPoll();
|
|
@@ -960,6 +1106,7 @@ var ConnectSDK = (() => {
|
|
|
960
1106
|
window.removeEventListener("unhandledrejection", this.errorEventHandler);
|
|
961
1107
|
window.removeEventListener("message", this.messageEventHandler);
|
|
962
1108
|
this.stopIframeDeliverabilityPoll();
|
|
1109
|
+
this.stopHostAuthRedelivery();
|
|
963
1110
|
this.configuredListeners = false;
|
|
964
1111
|
this.iframe = null;
|
|
965
1112
|
this.loginPopup = null;
|
|
@@ -967,6 +1114,7 @@ var ConnectSDK = (() => {
|
|
|
967
1114
|
this.connectOrigin = "";
|
|
968
1115
|
this.isIframeReady = false;
|
|
969
1116
|
this.pendingPopupAuth = [];
|
|
1117
|
+
this.pendingHostAuth = [];
|
|
970
1118
|
this.lastVerifiedPopupSource = null;
|
|
971
1119
|
}
|
|
972
1120
|
static handleErrorMessage(event) {
|
|
@@ -1039,10 +1187,64 @@ var ConnectSDK = (() => {
|
|
|
1039
1187
|
deliverable
|
|
1040
1188
|
});
|
|
1041
1189
|
}
|
|
1190
|
+
/**
|
|
1191
|
+
* Same-tab LOGIN resume: post immediately, then re-post on an interval until
|
|
1192
|
+
* FLOW_SUCCESS / onError / close stops redelivery. Connect dedupes repeats.
|
|
1193
|
+
*/
|
|
1194
|
+
static startHostAuthRedelivery(payload, intervalMs = HOST_AUTH_REDELIVERY_MS) {
|
|
1195
|
+
this.stopHostAuthRedelivery();
|
|
1196
|
+
this.upsertPendingHostAuth(payload);
|
|
1197
|
+
this.flushPendingHostAuth();
|
|
1198
|
+
this.hostAuthRedeliveryId = window.setInterval(() => {
|
|
1199
|
+
if (!this.pendingHostAuth.length) {
|
|
1200
|
+
this.stopHostAuthRedelivery();
|
|
1201
|
+
return;
|
|
1202
|
+
}
|
|
1203
|
+
this.flushPendingHostAuth();
|
|
1204
|
+
}, intervalMs);
|
|
1205
|
+
}
|
|
1206
|
+
static stopHostAuthRedelivery() {
|
|
1207
|
+
if (this.hostAuthRedeliveryId !== null) {
|
|
1208
|
+
window.clearInterval(this.hostAuthRedeliveryId);
|
|
1209
|
+
this.hostAuthRedeliveryId = null;
|
|
1210
|
+
}
|
|
1211
|
+
this.pendingHostAuth = [];
|
|
1212
|
+
}
|
|
1213
|
+
static upsertPendingHostAuth(payload) {
|
|
1214
|
+
const type = authMessageType(payload);
|
|
1215
|
+
if (!type) {
|
|
1216
|
+
this.pendingHostAuth.push(payload);
|
|
1217
|
+
return;
|
|
1218
|
+
}
|
|
1219
|
+
const existingIndex = this.pendingHostAuth.findIndex(
|
|
1220
|
+
(item) => authMessageType(item) === type
|
|
1221
|
+
);
|
|
1222
|
+
if (existingIndex >= 0) {
|
|
1223
|
+
this.pendingHostAuth[existingIndex] = payload;
|
|
1224
|
+
} else {
|
|
1225
|
+
this.pendingHostAuth.push(payload);
|
|
1226
|
+
}
|
|
1227
|
+
}
|
|
1228
|
+
static flushPendingHostAuth() {
|
|
1229
|
+
var _a, _b;
|
|
1230
|
+
if (!this.pendingHostAuth.length) return;
|
|
1231
|
+
const iframeWindow = (_b = (_a = this.iframe) == null ? void 0 : _a.contentWindow) != null ? _b : null;
|
|
1232
|
+
if (!iframeWindow || !this.canDeliverToConnectIframe()) {
|
|
1233
|
+
return;
|
|
1234
|
+
}
|
|
1235
|
+
const queued = [...this.pendingHostAuth];
|
|
1236
|
+
for (const payload of queued) {
|
|
1237
|
+
iframeWindow.postMessage(payload, this.connectOrigin);
|
|
1238
|
+
}
|
|
1239
|
+
console.debug("[Benji Connect SDK] LOGIN flushPendingHostAuth", {
|
|
1240
|
+
flushedCount: queued.length
|
|
1241
|
+
});
|
|
1242
|
+
}
|
|
1042
1243
|
static markIframeReady(iframe) {
|
|
1043
1244
|
if (this.iframe !== iframe) return;
|
|
1044
1245
|
this.isIframeReady = true;
|
|
1045
1246
|
console.debug("[Benji Connect SDK] LOGIN iframe_load");
|
|
1247
|
+
this.flushPendingHostAuth();
|
|
1046
1248
|
this.flushPendingPopupAuth();
|
|
1047
1249
|
}
|
|
1048
1250
|
static flushPendingPopupAuth() {
|
|
@@ -1248,6 +1450,16 @@ var ConnectSDK = (() => {
|
|
|
1248
1450
|
_MessageRouter.connectOrigin = "";
|
|
1249
1451
|
_MessageRouter.isIframeReady = false;
|
|
1250
1452
|
_MessageRouter.pendingPopupAuth = [];
|
|
1453
|
+
/**
|
|
1454
|
+
* Sticky host→iframe auth (same-tab LOGIN resume). Kept after each post so
|
|
1455
|
+
* redelivery can cover the window where the iframe is "deliverable" but
|
|
1456
|
+
* Connect has not installed its message listener yet.
|
|
1457
|
+
* Invariant: only `startHostAuthRedelivery` writes this queue, and it always
|
|
1458
|
+
* owns a timer while the queue is non-empty. The deliverability poll is
|
|
1459
|
+
* popup-only so it cannot double-post this payload.
|
|
1460
|
+
*/
|
|
1461
|
+
_MessageRouter.pendingHostAuth = [];
|
|
1462
|
+
_MessageRouter.hostAuthRedeliveryId = null;
|
|
1251
1463
|
_MessageRouter.lastVerifiedPopupSource = null;
|
|
1252
1464
|
_MessageRouter.iframeDeliverabilityPoll = null;
|
|
1253
1465
|
_MessageRouter.errorEventHandler = (event) => {
|
|
@@ -1260,6 +1472,7 @@ var ConnectSDK = (() => {
|
|
|
1260
1472
|
|
|
1261
1473
|
// src/connect-sdk.ts
|
|
1262
1474
|
var POPUP_CLOSED_POLL_MS = 500;
|
|
1475
|
+
var SAME_TAB_RESUME_TIMEOUT_MS = 45e3;
|
|
1263
1476
|
var ConnectSDK = class {
|
|
1264
1477
|
constructor(config) {
|
|
1265
1478
|
this.iframe = null;
|
|
@@ -1289,6 +1502,9 @@ var ConnectSDK = (() => {
|
|
|
1289
1502
|
* while the in-flight open() still mounts the iframe.
|
|
1290
1503
|
*/
|
|
1291
1504
|
this.openAbortController = null;
|
|
1505
|
+
/** Same-tab LOGIN resume mounts the iframe headless without partner auth type. */
|
|
1506
|
+
this.isResumingSameTabLogin = false;
|
|
1507
|
+
this.sameTabResumeTimeoutId = null;
|
|
1292
1508
|
this.onIframeLoad = () => {
|
|
1293
1509
|
if (this.isClosing || !this.iframe) return;
|
|
1294
1510
|
MessageRouter.markIframeReady(this.iframe);
|
|
@@ -1306,9 +1522,64 @@ var ConnectSDK = (() => {
|
|
|
1306
1522
|
}
|
|
1307
1523
|
isLoginPopupOnly() {
|
|
1308
1524
|
var _a;
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1525
|
+
return isNonDummyLogin(
|
|
1526
|
+
(_a = this.sdkConfig.mode) != null ? _a : 1 /* CONNECT */,
|
|
1527
|
+
this.resolveAuthType()
|
|
1528
|
+
);
|
|
1529
|
+
}
|
|
1530
|
+
shouldOpenSameTabLogin() {
|
|
1531
|
+
var _a, _b, _c;
|
|
1532
|
+
if (!this.isLoginPopupOnly()) return false;
|
|
1533
|
+
const partnerAuthLink = (_a = this.sdkConfig.tokenData) == null ? void 0 : _a.partnerAuthLink;
|
|
1534
|
+
const configToken = (_b = this.sdkConfig.tokenData) == null ? void 0 : _b.configToken;
|
|
1535
|
+
if (!partnerAuthLink || !configToken || !canStampLoginReturnState(partnerAuthLink, configToken)) {
|
|
1536
|
+
return false;
|
|
1537
|
+
}
|
|
1538
|
+
const storage = typeof sessionStorage === "undefined" ? null : sessionStorage;
|
|
1539
|
+
return shouldUseSameTabLogin({
|
|
1540
|
+
isNonDummyLogin: true,
|
|
1541
|
+
userAgent: typeof navigator === "undefined" ? "" : navigator.userAgent,
|
|
1542
|
+
maxTouchPoints: typeof navigator === "undefined" ? 0 : (_c = navigator.maxTouchPoints) != null ? _c : 0,
|
|
1543
|
+
forceRedirect: isLocalForceRedirectEnabled(Environment, storage)
|
|
1544
|
+
});
|
|
1545
|
+
}
|
|
1546
|
+
openSameTabLogin() {
|
|
1547
|
+
var _a, _b, _c, _d, _e, _f;
|
|
1548
|
+
const partnerAuthLink = (_a = this.sdkConfig.tokenData) == null ? void 0 : _a.partnerAuthLink;
|
|
1549
|
+
if (!partnerAuthLink) {
|
|
1550
|
+
console.warn("[Connect SDK] Same-tab LOGIN missing partnerAuthLink");
|
|
1551
|
+
(_c = (_b = this.sdkConfig).onError) == null ? void 0 : _c.call(
|
|
1552
|
+
_b,
|
|
1553
|
+
new Error("Partner sign-in URL is missing."),
|
|
1554
|
+
"400",
|
|
1555
|
+
{ context: buildContext() }
|
|
1556
|
+
);
|
|
1557
|
+
return;
|
|
1558
|
+
}
|
|
1559
|
+
const rewriteForLocalConnect = Environment === "local" /* LOCAL */;
|
|
1560
|
+
const returnOrigin = window.location.origin;
|
|
1561
|
+
const url = buildSameTabPartnerAuthUrl({
|
|
1562
|
+
partnerAuthLink,
|
|
1563
|
+
configToken: (_d = this.sdkConfig.tokenData) == null ? void 0 : _d.configToken,
|
|
1564
|
+
rewriteForLocalConnect,
|
|
1565
|
+
returnOrigin
|
|
1566
|
+
});
|
|
1567
|
+
try {
|
|
1568
|
+
writeLoginPending(sessionStorage, {
|
|
1569
|
+
connectToken: this.sdkConfig.token,
|
|
1570
|
+
path: `${window.location.pathname}${window.location.search}`
|
|
1571
|
+
});
|
|
1572
|
+
} catch (error) {
|
|
1573
|
+
console.warn("[Connect SDK] Failed to persist LOGIN pending state", error);
|
|
1574
|
+
(_f = (_e = this.sdkConfig).onError) == null ? void 0 : _f.call(
|
|
1575
|
+
_e,
|
|
1576
|
+
new Error("Sign-in could not be started."),
|
|
1577
|
+
"400",
|
|
1578
|
+
{ context: buildContext() }
|
|
1579
|
+
);
|
|
1580
|
+
return;
|
|
1581
|
+
}
|
|
1582
|
+
window.location.assign(url);
|
|
1312
1583
|
}
|
|
1313
1584
|
isSessionActive() {
|
|
1314
1585
|
return this.iframe != null || this.loginPopup != null;
|
|
@@ -1321,8 +1592,22 @@ var ConnectSDK = (() => {
|
|
|
1321
1592
|
}
|
|
1322
1593
|
initialize() {
|
|
1323
1594
|
MessageRouter.configureMessageRouter({
|
|
1324
|
-
onSuccess:
|
|
1325
|
-
|
|
1595
|
+
onSuccess: (token, metadata) => {
|
|
1596
|
+
var _a, _b;
|
|
1597
|
+
this.clearSameTabResumeTimeout();
|
|
1598
|
+
MessageRouter.stopHostAuthRedelivery();
|
|
1599
|
+
(_b = (_a = this.sdkConfig).onSuccess) == null ? void 0 : _b.call(_a, token, metadata);
|
|
1600
|
+
},
|
|
1601
|
+
onError: (error, errorId, metadata) => {
|
|
1602
|
+
var _a, _b;
|
|
1603
|
+
if (this.isResumingSameTabLogin) {
|
|
1604
|
+
this.close();
|
|
1605
|
+
} else {
|
|
1606
|
+
this.clearSameTabResumeTimeout();
|
|
1607
|
+
MessageRouter.stopHostAuthRedelivery();
|
|
1608
|
+
}
|
|
1609
|
+
(_b = (_a = this.sdkConfig).onError) == null ? void 0 : _b.call(_a, error, errorId, metadata);
|
|
1610
|
+
},
|
|
1326
1611
|
onExit: this.sdkConfig.onExit,
|
|
1327
1612
|
onEvent: this.sdkConfig.onEvent,
|
|
1328
1613
|
close: () => this.close(),
|
|
@@ -1416,6 +1701,11 @@ var ConnectSDK = (() => {
|
|
|
1416
1701
|
const abortController = new AbortController();
|
|
1417
1702
|
this.openAbortController = abortController;
|
|
1418
1703
|
const { signal } = abortController;
|
|
1704
|
+
if (this.shouldOpenSameTabLogin()) {
|
|
1705
|
+
this.openSameTabLogin();
|
|
1706
|
+
this.abortInflightOpen();
|
|
1707
|
+
return;
|
|
1708
|
+
}
|
|
1419
1709
|
this.initialize();
|
|
1420
1710
|
if (signal.aborted) return;
|
|
1421
1711
|
MessageRouter.setMode(mode);
|
|
@@ -1436,6 +1726,55 @@ var ConnectSDK = (() => {
|
|
|
1436
1726
|
this.openUI();
|
|
1437
1727
|
this.syncLoginContext(mode);
|
|
1438
1728
|
}
|
|
1729
|
+
/**
|
|
1730
|
+
* Finishes a same-tab LOGIN after the partner redirect returns to the host.
|
|
1731
|
+
* The Connect callback page has no session of its own, so the code exchange
|
|
1732
|
+
* runs in the headless Connect iframe, which authenticates with the connect
|
|
1733
|
+
* token. Completion arrives through the usual FLOW_SUCCESS → onSuccess path.
|
|
1734
|
+
*/
|
|
1735
|
+
async resumeSameTabLogin(params) {
|
|
1736
|
+
var _a;
|
|
1737
|
+
if (this.isSessionActive()) return;
|
|
1738
|
+
this.sdkConfig.mode = 5 /* LOGIN */;
|
|
1739
|
+
this.isResumingSameTabLogin = true;
|
|
1740
|
+
this.initialize();
|
|
1741
|
+
MessageRouter.setMode(5 /* LOGIN */);
|
|
1742
|
+
MessageRouter.addEventListeners();
|
|
1743
|
+
this.openUI();
|
|
1744
|
+
this.syncLoginContext(5 /* LOGIN */);
|
|
1745
|
+
const payload = buildRequestCodeExchangeMessage({
|
|
1746
|
+
partnerId: params.partnerId,
|
|
1747
|
+
code: params.code,
|
|
1748
|
+
token: params.state,
|
|
1749
|
+
redirectUri: (_a = params.redirectUri) != null ? _a : this.buildCallbackUrl(params.partnerId)
|
|
1750
|
+
});
|
|
1751
|
+
MessageRouter.startHostAuthRedelivery(payload);
|
|
1752
|
+
this.startSameTabResumeTimeout();
|
|
1753
|
+
}
|
|
1754
|
+
buildCallbackUrl(partnerId) {
|
|
1755
|
+
const origin = new URL(Endpoints.benji_connect_auth_url).origin;
|
|
1756
|
+
return `${origin}/auth/${partnerId}/callback`;
|
|
1757
|
+
}
|
|
1758
|
+
startSameTabResumeTimeout() {
|
|
1759
|
+
this.clearSameTabResumeTimeout();
|
|
1760
|
+
this.sameTabResumeTimeoutId = setTimeout(() => {
|
|
1761
|
+
var _a, _b;
|
|
1762
|
+
this.sameTabResumeTimeoutId = null;
|
|
1763
|
+
console.warn("[Connect SDK] Same-tab LOGIN resume timed out");
|
|
1764
|
+
(_b = (_a = this.sdkConfig).onError) == null ? void 0 : _b.call(
|
|
1765
|
+
_a,
|
|
1766
|
+
new Error("Sign-in could not be completed. Please try again."),
|
|
1767
|
+
"408",
|
|
1768
|
+
{ context: buildContext() }
|
|
1769
|
+
);
|
|
1770
|
+
this.close();
|
|
1771
|
+
}, SAME_TAB_RESUME_TIMEOUT_MS);
|
|
1772
|
+
}
|
|
1773
|
+
clearSameTabResumeTimeout() {
|
|
1774
|
+
if (this.sameTabResumeTimeoutId === null) return;
|
|
1775
|
+
clearTimeout(this.sameTabResumeTimeoutId);
|
|
1776
|
+
this.sameTabResumeTimeoutId = null;
|
|
1777
|
+
}
|
|
1439
1778
|
syncLoginContext(mode) {
|
|
1440
1779
|
MessageRouter.setLoginContext({
|
|
1441
1780
|
iframe: this.iframe,
|
|
@@ -1447,7 +1786,7 @@ var ConnectSDK = (() => {
|
|
|
1447
1786
|
var _a, _b;
|
|
1448
1787
|
if (this.iframe) return;
|
|
1449
1788
|
MessageRouter.resetIframeReady();
|
|
1450
|
-
const headless = this.isLoginPopupOnly();
|
|
1789
|
+
const headless = this.isResumingSameTabLogin || this.isLoginPopupOnly();
|
|
1451
1790
|
this.container = document.createElement("div");
|
|
1452
1791
|
if (headless) {
|
|
1453
1792
|
applyHeadlessContainerStyle(this.container);
|
|
@@ -1463,6 +1802,9 @@ var ConnectSDK = (() => {
|
|
|
1463
1802
|
if (this.sdkConfig.mode != null) {
|
|
1464
1803
|
url.searchParams.set("mode", String(this.sdkConfig.mode));
|
|
1465
1804
|
}
|
|
1805
|
+
if (this.isResumingSameTabLogin) {
|
|
1806
|
+
url.searchParams.set(LOGIN_RESUME_QUERY_FLAG, "1");
|
|
1807
|
+
}
|
|
1466
1808
|
this.iframe = document.createElement("iframe");
|
|
1467
1809
|
this.syncLoginContext((_a = this.sdkConfig.mode) != null ? _a : 1 /* CONNECT */);
|
|
1468
1810
|
this.iframe.addEventListener("load", this.onIframeLoad);
|
|
@@ -1509,6 +1851,10 @@ var ConnectSDK = (() => {
|
|
|
1509
1851
|
this.syncLoginContext((_b = this.sdkConfig.mode) != null ? _b : 1 /* CONNECT */);
|
|
1510
1852
|
}
|
|
1511
1853
|
navigateLoginPopup(url) {
|
|
1854
|
+
if (this.isResumingSameTabLogin) {
|
|
1855
|
+
console.debug("[Connect SDK] Ignoring PARTNER_LOGIN_OPEN during same-tab resume");
|
|
1856
|
+
return;
|
|
1857
|
+
}
|
|
1512
1858
|
if (this.hasLoginPopupUrl) return;
|
|
1513
1859
|
if (!this.loginPopup || this.loginPopup.closed) {
|
|
1514
1860
|
console.warn("[Connect SDK] Cannot navigate LOGIN popup \u2014 window unavailable");
|
|
@@ -1537,6 +1883,9 @@ var ConnectSDK = (() => {
|
|
|
1537
1883
|
close() {
|
|
1538
1884
|
var _a, _b;
|
|
1539
1885
|
this.abortInflightOpen();
|
|
1886
|
+
this.clearSameTabResumeTimeout();
|
|
1887
|
+
MessageRouter.stopHostAuthRedelivery();
|
|
1888
|
+
this.isResumingSameTabLogin = false;
|
|
1540
1889
|
this.isClosing = true;
|
|
1541
1890
|
this.stopPopupClosedPoll();
|
|
1542
1891
|
this.closeLoginPopup();
|