@miradorlabs/parallax-web 2.3.1 → 2.4.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 CHANGED
@@ -16,6 +16,7 @@ npm install @miradorlabs/parallax-web
16
16
  - **Fluent Builder Pattern** - Method chaining for building traces
17
17
  - **Browser-optimized** - Automatic client metadata collection (browser, OS, etc.)
18
18
  - **Blockchain Integration** - Built-in support for correlating traces with blockchain transactions
19
+ - **Stack Trace Capture** - Automatic or manual capture of call stack for debugging
19
20
  - **TypeScript Support** - Full type definitions included
20
21
  - **Strict Ordering** - Flush calls maintain strict ordering even when async
21
22
 
@@ -187,6 +188,9 @@ Creates a new trace builder.
187
188
  const trace = client.trace({ name: 'MyTrace' });
188
189
  const trace = client.trace({ name: 'MyTrace', autoFlush: false });
189
190
  const trace = client.trace({ autoFlush: false, flushPeriodMs: 100 });
191
+
192
+ // With stack trace capture - records where in your code the trace was created
193
+ const trace = client.trace({ name: 'MyTrace', captureStackTrace: true });
190
194
  ```
191
195
 
192
196
  | Option | Type | Default | Description |
@@ -198,6 +202,7 @@ const trace = client.trace({ autoFlush: false, flushPeriodMs: 100 });
198
202
  | `maxRetries` | `number` | `3` | Maximum retry attempts on network failure |
199
203
  | `retryBackoff` | `number` | `1000` | Base delay in ms for exponential backoff (doubles each retry) |
200
204
  | `autoClose` | `boolean` | `false` | Automatically close trace on page unload |
205
+ | `captureStackTrace` | `boolean` | `false` | Capture stack trace at trace creation point |
201
206
 
202
207
  Returns: `ParallaxTrace` builder instance
203
208
 
@@ -237,16 +242,62 @@ trace.addTag('transaction')
237
242
  .addTags(['ethereum', 'send'])
238
243
  ```
239
244
 
240
- #### `addEvent(name, details?, timestamp?)`
245
+ #### `addEvent(name, details?, options?)`
241
246
 
242
- Add an event with optional details (string or object).
247
+ Add an event with optional details (string or object) and optional settings.
243
248
 
244
249
  ```typescript
245
250
  trace.addEvent('wallet_connected', { wallet: 'MetaMask' })
246
251
  .addEvent('transaction_initiated')
247
252
  .addEvent('transaction_confirmed', { blockNumber: 12345 })
253
+
254
+ // With stack trace - captures where in your code the event was added
255
+ trace.addEvent('error_occurred', { code: 500 }, { captureStackTrace: true })
256
+
257
+ // Legacy: timestamp can still be passed as third parameter for backward compatibility
258
+ trace.addEvent('custom_event', 'details', new Date())
259
+ ```
260
+
261
+ | Parameter | Type | Description |
262
+ |-----------|----------------------------|-----------------------------------------------------|
263
+ | `name` | `string` | Event name |
264
+ | `details` | `string \| object` | Optional event details (objects are stringified) |
265
+ | `options` | `AddEventOptions \| Date` | Options with `captureStackTrace`, or legacy Date |
266
+
267
+ #### `addStackTrace(eventName?, additionalDetails?)`
268
+
269
+ Capture and add the current stack trace as an event. Useful for debugging or tracking code paths.
270
+
271
+ ```typescript
272
+ trace.addStackTrace() // Creates event named "stack_trace"
273
+ trace.addStackTrace('checkpoint', { stage: 'validation' })
274
+ ```
275
+
276
+ | Parameter | Type | Description |
277
+ |---------------------|----------|--------------------------------------------------|
278
+ | `eventName` | `string` | Event name (defaults to "stack_trace") |
279
+ | `additionalDetails` | `object` | Optional additional details to include |
280
+
281
+ #### `addExistingStackTrace(stackTrace, eventName?, additionalDetails?)`
282
+
283
+ Add a previously captured stack trace as an event. Useful when you need to capture a stack trace at one point but record it later.
284
+
285
+ ```typescript
286
+ import { captureStackTrace } from '@miradorlabs/parallax-web';
287
+
288
+ // Capture stack trace now
289
+ const stack = captureStackTrace();
290
+
291
+ // ... later ...
292
+ trace.addExistingStackTrace(stack, 'deferred_location', { reason: 'async operation' })
248
293
  ```
