@monoscopetech/browser 0.7.2 → 0.8.0
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 +24 -9
- package/dist/index.d.ts +6 -0
- package/dist/index.js +53 -3
- package/dist/monoscope.min.js +3 -3
- package/dist/monoscope.min.js.map +1 -1
- package/dist/monoscope.umd.js +3 -3
- package/dist/monoscope.umd.js.map +1 -1
- package/dist/overlay.d.ts +12 -0
- package/dist/overlay.js +63 -0
- package/dist/react.d.ts +7 -3
- package/dist/react.js +2 -1
- package/dist/replay.js +13 -4
- package/dist/tracing.d.ts +4 -0
- package/dist/tracing.js +42 -6
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/types.d.ts +4 -2
- package/package.json +1 -1
package/dist/overlay.js
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
const DISMISS_KEY = "monoscope-overlay-dismissed";
|
|
2
|
+
export class DevOverlay {
|
|
3
|
+
constructor() {
|
|
4
|
+
this.el = null;
|
|
5
|
+
this.eventCount = 0;
|
|
6
|
+
this.statusDot = null;
|
|
7
|
+
this.countEl = null;
|
|
8
|
+
this.connEl = null;
|
|
9
|
+
if (typeof document === "undefined")
|
|
10
|
+
return;
|
|
11
|
+
try {
|
|
12
|
+
if (sessionStorage.getItem(DISMISS_KEY))
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
catch { }
|
|
16
|
+
this.mount();
|
|
17
|
+
}
|
|
18
|
+
mount() {
|
|
19
|
+
const el = document.createElement("div");
|
|
20
|
+
Object.assign(el.style, {
|
|
21
|
+
position: "fixed", bottom: "12px", right: "12px", zIndex: "2147483647",
|
|
22
|
+
background: "#1a1a2e", color: "#e0e0e0", fontFamily: "system-ui, sans-serif",
|
|
23
|
+
fontSize: "12px", padding: "6px 10px", borderRadius: "6px",
|
|
24
|
+
boxShadow: "0 2px 8px rgba(0,0,0,0.3)", display: "flex", alignItems: "center", gap: "6px",
|
|
25
|
+
cursor: "default", userSelect: "none",
|
|
26
|
+
});
|
|
27
|
+
this.statusDot = document.createElement("span");
|
|
28
|
+
Object.assign(this.statusDot.style, {
|
|
29
|
+
width: "7px", height: "7px", borderRadius: "50%", background: "#22c55e", display: "inline-block",
|
|
30
|
+
});
|
|
31
|
+
this.countEl = document.createElement("span");
|
|
32
|
+
this.countEl.textContent = "0";
|
|
33
|
+
this.countEl.style.opacity = "0.7";
|
|
34
|
+
this.connEl = document.createElement("span");
|
|
35
|
+
this.connEl.style.opacity = "0.7";
|
|
36
|
+
const close = document.createElement("span");
|
|
37
|
+
close.textContent = "\u00d7";
|
|
38
|
+
Object.assign(close.style, { cursor: "pointer", marginLeft: "4px", opacity: "0.6", fontSize: "14px" });
|
|
39
|
+
close.onclick = () => this.dismiss();
|
|
40
|
+
el.append(this.statusDot, " Monoscope ", this.countEl, " ", this.connEl, close);
|
|
41
|
+
this.el = el;
|
|
42
|
+
(document.body || document.documentElement).appendChild(el);
|
|
43
|
+
}
|
|
44
|
+
incrementEvents() {
|
|
45
|
+
this.eventCount++;
|
|
46
|
+
if (this.countEl)
|
|
47
|
+
this.countEl.textContent = String(this.eventCount);
|
|
48
|
+
}
|
|
49
|
+
setConnectionStatus(ok) {
|
|
50
|
+
if (this.connEl)
|
|
51
|
+
this.connEl.textContent = ok ? "Connected" : "Connection failed";
|
|
52
|
+
if (this.statusDot)
|
|
53
|
+
this.statusDot.style.background = ok ? "#22c55e" : "#ef4444";
|
|
54
|
+
}
|
|
55
|
+
dismiss() {
|
|
56
|
+
this.el?.remove();
|
|
57
|
+
this.el = null;
|
|
58
|
+
try {
|
|
59
|
+
sessionStorage.setItem(DISMISS_KEY, "1");
|
|
60
|
+
}
|
|
61
|
+
catch { }
|
|
62
|
+
}
|
|
63
|
+
}
|
package/dist/react.d.ts
CHANGED
|
@@ -2,10 +2,14 @@ import { Component } from "react";
|
|
|
2
2
|
import type { ReactNode, ErrorInfo } from "react";
|
|
3
3
|
import Monoscope from ".";
|
|
4
4
|
import type { MonoscopeConfig, MonoscopeUser } from "./types";
|
|
5
|
-
|
|
6
|
-
config: MonoscopeConfig;
|
|
5
|
+
type ProviderProps = {
|
|
7
6
|
children: ReactNode;
|
|
8
|
-
}
|
|
7
|
+
} & ({
|
|
8
|
+
config: MonoscopeConfig;
|
|
9
|
+
} | ({
|
|
10
|
+
config?: undefined;
|
|
11
|
+
} & MonoscopeConfig));
|
|
12
|
+
export declare function MonoscopeProvider({ children, ...rest }: ProviderProps): import("react/jsx-runtime").JSX.Element;
|
|
9
13
|
export declare function useMonoscope(): Monoscope | null;
|
|
10
14
|
export declare function useMonoscopeUser(user: MonoscopeUser | null | undefined): void;
|
|
11
15
|
type ErrorBoundaryProps = {
|
package/dist/react.js
CHANGED
|
@@ -3,7 +3,8 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
3
3
|
import { createContext, useContext, useRef, useEffect, Component } from "react";
|
|
4
4
|
import Monoscope from ".";
|
|
5
5
|
const MonoscopeContext = createContext(null);
|
|
6
|
-
export function MonoscopeProvider({
|
|
6
|
+
export function MonoscopeProvider({ children, ...rest }) {
|
|
7
|
+
const config = rest.config ?? rest;
|
|
7
8
|
const ref = useRef(null);
|
|
8
9
|
if (!ref.current && typeof window !== "undefined") {
|
|
9
10
|
ref.current = new Monoscope(config);
|
package/dist/replay.js
CHANGED
|
@@ -128,7 +128,8 @@ export class MonoscopeReplay {
|
|
|
128
128
|
return;
|
|
129
129
|
this.trimEvents();
|
|
130
130
|
this.isSaving = true;
|
|
131
|
-
const
|
|
131
|
+
const apiKey = this.config.apiKey || this.config.projectId || "";
|
|
132
|
+
const baseUrl = `${this.config.replayEventsBaseUrl || "https://app.monoscope.tech"}/api/v1/rrweb`;
|
|
132
133
|
const eventsToSend = [...this.events];
|
|
133
134
|
this.events = [];
|
|
134
135
|
const payload = {
|
|
@@ -139,6 +140,7 @@ export class MonoscopeReplay {
|
|
|
139
140
|
eventCount: eventsToSend.length,
|
|
140
141
|
user: Object.keys(this.userAttributes).length > 0 ? this.userAttributes : undefined,
|
|
141
142
|
};
|
|
143
|
+
const headers = { "Content-Type": "application/json", "Authorization": `Bearer ${apiKey}` };
|
|
142
144
|
try {
|
|
143
145
|
if (forceSynchronous && typeof navigator !== "undefined" && navigator.sendBeacon) {
|
|
144
146
|
const blob = new Blob([JSON.stringify(payload)], {
|
|
@@ -148,7 +150,7 @@ export class MonoscopeReplay {
|
|
|
148
150
|
if (!sent) {
|
|
149
151
|
fetch(baseUrl, {
|
|
150
152
|
method: "POST",
|
|
151
|
-
headers
|
|
153
|
+
headers,
|
|
152
154
|
body: JSON.stringify(payload),
|
|
153
155
|
keepalive: true,
|
|
154
156
|
}).catch(() => { });
|
|
@@ -158,12 +160,19 @@ export class MonoscopeReplay {
|
|
|
158
160
|
const body = JSON.stringify(payload);
|
|
159
161
|
const response = await fetch(baseUrl, {
|
|
160
162
|
method: "POST",
|
|
161
|
-
headers
|
|
163
|
+
headers,
|
|
162
164
|
body,
|
|
163
165
|
keepalive: body.length < 63000,
|
|
164
166
|
});
|
|
165
167
|
if (!response.ok) {
|
|
166
|
-
|
|
168
|
+
const status = response.status;
|
|
169
|
+
if (status === 401 || status === 403) {
|
|
170
|
+
console.warn("[Monoscope] Replay upload authentication failed. Your apiKey may be invalid.");
|
|
171
|
+
}
|
|
172
|
+
else {
|
|
173
|
+
console.warn(`[Monoscope] Replay upload failed (${status}). Check your apiKey and network.`);
|
|
174
|
+
}
|
|
175
|
+
throw new Error(`Failed to save replay events: ${status} ${response.statusText}`);
|
|
167
176
|
}
|
|
168
177
|
if (this.config.debug) {
|
|
169
178
|
console.log(`Successfully saved ${eventsToSend.length} replay events`);
|
package/dist/tracing.d.ts
CHANGED
|
@@ -5,13 +5,16 @@ export declare class OpenTelemetryManager {
|
|
|
5
5
|
private sessionId;
|
|
6
6
|
private tabId;
|
|
7
7
|
private provider;
|
|
8
|
+
private processor;
|
|
8
9
|
private longTaskObserver;
|
|
9
10
|
private resourceObserver;
|
|
10
11
|
private _enabled;
|
|
11
12
|
private _configured;
|
|
13
|
+
private _firstExportLogged;
|
|
12
14
|
private pageSpan;
|
|
13
15
|
private pageContext;
|
|
14
16
|
private endPageSpanHandler;
|
|
17
|
+
onExportStatus: ((ok: boolean) => void) | null;
|
|
15
18
|
constructor(config: MonoscopeConfig, sessionId: string, tabId: string);
|
|
16
19
|
private createProvider;
|
|
17
20
|
private commonAttrs;
|
|
@@ -25,6 +28,7 @@ export declare class OpenTelemetryManager {
|
|
|
25
28
|
private observeResourceTiming;
|
|
26
29
|
startSpan<T>(name: string, fn: (span: Span) => T): T;
|
|
27
30
|
recordEvent(name: string, attributes?: Record<string, string | number | boolean>): void;
|
|
31
|
+
forceFlush(): Promise<void>;
|
|
28
32
|
updateSessionId(sessionId: string): void;
|
|
29
33
|
setEnabled(enabled: boolean): void;
|
|
30
34
|
shutdown(): Promise<void>;
|
package/dist/tracing.js
CHANGED
|
@@ -14,30 +14,65 @@ import { context, SpanStatusCode, trace } from "@opentelemetry/api";
|
|
|
14
14
|
const MONOSCOPE_TRACER = "monoscope";
|
|
15
15
|
export class OpenTelemetryManager {
|
|
16
16
|
constructor(config, sessionId, tabId) {
|
|
17
|
+
this.processor = null;
|
|
17
18
|
this.longTaskObserver = null;
|
|
18
19
|
this.resourceObserver = null;
|
|
19
20
|
this._enabled = true;
|
|
20
21
|
this._configured = false;
|
|
22
|
+
this._firstExportLogged = false;
|
|
21
23
|
this.pageSpan = null;
|
|
22
24
|
this.pageContext = null;
|
|
23
25
|
this.endPageSpanHandler = null;
|
|
26
|
+
this.onExportStatus = null;
|
|
24
27
|
this.config = config;
|
|
25
28
|
this.sessionId = sessionId;
|
|
26
29
|
this.tabId = tabId;
|
|
27
30
|
this.provider = this.createProvider();
|
|
28
31
|
}
|
|
29
32
|
createProvider() {
|
|
30
|
-
const { serviceName, resourceAttributes = {}, exporterEndpoint
|
|
33
|
+
const { serviceName, resourceAttributes = {}, exporterEndpoint } = this.config;
|
|
34
|
+
const apiKey = this.config.apiKey || this.config.projectId || "";
|
|
35
|
+
const self = this;
|
|
36
|
+
const realExporter = new OTLPTraceExporter({
|
|
37
|
+
url: exporterEndpoint || "https://otelcol.monoscope.tech/v1/traces",
|
|
38
|
+
headers: { "x-api-key": apiKey },
|
|
39
|
+
});
|
|
40
|
+
// Wrap exporter to capture export results for diagnostics
|
|
41
|
+
const wrappedExporter = Object.create(realExporter, {
|
|
42
|
+
export: {
|
|
43
|
+
value(spans, resultCallback) {
|
|
44
|
+
return realExporter.export(spans, (result) => {
|
|
45
|
+
if (!self._firstExportLogged) {
|
|
46
|
+
self._firstExportLogged = true;
|
|
47
|
+
const ok = result.code === 0;
|
|
48
|
+
if (self.config.debug) {
|
|
49
|
+
console.log(ok ? "%c[Monoscope] ✓ First trace sent successfully" : "%c[Monoscope] ✗ First trace export failed", ok ? "color: #22c55e; font-weight: bold" : "color: #ef4444; font-weight: bold", ok ? "" : result.error || "");
|
|
50
|
+
if (!ok) {
|
|
51
|
+
const msg = String(result.error || "");
|
|
52
|
+
if (msg.includes("401") || msg.includes("403")) {
|
|
53
|
+
console.warn("[Monoscope] Authentication failed. Your apiKey may be invalid.");
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
console.warn("[Monoscope] Could not reach Monoscope endpoint. Check your apiKey and network.");
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
self.onExportStatus?.(ok);
|
|
61
|
+
}
|
|
62
|
+
resultCallback(result);
|
|
63
|
+
});
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
});
|
|
67
|
+
const processor = new BatchSpanProcessor(wrappedExporter);
|
|
68
|
+
this.processor = processor;
|
|
31
69
|
return new WebTracerProvider({
|
|
32
70
|
resource: resourceFromAttributes({
|
|
33
71
|
[ATTR_SERVICE_NAME]: serviceName,
|
|
34
|
-
"
|
|
72
|
+
"x-api-key": apiKey,
|
|
35
73
|
...resourceAttributes,
|
|
36
74
|
}),
|
|
37
|
-
spanProcessors: [
|
|
38
|
-
url: exporterEndpoint || "https://otelcol.apitoolkit.io/v1/traces",
|
|
39
|
-
headers: {},
|
|
40
|
-
}))],
|
|
75
|
+
spanProcessors: [processor],
|
|
41
76
|
});
|
|
42
77
|
}
|
|
43
78
|
commonAttrs() {
|
|
@@ -225,6 +260,7 @@ export class OpenTelemetryManager {
|
|
|
225
260
|
recordEvent(name, attributes = {}) {
|
|
226
261
|
this.emitSpan(name, attributes);
|
|
227
262
|
}
|
|
263
|
+
async forceFlush() { await this.processor?.forceFlush(); }
|
|
228
264
|
updateSessionId(sessionId) { this.sessionId = sessionId; }
|
|
229
265
|
setEnabled(enabled) { this._enabled = enabled; }
|
|
230
266
|
async shutdown() {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"root":["../src/breadcrumbs.ts","../src/errors.ts","../src/index.ts","../src/react.tsx","../src/replay.ts","../src/router.ts","../src/tracing.ts","../src/types.ts","../src/web-vitals.ts"],"version":"5.9.3"}
|
|
1
|
+
{"root":["../src/breadcrumbs.ts","../src/errors.ts","../src/index.ts","../src/overlay.ts","../src/react.tsx","../src/replay.ts","../src/router.ts","../src/tracing.ts","../src/types.ts","../src/web-vitals.ts"],"version":"5.9.3"}
|
package/dist/types.d.ts
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import Monoscope from ".";
|
|
2
2
|
export type MonoscopeConfig = {
|
|
3
|
-
|
|
3
|
+
apiKey?: string;
|
|
4
|
+
serviceName?: string;
|
|
4
5
|
exporterEndpoint?: string;
|
|
5
6
|
propagateTraceHeaderCorsUrls?: RegExp[];
|
|
6
|
-
|
|
7
|
+
/** @deprecated Use `apiKey` instead. */
|
|
8
|
+
projectId?: string;
|
|
7
9
|
resourceAttributes?: Record<string, string>;
|
|
8
10
|
instrumentations?: unknown[];
|
|
9
11
|
replayEventsBaseUrl?: string;
|