@qontinui/ui-bridge 0.1.1

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 (47) hide show
  1. package/dist/control/index.d.mts +134 -0
  2. package/dist/control/index.d.ts +134 -0
  3. package/dist/control/index.js +924 -0
  4. package/dist/control/index.js.map +1 -0
  5. package/dist/control/index.mjs +919 -0
  6. package/dist/control/index.mjs.map +1 -0
  7. package/dist/core/index.d.mts +52 -0
  8. package/dist/core/index.d.ts +52 -0
  9. package/dist/core/index.js +1424 -0
  10. package/dist/core/index.js.map +1 -0
  11. package/dist/core/index.mjs +1409 -0
  12. package/dist/core/index.mjs.map +1 -0
  13. package/dist/debug/index.d.mts +93 -0
  14. package/dist/debug/index.d.ts +93 -0
  15. package/dist/debug/index.js +673 -0
  16. package/dist/debug/index.js.map +1 -0
  17. package/dist/debug/index.mjs +664 -0
  18. package/dist/debug/index.mjs.map +1 -0
  19. package/dist/index.d.mts +12 -0
  20. package/dist/index.d.ts +12 -0
  21. package/dist/index.js +4719 -0
  22. package/dist/index.js.map +1 -0
  23. package/dist/index.mjs +4665 -0
  24. package/dist/index.mjs.map +1 -0
  25. package/dist/metrics-BCG7z7Aq.d.mts +147 -0
  26. package/dist/metrics-QCnK0EFw.d.ts +147 -0
  27. package/dist/react/index.d.mts +786 -0
  28. package/dist/react/index.d.ts +786 -0
  29. package/dist/react/index.js +4312 -0
  30. package/dist/react/index.js.map +1 -0
  31. package/dist/react/index.mjs +4290 -0
  32. package/dist/react/index.mjs.map +1 -0
  33. package/dist/registry-CT6BVVKr.d.mts +253 -0
  34. package/dist/registry-D4mQ01B3.d.ts +253 -0
  35. package/dist/render-log/index.d.mts +340 -0
  36. package/dist/render-log/index.d.ts +340 -0
  37. package/dist/render-log/index.js +702 -0
  38. package/dist/render-log/index.js.map +1 -0
  39. package/dist/render-log/index.mjs +695 -0
  40. package/dist/render-log/index.mjs.map +1 -0
  41. package/dist/types-BDkXy5si.d.ts +354 -0
  42. package/dist/types-BpvpStn3.d.mts +802 -0
  43. package/dist/types-BpvpStn3.d.ts +802 -0
  44. package/dist/types-DdJD9yw5.d.mts +354 -0
  45. package/dist/websocket-client-B2LC9CYc.d.mts +124 -0
  46. package/dist/websocket-client-DupH0X7B.d.ts +124 -0
  47. package/package.json +83 -0
