@miradorlabs/parallax-web 1.0.7 → 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/.claude/settings.local.json +15 -0
- package/.github/dependabot.yml +39 -0
- package/.github/workflows/pr.yml +33 -0
- package/README.md +145 -280
- package/dist/index.d.ts +56 -214
- package/dist/index.esm.js +760 -1049
- package/dist/index.esm.js.map +1 -1
- package/dist/index.umd.js +764 -1054
- package/dist/index.umd.js.map +1 -1
- package/example/proxy-server.js +1 -1
- package/index.ts +2 -5
- package/package.json +4 -2
- package/scripts/release.sh +109 -0
- package/src/index.ts +2 -0
- package/src/parallax/client.ts +66 -0
- package/src/parallax/index.ts +22 -372
- package/src/parallax/metadata.ts +173 -0
- package/src/parallax/trace.ts +209 -0
- package/src/parallax/types.ts +73 -0
- package/tests/parallax.test.ts +395 -372
- package/SETUP.md +0 -220
- package/src/grpc/index.ts +0 -155
- package/src/helpers/index.ts +0 -13
- package/src/parallax/ParallaxService.ts +0 -296
package/example/proxy-server.js
CHANGED
|
@@ -17,7 +17,7 @@ const GATEWAY_URL = 'https://parallax-gateway.dev.mirador.org:443';
|
|
|
17
17
|
app.use(cors({
|
|
18
18
|
origin: '*',
|
|
19
19
|
methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
|
|
20
|
-
allowedHeaders: ['Content-Type', 'x-grpc-web', 'x-user-agent', 'x-api-key'],
|
|
20
|
+
allowedHeaders: ['Content-Type', 'x-grpc-web', 'x-user-agent', 'x-parallax-api-key'],
|
|
21
21
|
exposedHeaders: ['grpc-status', 'grpc-message'],
|
|
22
22
|
credentials: true
|
|
23
23
|
}));
|
package/index.ts
CHANGED
|
@@ -1,8 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
export {
|
|
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": "
|
|
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.
|
|
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,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
|
+
}
|
package/src/parallax/index.ts
CHANGED
|
@@ -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-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
|
-
*
|
|
196
|
-
*
|
|
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
|
-
|
|
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';
|