@tracewayapp/frontend 1.0.1 → 1.0.3

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/index.d.mts CHANGED
@@ -34,10 +34,20 @@ declare function formatBrowserStackTrace(error: Error): string;
34
34
 
35
35
  declare function installGlobalHandlers(client: TracewayFrontendClient): void;
36
36
 
37
+ declare function getActiveDistributedTraceId(): string | null;
38
+
37
39
  declare function init(connectionString: string, options?: TracewayFrontendOptions): void;
38
- declare function captureException(error: Error): void;
39
- declare function captureExceptionWithAttributes(error: Error, attributes?: Record<string, string>): void;
40
+ declare function captureException(error: Error, options?: {
41
+ distributedTraceId?: string;
42
+ }): void;
43
+ declare function captureExceptionWithAttributes(error: Error, attributes?: Record<string, string>, options?: {
44
+ distributedTraceId?: string;
45
+ }): void;
40
46
  declare function captureMessage(msg: string): void;
41
47
  declare function flush(timeoutMs?: number): Promise<void>;
42
48
 
43
- export { TracewayFrontendClient, type TracewayFrontendOptions, captureException, captureExceptionWithAttributes, captureMessage, flush, formatBrowserStackTrace, init, installGlobalHandlers };
49
+ declare const DISTRIBUTED_TRACE_HEADER = "traceway-trace-id";
50
+
51
+ declare function createAxiosInterceptor(): (config: any) => any;
52
+
53
+ export { DISTRIBUTED_TRACE_HEADER, TracewayFrontendClient, type TracewayFrontendOptions, captureException, captureExceptionWithAttributes, captureMessage, createAxiosInterceptor, flush, formatBrowserStackTrace, getActiveDistributedTraceId, init, installGlobalHandlers };
package/dist/index.d.ts CHANGED
@@ -34,10 +34,20 @@ declare function formatBrowserStackTrace(error: Error): string;
34
34
 
35
35
  declare function installGlobalHandlers(client: TracewayFrontendClient): void;
36
36
 
37
+ declare function getActiveDistributedTraceId(): string | null;
38
+
37
39
  declare function init(connectionString: string, options?: TracewayFrontendOptions): void;
38
- declare function captureException(error: Error): void;
39
- declare function captureExceptionWithAttributes(error: Error, attributes?: Record<string, string>): void;
40
+ declare function captureException(error: Error, options?: {
41
+ distributedTraceId?: string;
42
+ }): void;
43
+ declare function captureExceptionWithAttributes(error: Error, attributes?: Record<string, string>, options?: {
44
+ distributedTraceId?: string;
45
+ }): void;
40
46
  declare function captureMessage(msg: string): void;
41
47
  declare function flush(timeoutMs?: number): Promise<void>;
42
48
 
43
- export { TracewayFrontendClient, type TracewayFrontendOptions, captureException, captureExceptionWithAttributes, captureMessage, flush, formatBrowserStackTrace, init, installGlobalHandlers };
49
+ declare const DISTRIBUTED_TRACE_HEADER = "traceway-trace-id";
50
+
51
+ declare function createAxiosInterceptor(): (config: any) => any;
52
+
53
+ export { DISTRIBUTED_TRACE_HEADER, TracewayFrontendClient, type TracewayFrontendOptions, captureException, captureExceptionWithAttributes, captureMessage, createAxiosInterceptor, flush, formatBrowserStackTrace, getActiveDistributedTraceId, init, installGlobalHandlers };
package/dist/index.js CHANGED
@@ -20,17 +20,20 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/index.ts
21
21
  var index_exports = {};
22
22
  __export(index_exports, {
23
+ DISTRIBUTED_TRACE_HEADER: () => DISTRIBUTED_TRACE_HEADER,
23
24
  TracewayFrontendClient: () => TracewayFrontendClient,
24
25
  captureException: () => captureException,
25
26
  captureExceptionWithAttributes: () => captureExceptionWithAttributes,
26
27
  captureMessage: () => captureMessage,
28
+ createAxiosInterceptor: () => createAxiosInterceptor,
27
29
  flush: () => flush,
28
30
  formatBrowserStackTrace: () => formatBrowserStackTrace,
31
+ getActiveDistributedTraceId: () => getActiveDistributedTraceId,
29
32
  init: () => init,
30
33
  installGlobalHandlers: () => installGlobalHandlers
31
34
  });
32
35
  module.exports = __toCommonJS(index_exports);
33
- var import_core3 = require("@tracewayapp/core");
36
+ var import_core5 = require("@tracewayapp/core");
34
37
 
35
38
  // src/client.ts
36
39
  var import_core = require("@tracewayapp/core");
@@ -331,7 +334,52 @@ function shortenFilePath(filePath) {
331
334
  }
332
335
 
333
336
  // src/global-handlers.ts
337
+ var import_core3 = require("@tracewayapp/core");
338
+
339
+ // src/fetch-instrumentation.ts
334
340
  var import_core2 = require("@tracewayapp/core");
