@monoscopetech/browser 0.6.1 → 0.7.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/README.md +215 -27
- package/dist/breadcrumbs.d.ts +9 -0
- package/dist/breadcrumbs.js +13 -0
- package/dist/errors.d.ts +17 -0
- package/dist/errors.js +107 -0
- package/dist/index.d.ts +20 -1
- package/dist/index.js +161 -14
- package/dist/monoscope.min.js +5 -5
- package/dist/monoscope.min.js.map +1 -1
- package/dist/monoscope.umd.js +5 -5
- package/dist/monoscope.umd.js.map +1 -1
- package/dist/react.d.ts +28 -0
- package/dist/react.js +59 -0
- package/dist/replay.d.ts +11 -2
- package/dist/replay.js +80 -72
- package/dist/router.d.ts +13 -0
- package/dist/router.js +65 -0
- package/dist/tracing.d.ts +22 -2
- package/dist/tracing.js +196 -43
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/types.d.ts +7 -2
- package/dist/web-vitals.d.ts +10 -0
- package/dist/web-vitals.js +31 -0
- package/package.json +40 -6
package/dist/react.d.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { Component } from "react";
|
|
2
|
+
import type { ReactNode, ErrorInfo } from "react";
|
|
3
|
+
import Monoscope from ".";
|
|
4
|
+
import type { MonoscopeConfig, MonoscopeUser } from "./types";
|
|
5
|
+
export declare function MonoscopeProvider({ config, children }: {
|
|
6
|
+
config: MonoscopeConfig;
|
|
7
|
+
children: ReactNode;
|
|
8
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
9
|
+
export declare function useMonoscope(): Monoscope | null;
|
|
10
|
+
export declare function useMonoscopeUser(user: MonoscopeUser | null | undefined): void;
|
|
11
|
+
type ErrorBoundaryProps = {
|
|
12
|
+
children: ReactNode;
|
|
13
|
+
fallback?: ReactNode | ((error: Error) => ReactNode);
|
|
14
|
+
};
|
|
15
|
+
type ErrorBoundaryState = {
|
|
16
|
+
error: Error | null;
|
|
17
|
+
};
|
|
18
|
+
export declare class MonoscopeErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundaryState> {
|
|
19
|
+
static contextType: import("react").Context<Monoscope | null>;
|
|
20
|
+
context: Monoscope | null;
|
|
21
|
+
state: ErrorBoundaryState;
|
|
22
|
+
static getDerivedStateFromError(error: Error): {
|
|
23
|
+
error: Error;
|
|
24
|
+
};
|
|
25
|
+
componentDidCatch(error: Error, info: ErrorInfo): void;
|
|
26
|
+
render(): ReactNode;
|
|
27
|
+
}
|
|
28
|
+
export {};
|
package/dist/react.js
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { createContext, useContext, useRef, useEffect, Component } from "react";
|
|
4
|
+
import Monoscope from ".";
|
|
5
|
+
const MonoscopeContext = createContext(null);
|
|
6
|
+
export function MonoscopeProvider({ config, children }) {
|
|
7
|
+
const ref = useRef(null);
|
|
8
|
+
if (!ref.current && typeof window !== "undefined") {
|
|
9
|
+
ref.current = new Monoscope(config);
|
|
10
|
+
}
|
|
11
|
+
useEffect(() => {
|
|
12
|
+
const instance = ref.current;
|
|
13
|
+
if (!instance)
|
|
14
|
+
return;
|
|
15
|
+
// Deferred destroy — cleared if Strict Mode remounts immediately
|
|
16
|
+
let timer;
|
|
17
|
+
return () => {
|
|
18
|
+
timer = setTimeout(() => { instance.destroy(); ref.current = null; }, 0);
|
|
19
|
+
return void timer;
|
|
20
|
+
};
|
|
21
|
+
}, []);
|
|
22
|
+
return _jsx(MonoscopeContext.Provider, { value: ref.current, children: children });
|
|
23
|
+
}
|
|
24
|
+
export function useMonoscope() {
|
|
25
|
+
return useContext(MonoscopeContext);
|
|
26
|
+
}
|
|
27
|
+
export function useMonoscopeUser(user) {
|
|
28
|
+
const instance = useMonoscope();
|
|
29
|
+
useEffect(() => {
|
|
30
|
+
if (instance && user)
|
|
31
|
+
instance.setUser(user);
|
|
32
|
+
}, [instance, user]);
|
|
33
|
+
}
|
|
34
|
+
export class MonoscopeErrorBoundary extends Component {
|
|
35
|
+
constructor() {
|
|
36
|
+
super(...arguments);
|
|
37
|
+
this.state = { error: null };
|
|
38
|
+
}
|
|
39
|
+
static getDerivedStateFromError(error) {
|
|
40
|
+
return { error };
|
|
41
|
+
}
|
|
42
|
+
componentDidCatch(error, info) {
|
|
43
|
+
this.context?.recordEvent("react.error_boundary", {
|
|
44
|
+
"error.message": error.message,
|
|
45
|
+
"error.stack": error.stack ?? "",
|
|
46
|
+
"error.component_stack": info.componentStack ?? "",
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
render() {
|
|
50
|
+
if (this.state.error) {
|
|
51
|
+
const { fallback } = this.props;
|
|
52
|
+
if (typeof fallback === "function")
|
|
53
|
+
return fallback(this.state.error);
|
|
54
|
+
return fallback ?? null;
|
|
55
|
+
}
|
|
56
|
+
return this.props.children;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
MonoscopeErrorBoundary.contextType = MonoscopeContext;
|
package/dist/replay.d.ts
CHANGED
|
@@ -3,18 +3,27 @@ export declare class MonoscopeReplay {
|
|
|
3
3
|
private events;
|
|
4
4
|
private config;
|
|
5
5
|
private sessionId;
|
|
6
|
+
private tabId;
|
|
6
7
|
private stopRecording;
|
|
7
8
|
private saveInterval;
|
|
8
9
|
private isSaving;
|
|
9
10
|
private isConfigured;
|
|
10
|
-
|
|
11
|
-
private
|
|
11
|
+
private _enabled;
|
|
12
|
+
private userAttributes;
|
|
13
|
+
private _listenersAttached;
|
|
12
14
|
private handleUnload;
|
|
13
15
|
private handleVisibilityChange;
|
|
16
|
+
constructor(config: MonoscopeConfig, sessionId: string, tabId: string);
|
|
17
|
+
private setupListeners;
|
|
18
|
+
private removeListeners;
|
|
19
|
+
private trimEvents;
|
|
14
20
|
configure(): void;
|
|
15
21
|
save(forceSynchronous?: boolean): Promise<void>;
|
|
16
22
|
stop(): void;
|
|
23
|
+
setEnabled(enabled: boolean): void;
|
|
24
|
+
setUser(user: Record<string, string | string[] | undefined>): void;
|
|
17
25
|
getEventCount(): number;
|
|
26
|
+
updateSessionId(sessionId: string): void;
|
|
18
27
|
getSessionId(): string;
|
|
19
28
|
isRecording(): boolean;
|
|
20
29
|
}
|
package/dist/replay.js
CHANGED
|
@@ -4,46 +4,71 @@ const MAX_EVENT_BATCH = 50;
|
|
|
4
4
|
const SAVE_INTERVAL = 2000;
|
|
5
5
|
const MAX_RETRY_EVENTS = 5000;
|
|
6
6
|
export class MonoscopeReplay {
|
|
7
|
-
constructor(config, sessionId) {
|
|
7
|
+
constructor(config, sessionId, tabId) {
|
|
8
8
|
this.events = [];
|
|
9
9
|
this.stopRecording = undefined;
|
|
10
10
|
this.saveInterval = null;
|
|
11
11
|
this.isSaving = false;
|
|
12
12
|
this.isConfigured = false;
|
|
13
|
+
this._enabled = true;
|
|
14
|
+
this.userAttributes = {};
|
|
15
|
+
this._listenersAttached = false;
|
|
16
|
+
this.handleUnload = () => this.save(true);
|
|
17
|
+
this.handleVisibilityChange = () => { if (document.visibilityState === "hidden")
|
|
18
|
+
this.save(); };
|
|
13
19
|
this.sessionId = sessionId;
|
|
20
|
+
this.tabId = tabId;
|
|
14
21
|
this.config = config;
|
|
15
|
-
this.
|
|
16
|
-
// Bind methods
|
|
17
|
-
this.save = this.save.bind(this);
|
|
18
|
-
this.configure = this.configure.bind(this);
|
|
19
|
-
this.handleUnload = this.handleUnload.bind(this);
|
|
20
|
-
this.handleVisibilityChange = this.handleVisibilityChange.bind(this);
|
|
21
|
-
// Setup event listeners
|
|
22
|
-
this.setupEventListeners();
|
|
22
|
+
this.setupListeners();
|
|
23
23
|
}
|
|
24
|
-
|
|
24
|
+
setupListeners() {
|
|
25
|
+
if (typeof window === "undefined" || this._listenersAttached)
|
|
26
|
+
return;
|
|
27
|
+
this._listenersAttached = true;
|
|
25
28
|
window.addEventListener("beforeunload", this.handleUnload);
|
|
26
|
-
document.addEventListener("visibilitychange", this.handleVisibilityChange);
|
|
27
29
|
window.addEventListener("pagehide", this.handleUnload);
|
|
30
|
+
document.addEventListener("visibilitychange", this.handleVisibilityChange);
|
|
28
31
|
}
|
|
29
|
-
|
|
30
|
-
|
|
32
|
+
removeListeners() {
|
|
33
|
+
if (typeof window === "undefined" || !this._listenersAttached)
|
|
34
|
+
return;
|
|
35
|
+
this._listenersAttached = false;
|
|
36
|
+
window.removeEventListener("beforeunload", this.handleUnload);
|
|
37
|
+
window.removeEventListener("pagehide", this.handleUnload);
|
|
38
|
+
document.removeEventListener("visibilitychange", this.handleVisibilityChange);
|
|
31
39
|
}
|
|
32
|
-
|
|
33
|
-
if (
|
|
34
|
-
|
|
40
|
+
trimEvents() {
|
|
41
|
+
if (this.events.length <= MAX_RETRY_EVENTS)
|
|
42
|
+
return;
|
|
43
|
+
if (this.config.debug) {
|
|
44
|
+
console.warn(`Event queue exceeded ${MAX_RETRY_EVENTS}, dropping middle events (preserving snapshots)`);
|
|
35
45
|
}
|
|
46
|
+
// rrweb EventType.FullSnapshot (type 2) — required for replay playback
|
|
47
|
+
const fullSnapshots = this.events.filter((e) => e.type === 2);
|
|
48
|
+
const otherEvents = this.events.filter((e) => e.type !== 2);
|
|
49
|
+
const remainingSlots = Math.max(0, MAX_RETRY_EVENTS - fullSnapshots.length);
|
|
50
|
+
this.events = [...fullSnapshots, ...otherEvents.slice(-remainingSlots)];
|
|
51
|
+
this.events.sort((a, b) => a.timestamp - b.timestamp);
|
|
36
52
|
}
|
|
37
53
|
configure() {
|
|
38
|
-
if (
|
|
39
|
-
|
|
54
|
+
if (typeof window === "undefined")
|
|
55
|
+
return;
|
|
56
|
+
if (this.isConfigured)
|
|
57
|
+
return;
|
|
58
|
+
this.setupListeners();
|
|
59
|
+
const rate = Math.max(0, Math.min(1, this.config.replaySampleRate ?? 1));
|
|
60
|
+
if (Math.random() >= rate) {
|
|
61
|
+
this._enabled = false;
|
|
62
|
+
if (this.config.debug)
|
|
63
|
+
console.log("MonoscopeReplay: sampled out");
|
|
40
64
|
return;
|
|
41
65
|
}
|
|
42
66
|
try {
|
|
43
67
|
this.stopRecording = rrweb.record({
|
|
44
68
|
emit: (event) => {
|
|
69
|
+
if (!this._enabled)
|
|
70
|
+
return;
|
|
45
71
|
this.events.push(event);
|
|
46
|
-
// Auto-save when batch size reached
|
|
47
72
|
if (this.events.length >= MAX_EVENT_BATCH) {
|
|
48
73
|
this.save();
|
|
49
74
|
}
|
|
@@ -56,8 +81,7 @@ export class MonoscopeReplay {
|
|
|
56
81
|
tel: true,
|
|
57
82
|
},
|
|
58
83
|
maskTextClass: "rr-mask",
|
|
59
|
-
|
|
60
|
-
checkoutEveryNms: 15 * 1000, // Full snapshot every 15s
|
|
84
|
+
checkoutEveryNms: 15 * 1000,
|
|
61
85
|
sampling: {
|
|
62
86
|
mouseInteraction: {
|
|
63
87
|
MouseUp: false,
|
|
@@ -71,9 +95,9 @@ export class MonoscopeReplay {
|
|
|
71
95
|
TouchEnd: false,
|
|
72
96
|
},
|
|
73
97
|
mousemove: true,
|
|
74
|
-
scroll: 150,
|
|
98
|
+
scroll: 150,
|
|
75
99
|
media: 800,
|
|
76
|
-
input: "last",
|
|
100
|
+
input: "last",
|
|
77
101
|
},
|
|
78
102
|
plugins: [
|
|
79
103
|
getRecordConsolePlugin({
|
|
@@ -82,77 +106,59 @@ export class MonoscopeReplay {
|
|
|
82
106
|
stringifyOptions: {
|
|
83
107
|
stringLengthLimit: 1000,
|
|
84
108
|
numOfKeysLimit: 100,
|
|
85
|
-
depthOfLimit: 2,
|
|
109
|
+
depthOfLimit: 2,
|
|
86
110
|
},
|
|
87
111
|
}),
|
|
88
112
|
],
|
|
89
113
|
});
|
|
90
|
-
this.saveInterval = setInterval(() =>
|
|
91
|
-
this.save();
|
|
92
|
-
}, SAVE_INTERVAL);
|
|
114
|
+
this.saveInterval = setInterval(() => this.save(), SAVE_INTERVAL);
|
|
93
115
|
this.isConfigured = true;
|
|
94
116
|
if (this.config.debug) {
|
|
95
117
|
console.log("MonoscopeReplay configured successfully");
|
|
96
118
|
}
|
|
97
119
|
}
|
|
98
120
|
catch (error) {
|
|
99
|
-
console.
|
|
100
|
-
throw error;
|
|
121
|
+
console.warn("Monoscope: failed to configure replay", error);
|
|
101
122
|
}
|
|
102
123
|
}
|
|
103
124
|
async save(forceSynchronous = false) {
|
|
104
|
-
if (this.isSaving && !forceSynchronous)
|
|
125
|
+
if (this.isSaving && !forceSynchronous)
|
|
105
126
|
return;
|
|
106
|
-
|
|
107
|
-
if (this.events.length === 0) {
|
|
127
|
+
if (this.events.length === 0)
|
|
108
128
|
return;
|
|
109
|
-
|
|
110
|
-
if (this.events.length > MAX_RETRY_EVENTS) {
|
|
111
|
-
if (this.config.debug) {
|
|
112
|
-
console.warn(`Event queue exceeded ${MAX_RETRY_EVENTS}, dropping middle events (preserving snapshots)`);
|
|
113
|
-
}
|
|
114
|
-
// Find full snapshot events (type 2) - these are critical for replay
|
|
115
|
-
const fullSnapshots = this.events.filter((e) => e.type === 2);
|
|
116
|
-
const otherEvents = this.events.filter((e) => e.type !== 2);
|
|
117
|
-
// Keep all snapshots and the most recent other events
|
|
118
|
-
const remainingSlots = MAX_RETRY_EVENTS - fullSnapshots.length;
|
|
119
|
-
this.events = [...fullSnapshots, ...otherEvents.slice(-remainingSlots)];
|
|
120
|
-
// Re-sort by timestamp to maintain order
|
|
121
|
-
this.events.sort((a, b) => a.timestamp - b.timestamp);
|
|
122
|
-
}
|
|
129
|
+
this.trimEvents();
|
|
123
130
|
this.isSaving = true;
|
|
124
|
-
const {
|
|
125
|
-
// Construct base URL
|
|
126
|
-
let baseUrl = replayEventsBaseUrl || "https://app.monoscope.tech";
|
|
127
|
-
baseUrl = `${baseUrl}/rrweb/${projectId}`;
|
|
128
|
-
// Get events to send and clear buffer
|
|
131
|
+
const baseUrl = `${this.config.replayEventsBaseUrl || "https://app.monoscope.tech"}/rrweb/${this.config.projectId}`;
|
|
129
132
|
const eventsToSend = [...this.events];
|
|
130
133
|
this.events = [];
|
|
131
134
|
const payload = {
|
|
132
135
|
events: eventsToSend,
|
|
133
136
|
sessionId: this.sessionId,
|
|
137
|
+
tabId: this.tabId,
|
|
134
138
|
timestamp: new Date().toISOString(),
|
|
135
139
|
eventCount: eventsToSend.length,
|
|
140
|
+
user: Object.keys(this.userAttributes).length > 0 ? this.userAttributes : undefined,
|
|
136
141
|
};
|
|
137
142
|
try {
|
|
138
|
-
if (forceSynchronous && navigator.sendBeacon) {
|
|
143
|
+
if (forceSynchronous && typeof navigator !== "undefined" && navigator.sendBeacon) {
|
|
139
144
|
const blob = new Blob([JSON.stringify(payload)], {
|
|
140
145
|
type: "application/json",
|
|
141
146
|
});
|
|
142
147
|
const sent = navigator.sendBeacon(baseUrl, blob);
|
|
143
148
|
if (!sent) {
|
|
144
|
-
|
|
149
|
+
fetch(baseUrl, {
|
|
150
|
+
method: "POST",
|
|
151
|
+
headers: { "Content-Type": "application/json" },
|
|
152
|
+
body: JSON.stringify(payload),
|
|
153
|
+
keepalive: true,
|
|
154
|
+
}).catch(() => { });
|
|
145
155
|
}
|
|
146
156
|
}
|
|
147
157
|
else {
|
|
148
|
-
// Use keepalive so the request survives page navigation,
|
|
149
|
-
// but only when payload fits under the 64KB keepalive limit
|
|
150
158
|
const body = JSON.stringify(payload);
|
|
151
159
|
const response = await fetch(baseUrl, {
|
|
152
160
|
method: "POST",
|
|
153
|
-
headers: {
|
|
154
|
-
"Content-Type": "application/json",
|
|
155
|
-
},
|
|
161
|
+
headers: { "Content-Type": "application/json" },
|
|
156
162
|
body,
|
|
157
163
|
keepalive: body.length < 63000,
|
|
158
164
|
});
|
|
@@ -165,23 +171,16 @@ export class MonoscopeReplay {
|
|
|
165
171
|
}
|
|
166
172
|
}
|
|
167
173
|
catch (error) {
|
|
168
|
-
console.
|
|
174
|
+
console.warn("Monoscope: failed to save replay events:", error);
|
|
169
175
|
this.events = [...eventsToSend, ...this.events];
|
|
170
|
-
|
|
171
|
-
// Preserve full snapshots when trimming
|
|
172
|
-
const fullSnapshots = this.events.filter((e) => e.type === 2);
|
|
173
|
-
const otherEvents = this.events.filter((e) => e.type !== 2);
|
|
174
|
-
const remainingSlots = MAX_RETRY_EVENTS - fullSnapshots.length;
|
|
175
|
-
this.events = [...fullSnapshots, ...otherEvents.slice(-remainingSlots)];
|
|
176
|
-
this.events.sort((a, b) => a.timestamp - b.timestamp);
|
|
177
|
-
}
|
|
176
|
+
this.trimEvents();
|
|
178
177
|
}
|
|
179
178
|
finally {
|
|
180
179
|
this.isSaving = false;
|
|
181
180
|
}
|
|
182
181
|
}
|
|
183
182
|
stop() {
|
|
184
|
-
this.save(true);
|
|
183
|
+
this.save(true).catch(() => { });
|
|
185
184
|
if (this.stopRecording) {
|
|
186
185
|
this.stopRecording();
|
|
187
186
|
this.stopRecording = undefined;
|
|
@@ -190,21 +189,30 @@ export class MonoscopeReplay {
|
|
|
190
189
|
clearInterval(this.saveInterval);
|
|
191
190
|
this.saveInterval = null;
|
|
192
191
|
}
|
|
193
|
-
|
|
194
|
-
window.removeEventListener("pagehide", this.handleUnload);
|
|
195
|
-
document.removeEventListener("visibilitychange", this.handleVisibilityChange);
|
|
192
|
+
this.removeListeners();
|
|
196
193
|
this.isConfigured = false;
|
|
197
194
|
if (this.config.debug) {
|
|
198
195
|
console.log("MonoscopeReplay stopped");
|
|
199
196
|
}
|
|
200
197
|
}
|
|
198
|
+
setEnabled(enabled) {
|
|
199
|
+
this._enabled = enabled;
|
|
200
|
+
if (!enabled)
|
|
201
|
+
this.stop();
|
|
202
|
+
}
|
|
203
|
+
setUser(user) {
|
|
204
|
+
this.userAttributes = { ...this.userAttributes, ...user };
|
|
205
|
+
}
|
|
201
206
|
getEventCount() {
|
|
202
207
|
return this.events.length;
|
|
203
208
|
}
|
|
209
|
+
updateSessionId(sessionId) {
|
|
210
|
+
this.sessionId = sessionId;
|
|
211
|
+
}
|
|
204
212
|
getSessionId() {
|
|
205
213
|
return this.sessionId;
|
|
206
214
|
}
|
|
207
215
|
isRecording() {
|
|
208
|
-
return this.isConfigured && this.stopRecording !==
|
|
216
|
+
return this.isConfigured && this.stopRecording !== undefined;
|
|
209
217
|
}
|
|
210
218
|
}
|
package/dist/router.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
type EmitFn = (name: string, attrs: Record<string, string | number>) => void;
|
|
2
|
+
export declare class SPARouter {
|
|
3
|
+
private emit;
|
|
4
|
+
private currentUrl;
|
|
5
|
+
private _active;
|
|
6
|
+
private origPushState;
|
|
7
|
+
private origReplaceState;
|
|
8
|
+
private popstateHandler;
|
|
9
|
+
constructor(emit: EmitFn);
|
|
10
|
+
start(): void;
|
|
11
|
+
stop(): void;
|
|
12
|
+
}
|
|
13
|
+
export {};
|
package/dist/router.js
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { addBreadcrumb } from "./breadcrumbs";
|
|
2
|
+
export class SPARouter {
|
|
3
|
+
constructor(emit) {
|
|
4
|
+
this.currentUrl = "";
|
|
5
|
+
this._active = false;
|
|
6
|
+
this.origPushState = null;
|
|
7
|
+
this.origReplaceState = null;
|
|
8
|
+
this.popstateHandler = null;
|
|
9
|
+
this.emit = emit;
|
|
10
|
+
}
|
|
11
|
+
start() {
|
|
12
|
+
if (typeof window === "undefined" || this._active)
|
|
13
|
+
return;
|
|
14
|
+
this._active = true;
|
|
15
|
+
this.currentUrl = location.href;
|
|
16
|
+
this.origPushState = history.pushState.bind(history);
|
|
17
|
+
this.origReplaceState = history.replaceState.bind(history);
|
|
18
|
+
const onNav = (method) => {
|
|
19
|
+
try {
|
|
20
|
+
const from = this.currentUrl;
|
|
21
|
+
const to = location.href;
|
|
22
|
+
if (from === to)
|
|
23
|
+
return;
|
|
24
|
+
this.currentUrl = to;
|
|
25
|
+
addBreadcrumb({ type: "navigation", message: `${from} → ${to}`, data: { method } });
|
|
26
|
+
this.emit("navigation", {
|
|
27
|
+
"navigation.from": from,
|
|
28
|
+
"navigation.to": to,
|
|
29
|
+
"navigation.method": method,
|
|
30
|
+
"page.title": document.title,
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
catch (e) {
|
|
34
|
+
try {
|
|
35
|
+
console.warn("Monoscope: error in navigation tracking", e);
|
|
36
|
+
}
|
|
37
|
+
catch { /* must never throw */ }
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
history.pushState = (...args) => {
|
|
41
|
+
this.origPushState(...args);
|
|
42
|
+
onNav("pushState");
|
|
43
|
+
};
|
|
44
|
+
history.replaceState = (...args) => {
|
|
45
|
+
this.origReplaceState(...args);
|
|
46
|
+
onNav("replaceState");
|
|
47
|
+
};
|
|
48
|
+
this.popstateHandler = () => onNav("popstate");
|
|
49
|
+
window.addEventListener("popstate", this.popstateHandler);
|
|
50
|
+
}
|
|
51
|
+
stop() {
|
|
52
|
+
if (typeof window === "undefined" || !this._active)
|
|
53
|
+
return;
|
|
54
|
+
this._active = false;
|
|
55
|
+
if (this.origPushState)
|
|
56
|
+
history.pushState = this.origPushState;
|
|
57
|
+
if (this.origReplaceState)
|
|
58
|
+
history.replaceState = this.origReplaceState;
|
|
59
|
+
if (this.popstateHandler)
|
|
60
|
+
window.removeEventListener("popstate", this.popstateHandler);
|
|
61
|
+
this.origPushState = null;
|
|
62
|
+
this.origReplaceState = null;
|
|
63
|
+
this.popstateHandler = null;
|
|
64
|
+
}
|
|
65
|
+
}
|
package/dist/tracing.d.ts
CHANGED
|
@@ -1,12 +1,32 @@
|
|
|
1
1
|
import { MonoscopeConfig, MonoscopeUser } from "./types";
|
|
2
|
+
import { Span } from "@opentelemetry/api";
|
|
2
3
|
export declare class OpenTelemetryManager {
|
|
3
4
|
private config;
|
|
4
5
|
private sessionId;
|
|
6
|
+
private tabId;
|
|
5
7
|
private provider;
|
|
6
|
-
|
|
8
|
+
private longTaskObserver;
|
|
9
|
+
private resourceObserver;
|
|
10
|
+
private _enabled;
|
|
11
|
+
private _configured;
|
|
12
|
+
private pageSpan;
|
|
13
|
+
private pageContext;
|
|
14
|
+
private endPageSpanHandler;
|
|
15
|
+
constructor(config: MonoscopeConfig, sessionId: string, tabId: string);
|
|
7
16
|
private createProvider;
|
|
17
|
+
private commonAttrs;
|
|
18
|
+
private applyCommonAttrs;
|
|
8
19
|
configure(): void;
|
|
9
|
-
private
|
|
20
|
+
private startPageSpan;
|
|
21
|
+
getPageContext(): import("@opentelemetry/api").Context | null;
|
|
22
|
+
private withPageContext;
|
|
23
|
+
emitSpan(name: string, attrs: Record<string, string | number | boolean>, configure?: (span: Span) => void): void;
|
|
24
|
+
private observeLongTasks;
|
|
25
|
+
private observeResourceTiming;
|
|
26
|
+
startSpan<T>(name: string, fn: (span: Span) => T): T;
|
|
27
|
+
recordEvent(name: string, attributes?: Record<string, string | number | boolean>): void;
|
|
28
|
+
updateSessionId(sessionId: string): void;
|
|
29
|
+
setEnabled(enabled: boolean): void;
|
|
10
30
|
shutdown(): Promise<void>;
|
|
11
31
|
setUser(newConfig: MonoscopeUser): void;
|
|
12
32
|
}
|