@miradorlabs/parallax-web 1.0.6 → 1.0.7

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.
@@ -2,20 +2,11 @@
2
2
  import {
3
3
  CreateTraceRequest,
4
4
  CreateTraceResponse,
5
- StartSpanRequest,
6
- StartSpanResponse,
7
- FinishSpanRequest,
8
- FinishSpanResponse,
9
- AddSpanEventRequest,
10
- AddSpanEventResponse,
11
- AddSpanErrorRequest,
12
- AddSpanErrorResponse,
13
- AddSpanHintRequest,
14
- AddSpanHintResponse,
15
5
  } from "mirador-gateway-parallax-web/proto/gateway/parallax/v1/parallax_gateway_pb";
16
6
  import { ParallaxGatewayServiceClient } from "mirador-gateway-parallax-web/proto/gateway/parallax/v1/Parallax_gatewayServiceClientPb";
7
+ import { Timestamp } from "google-protobuf/google/protobuf/timestamp_pb";
17
8
 
18
- const GRPC_GATEWAY_API_URL = "https://gateway-parallax-dev.platform.svc.cluster.local:50053";
9
+ const GRPC_GATEWAY_API_URL = "https://parallax-gateway.dev.mirador.org:443";
19
10
 
20
11
  const debugIssue = (trace: string, error: Error) => {
21
12
  // Handle our own debugging / logging here
@@ -176,187 +167,209 @@ class ParallaxClient {
176
167
  }
177
168
 
178
169
  /**
179
- * Create a StartSpanRequest with optional attributes and client metadata
180
- * @param traceId trace id to associate the span with
181
- * @param name name of the span
182
- * @param parentSpanId (optional) create a span off a parent span id
183
- * @param attr (optional) attributes to add to the span
184
- * @param includeClientMeta (optional) flag to include client metadata (ip, browser, os, etc)
185
- * @returns
170
+ * Create a new trace builder
171
+ *
172
+ * Example usage:
173
+ * ```typescript
174
+ * const response = await client.trace("swap_execution")
175
+ * .addAttribute("user", "0xabc...")
176
+ * .addAttribute("slippage_bps", 25)
177
+ * .addTag("dex")
178
+ * .addTag("swap")
179
+ * .addEvent("wallet_connected", { wallet: "MetaMask" })
180
+ * .addEvent("quote_received")
181
+ * .submit("0x123...", "ethereum");
182
+ * ```
183
+ *
184
+ * @param name The name of the trace
185
+ * @param includeClientMeta Optional flag to automatically include client metadata
186
+ * @returns A ParallaxTrace builder instance
186
187
  */
187
- async createStartSpanRequest({ traceId, name, parentSpanId, attr, includeClientMeta = false}: {traceId: string, name: string, parentSpanId?: string, attr?: { [key: string]: string }, includeClientMeta?: boolean}): Promise<StartSpanRequest> {
188
- const startSpanReq = new StartSpanRequest();
189
- startSpanReq.setTraceId(traceId);
190
- startSpanReq.setName(name);
191
- if (parentSpanId) {
192
- startSpanReq.setParentSpanId(parentSpanId);
193
- }
194
- const spanAttrs = startSpanReq.getAttributesMap();
188
+ trace(name: string, includeClientMeta: boolean = false): ParallaxTrace {
189
+ return new ParallaxTrace(this, name, includeClientMeta);
190
+ }
195
191
 
196
- if (attr) {
197
- Object.entries(attr).forEach(([key, value]) => {
198
- if (key.includes('client.')) {
199
- console.warn(`Attribute key "${key}" is reserved for client metadata. It will be prefixed with "custom."`);
200
- } else {
201
- spanAttrs.set(key, typeof value === 'object' ? JSON.stringify(value) : String(value));
202
- }
203
- });
204
- }
205
- try {
206
- if (includeClientMeta) {
207
- const clientMetadata = await this.getClientMetadata();
208
- Object.entries(clientMetadata).forEach(([key, value]) => {
209
- spanAttrs.set(`client.${key}`, value);
210
- });
211
- }
212
- } catch (error) {
213
- console.error('Error gathering client metadata for span:', error);
214
- }
215
- return startSpanReq;
192
+ }
193
+
194
+ /**
195
+ * Builder class for constructing traces with method chaining
196
+ * Automatically handles web-specific features like client metadata
197
+ */
198
+ class ParallaxTrace {
199
+ private name: string;
200
+ private attributes: { [key: string]: string } = {};
201
+ private tags: string[] = [];
202
+ private events: Array<{ eventName: string; details?: string; timestamp: Date }> = [];
203
+ private txHashHint?: {
204
+ txHash: string;
205
+ chainId: string;
206
+ details?: string;
207
+ timestamp: Date;
208
+ };
209
+ private client: ParallaxClient;
210
+ private includeClientMeta: boolean;
211
+
212
+ constructor(client: ParallaxClient, name: string, includeClientMeta: boolean = false) {
213
+ this.client = client;
214
+ this.name = name;
215
+ this.includeClientMeta = includeClientMeta;
216
216
  }
217
217
 
218
218
  /**
219
- * Start a new span within a trace
220
- * @param params Parameters to start a new span
219
+ * Add an attribute to the trace
220
+ * @param key Attribute key
221
+ * @param value Attribute value (will be converted to string)
222
+ * @returns This trace builder for chaining
221
223
  */
222
- async startSpan(params: StartSpanRequest): Promise<StartSpanResponse> {
223
- try {
224
- return await this.client.startSpan(params, null);
225
- } catch (_error) {
226
- debugIssue("startSpan", new Error('Error starting span'));
227
- throw _error;
228
- }
224
+ addAttribute(key: string, value: string | number | boolean): this {
225
+ this.attributes[key] = String(value);
226
+ return this;
229
227
  }
230
228
 
231
229
  /**
232
- * Create a FinishSpanRequest
233
- * @param params Parameters to finish a span - traceId, spanId, status (optional) (success, errorMessage)
234
- * @returns FinishSpanRequest
230
+ * Add multiple attributes to the trace
231
+ * @param attributes Object containing key-value pairs
232
+ * @returns This trace builder for chaining
235
233
  */
236
- createFinishSpanRequest({ traceId, spanId, status }: { traceId: string, spanId: string, status?: { success: boolean, errorMessage: string } }): FinishSpanRequest {
237
- const request = new FinishSpanRequest();
238
- request.setTraceId(traceId);
239
- request.setSpanId(spanId);
240
- if (status !== undefined) {
241
- const spanStatus = new FinishSpanRequest.SpanStatus();
242
- spanStatus.setCode(status.success ? FinishSpanRequest.SpanStatus.StatusCode.STATUS_CODE_OK : FinishSpanRequest.SpanStatus.StatusCode.STATUS_CODE_ERROR);
243
- if (status.errorMessage) {
244
- spanStatus.setMessage(status.errorMessage);
245
- }
246
- request.setStatus(spanStatus);
234
+ addAttributes(attributes: { [key: string]: string | number | boolean }): this {
235
+ for (const [key, value] of Object.entries(attributes)) {
236
+ this.attributes[key] = String(value);
247
237
  }
248
- return request;
238
+ return this;
249
239
  }
250
240
 
251
241
  /**
252
- * Finish a span within a trace
253
- * @param params Parameters to finish a span
242
+ * Add a tag to the trace
243
+ * @param tag Tag to add
244
+ * @returns This trace builder for chaining
254
245
  */
255
- async finishSpan(params: FinishSpanRequest): Promise<FinishSpanResponse> {
256
- try {
257
- return await this.client.finishSpan(params, null);
258
- } catch (_error) {
259
- debugIssue("finishSpan", new Error('Error finishing span'));
260
- throw _error;
261
- }
246
+ addTag(tag: string): this {
247
+ this.tags.push(tag);
248
+ return this;
262
249
  }
263
250
 
264
251
  /**
265
- * Creates the add span event request
266
- * @param params - Parameters to create an AddSpanEventRequest - traceId, spanId, eventName, attr (optional)
267
- * @returns AddSpanEventRequest
252
+ * Add multiple tags to the trace
253
+ * @param tags Array of tags to add
254
+ * @returns This trace builder for chaining
268
255
  */
269
- createAddSpanEventRequest({ traceId, spanId, eventName, attr }: { traceId: string, spanId: string, eventName: string, attr?: { [key: string]: string } }): AddSpanEventRequest {
270
- const request = new AddSpanEventRequest();
271
- request.setTraceId(traceId);
272
- request.setSpanId(spanId);
273
- request.setEventName(eventName);
274
- const eventAttrs = request.getAttributesMap();
275
- if (attr) {
276
- Object.entries(attr).forEach(([key, value]) => {
277
- eventAttrs.set(key, typeof value === 'object' ? JSON.stringify(value) : String(value));
278
- });
279
- }
280
- eventAttrs.set('timestamp', new Date().toISOString());
281
- return request;
256
+ addTags(tags: string[]): this {
257
+ this.tags.push(...tags);
258
+ return this;
282
259
  }
283
260
 
284
261
  /**
285
- * Add an event to a span
286
- * @param params Parameters to add an event to a span
262
+ * Add an event to the trace
263
+ * @param eventName Name of the event
264
+ * @param details Optional details (can be a JSON string or object that will be stringified)
265
+ * @param timestamp Optional timestamp (defaults to current time)
266
+ * @returns This trace builder for chaining
287
267
  */
288
- async addSpanEvent(params: AddSpanEventRequest): Promise<AddSpanEventResponse> {
289
- try {
290
- return await this.client.addSpanEvent(params, null);
291
- } catch (_error) {
292
- debugIssue("addSpanEvent", new Error('Error adding span event'));
293
- throw _error;
294
- }
268
+ addEvent(eventName: string, details?: string | object, timestamp?: Date): this {
269
+ const detailsString = typeof details === 'object' && details !== null
270
+ ? JSON.stringify(details)
271
+ : details;
272
+
273
+ this.events.push({
274
+ eventName,
275
+ details: detailsString,
276
+ timestamp: timestamp || new Date(),
277
+ });
278
+ return this;
295
279
  }
296
280
 
297
281
  /**
298
- * Creates the add span error request
299
- * @param params - params used to generate the error request ( traceid, span id, error message, error type, stack trace)
300
- * @returns AddSpanErrorRequest
282
+ * Set or update the transaction hash hint
283
+ * @param txHash Transaction hash
284
+ * @param chainId Chain ID (e.g., "ethereum", "polygon")
285
+ * @param details Optional details about the transaction
286
+ * @param timestamp Optional timestamp (defaults to current time)
287
+ * @returns This trace builder for chaining
301
288
  */
302
- createAddSpanErrorRequest({ traceId, spanId, errorMessage, errorType, stackTrace }: { traceId: string, spanId: string, errorMessage: string, errorType?: string, stackTrace?: string }): AddSpanErrorRequest {
303
- const request = new AddSpanErrorRequest();
304
- request.setTraceId(traceId);
305
- request.setSpanId(spanId);
306
- request.setMessage(errorMessage);
307
- if (errorType) {
308
- request.setErrorType(errorType);
309
- }
310
- if (stackTrace) {
311
- request.setStackTrace(stackTrace);
312
- }
313
- return request;
289
+ setTxHash(txHash: string, chainId: string, details?: string, timestamp?: Date): this {
290
+ this.txHashHint = {
291
+ txHash,
292
+ chainId,
293
+ details,
294
+ timestamp: timestamp || new Date(),
295
+ };
296
+ return this;
314
297
  }
315
298
 
316
299
  /**
317
- * Add an error to a span
318
- * @param params Parameters to add an error to a span
300
+ * Submit the trace without a transaction hash hint (if not already set via setTxHash)
301
+ * @returns Response from the create trace operation
319
302
  */
320
- async addSpanError(params: AddSpanErrorRequest): Promise<AddSpanErrorResponse> {
321
- try {
322
- return await this.client.addSpanError(params, null);
323
- } catch (_error) {
324
- debugIssue("addSpanError", new Error('Error adding span error'));
325
- throw _error;
326
- }
327
- }
303
+ async submit(): Promise<CreateTraceResponse>;
328
304
 
329
305
  /**
330
- * Creates the add span hint request
331
- * @param params - params used to generate the span hint (trace id, parentSpanId, txHash and chainId)
332
- * @returns AddSpanHintRequest
306
+ * Submit the trace with a transaction hash hint (overrides any previously set via setTxHash)
307
+ * @param txHash Transaction hash
308
+ * @param chainId Chain ID (e.g., "ethereum", "polygon")
309
+ * @param details Optional details about the transaction
310
+ * @returns Response from the create trace operation
333
311
  */
334
- createAddSpanHintRequest({ traceId, parentSpanId, txHash, chainId }: { traceId: string, parentSpanId: string, txHash?: string, chainId?: number }): AddSpanHintRequest {
335
- const hintReq = new AddSpanHintRequest();
336
- hintReq.setTraceId(traceId);
337
- hintReq.setParentSpanId(parentSpanId);
338
-
339
- if (txHash && chainId !== undefined) {
340
- const chainTxReq = new AddSpanHintRequest.ChainTransaction();
341
- chainTxReq.setTxHash(txHash);
342
- chainTxReq.setChainId(chainId);
343
- hintReq.setChainTransaction(chainTxReq);
312
+ async submit(txHash: string, chainId: string, details?: string): Promise<CreateTraceResponse>;
313
+
314
+ async submit(txHash?: string, chainId?: string, details?: string): Promise<CreateTraceResponse> {
315
+ // If txHash and chainId are provided in submit(), they override any previously set txHashHint
316
+ const finalTxHashHint = txHash && chainId ? {
317
+ txHash,
318
+ chainId,
319
+ details,
320
+ timestamp: new Date(),
321
+ } : this.txHashHint;
322
+
323
+ // Build the CreateTraceRequest
324
+ const request = new CreateTraceRequest();
325
+ request.setName(this.name);
326
+ request.setTagsList(this.tags);
327
+
328
+ // Add attributes
329
+ const attrsMap = request.getAttributesMap();
330
+ for (const [key, value] of Object.entries(this.attributes)) {
331
+ attrsMap.set(key, value);
344
332
  }
345
- return hintReq;
346
- }
347
333
 
348
- /**
349
- * Add a hint to a span
350
- * @param params Parameters to add a hint to a span
351
- */
352
- async addSpanHint(params: AddSpanHintRequest): Promise<AddSpanHintResponse> {
353
- try {
354
- return await this.client.addSpanHint(params, null);
355
- } catch (_error) {
356
- debugIssue("addSpanHint", new Error('Error adding span hint'));
357
- throw _error;
334
+ // Add client metadata if requested
335
+ if (this.includeClientMeta) {
336
+ const clientMetadata = await this.client.getClientMetadata();
337
+ for (const [key, value] of Object.entries(clientMetadata)) {
338
+ attrsMap.set(`client.${key}`, value);
339
+ }
358
340
  }
341
+
342
+ // Add events
343
+ const eventsList: CreateTraceRequest.Event[] = [];
344
+ for (const event of this.events) {
345
+ const eventMsg = new CreateTraceRequest.Event();
346
+ eventMsg.setEventName(event.eventName);
347
+ if (event.details) {
348
+ eventMsg.setDetails(event.details);
349
+ }
350
+ const timestamp = new Timestamp();
351
+ timestamp.fromDate(event.timestamp);
352
+ eventMsg.setTimestamp(timestamp);
353
+ eventsList.push(eventMsg);
354
+ }
355
+ request.setEventsList(eventsList);
356
+
357
+ // Add transaction hash hint if present
358
+ if (finalTxHashHint) {
359
+ const txHint = new CreateTraceRequest.TxHashHint();
360
+ txHint.setTxHash(finalTxHashHint.txHash);
361
+ txHint.setChainId(finalTxHashHint.chainId);
362
+ if (finalTxHashHint.details) {
363
+ txHint.setDetails(finalTxHashHint.details);
364
+ }
365
+ const timestamp = new Timestamp();
366
+ timestamp.fromDate(finalTxHashHint.timestamp);
367
+ txHint.setTimestamp(timestamp);
368
+ request.setTxHashHint(txHint);
369
+ }
370
+
371
+ return this.client.createTrace(request);
359
372
  }
360
373
  }
361
374
 
362
- export { ParallaxClient };
375
+ export { ParallaxClient, ParallaxTrace };
@@ -1,306 +0,0 @@
1
- # ParallaxService Usage Guide
2
-
3
- The `ParallaxService` provides a simplified, high-level interface for tracking transactions in web applications. It automatically manages trace lifecycle, client metadata collection, and blockchain correlation.
4
-
5
- ## Features
6
-
7
- - **Automatic Root Span Creation**: When you create a trace, a root span is automatically created (no need to call `startSpan` separately)
8
- - **Transaction Lifecycle Management**: Track transactions from initiation to completion
9
- - **Automatic Client Metadata**: Optionally includes browser, OS, IP, and other client details
10
- - **Blockchain Integration**: Associate transaction hashes with traces for correlation
11
- - **Event Tracking**: Add events at any point in the transaction lifecycle
12
- - **Error Tracking**: Proper error handling with stack traces
13
-
14
- ## Quick Start
15
-
16
- ### Using the Singleton Instance
17
-
18
- ```typescript
19
- import { parallaxService } from '@miradorlabs/parallax-web';
20
-
21
- // Start tracking a transaction
22
- const { traceId, rootSpanId, txId } = await parallaxService.startTransactionTrace(
23
- {
24
- from: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb',
25
- to: '0x8626f6940E2eb28930eFb4CeF49B2d1F2C9C1199',
26
- value: '0.1',
27
- network: 'ethereum',
28
- walletAddress: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb',
29
- },
30
- 'SendTransaction', // trace name
31
- {
32
- includeClientMeta: true, // include browser, OS, IP, etc.
33
- apiKey: 'your-api-key', // optional
34
- gatewayUrl: 'https://gateway-parallax-dev.mirador.org', // optional
35
- }
36
- );
37
-
38
- // Later, when you get the transaction hash
39
- await parallaxService.associateTransactionHash(txId, '0xabc123...', 1);
40
-
41
- // Add events
42
- await parallaxService.addTransactionEvent(txId, 'wallet_signed', {
43
- timestamp: new Date().toISOString(),
44
- });
45
-
46
- // Track errors
47
- try {
48
- // transaction logic
49
- } catch (error) {
50
- await parallaxService.addTransactionError(txId, error, 'TransactionError');
51
- }
52
-
53
- // Finish the trace
54
- await parallaxService.finishTransactionTrace(txId, {
55
- success: true,
56
- });
57
- ```
58
-
59
- ### Creating Your Own Instance
60
-
61
- ```typescript
62
- import { ParallaxService } from '@miradorlabs/parallax-web';
63
-
64
- const myService = new ParallaxService();
65
- // Use the same API as above
66
- ```
67
-
68
- ## API Reference
69
-
70
- ### `startTransactionTrace(txData, name, options)`
71
-
72
- Starts a new transaction trace with automatic root span creation.
73
-
74
- **Parameters:**
75
- - `txData`: Object with transaction details
76
- - `from`: Sender address (required)
77
- - `to`: Recipient address (required)
78
- - `value`: Transaction value (required)
79
- - `network`: Network name (optional)
80
- - `walletAddress`: Wallet address (optional)
81
- - `additionalData`: Any extra data (optional)
82
- - `name`: Trace name (default: 'WalletTransaction')
83
- - `options`: Optional configuration
84
- - `apiKey`: API key for authentication
85
- - `gatewayUrl`: Custom gateway URL
86
- - `includeClientMeta`: Include browser/OS metadata (default: true)
87
-
88
- **Returns:**
89
- ```typescript
90
- Promise<{
91
- traceId: string;
92
- rootSpanId: string; // This is the automatically created root span
93
- txId: string; // Internal transaction identifier
94
- }>
95
- ```
96
-
97
- ### `associateTransactionHash(txId, txHash, chainId)`
98
-
99
- Associates a blockchain transaction hash with the trace for correlation.
100
-
101
- **Parameters:**
102
- - `txId`: Transaction identifier from `startTransactionTrace`
103
- - `txHash`: Blockchain transaction hash
104
- - `chainId`: Chain ID (e.g., 1 for Ethereum mainnet)
105
-
106
- ### `addTransactionEvent(txId, eventName, attributes)`
107
-
108
- Adds an event to the transaction trace.
109
-
110
- **Parameters:**
111
- - `txId`: Transaction identifier
112
- - `eventName`: Event name (e.g., 'wallet_signed', 'sent_to_network')
113
- - `attributes`: Event attributes (object)
114
-
115
- ### `addTransactionError(txId, error, errorType)`
116
-
117
- Adds an error to the transaction trace with stack trace support.
118
-
119
- **Parameters:**
120
- - `txId`: Transaction identifier
121
- - `error`: Error object or message
122
- - `errorType`: Error category (default: 'TransactionError')
123
-
124
- ### `finishTransactionTrace(txId, options)`
125
-
126
- Completes the transaction trace.
127
-
128
- **Parameters:**
129
- - `txId`: Transaction identifier
130
- - `options`: Finish options
131
- - `success`: Whether transaction succeeded (required)
132
- - `error`: Error message if failed (optional)
133
-
134
- ### `getTransactionInfo(txId)`
135
-
136
- Gets information about an active transaction.
137
-
138
- **Returns:** Transaction info object or null
139
-
140
- ### `getAllActiveTransactions()`
141
-
142
- Gets all currently active transactions.
143
-
144
- **Returns:** Array of transaction info objects
145
-
146
- ### `getClient(apiKey?, gatewayUrl?)`
147
-
148
- Gets the underlying `ParallaxClient` for advanced usage.
149
-
150
- ## Important Note: Automatic Root Span Creation
151
-
152
- **The key difference** from previous versions: When you call `createTrace`, a root span is **automatically created** on the backend. You receive a `rootSpanId` in the response.
153
-
154
- You **do NOT need** to call `startSpan` after creating a trace anymore. The `rootSpanId` serves as the parent span for any child spans you want to create.
155
-
156
- ### Example of Creating Child Spans (Optional)
157
-
158
- If you need child spans for more detailed tracking:
159
-
160
- ```typescript
161
- // Start transaction (creates trace + root span automatically)
162
- const { traceId, rootSpanId, txId } = await parallaxService.startTransactionTrace(
163
- txData,
164
- 'ComplexTransaction'
165
- );
166
-
167
- // Access the underlying client for advanced usage
168
- const client = parallaxService.getClient();
169
-
170
- // Create a child span if needed
171
- const childSpanReq = await client.createStartSpanRequest({
172
- traceId: traceId,
173
- name: 'SigningPhase',
174
- parentSpanId: rootSpanId, // Use the root span as parent
175
- attr: { phase: 'signing' },
176
- });
177
-
178
- const childSpanResponse = await client.startSpan(childSpanReq);
179
- const childSpanId = childSpanResponse.getSpanId();
180
-
181
- // Later, finish the child span
182
- const finishReq = client.createFinishSpanRequest({
183
- traceId: traceId,
184
- spanId: childSpanId,
185
- status: { success: true, errorMessage: '' },
186
- });
187
-
188
- await client.finishSpan(finishReq);
189
- ```
190
-
191
- ## Client Metadata
192
-
193
- When `includeClientMeta: true`, the following metadata is automatically collected:
194
- - Browser (Chrome, Firefox, Safari, Edge)
195
- - Operating System (Windows, macOS, Linux, Android, iOS)
196
- - User Agent
197
- - Platform
198
- - Language
199
- - Screen dimensions
200
- - Viewport dimensions
201
- - Timezone
202
- - Page URL
203
- - Referrer
204
- - IP address (if not blocked by CSP)
205
-
206
- All metadata is prefixed with `client.` in attributes.
207
-
208
- ## Environment Detection
209
-
210
- The service automatically detects the environment:
211
- - **Localhost/127.0.0.1**: Uses proxy endpoint `${window.location.protocol}//${window.location.host}/parallax-gateway`
212
- - **Production**: Uses `https://gateway-parallax-dev.mirador.org`
213
-
214
- You can override this with the `gatewayUrl` option.
215
-
216
- ## Example: Complete Transaction Flow
217
-
218
- ```typescript
219
- import { parallaxService } from '@miradorlabs/parallax-web';
220
-
221
- async function handleTransaction() {
222
- let txId: string;
223
-
224
- try {
225
- // 1. Start the trace
226
- const result = await parallaxService.startTransactionTrace(
227
- {
228
- from: userAddress,
229
- to: recipientAddress,
230
- value: amount,
231
- network: 'ethereum',
232
- walletAddress: userAddress,
233
- additionalData: {
234
- gasPrice: gasPrice,
235
- gasLimit: gasLimit,
236
- },
237
- },
238
- 'SendETH',
239
- { includeClientMeta: true }
240
- );
241
-
242
- txId = result.txId;
243
-
244
- // 2. User signs the transaction
245
- await parallaxService.addTransactionEvent(txId, 'user_signing', {});
246
-
247
- const signedTx = await wallet.signTransaction(txData);
248
-
249
- await parallaxService.addTransactionEvent(txId, 'transaction_signed', {});
250
-
251
- // 3. Send to network
252
- await parallaxService.addTransactionEvent(txId, 'sending_to_network', {});
253
-
254
- const txReceipt = await provider.sendTransaction(signedTx);
255
-
256
- // 4. Associate the transaction hash
257
- await parallaxService.associateTransactionHash(
258
- txId,
259
- txReceipt.hash,
260
- 1 // Ethereum mainnet
261
- );
262
-
263
- // 5. Wait for confirmation
264
- await parallaxService.addTransactionEvent(txId, 'waiting_confirmation', {
265
- txHash: txReceipt.hash,
266
- });
267
-
268
- await txReceipt.wait();
269
-
270
- // 6. Success!
271
- await parallaxService.finishTransactionTrace(txId, { success: true });
272
-
273
- } catch (error) {
274
- // Track the error
275
- if (txId) {
276
- await parallaxService.addTransactionError(txId, error, 'TransactionError');
277
- await parallaxService.finishTransactionTrace(txId, {
278
- success: false,
279
- error: error.message,
280
- });
281
- }
282
- throw error;
283
- }
284
- }
285
- ```
286
-
287
- ## TypeScript Support
288
-
289
- Full TypeScript support with exported types:
290
-
291
- ```typescript
292
- import type {
293
- CreateTraceRequest,
294
- CreateTraceResponse,
295
- StartSpanRequest,
296
- StartSpanResponse,
297
- FinishSpanRequest,
298
- FinishSpanResponse,
299
- AddSpanEventRequest,
300
- AddSpanEventResponse,
301
- AddSpanErrorRequest,
302
- AddSpanErrorResponse,
303
- AddSpanHintRequest,
304
- AddSpanHintResponse,
305
- } from '@miradorlabs/parallax-web';
306
- ```