@cuekit-ai/react 1.2.3 → 1.3.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/dist/index.js CHANGED
@@ -55,12 +55,223 @@ var init_globals = __esm({
55
55
  }
56
56
  });
57
57
 
58
+ // src/core/intent-store.ts
59
+ var store, GlobalStore;
60
+ var init_intent_store = __esm({
61
+ "src/core/intent-store.ts"() {
62
+ "use strict";
63
+ store = {
64
+ screenMetadata: {},
65
+ allElementsData: []
66
+ };
67
+ GlobalStore = {
68
+ // 🔹 Screen Metadata Methods
69
+ setMetadata(screen, metadata) {
70
+ store.screenMetadata[screen] = metadata;
71
+ },
72
+ getMetadata(screen) {
73
+ return store.screenMetadata[screen];
74
+ },
75
+ clearMetadata(screen) {
76
+ delete store.screenMetadata[screen];
77
+ },
78
+ // 🔹 Generic Store Access Methods
79
+ setData(key, value) {
80
+ store[key] = value;
81
+ },
82
+ getData(key) {
83
+ return store[key];
84
+ },
85
+ clearData(key) {
86
+ delete store[key];
87
+ },
88
+ // 🔹 Element Data Management
89
+ setElement(elementData) {
90
+ const index2 = store.allElementsData.findIndex((e3) => e3.elementId === elementData.elementId);
91
+ if (index2 >= 0) {
92
+ console.log("Updating existing element");
93
+ store.allElementsData[index2] = elementData;
94
+ } else {
95
+ console.log("Adding new element");
96
+ store.allElementsData.push(elementData);
97
+ }
98
+ },
99
+ getElementById(elementId) {
100
+ const match = store.allElementsData.find((e3) => e3.elementId === elementId);
101
+ if (!match) {
102
+ console.warn(`[GlobalStore] No element found for ID: ${elementId}`);
103
+ console.log("All elements in store:", store.allElementsData);
104
+ }
105
+ return match;
106
+ },
107
+ deleteElementById(id) {
108
+ store.allElementsData = store.allElementsData.filter((e3) => e3.elementId !== id);
109
+ },
110
+ clearAllElements() {
111
+ store.allElementsData = [];
112
+ }
113
+ };
114
+ }
115
+ });
116
+
117
+ // src/core/navigation.ts
118
+ function setNavigationHandler(handler) {
119
+ navigationHandler = handler;
120
+ }
121
+ function navigate(path2, params) {
122
+ const safeParams = params || {};
123
+ const absolutePath = path2.startsWith("/") ? path2 : `/${path2}`;
124
+ if (navigationHandler) {
125
+ try {
126
+ navigationHandler(absolutePath, safeParams);
127
+ } catch (error) {
128
+ console.error("[CueKit] navigation handler failed, falling back to default:", error);
129
+ }
130
+ return;
131
+ }
132
+ let fullPath = absolutePath;
133
+ if (safeParams) {
134
+ const searchParams = new URLSearchParams(safeParams).toString();
135
+ if (searchParams) {
136
+ fullPath += `?${searchParams}`;
137
+ }
138
+ }
139
+ if (navigation) {
140
+ navigation.push(fullPath);
141
+ } else {
142
+ if (typeof window !== "undefined") {
143
+ window.location.href = fullPath;
144
+ }
145
+ }
146
+ }
147
+ function getCurrentScreenName() {
148
+ try {
149
+ const path2 = getCurrentPath();
150
+ return path2 || "UnknownScreen";
151
+ } catch (e3) {
152
+ return "UnknownScreen";
153
+ }
154
+ }
155
+ function getCurrentRouteParams() {
156
+ try {
157
+ const params = {};
158
+ const searchParams = getSearchParams();
159
+ if (searchParams instanceof URLSearchParams) {
160
+ searchParams.forEach((value, key) => {
161
+ params[key] = value;
162
+ });
163
+ } else {
164
+ return searchParams;
165
+ }
166
+ return params;
167
+ } catch (e3) {
168
+ return {};
169
+ }
170
+ }
171
+ function onStateChange() {
172
+ const routeName = getCurrentScreenName();
173
+ const params = getCurrentRouteParams();
174
+ if (params && params.metadata) {
175
+ try {
176
+ const metadata = JSON.parse(params.metadata);
177
+ GlobalStore.setMetadata(routeName, metadata);
178
+ } catch (error) {
179
+ console.error("Failed to parse metadata from URL:", error);
180
+ }
181
+ }
182
+ }
183
+ function getElementPath(element3) {
184
+ if (element3.id) {
185
+ return `id(${element3.id})`;
186
+ }
187
+ const path2 = [];
188
+ let current = element3;
189
+ while (current && current !== document.body) {
190
+ let index2 = 1;
191
+ let sibling = current.previousElementSibling;
192
+ while (sibling) {
193
+ if (sibling.tagName === current.tagName) {
194
+ index2++;
195
+ }
196
+ sibling = sibling.previousElementSibling;
197
+ }
198
+ path2.unshift(`${current.tagName.toLowerCase()}[${index2}]`);
199
+ current = current.parentElement;
200
+ }
201
+ return path2.join("/");
202
+ }
203
+ var navigation, navigationHandler, getCurrentPath, getSearchParams, safeNavigate, handleNavigationAndClick;
204
+ var init_navigation = __esm({
205
+ "src/core/navigation.ts"() {
206
+ "use strict";
207
+ init_intent_store();
208
+ navigationHandler = null;
209
+ getCurrentPath = () => {
210
+ if (typeof window === "undefined") return "";
211
+ return window.location.pathname;
212
+ };
213
+ getSearchParams = () => {
214
+ if (typeof window === "undefined") return new URLSearchParams();
215
+ return new URLSearchParams(window.location.search);
216
+ };
217
+ safeNavigate = (name2, params = {}) => {
218
+ if (name2) {
219
+ navigate(name2, params);
220
+ } else {
221
+ console.warn("[CueKit] route name not provided");
222
+ }
223
+ };
224
+ handleNavigationAndClick = (routeName, elementHash) => {
225
+ safeNavigate(routeName);
226
+ if (typeof MutationObserver === "undefined" || typeof document === "undefined") return;
227
+ const observer = new MutationObserver((mutationsList, observer2) => {
228
+ setTimeout(() => {
229
+ const allElements = document.querySelectorAll("*");
230
+ let elementToClick = null;
231
+ for (const element3 of allElements) {
232
+ if (element3 instanceof HTMLElement) {
233
+ const tagName = element3.tagName.toLowerCase();
234
+ const text7 = (element3.textContent || "").trim().substring(0, 50);
235
+ let sibling = element3.previousElementSibling;
236
+ let position3 = 1;
237
+ while (sibling) {
238
+ if (sibling.tagName === element3.tagName) {
239
+ position3++;
240
+ }
241
+ sibling = sibling.previousElementSibling;
242
+ }
243
+ const path2 = getElementPath(element3);
244
+ const idString = `${tagName}[${position3}]_(${text7})_${path2}`;
245
+ let hash = 0;
246
+ for (let i2 = 0; i2 < idString.length; i2++) {
247
+ const char = idString.charCodeAt(i2);
248
+ hash = (hash << 5) - hash + char;
249
+ hash |= 0;
250
+ }
251
+ const elementHashValue = hash.toString(36);
252
+ if (elementHashValue === elementHash) {
253
+ elementToClick = element3;
254
+ break;
255
+ }
256
+ }
257
+ }
258
+ if (elementToClick) {
259
+ elementToClick.click();
260
+ observer2.disconnect();
261
+ }
262
+ }, 100);
263
+ });
264
+ observer.observe(document.body, { childList: true, subtree: true });
265
+ };
266
+ }
267
+ });
268
+
58
269
  // src/constants/index.ts
59
270
  var WEBRTC_BACKEND_SERVER_URL;
60
271
  var init_constants = __esm({
61
272
  "src/constants/index.ts"() {
62
273
  "use strict";
63
- WEBRTC_BACKEND_SERVER_URL = "https://api-webrtc.cuekit.ai";
274
+ WEBRTC_BACKEND_SERVER_URL = "https://api-webrtc-dev.cuekit.ai";
64
275
  }
65
276
  });
66
277
 
