@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 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 _(o, e) {
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
- }, c = _(n, i);
36
- c !== void 0 && (s.ctx = c), T(s);
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", Q = ["Understanding intent", "Reading web page", "Browsing the docs", "Enriching context", "Validating understanding", "Crafting response"];
64
- class N {
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 ?? Q;
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 c = (await this.openIndexedDB()).transaction([l.STORE_NAME], "readwrite").objectStore(l.STORE_NAME);
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 = c.put({
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 c = n.get("latest");
201
- c.onsuccess = () => r(c.result || null), c.onerror = () => s(c.error);
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 O = u({ context: { module: "sdk-verifier" } });
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 $(o) {
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 q(o, e, t) {
254
+ async function $(o, e, t) {
245
255
  try {
246
- const n = F(o), i = $(e), r = F(t), s = await crypto.subtle.importKey("raw", n, { name: "Ed25519" }, !1, ["verify"]);
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 O.error("Ed25519 signature verification failed", n), !1;
259
+ return N.error("Ed25519 signature verification failed", n), !1;
250
260
  }
251
261
  }
252
- async function z(o, e, t, n) {
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 q(n, e, t))
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 P {
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 c = Object.fromEntries(e.headers.entries());
285
- throw m.error("Failed to get required data from sdk fetch", { headers: c }), new Error("Invalid SDK response: missing version, code, or checksum");
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 z(s, n, r, t), { code: s, version: i, checksum: n, signature: r || "" };
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 V {
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 j {
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 H {
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 V(), this.commandQueue = new C(), this.sdkFetcher = new P(), this.configValidator = new j(), this.sdkConfigStore = new N(), this.remoteConfigFetcher = new M(), this.remoteConfigCache = new b();
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, c] = await Promise.all([this.fetchOrLoadSDK(n.appKey, i, r), this.fetchRemoteConfigWithCache(n, i)]);
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(c, n);
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 d = new H(), B = {
650
- init: (o) => d.init(o),
651
- identify: (o) => d.identify(o),
652
- reportEvent: (o, e) => d.reportEvent(o, e),
653
- setUserProfile: (o) => d.setUserProfile(o),
654
- show: (o) => d.show(o),
655
- hide: () => d.hide(),
656
- openChat: () => d.openChat(),
657
- resetUserLocally: () => d.resetUserLocally(),
658
- registerSupportCallback: (o) => d.registerSupportCallback(o),
659
- unregisterSupportCallback: () => d.unregisterSupportCallback(),
660
- isVisible: () => d.isVisible(),
661
- isInitialized: () => d.isInitialized(),
662
- destroy: () => d.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 {
@@ -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}));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@deway-ai/web-sdk",
3
- "version": "0.81.0",
3
+ "version": "0.83.0",
4
4
  "type": "module",
5
5
  "description": "Deway's Web SDK",
6
6
  "main": "dist/loader.umd.js",