@qontinui/ui-bridge 0.3.0 → 0.3.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 (127) hide show
  1. package/dist/ai/index.d.mts +312 -155
  2. package/dist/ai/index.d.ts +312 -155
  3. package/dist/ai/index.js +2363 -67
  4. package/dist/ai/index.js.map +1 -1
  5. package/dist/ai/index.mjs +2328 -68
  6. package/dist/ai/index.mjs.map +1 -1
  7. package/dist/annotations/index.d.mts +218 -0
  8. package/dist/annotations/index.d.ts +218 -0
  9. package/dist/annotations/index.js +246 -0
  10. package/dist/annotations/index.js.map +1 -0
  11. package/dist/annotations/index.mjs +241 -0
  12. package/dist/annotations/index.mjs.map +1 -0
  13. package/dist/assertions-BSR3afVr.d.ts +161 -0
  14. package/dist/assertions-CTw1hfOx.d.mts +161 -0
  15. package/dist/babel-plugin/index.js +23 -34
  16. package/dist/babel-plugin/index.js.map +1 -1
  17. package/dist/babel-plugin/index.mjs +23 -34
  18. package/dist/babel-plugin/index.mjs.map +1 -1
  19. package/dist/browser-capture-Bms60T6f.d.mts +47 -0
  20. package/dist/browser-capture-CsTU29mb.d.ts +47 -0
  21. package/dist/control/index.d.mts +26 -7
  22. package/dist/control/index.d.ts +26 -7
  23. package/dist/control/index.js +276 -48
  24. package/dist/control/index.js.map +1 -1
  25. package/dist/control/index.mjs +276 -48
  26. package/dist/control/index.mjs.map +1 -1
  27. package/dist/core/index.d.mts +2 -2
  28. package/dist/core/index.d.ts +2 -2
  29. package/dist/core/index.js.map +1 -1
  30. package/dist/core/index.mjs.map +1 -1
  31. package/dist/debug/index.d.mts +5 -3
  32. package/dist/debug/index.d.ts +5 -3
  33. package/dist/debug/index.js +925 -1
  34. package/dist/debug/index.js.map +1 -1
  35. package/dist/debug/index.mjs +924 -2
  36. package/dist/debug/index.mjs.map +1 -1
  37. package/dist/index.d.mts +12 -7
  38. package/dist/index.d.ts +12 -7
  39. package/dist/index.js +4720 -173
  40. package/dist/index.js.map +1 -1
  41. package/dist/index.mjs +4656 -174
  42. package/dist/index.mjs.map +1 -1
  43. package/dist/{metrics-DTA2bwG7.d.mts → metrics-DuA2qIIz.d.mts} +2 -2
  44. package/dist/{metrics-BfiT_rhZ.d.ts → metrics-KFAAKNEB.d.ts} +2 -2
  45. package/dist/native/control/index.js +2 -7
  46. package/dist/native/control/index.js.map +1 -1
  47. package/dist/native/control/index.mjs +2 -7
  48. package/dist/native/control/index.mjs.map +1 -1
  49. package/dist/native/core/index.js.map +1 -1
  50. package/dist/native/core/index.mjs.map +1 -1
  51. package/dist/native/debug/index.js +23 -66
  52. package/dist/native/debug/index.js.map +1 -1
  53. package/dist/native/debug/index.mjs +23 -66
  54. package/dist/native/debug/index.mjs.map +1 -1
  55. package/dist/native/index.js +89 -131
  56. package/dist/native/index.js.map +1 -1
  57. package/dist/native/index.mjs +89 -131
  58. package/dist/native/index.mjs.map +1 -1
  59. package/dist/native/react/index.js +28 -52
  60. package/dist/native/react/index.js.map +1 -1
  61. package/dist/native/react/index.mjs +28 -52
  62. package/dist/native/react/index.mjs.map +1 -1
  63. package/dist/native/server/index.js +38 -13
  64. package/dist/native/server/index.js.map +1 -1
  65. package/dist/native/server/index.mjs +38 -13
  66. package/dist/native/server/index.mjs.map +1 -1
  67. package/dist/react/index.d.mts +107 -8
  68. package/dist/react/index.d.ts +107 -8
  69. package/dist/react/index.js +2194 -84
  70. package/dist/react/index.js.map +1 -1
  71. package/dist/react/index.mjs +2194 -85
  72. package/dist/react/index.mjs.map +1 -1
  73. package/dist/{registry-BKLEm-yk.d.ts → registry-C6dDtn1v.d.ts} +27 -2
  74. package/dist/{registry-BmZgyCz8.d.mts → registry-POtcxnal.d.mts} +27 -2
  75. package/dist/render-log/index.d.mts +1 -1
  76. package/dist/render-log/index.d.ts +1 -1
  77. package/dist/server/express.d.mts +5 -4
  78. package/dist/server/express.d.ts +5 -4
  79. package/dist/server/express.js +104 -2
  80. package/dist/server/express.js.map +1 -1
  81. package/dist/server/express.mjs +104 -2
  82. package/dist/server/express.mjs.map +1 -1
  83. package/dist/server/handlers.d.mts +36 -5
  84. package/dist/server/handlers.d.ts +36 -5
  85. package/dist/server/handlers.js +3129 -224
  86. package/dist/server/handlers.js.map +1 -1
  87. package/dist/server/handlers.mjs +3129 -224
  88. package/dist/server/handlers.mjs.map +1 -1
  89. package/dist/server/index.d.mts +7 -5
  90. package/dist/server/index.d.ts +7 -5
  91. package/dist/server/index.js +3215 -183
  92. package/dist/server/index.js.map +1 -1
  93. package/dist/server/index.mjs +3215 -183
  94. package/dist/server/index.mjs.map +1 -1
  95. package/dist/server/nextjs.d.mts +6 -4
  96. package/dist/server/nextjs.d.ts +6 -4
  97. package/dist/server/nextjs.js +106 -3
  98. package/dist/server/nextjs.js.map +1 -1
  99. package/dist/server/nextjs.mjs +106 -3
  100. package/dist/server/nextjs.mjs.map +1 -1
  101. package/dist/server/standalone.d.mts +6 -5
  102. package/dist/server/standalone.d.ts +6 -5
  103. package/dist/server/standalone.js +131 -5
  104. package/dist/server/standalone.js.map +1 -1
  105. package/dist/server/standalone.mjs +131 -5
  106. package/dist/server/standalone.mjs.map +1 -1
  107. package/dist/specs/index.d.mts +365 -0
  108. package/dist/specs/index.d.ts +365 -0
  109. package/dist/specs/index.js +2809 -0
  110. package/dist/specs/index.js.map +1 -0
  111. package/dist/specs/index.mjs +2786 -0
  112. package/dist/specs/index.mjs.map +1 -0
  113. package/dist/{standalone-BURj8J3G.d.ts → standalone-B6GLIEmR.d.ts} +6 -2
  114. package/dist/{standalone-Dwmel29d.d.mts → standalone-CjdYqj3P.d.mts} +6 -2
  115. package/dist/{types-CHnlwiTK.d.ts → types-B2EfvEaq.d.ts} +83 -3
  116. package/dist/{types-B7J7noLK.d.mts → types-C7gVYRnF.d.ts} +72 -2
  117. package/dist/{types-BkNRILUa.d.ts → types-CJGrBEhC.d.mts} +72 -2
  118. package/dist/types-CebMQj76.d.ts +1275 -0
  119. package/dist/types-D_ypYl3T.d.mts +1275 -0
  120. package/dist/types-UBtp7R0u.d.mts +132 -0
  121. package/dist/types-UBtp7R0u.d.ts +132 -0
  122. package/dist/{types-CEQLnFMv.d.mts → types-gO696T_t.d.mts} +83 -3
  123. package/dist/{types-jKVgTI6_.d.mts → types-suaYwWWg.d.mts} +173 -2
  124. package/dist/{types-jKVgTI6_.d.ts → types-suaYwWWg.d.ts} +173 -2
  125. package/package.json +18 -2
  126. package/dist/types-B5Q0GVo0.d.mts +0 -646
  127. package/dist/types-DfPqwU-i.d.ts +0 -646
