@returningai/widget-sdk 1.8.4 → 1.8.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/CHANGELOG.md +29 -0
- package/dist/rai-banner.iife.js +1 -1
- package/dist/rai-banner.js +1 -1
- package/dist/rai-widget.iife.js +2 -2
- package/dist/rai-widget.js +396 -79
- package/dist/types/BaseWidget.d.ts +6 -9
- package/dist/types/core/auth-renewal-recovery.d.ts +19 -0
- package/dist/types/core/auth.d.ts +1 -0
- package/dist/types/core/bundle-readiness.d.ts +19 -2
- package/dist/types/core/widget-error-presentation.d.ts +15 -0
- package/package.json +4 -2
package/dist/rai-widget.js
CHANGED
|
@@ -12343,6 +12343,109 @@ function isTokenExpired(expiry) {
|
|
|
12343
12343
|
if (!expiry) return true;
|
|
12344
12344
|
return Date.now() >= expiry - 6e4;
|
|
12345
12345
|
}
|
|
12346
|
+
const RETRY_DELAYS_MS = [5e3, 15e3, 3e4];
|
|
12347
|
+
const RETRYABLE_CLIENT_STATUSES = /* @__PURE__ */ new Set([408, 425, 429]);
|
|
12348
|
+
function isPermanentAuthFailure(error) {
|
|
12349
|
+
if (!error) return false;
|
|
12350
|
+
const { status } = error;
|
|
12351
|
+
return status >= 400 && status < 500 && !RETRYABLE_CLIENT_STATUSES.has(status);
|
|
12352
|
+
}
|
|
12353
|
+
function createDefaultEnvironment$1() {
|
|
12354
|
+
const visibilityDocument = typeof document === "undefined" ? void 0 : document;
|
|
12355
|
+
const pageWindow = typeof window === "undefined" ? void 0 : window;
|
|
12356
|
+
return {
|
|
12357
|
+
isHidden: () => (visibilityDocument == null ? void 0 : visibilityDocument.visibilityState) === "hidden",
|
|
12358
|
+
setTimeout: (callback, delayMs) => globalThis.setTimeout(callback, delayMs),
|
|
12359
|
+
clearTimeout: (timerId) => globalThis.clearTimeout(timerId),
|
|
12360
|
+
addVisibilityChangeListener: (listener) => visibilityDocument == null ? void 0 : visibilityDocument.addEventListener("visibilitychange", listener),
|
|
12361
|
+
removeVisibilityChangeListener: (listener) => visibilityDocument == null ? void 0 : visibilityDocument.removeEventListener("visibilitychange", listener),
|
|
12362
|
+
addPageShowListener: (listener) => pageWindow == null ? void 0 : pageWindow.addEventListener("pageshow", listener),
|
|
12363
|
+
removePageShowListener: (listener) => pageWindow == null ? void 0 : pageWindow.removeEventListener("pageshow", listener),
|
|
12364
|
+
addOnlineListener: (listener) => pageWindow == null ? void 0 : pageWindow.addEventListener("online", listener),
|
|
12365
|
+
removeOnlineListener: (listener) => pageWindow == null ? void 0 : pageWindow.removeEventListener("online", listener)
|
|
12366
|
+
};
|
|
12367
|
+
}
|
|
12368
|
+
function createAuthRenewalRecoveryController(retry, environment = createDefaultEnvironment$1()) {
|
|
12369
|
+
let pending = false;
|
|
12370
|
+
let retryInFlight = false;
|
|
12371
|
+
let rescheduleRequested = false;
|
|
12372
|
+
let retryAttempt = 0;
|
|
12373
|
+
let timerId = null;
|
|
12374
|
+
let listening = false;
|
|
12375
|
+
const clearTimer = () => {
|
|
12376
|
+
if (timerId === null) return;
|
|
12377
|
+
environment.clearTimeout(timerId);
|
|
12378
|
+
timerId = null;
|
|
12379
|
+
};
|
|
12380
|
+
const disarmSignals = () => {
|
|
12381
|
+
if (!listening) return;
|
|
12382
|
+
listening = false;
|
|
12383
|
+
environment.removeVisibilityChangeListener(handleForeground);
|
|
12384
|
+
environment.removePageShowListener(handleForeground);
|
|
12385
|
+
environment.removeOnlineListener(handleOnline);
|
|
12386
|
+
};
|
|
12387
|
+
const reset = () => {
|
|
12388
|
+
pending = false;
|
|
12389
|
+
retryAttempt = 0;
|
|
12390
|
+
rescheduleRequested = false;
|
|
12391
|
+
clearTimer();
|
|
12392
|
+
disarmSignals();
|
|
12393
|
+
};
|
|
12394
|
+
const requestRetry = (resetBudget, allowWhileHidden) => {
|
|
12395
|
+
if (!pending || retryInFlight || !allowWhileHidden && environment.isHidden()) {
|
|
12396
|
+
return;
|
|
12397
|
+
}
|
|
12398
|
+
if (resetBudget) retryAttempt = 0;
|
|
12399
|
+
clearTimer();
|
|
12400
|
+
retryInFlight = true;
|
|
12401
|
+
Promise.resolve().then(retry).catch((error) => {
|
|
12402
|
+
console.error("[rai-widget] Session renewal retry failed:", error);
|
|
12403
|
+
}).finally(() => {
|
|
12404
|
+
retryInFlight = false;
|
|
12405
|
+
if (rescheduleRequested) {
|
|
12406
|
+
rescheduleRequested = false;
|
|
12407
|
+
scheduleRetry();
|
|
12408
|
+
}
|
|
12409
|
+
});
|
|
12410
|
+
};
|
|
12411
|
+
function handleForeground() {
|
|
12412
|
+
if (environment.isHidden()) return;
|
|
12413
|
+
requestRetry(true, false);
|
|
12414
|
+
}
|
|
12415
|
+
function handleOnline() {
|
|
12416
|
+
requestRetry(true, true);
|
|
12417
|
+
}
|
|
12418
|
+
const armSignals = () => {
|
|
12419
|
+
if (listening) return;
|
|
12420
|
+
listening = true;
|
|
12421
|
+
environment.addVisibilityChangeListener(handleForeground);
|
|
12422
|
+
environment.addPageShowListener(handleForeground);
|
|
12423
|
+
environment.addOnlineListener(handleOnline);
|
|
12424
|
+
};
|
|
12425
|
+
const scheduleRetry = () => {
|
|
12426
|
+
if (retryInFlight && !pending) return;
|
|
12427
|
+
pending = true;
|
|
12428
|
+
armSignals();
|
|
12429
|
+
if (retryInFlight) {
|
|
12430
|
+
rescheduleRequested = true;
|
|
12431
|
+
return;
|
|
12432
|
+
}
|
|
12433
|
+
if (timerId !== null || environment.isHidden() || retryAttempt >= RETRY_DELAYS_MS.length) {
|
|
12434
|
+
return;
|
|
12435
|
+
}
|
|
12436
|
+
const delayMs = RETRY_DELAYS_MS[retryAttempt];
|
|
12437
|
+
retryAttempt += 1;
|
|
12438
|
+
timerId = environment.setTimeout(() => {
|
|
12439
|
+
timerId = null;
|
|
12440
|
+
requestRetry(false, false);
|
|
12441
|
+
}, delayMs);
|
|
12442
|
+
};
|
|
12443
|
+
return {
|
|
12444
|
+
schedule: scheduleRetry,
|
|
12445
|
+
succeeded: reset,
|
|
12446
|
+
cancel: reset
|
|
12447
|
+
};
|
|
12448
|
+
}
|
|
12346
12449
|
function setTokens(config, state, data, onRefreshScheduled) {
|
|
12347
12450
|
state.accessToken = data.accessToken;
|
|
12348
12451
|
state.refreshToken = data.refreshToken;
|
|
@@ -12368,6 +12471,12 @@ function buildIdentityProof(config) {
|
|
|
12368
12471
|
}
|
|
12369
12472
|
return proof;
|
|
12370
12473
|
}
|
|
12474
|
+
function calculateRefreshDelay(accessTokenExpiry, now = Date.now()) {
|
|
12475
|
+
const remainingLifetime = accessTokenExpiry - now;
|
|
12476
|
+
if (remainingLifetime <= 0) return 0;
|
|
12477
|
+
const refreshLeadTime = Math.min(6e4, remainingLifetime / 2);
|
|
12478
|
+
return Math.max(0, Math.floor(remainingLifetime - refreshLeadTime));
|
|
12479
|
+
}
|
|
12371
12480
|
async function authenticateServerless(config, state, onRefreshScheduled) {
|
|
12372
12481
|
const nonce = crypto.randomUUID();
|
|
12373
12482
|
const timestamp = Date.now();
|
|
@@ -12380,6 +12489,7 @@ async function authenticateServerless(config, state, onRefreshScheduled) {
|
|
|
12380
12489
|
);
|
|
12381
12490
|
}
|
|
12382
12491
|
let is4xx = false;
|
|
12492
|
+
let responseStatus = 0;
|
|
12383
12493
|
try {
|
|
12384
12494
|
const body = {
|
|
12385
12495
|
nonce,
|
|
@@ -12393,6 +12503,7 @@ async function authenticateServerless(config, state, onRefreshScheduled) {
|
|
|
12393
12503
|
body: JSON.stringify(body),
|
|
12394
12504
|
credentials: "include"
|
|
12395
12505
|
});
|
|
12506
|
+
responseStatus = response.status;
|
|
12396
12507
|
if (!response.ok) {
|
|
12397
12508
|
is4xx = response.status >= 400 && response.status < 500;
|
|
12398
12509
|
const errorBody = await response.json().catch(() => ({ error: "Authentication failed" }));
|
|
@@ -12421,7 +12532,7 @@ async function authenticateServerless(config, state, onRefreshScheduled) {
|
|
|
12421
12532
|
} catch (err) {
|
|
12422
12533
|
if (is4xx || attempt === maxRetries) {
|
|
12423
12534
|
state.lastAuthError ?? (state.lastAuthError = {
|
|
12424
|
-
status:
|
|
12535
|
+
status: responseStatus,
|
|
12425
12536
|
error: err instanceof Error ? err.message : "Authentication failed"
|
|
12426
12537
|
});
|
|
12427
12538
|
state.isAuthenticated = false;
|
|
@@ -12435,6 +12546,15 @@ async function authenticateServerless(config, state, onRefreshScheduled) {
|
|
|
12435
12546
|
async function authenticateViaProxy(config, state, onRefreshScheduled) {
|
|
12436
12547
|
const maxRetries = config.maxRetries ?? 3;
|
|
12437
12548
|
const retryDelay = config.retryDelay ?? 500;
|
|
12549
|
+
const previousAuthentication = {
|
|
12550
|
+
accessToken: state.accessToken,
|
|
12551
|
+
refreshToken: state.refreshToken,
|
|
12552
|
+
tokenFamily: state.tokenFamily,
|
|
12553
|
+
accessTokenExpiry: state.accessTokenExpiry,
|
|
12554
|
+
refreshTokenExpiry: state.refreshTokenExpiry,
|
|
12555
|
+
isAuthenticated: state.isAuthenticated,
|
|
12556
|
+
widgetData: state.widgetData
|
|
12557
|
+
};
|
|
12438
12558
|
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
12439
12559
|
if (attempt > 0) {
|
|
12440
12560
|
await new Promise(
|
|
@@ -12476,7 +12596,13 @@ async function authenticateViaProxy(config, state, onRefreshScheduled) {
|
|
|
12476
12596
|
status,
|
|
12477
12597
|
error: err instanceof Error ? err.message : "Authentication failed"
|
|
12478
12598
|
};
|
|
12479
|
-
state.
|
|
12599
|
+
if (isPermanentAuthFailure(state.lastAuthError)) {
|
|
12600
|
+
const permanentError = state.lastAuthError;
|
|
12601
|
+
clearAuthenticationData(state);
|
|
12602
|
+
state.lastAuthError = permanentError;
|
|
12603
|
+
} else {
|
|
12604
|
+
Object.assign(state, previousAuthentication);
|
|
12605
|
+
}
|
|
12480
12606
|
return false;
|
|
12481
12607
|
}
|
|
12482
12608
|
}
|
|
@@ -12488,10 +12614,16 @@ async function refreshAccessToken(config, state, onRefreshScheduled, sendToken)
|
|
|
12488
12614
|
if (state.isRefreshing) {
|
|
12489
12615
|
return state.refreshPromise;
|
|
12490
12616
|
}
|
|
12491
|
-
if (!state.refreshToken) {
|
|
12492
|
-
return false;
|
|
12493
|
-
}
|
|
12494
12617
|
const presentedRefreshToken = state.refreshToken;
|
|
12618
|
+
const previousAuthentication = {
|
|
12619
|
+
accessToken: state.accessToken,
|
|
12620
|
+
refreshToken: state.refreshToken,
|
|
12621
|
+
tokenFamily: state.tokenFamily,
|
|
12622
|
+
accessTokenExpiry: state.accessTokenExpiry,
|
|
12623
|
+
refreshTokenExpiry: state.refreshTokenExpiry,
|
|
12624
|
+
isAuthenticated: state.isAuthenticated,
|
|
12625
|
+
widgetData: state.widgetData
|
|
12626
|
+
};
|
|
12495
12627
|
state.isRefreshing = true;
|
|
12496
12628
|
state.refreshPromise = (async () => {
|
|
12497
12629
|
const reauthenticateAfterRefreshFailure = async () => {
|
|
@@ -12500,13 +12632,22 @@ async function refreshAccessToken(config, state, onRefreshScheduled, sendToken)
|
|
|
12500
12632
|
if (sendToken) sendToken();
|
|
12501
12633
|
return true;
|
|
12502
12634
|
}
|
|
12503
|
-
clearAuthenticationData(state);
|
|
12504
|
-
clearStorage(config);
|
|
12505
12635
|
const authed = await authenticateServerless(config, state, onRefreshScheduled);
|
|
12506
12636
|
if (authed && sendToken) sendToken();
|
|
12637
|
+
if (!authed && isPermanentAuthFailure(state.lastAuthError)) {
|
|
12638
|
+
const permanentError = state.lastAuthError;
|
|
12639
|
+
clearAuthenticationData(state);
|
|
12640
|
+
state.lastAuthError = permanentError;
|
|
12641
|
+
clearStorage(config);
|
|
12642
|
+
} else if (!authed) {
|
|
12643
|
+
Object.assign(state, previousAuthentication);
|
|
12644
|
+
}
|
|
12507
12645
|
return authed;
|
|
12508
12646
|
};
|
|
12509
12647
|
try {
|
|
12648
|
+
if (!presentedRefreshToken) {
|
|
12649
|
+
return reauthenticateAfterRefreshFailure();
|
|
12650
|
+
}
|
|
12510
12651
|
const response = await fetch(`${config.apiUrl}/${config.widgetId}/auth/refresh`, {
|
|
12511
12652
|
method: "POST",
|
|
12512
12653
|
headers: {
|
|
@@ -12737,11 +12878,12 @@ function captureSnapshot(state) {
|
|
|
12737
12878
|
widgetData: state.widgetData
|
|
12738
12879
|
};
|
|
12739
12880
|
}
|
|
12740
|
-
function applySnapshot(subscriber, snapshot) {
|
|
12881
|
+
function applySnapshot(subscriber, snapshot, notify = true) {
|
|
12741
12882
|
var _a;
|
|
12742
12883
|
Object.assign(subscriber.state, snapshot);
|
|
12743
12884
|
if (snapshot.refreshToken) saveToStorage(subscriber.config, subscriber.state);
|
|
12744
12885
|
else clearStorage(subscriber.config);
|
|
12886
|
+
if (!notify) return;
|
|
12745
12887
|
try {
|
|
12746
12888
|
(_a = subscriber.onSnapshot) == null ? void 0 : _a.call(subscriber);
|
|
12747
12889
|
} catch (error) {
|
|
@@ -12786,7 +12928,7 @@ function subscribeAuthSession(config, state, onSnapshot) {
|
|
|
12786
12928
|
return Promise.resolve(true);
|
|
12787
12929
|
}
|
|
12788
12930
|
if (session.inFlight) return session.inFlight;
|
|
12789
|
-
if (session.snapshot) applySnapshot(subscriber, session.snapshot);
|
|
12931
|
+
if (session.snapshot) applySnapshot(subscriber, session.snapshot, false);
|
|
12790
12932
|
const startingGeneration = session.generation;
|
|
12791
12933
|
const inFlight = (async () => {
|
|
12792
12934
|
const succeeded = await execute();
|
|
@@ -12823,6 +12965,31 @@ function subscribeAuthSession(config, state, onSnapshot) {
|
|
|
12823
12965
|
};
|
|
12824
12966
|
}
|
|
12825
12967
|
const BUNDLE_READY_TIMEOUT_MS = 3e4;
|
|
12968
|
+
class BundleReadinessTimeoutError extends Error {
|
|
12969
|
+
constructor(phase, message) {
|
|
12970
|
+
super(message);
|
|
12971
|
+
__publicField(this, "phase");
|
|
12972
|
+
this.name = "BundleReadinessTimeoutError";
|
|
12973
|
+
this.phase = phase;
|
|
12974
|
+
}
|
|
12975
|
+
}
|
|
12976
|
+
function isBundleReadinessTimeoutError(error) {
|
|
12977
|
+
return error instanceof BundleReadinessTimeoutError;
|
|
12978
|
+
}
|
|
12979
|
+
function createDefaultEnvironment() {
|
|
12980
|
+
const visibilityDocument = typeof document === "undefined" ? void 0 : document;
|
|
12981
|
+
const pageWindow = typeof window === "undefined" ? void 0 : window;
|
|
12982
|
+
return {
|
|
12983
|
+
isHidden: () => (visibilityDocument == null ? void 0 : visibilityDocument.visibilityState) === "hidden",
|
|
12984
|
+
now: () => Date.now(),
|
|
12985
|
+
setTimeout: (callback, delayMs) => globalThis.setTimeout(callback, delayMs),
|
|
12986
|
+
clearTimeout: (timerId) => globalThis.clearTimeout(timerId),
|
|
12987
|
+
addVisibilityChangeListener: (listener) => visibilityDocument == null ? void 0 : visibilityDocument.addEventListener("visibilitychange", listener),
|
|
12988
|
+
removeVisibilityChangeListener: (listener) => visibilityDocument == null ? void 0 : visibilityDocument.removeEventListener("visibilitychange", listener),
|
|
12989
|
+
addPageShowListener: (listener) => pageWindow == null ? void 0 : pageWindow.addEventListener("pageshow", listener),
|
|
12990
|
+
removePageShowListener: (listener) => pageWindow == null ? void 0 : pageWindow.removeEventListener("pageshow", listener)
|
|
12991
|
+
};
|
|
12992
|
+
}
|
|
12826
12993
|
function isPromiseLike(value) {
|
|
12827
12994
|
return (typeof value === "object" || typeof value === "function") && value !== null && typeof value.then === "function";
|
|
12828
12995
|
}
|
|
@@ -12832,28 +12999,101 @@ function isReadyHandle(value) {
|
|
|
12832
12999
|
}
|
|
12833
13000
|
return isPromiseLike(value.ready);
|
|
12834
13001
|
}
|
|
12835
|
-
function
|
|
13002
|
+
function waitWithActiveTimeTimeout(promise, timeoutMs, timeoutError, environment) {
|
|
12836
13003
|
return new Promise((resolve, reject) => {
|
|
12837
|
-
|
|
12838
|
-
|
|
12839
|
-
|
|
13004
|
+
let settled = false;
|
|
13005
|
+
let remainingMs = Math.max(0, timeoutMs);
|
|
13006
|
+
let visibleStartedAt = null;
|
|
13007
|
+
let timeoutId = null;
|
|
13008
|
+
const clearActiveTimer = () => {
|
|
13009
|
+
if (timeoutId !== null) {
|
|
13010
|
+
environment.clearTimeout(timeoutId);
|
|
13011
|
+
timeoutId = null;
|
|
13012
|
+
}
|
|
13013
|
+
};
|
|
13014
|
+
const cleanup = () => {
|
|
13015
|
+
clearActiveTimer();
|
|
13016
|
+
environment.removeVisibilityChangeListener(handleVisibilityChange);
|
|
13017
|
+
};
|
|
13018
|
+
const finish = (callback) => {
|
|
13019
|
+
if (settled) return;
|
|
13020
|
+
settled = true;
|
|
13021
|
+
cleanup();
|
|
13022
|
+
callback();
|
|
13023
|
+
};
|
|
13024
|
+
const pauseDeadline = () => {
|
|
13025
|
+
clearActiveTimer();
|
|
13026
|
+
if (visibleStartedAt === null) return;
|
|
13027
|
+
remainingMs = Math.max(
|
|
13028
|
+
0,
|
|
13029
|
+
remainingMs - Math.max(0, environment.now() - visibleStartedAt)
|
|
13030
|
+
);
|
|
13031
|
+
visibleStartedAt = null;
|
|
13032
|
+
};
|
|
13033
|
+
const startDeadline = () => {
|
|
13034
|
+
if (settled || environment.isHidden() || timeoutId !== null) return;
|
|
13035
|
+
if (remainingMs <= 0) {
|
|
13036
|
+
finish(() => reject(timeoutError()));
|
|
13037
|
+
return;
|
|
13038
|
+
}
|
|
13039
|
+
visibleStartedAt = environment.now();
|
|
13040
|
+
timeoutId = environment.setTimeout(() => {
|
|
13041
|
+
timeoutId = null;
|
|
13042
|
+
if (environment.isHidden()) {
|
|
13043
|
+
visibleStartedAt = null;
|
|
13044
|
+
return;
|
|
13045
|
+
}
|
|
13046
|
+
visibleStartedAt = null;
|
|
13047
|
+
finish(() => reject(timeoutError()));
|
|
13048
|
+
}, remainingMs);
|
|
13049
|
+
};
|
|
13050
|
+
function handleVisibilityChange() {
|
|
13051
|
+
if (environment.isHidden()) {
|
|
13052
|
+
pauseDeadline();
|
|
13053
|
+
} else {
|
|
13054
|
+
startDeadline();
|
|
13055
|
+
}
|
|
13056
|
+
}
|
|
13057
|
+
environment.addVisibilityChangeListener(handleVisibilityChange);
|
|
13058
|
+
startDeadline();
|
|
12840
13059
|
Promise.resolve(promise).then(
|
|
12841
13060
|
(value) => {
|
|
12842
|
-
|
|
12843
|
-
resolve(value);
|
|
13061
|
+
finish(() => resolve(value));
|
|
12844
13062
|
},
|
|
12845
13063
|
(error) => {
|
|
12846
|
-
|
|
12847
|
-
reject(error);
|
|
13064
|
+
finish(() => reject(error));
|
|
12848
13065
|
}
|
|
12849
13066
|
);
|
|
12850
13067
|
});
|
|
12851
13068
|
}
|
|
12852
|
-
function
|
|
12853
|
-
return
|
|
13069
|
+
function scheduleForegroundRecovery(recover, environment = createDefaultEnvironment()) {
|
|
13070
|
+
if (!environment.isHidden()) return () => {
|
|
13071
|
+
};
|
|
13072
|
+
let active = true;
|
|
13073
|
+
const cleanup = () => {
|
|
13074
|
+
if (!active) return;
|
|
13075
|
+
active = false;
|
|
13076
|
+
environment.removeVisibilityChangeListener(handleForeground);
|
|
13077
|
+
environment.removePageShowListener(handleForeground);
|
|
13078
|
+
};
|
|
13079
|
+
const handleForeground = () => {
|
|
13080
|
+
if (!active || environment.isHidden()) return;
|
|
13081
|
+
cleanup();
|
|
13082
|
+
recover();
|
|
13083
|
+
};
|
|
13084
|
+
environment.addVisibilityChangeListener(handleForeground);
|
|
13085
|
+
environment.addPageShowListener(handleForeground);
|
|
13086
|
+
return cleanup;
|
|
13087
|
+
}
|
|
13088
|
+
function resolveBundleMountResult(mountResult, timeoutMs = BUNDLE_READY_TIMEOUT_MS, environment = createDefaultEnvironment()) {
|
|
13089
|
+
return isPromiseLike(mountResult) ? waitWithActiveTimeTimeout(
|
|
12854
13090
|
mountResult,
|
|
12855
13091
|
timeoutMs,
|
|
12856
|
-
|
|
13092
|
+
() => new BundleReadinessTimeoutError(
|
|
13093
|
+
"mount",
|
|
13094
|
+
`Widget bundle mount did not resolve within ${timeoutMs}ms`
|
|
13095
|
+
),
|
|
13096
|
+
environment
|
|
12857
13097
|
) : Promise.resolve(mountResult);
|
|
12858
13098
|
}
|
|
12859
13099
|
function createBundleMountCleanup(mountResult) {
|
|
@@ -12869,19 +13109,24 @@ function createBundleMountCleanup(mountResult) {
|
|
|
12869
13109
|
unmount.call(mountResult);
|
|
12870
13110
|
};
|
|
12871
13111
|
}
|
|
12872
|
-
async function waitForBundleMountReadiness(mountResult, firstPaint, timeoutMs = BUNDLE_READY_TIMEOUT_MS) {
|
|
13112
|
+
async function waitForBundleMountReadiness(mountResult, firstPaint, timeoutMs = BUNDLE_READY_TIMEOUT_MS, environment = createDefaultEnvironment()) {
|
|
12873
13113
|
const resolvedMountResult = await resolveBundleMountResult(
|
|
12874
13114
|
mountResult,
|
|
12875
|
-
timeoutMs
|
|
13115
|
+
timeoutMs,
|
|
13116
|
+
environment
|
|
12876
13117
|
);
|
|
12877
13118
|
if (!isReadyHandle(resolvedMountResult)) {
|
|
12878
13119
|
await firstPaint;
|
|
12879
13120
|
return "first-paint";
|
|
12880
13121
|
}
|
|
12881
|
-
await
|
|
13122
|
+
await waitWithActiveTimeTimeout(
|
|
12882
13123
|
resolvedMountResult.ready,
|
|
12883
13124
|
timeoutMs,
|
|
12884
|
-
|
|
13125
|
+
() => new BundleReadinessTimeoutError(
|
|
13126
|
+
"deep-ready",
|
|
13127
|
+
`Widget bundle did not report deep readiness within ${timeoutMs}ms`
|
|
13128
|
+
),
|
|
13129
|
+
environment
|
|
12885
13130
|
);
|
|
12886
13131
|
return "deep-ready";
|
|
12887
13132
|
}
|
|
@@ -13610,6 +13855,45 @@ function ensureWidgetPreconnects(origins, targetDocument) {
|
|
|
13610
13855
|
documentTarget.head.appendChild(link);
|
|
13611
13856
|
}
|
|
13612
13857
|
}
|
|
13858
|
+
const USER_LOOKUP_ERRORS = /* @__PURE__ */ new Set([
|
|
13859
|
+
"User not found",
|
|
13860
|
+
"Missing required user identifier fields",
|
|
13861
|
+
"Missing user identifier fields"
|
|
13862
|
+
]);
|
|
13863
|
+
function selectWidgetErrorPresentation({
|
|
13864
|
+
failureKind,
|
|
13865
|
+
customMessage,
|
|
13866
|
+
lastAuthError
|
|
13867
|
+
}) {
|
|
13868
|
+
if (failureKind === "bundle") {
|
|
13869
|
+
const message = "Widget failed to load. Please try again.";
|
|
13870
|
+
return {
|
|
13871
|
+
useCustomMessage: false,
|
|
13872
|
+
displayMessage: message,
|
|
13873
|
+
emittedMessage: message
|
|
13874
|
+
};
|
|
13875
|
+
}
|
|
13876
|
+
const useCustomMessage = Boolean(
|
|
13877
|
+
customMessage && (lastAuthError === null || (lastAuthError.error ? USER_LOOKUP_ERRORS.has(lastAuthError.error) : false))
|
|
13878
|
+
);
|
|
13879
|
+
if (useCustomMessage) {
|
|
13880
|
+
return {
|
|
13881
|
+
useCustomMessage: true,
|
|
13882
|
+
displayMessage: customMessage,
|
|
13883
|
+
emittedMessage: customMessage,
|
|
13884
|
+
hint: lastAuthError == null ? void 0 : lastAuthError.hint,
|
|
13885
|
+
status: lastAuthError == null ? void 0 : lastAuthError.status
|
|
13886
|
+
};
|
|
13887
|
+
}
|
|
13888
|
+
const emittedMessage = (lastAuthError == null ? void 0 : lastAuthError.error) || "Authentication failed";
|
|
13889
|
+
return {
|
|
13890
|
+
useCustomMessage: false,
|
|
13891
|
+
displayMessage: (lastAuthError == null ? void 0 : lastAuthError.hint) ? `${emittedMessage}: ${lastAuthError.hint}` : (lastAuthError == null ? void 0 : lastAuthError.error) ? emittedMessage : "Authentication failed. Please try again later.",
|
|
13892
|
+
emittedMessage,
|
|
13893
|
+
hint: lastAuthError == null ? void 0 : lastAuthError.hint,
|
|
13894
|
+
status: lastAuthError == null ? void 0 : lastAuthError.status
|
|
13895
|
+
};
|
|
13896
|
+
}
|
|
13613
13897
|
const widgetCSS = ':host{display:block;position:relative;width:100%;height:100%}.rai-loader{position:absolute;top:0;left:0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:.75rem;width:100%;height:100%;background:var(--rai-loading-background, var(--background-5, var(--rai-loader-bg, #ffffff)));border-radius:8px;z-index:10;transition:opacity .3s ease-out;font-family:var(--rai-loader-font, "Roboto", system-ui, -apple-system, sans-serif)}.rai-loader.fade-out{opacity:0;pointer-events:none}.rai-loader-pending-settings{visibility:hidden}.rai-loader-text{margin:.5rem 0 0;font-family:var(--rai-loading-text-font, var(--rai-loader-font, "Roboto", system-ui, -apple-system, sans-serif));font-size:var(--rai-loading-text-size, 1.125rem);line-height:1.75rem;font-weight:var(--rai-loading-text-weight, 400);font-style:var(--rai-loading-text-style, normal);text-decoration:var(--rai-loading-text-decoration, none);letter-spacing:normal;color:var(--rai-loading-text-color, var(--accent-1, var(--rai-accent, #000000)));text-align:center}@media (min-width: 768px){.rai-loader-text{font-size:var(--rai-loading-text-size, 1.5rem);line-height:2rem}}.rai-error{display:none;position:absolute;top:0;left:0;width:100%;height:100%;align-items:center;justify-content:center;flex-direction:column;gap:12px;background:var(--rai-error-bg, #1a1a1a);border-radius:8px;padding:24px;box-sizing:border-box;text-align:center;color:var(--rai-error-text, #9ca3af);font-family:system-ui,-apple-system,sans-serif;z-index:10}.rai-error.visible{display:flex}iframe{display:block;border:none;opacity:0;transition:opacity .3s ease-in}iframe.loaded{opacity:1}.rai-lottie-loader{width:100px;height:100px}.rai-lottie-loader svg{width:100%!important;height:100%!important}.rai-lottie-spinner{width:32px;height:32px;margin:34px auto;border:3px solid var(--rai-text4, #6b7280);border-top-color:var(--rai-accent, #000000);border-radius:50%;animation:rai-spin .7s linear infinite}@keyframes rai-spin{to{transform:rotate(360deg)}}.rai-sdk-loader{position:relative;width:75px;height:100px}.rai-sdk-loader__bar{position:absolute;bottom:0;width:10px;height:50%;background:var(--rai-accent, #000000);transform-origin:center bottom;box-shadow:1px 1px #0003}.rai-sdk-loader__bar:nth-child(1){left:0;transform:scaleY(.2);animation:rai-sdk-barUp1 4s infinite}.rai-sdk-loader__bar:nth-child(2){left:15px;transform:scaleY(.4);animation:rai-sdk-barUp2 4s infinite}.rai-sdk-loader__bar:nth-child(3){left:30px;transform:scaleY(.6);animation:rai-sdk-barUp3 4s infinite}.rai-sdk-loader__bar:nth-child(4){left:45px;transform:scaleY(.8);animation:rai-sdk-barUp4 4s infinite}.rai-sdk-loader__bar:nth-child(5){left:60px;transform:scale(1);animation:rai-sdk-barUp5 4s infinite}.rai-sdk-loader__ball{position:absolute;bottom:10px;left:0;width:10px;height:10px;background:var(--rai-accent, #000000);border-radius:50%;animation:rai-sdk-ball 4s infinite}@keyframes rai-sdk-ball{0%{transform:translate(0)}5%{transform:translate(8px,-14px)}10%{transform:translate(15px,-10px)}17%{transform:translate(23px,-24px)}20%{transform:translate(30px,-20px)}27%{transform:translate(38px,-34px)}30%{transform:translate(45px,-30px)}37%{transform:translate(53px,-44px)}40%{transform:translate(60px,-40px)}50%{transform:translate(60px)}57%{transform:translate(53px,-14px)}60%{transform:translate(45px,-10px)}67%{transform:translate(37px,-24px)}70%{transform:translate(30px,-20px)}77%{transform:translate(22px,-34px)}80%{transform:translate(15px,-30px)}87%{transform:translate(7px,-44px)}90%{transform:translateY(-40px)}to{transform:translate(0)}}@keyframes rai-sdk-barUp1{0%{transform:scaleY(.2)}40%{transform:scaleY(.2)}50%{transform:scale(1)}90%{transform:scale(1)}to{transform:scaleY(.2)}}@keyframes rai-sdk-barUp2{0%{transform:scaleY(.4)}40%{transform:scaleY(.4)}50%{transform:scaleY(.8)}90%{transform:scaleY(.8)}to{transform:scaleY(.4)}}@keyframes rai-sdk-barUp3{0%{transform:scaleY(.6)}to{transform:scaleY(.6)}}@keyframes rai-sdk-barUp4{0%{transform:scaleY(.8)}40%{transform:scaleY(.8)}50%{transform:scaleY(.4)}90%{transform:scaleY(.4)}to{transform:scaleY(.8)}}@keyframes rai-sdk-barUp5{0%{transform:scale(1)}40%{transform:scale(1)}50%{transform:scaleY(.2)}90%{transform:scaleY(.2)}to{transform:scale(1)}}#loading-square{width:75px;aspect-ratio:1;display:flex;color:var(--rai-accent, #000000);background:linear-gradient(currentColor 0 0) right / 51% 100%,linear-gradient(currentColor 0 0) bottom / 100% 51%;background-repeat:no-repeat;animation:l16-0 2s infinite linear .25s}#loading-square>div{width:50%;height:50%;background:currentColor;animation:l16-1 .5s infinite linear}@keyframes l16-0{0%,12.49%{transform:rotate(0)}12.5%,37.49%{transform:rotate(90deg)}37.5%,62.49%{transform:rotate(180deg)}62.5%,87.49%{transform:rotate(270deg)}87.5%,to{transform:rotate(360deg)}}@keyframes l16-1{0%{transform:perspective(80px) rotate3d(-1,-1,0,0)}80%,to{transform:perspective(80px) rotate3d(-1,-1,0,-180deg)}}#loading-circle{width:75px;aspect-ratio:1;display:grid;grid:50%/50%;color:var(--rai-accent, #000000);border-radius:50%;--_g: no-repeat linear-gradient(currentColor 0 0);background:var(--_g),var(--_g),var(--_g);background-size:50.1% 50.1%;animation:l9-0 1.5s infinite steps(1) alternate,l9-0-0 3s infinite steps(1) alternate}#loading-circle>div{background:var(--rai-text4, #6b7280);border-top-left-radius:100px;transform:perspective(150px) rotateY(0) rotateX(0);transform-origin:bottom right;animation:l9-1 1.5s infinite linear alternate}@keyframes l9-0{0%{background-position:0 100%,100% 100%,100% 0}33%{background-position:100% 100%,100% 100%,100% 0}66%{background-position:100% 0,100% 0,100% 0}}@keyframes l9-0-0{0%{transform:scaleX(1) rotate(0)}50%{transform:scaleX(-1) rotate(-90deg)}}@keyframes l9-1{16.5%{transform:perspective(150px) rotateX(-90deg) rotateY(0) rotateX(0);filter:grayscale(.8)}33%{transform:perspective(150px) rotateX(-180deg) rotateY(0) rotateX(0)}66%{transform:perspective(150px) rotateX(-180deg) rotateY(-180deg) rotateX(0)}to{transform:perspective(150px) rotateX(-180deg) rotateY(-180deg) rotateX(-180deg);filter:grayscale(.8)}}.rai-custom-error{position:absolute;top:0;left:0;width:100%;height:100%;z-index:10}.tiptap strong.tw-font-bold,.tiptap b.tw-font-bold{font-weight:700}.tiptap em.tw-font-italic,.tiptap i.tw-font-italic{font-style:italic}.tiptap a.tiptap-rich-text-link{color:#3b82f6;text-decoration:underline;position:relative;display:inline-block;width:fit-content}.tiptap a.tiptap-rich-text-link:hover{color:#3b82f6cc;text-decoration:none}.tiptap a.tiptap-rich-text-link:not([title=""]):before{content:attr(title);position:absolute;top:-2rem;left:50%;transform:translate(-50%);white-space:nowrap;border-radius:.25rem;background-color:#000;padding:.25rem .5rem;color:#fff;opacity:0;transition:opacity .2s;pointer-events:none}.tiptap a.tiptap-rich-text-link:not([title=""]):hover:before{opacity:1}.tiptap p[style*="text-align: left"]{text-align:left}.tiptap p[style*="text-align: center"]{text-align:center}.tiptap p[style*="text-align: right"]{text-align:right}.tiptap p[style*="text-align: justify"]{text-align:justify}.tiptap u{text-decoration:underline}.tiptap.ProseMirror{background-color:transparent;height:fit-content!important;word-wrap:break-word;white-space:pre-wrap;white-space:break-spaces;-webkit-font-variant-ligatures:none;font-variant-ligatures:none;font-feature-settings:"liga" 0;padding:0;width:100%;overflow-y:auto}.tiptap{line-height:1.6;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,sans-serif}.tiptap p{margin:.5em 0}.tiptap p:first-child{margin-top:0}.tiptap p:last-child{margin-bottom:0}.tiptap img{max-width:100%;height:auto;display:block}.tiptap p[style*="text-align: left"] img{margin-left:0;margin-right:auto}.tiptap p[style*="text-align: center"] img{margin-left:auto;margin-right:auto}.tiptap p[style*="text-align: right"] img{margin-left:auto;margin-right:0}.rai-retry-btn{padding:8px 20px;border:none;border-radius:6px;background:var(--rai-accent, #000000);color:var(--rai-error-bg, #ffffff);font-size:14px;font-family:system-ui,-apple-system,sans-serif;cursor:pointer}.rai-retry-btn:hover{opacity:.85}';
|
|
13614
13898
|
const DEFINED_ATTRS = /* @__PURE__ */ new Set([
|
|
13615
13899
|
"community-id",
|
|
@@ -14007,8 +14291,13 @@ class BaseWidget extends HTMLElement {
|
|
|
14007
14291
|
__publicField(this, "bannerNode", null);
|
|
14008
14292
|
__publicField(this, "releaseAutoThemeDisableLease");
|
|
14009
14293
|
__publicField(this, "bundleUnmount");
|
|
14294
|
+
__publicField(this, "cancelBundleForegroundRecovery");
|
|
14010
14295
|
__publicField(this, "authSession");
|
|
14296
|
+
__publicField(this, "authRenewalRecovery");
|
|
14011
14297
|
this.shadow = this.attachShadow({ mode: "closed" });
|
|
14298
|
+
this.authRenewalRecovery = createAuthRenewalRecoveryController(
|
|
14299
|
+
() => this.performScheduledRefresh()
|
|
14300
|
+
);
|
|
14012
14301
|
}
|
|
14013
14302
|
static get observedAttributes() {
|
|
14014
14303
|
return [
|
|
@@ -14062,15 +14351,18 @@ class BaseWidget extends HTMLElement {
|
|
|
14062
14351
|
}
|
|
14063
14352
|
}
|
|
14064
14353
|
disconnectedCallback() {
|
|
14065
|
-
var _a, _b, _c, _d;
|
|
14354
|
+
var _a, _b, _c, _d, _e;
|
|
14066
14355
|
(_a = this.intersectionObserver) == null ? void 0 : _a.disconnect();
|
|
14067
14356
|
(_b = this.themeObserver) == null ? void 0 : _b.disconnect();
|
|
14068
14357
|
(_c = this.identityAttributeObserver) == null ? void 0 : _c.disconnect();
|
|
14358
|
+
(_d = this.cancelBundleForegroundRecovery) == null ? void 0 : _d.call(this);
|
|
14359
|
+
this.cancelBundleForegroundRecovery = void 0;
|
|
14360
|
+
this.authRenewalRecovery.cancel();
|
|
14069
14361
|
this.teardownMountedWidget();
|
|
14070
14362
|
this.clearLottieInstances();
|
|
14071
14363
|
this.restoreLoaderHeight();
|
|
14072
14364
|
this.removeBanner();
|
|
14073
|
-
(
|
|
14365
|
+
(_e = this.authSession) == null ? void 0 : _e.release();
|
|
14074
14366
|
this.authSession = void 0;
|
|
14075
14367
|
clearState(this.state);
|
|
14076
14368
|
}
|
|
@@ -14498,25 +14790,24 @@ class BaseWidget extends HTMLElement {
|
|
|
14498
14790
|
if (container.children.length > 0) finish();
|
|
14499
14791
|
});
|
|
14500
14792
|
}
|
|
14501
|
-
showError() {
|
|
14793
|
+
showError(failureKind = "authentication") {
|
|
14502
14794
|
this.hideLoader();
|
|
14503
14795
|
const settings = this.state.errorSettings;
|
|
14504
|
-
const
|
|
14505
|
-
|
|
14506
|
-
|
|
14507
|
-
|
|
14796
|
+
const presentation = selectWidgetErrorPresentation({
|
|
14797
|
+
failureKind,
|
|
14798
|
+
customMessage: settings == null ? void 0 : settings.errorMessage,
|
|
14799
|
+
lastAuthError: this.state.lastAuthError
|
|
14800
|
+
});
|
|
14801
|
+
if (presentation.useCustomMessage) {
|
|
14508
14802
|
this.renderCustomError(settings);
|
|
14509
14803
|
} else if (this.errorEl) {
|
|
14510
|
-
if (
|
|
14511
|
-
this.msgEl.textContent = lastAuthError.hint ? `${lastAuthError.error}: ${lastAuthError.hint}` : lastAuthError.error;
|
|
14512
|
-
}
|
|
14804
|
+
if (this.msgEl) this.msgEl.textContent = presentation.displayMessage;
|
|
14513
14805
|
this.errorEl.classList.add("visible");
|
|
14514
14806
|
}
|
|
14515
|
-
const emittedMessage = shouldUseCustomMessage ? settings.errorMessage : (lastAuthError == null ? void 0 : lastAuthError.error) || "Authentication failed";
|
|
14516
14807
|
this.emit("rai-error", {
|
|
14517
|
-
message: emittedMessage,
|
|
14518
|
-
hint:
|
|
14519
|
-
status:
|
|
14808
|
+
message: presentation.emittedMessage,
|
|
14809
|
+
hint: presentation.hint,
|
|
14810
|
+
status: presentation.status
|
|
14520
14811
|
});
|
|
14521
14812
|
}
|
|
14522
14813
|
renderCustomError(settings) {
|
|
@@ -14672,7 +14963,10 @@ class BaseWidget extends HTMLElement {
|
|
|
14672
14963
|
}
|
|
14673
14964
|
// ── Initialization ─────────────────────────────────────────────────────
|
|
14674
14965
|
async init() {
|
|
14675
|
-
var _a;
|
|
14966
|
+
var _a, _b;
|
|
14967
|
+
(_a = this.cancelBundleForegroundRecovery) == null ? void 0 : _a.call(this);
|
|
14968
|
+
this.cancelBundleForegroundRecovery = void 0;
|
|
14969
|
+
this.authRenewalRecovery.cancel();
|
|
14676
14970
|
const initId = ++this.initGeneration;
|
|
14677
14971
|
this.hasAttemptedInit = true;
|
|
14678
14972
|
if (!this.config.communityId) {
|
|
@@ -14681,6 +14975,9 @@ class BaseWidget extends HTMLElement {
|
|
|
14681
14975
|
}
|
|
14682
14976
|
if (!this.config.authUrl && !this.authSession) {
|
|
14683
14977
|
this.authSession = subscribeAuthSession(this.config, this.state, () => {
|
|
14978
|
+
if (this.state.isAuthenticated && !this.state.lastAuthError) {
|
|
14979
|
+
this.authRenewalRecovery.succeeded();
|
|
14980
|
+
}
|
|
14684
14981
|
if (this.config.autoRefresh) this.scheduleRefresh();
|
|
14685
14982
|
if (this.state.iframe) {
|
|
14686
14983
|
sendTokenToWidget(this.config, this.state, this.state.iframe);
|
|
@@ -14772,7 +15069,7 @@ class BaseWidget extends HTMLElement {
|
|
|
14772
15069
|
launchWidget();
|
|
14773
15070
|
return;
|
|
14774
15071
|
}
|
|
14775
|
-
(
|
|
15072
|
+
(_b = this.authSession) == null ? void 0 : _b.publish();
|
|
14776
15073
|
const refreshed = await finishStartup(
|
|
14777
15074
|
this.authSession ? this.authSession.run(
|
|
14778
15075
|
"refresh",
|
|
@@ -14896,7 +15193,7 @@ class BaseWidget extends HTMLElement {
|
|
|
14896
15193
|
return { bundleApiUrl, colorMode };
|
|
14897
15194
|
}
|
|
14898
15195
|
async mountWidget(initId) {
|
|
14899
|
-
var _a;
|
|
15196
|
+
var _a, _b;
|
|
14900
15197
|
let container = null;
|
|
14901
15198
|
let cleanupBundleMount;
|
|
14902
15199
|
try {
|
|
@@ -15017,45 +15314,68 @@ class BaseWidget extends HTMLElement {
|
|
|
15017
15314
|
container == null ? void 0 : container.remove();
|
|
15018
15315
|
(_a = this.releaseAutoThemeDisableLease) == null ? void 0 : _a.call(this);
|
|
15019
15316
|
this.releaseAutoThemeDisableLease = void 0;
|
|
15020
|
-
|
|
15317
|
+
if (isBundleReadinessTimeoutError(err) && document.visibilityState === "hidden") {
|
|
15318
|
+
(_b = this.cancelBundleForegroundRecovery) == null ? void 0 : _b.call(this);
|
|
15319
|
+
let scheduledRecovery;
|
|
15320
|
+
scheduledRecovery = scheduleForegroundRecovery(() => {
|
|
15321
|
+
if (this.cancelBundleForegroundRecovery === scheduledRecovery) {
|
|
15322
|
+
this.cancelBundleForegroundRecovery = void 0;
|
|
15323
|
+
}
|
|
15324
|
+
if (this.isConnected) void this.init();
|
|
15325
|
+
});
|
|
15326
|
+
this.cancelBundleForegroundRecovery = scheduledRecovery;
|
|
15327
|
+
return;
|
|
15328
|
+
}
|
|
15329
|
+
this.showError("bundle");
|
|
15021
15330
|
}
|
|
15022
15331
|
}
|
|
15023
15332
|
// ── Token scheduling ──────────────────────────────────────────────────
|
|
15024
15333
|
scheduleRefresh() {
|
|
15025
15334
|
if (this.state.refreshTimer) clearTimeout(this.state.refreshTimer);
|
|
15026
15335
|
if (!this.state.accessTokenExpiry) return;
|
|
15027
|
-
const delay = this.state.accessTokenExpiry
|
|
15336
|
+
const delay = calculateRefreshDelay(this.state.accessTokenExpiry);
|
|
15337
|
+
if (delay > 0) {
|
|
15338
|
+
this.state.refreshTimer = setTimeout(
|
|
15339
|
+
() => void this.performScheduledRefresh(),
|
|
15340
|
+
delay
|
|
15341
|
+
);
|
|
15342
|
+
} else {
|
|
15343
|
+
void this.performScheduledRefresh();
|
|
15344
|
+
}
|
|
15345
|
+
}
|
|
15346
|
+
async performScheduledRefresh() {
|
|
15347
|
+
this.state.refreshTimer = null;
|
|
15028
15348
|
const pushToken = () => {
|
|
15029
15349
|
if (this.state.iframe)
|
|
15030
15350
|
sendTokenToWidget(this.config, this.state, this.state.iframe);
|
|
15031
15351
|
syncBundleAccessToken(this.config, this.state);
|
|
15032
15352
|
};
|
|
15033
|
-
|
|
15034
|
-
|
|
15035
|
-
|
|
15036
|
-
|
|
15037
|
-
|
|
15038
|
-
|
|
15039
|
-
|
|
15040
|
-
|
|
15041
|
-
else this.handleSessionExpired();
|
|
15042
|
-
} else {
|
|
15043
|
-
const ok = this.authSession ? await this.authSession.run(
|
|
15044
|
-
"refresh",
|
|
15045
|
-
() => refreshAccessToken(this.config, this.state)
|
|
15046
|
-
) : await refreshAccessToken(
|
|
15047
|
-
this.config,
|
|
15048
|
-
this.state,
|
|
15049
|
-
() => this.scheduleRefresh(),
|
|
15050
|
-
pushToken
|
|
15051
|
-
);
|
|
15052
|
-
if (!ok) this.handleSessionExpired();
|
|
15053
|
-
}
|
|
15054
|
-
};
|
|
15055
|
-
if (delay > 0) {
|
|
15056
|
-
this.state.refreshTimer = setTimeout(doRefresh, delay);
|
|
15353
|
+
let ok;
|
|
15354
|
+
if (this.config.authUrl) {
|
|
15355
|
+
ok = await authenticateViaProxy(
|
|
15356
|
+
this.config,
|
|
15357
|
+
this.state,
|
|
15358
|
+
() => this.scheduleRefresh()
|
|
15359
|
+
);
|
|
15360
|
+
if (ok) pushToken();
|
|
15057
15361
|
} else {
|
|
15058
|
-
|
|
15362
|
+
ok = this.authSession ? await this.authSession.run(
|
|
15363
|
+
"refresh",
|
|
15364
|
+
() => refreshAccessToken(this.config, this.state)
|
|
15365
|
+
) : await refreshAccessToken(
|
|
15366
|
+
this.config,
|
|
15367
|
+
this.state,
|
|
15368
|
+
() => this.scheduleRefresh(),
|
|
15369
|
+
pushToken
|
|
15370
|
+
);
|
|
15371
|
+
}
|
|
15372
|
+
if (ok) {
|
|
15373
|
+
this.authRenewalRecovery.succeeded();
|
|
15374
|
+
} else if (isPermanentAuthFailure(this.state.lastAuthError)) {
|
|
15375
|
+
this.authRenewalRecovery.cancel();
|
|
15376
|
+
this.handleSessionExpired();
|
|
15377
|
+
} else {
|
|
15378
|
+
this.authRenewalRecovery.schedule();
|
|
15059
15379
|
}
|
|
15060
15380
|
}
|
|
15061
15381
|
schedulePeriodicSync(iframe) {
|
|
@@ -15066,18 +15386,13 @@ class BaseWidget extends HTMLElement {
|
|
|
15066
15386
|
}, 12e4);
|
|
15067
15387
|
}
|
|
15068
15388
|
/**
|
|
15069
|
-
* A background refresh
|
|
15070
|
-
*
|
|
15071
|
-
*
|
|
15072
|
-
*
|
|
15073
|
-
* Every startup auth path already calls showError() on failure; this one is
|
|
15074
|
-
* reached from a timer, so without it the widget stays mounted showing stale
|
|
15075
|
-
* content while isAuthenticated() reports false to the host page — which is
|
|
15076
|
-
* how a signed-in user ends up looking at content meant for signed-out users.
|
|
15077
|
-
* The event gives hosts a signal to re-mint credentials instead of polling.
|
|
15389
|
+
* A background refresh reached a confirmed permanent authentication failure
|
|
15390
|
+
* after exhausting its safe recovery paths. Transient transport, throttling,
|
|
15391
|
+
* and server failures are retained by authRenewalRecovery instead.
|
|
15078
15392
|
*/
|
|
15079
15393
|
handleSessionExpired() {
|
|
15080
15394
|
var _a;
|
|
15395
|
+
this.authRenewalRecovery.cancel();
|
|
15081
15396
|
if (this.state.refreshTimer) {
|
|
15082
15397
|
clearTimeout(this.state.refreshTimer);
|
|
15083
15398
|
this.state.refreshTimer = null;
|
|
@@ -15097,6 +15412,7 @@ class BaseWidget extends HTMLElement {
|
|
|
15097
15412
|
// ── Logout helper ─────────────────────────────────────────────────────
|
|
15098
15413
|
async logoutAndClear() {
|
|
15099
15414
|
var _a;
|
|
15415
|
+
this.authRenewalRecovery.cancel();
|
|
15100
15416
|
await logout(this.config, this.state);
|
|
15101
15417
|
(_a = this.authSession) == null ? void 0 : _a.clear();
|
|
15102
15418
|
this.teardownMountedWidget();
|
|
@@ -15106,6 +15422,7 @@ class BaseWidget extends HTMLElement {
|
|
|
15106
15422
|
// ── Public API ────────────────────────────────────────────────────────
|
|
15107
15423
|
async reload() {
|
|
15108
15424
|
var _a, _b;
|
|
15425
|
+
this.authRenewalRecovery.cancel();
|
|
15109
15426
|
const previousConfig = this.config;
|
|
15110
15427
|
(_a = this.authSession) == null ? void 0 : _a.release();
|
|
15111
15428
|
this.authSession = void 0;
|
|
@@ -15253,7 +15570,7 @@ class CustomWidget extends BaseWidget {
|
|
|
15253
15570
|
}
|
|
15254
15571
|
}
|
|
15255
15572
|
}
|
|
15256
|
-
console.log(`[rai-widget] v${"1.8.
|
|
15573
|
+
console.log(`[rai-widget] v${"1.8.6"}`);
|
|
15257
15574
|
class StoreWidgetCompat extends StoreWidget {
|
|
15258
15575
|
}
|
|
15259
15576
|
const WIDGET_REGISTRY = [
|
|
@@ -15317,7 +15634,7 @@ function exposePublicApi() {
|
|
|
15317
15634
|
})();
|
|
15318
15635
|
const widget = container == null ? void 0 : container.querySelector(ALL_WIDGET_SELECTOR);
|
|
15319
15636
|
window.ReturningAIWidget = {
|
|
15320
|
-
version: "1.8.
|
|
15637
|
+
version: "1.8.6",
|
|
15321
15638
|
reload: () => (widget == null ? void 0 : widget.reload()) ?? Promise.resolve(),
|
|
15322
15639
|
logout: () => (widget == null ? void 0 : widget.logoutPublic()) ?? Promise.resolve(),
|
|
15323
15640
|
isAuthenticated: () => (widget == null ? void 0 : widget.isAuthenticated()) ?? false,
|