@deway-ai/web-sdk 0.36.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 ADDED
@@ -0,0 +1,302 @@
1
+ # Deway Web SDK
2
+
3
+ [![Accessibility](https://img.shields.io/badge/accessibility-WCAG%202.1%20AA-green)](./documentation/accessibility/compliance.md)
4
+
5
+ A lightweight TypeScript SDK for adding an AI-powered user engagement engine by Deway to your web app.
6
+
7
+ ## Quick Install with AI Assistant
8
+
9
+ Copy and paste this prompt to your AI coding assistant (Claude, Copilot, etc.) to get Deway set up with best practices:
10
+
11
+ ```text
12
+ Install and integrate the Deway Web SDK (@deway-ai/web-sdk) into my project.
13
+
14
+ PACKAGE INFO:
15
+ - Name: @deway-ai/web-sdk
16
+ - Purpose: Lightweight TypeScript SDK that adds an AI-powered user engagement engine
17
+ - Supports: React, Next.js, Vue, Nuxt, Angular, and vanilla JS
18
+ - Includes full TypeScript definitions
19
+
20
+ TASKS:
21
+ 1. Detect my framework and package manager (npm, pnpm, or yarn) from lock files
22
+ 2. Install the SDK using the detected package manager
23
+ 3. For vanilla JS/HTML projects: Use the CDN script instead:
24
+ <script src="https://unpkg.com/@deway-ai/web-sdk/dist/loader.umd.js"></script>
25
+ 4. Initialize early in the app lifecycle (use appropriate lifecycle hook for the framework):
26
+ - Import: import Deway from '@deway-ai/web-sdk'
27
+ - Call Deway.init() with the appKey:
28
+ Deway.init({ appKey: 'your-deway-app-key' })
29
+ 5. Identify users after authentication:
30
+ if (user?.id) Deway.identify(user.id);
31
+
32
+ IMPLEMENTATION NOTES:
33
+ - Follow my existing project structure and code style conventions
34
+ - Use appropriate lifecycle hooks: React (useEffect), Vue (onMounted), Angular (ngOnInit)
35
+
36
+ FIRST analyze my project structure and detect the framework and package manager. Then and only then implement the Deway Web SDK integration accordingly.
37
+ ```
38
+
39
+ ## Installation
40
+
41
+ ```bash
42
+ npm install @deway-ai/web-sdk
43
+ # or
44
+ pnpm add @deway-ai/web-sdk
45
+ # or
46
+ yarn add @deway-ai/web-sdk
47
+ ```
48
+
49
+ ## Quick Start
50
+
51
+ ### Basic Integration
52
+
53
+ ```typescript
54
+ import Deway from '@deway-ai/web-sdk';
55
+
56
+ // Initialize the SDK
57
+ Deway.init({
58
+ appKey: 'your-app-key'
59
+ });
60
+
61
+ // Identify a user
62
+ Deway.identify('user-123');
63
+ ```
64
+
65
+ **Note:** `Deway.init()` must be called before other methods. User identification via `Deway.identify()` enables activity
66
+ tracking.
67
+
68
+ ### HTML/JavaScript Integration
69
+
70
+ ```html
71
+
72
+ <script src="https://unpkg.com/@deway-ai/web-sdk/dist/loader.umd.js"></script>
73
+ <script>
74
+ Deway.init({
75
+ appKey: 'your-app-key'
76
+ });
77
+
78
+ Deway.identify('user-123');
79
+ </script>
80
+ ```
81
+
82
+ ## Configuration
83
+
84
+ ```typescript
85
+ Deway.init({
86
+ 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
+ autoShowBubble: boolean | undefined, // Optional: Auto-show bubble (default: true)
91
+ bubbleConfig: BubbleConfig | undefined, // Optional: Bubble appearance customization
92
+ });
93
+ ```
94
+
95
+ ### BubbleConfig
96
+
97
+ Customize the chat bubble appearance:
98
+
99
+ ```typescript
100
+ interface BubbleConfig {
101
+ position?: BubblePosition; // Position on screen
102
+ }
103
+
104
+ enum BubblePosition {
105
+ BOTTOM_LEFT = "bottom-left",
106
+ BOTTOM_RIGHT = "bottom-right" // default
107
+ }
108
+ ```
109
+
110
+ ### Example with Custom Configuration
111
+
112
+ ```typescript
113
+ Deway.init({
114
+ appKey: 'your-app-key',
115
+ isDevelopment: true,
116
+ autoShowBubble: true,
117
+ bubbleConfig: {
118
+ position: 'bottom-left'
119
+ }
120
+ });
121
+ ```
122
+
123
+ ## API Reference
124
+
125
+ ### `Deway.init(config)`
126
+
127
+ Initialize the SDK with configuration options. Must be called before using other methods.
128
+
129
+ ### `Deway.identify(userId)`
130
+
131
+ Associate a user ID with the current session for personalized experiences.
132
+
133
+ ### `Deway.reportEvent(name, params)`
134
+
135
+ Report a custom event with the given name and parameters.
136
+
137
+ **Parameters:**
138
+
139
+ - `name` (string): Event name (will be normalized: trimmed, lowercased, special characters replaced with underscores)
140
+ - `params` (object): Event parameters as a plain object
141
+
142
+ **Example:**
143
+
144
+ ```typescript
145
+ Deway.reportEvent('Product Purchased', {
146
+ product_id: 'ABC-123',
147
+ quantity: 5,
148
+ price: 99.99
149
+ });
150
+ // Event sent with normalized name: "product_purchased"
151
+ ```
152
+
153
+ ### `Deway.setUserProfile(userProfile)`
154
+
155
+ Set or update the user profile for the currently identified user.
156
+
157
+ **Parameters:**
158
+
159
+ - `userProfile` (object): User profile data as a plain object. Can contain any JSON-serializable properties.
160
+
161
+ **Example:**
162
+
163
+ ```typescript
164
+ Deway.setUserProfile({
165
+ name: 'Jane Doe',
166
+ email: 'jane@example.com',
167
+ age: 28,
168
+ preferences: {
169
+ theme: 'dark',
170
+ notifications: true
171
+ }
172
+ });
173
+ ```
174
+
175
+ **Notes:**
176
+
177
+ - Profile is upserted (created if new, replaced if exists)
178
+ - Profile data completely replaces existing profile on each call
179
+
180
+ ### `Deway.showBubble(config?)`
181
+
182
+ Show the AI chat bubble. Optional configuration for appearance customization.
183
+
184
+ ### `Deway.hideBubble()`
185
+
186
+ Hide the AI chat bubble.
187
+
188
+ ### `Deway.isBubbleVisible()`
189
+
190
+ Check if the bubble is currently visible.
191
+
192
+ ### `Deway.destroy()`
193
+
194
+ Clean up SDK resources and stop all tracking.
195
+
196
+ ## Framework Examples
197
+
198
+ ### React
199
+
200
+ ```tsx
201
+ import {useEffect} from 'react';
202
+ import Deway from '@deway-ai/web-sdk';
203
+
204
+ function App() {
205
+ useEffect(() => {
206
+ Deway.init({
207
+ appKey: 'your-app-key'
208
+ });
209
+
210
+ // Identify user when available
211
+ if (user?.id) {
212
+ Deway.identify(user.id);
213
+ }
214
+ }, [user?.id]);
215
+
216
+ return <div>Your App</div>;
217
+ }
218
+ ```
219
+
220
+ ### Vue
221
+
222
+ ```vue
223
+
224
+ <script setup>
225
+ import {onMounted} from 'vue';
226
+ import Deway from '@deway-ai/web-sdk';
227
+
228
+ onMounted(() => {
229
+ Deway.init({
230
+ appKey: 'your-app-key'
231
+ });
232
+ });
233
+ </script>
234
+ ```
235
+
236
+ ### Angular
237
+
238
+ ```typescript
239
+ import {Component, OnInit} from '@angular/core';
240
+ import Deway from '@deway-ai/web-sdk';
241
+
242
+ @Component({
243
+ selector: 'app-root',
244
+ template: '<div>Your App</div>'
245
+ })
246
+ export class AppComponent implements OnInit {
247
+ ngOnInit() {
248
+ Deway.init({
249
+ appKey: 'your-app-key'
250
+ });
251
+ }
252
+ }
253
+ ```
254
+
255
+ ## Features
256
+
257
+ - **AI-powered user engagement and assistance**: Interactive chat interface for user support
258
+ - **Automatic user behavior analysis**: Intelligent tracking and understanding of user interactions
259
+ - **Framework-agnostic integration**: Works with React, Vue, Angular, and vanilla JavaScript
260
+ - **Full TypeScript support**: Complete type definitions included
261
+ - **Lightweight**: Minimal bundle size impact
262
+
263
+ ## Edge Cases & Internal Behavior
264
+
265
+ ### Error Handling
266
+
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.
269
+
270
+ ### State Persistence
271
+
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.
274
+
275
+ ### Multiple init() Calls
276
+
277
+ Calling `Deway.init()` multiple times is safe. Subsequent calls after the first are ignored.
278
+
279
+ ### Automatic Retries
280
+
281
+ Failed API calls and uploads are automatically retried with exponential backoff. No manual intervention required.
282
+
283
+ ### Call Queue
284
+
285
+ All SDK calls should be called after the SDK is initialized via `Deway.init()`, and the user is identified via
286
+ `Deway.identify()`.
287
+ In case a call is made before `init` or `identify` the SDK queues the call internally and eventually executed once the
288
+ prerequisite calls were made.
289
+
290
+ ## Troubleshooting
291
+
292
+ ### Bubble doesn't appear
293
+
294
+ - Check `autoShowBubble` is set to `true` OR manually call `Deway.showBubble()`
295
+ - Verify `Deway.init()` was called with valid `appKey`
296
+ - Check browser console for initialization errors
297
+
298
+ ### User identification not working
299
+
300
+ - Ensure `Deway.init()` is called before `Deway.identify()`
301
+ - User ID must be non-empty string
302
+ - Check browser console for error logs
@@ -0,0 +1,12 @@
1
+ import { BubbleConfig } from '../deway-bubble/models/bubble-config';
2
+ import { DewayConfig } from '../sdk/types';
3
+ import { IDeway } from '../sdk/types';
4
+
5
+ export { BubbleConfig }
6
+
7
+ declare const Deway: IDeway;
8
+ export default Deway;
9
+
10
+ export { DewayConfig }
11
+
12
+ export { }
@@ -0,0 +1,497 @@
1
+ const w = "deway-sdk-config", p = ["Understanding intent", "Reading web page", "Browsing the docs", "Enriching context", "Validating understanding", "Crafting response"];
2
+ class S {
3
+ saveConfig(e) {
4
+ if (window?.localStorage)
5
+ try {
6
+ const t = JSON.stringify(e);
7
+ window.localStorage.setItem(w, t);
8
+ } catch (t) {
9
+ console.warn("Failed to save SDK config to localStorage:", t);
10
+ }
11
+ }
12
+ loadConfig() {
13
+ if (window?.localStorage)
14
+ try {
15
+ const e = window.localStorage.getItem(w);
16
+ return e ? JSON.parse(e) : null;
17
+ } catch (e) {
18
+ return console.warn("Failed to load SDK config from localStorage:", e), null;
19
+ }
20
+ return null;
21
+ }
22
+ getExcludedVendors() {
23
+ return this.loadConfig()?.excludedVendors ?? [];
24
+ }
25
+ getAssistantName() {
26
+ return this.loadConfig()?.assistantName ?? "Assistant";
27
+ }
28
+ getAiDisclaimer() {
29
+ return this.loadConfig()?.aiDisclaimer;
30
+ }
31
+ getThinkingMessages() {
32
+ return this.loadConfig()?.thinkingMessages ?? p;
33
+ }
34
+ getHumanHandoffUrl() {
35
+ return this.loadConfig()?.humanHandoffUrl;
36
+ }
37
+ }
38
+ class s {
39
+ static CACHE_KEY = "deway-sdk-cache";
40
+ static DB_NAME = "DewaySdk";
41
+ static DB_VERSION = 1;
42
+ static STORE_NAME = "sdk";
43
+ async cacheSDK(e, t, o, n) {
44
+ try {
45
+ const c = (await this.openIndexedDB()).transaction([s.STORE_NAME], "readwrite").objectStore(s.STORE_NAME);
46
+ await new Promise((h, y) => {
47
+ const d = c.put({
48
+ id: "latest",
49
+ code: e,
50
+ version: t,
51
+ checksum: o,
52
+ signature: n,
53
+ timestamp: Date.now()
54
+ });
55
+ d.onsuccess = () => h(d.result), d.onerror = () => y(d.error);
56
+ }), console.debug("SDK cached in IndexedDB");
57
+ } catch {
58
+ try {
59
+ const a = JSON.stringify({
60
+ code: e,
61
+ version: t,
62
+ checksum: o,
63
+ signature: n,
64
+ timestamp: Date.now()
65
+ });
66
+ localStorage.setItem(s.CACHE_KEY, a), console.debug("SDK cached in localStorage");
67
+ } catch (a) {
68
+ console.warn("Unable to cache SDK:", a);
69
+ }
70
+ }
71
+ }
72
+ async getCachedSDK() {
73
+ try {
74
+ const o = (await this.openIndexedDB()).transaction([s.STORE_NAME], "readonly").objectStore(s.STORE_NAME), n = await new Promise((i, a) => {
75
+ const c = o.get("latest");
76
+ c.onsuccess = () => i(c.result || null), c.onerror = () => a(c.error);
77
+ });
78
+ if (n)
79
+ return console.debug("Found cached SDK in IndexedDB"), n;
80
+ } catch {
81
+ console.debug("IndexedDB unavailable, trying localStorage");
82
+ }
83
+ try {
84
+ const e = localStorage.getItem(s.CACHE_KEY);
85
+ if (e)
86
+ return console.debug("Found cached SDK in localStorage"), JSON.parse(e);
87
+ } catch (e) {
88
+ console.warn("Failed to read from localStorage:", e);
89
+ }
90
+ return null;
91
+ }
92
+ openIndexedDB() {
93
+ return new Promise((e, t) => {
94
+ const o = indexedDB.open(s.DB_NAME, s.DB_VERSION);
95
+ o.onerror = () => t(o.error), o.onsuccess = () => e(o.result), o.onupgradeneeded = (n) => {
96
+ const i = n.target.result;
97
+ i.objectStoreNames.contains(s.STORE_NAME) || i.createObjectStore(s.STORE_NAME, { keyPath: "id" });
98
+ };
99
+ });
100
+ }
101
+ }
102
+ async function b(r) {
103
+ const t = new TextEncoder().encode(r), o = await crypto.subtle.digest("SHA-256", t);
104
+ return Array.from(new Uint8Array(o)).map((i) => i.toString(16).padStart(2, "0")).join("");
105
+ }
106
+ function g(r) {
107
+ const e = atob(r), t = new Uint8Array(e.length);
108
+ for (let o = 0; o < e.length; o++)
109
+ t[o] = e.charCodeAt(o);
110
+ return t;
111
+ }
112
+ function D(r) {
113
+ const e = new Uint8Array(r.length / 2);
114
+ for (let t = 0; t < r.length; t += 2)
115
+ e[t / 2] = Number.parseInt(r.substr(t, 2), 16);
116
+ return e;
117
+ }
118
+ async function E(r, e, t) {
119
+ try {
120
+ const o = g(r), n = D(e), i = g(t), a = await crypto.subtle.importKey("raw", o, { name: "Ed25519" }, !1, ["verify"]);
121
+ return await crypto.subtle.verify("Ed25519", a, i, n);
122
+ } catch (o) {
123
+ return console.error("Ed25519 signature verification failed:", o), !1;
124
+ }
125
+ }
126
+ async function C(r, e, t, o) {
127
+ if (!e || !t)
128
+ throw new Error("SDK verification failed: Missing security headers");
129
+ if (await b(r) !== e)
130
+ throw new Error("SDK verification failed: Checksum mismatch - content tampered");
131
+ if (!await E(o, e, t))
132
+ throw new Error("SDK verification failed: Invalid signature - content tampered");
133
+ }
134
+ class K {
135
+ cleanApiEndpoint(e) {
136
+ return e.trim().replace(/\/+$/, "");
137
+ }
138
+ async fetchSDK(e, t, o) {
139
+ try {
140
+ console.info("Fetching Deway SDK from backend...");
141
+ const n = this.cleanApiEndpoint(t), i = await fetch(`${n}/sdk-serve/sdk/v0`, {
142
+ method: "GET",
143
+ headers: {
144
+ Accept: "application/javascript",
145
+ "deway-app-key": e,
146
+ Origin: window?.location?.origin || ""
147
+ }
148
+ });
149
+ return i.ok ? this.handleSuccessfulFetch(i, o) : (console.warn(`Failed to fetch SDK: HTTP ${i.status}: ${i.statusText}`), null);
150
+ } catch (n) {
151
+ return console.warn("Failed to fetch SDK from server:", n), null;
152
+ }
153
+ }
154
+ async handleSuccessfulFetch(e, t) {
155
+ const o = e.headers.get("x-sdk-checksum"), n = e.headers.get("x-sdk-version"), i = e.headers.get("x-sdk-signature"), a = await e.text();
156
+ if (console.info(`Fetched Deway SDK version ${n}`), !n || !a || !o) {
157
+ const c = Object.fromEntries(e.headers.entries());
158
+ throw console.error(`Failed to get required data from sdk fetch. Headers: ${JSON.stringify(c)}`), new Error("Invalid SDK response: missing version, code, or checksum");
159
+ }
160
+ return await C(a, o, i, t), { code: a, version: n, checksum: o, signature: i || "" };
161
+ }
162
+ }
163
+ class u {
164
+ static MAX_QUEUE_SIZE = 50;
165
+ commandQueue = [];
166
+ queueCommand(e, ...t) {
167
+ this.commandQueue.length >= u.MAX_QUEUE_SIZE && (console.warn(`Command queue full (${u.MAX_QUEUE_SIZE} commands). Discarding oldest command.`), this.commandQueue.shift()), this.commandQueue.push({ method: e, args: t }), console.debug(`Queued command: ${e} (queue size: ${this.commandQueue.length})`);
168
+ }
169
+ replayQueuedCommands() {
170
+ if (this.commandQueue.length === 0)
171
+ return;
172
+ console.info(`Replaying ${this.commandQueue.length} queued commands`);
173
+ const e = [...this.commandQueue];
174
+ if (this.commandQueue = [], !this.isSDKAvailable()) {
175
+ console.warn("Deway SDK not available for command replay");
176
+ return;
177
+ }
178
+ for (const t of e)
179
+ this.replayCommand(t);
180
+ }
181
+ clearQueue() {
182
+ this.commandQueue = [];
183
+ }
184
+ isSDKAvailable() {
185
+ return typeof window < "u" && "Deway" in window && !!window.Deway;
186
+ }
187
+ replayCommand(e) {
188
+ try {
189
+ const t = window.Deway, o = t?.[e.method];
190
+ typeof o == "function" ? o.apply(t, e.args) : console.warn(`Method ${e.method} not found on Deway SDK`);
191
+ } catch (t) {
192
+ console.error(`Failed to replay command ${e.method}:`, t);
193
+ }
194
+ }
195
+ }
196
+ class f {
197
+ static CACHE_KEY = "deway-remote-config-cache";
198
+ /**
199
+ * Caches remote configuration in localStorage
200
+ * TTL only controls fetch frequency, cached config is never deleted
201
+ *
202
+ * @param config - Remote configuration to cache
203
+ * @param ttlSeconds - Time-to-live in seconds from server
204
+ */
205
+ async cacheRemoteConfig(e, t) {
206
+ try {
207
+ const o = {
208
+ config: e,
209
+ ttl_seconds: t,
210
+ timestamp: Date.now()
211
+ };
212
+ localStorage.setItem(f.CACHE_KEY, JSON.stringify(o)), console.debug("Remote configuration cached in localStorage");
213
+ } catch (o) {
214
+ console.warn("Failed to cache remote config:", o);
215
+ }
216
+ }
217
+ /**
218
+ * Retrieves cached remote configuration from localStorage
219
+ * Returns null if no cache exists
220
+ *
221
+ * @returns Cached remote config or null
222
+ */
223
+ async getCachedRemoteConfig() {
224
+ try {
225
+ const e = localStorage.getItem(f.CACHE_KEY);
226
+ if (!e)
227
+ return null;
228
+ const t = JSON.parse(e);
229
+ return console.debug("Found cached remote configuration"), t;
230
+ } catch (e) {
231
+ return console.warn("Failed to read cached remote config:", e), null;
232
+ }
233
+ }
234
+ /**
235
+ * Checks if the cached config is still valid based on TTL
236
+ * Note: This only affects whether we fetch fresh config, not if we use cached config
237
+ *
238
+ * @param timestamp - Timestamp when config was cached (milliseconds)
239
+ * @param ttlSeconds - TTL in seconds
240
+ * @returns true if cache is still valid
241
+ */
242
+ isCacheValid(e, t) {
243
+ const o = Date.now(), n = e + t * 1e3;
244
+ return o < n;
245
+ }
246
+ }
247
+ class v {
248
+ cleanApiEndpoint(e) {
249
+ return e.trim().replace(/\/+$/, "");
250
+ }
251
+ /**
252
+ * Fetches remote configuration from the backend
253
+ * Returns null if the fetch fails for any reason
254
+ *
255
+ * @param appKey - The application key for authentication
256
+ * @param apiEndpoint - The API endpoint URL
257
+ * @returns Remote config response or null on error
258
+ */
259
+ async fetchRemoteConfig(e, t) {
260
+ try {
261
+ console.info("Fetching remote configuration from backend...");
262
+ const o = this.cleanApiEndpoint(t), n = await fetch(`${o}/sdk-remote-config-serve/`, {
263
+ method: "GET",
264
+ headers: {
265
+ Accept: "application/json",
266
+ "deway-app-key": e,
267
+ Origin: window?.location?.origin || ""
268
+ }
269
+ });
270
+ if (n.ok) {
271
+ const i = await n.json();
272
+ return console.info("Remote configuration fetched successfully"), i;
273
+ }
274
+ return console.warn(`Failed to fetch remote config: HTTP ${n.status}: ${n.statusText}`), null;
275
+ } catch (o) {
276
+ return console.warn("Failed to fetch remote config from server:", o), null;
277
+ }
278
+ }
279
+ }
280
+ class A {
281
+ async executeSDK(e) {
282
+ return new Promise((t) => {
283
+ try {
284
+ if (!this.isDocumentReady()) {
285
+ console.error("Document is not available for script execution"), t(!1);
286
+ return;
287
+ }
288
+ const o = document.createElement("script");
289
+ o.textContent = e, o.type = "text/javascript";
290
+ let n = !1;
291
+ const i = (a) => {
292
+ n || (n = !0, this.cleanupScript(o), t(a));
293
+ };
294
+ o.onerror = () => {
295
+ console.error("Script execution failed"), i(!1);
296
+ }, o.onload = () => i(!0), document.head.appendChild(o), setTimeout(() => {
297
+ !n && this.verifySDKLoaded() ? i(!0) : n || (console.error("SDK execution timeout - Deway object not found"), i(!1));
298
+ }, 100);
299
+ } catch (o) {
300
+ console.error("Failed to execute SDK script:", o), t(!1);
301
+ }
302
+ });
303
+ }
304
+ isDocumentReady() {
305
+ return typeof document < "u" && document.head != null;
306
+ }
307
+ verifySDKLoaded() {
308
+ return typeof window < "u" && "Deway" in window && !!window.Deway;
309
+ }
310
+ cleanupScript(e) {
311
+ try {
312
+ e.parentNode && e.parentNode.removeChild(e);
313
+ } catch (t) {
314
+ console.debug("Failed to cleanup script element:", t);
315
+ }
316
+ }
317
+ }
318
+ class F {
319
+ validateConfig(e) {
320
+ return e ? !e.appKey || e.appKey.trim().length === 0 ? (console.error("Config.appKey is required and must be a non-empty string"), !1) : e.apiEndpoint !== void 0 && !this.isValidUrl(e.apiEndpoint) ? (console.error("Config.apiEndpoint must be a valid URL"), !1) : e.publicKey !== void 0 && e.publicKey.trim().length === 0 ? (console.error("Config.publicKey must be a non-empty string if provided"), !1) : !0 : (console.error("Config is required"), !1);
321
+ }
322
+ isValidUrl(e) {
323
+ try {
324
+ return new URL(e), !0;
325
+ } catch {
326
+ return !1;
327
+ }
328
+ }
329
+ }
330
+ const m = {
331
+ apiEndpoint: "https://service.deway.app",
332
+ publicKey: "9d3dBUvqyUQ7egd5j5uORdHSqZ7VFWOu+ud/SWt9WUY=",
333
+ isDevelopment: !1,
334
+ autoShowBubble: !1
335
+ };
336
+ class x {
337
+ isLoaded = !1;
338
+ isLoading = !1;
339
+ cacheManager;
340
+ scriptExecutor;
341
+ commandQueue;
342
+ sdkFetcher;
343
+ configValidator;
344
+ remoteConfigFetcher;
345
+ remoteConfigCache;
346
+ sdkConfigStore;
347
+ constructor() {
348
+ this.cacheManager = new s(), this.scriptExecutor = new A(), this.commandQueue = new u(), this.sdkFetcher = new K(), this.configValidator = new F(), this.sdkConfigStore = new S(), this.remoteConfigFetcher = new v(), this.remoteConfigCache = new f();
349
+ }
350
+ init(e) {
351
+ this.performInit(e).catch((t) => {
352
+ console.error("Failed to initialize Deway SDK:", t);
353
+ });
354
+ }
355
+ async performInit(e) {
356
+ try {
357
+ if (!this.canInitialize())
358
+ return;
359
+ const t = this.isInitializationPayload(e), o = t ? e.localConfig : e;
360
+ if (!this.configValidator.validateConfig(o)) {
361
+ console.error("Invalid config provided to Deway SDK");
362
+ return;
363
+ }
364
+ this.isLoading = !0;
365
+ const n = o.apiEndpoint || m.apiEndpoint, i = o.publicKey || m.publicKey, [a, c] = await Promise.all([this.fetchOrLoadSDK(o.appKey, n, i), this.fetchRemoteConfigWithCache(o, n)]);
366
+ if (!a)
367
+ return;
368
+ const h = t ? e : this.createInitializationPayload(c, o);
369
+ if (!await this.scriptExecutor.executeSDK(a.code)) {
370
+ console.error("SDK execution failed");
371
+ return;
372
+ }
373
+ if (!this.initializeSDK(h))
374
+ return;
375
+ this.commandQueue.replayQueuedCommands(), this.isLoaded = !0;
376
+ } finally {
377
+ this.isLoading = !1;
378
+ }
379
+ }
380
+ isInitializationPayload(e) {
381
+ return "localConfig" in e && "remoteConfig" in e && "defaults" in e;
382
+ }
383
+ canInitialize() {
384
+ return this.isLoaded ? (console.warn("Deway SDK already initialized"), !1) : this.isLoading ? (console.warn("Deway SDK initialization already in progress"), !1) : !0;
385
+ }
386
+ /**
387
+ * Fetches remote config from backend with cache fallback
388
+ * Returns null if both fetch and cache fail
389
+ */
390
+ async fetchRemoteConfigWithCache(e, t) {
391
+ this.sdkConfigStore.saveConfig(e);
392
+ const o = await this.remoteConfigFetcher.fetchRemoteConfig(e.appKey, t);
393
+ if (o)
394
+ return await this.remoteConfigCache.cacheRemoteConfig(o.config, o.ttl_seconds), o;
395
+ console.info("Using cached remote config as fallback");
396
+ const n = await this.remoteConfigCache.getCachedRemoteConfig();
397
+ return n ? {
398
+ config: n.config,
399
+ ttl_seconds: n.ttl_seconds
400
+ } : (console.warn("No remote config available (fetch failed and no cache)"), null);
401
+ }
402
+ /**
403
+ * Creates initialization payload for backend SDK (NEW LOADER v0.29.0+)
404
+ * Passes raw configuration data to backend for merging
405
+ * This allows backend to own merge logic and handle all current/future config fields
406
+ */
407
+ createInitializationPayload(e, t) {
408
+ return {
409
+ localConfig: t,
410
+ remoteConfig: e?.config ?? null,
411
+ defaults: m
412
+ };
413
+ }
414
+ async fetchOrLoadSDK(e, t, o) {
415
+ const n = await this.sdkFetcher.fetchSDK(e, t, o);
416
+ return n ? (await this.cacheManager.cacheSDK(n.code, n.version, n.checksum, n.signature), n) : (console.warn("Failed to fetch SDK from server, attempting cache fallback"), this.loadFromCache());
417
+ }
418
+ async loadFromCache() {
419
+ const e = await this.cacheManager.getCachedSDK();
420
+ return e ? (console.info(`Loading cached Deway SDK version ${e.version}`), { code: e.code, version: e.version }) : (console.error("SDK unavailable: Network error and no cached version found"), null);
421
+ }
422
+ initializeSDK(e) {
423
+ if (!this.isSDKAvailable())
424
+ return console.error("SDK execution failed: Deway object not found after loading"), !1;
425
+ try {
426
+ return window.Deway?.init(e), console.info("Deway SDK initialized successfully with payload"), !0;
427
+ } catch (t) {
428
+ return console.error("Failed to initialize SDK with payload:", t), !1;
429
+ }
430
+ }
431
+ identify(e) {
432
+ try {
433
+ this.isLoaded && this.isSDKAvailable() ? window.Deway?.identify(e) : this.commandQueue.queueCommand("identify", e);
434
+ } catch (t) {
435
+ console.error("Failed to identify user:", t);
436
+ }
437
+ }
438
+ reportEvent(e, t) {
439
+ try {
440
+ this.isLoaded && this.isSDKAvailable() ? window.Deway?.reportEvent(e, t) : this.commandQueue.queueCommand("reportEvent", e, t);
441
+ } catch (o) {
442
+ console.error("Failed to report event:", o);
443
+ }
444
+ }
445
+ setUserProfile(e) {
446
+ try {
447
+ this.isLoaded && this.isSDKAvailable() ? window.Deway?.setUserProfile(e) : this.commandQueue.queueCommand("setUserProfile", e);
448
+ } catch (t) {
449
+ console.error("Failed to set user profile:", t);
450
+ }
451
+ }
452
+ showBubble(e) {
453
+ try {
454
+ this.isLoaded && this.isSDKAvailable() ? window.Deway?.showBubble(e) : this.commandQueue.queueCommand("showBubble", e);
455
+ } catch (t) {
456
+ console.error("Failed to show bubble:", t);
457
+ }
458
+ }
459
+ hideBubble() {
460
+ try {
461
+ this.isLoaded && this.isSDKAvailable() ? window.Deway?.hideBubble() : this.commandQueue.queueCommand("hideBubble");
462
+ } catch (e) {
463
+ console.error("Failed to hide bubble:", e);
464
+ }
465
+ }
466
+ isBubbleVisible() {
467
+ try {
468
+ return this.isLoaded && this.isSDKAvailable() ? window.Deway?.isBubbleVisible() ?? !1 : !1;
469
+ } catch (e) {
470
+ return console.error("Failed to check bubble visibility:", e), !1;
471
+ }
472
+ }
473
+ destroy() {
474
+ try {
475
+ this.isLoaded && this.isSDKAvailable() ? window.Deway?.destroy() : this.commandQueue.queueCommand("destroy"), this.commandQueue.clearQueue();
476
+ } catch (e) {
477
+ console.error("Failed to destroy SDK:", e);
478
+ }
479
+ }
480
+ isSDKAvailable() {
481
+ return typeof window < "u" && "Deway" in window && !!window.Deway;
482
+ }
483
+ }
484
+ const l = new x(), k = {
485
+ init: (r) => l.init(r),
486
+ identify: (r) => l.identify(r),
487
+ reportEvent: (r, e) => l.reportEvent(r, e),
488
+ setUserProfile: (r) => l.setUserProfile(r),
489
+ showBubble: (r) => l.showBubble(r),
490
+ hideBubble: () => l.hideBubble(),
491
+ isBubbleVisible: () => l.isBubbleVisible(),
492
+ destroy: () => l.destroy()
493
+ };
494
+ typeof window < "u" && (window.Deway = k);
495
+ export {
496
+ k as default
497
+ };
@@ -0,0 +1 @@
1
+ (function(d,u){typeof exports=="object"&&typeof module<"u"?module.exports=u():typeof define=="function"&&define.amd?define(u):(d=typeof globalThis<"u"?globalThis:d||self,d.Deway=u())})(this,(function(){"use strict";const d="deway-sdk-config",u=["Understanding intent","Reading web page","Browsing the docs","Enriching context","Validating understanding","Crafting response"];class b{saveConfig(e){if(window?.localStorage)try{const t=JSON.stringify(e);window.localStorage.setItem(d,t)}catch(t){console.warn("Failed to save SDK config to localStorage:",t)}}loadConfig(){if(window?.localStorage)try{const e=window.localStorage.getItem(d);return e?JSON.parse(e):null}catch(e){return console.warn("Failed to load SDK config from localStorage:",e),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}getHumanHandoffUrl(){return this.loadConfig()?.humanHandoffUrl}}class s{static CACHE_KEY="deway-sdk-cache";static DB_NAME="DewaySdk";static DB_VERSION=1;static STORE_NAME="sdk";async cacheSDK(e,t,o,n){try{const c=(await this.openIndexedDB()).transaction([s.STORE_NAME],"readwrite").objectStore(s.STORE_NAME);await new Promise((w,S)=>{const f=c.put({id:"latest",code:e,version:t,checksum:o,signature:n,timestamp:Date.now()});f.onsuccess=()=>w(f.result),f.onerror=()=>S(f.error)}),console.debug("SDK cached in IndexedDB")}catch{try{const a=JSON.stringify({code:e,version:t,checksum:o,signature:n,timestamp:Date.now()});localStorage.setItem(s.CACHE_KEY,a),console.debug("SDK cached in localStorage")}catch(a){console.warn("Unable to cache SDK:",a)}}}async getCachedSDK(){try{const o=(await this.openIndexedDB()).transaction([s.STORE_NAME],"readonly").objectStore(s.STORE_NAME),n=await new Promise((i,a)=>{const c=o.get("latest");c.onsuccess=()=>i(c.result||null),c.onerror=()=>a(c.error)});if(n)return console.debug("Found cached SDK in IndexedDB"),n}catch{console.debug("IndexedDB unavailable, trying localStorage")}try{const e=localStorage.getItem(s.CACHE_KEY);if(e)return console.debug("Found cached SDK in localStorage"),JSON.parse(e)}catch(e){console.warn("Failed to read from localStorage:",e)}return null}openIndexedDB(){return new Promise((e,t)=>{const o=indexedDB.open(s.DB_NAME,s.DB_VERSION);o.onerror=()=>t(o.error),o.onsuccess=()=>e(o.result),o.onupgradeneeded=n=>{const i=n.target.result;i.objectStoreNames.contains(s.STORE_NAME)||i.createObjectStore(s.STORE_NAME,{keyPath:"id"})}})}}async function D(r){const t=new TextEncoder().encode(r),o=await crypto.subtle.digest("SHA-256",t);return Array.from(new Uint8Array(o)).map(i=>i.toString(16).padStart(2,"0")).join("")}function g(r){const e=atob(r),t=new Uint8Array(e.length);for(let o=0;o<e.length;o++)t[o]=e.charCodeAt(o);return t}function E(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 C(r,e,t){try{const o=g(r),n=E(e),i=g(t),a=await crypto.subtle.importKey("raw",o,{name:"Ed25519"},!1,["verify"]);return await crypto.subtle.verify("Ed25519",a,i,n)}catch(o){return console.error("Ed25519 signature verification failed:",o),!1}}async function K(r,e,t,o){if(!e||!t)throw new Error("SDK verification failed: Missing security headers");if(await D(r)!==e)throw new Error("SDK verification failed: Checksum mismatch - content tampered");if(!await C(o,e,t))throw new Error("SDK verification failed: Invalid signature - content tampered")}class v{cleanApiEndpoint(e){return e.trim().replace(/\/+$/,"")}async fetchSDK(e,t,o){try{console.info("Fetching Deway SDK from backend...");const n=this.cleanApiEndpoint(t),i=await fetch(`${n}/sdk-serve/sdk/v0`,{method:"GET",headers:{Accept:"application/javascript","deway-app-key":e,Origin:window?.location?.origin||""}});return i.ok?this.handleSuccessfulFetch(i,o):(console.warn(`Failed to fetch SDK: HTTP ${i.status}: ${i.statusText}`),null)}catch(n){return console.warn("Failed to fetch SDK from server:",n),null}}async handleSuccessfulFetch(e,t){const o=e.headers.get("x-sdk-checksum"),n=e.headers.get("x-sdk-version"),i=e.headers.get("x-sdk-signature"),a=await e.text();if(console.info(`Fetched Deway SDK version ${n}`),!n||!a||!o){const c=Object.fromEntries(e.headers.entries());throw console.error(`Failed to get required data from sdk fetch. Headers: ${JSON.stringify(c)}`),new Error("Invalid SDK response: missing version, code, or checksum")}return await K(a,o,i,t),{code:a,version:n,checksum:o,signature:i||""}}}class h{static MAX_QUEUE_SIZE=50;commandQueue=[];queueCommand(e,...t){this.commandQueue.length>=h.MAX_QUEUE_SIZE&&(console.warn(`Command queue full (${h.MAX_QUEUE_SIZE} commands). Discarding oldest command.`),this.commandQueue.shift()),this.commandQueue.push({method:e,args:t}),console.debug(`Queued command: ${e} (queue size: ${this.commandQueue.length})`)}replayQueuedCommands(){if(this.commandQueue.length===0)return;console.info(`Replaying ${this.commandQueue.length} queued commands`);const e=[...this.commandQueue];if(this.commandQueue=[],!this.isSDKAvailable()){console.warn("Deway SDK not available for command replay");return}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,o=t?.[e.method];typeof o=="function"?o.apply(t,e.args):console.warn(`Method ${e.method} not found on Deway SDK`)}catch(t){console.error(`Failed to replay command ${e.method}:`,t)}}}class m{static CACHE_KEY="deway-remote-config-cache";async cacheRemoteConfig(e,t){try{const o={config:e,ttl_seconds:t,timestamp:Date.now()};localStorage.setItem(m.CACHE_KEY,JSON.stringify(o)),console.debug("Remote configuration cached in localStorage")}catch(o){console.warn("Failed to cache remote config:",o)}}async getCachedRemoteConfig(){try{const e=localStorage.getItem(m.CACHE_KEY);if(!e)return null;const t=JSON.parse(e);return console.debug("Found cached remote configuration"),t}catch(e){return console.warn("Failed to read cached remote config:",e),null}}isCacheValid(e,t){const o=Date.now(),n=e+t*1e3;return o<n}}class A{cleanApiEndpoint(e){return e.trim().replace(/\/+$/,"")}async fetchRemoteConfig(e,t){try{console.info("Fetching remote configuration from backend...");const o=this.cleanApiEndpoint(t),n=await fetch(`${o}/sdk-remote-config-serve/`,{method:"GET",headers:{Accept:"application/json","deway-app-key":e,Origin:window?.location?.origin||""}});if(n.ok){const i=await n.json();return console.info("Remote configuration fetched successfully"),i}return console.warn(`Failed to fetch remote config: HTTP ${n.status}: ${n.statusText}`),null}catch(o){return console.warn("Failed to fetch remote config from server:",o),null}}}class F{async executeSDK(e){return new Promise(t=>{try{if(!this.isDocumentReady()){console.error("Document is not available for script execution"),t(!1);return}const o=document.createElement("script");o.textContent=e,o.type="text/javascript";let n=!1;const i=a=>{n||(n=!0,this.cleanupScript(o),t(a))};o.onerror=()=>{console.error("Script execution failed"),i(!1)},o.onload=()=>i(!0),document.head.appendChild(o),setTimeout(()=>{!n&&this.verifySDKLoaded()?i(!0):n||(console.error("SDK execution timeout - Deway object not found"),i(!1))},100)}catch(o){console.error("Failed to execute SDK script:",o),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(t){console.debug("Failed to cleanup script element:",t)}}}class x{validateConfig(e){return e?!e.appKey||e.appKey.trim().length===0?(console.error("Config.appKey is required and must be a non-empty string"),!1):e.apiEndpoint!==void 0&&!this.isValidUrl(e.apiEndpoint)?(console.error("Config.apiEndpoint must be a valid URL"),!1):e.publicKey!==void 0&&e.publicKey.trim().length===0?(console.error("Config.publicKey must be a non-empty string if provided"),!1):!0:(console.error("Config is required"),!1)}isValidUrl(e){try{return new URL(e),!0}catch{return!1}}}const y={apiEndpoint:"https://service.deway.app",publicKey:"9d3dBUvqyUQ7egd5j5uORdHSqZ7VFWOu+ud/SWt9WUY=",isDevelopment:!1,autoShowBubble:!1};class k{isLoaded=!1;isLoading=!1;cacheManager;scriptExecutor;commandQueue;sdkFetcher;configValidator;remoteConfigFetcher;remoteConfigCache;sdkConfigStore;constructor(){this.cacheManager=new s,this.scriptExecutor=new F,this.commandQueue=new h,this.sdkFetcher=new v,this.configValidator=new x,this.sdkConfigStore=new b,this.remoteConfigFetcher=new A,this.remoteConfigCache=new m}init(e){this.performInit(e).catch(t=>{console.error("Failed to initialize Deway SDK:",t)})}async performInit(e){try{if(!this.canInitialize())return;const t=this.isInitializationPayload(e),o=t?e.localConfig:e;if(!this.configValidator.validateConfig(o)){console.error("Invalid config provided to Deway SDK");return}this.isLoading=!0;const n=o.apiEndpoint||y.apiEndpoint,i=o.publicKey||y.publicKey,[a,c]=await Promise.all([this.fetchOrLoadSDK(o.appKey,n,i),this.fetchRemoteConfigWithCache(o,n)]);if(!a)return;const w=t?e:this.createInitializationPayload(c,o);if(!await this.scriptExecutor.executeSDK(a.code)){console.error("SDK execution failed");return}if(!this.initializeSDK(w))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?(console.warn("Deway SDK already initialized"),!1):this.isLoading?(console.warn("Deway SDK initialization already in progress"),!1):!0}async fetchRemoteConfigWithCache(e,t){this.sdkConfigStore.saveConfig(e);const o=await this.remoteConfigFetcher.fetchRemoteConfig(e.appKey,t);if(o)return await this.remoteConfigCache.cacheRemoteConfig(o.config,o.ttl_seconds),o;console.info("Using cached remote config as fallback");const n=await this.remoteConfigCache.getCachedRemoteConfig();return n?{config:n.config,ttl_seconds:n.ttl_seconds}:(console.warn("No remote config available (fetch failed and no cache)"),null)}createInitializationPayload(e,t){return{localConfig:t,remoteConfig:e?.config??null,defaults:y}}async fetchOrLoadSDK(e,t,o){const n=await this.sdkFetcher.fetchSDK(e,t,o);return n?(await this.cacheManager.cacheSDK(n.code,n.version,n.checksum,n.signature),n):(console.warn("Failed to fetch SDK from server, attempting cache fallback"),this.loadFromCache())}async loadFromCache(){const e=await this.cacheManager.getCachedSDK();return e?(console.info(`Loading cached Deway SDK version ${e.version}`),{code:e.code,version:e.version}):(console.error("SDK unavailable: Network error and no cached version found"),null)}initializeSDK(e){if(!this.isSDKAvailable())return console.error("SDK execution failed: Deway object not found after loading"),!1;try{return window.Deway?.init(e),console.info("Deway SDK initialized successfully with payload"),!0}catch(t){return console.error("Failed to initialize SDK with payload:",t),!1}}identify(e){try{this.isLoaded&&this.isSDKAvailable()?window.Deway?.identify(e):this.commandQueue.queueCommand("identify",e)}catch(t){console.error("Failed to identify user:",t)}}reportEvent(e,t){try{this.isLoaded&&this.isSDKAvailable()?window.Deway?.reportEvent(e,t):this.commandQueue.queueCommand("reportEvent",e,t)}catch(o){console.error("Failed to report event:",o)}}setUserProfile(e){try{this.isLoaded&&this.isSDKAvailable()?window.Deway?.setUserProfile(e):this.commandQueue.queueCommand("setUserProfile",e)}catch(t){console.error("Failed to set user profile:",t)}}showBubble(e){try{this.isLoaded&&this.isSDKAvailable()?window.Deway?.showBubble(e):this.commandQueue.queueCommand("showBubble",e)}catch(t){console.error("Failed to show bubble:",t)}}hideBubble(){try{this.isLoaded&&this.isSDKAvailable()?window.Deway?.hideBubble():this.commandQueue.queueCommand("hideBubble")}catch(e){console.error("Failed to hide bubble:",e)}}isBubbleVisible(){try{return this.isLoaded&&this.isSDKAvailable()?window.Deway?.isBubbleVisible()??!1:!1}catch(e){return console.error("Failed to check bubble visibility:",e),!1}}destroy(){try{this.isLoaded&&this.isSDKAvailable()?window.Deway?.destroy():this.commandQueue.queueCommand("destroy"),this.commandQueue.clearQueue()}catch(e){console.error("Failed to destroy SDK:",e)}}isSDKAvailable(){return typeof window<"u"&&"Deway"in window&&!!window.Deway}}const l=new k,p={init:r=>l.init(r),identify:r=>l.identify(r),reportEvent:(r,e)=>l.reportEvent(r,e),setUserProfile:r=>l.setUserProfile(r),showBubble:r=>l.showBubble(r),hideBubble:()=>l.hideBubble(),isBubbleVisible:()=>l.isBubbleVisible(),destroy:()=>l.destroy()};return typeof window<"u"&&(window.Deway=p),p}));
package/package.json ADDED
@@ -0,0 +1,110 @@
1
+ {
2
+ "name": "@deway-ai/web-sdk",
3
+ "version": "0.36.0",
4
+ "type": "module",
5
+ "description": "Deway's Web SDK",
6
+ "main": "dist/loader.umd.js",
7
+ "module": "dist/loader.es.js",
8
+ "types": "dist/loader.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/loader.d.ts",
12
+ "import": "./dist/loader.es.js",
13
+ "require": "./dist/loader.umd.js"
14
+ }
15
+ },
16
+ "files": [
17
+ "dist/loader.*",
18
+ "dist/backend.*"
19
+ ],
20
+ "scripts": {
21
+ "build:iframe": "node scripts/build-deway-bubble-iframe-bundle.js && node scripts/build-options-menu-iframe-bundle.js && node scripts/build-page-guide-iframe-bundle.js",
22
+ "build:iframe:dev": "node scripts/build-deway-bubble-iframe-bundle.js --dev && node scripts/build-options-menu-iframe-bundle.js --dev && node scripts/build-page-guide-iframe-bundle.js --dev",
23
+ "build:iframe:prod": "node scripts/build-deway-bubble-iframe-bundle.js && node scripts/build-options-menu-iframe-bundle.js && node scripts/build-page-guide-iframe-bundle.js",
24
+ "build:loader:dev": "vite build --config vite.config.loader.ts --mode development",
25
+ "build:loader:prod": "vite build --config vite.config.loader.ts --mode production",
26
+ "prebuild:backend:dev": "pnpm build:iframe:dev",
27
+ "build:backend:dev": "vite build --config vite.config.backend.ts --mode development",
28
+ "prebuild:backend:prod": "pnpm build:iframe:prod",
29
+ "build:backend:prod": "vite build --config vite.config.backend.ts --mode production",
30
+ "build:dev": "pnpm build:loader:dev && pnpm build:backend:dev",
31
+ "build:prod": "pnpm build:loader:prod && pnpm build:backend:prod",
32
+ "deploy:test": "node scripts/deploy-to-dev-env.js test",
33
+ "deploy:alon": "node scripts/deploy-to-dev-env.js alon",
34
+ "deploy:noy": "node scripts/deploy-to-dev-env.js noy",
35
+ "deploy:demo": "node scripts/deploy-to-dev-env.js demo",
36
+ "preserve:test": "pnpm deploy:test",
37
+ "serve:test": "http-server . -p 2999 -c-1 -o /demo-site/?env=test",
38
+ "preserve:alon": "pnpm deploy:alon",
39
+ "serve:alon": "http-server . -p 2999 -c-1 -o /demo-site/?env=alon",
40
+ "preserve:noy": "pnpm deploy:noy",
41
+ "serve:noy": "http-server . -p 2999 -c-1 -o /demo-site/?env=noy",
42
+ "preserve:demo": "pnpm deploy:demo",
43
+ "serve:demo": "http-server . -p 2999 -c-1 -o /demo-site/?env=demo",
44
+ "preserve:extension": "node ./scripts/version-burning.js && pnpm build:prod",
45
+ "serve:extension": "http-server . -p 2999 -c-1",
46
+ "postserve:extension": "node ./scripts/version-burning.js",
47
+ "preserve:prod": "node ./scripts/version-burning.js && pnpm build:prod",
48
+ "serve:prod": "http-server . -p 2999 -c-1",
49
+ "postserve:prod": "node ./scripts/version-burning.js",
50
+ "lint": "biome check --write .",
51
+ "typecheck:tests": "tsc --noEmit --project tsconfig.tests.json",
52
+ "test:unit": "vitest run --coverage --config vitest.config.ts",
53
+ "check": "pnpm lint && pnpm typecheck:tests && pnpm test:unit",
54
+ "test:e2e:ui": "TEST_ENV=noy playwright test --ui",
55
+ "test:e2e:debug": "TEST_ENV=noy playwright test --debug",
56
+ "test:e2e:headed": "TEST_ENV=noy playwright test --headed",
57
+ "test:e2e:test": "TEST_ENV=test playwright test",
58
+ "test:e2e:alon": "TEST_ENV=alon playwright test",
59
+ "test:e2e:noy": "TEST_ENV=noy playwright test"
60
+ },
61
+ "keywords": [
62
+ "walkthrough",
63
+ "guide",
64
+ "user-guide",
65
+ "product-tour",
66
+ "tour",
67
+ "tutorial",
68
+ "deway",
69
+ "theway",
70
+ "the-way"
71
+ ],
72
+ "repository": {
73
+ "type": "git",
74
+ "url": "git+https://github.com/Deway-AI/deway-web-sdk.git"
75
+ },
76
+ "dependencies": {
77
+ "markdown-it": "^14.1.0",
78
+ "pako": "^2.1.0"
79
+ },
80
+ "devDependencies": {
81
+ "@aws-sdk/client-cloudwatch-logs": "^3.919.0",
82
+ "@aws-sdk/client-s3": "^3.925.0",
83
+ "@axe-core/playwright": "^4.11.0",
84
+ "@biomejs/biome": "^2.2.4",
85
+ "@faker-js/faker": "^10.0.0",
86
+ "@playwright/test": "^1.55.1",
87
+ "@types/jsdom": "^21.1.7",
88
+ "@types/markdown-it": "^14.1.2",
89
+ "@types/node": "^22.18.1",
90
+ "@types/pako": "^2.0.4",
91
+ "@vitest/coverage-v8": "^3.2.4",
92
+ "axe-core": "^4.11.0",
93
+ "fishery": "^2.3.1",
94
+ "http-server": "^14.1.1",
95
+ "jsdom": "^26.1.0",
96
+ "ky": "^1.11.0",
97
+ "p-event": "^7.0.0",
98
+ "p-timeout": "^7.0.1",
99
+ "ts-node": "^10.9.2",
100
+ "typescript": "^5.9.2",
101
+ "vite": "7.1.11",
102
+ "vite-plugin-dts": "^4.5.4",
103
+ "vitest": "^3.2.4",
104
+ "zod": "^4.1.12"
105
+ },
106
+ "engines": {
107
+ "node": ">=22.0.0"
108
+ },
109
+ "packageManager": "pnpm@10.19.0"
110
+ }