@monoscopetech/browser 0.8.0 → 0.9.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/dist/errors.js CHANGED
@@ -21,7 +21,15 @@ export class ErrorTracker {
21
21
  createErrorSpan(spanName, errorType, attrs) {
22
22
  this.errorCount++;
23
23
  const crumbs = getBreadcrumbs();
24
- this.emit(spanName, { "error.type": errorType, "error.count": this.errorCount, ...attrs }, (s) => {
24
+ const name = String(attrs["error.name"] || errorType);
25
+ const msg = String(attrs["error.message"] || "").replace(/\s+/g, " ").slice(0, 80);
26
+ this.emit(spanName, {
27
+ "error.type": errorType,
28
+ "error.count": this.errorCount,
29
+ "monoscope.kind": "error",
30
+ "monoscope.display.label": msg ? `${name} · ${msg}` : name,
31
+ ...attrs,
32
+ }, (s) => {
25
33
  s.setStatus({ code: SpanStatusCode.ERROR });
26
34
  if (crumbs.length > 0)
27
35
  s.setAttribute("breadcrumbs", safeStringify(crumbs));
package/dist/index.d.ts CHANGED
@@ -17,6 +17,7 @@ declare class Monoscope {
17
17
  constructor(config: MonoscopeConfig);
18
18
  private logInitBanner;
19
19
  private resolveSessionId;
20
+ private resolveTabId;
20
21
  private persistActivity;
21
22
  private rotateSession;
22
23
  private checkAndRefreshSession;
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { MonoscopeReplay } from "./replay";
2
- import { OpenTelemetryManager } from "./tracing";
2
+ import { OpenTelemetryManager, newId } from "./tracing";
3
3
  import { ErrorTracker } from "./errors";
4
4
  import { WebVitalsCollector } from "./web-vitals";
5
5
  import { SPARouter } from "./router";
@@ -25,8 +25,8 @@ class Monoscope {
25
25
  config = { ...config, serviceName: isBrowser ? location.hostname : "unknown" };
26
26
  this.config = config;
27
27
  this._enabled = config.enabled !== false;
28
- this.tabId = crypto.randomUUID();
29
- this.sessionId = isBrowser ? this.resolveSessionId() : crypto.randomUUID();
28
+ this.tabId = isBrowser ? this.resolveTabId() : newId();
29
+ this.sessionId = isBrowser ? this.resolveSessionId() : newId();
30
30
  this.lastActivityTime = Date.now();
31
31
  if (isBrowser)
32
32
  this.persistActivity();
@@ -35,7 +35,7 @@ class Monoscope {
35
35
  const emit = (...args) => this.otel.emitSpan(...args);
36
36
  this.errors = new ErrorTracker(emit);
37
37
  this.vitals = new WebVitalsCollector(emit);
38
- this.router = new SPARouter(emit);
38
+ this.router = new SPARouter((from, to, method) => this.otel.startRouteChange(from, to, method));
39
39
  if (this._enabled) {
40
40
  this.otel.configure();
41
41
  this.replay.configure();
@@ -51,6 +51,7 @@ class Monoscope {
51
51
  if (isBrowser) {
52
52
  this.overlay = new DevOverlay();
53
53
  this.otel.onExportStatus = (ok) => this.overlay?.setConnectionStatus(ok);
54
+ this.otel.onSpanStart = () => this.overlay?.incrementEvents();
54
55
  }
55
56
  }
56
57
  if (isBrowser)
@@ -80,14 +81,29 @@ class Monoscope {
80
81
  if (elapsed < SESSION_TIMEOUT_MS)
81
82
  return storedId;
82
83
  }
83
- const newId = crypto.randomUUID();
84
- sessionStorage.setItem("monoscope-session-id", newId);
85
- return newId;
84
+ const id = newId();
85
+ sessionStorage.setItem("monoscope-session-id", id);
86
+ return id;
86
87
  }
87
88
  catch (e) {
88
89
  if (this.config.debug)
89
90
  console.warn("Monoscope: sessionStorage unavailable, using ephemeral session", e);
90
- return crypto.randomUUID();
91
+ return newId();
92
+ }
93
+ }
94
+ // sessionStorage is tab-scoped, so a persisted id naturally identifies a
95
+ // single tab across MPA navigations and SPA reloads.
96
+ resolveTabId() {
97
+ try {
98
+ const existing = sessionStorage.getItem("monoscope-tab-id");
99
+ if (existing)
100
+ return existing;
101
+ const id = newId();
102
+ sessionStorage.setItem("monoscope-tab-id", id);
103
+ return id;
104
+ }
105
+ catch {
106
+ return newId();
91
107
  }
92
108
  }
93
109
  persistActivity() {
@@ -105,7 +121,7 @@ class Monoscope {
105
121
  console.warn("Monoscope: failed to save replay on session rotation", e);
106
122
  });
107
123
  clearBreadcrumbs();
108
- this.sessionId = crypto.randomUUID();
124
+ this.sessionId = newId();
109
125
  try {
110
126
  sessionStorage.setItem("monoscope-session-id", this.sessionId);
111
127
  }
@@ -167,12 +183,10 @@ class Monoscope {
167
183
  this.replay.setUser(u);
168
184
  }
169
185
  startSpan(name, fn) {
170
- this.overlay?.incrementEvents();
171
186
  return this.otel.startSpan(name, fn);
172
187
  }
173
188
  recordEvent(name, attributes) {
174
189
  this.otel.recordEvent(name, attributes);
175
- this.overlay?.incrementEvents();
176
190
  }
177
191
  async test() {
178
192
  try {