341
+ var activeDistributedTraceId = null;
342
+ function getActiveDistributedTraceId() {
343
+ return activeDistributedTraceId;
344
+ }
345
+ function setActiveDistributedTraceId(id) {
346
+ activeDistributedTraceId = id;
347
+ }
348
+ function clearActiveDistributedTraceId(traceId) {
349
+ if (activeDistributedTraceId === traceId) {
350
+ activeDistributedTraceId = null;
351
+ }
352
+ }
353
+ function isSameOrigin(input) {
354
+ try {
355
+ const url = new URL(
356
+ typeof input === "string" ? input : input instanceof Request ? input.url : input.href,
357
+ window.location.origin
358
+ );
359
+ return url.origin === window.location.origin;
360
+ } catch {
361
+ return true;
362
+ }
363
+ }
364
+ function installFetchInstrumentation() {
365
+ const originalFetch = window.fetch;
366
+ window.fetch = function(input, init2) {
367
+ if (!isSameOrigin(input)) {
368
+ return originalFetch.call(this, input, init2);
369
+ }
370
+ const traceId = (0, import_core2.generateUUID)();
371
+ activeDistributedTraceId = traceId;
372
+ const headers = new Headers(init2?.headers);
373
+ headers.set("traceway-trace-id", traceId);
374
+ return originalFetch.call(this, input, { ...init2, headers }).finally(() => {
375
+ if (activeDistributedTraceId === traceId) {
376
+ activeDistributedTraceId = null;
377
+ }
378
+ });
379
+ };
380
+ }
381
+
382
+ // src/global-handlers.ts
335
383
  function installGlobalHandlers(client2) {
336
384
  const prevOnError = window.onerror;
337
385
  window.onerror = (message, source, lineno, colno, error) => {
@@ -339,15 +387,17 @@ function installGlobalHandlers(client2) {
339
387
  client2.addException({
340
388
  traceId: null,
341
389
  stackTrace: formatBrowserStackTrace(error),
342
- recordedAt: (0, import_core2.nowISO)(),
343
- isMessage: false
390
+ recordedAt: (0, import_core3.nowISO)(),
391
+ isMessage: false,
392
+ distributedTraceId: getActiveDistributedTraceId()
344
393
  });
345
394
  } else {
346
395
  client2.addException({
347
396
  traceId: null,
348
397
  stackTrace: String(message),
349
- recordedAt: (0, import_core2.nowISO)(),
350
- isMessage: false
398
+ recordedAt: (0, import_core3.nowISO)(),
399
+ isMessage: false,
400
+ distributedTraceId: getActiveDistributedTraceId()
351
401
  });
352
402
  }
353
403
  if (typeof prevOnError === "function") {
@@ -362,15 +412,17 @@ function installGlobalHandlers(client2) {
362
412
  client2.addException({
363
413
  traceId: null,
364
414
  stackTrace: formatBrowserStackTrace(reason),
365
- recordedAt: (0, import_core2.nowISO)(),
366
- isMessage: false
415
+ recordedAt: (0, import_core3.nowISO)(),
416
+ isMessage: false,
417
+ distributedTraceId: getActiveDistributedTraceId()
367
418
  });
368
419
  } else {
369
420
  client2.addException({
370
421
  traceId: null,
371
422
  stackTrace: String(reason),
372
- recordedAt: (0, import_core2.nowISO)(),
373
- isMessage: false
423
+ recordedAt: (0, import_core3.nowISO)(),
424
+ isMessage: false,
425
+ distributedTraceId: getActiveDistributedTraceId()
374
426
  });
375
427
  }
376
428
  if (typeof prevOnUnhandledRejection === "function") {
@@ -379,31 +431,71 @@ function installGlobalHandlers(client2) {
379
431
  };
380
432
  }
381
433
 
434
+ // src/xhr-instrumentation.ts
435
+ var import_core4 = require("@tracewayapp/core");
436
+ function isSameOriginUrl(url) {
437
+ try {
438
+ const resolved = new URL(url, window.location.origin);
439
+ return resolved.origin === window.location.origin;
440
+ } catch {
441
+ return true;
442
+ }
443
+ }
444
+ function installXhrInstrumentation() {
445
+ const originalOpen = XMLHttpRequest.prototype.open;
446
+ const originalSend = XMLHttpRequest.prototype.send;
447
+ XMLHttpRequest.prototype.open = function(method, url, ...rest) {
448
+ this._tracewaySameOrigin = isSameOriginUrl(String(url));
449
+ return originalOpen.apply(this, [method, url, ...rest]);
450
+ };
451
+ XMLHttpRequest.prototype.send = function(body) {
452
+ if (this._tracewaySameOrigin) {
453
+ const traceId = (0, import_core4.generateUUID)();
454
+ setActiveDistributedTraceId(traceId);
455
+ this.setRequestHeader("traceway-trace-id", traceId);
456
+ const onComplete = () => {
457
+ clearActiveDistributedTraceId(traceId);
458
+ this.removeEventListener("load", onComplete);
459
+ this.removeEventListener("error", onComplete);
460
+ this.removeEventListener("abort", onComplete);
461
+ };
462
+ this.addEventListener("load", onComplete);
463
+ this.addEventListener("error", onComplete);
464
+ this.addEventListener("abort", onComplete);
465
+ }
466
+ return originalSend.call(this, body);
467
+ };
468
+ }
469
+
382
470
  // src/index.ts
383
471
  var client = null;
384
472
  function init(connectionString, options = {}) {
385
473
  client = new TracewayFrontendClient(connectionString, options);
386
474
  if (typeof window !== "undefined") {
387
475
  installGlobalHandlers(client);
476
+ installFetchInstrumentation();
477
+ installXhrInstrumentation();
388
478
  }
389
479
  }
390
- function captureException(error) {
480
+ function captureException(error, options) {
391
481
  if (!client) return;
392
482
  client.addException({
393
483
  traceId: null,
394
484
  stackTrace: formatBrowserStackTrace(error),
395
- recordedAt: (0, import_core3.nowISO)(),
396
- isMessage: false
485
+ recordedAt: (0, import_core5.nowISO)(),
486
+ isMessage: false,
487
+ distributedTraceId: options?.distributedTraceId ?? getActiveDistributedTraceId()
397
488
  });
398
489
  }
399
- function captureExceptionWithAttributes(error, attributes) {
490
+ function captureExceptionWithAttributes(error, attributes, options) {
400
491
  if (!client) return;
401
492
  client.addException({
402
493
  traceId: null,
403
494
  stackTrace: formatBrowserStackTrace(error),
404
- recordedAt: (0, import_core3.nowISO)(),
495
+ recordedAt: (0, import_core5.nowISO)(),
405
496
  attributes,
406
- isMessage: false
497
+ isMessage: false,
498
+ distributedTraceId: options?.distributedTraceId ?? getActiveDistributedTraceId()
407
499
  });
408
500
  }
409
501
  function captureMessage(msg) {
@@ -411,7 +503,7 @@ function captureMessage(msg) {
411
503
  client.addException({
412
504
  traceId: null,
413
505
  stackTrace: msg,
414
- recordedAt: (0, import_core3.nowISO)(),
506
+ recordedAt: (0, import_core5.nowISO)(),
415
507
  isMessage: true
416
508
  });
417
509
  }
@@ -419,4 +511,12 @@ async function flush(timeoutMs) {
419
511
  if (!client) return;
420
512
  await client.flush(timeoutMs);
421
513
  }
514
+ var DISTRIBUTED_TRACE_HEADER = "traceway-trace-id";
515
+ function createAxiosInterceptor() {
516
+ return (config) => {
517
+ config.headers = config.headers || {};
518
+ config.headers["traceway-trace-id"] = (0, import_core5.generateUUID)();
519
+ return config;
520
+ };
521
+ }
422
522
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/client.ts","../src/transport.ts","../src/session-recorder.ts","../src/stack-trace.ts","../src/global-handlers.ts"],"sourcesContent":["import { nowISO } from \"@tracewayapp/core\";\nimport type { ExceptionStackTrace } from \"@tracewayapp/core\";\nimport {\n TracewayFrontendClient,\n type TracewayFrontendOptions,\n} from \"./client.js\";\nimport { formatBrowserStackTrace } from \"./stack-trace.js\";\nimport { installGlobalHandlers } from \"./global-handlers.js\";\n\nlet client: TracewayFrontendClient | null = null;\n\nexport function init(\n connectionString: string,\n options: TracewayFrontendOptions = {},\n): void {\n client = new TracewayFrontendClient(connectionString, options);\n if (typeof window !== \"undefined\") {\n installGlobalHandlers(client);\n }\n}\n\nexport function captureException(error: Error): void {\n if (!client) return;\n client.addException({\n traceId: null,\n stackTrace: formatBrowserStackTrace(error),\n recordedAt: nowISO(),\n isMessage: false,\n });\n}\n\nexport function captureExceptionWithAttributes(\n error: Error,\n attributes?: Record<string, string>,\n): void {\n if (!client) return;\n client.addException({\n traceId: null,\n stackTrace: formatBrowserStackTrace(error),\n recordedAt: nowISO(),\n attributes,\n isMessage: false,\n });\n}\n\nexport function captureMessage(msg: string): void {\n if (!client) return;\n client.addException({\n traceId: null,\n stackTrace: msg,\n recordedAt: nowISO(),\n isMessage: true,\n });\n}\n\nexport async function flush(timeoutMs?: number): Promise<void> {\n if (!client) return;\n await client.flush(timeoutMs);\n}\n\nexport { TracewayFrontendClient } from \"./client.js\";\nexport type { TracewayFrontendOptions } from \"./client.js\";\nexport { formatBrowserStackTrace } from \"./stack-trace.js\";\nexport { installGlobalHandlers } from \"./global-handlers.js\";\n\nexport type {\n ExceptionStackTrace,\n CollectionFrame,\n ReportRequest,\n} from \"@tracewayapp/core\";\n","import type {\n ExceptionStackTrace,\n ReportRequest,\n CollectionFrame,\n SessionRecordingPayload,\n} from \"@tracewayapp/core\";\nimport { parseConnectionString, generateUUID } from \"@tracewayapp/core\";\nimport { sendReport } from \"./transport.js\";\nimport { SessionRecorder } from \"./session-recorder.js\";\n\nexport interface TracewayFrontendOptions {\n debug?: boolean;\n debounceMs?: number;\n retryDelayMs?: number;\n version?: string;\n sessionRecording?: boolean;\n sessionRecordingSegmentDuration?: number;\n}\n\nexport class TracewayFrontendClient {\n private apiUrl: string;\n private token: string;\n private debug: boolean;\n private debounceMs: number;\n private retryDelayMs: number;\n private version: string;\n\n private pendingExceptions: ExceptionStackTrace[] = [];\n private pendingRecordings: SessionRecordingPayload[] = [];\n private isSyncing = false;\n private debounceTimer: ReturnType<typeof setTimeout> | null = null;\n private retryTimer: ReturnType<typeof setTimeout> | null = null;\n\n private recorder: SessionRecorder | null = null;\n\n constructor(connectionString: string, options: TracewayFrontendOptions = {}) {\n const { token, apiUrl } = parseConnectionString(connectionString);\n this.apiUrl = apiUrl;\n this.token = token;\n this.debug = options.debug ?? false;\n this.debounceMs = options.debounceMs ?? 1500;\n this.retryDelayMs = options.retryDelayMs ?? 10000;\n this.version = options.version ?? \"\";\n\n if (options.sessionRecording !== false && typeof window !== \"undefined\") {\n this.recorder = new SessionRecorder({\n segmentDuration: options.sessionRecordingSegmentDuration,\n });\n this.recorder.start();\n }\n }\n\n addException(exception: ExceptionStackTrace): void {\n if (this.recorder && this.recorder.hasSegments()) {\n const segments = this.recorder.getSegments();\n const allEvents = segments.flatMap((s) => s.events);\n const exceptionId = generateUUID();\n exception.sessionRecordingId = exceptionId;\n this.pendingRecordings.push({ exceptionId, events: allEvents });\n }\n\n this.pendingExceptions.push(exception);\n this.scheduleSync();\n }\n\n private scheduleSync(): void {\n if (this.debounceTimer !== null) {\n clearTimeout(this.debounceTimer);\n }\n this.debounceTimer = setTimeout(() => {\n this.debounceTimer = null;\n this.doSync();\n }, this.debounceMs);\n }\n\n private async doSync(): Promise<void> {\n if (this.isSyncing) return;\n if (this.pendingExceptions.length === 0) return;\n\n this.isSyncing = true;\n const batch = this.pendingExceptions.splice(0);\n const recordings = this.pendingRecordings.splice(0);\n\n const frame: CollectionFrame = {\n stackTraces: batch,\n metrics: [],\n traces: [],\n sessionRecordings: recordings.length > 0 ? recordings : undefined,\n };\n\n const payload: ReportRequest = {\n collectionFrames: [frame],\n appVersion: this.version,\n serverName: \"\",\n };\n\n let failed = false;\n try {\n const success = await sendReport(\n this.apiUrl,\n this.token,\n JSON.stringify(payload),\n );\n if (!success) {\n failed = true;\n this.pendingExceptions.unshift(...batch);\n this.pendingRecordings.unshift(...recordings);\n if (this.debug) {\n console.error(\"Traceway: sync failed, re-queued exceptions\");\n }\n }\n } catch (err) {\n failed = true;\n this.pendingExceptions.unshift(...batch);\n this.pendingRecordings.unshift(...recordings);\n if (this.debug) {\n console.error(\"Traceway: sync error:\", err);\n }\n } finally {\n this.isSyncing = false;\n if (this.pendingExceptions.length > 0) {\n if (failed) {\n this.scheduleRetry();\n } else {\n this.doSync();\n }\n }\n }\n }\n\n private scheduleRetry(): void {\n if (this.retryTimer !== null) return;\n this.retryTimer = setTimeout(() => {\n this.retryTimer = null;\n this.doSync();\n }, this.retryDelayMs);\n }\n\n async flush(timeoutMs?: number): Promise<void> {\n if (this.debounceTimer !== null) {\n clearTimeout(this.debounceTimer);\n this.debounceTimer = null;\n }\n if (this.retryTimer !== null) {\n clearTimeout(this.retryTimer);\n this.retryTimer = null;\n }\n if (this.recorder) {\n this.recorder.stop();\n }\n\n const syncPromise = this.doSync();\n\n if (timeoutMs !== undefined) {\n await Promise.race([\n syncPromise,\n new Promise<void>((resolve) => setTimeout(resolve, timeoutMs)),\n ]);\n } else {\n await syncPromise;\n }\n }\n}\n","export async function compressGzip(data: string): Promise<Uint8Array> {\n const encoder = new TextEncoder();\n const inputBytes = encoder.encode(data);\n\n const cs = new CompressionStream(\"gzip\");\n const writer = cs.writable.getWriter();\n writer.write(inputBytes);\n writer.close();\n\n const reader = cs.readable.getReader();\n const chunks: Uint8Array[] = [];\n let totalLength = 0;\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n chunks.push(value);\n totalLength += value.length;\n }\n\n const result = new Uint8Array(totalLength);\n let offset = 0;\n for (const chunk of chunks) {\n result.set(chunk, offset);\n offset += chunk.length;\n }\n\n return result;\n}\n\nexport async function sendReport(\n apiUrl: string,\n token: string,\n body: string,\n): Promise<boolean> {\n const compressed = await compressGzip(body);\n\n const resp = await fetch(apiUrl, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"Content-Encoding\": \"gzip\",\n Authorization: `Bearer ${token}`,\n },\n body: compressed,\n });\n\n return resp.status === 200;\n}\n","import type { eventWithTime } from \"rrweb\";\nimport { record } from \"rrweb\";\n\nexport interface SessionRecorderOptions {\n segmentDuration?: number;\n}\n\ninterface Segment {\n events: eventWithTime[];\n startedAt: string;\n}\n\nexport class SessionRecorder {\n private segmentDuration: number;\n private current: Segment;\n private previous: Segment | null = null;\n private stopFn: (() => void) | null = null;\n private rotateInterval: ReturnType<typeof setInterval> | null = null;\n\n constructor(options: SessionRecorderOptions = {}) {\n this.segmentDuration = options.segmentDuration ?? 10_000;\n this.current = { events: [], startedAt: new Date().toISOString() };\n }\n\n start(): void {\n this.stopFn = record({\n emit: (event) => {\n this.onEvent(event);\n },\n });\n\n this.rotateInterval = setInterval(() => {\n this.rotateSegment();\n }, this.segmentDuration);\n }\n\n stop(): void {\n if (this.stopFn) {\n this.stopFn();\n this.stopFn = null;\n }\n if (this.rotateInterval) {\n clearInterval(this.rotateInterval);\n this.rotateInterval = null;\n }\n }\n\n private onEvent(event: eventWithTime): void {\n this.current.events.push(event);\n }\n\n private rotateSegment(): void {\n this.previous = this.current;\n this.current = { events: [], startedAt: new Date().toISOString() };\n record.takeFullSnapshot();\n }\n\n getSegments(): { events: eventWithTime[]; timestamp: string }[] {\n const segments: { events: eventWithTime[]; timestamp: string }[] = [];\n if (this.previous && this.previous.events.length > 0) {\n segments.push({\n events: this.previous.events,\n timestamp: this.previous.startedAt,\n });\n }\n if (this.current.events.length > 0) {\n segments.push({\n events: this.current.events,\n timestamp: this.current.startedAt,\n });\n }\n return segments;\n }\n\n hasSegments(): boolean {\n return (\n this.current.events.length > 0 ||\n (this.previous !== null && this.previous.events.length > 0)\n );\n }\n\n flush(): void {\n this.previous = null;\n this.current = { events: [], startedAt: new Date().toISOString() };\n if (this.stopFn) {\n record.takeFullSnapshot();\n }\n }\n}\n","export function formatBrowserStackTrace(error: Error): string {\n const lines: string[] = [];\n const typeName = error.constructor?.name || \"Error\";\n lines.push(`${typeName}: ${error.message}`);\n\n if (error.stack) {\n const stackLines = error.stack.split(\"\\n\");\n for (const line of stackLines) {\n // V8 format: \" at funcName (file:line:col)\"\n const v8Match = line.match(/^\\s+at\\s+(.+?)\\s+\\((.+):(\\d+):(\\d+)\\)$/);\n if (v8Match) {\n const funcName = shortenFunctionName(v8Match[1]);\n const file = shortenFilePath(v8Match[2]);\n lines.push(`${funcName}()`);\n lines.push(` ${file}:${v8Match[3]}:${v8Match[4]}`);\n continue;\n }\n\n // V8 anonymous: \" at file:line:col\"\n const v8AnonMatch = line.match(/^\\s+at\\s+(.+):(\\d+):(\\d+)$/);\n if (v8AnonMatch) {\n const file = shortenFilePath(v8AnonMatch[1]);\n lines.push(`<anonymous>()`);\n lines.push(` ${file}:${v8AnonMatch[2]}:${v8AnonMatch[3]}`);\n continue;\n }\n\n // Firefox format: \"funcName@file:line:col\"\n const ffMatch = line.match(/^(.+)@(.+):(\\d+):(\\d+)$/);\n if (ffMatch) {\n const funcName = shortenFunctionName(ffMatch[1]) || \"<anonymous>\";\n const file = shortenFilePath(ffMatch[2]);\n lines.push(`${funcName}()`);\n lines.push(` ${file}:${ffMatch[3]}:${ffMatch[4]}`);\n continue;\n }\n\n // Firefox anonymous: \"@file:line:col\"\n const ffAnonMatch = line.match(/^@(.+):(\\d+):(\\d+)$/);\n if (ffAnonMatch) {\n const file = shortenFilePath(ffAnonMatch[1]);\n lines.push(`<anonymous>()`);\n lines.push(` ${file}:${ffAnonMatch[2]}:${ffAnonMatch[3]}`);\n continue;\n }\n }\n }\n\n return lines.join(\"\\n\") + \"\\n\";\n}\n\nfunction shortenFunctionName(fn: string): string {\n const slashIdx = fn.lastIndexOf(\"/\");\n if (slashIdx >= 0) {\n fn = fn.slice(slashIdx + 1);\n }\n const dotIdx = fn.indexOf(\".\");\n if (dotIdx >= 0) {\n fn = fn.slice(dotIdx + 1);\n }\n return fn;\n}\n\nfunction shortenFilePath(filePath: string): string {\n const parts = filePath.split(\"/\");\n return parts[parts.length - 1];\n}\n","import type { TracewayFrontendClient } from \"./client.js\";\nimport { formatBrowserStackTrace } from \"./stack-trace.js\";\nimport { nowISO } from \"@tracewayapp/core\";\n\nexport function installGlobalHandlers(client: TracewayFrontendClient): void {\n const prevOnError = window.onerror;\n window.onerror = (message, source, lineno, colno, error) => {\n if (error) {\n client.addException({\n traceId: null,\n stackTrace: formatBrowserStackTrace(error),\n recordedAt: nowISO(),\n isMessage: false,\n });\n } else {\n client.addException({\n traceId: null,\n stackTrace: String(message),\n recordedAt: nowISO(),\n isMessage: false,\n });\n }\n if (typeof prevOnError === \"function\") {\n return prevOnError(message, source, lineno, colno, error);\n }\n return false;\n };\n\n const prevOnUnhandledRejection = window.onunhandledrejection;\n window.onunhandledrejection = (event: PromiseRejectionEvent) => {\n const reason = event.reason;\n if (reason instanceof Error) {\n client.addException({\n traceId: null,\n stackTrace: formatBrowserStackTrace(reason),\n recordedAt: nowISO(),\n isMessage: false,\n });\n } else {\n client.addException({\n traceId: null,\n stackTrace: String(reason),\n recordedAt: nowISO(),\n isMessage: false,\n });\n }\n if (typeof prevOnUnhandledRejection === \"function\") {\n prevOnUnhandledRejection.call(window, event);\n }\n };\n}\n"],"mappings":"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","names":["import_core","import_core","client"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/client.ts","../src/transport.ts","../src/session-recorder.ts","../src/stack-trace.ts","../src/global-handlers.ts","../src/fetch-instrumentation.ts","../src/xhr-instrumentation.ts"],"sourcesContent":["import { nowISO, generateUUID } from \"@tracewayapp/core\";\nimport type { ExceptionStackTrace } from \"@tracewayapp/core\";\nimport {\n TracewayFrontendClient,\n type TracewayFrontendOptions,\n} from \"./client.js\";\nimport { formatBrowserStackTrace } from \"./stack-trace.js\";\nimport { installGlobalHandlers } from \"./global-handlers.js\";\nimport {\n installFetchInstrumentation,\n getActiveDistributedTraceId,\n} from \"./fetch-instrumentation.js\";\nimport { installXhrInstrumentation } from \"./xhr-instrumentation.js\";\n\nlet client: TracewayFrontendClient | null = null;\n\nexport function init(\n connectionString: string,\n options: TracewayFrontendOptions = {},\n): void {\n client = new TracewayFrontendClient(connectionString, options);\n if (typeof window !== \"undefined\") {\n installGlobalHandlers(client);\n installFetchInstrumentation();\n installXhrInstrumentation();\n }\n}\n\nexport function captureException(\n error: Error,\n options?: { distributedTraceId?: string },\n): void {\n if (!client) return;\n client.addException({\n traceId: null,\n stackTrace: formatBrowserStackTrace(error),\n recordedAt: nowISO(),\n isMessage: false,\n distributedTraceId:\n options?.distributedTraceId ?? getActiveDistributedTraceId(),\n });\n}\n\nexport function captureExceptionWithAttributes(\n error: Error,\n attributes?: Record<string, string>,\n options?: { distributedTraceId?: string },\n): void {\n if (!client) return;\n client.addException({\n traceId: null,\n stackTrace: formatBrowserStackTrace(error),\n recordedAt: nowISO(),\n attributes,\n isMessage: false,\n distributedTraceId:\n options?.distributedTraceId ?? getActiveDistributedTraceId(),\n });\n}\n\nexport function captureMessage(msg: string): void {\n if (!client) return;\n client.addException({\n traceId: null,\n stackTrace: msg,\n recordedAt: nowISO(),\n isMessage: true,\n });\n}\n\nexport async function flush(timeoutMs?: number): Promise<void> {\n if (!client) return;\n await client.flush(timeoutMs);\n}\n\nexport { TracewayFrontendClient } from \"./client.js\";\nexport type { TracewayFrontendOptions } from \"./client.js\";\nexport { formatBrowserStackTrace } from \"./stack-trace.js\";\nexport { installGlobalHandlers } from \"./global-handlers.js\";\n\nexport type {\n ExceptionStackTrace,\n CollectionFrame,\n ReportRequest,\n} from \"@tracewayapp/core\";\n\nexport const DISTRIBUTED_TRACE_HEADER = \"traceway-trace-id\";\n\nexport { getActiveDistributedTraceId } from \"./fetch-instrumentation.js\";\n\nexport function createAxiosInterceptor() {\n return (config: any) => {\n config.headers = config.headers || {};\n config.headers[\"traceway-trace-id\"] = generateUUID();\n return config;\n };\n}\n","import type {\n ExceptionStackTrace,\n ReportRequest,\n CollectionFrame,\n SessionRecordingPayload,\n} from \"@tracewayapp/core\";\nimport { parseConnectionString, generateUUID } from \"@tracewayapp/core\";\nimport { sendReport } from \"./transport.js\";\nimport { SessionRecorder } from \"./session-recorder.js\";\n\nexport interface TracewayFrontendOptions {\n debug?: boolean;\n debounceMs?: number;\n retryDelayMs?: number;\n version?: string;\n sessionRecording?: boolean;\n sessionRecordingSegmentDuration?: number;\n}\n\nexport class TracewayFrontendClient {\n private apiUrl: string;\n private token: string;\n private debug: boolean;\n private debounceMs: number;\n private retryDelayMs: number;\n private version: string;\n\n private pendingExceptions: ExceptionStackTrace[] = [];\n private pendingRecordings: SessionRecordingPayload[] = [];\n private isSyncing = false;\n private debounceTimer: ReturnType<typeof setTimeout> | null = null;\n private retryTimer: ReturnType<typeof setTimeout> | null = null;\n\n private recorder: SessionRecorder | null = null;\n\n constructor(connectionString: string, options: TracewayFrontendOptions = {}) {\n const { token, apiUrl } = parseConnectionString(connectionString);\n this.apiUrl = apiUrl;\n this.token = token;\n this.debug = options.debug ?? false;\n this.debounceMs = options.debounceMs ?? 1500;\n this.retryDelayMs = options.retryDelayMs ?? 10000;\n this.version = options.version ?? \"\";\n\n if (options.sessionRecording !== false && typeof window !== \"undefined\") {\n this.recorder = new SessionRecorder({\n segmentDuration: options.sessionRecordingSegmentDuration,\n });\n this.recorder.start();\n }\n }\n\n addException(exception: ExceptionStackTrace): void {\n if (this.recorder && this.recorder.hasSegments()) {\n const segments = this.recorder.getSegments();\n const allEvents = segments.flatMap((s) => s.events);\n const exceptionId = generateUUID();\n exception.sessionRecordingId = exceptionId;\n this.pendingRecordings.push({ exceptionId, events: allEvents });\n }\n\n this.pendingExceptions.push(exception);\n this.scheduleSync();\n }\n\n private scheduleSync(): void {\n if (this.debounceTimer !== null) {\n clearTimeout(this.debounceTimer);\n }\n this.debounceTimer = setTimeout(() => {\n this.debounceTimer = null;\n this.doSync();\n }, this.debounceMs);\n }\n\n private async doSync(): Promise<void> {\n if (this.isSyncing) return;\n if (this.pendingExceptions.length === 0) return;\n\n this.isSyncing = true;\n const batch = this.pendingExceptions.splice(0);\n const recordings = this.pendingRecordings.splice(0);\n\n const frame: CollectionFrame = {\n stackTraces: batch,\n metrics: [],\n traces: [],\n sessionRecordings: recordings.length > 0 ? recordings : undefined,\n };\n\n const payload: ReportRequest = {\n collectionFrames: [frame],\n appVersion: this.version,\n serverName: \"\",\n };\n\n let failed = false;\n try {\n const success = await sendReport(\n this.apiUrl,\n this.token,\n JSON.stringify(payload),\n );\n if (!success) {\n failed = true;\n this.pendingExceptions.unshift(...batch);\n this.pendingRecordings.unshift(...recordings);\n if (this.debug) {\n console.error(\"Traceway: sync failed, re-queued exceptions\");\n }\n }\n } catch (err) {\n failed = true;\n this.pendingExceptions.unshift(...batch);\n this.pendingRecordings.unshift(...recordings);\n if (this.debug) {\n console.error(\"Traceway: sync error:\", err);\n }\n } finally {\n this.isSyncing = false;\n if (this.pendingExceptions.length > 0) {\n if (failed) {\n this.scheduleRetry();\n } else {\n this.doSync();\n }\n }\n }\n }\n\n private scheduleRetry(): void {\n if (this.retryTimer !== null) return;\n this.retryTimer = setTimeout(() => {\n this.retryTimer = null;\n this.doSync();\n }, this.retryDelayMs);\n }\n\n async flush(timeoutMs?: number): Promise<void> {\n if (this.debounceTimer !== null) {\n clearTimeout(this.debounceTimer);\n this.debounceTimer = null;\n }\n if (this.retryTimer !== null) {\n clearTimeout(this.retryTimer);\n this.retryTimer = null;\n }\n if (this.recorder) {\n this.recorder.stop();\n }\n\n const syncPromise = this.doSync();\n\n if (timeoutMs !== undefined) {\n await Promise.race([\n syncPromise,\n new Promise<void>((resolve) => setTimeout(resolve, timeoutMs)),\n ]);\n } else {\n await syncPromise;\n }\n }\n}\n","export async function compressGzip(data: string): Promise<Uint8Array> {\n const encoder = new TextEncoder();\n const inputBytes = encoder.encode(data);\n\n const cs = new CompressionStream(\"gzip\");\n const writer = cs.writable.getWriter();\n writer.write(inputBytes);\n writer.close();\n\n const reader = cs.readable.getReader();\n const chunks: Uint8Array[] = [];\n let totalLength = 0;\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n chunks.push(value);\n totalLength += value.length;\n }\n\n const result = new Uint8Array(totalLength);\n let offset = 0;\n for (const chunk of chunks) {\n result.set(chunk, offset);\n offset += chunk.length;\n }\n\n return result;\n}\n\nexport async function sendReport(\n apiUrl: string,\n token: string,\n body: string,\n): Promise<boolean> {\n const compressed = await compressGzip(body);\n\n const resp = await fetch(apiUrl, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"Content-Encoding\": \"gzip\",\n Authorization: `Bearer ${token}`,\n },\n body: compressed,\n });\n\n return resp.status === 200;\n}\n","import type { eventWithTime } from \"rrweb\";\nimport { record } from \"rrweb\";\n\nexport interface SessionRecorderOptions {\n segmentDuration?: number;\n}\n\ninterface Segment {\n events: eventWithTime[];\n startedAt: string;\n}\n\nexport class SessionRecorder {\n private segmentDuration: number;\n private current: Segment;\n private previous: Segment | null = null;\n private stopFn: (() => void) | null = null;\n private rotateInterval: ReturnType<typeof setInterval> | null = null;\n\n constructor(options: SessionRecorderOptions = {}) {\n this.segmentDuration = options.segmentDuration ?? 10_000;\n this.current = { events: [], startedAt: new Date().toISOString() };\n }\n\n start(): void {\n this.stopFn = record({\n emit: (event) => {\n this.onEvent(event);\n },\n });\n\n this.rotateInterval = setInterval(() => {\n this.rotateSegment();\n }, this.segmentDuration);\n }\n\n stop(): void {\n if (this.stopFn) {\n this.stopFn();\n this.stopFn = null;\n }\n if (this.rotateInterval) {\n clearInterval(this.rotateInterval);\n this.rotateInterval = null;\n }\n }\n\n private onEvent(event: eventWithTime): void {\n this.current.events.push(event);\n }\n\n private rotateSegment(): void {\n this.previous = this.current;\n this.current = { events: [], startedAt: new Date().toISOString() };\n record.takeFullSnapshot();\n }\n\n getSegments(): { events: eventWithTime[]; timestamp: string }[] {\n const segments: { events: eventWithTime[]; timestamp: string }[] = [];\n if (this.previous && this.previous.events.length > 0) {\n segments.push({\n events: this.previous.events,\n timestamp: this.previous.startedAt,\n });\n }\n if (this.current.events.length > 0) {\n segments.push({\n events: this.current.events,\n timestamp: this.current.startedAt,\n });\n }\n return segments;\n }\n\n hasSegments(): boolean {\n return (\n this.current.events.length > 0 ||\n (this.previous !== null && this.previous.events.length > 0)\n );\n }\n\n flush(): void {\n this.previous = null;\n this.current = { events: [], startedAt: new Date().toISOString() };\n if (this.stopFn) {\n record.takeFullSnapshot();\n }\n }\n}\n","export function formatBrowserStackTrace(error: Error): string {\n const lines: string[] = [];\n const typeName = error.constructor?.name || \"Error\";\n lines.push(`${typeName}: ${error.message}`);\n\n if (error.stack) {\n const stackLines = error.stack.split(\"\\n\");\n for (const line of stackLines) {\n // V8 format: \" at funcName (file:line:col)\"\n const v8Match = line.match(/^\\s+at\\s+(.+?)\\s+\\((.+):(\\d+):(\\d+)\\)$/);\n if (v8Match) {\n const funcName = shortenFunctionName(v8Match[1]);\n const file = shortenFilePath(v8Match[2]);\n lines.push(`${funcName}()`);\n lines.push(` ${file}:${v8Match[3]}:${v8Match[4]}`);\n continue;\n }\n\n // V8 anonymous: \" at file:line:col\"\n const v8AnonMatch = line.match(/^\\s+at\\s+(.+):(\\d+):(\\d+)$/);\n if (v8AnonMatch) {\n const file = shortenFilePath(v8AnonMatch[1]);\n lines.push(`<anonymous>()`);\n lines.push(` ${file}:${v8AnonMatch[2]}:${v8AnonMatch[3]}`);\n continue;\n }\n\n // Firefox format: \"funcName@file:line:col\"\n const ffMatch = line.match(/^(.+)@(.+):(\\d+):(\\d+)$/);\n if (ffMatch) {\n const funcName = shortenFunctionName(ffMatch[1]) || \"<anonymous>\";\n const file = shortenFilePath(ffMatch[2]);\n lines.push(`${funcName}()`);\n lines.push(` ${file}:${ffMatch[3]}:${ffMatch[4]}`);\n continue;\n }\n\n // Firefox anonymous: \"@file:line:col\"\n const ffAnonMatch = line.match(/^@(.+):(\\d+):(\\d+)$/);\n if (ffAnonMatch) {\n const file = shortenFilePath(ffAnonMatch[1]);\n lines.push(`<anonymous>()`);\n lines.push(` ${file}:${ffAnonMatch[2]}:${ffAnonMatch[3]}`);\n continue;\n }\n }\n }\n\n return lines.join(\"\\n\") + \"\\n\";\n}\n\nfunction shortenFunctionName(fn: string): string {\n const slashIdx = fn.lastIndexOf(\"/\");\n if (slashIdx >= 0) {\n fn = fn.slice(slashIdx + 1);\n }\n const dotIdx = fn.indexOf(\".\");\n if (dotIdx >= 0) {\n fn = fn.slice(dotIdx + 1);\n }\n return fn;\n}\n\nfunction shortenFilePath(filePath: string): string {\n const parts = filePath.split(\"/\");\n return parts[parts.length - 1];\n}\n","import type { TracewayFrontendClient } from \"./client.js\";\nimport { formatBrowserStackTrace } from \"./stack-trace.js\";\nimport { nowISO } from \"@tracewayapp/core\";\nimport { getActiveDistributedTraceId } from \"./fetch-instrumentation.js\";\n\nexport function installGlobalHandlers(client: TracewayFrontendClient): void {\n const prevOnError = window.onerror;\n window.onerror = (message, source, lineno, colno, error) => {\n if (error) {\n client.addException({\n traceId: null,\n stackTrace: formatBrowserStackTrace(error),\n recordedAt: nowISO(),\n isMessage: false,\n distributedTraceId: getActiveDistributedTraceId(),\n });\n } else {\n client.addException({\n traceId: null,\n stackTrace: String(message),\n recordedAt: nowISO(),\n isMessage: false,\n distributedTraceId: getActiveDistributedTraceId(),\n });\n }\n if (typeof prevOnError === \"function\") {\n return prevOnError(message, source, lineno, colno, error);\n }\n return false;\n };\n\n const prevOnUnhandledRejection = window.onunhandledrejection;\n window.onunhandledrejection = (event: PromiseRejectionEvent) => {\n const reason = event.reason;\n if (reason instanceof Error) {\n client.addException({\n traceId: null,\n stackTrace: formatBrowserStackTrace(reason),\n recordedAt: nowISO(),\n isMessage: false,\n distributedTraceId: getActiveDistributedTraceId(),\n });\n } else {\n client.addException({\n traceId: null,\n stackTrace: String(reason),\n recordedAt: nowISO(),\n isMessage: false,\n distributedTraceId: getActiveDistributedTraceId(),\n });\n }\n if (typeof prevOnUnhandledRejection === \"function\") {\n prevOnUnhandledRejection.call(window, event);\n }\n };\n}\n","import { generateUUID } from \"@tracewayapp/core\";\n\nlet activeDistributedTraceId: string | null = null;\n\nexport function getActiveDistributedTraceId(): string | null {\n return activeDistributedTraceId;\n}\n\nexport function setActiveDistributedTraceId(id: string | null): void {\n activeDistributedTraceId = id;\n}\n\nexport function clearActiveDistributedTraceId(traceId: string): void {\n if (activeDistributedTraceId === traceId) {\n activeDistributedTraceId = null;\n }\n}\n\nfunction isSameOrigin(input: RequestInfo | URL): boolean {\n try {\n const url = new URL(\n typeof input === \"string\"\n ? input\n : input instanceof Request\n ? input.url\n : input.href,\n window.location.origin,\n );\n return url.origin === window.location.origin;\n } catch {\n return true;\n }\n}\n\nexport function installFetchInstrumentation(): void {\n const originalFetch = window.fetch;\n\n window.fetch = function (\n input: RequestInfo | URL,\n init?: RequestInit,\n ): Promise<Response> {\n if (!isSameOrigin(input)) {\n return originalFetch.call(this, input, init);\n }\n\n const traceId = generateUUID();\n activeDistributedTraceId = traceId;\n\n const headers = new Headers(init?.headers);\n headers.set(\"traceway-trace-id\", traceId);\n\n return originalFetch\n .call(this, input, { ...init, headers })\n .finally(() => {\n if (activeDistributedTraceId === traceId) {\n activeDistributedTraceId = null;\n }\n });\n };\n}\n","import { generateUUID } from \"@tracewayapp/core\";\nimport {\n setActiveDistributedTraceId,\n clearActiveDistributedTraceId,\n} from \"./fetch-instrumentation.js\";\n\nfunction isSameOriginUrl(url: string): boolean {\n try {\n const resolved = new URL(url, window.location.origin);\n return resolved.origin === window.location.origin;\n } catch {\n return true;\n }\n}\n\ninterface TracewayXHR extends XMLHttpRequest {\n _tracewaySameOrigin?: boolean;\n}\n\nexport function installXhrInstrumentation(): void {\n const originalOpen = XMLHttpRequest.prototype.open;\n const originalSend = XMLHttpRequest.prototype.send;\n\n XMLHttpRequest.prototype.open = function (\n this: TracewayXHR,\n method: string,\n url: string | URL,\n ...rest: any[]\n ) {\n this._tracewaySameOrigin = isSameOriginUrl(String(url));\n return originalOpen.apply(this, [method, url, ...rest] as any);\n };\n\n XMLHttpRequest.prototype.send = function (\n this: TracewayXHR,\n body?: Document | XMLHttpRequestBodyInit | null,\n ) {\n if (this._tracewaySameOrigin) {\n const traceId = generateUUID();\n setActiveDistributedTraceId(traceId);\n this.setRequestHeader(\"traceway-trace-id\", traceId);\n\n const onComplete = () => {\n clearActiveDistributedTraceId(traceId);\n this.removeEventListener(\"load\", onComplete);\n this.removeEventListener(\"error\", onComplete);\n this.removeEventListener(\"abort\", onComplete);\n };\n this.addEventListener(\"load\", onComplete);\n this.addEventListener(\"error\", onComplete);\n this.addEventListener(\"abort\", onComplete);\n }\n return originalSend.call(this, body);\n };\n}\n"],"mappings":"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","names":["import_core","import_core","import_core","init","client","import_core"]}
package/dist/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  // src/index.ts
2
- import { nowISO as nowISO2 } from "@tracewayapp/core";
2
+ import { nowISO as nowISO2, generateUUID as generateUUID4 } from "@tracewayapp/core";
3
3
 
4
4
  // src/client.ts
5
5
  import { parseConnectionString, generateUUID } from "@tracewayapp/core";
@@ -301,6 +301,51 @@ function shortenFilePath(filePath) {
301
301
 
302
302
  // src/global-handlers.ts
303
303
  import { nowISO } from "@tracewayapp/core";
304
+
305
+ // src/fetch-instrumentation.ts
306
+ import { generateUUID as generateUUID2 } from "@tracewayapp/core";
307
+ var activeDistributedTraceId = null;
308
+ function getActiveDistributedTraceId() {
309
+ return activeDistributedTraceId;
310
+ }
311
+ function setActiveDistributedTraceId(id) {
312
+ activeDistributedTraceId = id;
313
+ }
314
+ function clearActiveDistributedTraceId(traceId) {
315
+ if (activeDistributedTraceId === traceId) {
316
+ activeDistributedTraceId = null;
317
+ }
318
+ }
319
+ function isSameOrigin(input) {
320
+ try {
321
+ const url = new URL(
322
+ typeof input === "string" ? input : input instanceof Request ? input.url : input.href,
323
+ window.location.origin
324
+ );
325
+ return url.origin === window.location.origin;
326
+ } catch {
327
+ return true;
328
+ }
329
+ }
330
+ function installFetchInstrumentation() {
331
+ const originalFetch = window.fetch;
332
+ window.fetch = function(input, init2) {
333
+ if (!isSameOrigin(input)) {
334
+ return originalFetch.call(this, input, init2);
335
+ }
336
+ const traceId = generateUUID2();
337
+ activeDistributedTraceId = traceId;
338
+ const headers = new Headers(init2?.headers);
339
+ headers.set("traceway-trace-id", traceId);
340
+ return originalFetch.call(this, input, { ...init2, headers }).finally(() => {
341
+ if (activeDistributedTraceId === traceId) {
342
+ activeDistributedTraceId = null;
343
+ }
344
+ });
345
+ };
346
+ }
347
+
348
+ // src/global-handlers.ts
304
349
  function installGlobalHandlers(client2) {
305
350
  const prevOnError = window.onerror;
306
351
  window.onerror = (message, source, lineno, colno, error) => {
@@ -309,14 +354,16 @@ function installGlobalHandlers(client2) {
309
354
  traceId: null,
310
355
  stackTrace: formatBrowserStackTrace(error),
311
356
  recordedAt: nowISO(),
312
- isMessage: false
357
+ isMessage: false,
358
+ distributedTraceId: getActiveDistributedTraceId()
313
359
  });
314
360
  } else {
315
361
  client2.addException({
316
362
  traceId: null,
317
363
  stackTrace: String(message),
318
364
  recordedAt: nowISO(),
319
- isMessage: false
365
+ isMessage: false,
366
+ distributedTraceId: getActiveDistributedTraceId()
320
367
  });
321
368
  }
322
369
  if (typeof prevOnError === "function") {
@@ -332,14 +379,16 @@ function installGlobalHandlers(client2) {
332
379
  traceId: null,
333
380
  stackTrace: formatBrowserStackTrace(reason),
334
381
  recordedAt: nowISO(),
335
- isMessage: false
382
+ isMessage: false,
383
+ distributedTraceId: getActiveDistributedTraceId()
336
384
  });
337
385
  } else {
338
386
  client2.addException({
339
387
  traceId: null,
340
388
  stackTrace: String(reason),
341
389
  recordedAt: nowISO(),
342
- isMessage: false
390
+ isMessage: false,
391
+ distributedTraceId: getActiveDistributedTraceId()
343
392
  });
344
393
  }
345
394
  if (typeof prevOnUnhandledRejection === "function") {
@@ -348,31 +397,71 @@ function installGlobalHandlers(client2) {
348
397
  };
349
398
  }
350
399
 
400
+ // src/xhr-instrumentation.ts
401
+ import { generateUUID as generateUUID3 } from "@tracewayapp/core";
402
+ function isSameOriginUrl(url) {
403
+ try {
404
+ const resolved = new URL(url, window.location.origin);
405
+ return resolved.origin === window.location.origin;
406
+ } catch {
407
+ return true;
408
+ }
409
+ }
410
+ function installXhrInstrumentation() {
411
+ const originalOpen = XMLHttpRequest.prototype.open;
412
+ const originalSend = XMLHttpRequest.prototype.send;
413
+ XMLHttpRequest.prototype.open = function(method, url, ...rest) {
414
+ this._tracewaySameOrigin = isSameOriginUrl(String(url));
415
+ return originalOpen.apply(this, [method, url, ...rest]);
416
+ };
417
+ XMLHttpRequest.prototype.send = function(body) {
418
+ if (this._tracewaySameOrigin) {
419
+ const traceId = generateUUID3();
420
+ setActiveDistributedTraceId(traceId);
421
+ this.setRequestHeader("traceway-trace-id", traceId);
422
+ const onComplete = () => {
423
+ clearActiveDistributedTraceId(traceId);
424
+ this.removeEventListener("load", onComplete);
425
+ this.removeEventListener("error", onComplete);
426
+ this.removeEventListener("abort", onComplete);
427
+ };
428
+ this.addEventListener("load", onComplete);
429
+ this.addEventListener("error", onComplete);
430
+ this.addEventListener("abort", onComplete);
431
+ }
432
+ return originalSend.call(this, body);
433
+ };
434
+ }
435
+
351
436
  // src/index.ts
352
437
  var client = null;
353
438
  function init(connectionString, options = {}) {
354
439
  client = new TracewayFrontendClient(connectionString, options);
355
440
  if (typeof window !== "undefined") {
356
441
  installGlobalHandlers(client);
442
+ installFetchInstrumentation();
443
+ installXhrInstrumentation();
357
444
  }
358
445
  }
359
- function captureException(error) {
446
+ function captureException(error, options) {
360
447
  if (!client) return;
361
448
  client.addException({
362
449
  traceId: null,
363
450
  stackTrace: formatBrowserStackTrace(error),
364
451
  recordedAt: nowISO2(),
365
- isMessage: false
452
+ isMessage: false,
453
+ distributedTraceId: options?.distributedTraceId ?? getActiveDistributedTraceId()
366
454
  });
367
455
  }
368
- function captureExceptionWithAttributes(error, attributes) {
456
+ function captureExceptionWithAttributes(error, attributes, options) {
369
457
  if (!client) return;
370
458
  client.addException({
371
459
  traceId: null,
372
460
  stackTrace: formatBrowserStackTrace(error),
373
461
  recordedAt: nowISO2(),
374
462
  attributes,
375
- isMessage: false
463
+ isMessage: false,
464
+ distributedTraceId: options?.distributedTraceId ?? getActiveDistributedTraceId()
376
465
  });
377
466
  }
378
467
  function captureMessage(msg) {
@@ -388,13 +477,24 @@ async function flush(timeoutMs) {
388
477
  if (!client) return;
389
478
  await client.flush(timeoutMs);
390
479
  }
480
+ var DISTRIBUTED_TRACE_HEADER = "traceway-trace-id";
481
+ function createAxiosInterceptor() {
482
+ return (config) => {
483
+ config.headers = config.headers || {};
484
+ config.headers["traceway-trace-id"] = generateUUID4();
485
+ return config;
486
+ };
487
+ }
391
488
  export {
489
+ DISTRIBUTED_TRACE_HEADER,
392
490
  TracewayFrontendClient,
393
491
  captureException,
394
492
  captureExceptionWithAttributes,
395
493
  captureMessage,
494
+ createAxiosInterceptor,
396
495
  flush,
397
496
  formatBrowserStackTrace,
497
+ getActiveDistributedTraceId,
398
498
  init,
399
499
  installGlobalHandlers
400
500
  };