@deway-ai/web-sdk 0.81.0 → 0.83.0
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/README.md +107 -0
- package/dist/loader.es.js +69 -41
- package/dist/loader.umd.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -34,6 +34,7 @@ TASKS:
|
|
|
34
34
|
IMPLEMENTATION NOTES:
|
|
35
35
|
- Follow my existing project structure and code style conventions
|
|
36
36
|
- Use appropriate lifecycle hooks: React (useEffect), Vue (onMounted), Angular (ngOnInit)
|
|
37
|
+
- Ensure mobile compatibility support for the side panel integration feature.
|
|
37
38
|
|
|
38
39
|
FIRST analyze my project structure and detect the framework and package manager. Then and only then implement the Deway Web SDK integration accordingly.
|
|
39
40
|
```
|
|
@@ -94,6 +95,112 @@ Deway.init({
|
|
|
94
95
|
|
|
95
96
|
**Why so simple?** Themes, feature flags, AI prompts, and behavior settings are managed remotely and adapt automatically. This lets you iterate on user experiences without SDK updates or app deployments.
|
|
96
97
|
|
|
98
|
+
## Responsive Behavior with the Side Panel
|
|
99
|
+
|
|
100
|
+
> **Read this if your host page uses `@media` queries, `100vw`, or `window.innerWidth`-based layout logic.** When the AI assistant opens in side-panel mode, the host page is squeezed to make room for the panel. Existing responsive rules may not react the way you expect — this section explains the contract and the recommended migration.
|
|
101
|
+
|
|
102
|
+
### What changes when the panel opens
|
|
103
|
+
|
|
104
|
+
When the side panel opens (default width: `420px`), the SDK squeezes the host page by setting `<html>` to `width: calc(100vw - 420px)`. The browser's *real* viewport does not change — only the rendered width of `<html>` does. This has one important consequence:
|
|
105
|
+
|
|
106
|
+
**`@media` queries do NOT fire against the squeezed width.** Media queries evaluate against the real viewport, which is unchanged. A rule like `@media (max-width: 768px)` will not activate when the side panel reduces your content area to `760px` — your desktop layout will render in a 760px box.
|
|
107
|
+
|
|
108
|
+
### CSS custom properties published on `:root`
|
|
109
|
+
|
|
110
|
+
The SDK publishes two custom properties on `:root` while the panel is open:
|
|
111
|
+
|
|
112
|
+
| Property | Value when open | Value when closed |
|
|
113
|
+
|-----------------------|-----------------------|-----------------------------------------|
|
|
114
|
+
| `--deway-panel-width` | `"420px"` | *unset* (property removed) |
|
|
115
|
+
| `--deway-panel-side` | `"right"` or `"left"` | *unset* (property removed) |
|
|
116
|
+
|
|
117
|
+
Because the properties are removed (not set to `0px`) when the panel closes, host CSS should use a fallback:
|
|
118
|
+
|
|
119
|
+
```css
|
|
120
|
+
:root {
|
|
121
|
+
/* Read with fallback — works whether the panel is open or closed */
|
|
122
|
+
--my-effective-panel: var(--deway-panel-width, 0px);
|
|
123
|
+
}
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### Recommended: use `@container` for in-content breakpoints
|
|
127
|
+
|
|
128
|
+
Replace viewport `@media` queries with container queries scoped to your main content. The container will shrink along with the host page when the side panel opens, so breakpoints behave intuitively:
|
|
129
|
+
|
|
130
|
+
```css
|
|
131
|
+
/* Before — does not react when the side panel opens */
|
|
132
|
+
@media (max-width: 768px) {
|
|
133
|
+
.sidebar { display: none; }
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/* After — reacts to the content area, not the real viewport */
|
|
137
|
+
.content { container-type: inline-size; }
|
|
138
|
+
|
|
139
|
+
@container (max-width: 768px) {
|
|
140
|
+
.sidebar { display: none; }
|
|
141
|
+
}
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
**Browser support:** `@container` is supported in Chrome 105+, Safari 16+, Firefox 110+, and Edge 105+. Hosts on older browsers fall back to no breakpoint adjustment (same behavior as before this change).
|
|
145
|
+
|
|
146
|
+
### Fixed-position and `100vw` recipes
|
|
147
|
+
|
|
148
|
+
Use the custom property with a `0px` fallback to make full-bleed elements and fixed overlays panel-aware:
|
|
149
|
+
|
|
150
|
+
```css
|
|
151
|
+
/* Full-bleed hero that respects the side panel */
|
|
152
|
+
.hero {
|
|
153
|
+
width: calc(100vw - var(--deway-panel-width, 0px));
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/* Fixed modal/toast that stays clear of the side panel */
|
|
157
|
+
.modal {
|
|
158
|
+
position: fixed;
|
|
159
|
+
right: calc(var(--deway-panel-width, 0px));
|
|
160
|
+
}
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
### JS: replace `window.innerWidth` reads with the event
|
|
164
|
+
|
|
165
|
+
For layout logic that runs in JavaScript, listen for the `deway:panel-resize` event on `window` instead of (or in addition to) `resize`:
|
|
166
|
+
|
|
167
|
+
```js
|
|
168
|
+
window.addEventListener("deway:panel-resize", (event) => {
|
|
169
|
+
const { width, side, isOpen } = event.detail;
|
|
170
|
+
// Re-render anything that depended on window.innerWidth
|
|
171
|
+
});
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
Or read the current state synchronously:
|
|
175
|
+
|
|
176
|
+
```js
|
|
177
|
+
const { width, side, isOpen } = Deway.getPanelState();
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
### Opt-out
|
|
181
|
+
|
|
182
|
+
If you want full control over your layout, opt out of the host squeeze:
|
|
183
|
+
|
|
184
|
+
```typescript
|
|
185
|
+
Deway.init({
|
|
186
|
+
appKey: 'your-app-key',
|
|
187
|
+
sidePanel: { hostSqueeze: false }
|
|
188
|
+
});
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
When `hostSqueeze` is `false`, the SDK still publishes `--deway-panel-width`, `--deway-panel-side`, and the `deway:panel-resize` event — only the automatic `<html>` squeeze is skipped, so you can apply your own reflow logic.
|
|
192
|
+
|
|
193
|
+
### What this does NOT solve
|
|
194
|
+
|
|
195
|
+
The contract above covers CSS- and JS-driven layout in code you control. It does **not** intercept:
|
|
196
|
+
|
|
197
|
+
- `window.innerWidth` reads in third-party scripts you don't control
|
|
198
|
+
- `<picture>` and `srcset` size queries (resolved by the browser against the real viewport)
|
|
199
|
+
- Print stylesheets and `@page` rules
|
|
200
|
+
- Browser-native viewport units (`100vw`, `100dvw`) in third-party or non-modifiable CSS
|
|
201
|
+
|
|
202
|
+
For these cases, use the opt-out above and reflow with your own logic, or migrate the affected code to read from `--deway-panel-width` / `Deway.getPanelState()`.
|
|
203
|
+
|
|
97
204
|
## API Reference
|
|
98
205
|
|
|
99
206
|
### `Deway.init(config)`
|
package/dist/loader.es.js
CHANGED
|
@@ -19,7 +19,7 @@ function T(o) {
|
|
|
19
19
|
return i !== void 0 ? i : typeof n == "object" && n !== null ? U(n, e) : n;
|
|
20
20
|
});
|
|
21
21
|
}
|
|
22
|
-
function
|
|
22
|
+
function O(o, e) {
|
|
23
23
|
const t = o !== void 0 && Object.keys(o).length > 0, n = e !== void 0;
|
|
24
24
|
if (!t && !n) return;
|
|
25
25
|
const i = typeof e == "object" && e !== null && !Array.isArray(e) ? e : n ? { value: e } : {};
|
|
@@ -32,8 +32,8 @@ function w(o, e, t, n, i) {
|
|
|
32
32
|
level: o,
|
|
33
33
|
time: Date.now(),
|
|
34
34
|
msg: t
|
|
35
|
-
},
|
|
36
|
-
|
|
35
|
+
}, d = O(n, i);
|
|
36
|
+
d !== void 0 && (s.ctx = d), T(s);
|
|
37
37
|
}
|
|
38
38
|
function u(o) {
|
|
39
39
|
const e = o !== void 0 && "minLevel" in o ? o.minLevel : void 0, t = e === void 0 ? x : I[e], n = o?.context;
|
|
@@ -60,8 +60,8 @@ function u(o) {
|
|
|
60
60
|
}
|
|
61
61
|
};
|
|
62
62
|
}
|
|
63
|
-
const k = u({ context: { module: "sdk-config-store" } }), A = "deway-sdk-config",
|
|
64
|
-
class
|
|
63
|
+
const k = u({ context: { module: "sdk-config-store" } }), A = "deway-sdk-config", _ = ["Understanding intent", "Reading web page", "Browsing the docs", "Enriching context", "Validating understanding", "Crafting response"];
|
|
64
|
+
class Q {
|
|
65
65
|
saveConfig(e) {
|
|
66
66
|
if (window?.localStorage)
|
|
67
67
|
try {
|
|
@@ -91,7 +91,7 @@ class N {
|
|
|
91
91
|
return this.loadConfig()?.aiDisclaimer;
|
|
92
92
|
}
|
|
93
93
|
getThinkingMessages() {
|
|
94
|
-
return this.loadConfig()?.thinkingMessages ??
|
|
94
|
+
return this.loadConfig()?.thinkingMessages ?? _;
|
|
95
95
|
}
|
|
96
96
|
/**
|
|
97
97
|
* Get the support handoff configuration
|
|
@@ -158,6 +158,16 @@ class N {
|
|
|
158
158
|
getUIAlignmentSide() {
|
|
159
159
|
return this.getUIAlignment()?.side ?? "right";
|
|
160
160
|
}
|
|
161
|
+
/**
|
|
162
|
+
* Whether the SDK should inject the `<html>` squeeze stylesheet when the
|
|
163
|
+
* side-panel opens. Default is `true` — hosts can opt out via
|
|
164
|
+
* `Deway.init({ sidePanel: { hostSqueeze: false } })`. When `false`, the
|
|
165
|
+
* SDK still publishes the responsive contract (CSS custom properties +
|
|
166
|
+
* `deway:panel-resize` event) but skips the squeeze.
|
|
167
|
+
*/
|
|
168
|
+
getSidePanelHostSqueezeEnabled() {
|
|
169
|
+
return this.loadConfig()?.sidePanel?.hostSqueeze ?? !0;
|
|
170
|
+
}
|
|
161
171
|
}
|
|
162
172
|
const f = u({ context: { module: "sdk-cache-manager" } });
|
|
163
173
|
class l {
|
|
@@ -167,9 +177,9 @@ class l {
|
|
|
167
177
|
static STORE_NAME = "sdk";
|
|
168
178
|
async cacheSDK(e, t, n, i) {
|
|
169
179
|
try {
|
|
170
|
-
const
|
|
180
|
+
const d = (await this.openIndexedDB()).transaction([l.STORE_NAME], "readwrite").objectStore(l.STORE_NAME);
|
|
171
181
|
await new Promise((E, K) => {
|
|
172
|
-
const g =
|
|
182
|
+
const g = d.put({
|
|
173
183
|
id: "latest",
|
|
174
184
|
code: e,
|
|
175
185
|
version: t,
|
|
@@ -197,8 +207,8 @@ class l {
|
|
|
197
207
|
async getCachedSDK() {
|
|
198
208
|
try {
|
|
199
209
|
const n = (await this.openIndexedDB()).transaction([l.STORE_NAME], "readonly").objectStore(l.STORE_NAME), i = await new Promise((r, s) => {
|
|
200
|
-
const
|
|
201
|
-
|
|
210
|
+
const d = n.get("latest");
|
|
211
|
+
d.onsuccess = () => r(d.result || null), d.onerror = () => s(d.error);
|
|
202
212
|
});
|
|
203
213
|
if (i)
|
|
204
214
|
return f.debug("Found cached SDK in IndexedDB"), i;
|
|
@@ -224,7 +234,7 @@ class l {
|
|
|
224
234
|
});
|
|
225
235
|
}
|
|
226
236
|
}
|
|
227
|
-
const
|
|
237
|
+
const N = u({ context: { module: "sdk-verifier" } });
|
|
228
238
|
async function R(o) {
|
|
229
239
|
const t = new TextEncoder().encode(o), n = await crypto.subtle.digest("SHA-256", t);
|
|
230
240
|
return Array.from(new Uint8Array(n)).map((r) => r.toString(16).padStart(2, "0")).join("");
|
|
@@ -235,30 +245,30 @@ function F(o) {
|
|
|
235
245
|
t[n] = e.charCodeAt(n);
|
|
236
246
|
return t;
|
|
237
247
|
}
|
|
238
|
-
function
|
|
248
|
+
function P(o) {
|
|
239
249
|
const e = new Uint8Array(o.length / 2);
|
|
240
250
|
for (let t = 0; t < o.length; t += 2)
|
|
241
251
|
e[t / 2] = Number.parseInt(o.substr(t, 2), 16);
|
|
242
252
|
return e;
|
|
243
253
|
}
|
|
244
|
-
async function
|
|
254
|
+
async function $(o, e, t) {
|
|
245
255
|
try {
|
|
246
|
-
const n = F(o), i =
|
|
256
|
+
const n = F(o), i = P(e), r = F(t), s = await crypto.subtle.importKey("raw", n, { name: "Ed25519" }, !1, ["verify"]);
|
|
247
257
|
return await crypto.subtle.verify("Ed25519", s, r, i);
|
|
248
258
|
} catch (n) {
|
|
249
|
-
return
|
|
259
|
+
return N.error("Ed25519 signature verification failed", n), !1;
|
|
250
260
|
}
|
|
251
261
|
}
|
|
252
|
-
async function
|
|
262
|
+
async function q(o, e, t, n) {
|
|
253
263
|
if (!e || !t)
|
|
254
264
|
throw new Error("SDK verification failed: Missing security headers");
|
|
255
265
|
if (await R(o) !== e)
|
|
256
266
|
throw new Error("SDK verification failed: Checksum mismatch - content tampered");
|
|
257
|
-
if (!await
|
|
267
|
+
if (!await $(n, e, t))
|
|
258
268
|
throw new Error("SDK verification failed: Invalid signature - content tampered");
|
|
259
269
|
}
|
|
260
270
|
const m = u({ context: { module: "sdk-fetcher" } });
|
|
261
|
-
class
|
|
271
|
+
class z {
|
|
262
272
|
cleanApiEndpoint(e) {
|
|
263
273
|
return e.trim().replace(/\/+$/, "");
|
|
264
274
|
}
|
|
@@ -281,10 +291,10 @@ class P {
|
|
|
281
291
|
async handleSuccessfulFetch(e, t) {
|
|
282
292
|
const n = e.headers.get("x-sdk-checksum"), i = e.headers.get("x-sdk-version"), r = e.headers.get("x-sdk-signature"), s = await e.text();
|
|
283
293
|
if (m.info(`Fetched Deway SDK version ${i}`), !i || !s || !n) {
|
|
284
|
-
const
|
|
285
|
-
throw m.error("Failed to get required data from sdk fetch", { headers:
|
|
294
|
+
const d = Object.fromEntries(e.headers.entries());
|
|
295
|
+
throw m.error("Failed to get required data from sdk fetch", { headers: d }), new Error("Invalid SDK response: missing version, code, or checksum");
|
|
286
296
|
}
|
|
287
|
-
return await
|
|
297
|
+
return await q(s, n, r, t), { code: s, version: i, checksum: n, signature: r || "" };
|
|
288
298
|
}
|
|
289
299
|
}
|
|
290
300
|
const h = u({ context: { module: "command-queue" } });
|
|
@@ -408,7 +418,7 @@ class M {
|
|
|
408
418
|
}
|
|
409
419
|
}
|
|
410
420
|
const y = u({ context: { module: "script-executor" } });
|
|
411
|
-
class
|
|
421
|
+
class H {
|
|
412
422
|
async executeSDK(e) {
|
|
413
423
|
return new Promise((t) => {
|
|
414
424
|
try {
|
|
@@ -447,7 +457,7 @@ class V {
|
|
|
447
457
|
}
|
|
448
458
|
}
|
|
449
459
|
const D = u({ context: { module: "config-validator" } });
|
|
450
|
-
class
|
|
460
|
+
class V {
|
|
451
461
|
validateConfig(e) {
|
|
452
462
|
return e ? !e.appKey || e.appKey.trim().length === 0 ? (D.error("Config.appKey is required and must be a non-empty string"), !1) : e.apiEndpoint !== void 0 && !this.isValidUrl(e.apiEndpoint) ? (D.error("Config.apiEndpoint must be a valid URL"), !1) : e.publicKey !== void 0 && e.publicKey.trim().length === 0 ? (D.error("Config.publicKey must be a non-empty string if provided"), !1) : !0 : (D.error("Config is required"), !1);
|
|
453
463
|
}
|
|
@@ -463,7 +473,7 @@ const a = u({ context: { module: "sdk-loader" } }), v = {
|
|
|
463
473
|
apiEndpoint: "https://service.deway.app",
|
|
464
474
|
publicKey: "9d3dBUvqyUQ7egd5j5uORdHSqZ7VFWOu+ud/SWt9WUY="
|
|
465
475
|
};
|
|
466
|
-
class
|
|
476
|
+
class j {
|
|
467
477
|
isLoaded = !1;
|
|
468
478
|
isLoading = !1;
|
|
469
479
|
cacheManager;
|
|
@@ -475,7 +485,7 @@ class H {
|
|
|
475
485
|
remoteConfigCache;
|
|
476
486
|
sdkConfigStore;
|
|
477
487
|
constructor() {
|
|
478
|
-
this.cacheManager = new l(), this.scriptExecutor = new
|
|
488
|
+
this.cacheManager = new l(), this.scriptExecutor = new H(), this.commandQueue = new C(), this.sdkFetcher = new z(), this.configValidator = new V(), this.sdkConfigStore = new Q(), this.remoteConfigFetcher = new M(), this.remoteConfigCache = new b();
|
|
479
489
|
}
|
|
480
490
|
init(e) {
|
|
481
491
|
this.performInit(e).catch((t) => {
|
|
@@ -492,10 +502,10 @@ class H {
|
|
|
492
502
|
return;
|
|
493
503
|
}
|
|
494
504
|
this.isLoading = !0;
|
|
495
|
-
const i = n.apiEndpoint || v.apiEndpoint, r = n.publicKey || v.publicKey, [s,
|
|
505
|
+
const i = n.apiEndpoint || v.apiEndpoint, r = n.publicKey || v.publicKey, [s, d] = await Promise.all([this.fetchOrLoadSDK(n.appKey, i, r), this.fetchRemoteConfigWithCache(n, i)]);
|
|
496
506
|
if (!s)
|
|
497
507
|
return;
|
|
498
|
-
const E = t ? e : this.createInitializationPayload(
|
|
508
|
+
const E = t ? e : this.createInitializationPayload(d, n);
|
|
499
509
|
if (!await this.scriptExecutor.executeSDK(s.code)) {
|
|
500
510
|
a.error("SDK execution failed");
|
|
501
511
|
return;
|
|
@@ -621,6 +631,23 @@ class H {
|
|
|
621
631
|
return a.error("Failed to check initialization status", e), !1;
|
|
622
632
|
}
|
|
623
633
|
}
|
|
634
|
+
/**
|
|
635
|
+
* Returns the current side-panel state synchronously. This call must NOT be
|
|
636
|
+
* queued — when the backend SDK isn't loaded yet, return the default
|
|
637
|
+
* immediately so hosts can call this during render.
|
|
638
|
+
*/
|
|
639
|
+
getPanelState() {
|
|
640
|
+
try {
|
|
641
|
+
if (this.isLoaded && this.isSDKAvailable()) {
|
|
642
|
+
const e = window.Deway?.getPanelState;
|
|
643
|
+
if (typeof e == "function")
|
|
644
|
+
return e();
|
|
645
|
+
}
|
|
646
|
+
return { width: 0, side: "right", isOpen: !1 };
|
|
647
|
+
} catch (e) {
|
|
648
|
+
return a.error("Failed to read panel state", e), { width: 0, side: "right", isOpen: !1 };
|
|
649
|
+
}
|
|
650
|
+
}
|
|
624
651
|
registerSupportCallback(e) {
|
|
625
652
|
try {
|
|
626
653
|
this.isLoaded && this.isSDKAvailable() ? window.Deway?.registerSupportCallback(e) : this.commandQueue.queueCommand("registerSupportCallback", e);
|
|
@@ -646,20 +673,21 @@ class H {
|
|
|
646
673
|
return typeof window < "u" && "Deway" in window && !!window.Deway;
|
|
647
674
|
}
|
|
648
675
|
}
|
|
649
|
-
const
|
|
650
|
-
init: (o) =>
|
|
651
|
-
identify: (o) =>
|
|
652
|
-
reportEvent: (o, e) =>
|
|
653
|
-
setUserProfile: (o) =>
|
|
654
|
-
show: (o) =>
|
|
655
|
-
hide: () =>
|
|
656
|
-
openChat: () =>
|
|
657
|
-
resetUserLocally: () =>
|
|
658
|
-
registerSupportCallback: (o) =>
|
|
659
|
-
unregisterSupportCallback: () =>
|
|
660
|
-
isVisible: () =>
|
|
661
|
-
isInitialized: () =>
|
|
662
|
-
destroy: () =>
|
|
676
|
+
const c = new j(), B = {
|
|
677
|
+
init: (o) => c.init(o),
|
|
678
|
+
identify: (o) => c.identify(o),
|
|
679
|
+
reportEvent: (o, e) => c.reportEvent(o, e),
|
|
680
|
+
setUserProfile: (o) => c.setUserProfile(o),
|
|
681
|
+
show: (o) => c.show(o),
|
|
682
|
+
hide: () => c.hide(),
|
|
683
|
+
openChat: () => c.openChat(),
|
|
684
|
+
resetUserLocally: () => c.resetUserLocally(),
|
|
685
|
+
registerSupportCallback: (o) => c.registerSupportCallback(o),
|
|
686
|
+
unregisterSupportCallback: () => c.unregisterSupportCallback(),
|
|
687
|
+
isVisible: () => c.isVisible(),
|
|
688
|
+
isInitialized: () => c.isInitialized(),
|
|
689
|
+
destroy: () => c.destroy(),
|
|
690
|
+
getPanelState: () => c.getPanelState()
|
|
663
691
|
};
|
|
664
692
|
typeof window < "u" && (window.Deway = B);
|
|
665
693
|
export {
|
package/dist/loader.umd.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
(function(h,m){typeof exports=="object"&&typeof module<"u"?module.exports=m():typeof define=="function"&&define.amd?define(m):(h=typeof globalThis<"u"?globalThis:h||self,h.Deway=m())})(this,(function(){"use strict";const h={debug:0,info:1,warn:2,error:3},m=4;function U(o){if(typeof o=="bigint")return`${o}n`;if(typeof o=="symbol")return o.toString();if(typeof o=="function")return"[Function]"}function T(o,e){return o instanceof Error?{name:o.name,message:o.message,stack:o.stack}:e.has(o)?"[Circular]":(e.add(o),o)}function _(o){const e=new WeakSet;return JSON.stringify(o,(t,n)=>{const i=U(n);return i!==void 0?i:typeof n=="object"&&n!==null?T(n,e):n})}function Q(o,e){const t=o!==void 0&&Object.keys(o).length>0,n=e!==void 0;if(!t&&!n)return;const i=typeof e=="object"&&e!==null&&!Array.isArray(e)?e:n?{value:e}:{};return{...o,...i}}function S(o,e,t,n,i){const r=e;if(h[o]<r)return;const s={level:o,time:Date.now(),msg:t},d=Q(n,i);d!==void 0&&(s.ctx=d),_(s)}function u(o){const e=o!==void 0&&"minLevel"in o?o.minLevel:void 0,t=e===void 0?m:h[e],n=o?.context;return{debug(i,r){S("debug",t,i,n,r)},info(i,r){S("info",t,i,n,r)},warn(i,r){S("warn",t,i,n,r)},error(i,r){S("error",t,i,n,r)},child(i){return u({minLevel:e,context:{...n,...i}})},alwaysOnLog(i){}}}const A=u({context:{module:"sdk-config-store"}}),F="deway-sdk-config",N=["Understanding intent","Reading web page","Browsing the docs","Enriching context","Validating understanding","Crafting response"];class O{saveConfig(e){if(window?.localStorage)try{const t=JSON.stringify(e);window.localStorage.setItem(F,t)}catch(t){A.warn("Failed to save SDK config to localStorage",t)}}loadConfig(){if(window?.localStorage)try{const e=window.localStorage.getItem(F);return e?JSON.parse(e):null}catch(e){return A.warn("Failed to load SDK config from localStorage",e),null}return null}getExcludedVendors(){return this.loadConfig()?.excludedVendors??[]}getAssistantName(){return this.loadConfig()?.assistantName??"Assistant"}getAiDisclaimer(){return this.loadConfig()?.aiDisclaimer}getThinkingMessages(){return this.loadConfig()?.thinkingMessages??N}getSupportHandoff(){return this.loadConfig()?.supportHandoff??null}getSupportHandoffButtonText(){return this.getSupportHandoff()?.button_text??"talk to Support"}getFeatureFlags(){return this.loadConfig()?.featureFlags??{}}getFeatureFlag(e){return this.getFeatureFlags()[e]??!1}getPromptSuggestions(){return this.loadConfig()?.promptSuggestions}getWelcomeTitle(){return this.loadConfig()?.welcomeTitle??"How can I help you today?"}getWelcomeSubtitle(){return this.loadConfig()?.welcomeSubtitle??"I'm ready to help you navigate, learn, and get things done."}getEntrypointWidgetAppearanceMode(){return this.loadConfig()?.entrypointWidgetAppearanceMode??"bookmark"}getChatAppearanceMode(){return this.loadConfig()?.chatAppearanceMode??"floating-window"}getTenantTheme(){return this.loadConfig()?.tenantTheme??null}getTenantThemeForMode(e){const t=this.getTenantTheme();return t?e==="dark"?t.dark:t.light:null}getCustomIcons(){return this.loadConfig()?.customIcons??null}getEntrypointWidgetIconInlineSvg(){return this.getCustomIcons()?.entrypoint_widget_icon_inline_svg??void 0}getEmptyChatStateIconInlineSvg(){return this.getCustomIcons()?.empty_chat_state_icon_inline_svg??void 0}getUIAlignment(){return this.loadConfig()?.uiAlignment??null}getUIAlignmentAnchorSelector(){return this.getUIAlignment()?.anchor_selector??null}getUIAlignmentSide(){return this.getUIAlignment()?.side??"right"}}const f=u({context:{module:"sdk-cache-manager"}});class l{static CACHE_KEY="deway-sdk-cache";static DB_NAME="DewaySdk";static DB_VERSION=1;static STORE_NAME="sdk";async cacheSDK(e,t,n,i){try{const d=(await this.openIndexedDB()).transaction([l.STORE_NAME],"readwrite").objectStore(l.STORE_NAME);await new Promise((k,L)=>{const w=d.put({id:"latest",code:e,version:t,checksum:n,signature:i,timestamp:Date.now()});w.onsuccess=()=>k(w.result),w.onerror=()=>L(w.error)}),f.debug("SDK cached in IndexedDB")}catch{try{const s=JSON.stringify({code:e,version:t,checksum:n,signature:i,timestamp:Date.now()});localStorage.setItem(l.CACHE_KEY,s),f.debug("SDK cached in localStorage")}catch(s){f.warn("Unable to cache SDK",s)}}}async getCachedSDK(){try{const n=(await this.openIndexedDB()).transaction([l.STORE_NAME],"readonly").objectStore(l.STORE_NAME),i=await new Promise((r,s)=>{const d=n.get("latest");d.onsuccess=()=>r(d.result||null),d.onerror=()=>s(d.error)});if(i)return f.debug("Found cached SDK in IndexedDB"),i}catch{f.debug("IndexedDB unavailable, trying localStorage")}try{const e=localStorage.getItem(l.CACHE_KEY);if(e)return f.debug("Found cached SDK in localStorage"),JSON.parse(e)}catch(e){f.warn("Failed to read from localStorage",e)}return null}openIndexedDB(){return new Promise((e,t)=>{const n=indexedDB.open(l.DB_NAME,l.DB_VERSION);n.onerror=()=>t(n.error),n.onsuccess=()=>e(n.result),n.onupgradeneeded=i=>{const r=i.target.result;r.objectStoreNames.contains(l.STORE_NAME)||r.createObjectStore(l.STORE_NAME,{keyPath:"id"})}})}}const R=u({context:{module:"sdk-verifier"}});async function $(o){const t=new TextEncoder().encode(o),n=await crypto.subtle.digest("SHA-256",t);return Array.from(new Uint8Array(n)).map(r=>r.toString(16).padStart(2,"0")).join("")}function I(o){const e=atob(o),t=new Uint8Array(e.length);for(let n=0;n<e.length;n++)t[n]=e.charCodeAt(n);return t}function q(o){const e=new Uint8Array(o.length/2);for(let t=0;t<o.length;t+=2)e[t/2]=Number.parseInt(o.substr(t,2),16);return e}async function z(o,e,t){try{const n=I(o),i=q(e),r=I(t),s=await crypto.subtle.importKey("raw",n,{name:"Ed25519"},!1,["verify"]);return await crypto.subtle.verify("Ed25519",s,r,i)}catch(n){return R.error("Ed25519 signature verification failed",n),!1}}async function P(o,e,t,n){if(!e||!t)throw new Error("SDK verification failed: Missing security headers");if(await $(o)!==e)throw new Error("SDK verification failed: Checksum mismatch - content tampered");if(!await z(n,e,t))throw new Error("SDK verification failed: Invalid signature - content tampered")}const y=u({context:{module:"sdk-fetcher"}});class M{cleanApiEndpoint(e){return e.trim().replace(/\/+$/,"")}async fetchSDK(e,t,n){try{y.info("Fetching Deway SDK from backend...");const i=this.cleanApiEndpoint(t),r=await fetch(`${i}/sdk-serve/sdk/v0`,{method:"GET",headers:{Accept:"application/javascript","deway-app-key":e,Origin:window?.location?.origin||""}});return r.ok?this.handleSuccessfulFetch(r,n):(y.warn(`Failed to fetch SDK: HTTP ${r.status}: ${r.statusText}`),null)}catch(i){return y.warn("Failed to fetch SDK from server",i),null}}async handleSuccessfulFetch(e,t){const n=e.headers.get("x-sdk-checksum"),i=e.headers.get("x-sdk-version"),r=e.headers.get("x-sdk-signature"),s=await e.text();if(y.info(`Fetched Deway SDK version ${i}`),!i||!s||!n){const d=Object.fromEntries(e.headers.entries());throw y.error("Failed to get required data from sdk fetch",{headers:d}),new Error("Invalid SDK response: missing version, code, or checksum")}return await P(s,n,r,t),{code:s,version:i,checksum:n,signature:r||""}}}const g=u({context:{module:"command-queue"}});class D{static MAX_QUEUE_SIZE=50;commandQueue=[];queueCommand(e,...t){this.commandQueue.length>=D.MAX_QUEUE_SIZE&&(g.warn(`Command queue full (${D.MAX_QUEUE_SIZE} commands). Discarding oldest command.`),this.commandQueue.shift()),this.commandQueue.push({method:e,args:t}),g.debug(`Queued command: ${e} (queue size: ${this.commandQueue.length})`)}replayQueuedCommands(){if(this.commandQueue.length===0)return;g.info(`Replaying ${this.commandQueue.length} queued commands`);const e=[...this.commandQueue];if(this.commandQueue=[],!this.isSDKAvailable()){g.warn("Deway SDK not available for command replay");return}for(const t of e)this.replayCommand(t)}clearQueue(){this.commandQueue=[]}isSDKAvailable(){return typeof window<"u"&&"Deway"in window&&!!window.Deway}replayCommand(e){try{const t=window.Deway,n=t?.[e.method];typeof n=="function"?n.apply(t,e.args):g.warn(`Method ${e.method} not found on Deway SDK`)}catch(t){g.error(`Failed to replay command ${e.method}`,t)}}}const C=u({context:{module:"remote-config-cache"}});class b{static CACHE_KEY="deway-remote-config-cache";async cacheRemoteConfig(e,t){try{const n={config:e,ttl_seconds:t,timestamp:Date.now()};localStorage.setItem(b.CACHE_KEY,JSON.stringify(n)),C.debug("Remote configuration cached in localStorage")}catch(n){C.warn("Failed to cache remote config",n)}}async getCachedRemoteConfig(){try{const e=localStorage.getItem(b.CACHE_KEY);if(!e)return null;const t=JSON.parse(e);return C.debug("Found cached remote configuration"),t}catch(e){return C.warn("Failed to read cached remote config",e),null}}isCacheValid(e,t){const n=Date.now(),i=e+t*1e3;return n<i}}const E=u({context:{module:"remote-config-fetcher"}});class j{cleanApiEndpoint(e){return e.trim().replace(/\/+$/,"")}async fetchRemoteConfig(e,t){try{E.info("Fetching remote configuration from backend...");const n=this.cleanApiEndpoint(t),i=await fetch(`${n}/sdk-remote-config-serve/`,{method:"GET",headers:{Accept:"application/json","deway-app-key":e,Origin:window?.location?.origin||""}});if(i.ok){const r=await i.json();return E.info("Remote configuration fetched successfully"),r}return E.warn(`Failed to fetch remote config: HTTP ${i.status}: ${i.statusText}`),null}catch(n){return E.warn("Failed to fetch remote config from server",n),null}}}const p=u({context:{module:"script-executor"}});class V{async executeSDK(e){return new Promise(t=>{try{if(!this.isDocumentReady()){p.error("Document is not available for script execution"),t(!1);return}const n=document.createElement("script");n.textContent=e,n.type="text/javascript";let i=!1;const r=s=>{i||(i=!0,this.cleanupScript(n),t(s))};n.onerror=()=>{p.error("Script execution failed"),r(!1)},n.onload=()=>r(!0),document.head.appendChild(n),setTimeout(()=>{!i&&this.verifySDKLoaded()?r(!0):i||(p.error("SDK execution timeout - Deway object not found"),r(!1))},100)}catch(n){p.error("Failed to execute SDK script",n),t(!1)}})}isDocumentReady(){return typeof document<"u"&&document.head!=null}verifySDKLoaded(){return typeof window<"u"&&"Deway"in window&&!!window.Deway}cleanupScript(e){try{e.parentNode&&e.parentNode.removeChild(e)}catch(t){p.debug("Failed to cleanup script element",t)}}}const v=u({context:{module:"config-validator"}});class H{validateConfig(e){return e?!e.appKey||e.appKey.trim().length===0?(v.error("Config.appKey is required and must be a non-empty string"),!1):e.apiEndpoint!==void 0&&!this.isValidUrl(e.apiEndpoint)?(v.error("Config.apiEndpoint must be a valid URL"),!1):e.publicKey!==void 0&&e.publicKey.trim().length===0?(v.error("Config.publicKey must be a non-empty string if provided"),!1):!0:(v.error("Config is required"),!1)}isValidUrl(e){try{return new URL(e),!0}catch{return!1}}}const a=u({context:{module:"sdk-loader"}}),K={apiEndpoint:"https://service.deway.app",publicKey:"9d3dBUvqyUQ7egd5j5uORdHSqZ7VFWOu+ud/SWt9WUY="};class B{isLoaded=!1;isLoading=!1;cacheManager;scriptExecutor;commandQueue;sdkFetcher;configValidator;remoteConfigFetcher;remoteConfigCache;sdkConfigStore;constructor(){this.cacheManager=new l,this.scriptExecutor=new V,this.commandQueue=new D,this.sdkFetcher=new M,this.configValidator=new H,this.sdkConfigStore=new O,this.remoteConfigFetcher=new j,this.remoteConfigCache=new b}init(e){this.performInit(e).catch(t=>{a.error("Failed to initialize Deway SDK",t)})}async performInit(e){try{if(!this.canInitialize())return;const t=this.isInitializationPayload(e),n=t?e.localConfig:e;if(!this.configValidator.validateConfig(n)){a.error("Invalid config provided to Deway SDK");return}this.isLoading=!0;const i=n.apiEndpoint||K.apiEndpoint,r=n.publicKey||K.publicKey,[s,d]=await Promise.all([this.fetchOrLoadSDK(n.appKey,i,r),this.fetchRemoteConfigWithCache(n,i)]);if(!s)return;const k=t?e:this.createInitializationPayload(d,n);if(!await this.scriptExecutor.executeSDK(s.code)){a.error("SDK execution failed");return}if(!this.initializeSDK(k))return;this.commandQueue.replayQueuedCommands(),this.isLoaded=!0}finally{this.isLoading=!1}}isInitializationPayload(e){return"localConfig"in e&&"remoteConfig"in e&&"defaults"in e}canInitialize(){return this.isLoaded?(a.warn("Deway SDK already initialized"),!1):this.isLoading?(a.warn("Deway SDK initialization already in progress"),!1):!0}async fetchRemoteConfigWithCache(e,t){this.sdkConfigStore.saveConfig(e);const n=await this.remoteConfigFetcher.fetchRemoteConfig(e.appKey,t);if(n)return await this.remoteConfigCache.cacheRemoteConfig(n.config,n.ttl_seconds),n;a.info("Using cached remote config as fallback");const i=await this.remoteConfigCache.getCachedRemoteConfig();return i?{config:i.config,ttl_seconds:i.ttl_seconds}:(a.warn("No remote config available (fetch failed and no cache)"),null)}createInitializationPayload(e,t){return{localConfig:t,remoteConfig:e?.config??null,defaults:K}}async fetchOrLoadSDK(e,t,n){const i=await this.sdkFetcher.fetchSDK(e,t,n);return i?(await this.cacheManager.cacheSDK(i.code,i.version,i.checksum,i.signature),i):(a.warn("Failed to fetch SDK from server, attempting cache fallback"),this.loadFromCache())}async loadFromCache(){const e=await this.cacheManager.getCachedSDK();return e?(a.info(`Loading cached Deway SDK version ${e.version}`),{code:e.code,version:e.version}):(a.error("SDK unavailable: Network error and no cached version found"),null)}initializeSDK(e){if(!this.isSDKAvailable())return a.error("SDK execution failed: Deway object not found after loading"),!1;try{return window.Deway?.init(e),a.info("Deway SDK initialized successfully with payload"),!0}catch(t){return a.error("Failed to initialize SDK with payload",t),!1}}identify(e){try{this.isLoaded&&this.isSDKAvailable()?window.Deway?.identify(e):this.commandQueue.queueCommand("identify",e)}catch(t){a.error("Failed to identify user",t)}}reportEvent(e,t){try{this.isLoaded&&this.isSDKAvailable()?window.Deway?.reportEvent(e,t):this.commandQueue.queueCommand("reportEvent",e,t)}catch(n){a.error("Failed to report event",n)}}setUserProfile(e){try{this.isLoaded&&this.isSDKAvailable()?window.Deway?.setUserProfile(e):this.commandQueue.queueCommand("setUserProfile",e)}catch(t){a.error("Failed to set user profile",t)}}show(e){try{this.isLoaded&&this.isSDKAvailable()?window.Deway?.show(e):this.commandQueue.queueCommand("show",e)}catch(t){a.error("Failed to show bookmark",t)}}hide(){try{this.isLoaded&&this.isSDKAvailable()?window.Deway?.hide():this.commandQueue.queueCommand("hide")}catch(e){a.error("Failed to hide bookmark",e)}}openChat(){try{this.isLoaded&&this.isSDKAvailable()?window.Deway?.openChat():this.commandQueue.queueCommand("openChat")}catch(e){a.error("Failed to open chat",e)}}resetUserLocally(){try{this.isLoaded&&this.isSDKAvailable()?window.Deway?.resetUserLocally():this.commandQueue.queueCommand("resetUserLocally")}catch(e){a.error("Failed to reset user locally",e)}}isVisible(){try{return this.isLoaded&&this.isSDKAvailable()?window.Deway?.isVisible()??!1:!1}catch(e){return a.error("Failed to check bookmark visibility",e),!1}}isInitialized(){try{return this.isLoaded&&this.isSDKAvailable()?window.Deway?.isInitialized()??!1:!1}catch(e){return a.error("Failed to check initialization status",e),!1}}registerSupportCallback(e){try{this.isLoaded&&this.isSDKAvailable()?window.Deway?.registerSupportCallback(e):this.commandQueue.queueCommand("registerSupportCallback",e)}catch(t){a.error("Failed to register support callback",t)}}unregisterSupportCallback(){try{this.isLoaded&&this.isSDKAvailable()?window.Deway?.unregisterSupportCallback():this.commandQueue.queueCommand("unregisterSupportCallback")}catch(e){a.error("Failed to unregister support callback",e)}}destroy(){try{this.isLoaded&&this.isSDKAvailable()?window.Deway?.destroy():this.commandQueue.queueCommand("destroy"),this.commandQueue.clearQueue()}catch(e){a.error("Failed to destroy SDK",e)}}isSDKAvailable(){return typeof window<"u"&&"Deway"in window&&!!window.Deway}}const c=new B,x={init:o=>c.init(o),identify:o=>c.identify(o),reportEvent:(o,e)=>c.reportEvent(o,e),setUserProfile:o=>c.setUserProfile(o),show:o=>c.show(o),hide:()=>c.hide(),openChat:()=>c.openChat(),resetUserLocally:()=>c.resetUserLocally(),registerSupportCallback:o=>c.registerSupportCallback(o),unregisterSupportCallback:()=>c.unregisterSupportCallback(),isVisible:()=>c.isVisible(),isInitialized:()=>c.isInitialized(),destroy:()=>c.destroy()};return typeof window<"u"&&(window.Deway=x),x}));
|
|
1
|
+
(function(h,m){typeof exports=="object"&&typeof module<"u"?module.exports=m():typeof define=="function"&&define.amd?define(m):(h=typeof globalThis<"u"?globalThis:h||self,h.Deway=m())})(this,(function(){"use strict";const h={debug:0,info:1,warn:2,error:3},m=4;function U(o){if(typeof o=="bigint")return`${o}n`;if(typeof o=="symbol")return o.toString();if(typeof o=="function")return"[Function]"}function T(o,e){return o instanceof Error?{name:o.name,message:o.message,stack:o.stack}:e.has(o)?"[Circular]":(e.add(o),o)}function O(o){const e=new WeakSet;return JSON.stringify(o,(t,n)=>{const i=U(n);return i!==void 0?i:typeof n=="object"&&n!==null?T(n,e):n})}function _(o,e){const t=o!==void 0&&Object.keys(o).length>0,n=e!==void 0;if(!t&&!n)return;const i=typeof e=="object"&&e!==null&&!Array.isArray(e)?e:n?{value:e}:{};return{...o,...i}}function S(o,e,t,n,i){const r=e;if(h[o]<r)return;const s={level:o,time:Date.now(),msg:t},d=_(n,i);d!==void 0&&(s.ctx=d),O(s)}function u(o){const e=o!==void 0&&"minLevel"in o?o.minLevel:void 0,t=e===void 0?m:h[e],n=o?.context;return{debug(i,r){S("debug",t,i,n,r)},info(i,r){S("info",t,i,n,r)},warn(i,r){S("warn",t,i,n,r)},error(i,r){S("error",t,i,n,r)},child(i){return u({minLevel:e,context:{...n,...i}})},alwaysOnLog(i){}}}const A=u({context:{module:"sdk-config-store"}}),F="deway-sdk-config",Q=["Understanding intent","Reading web page","Browsing the docs","Enriching context","Validating understanding","Crafting response"];class N{saveConfig(e){if(window?.localStorage)try{const t=JSON.stringify(e);window.localStorage.setItem(F,t)}catch(t){A.warn("Failed to save SDK config to localStorage",t)}}loadConfig(){if(window?.localStorage)try{const e=window.localStorage.getItem(F);return e?JSON.parse(e):null}catch(e){return A.warn("Failed to load SDK config from localStorage",e),null}return null}getExcludedVendors(){return this.loadConfig()?.excludedVendors??[]}getAssistantName(){return this.loadConfig()?.assistantName??"Assistant"}getAiDisclaimer(){return this.loadConfig()?.aiDisclaimer}getThinkingMessages(){return this.loadConfig()?.thinkingMessages??Q}getSupportHandoff(){return this.loadConfig()?.supportHandoff??null}getSupportHandoffButtonText(){return this.getSupportHandoff()?.button_text??"talk to Support"}getFeatureFlags(){return this.loadConfig()?.featureFlags??{}}getFeatureFlag(e){return this.getFeatureFlags()[e]??!1}getPromptSuggestions(){return this.loadConfig()?.promptSuggestions}getWelcomeTitle(){return this.loadConfig()?.welcomeTitle??"How can I help you today?"}getWelcomeSubtitle(){return this.loadConfig()?.welcomeSubtitle??"I'm ready to help you navigate, learn, and get things done."}getEntrypointWidgetAppearanceMode(){return this.loadConfig()?.entrypointWidgetAppearanceMode??"bookmark"}getChatAppearanceMode(){return this.loadConfig()?.chatAppearanceMode??"floating-window"}getTenantTheme(){return this.loadConfig()?.tenantTheme??null}getTenantThemeForMode(e){const t=this.getTenantTheme();return t?e==="dark"?t.dark:t.light:null}getCustomIcons(){return this.loadConfig()?.customIcons??null}getEntrypointWidgetIconInlineSvg(){return this.getCustomIcons()?.entrypoint_widget_icon_inline_svg??void 0}getEmptyChatStateIconInlineSvg(){return this.getCustomIcons()?.empty_chat_state_icon_inline_svg??void 0}getUIAlignment(){return this.loadConfig()?.uiAlignment??null}getUIAlignmentAnchorSelector(){return this.getUIAlignment()?.anchor_selector??null}getUIAlignmentSide(){return this.getUIAlignment()?.side??"right"}getSidePanelHostSqueezeEnabled(){return this.loadConfig()?.sidePanel?.hostSqueeze??!0}}const f=u({context:{module:"sdk-cache-manager"}});class l{static CACHE_KEY="deway-sdk-cache";static DB_NAME="DewaySdk";static DB_VERSION=1;static STORE_NAME="sdk";async cacheSDK(e,t,n,i){try{const d=(await this.openIndexedDB()).transaction([l.STORE_NAME],"readwrite").objectStore(l.STORE_NAME);await new Promise((k,L)=>{const w=d.put({id:"latest",code:e,version:t,checksum:n,signature:i,timestamp:Date.now()});w.onsuccess=()=>k(w.result),w.onerror=()=>L(w.error)}),f.debug("SDK cached in IndexedDB")}catch{try{const s=JSON.stringify({code:e,version:t,checksum:n,signature:i,timestamp:Date.now()});localStorage.setItem(l.CACHE_KEY,s),f.debug("SDK cached in localStorage")}catch(s){f.warn("Unable to cache SDK",s)}}}async getCachedSDK(){try{const n=(await this.openIndexedDB()).transaction([l.STORE_NAME],"readonly").objectStore(l.STORE_NAME),i=await new Promise((r,s)=>{const d=n.get("latest");d.onsuccess=()=>r(d.result||null),d.onerror=()=>s(d.error)});if(i)return f.debug("Found cached SDK in IndexedDB"),i}catch{f.debug("IndexedDB unavailable, trying localStorage")}try{const e=localStorage.getItem(l.CACHE_KEY);if(e)return f.debug("Found cached SDK in localStorage"),JSON.parse(e)}catch(e){f.warn("Failed to read from localStorage",e)}return null}openIndexedDB(){return new Promise((e,t)=>{const n=indexedDB.open(l.DB_NAME,l.DB_VERSION);n.onerror=()=>t(n.error),n.onsuccess=()=>e(n.result),n.onupgradeneeded=i=>{const r=i.target.result;r.objectStoreNames.contains(l.STORE_NAME)||r.createObjectStore(l.STORE_NAME,{keyPath:"id"})}})}}const R=u({context:{module:"sdk-verifier"}});async function P(o){const t=new TextEncoder().encode(o),n=await crypto.subtle.digest("SHA-256",t);return Array.from(new Uint8Array(n)).map(r=>r.toString(16).padStart(2,"0")).join("")}function I(o){const e=atob(o),t=new Uint8Array(e.length);for(let n=0;n<e.length;n++)t[n]=e.charCodeAt(n);return t}function $(o){const e=new Uint8Array(o.length/2);for(let t=0;t<o.length;t+=2)e[t/2]=Number.parseInt(o.substr(t,2),16);return e}async function q(o,e,t){try{const n=I(o),i=$(e),r=I(t),s=await crypto.subtle.importKey("raw",n,{name:"Ed25519"},!1,["verify"]);return await crypto.subtle.verify("Ed25519",s,r,i)}catch(n){return R.error("Ed25519 signature verification failed",n),!1}}async function z(o,e,t,n){if(!e||!t)throw new Error("SDK verification failed: Missing security headers");if(await P(o)!==e)throw new Error("SDK verification failed: Checksum mismatch - content tampered");if(!await q(n,e,t))throw new Error("SDK verification failed: Invalid signature - content tampered")}const y=u({context:{module:"sdk-fetcher"}});class M{cleanApiEndpoint(e){return e.trim().replace(/\/+$/,"")}async fetchSDK(e,t,n){try{y.info("Fetching Deway SDK from backend...");const i=this.cleanApiEndpoint(t),r=await fetch(`${i}/sdk-serve/sdk/v0`,{method:"GET",headers:{Accept:"application/javascript","deway-app-key":e,Origin:window?.location?.origin||""}});return r.ok?this.handleSuccessfulFetch(r,n):(y.warn(`Failed to fetch SDK: HTTP ${r.status}: ${r.statusText}`),null)}catch(i){return y.warn("Failed to fetch SDK from server",i),null}}async handleSuccessfulFetch(e,t){const n=e.headers.get("x-sdk-checksum"),i=e.headers.get("x-sdk-version"),r=e.headers.get("x-sdk-signature"),s=await e.text();if(y.info(`Fetched Deway SDK version ${i}`),!i||!s||!n){const d=Object.fromEntries(e.headers.entries());throw y.error("Failed to get required data from sdk fetch",{headers:d}),new Error("Invalid SDK response: missing version, code, or checksum")}return await z(s,n,r,t),{code:s,version:i,checksum:n,signature:r||""}}}const g=u({context:{module:"command-queue"}});class D{static MAX_QUEUE_SIZE=50;commandQueue=[];queueCommand(e,...t){this.commandQueue.length>=D.MAX_QUEUE_SIZE&&(g.warn(`Command queue full (${D.MAX_QUEUE_SIZE} commands). Discarding oldest command.`),this.commandQueue.shift()),this.commandQueue.push({method:e,args:t}),g.debug(`Queued command: ${e} (queue size: ${this.commandQueue.length})`)}replayQueuedCommands(){if(this.commandQueue.length===0)return;g.info(`Replaying ${this.commandQueue.length} queued commands`);const e=[...this.commandQueue];if(this.commandQueue=[],!this.isSDKAvailable()){g.warn("Deway SDK not available for command replay");return}for(const t of e)this.replayCommand(t)}clearQueue(){this.commandQueue=[]}isSDKAvailable(){return typeof window<"u"&&"Deway"in window&&!!window.Deway}replayCommand(e){try{const t=window.Deway,n=t?.[e.method];typeof n=="function"?n.apply(t,e.args):g.warn(`Method ${e.method} not found on Deway SDK`)}catch(t){g.error(`Failed to replay command ${e.method}`,t)}}}const C=u({context:{module:"remote-config-cache"}});class b{static CACHE_KEY="deway-remote-config-cache";async cacheRemoteConfig(e,t){try{const n={config:e,ttl_seconds:t,timestamp:Date.now()};localStorage.setItem(b.CACHE_KEY,JSON.stringify(n)),C.debug("Remote configuration cached in localStorage")}catch(n){C.warn("Failed to cache remote config",n)}}async getCachedRemoteConfig(){try{const e=localStorage.getItem(b.CACHE_KEY);if(!e)return null;const t=JSON.parse(e);return C.debug("Found cached remote configuration"),t}catch(e){return C.warn("Failed to read cached remote config",e),null}}isCacheValid(e,t){const n=Date.now(),i=e+t*1e3;return n<i}}const E=u({context:{module:"remote-config-fetcher"}});class j{cleanApiEndpoint(e){return e.trim().replace(/\/+$/,"")}async fetchRemoteConfig(e,t){try{E.info("Fetching remote configuration from backend...");const n=this.cleanApiEndpoint(t),i=await fetch(`${n}/sdk-remote-config-serve/`,{method:"GET",headers:{Accept:"application/json","deway-app-key":e,Origin:window?.location?.origin||""}});if(i.ok){const r=await i.json();return E.info("Remote configuration fetched successfully"),r}return E.warn(`Failed to fetch remote config: HTTP ${i.status}: ${i.statusText}`),null}catch(n){return E.warn("Failed to fetch remote config from server",n),null}}}const p=u({context:{module:"script-executor"}});class H{async executeSDK(e){return new Promise(t=>{try{if(!this.isDocumentReady()){p.error("Document is not available for script execution"),t(!1);return}const n=document.createElement("script");n.textContent=e,n.type="text/javascript";let i=!1;const r=s=>{i||(i=!0,this.cleanupScript(n),t(s))};n.onerror=()=>{p.error("Script execution failed"),r(!1)},n.onload=()=>r(!0),document.head.appendChild(n),setTimeout(()=>{!i&&this.verifySDKLoaded()?r(!0):i||(p.error("SDK execution timeout - Deway object not found"),r(!1))},100)}catch(n){p.error("Failed to execute SDK script",n),t(!1)}})}isDocumentReady(){return typeof document<"u"&&document.head!=null}verifySDKLoaded(){return typeof window<"u"&&"Deway"in window&&!!window.Deway}cleanupScript(e){try{e.parentNode&&e.parentNode.removeChild(e)}catch(t){p.debug("Failed to cleanup script element",t)}}}const v=u({context:{module:"config-validator"}});class V{validateConfig(e){return e?!e.appKey||e.appKey.trim().length===0?(v.error("Config.appKey is required and must be a non-empty string"),!1):e.apiEndpoint!==void 0&&!this.isValidUrl(e.apiEndpoint)?(v.error("Config.apiEndpoint must be a valid URL"),!1):e.publicKey!==void 0&&e.publicKey.trim().length===0?(v.error("Config.publicKey must be a non-empty string if provided"),!1):!0:(v.error("Config is required"),!1)}isValidUrl(e){try{return new URL(e),!0}catch{return!1}}}const a=u({context:{module:"sdk-loader"}}),K={apiEndpoint:"https://service.deway.app",publicKey:"9d3dBUvqyUQ7egd5j5uORdHSqZ7VFWOu+ud/SWt9WUY="};class B{isLoaded=!1;isLoading=!1;cacheManager;scriptExecutor;commandQueue;sdkFetcher;configValidator;remoteConfigFetcher;remoteConfigCache;sdkConfigStore;constructor(){this.cacheManager=new l,this.scriptExecutor=new H,this.commandQueue=new D,this.sdkFetcher=new M,this.configValidator=new V,this.sdkConfigStore=new N,this.remoteConfigFetcher=new j,this.remoteConfigCache=new b}init(e){this.performInit(e).catch(t=>{a.error("Failed to initialize Deway SDK",t)})}async performInit(e){try{if(!this.canInitialize())return;const t=this.isInitializationPayload(e),n=t?e.localConfig:e;if(!this.configValidator.validateConfig(n)){a.error("Invalid config provided to Deway SDK");return}this.isLoading=!0;const i=n.apiEndpoint||K.apiEndpoint,r=n.publicKey||K.publicKey,[s,d]=await Promise.all([this.fetchOrLoadSDK(n.appKey,i,r),this.fetchRemoteConfigWithCache(n,i)]);if(!s)return;const k=t?e:this.createInitializationPayload(d,n);if(!await this.scriptExecutor.executeSDK(s.code)){a.error("SDK execution failed");return}if(!this.initializeSDK(k))return;this.commandQueue.replayQueuedCommands(),this.isLoaded=!0}finally{this.isLoading=!1}}isInitializationPayload(e){return"localConfig"in e&&"remoteConfig"in e&&"defaults"in e}canInitialize(){return this.isLoaded?(a.warn("Deway SDK already initialized"),!1):this.isLoading?(a.warn("Deway SDK initialization already in progress"),!1):!0}async fetchRemoteConfigWithCache(e,t){this.sdkConfigStore.saveConfig(e);const n=await this.remoteConfigFetcher.fetchRemoteConfig(e.appKey,t);if(n)return await this.remoteConfigCache.cacheRemoteConfig(n.config,n.ttl_seconds),n;a.info("Using cached remote config as fallback");const i=await this.remoteConfigCache.getCachedRemoteConfig();return i?{config:i.config,ttl_seconds:i.ttl_seconds}:(a.warn("No remote config available (fetch failed and no cache)"),null)}createInitializationPayload(e,t){return{localConfig:t,remoteConfig:e?.config??null,defaults:K}}async fetchOrLoadSDK(e,t,n){const i=await this.sdkFetcher.fetchSDK(e,t,n);return i?(await this.cacheManager.cacheSDK(i.code,i.version,i.checksum,i.signature),i):(a.warn("Failed to fetch SDK from server, attempting cache fallback"),this.loadFromCache())}async loadFromCache(){const e=await this.cacheManager.getCachedSDK();return e?(a.info(`Loading cached Deway SDK version ${e.version}`),{code:e.code,version:e.version}):(a.error("SDK unavailable: Network error and no cached version found"),null)}initializeSDK(e){if(!this.isSDKAvailable())return a.error("SDK execution failed: Deway object not found after loading"),!1;try{return window.Deway?.init(e),a.info("Deway SDK initialized successfully with payload"),!0}catch(t){return a.error("Failed to initialize SDK with payload",t),!1}}identify(e){try{this.isLoaded&&this.isSDKAvailable()?window.Deway?.identify(e):this.commandQueue.queueCommand("identify",e)}catch(t){a.error("Failed to identify user",t)}}reportEvent(e,t){try{this.isLoaded&&this.isSDKAvailable()?window.Deway?.reportEvent(e,t):this.commandQueue.queueCommand("reportEvent",e,t)}catch(n){a.error("Failed to report event",n)}}setUserProfile(e){try{this.isLoaded&&this.isSDKAvailable()?window.Deway?.setUserProfile(e):this.commandQueue.queueCommand("setUserProfile",e)}catch(t){a.error("Failed to set user profile",t)}}show(e){try{this.isLoaded&&this.isSDKAvailable()?window.Deway?.show(e):this.commandQueue.queueCommand("show",e)}catch(t){a.error("Failed to show bookmark",t)}}hide(){try{this.isLoaded&&this.isSDKAvailable()?window.Deway?.hide():this.commandQueue.queueCommand("hide")}catch(e){a.error("Failed to hide bookmark",e)}}openChat(){try{this.isLoaded&&this.isSDKAvailable()?window.Deway?.openChat():this.commandQueue.queueCommand("openChat")}catch(e){a.error("Failed to open chat",e)}}resetUserLocally(){try{this.isLoaded&&this.isSDKAvailable()?window.Deway?.resetUserLocally():this.commandQueue.queueCommand("resetUserLocally")}catch(e){a.error("Failed to reset user locally",e)}}isVisible(){try{return this.isLoaded&&this.isSDKAvailable()?window.Deway?.isVisible()??!1:!1}catch(e){return a.error("Failed to check bookmark visibility",e),!1}}isInitialized(){try{return this.isLoaded&&this.isSDKAvailable()?window.Deway?.isInitialized()??!1:!1}catch(e){return a.error("Failed to check initialization status",e),!1}}getPanelState(){try{if(this.isLoaded&&this.isSDKAvailable()){const e=window.Deway?.getPanelState;if(typeof e=="function")return e()}return{width:0,side:"right",isOpen:!1}}catch(e){return a.error("Failed to read panel state",e),{width:0,side:"right",isOpen:!1}}}registerSupportCallback(e){try{this.isLoaded&&this.isSDKAvailable()?window.Deway?.registerSupportCallback(e):this.commandQueue.queueCommand("registerSupportCallback",e)}catch(t){a.error("Failed to register support callback",t)}}unregisterSupportCallback(){try{this.isLoaded&&this.isSDKAvailable()?window.Deway?.unregisterSupportCallback():this.commandQueue.queueCommand("unregisterSupportCallback")}catch(e){a.error("Failed to unregister support callback",e)}}destroy(){try{this.isLoaded&&this.isSDKAvailable()?window.Deway?.destroy():this.commandQueue.queueCommand("destroy"),this.commandQueue.clearQueue()}catch(e){a.error("Failed to destroy SDK",e)}}isSDKAvailable(){return typeof window<"u"&&"Deway"in window&&!!window.Deway}}const c=new B,x={init:o=>c.init(o),identify:o=>c.identify(o),reportEvent:(o,e)=>c.reportEvent(o,e),setUserProfile:o=>c.setUserProfile(o),show:o=>c.show(o),hide:()=>c.hide(),openChat:()=>c.openChat(),resetUserLocally:()=>c.resetUserLocally(),registerSupportCallback:o=>c.registerSupportCallback(o),unregisterSupportCallback:()=>c.unregisterSupportCallback(),isVisible:()=>c.isVisible(),isInitialized:()=>c.isInitialized(),destroy:()=>c.destroy(),getPanelState:()=>c.getPanelState()};return typeof window<"u"&&(window.Deway=x),x}));
|