@deway-ai/web-sdk 0.46.0 → 0.48.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
@@ -62,8 +62,7 @@ Deway.init({
62
62
  Deway.identify('user-123');
63
63
  ```
64
64
 
65
- **Note:** `Deway.init()` must be called before other methods. User identification via `Deway.identify()` enables activity
66
- tracking.
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.
67
66
 
68
67
  ### HTML/JavaScript Integration
69
68
 
@@ -84,47 +83,16 @@ tracking.
84
83
  ```typescript
85
84
  Deway.init({
86
85
  appKey: string, // Required: Your Deway app key
87
- apiEndpoint: string | undefined, // Optional: Custom API endpoint
88
- wsEndpoint: string | undefined, // Optional: Custom WebSocket endpoint
89
- isDevelopment: boolean | undefined, // Optional: Enable dev mode logging (default: false)
90
- autoShowBookmark: boolean | undefined, // Optional: Auto-show bubble (default: true)
91
- bubbleConfig: BubbleConfig | undefined, // Optional: Bubble appearance customization
92
86
  });
93
87
  ```
94
88
 
95
- ### BubbleConfig
96
-
97
- Customize the chat bubble appearance:
98
-
99
- ```typescript
100
- interface BubbleConfig {
101
- position?: BubblePosition; // Position on screen
102
- }
103
-
104
- enum BubblePosition {
105
- BOTTOM_LEFT = "bottom-left",
106
- BOTTOM_RIGHT = "bottom-right" // default
107
- }
108
- ```
109
-
110
- ### Example with Custom Configuration
111
-
112
- ```typescript
113
- Deway.init({
114
- appKey: 'your-app-key',
115
- isDevelopment: true,
116
- autoShowBookmark: true,
117
- bubbleConfig: {
118
- position: 'bottom-left'
119
- }
120
- });
121
- ```
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.
122
90
 
123
91
  ## API Reference
124
92
 
125
93
  ### `Deway.init(config)`
126
94
 
127
- Initialize the SDK with configuration options. Must be called before using other methods.
95
+ Initialize the SDK with configuration options. Should be called early in your app lifecycle (commands are queued until initialization completes).
128
96
 
129
97
  ### `Deway.identify(userId)`
130
98
 
@@ -177,17 +145,31 @@ Deway.setUserProfile({
177
145
  - Profile is upserted (created if new, replaced if exists)
178
146
  - Profile data completely replaces existing profile on each call
179
147
 
180
- ### `Deway.showBookmark(config?)`
148
+ ### `Deway.show(config?)`
149
+
150
+ Show the AI chat interface. Optional configuration:
181
151
 
182
- Show the AI chat bookmark. Optional configuration for appearance customization.
152
+ ```typescript
153
+ interface BookmarkConfig {
154
+ appearanceMode?: "bookmark" | "bubble"; // Display mode (default: "bookmark")
155
+ }
156
+ ```
183
157
 
184
- ### `Deway.hideBookmark()`
158
+ **Appearance Modes:**
159
+ - `"bookmark"`: Edge-pinned vertical tab (default)
160
+ - `"bubble"`: Floating ellipsoid pill at bottom-right corner
185
161
 
186
- Hide the AI chat bookmark.
162
+ ### `Deway.hide()`
187
163
 
188
- ### `Deway.isBookmarkVisible()`
164
+ Hide the AI chat interface.
189
165
 
190
- Check if the bookmark is currently visible.
166
+ ### `Deway.isVisible()`
167
+
168
+ Check if the interface is currently visible.
169
+
170
+ ### `Deway.isInitialized()`
171
+
172
+ Check if the SDK has completed initialization.
191
173
 
192
174
  ### `Deway.destroy()`
193
175
 
@@ -256,21 +238,22 @@ export class AppComponent implements OnInit {
256
238
 
257
239
  - **AI-powered user engagement and assistance**: Interactive chat interface for user support
258
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
259
243
  - **Framework-agnostic integration**: Works with React, Vue, Angular, and vanilla JavaScript
260
244
  - **Full TypeScript support**: Complete type definitions included
261
- - **Lightweight**: Minimal bundle size impact
245
+ - **Lightweight loader**: ~5KB loader shell with dynamic backend loading
246
+ - **Offline resilience**: Backend bundle cached locally for faster loads
262
247
 
263
248
  ## Edge Cases & Internal Behavior
264
249
 
265
250
  ### Error Handling
266
251
 
267
- The SDK handles all errors internally. Callers don't need try-catch blocks around SDK methods. Failed operations are
268
- logged to the console and retried automatically when appropriate.
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.
269
253
 
270
254
  ### State Persistence
271
255
 
272
- User identification and settings persist across page reloads via localStorage. Once a user is identified, they remain
273
- identified until `Deway.destroy()` is called or localStorage is cleared.
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.
274
257
 
275
258
  ### Multiple init() Calls
276
259
 
@@ -278,25 +261,29 @@ Calling `Deway.init()` multiple times is safe. Subsequent calls after the first
278
261
 
279
262
  ### Automatic Retries
280
263
 
281
- Failed API calls and uploads are automatically retried with exponential backoff. No manual intervention required.
264
+ Failed API calls and uploads are automatically retried with exponential backoff. No manual intervention is required.
282
265
 
283
- ### Call Queue
266
+ ### Command Queue
284
267
 
285
- All SDK calls should be called after the SDK is initialized via `Deway.init()`, and the user is identified via
286
- `Deway.identify()`.
287
- In case a call is made before `init` or `identify` the SDK queues the call internally and eventually executed once the
288
- prerequisite calls were made.
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.
289
269
 
290
270
  ## Troubleshooting
291
271
 
292
- ### Bubble doesn't appear
272
+ ### Interface doesn't appear
293
273
 
294
- - Check `autoShowBookmark` is set to `true` OR manually call `Deway.showBookmark()`
295
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()`
296
276
  - Check browser console for initialization errors
277
+ - Verify the SDK completed initialization with `Deway.isInitialized()`
297
278
 
298
279
  ### User identification not working
299
280
 
300
281
  - Ensure `Deway.init()` is called before `Deway.identify()`
301
- - User ID must be non-empty string
282
+ - User ID must be a non-empty string
302
283
  - Check browser console for error logs
284
+
285
+ ### Commands not executing
286
+
287
+ - The SDK queues commands called before initialization
288
+ - Commands execute automatically once `Deway.init()` completes
289
+ - Check browser console for errors during initialization
package/dist/loader.es.js CHANGED
@@ -83,6 +83,9 @@ class S {
83
83
  getEmptyChatStateIconInlineSvg() {
84
84
  return this.getCustomIcons()?.empty_chat_state_icon_inline_svg ?? void 0;
85
85
  }
86
+ getIntroIconSize() {
87
+ return this.loadConfig()?.introIconSize ?? 18;
88
+ }
86
89
  }
87
90
  class s {
88
91
  static CACHE_KEY = "deway-sdk-cache";
@@ -169,7 +172,7 @@ async function D(o, e, t) {
169
172
  return !1;
170
173
  }
171
174
  }
172
- async function v(o, e, t, n) {
175
+ async function A(o, e, t, n) {
173
176
  if (!e || !t)
174
177
  throw new Error("SDK verification failed: Missing security headers");
175
178
  if (await C(o) !== e)
@@ -177,7 +180,7 @@ async function v(o, e, t, n) {
177
180
  if (!await D(n, e, t))
178
181
  throw new Error("SDK verification failed: Invalid signature - content tampered");
179
182
  }
180
- class A {
183
+ class I {
181
184
  cleanApiEndpoint(e) {
182
185
  return e.trim().replace(/\/+$/, "");
183
186
  }
@@ -200,7 +203,7 @@ class A {
200
203
  const n = e.headers.get("x-sdk-checksum"), i = e.headers.get("x-sdk-version"), r = e.headers.get("x-sdk-signature"), a = await e.text();
201
204
  if (!i || !a || !n)
202
205
  throw Object.fromEntries(e.headers.entries()), new Error("Invalid SDK response: missing version, code, or checksum");
203
- return await v(a, n, r, t), { code: a, version: i, checksum: n, signature: r || "" };
206
+ return await A(a, n, r, t), { code: a, version: i, checksum: n, signature: r || "" };
204
207
  }
205
208
  }
206
209
  class g {
@@ -278,7 +281,7 @@ class u {
278
281
  return n < i;
279
282
  }
280
283
  }
281
- class b {
284
+ class v {
282
285
  cleanApiEndpoint(e) {
283
286
  return e.trim().replace(/\/+$/, "");
284
287
  }
@@ -306,7 +309,7 @@ class b {
306
309
  }
307
310
  }
308
311
  }
309
- class I {
312
+ class b {
310
313
  async executeSDK(e) {
311
314
  return new Promise((t) => {
312
315
  try {
@@ -371,7 +374,7 @@ class k {
371
374
  remoteConfigCache;
372
375
  sdkConfigStore;
373
376
  constructor() {
374
- this.cacheManager = new s(), this.scriptExecutor = new I(), this.commandQueue = new g(), this.sdkFetcher = new A(), this.configValidator = new K(), this.sdkConfigStore = new S(), this.remoteConfigFetcher = new b(), this.remoteConfigCache = new u();
377
+ this.cacheManager = new s(), this.scriptExecutor = new b(), this.commandQueue = new g(), this.sdkFetcher = new I(), this.configValidator = new K(), this.sdkConfigStore = new S(), this.remoteConfigFetcher = new v(), this.remoteConfigCache = new u();
375
378
  }
376
379
  init(e) {
377
380
  this.performInit(e).catch((t) => {
@@ -500,7 +503,7 @@ class k {
500
503
  return typeof window < "u" && "Deway" in window && !!window.Deway;
501
504
  }
502
505
  }
503
- const c = new k(), x = {
506
+ const c = new k(), T = {
504
507
  init: (o) => c.init(o),
505
508
  identify: (o) => c.identify(o),
506
509
  reportEvent: (o, e) => c.reportEvent(o, e),
@@ -511,7 +514,7 @@ const c = new k(), x = {
511
514
  isInitialized: () => c.isInitialized(),
512
515
  destroy: () => c.destroy()
513
516
  };
514
- typeof window < "u" && (window.Deway = x);
517
+ typeof window < "u" && (window.Deway = T);
515
518
  export {
516
- x as default
519
+ T as default
517
520
  };
@@ -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."}getBookmarkAppearanceMode(){return this.loadConfig()?.bookmarkAppearanceMode??"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}getBookmarkIconInlineSvg(){return this.getCustomIcons()?.bookmark_icon_inline_svg??void 0}getEmptyChatStateIconInlineSvg(){return this.getCustomIcons()?.empty_chat_state_icon_inline_svg??void 0}}class s{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([s.STORE_NAME],"readwrite").objectStore(s.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 a=JSON.stringify({code:e,version:t,checksum:n,signature:i,timestamp:Date.now()});localStorage.setItem(s.CACHE_KEY,a)}catch{}}}async getCachedSDK(){try{const n=(await this.openIndexedDB()).transaction([s.STORE_NAME],"readonly").objectStore(s.STORE_NAME),i=await new Promise((r,a)=>{const d=n.get("latest");d.onsuccess=()=>r(d.result||null),d.onerror=()=>a(d.error)});if(i)return i}catch{}try{const e=localStorage.getItem(s.CACHE_KEY);if(e)return JSON.parse(e)}catch{}return null}openIndexedDB(){return new Promise((e,t)=>{const n=indexedDB.open(s.DB_NAME,s.DB_VERSION);n.onerror=()=>t(n.error),n.onsuccess=()=>e(n.result),n.onupgradeneeded=i=>{const r=i.target.result;r.objectStoreNames.contains(s.STORE_NAME)||r.createObjectStore(s.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 v(o,e,t){try{const n=w(o),i=D(e),r=w(t),a=await crypto.subtle.importKey("raw",n,{name:"Ed25519"},!1,["verify"]);return await crypto.subtle.verify("Ed25519",a,r,i)}catch{return!1}}async function A(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 v(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"),a=await e.text();if(!i||!a||!n)throw Object.fromEntries(e.headers.entries()),new Error("Invalid SDK response: missing version, code, or checksum");return await A(a,n,r,t),{code:a,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=a=>{i||(i=!0,this.cleanupScript(n),t(a))};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 x{isLoaded=!1;isLoading=!1;cacheManager;scriptExecutor;commandQueue;sdkFetcher;configValidator;remoteConfigFetcher;remoteConfigCache;sdkConfigStore;constructor(){this.cacheManager=new s,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,[a,d]=await Promise.all([this.fetchOrLoadSDK(n.appKey,i,r),this.fetchRemoteConfigWithCache(n,i)]);if(!a)return;const y=t?e:this.createInitializationPayload(d,n);if(!await this.scriptExecutor.executeSDK(a.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 x,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."}getBookmarkAppearanceMode(){return this.loadConfig()?.bookmarkAppearanceMode??"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}getBookmarkIconInlineSvg(){return this.getCustomIcons()?.bookmark_icon_inline_svg??void 0}getEmptyChatStateIconInlineSvg(){return this.getCustomIcons()?.empty_chat_state_icon_inline_svg??void 0}getIntroIconSize(){return this.loadConfig()?.introIconSize??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 I(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 v{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 I(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 b{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 T{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 v,this.configValidator=new k,this.sdkConfigStore=new C,this.remoteConfigFetcher=new b,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 T,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}));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@deway-ai/web-sdk",
3
- "version": "0.46.0",
3
+ "version": "0.48.0",
4
4
  "type": "module",
5
5
  "description": "Deway's Web SDK",
6
6
  "main": "dist/loader.umd.js",