249
294
 
295
+ | Parameter | Type | Description |
296
+ |---------------------|--------------|--------------------------------------------------|
297
+ | `stackTrace` | `StackTrace` | Previously captured stack trace |
298
+ | `eventName` | `string` | Event name (defaults to "stack_trace") |
299
+ | `additionalDetails` | `object` | Optional additional details to include |
300
+
250
301
  #### `addTxHint(txHash, chain, details?)`
251
302
 
252
303
  Add a transaction hash hint for blockchain correlation. Multiple hints can be added.
@@ -384,6 +435,32 @@ When `includeClientMeta: true` is set (default), the SDK automatically collects:
384
435
 
385
436
  Note: IP address is captured by the backend from request headers.
386
437
 
438
+ ## Stack Trace Utilities
439
+
440
+ The SDK exports utilities for capturing and formatting stack traces:
441
+
442
+ ```typescript
443
+ import {
444
+ captureStackTrace,
445
+ formatStackTrace,
446
+ formatStackTraceReadable
447
+ } from '@miradorlabs/parallax-web';
448
+
449
+ // Capture current stack trace
450
+ const stack = captureStackTrace();
451
+ // stack.frames: Array of { functionName, fileName, lineNumber, columnNumber }
452
+ // stack.raw: Original Error.stack string
453
+
454
+ // Format for storage (JSON string)
455
+ const json = formatStackTrace(stack);
456
+
457
+ // Format for display (human-readable)
458
+ const readable = formatStackTraceReadable(stack);
459
+ // Output:
460
+ // at myFunction (/path/to/file.js:42:10)
461
+ // at caller (/path/to/other.js:15:5)
462
+ ```
463
+
387
464
  ## TypeScript Support
388
465
 
389
466
  Full TypeScript support with exported types:
@@ -393,8 +470,11 @@ import {
393
470
  ParallaxClient,
394
471
  ParallaxTrace,
395
472
  ParallaxClientOptions,
396
- TraceOptions,
397
- ChainName, // 'ethereum' | 'polygon' | 'arbitrum' | 'base' | 'optimism' | 'bsc'
473
+ TraceOptions, // { captureStackTrace?: boolean, ... }
474
+ AddEventOptions, // { captureStackTrace?: boolean }
475
+ StackFrame, // { functionName, fileName, lineNumber, columnNumber }
476
+ StackTrace, // { frames: StackFrame[], raw: string }
477
+ ChainName, // 'ethereum' | 'polygon' | 'arbitrum' | 'base' | 'optimism' | 'bsc'
398
478
  } from '@miradorlabs/parallax-web';
