@miradorlabs/parallax-web 1.0.8 → 2.0.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/index.ts CHANGED
@@ -1,8 +1,5 @@
1
- export * from './src/parallax';
2
- export { GrpcWebRpc } from './src/grpc';
3
-
4
- // Export ParallaxService
5
- export { ParallaxService, parallaxService } from './src/parallax/ParallaxService';
1
+ // Core SDK exports
2
+ export { ParallaxClient, ParallaxTrace } from './src/parallax';
6
3
 
7
4
  // Re-export proto types for convenience
8
5
  export {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@miradorlabs/parallax-web",
3
- "version": "1.0.8",
3
+ "version": "2.0.0",
4
4
  "description": "Parallax Web Client Side SDK ",
5
5
  "main": "dist/index.umd.js",
6
6
  "module": "dist/index.esm.js",
@@ -13,6 +13,8 @@
13
13
  "scripts": {
14
14
  "prepare": "npm run build",
15
15
  "build": "rm -rf dist/ && rollup -c",
16
+ "lint": "eslint src/ tests/",
17
+ "lint:fix": "eslint src/ tests/ --fix",
16
18
  "test": "jest",
17
19
  "test:watch": "jest --watch",
18
20
  "test:coverage": "jest --coverage",
@@ -47,7 +49,7 @@
47
49
  "dependencies": {
48
50
  "google-protobuf": "^3.21.4",
49
51
  "grpc-web": "^2.0.2",
50
- "mirador-gateway-parallax-web": "https://storage.googleapis.com/mirador-shd-packages/gateway/parallax/grpc-web/mirador-gateway-parallax-grpc-web-1.0.11.tgz",
52
+ "mirador-gateway-parallax-web": "https://storage.googleapis.com/mirador-shd-packages/gateway/parallax/grpc-web/mirador-gateway-parallax-grpc-web-1.0.13.tgz",
51
53
  "rxjs": "^7.8.2"
52
54
  },
53
55
  "author": "@mirador",
@@ -0,0 +1,109 @@
1
+ #!/bin/bash
2
+
3
+ set -e
4
+
5
+ # Colors for output
6
+ RED='\033[0;31m'
7
+ GREEN='\033[0;32m'
8
+ YELLOW='\033[1;33m'
9
+ BLUE='\033[0;34m'
10
+ NC='\033[0m' # No Color
11
+
12
+ echo -e "${BLUE}========================================${NC}"
13
+ echo -e "${BLUE} Parallax Web Client Release Script${NC}"
14
+ echo -e "${BLUE}========================================${NC}"
15
+ echo ""
16
+
17
+ # Check if logged in to npm
18
+ echo -e "${YELLOW}Checking npm login status...${NC}"
19
+ if ! npm whoami &> /dev/null; then
20
+ echo -e "${RED}Not logged in to npm. Starting login...${NC}"
21
+ npm login
22
+ echo ""
23
+ fi
24
+
25
+ NPM_USER=$(npm whoami)
26
+ echo -e "${GREEN}Logged in as: ${NPM_USER}${NC}"
27
+ echo ""
28
+
29
+ # Get current version
30
+ CURRENT_VERSION=$(node -p "require('./package.json').version")
31
+ echo -e "Current version: ${YELLOW}${CURRENT_VERSION}${NC}"
32
+
33
+ # Parse version components
34
+ IFS='.' read -r MAJOR MINOR PATCH <<< "$CURRENT_VERSION"
35
+
36
+ # Calculate next versions
37
+ NEXT_PATCH="$MAJOR.$MINOR.$((PATCH + 1))"
38
+ NEXT_MINOR="$MAJOR.$((MINOR + 1)).0"
39
+ NEXT_MAJOR="$((MAJOR + 1)).0.0"
40
+
41
+ echo ""
42
+ echo -e "${BLUE}Select release type:${NC}"
43
+ echo -e " ${GREEN}1)${NC} patch → ${NEXT_PATCH} (bug fixes)"
44
+ echo -e " ${GREEN}2)${NC} minor → ${NEXT_MINOR} (new features, backwards compatible)"
45
+ echo -e " ${GREEN}3)${NC} major → ${NEXT_MAJOR} (breaking changes)"
46
+ echo -e " ${GREEN}4)${NC} cancel"
47
+ echo ""
48
+
49
+ read -p "Enter choice [1-4]: " choice
50
+
51
+ case $choice in
52
+ 1)
53
+ RELEASE_TYPE="patch"
54
+ NEXT_VERSION=$NEXT_PATCH
55
+ ;;
56
+ 2)
57
+ RELEASE_TYPE="minor"
58
+ NEXT_VERSION=$NEXT_MINOR
59
+ ;;
60
+ 3)
61
+ RELEASE_TYPE="major"
62
+ NEXT_VERSION=$NEXT_MAJOR
63
+ ;;
64
+ 4)
65
+ echo -e "${YELLOW}Release cancelled.${NC}"
66
+ exit 0
67
+ ;;
68
+ *)
69
+ echo -e "${RED}Invalid choice. Exiting.${NC}"
70
+ exit 1
71
+ ;;
72
+ esac
73
+
74
+ echo ""
75
+ echo -e "${YELLOW}Releasing version ${NEXT_VERSION}...${NC}"
76
+ echo ""
77
+
78
+ # Check for uncommitted changes
79
+ if [[ -n $(git status --porcelain) ]]; then
80
+ echo -e "${RED}Error: You have uncommitted changes.${NC}"
81
+ echo "Please commit or stash your changes before releasing."
82
+ git status --short
83
+ exit 1
84
+ fi
85
+
86
+ # Run tests
87
+ echo -e "${BLUE}Running tests...${NC}"
88
+ npm test
89
+
90
+ # Build
91
+ echo -e "${BLUE}Building...${NC}"
92
+ npm run build
93
+
94
+ # Bump version and create git tag
95
+ echo -e "${BLUE}Bumping version...${NC}"
96
+ npm version $RELEASE_TYPE
97
+
98
+ # Push to git with tags
99
+ echo -e "${BLUE}Pushing to git...${NC}"
100
+ git push --follow-tags
101
+
102
+ # Publish to npm
103
+ echo -e "${BLUE}Publishing to npm...${NC}"
104
+ npm publish
105
+
106
+ echo ""
107
+ echo -e "${GREEN}========================================${NC}"
108
+ echo -e "${GREEN} Successfully released v${NEXT_VERSION}${NC}"
109
+ echo -e "${GREEN}========================================${NC}"
package/src/index.ts ADDED
@@ -0,0 +1,2 @@
1
+ // Parallax Web Client SDK - Public API
2
+ export * from './parallax';
@@ -0,0 +1,66 @@
1
+ /**
2
+ * ParallaxClient - Main client for interacting with the Parallax Gateway
3
+ */
4
+ import { CreateTraceRequest } from 'mirador-gateway-parallax-web/proto/gateway/parallax/v1/parallax_gateway_pb';
5
+ import { ParallaxGatewayServiceClient } from 'mirador-gateway-parallax-web/proto/gateway/parallax/v1/Parallax_gatewayServiceClientPb';
6
+ import { ParallaxTrace } from './trace';
7
+
8
+ const DEFAULT_API_URL = 'https://parallax-gateway.dev.mirador.org:443';
9
+
10
+ /**
11
+ * Main client for interacting with the Parallax Gateway API
12
+ */
13
+ export class ParallaxClient {
14
+ public apiUrl: string;
15
+ public apiKey: string;
16
+ private client: ParallaxGatewayServiceClient;
17
+
18
+ /**
19
+ * Create a new ParallaxClient instance
20
+ * @param apiKey Required API key for authentication (sent as x-parallax-api-key header)
21
+ * @param apiUrl Optional gateway URL (defaults to parallax-gateway.dev.mirador.org:443)
22
+ */
23
+ constructor(apiKey: string, apiUrl?: string) {
24
+ this.apiKey = apiKey;
25
+ this.apiUrl = apiUrl || DEFAULT_API_URL;
26
+
27
+ // API key is required - always include in credentials
28
+ const credentials = { 'x-parallax-api-key': apiKey };
29
+
30
+ // Initialize the gRPC-Web client
31
+ this.client = new ParallaxGatewayServiceClient(this.apiUrl, credentials);
32
+ }
33
+
34
+ /**
35
+ * Internal method to send trace to gateway
36
+ * @internal
37
+ */
38
+ async _sendTrace(request: CreateTraceRequest) {
39
+ const metadata = { 'x-parallax-api-key': this.apiKey };
40
+ return await this.client.createTrace(request, metadata);
41
+ }
42
+
43
+ /**
44
+ * Create a new trace builder
45
+ *
46
+ * Example usage:
47
+ * ```typescript
48
+ * const response = await client.trace("swap_execution")
49
+ * .addAttribute("user", "0xabc...")
50
+ * .addAttribute("slippage_bps", 25)
51
+ * .addTag("dex")
52
+ * .addTag("swap")
53
+ * .addEvent("wallet_connected", { wallet: "MetaMask" })
54
+ * .addEvent("quote_received")
55
+ * .setTxHint("0x123...", "ethereum")
56
+ * .create();
57
+ * ```
58
+ *
59
+ * @param name Optional name of the trace (defaults to empty string)
60
+ * @param includeClientMeta Optional flag to automatically include client metadata
61
+ * @returns A ParallaxTrace builder instance
62
+ */
63
+ trace(name: string = '', includeClientMeta: boolean = true): ParallaxTrace {
64
+ return new ParallaxTrace(this, name, includeClientMeta);
65
+ }
66
+ }
@@ -1,375 +1,25 @@
1
- // Parallax SDK Web Client
2
- import {
3
- CreateTraceRequest,
4
- CreateTraceResponse,
5
- } from "mirador-gateway-parallax-web/proto/gateway/parallax/v1/parallax_gateway_pb";
6
- import { ParallaxGatewayServiceClient } from "mirador-gateway-parallax-web/proto/gateway/parallax/v1/Parallax_gatewayServiceClientPb";
7
- import { Timestamp } from "google-protobuf/google/protobuf/timestamp_pb";
8
-
9
- const GRPC_GATEWAY_API_URL = "https://parallax-gateway.dev.mirador.org:443";
10
-
11
- const debugIssue = (trace: string, error: Error) => {
12
- // Handle our own debugging / logging here
13
- console.error(`[ParallaxClient][${trace}] Error:`, error);
14
- }
15
-
16
- class ParallaxClient {
17
- public apiUrl: string = GRPC_GATEWAY_API_URL;
18
- private client: ParallaxGatewayServiceClient;
19
-
20
- constructor(public apiKey?: string, apiUrl?: string) {
21
- if (apiUrl) {
22
- this.apiUrl = apiUrl;
23
- }
24
-
25
- // Create credentials object with API key if provided
26
- const credentials = apiKey ? { 'x-parallax-api-key': apiKey } : undefined;
27
-
28
- // Initialize the gRPC-Web client
29
- this.client = new ParallaxGatewayServiceClient(this.apiUrl, credentials);
30
- }
31
-
32
- /**
33
- * Gather client metadata for traces/spans
34
- * Returns a metadata object with client environment details
35
- * This includes browser, OS, screen size, IP address, and more
36
- * @returns metadata
37
- */
38
- async getClientMetadata(): Promise<{ [key: string]: string }> {
39
- const metadata: { [key: string]: string } = {};
40
- // Browser info
41
- metadata.userAgent = navigator.userAgent;
42
- metadata.platform = navigator.platform;
43
- metadata.language = navigator.language;
44
-
45
- // Screen info
46
- metadata.screenWidth = window.screen.width.toString();
47
- metadata.screenHeight = window.screen.height.toString();
48
- metadata.viewportWidth = window.innerWidth.toString();
49
- metadata.viewportHeight = window.innerHeight.toString();
50
-
51
- // Try to get IP address (non-blocking)
52
- // Note: This may be blocked by Content Security Policy (CSP)
53
- // If blocked, the backend should capture IP from request headers instead
54
- try {
55
- // Use ipify API (simple and fast JSON response)
56
- const ipResponse: Response | Error = await fetch('https://api.ipify.org?format=json');
57
-
58
- if (ipResponse && ipResponse.ok) {
59
- const data = await ipResponse.json();
60
- if (data && data.ip) {
61
- metadata.ip = data.ip;
62
- } else {
63
- metadata.ip = 'client_unavailable';
64
- }
65
- } else {
66
- metadata.ip = 'client_unavailable';
67
- }
68
- } catch (error) {
69
- // IP lookup failed (CSP block, timeout, or network error)
70
- // This is expected if CSP blocks external requests
71
- // Backend should capture IP from request headers instead
72
- if (error instanceof Error && error.message.includes('Content Security Policy')) {
73
- console.debug('IP fetch blocked by CSP - backend will capture from headers');
74
- } else {
75
- console.debug('Could not fetch IP address');
76
- }
77
- metadata.ip = 'client_unavailable';
78
- }
79
-
80
- // Browser details (parse from user agent)
81
- const ua = navigator.userAgent;
82
- if (ua.includes('Chrome')) {
83
- metadata.browser = 'Chrome';
84
- } else if (ua.includes('Firefox')) {
85
- metadata.browser = 'Firefox';
86
- } else if (ua.includes('Safari')) {
87
- metadata.browser = 'Safari';
88
- } else if (ua.includes('Edge')) {
89
- metadata.browser = 'Edge';
90
- } else {
91
- metadata.browser = 'Unknown';
92
- }
93
-
94
- // OS detection
95
- if (ua.includes('Windows')) {
96
- metadata.os = 'Windows';
97
- } else if (ua.includes('Mac')) {
98
- metadata.os = 'macOS';
99
- } else if (ua.includes('Linux')) {
100
- metadata.os = 'Linux';
101
- } else if (ua.includes('Android')) {
102
- metadata.os = 'Android';
103
- } else if (ua.includes('iOS')) {
104
- metadata.os = 'iOS';
105
- } else {
106
- metadata.os = 'Unknown';
107
- }
108
-
109
- // Timezone
110
- metadata.timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
111
- metadata.timezoneOffset = new Date().getTimezoneOffset().toString();
112
-
113
- // Page info
114
- metadata.url = window.location.href;
115
- metadata.referrer = document.referrer || 'direct';
116
-
117
- return metadata;
118
- }
119
-
120
- /**
121
- * Creates a CreateTraceRequest with optional attributes and client metadata
122
- * @param name name of the trace
123
- * @param tags optional tags for trace
124
- * @param attr optional attributes for trace
125
- * @param includeClientMeta optional flag to include client metadata (ip, browser, os, etc)
126
- * @returns a CreateTraceRequest object to be used for the createTrace request
127
- */
128
- async createTraceRequest({name, tags, attr, includeClientMeta = false}: {name: string, tags?: string[], attr?: { [key: string]: string }, includeClientMeta?: boolean}): Promise<CreateTraceRequest> {
129
- const createTraceReq = new CreateTraceRequest();
130
- createTraceReq.setName(name);
131
- if (tags) {
132
- createTraceReq.setTagsList(tags);
133
- }
134
- const traceAttrs = createTraceReq.getAttributesMap();
135
-
136
- if (attr) {
137
- Object.entries(attr).forEach(([key, value]) => {
138
- if (key.includes('client.')) {
139
- console.warn(`Attribute key "${key}" is reserved for client metadata. It will be prefixed with "custom."`);
140
- } else {
141
- traceAttrs.set(key, typeof value === 'object' ? JSON.stringify(value) : String(value));
142
- }
143
- });
144
- }
145
- if (includeClientMeta) {
146
- const clientMetadata = await this.getClientMetadata();
147
- Object.entries(clientMetadata).forEach(([key, value]) => {
148
- traceAttrs.set(`client.${key}`, value);
149
- });
150
- }
151
- return createTraceReq;
152
- }
153
-
154
-
155
- /**
156
- * Create a new trace
157
- * @param params Parameters to create a new trace
158
- * @returns Response from the create trace operation
159
- */
160
- async createTrace(params: CreateTraceRequest): Promise<CreateTraceResponse> {
161
- try {
162
- return await this.client.createTrace(params, null);
163
- } catch (_error) {
164
- debugIssue("createTrace", new Error('Error creating trace'));
165
- throw _error;
166
- }
167
- }
168
-
169
- /**
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
187
- */
188
- trace(name: string, includeClientMeta: boolean = false): ParallaxTrace {
189
- return new ParallaxTrace(this, name, includeClientMeta);
190
- }
191
-
192
- }
193
-
194
1
  /**
195
- * Builder class for constructing traces with method chaining
196
- * Automatically handles web-specific features like client metadata
2
+ * Parallax Web Client SDK
3
+ * Browser SDK for the Parallax tracing platform
197
4
  */
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
- }
217
-
218
- /**
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
223
- */
224
- addAttribute(key: string, value: string | number | boolean): this {
225
- this.attributes[key] = String(value);
226
- return this;
227
- }
228
-
229
- /**
230
- * Add multiple attributes to the trace
231
- * @param attributes Object containing key-value pairs
232
- * @returns This trace builder for chaining
233
- */
234
- addAttributes(attributes: { [key: string]: string | number | boolean }): this {
235
- for (const [key, value] of Object.entries(attributes)) {
236
- this.attributes[key] = String(value);
237
- }
238
- return this;
239
- }
240
-
241
- /**
242
- * Add a tag to the trace
243
- * @param tag Tag to add
244
- * @returns This trace builder for chaining
245
- */
246
- addTag(tag: string): this {
247
- this.tags.push(tag);
248
- return this;
249
- }
250
-
251
- /**
252
- * Add multiple tags to the trace
253
- * @param tags Array of tags to add
254
- * @returns This trace builder for chaining
255
- */
256
- addTags(tags: string[]): this {
257
- this.tags.push(...tags);
258
- return this;
259
- }
260
-
261
- /**
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
267
- */
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;
279
- }
280
-
281
- /**
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
288
- */
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;
297
- }
298
-
299
- /**
300
- * Submit the trace without a transaction hash hint (if not already set via setTxHash)
301
- * @returns Response from the create trace operation
302
- */
303
- async submit(): Promise<CreateTraceResponse>;
304
-
305
- /**
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
311
- */
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);
332
- }
333
-
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
- }
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);
372
- }
373
- }
374
5
 
375
- export { ParallaxClient, ParallaxTrace };
6
+ // Classes
7
+ export { ParallaxClient } from './client';
8
+ export { ParallaxTrace } from './trace';
9
+
10
+ // Types
11
+ export type {
12
+ ParallaxClientConfig,
13
+ ClientMetadata,
14
+ TraceEvent,
15
+ TxHashHint,
16
+ ChainName,
17
+ } from './types';
18
+
19
+ // Metadata utilities (for advanced usage)
20
+ export {
21
+ getClientMetadata,
22
+ detectBrowser,
23
+ detectOS,
24
+ detectDeviceType,
25
+ } from './metadata';