@miradorlabs/parallax-web 1.0.2 → 1.0.4
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/dist/index.d.ts +92 -0
- package/dist/index.esm.js +453 -525
- package/dist/index.esm.js.map +1 -1
- package/dist/index.umd.js +4706 -4778
- package/dist/index.umd.js.map +1 -1
- package/package.json +2 -2
- package/src/parallax/index.ts +241 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@miradorlabs/parallax-web",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.4",
|
|
4
4
|
"description": "Parallax Web Client Side SDK ",
|
|
5
5
|
"main": "dist/index.umd.js",
|
|
6
6
|
"module": "dist/index.esm.js",
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
"typescript-eslint": "^8.47.0"
|
|
45
45
|
},
|
|
46
46
|
"dependencies": {
|
|
47
|
-
"google-protobuf": "^
|
|
47
|
+
"google-protobuf": "^3.21.4",
|
|
48
48
|
"grpc-web": "^2.0.2",
|
|
49
49
|
"mirador-gateway-parallax-web": "https://storage.googleapis.com/mirador-shd-packages/gateway/parallax/grpc-web/mirador-gateway-parallax-grpc-web-1.0.9.tgz",
|
|
50
50
|
"rxjs": "^7.8.2"
|
package/src/parallax/index.ts
CHANGED
|
@@ -38,6 +38,129 @@ class ParallaxClient {
|
|
|
38
38
|
this.client = new ParallaxGatewayServiceClient(this.apiUrl, credentials);
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
+
/**
|
|
42
|
+
* Gather client metadata for traces/spans
|
|
43
|
+
* Returns a metadata object with client environment details
|
|
44
|
+
* This includes browser, OS, screen size, IP address, and more
|
|
45
|
+
* @returns metadata
|
|
46
|
+
*/
|
|
47
|
+
async getClientMetadata(): Promise<{ [key: string]: string }> {
|
|
48
|
+
const metadata: { [key: string]: string } = {};
|
|
49
|
+
// Browser info
|
|
50
|
+
metadata.userAgent = navigator.userAgent;
|
|
51
|
+
metadata.platform = navigator.platform;
|
|
52
|
+
metadata.language = navigator.language;
|
|
53
|
+
|
|
54
|
+
// Screen info
|
|
55
|
+
metadata.screenWidth = window.screen.width.toString();
|
|
56
|
+
metadata.screenHeight = window.screen.height.toString();
|
|
57
|
+
metadata.viewportWidth = window.innerWidth.toString();
|
|
58
|
+
metadata.viewportHeight = window.innerHeight.toString();
|
|
59
|
+
|
|
60
|
+
// Try to get IP address (non-blocking)
|
|
61
|
+
// Note: This may be blocked by Content Security Policy (CSP)
|
|
62
|
+
// If blocked, the backend should capture IP from request headers instead
|
|
63
|
+
try {
|
|
64
|
+
// Use ipify API (simple and fast JSON response)
|
|
65
|
+
const ipResponse: Response | Error = await fetch('https://api.ipify.org?format=json');
|
|
66
|
+
|
|
67
|
+
if (ipResponse && ipResponse.ok) {
|
|
68
|
+
const data = await ipResponse.json();
|
|
69
|
+
if (data && data.ip) {
|
|
70
|
+
metadata.ip = data.ip;
|
|
71
|
+
} else {
|
|
72
|
+
metadata.ip = 'client_unavailable';
|
|
73
|
+
}
|
|
74
|
+
} else {
|
|
75
|
+
metadata.ip = 'client_unavailable';
|
|
76
|
+
}
|
|
77
|
+
} catch (error) {
|
|
78
|
+
// IP lookup failed (CSP block, timeout, or network error)
|
|
79
|
+
// This is expected if CSP blocks external requests
|
|
80
|
+
// Backend should capture IP from request headers instead
|
|
81
|
+
if (error instanceof Error && error.message.includes('Content Security Policy')) {
|
|
82
|
+
console.debug('IP fetch blocked by CSP - backend will capture from headers');
|
|
83
|
+
} else {
|
|
84
|
+
console.debug('Could not fetch IP address');
|
|
85
|
+
}
|
|
86
|
+
metadata.ip = 'client_unavailable';
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Browser details (parse from user agent)
|
|
90
|
+
const ua = navigator.userAgent;
|
|
91
|
+
if (ua.includes('Chrome')) {
|
|
92
|
+
metadata.browser = 'Chrome';
|
|
93
|
+
} else if (ua.includes('Firefox')) {
|
|
94
|
+
metadata.browser = 'Firefox';
|
|
95
|
+
} else if (ua.includes('Safari')) {
|
|
96
|
+
metadata.browser = 'Safari';
|
|
97
|
+
} else if (ua.includes('Edge')) {
|
|
98
|
+
metadata.browser = 'Edge';
|
|
99
|
+
} else {
|
|
100
|
+
metadata.browser = 'Unknown';
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// OS detection
|
|
104
|
+
if (ua.includes('Windows')) {
|
|
105
|
+
metadata.os = 'Windows';
|
|
106
|
+
} else if (ua.includes('Mac')) {
|
|
107
|
+
metadata.os = 'macOS';
|
|
108
|
+
} else if (ua.includes('Linux')) {
|
|
109
|
+
metadata.os = 'Linux';
|
|
110
|
+
} else if (ua.includes('Android')) {
|
|
111
|
+
metadata.os = 'Android';
|
|
112
|
+
} else if (ua.includes('iOS')) {
|
|
113
|
+
metadata.os = 'iOS';
|
|
114
|
+
} else {
|
|
115
|
+
metadata.os = 'Unknown';
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Timezone
|
|
119
|
+
metadata.timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
120
|
+
metadata.timezoneOffset = new Date().getTimezoneOffset().toString();
|
|
121
|
+
|
|
122
|
+
// Page info
|
|
123
|
+
metadata.url = window.location.href;
|
|
124
|
+
metadata.referrer = document.referrer || 'direct';
|
|
125
|
+
|
|
126
|
+
return metadata;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Creates a CreateTraceRequest with optional attributes and client metadata
|
|
131
|
+
* @param name name of the trace
|
|
132
|
+
* @param tags optional tags for trace
|
|
133
|
+
* @param attr optional attributes for trace
|
|
134
|
+
* @param includeClientMeta optional flag to include client metadata (ip, browser, os, etc)
|
|
135
|
+
* @returns a CreateTraceRequest object to be used for the createTrace request
|
|
136
|
+
*/
|
|
137
|
+
async createTraceRequest({name, tags, attr, includeClientMeta = false}: {name: string, tags?: string[], attr?: { [key: string]: string }, includeClientMeta?: boolean}): Promise<CreateTraceRequest> {
|
|
138
|
+
const createTraceReq = new CreateTraceRequest();
|
|
139
|
+
createTraceReq.setName(name);
|
|
140
|
+
if (tags) {
|
|
141
|
+
createTraceReq.setTagsList(tags);
|
|
142
|
+
}
|
|
143
|
+
const traceAttrs = createTraceReq.getAttributesMap();
|
|
144
|
+
|
|
145
|
+
if (attr) {
|
|
146
|
+
Object.entries(attr).forEach(([key, value]) => {
|
|
147
|
+
if (key.includes('client.')) {
|
|
148
|
+
console.warn(`Attribute key "${key}" is reserved for client metadata. It will be prefixed with "custom."`);
|
|
149
|
+
} else {
|
|
150
|
+
traceAttrs.set(key, typeof value === 'object' ? JSON.stringify(value) : String(value));
|
|
151
|
+
}
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
if (includeClientMeta) {
|
|
155
|
+
const clientMetadata = await this.getClientMetadata();
|
|
156
|
+
Object.entries(clientMetadata).forEach(([key, value]) => {
|
|
157
|
+
traceAttrs.set(`client.${key}`, value);
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
return createTraceReq;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
|
|
41
164
|
/**
|
|
42
165
|
* Create a new trace
|
|
43
166
|
* @param params Parameters to create a new trace
|
|
@@ -52,6 +175,46 @@ class ParallaxClient {
|
|
|
52
175
|
}
|
|
53
176
|
}
|
|
54
177
|
|
|
178
|
+
/**
|
|
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
|
|
186
|
+
*/
|
|
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();
|
|
195
|
+
|
|
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;
|
|
216
|
+
}
|
|
217
|
+
|
|
55
218
|
/**
|
|
56
219
|
* Start a new span within a trace
|
|
57
220
|
* @param params Parameters to start a new span
|
|
@@ -65,6 +228,26 @@ class ParallaxClient {
|
|
|
65
228
|
}
|
|
66
229
|
}
|
|
67
230
|
|
|
231
|
+
/**
|
|
232
|
+
* Create a FinishSpanRequest
|
|
233
|
+
* @param params Parameters to finish a span - traceId, spanId, status (optional) (success, errorMessage)
|
|
234
|
+
* @returns FinishSpanRequest
|
|
235
|
+
*/
|
|
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);
|
|
247
|
+
}
|
|
248
|
+
return request;
|
|
249
|
+
}
|
|
250
|
+
|
|
68
251
|
/**
|
|
69
252
|
* Finish a span within a trace
|
|
70
253
|
* @param params Parameters to finish a span
|
|
@@ -78,6 +261,26 @@ class ParallaxClient {
|
|
|
78
261
|
}
|
|
79
262
|
}
|
|
80
263
|
|
|
264
|
+
/**
|
|
265
|
+
* Creates the add span event request
|
|
266
|
+
* @param params - Parameters to create an AddSpanEventRequest - traceId, spanId, eventName, attr (optional)
|
|
267
|
+
* @returns AddSpanEventRequest
|
|
268
|
+
*/
|
|
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;
|
|
282
|
+
}
|
|
283
|
+
|
|
81
284
|
/**
|
|
82
285
|
* Add an event to a span
|
|
83
286
|
* @param params Parameters to add an event to a span
|
|
@@ -91,6 +294,25 @@ class ParallaxClient {
|
|
|
91
294
|
}
|
|
92
295
|
}
|
|
93
296
|
|
|
297
|
+
/**
|
|
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
|
|
301
|
+
*/
|
|
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;
|
|
314
|
+
}
|
|
315
|
+
|
|
94
316
|
/**
|
|
95
317
|
* Add an error to a span
|
|
96
318
|
* @param params Parameters to add an error to a span
|
|
@@ -104,6 +326,25 @@ class ParallaxClient {
|
|
|
104
326
|
}
|
|
105
327
|
}
|
|
106
328
|
|
|
329
|
+
/**
|
|
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
|
|
333
|
+
*/
|
|
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);
|
|
344
|
+
}
|
|
345
|
+
return hintReq;
|
|
346
|
+
}
|
|
347
|
+
|
|
107
348
|
/**
|
|
108
349
|
* Add a hint to a span
|
|
109
350
|
* @param params Parameters to add a hint to a span
|