@@ -117,6 +117,241 @@ function createElementIdentifier(element) {
117
117
  selector: generateCSSSelector(element)
118
118
  };
119
119
  }
120
+
121
+ // src/annotations/types.ts
122
+ var ANNOTATION_CONFIG_VERSION = "1.0.0";
123
+
124
+ // src/annotations/store.ts
125
+ var AnnotationStore = class {
126
+ constructor() {
127
+ this.store = /* @__PURE__ */ new Map();
128
+ this.listeners = /* @__PURE__ */ new Set();
129
+ }
130
+ /**
131
+ * Get an annotation by element ID.
132
+ */
133
+ get(elementId) {
134
+ return this.store.get(elementId);
135
+ }
136
+ /**
137
+ * Get all annotations as a record.
138
+ */
139
+ getAll() {
140
+ const result = {};
141
+ for (const [id, annotation] of this.store) {
142
+ result[id] = annotation;
143
+ }
144
+ return result;
145
+ }
146
+ /**
147
+ * Set an annotation for an element. Auto-sets `updatedAt`.
148
+ */
149
+ set(elementId, annotation) {
150
+ const updated = {
151
+ ...annotation,
152
+ updatedAt: Date.now()
153
+ };
154
+ this.store.set(elementId, updated);
155
+ this.emit({
156
+ type: "annotation:set",
157
+ elementId,
158
+ annotation: updated,
159
+ timestamp: Date.now()
160
+ });
161
+ }
162
+ /**
163
+ * Delete an annotation by element ID.
164
+ *
165
+ * @returns true if the annotation existed and was deleted
166
+ */
167
+ delete(elementId) {
168
+ const existed = this.store.delete(elementId);
169
+ if (existed) {
170
+ this.emit({
171
+ type: "annotation:deleted",
172
+ elementId,
173
+ timestamp: Date.now()
174
+ });
175
+ }
176
+ return existed;
177
+ }
178
+ /**
179
+ * Check if an annotation exists for an element.
180
+ */
181
+ has(elementId) {
182
+ return this.store.has(elementId);
183
+ }
184
+ /**
185
+ * Get the number of stored annotations.
186
+ */
187
+ get count() {
188
+ return this.store.size;
189
+ }
190
+ /**
191
+ * Clear all annotations.
192
+ */
193
+ clear() {
194
+ this.store.clear();
195
+ this.emit({
196
+ type: "annotation:cleared",
197
+ timestamp: Date.now()
198
+ });
199
+ }
200
+ /**
201
+ * Import annotations from a config object.
202
+ *
203
+ * Merges with existing annotations (new values overwrite per element ID).
204
+ *
205
+ * @returns Number of annotations imported
206
+ *
207
+ * @example
208
+ * ```ts
209
+ * const config: AnnotationConfig = {
210
+ * version: '1.0.0',
211
+ * annotations: {
212
+ * 'btn-1': { description: 'Submit button', tags: ['form'] },
213
+ * 'input-1': { description: 'Name field' },
214
+ * },
215
+ * };
216
+ * const count = store.importConfig(config); // 2
217
+ * ```
218
+ */
219
+ importConfig(config) {
220
+ let count = 0;
221
+ for (const [id, annotation] of Object.entries(config.annotations)) {
222
+ this.store.set(id, {
223
+ ...annotation,
224
+ updatedAt: annotation.updatedAt ?? Date.now()
225
+ });
226
+ count++;
227
+ }
228
+ this.emit({
229
+ type: "annotation:imported",
230
+ count,
231
+ timestamp: Date.now()
232
+ });
233
+ return count;
234
+ }
235
+ /**
236
+ * Export all annotations as a config object.
237
+ *
238
+ * The returned object can be serialized to JSON and saved to a file,
239
+ * then later re-imported with {@link importConfig}.
240
+ *
241
+ * @param metadata - Optional metadata to include (appName, description, etc.)
242
+ * @returns AnnotationConfig with all current annotations
243
+ *
244
+ * @example
245
+ * ```ts
246
+ * const config = store.exportConfig({ appName: 'MyApp' });
247
+ * // config.version === '1.0.0'
248
+ * // config.annotations === { 'btn-1': { ... }, 'input-1': { ... } }
249
+ * // config.metadata === { appName: 'MyApp', exportedAt: 1706900000000 }
250
+ *
251
+ * // Save to file
252
+ * fs.writeFileSync('annotations.json', JSON.stringify(config, null, 2));
253
+ * ```
254
+ */
255
+ exportConfig(metadata) {
256
+ return {
257
+ version: ANNOTATION_CONFIG_VERSION,
258
+ annotations: this.getAll(),
259
+ metadata: {
260
+ ...metadata,
261
+ exportedAt: Date.now()
262
+ }
263
+ };
264
+ }
265
+ /**
266
+ * Compute annotation coverage against a set of known element IDs.
267
+ *
268
+ * Compares the store's annotations against the provided list of element IDs
269
+ * to determine what percentage of elements have been annotated.
270
+ *
271
+ * @param allElementIds - Array of all known element IDs in the UI
272
+ * @returns Coverage statistics including percentages and lists of annotated/unannotated IDs
273
+ *
274
+ * @example
275
+ * ```ts
276
+ * store.set('btn-1', { description: 'Submit' });
277
+ * store.set('input-1', { description: 'Name' });
278
+ *
279
+ * const coverage = store.getCoverage(['btn-1', 'input-1', 'input-2', 'link-1']);
280
+ * // coverage.totalElements === 4
281
+ * // coverage.annotatedElements === 2
282
+ * // coverage.coveragePercent === 50
283
+ * // coverage.annotatedIds === ['btn-1', 'input-1']
284
+ * // coverage.unannotatedIds === ['input-2', 'link-1']
285
+ * ```
286
+ */
287
+ getCoverage(allElementIds) {
288
+ const annotatedIds = [];
289
+ const unannotatedIds = [];
290
+ for (const id of allElementIds) {
291
+ if (this.store.has(id)) {
292
+ annotatedIds.push(id);
293
+ } else {
294
+ unannotatedIds.push(id);
295
+ }
296
+ }
297
+ const total = allElementIds.length;
298
+ return {
299
+ totalElements: total,
300
+ annotatedElements: annotatedIds.length,
301
+ coveragePercent: total > 0 ? annotatedIds.length / total * 100 : 0,
302
+ annotatedIds,
303
+ unannotatedIds,
304
+ timestamp: Date.now()
305
+ };
306
+ }
307
+ /**
308
+ * Subscribe to annotation events.
309
+ *
310
+ * The listener is called whenever annotations are set, deleted, imported,
311
+ * or cleared. Returns an unsubscribe function to stop listening.
312
+ *
313
+ * @param listener - Callback function receiving {@link AnnotationEvent} objects
314
+ * @returns Unsubscribe function - call it to remove the listener
315
+ *
316
+ * @example
317
+ * ```ts
318
+ * const unsubscribe = store.on((event) => {
319
+ * if (event.type === 'annotation:set') {
320
+ * console.log(`Element ${event.elementId} annotated:`, event.annotation);
321
+ * }
322
+ * });
323
+ *
324
+ * store.set('btn-1', { description: 'Submit' });
325
+ * // Logs: "Element btn-1 annotated: { description: 'Submit', updatedAt: ... }"
326
+ *
327
+ * unsubscribe(); // Stop listening
328
+ * ```
329
+ */
330
+ on(listener) {
331
+ this.listeners.add(listener);
332
+ return () => {
333
+ this.listeners.delete(listener);
334
+ };
335
+ }
336
+ /**
337
+ * Emit an event to all listeners.
338
+ */
339
+ emit(event) {
340
+ for (const listener of this.listeners) {
341
+ try {
342
+ listener(event);
343
+ } catch {
344
+ }
345
+ }
346
+ }
347
+ };
348
+ var globalStore = null;
349
+ function getGlobalAnnotationStore() {
350
+ if (!globalStore) {
351
+ globalStore = new AnnotationStore();
352
+ }
353
+ return globalStore;
354
+ }
120
355
  var overlayStyles = {
121
356
  position: "fixed",
122
357
  pointerEvents: "none",
@@ -332,7 +567,7 @@ function InfoPanel({ element, onClose, registeredElement }) {
332
567
  /* @__PURE__ */ jsx("span", { style: valueStyles, children: identifier.xpath })
333
568
  ] })
