@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 +84 -4
- package/dist/index.d.ts +159 -3
- package/dist/index.esm.js +200 -8
- package/dist/index.esm.js.map +1 -1
- package/dist/index.umd.js +206 -7
- package/dist/index.umd.js.map +1 -1
- package/index.ts +19 -0
- package/package.json +2 -2
- package/src/parallax/client.ts +1 -0
- package/src/parallax/index.ts +6 -0
- package/src/parallax/stacktrace.ts +103 -0
- package/src/parallax/trace.ts +116 -8
- package/src/parallax/types.ts +34 -0
- package/tests/parallax.test.ts +261 -1
- package/tests/stacktrace.test.ts +228 -0
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?,
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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,
|
|
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
|
-
|
|
4168
|
-
|
|
4169
|
-
|
|
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:
|
|
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
|