@watchforge/browser 0.1.22 → 0.1.23

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@watchforge/browser",
3
- "version": "0.1.22",
3
+ "version": "0.1.23",
4
4
  "main": "./src/index.js",
5
5
  "types": "./src/index.d.ts",
6
6
  "description": "WatchForge JavaScript SDK for browser JavaScript, Next.js, React, Node.js, and Express.js",
package/src/client.js CHANGED
@@ -627,7 +627,7 @@ function setupBrowserInstrumentation() {
627
627
  }
628
628
  }
629
629
 
630
- import { initTracing } from "./tracing.js";
630
+ import { getCurrentTransaction, initTracing, setupBrowserTracing } from "./tracing.js";
631
631
 
632
632
  async function buildEventContexts(context = {}) {
633
633
  const runtime = getRuntimeContext();
@@ -670,6 +670,7 @@ export function register({
670
670
  captureNodeWarnings = false,
671
671
  captureNodeMultipleResolves = false,
672
672
  projectRoot = null,
673
+ tracesSampleRate = 1,
673
674
  }) {
674
675
  const nextBrowserRegisterKey = isBrowser
675
676
  ? JSON.stringify({
@@ -711,7 +712,7 @@ export function register({
711
712
  );
712
713
 
713
714
  // Initialize tracing
714
- initTracing(dsn, app_env, debug);
715
+ initTracing(dsn, app_env, debug, tracesSampleRate);
715
716
 
716
717
  if (DEBUG) {
717
718
  // Parse DSN to show API URL in debug
@@ -736,6 +737,7 @@ export function register({
736
737
  if (isBrowser) {
737
738
  browserRegisterKey = nextBrowserRegisterKey;
738
739
  setupBrowserInstrumentation();
740
+ setupBrowserTracing(getPageContext);
739
741
  replayInitPromise = initReplay({
740
742
  replaysSessionSampleRate,
741
743
  replaysOnErrorSampleRate,
@@ -831,6 +833,7 @@ export async function captureException(error, context = {}) {
831
833
  );
832
834
  }
833
835
 
836
+ const currentTransaction = getCurrentTransaction();
834
837
  const event = {
835
838
  event_id: generateEventId(),
836
839
  level: "error",
@@ -842,6 +845,11 @@ export async function captureException(error, context = {}) {
842
845
  sdk: getSdkMetadata(),
843
846
  };
844
847
 
848
+ if (currentTransaction?.trace_id) {
849
+ event.trace_id = currentTransaction.trace_id;
850
+ event.transaction = currentTransaction.transaction;
851
+ }
852
+
845
853
  if (isBrowser && replayInitPromise) {
846
854
  try {
847
855
  await replayInitPromise;
package/src/tracing.js CHANGED
@@ -3,14 +3,31 @@
3
3
  let DSN = null;
4
4
  let APP_ENV = "production";
5
5
  let DEBUG = false;
6
+ let TRACES_SAMPLE_RATE = 1;
6
7
 
7
8
  // Active transaction stack (for nested transactions)
8
9
  const transactionStack = [];
9
-
10
- export function initTracing(dsn, environment = "production", debug = false) {
10
+ let activePageTransaction = null;
11
+ let browserTracingInstalled = false;
12
+ let navigationFinishTimer = null;
13
+
14
+ export function initTracing(
15
+ dsn,
16
+ environment = "production",
17
+ debug = false,
18
+ tracesSampleRate = 1
19
+ ) {
11
20
  DSN = dsn;
12
21
  APP_ENV = environment;
13
22
  DEBUG = debug;
23
+ TRACES_SAMPLE_RATE =
24
+ typeof tracesSampleRate === "number" && tracesSampleRate >= 0 && tracesSampleRate <= 1
25
+ ? tracesSampleRate
26
+ : 1;
27
+ }
28
+
29
+ function shouldSampleTrace() {
30
+ return TRACES_SAMPLE_RATE >= 1 || Math.random() < TRACES_SAMPLE_RATE;
14
31
  }
15
32
 
16
33
  class Span {
@@ -250,4 +267,73 @@ export function finishTransaction(status = "ok") {
250
267
  return null;
251
268
  }
252
269
 
270
+ function endPageTransaction(status = "ok") {
271
+ if (navigationFinishTimer) {
272
+ clearTimeout(navigationFinishTimer);
273
+ navigationFinishTimer = null;
274
+ }
275
+ if (!activePageTransaction) return;
276
+ activePageTransaction.finish(status);
277
+ if (transactionStack[transactionStack.length - 1] === activePageTransaction) {
278
+ transactionStack.pop();
279
+ }
280
+ activePageTransaction = null;
281
+ }
282
+
283
+ function beginPageTransaction(op, getPageContext) {
284
+ if (!shouldSampleTrace()) return null;
285
+
286
+ const page = typeof getPageContext === "function" ? getPageContext() : null;
287
+ const path = page?.pathname || (typeof window !== "undefined" ? window.location.pathname : "/");
288
+ const name = page?.title || (typeof document !== "undefined" ? document.title : path) || path;
289
+ const txn = startTransaction(path, name, op);
290
+ txn.setRequest({
291
+ url: page?.url || (typeof window !== "undefined" ? window.location.href : path),
292
+ method: "GET",
293
+ });
294
+ activePageTransaction = txn;
295
+ return txn;
296
+ }
297
+
298
+ function schedulePageTransactionFinish(delayMs = 5000) {
299
+ if (navigationFinishTimer) clearTimeout(navigationFinishTimer);
300
+ navigationFinishTimer = setTimeout(() => {
301
+ endPageTransaction();
302
+ navigationFinishTimer = null;
303
+ }, delayMs);
304
+ }
305
+
306
+ export function setupBrowserTracing(getPageContext) {
307
+ if (typeof window === "undefined" || browserTracingInstalled) return;
308
+ browserTracingInstalled = true;
309
+
310
+ beginPageTransaction("pageload", getPageContext);
311
+
312
+ if (document.readyState === "complete") {
313
+ endPageTransaction();
314
+ } else {
315
+ window.addEventListener("load", () => endPageTransaction(), { once: true });
316
+ }
317
+
318
+ const onNavigation = () => {
319
+ endPageTransaction();
320
+ if (!beginPageTransaction("navigation", getPageContext)) return;
321
+ schedulePageTransactionFinish();
322
+ };
323
+
324
+ const originalPushState = history.pushState;
325
+ history.pushState = function (...args) {
326
+ originalPushState.apply(history, args);
327
+ onNavigation();
328
+ };
329
+
330
+ const originalReplaceState = history.replaceState;
331
+ history.replaceState = function (...args) {
332
+ originalReplaceState.apply(history, args);
333
+ onNavigation();
334
+ };
335
+
336
+ window.addEventListener("hashchange", onNavigation);
337
+ }
338
+
253
339
  export { Transaction, Span };