334
569
  ] }),
335
- registeredElement && registeredElement.actions.length > 0 && /* @__PURE__ */ jsxs("div", { style: { ...sectionStyles, borderBottom: "none" }, children: [
570
+ registeredElement && registeredElement.actions.length > 0 && /* @__PURE__ */ jsxs("div", { style: sectionStyles, children: [
336
571
  /* @__PURE__ */ jsx("div", { style: { marginBottom: "8px", fontWeight: "bold", color: "#f3f4f6" }, children: "Actions" }),
337
572
  /* @__PURE__ */ jsx("div", { style: { display: "flex", flexWrap: "wrap", gap: "4px" }, children: registeredElement.actions.map((action) => /* @__PURE__ */ jsx(
338
573
  "span",
@@ -347,6 +582,43 @@ function InfoPanel({ element, onClose, registeredElement }) {
347
582
  },
348
583
  action
349
584
  )) })
585
+ ] }),
586
+ /* @__PURE__ */ jsx(AnnotationSection, { elementId: bestId })
587
+ ] });
588
+ }
589
+ function AnnotationSection({ elementId }) {
590
+ const annotation = getGlobalAnnotationStore().get(elementId);
591
+ if (!annotation) return null;
592
+ return /* @__PURE__ */ jsxs("div", { style: { ...sectionStyles, borderBottom: "none" }, children: [
593
+ /* @__PURE__ */ jsx("div", { style: { marginBottom: "8px", fontWeight: "bold", color: "#f3f4f6" }, children: "Annotation" }),
594
+ annotation.description && /* @__PURE__ */ jsxs("div", { style: { marginBottom: "4px" }, children: [
595
+ /* @__PURE__ */ jsx("span", { style: labelKeyStyles, children: "Description:" }),
596
+ /* @__PURE__ */ jsx("span", { style: valueStyles, children: annotation.description })
597
+ ] }),
598
+ annotation.purpose && /* @__PURE__ */ jsxs("div", { style: { marginBottom: "4px" }, children: [
599
+ /* @__PURE__ */ jsx("span", { style: labelKeyStyles, children: "Purpose:" }),
600
+ /* @__PURE__ */ jsx("span", { style: valueStyles, children: annotation.purpose })
601
+ ] }),
602
+ annotation.notes && /* @__PURE__ */ jsxs("div", { style: { marginBottom: "4px" }, children: [
603
+ /* @__PURE__ */ jsx("span", { style: labelKeyStyles, children: "Notes:" }),
604
+ /* @__PURE__ */ jsx("span", { style: { color: "#fbbf24" }, children: annotation.notes })
605
+ ] }),
606
+ annotation.tags && annotation.tags.length > 0 && /* @__PURE__ */ jsxs("div", { children: [
607
+ /* @__PURE__ */ jsx("span", { style: labelKeyStyles, children: "Tags:" }),
608
+ /* @__PURE__ */ jsx("span", { style: { display: "inline-flex", flexWrap: "wrap", gap: "4px" }, children: annotation.tags.map((tag) => /* @__PURE__ */ jsx(
609
+ "span",
610
+ {
611
+ style: {
612
+ padding: "1px 6px",
613
+ backgroundColor: "#1e3a5f",
614
+ borderRadius: "4px",
615
+ color: "#93c5fd",
616
+ fontSize: "11px"
617
+ },
618
+ children: tag
619
+ },
620
+ tag
621
+ )) })
350
622
  ] })
351
623
  ] });
352
624
  }
