@deway-ai/web-sdk 0.45.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 +108 -88
- 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
|
@@ -30,11 +30,19 @@ class S {
|
|
|
30
30
|
getThinkingMessages() {
|
|
31
31
|
return this.loadConfig()?.thinkingMessages ?? p;
|
|
32
32
|
}
|
|
33
|
-
|
|
34
|
-
|
|
33
|
+
/**
|
|
34
|
+
* Get the support handoff configuration
|
|
35
|
+
* @returns SupportHandoff config or null if not configured
|
|
36
|
+
*/
|
|
37
|
+
getSupportHandoff() {
|
|
38
|
+
return this.loadConfig()?.supportHandoff ?? null;
|
|
35
39
|
}
|
|
36
|
-
|
|
37
|
-
|
|
40
|
+
/**
|
|
41
|
+
* Get the support handoff button text
|
|
42
|
+
* @returns Custom button text or default "talk to Support"
|
|
43
|
+
*/
|
|
44
|
+
getSupportHandoffButtonText() {
|
|
45
|
+
return this.getSupportHandoff()?.button_text ?? "talk to Support";
|
|
38
46
|
}
|
|
39
47
|
getFeatureFlags() {
|
|
40
48
|
return this.loadConfig()?.featureFlags ?? {};
|
|
@@ -66,33 +74,45 @@ class S {
|
|
|
66
74
|
const t = this.getTenantTheme();
|
|
67
75
|
return t ? e === "dark" ? t.dark : t.light : null;
|
|
68
76
|
}
|
|
77
|
+
getCustomIcons() {
|
|
78
|
+
return this.loadConfig()?.customIcons ?? null;
|
|
79
|
+
}
|
|
80
|
+
getBookmarkIconInlineSvg() {
|
|
81
|
+
return this.getCustomIcons()?.bookmark_icon_inline_svg ?? void 0;
|
|
82
|
+
}
|
|
83
|
+
getEmptyChatStateIconInlineSvg() {
|
|
84
|
+
return this.getCustomIcons()?.empty_chat_state_icon_inline_svg ?? void 0;
|
|
85
|
+
}
|
|
86
|
+
getIntroIconSize() {
|
|
87
|
+
return this.loadConfig()?.introIconSize ?? 18;
|
|
88
|
+
}
|
|
69
89
|
}
|
|
70
90
|
class s {
|
|
71
91
|
static CACHE_KEY = "deway-sdk-cache";
|
|
72
92
|
static DB_NAME = "DewaySdk";
|
|
73
93
|
static DB_VERSION = 1;
|
|
74
94
|
static STORE_NAME = "sdk";
|
|
75
|
-
async cacheSDK(e, t,
|
|
95
|
+
async cacheSDK(e, t, n, i) {
|
|
76
96
|
try {
|
|
77
97
|
const d = (await this.openIndexedDB()).transaction([s.STORE_NAME], "readwrite").objectStore(s.STORE_NAME);
|
|
78
|
-
await new Promise((
|
|
98
|
+
await new Promise((f, m) => {
|
|
79
99
|
const l = d.put({
|
|
80
100
|
id: "latest",
|
|
81
101
|
code: e,
|
|
82
102
|
version: t,
|
|
83
|
-
checksum:
|
|
84
|
-
signature:
|
|
103
|
+
checksum: n,
|
|
104
|
+
signature: i,
|
|
85
105
|
timestamp: Date.now()
|
|
86
106
|
});
|
|
87
|
-
l.onsuccess = () =>
|
|
107
|
+
l.onsuccess = () => f(l.result), l.onerror = () => m(l.error);
|
|
88
108
|
});
|
|
89
109
|
} catch {
|
|
90
110
|
try {
|
|
91
111
|
const a = JSON.stringify({
|
|
92
112
|
code: e,
|
|
93
113
|
version: t,
|
|
94
|
-
checksum:
|
|
95
|
-
signature:
|
|
114
|
+
checksum: n,
|
|
115
|
+
signature: i,
|
|
96
116
|
timestamp: Date.now()
|
|
97
117
|
});
|
|
98
118
|
localStorage.setItem(s.CACHE_KEY, a);
|
|
@@ -102,12 +122,12 @@ class s {
|
|
|
102
122
|
}
|
|
103
123
|
async getCachedSDK() {
|
|
104
124
|
try {
|
|
105
|
-
const
|
|
106
|
-
const d =
|
|
107
|
-
d.onsuccess = () =>
|
|
125
|
+
const n = (await this.openIndexedDB()).transaction([s.STORE_NAME], "readonly").objectStore(s.STORE_NAME), i = await new Promise((r, a) => {
|
|
126
|
+
const d = n.get("latest");
|
|
127
|
+
d.onsuccess = () => r(d.result || null), d.onerror = () => a(d.error);
|
|
108
128
|
});
|
|
109
|
-
if (
|
|
110
|
-
return
|
|
129
|
+
if (i)
|
|
130
|
+
return i;
|
|
111
131
|
} catch {
|
|
112
132
|
}
|
|
113
133
|
try {
|
|
@@ -120,53 +140,53 @@ class s {
|
|
|
120
140
|
}
|
|
121
141
|
openIndexedDB() {
|
|
122
142
|
return new Promise((e, t) => {
|
|
123
|
-
const
|
|
124
|
-
|
|
125
|
-
const
|
|
126
|
-
|
|
143
|
+
const n = indexedDB.open(s.DB_NAME, s.DB_VERSION);
|
|
144
|
+
n.onerror = () => t(n.error), n.onsuccess = () => e(n.result), n.onupgradeneeded = (i) => {
|
|
145
|
+
const r = i.target.result;
|
|
146
|
+
r.objectStoreNames.contains(s.STORE_NAME) || r.createObjectStore(s.STORE_NAME, { keyPath: "id" });
|
|
127
147
|
};
|
|
128
148
|
});
|
|
129
149
|
}
|
|
130
150
|
}
|
|
131
|
-
async function C(
|
|
132
|
-
const t = new TextEncoder().encode(
|
|
133
|
-
return Array.from(new Uint8Array(
|
|
151
|
+
async function C(o) {
|
|
152
|
+
const t = new TextEncoder().encode(o), n = await crypto.subtle.digest("SHA-256", t);
|
|
153
|
+
return Array.from(new Uint8Array(n)).map((r) => r.toString(16).padStart(2, "0")).join("");
|
|
134
154
|
}
|
|
135
|
-
function w(
|
|
136
|
-
const e = atob(
|
|
137
|
-
for (let
|
|
138
|
-
t[
|
|
155
|
+
function w(o) {
|
|
156
|
+
const e = atob(o), t = new Uint8Array(e.length);
|
|
157
|
+
for (let n = 0; n < e.length; n++)
|
|
158
|
+
t[n] = e.charCodeAt(n);
|
|
139
159
|
return t;
|
|
140
160
|
}
|
|
141
|
-
function E(
|
|
142
|
-
const e = new Uint8Array(
|
|
143
|
-
for (let t = 0; t <
|
|
144
|
-
e[t / 2] = Number.parseInt(
|
|
161
|
+
function E(o) {
|
|
162
|
+
const e = new Uint8Array(o.length / 2);
|
|
163
|
+
for (let t = 0; t < o.length; t += 2)
|
|
164
|
+
e[t / 2] = Number.parseInt(o.substr(t, 2), 16);
|
|
145
165
|
return e;
|
|
146
166
|
}
|
|
147
|
-
async function D(
|
|
167
|
+
async function D(o, e, t) {
|
|
148
168
|
try {
|
|
149
|
-
const
|
|
150
|
-
return await crypto.subtle.verify("Ed25519", a,
|
|
169
|
+
const n = w(o), i = E(e), r = w(t), a = await crypto.subtle.importKey("raw", n, { name: "Ed25519" }, !1, ["verify"]);
|
|
170
|
+
return await crypto.subtle.verify("Ed25519", a, r, i);
|
|
151
171
|
} catch {
|
|
152
172
|
return !1;
|
|
153
173
|
}
|
|
154
174
|
}
|
|
155
|
-
async function A(
|
|
175
|
+
async function A(o, e, t, n) {
|
|
156
176
|
if (!e || !t)
|
|
157
177
|
throw new Error("SDK verification failed: Missing security headers");
|
|
158
|
-
if (await C(
|
|
178
|
+
if (await C(o) !== e)
|
|
159
179
|
throw new Error("SDK verification failed: Checksum mismatch - content tampered");
|
|
160
|
-
if (!await D(
|
|
180
|
+
if (!await D(n, e, t))
|
|
161
181
|
throw new Error("SDK verification failed: Invalid signature - content tampered");
|
|
162
182
|
}
|
|
163
|
-
class
|
|
183
|
+
class I {
|
|
164
184
|
cleanApiEndpoint(e) {
|
|
165
185
|
return e.trim().replace(/\/+$/, "");
|
|
166
186
|
}
|
|
167
|
-
async fetchSDK(e, t,
|
|
187
|
+
async fetchSDK(e, t, n) {
|
|
168
188
|
try {
|
|
169
|
-
const
|
|
189
|
+
const i = this.cleanApiEndpoint(t), r = await fetch(`${i}/sdk-serve/sdk/v0`, {
|
|
170
190
|
method: "GET",
|
|
171
191
|
headers: {
|
|
172
192
|
Accept: "application/javascript",
|
|
@@ -174,16 +194,16 @@ class b {
|
|
|
174
194
|
Origin: window?.location?.origin || ""
|
|
175
195
|
}
|
|
176
196
|
});
|
|
177
|
-
return
|
|
197
|
+
return r.ok ? this.handleSuccessfulFetch(r, n) : null;
|
|
178
198
|
} catch {
|
|
179
199
|
return null;
|
|
180
200
|
}
|
|
181
201
|
}
|
|
182
202
|
async handleSuccessfulFetch(e, t) {
|
|
183
|
-
const
|
|
184
|
-
if (!
|
|
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();
|
|
204
|
+
if (!i || !a || !n)
|
|
185
205
|
throw Object.fromEntries(e.headers.entries()), new Error("Invalid SDK response: missing version, code, or checksum");
|
|
186
|
-
return await A(a,
|
|
206
|
+
return await A(a, n, r, t), { code: a, version: i, checksum: n, signature: r || "" };
|
|
187
207
|
}
|
|
188
208
|
}
|
|
189
209
|
class g {
|
|
@@ -208,8 +228,8 @@ class g {
|
|
|
208
228
|
}
|
|
209
229
|
replayCommand(e) {
|
|
210
230
|
try {
|
|
211
|
-
const t = window.Deway,
|
|
212
|
-
typeof
|
|
231
|
+
const t = window.Deway, n = t?.[e.method];
|
|
232
|
+
typeof n == "function" && n.apply(t, e.args);
|
|
213
233
|
} catch {
|
|
214
234
|
}
|
|
215
235
|
}
|
|
@@ -225,12 +245,12 @@ class u {
|
|
|
225
245
|
*/
|
|
226
246
|
async cacheRemoteConfig(e, t) {
|
|
227
247
|
try {
|
|
228
|
-
const
|
|
248
|
+
const n = {
|
|
229
249
|
config: e,
|
|
230
250
|
ttl_seconds: t,
|
|
231
251
|
timestamp: Date.now()
|
|
232
252
|
};
|
|
233
|
-
localStorage.setItem(u.CACHE_KEY, JSON.stringify(
|
|
253
|
+
localStorage.setItem(u.CACHE_KEY, JSON.stringify(n));
|
|
234
254
|
} catch {
|
|
235
255
|
}
|
|
236
256
|
}
|
|
@@ -257,8 +277,8 @@ class u {
|
|
|
257
277
|
* @returns true if cache is still valid
|
|
258
278
|
*/
|
|
259
279
|
isCacheValid(e, t) {
|
|
260
|
-
const
|
|
261
|
-
return
|
|
280
|
+
const n = Date.now(), i = e + t * 1e3;
|
|
281
|
+
return n < i;
|
|
262
282
|
}
|
|
263
283
|
}
|
|
264
284
|
class v {
|
|
@@ -275,7 +295,7 @@ class v {
|
|
|
275
295
|
*/
|
|
276
296
|
async fetchRemoteConfig(e, t) {
|
|
277
297
|
try {
|
|
278
|
-
const
|
|
298
|
+
const n = this.cleanApiEndpoint(t), i = await fetch(`${n}/sdk-remote-config-serve/`, {
|
|
279
299
|
method: "GET",
|
|
280
300
|
headers: {
|
|
281
301
|
Accept: "application/json",
|
|
@@ -283,13 +303,13 @@ class v {
|
|
|
283
303
|
Origin: window?.location?.origin || ""
|
|
284
304
|
}
|
|
285
305
|
});
|
|
286
|
-
return
|
|
306
|
+
return i.ok ? await i.json() : null;
|
|
287
307
|
} catch {
|
|
288
308
|
return null;
|
|
289
309
|
}
|
|
290
310
|
}
|
|
291
311
|
}
|
|
292
|
-
class
|
|
312
|
+
class b {
|
|
293
313
|
async executeSDK(e) {
|
|
294
314
|
return new Promise((t) => {
|
|
295
315
|
try {
|
|
@@ -297,16 +317,16 @@ class K {
|
|
|
297
317
|
t(!1);
|
|
298
318
|
return;
|
|
299
319
|
}
|
|
300
|
-
const
|
|
301
|
-
|
|
302
|
-
let
|
|
303
|
-
const
|
|
304
|
-
|
|
320
|
+
const n = document.createElement("script");
|
|
321
|
+
n.textContent = e, n.type = "text/javascript";
|
|
322
|
+
let i = !1;
|
|
323
|
+
const r = (a) => {
|
|
324
|
+
i || (i = !0, this.cleanupScript(n), t(a));
|
|
305
325
|
};
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
},
|
|
309
|
-
!
|
|
326
|
+
n.onerror = () => {
|
|
327
|
+
r(!1);
|
|
328
|
+
}, n.onload = () => r(!0), document.head.appendChild(n), setTimeout(() => {
|
|
329
|
+
!i && this.verifySDKLoaded() ? r(!0) : i || r(!1);
|
|
310
330
|
}, 100);
|
|
311
331
|
} catch {
|
|
312
332
|
t(!1);
|
|
@@ -326,7 +346,7 @@ class K {
|
|
|
326
346
|
}
|
|
327
347
|
}
|
|
328
348
|
}
|
|
329
|
-
class
|
|
349
|
+
class K {
|
|
330
350
|
validateConfig(e) {
|
|
331
351
|
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);
|
|
332
352
|
}
|
|
@@ -338,11 +358,11 @@ class k {
|
|
|
338
358
|
}
|
|
339
359
|
}
|
|
340
360
|
}
|
|
341
|
-
const
|
|
361
|
+
const h = {
|
|
342
362
|
apiEndpoint: "https://service.deway.app",
|
|
343
363
|
publicKey: "9d3dBUvqyUQ7egd5j5uORdHSqZ7VFWOu+ud/SWt9WUY="
|
|
344
364
|
};
|
|
345
|
-
class
|
|
365
|
+
class k {
|
|
346
366
|
isLoaded = !1;
|
|
347
367
|
isLoading = !1;
|
|
348
368
|
cacheManager;
|
|
@@ -354,7 +374,7 @@ class I {
|
|
|
354
374
|
remoteConfigCache;
|
|
355
375
|
sdkConfigStore;
|
|
356
376
|
constructor() {
|
|
357
|
-
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();
|
|
358
378
|
}
|
|
359
379
|
init(e) {
|
|
360
380
|
this.performInit(e).catch((t) => {
|
|
@@ -364,15 +384,15 @@ class I {
|
|
|
364
384
|
try {
|
|
365
385
|
if (!this.canInitialize())
|
|
366
386
|
return;
|
|
367
|
-
const t = this.isInitializationPayload(e),
|
|
368
|
-
if (!this.configValidator.validateConfig(
|
|
387
|
+
const t = this.isInitializationPayload(e), n = t ? e.localConfig : e;
|
|
388
|
+
if (!this.configValidator.validateConfig(n))
|
|
369
389
|
return;
|
|
370
390
|
this.isLoading = !0;
|
|
371
|
-
const
|
|
391
|
+
const i = n.apiEndpoint || h.apiEndpoint, r = n.publicKey || h.publicKey, [a, d] = await Promise.all([this.fetchOrLoadSDK(n.appKey, i, r), this.fetchRemoteConfigWithCache(n, i)]);
|
|
372
392
|
if (!a)
|
|
373
393
|
return;
|
|
374
|
-
const
|
|
375
|
-
if (!await this.scriptExecutor.executeSDK(a.code) || !this.initializeSDK(
|
|
394
|
+
const f = t ? e : this.createInitializationPayload(d, n);
|
|
395
|
+
if (!await this.scriptExecutor.executeSDK(a.code) || !this.initializeSDK(f))
|
|
376
396
|
return;
|
|
377
397
|
this.commandQueue.replayQueuedCommands(), this.isLoaded = !0;
|
|
378
398
|
} finally {
|
|
@@ -391,13 +411,13 @@ class I {
|
|
|
391
411
|
*/
|
|
392
412
|
async fetchRemoteConfigWithCache(e, t) {
|
|
393
413
|
this.sdkConfigStore.saveConfig(e);
|
|
394
|
-
const
|
|
395
|
-
if (
|
|
396
|
-
return await this.remoteConfigCache.cacheRemoteConfig(
|
|
397
|
-
const
|
|
398
|
-
return
|
|
399
|
-
config:
|
|
400
|
-
ttl_seconds:
|
|
414
|
+
const n = await this.remoteConfigFetcher.fetchRemoteConfig(e.appKey, t);
|
|
415
|
+
if (n)
|
|
416
|
+
return await this.remoteConfigCache.cacheRemoteConfig(n.config, n.ttl_seconds), n;
|
|
417
|
+
const i = await this.remoteConfigCache.getCachedRemoteConfig();
|
|
418
|
+
return i ? {
|
|
419
|
+
config: i.config,
|
|
420
|
+
ttl_seconds: i.ttl_seconds
|
|
401
421
|
} : null;
|
|
402
422
|
}
|
|
403
423
|
/**
|
|
@@ -409,12 +429,12 @@ class I {
|
|
|
409
429
|
return {
|
|
410
430
|
localConfig: t,
|
|
411
431
|
remoteConfig: e?.config ?? null,
|
|
412
|
-
defaults:
|
|
432
|
+
defaults: h
|
|
413
433
|
};
|
|
414
434
|
}
|
|
415
|
-
async fetchOrLoadSDK(e, t,
|
|
416
|
-
const
|
|
417
|
-
return
|
|
435
|
+
async fetchOrLoadSDK(e, t, n) {
|
|
436
|
+
const i = await this.sdkFetcher.fetchSDK(e, t, n);
|
|
437
|
+
return i ? (await this.cacheManager.cacheSDK(i.code, i.version, i.checksum, i.signature), i) : this.loadFromCache();
|
|
418
438
|
}
|
|
419
439
|
async loadFromCache() {
|
|
420
440
|
const e = await this.cacheManager.getCachedSDK();
|
|
@@ -483,12 +503,12 @@ class I {
|
|
|
483
503
|
return typeof window < "u" && "Deway" in window && !!window.Deway;
|
|
484
504
|
}
|
|
485
505
|
}
|
|
486
|
-
const c = new
|
|
487
|
-
init: (
|
|
488
|
-
identify: (
|
|
489
|
-
reportEvent: (
|
|
490
|
-
setUserProfile: (
|
|
491
|
-
show: (
|
|
506
|
+
const c = new k(), T = {
|
|
507
|
+
init: (o) => c.init(o),
|
|
508
|
+
identify: (o) => c.identify(o),
|
|
509
|
+
reportEvent: (o, e) => c.reportEvent(o, e),
|
|
510
|
+
setUserProfile: (o) => c.setUserProfile(o),
|
|
511
|
+
show: (o) => c.show(o),
|
|
492
512
|
hide: () => c.hide(),
|
|
493
513
|
isVisible: () => c.isVisible(),
|
|
494
514
|
isInitialized: () => c.isInitialized(),
|
package/dist/loader.umd.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
(function(l,u){typeof exports=="object"&&typeof module<"u"?module.exports=u():typeof define=="function"&&define.amd?define(u):(l=typeof globalThis<"u"?globalThis:l||self,l.Deway=u())})(this,(function(){"use strict";const l="deway-sdk-config",u=["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(l,t)}catch{}}loadConfig(){if(window?.localStorage)try{const e=window.localStorage.getItem(l);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??u}getTalkToHumanBtnTxt(){return this.loadConfig()?.talkToHumanBtnTxt??"talk to Support"}getHumanHandoffUrl(){return this.loadConfig()?.humanHandoffUrl}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}}class s{static CACHE_KEY="deway-sdk-cache";static DB_NAME="DewaySdk";static DB_VERSION=1;static STORE_NAME="sdk";async cacheSDK(e,t,i,n){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:i,signature:n,timestamp:Date.now()});f.onsuccess=()=>y(f.result),f.onerror=()=>S(f.error)})}catch{try{const a=JSON.stringify({code:e,version:t,checksum:i,signature:n,timestamp:Date.now()});localStorage.setItem(s.CACHE_KEY,a)}catch{}}}async getCachedSDK(){try{const i=(await this.openIndexedDB()).transaction([s.STORE_NAME],"readonly").objectStore(s.STORE_NAME),n=await new Promise((o,a)=>{const d=i.get("latest");d.onsuccess=()=>o(d.result||null),d.onerror=()=>a(d.error)});if(n)return n}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 i=indexedDB.open(s.DB_NAME,s.DB_VERSION);i.onerror=()=>t(i.error),i.onsuccess=()=>e(i.result),i.onupgradeneeded=n=>{const o=n.target.result;o.objectStoreNames.contains(s.STORE_NAME)||o.createObjectStore(s.STORE_NAME,{keyPath:"id"})}})}}async function E(r){const t=new TextEncoder().encode(r),i=await crypto.subtle.digest("SHA-256",t);return Array.from(new Uint8Array(i)).map(o=>o.toString(16).padStart(2,"0")).join("")}function w(r){const e=atob(r),t=new Uint8Array(e.length);for(let i=0;i<e.length;i++)t[i]=e.charCodeAt(i);return t}function D(r){const e=new Uint8Array(r.length/2);for(let t=0;t<r.length;t+=2)e[t/2]=Number.parseInt(r.substr(t,2),16);return e}async function A(r,e,t){try{const i=w(r),n=D(e),o=w(t),a=await crypto.subtle.importKey("raw",i,{name:"Ed25519"},!1,["verify"]);return await crypto.subtle.verify("Ed25519",a,o,n)}catch{return!1}}async function b(r,e,t,i){if(!e||!t)throw new Error("SDK verification failed: Missing security headers");if(await E(r)!==e)throw new Error("SDK verification failed: Checksum mismatch - content tampered");if(!await A(i,e,t))throw new Error("SDK verification failed: Invalid signature - content tampered")}class v{cleanApiEndpoint(e){return e.trim().replace(/\/+$/,"")}async fetchSDK(e,t,i){try{const n=this.cleanApiEndpoint(t),o=await fetch(`${n}/sdk-serve/sdk/v0`,{method:"GET",headers:{Accept:"application/javascript","deway-app-key":e,Origin:window?.location?.origin||""}});return o.ok?this.handleSuccessfulFetch(o,i):null}catch{return null}}async handleSuccessfulFetch(e,t){const i=e.headers.get("x-sdk-checksum"),n=e.headers.get("x-sdk-version"),o=e.headers.get("x-sdk-signature"),a=await e.text();if(!n||!a||!i)throw Object.fromEntries(e.headers.entries()),new Error("Invalid SDK response: missing version, code, or checksum");return await b(a,i,o,t),{code:a,version:n,checksum:i,signature:o||""}}}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,i=t?.[e.method];typeof i=="function"&&i.apply(t,e.args)}catch{}}}class h{static CACHE_KEY="deway-remote-config-cache";async cacheRemoteConfig(e,t){try{const i={config:e,ttl_seconds:t,timestamp:Date.now()};localStorage.setItem(h.CACHE_KEY,JSON.stringify(i))}catch{}}async getCachedRemoteConfig(){try{const e=localStorage.getItem(h.CACHE_KEY);return e?JSON.parse(e):null}catch{return null}}isCacheValid(e,t){const i=Date.now(),n=e+t*1e3;return i<n}}class K{cleanApiEndpoint(e){return e.trim().replace(/\/+$/,"")}async fetchRemoteConfig(e,t){try{const i=this.cleanApiEndpoint(t),n=await fetch(`${i}/sdk-remote-config-serve/`,{method:"GET",headers:{Accept:"application/json","deway-app-key":e,Origin:window?.location?.origin||""}});return n.ok?await n.json():null}catch{return null}}}class k{async executeSDK(e){return new Promise(t=>{try{if(!this.isDocumentReady()){t(!1);return}const i=document.createElement("script");i.textContent=e,i.type="text/javascript";let n=!1;const o=a=>{n||(n=!0,this.cleanupScript(i),t(a))};i.onerror=()=>{o(!1)},i.onload=()=>o(!0),document.head.appendChild(i),setTimeout(()=>{!n&&this.verifySDKLoaded()?o(!0):n||o(!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 T{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 I{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 v,this.configValidator=new T,this.sdkConfigStore=new C,this.remoteConfigFetcher=new K,this.remoteConfigCache=new h}init(e){this.performInit(e).catch(t=>{})}async performInit(e){try{if(!this.canInitialize())return;const t=this.isInitializationPayload(e),i=t?e.localConfig:e;if(!this.configValidator.validateConfig(i))return;this.isLoading=!0;const n=i.apiEndpoint||m.apiEndpoint,o=i.publicKey||m.publicKey,[a,d]=await Promise.all([this.fetchOrLoadSDK(i.appKey,n,o),this.fetchRemoteConfigWithCache(i,n)]);if(!a)return;const y=t?e:this.createInitializationPayload(d,i);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 i=await this.remoteConfigFetcher.fetchRemoteConfig(e.appKey,t);if(i)return await this.remoteConfigCache.cacheRemoteConfig(i.config,i.ttl_seconds),i;const n=await this.remoteConfigCache.getCachedRemoteConfig();return n?{config:n.config,ttl_seconds:n.ttl_seconds}:null}createInitializationPayload(e,t){return{localConfig:t,remoteConfig:e?.config??null,defaults:m}}async fetchOrLoadSDK(e,t,i){const n=await this.sdkFetcher.fetchSDK(e,t,i);return n?(await this.cacheManager.cacheSDK(n.code,n.version,n.checksum,n.signature),n):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 I,p={init:r=>c.init(r),identify:r=>c.identify(r),reportEvent:(r,e)=>c.reportEvent(r,e),setUserProfile:r=>c.setUserProfile(r),show:r=>c.show(r),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}));
|