@v-tilt/browser 1.5.1 → 1.7.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.
Files changed (108) hide show
  1. package/dist/array.full.js +1 -1
  2. package/dist/array.full.js.map +1 -1
  3. package/dist/array.js +1 -1
  4. package/dist/array.js.map +1 -1
  5. package/dist/array.no-external.js +1 -1
  6. package/dist/array.no-external.js.map +1 -1
  7. package/dist/chat.js +1 -1
  8. package/dist/chat.js.map +1 -1
  9. package/dist/constants.d.ts +4 -0
  10. package/dist/entrypoints/server.es.d.ts +12 -0
  11. package/dist/external-scripts-loader.js +1 -1
  12. package/dist/external-scripts-loader.js.map +1 -1
  13. package/dist/main.js +1 -1
  14. package/dist/main.js.map +1 -1
  15. package/dist/module.d.ts +51 -7
  16. package/dist/module.js +1 -1
  17. package/dist/module.js.map +1 -1
  18. package/dist/module.no-external.d.ts +51 -7
  19. package/dist/module.no-external.js +1 -1
  20. package/dist/module.no-external.js.map +1 -1
  21. package/dist/server.d.ts +105 -0
  22. package/dist/server.js +2 -0
  23. package/dist/server.js.map +1 -0
  24. package/dist/types.d.ts +32 -6
  25. package/dist/vtilt.d.ts +19 -1
  26. package/package.json +1 -2
  27. package/lib/config.d.ts +0 -17
  28. package/lib/config.js +0 -76
  29. package/lib/constants.d.ts +0 -174
  30. package/lib/constants.js +0 -649
  31. package/lib/entrypoints/all-external-dependencies.d.ts +0 -8
  32. package/lib/entrypoints/all-external-dependencies.js +0 -10
  33. package/lib/entrypoints/array.d.ts +0 -2
  34. package/lib/entrypoints/array.full.d.ts +0 -17
  35. package/lib/entrypoints/array.full.js +0 -19
  36. package/lib/entrypoints/array.js +0 -4
  37. package/lib/entrypoints/array.no-external.d.ts +0 -1
  38. package/lib/entrypoints/array.no-external.js +0 -4
  39. package/lib/entrypoints/chat.d.ts +0 -22
  40. package/lib/entrypoints/chat.js +0 -32
  41. package/lib/entrypoints/external-scripts-loader.d.ts +0 -24
  42. package/lib/entrypoints/external-scripts-loader.js +0 -107
  43. package/lib/entrypoints/main.cjs.d.ts +0 -4
  44. package/lib/entrypoints/main.cjs.js +0 -29
  45. package/lib/entrypoints/module.es.d.ts +0 -4
  46. package/lib/entrypoints/module.es.js +0 -23
  47. package/lib/entrypoints/module.no-external.es.d.ts +0 -4
  48. package/lib/entrypoints/module.no-external.es.js +0 -23
  49. package/lib/entrypoints/recorder.d.ts +0 -23
  50. package/lib/entrypoints/recorder.js +0 -42
  51. package/lib/entrypoints/web-vitals.d.ts +0 -14
  52. package/lib/entrypoints/web-vitals.js +0 -29
  53. package/lib/extensions/chat/chat-wrapper.d.ts +0 -196
  54. package/lib/extensions/chat/chat-wrapper.js +0 -545
  55. package/lib/extensions/chat/chat.d.ts +0 -99
  56. package/lib/extensions/chat/chat.js +0 -1891
  57. package/lib/extensions/chat/index.d.ts +0 -10
  58. package/lib/extensions/chat/index.js +0 -27
  59. package/lib/extensions/chat/types.d.ts +0 -159
  60. package/lib/extensions/chat/types.js +0 -22
  61. package/lib/extensions/history-autocapture.d.ts +0 -17
  62. package/lib/extensions/history-autocapture.js +0 -105
  63. package/lib/extensions/replay/index.d.ts +0 -13
  64. package/lib/extensions/replay/index.js +0 -31
  65. package/lib/extensions/replay/session-recording-utils.d.ts +0 -92
  66. package/lib/extensions/replay/session-recording-utils.js +0 -212
  67. package/lib/extensions/replay/session-recording-wrapper.d.ts +0 -61
  68. package/lib/extensions/replay/session-recording-wrapper.js +0 -149
  69. package/lib/extensions/replay/session-recording.d.ts +0 -95
  70. package/lib/extensions/replay/session-recording.js +0 -700
  71. package/lib/extensions/replay/types.d.ts +0 -211
  72. package/lib/extensions/replay/types.js +0 -8
  73. package/lib/geolocation.d.ts +0 -5
  74. package/lib/geolocation.js +0 -31
  75. package/lib/rate-limiter.d.ts +0 -52
  76. package/lib/rate-limiter.js +0 -80
  77. package/lib/request-queue.d.ts +0 -78
  78. package/lib/request-queue.js +0 -156
  79. package/lib/request.d.ts +0 -54
  80. package/lib/request.js +0 -265
  81. package/lib/retry-queue.d.ts +0 -64
  82. package/lib/retry-queue.js +0 -182
  83. package/lib/session.d.ts +0 -66
  84. package/lib/session.js +0 -191
  85. package/lib/storage.d.ts +0 -117
  86. package/lib/storage.js +0 -438
  87. package/lib/types.d.ts +0 -326
  88. package/lib/types.js +0 -24
  89. package/lib/user-manager.d.ts +0 -154
  90. package/lib/user-manager.js +0 -589
  91. package/lib/utils/event-utils.d.ts +0 -52
  92. package/lib/utils/event-utils.js +0 -306
  93. package/lib/utils/globals.d.ts +0 -235
  94. package/lib/utils/globals.js +0 -30
  95. package/lib/utils/index.d.ts +0 -46
  96. package/lib/utils/index.js +0 -134
  97. package/lib/utils/patch.d.ts +0 -6
  98. package/lib/utils/patch.js +0 -39
  99. package/lib/utils/request-utils.d.ts +0 -17
  100. package/lib/utils/request-utils.js +0 -80
  101. package/lib/utils/type-utils.d.ts +0 -4
  102. package/lib/utils/type-utils.js +0 -9
  103. package/lib/utils/user-agent-utils.d.ts +0 -18
  104. package/lib/utils/user-agent-utils.js +0 -411
  105. package/lib/vtilt.d.ts +0 -342
  106. package/lib/vtilt.js +0 -1073
  107. package/lib/web-vitals.d.ts +0 -95
  108. package/lib/web-vitals.js +0 -380