399
479
  ```
400
480
 
package/dist/index.d.ts CHANGED
@@ -32,11 +32,95 @@ interface TraceOptions {
32
32
  retryBackoff?: number;
33
33
  /** Automatically close trace on page unload (default: false) */
34
34
  autoClose?: boolean;
35
+ /** Capture stack trace at trace creation point */
36
+ captureStackTrace?: boolean;
37
+ }
38
+ /**
39
+ * Client metadata collected from the browser environment
40
+ */
41
+ interface ClientMetadata {
42
+ browser: string;
43
+ browserVersion: string;
44
+ os: string;
45
+ osVersion: string;
46
+ deviceType: 'desktop' | 'mobile' | 'tablet';
47
+ userAgent: string;
48
+ language: string;
49
+ languages: string;
50
+ screenWidth: string;
51
+ screenHeight: string;
52
+ viewportWidth: string;
53
+ viewportHeight: string;
54
+ colorDepth: string;
55
+ pixelRatio: string;
56
+ cpuCores: string;
57
+ deviceMemory?: string;
58
+ touchSupport: string;
59
+ maxTouchPoints: string;
60
+ connectionType?: string;
61
+ connectionSpeed?: string;
62
+ dataSaver?: string;
63
+ cookiesEnabled: string;
64
+ online: string;
65
+ doNotTrack: string;
66
+ timezone: string;
67
+ timezoneOffset: string;
68
+ url: string;
69
+ origin: string;
70
+ pathname: string;
71
+ referrer: string;
72
+ documentVisibility: string;
73
+ }
74
+ /**
75
+ * An event to be recorded in a trace
76
+ */
77
+ interface TraceEvent {
78
+ eventName: string;
79
+ details?: string;
80
+ timestamp: Date;
35
81
  }
36
82
  /**
37
83
  * Supported chain names (maps to Chain enum in proto)
38
84
  */
39
85
  type ChainName = 'ethereum' | 'polygon' | 'arbitrum' | 'base' | 'optimism' | 'bsc';
86
+ /**
87
+ * Transaction hash hint for blockchain correlation
88
+ */
89
+ interface TxHashHint {
90
+ txHash: string;
91
+ chain: ChainName;
92
+ details?: string;
93
+ timestamp: Date;
94
+ }
95
+ /**
96
+ * A single frame in a stack trace
97
+ */
98
+ interface StackFrame {
99
+ /** Function or method name */
100
+ functionName: string;
101
+ /** File path */
102
+ fileName: string;
103
+ /** Line number */
104
+ lineNumber: number;
105
+ /** Column number */
106
+ columnNumber: number;
107
+ }
108
+ /**
109
+ * A captured stack trace
110
+ */
111
+ interface StackTrace {
112
+ /** Array of stack frames (top of stack first) */
113
+ frames: StackFrame[];
114
+ /** Raw stack string from Error.stack */
115
+ raw: string;
116
+ }
117
+ /**
118
+ * Options for adding an event
119
+ */
120
+ interface AddEventOptions {
121
+ /** Capture stack trace at the point where addEvent is called */
122
+ captureStackTrace?: boolean;
123
+ }
40
124
 
41
125
  /**
42
126
  * ParallaxTrace builder class for constructing traces with method chaining
@@ -62,6 +146,7 @@ interface ResolvedTraceOptions {
62
146
  retryBackoff: number;
63
147
  keepAliveIntervalMs: number;
64
148
  autoClose: boolean;
149
+ captureStackTrace: boolean;
65
150
  }
66
151
  /**
67
152
  * Builder class for constructing traces with method chaining.
@@ -87,6 +172,7 @@ declare class ParallaxTrace {
87
172
  private pendingTags;
88
173
  private pendingEvents;
89
174
  private pendingTxHashHints;
175
+ private creationStackTrace;
90
176
  private flushQueue;
91
177
  constructor(client: TraceSubmitter, options: ResolvedTraceOptions);
92
178
  /**
@@ -126,10 +212,25 @@ declare class ParallaxTrace {
126
212
  * Add an event to the trace
127
213
  * @param eventName Name of the event
128
214
  * @param details Optional details (can be a JSON string or object that will be stringified)
129
- * @param timestamp Optional timestamp (defaults to current time)
215
+ * @param options Optional settings including captureStackTrace, or a Date for backward compatibility
216
+ * @returns This trace builder for chaining
217
+ */
218
+ addEvent(eventName: string, details?: string | object, options?: AddEventOptions | Date): this;
219
+ /**
220
+ * Capture and add the current stack trace as an event
221
+ * @param eventName Name for the stack trace event (defaults to "stack_trace")
222
+ * @param additionalDetails Optional additional details to include with the stack trace
223
+ * @returns This trace builder for chaining
224
+ */
225
+ addStackTrace(eventName?: string, additionalDetails?: object): this;
226
+ /**
227
+ * Add a pre-captured stack trace as an event
228
+ * @param stackTrace The stack trace to add
229
+ * @param eventName Name for the stack trace event (defaults to "stack_trace")
230
+ * @param additionalDetails Optional additional details to include with the stack trace
130
231
  * @returns This trace builder for chaining
131
232
  */
132
- addEvent(eventName: string, details?: string | object, timestamp?: Date): this;
233
+ addExistingStackTrace(stackTrace: StackTrace, eventName?: string, additionalDetails?: object): this;
133
234
  /**
134
235
  * Add a transaction hash hint for blockchain correlation.
135
236
  * Multiple hints can be added to the same trace.
@@ -230,4 +331,59 @@ declare class ParallaxClient {
230
331
  trace(options?: TraceOptions): ParallaxTrace;
231
332
  }
232
333
 
233
- export { ParallaxClient, ParallaxTrace };
334
+ /**
335
+ * Stack trace capture utilities
336
+ */
337
+
338
+ /**
339
+ * Capture the current stack trace
340
+ * @param skipFrames Number of frames to skip from the top (default: 1 to skip this function)
341
+ * @returns Captured stack trace with parsed frames and raw string
342
+ */
343
+ declare function captureStackTrace(skipFrames?: number): StackTrace;
344
+ /**
345
+ * Format a stack trace for storage/display
346
+ * @param stackTrace The stack trace to format
347
+ * @returns JSON string representation of the stack trace
348
+ */
349
+ declare function formatStackTrace(stackTrace: StackTrace): string;
350
+ /**
351
+ * Format a stack trace as a human-readable string
352
+ * @param stackTrace The stack trace to format
353
+ * @returns Human-readable stack trace string
354
+ */
355
+ declare function formatStackTraceReadable(stackTrace: StackTrace): string;
356
+
357
+ /**
358
+ * Browser metadata collection utilities
359
+ */
360
+ interface BrowserInfo {
361
+ name: string;
362
+ version: string;
363
+ }
364
+ interface OSInfo {
365
+ name: string;
366
+ version: string;
367
+ }
368
+ /**
369
+ * Detect browser name and version from user agent
370
+ */
371
+ declare function detectBrowser(ua: string): BrowserInfo;
372
+ /**
373
+ * Detect operating system name and version from user agent
374
+ */
375
+ declare function detectOS(ua: string): OSInfo;
376
+ /**
377
+ * Detect device type from user agent
378
+ */
379
+ declare function detectDeviceType(ua: string): 'desktop' | 'mobile' | 'tablet';
380
+ /**
381
+ * Gather client metadata from the browser environment
382
+ * Note: IP address is captured by the backend from request headers
383
+ */
384
+ declare function getClientMetadata(): {
385
+ [key: string]: string;
386
+ };
387
+
388
+ export { ParallaxClient, ParallaxTrace, captureStackTrace, detectBrowser, detectDeviceType, detectOS, formatStackTrace, formatStackTraceReadable, getClientMetadata };
389
+ export type { AddEventOptions, ChainName, ClientMetadata, ParallaxClientOptions, StackFrame, StackTrace, TraceEvent, TraceOptions, TxHashHint };
package/dist/index.esm.js CHANGED
@@ -3908,6 +3908,94 @@ function getClientMetadata() {
3908
3908
  return metadata;
3909
3909
  }
3910
3910
 
3911
+ /**
3912
+ * Parse a V8/browser stack trace string into structured frames
3913
+ * @param stack Raw stack string from Error.stack
3914
+ * @returns Array of parsed stack frames
3915
+ */
3916
+ function parseStackString(stack) {
3917
+ const frames = [];
3918
+ const lines = stack.split('\n');
3919
+ for (const line of lines) {
3920
+ // Skip the first line (error message) and empty lines
3921
+ if (!line.trim().startsWith('at ')) {
3922
+ continue;
3923
+ }
3924
+ // Parse V8 stack frame format:
3925
+ // " at functionName (filename:line:column)"
3926
+ // " at filename:line:column"
3927
+ // " at async functionName (filename:line:column)"
3928
+ const trimmed = line.trim().slice(3); // Remove "at "
3929
+ let functionName = '<anonymous>';
3930
+ let locationPart = trimmed;
3931
+ // Check if there's a function name before the location
3932
+ const parenMatch = trimmed.match(/^(.*?)\s*\((.+)\)$/);
3933
+ if (parenMatch) {
3934
+ functionName = parenMatch[1].replace(/^async\s+/, '').trim() || '<anonymous>';
3935
+ locationPart = parenMatch[2];
3936
+ }
3937
+ // Parse location: filename:line:column
3938
+ const locationMatch = locationPart.match(/^(.+):(\d+):(\d+)$/);
3939
+ if (locationMatch) {
3940
+ frames.push({
3941
+ functionName,
3942
+ fileName: locationMatch[1],
3943
+ lineNumber: parseInt(locationMatch[2], 10),
3944
+ columnNumber: parseInt(locationMatch[3], 10),
3945
+ });
3946
+ }
3947
+ else {
3948
+ // Fallback for unusual formats
3949
+ frames.push({
3950
+ functionName,
3951
+ fileName: locationPart,
3952
+ lineNumber: 0,
3953
+ columnNumber: 0,
3954
+ });
3955
+ }
3956
+ }
3957
+ return frames;
3958
+ }
3959
+ /**
3960
+ * Capture the current stack trace
3961
+ * @param skipFrames Number of frames to skip from the top (default: 1 to skip this function)
3962
+ * @returns Captured stack trace with parsed frames and raw string
3963
+ */
3964
+ function captureStackTrace(skipFrames = 1) {
3965
+ const error = new Error();
3966
+ const rawStack = error.stack || '';
3967
+ // Parse all frames
3968
+ const allFrames = parseStackString(rawStack);
3969
+ // Skip internal frames (this function + any additional requested skips)
3970
+ // Add 1 to account for this function itself
3971
+ const frames = allFrames.slice(skipFrames + 1);
3972
+ return {
3973
+ frames,
3974
+ raw: rawStack,
3975
+ };
3976
+ }
3977
+ /**
3978
+ * Format a stack trace for storage/display
3979
+ * @param stackTrace The stack trace to format
3980
+ * @returns JSON string representation of the stack trace
3981
+ */
3982
+ function formatStackTrace(stackTrace) {
3983
+ return JSON.stringify({
3984
+ frames: stackTrace.frames,
3985
+ raw: stackTrace.raw,
3986
+ });
3987
+ }
3988
+ /**
3989
+ * Format a stack trace as a human-readable string
3990
+ * @param stackTrace The stack trace to format
3991
+ * @returns Human-readable stack trace string
3992
+ */
3993
+ function formatStackTraceReadable(stackTrace) {
3994
+ return stackTrace.frames
3995
+ .map((frame) => ` at ${frame.functionName} (${frame.fileName}:${frame.lineNumber}:${frame.columnNumber})`)
3996
+ .join('\n');
3997
+ }
3998
+
3911
3999
  /**
3912
4000
  * ParallaxTrace builder class for constructing traces with method chaining
3913
4001
  */
@@ -4042,6 +4130,12 @@ class ParallaxTrace {
4042
4130
  writable: true,
4043
4131
  value: []
4044
4132
  });
4133
+ Object.defineProperty(this, "creationStackTrace", {
4134
+ enumerable: true,
4135
+ configurable: true,
4136
+ writable: true,
4137
+ value: null
4138
+ });
4045
4139
  // Queue for maintaining strict ordering of flushes
4046
4140
  Object.defineProperty(this, "flushQueue", {
4047
4141
  enumerable: true,
@@ -4058,6 +4152,10 @@ class ParallaxTrace {
4058
4152
  this.retryBackoff = options.retryBackoff;
4059
4153
  this.keepAliveIntervalMs = options.keepAliveIntervalMs;
4060
4154
  this.autoClose = options.autoClose;
4155
+ if (options.captureStackTrace) {
4156
+ // Skip 2 frames: this constructor and the trace() method that called it
4157
+ this.creationStackTrace = captureStackTrace(2);
4158
+ }
4061
4159
  // Set up auto-close on page unload if enabled
4062
4160
  if (this.autoClose && typeof window !== 'undefined') {
4063
4161
  this.unloadHandler = () => {
@@ -4156,25 +4254,108 @@ class ParallaxTrace {
4156
4254
  * Add an event to the trace
4157
4255
  * @param eventName Name of the event
4158
4256
  * @param details Optional details (can be a JSON string or object that will be stringified)
4159
- * @param timestamp Optional timestamp (defaults to current time)
4257
+ * @param options Optional settings including captureStackTrace, or a Date for backward compatibility
4160
4258
  * @returns This trace builder for chaining
4161
4259
  */
4162
- addEvent(eventName, details, timestamp) {
4260
+ addEvent(eventName, details, options) {
4163
4261
  if (this.closed) {
4164
4262
  console.warn('[ParallaxTrace] Trace is closed. Ignoring addEvent call.');
4165
4263
  return this;
4166
4264
  }
4167
- const detailsString = typeof details === 'object' && details !== null
4168
- ? JSON.stringify(details)
4169
- : details;
4265
+ // Handle backward compatibility: options can be a Date (legacy timestamp parameter)
4266
+ let timestamp;
4267
+ let eventOptions;
4268
+ if (options instanceof Date) {
4269
+ timestamp = options;
4270
+ }
4271
+ else {
4272
+ eventOptions = options;
4273
+ }
4274
+ // Build details object with optional stack trace
4275
+ let finalDetails;
4276
+ if (eventOptions?.captureStackTrace) {
4277
+ const stackTrace = captureStackTrace(1); // Skip 1 frame (this method)
4278
+ const detailsObj = typeof details === 'object' && details !== null
4279
+ ? details
4280
+ : details !== undefined
4281
+ ? { message: details }
4282
+ : {};
4283
+ finalDetails = JSON.stringify({
4284
+ ...detailsObj,
4285
+ stackTrace: {
4286
+ frames: stackTrace.frames,
4287
+ raw: stackTrace.raw,
4288
+ },
4289
+ });
4290
+ }
4291
+ else {
4292
+ finalDetails =
4293
+ typeof details === 'object' && details !== null
4294
+ ? JSON.stringify(details)
4295
+ : details;
4296
+ }
4170
4297
  this.pendingEvents.push({
4171
4298
  eventName,
4172
- details: detailsString,
4299
+ details: finalDetails,
4173
4300
  timestamp: timestamp || new Date(),
4174
4301
  });
4175
4302
  this.scheduleFlush();
4176
4303
  return this;
4177
4304
  }
4305
+ /**
4306
+ * Capture and add the current stack trace as an event
4307
+ * @param eventName Name for the stack trace event (defaults to "stack_trace")
4308
+ * @param additionalDetails Optional additional details to include with the stack trace
4309
+ * @returns This trace builder for chaining
4310
+ */
4311
+ addStackTrace(eventName = 'stack_trace', additionalDetails) {
4312
+ if (this.closed) {
4313
+ console.warn('[ParallaxTrace] Trace is closed. Ignoring addStackTrace call.');
4314
+ return this;
4315
+ }
4316
+ const stackTrace = captureStackTrace(1); // Skip 1 frame (this method)
4317
+ const details = {
4318
+ ...additionalDetails,
4319
+ stackTrace: {
4320
+ frames: stackTrace.frames,
4321
+ raw: stackTrace.raw,
4322
+ },
4323
+ };
4324
+ this.pendingEvents.push({
4325
+ eventName,
4326
+ details: JSON.stringify(details),
4327
+ timestamp: new Date(),
4328
+ });
4329
+ this.scheduleFlush();
4330
+ return this;
4331
+ }
4332
+ /**
4333
+ * Add a pre-captured stack trace as an event
4334
+ * @param stackTrace The stack trace to add
4335
+ * @param eventName Name for the stack trace event (defaults to "stack_trace")
4336
+ * @param additionalDetails Optional additional details to include with the stack trace
4337
+ * @returns This trace builder for chaining
4338
+ */
4339
+ addExistingStackTrace(stackTrace, eventName = 'stack_trace', additionalDetails) {
4340
+ if (this.closed) {
4341
+ console.warn('[ParallaxTrace] Trace is closed. Ignoring addExistingStackTrace call.');
4342
+ return this;
4343
+ }
4344
+ const details = {
4345
+ ...additionalDetails,
4346
+ stackTrace: {
4347
+ frames: stackTrace.frames,
4348
+ raw: stackTrace.raw,
4349
+ },
4350
+ };
4351
+ this.pendingEvents.push({
4352
+ eventName,
4353
+ details: JSON.stringify(details),
4354
+ timestamp: new Date(),
4355
+ });
4356
+ this.scheduleFlush();
4357
+ return this;
4358
+ }
4178
4359
  /**
4179
4360
  * Add a transaction hash hint for blockchain correlation.
4180
4361
  * Multiple hints can be added to the same trace.
@@ -4247,7 +4428,7 @@ class ParallaxTrace {
4247
4428
  */
4248
4429
  buildTraceData() {
4249
4430
  const traceData = new parallax_gateway_pbExports.TraceData();
4250
- // Add pending attributes (+ client metadata on first flush)
4431
+ // Add pending attributes (+ client metadata on first flush + stack trace if captured)
4251
4432
  const allAttrs = { ...this.pendingAttributes };
4252
4433
  if (this.traceId === null && this.includeClientMeta) {
4253
4434
  const clientMeta = getClientMetadata();
@@ -4255,6 +4436,16 @@ class ParallaxTrace {
4255
4436
  allAttrs[`client.${key}`] = value;
4256
4437
  }
4257
4438
  }
4439
+ // Add creation stack trace attributes on first flush
4440
+ if (this.traceId === null && this.creationStackTrace) {
4441
+ allAttrs['source.stack_trace'] = formatStackTrace(this.creationStackTrace);
4442
+ if (this.creationStackTrace.frames.length > 0) {
4443
+ const topFrame = this.creationStackTrace.frames[0];
4444
+ allAttrs['source.file'] = topFrame.fileName;
4445
+ allAttrs['source.line'] = String(topFrame.lineNumber);
4446
+ allAttrs['source.function'] = topFrame.functionName;
4447
+ }
4448
+ }
4258
4449
  if (Object.keys(allAttrs).length > 0) {
4259
4450
  const attrsMsg = new parallax_gateway_pbExports.Attributes();
4260
4451
  const attrsMap = attrsMsg.getAttributesMap();
@@ -4557,11 +4748,12 @@ class ParallaxClient {
4557
4748
  retryBackoff: options?.retryBackoff ?? DEFAULT_RETRY_BACKOFF,
4558
4749
  keepAliveIntervalMs: this.keepAliveIntervalMs,
4559
4750
  autoClose: options?.autoClose ?? DEFAULT_AUTO_CLOSE,
4751
+ captureStackTrace: options?.captureStackTrace ?? false,
4560
4752
  });
4561
4753
  }
4562
4754
  }
4563
4755
 
4564
4756
  var CreateTraceRequest = parallax_gateway_pbExports.CreateTraceRequest;
4565
4757
  var CreateTraceResponse = parallax_gateway_pbExports.CreateTraceResponse;
4566
- export { CreateTraceRequest, CreateTraceResponse, ParallaxClient, ParallaxTrace };
4758
+ export { CreateTraceRequest, CreateTraceResponse, ParallaxClient, ParallaxTrace, captureStackTrace, detectBrowser, detectDeviceType, detectOS, formatStackTrace, formatStackTraceReadable, getClientMetadata };
4567
4759
  //# sourceMappingURL=index.esm.js.map