@returningai/widget-sdk 1.4.0 → 1.4.1
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 +104 -0
- package/README.md +27 -33
- package/dist/rai-widget.iife.js +1 -1
- package/dist/rai-widget.js +84 -19
- package/dist/types/BaseWidget.d.ts +3 -0
- package/package.json +4 -2
package/dist/rai-widget.js
CHANGED
|
@@ -10336,6 +10336,9 @@ var lottie_light = { exports: {} };
|
|
|
10336
10336
|
var lottie_lightExports = lottie_light.exports;
|
|
10337
10337
|
const lottie = /* @__PURE__ */ getDefaultExportFromCjs(lottie_lightExports);
|
|
10338
10338
|
function storageKey(config) {
|
|
10339
|
+
return `${config.storagePrefix}-${config.widgetId}-${config.container}-auth`;
|
|
10340
|
+
}
|
|
10341
|
+
function legacyStorageKey(config) {
|
|
10339
10342
|
return `${config.storagePrefix}-${config.widgetId}-auth`;
|
|
10340
10343
|
}
|
|
10341
10344
|
function errorSettingsKey(config) {
|
|
@@ -10354,13 +10357,21 @@ function saveToStorage(config, state) {
|
|
|
10354
10357
|
}
|
|
10355
10358
|
function loadFromStorage(config, state) {
|
|
10356
10359
|
try {
|
|
10357
|
-
|
|
10360
|
+
let raw = localStorage.getItem(storageKey(config));
|
|
10361
|
+
const loadedLegacyKey = !raw;
|
|
10362
|
+
if (!raw) {
|
|
10363
|
+
raw = localStorage.getItem(legacyStorageKey(config));
|
|
10364
|
+
}
|
|
10358
10365
|
if (!raw) return false;
|
|
10359
10366
|
const parsed = JSON.parse(raw);
|
|
10360
10367
|
if (parsed.refreshToken && !isTokenExpired(parsed.refreshTokenExpiry)) {
|
|
10361
10368
|
state.refreshToken = parsed.refreshToken;
|
|
10362
10369
|
state.tokenFamily = parsed.tokenFamily;
|
|
10363
10370
|
state.refreshTokenExpiry = parsed.refreshTokenExpiry;
|
|
10371
|
+
if (loadedLegacyKey) {
|
|
10372
|
+
saveToStorage(config, state);
|
|
10373
|
+
localStorage.removeItem(legacyStorageKey(config));
|
|
10374
|
+
}
|
|
10364
10375
|
return true;
|
|
10365
10376
|
}
|
|
10366
10377
|
clearStorage(config);
|
|
@@ -10372,6 +10383,7 @@ function loadFromStorage(config, state) {
|
|
|
10372
10383
|
function clearStorage(config) {
|
|
10373
10384
|
try {
|
|
10374
10385
|
localStorage.removeItem(storageKey(config));
|
|
10386
|
+
localStorage.removeItem(legacyStorageKey(config));
|
|
10375
10387
|
} catch {
|
|
10376
10388
|
}
|
|
10377
10389
|
}
|
|
@@ -10412,6 +10424,16 @@ function setTokens(config, state, data, onRefreshScheduled) {
|
|
|
10412
10424
|
onRefreshScheduled();
|
|
10413
10425
|
}
|
|
10414
10426
|
}
|
|
10427
|
+
function buildIdentityProof(config) {
|
|
10428
|
+
const proof = {};
|
|
10429
|
+
if (config.embedToken) {
|
|
10430
|
+
proof.embedToken = config.embedToken;
|
|
10431
|
+
}
|
|
10432
|
+
if (config.userIdentifiers && Object.keys(config.userIdentifiers).length > 0) {
|
|
10433
|
+
proof.userIdentifiers = config.userIdentifiers;
|
|
10434
|
+
}
|
|
10435
|
+
return proof;
|
|
10436
|
+
}
|
|
10415
10437
|
async function authenticateServerless(config, state, onRefreshScheduled) {
|
|
10416
10438
|
const nonce = crypto.randomUUID();
|
|
10417
10439
|
const timestamp = Date.now();
|
|
@@ -10428,14 +10450,9 @@ async function authenticateServerless(config, state, onRefreshScheduled) {
|
|
|
10428
10450
|
const body = {
|
|
10429
10451
|
nonce,
|
|
10430
10452
|
timestamp,
|
|
10431
|
-
widgetType: config.widgetType
|
|
10453
|
+
widgetType: config.widgetType,
|
|
10454
|
+
...buildIdentityProof(config)
|
|
10432
10455
|
};
|
|
10433
|
-
if (config.embedToken) {
|
|
10434
|
-
body.embedToken = config.embedToken;
|
|
10435
|
-
}
|
|
10436
|
-
if (config.userIdentifiers && Object.keys(config.userIdentifiers).length > 0) {
|
|
10437
|
-
body.userIdentifiers = config.userIdentifiers;
|
|
10438
|
-
}
|
|
10439
10456
|
const response = await fetch(`${config.apiUrl}/${config.widgetId}/auth/serverless`, {
|
|
10440
10457
|
method: "POST",
|
|
10441
10458
|
headers: { "Content-Type": "application/json" },
|
|
@@ -10531,6 +10548,13 @@ async function refreshAccessToken(config, state, onRefreshScheduled, sendToken)
|
|
|
10531
10548
|
}
|
|
10532
10549
|
state.isRefreshing = true;
|
|
10533
10550
|
state.refreshPromise = (async () => {
|
|
10551
|
+
const reauthenticateAfterRefreshFailure = async () => {
|
|
10552
|
+
clearState(state);
|
|
10553
|
+
clearStorage(config);
|
|
10554
|
+
const authed = await authenticateServerless(config, state, onRefreshScheduled);
|
|
10555
|
+
if (authed && sendToken) sendToken();
|
|
10556
|
+
return authed;
|
|
10557
|
+
};
|
|
10534
10558
|
try {
|
|
10535
10559
|
const response = await fetch(`${config.apiUrl}/${config.widgetId}/auth/refresh`, {
|
|
10536
10560
|
method: "POST",
|
|
@@ -10538,13 +10562,14 @@ async function refreshAccessToken(config, state, onRefreshScheduled, sendToken)
|
|
|
10538
10562
|
"Content-Type": "application/json",
|
|
10539
10563
|
Authorization: `Bearer ${state.refreshToken}`
|
|
10540
10564
|
},
|
|
10541
|
-
body: JSON.stringify({
|
|
10565
|
+
body: JSON.stringify({
|
|
10566
|
+
widgetType: config.widgetType,
|
|
10567
|
+
...buildIdentityProof(config)
|
|
10568
|
+
})
|
|
10542
10569
|
});
|
|
10543
10570
|
if (!response.ok) {
|
|
10544
|
-
if (response.status === 401 || response.status === 403) {
|
|
10545
|
-
|
|
10546
|
-
clearStorage(config);
|
|
10547
|
-
return authenticateServerless(config, state, onRefreshScheduled);
|
|
10571
|
+
if (response.status === 400 || response.status === 401 || response.status === 403) {
|
|
10572
|
+
return reauthenticateAfterRefreshFailure();
|
|
10548
10573
|
}
|
|
10549
10574
|
const error = await response.json().catch(() => ({ error: "Token refresh failed" }));
|
|
10550
10575
|
throw new Error(error.error || `HTTP ${response.status}`);
|
|
@@ -10557,9 +10582,7 @@ async function refreshAccessToken(config, state, onRefreshScheduled, sendToken)
|
|
|
10557
10582
|
if (sendToken) sendToken();
|
|
10558
10583
|
return true;
|
|
10559
10584
|
} catch {
|
|
10560
|
-
|
|
10561
|
-
clearStorage(config);
|
|
10562
|
-
return authenticateServerless(config, state, onRefreshScheduled);
|
|
10585
|
+
return reauthenticateAfterRefreshFailure();
|
|
10563
10586
|
} finally {
|
|
10564
10587
|
state.isRefreshing = false;
|
|
10565
10588
|
state.refreshPromise = null;
|
|
@@ -11030,6 +11053,13 @@ function readConfig(el, existingId) {
|
|
|
11030
11053
|
firstPaintFont: get("font") || void 0
|
|
11031
11054
|
};
|
|
11032
11055
|
}
|
|
11056
|
+
function identitySignatureForConfig(config) {
|
|
11057
|
+
const identifiers = Object.keys(config.userIdentifiers || {}).sort().map((key) => [key, config.userIdentifiers[key]]);
|
|
11058
|
+
return JSON.stringify({
|
|
11059
|
+
embedToken: config.embedToken || "",
|
|
11060
|
+
userIdentifiers: identifiers
|
|
11061
|
+
});
|
|
11062
|
+
}
|
|
11033
11063
|
function createInitialState() {
|
|
11034
11064
|
return {
|
|
11035
11065
|
accessToken: null,
|
|
@@ -11064,11 +11094,15 @@ class BaseWidget extends HTMLElement {
|
|
|
11064
11094
|
__publicField(this, "intersectionObserver");
|
|
11065
11095
|
// #3
|
|
11066
11096
|
__publicField(this, "themeObserver");
|
|
11097
|
+
__publicField(this, "authAttributeObserver");
|
|
11098
|
+
__publicField(this, "identitySignature", "");
|
|
11067
11099
|
__publicField(this, "lottieInstances", []);
|
|
11068
11100
|
this.shadow = this.attachShadow({ mode: "closed" });
|
|
11069
11101
|
}
|
|
11070
11102
|
connectedCallback() {
|
|
11071
11103
|
this.config = readConfig(this, void 0);
|
|
11104
|
+
this.identitySignature = identitySignatureForConfig(this.config);
|
|
11105
|
+
this.setupAuthAttributeObserver();
|
|
11072
11106
|
const style = document.createElement("style");
|
|
11073
11107
|
style.textContent = widgetCSS;
|
|
11074
11108
|
this.shadow.appendChild(style);
|
|
@@ -11098,13 +11132,36 @@ class BaseWidget extends HTMLElement {
|
|
|
11098
11132
|
}
|
|
11099
11133
|
}
|
|
11100
11134
|
disconnectedCallback() {
|
|
11101
|
-
var _a, _b;
|
|
11135
|
+
var _a, _b, _c;
|
|
11102
11136
|
(_a = this.intersectionObserver) == null ? void 0 : _a.disconnect();
|
|
11103
11137
|
(_b = this.themeObserver) == null ? void 0 : _b.disconnect();
|
|
11138
|
+
(_c = this.authAttributeObserver) == null ? void 0 : _c.disconnect();
|
|
11104
11139
|
if (this.cleanupListener) this.cleanupListener();
|
|
11105
11140
|
this.clearLottieInstances();
|
|
11106
11141
|
clearState(this.state);
|
|
11107
11142
|
}
|
|
11143
|
+
setupAuthAttributeObserver() {
|
|
11144
|
+
var _a;
|
|
11145
|
+
(_a = this.authAttributeObserver) == null ? void 0 : _a.disconnect();
|
|
11146
|
+
this.authAttributeObserver = new MutationObserver(() => {
|
|
11147
|
+
var _a2;
|
|
11148
|
+
const nextConfig = readConfig(this, (_a2 = this.config) == null ? void 0 : _a2.communityId);
|
|
11149
|
+
const nextIdentitySignature = identitySignatureForConfig(nextConfig);
|
|
11150
|
+
if (nextIdentitySignature === this.identitySignature) {
|
|
11151
|
+
this.config = nextConfig;
|
|
11152
|
+
return;
|
|
11153
|
+
}
|
|
11154
|
+
const previousConfig = this.config;
|
|
11155
|
+
this.config = nextConfig;
|
|
11156
|
+
this.identitySignature = nextIdentitySignature;
|
|
11157
|
+
clearStorage(previousConfig);
|
|
11158
|
+
clearStorage(this.config);
|
|
11159
|
+
if (this.state.isAuthenticated || this.state.accessToken || this.state.refreshToken || this.state.iframe) {
|
|
11160
|
+
void this.reload();
|
|
11161
|
+
}
|
|
11162
|
+
});
|
|
11163
|
+
this.authAttributeObserver.observe(this, { attributes: true });
|
|
11164
|
+
}
|
|
11108
11165
|
// ── DOM event helper (#1) ─────────────────────────────────────────────
|
|
11109
11166
|
emit(type, detail) {
|
|
11110
11167
|
this.dispatchEvent(
|
|
@@ -11645,6 +11702,14 @@ class BaseWidget extends HTMLElement {
|
|
|
11645
11702
|
}
|
|
11646
11703
|
// ── Public API ────────────────────────────────────────────────────────
|
|
11647
11704
|
async reload() {
|
|
11705
|
+
var _a;
|
|
11706
|
+
const previousConfig = this.config;
|
|
11707
|
+
this.config = readConfig(this, (_a = this.config) == null ? void 0 : _a.communityId);
|
|
11708
|
+
this.identitySignature = identitySignatureForConfig(this.config);
|
|
11709
|
+
this.style.width = this.config.width;
|
|
11710
|
+
this.style.height = this.config.height;
|
|
11711
|
+
clearStorage(previousConfig);
|
|
11712
|
+
clearStorage(this.config);
|
|
11648
11713
|
clearState(this.state);
|
|
11649
11714
|
this.shadow.querySelectorAll("iframe").forEach((el) => el.remove());
|
|
11650
11715
|
await this.init();
|
|
@@ -11767,7 +11832,7 @@ class CustomWidget extends BaseWidget {
|
|
|
11767
11832
|
}
|
|
11768
11833
|
}
|
|
11769
11834
|
}
|
|
11770
|
-
console.log(`[rai-widget] v${"1.4.
|
|
11835
|
+
console.log(`[rai-widget] v${"1.4.1"}`);
|
|
11771
11836
|
class StoreWidgetCompat extends StoreWidget {
|
|
11772
11837
|
}
|
|
11773
11838
|
const WIDGET_REGISTRY = [
|
|
@@ -11831,7 +11896,7 @@ function exposePublicApi() {
|
|
|
11831
11896
|
})();
|
|
11832
11897
|
const widget = container == null ? void 0 : container.querySelector(ALL_WIDGET_SELECTOR);
|
|
11833
11898
|
window.ReturningAIWidget = {
|
|
11834
|
-
version: "1.4.
|
|
11899
|
+
version: "1.4.1",
|
|
11835
11900
|
reload: () => (widget == null ? void 0 : widget.reload()) ?? Promise.resolve(),
|
|
11836
11901
|
logout: () => (widget == null ? void 0 : widget.logoutPublic()) ?? Promise.resolve(),
|
|
11837
11902
|
isAuthenticated: () => (widget == null ? void 0 : widget.isAuthenticated()) ?? false,
|
|
@@ -10,11 +10,14 @@ export declare abstract class BaseWidget extends HTMLElement {
|
|
|
10
10
|
private cleanupListener?;
|
|
11
11
|
private intersectionObserver?;
|
|
12
12
|
private themeObserver?;
|
|
13
|
+
private authAttributeObserver?;
|
|
14
|
+
private identitySignature;
|
|
13
15
|
private lottieInstances;
|
|
14
16
|
constructor();
|
|
15
17
|
protected abstract buildWidgetUrl(config: WidgetConfig): string;
|
|
16
18
|
connectedCallback(): void;
|
|
17
19
|
disconnectedCallback(): void;
|
|
20
|
+
private setupAuthAttributeObserver;
|
|
18
21
|
private emit;
|
|
19
22
|
/**
|
|
20
23
|
* Apply widget-defined CSS colors before first paint so the loader uses
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@returningai/widget-sdk",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.1",
|
|
4
4
|
"description": "Shadow DOM isolated widget SDK for ReturningAI",
|
|
5
5
|
"main": "dist/rai-widget.iife.js",
|
|
6
6
|
"module": "dist/rai-widget.js",
|
|
@@ -13,7 +13,9 @@
|
|
|
13
13
|
}
|
|
14
14
|
},
|
|
15
15
|
"files": [
|
|
16
|
-
"dist"
|
|
16
|
+
"dist",
|
|
17
|
+
"CHANGELOG.md",
|
|
18
|
+
"README.md"
|
|
17
19
|
],
|
|
18
20
|
"scripts": {
|
|
19
21
|
"dev": "vite",
|