browsertrack 0.2.1 → 0.2.2
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/AGENTS.md +9 -6
- package/README.md +2 -0
- package/dist/{chunk-INXDWPJW.js → chunk-4HRLW6YF.js} +161 -106
- package/dist/chunk-4HRLW6YF.js.map +1 -0
- package/dist/{chunk-3HOXPTM2.js → chunk-AYSVE6NG.js} +808 -53
- package/dist/chunk-AYSVE6NG.js.map +1 -0
- package/dist/{chunk-6VA7GBAO.js → chunk-QRZ57ME3.js} +70 -2
- package/dist/chunk-QRZ57ME3.js.map +1 -0
- package/dist/{chunk-464D4U2U.js → chunk-TWEYRBDU.js} +279 -43
- package/dist/chunk-TWEYRBDU.js.map +1 -0
- package/dist/cli/index.js +1038 -545
- package/dist/cli/index.js.map +1 -1
- package/dist/client/index.cjs +184 -104
- package/dist/client/index.js +2 -2
- package/dist/client.iife.js +9 -9
- package/dist/core/index.d.ts +24 -1
- package/dist/core/index.js +9 -1
- package/dist/daemon/index.d.ts +2 -2
- package/dist/daemon/index.js +6 -8
- package/dist/index.d.ts +2 -2
- package/dist/index.js +14 -7
- package/dist/mcp/index.d.ts +1 -1
- package/dist/mcp/index.js +7 -4
- package/dist/{server-DiVmTrIR.d.ts → server-DjV7RWQM.d.ts} +9 -1
- package/docs/cli.md +4 -1
- package/docs/getting-started.md +60 -6
- package/docs/mcp-reference.md +42 -0
- package/package.json +1 -1
- package/packages/cli/src/index.ts +247 -151
- package/packages/client/src/interceptors/navigation.ts +38 -26
- package/packages/client/src/interceptors/network.ts +22 -17
- package/packages/client/src/notes/inspector.ts +81 -48
- package/packages/client/src/source/resolver.ts +9 -3
- package/packages/client/src/transport/websocket.ts +23 -18
- package/packages/core/src/index.ts +1 -0
- package/packages/core/src/safety.ts +86 -0
- package/packages/daemon/src/server/daemon.ts +7 -1
- package/packages/daemon/src/server/http.ts +125 -5
- package/packages/daemon/src/server/ws.ts +33 -29
- package/packages/daemon/src/storage/db.ts +57 -35
- package/packages/mcp/src/handlers.ts +114 -45
- package/packages/mcp/src/server.ts +202 -2
- package/test/core/safety.test.ts +106 -0
- package/test/daemon/storage.test.ts +36 -0
- package/test/e2e/daemon-mcp-e2e.test.ts +10 -0
- package/test/mcp/auto-start.test.ts +87 -0
- package/dist/chunk-3HOXPTM2.js.map +0 -1
- package/dist/chunk-464D4U2U.js.map +0 -1
- package/dist/chunk-6VA7GBAO.js.map +0 -1
- package/dist/chunk-7OCOQGDN.js +0 -635
- package/dist/chunk-7OCOQGDN.js.map +0 -1
- package/dist/chunk-INXDWPJW.js.map +0 -1
package/dist/client/index.cjs
CHANGED
|
@@ -169,6 +169,32 @@ function truncate(str, maxLength = 200) {
|
|
|
169
169
|
return str.slice(0, maxLength) + "...";
|
|
170
170
|
}
|
|
171
171
|
|
|
172
|
+
// packages/core/src/safety.ts
|
|
173
|
+
function safeJsonStringify(val, fallback = "{}") {
|
|
174
|
+
if (val === void 0) return fallback;
|
|
175
|
+
try {
|
|
176
|
+
const seen = /* @__PURE__ */ new WeakSet();
|
|
177
|
+
return JSON.stringify(val, (key, value) => {
|
|
178
|
+
if (typeof value === "object" && value !== null) {
|
|
179
|
+
if (seen.has(value)) {
|
|
180
|
+
return "[Circular]";
|
|
181
|
+
}
|
|
182
|
+
seen.add(value);
|
|
183
|
+
}
|
|
184
|
+
if (typeof value === "bigint") {
|
|
185
|
+
return value.toString();
|
|
186
|
+
}
|
|
187
|
+
return value;
|
|
188
|
+
});
|
|
189
|
+
} catch {
|
|
190
|
+
try {
|
|
191
|
+
return JSON.stringify(String(val));
|
|
192
|
+
} catch {
|
|
193
|
+
return fallback;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
172
198
|
// packages/client/src/source/resolver.ts
|
|
173
199
|
function resolveComponentSource(el) {
|
|
174
200
|
if (!el || typeof el !== "object") return void 0;
|
|
@@ -218,7 +244,9 @@ function resolveReactComponent(el) {
|
|
|
218
244
|
}
|
|
219
245
|
}
|
|
220
246
|
let curr = hostFiber;
|
|
221
|
-
|
|
247
|
+
let depth = 0;
|
|
248
|
+
while (curr && depth < 50) {
|
|
249
|
+
depth++;
|
|
222
250
|
const type = curr.type;
|
|
223
251
|
const name = getReactComponentName(type);
|
|
224
252
|
if (name && !name.startsWith("html:") && name !== "Fragment") {
|
|
@@ -273,7 +301,9 @@ function resolveVueComponent(el) {
|
|
|
273
301
|
const sourceFile = type.__file;
|
|
274
302
|
const hierarchy = [];
|
|
275
303
|
let curr = vueParent;
|
|
276
|
-
|
|
304
|
+
let depth = 0;
|
|
305
|
+
while (curr && depth < 50) {
|
|
306
|
+
depth++;
|
|
277
307
|
const cType = curr.type || {};
|
|
278
308
|
const cName = cType.name || cType.__name || cType.displayName;
|
|
279
309
|
if (cName && !hierarchy.includes(cName)) {
|
|
@@ -310,7 +340,9 @@ function resolveVueComponent(el) {
|
|
|
310
340
|
function resolveSvelteComponent(el) {
|
|
311
341
|
try {
|
|
312
342
|
let curr = el;
|
|
313
|
-
|
|
343
|
+
let depth = 0;
|
|
344
|
+
while (curr && depth < 50) {
|
|
345
|
+
depth++;
|
|
314
346
|
const meta = curr.__svelte_meta;
|
|
315
347
|
if (meta && meta.loc) {
|
|
316
348
|
return {
|
|
@@ -849,12 +881,16 @@ function setupConsoleInterceptors(onConsole) {
|
|
|
849
881
|
function setupNavigationInterceptors(onNavigation) {
|
|
850
882
|
if (typeof window === "undefined" || typeof history === "undefined") return () => {
|
|
851
883
|
};
|
|
852
|
-
let currentUrl =
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
884
|
+
let currentUrl = "";
|
|
885
|
+
try {
|
|
886
|
+
currentUrl = redactUrl(window.location.href);
|
|
887
|
+
onNavigation({
|
|
888
|
+
to: currentUrl,
|
|
889
|
+
type: "initial",
|
|
890
|
+
timestamp: Date.now()
|
|
891
|
+
});
|
|
892
|
+
} catch {
|
|
893
|
+
}
|
|
858
894
|
const originalPushState = history.pushState;
|
|
859
895
|
const originalReplaceState = history.replaceState;
|
|
860
896
|
history.pushState = function(data, unused, url) {
|
|
@@ -890,26 +926,32 @@ function setupNavigationInterceptors(onNavigation) {
|
|
|
890
926
|
return result;
|
|
891
927
|
};
|
|
892
928
|
const onPopState = () => {
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
929
|
+
try {
|
|
930
|
+
const from = currentUrl;
|
|
931
|
+
const to = redactUrl(window.location.href);
|
|
932
|
+
currentUrl = to;
|
|
933
|
+
onNavigation({
|
|
934
|
+
from,
|
|
935
|
+
to,
|
|
936
|
+
type: "popstate",
|
|
937
|
+
timestamp: Date.now()
|
|
938
|
+
});
|
|
939
|
+
} catch {
|
|
940
|
+
}
|
|
902
941
|
};
|
|
903
942
|
const onHashChange = () => {
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
943
|
+
try {
|
|
944
|
+
const from = currentUrl;
|
|
945
|
+
const to = redactUrl(window.location.href);
|
|
946
|
+
currentUrl = to;
|
|
947
|
+
onNavigation({
|
|
948
|
+
from,
|
|
949
|
+
to,
|
|
950
|
+
type: "hashchange",
|
|
951
|
+
timestamp: Date.now()
|
|
952
|
+
});
|
|
953
|
+
} catch {
|
|
954
|
+
}
|
|
913
955
|
};
|
|
914
956
|
window.addEventListener("popstate", onPopState);
|
|
915
957
|
window.addEventListener("hashchange", onHashChange);
|
|
@@ -946,31 +988,38 @@ function setupNetworkInterceptors(onNetwork) {
|
|
|
946
988
|
urlStr = "unknown_url";
|
|
947
989
|
}
|
|
948
990
|
const safeUrl = redactUrl(urlStr);
|
|
991
|
+
let response;
|
|
949
992
|
try {
|
|
950
|
-
|
|
951
|
-
const durationMs = Date.now() - startTime;
|
|
952
|
-
onNetwork({
|
|
953
|
-
url: safeUrl,
|
|
954
|
-
method,
|
|
955
|
-
status: response.status,
|
|
956
|
-
statusText: response.statusText,
|
|
957
|
-
durationMs,
|
|
958
|
-
timestamp: startTime
|
|
959
|
-
});
|
|
960
|
-
return response;
|
|
993
|
+
response = await originalFetch.apply(window, [input, init2]);
|
|
961
994
|
} catch (err) {
|
|
962
|
-
const
|
|
995
|
+
const durationMs2 = Date.now() - startTime;
|
|
963
996
|
const isAbort = err?.name === "AbortError";
|
|
997
|
+
try {
|
|
998
|
+
onNetwork({
|
|
999
|
+
url: safeUrl,
|
|
1000
|
+
method,
|
|
1001
|
+
durationMs: durationMs2,
|
|
1002
|
+
error: err?.message || "Network request failed",
|
|
1003
|
+
aborted: isAbort,
|
|
1004
|
+
timestamp: startTime
|
|
1005
|
+
});
|
|
1006
|
+
} catch {
|
|
1007
|
+
}
|
|
1008
|
+
throw err;
|
|
1009
|
+
}
|
|
1010
|
+
const durationMs = Date.now() - startTime;
|
|
1011
|
+
try {
|
|
964
1012
|
onNetwork({
|
|
965
1013
|
url: safeUrl,
|
|
966
1014
|
method,
|
|
1015
|
+
status: response.status,
|
|
1016
|
+
statusText: response.statusText,
|
|
967
1017
|
durationMs,
|
|
968
|
-
error: err?.message || "Network request failed",
|
|
969
|
-
aborted: isAbort,
|
|
970
1018
|
timestamp: startTime
|
|
971
1019
|
});
|
|
972
|
-
|
|
1020
|
+
} catch {
|
|
973
1021
|
}
|
|
1022
|
+
return response;
|
|
974
1023
|
};
|
|
975
1024
|
cleanups.push(() => {
|
|
976
1025
|
window.fetch = originalFetch;
|
|
@@ -1358,15 +1407,18 @@ var WebSocketTransport = class {
|
|
|
1358
1407
|
}
|
|
1359
1408
|
}
|
|
1360
1409
|
send(payload) {
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1410
|
+
try {
|
|
1411
|
+
const raw = safeJsonStringify(payload);
|
|
1412
|
+
if (this.isConnected()) {
|
|
1413
|
+
try {
|
|
1414
|
+
this.ws.send(raw);
|
|
1415
|
+
} catch {
|
|
1416
|
+
this.enqueue(raw);
|
|
1417
|
+
}
|
|
1418
|
+
} else {
|
|
1366
1419
|
this.enqueue(raw);
|
|
1367
1420
|
}
|
|
1368
|
-
}
|
|
1369
|
-
this.enqueue(raw);
|
|
1421
|
+
} catch {
|
|
1370
1422
|
}
|
|
1371
1423
|
}
|
|
1372
1424
|
enqueue(raw) {
|
|
@@ -1391,17 +1443,17 @@ var WebSocketTransport = class {
|
|
|
1391
1443
|
}
|
|
1392
1444
|
sendHello() {
|
|
1393
1445
|
if (typeof window === "undefined") return;
|
|
1394
|
-
const hello = {
|
|
1395
|
-
type: "hello",
|
|
1396
|
-
origin: window.location.origin,
|
|
1397
|
-
url: window.location.href,
|
|
1398
|
-
title: document.title,
|
|
1399
|
-
userAgent: navigator.userAgent,
|
|
1400
|
-
timestamp: Date.now(),
|
|
1401
|
-
projectId: this.projectId
|
|
1402
|
-
};
|
|
1403
1446
|
try {
|
|
1404
|
-
|
|
1447
|
+
const hello = {
|
|
1448
|
+
type: "hello",
|
|
1449
|
+
origin: window.location.origin,
|
|
1450
|
+
url: window.location.href,
|
|
1451
|
+
title: document.title,
|
|
1452
|
+
userAgent: navigator.userAgent,
|
|
1453
|
+
timestamp: Date.now(),
|
|
1454
|
+
projectId: this.projectId
|
|
1455
|
+
};
|
|
1456
|
+
this.ws.send(safeJsonStringify(hello));
|
|
1405
1457
|
} catch {
|
|
1406
1458
|
}
|
|
1407
1459
|
}
|
|
@@ -2389,9 +2441,15 @@ var NoteInspector = class {
|
|
|
2389
2441
|
this.markersContainer.innerHTML = "";
|
|
2390
2442
|
if (!this.showMarkers || this.isHidden) return;
|
|
2391
2443
|
const currentPath = window.location.pathname;
|
|
2392
|
-
const activeNotes = this.savedNotes.filter(
|
|
2393
|
-
(n
|
|
2394
|
-
|
|
2444
|
+
const activeNotes = this.savedNotes.filter((n) => {
|
|
2445
|
+
if (n.status !== "OPEN") return false;
|
|
2446
|
+
if (!n.route) return true;
|
|
2447
|
+
if (n.route === currentPath) return true;
|
|
2448
|
+
if (n.route.includes("#") || n.route.includes("?")) {
|
|
2449
|
+
return window.location.href.includes(n.route);
|
|
2450
|
+
}
|
|
2451
|
+
return false;
|
|
2452
|
+
});
|
|
2395
2453
|
const pageNotes = [];
|
|
2396
2454
|
activeNotes.forEach((note, index) => {
|
|
2397
2455
|
if (note.type === "page") {
|
|
@@ -2616,65 +2674,83 @@ var NoteInspector = class {
|
|
|
2616
2674
|
}
|
|
2617
2675
|
setupListeners() {
|
|
2618
2676
|
const onMouseMove = (e) => {
|
|
2619
|
-
|
|
2620
|
-
|
|
2621
|
-
|
|
2622
|
-
this.
|
|
2623
|
-
|
|
2624
|
-
}
|
|
2625
|
-
if (e.altKey || this.activeMode === "element") {
|
|
2626
|
-
const target = document.elementFromPoint(e.clientX, e.clientY);
|
|
2627
|
-
if (target && target !== this.container && !this.container?.contains(target)) {
|
|
2628
|
-
this.hoveredElement = target;
|
|
2629
|
-
this.updateHighlight(target);
|
|
2677
|
+
try {
|
|
2678
|
+
if (this.isHidden || this.modalOverlay || this.cardOverlay || this.isDraggingRegion || this.activeMode === "region") return;
|
|
2679
|
+
const path = e.composedPath ? e.composedPath() : [];
|
|
2680
|
+
if (this.container && path.includes(this.container)) {
|
|
2681
|
+
this.hideHighlight();
|
|
2630
2682
|
return;
|
|
2631
2683
|
}
|
|
2632
|
-
|
|
2633
|
-
|
|
2634
|
-
|
|
2684
|
+
if (e.altKey || this.activeMode === "element") {
|
|
2685
|
+
const target = document.elementFromPoint(e.clientX, e.clientY);
|
|
2686
|
+
if (target && target !== this.container && !this.container?.contains(target)) {
|
|
2687
|
+
this.hoveredElement = target;
|
|
2688
|
+
this.updateHighlight(target);
|
|
2689
|
+
return;
|
|
2690
|
+
}
|
|
2691
|
+
}
|
|
2692
|
+
if (!e.altKey && this.activeMode !== "element") {
|
|
2693
|
+
this.hideHighlight();
|
|
2694
|
+
}
|
|
2695
|
+
} catch {
|
|
2635
2696
|
}
|
|
2636
2697
|
};
|
|
2637
2698
|
const onClick = (e) => {
|
|
2638
|
-
|
|
2639
|
-
|
|
2640
|
-
|
|
2641
|
-
|
|
2642
|
-
|
|
2643
|
-
|
|
2644
|
-
|
|
2645
|
-
e.
|
|
2646
|
-
|
|
2647
|
-
|
|
2648
|
-
|
|
2649
|
-
this.
|
|
2650
|
-
|
|
2651
|
-
|
|
2652
|
-
this.
|
|
2699
|
+
try {
|
|
2700
|
+
if (this.isHidden || this.modalOverlay || this.cardOverlay) return;
|
|
2701
|
+
const path = e.composedPath ? e.composedPath() : [];
|
|
2702
|
+
if (this.container && path.includes(this.container)) {
|
|
2703
|
+
return;
|
|
2704
|
+
}
|
|
2705
|
+
if (this.activeMode === "region") return;
|
|
2706
|
+
if (e.altKey || this.activeMode === "element") {
|
|
2707
|
+
e.preventDefault();
|
|
2708
|
+
e.stopPropagation();
|
|
2709
|
+
const target = this.hoveredElement || document.elementFromPoint(e.clientX, e.clientY);
|
|
2710
|
+
if (target && target !== this.container && !this.container?.contains(target)) {
|
|
2711
|
+
this.selectedElement = target;
|
|
2712
|
+
this.openNoteEditor(target, "element");
|
|
2713
|
+
if (this.activeMode === "element" && !this.activeScenario) {
|
|
2714
|
+
this.setMode("idle");
|
|
2715
|
+
}
|
|
2653
2716
|
}
|
|
2654
2717
|
}
|
|
2718
|
+
} catch {
|
|
2655
2719
|
}
|
|
2656
2720
|
};
|
|
2657
2721
|
const onKeyDown = (e) => {
|
|
2658
|
-
|
|
2659
|
-
if (
|
|
2660
|
-
this.
|
|
2661
|
-
|
|
2662
|
-
|
|
2663
|
-
if (
|
|
2664
|
-
this.
|
|
2722
|
+
try {
|
|
2723
|
+
if (e.key === "Escape") {
|
|
2724
|
+
if (this.cardOverlay && this.cardOverlay.parentElement && this.shadowRoot) {
|
|
2725
|
+
this.shadowRoot.removeChild(this.cardOverlay);
|
|
2726
|
+
this.cardOverlay = null;
|
|
2727
|
+
} else if (this.activeMode === "region" || this.activeMode === "element") {
|
|
2728
|
+
if (!this.activeScenario) {
|
|
2729
|
+
this.setMode("idle");
|
|
2730
|
+
}
|
|
2665
2731
|
}
|
|
2666
2732
|
}
|
|
2733
|
+
} catch {
|
|
2667
2734
|
}
|
|
2668
2735
|
};
|
|
2669
2736
|
const onKeyUp = (e) => {
|
|
2670
|
-
|
|
2671
|
-
this.
|
|
2737
|
+
try {
|
|
2738
|
+
if (e.key === "Alt" && !this.modalOverlay && !this.cardOverlay && this.activeMode !== "element") {
|
|
2739
|
+
this.hideHighlight();
|
|
2740
|
+
}
|
|
2741
|
+
} catch {
|
|
2672
2742
|
}
|
|
2673
2743
|
};
|
|
2674
2744
|
const onScrollOrResize = () => {
|
|
2675
|
-
|
|
2676
|
-
|
|
2677
|
-
|
|
2745
|
+
try {
|
|
2746
|
+
requestAnimationFrame(() => {
|
|
2747
|
+
try {
|
|
2748
|
+
this.updateMarkerPositions();
|
|
2749
|
+
} catch {
|
|
2750
|
+
}
|
|
2751
|
+
});
|
|
2752
|
+
} catch {
|
|
2753
|
+
}
|
|
2678
2754
|
};
|
|
2679
2755
|
window.addEventListener("mousemove", onMouseMove, { capture: true, passive: true });
|
|
2680
2756
|
window.addEventListener("click", onClick, { capture: true });
|
|
@@ -3136,7 +3212,11 @@ var NoteInspector = class {
|
|
|
3136
3212
|
region.width,
|
|
3137
3213
|
region.height
|
|
3138
3214
|
);
|
|
3139
|
-
|
|
3215
|
+
try {
|
|
3216
|
+
resolve(canvas.toDataURL("image/png"));
|
|
3217
|
+
} catch {
|
|
3218
|
+
resolve(dataUrl);
|
|
3219
|
+
}
|
|
3140
3220
|
};
|
|
3141
3221
|
img.onerror = () => resolve(dataUrl);
|
|
3142
3222
|
img.src = dataUrl;
|
package/dist/client/index.js
CHANGED
|
@@ -8,8 +8,8 @@ import {
|
|
|
8
8
|
init,
|
|
9
9
|
resolveComponentSource,
|
|
10
10
|
shouldHideUIFromUrl
|
|
11
|
-
} from "../chunk-
|
|
12
|
-
import "../chunk-
|
|
11
|
+
} from "../chunk-4HRLW6YF.js";
|
|
12
|
+
import "../chunk-QRZ57ME3.js";
|
|
13
13
|
export {
|
|
14
14
|
BreadcrumbBuffer,
|
|
15
15
|
BrowserScriptScreenshotDriver,
|