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