@@ -443,6 +715,656 @@ function Inspector({ getRegisteredElement, initialActive }) {
443
715
  ] });
444
716
  }
445
717
 
718
+ // src/debug/browser-capture-types.ts
719
+ var DEFAULT_CAPTURE_CONFIG = {
720
+ console: true,
721
+ network: true,
722
+ navigation: true,
723
+ longTasks: true,
724
+ longAnimationFrames: true,
725
+ resourceErrors: true,
726
+ wsDisconnections: true,
727
+ hmr: true,
728
+ webVitals: false,
729
+ memory: false,
730
+ memoryIntervalMs: 3e4,
731
+ maxEntries: 200
732
+ };
733
+
734
+ // src/debug/captures/console.ts
735
+ function argsToMessage(args) {
736
+ return args.map((a) => {
737
+ if (a instanceof Error) return a.message;
738
+ if (typeof a === "string") return a;
739
+ try {
740
+ return JSON.stringify(a);
741
+ } catch {
742
+ return String(a);
743
+ }
744
+ }).join(" ");
745
+ }
746
+ function extractStack(args) {
747
+ const err = args.find((a) => a instanceof Error);
748
+ return err?.stack;
749
+ }
750
+ function makeEvent(level, message, stack) {
751
+ return {
752
+ type: "console",
753
+ timestamp: Date.now(),
754
+ url: typeof window !== "undefined" ? window.location.href : "",
755
+ level,
756
+ message,
757
+ stack
758
+ };
759
+ }
760
+ function installConsoleCapture(emit) {
761
+ const originalError = console.error;
762
+ const originalWarn = console.warn;
763
+ console.error = (...args) => {
764
+ emit(makeEvent("error", argsToMessage(args), extractStack(args)));
765
+ originalError.apply(console, args);
766
+ };
767
+ console.warn = (...args) => {
768
+ emit(makeEvent("warn", argsToMessage(args), extractStack(args)));
769
+ originalWarn.apply(console, args);
770
+ };
771
+ const rejectionHandler = (event) => {
772
+ const reason = event.reason;
773
+ const message = reason instanceof Error ? reason.message : String(reason ?? "Unhandled rejection");
774
+ const stack = reason instanceof Error ? reason.stack : void 0;
775
+ emit(makeEvent("unhandledrejection", message, stack));
776
+ };
777
+ if (typeof window !== "undefined") {
778
+ window.addEventListener("unhandledrejection", rejectionHandler);
779
+ }
780
+ return () => {
781
+ console.error = originalError;
782
+ console.warn = originalWarn;
783
+ if (typeof window !== "undefined") {
784
+ window.removeEventListener("unhandledrejection", rejectionHandler);
785
+ }
786
+ };
787
+ }
788
+
789
+ // src/debug/captures/network.ts
790
+ var DEFAULT_IGNORE = ["/api/dev-debug/", "/api/ui-bridge/", "localhost:9876"];
791
+ function installNetworkCapture(emit, options) {
792
+ if (typeof window === "undefined" || typeof window.fetch !== "function") {
793
+ return () => {
794
+ };
795
+ }
796
+ const originalFetch = window.fetch;
797
+ const ignorePatterns = options?.ignorePatterns ?? DEFAULT_IGNORE;
798
+ function shouldIgnore(url) {
799
+ return ignorePatterns.some((p) => url.includes(p));
800
+ }
801
+ function getMethod(input, init) {
802
+ if (init?.method) return init.method.toUpperCase();
803
+ if (input instanceof Request) return input.method.toUpperCase();
804
+ return "GET";
805
+ }
806
+ function getUrl(input) {
807
+ if (typeof input === "string") return input;
808
+ if (input instanceof URL) return input.href;
809
+ if (input instanceof Request) return input.url;
810
+ return String(input);
811
+ }
812
+ window.fetch = async function patchedFetch(input, init) {
813
+ const requestUrl = getUrl(input);
814
+ if (shouldIgnore(requestUrl)) {
815
+ return originalFetch.call(window, input, init);
816
+ }
817
+ const method = getMethod(input, init);
818
+ const start = performance.now();
819
+ try {
820
+ const response = await originalFetch.call(window, input, init);
821
+ const durationMs = Math.round(performance.now() - start);
822
+ if (response.status >= 400) {
823
+ const event = {
824
+ type: "network",
825
+ timestamp: Date.now(),
826
+ url: typeof window !== "undefined" ? window.location.href : "",
827
+ method,
828
+ requestUrl,
829
+ status: response.status,
830
+ statusText: response.statusText,
831
+ durationMs,
832
+ kind: "http-error"
833
+ };
834
+ emit(event);
835
+ }
836
+ return response;
837
+ } catch (err) {
838
+ const durationMs = Math.round(performance.now() - start);
839
+ const errorMessage = err instanceof Error ? err.message : String(err);
840
+ let kind = "network-error";
841
+ if (err instanceof DOMException && err.name === "AbortError") {
842
+ kind = "abort";
843
+ } else if (errorMessage.includes("CORS") || errorMessage.includes("cross-origin")) {
844
+ kind = "cors";
845
+ } else if (errorMessage.includes("timeout") || errorMessage.includes("timed out")) {
846
+ kind = "timeout";
847
+ }
848
+ const event = {
849
+ type: "network",
850
+ timestamp: Date.now(),
851
+ url: typeof window !== "undefined" ? window.location.href : "",
852
+ method,
853
+ requestUrl,
854
+ durationMs,
855
+ kind,
856
+ errorMessage
857
+ };
858
+ emit(event);
859
+ throw err;
860
+ }
861
+ };
862
+ return () => {
863
+ window.fetch = originalFetch;
864
+ };
865
+ }
866
+
867
+ // src/debug/captures/navigation.ts
868
+ function installNavigationCapture(emit) {
869
+ if (typeof window === "undefined" || typeof history === "undefined") {
870
+ return () => {
871
+ };
872
+ }
873
+ let lastUrl = window.location.href;
874
+ function emitNav(to, trigger) {
875
+ const from = lastUrl;
876
+ lastUrl = to;
877
+ if (from === to) return;
878
+ emit({
879
+ type: "navigation",
880
+ timestamp: Date.now(),
881
+ url: to,
882
+ from,
883
+ to,
884
+ trigger
885
+ });
886
+ }
887
+ const originalPushState = history.pushState;
888
+ const originalReplaceState = history.replaceState;
889
+ history.pushState = function(...args) {
890
+ originalPushState.apply(this, args);
891
+ emitNav(window.location.href, "pushState");
892
+ };
893
+ history.replaceState = function(...args) {
894
+ originalReplaceState.apply(this, args);
895
+ emitNav(window.location.href, "replaceState");
896
+ };
897
+ const popstateHandler = () => {
898
+ emitNav(window.location.href, "popstate");
899
+ };
900
+ window.addEventListener("popstate", popstateHandler);
901
+ return () => {
902
+ history.pushState = originalPushState;
903
+ history.replaceState = originalReplaceState;
904
+ window.removeEventListener("popstate", popstateHandler);
905
+ };
906
+ }
907
+
908
+ // src/debug/captures/long-tasks.ts
909
+ function installLongTaskCapture(emit) {
910
+ if (typeof window === "undefined" || typeof PerformanceObserver === "undefined") {
911
+ return () => {
912
+ };
913
+ }
914
+ try {
915
+ const observer = new PerformanceObserver((list) => {
916
+ for (const entry of list.getEntries()) {
917
+ emit({
918
+ type: "long-task",
919
+ timestamp: Date.now(),
920
+ url: window.location.href,
921
+ durationMs: Math.round(entry.duration)
922
+ });
923
+ }
924
+ });
925
+ observer.observe({ type: "longtask", buffered: true });
926
+ return () => {
927
+ observer.disconnect();
928
+ };
929
+ } catch {
930
+ return () => {
931
+ };
932
+ }
933
+ }
934
+
935
+ // src/debug/captures/resource-errors.ts
936
+ var TRACKED_TAGS = /* @__PURE__ */ new Set(["IMG", "SCRIPT", "LINK"]);
937
+ function installResourceErrorCapture(emit) {
938
+ if (typeof window === "undefined") {
939
+ return () => {
940
+ };
941
+ }
942
+ const handler = (event) => {
943
+ const target = event.target;
944
+ if (!target || !target.tagName) return;
945
+ if (!TRACKED_TAGS.has(target.tagName)) return;
946
+ const resourceUrl = target.src || target.src || target.href || "";
947
+ if (!resourceUrl) return;
948
+ emit({
949
+ type: "resource-error",
950
+ timestamp: Date.now(),
951
+ url: window.location.href,
952
+ resourceUrl,
953
+ tagName: target.tagName
954
+ });
955
+ };
956
+ window.addEventListener("error", handler, true);
957
+ return () => {
958
+ window.removeEventListener("error", handler, true);
959
+ };
960
+ }
961
+
962
+ // src/debug/captures/web-vitals.ts
963
+ function installWebVitalsCapture(emit) {
964
+ if (typeof window === "undefined" || typeof PerformanceObserver === "undefined") {
965
+ return () => {
966
+ };
967
+ }
968
+ const observers = [];
969
+ try {
970
+ const lcpObserver = new PerformanceObserver((list) => {
971
+ const entries = list.getEntries();
972
+ const last = entries[entries.length - 1];
973
+ if (last) {
974
+ emit({
975
+ type: "web-vital",
976
+ timestamp: Date.now(),
977
+ url: window.location.href,
978
+ metric: "LCP",
979
+ value: Math.round(last.startTime)
980
+ });
981
+ }
982
+ });
983
+ lcpObserver.observe({ type: "largest-contentful-paint", buffered: true });
984
+ observers.push(lcpObserver);
985
+ } catch {
986
+ }
987
+ try {
988
+ let clsValue = 0;
989
+ const clsObserver = new PerformanceObserver((list) => {
990
+ for (const entry of list.getEntries()) {
991
+ if (!entry.hadRecentInput) {
992
+ clsValue += entry.value ?? 0;
993
+ }
994
+ }
995
+ emit({
996
+ type: "web-vital",
997
+ timestamp: Date.now(),
998
+ url: window.location.href,
999
+ metric: "CLS",
1000
+ value: Math.round(clsValue * 1e3) / 1e3
1001
+ });
1002
+ });
1003
+ clsObserver.observe({ type: "layout-shift", buffered: true });
1004
+ observers.push(clsObserver);
1005
+ } catch {
1006
+ }
1007
+ return () => {
1008
+ for (const obs of observers) {
1009
+ obs.disconnect();
1010
+ }
1011
+ };
1012
+ }
1013
+
1014
+ // src/debug/captures/memory.ts
1015
+ function installMemoryCapture(emit, intervalMs = 3e4) {
1016
+ if (typeof window === "undefined") {
1017
+ return () => {
1018
+ };
1019
+ }
1020
+ const perf = performance;
1021
+ if (!perf.memory) {
1022
+ return () => {
1023
+ };
1024
+ }
1025
+ const tick = () => {
1026
+ const mem = perf.memory;
1027
+ if (!mem) return;
1028
+ emit({
1029
+ type: "memory",
1030
+ timestamp: Date.now(),
1031
+ url: window.location.href,
1032
+ usedJSHeapSize: mem.usedJSHeapSize,
1033
+ totalJSHeapSize: mem.totalJSHeapSize,
1034
+ jsHeapSizeLimit: mem.jsHeapSizeLimit
1035
+ });
1036
+ };
1037
+ tick();
1038
+ const id = setInterval(tick, intervalMs);
1039
+ return () => {
1040
+ clearInterval(id);
1041
+ };
1042
+ }
1043
+
1044
+ // src/debug/captures/hmr.ts
1045
+ var HMR_PATH_PATTERNS = ["/_next/webpack-hmr", "/__turbopack_hmr", "/_next/turbopack-hmr"];
1046
+ function isHmrUrl(url) {
1047
+ return HMR_PATH_PATTERNS.some((p) => url.includes(p));
1048
+ }
1049
+ function makeEvent2(level, message, moduleName, loc) {
1050
+ return {
1051
+ type: "hmr",
1052
+ level,
1053
+ message,
1054
+ moduleName,
1055
+ loc,
1056
+ timestamp: Date.now(),
1057
+ url: typeof window !== "undefined" ? window.location.href : ""
1058
+ };
1059
+ }
1060
+ function processHmrMessage(data, emit) {
1061
+ try {
1062
+ const msg = JSON.parse(data);
1063
+ if (Array.isArray(msg.errors)) {
1064
+ for (const err of msg.errors) {
1065
+ emit(
1066
+ makeEvent2(
1067
+ "error",
1068
+ typeof err === "string" ? err : err.message ?? String(err),
1069
+ err.moduleName ?? err.moduleIdentifier,
1070
+ err.loc ? String(err.loc) : void 0
1071
+ )
1072
+ );
1073
+ }
1074
+ }
1075
+ if (Array.isArray(msg.warnings)) {
1076
+ for (const warn of msg.warnings) {
1077
+ emit(
1078
+ makeEvent2(
1079
+ "warning",
1080
+ typeof warn === "string" ? warn : warn.message ?? String(warn),
1081
+ warn.moduleName ?? warn.moduleIdentifier,
1082
+ warn.loc ? String(warn.loc) : void 0
1083
+ )
1084
+ );
1085
+ }
1086
+ }
1087
+ if (msg.action === "serverError" && msg.errorJSON) {
1088
+ try {
1089
+ const err = JSON.parse(msg.errorJSON);
1090
+ emit(makeEvent2("error", err.message ?? String(err)));
1091
+ } catch {
1092
+ emit(makeEvent2("error", msg.errorJSON));
1093
+ }
1094
+ }
1095
+ if ((msg.action === "turbopack-message" || msg.type === "turbopack-message") && msg.data?.diagnostics) {
1096
+ for (const diag of msg.data.diagnostics) {
1097
+ emit(
1098
+ makeEvent2(
1099
+ diag.category === "warning" ? "warning" : "error",
1100
+ diag.message ?? String(diag),
1101
+ diag.filePath,
1102
+ diag.line != null ? `${diag.line}:${diag.column ?? 0}` : void 0
1103
+ )
1104
+ );
1105
+ }
1106
+ }
1107
+ } catch {
1108
+ }
1109
+ }
1110
+ function installWebSocketCapture(emit, cleanups) {
1111
+ if (!window.WebSocket) return;
1112
+ const OriginalWebSocket = window.WebSocket;
1113
+ const trackedSockets = [];
1114
+ const PatchedWebSocket = function(url, protocols) {
1115
+ const ws = new OriginalWebSocket(url, protocols);
1116
+ const urlStr = typeof url === "string" ? url : url.toString();
1117
+ if (isHmrUrl(urlStr)) {
1118
+ ws.addEventListener("message", (event) => {
1119
+ if (typeof event.data === "string") {
1120
+ processHmrMessage(event.data, emit);
1121
+ }
1122
+ });
1123
+ trackedSockets.push(ws);
1124
+ }
1125
+ return ws;
1126
+ };
1127
+ PatchedWebSocket.prototype = OriginalWebSocket.prototype;
1128
+ Object.defineProperty(PatchedWebSocket, "CONNECTING", { value: OriginalWebSocket.CONNECTING });
1129
+ Object.defineProperty(PatchedWebSocket, "OPEN", { value: OriginalWebSocket.OPEN });
1130
+ Object.defineProperty(PatchedWebSocket, "CLOSING", { value: OriginalWebSocket.CLOSING });
1131
+ Object.defineProperty(PatchedWebSocket, "CLOSED", { value: OriginalWebSocket.CLOSED });
1132
+ window.WebSocket = PatchedWebSocket;
1133
+ cleanups.push(() => {
1134
+ window.WebSocket = OriginalWebSocket;
1135
+ for (const ws of trackedSockets) {
1136
+ ws.close();
1137
+ }
1138
+ trackedSockets.length = 0;
1139
+ });
1140
+ }
1141
+ function installEventSourceCapture(emit, cleanups) {
1142
+ if (!window.EventSource) return;
1143
+ const OriginalEventSource = window.EventSource;
1144
+ const trackedSources = [];
1145
+ const messageHandler = (event) => {
1146
+ if (typeof event.data === "string") {
1147
+ processHmrMessage(event.data, emit);
1148
+ }
1149
+ };
1150
+ const PatchedEventSource = function(url, init) {
1151
+ const es = new OriginalEventSource(url, init);
1152
+ const urlStr = typeof url === "string" ? url : url.toString();
1153
+ if (isHmrUrl(urlStr)) {
1154
+ es.addEventListener("message", messageHandler);
1155
+ trackedSources.push(es);
1156
+ }
1157
+ return es;
1158
+ };
1159
+ PatchedEventSource.prototype = OriginalEventSource.prototype;
1160
+ Object.defineProperty(PatchedEventSource, "CONNECTING", {
1161
+ value: OriginalEventSource.CONNECTING
1162
+ });
1163
+ Object.defineProperty(PatchedEventSource, "OPEN", { value: OriginalEventSource.OPEN });
1164
+ Object.defineProperty(PatchedEventSource, "CLOSED", { value: OriginalEventSource.CLOSED });
1165
+ window.EventSource = PatchedEventSource;
1166
+ cleanups.push(() => {
1167
+ window.EventSource = OriginalEventSource;
1168
+ for (const es of trackedSources) {
1169
+ es.close();
1170
+ }
1171
+ trackedSources.length = 0;
1172
+ });
1173
+ }
1174
+ function installHmrCapture(emit) {
1175
+ if (typeof window === "undefined") return () => {
1176
+ };
1177
+ const cleanups = [];
1178
+ installWebSocketCapture(emit, cleanups);
1179
+ installEventSourceCapture(emit, cleanups);
1180
+ return () => {
1181
+ for (const cleanup of cleanups) {
1182
+ cleanup();
1183
+ }
1184
+ };
1185
+ }
1186
+
1187
+ // src/debug/captures/long-animation-frames.ts
1188
+ function installLoafCapture(emit) {
1189
+ if (typeof window === "undefined" || typeof PerformanceObserver === "undefined") {
1190
+ return () => {
1191
+ };
1192
+ }
1193
+ try {
1194
+ const observer = new PerformanceObserver((list) => {
1195
+ for (const entry of list.getEntries()) {
1196
+ const scripts = (entry.scripts ?? []).map((s) => {
1197
+ const script = s;
1198
+ return {
1199
+ invoker: script.invoker ?? "",
1200
+ sourceURL: script.sourceURL ?? "",
1201
+ sourceFunctionName: script.sourceFunctionName ?? "",
1202
+ sourceCharPosition: script.sourceCharPosition ?? 0,
1203
+ duration: Math.round(script.duration ?? 0)
1204
+ };
1205
+ });
1206
+ emit({
1207
+ type: "long-animation-frame",
1208
+ timestamp: Date.now(),
1209
+ url: window.location.href,
1210
+ durationMs: Math.round(entry.duration),
1211
+ blockingDurationMs: Math.round(
1212
+ entry.blockingDuration ?? 0
1213
+ ),
1214
+ scripts
1215
+ });
1216
+ }
1217
+ });
1218
+ observer.observe({ type: "long-animation-frame", buffered: true });
1219
+ return () => {
1220
+ observer.disconnect();
1221
+ };
1222
+ } catch {
1223
+ return () => {
1224
+ };
1225
+ }
1226
+ }
1227
+
1228
+ // src/debug/browser-capture.ts
1229
+ var BrowserEventCapture = class {
1230
+ constructor(config) {
1231
+ this.buffer = [];
1232
+ this.installed = false;
1233
+ this.cleanups = [];
1234
+ this.onEvent = null;
1235
+ this.config = config ?? {};
1236
+ this.maxEntries = config?.maxEntries ?? DEFAULT_CAPTURE_CONFIG.maxEntries;
1237
+ }
1238
+ setOnEvent(cb) {
1239
+ this.onEvent = cb;
1240
+ }
1241
+ /**
1242
+ * Install all enabled capture sub-modules.
1243
+ * Safe to call multiple times (no-ops if already installed).
1244
+ */
1245
+ install() {
1246
+ if (this.installed) return;
1247
+ const cfg = { ...DEFAULT_CAPTURE_CONFIG, ...this.config };
1248
+ const emit = (event) => {
1249
+ this.buffer.push(event);
1250
+ this.trim();
1251
+ this.onEvent?.(event);
1252
+ };
1253
+ if (cfg.console) {
1254
+ this.cleanups.push(installConsoleCapture(emit));
1255
+ }
1256
+ if (cfg.network) {
1257
+ this.cleanups.push(installNetworkCapture(emit, cfg.networkOptions));
1258
+ }
1259
+ if (cfg.navigation) {
1260
+ this.cleanups.push(installNavigationCapture(emit));
1261
+ }
1262
+ if (cfg.longTasks) {
1263
+ this.cleanups.push(installLongTaskCapture(emit));
1264
+ }
1265
+ if (cfg.longAnimationFrames) {
1266
+ this.cleanups.push(installLoafCapture(emit));
1267
+ }
1268
+ if (cfg.resourceErrors) {
1269
+ this.cleanups.push(installResourceErrorCapture(emit));
1270
+ }
1271
+ if (cfg.webVitals) {
1272
+ this.cleanups.push(installWebVitalsCapture(emit));
1273
+ }
1274
+ if (cfg.memory) {
1275
+ this.cleanups.push(installMemoryCapture(emit, cfg.memoryIntervalMs));
1276
+ }
1277
+ if (cfg.hmr) {
1278
+ this.cleanups.push(installHmrCapture(emit));
1279
+ }
1280
+ this.installed = true;
1281
+ }
1282
+ /**
1283
+ * Uninstall all capture sub-modules.
1284
+ */
1285
+ uninstall() {
1286
+ if (!this.installed) return;
1287
+ for (const cleanup of this.cleanups) {
1288
+ cleanup();
1289
+ }
1290
+ this.cleanups = [];
1291
+ this.installed = false;
1292
+ }
1293
+ // -------------------------------------------------------------------------
1294
+ // Manual event reporting (for events that can't be auto-captured)
1295
+ // -------------------------------------------------------------------------
1296
+ reportReactError(error, errorInfo) {
1297
+ const event = {
1298
+ type: "react-error",
1299
+ timestamp: Date.now(),
1300
+ url: typeof window !== "undefined" ? window.location.href : "",
1301
+ message: error.message,
1302
+ stack: error.stack,
1303
+ componentStack: errorInfo.componentStack
1304
+ };
1305
+ this.buffer.push(event);
1306
+ this.trim();
1307
+ this.onEvent?.(event);
1308
+ }
1309
+ reportWsStateChange(prev, next, reconnectAttempt) {
1310
+ if (next === "disconnected" || next === "error") {
1311
+ const event = {
1312
+ type: "ws-disconnection",
1313
+ timestamp: Date.now(),
1314
+ url: typeof window !== "undefined" ? window.location.href : "",
1315
+ previousState: prev,
1316
+ newState: next,
1317
+ reconnectAttempt
1318
+ };
1319
+ this.buffer.push(event);
1320
+ this.trim();
1321
+ this.onEvent?.(event);
1322
+ }
1323
+ }
1324
+ // -------------------------------------------------------------------------
1325
+ // Query methods
1326
+ // -------------------------------------------------------------------------
1327
+ getSince(ts) {
1328
+ return this.buffer.filter((e) => e.timestamp >= ts);
1329
+ }
1330
+ getRecent(n = 50) {
1331
+ return this.buffer.slice(-n);
1332
+ }
1333
+ getByType(type) {
1334
+ return this.buffer.filter((e) => e.type === type);
1335
+ }
1336
+ /**
1337
+ * Get console errors since a timestamp (backward-compat for ActionExecutor).
1338
+ */
1339
+ getConsoleSince(ts) {
1340
+ return this.buffer.filter((e) => (e.type === "console" || e.type === "hmr") && e.timestamp >= ts).map((e) => ({
1341
+ timestamp: e.timestamp,
1342
+ level: e.type === "hmr" ? e.level === "warning" ? "warn" : e.level : e.level,
1343
+ message: e.message,
1344
+ stack: e.stack
1345
+ }));
1346
+ }
1347
+ /**
1348
+ * Get recent console errors (backward-compat for ActionExecutor).
1349
+ */
1350
+ getConsoleRecent(n = 50) {
1351
+ return this.buffer.filter((e) => e.type === "console" || e.type === "hmr").slice(-n).map((e) => ({
1352
+ timestamp: e.timestamp,
1353
+ level: e.type === "hmr" ? e.level === "warning" ? "warn" : e.level : e.level,
1354
+ message: e.message,
1355
+ stack: e.stack
1356
+ }));
1357
+ }
1358
+ clear() {
1359
+ this.buffer = [];
1360
+ }
1361
+ trim() {
1362
+ if (this.buffer.length > this.maxEntries) {
1363
+ this.buffer = this.buffer.slice(-this.maxEntries);
1364
+ }
1365
+ }
1366
+ };
1367
+
446
1368
  // src/debug/metrics.ts
447
1369
  function generateId() {
448
1370
  return `${Date.now()}-${Math.random().toString(36).substr(2, 8)}`;
@@ -659,6 +1581,6 @@ function formatPercentage(value) {
659
1581
  return `${(value * 100).toFixed(1)}%`;
660
1582
  }
661
1583
 
662
- export { InfoPanel, Inspector, InspectorOverlay, MetricsCollector, createMetricsCollector, formatDuration, formatPercentage, useInspector };
1584
+ export { BrowserEventCapture, DEFAULT_CAPTURE_CONFIG, InfoPanel, Inspector, InspectorOverlay, MetricsCollector, createMetricsCollector, formatDuration, formatPercentage, useInspector };
663
1585
  //# sourceMappingURL=index.mjs.map
664
1586
  //# sourceMappingURL=index.mjs.map