@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.
- package/dist/ai/index.d.mts +312 -155
- package/dist/ai/index.d.ts +312 -155
- package/dist/ai/index.js +2363 -67
- package/dist/ai/index.js.map +1 -1
- package/dist/ai/index.mjs +2328 -68
- package/dist/ai/index.mjs.map +1 -1
- package/dist/annotations/index.d.mts +218 -0
- package/dist/annotations/index.d.ts +218 -0
- package/dist/annotations/index.js +246 -0
- package/dist/annotations/index.js.map +1 -0
- package/dist/annotations/index.mjs +241 -0
- package/dist/annotations/index.mjs.map +1 -0
- package/dist/assertions-BSR3afVr.d.ts +161 -0
- package/dist/assertions-CTw1hfOx.d.mts +161 -0
- package/dist/babel-plugin/index.js +23 -34
- package/dist/babel-plugin/index.js.map +1 -1
- package/dist/babel-plugin/index.mjs +23 -34
- package/dist/babel-plugin/index.mjs.map +1 -1
- package/dist/browser-capture-Bms60T6f.d.mts +47 -0
- package/dist/browser-capture-CsTU29mb.d.ts +47 -0
- package/dist/control/index.d.mts +26 -7
- package/dist/control/index.d.ts +26 -7
- package/dist/control/index.js +276 -48
- package/dist/control/index.js.map +1 -1
- package/dist/control/index.mjs +276 -48
- package/dist/control/index.mjs.map +1 -1
- package/dist/core/index.d.mts +2 -2
- package/dist/core/index.d.ts +2 -2
- package/dist/core/index.js.map +1 -1
- package/dist/core/index.mjs.map +1 -1
- package/dist/debug/index.d.mts +5 -3
- package/dist/debug/index.d.ts +5 -3
- package/dist/debug/index.js +925 -1
- package/dist/debug/index.js.map +1 -1
- package/dist/debug/index.mjs +924 -2
- package/dist/debug/index.mjs.map +1 -1
- package/dist/index.d.mts +12 -7
- package/dist/index.d.ts +12 -7
- package/dist/index.js +4720 -173
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +4656 -174
- package/dist/index.mjs.map +1 -1
- package/dist/{metrics-DTA2bwG7.d.mts → metrics-DuA2qIIz.d.mts} +2 -2
- package/dist/{metrics-BfiT_rhZ.d.ts → metrics-KFAAKNEB.d.ts} +2 -2
- package/dist/native/control/index.js +2 -7
- package/dist/native/control/index.js.map +1 -1
- package/dist/native/control/index.mjs +2 -7
- package/dist/native/control/index.mjs.map +1 -1
- package/dist/native/core/index.js.map +1 -1
- package/dist/native/core/index.mjs.map +1 -1
- package/dist/native/debug/index.js +23 -66
- package/dist/native/debug/index.js.map +1 -1
- package/dist/native/debug/index.mjs +23 -66
- package/dist/native/debug/index.mjs.map +1 -1
- package/dist/native/index.js +89 -131
- package/dist/native/index.js.map +1 -1
- package/dist/native/index.mjs +89 -131
- package/dist/native/index.mjs.map +1 -1
- package/dist/native/react/index.js +28 -52
- package/dist/native/react/index.js.map +1 -1
- package/dist/native/react/index.mjs +28 -52
- package/dist/native/react/index.mjs.map +1 -1
- package/dist/native/server/index.js +38 -13
- package/dist/native/server/index.js.map +1 -1
- package/dist/native/server/index.mjs +38 -13
- package/dist/native/server/index.mjs.map +1 -1
- package/dist/react/index.d.mts +107 -8
- package/dist/react/index.d.ts +107 -8
- package/dist/react/index.js +2194 -84
- package/dist/react/index.js.map +1 -1
- package/dist/react/index.mjs +2194 -85
- package/dist/react/index.mjs.map +1 -1
- package/dist/{registry-BKLEm-yk.d.ts → registry-C6dDtn1v.d.ts} +27 -2
- package/dist/{registry-BmZgyCz8.d.mts → registry-POtcxnal.d.mts} +27 -2
- package/dist/render-log/index.d.mts +1 -1
- package/dist/render-log/index.d.ts +1 -1
- package/dist/server/express.d.mts +5 -4
- package/dist/server/express.d.ts +5 -4
- package/dist/server/express.js +104 -2
- package/dist/server/express.js.map +1 -1
- package/dist/server/express.mjs +104 -2
- package/dist/server/express.mjs.map +1 -1
- package/dist/server/handlers.d.mts +36 -5
- package/dist/server/handlers.d.ts +36 -5
- package/dist/server/handlers.js +3129 -224
- package/dist/server/handlers.js.map +1 -1
- package/dist/server/handlers.mjs +3129 -224
- package/dist/server/handlers.mjs.map +1 -1
- package/dist/server/index.d.mts +7 -5
- package/dist/server/index.d.ts +7 -5
- package/dist/server/index.js +3215 -183
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +3215 -183
- package/dist/server/index.mjs.map +1 -1
- package/dist/server/nextjs.d.mts +6 -4
- package/dist/server/nextjs.d.ts +6 -4
- package/dist/server/nextjs.js +106 -3
- package/dist/server/nextjs.js.map +1 -1
- package/dist/server/nextjs.mjs +106 -3
- package/dist/server/nextjs.mjs.map +1 -1
- package/dist/server/standalone.d.mts +6 -5
- package/dist/server/standalone.d.ts +6 -5
- package/dist/server/standalone.js +131 -5
- package/dist/server/standalone.js.map +1 -1
- package/dist/server/standalone.mjs +131 -5
- package/dist/server/standalone.mjs.map +1 -1
- package/dist/specs/index.d.mts +365 -0
- package/dist/specs/index.d.ts +365 -0
- package/dist/specs/index.js +2809 -0
- package/dist/specs/index.js.map +1 -0
- package/dist/specs/index.mjs +2786 -0
- package/dist/specs/index.mjs.map +1 -0
- package/dist/{standalone-BURj8J3G.d.ts → standalone-B6GLIEmR.d.ts} +6 -2
- package/dist/{standalone-Dwmel29d.d.mts → standalone-CjdYqj3P.d.mts} +6 -2
- package/dist/{types-CHnlwiTK.d.ts → types-B2EfvEaq.d.ts} +83 -3
- package/dist/{types-B7J7noLK.d.mts → types-C7gVYRnF.d.ts} +72 -2
- package/dist/{types-BkNRILUa.d.ts → types-CJGrBEhC.d.mts} +72 -2
- package/dist/types-CebMQj76.d.ts +1275 -0
- package/dist/types-D_ypYl3T.d.mts +1275 -0
- package/dist/types-UBtp7R0u.d.mts +132 -0
- package/dist/types-UBtp7R0u.d.ts +132 -0
- package/dist/{types-CEQLnFMv.d.mts → types-gO696T_t.d.mts} +83 -3
- package/dist/{types-jKVgTI6_.d.mts → types-suaYwWWg.d.mts} +173 -2
- package/dist/{types-jKVgTI6_.d.ts → types-suaYwWWg.d.ts} +173 -2
- package/package.json +18 -2
- package/dist/types-B5Q0GVo0.d.mts +0 -646
- package/dist/types-DfPqwU-i.d.ts +0 -646
package/dist/debug/index.mjs
CHANGED
|
@@ -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:
|
|
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
|