@cuekit-ai/react 1.3.2 → 1.3.4

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.
@@ -1,764 +0,0 @@
1
- // src/core/globals.ts
2
- var _apiKey = "";
3
- var _appId = "";
4
- var setApiKey = (key) => _apiKey = key;
5
- var setAppId = (id) => _appId = id;
6
- var _webRTCConfig = null;
7
- var _webRTCConnectionState = {
8
- isConnected: false,
9
- isConnecting: false,
10
- participants: []
11
- };
12
- var setWebRTCConfig = (config) => _webRTCConfig = config;
13
- var setWebRTCConnectionState = (state) => {
14
- _webRTCConnectionState = { ..._webRTCConnectionState, ...state };
15
- };
16
-
17
- // src/constants/index.ts
18
- var WEBRTC_BACKEND_SERVER_URL = "https://api-webrtc-dev.ansyr.ai";
19
-
20
- // src/utils/jsx-encoder.ts
21
- function generateStableDOMId(element) {
22
- const tagName = element.tagName.toLowerCase();
23
- const text = (element.textContent || "").trim().substring(0, 50);
24
- let sibling = element.previousElementSibling;
25
- let position = 1;
26
- while (sibling) {
27
- if (sibling.tagName === element.tagName) {
28
- position++;
29
- }
30
- sibling = sibling.previousElementSibling;
31
- }
32
- const path = getElementPath(element);
33
- const idString = `${tagName}[${position}]_(${text})_${path}`;
34
- let hash = 0;
35
- for (let i = 0; i < idString.length; i++) {
36
- const char = idString.charCodeAt(i);
37
- hash = (hash << 5) - hash + char;
38
- hash |= 0;
39
- }
40
- return hash.toString(36);
41
- }
42
- function getElementPath(element) {
43
- if (element.id) {
44
- return `id(${element.id})`;
45
- }
46
- if (element.tagName.toLowerCase() === "body") {
47
- return "/body";
48
- }
49
- let ix = 0;
50
- const siblings = element.parentNode?.children || new HTMLCollection();
51
- for (let i = 0; i < siblings.length; i++) {
52
- const sibling = siblings[i];
53
- if (sibling === element) {
54
- return `${getElementPath(element.parentNode)}/${element.tagName}[${ix + 1}]`;
55
- }
56
- if (sibling.nodeType === 1 && sibling.tagName === element.tagName) {
57
- ix++;
58
- }
59
- }
60
- return "not_found";
61
- }
62
-
63
- // src/core/intent-store.ts
64
- var store = {
65
- screenMetadata: {},
66
- allElementsData: []
67
- };
68
- var GlobalStore = {
69
- // 🔹 Screen Metadata Methods
70
- setMetadata(screen, metadata) {
71
- store.screenMetadata[screen] = metadata;
72
- },
73
- getMetadata(screen) {
74
- return store.screenMetadata[screen];
75
- },
76
- clearMetadata(screen) {
77
- delete store.screenMetadata[screen];
78
- },
79
- // 🔹 Generic Store Access Methods
80
- setData(key, value) {
81
- store[key] = value;
82
- },
83
- getData(key) {
84
- return store[key];
85
- },
86
- clearData(key) {
87
- delete store[key];
88
- },
89
- // 🔹 Element Data Management
90
- setElement(elementData) {
91
- const index = store.allElementsData.findIndex((e) => e.elementId === elementData.elementId);
92
- if (index >= 0) {
93
- console.log("Updating existing element");
94
- store.allElementsData[index] = elementData;
95
- } else {
96
- console.log("Adding new element");
97
- store.allElementsData.push(elementData);
98
- }
99
- },
100
- getElementById(elementId) {
101
- const match = store.allElementsData.find((e) => e.elementId === elementId);
102
- if (!match) {
103
- console.warn(`[GlobalStore] No element found for ID: ${elementId}`);
104
- console.log("All elements in store:", store.allElementsData);
105
- }
106
- return match;
107
- },
108
- deleteElementById(id) {
109
- store.allElementsData = store.allElementsData.filter((e) => e.elementId !== id);
110
- },
111
- clearAllElements() {
112
- store.allElementsData = [];
113
- }
114
- };
115
-
116
- // src/core/navigation.ts
117
- var navigation;
118
- var navigationHandler = null;
119
- function setNavigationHandler(handler) {
120
- navigationHandler = handler;
121
- }
122
- function navigate(path, params) {
123
- const safeParams = params || {};
124
- const absolutePath = path.startsWith("/") ? path : `/${path}`;
125
- if (navigationHandler) {
126
- try {
127
- navigationHandler(absolutePath, safeParams);
128
- } catch (error) {
129
- console.error("[CueKit] navigation handler failed, falling back to default:", error);
130
- }
131
- return;
132
- }
133
- let fullPath = absolutePath;
134
- if (safeParams) {
135
- const searchParams = new URLSearchParams(safeParams).toString();
136
- if (searchParams) {
137
- fullPath += `?${searchParams}`;
138
- }
139
- }
140
- if (navigation) {
141
- navigation.push(fullPath);
142
- } else {
143
- if (typeof window !== "undefined") {
144
- window.location.href = fullPath;
145
- }
146
- }
147
- }
148
- var getCurrentPath = () => {
149
- if (typeof window === "undefined") return "";
150
- return window.location.pathname;
151
- };
152
- var getSearchParams = () => {
153
- if (typeof window === "undefined") return new URLSearchParams();
154
- return new URLSearchParams(window.location.search);
155
- };
156
- var safeNavigate = (name, params = {}) => {
157
- if (name) {
158
- navigate(name, params);
159
- } else {
160
- console.warn("[CueKit] route name not provided");
161
- }
162
- };
163
- function getCurrentScreenName() {
164
- try {
165
- const path = getCurrentPath();
166
- return path || "UnknownScreen";
167
- } catch (e) {
168
- return "UnknownScreen";
169
- }
170
- }
171
- function getCurrentRouteParams() {
172
- try {
173
- const params = {};
174
- const searchParams = getSearchParams();
175
- if (searchParams instanceof URLSearchParams) {
176
- searchParams.forEach((value, key) => {
177
- params[key] = value;
178
- });
179
- } else {
180
- return searchParams;
181
- }
182
- return params;
183
- } catch (e) {
184
- return {};
185
- }
186
- }
187
- function onStateChange() {
188
- const routeName = getCurrentScreenName();
189
- const params = getCurrentRouteParams();
190
- if (params && params.metadata) {
191
- try {
192
- const metadata = JSON.parse(params.metadata);
193
- GlobalStore.setMetadata(routeName, metadata);
194
- } catch (error) {
195
- console.error("Failed to parse metadata from URL:", error);
196
- }
197
- }
198
- }
199
- var handleNavigationAndClick = (routeName, elementHash) => {
200
- safeNavigate(routeName);
201
- if (typeof MutationObserver === "undefined" || typeof document === "undefined") return;
202
- const observer = new MutationObserver((mutationsList, observer2) => {
203
- setTimeout(() => {
204
- const allElements = document.querySelectorAll("*");
205
- let elementToClick = null;
206
- for (const element of allElements) {
207
- if (element instanceof HTMLElement) {
208
- const tagName = element.tagName.toLowerCase();
209
- const text = (element.textContent || "").trim().substring(0, 50);
210
- let sibling = element.previousElementSibling;
211
- let position = 1;
212
- while (sibling) {
213
- if (sibling.tagName === element.tagName) {
214
- position++;
215
- }
216
- sibling = sibling.previousElementSibling;
217
- }
218
- const path = getElementPath2(element);
219
- const idString = `${tagName}[${position}]_(${text})_${path}`;
220
- let hash = 0;
221
- for (let i = 0; i < idString.length; i++) {
222
- const char = idString.charCodeAt(i);
223
- hash = (hash << 5) - hash + char;
224
- hash |= 0;
225
- }
226
- const elementHashValue = hash.toString(36);
227
- if (elementHashValue === elementHash) {
228
- elementToClick = element;
229
- break;
230
- }
231
- }
232
- }
233
- if (elementToClick) {
234
- elementToClick.click();
235
- observer2.disconnect();
236
- }
237
- }, 100);
238
- });
239
- if (typeof window === "undefined") return;
240
- observer.observe(document.body, { childList: true, subtree: true });
241
- };
242
- function getElementPath2(element) {
243
- if (typeof window === "undefined") return "";
244
- if (element.id) {
245
- return `id(${element.id})`;
246
- }
247
- const path = [];
248
- let current = element;
249
- while (current && current !== document.body) {
250
- let index = 1;
251
- let sibling = current.previousElementSibling;
252
- while (sibling) {
253
- if (sibling.tagName === current.tagName) {
254
- index++;
255
- }
256
- sibling = sibling.previousElementSibling;
257
- }
258
- path.unshift(`${current.tagName.toLowerCase()}[${index}]`);
259
- current = current.parentElement;
260
- }
261
- return path.join("/");
262
- }
263
-
264
- // src/utils/element-service.ts
265
- var INTERACTIVE_ELEMENT_SELECTOR = 'a, button, input, textarea, select, [role="button"], [onclick]';
266
- function getInteractiveElements() {
267
- if (typeof document === "undefined") {
268
- return new class extends Array {
269
- }();
270
- }
271
- return document.querySelectorAll(INTERACTIVE_ELEMENT_SELECTOR);
272
- }
273
- function getImmediateText(element) {
274
- let text = "";
275
- if (element.childNodes) {
276
- for (const node of Array.from(element.childNodes)) {
277
- if (node.nodeType === 3) {
278
- text += node.textContent || "";
279
- }
280
- }
281
- }
282
- return text.trim();
283
- }
284
- function captureFullDOMStructure() {
285
- console.log("\u{1F333} Capturing full DOM structure...");
286
- const components = [];
287
- const interactiveElements = getInteractiveElements();
288
- interactiveElements.forEach((element) => {
289
- if (element instanceof HTMLElement && !element.closest("[data-cuekit-ignore]")) {
290
- const nodeData = buildFlatDOMNode(element);
291
- if (nodeData) {
292
- components.push(nodeData);
293
- }
294
- }
295
- });
296
- const result = { components };
297
- console.log("\u{1F333} Full DOM structure captured:", result);
298
- return result;
299
- }
300
- function buildFlatDOMNode(element) {
301
- if (element.tagName.toLowerCase() === "script" || element.hasAttribute("data-cuekit-ignore") || element.style.display === "none" || element.style.visibility === "hidden") {
302
- return null;
303
- }
304
- const hash = generateStableDOMId(element);
305
- const text = getImmediateText(element).substring(0, 100);
306
- const isClickable = isElementClickable(element);
307
- const componentType = element.tagName.toLowerCase();
308
- return {
309
- hash,
310
- text,
311
- isClickable,
312
- componentType,
313
- children: []
314
- // No children in a flat structure
315
- };
316
- }
317
- function isElementClickable(element) {
318
- const interactiveSelectors = [
319
- "button",
320
- "a",
321
- "input",
322
- "select",
323
- "textarea",
324
- '[role="button"]',
325
- '[role="link"]',
326
- '[role="tab"]',
327
- "[data-onclick-id]",
328
- "[data-on-press-id]",
329
- "[onclick]",
330
- "[onmousedown]",
331
- "[onmouseup]",
332
- "[ontouchstart]",
333
- "[ontouchend]",
334
- "[onkeydown]",
335
- "[onkeyup]",
336
- "[onkeypress]"
337
- ];
338
- for (const selector of interactiveSelectors) {
339
- if (element.matches(selector)) {
340
- return true;
341
- }
342
- }
343
- const hasClickEvents = element.onclick !== null || element.getAttribute("onclick") !== null;
344
- const hasInteractiveEvents = element.ontouchstart !== null || element.getAttribute("ontouchstart") !== null || element.ontouchend !== null || element.getAttribute("ontouchend") !== null || element.onkeydown !== null || element.getAttribute("onkeydown") !== null || element.onkeyup !== null || element.getAttribute("onkeyup") !== null || element.onkeypress !== null || element.getAttribute("onkeypress") !== null;
345
- const hasPointerCursor = element.style.cursor === "pointer" || getComputedStyle(element).cursor === "pointer";
346
- const hasTabIndex = element.hasAttribute("tabindex") && parseInt(element.getAttribute("tabindex") || "0") >= 0;
347
- const hasInteractiveDataAttrs = element.hasAttribute("data-clickable") || element.hasAttribute("data-interactive") || element.hasAttribute("data-action") || element.hasAttribute("data-handler");
348
- const hasInteractiveAria = element.hasAttribute("aria-pressed") || element.hasAttribute("aria-expanded") || element.hasAttribute("aria-selected") || element.hasAttribute("aria-checked");
349
- return hasClickEvents || hasInteractiveEvents || hasPointerCursor || hasTabIndex || hasInteractiveDataAttrs || hasInteractiveAria;
350
- }
351
- function executeAction(action) {
352
- console.log("\u{1F3AF} Executing element action:", action);
353
- const { action_type, target_element, target } = action;
354
- switch (action_type) {
355
- case "click":
356
- return clickElement(target_element);
357
- case "navigate":
358
- return navigateToElement(target_element || target);
359
- case "input":
360
- case "focus":
361
- return focusElement(target_element);
362
- case "toggle":
363
- return toggleElement(target_element);
364
- default:
365
- console.warn(`\u26A0\uFE0F Unknown action type: ${action_type}`);
366
- return false;
367
- }
368
- }
369
- function getFullDOMStructure() {
370
- console.log("\u{1F333} ElementService: Getting full DOM structure...");
371
- return captureFullDOMStructure();
372
- }
373
- function clickElement(elementId) {
374
- if (!elementId) {
375
- console.warn("\u26A0\uFE0F No element ID provided for click action");
376
- return false;
377
- }
378
- const domStructure = getFullDOMStructure();
379
- const elementToClick = findElementById(domStructure, elementId);
380
- if (elementToClick) {
381
- console.log(`\u{1F3AF} Clicking element: ${elementId}`);
382
- const domElement = findDOMElementById(elementId);
383
- if (domElement) {
384
- domElement.click();
385
- return true;
386
- }
387
- } else {
388
- console.warn(`\u26A0\uFE0F Element not found: ${elementId}`);
389
- }
390
- return false;
391
- }
392
- function navigateToElement(target) {
393
- if (!target) {
394
- console.warn("\u26A0\uFE0F No target provided for navigation action");
395
- return false;
396
- }
397
- console.log(`\u{1F9ED} Navigating to: ${target}`);
398
- if (target.includes("/") || target.startsWith("http")) {
399
- safeNavigate(target, {});
400
- } else {
401
- handleNavigationAndClick(target, target);
402
- }
403
- return true;
404
- }
405
- function focusElement(elementId) {
406
- if (!elementId) {
407
- console.warn("\u26A0\uFE0F No element ID provided for focus action");
408
- return false;
409
- }
410
- const domElement = findDOMElementById(elementId);
411
- if (domElement instanceof HTMLInputElement || domElement instanceof HTMLTextAreaElement || domElement instanceof HTMLSelectElement) {
412
- console.log(`\u{1F4DD} Focusing element: ${elementId}`);
413
- domElement.focus();
414
- return true;
415
- } else {
416
- console.warn(`\u26A0\uFE0F Focusable element not found: ${elementId}`);
417
- return false;
418
- }
419
- }
420
- function toggleElement(elementId) {
421
- if (!elementId) {
422
- console.warn("\u26A0\uFE0F No element ID provided for toggle action");
423
- return false;
424
- }
425
- const domElement = findDOMElementById(elementId);
426
- if (domElement instanceof HTMLElement) {
427
- console.log(`\u{1F504} Toggling element: ${elementId}`);
428
- if (domElement instanceof HTMLInputElement) {
429
- if (domElement.type === "checkbox") {
430
- domElement.checked = !domElement.checked;
431
- } else if (domElement.type === "radio") {
432
- domElement.checked = true;
433
- }
434
- domElement.dispatchEvent(new Event("change", { bubbles: true }));
435
- } else {
436
- domElement.click();
437
- }
438
- return true;
439
- } else {
440
- console.warn(`\u26A0\uFE0F Toggleable element not found: ${elementId}`);
441
- return false;
442
- }
443
- }
444
- function findElementById(domStructure, elementId) {
445
- const searchInComponents = (components) => {
446
- for (const component of components) {
447
- if (component.hash === elementId) {
448
- return component;
449
- }
450
- if (component.children.length > 0) {
451
- const found = searchInComponents(component.children);
452
- if (found) return found;
453
- }
454
- }
455
- return null;
456
- };
457
- return searchInComponents(domStructure.components);
458
- }
459
- function findDOMElementById(elementId) {
460
- const interactiveElements = getInteractiveElements();
461
- for (const element of interactiveElements) {
462
- if (element instanceof HTMLElement) {
463
- console.log("\u{1F50D} Checking element:", element);
464
- const hash = generateStableDOMId(element);
465
- console.log("\u{1F50D} Generated hash:", hash);
466
- if (hash === elementId) {
467
- console.log("\u{1F50D} Found element:", element);
468
- return element;
469
- }
470
- }
471
- }
472
- return null;
473
- }
474
-
475
- // src/utils/webrtc-service.ts
476
- var room = null;
477
- var reconnectTimeout = null;
478
- var serverUrl = WEBRTC_BACKEND_SERVER_URL || "https://bdd4c945f073.ngrok-free.app";
479
- var callbacks = {};
480
- var audioContainerRef = null;
481
- var livekitUrl = null;
482
- var token = null;
483
- var roomName = null;
484
- var livekitClient = null;
485
- async function getLiveKitClient() {
486
- if (!livekitClient) {
487
- livekitClient = await import("./livekit-client.esm-33GHDCYA.mjs");
488
- }
489
- return livekitClient;
490
- }
491
- function setServerUrl(url) {
492
- serverUrl = url;
493
- }
494
- function setAudioContainer(newAudioContainerRef) {
495
- audioContainerRef = newAudioContainerRef;
496
- }
497
- function setWebRTCCallbacks(newCallbacks) {
498
- callbacks = newCallbacks;
499
- }
500
- async function authenticate(userIdentity, apiKey, appId) {
501
- try {
502
- console.log("\u{1F3A4} WebRTCService: Authenticating user...", { userIdentity });
503
- const response = await fetch(`${serverUrl}/auth/login`, {
504
- method: "POST",
505
- headers: {
506
- "Content-Type": "application/json",
507
- "X-API-Key": apiKey
508
- },
509
- body: JSON.stringify({
510
- user_identity: userIdentity,
511
- app_id: appId || _appId
512
- })
513
- });
514
- if (!response.ok) {
515
- const errorData = await response.json();
516
- throw new Error(errorData.detail || "Authentication failed");
517
- }
518
- const authData = await response.json();
519
- console.log("\u{1F3A4} WebRTCService: Authentication successful:", authData);
520
- livekitUrl = authData.livekit_url;
521
- token = authData.livekit_token;
522
- roomName = authData.room_name;
523
- userIdentity = authData.user_identity;
524
- return authData;
525
- } catch (error) {
526
- console.error("\u{1F3A4} WebRTCService: Authentication failed:", error);
527
- throw error;
528
- }
529
- }
530
- async function connectToRoom(newLivekitUrl, newToken) {
531
- const url = newLivekitUrl || livekitUrl;
532
- const authToken = newToken || token;
533
- if (!url || !authToken) {
534
- throw new Error("Missing LiveKit URL or token. Please authenticate first.");
535
- }
536
- console.log("\u{1F3A4} WebRTCService: Connecting to room...", { url, hasToken: !!authToken });
537
- try {
538
- setWebRTCConnectionState({ isConnected: false, isConnecting: true });
539
- const { Room } = await getLiveKitClient();
540
- room = new Room({
541
- adaptiveStream: true,
542
- dynacast: true
543
- });
544
- await setupEventListeners();
545
- await room?.connect(url, authToken);
546
- console.log("\u{1F3A4} WebRTCService: Successfully connected to room:", room?.name);
547
- setWebRTCConnectionState({ isConnected: true, isConnecting: false });
548
- try {
549
- await room?.localParticipant.setMicrophoneEnabled(true);
550
- console.log("\u{1F3A4} WebRTCService: Microphone enabled");
551
- } catch (micError) {
552
- console.warn("\u{1F3A4} WebRTCService: Failed to enable microphone:", micError);
553
- }
554
- return { success: true };
555
- } catch (error) {
556
- console.error("\u{1F3A4} WebRTCService: Failed to connect to room:", error);
557
- setWebRTCConnectionState({ isConnected: false, isConnecting: false });
558
- throw error;
559
- }
560
- }
561
- async function setupEventListeners() {
562
- if (!room) return;
563
- const { RoomEvent, ConnectionState, Track } = await getLiveKitClient();
564
- room.on(RoomEvent.ConnectionStateChanged, (state) => {
565
- console.log("\u{1F3A4} WebRTCService: Connection state changed:", state);
566
- callbacks.onConnectionStateChange?.(state);
567
- if (state === ConnectionState.Connected) {
568
- console.log("\u{1F3A4} WebRTCService: Successfully connected to room");
569
- setWebRTCConnectionState({ isConnected: true, isConnecting: false });
570
- } else if (state === ConnectionState.Disconnected) {
571
- console.log("\u{1F3A4} WebRTCService: Disconnected from room");
572
- setWebRTCConnectionState({ isConnected: false, isConnecting: false });
573
- } else if (state === ConnectionState.Connecting) {
574
- console.log("\u{1F3A4} WebRTCService: Connecting to room...");
575
- setWebRTCConnectionState({ isConnected: false, isConnecting: true });
576
- }
577
- }).on(RoomEvent.ParticipantConnected, (participant) => {
578
- console.log("\u{1F3A4} WebRTCService: Participant connected:", participant.identity);
579
- updateParticipantsList();
580
- }).on(RoomEvent.ParticipantDisconnected, (participant) => {
581
- console.log("\u{1F3A4} WebRTCService: Participant disconnected:", participant.identity);
582
- updateParticipantsList();
583
- }).on(
584
- RoomEvent.TrackSubscribed,
585
- (track, publication, participant) => {
586
- if (track.kind === Track.Kind.Audio && !participant.isLocal) {
587
- const isAIParticipant = participant.identity.toLowerCase().includes("ai") || participant.identity.toLowerCase().includes("bot") || !participant.identity.startsWith("user_");
588
- if (isAIParticipant) {
589
- const element = track.attach();
590
- if (audioContainerRef?.current) {
591
- audioContainerRef.current.appendChild(element);
592
- if (element instanceof HTMLAudioElement) {
593
- const trackId = track.sid || `track_${Date.now()}_${Math.random()}`;
594
- callbacks.onAISpeechStart?.(trackId);
595
- element.play().catch(
596
- (error) => console.warn("\u{1F3A4} WebRTCService: Failed to auto-play audio:", error)
597
- );
598
- element.addEventListener("ended", () => callbacks.onAISpeechEnd?.(trackId));
599
- element.addEventListener("pause", () => callbacks.onAISpeechEnd?.(trackId));
600
- }
601
- }
602
- }
603
- }
604
- }
605
- ).on(RoomEvent.TrackUnsubscribed, (track) => {
606
- track.detach().forEach((element) => element.remove());
607
- }).on(RoomEvent.DataReceived, (payload, participant) => {
608
- console.log("\u{1F4E1} LiveKit data received:", new TextDecoder().decode(payload));
609
- try {
610
- const message = JSON.parse(new TextDecoder().decode(payload));
611
- console.log("\u{1F4E1} LiveKit data received:", message);
612
- callbacks.onNavigationCommand?.(message);
613
- } catch (error) {
614
- const message = new TextDecoder().decode(payload);
615
- callbacks.onNavigationCommand?.({ type: "raw_text", data: message });
616
- }
617
- }).on(RoomEvent.Disconnected, () => {
618
- setWebRTCConnectionState({ isConnected: false, isConnecting: false });
619
- });
620
- }
621
- function updateParticipantsList() {
622
- if (!room) return;
623
- const participants = [
624
- room.localParticipant.identity,
625
- ...Array.from(room.remoteParticipants.values()).map((p) => p.identity)
626
- ];
627
- setWebRTCConnectionState({ participants });
628
- callbacks.onParticipantUpdate?.(participants);
629
- }
630
- async function sendData(data, reliable = true) {
631
- if (!room) throw new Error("Not connected to room");
632
- try {
633
- console.log("\u{1F4E1} LiveKit data sending:", data);
634
- const encoder = new TextEncoder();
635
- const encodedData = encoder.encode(data);
636
- await room.localParticipant.publishData(encodedData, {
637
- reliable
638
- });
639
- } catch (error) {
640
- console.error("\u274C Failed to send data:", error);
641
- }
642
- }
643
- async function sendScreenStatus(screenData) {
644
- try {
645
- await fetch(`${serverUrl}/ai/data`, {
646
- method: "POST",
647
- headers: { "Content-Type": "application/json" },
648
- body: JSON.stringify(screenData)
649
- });
650
- } catch (error) {
651
- console.error("Error sending screen status:", error);
652
- throw error;
653
- }
654
- }
655
- async function isConnected() {
656
- if (!room) return false;
657
- const { ConnectionState } = await getLiveKitClient();
658
- return room?.state === ConnectionState.Connected;
659
- }
660
- function getRoomName() {
661
- return roomName;
662
- }
663
- function getParticipants() {
664
- return Array.from(room?.remoteParticipants.values() ?? []);
665
- }
666
- async function sendUserCommand(command) {
667
- if (!room) return;
668
- console.log(`\u{1F4AC} Sending user command: "${command}"`);
669
- await sendData(command);
670
- }
671
- async function sendRuntimeData() {
672
- if (!room) {
673
- console.error("\u274C Cannot send runtime data without a room connection");
674
- return;
675
- }
676
- try {
677
- const domStructure = captureFullDOMStructure();
678
- const screenName = getCurrentScreenName();
679
- const response = {
680
- type: "runtime_data_response",
681
- data: {
682
- components: domStructure.components,
683
- current_screen: screenName
684
- }
685
- };
686
- console.log("\u{1F4E6} Sending runtime data response");
687
- await sendData(JSON.stringify(response));
688
- console.log("\u{1F4E6} Runtime data sent successfully");
689
- } catch (error) {
690
- console.error("\u274C Failed to send runtime data:", error);
691
- }
692
- }
693
- async function sendStaticData(componentData, appId = "default") {
694
- try {
695
- const response = await fetch(`${serverUrl}/ai/data`, {
696
- method: "POST",
697
- headers: {
698
- "Content-Type": "application/json"
699
- },
700
- body: JSON.stringify({
701
- type: "dashboard_data",
702
- app_id: appId,
703
- data: componentData
704
- })
705
- });
706
- if (response.ok) {
707
- const result = await response.json();
708
- return { success: true, data: result };
709
- } else {
710
- const errorText = await response.text();
711
- return { success: false, error: `HTTP ${response.status}: ${errorText}` };
712
- }
713
- } catch (error) {
714
- return { success: false, error: error instanceof Error ? error.message : "Network error" };
715
- }
716
- }
717
- async function disconnectFromRoom() {
718
- if (room) {
719
- await room.disconnect();
720
- room = null;
721
- }
722
- if (reconnectTimeout) {
723
- clearTimeout(reconnectTimeout);
724
- reconnectTimeout = null;
725
- }
726
- setWebRTCConnectionState({
727
- isConnected: false,
728
- isConnecting: false,
729
- participants: []
730
- });
731
- }
732
- function getRoom() {
733
- return room;
734
- }
735
-
736
- export {
737
- _apiKey,
738
- _appId,
739
- setApiKey,
740
- setAppId,
741
- setWebRTCConfig,
742
- GlobalStore,
743
- setNavigationHandler,
744
- onStateChange,
745
- WEBRTC_BACKEND_SERVER_URL,
746
- captureFullDOMStructure,
747
- executeAction,
748
- getFullDOMStructure,
749
- setServerUrl,
750
- setAudioContainer,
751
- setWebRTCCallbacks,
752
- authenticate,
753
- connectToRoom,
754
- sendData,
755
- sendScreenStatus,
756
- isConnected,
757
- getRoomName,
758
- getParticipants,
759
- sendUserCommand,
760
- sendRuntimeData,
761
- sendStaticData,
762
- disconnectFromRoom,
763
- getRoom
764
- };