@@ -0,0 +1,673 @@
1
+ 'use strict';
2
+
3
+ var react = require('react');
4
+ var jsxRuntime = require('react/jsx-runtime');
5
+
6
+ // src/debug/inspector.tsx
7
+
8
+ // src/core/element-identifier.ts
9
+ function generateXPath(element) {
10
+ if (element.id) {
11
+ return `//*[@id="${element.id}"]`;
12
+ }
13
+ const parts = [];
14
+ let current = element;
15
+ while (current && current.nodeType === Node.ELEMENT_NODE) {
16
+ let selector = current.nodeName.toLowerCase();
17
+ const uiId = current.getAttribute("data-ui-id");
18
+ if (uiId) {
19
+ selector += `[@data-ui-id="${uiId}"]`;
20
+ parts.unshift(selector);
21
+ break;
22
+ }
23
+ const testId = current.getAttribute("data-testid");
24
+ if (testId) {
25
+ selector += `[@data-testid="${testId}"]`;
26
+ parts.unshift(selector);
27
+ break;
28
+ }
29
+ const id = current.id;
30
+ if (id) {
31
+ selector += `[@id="${id}"]`;
32
+ parts.unshift(selector);
33
+ break;
34
+ }
35
+ const parentEl = current.parentElement;
36
+ if (parentEl) {
37
+ const currentEl = current;
38
+ const siblings = Array.from(parentEl.children).filter(
39
+ (child) => child.nodeName === currentEl.nodeName
40
+ );
41
+ if (siblings.length > 1) {
42
+ const index = siblings.indexOf(currentEl) + 1;
43
+ selector += `[${index}]`;
44
+ }
45
+ }
46
+ parts.unshift(selector);
47
+ current = parentEl;
48
+ }
49
+ return "/" + parts.join("/");
50
+ }
51
+ function generateCSSSelector(element) {
52
+ const uiId = element.getAttribute("data-ui-id");
53
+ if (uiId) {
54
+ return `[data-ui-id="${uiId}"]`;
55
+ }
56
+ const testId = element.getAttribute("data-testid");
57
+ if (testId) {
58
+ return `[data-testid="${testId}"]`;
59
+ }
60
+ const awasId = element.getAttribute("data-awas-element");
61
+ if (awasId) {
62
+ return `[data-awas-element="${awasId}"]`;
63
+ }
64
+ if (element.id) {
65
+ return `#${CSS.escape(element.id)}`;
66
+ }
67
+ const path = [];
68
+ let current = element;
69
+ while (current && current.nodeType === Node.ELEMENT_NODE) {
70
+ let selector = current.nodeName.toLowerCase();
71
+ const parentUiId = current.getAttribute("data-ui-id");
72
+ if (parentUiId && current !== element) {
73
+ path.unshift(`[data-ui-id="${parentUiId}"]`);
74
+ break;
75
+ }
76
+ const parentTestId = current.getAttribute("data-testid");
77
+ if (parentTestId && current !== element) {
78
+ path.unshift(`[data-testid="${parentTestId}"]`);
79
+ break;
80
+ }
81
+ if (current.id) {
82
+ path.unshift(`#${CSS.escape(current.id)}`);
83
+ break;
84
+ }
85
+ const parentEl = current.parentElement;
86
+ if (parentEl) {
87
+ const currentEl = current;
88
+ const siblings = Array.from(parentEl.children);
89
+ const sameTagSiblings = siblings.filter(
90
+ (s) => s.nodeName === currentEl.nodeName
91
+ );
92
+ if (sameTagSiblings.length > 1) {
93
+ const index = siblings.indexOf(currentEl) + 1;
94
+ selector += `:nth-child(${index})`;
95
+ }
96
+ }
97
+ path.unshift(selector);
98
+ current = current.parentElement;
99
+ }
100
+ return path.join(" > ");
101
+ }
102
+ function getBestIdentifier(element) {
103
+ const uiId = element.getAttribute("data-ui-id");
104
+ if (uiId) return uiId;
105
+ const testId = element.getAttribute("data-testid");
106
+ if (testId) return testId;
107
+ const awasId = element.getAttribute("data-awas-element");
108
+ if (awasId) return awasId;
109
+ if (element.id) return element.id;
110
+ return generateCSSSelector(element);
111
+ }
112
+ function createElementIdentifier(element) {
113
+ return {
114
+ uiId: element.getAttribute("data-ui-id") || void 0,
115
+ testId: element.getAttribute("data-testid") || void 0,
116
+ awasId: element.getAttribute("data-awas-element") || void 0,
117
+ htmlId: element.id || void 0,
118
+ xpath: generateXPath(element),
119
+ selector: generateCSSSelector(element)
120
+ };
121
+ }
122
+ var overlayStyles = {
123
+ position: "fixed",
124
+ pointerEvents: "none",
125
+ zIndex: 999999,
126
+ border: "2px solid #3b82f6",
127
+ backgroundColor: "rgba(59, 130, 246, 0.1)",
128
+ transition: "all 0.1s ease-out"
129
+ };
130
+ var labelStyles = {
131
+ position: "absolute",
132
+ top: "-24px",
133
+ left: "0",
134
+ padding: "2px 8px",
135
+ backgroundColor: "#3b82f6",
136
+ color: "white",
137
+ fontSize: "12px",
138
+ fontFamily: "monospace",
139
+ whiteSpace: "nowrap",
140
+ borderRadius: "4px 4px 0 0"
141
+ };
142
+ var panelStyles = {
143
+ position: "fixed",
144
+ bottom: "20px",
145
+ right: "20px",
146
+ width: "400px",
147
+ maxHeight: "500px",
148
+ overflow: "auto",
149
+ backgroundColor: "#1f2937",
150
+ color: "#f3f4f6",
151
+ borderRadius: "8px",
152
+ boxShadow: "0 4px 20px rgba(0, 0, 0, 0.3)",
153
+ fontFamily: "monospace",
154
+ fontSize: "12px",
155
+ zIndex: 999998
156
+ };
157
+ var headerStyles = {
158
+ padding: "12px 16px",
159
+ backgroundColor: "#111827",
160
+ borderBottom: "1px solid #374151",
161
+ display: "flex",
162
+ justifyContent: "space-between",
163
+ alignItems: "center",
164
+ borderRadius: "8px 8px 0 0"
165
+ };
166
+ var sectionStyles = {
167
+ padding: "12px 16px",
168
+ borderBottom: "1px solid #374151"
169
+ };
170
+ var labelKeyStyles = {
171
+ color: "#9ca3af",
172
+ marginRight: "8px"
173
+ };
174
+ var valueStyles = {
175
+ color: "#60a5fa"
176
+ };
177
+ function getElementState(element) {
178
+ const rect = element.getBoundingClientRect();
179
+ const style = window.getComputedStyle(element);
180
+ const state = {
181
+ visible: rect.width > 0 && rect.height > 0 && style.display !== "none",
182
+ enabled: !("disabled" in element && element.disabled),
183
+ focused: document.activeElement === element,
184
+ rect: {
185
+ x: rect.x,
186
+ y: rect.y,
187
+ width: rect.width,
188
+ height: rect.height,
189
+ top: rect.top,
190
+ right: rect.right,
191
+ bottom: rect.bottom,
192
+ left: rect.left
193
+ },
194
+ computedStyles: {
195
+ display: style.display,
196
+ visibility: style.visibility,
197
+ opacity: style.opacity,
198
+ pointerEvents: style.pointerEvents
199
+ }
200
+ };
201
+ if (element instanceof HTMLInputElement) {
202
+ state.value = element.value;
203
+ if (element.type === "checkbox" || element.type === "radio") {
204
+ state.checked = element.checked;
205
+ }
206
+ }
207
+ return state;
208
+ }
209
+ function InspectorOverlay({ bounds, label }) {
210
+ return /* @__PURE__ */ jsxRuntime.jsx(
211
+ "div",
212
+ {
213
+ style: {
214
+ ...overlayStyles,
215
+ left: bounds.left + window.scrollX,
216
+ top: bounds.top + window.scrollY,
217
+ width: bounds.width,
218
+ height: bounds.height
219
+ },
220
+ children: /* @__PURE__ */ jsxRuntime.jsx("span", { style: labelStyles, children: label })
221
+ }
222
+ );
223
+ }
224
+ function InfoPanel({ element, onClose, registeredElement }) {
225
+ if (!element) return null;
226
+ const identifier = createElementIdentifier(element);
227
+ const state = getElementState(element);
228
+ const bestId = getBestIdentifier(element);
229
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: panelStyles, children: [
230
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: headerStyles, children: [
231
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontWeight: "bold", color: "#60a5fa" }, children: "UI Bridge Inspector" }),
232
+ /* @__PURE__ */ jsxRuntime.jsx(
233
+ "button",
234
+ {
235
+ onClick: onClose,
236
+ style: {
237
+ background: "none",
238
+ border: "none",
239
+ color: "#9ca3af",
240
+ cursor: "pointer",
241
+ fontSize: "16px"
242
+ },
243
+ children: "\xD7"
244
+ }
245
+ )
246
+ ] }),
247
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: sectionStyles, children: [
248
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { marginBottom: "8px", fontWeight: "bold", color: "#f3f4f6" }, children: "Element" }),
249
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
250
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: labelKeyStyles, children: "Tag:" }),
251
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: valueStyles, children: element.tagName.toLowerCase() })
252
+ ] }),
253
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
254
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: labelKeyStyles, children: "Best ID:" }),
255
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: valueStyles, children: bestId })
256
+ ] }),
257
+ identifier.uiId && /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
258
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: labelKeyStyles, children: "data-ui-id:" }),
259
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: valueStyles, children: identifier.uiId })
260
+ ] }),
261
+ identifier.testId && /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
262
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: labelKeyStyles, children: "data-testid:" }),
263
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: valueStyles, children: identifier.testId })
264
+ ] }),
265
+ identifier.htmlId && /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
266
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: labelKeyStyles, children: "id:" }),
267
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: valueStyles, children: identifier.htmlId })
268
+ ] }),
269
+ registeredElement && /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
270
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: labelKeyStyles, children: "Registered:" }),
271
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { style: { color: "#10b981" }, children: [
272
+ "Yes (",
273
+ registeredElement.type,
274
+ ")"
275
+ ] })
276
+ ] })
277
+ ] }),
278
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: sectionStyles, children: [
279
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { marginBottom: "8px", fontWeight: "bold", color: "#f3f4f6" }, children: "State" }),
280
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
281
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: labelKeyStyles, children: "Visible:" }),
282
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: { color: state.visible ? "#10b981" : "#ef4444" }, children: state.visible ? "Yes" : "No" })
283
+ ] }),
284
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
285
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: labelKeyStyles, children: "Enabled:" }),
286
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: { color: state.enabled ? "#10b981" : "#ef4444" }, children: state.enabled ? "Yes" : "No" })
287
+ ] }),
288
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
289
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: labelKeyStyles, children: "Focused:" }),
290
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: { color: state.focused ? "#10b981" : "#9ca3af" }, children: state.focused ? "Yes" : "No" })
291
+ ] }),
292
+ state.value !== void 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
293
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: labelKeyStyles, children: "Value:" }),
294
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { style: valueStyles, children: [
295
+ '"',
296
+ state.value,
297
+ '"'
298
+ ] })
299
+ ] }),
300
+ state.checked !== void 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
301
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: labelKeyStyles, children: "Checked:" }),
302
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: { color: state.checked ? "#10b981" : "#9ca3af" }, children: state.checked ? "Yes" : "No" })
303
+ ] })
304
+ ] }),
305
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: sectionStyles, children: [
306
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { marginBottom: "8px", fontWeight: "bold", color: "#f3f4f6" }, children: "Bounds" }),
307
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
308
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: labelKeyStyles, children: "Position:" }),
309
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { style: valueStyles, children: [
310
+ "(",
311
+ Math.round(state.rect.x),
312
+ ", ",
313
+ Math.round(state.rect.y),
314
+ ")"
315
+ ] })
316
+ ] }),
317
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
318
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: labelKeyStyles, children: "Size:" }),
319
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { style: valueStyles, children: [
320
+ Math.round(state.rect.width),
321
+ " \xD7 ",
322
+ Math.round(state.rect.height)
323
+ ] })
324
+ ] })
325
+ ] }),
326
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { ...sectionStyles, borderBottom: "none" }, children: [
327
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { marginBottom: "8px", fontWeight: "bold", color: "#f3f4f6" }, children: "Selectors" }),
328
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { wordBreak: "break-all", marginBottom: "4px" }, children: [
329
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: labelKeyStyles, children: "CSS:" }),
330
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: valueStyles, children: identifier.selector })
331
+ ] }),
332
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { wordBreak: "break-all" }, children: [
333
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: labelKeyStyles, children: "XPath:" }),
334
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: valueStyles, children: identifier.xpath })
335
+ ] })
336
+ ] }),
337
+ registeredElement && registeredElement.actions.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { ...sectionStyles, borderBottom: "none" }, children: [
338
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { marginBottom: "8px", fontWeight: "bold", color: "#f3f4f6" }, children: "Actions" }),
339
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { display: "flex", flexWrap: "wrap", gap: "4px" }, children: registeredElement.actions.map((action) => /* @__PURE__ */ jsxRuntime.jsx(
340
+ "span",
341
+ {
342
+ style: {
343
+ padding: "2px 8px",
344
+ backgroundColor: "#374151",
345
+ borderRadius: "4px",
346
+ color: "#60a5fa"
347
+ },
348
+ children: action
349
+ },
350
+ action
351
+ )) })
352
+ ] })
353
+ ] });
354
+ }
355
+ function useInspector(options = {}) {
356
+ const [active, setActive] = react.useState(false);
357
+ const [hoveredElement, setHoveredElement] = react.useState(null);
358
+ const [selectedElement, setSelectedElement] = react.useState(null);
359
+ const shortcut = react.useMemo(
360
+ () => options.shortcut ?? { key: "i", ctrl: true, shift: true },
361
+ [options.shortcut]
362
+ );
363
+ const toggle = react.useCallback(() => {
364
+ setActive((prev) => !prev);
365
+ if (active) {
366
+ setHoveredElement(null);
367
+ setSelectedElement(null);
368
+ }
369
+ }, [active]);
370
+ react.useEffect(() => {
371
+ const handleKeyDown = (e) => {
372
+ if (e.key.toLowerCase() === shortcut.key && e.ctrlKey === !!shortcut.ctrl && e.shiftKey === !!shortcut.shift && e.altKey === !!shortcut.alt) {
373
+ e.preventDefault();
374
+ toggle();
375
+ }
376
+ };
377
+ window.addEventListener("keydown", handleKeyDown);
378
+ return () => window.removeEventListener("keydown", handleKeyDown);
379
+ }, [toggle, shortcut]);
380
+ react.useEffect(() => {
381
+ if (!active) return;
382
+ const handleMouseOver = (e) => {
383
+ const target = e.target;
384
+ if (target && target !== hoveredElement) {
385
+ setHoveredElement(target);
386
+ }
387
+ };
388
+ const handleClick = (e) => {
389
+ e.preventDefault();
390
+ e.stopPropagation();
391
+ const target = e.target;
392
+ setSelectedElement(target);
393
+ options.onSelect?.(target);
394
+ };
395
+ document.addEventListener("mouseover", handleMouseOver, true);
396
+ document.addEventListener("click", handleClick, true);
397
+ return () => {
398
+ document.removeEventListener("mouseover", handleMouseOver, true);
399
+ document.removeEventListener("click", handleClick, true);
400
+ };
401
+ }, [active, hoveredElement, options]);
402
+ const displayElement = selectedElement || hoveredElement;
403
+ const bounds = displayElement?.getBoundingClientRect() || null;
404
+ const registeredElement = displayElement ? options.getRegisteredElement?.(displayElement) : void 0;
405
+ return {
406
+ active,
407
+ toggle,
408
+ hoveredElement,
409
+ selectedElement,
410
+ setSelectedElement,
411
+ displayElement,
412
+ bounds,
413
+ registeredElement,
414
+ clearSelection: () => {
415
+ setSelectedElement(null);
416
+ }
417
+ };
418
+ }
419
+ function Inspector({ getRegisteredElement, initialActive }) {
420
+ const inspector = useInspector({
421
+ getRegisteredElement
422
+ });
423
+ react.useEffect(() => {
424
+ if (initialActive && !inspector.active) {
425
+ inspector.toggle();
426
+ }
427
+ }, [initialActive]);
428
+ if (!inspector.active) return null;
429
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
430
+ inspector.bounds && /* @__PURE__ */ jsxRuntime.jsx(
431
+ InspectorOverlay,
432
+ {
433
+ bounds: inspector.bounds,
434
+ label: inspector.displayElement ? getBestIdentifier(inspector.displayElement) : ""
435
+ }
436
+ ),
437
+ inspector.selectedElement && /* @__PURE__ */ jsxRuntime.jsx(
438
+ InfoPanel,
439
+ {
440
+ element: inspector.selectedElement,
441
+ onClose: inspector.clearSelection,
442
+ registeredElement: inspector.registeredElement
443
+ }
444
+ )
445
+ ] });
446
+ }
447
+
448
+ // src/debug/metrics.ts
449
+ function generateId() {
450
+ return `${Date.now()}-${Math.random().toString(36).substr(2, 8)}`;
451
+ }
452
+ var MetricsCollector = class {
453
+ constructor(options = {}) {
454
+ this.history = [];
455
+ this.maxHistoryEntries = options.maxHistoryEntries ?? 1e3;
456
+ this.rateWindow = options.rateWindow ?? 6e4;
457
+ }
458
+ /**
459
+ * Record an element action
460
+ */
461
+ recordElementAction(target, action, response, params) {
462
+ const entry = {
463
+ id: generateId(),
464
+ timestamp: response.timestamp,
465
+ type: "element",
466
+ target,
467
+ action,
468
+ success: response.success,
469
+ durationMs: response.durationMs,
470
+ error: response.error,
471
+ params,
472
+ response: response.elementState
473
+ };
474
+ this.addEntry(entry);
475
+ return entry;
476
+ }
477
+ /**
478
+ * Record a component action
479
+ */
480
+ recordComponentAction(target, action, response, params) {
481
+ const entry = {
482
+ id: generateId(),
483
+ timestamp: response.timestamp,
484
+ type: "component",
485
+ target,
486
+ action,
487
+ success: response.success,
488
+ durationMs: response.durationMs,
489
+ error: response.error,
490
+ params,
491
+ response: response.result
492
+ };
493
+ this.addEntry(entry);
494
+ return entry;
495
+ }
496
+ /**
497
+ * Record a workflow step
498
+ */
499
+ recordWorkflowStep(workflowId, result) {
500
+ const entry = {
501
+ id: generateId(),
502
+ timestamp: result.timestamp,
503
+ type: "workflow-step",
504
+ target: workflowId,
505
+ action: result.stepId,
506
+ success: result.success,
507
+ durationMs: result.durationMs,
508
+ error: result.error,
509
+ response: result.result
510
+ };
511
+ this.addEntry(entry);
512
+ return entry;
513
+ }
514
+ /**
515
+ * Record from a bridge event
516
+ */
517
+ recordEvent(event) {
518
+ if (event.type === "action:completed" || event.type === "action:failed") {
519
+ const data = event.data;
520
+ if (data.elementId) {
521
+ this.recordElementAction(
522
+ data.elementId,
523
+ data.action,
524
+ data.response,
525
+ data.params
526
+ );
527
+ } else if (data.componentId) {
528
+ this.recordComponentAction(
529
+ data.componentId,
530
+ data.action,
531
+ data.response,
532
+ data.params
533
+ );
534
+ }
535
+ }
536
+ }
537
+ /**
538
+ * Get action history
539
+ */
540
+ getHistory(options) {
541
+ let results = [...this.history];
542
+ if (options?.type) {
543
+ results = results.filter((e) => e.type === options.type);
544
+ }
545
+ if (options?.target) {
546
+ results = results.filter((e) => e.target === options.target);
547
+ }
548
+ if (options?.action) {
549
+ results = results.filter((e) => e.action === options.action);
550
+ }
551
+ if (options?.success !== void 0) {
552
+ results = results.filter((e) => e.success === options.success);
553
+ }
554
+ if (options?.since) {
555
+ results = results.filter((e) => e.timestamp >= options.since);
556
+ }
557
+ if (options?.limit) {
558
+ results = results.slice(-options.limit);
559
+ }
560
+ return results;
561
+ }
562
+ /**
563
+ * Get performance metrics
564
+ */
565
+ getMetrics(since) {
566
+ const entries = since ? this.history.filter((e) => e.timestamp >= since) : this.history;
567
+ if (entries.length === 0) {
568
+ return {
569
+ totalActions: 0,
570
+ successfulActions: 0,
571
+ failedActions: 0,
572
+ successRate: 0,
573
+ avgDurationMs: 0,
574
+ minDurationMs: 0,
575
+ maxDurationMs: 0,
576
+ p95DurationMs: 0,
577
+ actionsPerSecond: 0,
578
+ errorsByType: {},
579
+ actionsByType: {}
580
+ };
581
+ }
582
+ const successful = entries.filter((e) => e.success);
583
+ const failed = entries.filter((e) => !e.success);
584
+ const durations = entries.map((e) => e.durationMs).sort((a, b) => a - b);
585
+ const now = Date.now();
586
+ const windowStart = now - this.rateWindow;
587
+ const recentActions = this.history.filter((e) => e.timestamp >= windowStart);
588
+ const windowSeconds = this.rateWindow / 1e3;
589
+ const errorsByType = {};
590
+ for (const entry of failed) {
591
+ const errorType = entry.error?.split(":")[0] || "Unknown";
592
+ errorsByType[errorType] = (errorsByType[errorType] || 0) + 1;
593
+ }
594
+ const actionsByType = {};
595
+ for (const entry of entries) {
596
+ const key = `${entry.type}:${entry.action}`;
597
+ actionsByType[key] = (actionsByType[key] || 0) + 1;
598
+ }
599
+ return {
600
+ totalActions: entries.length,
601
+ successfulActions: successful.length,
602
+ failedActions: failed.length,
603
+ successRate: successful.length / entries.length,
604
+ avgDurationMs: durations.reduce((a, b) => a + b, 0) / durations.length,
605
+ minDurationMs: durations[0],
606
+ maxDurationMs: durations[durations.length - 1],
607
+ p95DurationMs: durations[Math.floor(durations.length * 0.95)],
608
+ actionsPerSecond: recentActions.length / windowSeconds,
609
+ errorsByType,
610
+ actionsByType
611
+ };
612
+ }
613
+ /**
614
+ * Get recent errors
615
+ */
616
+ getRecentErrors(limit = 10) {
617
+ return this.history.filter((e) => !e.success).slice(-limit);
618
+ }
619
+ /**
620
+ * Get slowest actions
621
+ */
622
+ getSlowestActions(limit = 10) {
623
+ return [...this.history].sort((a, b) => b.durationMs - a.durationMs).slice(0, limit);
624
+ }
625
+ /**
626
+ * Clear history
627
+ */
628
+ clearHistory() {
629
+ this.history = [];
630
+ }
631
+ /**
632
+ * Export history as JSON
633
+ */
634
+ exportHistory() {
635
+ return JSON.stringify(this.history, null, 2);
636
+ }
637
+ /**
638
+ * Import history from JSON
639
+ */
640
+ importHistory(json) {
641
+ const entries = JSON.parse(json);
642
+ this.history = entries.slice(-this.maxHistoryEntries);
643
+ }
644
+ addEntry(entry) {
645
+ this.history.push(entry);
646
+ while (this.history.length > this.maxHistoryEntries) {
647
+ this.history.shift();
648
+ }
649
+ }
650
+ };
651
+ function createMetricsCollector(options) {
652
+ return new MetricsCollector(options);
653
+ }
654
+ function formatDuration(ms) {
655
+ if (ms < 1) return "<1ms";
656
+ if (ms < 1e3) return `${Math.round(ms)}ms`;
657
+ if (ms < 6e4) return `${(ms / 1e3).toFixed(1)}s`;
658
+ return `${(ms / 6e4).toFixed(1)}m`;
659
+ }
660
+ function formatPercentage(value) {
661
+ return `${(value * 100).toFixed(1)}%`;
662
+ }
663
+
664
+ exports.InfoPanel = InfoPanel;
665
+ exports.Inspector = Inspector;
666
+ exports.InspectorOverlay = InspectorOverlay;
667
+ exports.MetricsCollector = MetricsCollector;
668
+ exports.createMetricsCollector = createMetricsCollector;
669
+ exports.formatDuration = formatDuration;
670
+ exports.formatPercentage = formatPercentage;
671
+ exports.useInspector = useInspector;
672
+ //# sourceMappingURL=index.js.map
673
+ //# sourceMappingURL=index.js.map