@deway-ai/web-sdk 0.51.0 → 0.53.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
@@ -2,11 +2,13 @@
2
2
 
3
3
  [![Accessibility](https://img.shields.io/badge/accessibility-WCAG%202.1%20AA-green)](./documentation/accessibility/compliance.md)
4
4
 
5
- A lightweight TypeScript SDK for adding an AI-powered user engagement engine by Deway to your web app.
5
+ **Software should adapt to users not the other way around.**
6
+
7
+ Deway is your AI assistant that learns your product, embedding proactive guidance directly into your web app. Scale expert knowledge across your entire user base with real-time, intelligent assistance that continuously improves with every interaction.
6
8
 
7
9
  ## Quick Install with AI Assistant
8
10
 
9
- Copy and paste this prompt to your AI coding assistant (Claude, Copilot, etc.) to get Deway set up with best practices:
11
+ Let AI help AI. Copy this prompt to your coding assistant (Claude, Copilot, etc.) to get Deway integrated with best practices for your specific framework:
10
12
 
11
13
  ```text
12
14
  Install and integrate the Deway Web SDK (@deway-ai/web-sdk) into my project.
@@ -38,6 +40,8 @@ FIRST analyze my project structure and detect the framework and package manager.
38
40
 
39
41
  ## Installation
40
42
 
43
+ Add Deway to your project with your preferred package manager:
44
+
41
45
  ```bash
42
46
  npm install @deway-ai/web-sdk
43
47
  # or
@@ -58,11 +62,11 @@ Deway.init({
58
62
  appKey: 'your-app-key'
59
63
  });
60
64
 
61
- // Identify a user
65
+ // Identify users for personalized experiences
62
66
  Deway.identify('user-123');
63
67
  ```
64
68
 
65
- **Note:** While methods can be called immediately (they're queued until initialization completes), best practice is to call `Deway.init()` early in your app lifecycle.
69
+ **Note:** Methods can be called immediately and are queued until initialization completes. For best results, call `Deway.init()` early in your app lifecycle to start learning user patterns from the first interaction.
66
70
 
67
71
  ### HTML/JavaScript Integration
68
72
 
@@ -80,27 +84,29 @@ Deway.identify('user-123');
80
84
 
81
85
  ## Configuration
82
86
 
87
+ Deway keeps configuration simple—just provide your app key and we handle the rest:
88
+
83
89
  ```typescript
84
90
  Deway.init({
85
91
  appKey: string, // Required: Your Deway app key
86
92
  });
87
93
  ```
88
94
 
89
- **Note:** Most configuration options (themes, feature flags, prompts, etc.) are managed remotely and automatically fetched during initialization. Only the fields above are configurable by SDK callers.
95
+ **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.
90
96
 
91
97
  ## API Reference
92
98
 
93
99
  ### `Deway.init(config)`
94
100
 
95
- Initialize the SDK with configuration options. Should be called early in your app lifecycle (commands are queued until initialization completes).
101
+ Start learning your product and embedding intelligent guidance into your app. Call this early in your app lifecycle to begin building user-specific insights (commands are queued until initialization completes).
96
102
 
97
103
  ### `Deway.identify(userId)`
98
104
 
99
- Associate a user ID with the current session for personalized experiences.
105
+ Connect a user ID to enable personalized, context-aware assistance that adapts to their unique journey.
100
106
 
101
107
  ### `Deway.reportEvent(name, params)`
102
108
 
103
- Report a custom event with the given name and parameters.
109
+ Track custom events to help Deway understand your product's unique workflows and provide smarter, context-aware guidance.
104
110
 
105
111
  **Parameters:**
106
112
 
@@ -120,7 +126,7 @@ Deway.reportEvent('Product Purchased', {
120
126
 
121
127
  ### `Deway.setUserProfile(userProfile)`
122
128
 
123
- Set or update the user profile for the currently identified user.
129
+ Enrich user profiles to enable deeper personalization and more intelligent assistance tailored to each user's context.
124
130
 
125
131
  **Parameters:**
126
132
 
@@ -147,7 +153,7 @@ Deway.setUserProfile({
147
153
 
148
154
  ### `Deway.show(config?)`
149
155
 
150
- Show the AI chat interface. Optional configuration:
156
+ Display the AI assistant interface that adapts to your users' needs. Choose the appearance that fits your product best.
151
157
 
152
158
  ```typescript
153
159
  interface EntrypointWidgetConfig {
@@ -156,12 +162,31 @@ interface EntrypointWidgetConfig {
156
162
  ```
157
163
 
158
164
  **Appearance Modes:**
159
- - `"bookmark"`: Edge-pinned vertical tab (default)
160
- - `"bubble"`: Floating ellipsoid pill at bottom-right corner
165
+ - `"bookmark"`: Edge-pinned vertical tab for persistent, non-intrusive access (default)
166
+ - `"bubble"`: Floating ellipsoid pill at bottom-right for prominent visibility
161
167
 
162
168
  ### `Deway.hide()`
163
169
 
164
- Hide the AI chat interface.
170
+ Temporarily hide the AI assistant interface while keeping the intelligent learning active in the background.
171
+
172
+ ### `Deway.openChat()`
173
+
174
+ Programmatically open the chat interface to guide users exactly when they need assistance. Perfect for contextual help triggers.
175
+
176
+ **Example:**
177
+
178
+ ```typescript
179
+ // Open chat via a custom button
180
+ document.getElementById('my-chat-button').addEventListener('click', () => {
181
+ Deway.openChat();
182
+ });
183
+ ```
184
+
185
+ **Notes:**
186
+
187
+ - The SDK must be initialized before calling this method
188
+ - Calling before initialization will log a warning
189
+ - This hides the entrypoint widget (same as clicking it)
165
190
 
166
191
  ### `Deway.isVisible()`
167
192
 
@@ -177,6 +202,8 @@ Clean up SDK resources and stop all tracking.
177
202
 
178
203
  ## Framework Examples
179
204
 
205
+ Deway adapts seamlessly to your framework of choice. Here's how to integrate intelligent user assistance into popular frameworks:
206
+
180
207
  ### React
181
208
 
182
209
  ```tsx
@@ -189,7 +216,7 @@ function App() {
189
216
  appKey: 'your-app-key'
190
217
  });
191
218
 
192
- // Identify user when available
219
+ // Enable personalized assistance when user is known
193
220
  if (user?.id) {
194
221
  Deway.identify(user.id);
195
222
  }
@@ -234,56 +261,59 @@ export class AppComponent implements OnInit {
234
261
  }
235
262
  ```
236
263
 
237
- ## Features
264
+ ## What You Get
238
265
 
239
- - **AI-powered user engagement and assistance**: Interactive chat interface for user support
240
- - **Automatic user behavior analysis**: Intelligent tracking and understanding of user interactions
241
- - **Remote configuration management**: Feature flags, themes, and prompts managed remotely
242
- - **Dual appearance modes**: Edge-pinned bookmark or floating bubble display
243
- - **Framework-agnostic integration**: Works with React, Vue, Angular, and vanilla JavaScript
244
- - **Full TypeScript support**: Complete type definitions included
245
- - **Lightweight loader**: ~5KB loader shell with dynamic backend loading
246
- - **Offline resilience**: Backend bundle cached locally for faster loads
266
+ - **Proactive AI Guidance**: Intelligent assistance that learns your product and adapts to each user's journey
267
+ - **Real-time Issue Prevention**: Detect and resolve problems before users encounter them
268
+ - **Continuous Learning**: Self-improving knowledge graph that gets smarter with every interaction
269
+ - **Scaled Expert Knowledge**: Give every user the experience of having a dedicated specialist
270
+ - **Seamless Integration**: Works with React, Vue, Angular, and vanilla JavaScript
271
+ - **Zero Configuration Overhead**: Feature flags, themes, and AI prompts managed remotely
272
+ - **Performance First**: ~5KB loader with dynamic backend loading and offline resilience
273
+ - **Full TypeScript Support**: Complete type definitions for a superior developer experience
247
274
 
248
- ## Edge Cases & Internal Behavior
275
+ ## How Deway Adapts for You
249
276
 
250
- ### Error Handling
277
+ ### Graceful Error Handling
251
278
 
252
- The SDK handles all errors internally. Callers don't need try-catch blocks around SDK methods. Failed operations are logged to the console and retried automatically when appropriate.
279
+ The SDK handles all errors internally with intelligent recovery. No try-catch blocks needed—failed operations are logged and retried automatically so your app stays resilient.
253
280
 
254
- ### State Persistence
281
+ ### Persistent User Context
255
282
 
256
- User identification and settings persist across page reloads via localStorage. Once a user is identified, they remain identified until `Deway.destroy()` is called or localStorage is cleared.
283
+ User identification and preferences persist across sessions via localStorage. Once identified, users receive continuous personalized assistance until you explicitly call `Deway.destroy()` or clear storage.
257
284
 
258
- ### Multiple init() Calls
285
+ ### Idempotent Initialization
259
286
 
260
- Calling `Deway.init()` multiple times is safe. Subsequent calls after the first are ignored.
287
+ Multiple `Deway.init()` calls are safe and ignored after the first. The SDK adapts to your initialization patterns without breaking.
261
288
 
262
- ### Automatic Retries
289
+ ### Smart Retry Logic
263
290
 
264
- Failed API calls and uploads are automatically retried with exponential backoff. No manual intervention is required.
291
+ Failed network operations automatically retry with exponential backoff. The SDK handles connectivity issues gracefully—no manual intervention required.
265
292
 
266
- ### Command Queue
293
+ ### Intelligent Command Queuing
267
294
 
268
- All SDK methods can be called immediately, even before initialization completes. The loader queues commands and executes them automatically once the backend bundle loads and `Deway.init()` completes.
295
+ Call SDK methods immediately without waiting for initialization. Commands queue automatically and execute once the backend loads—your code stays simple while Deway handles the complexity.
269
296
 
270
297
  ## Troubleshooting
271
298
 
272
299
  ### Interface doesn't appear
273
300
 
274
- - Verify `Deway.init()` was called with valid `appKey`
275
- - Check if auto-show is enabled in your remote configuration, or manually call `Deway.show()`
276
- - Check browser console for initialization errors
277
- - Verify the SDK completed initialization with `Deway.isInitialized()`
301
+ Deway adapts its visibility to your configuration. Check these common solutions:
302
+ - Verify `Deway.init()` was called with a valid `appKey`
303
+ - Enable auto-show in your remote configuration, or call `Deway.show()` manually
304
+ - Confirm initialization completed using `Deway.isInitialized()`
305
+ - Check browser console for initialization errors—the SDK logs helpful guidance
278
306
 
279
307
  ### User identification not working
280
308
 
281
- - Ensure `Deway.init()` is called before `Deway.identify()`
282
- - User ID must be a non-empty string
283
- - Check browser console for error logs
309
+ For personalized experiences to activate:
310
+ - Call `Deway.init()` before `Deway.identify()`—initialization must complete first
311
+ - Ensure user ID is a non-empty string
312
+ - Check browser console for diagnostic logs—Deway provides clear error messages
284
313
 
285
314
  ### Commands not executing
286
315
 
287
- - The SDK queues commands called before initialization
288
- - Commands execute automatically once `Deway.init()` completes
289
- - Check browser console for errors during initialization
316
+ Deway's intelligent command queue handles this automatically:
317
+ - Commands called before initialization are queued and execute once ready
318
+ - Check `Deway.isInitialized()` to confirm the SDK is ready
319
+ - Review browser console for any initialization errors—Deway adapts and retries when possible
package/dist/loader.es.js CHANGED
@@ -95,7 +95,7 @@ class s {
95
95
  async cacheSDK(e, t, n, i) {
96
96
  try {
97
97
  const d = (await this.openIndexedDB()).transaction([s.STORE_NAME], "readwrite").objectStore(s.STORE_NAME);
98
- await new Promise((f, m) => {
98
+ await new Promise((h, m) => {
99
99
  const l = d.put({
100
100
  id: "latest",
101
101
  code: e,
@@ -104,7 +104,7 @@ class s {
104
104
  signature: i,
105
105
  timestamp: Date.now()
106
106
  });
107
- l.onsuccess = () => f(l.result), l.onerror = () => m(l.error);
107
+ l.onsuccess = () => h(l.result), l.onerror = () => m(l.error);
108
108
  });
109
109
  } catch {
110
110
  try {
@@ -358,7 +358,7 @@ class K {
358
358
  }
359
359
  }
360
360
  }
361
- const h = {
361
+ const f = {
362
362
  apiEndpoint: "https://service.deway.app",
363
363
  publicKey: "9d3dBUvqyUQ7egd5j5uORdHSqZ7VFWOu+ud/SWt9WUY="
364
364
  };
@@ -388,11 +388,11 @@ class k {
388
388
  if (!this.configValidator.validateConfig(n))
389
389
  return;
390
390
  this.isLoading = !0;
391
- const i = n.apiEndpoint || h.apiEndpoint, r = n.publicKey || h.publicKey, [a, d] = await Promise.all([this.fetchOrLoadSDK(n.appKey, i, r), this.fetchRemoteConfigWithCache(n, i)]);
391
+ const i = n.apiEndpoint || f.apiEndpoint, r = n.publicKey || f.publicKey, [a, d] = await Promise.all([this.fetchOrLoadSDK(n.appKey, i, r), this.fetchRemoteConfigWithCache(n, i)]);
392
392
  if (!a)
393
393
  return;
394
- const f = t ? e : this.createInitializationPayload(d, n);
395
- if (!await this.scriptExecutor.executeSDK(a.code) || !this.initializeSDK(f))
394
+ const h = t ? e : this.createInitializationPayload(d, n);
395
+ if (!await this.scriptExecutor.executeSDK(a.code) || !this.initializeSDK(h))
396
396
  return;
397
397
  this.commandQueue.replayQueuedCommands(), this.isLoaded = !0;
398
398
  } finally {
@@ -429,7 +429,7 @@ class k {
429
429
  return {
430
430
  localConfig: t,
431
431
  remoteConfig: e?.config ?? null,
432
- defaults: h
432
+ defaults: f
433
433
  };
434
434
  }
435
435
  async fetchOrLoadSDK(e, t, n) {
@@ -479,6 +479,12 @@ class k {
479
479
  } catch {
480
480
  }
481
481
  }
482
+ openChat() {
483
+ try {
484
+ this.isLoaded && this.isSDKAvailable() ? window.Deway?.openChat() : this.commandQueue.queueCommand("openChat");
485
+ } catch {
486
+ }
487
+ }
482
488
  isVisible() {
483
489
  try {
484
490
  return this.isLoaded && this.isSDKAvailable() ? window.Deway?.isVisible() ?? !1 : !1;
@@ -510,6 +516,7 @@ const c = new k(), _ = {
510
516
  setUserProfile: (o) => c.setUserProfile(o),
511
517
  show: (o) => c.show(o),
512
518
  hide: () => c.hide(),
519
+ openChat: () => c.openChat(),
513
520
  isVisible: () => c.isVisible(),
514
521
  isInitialized: () => c.isInitialized(),
515
522
  destroy: () => c.destroy()
@@ -1 +1 @@
1
- (function(u,l){typeof exports=="object"&&typeof module<"u"?module.exports=l():typeof define=="function"&&define.amd?define(l):(u=typeof globalThis<"u"?globalThis:u||self,u.Deway=l())})(this,(function(){"use strict";const u="deway-sdk-config",l=["Understanding intent","Reading web page","Browsing the docs","Enriching context","Validating understanding","Crafting response"];class C{saveConfig(e){if(window?.localStorage)try{const t=JSON.stringify(e);window.localStorage.setItem(u,t)}catch{}}loadConfig(){if(window?.localStorage)try{const e=window.localStorage.getItem(u);return e?JSON.parse(e):null}catch{return null}return null}getExcludedVendors(){return this.loadConfig()?.excludedVendors??[]}getAssistantName(){return this.loadConfig()?.assistantName??"Assistant"}getAiDisclaimer(){return this.loadConfig()?.aiDisclaimer}getThinkingMessages(){return this.loadConfig()?.thinkingMessages??l}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"}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}getEntrypointWidgetIconSize(){return this.loadConfig()?.entrypointWidgetIconSize??18}}class a{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([a.STORE_NAME],"readwrite").objectStore(a.STORE_NAME);await new Promise((y,S)=>{const f=d.put({id:"latest",code:e,version:t,checksum:n,signature:i,timestamp:Date.now()});f.onsuccess=()=>y(f.result),f.onerror=()=>S(f.error)})}catch{try{const s=JSON.stringify({code:e,version:t,checksum:n,signature:i,timestamp:Date.now()});localStorage.setItem(a.CACHE_KEY,s)}catch{}}}async getCachedSDK(){try{const n=(await this.openIndexedDB()).transaction([a.STORE_NAME],"readonly").objectStore(a.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 i}catch{}try{const e=localStorage.getItem(a.CACHE_KEY);if(e)return JSON.parse(e)}catch{}return null}openIndexedDB(){return new Promise((e,t)=>{const n=indexedDB.open(a.DB_NAME,a.DB_VERSION);n.onerror=()=>t(n.error),n.onsuccess=()=>e(n.result),n.onupgradeneeded=i=>{const r=i.target.result;r.objectStoreNames.contains(a.STORE_NAME)||r.createObjectStore(a.STORE_NAME,{keyPath:"id"})}})}}async function E(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 w(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 D(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 A(o,e,t){try{const n=w(o),i=D(e),r=w(t),s=await crypto.subtle.importKey("raw",n,{name:"Ed25519"},!1,["verify"]);return await crypto.subtle.verify("Ed25519",s,r,i)}catch{return!1}}async function v(o,e,t,n){if(!e||!t)throw new Error("SDK verification failed: Missing security headers");if(await E(o)!==e)throw new Error("SDK verification failed: Checksum mismatch - content tampered");if(!await A(n,e,t))throw new Error("SDK verification failed: Invalid signature - content tampered")}class b{cleanApiEndpoint(e){return e.trim().replace(/\/+$/,"")}async fetchSDK(e,t,n){try{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):null}catch{return 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(!i||!s||!n)throw Object.fromEntries(e.headers.entries()),new Error("Invalid SDK response: missing version, code, or checksum");return await v(s,n,r,t),{code:s,version:i,checksum:n,signature:r||""}}}class g{static MAX_QUEUE_SIZE=50;commandQueue=[];queueCommand(e,...t){this.commandQueue.length>=g.MAX_QUEUE_SIZE&&this.commandQueue.shift(),this.commandQueue.push({method:e,args:t})}replayQueuedCommands(){if(this.commandQueue.length===0)return;const e=[...this.commandQueue];if(this.commandQueue=[],!!this.isSDKAvailable())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)}catch{}}}class h{static CACHE_KEY="deway-remote-config-cache";async cacheRemoteConfig(e,t){try{const n={config:e,ttl_seconds:t,timestamp:Date.now()};localStorage.setItem(h.CACHE_KEY,JSON.stringify(n))}catch{}}async getCachedRemoteConfig(){try{const e=localStorage.getItem(h.CACHE_KEY);return e?JSON.parse(e):null}catch{return null}}isCacheValid(e,t){const n=Date.now(),i=e+t*1e3;return n<i}}class I{cleanApiEndpoint(e){return e.trim().replace(/\/+$/,"")}async fetchRemoteConfig(e,t){try{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||""}});return i.ok?await i.json():null}catch{return null}}}class K{async executeSDK(e){return new Promise(t=>{try{if(!this.isDocumentReady()){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=()=>{r(!1)},n.onload=()=>r(!0),document.head.appendChild(n),setTimeout(()=>{!i&&this.verifySDKLoaded()?r(!0):i||r(!1)},100)}catch{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{}}}class k{validateConfig(e){return!(!e||!e.appKey||e.appKey.trim().length===0||e.apiEndpoint!==void 0&&!this.isValidUrl(e.apiEndpoint)||e.publicKey!==void 0&&e.publicKey.trim().length===0)}isValidUrl(e){try{return new URL(e),!0}catch{return!1}}}const m={apiEndpoint:"https://service.deway.app",publicKey:"9d3dBUvqyUQ7egd5j5uORdHSqZ7VFWOu+ud/SWt9WUY="};class _{isLoaded=!1;isLoading=!1;cacheManager;scriptExecutor;commandQueue;sdkFetcher;configValidator;remoteConfigFetcher;remoteConfigCache;sdkConfigStore;constructor(){this.cacheManager=new a,this.scriptExecutor=new K,this.commandQueue=new g,this.sdkFetcher=new b,this.configValidator=new k,this.sdkConfigStore=new C,this.remoteConfigFetcher=new I,this.remoteConfigCache=new h}init(e){this.performInit(e).catch(t=>{})}async performInit(e){try{if(!this.canInitialize())return;const t=this.isInitializationPayload(e),n=t?e.localConfig:e;if(!this.configValidator.validateConfig(n))return;this.isLoading=!0;const i=n.apiEndpoint||m.apiEndpoint,r=n.publicKey||m.publicKey,[s,d]=await Promise.all([this.fetchOrLoadSDK(n.appKey,i,r),this.fetchRemoteConfigWithCache(n,i)]);if(!s)return;const y=t?e:this.createInitializationPayload(d,n);if(!await this.scriptExecutor.executeSDK(s.code)||!this.initializeSDK(y))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||this.isLoading)}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;const i=await this.remoteConfigCache.getCachedRemoteConfig();return i?{config:i.config,ttl_seconds:i.ttl_seconds}:null}createInitializationPayload(e,t){return{localConfig:t,remoteConfig:e?.config??null,defaults:m}}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):this.loadFromCache()}async loadFromCache(){const e=await this.cacheManager.getCachedSDK();return e?{code:e.code,version:e.version}:null}initializeSDK(e){if(!this.isSDKAvailable())return!1;try{return window.Deway?.init(e),!0}catch{return!1}}identify(e){try{this.isLoaded&&this.isSDKAvailable()?window.Deway?.identify(e):this.commandQueue.queueCommand("identify",e)}catch{}}reportEvent(e,t){try{this.isLoaded&&this.isSDKAvailable()?window.Deway?.reportEvent(e,t):this.commandQueue.queueCommand("reportEvent",e,t)}catch{}}setUserProfile(e){try{this.isLoaded&&this.isSDKAvailable()?window.Deway?.setUserProfile(e):this.commandQueue.queueCommand("setUserProfile",e)}catch{}}show(e){try{this.isLoaded&&this.isSDKAvailable()?window.Deway?.show(e):this.commandQueue.queueCommand("show",e)}catch{}}hide(){try{this.isLoaded&&this.isSDKAvailable()?window.Deway?.hide():this.commandQueue.queueCommand("hide")}catch{}}isVisible(){try{return this.isLoaded&&this.isSDKAvailable()?window.Deway?.isVisible()??!1:!1}catch{return!1}}isInitialized(){try{return this.isLoaded&&this.isSDKAvailable()?window.Deway?.isInitialized()??!1:!1}catch{return!1}}destroy(){try{this.isLoaded&&this.isSDKAvailable()?window.Deway?.destroy():this.commandQueue.queueCommand("destroy"),this.commandQueue.clearQueue()}catch{}}isSDKAvailable(){return typeof window<"u"&&"Deway"in window&&!!window.Deway}}const c=new _,p={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(),isVisible:()=>c.isVisible(),isInitialized:()=>c.isInitialized(),destroy:()=>c.destroy()};return typeof window<"u"&&(window.Deway=p),p}));
1
+ (function(u,l){typeof exports=="object"&&typeof module<"u"?module.exports=l():typeof define=="function"&&define.amd?define(l):(u=typeof globalThis<"u"?globalThis:u||self,u.Deway=l())})(this,(function(){"use strict";const u="deway-sdk-config",l=["Understanding intent","Reading web page","Browsing the docs","Enriching context","Validating understanding","Crafting response"];class C{saveConfig(e){if(window?.localStorage)try{const t=JSON.stringify(e);window.localStorage.setItem(u,t)}catch{}}loadConfig(){if(window?.localStorage)try{const e=window.localStorage.getItem(u);return e?JSON.parse(e):null}catch{return null}return null}getExcludedVendors(){return this.loadConfig()?.excludedVendors??[]}getAssistantName(){return this.loadConfig()?.assistantName??"Assistant"}getAiDisclaimer(){return this.loadConfig()?.aiDisclaimer}getThinkingMessages(){return this.loadConfig()?.thinkingMessages??l}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"}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}getEntrypointWidgetIconSize(){return this.loadConfig()?.entrypointWidgetIconSize??18}}class a{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([a.STORE_NAME],"readwrite").objectStore(a.STORE_NAME);await new Promise((y,S)=>{const f=d.put({id:"latest",code:e,version:t,checksum:n,signature:i,timestamp:Date.now()});f.onsuccess=()=>y(f.result),f.onerror=()=>S(f.error)})}catch{try{const s=JSON.stringify({code:e,version:t,checksum:n,signature:i,timestamp:Date.now()});localStorage.setItem(a.CACHE_KEY,s)}catch{}}}async getCachedSDK(){try{const n=(await this.openIndexedDB()).transaction([a.STORE_NAME],"readonly").objectStore(a.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 i}catch{}try{const e=localStorage.getItem(a.CACHE_KEY);if(e)return JSON.parse(e)}catch{}return null}openIndexedDB(){return new Promise((e,t)=>{const n=indexedDB.open(a.DB_NAME,a.DB_VERSION);n.onerror=()=>t(n.error),n.onsuccess=()=>e(n.result),n.onupgradeneeded=i=>{const r=i.target.result;r.objectStoreNames.contains(a.STORE_NAME)||r.createObjectStore(a.STORE_NAME,{keyPath:"id"})}})}}async function E(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 w(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 D(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 A(o,e,t){try{const n=w(o),i=D(e),r=w(t),s=await crypto.subtle.importKey("raw",n,{name:"Ed25519"},!1,["verify"]);return await crypto.subtle.verify("Ed25519",s,r,i)}catch{return!1}}async function v(o,e,t,n){if(!e||!t)throw new Error("SDK verification failed: Missing security headers");if(await E(o)!==e)throw new Error("SDK verification failed: Checksum mismatch - content tampered");if(!await A(n,e,t))throw new Error("SDK verification failed: Invalid signature - content tampered")}class b{cleanApiEndpoint(e){return e.trim().replace(/\/+$/,"")}async fetchSDK(e,t,n){try{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):null}catch{return 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(!i||!s||!n)throw Object.fromEntries(e.headers.entries()),new Error("Invalid SDK response: missing version, code, or checksum");return await v(s,n,r,t),{code:s,version:i,checksum:n,signature:r||""}}}class g{static MAX_QUEUE_SIZE=50;commandQueue=[];queueCommand(e,...t){this.commandQueue.length>=g.MAX_QUEUE_SIZE&&this.commandQueue.shift(),this.commandQueue.push({method:e,args:t})}replayQueuedCommands(){if(this.commandQueue.length===0)return;const e=[...this.commandQueue];if(this.commandQueue=[],!!this.isSDKAvailable())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)}catch{}}}class h{static CACHE_KEY="deway-remote-config-cache";async cacheRemoteConfig(e,t){try{const n={config:e,ttl_seconds:t,timestamp:Date.now()};localStorage.setItem(h.CACHE_KEY,JSON.stringify(n))}catch{}}async getCachedRemoteConfig(){try{const e=localStorage.getItem(h.CACHE_KEY);return e?JSON.parse(e):null}catch{return null}}isCacheValid(e,t){const n=Date.now(),i=e+t*1e3;return n<i}}class I{cleanApiEndpoint(e){return e.trim().replace(/\/+$/,"")}async fetchRemoteConfig(e,t){try{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||""}});return i.ok?await i.json():null}catch{return null}}}class K{async executeSDK(e){return new Promise(t=>{try{if(!this.isDocumentReady()){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=()=>{r(!1)},n.onload=()=>r(!0),document.head.appendChild(n),setTimeout(()=>{!i&&this.verifySDKLoaded()?r(!0):i||r(!1)},100)}catch{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{}}}class k{validateConfig(e){return!(!e||!e.appKey||e.appKey.trim().length===0||e.apiEndpoint!==void 0&&!this.isValidUrl(e.apiEndpoint)||e.publicKey!==void 0&&e.publicKey.trim().length===0)}isValidUrl(e){try{return new URL(e),!0}catch{return!1}}}const m={apiEndpoint:"https://service.deway.app",publicKey:"9d3dBUvqyUQ7egd5j5uORdHSqZ7VFWOu+ud/SWt9WUY="};class _{isLoaded=!1;isLoading=!1;cacheManager;scriptExecutor;commandQueue;sdkFetcher;configValidator;remoteConfigFetcher;remoteConfigCache;sdkConfigStore;constructor(){this.cacheManager=new a,this.scriptExecutor=new K,this.commandQueue=new g,this.sdkFetcher=new b,this.configValidator=new k,this.sdkConfigStore=new C,this.remoteConfigFetcher=new I,this.remoteConfigCache=new h}init(e){this.performInit(e).catch(t=>{})}async performInit(e){try{if(!this.canInitialize())return;const t=this.isInitializationPayload(e),n=t?e.localConfig:e;if(!this.configValidator.validateConfig(n))return;this.isLoading=!0;const i=n.apiEndpoint||m.apiEndpoint,r=n.publicKey||m.publicKey,[s,d]=await Promise.all([this.fetchOrLoadSDK(n.appKey,i,r),this.fetchRemoteConfigWithCache(n,i)]);if(!s)return;const y=t?e:this.createInitializationPayload(d,n);if(!await this.scriptExecutor.executeSDK(s.code)||!this.initializeSDK(y))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||this.isLoading)}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;const i=await this.remoteConfigCache.getCachedRemoteConfig();return i?{config:i.config,ttl_seconds:i.ttl_seconds}:null}createInitializationPayload(e,t){return{localConfig:t,remoteConfig:e?.config??null,defaults:m}}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):this.loadFromCache()}async loadFromCache(){const e=await this.cacheManager.getCachedSDK();return e?{code:e.code,version:e.version}:null}initializeSDK(e){if(!this.isSDKAvailable())return!1;try{return window.Deway?.init(e),!0}catch{return!1}}identify(e){try{this.isLoaded&&this.isSDKAvailable()?window.Deway?.identify(e):this.commandQueue.queueCommand("identify",e)}catch{}}reportEvent(e,t){try{this.isLoaded&&this.isSDKAvailable()?window.Deway?.reportEvent(e,t):this.commandQueue.queueCommand("reportEvent",e,t)}catch{}}setUserProfile(e){try{this.isLoaded&&this.isSDKAvailable()?window.Deway?.setUserProfile(e):this.commandQueue.queueCommand("setUserProfile",e)}catch{}}show(e){try{this.isLoaded&&this.isSDKAvailable()?window.Deway?.show(e):this.commandQueue.queueCommand("show",e)}catch{}}hide(){try{this.isLoaded&&this.isSDKAvailable()?window.Deway?.hide():this.commandQueue.queueCommand("hide")}catch{}}openChat(){try{this.isLoaded&&this.isSDKAvailable()?window.Deway?.openChat():this.commandQueue.queueCommand("openChat")}catch{}}isVisible(){try{return this.isLoaded&&this.isSDKAvailable()?window.Deway?.isVisible()??!1:!1}catch{return!1}}isInitialized(){try{return this.isLoaded&&this.isSDKAvailable()?window.Deway?.isInitialized()??!1:!1}catch{return!1}}destroy(){try{this.isLoaded&&this.isSDKAvailable()?window.Deway?.destroy():this.commandQueue.queueCommand("destroy"),this.commandQueue.clearQueue()}catch{}}isSDKAvailable(){return typeof window<"u"&&"Deway"in window&&!!window.Deway}}const c=new _,p={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(),isVisible:()=>c.isVisible(),isInitialized:()=>c.isInitialized(),destroy:()=>c.destroy()};return typeof window<"u"&&(window.Deway=p),p}));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@deway-ai/web-sdk",
3
- "version": "0.51.0",
3
+ "version": "0.53.0",
4
4
  "type": "module",
5
5
  "description": "Deway's Web SDK",
6
6
  "main": "dist/loader.umd.js",