@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 +74 -44
- package/dist/loader.es.js +14 -7
- package/dist/loader.umd.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,11 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
[](./documentation/accessibility/compliance.md)
|
|
4
4
|
|
|
5
|
-
|
|
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
|
-
|
|
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
|
|
65
|
+
// Identify users for personalized experiences
|
|
62
66
|
Deway.identify('user-123');
|
|
63
67
|
```
|
|
64
68
|
|
|
65
|
-
**Note:**
|
|
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
|
-
**
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
//
|
|
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
|
-
##
|
|
264
|
+
## What You Get
|
|
238
265
|
|
|
239
|
-
- **AI
|
|
240
|
-
- **
|
|
241
|
-
- **
|
|
242
|
-
- **
|
|
243
|
-
- **
|
|
244
|
-
- **
|
|
245
|
-
- **
|
|
246
|
-
- **
|
|
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
|
-
##
|
|
275
|
+
## How Deway Adapts for You
|
|
249
276
|
|
|
250
|
-
### Error Handling
|
|
277
|
+
### Graceful Error Handling
|
|
251
278
|
|
|
252
|
-
The SDK handles all errors internally
|
|
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
|
-
###
|
|
281
|
+
### Persistent User Context
|
|
255
282
|
|
|
256
|
-
User identification and
|
|
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
|
-
###
|
|
285
|
+
### Idempotent Initialization
|
|
259
286
|
|
|
260
|
-
|
|
287
|
+
Multiple `Deway.init()` calls are safe and ignored after the first. The SDK adapts to your initialization patterns without breaking.
|
|
261
288
|
|
|
262
|
-
###
|
|
289
|
+
### Smart Retry Logic
|
|
263
290
|
|
|
264
|
-
Failed
|
|
291
|
+
Failed network operations automatically retry with exponential backoff. The SDK handles connectivity issues gracefully—no manual intervention required.
|
|
265
292
|
|
|
266
|
-
### Command
|
|
293
|
+
### Intelligent Command Queuing
|
|
267
294
|
|
|
268
|
-
|
|
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
|
-
|
|
275
|
-
-
|
|
276
|
-
-
|
|
277
|
-
-
|
|
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
|
-
|
|
282
|
-
-
|
|
283
|
-
-
|
|
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
|
-
|
|
288
|
-
- Commands execute
|
|
289
|
-
- Check
|
|
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((
|
|
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 = () =>
|
|
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
|
|
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 ||
|
|
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
|
|
395
|
-
if (!await this.scriptExecutor.executeSDK(a.code) || !this.initializeSDK(
|
|
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:
|
|
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()
|
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."}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}));
|