@abbox/inspector 0.4.15 → 0.4.17

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.
@@ -1 +1 @@
1
- {"version":3,"file":"client-bridge.d.ts","sourceRoot":"","sources":["../../src/host/client-bridge.ts"],"names":[],"mappings":"AAWA,MAAM,MAAM,sBAAsB,GAAG;IACnC,SAAS,EAAE,MAAM,CAAC;IAClB,6EAA6E;IAC7E,kBAAkB,EAAE,SAAS,MAAM,EAAE,CAAC;IACtC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,QAAQ,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,IAAI,EAAE,MAAM,IAAI,CAAC;CAClB,CAAC;AAEF,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,sBAAsB,GAC9B,eAAe,CA4EjB"}
1
+ {"version":3,"file":"client-bridge.d.ts","sourceRoot":"","sources":["../../src/host/client-bridge.ts"],"names":[],"mappings":"AAYA,MAAM,MAAM,sBAAsB,GAAG;IACnC,SAAS,EAAE,MAAM,CAAC;IAClB,6EAA6E;IAC7E,kBAAkB,EAAE,SAAS,MAAM,EAAE,CAAC;IACtC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,QAAQ,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,IAAI,EAAE,MAAM,IAAI,CAAC;CAClB,CAAC;AAEF,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,sBAAsB,GAC9B,eAAe,CAmFjB"}
@@ -1,5 +1,6 @@
1
1
  import { ABBBOX_INSPECTOR_CHANNEL, PROTOCOL_VERSION, } from "../protocol.js";
2
2
  import { createInspectorRuntime } from "../runtime/inspector.js";
3
+ import { createRecorder } from "../runtime/recorder.js";
3
4
  import { withLocalhostAliases } from "./origin-aliases.js";
4
5
  import { validateIncomingMessage } from "./validate.js";
5
6
  export function createInspectorClient(options) {
@@ -45,6 +46,8 @@ export function createInspectorClient(options) {
45
46
  send({ ...base(), type: "ROUTE_CHANGED", path });
46
47
  },
47
48
  });
