@deway-ai/web-sdk 0.46.0 → 0.47.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 +42 -55
- package/dist/loader.es.js +12 -9
- package/dist/loader.umd.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -62,8 +62,7 @@ Deway.init({
|
|
|
62
62
|
Deway.identify('user-123');
|
|
63
63
|
```
|
|
64
64
|
|
|
65
|
-
**Note:**
|
|
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
|
-
|
|
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.
|
|
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.
|
|
148
|
+
### `Deway.show(config?)`
|
|
149
|
+
|
|
150
|
+
Show the AI chat interface. Optional configuration:
|
|
181
151
|
|
|
182
|
-
|
|
152
|
+
```typescript
|
|
153
|
+
interface BookmarkConfig {
|
|
154
|
+
appearanceMode?: "bookmark" | "bubble"; // Display mode (default: "bookmark")
|
|
155
|
+
}
|
|
156
|
+
```
|
|
183
157
|
|
|
184
|
-
|
|
158
|
+
**Appearance Modes:**
|
|
159
|
+
- `"bookmark"`: Edge-pinned vertical tab (default)
|
|
160
|
+
- `"bubble"`: Floating ellipsoid pill at bottom-right corner
|
|
185
161
|
|
|
186
|
-
|
|
162
|
+
### `Deway.hide()`
|
|
187
163
|
|
|
188
|
-
|
|
164
|
+
Hide the AI chat interface.
|
|
189
165
|
|
|
190
|
-
|
|
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**:
|
|
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
|
-
###
|
|
266
|
+
### Command Queue
|
|
284
267
|
|
|
285
|
-
All SDK
|
|
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
|
-
###
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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(),
|
|
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 =
|
|
517
|
+
typeof window < "u" && (window.Deway = T);
|
|
515
518
|
export {
|
|
516
|
-
|
|
519
|
+
T as default
|
|
517
520
|
};
|
package/dist/loader.umd.js
CHANGED
|
@@ -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}));
|