@@ -1,545 +0,0 @@
1
- "use strict";
2
- /**
3
- * Chat Wrapper
4
- *
5
- * Lightweight wrapper that handles the decision of WHEN to load the chat widget.
6
- * The actual chat logic is in LazyLoadedChat which is loaded on demand.
7
- *
8
- * This follows the same pattern as SessionRecordingWrapper.
9
- *
10
- * ## Initialization Modes (Intercom-like flexibility)
11
- *
12
- * 1. **Snippet-only (dashboard configured)**:
13
- * Just add the vTilt snippet - widget auto-configures from project settings.
14
- * ```js
15
- * vt.init('token', { api_host: '...' })
16
- * // Chat widget appears based on dashboard settings
17
- * ```
18
- *
19
- * 2. **Code-configured (optional overrides)**:
20
- * Override dashboard settings with code for advanced customization.
21
- * ```js
22
- * vt.init('token', {
23
- * api_host: '...',
24
- * chat: {
25
- * enabled: true,
26
- * position: 'bottom-left',
27
- * greeting: 'Custom greeting!'
28
- * }
29
- * })
30
- * ```
31
- *
32
- * Code config always takes precedence over dashboard settings.
33
- */
34
- Object.defineProperty(exports, "__esModule", { value: true });
35
- exports.ChatWrapper = exports.CHAT_LOADING = void 0;
36
- const globals_1 = require("../../utils/globals");
37
- const LOGGER_PREFIX = "[Chat]";
38
- /** Status when lazy loading is in progress */
39
- exports.CHAT_LOADING = "loading";
40
- /**
41
- * Chat Wrapper
42
- *
43
- * This is the lightweight class that lives in the main bundle.
44
- * It handles:
45
- * - Auto-fetching settings from dashboard (Intercom-like)
46
- * - Merging server settings with code config
47
- * - Deciding if chat should be enabled
48
- * - Lazy loading the actual chat widget code
49
- * - Delegating to LazyLoadedChat
50
- * - Queuing messages/callbacks before widget loads
51
- */
52
- class ChatWrapper {
53
- constructor(_instance, config = {}) {
54
- this._instance = _instance;
55
- this._serverConfig = null;
56
- this._configFetched = false;
57
- this._isLoading = false;
58
- this._loadError = null;
59
- // Queues for operations before widget loads
60
- this._pendingMessages = [];
61
- this._pendingCallbacks = [];
62
- this._messageCallbacks = [];
63
- this._typingCallbacks = [];
64
- this._connectionCallbacks = [];
65
- this._config = config;
66
- }
67
- // ============================================================================
68
- // Public API - State
69
- // ============================================================================
70
- /**
71
- * Whether the chat widget is open
72
- */
73
- get isOpen() {
74
- var _a, _b;
75
- return (_b = (_a = this._lazyLoadedChat) === null || _a === void 0 ? void 0 : _a.isOpen) !== null && _b !== void 0 ? _b : false;
76
- }
77
- /**
78
- * Whether connected to realtime service
79
- */
80
- get isConnected() {
81
- var _a, _b;
82
- return (_b = (_a = this._lazyLoadedChat) === null || _a === void 0 ? void 0 : _a.isConnected) !== null && _b !== void 0 ? _b : false;
83
- }
84
- /**
85
- * Whether the widget is loading
86
- */
87
- get isLoading() {
88
- var _a, _b;
89
- return this._isLoading || ((_b = (_a = this._lazyLoadedChat) === null || _a === void 0 ? void 0 : _a.isLoading) !== null && _b !== void 0 ? _b : false);
90
- }
91
- /**
92
- * Number of unread messages
93
- */
94
- get unreadCount() {
95
- var _a, _b;
96
- return (_b = (_a = this._lazyLoadedChat) === null || _a === void 0 ? void 0 : _a.unreadCount) !== null && _b !== void 0 ? _b : 0;
97
- }
98
- /**
99
- * Current channel (if any)
100
- */
101
- get channel() {
102
- var _a, _b;
103
- return (_b = (_a = this._lazyLoadedChat) === null || _a === void 0 ? void 0 : _a.channel) !== null && _b !== void 0 ? _b : null;
104
- }
105
- /**
106
- * List of user's channels (multi-channel support)
107
- */
108
- get channels() {
109
- var _a, _b;
110
- return (_b = (_a = this._lazyLoadedChat) === null || _a === void 0 ? void 0 : _a.channels) !== null && _b !== void 0 ? _b : [];
111
- }
112
- /**
113
- * Current view state ('list' or 'conversation')
114
- */
115
- get currentView() {
116
- var _a, _b;
117
- return (_b = (_a = this._lazyLoadedChat) === null || _a === void 0 ? void 0 : _a.currentView) !== null && _b !== void 0 ? _b : "list";
118
- }
119
- // ============================================================================
120
- // Public API - Widget Control
121
- // ============================================================================
122
- /**
123
- * Open the chat widget
124
- */
125
- open() {
126
- this._lazyLoadAndThen(() => { var _a; return (_a = this._lazyLoadedChat) === null || _a === void 0 ? void 0 : _a.open(); });
127
- }
128
- /**
129
- * Close the chat widget
130
- */
131
- close() {
132
- var _a;
133
- (_a = this._lazyLoadedChat) === null || _a === void 0 ? void 0 : _a.close();
134
- }
135
- /**
136
- * Toggle the chat widget open/closed
137
- */
138
- toggle() {
139
- if (this._lazyLoadedChat) {
140
- this._lazyLoadedChat.toggle();
141
- }
142
- else {
143
- this.open();
144
- }
145
- }
146
- /**
147
- * Show the chat widget (make visible but not necessarily open)
148
- */
149
- show() {
150
- this._lazyLoadAndThen(() => { var _a; return (_a = this._lazyLoadedChat) === null || _a === void 0 ? void 0 : _a.show(); });
151
- }
152
- /**
153
- * Hide the chat widget
154
- */
155
- hide() {
156
- var _a;
157
- (_a = this._lazyLoadedChat) === null || _a === void 0 ? void 0 : _a.hide();
158
- }
159
- // ============================================================================
160
- // Public API - Channel Management (Multi-channel support)
161
- // ============================================================================
162
- /**
163
- * Fetch/refresh the list of user's channels
164
- */
165
- getChannels() {
166
- this._lazyLoadAndThen(() => { var _a; return (_a = this._lazyLoadedChat) === null || _a === void 0 ? void 0 : _a.getChannels(); });
167
- }
168
- /**
169
- * Select a channel and load its messages
170
- */
171
- selectChannel(channelId) {
172
- this._lazyLoadAndThen(() => { var _a; return (_a = this._lazyLoadedChat) === null || _a === void 0 ? void 0 : _a.selectChannel(channelId); });
173
- }
174
- /**
175
- * Create a new channel and enter it
176
- */
177
- createChannel() {
178
- this._lazyLoadAndThen(() => { var _a; return (_a = this._lazyLoadedChat) === null || _a === void 0 ? void 0 : _a.createChannel(); });
179
- }
180
- /**
181
- * Go back to channel list from conversation view
182
- */
183
- goToChannelList() {
184
- var _a;
185
- (_a = this._lazyLoadedChat) === null || _a === void 0 ? void 0 : _a.goToChannelList();
186
- }
187
- // ============================================================================
188
- // Public API - Messaging
189
- // ============================================================================
190
- /**
191
- * Send a message
192
- */
193
- sendMessage(content) {
194
- if (this._lazyLoadedChat) {
195
- this._lazyLoadedChat.sendMessage(content);
196
- }
197
- else {
198
- // Queue message until widget loads
199
- this._pendingMessages.push(content);
200
- this._lazyLoadAndThen(() => {
201
- // Send all queued messages
202
- this._pendingMessages.forEach((msg) => { var _a; return (_a = this._lazyLoadedChat) === null || _a === void 0 ? void 0 : _a.sendMessage(msg); });
203
- this._pendingMessages = [];
204
- });
205
- }
206
- }
207
- /**
208
- * Mark messages as read
209
- */
210
- markAsRead() {
211
- var _a;
212
- (_a = this._lazyLoadedChat) === null || _a === void 0 ? void 0 : _a.markAsRead();
213
- }
214
- // ============================================================================
215
- // Public API - Events
216
- // ============================================================================
217
- /**
218
- * Subscribe to new messages
219
- */
220
- onMessage(callback) {
221
- this._messageCallbacks.push(callback);
222
- if (this._lazyLoadedChat) {
223
- return this._lazyLoadedChat.onMessage(callback);
224
- }
225
- // Return unsubscribe that removes from queue
226
- return () => {
227
- const index = this._messageCallbacks.indexOf(callback);
228
- if (index > -1) {
229
- this._messageCallbacks.splice(index, 1);
230
- }
231
- };
232
- }
233
- /**
234
- * Subscribe to typing indicators
235
- */
236
- onTyping(callback) {
237
- this._typingCallbacks.push(callback);
238
- if (this._lazyLoadedChat) {
239
- return this._lazyLoadedChat.onTyping(callback);
240
- }
241
- return () => {
242
- const index = this._typingCallbacks.indexOf(callback);
243
- if (index > -1) {
244
- this._typingCallbacks.splice(index, 1);
245
- }
246
- };
247
- }
248
- /**
249
- * Subscribe to connection changes
250
- */
251
- onConnectionChange(callback) {
252
- this._connectionCallbacks.push(callback);
253
- if (this._lazyLoadedChat) {
254
- return this._lazyLoadedChat.onConnectionChange(callback);
255
- }
256
- return () => {
257
- const index = this._connectionCallbacks.indexOf(callback);
258
- if (index > -1) {
259
- this._connectionCallbacks.splice(index, 1);
260
- }
261
- };
262
- }
263
- // ============================================================================
264
- // Initialization
265
- // ============================================================================
266
- /**
267
- * Start chat if enabled, called by VTilt after init
268
- *
269
- * This method supports two modes (Intercom-like):
270
- * 1. Auto-config: Fetch settings from /api/chat/settings (default)
271
- * 2. Code-only: Use only code config (autoConfig: false)
272
- */
273
- async startIfEnabled() {
274
- var _a, _b, _c, _d;
275
- // If explicitly disabled in code, don't even fetch settings
276
- if (this._config.enabled === false) {
277
- console.info(`${LOGGER_PREFIX} disabled by code config`);
278
- return;
279
- }
280
- // If disable_chat is set in main config, don't enable
281
- const mainConfig = this._instance.getConfig();
282
- if (mainConfig.disable_chat) {
283
- console.info(`${LOGGER_PREFIX} disabled by disable_chat config`);
284
- return;
285
- }
286
- // Fetch server settings unless autoConfig is explicitly false
287
- if (this._config.autoConfig !== false) {
288
- await this._fetchServerSettings();
289
- }
290
- // After fetching, check if chat should be enabled
291
- if (!this._isChatEnabled) {
292
- console.info(`${LOGGER_PREFIX} not enabled (check dashboard settings)`);
293
- return;
294
- }
295
- // Preload on idle if configured (code or server)
296
- const shouldPreload = (_c = (_a = this._config.preload) !== null && _a !== void 0 ? _a : (_b = this._serverConfig) === null || _b === void 0 ? void 0 : _b.enabled) !== null && _c !== void 0 ? _c : false;
297
- if (shouldPreload) {
298
- this._schedulePreload();
299
- }
300
- // If enabled by server, show the chat bubble immediately
301
- // (Note: we already returned above if this._config.enabled === false)
302
- if ((_d = this._serverConfig) === null || _d === void 0 ? void 0 : _d.enabled) {
303
- this._showBubble();
304
- }
305
- console.info(`${LOGGER_PREFIX} ready (lazy-load on demand)`);
306
- }
307
- /**
308
- * Update configuration
309
- */
310
- updateConfig(config) {
311
- this._config = { ...this._config, ...config };
312
- }
313
- /**
314
- * Get the merged configuration (server + code, code takes precedence)
315
- */
316
- getMergedConfig() {
317
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t;
318
- const server = this._serverConfig;
319
- const code = this._config;
320
- return {
321
- enabled: (_b = (_a = code.enabled) !== null && _a !== void 0 ? _a : server === null || server === void 0 ? void 0 : server.enabled) !== null && _b !== void 0 ? _b : false,
322
- autoConfig: (_c = code.autoConfig) !== null && _c !== void 0 ? _c : true,
323
- position: (_e = (_d = code.position) !== null && _d !== void 0 ? _d : server === null || server === void 0 ? void 0 : server.position) !== null && _e !== void 0 ? _e : "bottom-right",
324
- greeting: (_f = code.greeting) !== null && _f !== void 0 ? _f : server === null || server === void 0 ? void 0 : server.greeting,
325
- color: (_h = (_g = code.color) !== null && _g !== void 0 ? _g : server === null || server === void 0 ? void 0 : server.color) !== null && _h !== void 0 ? _h : "#6366f1",
326
- aiMode: (_k = (_j = code.aiMode) !== null && _j !== void 0 ? _j : server === null || server === void 0 ? void 0 : server.ai_enabled) !== null && _k !== void 0 ? _k : true,
327
- aiGreeting: (_l = code.aiGreeting) !== null && _l !== void 0 ? _l : server === null || server === void 0 ? void 0 : server.ai_greeting,
328
- preload: (_m = code.preload) !== null && _m !== void 0 ? _m : false,
329
- theme: (_o = code.theme) !== null && _o !== void 0 ? _o : {
330
- primaryColor: (_q = (_p = code.color) !== null && _p !== void 0 ? _p : server === null || server === void 0 ? void 0 : server.color) !== null && _q !== void 0 ? _q : "#6366f1",
331
- },
332
- offlineMessage: (_r = code.offlineMessage) !== null && _r !== void 0 ? _r : server === null || server === void 0 ? void 0 : server.offline_message,
333
- collectEmailOffline: (_t = (_s = code.collectEmailOffline) !== null && _s !== void 0 ? _s : server === null || server === void 0 ? void 0 : server.collect_email_offline) !== null && _t !== void 0 ? _t : true,
334
- };
335
- }
336
- /**
337
- * Destroy the chat widget
338
- */
339
- destroy() {
340
- var _a;
341
- (_a = this._lazyLoadedChat) === null || _a === void 0 ? void 0 : _a.destroy();
342
- this._lazyLoadedChat = undefined;
343
- this._pendingMessages = [];
344
- this._pendingCallbacks = [];
345
- this._messageCallbacks = [];
346
- this._typingCallbacks = [];
347
- this._connectionCallbacks = [];
348
- }
349
- // ============================================================================
350
- // Private - Configuration
351
- // ============================================================================
352
- get _isChatEnabled() {
353
- var _a;
354
- // Code config takes precedence
355
- if (this._config.enabled === false) {
356
- return false;
357
- }
358
- if (this._config.enabled === true) {
359
- return true;
360
- }
361
- // Fall back to server config
362
- if (((_a = this._serverConfig) === null || _a === void 0 ? void 0 : _a.enabled) === true) {
363
- return true;
364
- }
365
- // Default: disabled unless explicitly enabled
366
- return false;
367
- }
368
- /**
369
- * Fetch chat settings from the server
370
- * This enables "snippet-only" installation where widget configures from dashboard
371
- */
372
- async _fetchServerSettings() {
373
- if (this._configFetched) {
374
- return;
375
- }
376
- const config = this._instance.getConfig();
377
- const token = config.token;
378
- const apiHost = config.api_host;
379
- if (!token || !apiHost) {
380
- console.warn(`${LOGGER_PREFIX} Cannot fetch settings: missing token or api_host`);
381
- this._configFetched = true;
382
- return;
383
- }
384
- try {
385
- const url = `${apiHost}/api/chat/settings?token=${encodeURIComponent(token)}`;
386
- const response = await fetch(url);
387
- if (!response.ok) {
388
- console.warn(`${LOGGER_PREFIX} Failed to fetch settings: ${response.status}`);
389
- this._configFetched = true;
390
- return;
391
- }
392
- this._serverConfig = await response.json();
393
- this._configFetched = true;
394
- console.info(`${LOGGER_PREFIX} Loaded settings from dashboard`);
395
- }
396
- catch (error) {
397
- console.warn(`${LOGGER_PREFIX} Error fetching settings:`, error);
398
- this._configFetched = true;
399
- }
400
- }
401
- /**
402
- * Show the chat bubble (launcher button) without fully loading the widget
403
- * This creates a lightweight bubble that loads the full widget on click
404
- */
405
- _showBubble() {
406
- if (!(globals_1.window === null || globals_1.window === void 0 ? void 0 : globals_1.window.document)) {
407
- return;
408
- }
409
- // Don't create if already exists
410
- if (document.getElementById("vtilt-chat-bubble")) {
411
- return;
412
- }
413
- const mergedConfig = this.getMergedConfig();
414
- const position = mergedConfig.position || "bottom-right";
415
- const color = mergedConfig.color || "#6366f1";
416
- const bubble = document.createElement("div");
417
- bubble.id = "vtilt-chat-bubble";
418
- bubble.setAttribute("style", `
419
- position: fixed;
420
- bottom: 20px;
421
- ${position === "bottom-right" ? "right: 20px;" : "left: 20px;"}
422
- width: 60px;
423
- height: 60px;
424
- border-radius: 50%;
425
- background: ${color};
426
- cursor: pointer;
427
- display: flex;
428
- align-items: center;
429
- justify-content: center;
430
- box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
431
- transition: transform 0.2s, box-shadow 0.2s;
432
- z-index: 999999;
433
- `.trim());
434
- bubble.innerHTML = `
435
- <svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="white" stroke-width="2">
436
- <path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"></path>
437
- </svg>
438
- `;
439
- // Hover effect
440
- bubble.addEventListener("mouseenter", () => {
441
- bubble.style.transform = "scale(1.05)";
442
- bubble.style.boxShadow = "0 6px 16px rgba(0, 0, 0, 0.2)";
443
- });
444
- bubble.addEventListener("mouseleave", () => {
445
- bubble.style.transform = "scale(1)";
446
- bubble.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.15)";
447
- });
448
- // Click to open (this will lazy load the full widget)
449
- bubble.addEventListener("click", () => {
450
- this.open();
451
- });
452
- document.body.appendChild(bubble);
453
- }
454
- get _scriptName() {
455
- return "chat";
456
- }
457
- // ============================================================================
458
- // Private - Lazy Loading
459
- // ============================================================================
460
- /**
461
- * Schedule preload on idle
462
- */
463
- _schedulePreload() {
464
- if (typeof requestIdleCallback !== "undefined") {
465
- requestIdleCallback(() => this._lazyLoad(), { timeout: 5000 });
466
- }
467
- else {
468
- // Fallback for browsers without requestIdleCallback
469
- setTimeout(() => this._lazyLoad(), 3000);
470
- }
471
- }
472
- /**
473
- * Lazy load and then execute callback
474
- */
475
- _lazyLoadAndThen(callback) {
476
- if (this._lazyLoadedChat) {
477
- callback();
478
- return;
479
- }
480
- this._pendingCallbacks.push(callback);
481
- this._lazyLoad();
482
- }
483
- /**
484
- * Lazy load the chat script
485
- */
486
- _lazyLoad() {
487
- var _a, _b;
488
- if (this._isLoading || this._lazyLoadedChat || this._loadError) {
489
- return;
490
- }
491
- // Check if already loaded
492
- if ((_a = globals_1.assignableWindow.__VTiltExtensions__) === null || _a === void 0 ? void 0 : _a.initChat) {
493
- this._onScriptLoaded();
494
- return;
495
- }
496
- this._isLoading = true;
497
- const loadExternalDependency = (_b = globals_1.assignableWindow.__VTiltExtensions__) === null || _b === void 0 ? void 0 : _b.loadExternalDependency;
498
- if (!loadExternalDependency) {
499
- console.error(`${LOGGER_PREFIX} loadExternalDependency not available. Chat cannot start.`);
500
- this._isLoading = false;
501
- this._loadError = "loadExternalDependency not available";
502
- return;
503
- }
504
- loadExternalDependency(this._instance, this._scriptName, (err) => {
505
- this._isLoading = false;
506
- if (err) {
507
- console.error(`${LOGGER_PREFIX} Failed to load:`, err);
508
- this._loadError = String(err);
509
- return;
510
- }
511
- this._onScriptLoaded();
512
- });
513
- }
514
- /**
515
- * Called after the chat script is loaded
516
- */
517
- _onScriptLoaded() {
518
- var _a;
519
- const initChat = (_a = globals_1.assignableWindow.__VTiltExtensions__) === null || _a === void 0 ? void 0 : _a.initChat;
520
- if (!initChat) {
521
- console.error(`${LOGGER_PREFIX} initChat not available after script load`);
522
- this._loadError = "initChat not available";
523
- return;
524
- }
525
- if (!this._lazyLoadedChat) {
526
- // Use merged config (server + code)
527
- const mergedConfig = this.getMergedConfig();
528
- this._lazyLoadedChat = initChat(this._instance, mergedConfig);
529
- // Re-register queued callbacks
530
- this._messageCallbacks.forEach((cb) => { var _a; return (_a = this._lazyLoadedChat) === null || _a === void 0 ? void 0 : _a.onMessage(cb); });
531
- this._typingCallbacks.forEach((cb) => { var _a; return (_a = this._lazyLoadedChat) === null || _a === void 0 ? void 0 : _a.onTyping(cb); });
532
- this._connectionCallbacks.forEach((cb) => { var _a; return (_a = this._lazyLoadedChat) === null || _a === void 0 ? void 0 : _a.onConnectionChange(cb); });
533
- // Remove the lightweight bubble since full widget is now loaded
534
- const existingBubble = document === null || document === void 0 ? void 0 : document.getElementById("vtilt-chat-bubble");
535
- if (existingBubble) {
536
- existingBubble.remove();
537
- }
538
- }
539
- // Execute pending callbacks
540
- this._pendingCallbacks.forEach((cb) => cb());
541
- this._pendingCallbacks = [];
542
- console.info(`${LOGGER_PREFIX} loaded and ready`);
543
- }
544
- }
545
- exports.ChatWrapper = ChatWrapper;
@@ -1,99 +0,0 @@
1
- /**
2
- * Chat Widget - Lazy loaded chat implementation using Ably for real-time messaging.
3
- */
4
- import type { VTilt } from "../../vtilt";
5
- import { type ChatConfig, type ChatChannel, type ChatChannelSummary, type ChatWidgetView, type LazyLoadedChatInterface } from "../../utils/globals";
6
- import { type MessageCallback, type TypingCallback, type ConnectionCallback, type Unsubscribe } from "./types";
7
- export declare class LazyLoadedChat implements LazyLoadedChatInterface {
8
- private _instance;
9
- private _config;
10
- private _state;
11
- private _container;
12
- private _widget;
13
- private _bubble;
14
- private _ably;
15
- private _ablyChannel;
16
- private _typingChannel;
17
- private _connectionState;
18
- private _messageCallbacks;
19
- private _typingCallbacks;
20
- private _connectionCallbacks;
21
- private _typingDebounce;
22
- private _isUserTyping;
23
- private _initialUserReadAt;
24
- private _isMarkingRead;
25
- constructor(instance: VTilt, config?: ChatConfig);
26
- get isOpen(): boolean;
27
- get isConnected(): boolean;
28
- get isLoading(): boolean;
29
- get unreadCount(): number;
30
- get channel(): ChatChannel | null;
31
- get channels(): ChatChannelSummary[];
32
- get currentView(): ChatWidgetView;
33
- private get _theme();
34
- private get _distinctId();
35
- open(): void;
36
- close(): void;
37
- toggle(): void;
38
- show(): void;
39
- hide(): void;
40
- getChannels(): Promise<void>;
41
- selectChannel(channelId: string): Promise<void>;
42
- createChannel(): Promise<void>;
43
- goToChannelList(): void;
44
- sendMessage(content: string): Promise<void>;
45
- markAsRead(): void;
46
- private _autoMarkAsRead;
47
- private _isMessageReadByUser;
48
- /**
49
- * Calculate unread count based on messages and user_last_read_at
50
- * (unread agent/AI messages for the user)
51
- */
52
- private _calculateUnreadCount;
53
- onMessage(callback: MessageCallback): Unsubscribe;
54
- onTyping(callback: TypingCallback): Unsubscribe;
55
- onConnectionChange(callback: ConnectionCallback): Unsubscribe;
56
- destroy(): void;
57
- private _connectRealtime;
58
- private _disconnectRealtime;
59
- private _extractProjectId;
60
- private _handleNewMessage;
61
- private _handleTypingEvent;
62
- private _handleReadCursorEvent;
63
- private _notifyConnectionChange;
64
- private _createUI;
65
- private _attachEventListeners;
66
- private _handleUserTyping;
67
- private _sendTypingIndicator;
68
- private _handleSend;
69
- private _updateUI;
70
- private _updateHeader;
71
- private _getChannelListHTML;
72
- private _getChannelItemHTML;
73
- private _getConversationHTML;
74
- private _attachChannelListListeners;
75
- private _attachConversationListeners;
76
- private _formatRelativeTime;
77
- private _renderMessages;
78
- private _getContainerStyles;
79
- private _getBubbleStyles;
80
- private _getBubbleHTML;
81
- private _getWidgetStyles;
82
- private _getWidgetHTML;
83
- private _getMessageHTML;
84
- private _isMessageReadByAgent;
85
- /**
86
- * Handle streaming AI response
87
- * Industry standard: Real-time streaming with progressive UI updates
88
- */
89
- private _handleStreamingResponse;
90
- /**
91
- * Remove temporary message by ID
92
- */
93
- private _removeTempMessage;
94
- private _apiRequest;
95
- private _trackEvent;
96
- private _getTimeOpen;
97
- private _escapeHTML;
98
- private _formatTime;
99
- }