@returningai/widget-sdk 1.8.12 → 1.8.14
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 +49 -4
- package/README.md +133 -27
- 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 +776 -385
- package/dist/types/BaseWidget.d.ts +27 -0
- package/dist/types/core/auth.d.ts +18 -3
- package/dist/types/core/embed-token-renewal.d.ts +116 -0
- package/dist/types/core/host-callback.d.ts +4 -0
- package/dist/types/core/storage.d.ts +3 -1
- package/dist/types/index.d.ts +1 -1
- package/dist/types/types.d.ts +30 -0
- package/package.json +8 -3
package/dist/rai-widget.js
CHANGED
|
@@ -12275,7 +12275,12 @@ function legacyStorageKey(config) {
|
|
|
12275
12275
|
function errorSettingsKey(config) {
|
|
12276
12276
|
return `${config.storagePrefix}-${config.widgetId}-error-settings`;
|
|
12277
12277
|
}
|
|
12278
|
+
const retiredStates = /* @__PURE__ */ new WeakSet();
|
|
12279
|
+
function retireWidgetState(state) {
|
|
12280
|
+
retiredStates.add(state);
|
|
12281
|
+
}
|
|
12278
12282
|
function saveToStorage(config, state) {
|
|
12283
|
+
if (retiredStates.has(state)) return;
|
|
12279
12284
|
try {
|
|
12280
12285
|
const data = {
|
|
12281
12286
|
refreshToken: state.refreshToken,
|
|
@@ -12311,7 +12316,8 @@ function loadFromStorage(config, state) {
|
|
|
12311
12316
|
return false;
|
|
12312
12317
|
}
|
|
12313
12318
|
}
|
|
12314
|
-
function clearStorage(config) {
|
|
12319
|
+
function clearStorage(config, state) {
|
|
12320
|
+
if (state && retiredStates.has(state)) return;
|
|
12315
12321
|
try {
|
|
12316
12322
|
localStorage.removeItem(storageKey(config));
|
|
12317
12323
|
localStorage.removeItem(legacyStorageKey(config));
|
|
@@ -12446,6 +12452,363 @@ function createAuthRenewalRecoveryController(retry, environment = createDefaultE
|
|
|
12446
12452
|
cancel: reset
|
|
12447
12453
|
};
|
|
12448
12454
|
}
|
|
12455
|
+
const STORE_CALLBACK_FIELD_OPTIONS_SCOPE = "store.callback_field_options";
|
|
12456
|
+
const STORE_CALLBACK_FIELD_OPTIONS_CALLBACK_NAME = "callbackFieldOptions";
|
|
12457
|
+
const STORE_CALLBACK_FIELD_OPTIONS_TIMEOUT_MS = 15e3;
|
|
12458
|
+
const STORE_PURCHASE_SUCCESS_SCOPE = "store.purchase_success";
|
|
12459
|
+
const STORE_PURCHASE_SUCCESS_CALLBACK_NAME = "storePurchaseSuccess";
|
|
12460
|
+
const MILESTONE_CTA_CLICK_SCOPE = "milestone.cta_click";
|
|
12461
|
+
const MILESTONE_CTA_CLICK_CALLBACK_NAME = "milestoneCtaClick";
|
|
12462
|
+
const MILESTONE_CTA_CLICK_EVENT = "milestone_cta_clicked";
|
|
12463
|
+
function isRecord$1(value) {
|
|
12464
|
+
return typeof value === "object" && value !== null;
|
|
12465
|
+
}
|
|
12466
|
+
function isStringRecord$1(value) {
|
|
12467
|
+
return isRecord$1(value) && Object.values(value).every((item) => typeof item === "string");
|
|
12468
|
+
}
|
|
12469
|
+
function readEmbedTokenClaims(embedToken) {
|
|
12470
|
+
if (!embedToken) return null;
|
|
12471
|
+
const encodedPayload = embedToken.split(".")[1];
|
|
12472
|
+
if (!encodedPayload) return null;
|
|
12473
|
+
try {
|
|
12474
|
+
const normalizedPayload = encodedPayload.replace(/-/g, "+").replace(/_/g, "/");
|
|
12475
|
+
const paddedPayload = normalizedPayload.padEnd(
|
|
12476
|
+
Math.ceil(normalizedPayload.length / 4) * 4,
|
|
12477
|
+
"="
|
|
12478
|
+
);
|
|
12479
|
+
const bytes = Uint8Array.from(atob(paddedPayload), (character) => character.charCodeAt(0));
|
|
12480
|
+
const claims = JSON.parse(new TextDecoder().decode(bytes));
|
|
12481
|
+
return isRecord$1(claims) ? claims : null;
|
|
12482
|
+
} catch {
|
|
12483
|
+
return null;
|
|
12484
|
+
}
|
|
12485
|
+
}
|
|
12486
|
+
function readEmbedTokenUserIdentifiers(embedToken) {
|
|
12487
|
+
const claims = readEmbedTokenClaims(embedToken);
|
|
12488
|
+
if (!claims || !isStringRecord$1(claims.userIdentifiers)) return null;
|
|
12489
|
+
return { ...claims.userIdentifiers };
|
|
12490
|
+
}
|
|
12491
|
+
function resolveHostUserIdentifiers(config) {
|
|
12492
|
+
return readEmbedTokenUserIdentifiers(config.embedToken) ?? { ...config.userIdentifiers };
|
|
12493
|
+
}
|
|
12494
|
+
function hasCallbackContract(payload, callbackName, scope) {
|
|
12495
|
+
return isRecord$1(payload) && payload.callbackName === callbackName && payload.scope === scope;
|
|
12496
|
+
}
|
|
12497
|
+
function isMilestoneCtaClickPayload(payload) {
|
|
12498
|
+
if (!hasCallbackContract(
|
|
12499
|
+
payload,
|
|
12500
|
+
MILESTONE_CTA_CLICK_CALLBACK_NAME,
|
|
12501
|
+
MILESTONE_CTA_CLICK_SCOPE
|
|
12502
|
+
)) return false;
|
|
12503
|
+
const context = payload.context;
|
|
12504
|
+
if (!isRecord$1(context)) return false;
|
|
12505
|
+
const community = context.community;
|
|
12506
|
+
const milestone = context.milestone;
|
|
12507
|
+
const stage = context.stage;
|
|
12508
|
+
const button = context.button;
|
|
12509
|
+
const user = context.user;
|
|
12510
|
+
return context.event === MILESTONE_CTA_CLICK_EVENT && isRecord$1(community) && typeof community.id === "string" && community.id.length > 0 && (community.name === void 0 || community.name === null || typeof community.name === "string") && isRecord$1(milestone) && typeof milestone.id === "string" && milestone.id.length > 0 && typeof milestone.name === "string" && milestone.name.length > 0 && isRecord$1(stage) && typeof stage.id === "string" && stage.id.length > 0 && typeof stage.name === "string" && stage.name.length > 0 && isRecord$1(button) && typeof button.name === "string" && button.name.length > 0 && isRecord$1(user) && isStringRecord$1(user.identifiers) && typeof context.clickedAt === "string" && context.clickedAt.length > 0 && !Number.isNaN(Date.parse(context.clickedAt));
|
|
12511
|
+
}
|
|
12512
|
+
function enrichHostCallbackPayload(payload, userIdentifiers) {
|
|
12513
|
+
if (!userIdentifiers || Object.keys(userIdentifiers).length === 0) return payload;
|
|
12514
|
+
if (!isRecord$1(payload)) return payload;
|
|
12515
|
+
const context = payload.context;
|
|
12516
|
+
if (!isRecord$1(context)) return payload;
|
|
12517
|
+
const user = context.user;
|
|
12518
|
+
if (!isRecord$1(user)) return payload;
|
|
12519
|
+
return {
|
|
12520
|
+
...payload,
|
|
12521
|
+
context: {
|
|
12522
|
+
...context,
|
|
12523
|
+
user: {
|
|
12524
|
+
...user,
|
|
12525
|
+
identifiers: { ...userIdentifiers }
|
|
12526
|
+
}
|
|
12527
|
+
}
|
|
12528
|
+
};
|
|
12529
|
+
}
|
|
12530
|
+
const HOST_CALLBACK_DEFINITIONS = {
|
|
12531
|
+
[STORE_CALLBACK_FIELD_OPTIONS_CALLBACK_NAME]: {
|
|
12532
|
+
callbackName: STORE_CALLBACK_FIELD_OPTIONS_CALLBACK_NAME,
|
|
12533
|
+
scope: STORE_CALLBACK_FIELD_OPTIONS_SCOPE,
|
|
12534
|
+
sourceWidgetType: "store",
|
|
12535
|
+
allowedHostWidgetTypes: ["store", "custom"],
|
|
12536
|
+
completionMode: "result",
|
|
12537
|
+
missingHandler: "reject",
|
|
12538
|
+
legacyActions: ["store:host-callback"],
|
|
12539
|
+
validatePayload: (payload) => hasCallbackContract(
|
|
12540
|
+
payload,
|
|
12541
|
+
STORE_CALLBACK_FIELD_OPTIONS_CALLBACK_NAME,
|
|
12542
|
+
STORE_CALLBACK_FIELD_OPTIONS_SCOPE
|
|
12543
|
+
)
|
|
12544
|
+
},
|
|
12545
|
+
[STORE_PURCHASE_SUCCESS_CALLBACK_NAME]: {
|
|
12546
|
+
callbackName: STORE_PURCHASE_SUCCESS_CALLBACK_NAME,
|
|
12547
|
+
scope: STORE_PURCHASE_SUCCESS_SCOPE,
|
|
12548
|
+
sourceWidgetType: "store",
|
|
12549
|
+
allowedHostWidgetTypes: ["store", "custom"],
|
|
12550
|
+
completionMode: "acknowledged",
|
|
12551
|
+
missingHandler: "reject",
|
|
12552
|
+
legacyActions: ["store:host-callback"],
|
|
12553
|
+
validatePayload: (payload) => hasCallbackContract(
|
|
12554
|
+
payload,
|
|
12555
|
+
STORE_PURCHASE_SUCCESS_CALLBACK_NAME,
|
|
12556
|
+
STORE_PURCHASE_SUCCESS_SCOPE
|
|
12557
|
+
)
|
|
12558
|
+
},
|
|
12559
|
+
[MILESTONE_CTA_CLICK_CALLBACK_NAME]: {
|
|
12560
|
+
callbackName: MILESTONE_CTA_CLICK_CALLBACK_NAME,
|
|
12561
|
+
scope: MILESTONE_CTA_CLICK_SCOPE,
|
|
12562
|
+
sourceWidgetType: "milestone",
|
|
12563
|
+
allowedHostWidgetTypes: ["milestone", "custom"],
|
|
12564
|
+
completionMode: "detached",
|
|
12565
|
+
missingHandler: "ignore",
|
|
12566
|
+
legacyActions: [],
|
|
12567
|
+
validatePayload: isMilestoneCtaClickPayload
|
|
12568
|
+
}
|
|
12569
|
+
};
|
|
12570
|
+
function createInvocationId() {
|
|
12571
|
+
return `host_callback_${Date.now()}_${Math.random().toString(36).slice(2)}`;
|
|
12572
|
+
}
|
|
12573
|
+
function observe(observer, event) {
|
|
12574
|
+
if (!observer) return;
|
|
12575
|
+
try {
|
|
12576
|
+
observer(event);
|
|
12577
|
+
} catch {
|
|
12578
|
+
}
|
|
12579
|
+
}
|
|
12580
|
+
function getHostCallbackDefinition(callbackName, payload) {
|
|
12581
|
+
const definition = HOST_CALLBACK_DEFINITIONS[callbackName];
|
|
12582
|
+
return (definition == null ? void 0 : definition.validatePayload(payload)) ? definition : void 0;
|
|
12583
|
+
}
|
|
12584
|
+
function getSupportedHostCallbacks(callbacks, hostWidgetType) {
|
|
12585
|
+
return Object.values(HOST_CALLBACK_DEFINITIONS).filter(
|
|
12586
|
+
(definition) => definition.allowedHostWidgetTypes.includes(hostWidgetType) && Object.prototype.hasOwnProperty.call(callbacks, definition.callbackName) && typeof callbacks[definition.callbackName] === "function"
|
|
12587
|
+
).map((definition) => definition.callbackName);
|
|
12588
|
+
}
|
|
12589
|
+
function isHostCallbackMessageSupported(definition, action, sourceWidgetType, hostWidgetType) {
|
|
12590
|
+
const actionSupported = action === "widget:host-callback" || definition.legacyActions.includes(action);
|
|
12591
|
+
return actionSupported && sourceWidgetType === definition.sourceWidgetType && definition.allowedHostWidgetTypes.includes(hostWidgetType);
|
|
12592
|
+
}
|
|
12593
|
+
function dispatchHostCallback(input) {
|
|
12594
|
+
const definition = getHostCallbackDefinition(input.callbackName, input.payload);
|
|
12595
|
+
if (!definition || !definition.allowedHostWidgetTypes.includes(input.hostWidgetType)) {
|
|
12596
|
+
throw new Error("Host callback is not supported for this widget");
|
|
12597
|
+
}
|
|
12598
|
+
const invocationId = input.invocationId || createInvocationId();
|
|
12599
|
+
const eventBase = {
|
|
12600
|
+
invocationId,
|
|
12601
|
+
callbackName: definition.callbackName,
|
|
12602
|
+
scope: definition.scope,
|
|
12603
|
+
sourceWidgetType: definition.sourceWidgetType,
|
|
12604
|
+
hostWidgetType: input.hostWidgetType,
|
|
12605
|
+
completionMode: definition.completionMode,
|
|
12606
|
+
transport: input.transport
|
|
12607
|
+
};
|
|
12608
|
+
observe(input.observer, { type: "callback.received", ...eventBase });
|
|
12609
|
+
const callback = input.callbacks[definition.callbackName];
|
|
12610
|
+
if (!callback) {
|
|
12611
|
+
observe(input.observer, { type: "callback.handler_missing", ...eventBase });
|
|
12612
|
+
if (definition.missingHandler === "ignore") return;
|
|
12613
|
+
return Promise.reject(new Error("Host callback is not registered"));
|
|
12614
|
+
}
|
|
12615
|
+
observe(input.observer, { type: "callback.handler_started", ...eventBase });
|
|
12616
|
+
let result;
|
|
12617
|
+
try {
|
|
12618
|
+
result = callback(input.payload);
|
|
12619
|
+
} catch (error) {
|
|
12620
|
+
observe(input.observer, {
|
|
12621
|
+
type: "callback.handler_rejected",
|
|
12622
|
+
...eventBase,
|
|
12623
|
+
error
|
|
12624
|
+
});
|
|
12625
|
+
if (definition.completionMode === "detached") return;
|
|
12626
|
+
return Promise.reject(new Error("Host callback failed"));
|
|
12627
|
+
}
|
|
12628
|
+
if (definition.completionMode === "detached") {
|
|
12629
|
+
if (result && typeof result.then === "function") {
|
|
12630
|
+
void Promise.resolve(result).then(
|
|
12631
|
+
() => observe(input.observer, { type: "callback.handler_resolved", ...eventBase }),
|
|
12632
|
+
(error) => observe(input.observer, {
|
|
12633
|
+
type: "callback.handler_rejected",
|
|
12634
|
+
...eventBase,
|
|
12635
|
+
error
|
|
12636
|
+
})
|
|
12637
|
+
);
|
|
12638
|
+
} else {
|
|
12639
|
+
observe(input.observer, { type: "callback.handler_resolved", ...eventBase });
|
|
12640
|
+
}
|
|
12641
|
+
return;
|
|
12642
|
+
}
|
|
12643
|
+
return Promise.resolve(result).then(
|
|
12644
|
+
(value) => {
|
|
12645
|
+
observe(input.observer, { type: "callback.handler_resolved", ...eventBase });
|
|
12646
|
+
return definition.completionMode === "result" ? value : void 0;
|
|
12647
|
+
},
|
|
12648
|
+
(error) => {
|
|
12649
|
+
observe(input.observer, {
|
|
12650
|
+
type: "callback.handler_rejected",
|
|
12651
|
+
...eventBase,
|
|
12652
|
+
error
|
|
12653
|
+
});
|
|
12654
|
+
throw new Error("Host callback failed");
|
|
12655
|
+
}
|
|
12656
|
+
);
|
|
12657
|
+
}
|
|
12658
|
+
const EMBED_TOKEN_REJECTED_ERROR = "Invalid or expired embed token";
|
|
12659
|
+
const EMBED_TOKEN_EXPIRY_WINDOW_MS = 3e4;
|
|
12660
|
+
const EMBED_TOKEN_REQUEST_TIMEOUT_MS = 1e4;
|
|
12661
|
+
const EMBED_TOKEN_REQUEST_COOLDOWN_MS = 3e4;
|
|
12662
|
+
const EMBED_TOKEN_CACHE_MARGIN_MS = 6e4;
|
|
12663
|
+
const defaultClock = {
|
|
12664
|
+
now: () => Date.now(),
|
|
12665
|
+
setTimeout: (callback, ms) => setTimeout(callback, ms),
|
|
12666
|
+
clearTimeout: (handle) => clearTimeout(handle)
|
|
12667
|
+
};
|
|
12668
|
+
function isRecord(value) {
|
|
12669
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
12670
|
+
}
|
|
12671
|
+
function isStringRecord(value) {
|
|
12672
|
+
return isRecord(value) && Object.values(value).every((item) => typeof item === "string");
|
|
12673
|
+
}
|
|
12674
|
+
function decodeEmbedTokenClaims(embedToken) {
|
|
12675
|
+
const payload = readEmbedTokenClaims(embedToken ?? void 0);
|
|
12676
|
+
if (!payload) return null;
|
|
12677
|
+
return {
|
|
12678
|
+
accessId: typeof payload.accessId === "string" ? payload.accessId : void 0,
|
|
12679
|
+
communityId: typeof payload.communityId === "string" ? payload.communityId : void 0,
|
|
12680
|
+
userIdentifiers: isStringRecord(payload.userIdentifiers) ? { ...payload.userIdentifiers } : void 0,
|
|
12681
|
+
exp: typeof payload.exp === "number" && Number.isFinite(payload.exp) ? payload.exp : void 0
|
|
12682
|
+
};
|
|
12683
|
+
}
|
|
12684
|
+
function sortedIdentifiers(identifiers) {
|
|
12685
|
+
return Object.keys(identifiers || {}).sort().map((key) => [key, identifiers[key]]);
|
|
12686
|
+
}
|
|
12687
|
+
function hasIdentifiers(identifiers) {
|
|
12688
|
+
return !!identifiers && Object.keys(identifiers).length > 0;
|
|
12689
|
+
}
|
|
12690
|
+
function embedIdentityKey(embedToken) {
|
|
12691
|
+
if (!embedToken) return "";
|
|
12692
|
+
const claims = decodeEmbedTokenClaims(embedToken);
|
|
12693
|
+
if (!claims || !hasIdentifiers(claims.userIdentifiers)) return embedToken;
|
|
12694
|
+
return JSON.stringify({
|
|
12695
|
+
accessId: claims.accessId ?? "",
|
|
12696
|
+
communityId: claims.communityId ?? "",
|
|
12697
|
+
userIdentifiers: sortedIdentifiers(claims.userIdentifiers)
|
|
12698
|
+
});
|
|
12699
|
+
}
|
|
12700
|
+
function identitySignatureForConfig(config) {
|
|
12701
|
+
return JSON.stringify({
|
|
12702
|
+
embedToken: embedIdentityKey(config.embedToken),
|
|
12703
|
+
userIdentifiers: sortedIdentifiers(config.userIdentifiers)
|
|
12704
|
+
});
|
|
12705
|
+
}
|
|
12706
|
+
function isEmbedTokenRejected(error) {
|
|
12707
|
+
return !!error && error.status === 401 && error.error === EMBED_TOKEN_REJECTED_ERROR;
|
|
12708
|
+
}
|
|
12709
|
+
function isEmbedTokenExpiring(embedToken, now = Date.now()) {
|
|
12710
|
+
var _a;
|
|
12711
|
+
const exp = (_a = decodeEmbedTokenClaims(embedToken)) == null ? void 0 : _a.exp;
|
|
12712
|
+
if (exp === void 0) return false;
|
|
12713
|
+
return exp * 1e3 <= now + EMBED_TOKEN_EXPIRY_WINDOW_MS;
|
|
12714
|
+
}
|
|
12715
|
+
function readEmbedTokenProvider(callbacks) {
|
|
12716
|
+
const provider = callbacks == null ? void 0 : callbacks.embedTokenRequest;
|
|
12717
|
+
return typeof provider === "function" ? provider : null;
|
|
12718
|
+
}
|
|
12719
|
+
function sameIdentifiers(left, right) {
|
|
12720
|
+
return JSON.stringify(sortedIdentifiers(left)) === JSON.stringify(sortedIdentifiers(right));
|
|
12721
|
+
}
|
|
12722
|
+
function acceptRenewedEmbedToken(staleToken, result, now = Date.now()) {
|
|
12723
|
+
if (!isRecord(result)) return null;
|
|
12724
|
+
const candidate = result.embedToken;
|
|
12725
|
+
if (typeof candidate !== "string" || !candidate || candidate === staleToken) return null;
|
|
12726
|
+
const stale = decodeEmbedTokenClaims(staleToken);
|
|
12727
|
+
const next = decodeEmbedTokenClaims(candidate);
|
|
12728
|
+
if (!stale || !next) return null;
|
|
12729
|
+
if (next.exp === void 0 || next.exp * 1e3 <= now + EMBED_TOKEN_EXPIRY_WINDOW_MS) return null;
|
|
12730
|
+
if (!stale.communityId || stale.communityId !== next.communityId) return null;
|
|
12731
|
+
if (hasIdentifiers(stale.userIdentifiers)) {
|
|
12732
|
+
if (!sameIdentifiers(stale.userIdentifiers, next.userIdentifiers)) return null;
|
|
12733
|
+
} else if (hasIdentifiers(next.userIdentifiers)) {
|
|
12734
|
+
return null;
|
|
12735
|
+
}
|
|
12736
|
+
return candidate;
|
|
12737
|
+
}
|
|
12738
|
+
const REGISTRY_SYMBOL$1 = Symbol.for("returningai.widget-sdk.embed-token-renewal.v1");
|
|
12739
|
+
function registry$1() {
|
|
12740
|
+
const root = globalThis;
|
|
12741
|
+
root[REGISTRY_SYMBOL$1] ?? (root[REGISTRY_SYMBOL$1] = /* @__PURE__ */ new Map());
|
|
12742
|
+
return root[REGISTRY_SYMBOL$1];
|
|
12743
|
+
}
|
|
12744
|
+
function registryEntry(key) {
|
|
12745
|
+
const entries2 = registry$1();
|
|
12746
|
+
let entry = entries2.get(key);
|
|
12747
|
+
if (!entry) {
|
|
12748
|
+
entry = { inFlight: null, cachedToken: null, cachedUntil: 0, cooldownUntil: 0 };
|
|
12749
|
+
entries2.set(key, entry);
|
|
12750
|
+
}
|
|
12751
|
+
return entry;
|
|
12752
|
+
}
|
|
12753
|
+
function markRenewedEmbedTokenRefused(staleToken, refusedToken, clock = defaultClock) {
|
|
12754
|
+
const cooldownUntil = clock.now() + EMBED_TOKEN_REQUEST_COOLDOWN_MS;
|
|
12755
|
+
for (const token of /* @__PURE__ */ new Set([staleToken, refusedToken])) {
|
|
12756
|
+
const entry = registryEntry(embedIdentityKey(token));
|
|
12757
|
+
if (entry.cachedToken === refusedToken) {
|
|
12758
|
+
entry.cachedToken = null;
|
|
12759
|
+
entry.cachedUntil = 0;
|
|
12760
|
+
}
|
|
12761
|
+
entry.cooldownUntil = Math.max(entry.cooldownUntil, cooldownUntil);
|
|
12762
|
+
}
|
|
12763
|
+
}
|
|
12764
|
+
function renewEmbedToken(request) {
|
|
12765
|
+
const clock = request.clock ?? defaultClock;
|
|
12766
|
+
const entry = registryEntry(embedIdentityKey(request.staleToken));
|
|
12767
|
+
const now = clock.now();
|
|
12768
|
+
if (entry.cachedToken && entry.cachedToken !== request.staleToken && now < entry.cachedUntil) {
|
|
12769
|
+
return Promise.resolve(entry.cachedToken);
|
|
12770
|
+
}
|
|
12771
|
+
if (entry.inFlight) return entry.inFlight;
|
|
12772
|
+
if (now < entry.cooldownUntil) return Promise.resolve(null);
|
|
12773
|
+
const current = entry;
|
|
12774
|
+
const inFlight = (async () => {
|
|
12775
|
+
var _a;
|
|
12776
|
+
let timer;
|
|
12777
|
+
const timeout = new Promise((resolve) => {
|
|
12778
|
+
timer = clock.setTimeout(() => resolve(void 0), EMBED_TOKEN_REQUEST_TIMEOUT_MS);
|
|
12779
|
+
});
|
|
12780
|
+
let accepted = null;
|
|
12781
|
+
try {
|
|
12782
|
+
const answer = await Promise.race([
|
|
12783
|
+
Promise.resolve().then(() => request.provider({ reason: request.reason })),
|
|
12784
|
+
timeout
|
|
12785
|
+
]);
|
|
12786
|
+
accepted = acceptRenewedEmbedToken(request.staleToken, answer, clock.now());
|
|
12787
|
+
} catch {
|
|
12788
|
+
accepted = null;
|
|
12789
|
+
} finally {
|
|
12790
|
+
clock.clearTimeout(timer);
|
|
12791
|
+
}
|
|
12792
|
+
if (accepted) {
|
|
12793
|
+
const exp = ((_a = decodeEmbedTokenClaims(accepted)) == null ? void 0 : _a.exp) ?? 0;
|
|
12794
|
+
current.cachedToken = accepted;
|
|
12795
|
+
current.cachedUntil = exp * 1e3 - EMBED_TOKEN_CACHE_MARGIN_MS;
|
|
12796
|
+
current.cooldownUntil = 0;
|
|
12797
|
+
} else {
|
|
12798
|
+
current.cooldownUntil = clock.now() + EMBED_TOKEN_REQUEST_COOLDOWN_MS;
|
|
12799
|
+
}
|
|
12800
|
+
current.inFlight = null;
|
|
12801
|
+
return accepted;
|
|
12802
|
+
})();
|
|
12803
|
+
current.inFlight = inFlight;
|
|
12804
|
+
return inFlight;
|
|
12805
|
+
}
|
|
12806
|
+
function decideEmbedTokenChange(input) {
|
|
12807
|
+
if (!input.hasAttemptedInit) return "update";
|
|
12808
|
+
if (!input.sameSignature) return "reload";
|
|
12809
|
+
if (!input.tokenChanged) return "update";
|
|
12810
|
+
return input.healthy && input.hasProvider ? "swap" : "reload";
|
|
12811
|
+
}
|
|
12449
12812
|
function setTokens(config, state, data, onRefreshScheduled) {
|
|
12450
12813
|
state.accessToken = data.accessToken;
|
|
12451
12814
|
state.refreshToken = data.refreshToken;
|
|
@@ -12471,13 +12834,62 @@ function buildIdentityProof(config) {
|
|
|
12471
12834
|
}
|
|
12472
12835
|
return proof;
|
|
12473
12836
|
}
|
|
12837
|
+
function canReauthenticateAfterTransientFailure(config) {
|
|
12838
|
+
var _a;
|
|
12839
|
+
if (!config.embedToken) return true;
|
|
12840
|
+
const exp = (_a = readEmbedTokenClaims(config.embedToken)) == null ? void 0 : _a.exp;
|
|
12841
|
+
return typeof exp === "number" && exp * 1e3 > Date.now();
|
|
12842
|
+
}
|
|
12474
12843
|
function calculateRefreshDelay(accessTokenExpiry, now = Date.now()) {
|
|
12475
12844
|
const remainingLifetime = accessTokenExpiry - now;
|
|
12476
12845
|
if (remainingLifetime <= 0) return 0;
|
|
12477
12846
|
const refreshLeadTime = Math.min(6e4, remainingLifetime / 2);
|
|
12478
12847
|
return Math.max(0, Math.floor(remainingLifetime - refreshLeadTime));
|
|
12479
12848
|
}
|
|
12480
|
-
async function authenticateServerless(config, state, onRefreshScheduled) {
|
|
12849
|
+
async function authenticateServerless(config, state, renewal, onRefreshScheduled) {
|
|
12850
|
+
var _a;
|
|
12851
|
+
const provider = ((_a = renewal.getEmbedTokenProvider) == null ? void 0 : _a.call(renewal)) ?? null;
|
|
12852
|
+
const isCurrent = () => !renewal.isCurrent || renewal.isCurrent();
|
|
12853
|
+
let renewalAttempted = false;
|
|
12854
|
+
let renewed = null;
|
|
12855
|
+
let presentedToken;
|
|
12856
|
+
const renewEmbedTokenOnce = async () => {
|
|
12857
|
+
const staleToken = config.embedToken;
|
|
12858
|
+
if (!provider || !staleToken || renewalAttempted) return false;
|
|
12859
|
+
renewalAttempted = true;
|
|
12860
|
+
const fresh = await renewEmbedToken({
|
|
12861
|
+
staleToken,
|
|
12862
|
+
reason: renewal.reason ?? "expired",
|
|
12863
|
+
provider
|
|
12864
|
+
});
|
|
12865
|
+
if (!fresh) return false;
|
|
12866
|
+
if (config.embedToken === staleToken) config.embedToken = fresh;
|
|
12867
|
+
renewed = { from: staleToken, to: fresh };
|
|
12868
|
+
return true;
|
|
12869
|
+
};
|
|
12870
|
+
const signIn = async () => {
|
|
12871
|
+
const presented = config.embedToken;
|
|
12872
|
+
presentedToken = presented;
|
|
12873
|
+
const authed = await signInOnce(config, state, onRefreshScheduled);
|
|
12874
|
+
if (!authed && renewed && presented === renewed.to && isEmbedTokenRejected(state.lastAuthError)) {
|
|
12875
|
+
markRenewedEmbedTokenRefused(renewed.from, renewed.to);
|
|
12876
|
+
}
|
|
12877
|
+
return authed;
|
|
12878
|
+
};
|
|
12879
|
+
if (provider && config.embedToken && isEmbedTokenExpiring(config.embedToken)) {
|
|
12880
|
+
await renewEmbedTokenOnce();
|
|
12881
|
+
}
|
|
12882
|
+
if (await signIn()) return true;
|
|
12883
|
+
if (!isEmbedTokenRejected(state.lastAuthError)) return false;
|
|
12884
|
+
if (provider && config.embedToken && config.embedToken !== presentedToken) {
|
|
12885
|
+
if (!isCurrent()) return false;
|
|
12886
|
+
return signIn();
|
|
12887
|
+
}
|
|
12888
|
+
if (!await renewEmbedTokenOnce() || !isCurrent()) return false;
|
|
12889
|
+
return signIn();
|
|
12890
|
+
}
|
|
12891
|
+
async function signInOnce(config, state, onRefreshScheduled) {
|
|
12892
|
+
state.lastAuthError = null;
|
|
12481
12893
|
const nonce = crypto.randomUUID();
|
|
12482
12894
|
const timestamp = Date.now();
|
|
12483
12895
|
const maxRetries = config.maxRetries ?? 3;
|
|
@@ -12610,7 +13022,7 @@ async function authenticateViaProxy(config, state, onRefreshScheduled) {
|
|
|
12610
13022
|
state.isAuthenticated = false;
|
|
12611
13023
|
return false;
|
|
12612
13024
|
}
|
|
12613
|
-
async function refreshAccessToken(config, state, onRefreshScheduled, sendToken) {
|
|
13025
|
+
async function refreshAccessToken(config, state, renewal, onRefreshScheduled, sendToken) {
|
|
12614
13026
|
if (state.isRefreshing) {
|
|
12615
13027
|
return state.refreshPromise;
|
|
12616
13028
|
}
|
|
@@ -12626,50 +13038,81 @@ async function refreshAccessToken(config, state, onRefreshScheduled, sendToken)
|
|
|
12626
13038
|
};
|
|
12627
13039
|
state.isRefreshing = true;
|
|
12628
13040
|
state.refreshPromise = (async () => {
|
|
12629
|
-
const
|
|
13041
|
+
const adoptNewerGeneration = () => {
|
|
12630
13042
|
if (state.refreshToken && state.refreshToken !== presentedRefreshToken && state.accessToken && state.accessTokenExpiry && Date.now() < state.accessTokenExpiry) {
|
|
12631
13043
|
state.isAuthenticated = true;
|
|
12632
13044
|
if (sendToken) sendToken();
|
|
12633
13045
|
return true;
|
|
12634
13046
|
}
|
|
12635
|
-
|
|
13047
|
+
return false;
|
|
13048
|
+
};
|
|
13049
|
+
const reauthenticateAfterRefreshFailure = async () => {
|
|
13050
|
+
if (adoptNewerGeneration()) return true;
|
|
13051
|
+
const authed = await authenticateServerless(
|
|
13052
|
+
config,
|
|
13053
|
+
state,
|
|
13054
|
+
{ ...renewal, reason: "session-expired" },
|
|
13055
|
+
onRefreshScheduled
|
|
13056
|
+
);
|
|
12636
13057
|
if (authed && sendToken) sendToken();
|
|
12637
13058
|
if (!authed && isPermanentAuthFailure(state.lastAuthError)) {
|
|
12638
13059
|
const permanentError = state.lastAuthError;
|
|
12639
13060
|
clearAuthenticationData(state);
|
|
12640
13061
|
state.lastAuthError = permanentError;
|
|
12641
|
-
clearStorage(config);
|
|
13062
|
+
clearStorage(config, state);
|
|
12642
13063
|
} else if (!authed) {
|
|
12643
13064
|
Object.assign(state, previousAuthentication);
|
|
12644
13065
|
}
|
|
12645
13066
|
return authed;
|
|
12646
13067
|
};
|
|
13068
|
+
const retainSessionAfterTransientFailure = async (failure) => {
|
|
13069
|
+
if (adoptNewerGeneration()) return true;
|
|
13070
|
+
if (canReauthenticateAfterTransientFailure(config)) {
|
|
13071
|
+
return reauthenticateAfterRefreshFailure();
|
|
13072
|
+
}
|
|
13073
|
+
Object.assign(state, previousAuthentication);
|
|
13074
|
+
state.lastAuthError = failure;
|
|
13075
|
+
return false;
|
|
13076
|
+
};
|
|
12647
13077
|
try {
|
|
12648
13078
|
if (!presentedRefreshToken) {
|
|
12649
13079
|
return reauthenticateAfterRefreshFailure();
|
|
12650
13080
|
}
|
|
12651
|
-
|
|
12652
|
-
|
|
12653
|
-
|
|
12654
|
-
|
|
12655
|
-
|
|
12656
|
-
|
|
12657
|
-
|
|
12658
|
-
|
|
12659
|
-
|
|
12660
|
-
|
|
12661
|
-
|
|
13081
|
+
let response;
|
|
13082
|
+
try {
|
|
13083
|
+
response = await fetch(`${config.apiUrl}/${config.widgetId}/auth/refresh`, {
|
|
13084
|
+
method: "POST",
|
|
13085
|
+
headers: {
|
|
13086
|
+
"Content-Type": "application/json",
|
|
13087
|
+
Authorization: `Bearer ${presentedRefreshToken}`
|
|
13088
|
+
},
|
|
13089
|
+
body: JSON.stringify({
|
|
13090
|
+
widgetType: config.widgetType,
|
|
13091
|
+
...buildIdentityProof(config)
|
|
13092
|
+
})
|
|
13093
|
+
});
|
|
13094
|
+
} catch (err) {
|
|
13095
|
+
return retainSessionAfterTransientFailure({
|
|
13096
|
+
status: 0,
|
|
13097
|
+
error: err instanceof Error ? err.message : "Token refresh failed"
|
|
13098
|
+
});
|
|
13099
|
+
}
|
|
12662
13100
|
if (!response.ok) {
|
|
12663
|
-
|
|
13101
|
+
const error = await response.json().catch(() => ({ error: "Token refresh failed" }));
|
|
13102
|
+
const failure = {
|
|
13103
|
+
status: response.status,
|
|
13104
|
+
error: (error == null ? void 0 : error.error) || `HTTP ${response.status}`
|
|
13105
|
+
};
|
|
13106
|
+
if (isPermanentAuthFailure(failure)) {
|
|
12664
13107
|
return reauthenticateAfterRefreshFailure();
|
|
12665
13108
|
}
|
|
12666
|
-
|
|
12667
|
-
throw new Error(error.error || `HTTP ${response.status}`);
|
|
13109
|
+
return retainSessionAfterTransientFailure(failure);
|
|
12668
13110
|
}
|
|
12669
13111
|
const data = await response.json();
|
|
12670
13112
|
if (!data.accessToken || !data.refreshToken) {
|
|
12671
13113
|
throw new Error("Invalid refresh response");
|
|
12672
13114
|
}
|
|
13115
|
+
state.lastAuthError = null;
|
|
12673
13116
|
setTokens(config, state, data, onRefreshScheduled);
|
|
12674
13117
|
state.isAuthenticated = true;
|
|
12675
13118
|
if (sendToken) sendToken();
|
|
@@ -12683,19 +13126,17 @@ async function refreshAccessToken(config, state, onRefreshScheduled, sendToken)
|
|
|
12683
13126
|
})();
|
|
12684
13127
|
return state.refreshPromise;
|
|
12685
13128
|
}
|
|
12686
|
-
async function getValidToken(config, state, onRefreshScheduled) {
|
|
13129
|
+
async function getValidToken(config, state, renewal, onRefreshScheduled) {
|
|
12687
13130
|
if (state.accessToken && !isTokenExpired(state.accessTokenExpiry)) {
|
|
12688
13131
|
return state.accessToken;
|
|
12689
13132
|
}
|
|
12690
13133
|
if (config.authUrl) {
|
|
12691
|
-
const
|
|
12692
|
-
if (
|
|
13134
|
+
const authed = await authenticateViaProxy(config, state, onRefreshScheduled);
|
|
13135
|
+
if (authed && state.accessToken) return state.accessToken;
|
|
12693
13136
|
throw new Error("Unable to obtain valid token");
|
|
12694
13137
|
}
|
|
12695
|
-
const refreshed = await refreshAccessToken(config, state, onRefreshScheduled);
|
|
13138
|
+
const refreshed = await refreshAccessToken(config, state, renewal, onRefreshScheduled);
|
|
12696
13139
|
if (refreshed && state.accessToken) return state.accessToken;
|
|
12697
|
-
const authed = await authenticateServerless(config, state, onRefreshScheduled);
|
|
12698
|
-
if (authed && state.accessToken) return state.accessToken;
|
|
12699
13140
|
throw new Error("Unable to obtain valid token");
|
|
12700
13141
|
}
|
|
12701
13142
|
async function logout(config, state) {
|
|
@@ -12713,7 +13154,7 @@ async function logout(config, state) {
|
|
|
12713
13154
|
}
|
|
12714
13155
|
}
|
|
12715
13156
|
clearState(state);
|
|
12716
|
-
clearStorage(config);
|
|
13157
|
+
clearStorage(config, state);
|
|
12717
13158
|
}
|
|
12718
13159
|
const inflightErrorSettings = /* @__PURE__ */ new Map();
|
|
12719
13160
|
function applyErrorSettingsToState(state, data) {
|
|
@@ -12882,7 +13323,7 @@ function applySnapshot(subscriber, snapshot, notify = true) {
|
|
|
12882
13323
|
var _a;
|
|
12883
13324
|
Object.assign(subscriber.state, snapshot);
|
|
12884
13325
|
if (snapshot.refreshToken) saveToStorage(subscriber.config, subscriber.state);
|
|
12885
|
-
else clearStorage(subscriber.config);
|
|
13326
|
+
else clearStorage(subscriber.config, subscriber.state);
|
|
12886
13327
|
if (!notify) return;
|
|
12887
13328
|
try {
|
|
12888
13329
|
(_a = subscriber.onSnapshot) == null ? void 0 : _a.call(subscriber);
|
|
@@ -12944,10 +13385,9 @@ function subscribeAuthSession(config, state, onSnapshot) {
|
|
|
12944
13385
|
return inFlight;
|
|
12945
13386
|
},
|
|
12946
13387
|
publish() {
|
|
12947
|
-
|
|
13388
|
+
publishSnapshot(session, state);
|
|
12948
13389
|
},
|
|
12949
13390
|
clear() {
|
|
12950
|
-
if (released) return;
|
|
12951
13391
|
state.accessToken = null;
|
|
12952
13392
|
state.refreshToken = null;
|
|
12953
13393
|
state.tokenFamily = null;
|
|
@@ -13365,283 +13805,89 @@ class WidgetCallbackRegistry {
|
|
|
13365
13805
|
return { ...this.registeredCallbacks };
|
|
13366
13806
|
}
|
|
13367
13807
|
}
|
|
13368
|
-
const loadedGoogleFontFamilies = /* @__PURE__ */ new Set();
|
|
13369
|
-
const LOCAL_OR_SYSTEM_FONT_FAMILIES = /* @__PURE__ */ new Set([
|
|
13370
|
-
"aeonik",
|
|
13371
|
-
"courier",
|
|
13372
|
-
"courier new",
|
|
13373
|
-
"monaco",
|
|
13374
|
-
"monospace",
|
|
13375
|
-
"sans-serif",
|
|
13376
|
-
"serif",
|
|
13377
|
-
"system-ui"
|
|
13378
|
-
]);
|
|
13379
|
-
const SERIF_FONT_FAMILIES = /* @__PURE__ */ new Set(["lora", "playfair display", "prata"]);
|
|
13380
|
-
const GOOGLE_FONT_VARIANTS = ":ital,wght@0,300;0,400;0,500;0,600;0,700;1,400;1,700";
|
|
13381
|
-
function normalizeFontFamily(family) {
|
|
13382
|
-
return family.trim() === "Noto" ? "Noto Sans" : family.trim();
|
|
13383
|
-
}
|
|
13384
|
-
function getFontStack(family) {
|
|
13385
|
-
const normalizedFamily = normalizeFontFamily(family);
|
|
13386
|
-
if (normalizedFamily.includes(",")) return normalizedFamily;
|
|
13387
|
-
const normalizedKey = normalizedFamily.toLowerCase();
|
|
13388
|
-
switch (normalizedKey) {
|
|
13389
|
-
case "monospace":
|
|
13390
|
-
return "monospace";
|
|
13391
|
-
case "courier":
|
|
13392
|
-
case "courier new":
|
|
13393
|
-
return '"Courier New", Courier, monospace';
|
|
13394
|
-
case "monaco":
|
|
13395
|
-
return "Monaco, Menlo, Consolas, monospace";
|
|
13396
|
-
case "system-ui":
|
|
13397
|
-
return "system-ui, -apple-system, sans-serif";
|
|
13398
|
-
case "sans-serif":
|
|
13399
|
-
case "serif":
|
|
13400
|
-
return normalizedKey;
|
|
13401
|
-
default:
|
|
13402
|
-
return `'${normalizedFamily.replace(/[\\']/g, "\\\\$&")}', ${SERIF_FONT_FAMILIES.has(normalizedKey) ? "Georgia, 'Times New Roman', serif" : "system-ui, -apple-system, sans-serif"}`;
|
|
13403
|
-
}
|
|
13404
|
-
}
|
|
13405
|
-
function ensureGoogleFontPreconnect() {
|
|
13406
|
-
if (!document.getElementById("rai-fonts-preconnect")) {
|
|
13407
|
-
const link = document.createElement("link");
|
|
13408
|
-
link.id = "rai-fonts-preconnect";
|
|
13409
|
-
link.rel = "preconnect";
|
|
13410
|
-
link.href = "https://fonts.googleapis.com";
|
|
13411
|
-
document.head.appendChild(link);
|
|
13412
|
-
}
|
|
13413
|
-
if (!document.getElementById("rai-fonts-static-preconnect")) {
|
|
13414
|
-
const link = document.createElement("link");
|
|
13415
|
-
link.id = "rai-fonts-static-preconnect";
|
|
13416
|
-
link.rel = "preconnect";
|
|
13417
|
-
link.href = "https://fonts.gstatic.com";
|
|
13418
|
-
link.crossOrigin = "anonymous";
|
|
13419
|
-
document.head.appendChild(link);
|
|
13420
|
-
}
|
|
13421
|
-
}
|
|
13422
|
-
function ensureGoogleFontLoaded(family) {
|
|
13423
|
-
const normalizedFamily = normalizeFontFamily(family);
|
|
13424
|
-
const fontKey = normalizedFamily.toLowerCase();
|
|
13425
|
-
if (!normalizedFamily || normalizedFamily.includes(",") || LOCAL_OR_SYSTEM_FONT_FAMILIES.has(fontKey)) {
|
|
13426
|
-
return;
|
|
13427
|
-
}
|
|
13428
|
-
if (loadedGoogleFontFamilies.has(fontKey)) return;
|
|
13429
|
-
ensureGoogleFontPreconnect();
|
|
13430
|
-
const linkId = `rai-font-${normalizedFamily.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`;
|
|
13431
|
-
const fontUrl = `https://fonts.googleapis.com/css2?family=${encodeURIComponent(
|
|
13432
|
-
normalizedFamily
|
|
13433
|
-
)}${GOOGLE_FONT_VARIANTS}&display=swap`;
|
|
13434
|
-
let link = document.getElementById(linkId);
|
|
13435
|
-
if (link && link.href !== fontUrl) {
|
|
13436
|
-
link.remove();
|
|
13437
|
-
link = null;
|
|
13438
|
-
}
|
|
13439
|
-
if (!link) {
|
|
13440
|
-
link = document.createElement("link");
|
|
13441
|
-
link.id = linkId;
|
|
13442
|
-
link.rel = "stylesheet";
|
|
13443
|
-
link.href = fontUrl;
|
|
13444
|
-
document.head.appendChild(link);
|
|
13445
|
-
}
|
|
13446
|
-
loadedGoogleFontFamilies.add(fontKey);
|
|
13447
|
-
link.onerror = () => {
|
|
13448
|
-
loadedGoogleFontFamilies.delete(fontKey);
|
|
13449
|
-
link == null ? void 0 : link.remove();
|
|
13450
|
-
};
|
|
13451
|
-
}
|
|
13452
|
-
const STORE_CALLBACK_FIELD_OPTIONS_SCOPE = "store.callback_field_options";
|
|
13453
|
-
const STORE_CALLBACK_FIELD_OPTIONS_CALLBACK_NAME = "callbackFieldOptions";
|
|
13454
|
-
const STORE_CALLBACK_FIELD_OPTIONS_TIMEOUT_MS = 15e3;
|
|
13455
|
-
const STORE_PURCHASE_SUCCESS_SCOPE = "store.purchase_success";
|
|
13456
|
-
const STORE_PURCHASE_SUCCESS_CALLBACK_NAME = "storePurchaseSuccess";
|
|
13457
|
-
const MILESTONE_CTA_CLICK_SCOPE = "milestone.cta_click";
|
|
13458
|
-
const MILESTONE_CTA_CLICK_CALLBACK_NAME = "milestoneCtaClick";
|
|
13459
|
-
const MILESTONE_CTA_CLICK_EVENT = "milestone_cta_clicked";
|
|
13460
|
-
function isRecord(value) {
|
|
13461
|
-
return typeof value === "object" && value !== null;
|
|
13462
|
-
}
|
|
13463
|
-
function isStringRecord(value) {
|
|
13464
|
-
return isRecord(value) && Object.values(value).every((item) => typeof item === "string");
|
|
13465
|
-
}
|
|
13466
|
-
function readEmbedTokenUserIdentifiers(embedToken) {
|
|
13467
|
-
if (!embedToken) return null;
|
|
13468
|
-
const encodedPayload = embedToken.split(".")[1];
|
|
13469
|
-
if (!encodedPayload) return null;
|
|
13470
|
-
try {
|
|
13471
|
-
const normalizedPayload = encodedPayload.replace(/-/g, "+").replace(/_/g, "/");
|
|
13472
|
-
const paddedPayload = normalizedPayload.padEnd(
|
|
13473
|
-
Math.ceil(normalizedPayload.length / 4) * 4,
|
|
13474
|
-
"="
|
|
13475
|
-
);
|
|
13476
|
-
const bytes = Uint8Array.from(atob(paddedPayload), (character) => character.charCodeAt(0));
|
|
13477
|
-
const claims = JSON.parse(new TextDecoder().decode(bytes));
|
|
13478
|
-
if (!isRecord(claims) || !isStringRecord(claims.userIdentifiers)) return null;
|
|
13479
|
-
return { ...claims.userIdentifiers };
|
|
13480
|
-
} catch {
|
|
13481
|
-
return null;
|
|
13482
|
-
}
|
|
13483
|
-
}
|
|
13484
|
-
function resolveHostUserIdentifiers(config) {
|
|
13485
|
-
return readEmbedTokenUserIdentifiers(config.embedToken) ?? { ...config.userIdentifiers };
|
|
13486
|
-
}
|
|
13487
|
-
function hasCallbackContract(payload, callbackName, scope) {
|
|
13488
|
-
return isRecord(payload) && payload.callbackName === callbackName && payload.scope === scope;
|
|
13489
|
-
}
|
|
13490
|
-
function isMilestoneCtaClickPayload(payload) {
|
|
13491
|
-
if (!hasCallbackContract(
|
|
13492
|
-
payload,
|
|
13493
|
-
MILESTONE_CTA_CLICK_CALLBACK_NAME,
|
|
13494
|
-
MILESTONE_CTA_CLICK_SCOPE
|
|
13495
|
-
)) return false;
|
|
13496
|
-
const context = payload.context;
|
|
13497
|
-
if (!isRecord(context)) return false;
|
|
13498
|
-
const community = context.community;
|
|
13499
|
-
const milestone = context.milestone;
|
|
13500
|
-
const stage = context.stage;
|
|
13501
|
-
const button = context.button;
|
|
13502
|
-
const user = context.user;
|
|
13503
|
-
return context.event === MILESTONE_CTA_CLICK_EVENT && isRecord(community) && typeof community.id === "string" && community.id.length > 0 && (community.name === void 0 || community.name === null || typeof community.name === "string") && isRecord(milestone) && typeof milestone.id === "string" && milestone.id.length > 0 && typeof milestone.name === "string" && milestone.name.length > 0 && isRecord(stage) && typeof stage.id === "string" && stage.id.length > 0 && typeof stage.name === "string" && stage.name.length > 0 && isRecord(button) && typeof button.name === "string" && button.name.length > 0 && isRecord(user) && isStringRecord(user.identifiers) && typeof context.clickedAt === "string" && context.clickedAt.length > 0 && !Number.isNaN(Date.parse(context.clickedAt));
|
|
13504
|
-
}
|
|
13505
|
-
function enrichHostCallbackPayload(payload, userIdentifiers) {
|
|
13506
|
-
if (!userIdentifiers || Object.keys(userIdentifiers).length === 0) return payload;
|
|
13507
|
-
if (!isRecord(payload)) return payload;
|
|
13508
|
-
const context = payload.context;
|
|
13509
|
-
if (!isRecord(context)) return payload;
|
|
13510
|
-
const user = context.user;
|
|
13511
|
-
if (!isRecord(user)) return payload;
|
|
13512
|
-
return {
|
|
13513
|
-
...payload,
|
|
13514
|
-
context: {
|
|
13515
|
-
...context,
|
|
13516
|
-
user: {
|
|
13517
|
-
...user,
|
|
13518
|
-
identifiers: { ...userIdentifiers }
|
|
13519
|
-
}
|
|
13520
|
-
}
|
|
13521
|
-
};
|
|
13522
|
-
}
|
|
13523
|
-
const HOST_CALLBACK_DEFINITIONS = {
|
|
13524
|
-
[STORE_CALLBACK_FIELD_OPTIONS_CALLBACK_NAME]: {
|
|
13525
|
-
callbackName: STORE_CALLBACK_FIELD_OPTIONS_CALLBACK_NAME,
|
|
13526
|
-
scope: STORE_CALLBACK_FIELD_OPTIONS_SCOPE,
|
|
13527
|
-
sourceWidgetType: "store",
|
|
13528
|
-
allowedHostWidgetTypes: ["store", "custom"],
|
|
13529
|
-
completionMode: "result",
|
|
13530
|
-
missingHandler: "reject",
|
|
13531
|
-
legacyActions: ["store:host-callback"],
|
|
13532
|
-
validatePayload: (payload) => hasCallbackContract(
|
|
13533
|
-
payload,
|
|
13534
|
-
STORE_CALLBACK_FIELD_OPTIONS_CALLBACK_NAME,
|
|
13535
|
-
STORE_CALLBACK_FIELD_OPTIONS_SCOPE
|
|
13536
|
-
)
|
|
13537
|
-
},
|
|
13538
|
-
[STORE_PURCHASE_SUCCESS_CALLBACK_NAME]: {
|
|
13539
|
-
callbackName: STORE_PURCHASE_SUCCESS_CALLBACK_NAME,
|
|
13540
|
-
scope: STORE_PURCHASE_SUCCESS_SCOPE,
|
|
13541
|
-
sourceWidgetType: "store",
|
|
13542
|
-
allowedHostWidgetTypes: ["store", "custom"],
|
|
13543
|
-
completionMode: "acknowledged",
|
|
13544
|
-
missingHandler: "reject",
|
|
13545
|
-
legacyActions: ["store:host-callback"],
|
|
13546
|
-
validatePayload: (payload) => hasCallbackContract(
|
|
13547
|
-
payload,
|
|
13548
|
-
STORE_PURCHASE_SUCCESS_CALLBACK_NAME,
|
|
13549
|
-
STORE_PURCHASE_SUCCESS_SCOPE
|
|
13550
|
-
)
|
|
13551
|
-
},
|
|
13552
|
-
[MILESTONE_CTA_CLICK_CALLBACK_NAME]: {
|
|
13553
|
-
callbackName: MILESTONE_CTA_CLICK_CALLBACK_NAME,
|
|
13554
|
-
scope: MILESTONE_CTA_CLICK_SCOPE,
|
|
13555
|
-
sourceWidgetType: "milestone",
|
|
13556
|
-
allowedHostWidgetTypes: ["milestone", "custom"],
|
|
13557
|
-
completionMode: "detached",
|
|
13558
|
-
missingHandler: "ignore",
|
|
13559
|
-
legacyActions: [],
|
|
13560
|
-
validatePayload: isMilestoneCtaClickPayload
|
|
13561
|
-
}
|
|
13562
|
-
};
|
|
13563
|
-
function createInvocationId() {
|
|
13564
|
-
return `host_callback_${Date.now()}_${Math.random().toString(36).slice(2)}`;
|
|
13565
|
-
}
|
|
13566
|
-
function observe(observer, event) {
|
|
13567
|
-
if (!observer) return;
|
|
13568
|
-
try {
|
|
13569
|
-
observer(event);
|
|
13570
|
-
} catch {
|
|
13571
|
-
}
|
|
13572
|
-
}
|
|
13573
|
-
function getHostCallbackDefinition(callbackName, payload) {
|
|
13574
|
-
const definition = HOST_CALLBACK_DEFINITIONS[callbackName];
|
|
13575
|
-
return (definition == null ? void 0 : definition.validatePayload(payload)) ? definition : void 0;
|
|
13576
|
-
}
|
|
13577
|
-
function isHostCallbackMessageSupported(definition, action, sourceWidgetType, hostWidgetType) {
|
|
13578
|
-
const actionSupported = action === "widget:host-callback" || definition.legacyActions.includes(action);
|
|
13579
|
-
return actionSupported && sourceWidgetType === definition.sourceWidgetType && definition.allowedHostWidgetTypes.includes(hostWidgetType);
|
|
13808
|
+
const loadedGoogleFontFamilies = /* @__PURE__ */ new Set();
|
|
13809
|
+
const LOCAL_OR_SYSTEM_FONT_FAMILIES = /* @__PURE__ */ new Set([
|
|
13810
|
+
"aeonik",
|
|
13811
|
+
"courier",
|
|
13812
|
+
"courier new",
|
|
13813
|
+
"monaco",
|
|
13814
|
+
"monospace",
|
|
13815
|
+
"sans-serif",
|
|
13816
|
+
"serif",
|
|
13817
|
+
"system-ui"
|
|
13818
|
+
]);
|
|
13819
|
+
const SERIF_FONT_FAMILIES = /* @__PURE__ */ new Set(["lora", "playfair display", "prata"]);
|
|
13820
|
+
const GOOGLE_FONT_VARIANTS = ":ital,wght@0,300;0,400;0,500;0,600;0,700;1,400;1,700";
|
|
13821
|
+
function normalizeFontFamily(family) {
|
|
13822
|
+
return family.trim() === "Noto" ? "Noto Sans" : family.trim();
|
|
13580
13823
|
}
|
|
13581
|
-
function
|
|
13582
|
-
const
|
|
13583
|
-
if (
|
|
13584
|
-
|
|
13824
|
+
function getFontStack(family) {
|
|
13825
|
+
const normalizedFamily = normalizeFontFamily(family);
|
|
13826
|
+
if (normalizedFamily.includes(",")) return normalizedFamily;
|
|
13827
|
+
const normalizedKey = normalizedFamily.toLowerCase();
|
|
13828
|
+
switch (normalizedKey) {
|
|
13829
|
+
case "monospace":
|
|
13830
|
+
return "monospace";
|
|
13831
|
+
case "courier":
|
|
13832
|
+
case "courier new":
|
|
13833
|
+
return '"Courier New", Courier, monospace';
|
|
13834
|
+
case "monaco":
|
|
13835
|
+
return "Monaco, Menlo, Consolas, monospace";
|
|
13836
|
+
case "system-ui":
|
|
13837
|
+
return "system-ui, -apple-system, sans-serif";
|
|
13838
|
+
case "sans-serif":
|
|
13839
|
+
case "serif":
|
|
13840
|
+
return normalizedKey;
|
|
13841
|
+
default:
|
|
13842
|
+
return `'${normalizedFamily.replace(/[\\']/g, "\\\\$&")}', ${SERIF_FONT_FAMILIES.has(normalizedKey) ? "Georgia, 'Times New Roman', serif" : "system-ui, -apple-system, sans-serif"}`;
|
|
13585
13843
|
}
|
|
13586
|
-
|
|
13587
|
-
|
|
13588
|
-
|
|
13589
|
-
|
|
13590
|
-
|
|
13591
|
-
|
|
13592
|
-
|
|
13593
|
-
|
|
13594
|
-
transport: input.transport
|
|
13595
|
-
};
|
|
13596
|
-
observe(input.observer, { type: "callback.received", ...eventBase });
|
|
13597
|
-
const callback = input.callbacks[definition.callbackName];
|
|
13598
|
-
if (!callback) {
|
|
13599
|
-
observe(input.observer, { type: "callback.handler_missing", ...eventBase });
|
|
13600
|
-
if (definition.missingHandler === "ignore") return;
|
|
13601
|
-
return Promise.reject(new Error("Host callback is not registered"));
|
|
13844
|
+
}
|
|
13845
|
+
function ensureGoogleFontPreconnect() {
|
|
13846
|
+
if (!document.getElementById("rai-fonts-preconnect")) {
|
|
13847
|
+
const link = document.createElement("link");
|
|
13848
|
+
link.id = "rai-fonts-preconnect";
|
|
13849
|
+
link.rel = "preconnect";
|
|
13850
|
+
link.href = "https://fonts.googleapis.com";
|
|
13851
|
+
document.head.appendChild(link);
|
|
13602
13852
|
}
|
|
13603
|
-
|
|
13604
|
-
|
|
13605
|
-
|
|
13606
|
-
|
|
13607
|
-
|
|
13608
|
-
|
|
13609
|
-
|
|
13610
|
-
...eventBase,
|
|
13611
|
-
error
|
|
13612
|
-
});
|
|
13613
|
-
if (definition.completionMode === "detached") return;
|
|
13614
|
-
return Promise.reject(new Error("Host callback failed"));
|
|
13853
|
+
if (!document.getElementById("rai-fonts-static-preconnect")) {
|
|
13854
|
+
const link = document.createElement("link");
|
|
13855
|
+
link.id = "rai-fonts-static-preconnect";
|
|
13856
|
+
link.rel = "preconnect";
|
|
13857
|
+
link.href = "https://fonts.gstatic.com";
|
|
13858
|
+
link.crossOrigin = "anonymous";
|
|
13859
|
+
document.head.appendChild(link);
|
|
13615
13860
|
}
|
|
13616
|
-
|
|
13617
|
-
|
|
13618
|
-
|
|
13619
|
-
|
|
13620
|
-
|
|
13621
|
-
type: "callback.handler_rejected",
|
|
13622
|
-
...eventBase,
|
|
13623
|
-
error
|
|
13624
|
-
})
|
|
13625
|
-
);
|
|
13626
|
-
} else {
|
|
13627
|
-
observe(input.observer, { type: "callback.handler_resolved", ...eventBase });
|
|
13628
|
-
}
|
|
13861
|
+
}
|
|
13862
|
+
function ensureGoogleFontLoaded(family) {
|
|
13863
|
+
const normalizedFamily = normalizeFontFamily(family);
|
|
13864
|
+
const fontKey = normalizedFamily.toLowerCase();
|
|
13865
|
+
if (!normalizedFamily || normalizedFamily.includes(",") || LOCAL_OR_SYSTEM_FONT_FAMILIES.has(fontKey)) {
|
|
13629
13866
|
return;
|
|
13630
13867
|
}
|
|
13631
|
-
|
|
13632
|
-
|
|
13633
|
-
|
|
13634
|
-
|
|
13635
|
-
|
|
13636
|
-
|
|
13637
|
-
|
|
13638
|
-
|
|
13639
|
-
|
|
13640
|
-
|
|
13641
|
-
|
|
13642
|
-
|
|
13643
|
-
|
|
13644
|
-
|
|
13868
|
+
if (loadedGoogleFontFamilies.has(fontKey)) return;
|
|
13869
|
+
ensureGoogleFontPreconnect();
|
|
13870
|
+
const linkId = `rai-font-${normalizedFamily.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`;
|
|
13871
|
+
const fontUrl = `https://fonts.googleapis.com/css2?family=${encodeURIComponent(
|
|
13872
|
+
normalizedFamily
|
|
13873
|
+
)}${GOOGLE_FONT_VARIANTS}&display=swap`;
|
|
13874
|
+
let link = document.getElementById(linkId);
|
|
13875
|
+
if (link && link.href !== fontUrl) {
|
|
13876
|
+
link.remove();
|
|
13877
|
+
link = null;
|
|
13878
|
+
}
|
|
13879
|
+
if (!link) {
|
|
13880
|
+
link = document.createElement("link");
|
|
13881
|
+
link.id = linkId;
|
|
13882
|
+
link.rel = "stylesheet";
|
|
13883
|
+
link.href = fontUrl;
|
|
13884
|
+
document.head.appendChild(link);
|
|
13885
|
+
}
|
|
13886
|
+
loadedGoogleFontFamilies.add(fontKey);
|
|
13887
|
+
link.onerror = () => {
|
|
13888
|
+
loadedGoogleFontFamilies.delete(fontKey);
|
|
13889
|
+
link == null ? void 0 : link.remove();
|
|
13890
|
+
};
|
|
13645
13891
|
}
|
|
13646
13892
|
const SUPPORTED_WIDGET_LANGUAGES = [
|
|
13647
13893
|
"en",
|
|
@@ -13779,15 +14025,36 @@ function setupMessageListener(config, state, _shadow, iframe, onRefreshScheduled
|
|
|
13779
14025
|
emit == null ? void 0 : emit("rai-height-change", { height: h });
|
|
13780
14026
|
}, config.heightDebounce ?? 100);
|
|
13781
14027
|
const handler = async (event) => {
|
|
13782
|
-
var _a;
|
|
14028
|
+
var _a, _b;
|
|
13783
14029
|
if (event.origin !== config.widgetDomain) return;
|
|
13784
14030
|
if (!event.data || typeof event.data.type !== "string") return;
|
|
13785
14031
|
const { type, containerId, widgetId, payload } = event.data;
|
|
13786
14032
|
switch (type) {
|
|
14033
|
+
case "RETURNINGAI_WIDGET_REQUEST_CALLBACK_CAPABILITIES": {
|
|
14034
|
+
if (event.source !== iframe.contentWindow) break;
|
|
14035
|
+
if (widgetId !== void 0 && widgetId !== config.widgetId) break;
|
|
14036
|
+
if (containerId !== void 0 && containerId !== config.container) break;
|
|
14037
|
+
const requestId = event.data.requestId;
|
|
14038
|
+
if (typeof requestId !== "string" || !requestId || requestId.length > 256) break;
|
|
14039
|
+
(_a = iframe.contentWindow) == null ? void 0 : _a.postMessage({
|
|
14040
|
+
type: "RETURNINGAI_WIDGET_CALLBACK_CAPABILITIES",
|
|
14041
|
+
requestId,
|
|
14042
|
+
supportedCallbacks: getSupportedHostCallbacks((getCallbacks == null ? void 0 : getCallbacks()) ?? {}, config.widgetType)
|
|
14043
|
+
}, config.widgetDomain);
|
|
14044
|
+
break;
|
|
14045
|
+
}
|
|
13787
14046
|
case "RETURNINGAI_WIDGET_REQUEST_TOKEN": {
|
|
13788
14047
|
try {
|
|
13789
|
-
const token = await getValidToken(
|
|
13790
|
-
|
|
14048
|
+
const token = await getValidToken(
|
|
14049
|
+
config,
|
|
14050
|
+
state,
|
|
14051
|
+
{
|
|
14052
|
+
getEmbedTokenProvider: () => readEmbedTokenProvider(getCallbacks == null ? void 0 : getCallbacks()),
|
|
14053
|
+
isCurrent: () => iframe.isConnected
|
|
14054
|
+
},
|
|
14055
|
+
onRefreshScheduled
|
|
14056
|
+
);
|
|
14057
|
+
(_b = iframe.contentWindow) == null ? void 0 : _b.postMessage(
|
|
13791
14058
|
{
|
|
13792
14059
|
type: "RETURNINGAI_WIDGET_TOKEN",
|
|
13793
14060
|
value: {
|
|
@@ -14238,13 +14505,6 @@ function readConfig(el2, existingId) {
|
|
|
14238
14505
|
firstPaintFont: get("font") || void 0
|
|
14239
14506
|
};
|
|
14240
14507
|
}
|
|
14241
|
-
function identitySignatureForConfig(config) {
|
|
14242
|
-
const identifiers = Object.keys(config.userIdentifiers || {}).sort().map((key) => [key, config.userIdentifiers[key]]);
|
|
14243
|
-
return JSON.stringify({
|
|
14244
|
-
embedToken: config.embedToken || "",
|
|
14245
|
-
userIdentifiers: identifiers
|
|
14246
|
-
});
|
|
14247
|
-
}
|
|
14248
14508
|
function createInitialState() {
|
|
14249
14509
|
return {
|
|
14250
14510
|
accessToken: null,
|
|
@@ -14268,6 +14528,17 @@ function createInitialState() {
|
|
|
14268
14528
|
widgetData: null
|
|
14269
14529
|
};
|
|
14270
14530
|
}
|
|
14531
|
+
function forkWidgetState(previous) {
|
|
14532
|
+
return {
|
|
14533
|
+
...createInitialState(),
|
|
14534
|
+
errorSettings: previous.errorSettings ?? null,
|
|
14535
|
+
loadingAnimation: previous.loadingAnimation ?? null,
|
|
14536
|
+
loadingSettings: previous.loadingSettings ?? null,
|
|
14537
|
+
themePalette: previous.themePalette ?? null,
|
|
14538
|
+
font: previous.font ?? null,
|
|
14539
|
+
defaultColorSchema: previous.defaultColorSchema ?? null
|
|
14540
|
+
};
|
|
14541
|
+
}
|
|
14271
14542
|
class BaseWidget extends HTMLElement {
|
|
14272
14543
|
constructor() {
|
|
14273
14544
|
super();
|
|
@@ -14285,6 +14556,14 @@ class BaseWidget extends HTMLElement {
|
|
|
14285
14556
|
__publicField(this, "themeObserver");
|
|
14286
14557
|
__publicField(this, "identityAttributeObserver");
|
|
14287
14558
|
__publicField(this, "identitySignature", "");
|
|
14559
|
+
/** The `embed-token` attribute as last read; `config.embedToken` may hold a renewed pass instead. */
|
|
14560
|
+
__publicField(this, "lastEmbedTokenAttribute");
|
|
14561
|
+
/** The init generation whose widget launched; part of the silent-swap health check. */
|
|
14562
|
+
__publicField(this, "launchedInitId", 0);
|
|
14563
|
+
/** Set when the expired-pass error was shown with no `embedTokenRequest` registered. */
|
|
14564
|
+
__publicField(this, "lateEmbedTokenRegistrationReload", false);
|
|
14565
|
+
/** An error screen is showing for the current init (any cause); clears on the next launch. */
|
|
14566
|
+
__publicField(this, "errorScreenShown", false);
|
|
14288
14567
|
__publicField(this, "hasAttemptedInit", false);
|
|
14289
14568
|
__publicField(this, "initGeneration", 0);
|
|
14290
14569
|
__publicField(this, "lottieInstances", []);
|
|
@@ -14304,6 +14583,8 @@ class BaseWidget extends HTMLElement {
|
|
|
14304
14583
|
return [
|
|
14305
14584
|
"embed-token",
|
|
14306
14585
|
"data-embed-token",
|
|
14586
|
+
"theme",
|
|
14587
|
+
"data-theme",
|
|
14307
14588
|
"language",
|
|
14308
14589
|
"data-language",
|
|
14309
14590
|
"locale",
|
|
@@ -14312,6 +14593,10 @@ class BaseWidget extends HTMLElement {
|
|
|
14312
14593
|
}
|
|
14313
14594
|
registerCallback(callbackName, callback) {
|
|
14314
14595
|
this.callbackRegistry.registerCallback(callbackName, callback);
|
|
14596
|
+
if (callbackName === "embedTokenRequest" && this.lateEmbedTokenRegistrationReload && !this.callbackRegistry.isLocked && this.readEmbedTokenProvider() && isEmbedTokenRejected(this.state.lastAuthError) && this.isConnected) {
|
|
14597
|
+
this.lateEmbedTokenRegistrationReload = false;
|
|
14598
|
+
void this.reload();
|
|
14599
|
+
}
|
|
14315
14600
|
}
|
|
14316
14601
|
lockCallbacks() {
|
|
14317
14602
|
this.callbackRegistry.lock();
|
|
@@ -14319,6 +14604,7 @@ class BaseWidget extends HTMLElement {
|
|
|
14319
14604
|
connectedCallback() {
|
|
14320
14605
|
this.config = readConfig(this, void 0);
|
|
14321
14606
|
this.identitySignature = identitySignatureForConfig(this.config);
|
|
14607
|
+
this.lastEmbedTokenAttribute = this.config.embedToken;
|
|
14322
14608
|
this.setupIdentityAttributeObserver();
|
|
14323
14609
|
ensureWidgetPreconnects(
|
|
14324
14610
|
resolveWidgetPreconnectOrigins(this.config, document.baseURI)
|
|
@@ -14326,16 +14612,8 @@ class BaseWidget extends HTMLElement {
|
|
|
14326
14612
|
const style = document.createElement("style");
|
|
14327
14613
|
style.textContent = widgetCSS;
|
|
14328
14614
|
this.shadow.appendChild(style);
|
|
14329
|
-
const theme = this.config.theme;
|
|
14330
|
-
const accentColor = theme === "dark" ? "#ffffff" : "#000000";
|
|
14331
|
-
const text4Color = theme === "dark" ? "#9ca3af" : "#6b7280";
|
|
14332
|
-
const bgColor = theme === "dark" ? "#1a1a1a" : "#ffffff";
|
|
14333
14615
|
this.style.width = this.config.width;
|
|
14334
14616
|
this.style.height = this.config.height;
|
|
14335
|
-
this.style.setProperty("--rai-accent", accentColor);
|
|
14336
|
-
this.style.setProperty("--rai-text4", text4Color);
|
|
14337
|
-
this.style.setProperty("--rai-loader-bg", bgColor);
|
|
14338
|
-
this.style.setProperty("--rai-error-bg", bgColor);
|
|
14339
14617
|
this.applyFirstPaintColors();
|
|
14340
14618
|
this.renderShell();
|
|
14341
14619
|
if (this.hasAttribute("eager")) {
|
|
@@ -14378,6 +14656,8 @@ class BaseWidget extends HTMLElement {
|
|
|
14378
14656
|
void this.reload();
|
|
14379
14657
|
} else {
|
|
14380
14658
|
this.config = readConfig(this, this.config.communityId);
|
|
14659
|
+
this.applyFirstPaintColors();
|
|
14660
|
+
this.renderLoaderAnimation();
|
|
14381
14661
|
}
|
|
14382
14662
|
}
|
|
14383
14663
|
}
|
|
@@ -14398,7 +14678,22 @@ class BaseWidget extends HTMLElement {
|
|
|
14398
14678
|
if (!this.isConnected || !this.config) return;
|
|
14399
14679
|
const nextConfig = readConfig(this, this.config.communityId);
|
|
14400
14680
|
const nextIdentitySignature = identitySignatureForConfig(nextConfig);
|
|
14401
|
-
|
|
14681
|
+
const tokenChanged = nextConfig.embedToken !== this.lastEmbedTokenAttribute;
|
|
14682
|
+
const sameSignature = nextIdentitySignature === this.identitySignature;
|
|
14683
|
+
const decision = decideEmbedTokenChange({
|
|
14684
|
+
tokenChanged,
|
|
14685
|
+
sameSignature,
|
|
14686
|
+
hasAttemptedInit: this.hasAttemptedInit,
|
|
14687
|
+
healthy: this.isHealthyForEmbedTokenSwap(),
|
|
14688
|
+
hasProvider: !!this.readEmbedTokenProvider()
|
|
14689
|
+
});
|
|
14690
|
+
this.lastEmbedTokenAttribute = nextConfig.embedToken;
|
|
14691
|
+
if (decision === "swap") {
|
|
14692
|
+
this.config.embedToken = nextConfig.embedToken;
|
|
14693
|
+
return;
|
|
14694
|
+
}
|
|
14695
|
+
if (decision === "update" && sameSignature) {
|
|
14696
|
+
if (!tokenChanged) nextConfig.embedToken = this.config.embedToken;
|
|
14402
14697
|
this.config = nextConfig;
|
|
14403
14698
|
return;
|
|
14404
14699
|
}
|
|
@@ -14407,10 +14702,28 @@ class BaseWidget extends HTMLElement {
|
|
|
14407
14702
|
this.identitySignature = nextIdentitySignature;
|
|
14408
14703
|
clearStorage(previousConfig);
|
|
14409
14704
|
clearStorage(this.config);
|
|
14410
|
-
if (
|
|
14705
|
+
if (decision === "reload") {
|
|
14411
14706
|
void this.reload();
|
|
14412
14707
|
}
|
|
14413
14708
|
}
|
|
14709
|
+
readEmbedTokenProvider() {
|
|
14710
|
+
return readEmbedTokenProvider(this.callbackRegistry.read());
|
|
14711
|
+
}
|
|
14712
|
+
/**
|
|
14713
|
+
* Renewal options for auth calls started by init `initId`; the provider is
|
|
14714
|
+
* read at call time. A disconnect or a newer init stops the retry. Writes
|
|
14715
|
+
* from this call land only in the state object init `initId` owns.
|
|
14716
|
+
*/
|
|
14717
|
+
embedTokenRenewal(initId) {
|
|
14718
|
+
return {
|
|
14719
|
+
getEmbedTokenProvider: () => this.readEmbedTokenProvider(),
|
|
14720
|
+
isCurrent: () => this.isCurrentInit(initId)
|
|
14721
|
+
};
|
|
14722
|
+
}
|
|
14723
|
+
/** Authenticated, no error state or error screen, and launched for the current init. */
|
|
14724
|
+
isHealthyForEmbedTokenSwap() {
|
|
14725
|
+
return this.state.isAuthenticated && !this.state.lastAuthError && !this.errorScreenShown && this.launchedInitId !== 0 && this.launchedInitId === this.initGeneration;
|
|
14726
|
+
}
|
|
14414
14727
|
// ── DOM event helper (#1) ─────────────────────────────────────────────
|
|
14415
14728
|
emit(type, detail) {
|
|
14416
14729
|
this.dispatchEvent(
|
|
@@ -14453,6 +14766,17 @@ class BaseWidget extends HTMLElement {
|
|
|
14453
14766
|
}
|
|
14454
14767
|
}
|
|
14455
14768
|
const theme = this.config.theme === "dark" ? "dark" : "light";
|
|
14769
|
+
this.style.setProperty(
|
|
14770
|
+
"--rai-accent",
|
|
14771
|
+
theme === "dark" ? "#ffffff" : "#000000"
|
|
14772
|
+
);
|
|
14773
|
+
this.style.setProperty(
|
|
14774
|
+
"--rai-text4",
|
|
14775
|
+
theme === "dark" ? "#9ca3af" : "#6b7280"
|
|
14776
|
+
);
|
|
14777
|
+
const bgColor = theme === "dark" ? "#1a1a1a" : "#ffffff";
|
|
14778
|
+
this.style.setProperty("--rai-loader-bg", bgColor);
|
|
14779
|
+
this.style.setProperty("--rai-error-bg", bgColor);
|
|
14456
14780
|
const cachedPalette = (_a = cached == null ? void 0 : cached.themePalette) == null ? void 0 : _a[theme];
|
|
14457
14781
|
if (cachedPalette) this.applyPalette(cachedPalette);
|
|
14458
14782
|
const cachedFont = typeof (cached == null ? void 0 : cached.font) === "string" ? cached.font : void 0;
|
|
@@ -14536,19 +14860,7 @@ class BaseWidget extends HTMLElement {
|
|
|
14536
14860
|
}
|
|
14537
14861
|
}
|
|
14538
14862
|
renderShell() {
|
|
14539
|
-
this.
|
|
14540
|
-
this.loaderEl.className = "rai-loader";
|
|
14541
|
-
if (this.config.widgetType === "custom" && !loadErrorSettingsFromStorage(this.config)) {
|
|
14542
|
-
this.loaderEl.classList.add("rai-loader-pending-settings");
|
|
14543
|
-
}
|
|
14544
|
-
const textEl = document.createElement("h1");
|
|
14545
|
-
textEl.className = "rai-loader-text";
|
|
14546
|
-
textEl.textContent = this.config.loadingText;
|
|
14547
|
-
this.loaderEl.appendChild(textEl);
|
|
14548
|
-
this.shadow.appendChild(this.loaderEl);
|
|
14549
|
-
this.freezeIframeLoaderHeight();
|
|
14550
|
-
this.applyLoadingSettings();
|
|
14551
|
-
this.fetchAndRenderLoader();
|
|
14863
|
+
this.showLoader();
|
|
14552
14864
|
this.errorEl = document.createElement("div");
|
|
14553
14865
|
this.errorEl.className = "rai-error";
|
|
14554
14866
|
this.msgEl = document.createElement("span");
|
|
@@ -14563,6 +14875,26 @@ class BaseWidget extends HTMLElement {
|
|
|
14563
14875
|
this.errorEl.appendChild(btn);
|
|
14564
14876
|
this.shadow.appendChild(this.errorEl);
|
|
14565
14877
|
}
|
|
14878
|
+
showLoader() {
|
|
14879
|
+
var _a;
|
|
14880
|
+
this.clearLottieInstances();
|
|
14881
|
+
this.shadow.querySelectorAll(".rai-loader").forEach((el2) => el2.remove());
|
|
14882
|
+
(_a = this.errorEl) == null ? void 0 : _a.classList.remove("visible");
|
|
14883
|
+
this.shadow.querySelectorAll(".rai-custom-error").forEach((el2) => el2.remove());
|
|
14884
|
+
this.loaderEl = document.createElement("div");
|
|
14885
|
+
this.loaderEl.className = "rai-loader";
|
|
14886
|
+
if (this.config.widgetType === "custom" && !loadErrorSettingsFromStorage(this.config)) {
|
|
14887
|
+
this.loaderEl.classList.add("rai-loader-pending-settings");
|
|
14888
|
+
}
|
|
14889
|
+
const textEl = document.createElement("h1");
|
|
14890
|
+
textEl.className = "rai-loader-text";
|
|
14891
|
+
textEl.textContent = this.config.loadingText;
|
|
14892
|
+
this.loaderEl.appendChild(textEl);
|
|
14893
|
+
this.shadow.appendChild(this.loaderEl);
|
|
14894
|
+
this.freezeIframeLoaderHeight();
|
|
14895
|
+
this.applyLoadingSettings();
|
|
14896
|
+
void this.fetchAndRenderLoader();
|
|
14897
|
+
}
|
|
14566
14898
|
/**
|
|
14567
14899
|
* Loads the community loading animation + theme palette from cache or API
|
|
14568
14900
|
* and renders the configured animation above the loading text.
|
|
@@ -14573,6 +14905,7 @@ class BaseWidget extends HTMLElement {
|
|
|
14573
14905
|
*/
|
|
14574
14906
|
async fetchAndRenderLoader() {
|
|
14575
14907
|
var _a;
|
|
14908
|
+
const loaderEl = this.loaderEl;
|
|
14576
14909
|
const cached = loadErrorSettingsFromStorage(this.config);
|
|
14577
14910
|
if (cached) {
|
|
14578
14911
|
applyErrorSettingsToState(this.state, cached);
|
|
@@ -14580,12 +14913,16 @@ class BaseWidget extends HTMLElement {
|
|
|
14580
14913
|
this.renderLoaderAnimation();
|
|
14581
14914
|
return;
|
|
14582
14915
|
}
|
|
14916
|
+
const target = this.state;
|
|
14583
14917
|
try {
|
|
14584
|
-
await fetchErrorSettings(this.config,
|
|
14918
|
+
await fetchErrorSettings(this.config, target);
|
|
14585
14919
|
} catch {
|
|
14586
14920
|
}
|
|
14587
|
-
|
|
14588
|
-
|
|
14921
|
+
if (target !== this.state) {
|
|
14922
|
+
const fetched = loadErrorSettingsFromStorage(this.config);
|
|
14923
|
+
if (fetched) applyErrorSettingsToState(this.state, fetched);
|
|
14924
|
+
}
|
|
14925
|
+
if (!loaderEl || loaderEl !== this.loaderEl || !this.isConnected) return;
|
|
14589
14926
|
if (!this.config.themeExplicit && (this.state.defaultColorSchema === "light" || this.state.defaultColorSchema === "dark") && this.state.defaultColorSchema !== this.config.theme) {
|
|
14590
14927
|
this.config.theme = this.state.defaultColorSchema;
|
|
14591
14928
|
}
|
|
@@ -14690,7 +15027,7 @@ class BaseWidget extends HTMLElement {
|
|
|
14690
15027
|
setTimeout(() => {
|
|
14691
15028
|
loader.remove();
|
|
14692
15029
|
lottieInstances.forEach((instance) => instance.destroy());
|
|
14693
|
-
this.restoreLoaderHeight();
|
|
15030
|
+
if (!this.loaderEl) this.restoreLoaderHeight();
|
|
14694
15031
|
}, 300);
|
|
14695
15032
|
this.loaderEl = null;
|
|
14696
15033
|
}
|
|
@@ -14793,6 +15130,8 @@ class BaseWidget extends HTMLElement {
|
|
|
14793
15130
|
}
|
|
14794
15131
|
showError(failureKind = "authentication") {
|
|
14795
15132
|
this.hideLoader();
|
|
15133
|
+
this.errorScreenShown = true;
|
|
15134
|
+
this.lateEmbedTokenRegistrationReload = failureKind === "authentication" && isEmbedTokenRejected(this.state.lastAuthError) && !this.readEmbedTokenProvider();
|
|
14796
15135
|
const settings = this.state.errorSettings;
|
|
14797
15136
|
const presentation = selectWidgetErrorPresentation({
|
|
14798
15137
|
failureKind,
|
|
@@ -14963,29 +15302,61 @@ class BaseWidget extends HTMLElement {
|
|
|
14963
15302
|
}
|
|
14964
15303
|
}
|
|
14965
15304
|
// ── Initialization ─────────────────────────────────────────────────────
|
|
15305
|
+
/**
|
|
15306
|
+
* Starts a new init: it owns a fresh state object and its own auth-session
|
|
15307
|
+
* subscription. The previous init's in-flight work keeps the retired state,
|
|
15308
|
+
* so it can finish but never writes this init's state or storage. It still
|
|
15309
|
+
* publishes to the session it started on; after a same-member reload that is
|
|
15310
|
+
* the same shared session this init joined, which is intended (siblings and
|
|
15311
|
+
* this init get the result).
|
|
15312
|
+
*/
|
|
15313
|
+
beginInit() {
|
|
15314
|
+
const initId = ++this.initGeneration;
|
|
15315
|
+
const retired = this.state;
|
|
15316
|
+
if (retired.refreshTimer) clearTimeout(retired.refreshTimer);
|
|
15317
|
+
if (retired.syncTimer) clearInterval(retired.syncTimer);
|
|
15318
|
+
retired.refreshTimer = null;
|
|
15319
|
+
retired.syncTimer = null;
|
|
15320
|
+
retireWidgetState(retired);
|
|
15321
|
+
const state = forkWidgetState(retired);
|
|
15322
|
+
this.state = state;
|
|
15323
|
+
const previousSession = this.authSession;
|
|
15324
|
+
this.authSession = void 0;
|
|
15325
|
+
if (this.config.communityId && !this.config.authUrl) {
|
|
15326
|
+
let subscribing = true;
|
|
15327
|
+
this.authSession = subscribeAuthSession(this.config, state, () => {
|
|
15328
|
+
if (this.state !== state) return;
|
|
15329
|
+
if (state.isAuthenticated && !state.lastAuthError) {
|
|
15330
|
+
this.authRenewalRecovery.succeeded();
|
|
15331
|
+
}
|
|
15332
|
+
if (this.config.autoRefresh && !state.lastAuthError) {
|
|
15333
|
+
if (!subscribing) {
|
|
15334
|
+
this.scheduleRefresh();
|
|
15335
|
+
} else if (state.accessTokenExpiry && calculateRefreshDelay(state.accessTokenExpiry) > 0) {
|
|
15336
|
+
this.scheduleRefresh();
|
|
15337
|
+
}
|
|
15338
|
+
}
|
|
15339
|
+
if (state.iframe) {
|
|
15340
|
+
sendTokenToWidget(this.config, state, state.iframe);
|
|
15341
|
+
}
|
|
15342
|
+
syncBundleAccessToken(this.config, state);
|
|
15343
|
+
});
|
|
15344
|
+
subscribing = false;
|
|
15345
|
+
}
|
|
15346
|
+
previousSession == null ? void 0 : previousSession.release();
|
|
15347
|
+
return initId;
|
|
15348
|
+
}
|
|
14966
15349
|
async init() {
|
|
14967
15350
|
var _a, _b;
|
|
14968
15351
|
(_a = this.cancelBundleForegroundRecovery) == null ? void 0 : _a.call(this);
|
|
14969
15352
|
this.cancelBundleForegroundRecovery = void 0;
|
|
14970
15353
|
this.authRenewalRecovery.cancel();
|
|
14971
|
-
const initId =
|
|
15354
|
+
const initId = this.beginInit();
|
|
14972
15355
|
this.hasAttemptedInit = true;
|
|
14973
15356
|
if (!this.config.communityId) {
|
|
14974
15357
|
this.showError();
|
|
14975
15358
|
return;
|
|
14976
15359
|
}
|
|
14977
|
-
if (!this.config.authUrl && !this.authSession) {
|
|
14978
|
-
this.authSession = subscribeAuthSession(this.config, this.state, () => {
|
|
14979
|
-
if (this.state.isAuthenticated && !this.state.lastAuthError) {
|
|
14980
|
-
this.authRenewalRecovery.succeeded();
|
|
14981
|
-
}
|
|
14982
|
-
if (this.config.autoRefresh) this.scheduleRefresh();
|
|
14983
|
-
if (this.state.iframe) {
|
|
14984
|
-
sendTokenToWidget(this.config, this.state, this.state.iframe);
|
|
14985
|
-
}
|
|
14986
|
-
syncBundleAccessToken(this.config, this.state);
|
|
14987
|
-
});
|
|
14988
|
-
}
|
|
14989
15360
|
if (this.config.bundleUrl) {
|
|
14990
15361
|
this.prepareBundleRuntimeEnvironment();
|
|
14991
15362
|
warmBundleRuntime(
|
|
@@ -14993,6 +15364,7 @@ class BaseWidget extends HTMLElement {
|
|
|
14993
15364
|
this.config.bundleUrl
|
|
14994
15365
|
);
|
|
14995
15366
|
}
|
|
15367
|
+
const renewal = this.embedTokenRenewal(initId);
|
|
14996
15368
|
const finishStartup = (authentication) => resolveStartupAuthentication(
|
|
14997
15369
|
authentication,
|
|
14998
15370
|
(options) => fetchErrorSettings(this.config, this.state, options)
|
|
@@ -15000,6 +15372,9 @@ class BaseWidget extends HTMLElement {
|
|
|
15000
15372
|
const launchWidget = () => {
|
|
15001
15373
|
var _a2;
|
|
15002
15374
|
if (!this.isCurrentInit(initId)) return;
|
|
15375
|
+
this.launchedInitId = initId;
|
|
15376
|
+
this.lateEmbedTokenRegistrationReload = false;
|
|
15377
|
+
this.errorScreenShown = false;
|
|
15003
15378
|
(_a2 = this.errorEl) == null ? void 0 : _a2.classList.remove("visible");
|
|
15004
15379
|
this.shadow.querySelectorAll(".rai-custom-error").forEach((el2) => el2.remove());
|
|
15005
15380
|
let bannerGated = false;
|
|
@@ -15023,11 +15398,9 @@ class BaseWidget extends HTMLElement {
|
|
|
15023
15398
|
};
|
|
15024
15399
|
if (this.config.authUrl) {
|
|
15025
15400
|
const authed2 = await finishStartup(
|
|
15026
|
-
authenticateViaProxy(
|
|
15027
|
-
this.
|
|
15028
|
-
|
|
15029
|
-
() => this.scheduleRefresh()
|
|
15030
|
-
)
|
|
15401
|
+
authenticateViaProxy(this.config, this.state, () => {
|
|
15402
|
+
if (initId === this.initGeneration) this.scheduleRefresh();
|
|
15403
|
+
})
|
|
15031
15404
|
);
|
|
15032
15405
|
if (!this.isCurrentInit(initId)) return;
|
|
15033
15406
|
if (authed2) {
|
|
@@ -15044,10 +15417,11 @@ class BaseWidget extends HTMLElement {
|
|
|
15044
15417
|
const authed2 = await finishStartup(
|
|
15045
15418
|
this.authSession ? this.authSession.run(
|
|
15046
15419
|
"authenticate",
|
|
15047
|
-
() => authenticateServerless(this.config, this.state)
|
|
15420
|
+
() => authenticateServerless(this.config, this.state, renewal)
|
|
15048
15421
|
) : authenticateServerless(
|
|
15049
15422
|
this.config,
|
|
15050
15423
|
this.state,
|
|
15424
|
+
renewal,
|
|
15051
15425
|
() => this.scheduleRefresh()
|
|
15052
15426
|
)
|
|
15053
15427
|
);
|
|
@@ -15074,10 +15448,11 @@ class BaseWidget extends HTMLElement {
|
|
|
15074
15448
|
const refreshed = await finishStartup(
|
|
15075
15449
|
this.authSession ? this.authSession.run(
|
|
15076
15450
|
"refresh",
|
|
15077
|
-
() => refreshAccessToken(this.config, this.state)
|
|
15451
|
+
() => refreshAccessToken(this.config, this.state, renewal)
|
|
15078
15452
|
) : refreshAccessToken(
|
|
15079
15453
|
this.config,
|
|
15080
15454
|
this.state,
|
|
15455
|
+
renewal,
|
|
15081
15456
|
() => this.scheduleRefresh()
|
|
15082
15457
|
)
|
|
15083
15458
|
);
|
|
@@ -15094,10 +15469,11 @@ class BaseWidget extends HTMLElement {
|
|
|
15094
15469
|
const authed = await finishStartup(
|
|
15095
15470
|
this.authSession ? this.authSession.run(
|
|
15096
15471
|
"authenticate",
|
|
15097
|
-
() => authenticateServerless(this.config, this.state)
|
|
15472
|
+
() => authenticateServerless(this.config, this.state, renewal)
|
|
15098
15473
|
) : authenticateServerless(
|
|
15099
15474
|
this.config,
|
|
15100
15475
|
this.state,
|
|
15476
|
+
renewal,
|
|
15101
15477
|
() => this.scheduleRefresh()
|
|
15102
15478
|
)
|
|
15103
15479
|
);
|
|
@@ -15139,6 +15515,8 @@ class BaseWidget extends HTMLElement {
|
|
|
15139
15515
|
}
|
|
15140
15516
|
createIframe() {
|
|
15141
15517
|
this.teardownMountedWidget();
|
|
15518
|
+
const session = this.authSession;
|
|
15519
|
+
const initId = this.initGeneration;
|
|
15142
15520
|
const iframe = document.createElement("iframe");
|
|
15143
15521
|
iframe.src = this.buildWidgetUrl(this.config);
|
|
15144
15522
|
iframe.allow = "clipboard-write";
|
|
@@ -15166,7 +15544,14 @@ class BaseWidget extends HTMLElement {
|
|
|
15166
15544
|
this.state,
|
|
15167
15545
|
this.shadow,
|
|
15168
15546
|
iframe,
|
|
15169
|
-
|
|
15547
|
+
// A token the iframe asks for can renew the session outside the shared
|
|
15548
|
+
// auth session. Publish it: the next session refresh would otherwise
|
|
15549
|
+
// copy the old snapshot back and present a rotated-away refresh token,
|
|
15550
|
+
// which the server treats as reuse once its 60 s grace has passed.
|
|
15551
|
+
() => {
|
|
15552
|
+
if (session) session.publish();
|
|
15553
|
+
else if (initId === this.initGeneration) this.scheduleRefresh();
|
|
15554
|
+
},
|
|
15170
15555
|
() => this.logoutAndClear(),
|
|
15171
15556
|
() => this.hideLoader(),
|
|
15172
15557
|
(type, detail) => this.emit(type, detail),
|
|
@@ -15271,7 +15656,7 @@ class BaseWidget extends HTMLElement {
|
|
|
15271
15656
|
// host page. Bundle consumers use this explicit contract instead of
|
|
15272
15657
|
// inferring the SDK host element from their rendered DOM.
|
|
15273
15658
|
autoHeight,
|
|
15274
|
-
requestHostCallback: (callbackName, payload) => dispatchHostCallback({
|
|
15659
|
+
requestHostCallback: Object.defineProperty((callbackName, payload) => dispatchHostCallback({
|
|
15275
15660
|
callbacks: this.readRuntimeCallbacks(),
|
|
15276
15661
|
callbackName,
|
|
15277
15662
|
payload: enrichHostCallbackPayload(
|
|
@@ -15280,6 +15665,8 @@ class BaseWidget extends HTMLElement {
|
|
|
15280
15665
|
),
|
|
15281
15666
|
hostWidgetType: this.config.widgetType,
|
|
15282
15667
|
transport: "bundle"
|
|
15668
|
+
}), "supportedCallbacks", {
|
|
15669
|
+
get: () => getSupportedHostCallbacks(this.readRuntimeCallbacks(), this.config.widgetType)
|
|
15283
15670
|
})
|
|
15284
15671
|
});
|
|
15285
15672
|
const resolvedMountResult = await resolveBundleMountResult(mountResult);
|
|
@@ -15346,30 +15733,29 @@ class BaseWidget extends HTMLElement {
|
|
|
15346
15733
|
}
|
|
15347
15734
|
async performScheduledRefresh() {
|
|
15348
15735
|
this.state.refreshTimer = null;
|
|
15736
|
+
const initId = this.initGeneration;
|
|
15737
|
+
const { state, config, authSession } = this;
|
|
15738
|
+
const current = () => initId === this.initGeneration;
|
|
15349
15739
|
const pushToken = () => {
|
|
15350
|
-
if (
|
|
15351
|
-
|
|
15352
|
-
syncBundleAccessToken(
|
|
15740
|
+
if (!current()) return;
|
|
15741
|
+
if (state.iframe) sendTokenToWidget(config, state, state.iframe);
|
|
15742
|
+
syncBundleAccessToken(config, state);
|
|
15743
|
+
};
|
|
15744
|
+
const rearm = () => {
|
|
15745
|
+
if (current()) this.scheduleRefresh();
|
|
15353
15746
|
};
|
|
15354
15747
|
let ok;
|
|
15355
|
-
if (
|
|
15356
|
-
ok = await authenticateViaProxy(
|
|
15357
|
-
this.config,
|
|
15358
|
-
this.state,
|
|
15359
|
-
() => this.scheduleRefresh()
|
|
15360
|
-
);
|
|
15748
|
+
if (config.authUrl) {
|
|
15749
|
+
ok = await authenticateViaProxy(config, state, rearm);
|
|
15361
15750
|
if (ok) pushToken();
|
|
15362
15751
|
} else {
|
|
15363
|
-
|
|
15752
|
+
const renewal = this.embedTokenRenewal(initId);
|
|
15753
|
+
ok = authSession ? await authSession.run(
|
|
15364
15754
|
"refresh",
|
|
15365
|
-
() => refreshAccessToken(
|
|
15366
|
-
) : await refreshAccessToken(
|
|
15367
|
-
this.config,
|
|
15368
|
-
this.state,
|
|
15369
|
-
() => this.scheduleRefresh(),
|
|
15370
|
-
pushToken
|
|
15371
|
-
);
|
|
15755
|
+
() => refreshAccessToken(config, state, renewal)
|
|
15756
|
+
) : await refreshAccessToken(config, state, renewal, rearm, pushToken);
|
|
15372
15757
|
}
|
|
15758
|
+
if (initId !== this.initGeneration) return;
|
|
15373
15759
|
if (ok) {
|
|
15374
15760
|
this.authRenewalRecovery.succeeded();
|
|
15375
15761
|
} else if (isPermanentAuthFailure(this.state.lastAuthError)) {
|
|
@@ -15412,12 +15798,15 @@ class BaseWidget extends HTMLElement {
|
|
|
15412
15798
|
}
|
|
15413
15799
|
// ── Logout helper ─────────────────────────────────────────────────────
|
|
15414
15800
|
async logoutAndClear() {
|
|
15415
|
-
|
|
15801
|
+
const initId = this.initGeneration;
|
|
15802
|
+
const session = this.authSession;
|
|
15416
15803
|
this.authRenewalRecovery.cancel();
|
|
15417
15804
|
await logout(this.config, this.state);
|
|
15418
|
-
|
|
15419
|
-
this.
|
|
15420
|
-
|
|
15805
|
+
session == null ? void 0 : session.clear();
|
|
15806
|
+
if (initId === this.initGeneration) {
|
|
15807
|
+
this.teardownMountedWidget();
|
|
15808
|
+
this.removeBanner();
|
|
15809
|
+
}
|
|
15421
15810
|
this.emit("rai-logout");
|
|
15422
15811
|
}
|
|
15423
15812
|
// ── Public API ────────────────────────────────────────────────────────
|
|
@@ -15429,13 +15818,15 @@ class BaseWidget extends HTMLElement {
|
|
|
15429
15818
|
this.authSession = void 0;
|
|
15430
15819
|
this.config = readConfig(this, (_b = this.config) == null ? void 0 : _b.communityId);
|
|
15431
15820
|
this.identitySignature = identitySignatureForConfig(this.config);
|
|
15821
|
+
this.lastEmbedTokenAttribute = this.config.embedToken;
|
|
15432
15822
|
this.style.width = this.config.width;
|
|
15433
15823
|
this.style.height = this.config.height;
|
|
15434
15824
|
clearStorage(previousConfig);
|
|
15435
15825
|
clearStorage(this.config);
|
|
15436
15826
|
this.teardownMountedWidget();
|
|
15437
15827
|
this.removeBanner();
|
|
15438
|
-
|
|
15828
|
+
this.applyFirstPaintColors();
|
|
15829
|
+
this.showLoader();
|
|
15439
15830
|
await this.init();
|
|
15440
15831
|
}
|
|
15441
15832
|
async logoutPublic() {
|
|
@@ -15571,7 +15962,7 @@ class CustomWidget extends BaseWidget {
|
|
|
15571
15962
|
}
|
|
15572
15963
|
}
|
|
15573
15964
|
}
|
|
15574
|
-
console.log(`[rai-widget] v${"1.8.
|
|
15965
|
+
console.log(`[rai-widget] v${"1.8.14"}`);
|
|
15575
15966
|
class StoreWidgetCompat extends StoreWidget {
|
|
15576
15967
|
}
|
|
15577
15968
|
const WIDGET_REGISTRY = [
|
|
@@ -15635,7 +16026,7 @@ function exposePublicApi() {
|
|
|
15635
16026
|
})();
|
|
15636
16027
|
const widget = container == null ? void 0 : container.querySelector(ALL_WIDGET_SELECTOR);
|
|
15637
16028
|
window.ReturningAIWidget = {
|
|
15638
|
-
version: "1.8.
|
|
16029
|
+
version: "1.8.14",
|
|
15639
16030
|
reload: () => (widget == null ? void 0 : widget.reload()) ?? Promise.resolve(),
|
|
15640
16031
|
logout: () => (widget == null ? void 0 : widget.logoutPublic()) ?? Promise.resolve(),
|
|
15641
16032
|
isAuthenticated: () => (widget == null ? void 0 : widget.isAuthenticated()) ?? false,
|