browsertrack 0.1.2 → 0.2.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/AGENTS.md +6 -2
- package/dist/{chunk-ILRYKMME.js → chunk-3HOXPTM2.js} +97 -3
- package/dist/chunk-3HOXPTM2.js.map +1 -0
- package/dist/{chunk-G2Y3CXCY.js → chunk-464D4U2U.js} +86 -3
- package/dist/chunk-464D4U2U.js.map +1 -0
- package/dist/{chunk-SPCIROIU.js → chunk-7OCOQGDN.js} +24 -5
- package/dist/chunk-7OCOQGDN.js.map +1 -0
- package/dist/{chunk-SKCMT2DE.js → chunk-INXDWPJW.js} +806 -160
- package/dist/chunk-INXDWPJW.js.map +1 -0
- package/dist/cli/index.js +202 -6
- package/dist/cli/index.js.map +1 -1
- package/dist/client/index.cjs +809 -161
- package/dist/client/index.d.ts +62 -11
- package/dist/client/index.js +7 -3
- package/dist/client.iife.js +206 -27
- package/dist/{notes-CBvN91Wf.d.ts → commands-fjuqKzkm.d.ts} +125 -91
- package/dist/core/index.d.ts +2 -2
- package/dist/daemon/index.d.ts +3 -3
- package/dist/daemon/index.js +2 -2
- package/dist/{engine-CeT9URuN.d.ts → engine-CmchnMDq.d.ts} +13 -2
- package/dist/index.d.ts +4 -4
- package/dist/index.js +4 -4
- package/dist/mcp/index.d.ts +4 -4
- package/dist/mcp/index.js +2 -2
- package/dist/{projects-CY8ungMt.d.ts → projects-DB7S312i.d.ts} +1 -1
- package/dist/{server-Dd8NX2Mk.d.ts → server-DiVmTrIR.d.ts} +1 -1
- package/docs/component-resolver.md +108 -0
- package/docs/index.md +3 -1
- package/docs/mcp-reference.md +15 -2
- package/docs/scenarios-flows.md +86 -0
- package/docs/visual-notes.md +36 -0
- package/package.json +1 -1
- package/packages/client/src/client.ts +18 -1
- package/packages/client/src/config.ts +84 -1
- package/packages/client/src/index.ts +4 -1
- package/packages/client/src/interceptors/interaction.ts +3 -0
- package/packages/client/src/notes/inspector.ts +640 -166
- package/packages/client/src/source/resolver.ts +272 -0
- package/packages/core/src/types/events.ts +3 -0
- package/packages/core/src/types/notes.ts +36 -0
- package/packages/daemon/src/notes/engine.ts +6 -0
- package/packages/daemon/src/server/ws.ts +23 -1
- package/packages/daemon/src/storage/db.ts +106 -3
- package/packages/mcp/src/handlers.ts +59 -0
- package/packages/mcp/src/tools.ts +28 -0
- package/test/client/component-resolver.test.ts +141 -0
- package/test/client/interceptors.test.ts +120 -0
- package/test/daemon/scenario-storage.test.ts +158 -0
- package/dist/chunk-G2Y3CXCY.js.map +0 -1
- package/dist/chunk-ILRYKMME.js.map +0 -1
- package/dist/chunk-SKCMT2DE.js.map +0 -1
- package/dist/chunk-SPCIROIU.js.map +0 -1
package/docs/visual-notes.md
CHANGED
|
@@ -64,4 +64,40 @@ The bottom-right floating toolbar gives quick access:
|
|
|
64
64
|
- **`🎯 Element`**: Toggle element inspection mode.
|
|
65
65
|
- **`📐 Region`**: Activate rectangle drag mode.
|
|
66
66
|
- **`📄 Page`**: Open full-page note modal.
|
|
67
|
+
- **`🎬 Flow`**: Start/finish sequential scenario recording.
|
|
67
68
|
- **`📌 Notes (N)`**: Toggle visibility of all note markers on screen.
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
## 🙈 Hiding the Tool via Query String (Headless / Clean Mode)
|
|
73
|
+
|
|
74
|
+
When running automated visual regression tests, Cypress, Playwright, or giving clean demo presentations, you can hide the visible BrowserTrack UI (dock, pins, overlays) completely using URL query parameters:
|
|
75
|
+
|
|
76
|
+
### 1. Built-in Query Parameters
|
|
77
|
+
Simply append any of the following to your page URL:
|
|
78
|
+
- `?bt=0` or `?bt=false` or `?bt=hidden` or `?bt=off`
|
|
79
|
+
- `?browsertrack=false` or `?browsertrack=0` or `?browsertrack=hidden`
|
|
80
|
+
- `?no_bt` / `?no_bt=1` or `?no_browsertrack=1`
|
|
81
|
+
- `?hide_bt=1` or `?hide_browsertrack=1`
|
|
82
|
+
|
|
83
|
+
```text
|
|
84
|
+
http://localhost:3000/dashboard?bt=false
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### 2. Custom Query Parameter Configuration
|
|
88
|
+
You can also define your own custom query parameters in client options:
|
|
89
|
+
```typescript
|
|
90
|
+
import { init } from 'browsertrack/client';
|
|
91
|
+
|
|
92
|
+
init({
|
|
93
|
+
hideQueryParam: ['cypress', 'clean_view', 'no_ui'],
|
|
94
|
+
// or hide by default in specific environments:
|
|
95
|
+
hidden: process.env.NODE_ENV === 'test',
|
|
96
|
+
});
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
When hidden:
|
|
100
|
+
- The floating toolbar and on-screen note pins are not displayed.
|
|
101
|
+
- Alt+Click hover highlights and selection shortcuts are inactive.
|
|
102
|
+
- Background diagnostics (runtime errors, console capture, network logging, MCP command execution) continue working seamlessly in headless mode.
|
|
103
|
+
- Programmatic visibility can be restored anytime via `client.setUIVisible(true)`.
|
package/package.json
CHANGED
|
@@ -22,7 +22,10 @@ import { WebSocketTransport } from './transport/websocket.js';
|
|
|
22
22
|
import { NoteInspector } from './notes/inspector.js';
|
|
23
23
|
|
|
24
24
|
export class BrowserTrackClient {
|
|
25
|
-
public options: Required<Omit<BrowserDiagClientOptions, 'notes'
|
|
25
|
+
public options: Required<Omit<BrowserDiagClientOptions, 'notes' | 'hideQueryParam'>> & {
|
|
26
|
+
hideQueryParam?: string | string[];
|
|
27
|
+
notes: Required<NonNullable<BrowserDiagClientOptions['notes']>>;
|
|
28
|
+
};
|
|
26
29
|
private breadcrumbs: BreadcrumbBuffer;
|
|
27
30
|
private transport: WebSocketTransport;
|
|
28
31
|
private screenshotDriver: ScreenshotDriver;
|
|
@@ -56,6 +59,10 @@ export class BrowserTrackClient {
|
|
|
56
59
|
this.inspector = new NoteInspector(this.transport, this.screenshotDriver, {
|
|
57
60
|
shortcut: this.options.notes.shortcut,
|
|
58
61
|
maskSelectors: this.options.notes.maskSelectors,
|
|
62
|
+
showToolbar: this.options.notes.showToolbar,
|
|
63
|
+
showBadges: this.options.notes.showBadges,
|
|
64
|
+
hidden: this.options.hidden,
|
|
65
|
+
hideQueryParam: this.options.hideQueryParam,
|
|
59
66
|
});
|
|
60
67
|
}
|
|
61
68
|
}
|
|
@@ -142,6 +149,16 @@ export class BrowserTrackClient {
|
|
|
142
149
|
}
|
|
143
150
|
}
|
|
144
151
|
|
|
152
|
+
public isUIVisible(): boolean {
|
|
153
|
+
return this.inspector ? this.inspector.isVisible() : false;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
public setUIVisible(visible: boolean): void {
|
|
157
|
+
if (this.inspector) {
|
|
158
|
+
this.inspector.setVisible(visible);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
145
162
|
public setInspectMode(mode: 'element' | 'region' | 'page' | 'idle'): void {
|
|
146
163
|
if (this.inspector) {
|
|
147
164
|
this.inspector.setMode(mode);
|
|
@@ -12,12 +12,25 @@ export interface BrowserDiagClientOptions {
|
|
|
12
12
|
enabled?: boolean;
|
|
13
13
|
shortcut?: string;
|
|
14
14
|
showBadges?: boolean;
|
|
15
|
+
showToolbar?: boolean;
|
|
15
16
|
maskSelectors?: string[];
|
|
16
17
|
};
|
|
18
|
+
/**
|
|
19
|
+
* Hide visible BrowserTrack UI (toolbar dock, pins, hover overlay) by default.
|
|
20
|
+
*/
|
|
21
|
+
hidden?: boolean;
|
|
22
|
+
/**
|
|
23
|
+
* Custom query parameter(s) used to hide the UI (e.g. 'e2e', 'no_ui', 'clean').
|
|
24
|
+
* Built-in query params like ?bt=0, ?bt=false, ?bt=hidden, ?browsertrack=false, ?no_bt are supported automatically.
|
|
25
|
+
*/
|
|
26
|
+
hideQueryParam?: string | string[];
|
|
17
27
|
debug?: boolean;
|
|
18
28
|
}
|
|
19
29
|
|
|
20
|
-
export const DEFAULT_OPTIONS: Required<Omit<BrowserDiagClientOptions, 'notes'
|
|
30
|
+
export const DEFAULT_OPTIONS: Required<Omit<BrowserDiagClientOptions, 'notes' | 'hideQueryParam'>> & {
|
|
31
|
+
hideQueryParam?: string | string[];
|
|
32
|
+
notes: Required<NonNullable<BrowserDiagClientOptions['notes']>>;
|
|
33
|
+
} = {
|
|
21
34
|
daemonUrl: 'ws://127.0.0.1:7331',
|
|
22
35
|
projectId: '',
|
|
23
36
|
maxBreadcrumbs: 50,
|
|
@@ -31,7 +44,77 @@ export const DEFAULT_OPTIONS: Required<Omit<BrowserDiagClientOptions, 'notes'>>
|
|
|
31
44
|
enabled: true,
|
|
32
45
|
shortcut: 'Alt+Click',
|
|
33
46
|
showBadges: true,
|
|
47
|
+
showToolbar: true,
|
|
34
48
|
maskSelectors: ['input[type="password"]', '[data-sensitive]'],
|
|
35
49
|
},
|
|
50
|
+
hidden: false,
|
|
51
|
+
hideQueryParam: undefined,
|
|
36
52
|
debug: false,
|
|
37
53
|
};
|
|
54
|
+
|
|
55
|
+
const HIDE_VALUES = new Set(['0', 'false', 'hidden', 'hide', 'off', 'none', 'disabled', 'ui_off', 'silent']);
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Checks if the tool's visible UI should be hidden based on URL search query parameters.
|
|
59
|
+
*/
|
|
60
|
+
export function shouldHideUIFromUrl(customParam?: string | string[], searchString?: string): boolean {
|
|
61
|
+
let search = searchString;
|
|
62
|
+
if (search === undefined) {
|
|
63
|
+
if (typeof window === 'undefined' || !window.location) return false;
|
|
64
|
+
search = window.location.search;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (!search) return false;
|
|
68
|
+
|
|
69
|
+
try {
|
|
70
|
+
const params = new URLSearchParams(search);
|
|
71
|
+
|
|
72
|
+
// 1. Check custom parameters if configured
|
|
73
|
+
if (customParam) {
|
|
74
|
+
const customKeys = Array.isArray(customParam) ? customParam : [customParam];
|
|
75
|
+
for (const key of customKeys) {
|
|
76
|
+
if (params.has(key)) {
|
|
77
|
+
const val = (params.get(key) || '').toLowerCase().trim();
|
|
78
|
+
if (val === '' || val === '1' || val === 'true' || HIDE_VALUES.has(val)) {
|
|
79
|
+
return true;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// 2. Boolean flags without values or with 1/true: ?no_bt, ?no_browsertrack, ?hide_bt, ?hide_browsertrack
|
|
86
|
+
for (const flag of ['no_bt', 'no_browsertrack', 'hide_bt', 'hide_browsertrack']) {
|
|
87
|
+
if (params.has(flag)) {
|
|
88
|
+
const val = (params.get(flag) || '').toLowerCase().trim();
|
|
89
|
+
if (val === '' || val === '1' || val === 'true' || val === 'yes') {
|
|
90
|
+
return true;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// 3. Value-based parameters: ?bt=false, ?bt=0, ?bt=hidden, ?bt=off
|
|
96
|
+
if (params.has('bt')) {
|
|
97
|
+
const val = (params.get('bt') || '').toLowerCase().trim();
|
|
98
|
+
if (HIDE_VALUES.has(val)) return true;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (params.has('browsertrack')) {
|
|
102
|
+
const val = (params.get('browsertrack') || '').toLowerCase().trim();
|
|
103
|
+
if (HIDE_VALUES.has(val)) return true;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (params.has('bt_ui')) {
|
|
107
|
+
const val = (params.get('bt_ui') || '').toLowerCase().trim();
|
|
108
|
+
if (HIDE_VALUES.has(val) || val === '0' || val === 'false') return true;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if (params.has('bt_hide')) {
|
|
112
|
+
const val = (params.get('bt_hide') || '').toLowerCase().trim();
|
|
113
|
+
if (val === '' || val === '1' || val === 'true') return true;
|
|
114
|
+
}
|
|
115
|
+
} catch {
|
|
116
|
+
// Defensive in non-standard environments
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return false;
|
|
120
|
+
}
|
|
@@ -7,6 +7,7 @@ export * from './breadcrumbs.js';
|
|
|
7
7
|
export * from './screenshot/driver.js';
|
|
8
8
|
export * from './screenshot/browser-script-driver.js';
|
|
9
9
|
export * from './notes/inspector.js';
|
|
10
|
+
export * from './source/resolver.js';
|
|
10
11
|
|
|
11
12
|
let defaultClient: BrowserTrackClient | null = null;
|
|
12
13
|
|
|
@@ -40,9 +41,11 @@ if (typeof window !== 'undefined') {
|
|
|
40
41
|
const autoInit = currentScript?.getAttribute('data-auto-init') !== 'false';
|
|
41
42
|
const daemonUrl = currentScript?.getAttribute('data-daemon-url') || undefined;
|
|
42
43
|
const projectId = currentScript?.getAttribute('data-project-id') || undefined;
|
|
44
|
+
const hidden = currentScript?.getAttribute('data-hidden') === 'true';
|
|
45
|
+
const hideQueryParam = currentScript?.getAttribute('data-hide-query-param') || undefined;
|
|
43
46
|
|
|
44
47
|
if (autoInit) {
|
|
45
|
-
init({ daemonUrl, projectId });
|
|
48
|
+
init({ daemonUrl, projectId, hidden, hideQueryParam });
|
|
46
49
|
}
|
|
47
50
|
} catch {
|
|
48
51
|
// If auto-start fails, don't crash
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { Breadcrumb, ElementSummary } from '../../../core/src/index.js';
|
|
2
2
|
import { getSemanticSelector, truncate } from '../../../core/src/index.js';
|
|
3
|
+
import { resolveComponentSource } from '../source/resolver.js';
|
|
3
4
|
|
|
4
5
|
export type InteractionCallback = (breadcrumb: Breadcrumb, elementSummary?: ElementSummary) => void;
|
|
5
6
|
|
|
@@ -12,6 +13,7 @@ export function extractElementSummary(el: HTMLElement | Element): ElementSummary
|
|
|
12
13
|
const tag = el.tagName.toLowerCase();
|
|
13
14
|
const id = el.id || undefined;
|
|
14
15
|
const classes = Array.from(el.classList || []);
|
|
16
|
+
const componentSource = resolveComponentSource(el as HTMLElement);
|
|
15
17
|
|
|
16
18
|
let boundingRect: ElementSummary['boundingRect'] = undefined;
|
|
17
19
|
let visible = true;
|
|
@@ -53,6 +55,7 @@ export function extractElementSummary(el: HTMLElement | Element): ElementSummary
|
|
|
53
55
|
visible,
|
|
54
56
|
innerText,
|
|
55
57
|
outerHTML,
|
|
58
|
+
componentSource,
|
|
56
59
|
};
|
|
57
60
|
}
|
|
58
61
|
|