@@ -4472,15 +4683,15 @@ function requireSdp() {
4472
4683
  return Math.random().toString().substr(2, 22);
4473
4684
  };
4474
4685
  SDPUtils2.writeSessionBoilerplate = function(sessId, sessVer, sessUser) {
4475
- let sessionId2;
4686
+ let sessionId;
4476
4687
  const version2 = sessVer !== void 0 ? sessVer : 2;
4477
4688
  if (sessId) {
4478
- sessionId2 = sessId;
4689
+ sessionId = sessId;
4479
4690
  } else {
4480
- sessionId2 = SDPUtils2.generateSessionId();
4691
+ sessionId = SDPUtils2.generateSessionId();
4481
4692
  }
4482
4693
  const user = sessUser || "thisisadapterortc";
4483
- return "v=0\r\no=" + user + " " + sessionId2 + " " + version2 + " IN IP4 127.0.0.1\r\ns=-\r\nt=0 0\r\n";
4694
+ return "v=0\r\no=" + user + " " + sessionId + " " + version2 + " IN IP4 127.0.0.1\r\ns=-\r\nt=0 0\r\n";
4484
4695
  };
4485
4696
  SDPUtils2.getDirection = function(mediaSection, sessionpart) {
4486
4697
  const lines = SDPUtils2.splitLines(mediaSection);
@@ -5204,8 +5415,8 @@ function isWeb() {
5204
5415
  function isReactNative() {
5205
5416
  return navigator.product == "ReactNative";
5206
5417
  }
5207
- function isCloud(serverUrl3) {
5208
- return serverUrl3.hostname.endsWith(".livekit.cloud") || serverUrl3.hostname.endsWith(".livekit.run");
5418
+ function isCloud(serverUrl2) {
5419
+ return serverUrl2.hostname.endsWith(".livekit.cloud") || serverUrl2.hostname.endsWith(".livekit.run");
5209
5420
  }
5210
5421
  function getLKReactNativeInfo() {
5211
5422
  if (global && global.LiveKitReactNativeGlobal) {
@@ -7127,8 +7338,8 @@ function applyUserDataCompat(newObj, oldObj) {
7127
7338
  newObj.destinationIdentities = destinationIdentities;
7128
7339
  oldObj.destinationIdentities = destinationIdentities;
7129
7340
  }
7130
- function getCloudConfigUrl(serverUrl3) {
7131
- return "".concat(serverUrl3.protocol.replace("ws", "http"), "//").concat(serverUrl3.host, "/settings");
7341
+ function getCloudConfigUrl(serverUrl2) {
7342
+ return "".concat(serverUrl2.protocol.replace("ws", "http"), "//").concat(serverUrl2.host, "/settings");
7132
7343
  }
7133
7344
  function isElementInPiP(el) {
7134
7345
  var _a, _b;
@@ -22657,6 +22868,142 @@ var init_livekit_client_esm = __esm({
22657
22868
  }
22658
22869
  });
22659
22870
 
22871
+ // src/utils/jsx-encoder.ts
22872
+ function generateStableDOMId(element3) {
22873
+ const tagName = element3.tagName.toLowerCase();
22874
+ const text7 = (element3.textContent || "").trim().substring(0, 50);
22875
+ let sibling = element3.previousElementSibling;
22876
+ let position3 = 1;
22877
+ while (sibling) {
22878
+ if (sibling.tagName === element3.tagName) {
22879
+ position3++;
22880
+ }
22881
+ sibling = sibling.previousElementSibling;
22882
+ }
22883
+ const path2 = getElementPath2(element3);
22884
+ const idString = `${tagName}[${position3}]_(${text7})_${path2}`;
22885
+ let hash = 0;
22886
+ for (let i2 = 0; i2 < idString.length; i2++) {
22887
+ const char = idString.charCodeAt(i2);
22888
+ hash = (hash << 5) - hash + char;
22889
+ hash |= 0;
22890
+ }
22891
+ return hash.toString(36);
22892
+ }
22893
+ function getElementPath2(element3) {
22894
+ if (element3.id) {
22895
+ return `id(${element3.id})`;
22896
+ }
22897
+ if (element3.tagName.toLowerCase() === "body") {
22898
+ return "/body";
22899
+ }
22900
+ let ix = 0;
22901
+ const siblings = element3.parentNode?.children || new HTMLCollection();
22902
+ for (let i2 = 0; i2 < siblings.length; i2++) {
22903
+ const sibling = siblings[i2];
22904
+ if (sibling === element3) {
22905
+ return `${getElementPath2(element3.parentNode)}/${element3.tagName}[${ix + 1}]`;
22906
+ }
22907
+ if (sibling.nodeType === 1 && sibling.tagName === element3.tagName) {
22908
+ ix++;
22909
+ }
22910
+ }
22911
+ return "not_found";
22912
+ }
22913
+ var init_jsx_encoder = __esm({
22914
+ "src/utils/jsx-encoder.ts"() {
22915
+ "use strict";
22916
+ }
22917
+ });
22918
+
22919
+ // src/utils/patch-react.ts
22920
+ function getImmediateText(element3) {
22921
+ let text7 = "";
22922
+ if (element3.childNodes) {
22923
+ for (const node2 of Array.from(element3.childNodes)) {
22924
+ if (node2.nodeType === 3) {
22925
+ text7 += node2.textContent || "";
22926
+ }
22927
+ }
22928
+ }
22929
+ return text7.trim();
22930
+ }
22931
+ function captureFullDOMStructure() {
22932
+ console.log("\u{1F333} Capturing full DOM structure...");
22933
+ const components = [];
22934
+ const interactiveElements = document.querySelectorAll(
22935
+ 'a, button, input, textarea, select, [role="button"], [onclick]'
22936
+ );
22937
+ interactiveElements.forEach((element3) => {
22938
+ if (element3 instanceof HTMLElement && !element3.closest("[data-cuekit-ignore]")) {
22939
+ const nodeData = buildFlatDOMNode(element3);
22940
+ if (nodeData) {
22941
+ components.push(nodeData);
22942
+ }
22943
+ }
22944
+ });
22945
+ const result = { components };
22946
+ console.log("\u{1F333} Full DOM structure captured:", result);
22947
+ return result;
22948
+ }
22949
+ function buildFlatDOMNode(element3) {
22950
+ if (element3.tagName.toLowerCase() === "script" || element3.hasAttribute("data-cuekit-ignore") || element3.style.display === "none" || element3.style.visibility === "hidden") {
22951
+ return null;
22952
+ }
22953
+ const hash = generateStableDOMId(element3);
22954
+ const text7 = getImmediateText(element3).substring(0, 100);
22955
+ const isClickable = isElementClickable(element3);
22956
+ const componentType = element3.tagName.toLowerCase();
22957
+ return {
22958
+ hash,
22959
+ text: text7,
22960
+ isClickable,
22961
+ componentType,
22962
+ children: []
22963
+ // No children in a flat structure
22964
+ };
22965
+ }
22966
+ function isElementClickable(element3) {
22967
+ const interactiveSelectors = [
22968
+ "button",
22969
+ "a",
22970
+ "input",
22971
+ "select",
22972
+ "textarea",
22973
+ '[role="button"]',
22974
+ '[role="link"]',
22975
+ '[role="tab"]',
22976
+ "[data-onclick-id]",
22977
+ "[data-on-press-id]",
22978
+ "[onclick]",
22979
+ "[onmousedown]",
22980
+ "[onmouseup]",
22981
+ "[ontouchstart]",
22982
+ "[ontouchend]",
22983
+ "[onkeydown]",
22984
+ "[onkeyup]",
22985
+ "[onkeypress]"
22986
+ ];
22987
+ for (const selector of interactiveSelectors) {
22988
+ if (element3.matches(selector)) {
22989
+ return true;
22990
+ }
22991
+ }
22992
+ const hasClickEvents = element3.onclick !== null || element3.getAttribute("onclick") !== null;
22993
+ const hasInteractiveEvents = element3.ontouchstart !== null || element3.getAttribute("ontouchstart") !== null || element3.ontouchend !== null || element3.getAttribute("ontouchend") !== null || element3.onkeydown !== null || element3.getAttribute("onkeydown") !== null || element3.onkeyup !== null || element3.getAttribute("onkeyup") !== null || element3.onkeypress !== null || element3.getAttribute("onkeypress") !== null;
22994
+ const hasPointerCursor = element3.style.cursor === "pointer" || getComputedStyle(element3).cursor === "pointer";
22995
+ const hasTabIndex = element3.hasAttribute("tabindex") && parseInt(element3.getAttribute("tabindex") || "0") >= 0;
22996
+ const hasInteractiveDataAttrs = element3.hasAttribute("data-clickable") || element3.hasAttribute("data-interactive") || element3.hasAttribute("data-action") || element3.hasAttribute("data-handler");
22997
+ const hasInteractiveAria = element3.hasAttribute("aria-pressed") || element3.hasAttribute("aria-expanded") || element3.hasAttribute("aria-selected") || element3.hasAttribute("aria-checked");
22998
+ return hasClickEvents || hasInteractiveEvents || hasPointerCursor || hasTabIndex || hasInteractiveDataAttrs || hasInteractiveAria;
22999
+ }
23000
+ var init_patch_react = __esm({
23001
+ "src/utils/patch-react.ts"() {
23002
+ "use strict";
23003
+ init_jsx_encoder();
23004
+ }
23005
+ });
23006
+
22660
23007
  // src/utils/webrtc-service.ts
22661
23008
  var webrtc_service_exports = {};
22662
23009
  __export(webrtc_service_exports, {
@@ -22668,6 +23015,7 @@ __export(webrtc_service_exports, {
22668
23015
  getRoomName: () => getRoomName,
22669
23016
  isConnected: () => isConnected,
22670
23017
  sendData: () => sendData,
23018
+ sendRuntimeData: () => sendRuntimeData,
22671
23019
  sendScreenStatus: () => sendScreenStatus,
22672
23020
  sendStaticData: () => sendStaticData,
22673
23021
  sendUserCommand: () => sendUserCommand,
@@ -22787,19 +23135,17 @@ function setupEventListeners() {
22787
23135
  }).on(RoomEvent.TrackUnsubscribed, (track) => {
22788
23136
  track.detach().forEach((element3) => element3.remove());
22789
23137
  }).on(RoomEvent.DataReceived, (payload, participant) => {
22790
- handleDataReceived(payload, participant);
23138
+ try {
23139
+ const message = JSON.parse(new TextDecoder().decode(payload));
23140
+ callbacks.onNavigationCommand?.(message);
23141
+ } catch (error) {
23142
+ const message = new TextDecoder().decode(payload);
23143
+ callbacks.onNavigationCommand?.({ type: "raw_text", data: message });
23144
+ }
22791
23145
  }).on(RoomEvent.Disconnected, () => {
22792
23146
  setWebRTCConnectionState({ isConnected: false, isConnecting: false });
22793
23147
  });
22794
23148
  }
22795
- function handleDataReceived(payload, participant) {
22796
- try {
22797
- const message = JSON.parse(new TextDecoder().decode(payload));
22798
- callbacks.onNavigationCommand?.(message);
22799
- } catch (error) {
22800
- console.error("\u{1F3A4} WebRTCService: Error parsing data:", error);
22801
- }
22802
- }
22803
23149
  function updateParticipantsList() {
22804
23150
  if (!room) return;
22805
23151
  const participants = [
@@ -22812,7 +23158,9 @@ function updateParticipantsList() {
22812
23158
  async function sendData(data, reliable = true) {
22813
23159
  if (!room) throw new Error("Not connected to room");
22814
23160
  try {
22815
- await room.localParticipant.publishData(new TextEncoder().encode(JSON.stringify(data)), {
23161
+ const encoder = new TextEncoder();
23162
+ const encodedData = encoder.encode(data);
23163
+ await room.localParticipant.publishData(encodedData, {
22816
23164
  reliable
22817
23165
  });
22818
23166
  } catch (error) {
@@ -22843,14 +23191,28 @@ function getParticipants() {
22843
23191
  }
22844
23192
  async function sendUserCommand(command) {
22845
23193
  if (!room) return;
22846
- const userCommand = {
22847
- type: "user_command",
22848
- data: {
22849
- command,
22850
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
22851
- }
22852
- };
22853
- await sendData(userCommand);
23194
+ await sendData(command);
23195
+ }
23196
+ async function sendRuntimeData() {
23197
+ if (!room) {
23198
+ console.error("\u274C Cannot send runtime data without a room connection");
23199
+ return;
23200
+ }
23201
+ try {
23202
+ const domStructure = captureFullDOMStructure();
23203
+ const screenName = getCurrentScreenName();
23204
+ const response = {
23205
+ type: "runtime_data_response",
23206
+ data: {
23207
+ components: domStructure.components,
23208
+ current_screen: screenName
23209
+ }
23210
+ };
23211
+ await sendData(JSON.stringify(response));
23212
+ console.log("\u{1F4E6} Runtime data sent successfully");
23213
+ } catch (error) {
23214
+ console.error("\u274C Failed to send runtime data:", error);
23215
+ }
22854
23216
  }
22855
23217
  async function sendStaticData(componentData, appId = "default") {
22856
23218
  try {
@@ -22881,10 +23243,6 @@ async function disconnectFromRoom() {
22881
23243
  await room.disconnect();
22882
23244
  room = null;
22883
23245
  }
22884
- if (eventSource) {
22885
- eventSource.close();
22886
- eventSource = null;
22887
- }
22888
23246
  if (reconnectTimeout) {
22889
23247
  clearTimeout(reconnectTimeout);
22890
23248
  reconnectTimeout = null;
@@ -22898,15 +23256,16 @@ async function disconnectFromRoom() {
22898
23256
  function getRoom() {
22899
23257
  return room;
22900
23258
  }
22901
- var room, eventSource, reconnectTimeout, serverUrl, callbacks, audioContainerRef, livekitUrl, token, roomName;
23259
+ var room, reconnectTimeout, serverUrl, callbacks, audioContainerRef, livekitUrl, token, roomName;
22902
23260
  var init_webrtc_service = __esm({
22903
23261
  "src/utils/webrtc-service.ts"() {
22904
23262
  "use strict";
22905
23263
  init_livekit_client_esm();
22906
23264
  init_globals();
22907
23265
  init_constants();
23266
+ init_patch_react();
23267
+ init_navigation();
22908
23268
  room = null;
22909
- eventSource = null;
22910
23269
  reconnectTimeout = null;
22911
23270
  serverUrl = WEBRTC_BACKEND_SERVER_URL || "https://bdd4c945f073.ngrok-free.app";
22912
23271
  callbacks = {};
@@ -23258,19 +23617,11 @@ __export(index_exports, {
23258
23617
  VoiceIntensityVisualizer: () => VoiceIntensityVisualizer,
23259
23618
  captureFullDOMStructure: () => captureFullDOMStructure,
23260
23619
  configureWebRTCServer: () => configureWebRTCServer,
23261
- connectSSE: () => connectSSE,
23262
- disconnectSSE: () => disconnectSSE,
23263
23620
  executeAction: () => executeAction,
23264
23621
  getFullDOMStructure: () => getFullDOMStructure,
23265
- getSSEConnectionState: () => getSSEConnectionState,
23266
- getSSEConnectionStatus: () => getSSEConnectionStatus,
23267
23622
  getWebRTCServerConfig: () => getWebRTCServerConfig,
23268
23623
  initWebRTC: () => initWebRTC,
23269
23624
  initWebRTCWithDeployedBackend: () => initWebRTCWithDeployedBackend,
23270
- sendDashboardData: () => sendDashboardData,
23271
- sendElementData: () => sendElementData,
23272
- sendRuntimeData: () => sendRuntimeData,
23273
- setSSECallbacks: () => setSSECallbacks,
23274
23625
  useCuekit: () => useCuekit,
23275
23626
  useQubeContext: () => useQubeContext,
23276
23627
  useWebRTC: () => useWebRTC
@@ -23296,204 +23647,9 @@ function InitCuekit(config) {
23296
23647
  setWebRTCConfig(webRTCConfig);
23297
23648
  }
23298
23649
 
23299
- // src/core/intent-store.ts
23300
- var store = {
23301
- screenMetadata: {},
23302
- allElementsData: []
23303
- };
23304
- var GlobalStore = {
23305
- // 🔹 Screen Metadata Methods
23306
- setMetadata(screen, metadata) {
23307
- store.screenMetadata[screen] = metadata;
23308
- },
23309
- getMetadata(screen) {
23310
- return store.screenMetadata[screen];
23311
- },
23312
- clearMetadata(screen) {
23313
- delete store.screenMetadata[screen];
23314
- },
23315
- // 🔹 Generic Store Access Methods
23316
- setData(key, value) {
23317
- store[key] = value;
23318
- },
23319
- getData(key) {
23320
- return store[key];
23321
- },
23322
- clearData(key) {
23323
- delete store[key];
23324
- },
23325
- // 🔹 Element Data Management
23326
- setElement(elementData) {
23327
- const index2 = store.allElementsData.findIndex((e3) => e3.elementId === elementData.elementId);
23328
- if (index2 >= 0) {
23329
- console.log("Updating existing element");
23330
- store.allElementsData[index2] = elementData;
23331
- } else {
23332
- console.log("Adding new element");
23333
- store.allElementsData.push(elementData);
23334
- }
23335
- },
23336
- getElementById(elementId) {
23337
- const match = store.allElementsData.find((e3) => e3.elementId === elementId);
23338
- if (!match) {
23339
- console.warn(`[GlobalStore] No element found for ID: ${elementId}`);
23340
- console.log("All elements in store:", store.allElementsData);
23341
- }
23342
- return match;
23343
- },
23344
- deleteElementById(id) {
23345
- store.allElementsData = store.allElementsData.filter((e3) => e3.elementId !== id);
23346
- },
23347
- clearAllElements() {
23348
- store.allElementsData = [];
23349
- }
23350
- };
23351
-
23352
- // src/core/navigation.ts
23353
- var navigation;
23354
- var navigationHandler = null;
23355
- function setNavigationHandler(handler) {
23356
- navigationHandler = handler;
23357
- }
23358
- function navigate(path2, params) {
23359
- const safeParams = params || {};
23360
- const absolutePath = path2.startsWith("/") ? path2 : `/${path2}`;
23361
- if (navigationHandler) {
23362
- try {
23363
- navigationHandler(absolutePath, safeParams);
23364
- } catch (error) {
23365
- console.error("[CueKit] navigation handler failed, falling back to default:", error);
23366
- }
23367
- return;
23368
- }
23369
- let fullPath = absolutePath;
23370
- if (safeParams) {
23371
- const searchParams = new URLSearchParams(safeParams).toString();
23372
- if (searchParams) {
23373
- fullPath += `?${searchParams}`;
23374
- }
23375
- }
23376
- if (navigation) {
23377
- navigation.push(fullPath);
23378
- } else {
23379
- if (typeof window !== "undefined") {
23380
- window.location.href = fullPath;
23381
- }
23382
- }
23383
- }
23384
- var getCurrentPath = () => {
23385
- if (typeof window === "undefined") return "";
23386
- return window.location.pathname;
23387
- };
23388
- var getSearchParams = () => {
23389
- if (typeof window === "undefined") return new URLSearchParams();
23390
- return new URLSearchParams(window.location.search);
23391
- };
23392
- var safeNavigate = (name2, params = {}) => {
23393
- if (name2) {
23394
- navigate(name2, params);
23395
- } else {
23396
- console.warn("[CueKit] route name not provided");
23397
- }
23398
- };
23399
- function getCurrentScreenName() {
23400
- try {
23401
- const path2 = getCurrentPath();
23402
- return path2 || "UnknownScreen";
23403
- } catch (e3) {
23404
- return "UnknownScreen";
23405
- }
23406
- }
23407
- function getCurrentRouteParams() {
23408
- try {
23409
- const params = {};
23410
- const searchParams = getSearchParams();
23411
- if (searchParams instanceof URLSearchParams) {
23412
- searchParams.forEach((value, key) => {
23413
- params[key] = value;
23414
- });
23415
- } else {
23416
- return searchParams;
23417
- }
23418
- return params;
23419
- } catch (e3) {
23420
- return {};
23421
- }
23422
- }
23423
- function onStateChange() {
23424
- const routeName = getCurrentScreenName();
23425
- const params = getCurrentRouteParams();
23426
- if (params && params.metadata) {
23427
- try {
23428
- const metadata = JSON.parse(params.metadata);
23429
- GlobalStore.setMetadata(routeName, metadata);
23430
- } catch (error) {
23431
- console.error("Failed to parse metadata from URL:", error);
23432
- }
23433
- }
23434
- }
23435
- var handleNavigationAndClick = (routeName, elementHash) => {
23436
- safeNavigate(routeName);
23437
- if (typeof MutationObserver === "undefined" || typeof document === "undefined") return;
23438
- const observer = new MutationObserver((mutationsList, observer2) => {
23439
- setTimeout(() => {
23440
- const allElements = document.querySelectorAll("*");
23441
- let elementToClick = null;
23442
- for (const element3 of allElements) {
23443
- if (element3 instanceof HTMLElement) {
23444
- const tagName = element3.tagName.toLowerCase();
23445
- const text7 = (element3.textContent || "").trim().substring(0, 50);
23446
- let sibling = element3.previousElementSibling;
23447
- let position3 = 1;
23448
- while (sibling) {
23449
- if (sibling.tagName === element3.tagName) {
23450
- position3++;
23451
- }
23452
- sibling = sibling.previousElementSibling;
23453
- }
23454
- const path2 = getElementPath(element3);
23455
- const idString = `${tagName}[${position3}]_(${text7})_${path2}`;
23456
- let hash = 0;
23457
- for (let i2 = 0; i2 < idString.length; i2++) {
23458
- const char = idString.charCodeAt(i2);
23459
- hash = (hash << 5) - hash + char;
23460
- hash |= 0;
23461
- }
23462
- const elementHashValue = hash.toString(36);
23463
- if (elementHashValue === elementHash) {
23464
- elementToClick = element3;
23465
- break;
23466
- }
23467
- }
23468
- }
23469
- if (elementToClick) {
23470
- elementToClick.click();
23471
- observer2.disconnect();
23472
- }
23473
- }, 100);
23474
- });
23475
- observer.observe(document.body, { childList: true, subtree: true });
23476
- };
23477
- function getElementPath(element3) {
23478
- if (element3.id) {
23479
- return `id(${element3.id})`;
23480
- }
23481
- const path2 = [];
23482
- let current = element3;
23483
- while (current && current !== document.body) {
23484
- let index2 = 1;
23485
- let sibling = current.previousElementSibling;
23486
- while (sibling) {
23487
- if (sibling.tagName === current.tagName) {
23488
- index2++;
23489
- }
23490
- sibling = sibling.previousElementSibling;
23491
- }
23492
- path2.unshift(`${current.tagName.toLowerCase()}[${index2}]`);
23493
- current = current.parentElement;
23494
- }
23495
- return path2.join("/");
23496
- }
23650
+ // src/providers/cuekit-provider.tsx
23651
+ init_navigation();
23652
+ init_intent_store();
23497
23653
 
23498
23654
  // src/utils/webrtc-config.ts
23499
23655
  init_constants();
@@ -23725,7 +23881,7 @@ init_livekit_client_esm();
23725
23881
  init_webrtc_service();
23726
23882
  init_globals();
23727
23883
  var useWebRTC = (options) => {
23728
- const [isConnected4, setIsConnected] = (0, import_react2.useState)(false);
23884
+ const [isConnected3, setIsConnected] = (0, import_react2.useState)(false);
23729
23885
  const [isConnecting, setIsConnecting] = (0, import_react2.useState)(false);
23730
23886
  const [connectionState, setConnectionState] = (0, import_react2.useState)(null);
23731
23887
  const [participants, setParticipants] = (0, import_react2.useState)([]);
@@ -23789,7 +23945,7 @@ var useWebRTC = (options) => {
23789
23945
  return getParticipants().map((p) => p.identity);
23790
23946
  }, [participants]);
23791
23947
  return {
23792
- isConnected: isConnected4,
23948
+ isConnected: isConnected3,
23793
23949
  isConnecting,
23794
23950
  connectionState,
23795
23951
  room: room2,
@@ -23806,335 +23962,12 @@ var useWebRTC = (options) => {
23806
23962
  };
23807
23963
  };
23808
23964
 
23809
- // src/utils/sse-service.ts
23810
- init_constants();
23811
-
23812
- // src/utils/jsx-encoder.ts
23813
- function generateStableDOMId(element3) {
23814
- const tagName = element3.tagName.toLowerCase();
23815
- const text7 = (element3.textContent || "").trim().substring(0, 50);
23816
- let sibling = element3.previousElementSibling;
23817
- let position3 = 1;
23818
- while (sibling) {
23819
- if (sibling.tagName === element3.tagName) {
23820
- position3++;
23821
- }
23822
- sibling = sibling.previousElementSibling;
23823
- }
23824
- const path2 = getElementPath2(element3);
23825
- const idString = `${tagName}[${position3}]_(${text7})_${path2}`;
23826
- let hash = 0;
23827
- for (let i2 = 0; i2 < idString.length; i2++) {
23828
- const char = idString.charCodeAt(i2);
23829
- hash = (hash << 5) - hash + char;
23830
- hash |= 0;
23831
- }
23832
- return hash.toString(36);
23833
- }
23834
- function getElementPath2(element3) {
23835
- if (element3.id) {
23836
- return `id(${element3.id})`;
23837
- }
23838
- if (element3.tagName.toLowerCase() === "body") {
23839
- return "/body";
23840
- }
23841
- let ix = 0;
23842
- const siblings = element3.parentNode?.children || new HTMLCollection();
23843
- for (let i2 = 0; i2 < siblings.length; i2++) {
23844
- const sibling = siblings[i2];
23845
- if (sibling === element3) {
23846
- return `${getElementPath2(element3.parentNode)}/${element3.tagName}[${ix + 1}]`;
23847
- }
23848
- if (sibling.nodeType === 1 && sibling.tagName === element3.tagName) {
23849
- ix++;
23850
- }
23851
- }
23852
- return "not_found";
23853
- }
23854
-
23855
- // src/utils/patch-react.ts
23856
- function getImmediateText(element3) {
23857
- let text7 = "";
23858
- if (element3.childNodes) {
23859
- for (const node2 of Array.from(element3.childNodes)) {
23860
- if (node2.nodeType === 3) {
23861
- text7 += node2.textContent || "";
23862
- }
23863
- }
23864
- }
23865
- return text7.trim();
23866
- }
23867
- function captureFullDOMStructure() {
23868
- console.log("\u{1F333} Capturing full DOM structure...");
23869
- const components = [];
23870
- const interactiveElements = document.querySelectorAll(
23871
- 'a, button, input, textarea, select, [role="button"], [onclick]'
23872
- );
23873
- interactiveElements.forEach((element3) => {
23874
- if (element3 instanceof HTMLElement && !element3.closest("[data-cuekit-ignore]")) {
23875
- const nodeData = buildFlatDOMNode(element3);
23876
- if (nodeData) {
23877
- components.push(nodeData);
23878
- }
23879
- }
23880
- });
23881
- const result = { components };
23882
- console.log("\u{1F333} Full DOM structure captured:", result);
23883
- return result;
23884
- }
23885
- function buildFlatDOMNode(element3) {
23886
- if (element3.tagName.toLowerCase() === "script" || element3.hasAttribute("data-cuekit-ignore") || element3.style.display === "none" || element3.style.visibility === "hidden") {
23887
- return null;
23888
- }
23889
- const hash = generateStableDOMId(element3);
23890
- const text7 = getImmediateText(element3).substring(0, 100);
23891
- const isClickable = isElementClickable(element3);
23892
- const componentType = element3.tagName.toLowerCase();
23893
- return {
23894
- hash,
23895
- text: text7,
23896
- isClickable,
23897
- componentType,
23898
- children: []
23899
- // No children in a flat structure
23900
- };
23901
- }
23902
- function isElementClickable(element3) {
23903
- const interactiveSelectors = [
23904
- "button",
23905
- "a",
23906
- "input",
23907
- "select",
23908
- "textarea",
23909
- '[role="button"]',
23910
- '[role="link"]',
23911
- '[role="tab"]',
23912
- "[data-onclick-id]",
23913
- "[data-on-press-id]",
23914
- "[onclick]",
23915
- "[onmousedown]",
23916
- "[onmouseup]",
23917
- "[ontouchstart]",
23918
- "[ontouchend]",
23919
- "[onkeydown]",
23920
- "[onkeyup]",
23921
- "[onkeypress]"
23922
- ];
23923
- for (const selector of interactiveSelectors) {
23924
- if (element3.matches(selector)) {
23925
- return true;
23926
- }
23927
- }
23928
- const hasClickEvents = element3.onclick !== null || element3.getAttribute("onclick") !== null;
23929
- const hasInteractiveEvents = element3.ontouchstart !== null || element3.getAttribute("ontouchstart") !== null || element3.ontouchend !== null || element3.getAttribute("ontouchend") !== null || element3.onkeydown !== null || element3.getAttribute("onkeydown") !== null || element3.onkeyup !== null || element3.getAttribute("onkeyup") !== null || element3.onkeypress !== null || element3.getAttribute("onkeypress") !== null;
23930
- const hasPointerCursor = element3.style.cursor === "pointer" || getComputedStyle(element3).cursor === "pointer";
23931
- const hasTabIndex = element3.hasAttribute("tabindex") && parseInt(element3.getAttribute("tabindex") || "0") >= 0;
23932
- const hasInteractiveDataAttrs = element3.hasAttribute("data-clickable") || element3.hasAttribute("data-interactive") || element3.hasAttribute("data-action") || element3.hasAttribute("data-handler");
23933
- const hasInteractiveAria = element3.hasAttribute("aria-pressed") || element3.hasAttribute("aria-expanded") || element3.hasAttribute("aria-selected") || element3.hasAttribute("aria-checked");
23934
- return hasClickEvents || hasInteractiveEvents || hasPointerCursor || hasTabIndex || hasInteractiveDataAttrs || hasInteractiveAria;
23935
- }
23936
-
23937
- // src/utils/sse-service.ts
23938
- init_globals();
23939
- var eventSource2 = null;
23940
- var isConnected3 = false;
23941
- var serverUrl2 = WEBRTC_BACKEND_SERVER_URL || "https://bdd4c945f073.ngrok-free.app";
23942
- var callbacks2 = {};
23943
- var sessionId = null;
23944
- function setSSECallbacks(newCallbacks) {
23945
- callbacks2 = newCallbacks;
23946
- }
23947
- async function connectSSE(newSessionId) {
23948
- if (eventSource2) {
23949
- eventSource2.close();
23950
- }
23951
- if (typeof EventSource === "undefined") {
23952
- console.warn("\u{1F527} EventSource not available, SSE functionality disabled");
23953
- callbacks2.onError?.("EventSource not available");
23954
- return;
23955
- }
23956
- try {
23957
- const url = `${serverUrl2}/navigation/stream?session_id=${newSessionId}`;
23958
- eventSource2 = new EventSource(url);
23959
- sessionId = newSessionId;
23960
- eventSource2.onopen = () => {
23961
- console.log("\u{1F517} SSE connection opened");
23962
- isConnected3 = true;
23963
- callbacks2.onConnectionChange?.(true);
23964
- };
23965
- eventSource2.onmessage = (event) => {
23966
- console.log("\u{1F4E1} SSE MESSAGE RECEIVED:", event.data);
23967
- try {
23968
- const data = JSON.parse(event.data);
23969
- console.log("\u{1F4E1} SSE MESSAGE PARSED:", data);
23970
- handleSSEMessage(data);
23971
- } catch (error) {
23972
- console.error("\u274C Failed to parse SSE message:", error);
23973
- }
23974
- };
23975
- eventSource2.onerror = (error) => {
23976
- console.error("\u274C SSE connection error:", error);
23977
- isConnected3 = false;
23978
- callbacks2.onConnectionChange?.(false);
23979
- callbacks2.onError?.("SSE connection failed");
23980
- };
23981
- } catch (error) {
23982
- console.error("\u274C Failed to create SSE connection:", error);
23983
- callbacks2.onError?.("Failed to create SSE connection");
23984
- }
23985
- }
23986
- function handleSSEMessage(data) {
23987
- console.log("\u{1F50D} Processing SSE message type:", data.type);
23988
- console.log("\u{1F50D} Full SSE data:", data);
23989
- console.log("\u{1F50D} SSE data.data:", data.data);
23990
- const actionEvent = data;
23991
- console.log("\u{1F50D} Created action event:", actionEvent);
23992
- callbacks2.onActionEvent?.(actionEvent);
23993
- switch (actionEvent.type) {
23994
- case "static_data_ready":
23995
- console.log("\u{1F4E6} Handling static_data_ready event");
23996
- callbacks2.onStaticDataUpdate?.(actionEvent.data);
23997
- break;
23998
- case "ai_intent":
23999
- console.log("\u{1F3AF} Handling ai_intent event");
24000
- callbacks2.onIntentUpdate?.(actionEvent.data);
24001
- break;
24002
- case "request_runtime_data":
24003
- console.log("\u{1F4E6} Handling request_runtime_data event");
24004
- sendRuntimeData();
24005
- break;
24006
- case "user_speech_chunk":
24007
- console.log("\u{1F464} Handling user_speech_chunk event");
24008
- const userSpeechEntry = {
24009
- speaker: "user",
24010
- text: actionEvent.data?.text_chunk,
24011
- is_final: actionEvent.data?.is_final
24012
- };
24013
- callbacks2.onConversationUpdate?.(userSpeechEntry);
24014
- break;
24015
- case "ai_speech_chunk":
24016
- console.log("\u{1F916} Handling ai_speech_chunk event");
24017
- callbacks2.onConversationUpdate?.({
24018
- speaker: "ai",
24019
- text: actionEvent.data?.text_chunk,
24020
- is_final: actionEvent.data?.is_final
24021
- });
24022
- break;
24023
- case "ai_interrupted":
24024
- console.log("\u{1F507} Handling ai_interrupted event");
24025
- break;
24026
- case "tool_log":
24027
- console.log("\u{1F527} Handling tool_log event");
24028
- callbacks2.onToolStatusUpdate?.(actionEvent.data);
24029
- break;
24030
- case "connection":
24031
- console.log("\u{1F517} Handling connection event");
24032
- break;
24033
- case "keepalive":
24034
- console.log("\u{1F493} Handling keepalive event");
24035
- break;
24036
- default:
24037
- console.log("\u{1F50D} Unknown SSE message type:", data.type);
24038
- }
24039
- }
24040
- async function sendRuntimeData() {
24041
- if (!sessionId) {
24042
- console.error("\u274C Cannot send runtime data without a session ID");
24043
- return;
24044
- }
24045
- try {
24046
- const domStructure = captureFullDOMStructure();
24047
- const screenName = getCurrentScreenName();
24048
- const response = await fetch(`${serverUrl2}/api/runtime/data/${sessionId}`, {
24049
- method: "POST",
24050
- headers: {
24051
- "Content-Type": "application/json",
24052
- Authorization: `Bearer ${_apiKey}`
24053
- },
24054
- body: JSON.stringify({
24055
- session_id: sessionId,
24056
- components: domStructure.components,
24057
- screen: screenName
24058
- })
24059
- });
24060
- if (!response.ok) {
24061
- const errorData = await response.json();
24062
- throw new Error(errorData.detail || "Failed to send runtime data");
24063
- }
24064
- console.log("\u{1F4E6} Runtime data sent successfully");
24065
- } catch (error) {
24066
- console.error("\u274C Failed to send runtime data:", error);
24067
- callbacks2.onError?.("Failed to send runtime data");
24068
- }
24069
- }
24070
- async function sendDashboardData(dashboardData) {
24071
- try {
24072
- console.log("\u{1F4E4} SSEService: Sending dashboard data...");
24073
- const response = await fetch(`${serverUrl2}/ai/data`, {
24074
- method: "POST",
24075
- headers: {
24076
- "Content-Type": "application/json"
24077
- },
24078
- body: JSON.stringify({
24079
- type: "dashboard_data",
24080
- data: dashboardData
24081
- })
24082
- });
24083
- if (!response.ok) {
24084
- throw new Error(`HTTP ${response.status}: ${response.statusText}`);
24085
- }
24086
- console.log("\u2705 SSEService: Dashboard data sent successfully");
24087
- } catch (error) {
24088
- console.error("\u274C SSEService: Failed to send dashboard data:", error);
24089
- }
24090
- }
24091
- async function sendElementData(appId = "default") {
24092
- try {
24093
- console.log("\u{1F4E4} SSEService: Sending element data...");
24094
- const domStructure = captureFullDOMStructure();
24095
- const currentPage = getCurrentScreenName();
24096
- const elementData = {
24097
- app_id: appId,
24098
- current_page: currentPage,
24099
- dom_structure: domStructure,
24100
- timestamp: Date.now()
24101
- };
24102
- const response = await fetch(`${serverUrl2}/ai/data`, {
24103
- method: "POST",
24104
- headers: {
24105
- "Content-Type": "application/json"
24106
- },
24107
- body: JSON.stringify(elementData)
24108
- });
24109
- if (!response.ok) {
24110
- throw new Error(`HTTP ${response.status}: ${response.statusText}`);
24111
- }
24112
- console.log("\u2705 SSEService: Element data sent successfully");
24113
- return elementData;
24114
- } catch (error) {
24115
- console.error("\u274C SSEService: Failed to send element data:", error);
24116
- throw error;
24117
- }
24118
- }
24119
- function disconnectSSE() {
24120
- console.log("\u{1F50C} SSEService: Disconnecting SSE...");
24121
- if (eventSource2) {
24122
- eventSource2.close();
24123
- eventSource2 = null;
24124
- }
24125
- isConnected3 = false;
24126
- callbacks2.onConnectionChange?.(false);
24127
- }
24128
- function getSSEConnectionStatus() {
24129
- return isConnected3 && eventSource2?.readyState === EventSource.OPEN;
24130
- }
24131
- function getSSEConnectionState() {
24132
- if (isConnected3 && eventSource2?.readyState === EventSource.OPEN) return "connected";
24133
- if (eventSource2?.readyState === EventSource.CONNECTING) return "connecting";
24134
- return "disconnected";
24135
- }
23965
+ // src/hooks/use-cuekit.ts
23966
+ init_webrtc_service();
24136
23967
 
24137
23968
  // src/utils/element-service.ts
23969
+ init_patch_react();
23970
+ init_navigation();
24138
23971
  function executeAction(action) {
24139
23972
  console.log("\u{1F3AF} Executing element action:", action);
24140
23973
  const { action_type, target_element, target } = action;
@@ -24319,89 +24152,83 @@ var useCuekit = (options) => {
24319
24152
  }, []);
24320
24153
  const [micState, setMicState] = (0, import_react3.useState)("idle");
24321
24154
  const [status, setStatus] = (0, import_react3.useState)("");
24322
- const [isSseConnected, setIsSseConnected] = (0, import_react3.useState)(false);
24323
- const [lastActionEvent, setLastActionEvent] = (0, import_react3.useState)(null);
24324
- (0, import_react3.useEffect)(() => {
24325
- setSSECallbacks({
24326
- onActionEvent: (event) => {
24327
- setLastActionEvent(event);
24328
- switch (event.type) {
24329
- case "user_speech_chunk":
24330
- case "ai_speech_chunk": {
24331
- const role = event.type === "user_speech_chunk" ? "user" : "ai";
24332
- if (role === "user" && currentAIMessageRef.current) {
24333
- const finalMessageId = currentAIMessageRef.current.id;
24334
- setMessages(
24335
- (prev) => prev.map((m) => m.id === finalMessageId ? { ...m, isFinal: true } : m)
24336
- );
24337
- currentAIMessageRef.current = null;
24338
- }
24339
- if (role === "ai" && currentUserMessageRef.current) {
24340
- const finalMessageId = currentUserMessageRef.current.id;
24341
- setMessages(
24342
- (prev) => prev.map((m) => m.id === finalMessageId ? { ...m, isFinal: true } : m)
24343
- );
24344
- currentUserMessageRef.current = null;
24345
- }
24346
- const entry = {
24347
- speaker: role,
24348
- text: event.data.text_chunk,
24349
- is_final: event.data.is_final,
24350
- timestamp: new Date(event.timestamp || Date.now()).toISOString()
24351
- };
24352
- handleMessageChunk(entry.text, entry.speaker, entry.is_final);
24353
- if (entry.is_final) {
24354
- if (entry.speaker === "user") {
24355
- setMicState("thinking");
24356
- } else if (entry.speaker === "ai") {
24357
- setTimeout(() => setMicState("listening"), 1e3);
24358
- }
24359
- }
24360
- break;
24361
- }
24362
- case "ai_intent": {
24363
- const intent = event.data;
24364
- if (intent.actionType === "click" && intent.actionMetadata.elementId) {
24365
- executeAction({
24366
- action_type: "click",
24367
- target_element: intent.actionMetadata.elementId
24368
- });
24369
- } else if (intent.actionType === "navigate" && intent.actionMetadata.routeName) {
24370
- executeAction({
24371
- action_type: "navigate",
24372
- target_element: intent.actionMetadata.routeName
24373
- });
24374
- }
24375
- break;
24376
- }
24377
- case "ai_interrupted": {
24378
- handleAIInterruption();
24379
- break;
24380
- }
24381
- case "keepalive": {
24382
- if (currentUserMessageRef.current) {
24383
- const finalMessageId = currentUserMessageRef.current.id;
24384
- setMessages(
24385
- (prev) => prev.map((m) => m.id === finalMessageId ? { ...m, isFinal: true } : m)
24386
- );
24387
- currentUserMessageRef.current = null;
24388
- }
24389
- if (currentAIMessageRef.current) {
24390
- const finalMessageId = currentAIMessageRef.current.id;
24391
- setMessages(
24392
- (prev) => prev.map((m) => m.id === finalMessageId ? { ...m, isFinal: true } : m)
24393
- );
24394
- currentAIMessageRef.current = null;
24395
- }
24396
- break;
24155
+ const handleNavigationCommand = (event) => {
24156
+ switch (event.type) {
24157
+ case "user_speech_chunk":
24158
+ case "ai_speech_chunk": {
24159
+ const role = event.type === "user_speech_chunk" ? "user" : "ai";
24160
+ if (role === "user" && currentAIMessageRef.current) {
24161
+ const finalMessageId = currentAIMessageRef.current.id;
24162
+ setMessages(
24163
+ (prev) => prev.map((m) => m.id === finalMessageId ? { ...m, isFinal: true } : m)
24164
+ );
24165
+ currentAIMessageRef.current = null;
24166
+ }
24167
+ if (role === "ai" && currentUserMessageRef.current) {
24168
+ const finalMessageId = currentUserMessageRef.current.id;
24169
+ setMessages(
24170
+ (prev) => prev.map((m) => m.id === finalMessageId ? { ...m, isFinal: true } : m)
24171
+ );
24172
+ currentUserMessageRef.current = null;
24173
+ }
24174
+ const entry = {
24175
+ speaker: role,
24176
+ text: event.data.text_chunk,
24177
+ is_final: event.data.is_final,
24178
+ timestamp: new Date(event.timestamp || Date.now()).toISOString()
24179
+ };
24180
+ handleMessageChunk(entry.text, entry.speaker, entry.is_final);
24181
+ if (entry.is_final) {
24182
+ if (entry.speaker === "user") {
24183
+ setMicState("thinking");
24184
+ } else if (entry.speaker === "ai") {
24185
+ setTimeout(() => setMicState("listening"), 1e3);
24397
24186
  }
24398
24187
  }
24399
- },
24400
- onConnectionChange: (isConnected4) => {
24401
- setIsSseConnected(isConnected4);
24188
+ break;
24402
24189
  }
24403
- });
24404
- }, [handleMessageChunk, handleAIInterruption]);
24190
+ case "ai_intent": {
24191
+ const intent = event.data;
24192
+ if (intent.actionType === "click" && intent.actionMetadata.elementId) {
24193
+ executeAction({
24194
+ action_type: "click",
24195
+ target_element: intent.actionMetadata.elementId
24196
+ });
24197
+ } else if (intent.actionType === "navigate" && intent.actionMetadata.routeName) {
24198
+ executeAction({
24199
+ action_type: "navigate",
24200
+ target_element: intent.actionMetadata.routeName
24201
+ });
24202
+ }
24203
+ break;
24204
+ }
24205
+ case "request_runtime_data": {
24206
+ sendRuntimeData();
24207
+ break;
24208
+ }
24209
+ case "ai_interrupted": {
24210
+ handleAIInterruption();
24211
+ break;
24212
+ }
24213
+ case "keepalive": {
24214
+ if (currentUserMessageRef.current) {
24215
+ const finalMessageId = currentUserMessageRef.current.id;
24216
+ setMessages(
24217
+ (prev) => prev.map((m) => m.id === finalMessageId ? { ...m, isFinal: true } : m)
24218
+ );
24219
+ currentUserMessageRef.current = null;
24220
+ }
24221
+ if (currentAIMessageRef.current) {
24222
+ const finalMessageId = currentAIMessageRef.current.id;
24223
+ setMessages(
24224
+ (prev) => prev.map((m) => m.id === finalMessageId ? { ...m, isFinal: true } : m)
24225
+ );
24226
+ currentAIMessageRef.current = null;
24227
+ }
24228
+ break;
24229
+ }
24230
+ }
24231
+ };
24405
24232
  const handleConnectionStateChange = (state) => {
24406
24233
  switch (state) {
24407
24234
  case "connecting":
@@ -24425,32 +24252,22 @@ var useCuekit = (options) => {
24425
24252
  };
24426
24253
  const webrtc = useWebRTC({
24427
24254
  ...options,
24428
- onConnectionStateChange: handleConnectionStateChange
24255
+ onConnectionStateChange: handleConnectionStateChange,
24256
+ onNavigationCommand: handleNavigationCommand
24429
24257
  });
24430
24258
  const connect = (0, import_react3.useCallback)(
24431
24259
  async (identity, apiKey, appId) => {
24432
- const authData = await webrtc.connect(identity, apiKey, appId);
24433
- if (authData?.session_id) {
24434
- connectSSE(authData.session_id);
24435
- }
24260
+ await webrtc.connect(identity, apiKey, appId);
24436
24261
  },
24437
24262
  [webrtc]
24438
24263
  );
24439
24264
  const disconnect = (0, import_react3.useCallback)(async () => {
24440
24265
  await webrtc.disconnect();
24441
- disconnectSSE();
24442
24266
  clearMessages();
24443
24267
  setMicState("idle");
24444
24268
  }, [webrtc, clearMessages]);
24445
- (0, import_react3.useEffect)(() => {
24446
- if (lastActionEvent?.type === "ai_interrupted") {
24447
- handleAIInterruption();
24448
- }
24449
- }, [lastActionEvent, handleAIInterruption]);
24450
24269
  return {
24451
24270
  ...webrtc,
24452
- isSseConnected,
24453
- lastActionEvent,
24454
24271
  messages,
24455
24272
  micState,
24456
24273
  setMicState,
@@ -37216,7 +37033,7 @@ var ChatPopup = ({
37216
37033
  onSendText,
37217
37034
  onEndCall,
37218
37035
  messages,
37219
- isConnected: isConnected4,
37036
+ isConnected: isConnected3,
37220
37037
  micState,
37221
37038
  error,
37222
37039
  currentTheme = "dark",
@@ -37803,7 +37620,7 @@ var ChatPopup = ({
37803
37620
  }
37804
37621
  }
37805
37622
  ),
37806
- isConnected4 && onEndCall && /* @__PURE__ */ import_react9.default.createElement(
37623
+ isConnected3 && onEndCall && /* @__PURE__ */ import_react9.default.createElement(
37807
37624
  "button",
37808
37625
  {
37809
37626
  type: "submit",
@@ -40002,13 +39819,12 @@ var MicButton = ({
40002
39819
  const aiSpeechTimeoutRef = (0, import_react15.useRef)(null);
40003
39820
  const activeAITracksRef = (0, import_react15.useRef)(/* @__PURE__ */ new Set());
40004
39821
  const {
40005
- isConnected: isConnected4,
39822
+ isConnected: isConnected3,
40006
39823
  isConnecting,
40007
39824
  error: voiceError,
40008
39825
  connect: voiceConnect,
40009
39826
  disconnect: voiceDisconnect,
40010
39827
  sendUserCommand: sendUserCommand2,
40011
- lastActionEvent,
40012
39828
  messages: messageManagerMessages,
40013
39829
  micState,
40014
39830
  setMicState,
@@ -40088,8 +39904,8 @@ var MicButton = ({
40088
39904
  console.log("\u{1F3A4} MicButton: Current active AI tracks:", Array.from(activeAITracksRef.current));
40089
39905
  console.log("\u{1F3A4} MicButton: Current status:", status);
40090
39906
  console.log("\u{1F3A4} MicButton: Current mic state:", micState);
40091
- console.log("\u{1F3A4} MicButton: Is listening:", isConnected4);
40092
- console.log("\u{1F3A4} MicButton: Is connected:", isConnected4);
39907
+ console.log("\u{1F3A4} MicButton: Is listening:", isConnected3);
39908
+ console.log("\u{1F3A4} MicButton: Is connected:", isConnected3);
40093
39909
  if (isSpeaking && trackId) {
40094
39910
  console.log("\u{1F3A4} MicButton: ===== AI SPEECH START =====");
40095
39911
  console.log("\u{1F3A4} MicButton: Adding track to active set:", trackId);
@@ -40144,7 +39960,7 @@ var MicButton = ({
40144
39960
  console.log("\u{1F3A4} MicButton: - Status:", status);
40145
39961
  console.log("\u{1F3A4} MicButton: ================================");
40146
39962
  },
40147
- [status, micState, isConnected4]
39963
+ [status, micState, isConnected3]
40148
39964
  );
40149
39965
  (0, import_react15.useEffect)(() => {
40150
39966
  if (audioContainerRef2.current) {
@@ -40157,10 +39973,9 @@ var MicButton = ({
40157
39973
  }
40158
39974
  };
40159
39975
  }, [handleAISpeech]);
40160
- const isListening = isConnected4;
40161
- const transcript = (lastActionEvent?.type === "user_speech_chunk" || lastActionEvent?.type === "ai_speech_chunk") && lastActionEvent?.data?.text_chunk ? lastActionEvent.data.text_chunk : "";
40162
- const getUserFriendlyStatus = (micState2, isConnected5) => {
40163
- if (!isConnected5) {
39976
+ const isListening = isConnected3;
39977
+ const getUserFriendlyStatus = (micState2, isConnected4) => {
39978
+ if (!isConnected4) {
40164
39979
  return "Connecting...";
40165
39980
  }
40166
39981
  if (status && !status.includes("error") && !status.includes("failed") && !status.includes("Connection error") && !status.includes("Unable to")) {
@@ -40170,28 +39985,28 @@ var MicButton = ({
40170
39985
  if (micState2 === "thinking") return "Thinking...";
40171
39986
  if (micState2 === "replying") return "Responding...";
40172
39987
  if (micState2 === "idle") {
40173
- if (isConnected5) return "Listening...";
39988
+ if (isConnected4) return "Listening...";
40174
39989
  return "Connecting...";
40175
39990
  }
40176
- return isConnected5 ? "Ready" : "Connecting...";
39991
+ return isConnected4 ? "Ready" : "Connecting...";
40177
39992
  };
40178
39993
  (0, import_react15.useEffect)(() => {
40179
- if (isConnected4) {
39994
+ if (isConnected3) {
40180
39995
  console.log("\u{1F3A4} MicButton: WebRTC and SSE connections established - ready for commands");
40181
39996
  } else {
40182
39997
  console.log("\u{1F3A4} MicButton: WebRTC not yet connected - ignoring speech");
40183
39998
  }
40184
- }, [isConnected4]);
39999
+ }, [isConnected3]);
40185
40000
  (0, import_react15.useEffect)(() => {
40186
40001
  console.log("\u{1F3A4} MicButton: Auto-open check:", {
40187
- isConnected: isConnected4,
40002
+ isConnected: isConnected3,
40188
40003
  chatIsOpen: isChatOpen
40189
40004
  });
40190
- if (isConnected4 && !isChatOpen) {
40005
+ if (isConnected3 && !isChatOpen) {
40191
40006
  console.log("\u{1F3A4} MicButton: Auto-opening chat popup");
40192
40007
  openChat();
40193
40008
  }
40194
- }, [isConnected4, isChatOpen, openChat]);
40009
+ }, [isConnected3, isChatOpen, openChat]);
40195
40010
  (0, import_react15.useEffect)(() => {
40196
40011
  if (messageManagerMessages.length > 0 && !isChatOpen) {
40197
40012
  console.log("\u{1F3A4} MicButton: Auto-opening chat popup due to messages");
@@ -40199,7 +40014,7 @@ var MicButton = ({
40199
40014
  }
40200
40015
  }, [messageManagerMessages.length, isChatOpen, openChat]);
40201
40016
  const handleMicClick = (0, import_react15.useCallback)(() => {
40202
- const shouldStop = micState === "listening" && isConnected4;
40017
+ const shouldStop = micState === "listening" && isConnected3;
40203
40018
  if (shouldStop) {
40204
40019
  console.log("\u{1F3A4} MicButton: User wants to stop - closing everything");
40205
40020
  voiceDisconnect().then(() => {
@@ -40224,7 +40039,7 @@ var MicButton = ({
40224
40039
  }
40225
40040
  }, [
40226
40041
  micState,
40227
- isConnected4,
40042
+ isConnected3,
40228
40043
  voiceDisconnect,
40229
40044
  voiceConnect,
40230
40045
  apiKey,
@@ -40232,19 +40047,6 @@ var MicButton = ({
40232
40047
  openChat,
40233
40048
  showBorderGlow
40234
40049
  ]);
40235
- (0, import_react15.useEffect)(() => {
40236
- if (!isConnected4) {
40237
- return;
40238
- }
40239
- if (transcript && transcript.trim() && !aiSpeakingRef.current) {
40240
- console.log("\u{1F3A4} MicButton: Processing new transcript:", transcript);
40241
- sendUserCommand2(transcript).then(() => {
40242
- console.log("\u{1F3A4} MicButton: User command sent successfully");
40243
- }).catch((error) => {
40244
- console.error("\u{1F3A4} MicButton: Failed to send user command:", error);
40245
- });
40246
- }
40247
- }, [transcript, isConnected4, sendUserCommand2]);
40248
40050
  const handleSendText = async (textToSend) => {
40249
40051
  console.log("\u{1F3A4} MicButton: handleSendText called with:", textToSend);
40250
40052
  setMicState("thinking");
@@ -40252,7 +40054,7 @@ var MicButton = ({
40252
40054
  if (!isChatOpen) {
40253
40055
  openChat();
40254
40056
  }
40255
- if (isConnected4) {
40057
+ if (isConnected3) {
40256
40058
  console.log("\u{1F3A4} MicButton: Sending via WebRTC");
40257
40059
  try {
40258
40060
  await sendUserCommand2(textToSend);
@@ -40449,13 +40251,13 @@ var MicButton = ({
40449
40251
  text: msg.text,
40450
40252
  sender: msg.role === "ai" ? "assistant" : "user"
40451
40253
  })),
40452
- isConnected: isConnected4 ?? false,
40254
+ isConnected: isConnected3 ?? false,
40453
40255
  micState,
40454
40256
  participants,
40455
40257
  error: voiceError,
40456
40258
  currentTheme,
40457
40259
  onThemeToggle: setCurrentTheme,
40458
- status: getUserFriendlyStatus(micState, isConnected4 ?? false),
40260
+ status: getUserFriendlyStatus(micState, isConnected3 ?? false),
40459
40261
  anchor: { position: screenPosition, bottom: bottomSpace, size: buttonSize }
40460
40262
  }
40461
40263
  ), isChatOpen && isChatMinimized && /* @__PURE__ */ import_react15.default.createElement(
@@ -40482,3 +40284,6 @@ var MicButton = ({
40482
40284
  /* @__PURE__ */ import_react15.default.createElement("span", { style: { fontSize: 12, fontWeight: 600, color: "hsl(var(--voice-text))" } }, "Open chat")
40483
40285
  ), /* @__PURE__ */ import_react15.default.createElement("div", { ref: audioContainerRef2, style: { display: "none" } }), showBorderGlow && showBodyGlow && /* @__PURE__ */ import_react15.default.createElement(border_glow_default, { isActive: true }));
40484
40286
  };
40287
+
40288
+ // src/index.ts
40289
+ init_patch_react();