@lavarage/telemetry 1.2.0 → 1.2.1
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.js +100 -10
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -124,16 +124,57 @@ class LavarageTelemetry {
|
|
|
124
124
|
}
|
|
125
125
|
shouldCaptureHost(url) {
|
|
126
126
|
try {
|
|
127
|
-
|
|
128
|
-
|
|
127
|
+
// Skip empty or invalid URLs
|
|
128
|
+
if (!url || url.trim() === '') {
|
|
129
|
+
return false;
|
|
130
|
+
}
|
|
131
|
+
// Resolve relative URLs to absolute URLs
|
|
132
|
+
let absoluteUrl;
|
|
133
|
+
try {
|
|
134
|
+
// Try to parse as absolute URL first
|
|
135
|
+
new URL(url);
|
|
136
|
+
absoluteUrl = url;
|
|
137
|
+
}
|
|
138
|
+
catch {
|
|
139
|
+
// If it fails, it's likely a relative URL - resolve it using current origin
|
|
140
|
+
if (typeof window !== 'undefined' && window.location) {
|
|
141
|
+
try {
|
|
142
|
+
absoluteUrl = new URL(url, window.location.origin).href;
|
|
143
|
+
}
|
|
144
|
+
catch {
|
|
145
|
+
// Still can't resolve, don't capture
|
|
146
|
+
return false;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
else {
|
|
150
|
+
// Not in browser environment, can't resolve relative URLs
|
|
151
|
+
return false;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
const urlObj = new URL(absoluteUrl);
|
|
155
|
+
let hostname = urlObj.hostname;
|
|
156
|
+
// Handle special URL types that don't have a hostname (data:, blob:, etc.)
|
|
157
|
+
if (!hostname || hostname === '') {
|
|
158
|
+
// For include mode, don't capture URLs without hostnames
|
|
159
|
+
// For exclude mode, these would be captured (but they're unlikely to be in exclude list)
|
|
160
|
+
return false;
|
|
161
|
+
}
|
|
162
|
+
// Remove port number if present (hostname property should already exclude it, but be defensive)
|
|
163
|
+
// Also normalize: lowercase and trim
|
|
164
|
+
hostname = hostname.split(':')[0].toLowerCase().trim();
|
|
129
165
|
const { mode, hosts = [], patterns = [] } = this.hostFilter;
|
|
130
166
|
if (mode === 'all')
|
|
131
167
|
return true;
|
|
132
168
|
if (mode === 'none')
|
|
133
169
|
return false;
|
|
134
|
-
//
|
|
170
|
+
// In include mode, if no hosts or patterns are specified, don't capture anything
|
|
171
|
+
if (mode === 'include' && hosts.length === 0 && patterns.length === 0) {
|
|
172
|
+
return false;
|
|
173
|
+
}
|
|
174
|
+
// Check host patterns (normalize them too)
|
|
135
175
|
for (const host of hosts) {
|
|
136
|
-
|
|
176
|
+
const normalizedHost = host.toLowerCase().trim();
|
|
177
|
+
if (this.matchesHost(hostname, normalizedHost)) {
|
|
137
178
|
return mode === 'include';
|
|
138
179
|
}
|
|
139
180
|
}
|
|
@@ -159,16 +200,26 @@ class LavarageTelemetry {
|
|
|
159
200
|
}
|
|
160
201
|
}
|
|
161
202
|
matchesHost(hostname, pattern) {
|
|
203
|
+
// Normalize inputs (should already be normalized, but be defensive)
|
|
204
|
+
hostname = hostname.toLowerCase().trim();
|
|
205
|
+
pattern = pattern.toLowerCase().trim();
|
|
162
206
|
// Exact match
|
|
163
207
|
if (hostname === pattern)
|
|
164
208
|
return true;
|
|
165
209
|
// Wildcard subdomain: *.example.com
|
|
166
210
|
if (pattern.startsWith('*.')) {
|
|
167
|
-
const domain = pattern.substring(2);
|
|
211
|
+
const domain = pattern.substring(2).toLowerCase().trim();
|
|
212
|
+
// Match exact domain or any subdomain
|
|
168
213
|
return hostname === domain || hostname.endsWith('.' + domain);
|
|
169
214
|
}
|
|
170
215
|
// Domain match (matches domain and all subdomains)
|
|
171
|
-
|
|
216
|
+
// e.g., 'lavarave.wtf' matches 'lavarave.wtf' and 'api.lavarave.wtf'
|
|
217
|
+
if (hostname === pattern) {
|
|
218
|
+
return true;
|
|
219
|
+
}
|
|
220
|
+
// Check if hostname is a subdomain of pattern
|
|
221
|
+
// e.g., 'api.lavarave.wtf' ends with '.lavarave.wtf'
|
|
222
|
+
if (hostname.endsWith('.' + pattern)) {
|
|
172
223
|
return true;
|
|
173
224
|
}
|
|
174
225
|
return false;
|
|
@@ -502,16 +553,53 @@ class LavarageTelemetry {
|
|
|
502
553
|
}
|
|
503
554
|
// Request interceptor
|
|
504
555
|
axiosInstance.interceptors.request.use((config) => {
|
|
505
|
-
|
|
556
|
+
// Construct full URL from axios config
|
|
557
|
+
let url;
|
|
558
|
+
try {
|
|
559
|
+
if (config.url) {
|
|
560
|
+
// If url is absolute (starts with http:// or https://), use it directly
|
|
561
|
+
if (config.url.startsWith('http://') || config.url.startsWith('https://')) {
|
|
562
|
+
url = config.url;
|
|
563
|
+
}
|
|
564
|
+
else if (config.baseURL) {
|
|
565
|
+
// Relative URL with baseURL - use URL constructor to properly combine them
|
|
566
|
+
try {
|
|
567
|
+
url = new URL(config.url, config.baseURL).href;
|
|
568
|
+
}
|
|
569
|
+
catch {
|
|
570
|
+
// Fallback to manual concatenation if URL constructor fails
|
|
571
|
+
const base = config.baseURL.endsWith('/') ? config.baseURL.slice(0, -1) : config.baseURL;
|
|
572
|
+
const path = config.url.startsWith('/') ? config.url : '/' + config.url;
|
|
573
|
+
url = base + path;
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
else {
|
|
577
|
+
// Relative URL without baseURL - will be resolved in shouldCaptureHost
|
|
578
|
+
url = config.url;
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
else if (config.baseURL) {
|
|
582
|
+
url = config.baseURL;
|
|
583
|
+
}
|
|
584
|
+
else {
|
|
585
|
+
// No URL and no baseURL - skip capture
|
|
586
|
+
return config;
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
catch {
|
|
590
|
+
// If URL construction fails, skip capture
|
|
591
|
+
return config;
|
|
592
|
+
}
|
|
506
593
|
const method = config.method?.toUpperCase() || 'GET';
|
|
507
594
|
if (!this.shouldCaptureHost(url)) {
|
|
508
595
|
return config;
|
|
509
596
|
}
|
|
510
597
|
const requestId = this.generateRequestId();
|
|
511
598
|
const startTime = Date.now();
|
|
512
|
-
// Store request metadata
|
|
599
|
+
// Store request metadata (including full URL for response interceptor)
|
|
513
600
|
config._telemetryRequestId = requestId;
|
|
514
601
|
config._telemetryStartTime = startTime;
|
|
602
|
+
config._telemetryUrl = url; // Store full URL for response interceptor
|
|
515
603
|
// Track request start
|
|
516
604
|
this.enqueue({
|
|
517
605
|
type: 'request',
|
|
@@ -535,7 +623,8 @@ class LavarageTelemetry {
|
|
|
535
623
|
const startTime = config._telemetryStartTime;
|
|
536
624
|
if (requestId && startTime) {
|
|
537
625
|
const duration = Date.now() - startTime;
|
|
538
|
-
|
|
626
|
+
// Use stored URL from request interceptor, fallback to response URL
|
|
627
|
+
const url = config._telemetryUrl || response.config?.url || response.request?.responseURL || '';
|
|
539
628
|
this.enqueue({
|
|
540
629
|
type: 'request',
|
|
541
630
|
wallet: this.wallet,
|
|
@@ -557,7 +646,8 @@ class LavarageTelemetry {
|
|
|
557
646
|
const startTime = config._telemetryStartTime;
|
|
558
647
|
if (requestId && startTime) {
|
|
559
648
|
const duration = Date.now() - startTime;
|
|
560
|
-
|
|
649
|
+
// Use stored URL from request interceptor, fallback to error config URL
|
|
650
|
+
const url = config._telemetryUrl || config.url || error.request?.responseURL || '';
|
|
561
651
|
const errorMessage = error.message || 'Request failed';
|
|
562
652
|
this.enqueue({
|
|
563
653
|
type: 'request',
|