@rely-net/sdk 1.0.1 → 1.0.3
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/README.md +17 -0
- package/dist/index.d.mts +19 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.js +112 -0
- package/dist/index.mjs +112 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -5,6 +5,7 @@ Official SDK for [rely.net](https://rely.net) — monitor your application from
|
|
|
5
5
|
## What it does
|
|
6
6
|
|
|
7
7
|
- Sends health check results from inside your app to rely.net
|
|
8
|
+
- Attributes outgoing HTTP calls to vendors (Stripe, OpenAI, etc.) with per-vendor p95 + error rates
|
|
8
9
|
- Tracks custom metrics alongside vendor status
|
|
9
10
|
- Marks deployments on your monitoring charts
|
|
10
11
|
- Captures request telemetry (error rate, response times)
|
|
@@ -145,6 +146,21 @@ export const config = {
|
|
|
145
146
|
}
|
|
146
147
|
```
|
|
147
148
|
|
|
149
|
+
## Outgoing vendor calls
|
|
150
|
+
|
|
151
|
+
The SDK wraps the global `fetch` on init to bucket outgoing HTTP calls by hostname and report p50/p95/p99 + error rates per vendor. rely.net matches hostnames to known vendors (Stripe, OpenAI, Supabase, etc.) so you see vendor latency from your app's perspective — the answer to "is it me or is it Stripe?" without writing any code.
|
|
152
|
+
|
|
153
|
+
Enabled by default. Disable with:
|
|
154
|
+
|
|
155
|
+
```ts
|
|
156
|
+
new Rely({
|
|
157
|
+
apiKey: process.env.RELY_API_KEY!,
|
|
158
|
+
instrumentFetch: false,
|
|
159
|
+
})
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
Self-calls to the rely.net ingest endpoint are always skipped.
|
|
163
|
+
|
|
148
164
|
## Deployment markers
|
|
149
165
|
|
|
150
166
|
Deployment markers are sent automatically when the SDK initializes. They appear as vertical lines on your charts in rely.net, making it easy to correlate issues with deploys.
|
|
@@ -167,6 +183,7 @@ new Rely({
|
|
|
167
183
|
environment?: string, // default: process.env.NODE_ENV
|
|
168
184
|
flushInterval?: number, // default: 60000 (ms)
|
|
169
185
|
sanitizeErrors?: boolean, // default: true (recommended)
|
|
186
|
+
instrumentFetch?: boolean,// default: true (wraps global fetch)
|
|
170
187
|
debug?: boolean, // default: false
|
|
171
188
|
})
|
|
172
189
|
```
|
package/dist/index.d.mts
CHANGED
|
@@ -61,6 +61,16 @@ interface DeploymentPayload {
|
|
|
61
61
|
deployment_url: string;
|
|
62
62
|
metadata: Record<string, unknown>;
|
|
63
63
|
}
|
|
64
|
+
interface VendorCallWindow {
|
|
65
|
+
window_start: string;
|
|
66
|
+
window_end: string;
|
|
67
|
+
hostname: string;
|
|
68
|
+
call_count: number;
|
|
69
|
+
error_count: number;
|
|
70
|
+
p50_ms: number;
|
|
71
|
+
p95_ms: number;
|
|
72
|
+
p99_ms: number;
|
|
73
|
+
}
|
|
64
74
|
interface IngestPayload {
|
|
65
75
|
version: string;
|
|
66
76
|
timestamp: string;
|
|
@@ -69,6 +79,7 @@ interface IngestPayload {
|
|
|
69
79
|
metrics?: MetricDatapoint[];
|
|
70
80
|
runtime?: RuntimeStats;
|
|
71
81
|
request_telemetry?: RequestWindowData;
|
|
82
|
+
vendor_calls?: VendorCallWindow[];
|
|
72
83
|
}
|
|
73
84
|
interface IngestResponse {
|
|
74
85
|
received: boolean;
|
|
@@ -78,6 +89,7 @@ interface IngestResponse {
|
|
|
78
89
|
metrics: number;
|
|
79
90
|
runtime: boolean;
|
|
80
91
|
request_telemetry: boolean;
|
|
92
|
+
vendor_calls: number;
|
|
81
93
|
};
|
|
82
94
|
warnings: string[];
|
|
83
95
|
timestamp: string;
|
|
@@ -89,6 +101,7 @@ interface RelyClientOptions {
|
|
|
89
101
|
flushInterval?: number;
|
|
90
102
|
sanitizeErrors?: boolean;
|
|
91
103
|
debug?: boolean;
|
|
104
|
+
instrumentFetch?: boolean;
|
|
92
105
|
}
|
|
93
106
|
|
|
94
107
|
declare class RelyClient {
|
|
@@ -98,12 +111,16 @@ declare class RelyClient {
|
|
|
98
111
|
private readonly flushInterval;
|
|
99
112
|
private readonly sanitizeErrors;
|
|
100
113
|
private readonly debug;
|
|
114
|
+
private readonly instrumentFetchEnabled;
|
|
101
115
|
private healthChecks;
|
|
102
116
|
private pendingMetrics;
|
|
103
117
|
private requestBuffer;
|
|
118
|
+
private vendorCallBuffer;
|
|
104
119
|
private flushTimer;
|
|
105
120
|
private deploymentSent;
|
|
106
121
|
private isDestroyed;
|
|
122
|
+
private originalFetch;
|
|
123
|
+
private ingestHost;
|
|
107
124
|
constructor(options: RelyClientOptions);
|
|
108
125
|
healthCheck(name: string, fn: HealthCheckFn): this;
|
|
109
126
|
metric(name: string, value: number, tags?: Record<string, string>): this;
|
|
@@ -119,6 +136,8 @@ declare class RelyClient {
|
|
|
119
136
|
private sanitize;
|
|
120
137
|
private sanitizeTags;
|
|
121
138
|
private detectFrameworkVersion;
|
|
139
|
+
private installFetchInstrumentation;
|
|
140
|
+
private extractHostname;
|
|
122
141
|
private log;
|
|
123
142
|
}
|
|
124
143
|
|
package/dist/index.d.ts
CHANGED
|
@@ -61,6 +61,16 @@ interface DeploymentPayload {
|
|
|
61
61
|
deployment_url: string;
|
|
62
62
|
metadata: Record<string, unknown>;
|
|
63
63
|
}
|
|
64
|
+
interface VendorCallWindow {
|
|
65
|
+
window_start: string;
|
|
66
|
+
window_end: string;
|
|
67
|
+
hostname: string;
|
|
68
|
+
call_count: number;
|
|
69
|
+
error_count: number;
|
|
70
|
+
p50_ms: number;
|
|
71
|
+
p95_ms: number;
|
|
72
|
+
p99_ms: number;
|
|
73
|
+
}
|
|
64
74
|
interface IngestPayload {
|
|
65
75
|
version: string;
|
|
66
76
|
timestamp: string;
|
|
@@ -69,6 +79,7 @@ interface IngestPayload {
|
|
|
69
79
|
metrics?: MetricDatapoint[];
|
|
70
80
|
runtime?: RuntimeStats;
|
|
71
81
|
request_telemetry?: RequestWindowData;
|
|
82
|
+
vendor_calls?: VendorCallWindow[];
|
|
72
83
|
}
|
|
73
84
|
interface IngestResponse {
|
|
74
85
|
received: boolean;
|
|
@@ -78,6 +89,7 @@ interface IngestResponse {
|
|
|
78
89
|
metrics: number;
|
|
79
90
|
runtime: boolean;
|
|
80
91
|
request_telemetry: boolean;
|
|
92
|
+
vendor_calls: number;
|
|
81
93
|
};
|
|
82
94
|
warnings: string[];
|
|
83
95
|
timestamp: string;
|
|
@@ -89,6 +101,7 @@ interface RelyClientOptions {
|
|
|
89
101
|
flushInterval?: number;
|
|
90
102
|
sanitizeErrors?: boolean;
|
|
91
103
|
debug?: boolean;
|
|
104
|
+
instrumentFetch?: boolean;
|
|
92
105
|
}
|
|
93
106
|
|
|
94
107
|
declare class RelyClient {
|
|
@@ -98,12 +111,16 @@ declare class RelyClient {
|
|
|
98
111
|
private readonly flushInterval;
|
|
99
112
|
private readonly sanitizeErrors;
|
|
100
113
|
private readonly debug;
|
|
114
|
+
private readonly instrumentFetchEnabled;
|
|
101
115
|
private healthChecks;
|
|
102
116
|
private pendingMetrics;
|
|
103
117
|
private requestBuffer;
|
|
118
|
+
private vendorCallBuffer;
|
|
104
119
|
private flushTimer;
|
|
105
120
|
private deploymentSent;
|
|
106
121
|
private isDestroyed;
|
|
122
|
+
private originalFetch;
|
|
123
|
+
private ingestHost;
|
|
107
124
|
constructor(options: RelyClientOptions);
|
|
108
125
|
healthCheck(name: string, fn: HealthCheckFn): this;
|
|
109
126
|
metric(name: string, value: number, tags?: Record<string, string>): this;
|
|
@@ -119,6 +136,8 @@ declare class RelyClient {
|
|
|
119
136
|
private sanitize;
|
|
120
137
|
private sanitizeTags;
|
|
121
138
|
private detectFrameworkVersion;
|
|
139
|
+
private installFetchInstrumentation;
|
|
140
|
+
private extractHostname;
|
|
122
141
|
private log;
|
|
123
142
|
}
|
|
124
143
|
|
package/dist/index.js
CHANGED
|
@@ -110,6 +110,55 @@ var RequestBuffer = class {
|
|
|
110
110
|
}
|
|
111
111
|
};
|
|
112
112
|
|
|
113
|
+
// src/collectors/vendorCalls.ts
|
|
114
|
+
function percentile2(arr, p) {
|
|
115
|
+
if (arr.length === 0) return 0;
|
|
116
|
+
const sorted = [...arr].sort((a, b) => a - b);
|
|
117
|
+
const index = Math.ceil(p / 100 * sorted.length) - 1;
|
|
118
|
+
return sorted[Math.max(0, index)];
|
|
119
|
+
}
|
|
120
|
+
var VendorCallBuffer = class {
|
|
121
|
+
constructor() {
|
|
122
|
+
this.hosts = /* @__PURE__ */ new Map();
|
|
123
|
+
this.windowStart = /* @__PURE__ */ new Date();
|
|
124
|
+
}
|
|
125
|
+
record(hostname, durationMs, isError) {
|
|
126
|
+
if (!hostname) return;
|
|
127
|
+
let data = this.hosts.get(hostname);
|
|
128
|
+
if (!data) {
|
|
129
|
+
data = { durations: [], errors: 0 };
|
|
130
|
+
this.hosts.set(hostname, data);
|
|
131
|
+
}
|
|
132
|
+
data.durations.push(Math.max(0, durationMs));
|
|
133
|
+
if (isError) data.errors += 1;
|
|
134
|
+
}
|
|
135
|
+
get totalCalls() {
|
|
136
|
+
let total = 0;
|
|
137
|
+
for (const d of Array.from(this.hosts.values())) total += d.durations.length;
|
|
138
|
+
return total;
|
|
139
|
+
}
|
|
140
|
+
flush() {
|
|
141
|
+
const windowEnd = (/* @__PURE__ */ new Date()).toISOString();
|
|
142
|
+
const windowStart = this.windowStart.toISOString();
|
|
143
|
+
const out = [];
|
|
144
|
+
for (const [hostname, data] of Array.from(this.hosts.entries())) {
|
|
145
|
+
out.push({
|
|
146
|
+
window_start: windowStart,
|
|
147
|
+
window_end: windowEnd,
|
|
148
|
+
hostname,
|
|
149
|
+
call_count: data.durations.length,
|
|
150
|
+
error_count: data.errors,
|
|
151
|
+
p50_ms: percentile2(data.durations, 50),
|
|
152
|
+
p95_ms: percentile2(data.durations, 95),
|
|
153
|
+
p99_ms: percentile2(data.durations, 99)
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
this.hosts = /* @__PURE__ */ new Map();
|
|
157
|
+
this.windowStart = /* @__PURE__ */ new Date();
|
|
158
|
+
return out;
|
|
159
|
+
}
|
|
160
|
+
};
|
|
161
|
+
|
|
113
162
|
// src/client.ts
|
|
114
163
|
var SDK_VERSION = "1.0.0";
|
|
115
164
|
var SECRET_PATTERNS = [
|
|
@@ -156,12 +205,20 @@ var RelyClient = class {
|
|
|
156
205
|
);
|
|
157
206
|
this.sanitizeErrors = options.sanitizeErrors ?? true;
|
|
158
207
|
this.debug = options.debug ?? false;
|
|
208
|
+
this.instrumentFetchEnabled = options.instrumentFetch ?? true;
|
|
159
209
|
this.healthChecks = /* @__PURE__ */ new Map();
|
|
160
210
|
this.pendingMetrics = [];
|
|
161
211
|
this.requestBuffer = new RequestBuffer();
|
|
212
|
+
this.vendorCallBuffer = new VendorCallBuffer();
|
|
162
213
|
this.flushTimer = null;
|
|
163
214
|
this.deploymentSent = false;
|
|
164
215
|
this.isDestroyed = false;
|
|
216
|
+
this.originalFetch = null;
|
|
217
|
+
try {
|
|
218
|
+
this.ingestHost = new URL(this.baseUrl).hostname;
|
|
219
|
+
} catch {
|
|
220
|
+
this.ingestHost = "";
|
|
221
|
+
}
|
|
165
222
|
this.log(`SDK initialized`);
|
|
166
223
|
this.log(`Environment: ${this.environment}`);
|
|
167
224
|
this.log(`Flush interval: ${this.flushInterval / 1e3}s`);
|
|
@@ -247,6 +304,9 @@ var RelyClient = class {
|
|
|
247
304
|
if (this.requestBuffer.totalRequests > 0) {
|
|
248
305
|
payload.request_telemetry = this.requestBuffer.flush();
|
|
249
306
|
}
|
|
307
|
+
if (this.vendorCallBuffer.totalCalls > 0) {
|
|
308
|
+
payload.vendor_calls = this.vendorCallBuffer.flush();
|
|
309
|
+
}
|
|
250
310
|
await this.sendPayload(payload);
|
|
251
311
|
}
|
|
252
312
|
// Destroy the client and stop all background activity.
|
|
@@ -258,9 +318,19 @@ var RelyClient = class {
|
|
|
258
318
|
clearInterval(this.flushTimer);
|
|
259
319
|
this.flushTimer = null;
|
|
260
320
|
}
|
|
321
|
+
if (this.originalFetch && typeof globalThis !== "undefined") {
|
|
322
|
+
try {
|
|
323
|
+
globalThis.fetch = this.originalFetch;
|
|
324
|
+
} catch {
|
|
325
|
+
}
|
|
326
|
+
this.originalFetch = null;
|
|
327
|
+
}
|
|
261
328
|
this.log("SDK destroyed");
|
|
262
329
|
}
|
|
263
330
|
initialize() {
|
|
331
|
+
if (this.instrumentFetchEnabled) {
|
|
332
|
+
this.installFetchInstrumentation();
|
|
333
|
+
}
|
|
264
334
|
if (this.environment === "production" || this.environment === "staging") {
|
|
265
335
|
this.sendDeploymentMarker();
|
|
266
336
|
}
|
|
@@ -400,6 +470,48 @@ var RelyClient = class {
|
|
|
400
470
|
return "unknown";
|
|
401
471
|
}
|
|
402
472
|
}
|
|
473
|
+
installFetchInstrumentation() {
|
|
474
|
+
if (typeof globalThis === "undefined" || typeof globalThis.fetch !== "function") {
|
|
475
|
+
this.log("Global fetch not available, skipping instrumentation");
|
|
476
|
+
return;
|
|
477
|
+
}
|
|
478
|
+
const original = globalThis.fetch;
|
|
479
|
+
this.originalFetch = original;
|
|
480
|
+
const self = this;
|
|
481
|
+
const wrapped = async function(input, init) {
|
|
482
|
+
const hostname = self.extractHostname(input);
|
|
483
|
+
if (!hostname || hostname === self.ingestHost) {
|
|
484
|
+
return original(input, init);
|
|
485
|
+
}
|
|
486
|
+
const start = Date.now();
|
|
487
|
+
try {
|
|
488
|
+
const res = await original(input, init);
|
|
489
|
+
self.vendorCallBuffer.record(
|
|
490
|
+
hostname,
|
|
491
|
+
Date.now() - start,
|
|
492
|
+
res.status >= 400
|
|
493
|
+
);
|
|
494
|
+
return res;
|
|
495
|
+
} catch (err) {
|
|
496
|
+
self.vendorCallBuffer.record(hostname, Date.now() - start, true);
|
|
497
|
+
throw err;
|
|
498
|
+
}
|
|
499
|
+
};
|
|
500
|
+
try {
|
|
501
|
+
globalThis.fetch = wrapped;
|
|
502
|
+
this.log("Fetch instrumentation installed");
|
|
503
|
+
} catch {
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
extractHostname(input) {
|
|
507
|
+
try {
|
|
508
|
+
if (typeof input === "string") return new URL(input).hostname;
|
|
509
|
+
if (input instanceof URL) return input.hostname;
|
|
510
|
+
return new URL(input.url).hostname;
|
|
511
|
+
} catch {
|
|
512
|
+
return "";
|
|
513
|
+
}
|
|
514
|
+
}
|
|
403
515
|
log(message) {
|
|
404
516
|
if (this.debug) {
|
|
405
517
|
console.log(`[Rely] ${message}`);
|
package/dist/index.mjs
CHANGED
|
@@ -76,6 +76,55 @@ var RequestBuffer = class {
|
|
|
76
76
|
}
|
|
77
77
|
};
|
|
78
78
|
|
|
79
|
+
// src/collectors/vendorCalls.ts
|
|
80
|
+
function percentile2(arr, p) {
|
|
81
|
+
if (arr.length === 0) return 0;
|
|
82
|
+
const sorted = [...arr].sort((a, b) => a - b);
|
|
83
|
+
const index = Math.ceil(p / 100 * sorted.length) - 1;
|
|
84
|
+
return sorted[Math.max(0, index)];
|
|
85
|
+
}
|
|
86
|
+
var VendorCallBuffer = class {
|
|
87
|
+
constructor() {
|
|
88
|
+
this.hosts = /* @__PURE__ */ new Map();
|
|
89
|
+
this.windowStart = /* @__PURE__ */ new Date();
|
|
90
|
+
}
|
|
91
|
+
record(hostname, durationMs, isError) {
|
|
92
|
+
if (!hostname) return;
|
|
93
|
+
let data = this.hosts.get(hostname);
|
|
94
|
+
if (!data) {
|
|
95
|
+
data = { durations: [], errors: 0 };
|
|
96
|
+
this.hosts.set(hostname, data);
|
|
97
|
+
}
|
|
98
|
+
data.durations.push(Math.max(0, durationMs));
|
|
99
|
+
if (isError) data.errors += 1;
|
|
100
|
+
}
|
|
101
|
+
get totalCalls() {
|
|
102
|
+
let total = 0;
|
|
103
|
+
for (const d of Array.from(this.hosts.values())) total += d.durations.length;
|
|
104
|
+
return total;
|
|
105
|
+
}
|
|
106
|
+
flush() {
|
|
107
|
+
const windowEnd = (/* @__PURE__ */ new Date()).toISOString();
|
|
108
|
+
const windowStart = this.windowStart.toISOString();
|
|
109
|
+
const out = [];
|
|
110
|
+
for (const [hostname, data] of Array.from(this.hosts.entries())) {
|
|
111
|
+
out.push({
|
|
112
|
+
window_start: windowStart,
|
|
113
|
+
window_end: windowEnd,
|
|
114
|
+
hostname,
|
|
115
|
+
call_count: data.durations.length,
|
|
116
|
+
error_count: data.errors,
|
|
117
|
+
p50_ms: percentile2(data.durations, 50),
|
|
118
|
+
p95_ms: percentile2(data.durations, 95),
|
|
119
|
+
p99_ms: percentile2(data.durations, 99)
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
this.hosts = /* @__PURE__ */ new Map();
|
|
123
|
+
this.windowStart = /* @__PURE__ */ new Date();
|
|
124
|
+
return out;
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
|
|
79
128
|
// src/client.ts
|
|
80
129
|
var SDK_VERSION = "1.0.0";
|
|
81
130
|
var SECRET_PATTERNS = [
|
|
@@ -122,12 +171,20 @@ var RelyClient = class {
|
|
|
122
171
|
);
|
|
123
172
|
this.sanitizeErrors = options.sanitizeErrors ?? true;
|
|
124
173
|
this.debug = options.debug ?? false;
|
|
174
|
+
this.instrumentFetchEnabled = options.instrumentFetch ?? true;
|
|
125
175
|
this.healthChecks = /* @__PURE__ */ new Map();
|
|
126
176
|
this.pendingMetrics = [];
|
|
127
177
|
this.requestBuffer = new RequestBuffer();
|
|
178
|
+
this.vendorCallBuffer = new VendorCallBuffer();
|
|
128
179
|
this.flushTimer = null;
|
|
129
180
|
this.deploymentSent = false;
|
|
130
181
|
this.isDestroyed = false;
|
|
182
|
+
this.originalFetch = null;
|
|
183
|
+
try {
|
|
184
|
+
this.ingestHost = new URL(this.baseUrl).hostname;
|
|
185
|
+
} catch {
|
|
186
|
+
this.ingestHost = "";
|
|
187
|
+
}
|
|
131
188
|
this.log(`SDK initialized`);
|
|
132
189
|
this.log(`Environment: ${this.environment}`);
|
|
133
190
|
this.log(`Flush interval: ${this.flushInterval / 1e3}s`);
|
|
@@ -213,6 +270,9 @@ var RelyClient = class {
|
|
|
213
270
|
if (this.requestBuffer.totalRequests > 0) {
|
|
214
271
|
payload.request_telemetry = this.requestBuffer.flush();
|
|
215
272
|
}
|
|
273
|
+
if (this.vendorCallBuffer.totalCalls > 0) {
|
|
274
|
+
payload.vendor_calls = this.vendorCallBuffer.flush();
|
|
275
|
+
}
|
|
216
276
|
await this.sendPayload(payload);
|
|
217
277
|
}
|
|
218
278
|
// Destroy the client and stop all background activity.
|
|
@@ -224,9 +284,19 @@ var RelyClient = class {
|
|
|
224
284
|
clearInterval(this.flushTimer);
|
|
225
285
|
this.flushTimer = null;
|
|
226
286
|
}
|
|
287
|
+
if (this.originalFetch && typeof globalThis !== "undefined") {
|
|
288
|
+
try {
|
|
289
|
+
globalThis.fetch = this.originalFetch;
|
|
290
|
+
} catch {
|
|
291
|
+
}
|
|
292
|
+
this.originalFetch = null;
|
|
293
|
+
}
|
|
227
294
|
this.log("SDK destroyed");
|
|
228
295
|
}
|
|
229
296
|
initialize() {
|
|
297
|
+
if (this.instrumentFetchEnabled) {
|
|
298
|
+
this.installFetchInstrumentation();
|
|
299
|
+
}
|
|
230
300
|
if (this.environment === "production" || this.environment === "staging") {
|
|
231
301
|
this.sendDeploymentMarker();
|
|
232
302
|
}
|
|
@@ -366,6 +436,48 @@ var RelyClient = class {
|
|
|
366
436
|
return "unknown";
|
|
367
437
|
}
|
|
368
438
|
}
|
|
439
|
+
installFetchInstrumentation() {
|
|
440
|
+
if (typeof globalThis === "undefined" || typeof globalThis.fetch !== "function") {
|
|
441
|
+
this.log("Global fetch not available, skipping instrumentation");
|
|
442
|
+
return;
|
|
443
|
+
}
|
|
444
|
+
const original = globalThis.fetch;
|
|
445
|
+
this.originalFetch = original;
|
|
446
|
+
const self = this;
|
|
447
|
+
const wrapped = async function(input, init) {
|
|
448
|
+
const hostname = self.extractHostname(input);
|
|
449
|
+
if (!hostname || hostname === self.ingestHost) {
|
|
450
|
+
return original(input, init);
|
|
451
|
+
}
|
|
452
|
+
const start = Date.now();
|
|
453
|
+
try {
|
|
454
|
+
const res = await original(input, init);
|
|
455
|
+
self.vendorCallBuffer.record(
|
|
456
|
+
hostname,
|
|
457
|
+
Date.now() - start,
|
|
458
|
+
res.status >= 400
|
|
459
|
+
);
|
|
460
|
+
return res;
|
|
461
|
+
} catch (err) {
|
|
462
|
+
self.vendorCallBuffer.record(hostname, Date.now() - start, true);
|
|
463
|
+
throw err;
|
|
464
|
+
}
|
|
465
|
+
};
|
|
466
|
+
try {
|
|
467
|
+
globalThis.fetch = wrapped;
|
|
468
|
+
this.log("Fetch instrumentation installed");
|
|
469
|
+
} catch {
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
extractHostname(input) {
|
|
473
|
+
try {
|
|
474
|
+
if (typeof input === "string") return new URL(input).hostname;
|
|
475
|
+
if (input instanceof URL) return input.hostname;
|
|
476
|
+
return new URL(input.url).hostname;
|
|
477
|
+
} catch {
|
|
478
|
+
return "";
|
|
479
|
+
}
|
|
480
|
+
}
|
|
369
481
|
log(message) {
|
|
370
482
|
if (this.debug) {
|
|
371
483
|
console.log(`[Rely] ${message}`);
|