49
+ // The last minute of activity, for bug reports from the Viewer.
50
+ const recorder = createRecorder(win, doc);
48
51
  const onMessage = (event) => {
49
52
  const msg = validateIncomingMessage(event.data, event.origin, {
50
53
  sessionId: options.sessionId,
@@ -61,6 +64,9 @@ export function createInspectorClient(options) {
61
64
  if (msg.type === "APPLY_CHANGE_MARKERS") {
62
65
  runtime.setChangeMarkers(msg.markers);
63
66
  }
67
+ if (msg.type === "REQUEST_RECORDING") {
68
+ send({ ...base(), type: "RECORDING", steps: recorder.snapshot() });
69
+ }
64
70
  };
65
71
  return {
66
72
  start: () => {
@@ -75,6 +81,7 @@ export function createInspectorClient(options) {
75
81
  },
76
82
  stop: () => {
77
83
  win.removeEventListener("message", onMessage);
84
+ recorder.stop();
78
85
  runtime.destroy();
79
86
  },
80
87
  };
@@ -1,4 +1,4 @@
1
- import { type ChangeMarker, type ClientToHostMessage } from "../protocol.js";
1
+ import { type ChangeMarker, type ClientToHostMessage, type RecordedStep } from "../protocol.js";
2
2
  export type InspectorHostOptions = {
3
3
  sessionId: string;
4
4
  /** Origin of the embedded preview (iframe src origin). */
@@ -20,6 +20,7 @@ export type InspectorHostHandlers = {
20
20
  onCleared?: () => void;
21
21
  onChangeMarkerSelected?: (changeId: string) => void;
22
22
  onRouteChange?: (path: string) => void;
23
+ onRecording?: (steps: RecordedStep[]) => void;
23
24
  onError?: (code: string, message: string) => void;
24
25
  };
25
26
  export type InspectorHost = {
@@ -30,6 +31,8 @@ export type InspectorHost = {
30
31
  applyChangeMarkers: (markers: ChangeMarker[]) => void;
31
32
  /** Ask the preview to resend INSPECTOR_READY (call after iframe load). */
32
33
  pingPreview: () => void;
34
+ /** Ask the preview for its last minute of activity (answered via onRecording). */
35
+ requestRecording: () => void;
33
36
  };
34
37
  export declare function createInspectorHost(options: InspectorHostOptions, handlers: InspectorHostHandlers): InspectorHost;
35
38
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"host-bridge.d.ts","sourceRoot":"","sources":["../../src/host/host-bridge.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,YAAY,EACjB,KAAK,mBAAmB,EAGzB,MAAM,gBAAgB,CAAC;AAIxB,MAAM,MAAM,oBAAoB,GAAG;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,0DAA0D;IAC1D,aAAa,EAAE,MAAM,CAAC;IACtB,mDAAmD;IACnD,UAAU,EAAE,MAAM,CAAC;IACnB,gBAAgB,EAAE,MAAM,MAAM,GAAG,IAAI,CAAC;CACvC,CAAC;AAEF,KAAK,YAAY,GAAG,OAAO,CACzB,mBAAmB,EACnB;IAAE,IAAI,EAAE,iBAAiB,CAAA;CAAE,CAC5B,CAAC,SAAS,CAAC,CAAC;AACb,KAAK,aAAa,GAAG,OAAO,CAC1B,mBAAmB,EACnB;IAAE,IAAI,EAAE,kBAAkB,CAAA;CAAE,CAC7B,CAAC,SAAS,CAAC,CAAC;AAEb,MAAM,MAAM,qBAAqB,GAAG;IAClC,OAAO,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,YAAY,KAAK,IAAI,CAAC;IAC1C,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,IAAI,CAAC;IAC5C,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IACvB,sBAAsB,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IACpD,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CACnD,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,UAAU,EAAE,MAAM,IAAI,CAAC;IACvB,aAAa,EAAE,MAAM,IAAI,CAAC;IAC1B,cAAc,EAAE,MAAM,IAAI,CAAC;IAC3B,kBAAkB,EAAE,CAAC,OAAO,EAAE,YAAY,EAAE,KAAK,IAAI,CAAC;IACtD,0EAA0E;IAC1E,WAAW,EAAE,MAAM,IAAI,CAAC;CACzB,CAAC;AAEF,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,oBAAoB,EAC7B,QAAQ,EAAE,qBAAqB,GAC9B,aAAa,CAkEf"}
1
+ {"version":3,"file":"host-bridge.d.ts","sourceRoot":"","sources":["../../src/host/host-bridge.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,YAAY,EACjB,KAAK,mBAAmB,EAGxB,KAAK,YAAY,EAClB,MAAM,gBAAgB,CAAC;AAIxB,MAAM,MAAM,oBAAoB,GAAG;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,0DAA0D;IAC1D,aAAa,EAAE,MAAM,CAAC;IACtB,mDAAmD;IACnD,UAAU,EAAE,MAAM,CAAC;IACnB,gBAAgB,EAAE,MAAM,MAAM,GAAG,IAAI,CAAC;CACvC,CAAC;AAEF,KAAK,YAAY,GAAG,OAAO,CACzB,mBAAmB,EACnB;IAAE,IAAI,EAAE,iBAAiB,CAAA;CAAE,CAC5B,CAAC,SAAS,CAAC,CAAC;AACb,KAAK,aAAa,GAAG,OAAO,CAC1B,mBAAmB,EACnB;IAAE,IAAI,EAAE,kBAAkB,CAAA;CAAE,CAC7B,CAAC,SAAS,CAAC,CAAC;AAEb,MAAM,MAAM,qBAAqB,GAAG;IAClC,OAAO,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,YAAY,KAAK,IAAI,CAAC;IAC1C,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,IAAI,CAAC;IAC5C,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IACvB,sBAAsB,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IACpD,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,YAAY,EAAE,KAAK,IAAI,CAAC;IAC9C,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CACnD,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,UAAU,EAAE,MAAM,IAAI,CAAC;IACvB,aAAa,EAAE,MAAM,IAAI,CAAC;IAC1B,cAAc,EAAE,MAAM,IAAI,CAAC;IAC3B,kBAAkB,EAAE,CAAC,OAAO,EAAE,YAAY,EAAE,KAAK,IAAI,CAAC;IACtD,0EAA0E;IAC1E,WAAW,EAAE,MAAM,IAAI,CAAC;IACxB,kFAAkF;IAClF,gBAAgB,EAAE,MAAM,IAAI,CAAC;CAC9B,CAAC;AAEF,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,oBAAoB,EAC7B,QAAQ,EAAE,qBAAqB,GAC9B,aAAa,CAwEf"}
@@ -38,6 +38,9 @@ export function createInspectorHost(options, handlers) {
38
38
  if (msg.type === "ROUTE_CHANGED") {
39
39
  handlers.onRouteChange?.(msg.path);
40
40
  }
41
+ if (msg.type === "RECORDING") {
42
+ handlers.onRecording?.(msg.steps);
43
+ }
41
44
  if (msg.type === "INSPECTOR_ERROR") {
42
45
  handlers.onError?.(msg.code, msg.message);
43
46
  }
@@ -58,6 +61,9 @@ export function createInspectorHost(options, handlers) {
58
61
  applyChangeMarkers: (markers) => {
59
62
  send({ ...base(), type: "APPLY_CHANGE_MARKERS", markers });
60
63
  },
64
+ requestRecording: () => {
65
+ send({ ...base(), type: "REQUEST_RECORDING" });
66
+ },
61
67
  pingPreview: () => {
62
68
  send({
63
69
  ...base(),
@@ -92,7 +92,7 @@ export type InspectorErrorMessage = InspectorMessageBase & {
92
92
  code: string;
93
93
  message: string;
94
94
  };
95
- export type ChangeMarkerKind = "mock" | "pr-preview" | "change-added" | "change-modified" | "seo-error" | "seo-warning" | "seo-info";
95
+ export type ChangeMarkerKind = "mock" | "pr-preview" | "change-added" | "change-modified" | "seo-error" | "seo-warning" | "seo-info" | "track-on" | "track-key" | "track-off" | "track-page";
96
96
  /** Optional overlay markers supplied by the host (diff engine lives outside inspector). */
97
97
  export type ChangeMarker = {
98
98
  elementRefId: string;
@@ -100,6 +100,12 @@ export type ChangeMarker = {
100
100
  kind: ChangeMarkerKind;
101
101
  /** Short text drawn as a pill instead of a dot (e.g. "H1 ×2"). */
102
102
  badge?: string;
103
+ /**
104
+ * CSS selector tried when source and text don't find the element, e.g. a nav
105
+ * link (`nav a[href="/pricing"]`) or a control by name (`[aria-label="Sort"]`).
106
+ * Alternatives separated by ` || ` are tried in order until one matches.
107
+ */
108
+ hintSelector?: string;
103
109
  pulse?: boolean;
104
110
  sourceKeyPrefix?: string;
105
111
  textHint?: string;
@@ -120,8 +126,33 @@ export type ApplyChangeMarkersMessage = InspectorMessageBase & {
120
126
  type: "APPLY_CHANGE_MARKERS";
121
127
  markers: ChangeMarker[];
122
128
  };
123
- export type HostToClientMessage = InspectorEnableMessage | InspectorDisableMessage | InspectorHostHelloMessage | ApplyChangeMarkersMessage;
124
- export type ClientToHostMessage = InspectorReadyMessage | ElementHoveredMessage | ElementSelectedMessage | ElementClearedMessage | ChangeMarkerSelectedMessage | RouteChangedMessage | InspectorErrorMessage;
129
+ /** One step from the preview's last minute, for bug reports. Never holds field values. */
130
+ export type RecordedStep = {
131
+ /** Epoch milliseconds. */
132
+ t: number;
133
+ kind: "click" | "submit" | "input" | "route" | "scroll" | "error" | "console-error" | "request";
134
+ route: string;
135
+ label?: string;
136
+ /** `data-abbox-src` of the element, linking the step to code. */
137
+ source?: string;
138
+ tag?: string;
139
+ detail?: string;
140
+ /** Script location of an error, when the browser reports one. */
141
+ location?: string;
142
+ method?: string;
143
+ url?: string;
144
+ status?: number;
145
+ durationMs?: number;
146
+ };
147
+ export type RequestRecordingMessage = InspectorMessageBase & {
148
+ type: "REQUEST_RECORDING";
149
+ };
150
+ export type RecordingMessage = InspectorMessageBase & {
151
+ type: "RECORDING";
152
+ steps: RecordedStep[];
153
+ };
154
+ export type HostToClientMessage = InspectorEnableMessage | InspectorDisableMessage | InspectorHostHelloMessage | ApplyChangeMarkersMessage | RequestRecordingMessage;
155
+ export type ClientToHostMessage = InspectorReadyMessage | ElementHoveredMessage | ElementSelectedMessage | ElementClearedMessage | ChangeMarkerSelectedMessage | RouteChangedMessage | RecordingMessage | InspectorErrorMessage;
125
156
  export type InspectorMessage = HostToClientMessage | ClientToHostMessage;
126
157
  export declare function isInspectorMessage(value: unknown): value is InspectorMessage;
127
158
  //# sourceMappingURL=protocol.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"AAAA,mFAAmF;AACnF,eAAO,MAAM,gBAAgB,EAAG,CAAU,CAAC;AAE3C,eAAO,MAAM,wBAAwB,EAAG,iBAA0B,CAAC;AAEnE,MAAM,MAAM,oBAAoB,GAAG;IACjC,OAAO,EAAE,OAAO,wBAAwB,CAAC;IACzC,OAAO,EAAE,OAAO,gBAAgB,CAAC;IACjC,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG,oBAAoB,GAAG;IACzD,IAAI,EAAE,iBAAiB,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,sBAAsB,GAAG,oBAAoB,GAAG;IAC1D,IAAI,EAAE,kBAAkB,CAAC;CAC1B,CAAC;AAEF,MAAM,MAAM,uBAAuB,GAAG,oBAAoB,GAAG;IAC3D,IAAI,EAAE,mBAAmB,CAAC;CAC3B,CAAC;AAEF,uFAAuF;AACvF,MAAM,MAAM,yBAAyB,GAAG,oBAAoB,GAAG;IAC7D,IAAI,EAAE,sBAAsB,CAAC;IAC7B,qFAAqF;IACrF,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG;IACxB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAC3B,4DAA4D;IAC5D,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,+CAA+C;IAC/C,GAAG,CAAC,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG,UAAU,GAAG,YAAY,GAAG,SAAS,CAAC;AAExE,MAAM,MAAM,eAAe,GAAG;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;IAClB,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,+EAA+E;IAC/E,QAAQ,EAAE,OAAO,GAAG,IAAI,CAAC;IACzB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACnC;;;OAGG;IACH,YAAY,CAAC,EAAE,gBAAgB,EAAE,CAAC;CACnC,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,QAAQ,EAAE,OAAO,CAAC;IAClB,QAAQ,EAAE,OAAO,CAAC;IAClB,KAAK,EAAE,OAAO,GAAG,QAAQ,GAAG,SAAS,GAAG,WAAW,CAAC;IACpD,UAAU,EAAE,OAAO,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,qEAAqE;IACrE,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,UAAU,EAAE,iBAAiB,CAAC;IAC9B,IAAI,EAAE,WAAW,CAAC;IAClB,QAAQ,EAAE,eAAe,CAAC;IAC1B,MAAM,EAAE,cAAc,GAAG,IAAI,CAAC;IAC9B,aAAa,EAAE,mBAAmB,CAAC;CACpC,CAAC;AAEF,MAAM,MAAM,sBAAsB,GAAG,mBAAmB,CAAC;AAEzD,MAAM,MAAM,qBAAqB,GAAG,oBAAoB,GAAG;IACzD,IAAI,EAAE,iBAAiB,CAAC;IACxB,OAAO,EAAE,mBAAmB,CAAC;CAC9B,CAAC;AAEF,MAAM,MAAM,sBAAsB,GAAG,oBAAoB,GAAG;IAC1D,IAAI,EAAE,kBAAkB,CAAC;IACzB,OAAO,EAAE,sBAAsB,CAAC;CACjC,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG,oBAAoB,GAAG;IACzD,IAAI,EAAE,iBAAiB,CAAC;CACzB,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG,oBAAoB,GAAG;IACzD,IAAI,EAAE,iBAAiB,CAAC;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,gBAAgB,GACxB,MAAM,GACN,YAAY,GACZ,cAAc,GACd,iBAAiB,GACjB,WAAW,GACX,aAAa,GACb,UAAU,GACV,UAAU,GACV,WAAW,GACX,WAAW,GACX,YAAY,CAAC;AAEjB,2FAA2F;AAC3F,MAAM,MAAM,YAAY,GAAG;IACzB,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,gBAAgB,CAAC;IACvB,kEAAkE;IAClE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,2BAA2B,GAAG,oBAAoB,GAAG;IAC/D,IAAI,EAAE,wBAAwB,CAAC;IAC/B,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,sEAAsE;AACtE,MAAM,MAAM,mBAAmB,GAAG,oBAAoB,GAAG;IACvD,IAAI,EAAE,eAAe,CAAC;IACtB,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,yBAAyB,GAAG,oBAAoB,GAAG;IAC7D,IAAI,EAAE,sBAAsB,CAAC;IAC7B,OAAO,EAAE,YAAY,EAAE,CAAC;CACzB,CAAC;AAEF,0FAA0F;AAC1F,MAAM,MAAM,YAAY,GAAG;IACzB,0BAA0B;IAC1B,CAAC,EAAE,MAAM,CAAC;IACV,IAAI,EACA,OAAO,GACP,QAAQ,GACR,OAAO,GACP,OAAO,GACP,QAAQ,GACR,OAAO,GACP,eAAe,GACf,SAAS,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,iEAAiE;IACjE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,iEAAiE;IACjE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,uBAAuB,GAAG,oBAAoB,GAAG;IAC3D,IAAI,EAAE,mBAAmB,CAAC;CAC3B,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG,oBAAoB,GAAG;IACpD,IAAI,EAAE,WAAW,CAAC;IAClB,KAAK,EAAE,YAAY,EAAE,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAC3B,sBAAsB,GACtB,uBAAuB,GACvB,yBAAyB,GACzB,yBAAyB,GACzB,uBAAuB,CAAC;AAE5B,MAAM,MAAM,mBAAmB,GAC3B,qBAAqB,GACrB,qBAAqB,GACrB,sBAAsB,GACtB,qBAAqB,GACrB,2BAA2B,GAC3B,mBAAmB,GACnB,gBAAgB,GAChB,qBAAqB,CAAC;AAE1B,MAAM,MAAM,gBAAgB,GAAG,mBAAmB,GAAG,mBAAmB,CAAC;AAEzE,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,gBAAgB,CAS5E"}
@@ -1 +1 @@
1
- {"version":3,"file":"inspector.d.ts","sourceRoot":"","sources":["../../src/runtime/inspector.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAyCxE,MAAM,MAAM,uBAAuB,GAAG;IACpC,QAAQ,EAAE,QAAQ,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,mBAAmB,KAAK,IAAI,CAAC;IACjD,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,mBAAmB,KAAK,IAAI,CAAC;IAClD,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,sBAAsB,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IACpD,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CACxC,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,SAAS,EAAE,MAAM,OAAO,CAAC;IACzB,gBAAgB,EAAE,CAAC,OAAO,EAAE,YAAY,EAAE,KAAK,IAAI,CAAC;IACpD,iBAAiB,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,GAAG,IAAI,CAAC;IACrD,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB,CAAC;AAEF,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,uBAAuB,GAC/B,gBAAgB,CAsVlB"}
1
+ {"version":3,"file":"inspector.d.ts","sourceRoot":"","sources":["../../src/runtime/inspector.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAyCxE,MAAM,MAAM,uBAAuB,GAAG;IACpC,QAAQ,EAAE,QAAQ,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,mBAAmB,KAAK,IAAI,CAAC;IACjD,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,mBAAmB,KAAK,IAAI,CAAC;IAClD,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,sBAAsB,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IACpD,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CACxC,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,SAAS,EAAE,MAAM,OAAO,CAAC;IACzB,gBAAgB,EAAE,CAAC,OAAO,EAAE,YAAY,EAAE,KAAK,IAAI,CAAC;IACpD,iBAAiB,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,GAAG,IAAI,CAAC;IACrD,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB,CAAC;AAEF,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,uBAAuB,GAC/B,gBAAgB,CAsWlB"}
@@ -198,6 +198,17 @@ export function createInspectorRuntime(options) {
198
198
  if (inFile.length === 1)
199
199
  return inFile[0] ?? null;
200
200
  }
201
+ for (const selector of marker.hintSelector?.split(" || ") ?? []) {
202
+ let hinted = [];
203
+ try {
204
+ hinted = Array.from(doc.querySelectorAll(selector)).filter((node) => isRendered(node) && !node.closest("[data-abbox-inspector]"));
205
+ }
206
+ catch {
207
+ // An invalid selector from the host finds nothing.
208
+ }
209
+ if (hinted.length > 0)
210
+ return hinted[0] ?? null;
211
+ }
201
212
  return null;
202
213
  }
203
214
  function resolveMarkerElements(next) {
@@ -248,8 +259,15 @@ export function createInspectorRuntime(options) {
248
259
  refreshFrame = 0;
249
260
  if (win.location.pathname !== lastPath) {
250
261
  lastPath = win.location.pathname;
262
+ // The selection belonged to the previous page.
263
+ if (selected)
264
+ clearSelection();
251
265
  options.onRouteChange?.(lastPath);
252
266
  }
267
+ else if (selected && !selected.isConnected) {
268
+ // The app re-rendered without the selected element.
269
+ clearSelection();
270
+ }
253
271
  if (markers.length)
254
272
  refreshMarkers();
255
273
  });
@@ -165,6 +165,10 @@ const BADGE_COLORS = {
165
165
  "seo-error": "#dc2626",
166
166
  "seo-warning": "#d97706",
167
167
  "seo-info": "#2563eb",
168
+ "track-on": "#16a34a",
169
+ "track-key": "#d97706",
170
+ "track-off": "#6b7280",
171
+ "track-page": "#2563eb",
168
172
  };
169
173
  function styleBadge(node, marker) {
170
174
  Object.assign(node.style, {
@@ -0,0 +1,15 @@
1
+ import type { RecordedStep } from "../protocol.js";
2
+ /** Like a dashcam: only the last minute is kept. */
3
+ export declare const RECORDING_WINDOW_MS = 60000;
4
+ export type Recorder = {
5
+ snapshot: () => RecordedStep[];
6
+ stop: () => void;
7
+ };
8
+ /**
9
+ * Records the last minute of what happened in the page so a bug report can
10
+ * show the steps that led to it. Field values, request bodies and query strings
11
+ * are never stored. Lives only in this tab's sessionStorage, so it survives a
12
+ * reload and never leaves the page until the Viewer asks for it.
13
+ */
14
+ export declare function createRecorder(win: Window, doc: Document): Recorder;
15
+ //# sourceMappingURL=recorder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"recorder.d.ts","sourceRoot":"","sources":["../../src/runtime/recorder.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAEnD,oDAAoD;AACpD,eAAO,MAAM,mBAAmB,QAAS,CAAC;AAK1C,MAAM,MAAM,QAAQ,GAAG;IACrB,QAAQ,EAAE,MAAM,YAAY,EAAE,CAAC;IAC/B,IAAI,EAAE,MAAM,IAAI,CAAC;CAClB,CAAC;AA+EF;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,QAAQ,GAAG,QAAQ,CAuLnE"}
@@ -0,0 +1,245 @@
1
+ import { ABBBOX_SOURCE_ATTR } from "../instrument/constants.js";
2
+ /** Like a dashcam: only the last minute is kept. */
3
+ export const RECORDING_WINDOW_MS = 60_000;
4
+ const STORAGE_KEY = "abbox:recording";
5
+ const MAX_STEPS = 400;
6
+ const LABEL_LIMIT = 80;
7
+ function readStored(win) {
8
+ try {
9
+ const raw = win.sessionStorage.getItem(STORAGE_KEY);
10
+ return raw ? JSON.parse(raw) : [];
11
+ }
12
+ catch {
13
+ return [];
14
+ }
15
+ }
16
+ function labelOf(el) {
17
+ // Prefer what a person would call the control: its label, then its hint or name.
18
+ const field = el instanceof HTMLInputElement ||
19
+ el instanceof HTMLTextAreaElement ||
20
+ el instanceof HTMLSelectElement
21
+ ? el
22
+ : null;
23
+ const fieldHint = field instanceof HTMLSelectElement
24
+ ? field.name
25
+ : field
26
+ ? field.placeholder || field.name
27
+ : null;
28
+ const text = el.getAttribute("aria-label") ??
29
+ field?.labels?.[0]?.textContent ??
30
+ fieldHint ??
31
+ el.textContent;
32
+ const trimmed = text?.replace(/\s+/g, " ").trim();
33
+ return trimmed ? trimmed.slice(0, LABEL_LIMIT) : undefined;
34
+ }
35
+ /**
36
+ * What was entered, without the content: enough for a diagnosis to tell a
37
+ * single word from a phrase, or an empty field from a filled one.
38
+ */
39
+ function shapeOf(el) {
40
+ if (el instanceof HTMLSelectElement) {
41
+ return `selected option ${el.selectedIndex + 1} of ${el.options.length}`;
42
+ }
43
+ if (el instanceof HTMLInputElement &&
44
+ (el.type === "checkbox" || el.type === "radio")) {
45
+ return el.checked ? "checked" : "unchecked";
46
+ }
47
+ const text = el.value.trim();
48
+ if (text === "")
49
+ return "cleared";
50
+ const words = text.split(/\s+/).length;
51
+ const kind = el instanceof HTMLInputElement && !["text", "search"].includes(el.type)
52
+ ? `${el.type}, `
53
+ : "";
54
+ return `filled: ${kind}${words} word${words === 1 ? "" : "s"}, ${text.length} characters`;
55
+ }
56
+ function sourceOf(el) {
57
+ return (el.closest(`[${ABBBOX_SOURCE_ATTR}]`)?.getAttribute(ABBBOX_SOURCE_ATTR) ??
58
+ undefined);
59
+ }
60
+ /** Path only: query strings and fragments can carry tokens or personal data. */
61
+ function pathOf(url, base) {
62
+ try {
63
+ const parsed = new URL(url, base);
64
+ return parsed.origin === new URL(base).origin
65
+ ? parsed.pathname
66
+ : `${parsed.origin}${parsed.pathname}`;
67
+ }
68
+ catch {
69
+ return url.split(/[?#]/)[0] ?? url;
70
+ }
71
+ }
72
+ /**
73
+ * Records the last minute of what happened in the page so a bug report can
74
+ * show the steps that led to it. Field values, request bodies and query strings
75
+ * are never stored. Lives only in this tab's sessionStorage, so it survives a
76
+ * reload and never leaves the page until the Viewer asks for it.
77
+ */
78
+ export function createRecorder(win, doc) {
79
+ let steps = readStored(win);
80
+ const prune = (now) => {
81
+ steps = steps
82
+ .filter((step) => now - step.t <= RECORDING_WINDOW_MS)
83
+ .slice(-MAX_STEPS);
84
+ };
85
+ const push = (step) => {
86
+ const now = Date.now();
87
+ steps.push({ t: now, route: win.location.pathname, ...step });
88
+ prune(now);
89
+ try {
90
+ win.sessionStorage.setItem(STORAGE_KEY, JSON.stringify(steps));
91
+ }
92
+ catch {
93
+ // Storage full or blocked: the in-memory copy still works for this page.
94
+ }
95
+ };
96
+ const onClick = (event) => {
97
+ const target = event.target instanceof Element ? event.target : null;
98
+ const el = target?.closest("button, a, [role=button], input, select, label") ??
99
+ target;
100
+ if (!el)
101
+ return;
102
+ push({
103
+ kind: "click",
104
+ label: labelOf(el),
105
+ source: sourceOf(el),
106
+ tag: el.tagName.toLowerCase(),
107
+ });
108
+ };
109
+ const onSubmit = (event) => {
110
+ const form = event.target instanceof Element ? event.target : null;
111
+ if (!form)
112
+ return;
113
+ const submitter = event.submitter;
114
+ push({
115
+ kind: "submit",
116
+ label: submitter ? labelOf(submitter) : labelOf(form),
117
+ source: sourceOf(form),
118
+ tag: "form",
119
+ });
120
+ };
121
+ const onChange = (event) => {
122
+ const el = event.target;
123
+ if (!(el instanceof HTMLInputElement ||
124
+ el instanceof HTMLTextAreaElement ||
125
+ el instanceof HTMLSelectElement))
126
+ return;
127
+ if (el instanceof HTMLInputElement && el.type === "password")
128
+ return;
129
+ push({
130
+ kind: "input",
131
+ label: labelOf(el) ?? el.name ?? undefined,
132
+ source: sourceOf(el),
133
+ tag: el.tagName.toLowerCase(),
134
+ detail: shapeOf(el),
135
+ });
136
+ };
137
+ let lastScroll = 0;
138
+ const onScroll = () => {
139
+ const now = Date.now();
140
+ if (now - lastScroll < 1000)
141
+ return;
142
+ lastScroll = now;
143
+ const max = doc.documentElement.scrollHeight - win.innerHeight;
144
+ const pct = max > 0 ? Math.round((win.scrollY / max) * 100) : 0;
145
+ push({ kind: "scroll", detail: `${pct}% down` });
146
+ };
147
+ let lastPath = win.location.pathname;
148
+ const routeTimer = win.setInterval(() => {
149
+ if (win.location.pathname === lastPath)
150
+ return;
151
+ lastPath = win.location.pathname;
152
+ push({ kind: "route", detail: lastPath });
153
+ }, 300);
154
+ const onError = (event) => {
155
+ push({
156
+ kind: "error",
157
+ detail: String(event.message).slice(0, 300),
158
+ ...(event.filename
159
+ ? {
160
+ location: `${pathOf(event.filename, win.location.href)}:${event.lineno}`,
161
+ }
162
+ : {}),
163
+ });
164
+ };
165
+ const onRejection = (event) => {
166
+ const reason = event.reason instanceof Error
167
+ ? event.reason.message
168
+ : String(event.reason);
169
+ push({
170
+ kind: "error",
171
+ detail: `Unhandled rejection: ${reason}`.slice(0, 300),
172
+ });
173
+ };
174
+ const originalConsoleError = console.error;
175
+ console.error = (...args) => {
176
+ push({
177
+ kind: "console-error",
178
+ detail: args
179
+ .map((a) => a instanceof Error ? a.message : typeof a === "string" ? a : "")
180
+ .join(" ")
181
+ .trim()
182
+ .slice(0, 300),
183
+ });
184
+ originalConsoleError.apply(console, args);
185
+ };
186
+ const originalFetch = win.fetch;
187
+ win.fetch = async (input, init) => {
188
+ const started = Date.now();
189
+ const url = typeof input === "string"
190
+ ? input
191
+ : input instanceof URL
192
+ ? input.href
193
+ : input.url;
194
+ // Framework dev tooling (Next.js overlay, HMR) is not the app's activity.
195
+ if (/\/(__nextjs|_next\/)/.test(url)) {
196
+ return originalFetch.call(win, input, init);
197
+ }
198
+ const method = (init?.method ?? (input instanceof Request ? input.method : "GET")).toUpperCase();
199
+ try {
200
+ const response = await originalFetch.call(win, input, init);
201
+ push({
202
+ kind: "request",
203
+ method,
204
+ url: pathOf(url, win.location.href),
205
+ status: response.status,
206
+ durationMs: Date.now() - started,
207
+ });
208
+ return response;
209
+ }
210
+ catch (error) {
211
+ push({
212
+ kind: "request",
213
+ method,
214
+ url: pathOf(url, win.location.href),
215
+ status: 0,
216
+ detail: error instanceof Error ? error.message : "Network error",
217
+ durationMs: Date.now() - started,
218
+ });
219
+ throw error;
220
+ }
221
+ };
222
+ doc.addEventListener("click", onClick, true);
223
+ doc.addEventListener("submit", onSubmit, true);
224
+ doc.addEventListener("change", onChange, true);
225
+ win.addEventListener("scroll", onScroll, { passive: true });
226
+ win.addEventListener("error", onError);
227
+ win.addEventListener("unhandledrejection", onRejection);
228
+ return {
229
+ snapshot: () => {
230
+ prune(Date.now());
231
+ return [...steps];
232
+ },
233
+ stop: () => {
234
+ doc.removeEventListener("click", onClick, true);
235
+ doc.removeEventListener("submit", onSubmit, true);
236
+ doc.removeEventListener("change", onChange, true);
237
+ win.removeEventListener("scroll", onScroll);
238
+ win.removeEventListener("error", onError);
239
+ win.removeEventListener("unhandledrejection", onRejection);
240
+ win.clearInterval(routeTimer);
241
+ console.error = originalConsoleError;
242
+ win.fetch = originalFetch;
243
+ },
244
+ };
245
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@abbox/inspector",
3
- "version": "0.4.15",
3
+ "version": "0.4.17",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },