@vybesec/sdk 0.1.3 → 0.1.5
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 +26 -2
- package/dist/index.cjs +226 -9
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +10 -48
- package/dist/index.d.ts +10 -48
- package/dist/index.js +214 -9
- package/dist/index.js.map +1 -1
- package/dist/v1/sdk.js +74 -1
- package/dist/v1/sdk.js.map +4 -4
- package/package.json +6 -2
package/README.md
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# @vybesec/sdk
|
|
2
2
|
|
|
3
3
|
Browser SDK for sending VybeSec events to your ingest endpoint.
|
|
4
|
+
This package is **browser-only** (not intended for Node.js or React Native yet).
|
|
4
5
|
|
|
5
6
|
## Install (npm)
|
|
6
7
|
|
|
@@ -41,19 +42,42 @@ captureEvent({
|
|
|
41
42
|
</script>
|
|
42
43
|
```
|
|
43
44
|
|
|
45
|
+
## Dev test snippet
|
|
46
|
+
|
|
47
|
+
Paste this into a dev page to confirm events are flowing:
|
|
48
|
+
|
|
49
|
+
```html
|
|
50
|
+
<button id="vs-test-success">Trigger test success</button>
|
|
51
|
+
<button id="vs-test-error">Trigger test error</button>
|
|
52
|
+
<script>
|
|
53
|
+
const sdk = window.VybeSec?.vybesec ?? window.VybeSec;
|
|
54
|
+
document.getElementById("vs-test-success")?.addEventListener("click", () => {
|
|
55
|
+
sdk?.captureEvent?.({
|
|
56
|
+
type: "info",
|
|
57
|
+
message: "VybeSec test success",
|
|
58
|
+
timestamp: Date.now()
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
document.getElementById("vs-test-error")?.addEventListener("click", () => {
|
|
62
|
+
sdk?.captureError?.(new Error("VybeSec test error"));
|
|
63
|
+
});
|
|
64
|
+
</script>
|
|
65
|
+
```
|
|
66
|
+
|
|
44
67
|
## Configuration
|
|
45
68
|
|
|
46
69
|
| Option | Type | Description | Default |
|
|
47
70
|
| --- | --- | --- | --- |
|
|
48
71
|
| `key` | `string` | Project public key (DSN key). | **Required** |
|
|
49
72
|
| `environment` | `"production" | "staging" | "development"` | Environment tag. | `"production"` |
|
|
50
|
-
| `platform` | `
|
|
73
|
+
| `platform` | `Platform` | Tool/framework tag (examples: `lovable`, `cursor`, `nextjs`, `react`, `vue`, `svelte`, `react-native`, `expo`, `other`). | `"other"` |
|
|
51
74
|
| `release` | `string` | Release identifier. | `""` |
|
|
52
75
|
| `userId` | `string` | User identifier. | `undefined` |
|
|
53
76
|
| `sampleRate` | `number` | 0–1 sampling. | `1` |
|
|
54
77
|
| `maxBuffer` | `number` | Max buffered events. | `100` |
|
|
55
78
|
| `maxEventsPerMinute` | `number` | Client-side rate limit. | `120` |
|
|
56
|
-
|
|
79
|
+
|
|
80
|
+
Full platform list is documented in the VybeSec docs and kept in sync with the dashboard.
|
|
57
81
|
|
|
58
82
|
## Events
|
|
59
83
|
|
package/dist/index.cjs
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
2
3
|
var __defProp = Object.defineProperty;
|
|
3
4
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
5
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
8
|
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
7
9
|
var __export = (target, all) => {
|
|
@@ -16,6 +18,14 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
16
18
|
}
|
|
17
19
|
return to;
|
|
18
20
|
};
|
|
21
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
22
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
23
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
24
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
25
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
26
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
27
|
+
mod
|
|
28
|
+
));
|
|
19
29
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
20
30
|
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
21
31
|
|
|
@@ -29,7 +39,122 @@ __export(index_exports, {
|
|
|
29
39
|
vybesec: () => vybesec
|
|
30
40
|
});
|
|
31
41
|
module.exports = __toCommonJS(index_exports);
|
|
42
|
+
|
|
43
|
+
// src/vitals.ts
|
|
44
|
+
var thresholds = {
|
|
45
|
+
LCP: [2500, 4e3],
|
|
46
|
+
TTFB: [800, 1800],
|
|
47
|
+
FCP: [1800, 3e3],
|
|
48
|
+
INP: [200, 500],
|
|
49
|
+
CLS: [0.1, 0.25]
|
|
50
|
+
};
|
|
51
|
+
function rateMetric(metric) {
|
|
52
|
+
const [good, poor] = thresholds[metric.name] ?? [0, 0];
|
|
53
|
+
if (metric.value <= good) return "good";
|
|
54
|
+
if (metric.value <= poor) return "needs_improvement";
|
|
55
|
+
return "poor";
|
|
56
|
+
}
|
|
57
|
+
async function captureWebVitals(onMetric) {
|
|
58
|
+
const { onLCP, onTTFB, onFCP, onINP, onCLS } = await import("web-vitals");
|
|
59
|
+
const report = (metric) => {
|
|
60
|
+
onMetric({
|
|
61
|
+
metricName: metric.name,
|
|
62
|
+
value: metric.value,
|
|
63
|
+
rating: rateMetric(metric)
|
|
64
|
+
});
|
|
65
|
+
};
|
|
66
|
+
onLCP(report);
|
|
67
|
+
onTTFB(report);
|
|
68
|
+
onFCP(report);
|
|
69
|
+
onINP(report);
|
|
70
|
+
onCLS(report);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// src/replay.ts
|
|
74
|
+
var BUFFER_SECONDS = 60;
|
|
75
|
+
var MAX_EVENTS = 2e3;
|
|
76
|
+
var ReplayCapture = class {
|
|
77
|
+
constructor() {
|
|
78
|
+
__publicField(this, "events", []);
|
|
79
|
+
__publicField(this, "stopFn");
|
|
80
|
+
__publicField(this, "flushed", false);
|
|
81
|
+
}
|
|
82
|
+
async start() {
|
|
83
|
+
if (this.stopFn) return;
|
|
84
|
+
const { record } = await import("rrweb");
|
|
85
|
+
this.stopFn = record({
|
|
86
|
+
emit: (event) => {
|
|
87
|
+
const now = Date.now();
|
|
88
|
+
this.events.push(event);
|
|
89
|
+
const cutoff = now - BUFFER_SECONDS * 1e3;
|
|
90
|
+
while (this.events.length > 0 && this.events[0].timestamp < cutoff) {
|
|
91
|
+
this.events.shift();
|
|
92
|
+
}
|
|
93
|
+
if (this.events.length > MAX_EVENTS) {
|
|
94
|
+
this.events = this.events.slice(-MAX_EVENTS);
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
maskAllInputs: true,
|
|
98
|
+
maskInputOptions: {
|
|
99
|
+
password: true,
|
|
100
|
+
email: true,
|
|
101
|
+
tel: true,
|
|
102
|
+
text: true,
|
|
103
|
+
number: false,
|
|
104
|
+
search: false
|
|
105
|
+
},
|
|
106
|
+
blockClass: "vybesec-block",
|
|
107
|
+
maskTextClass: "vybesec-mask",
|
|
108
|
+
ignoreClass: "vybesec-ignore",
|
|
109
|
+
recordCrossOriginIframes: false,
|
|
110
|
+
sampling: {
|
|
111
|
+
mousemove: 100,
|
|
112
|
+
scroll: 150,
|
|
113
|
+
input: "last"
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
async flushOnError(config, errorFingerprint) {
|
|
118
|
+
if (this.flushed || this.events.length < 10) return;
|
|
119
|
+
this.flushed = true;
|
|
120
|
+
const payload = scrubReplayPayload(
|
|
121
|
+
this.events.map((event) => JSON.stringify(event)).join("\n")
|
|
122
|
+
);
|
|
123
|
+
const blob = new Blob([payload], { type: "application/x-ndjson" });
|
|
124
|
+
const url = new URL(
|
|
125
|
+
`${config.replayUrl}/v1/replay/${config.publicKey}/${config.sessionId}`
|
|
126
|
+
);
|
|
127
|
+
if (errorFingerprint) {
|
|
128
|
+
url.searchParams.set("fingerprint", errorFingerprint);
|
|
129
|
+
}
|
|
130
|
+
if (typeof window !== "undefined") {
|
|
131
|
+
url.searchParams.set("urlPath", window.location.pathname);
|
|
132
|
+
}
|
|
133
|
+
if (navigator.sendBeacon) {
|
|
134
|
+
navigator.sendBeacon(url.toString(), blob);
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
await fetch(url.toString(), {
|
|
138
|
+
method: "POST",
|
|
139
|
+
headers: { "Content-Type": "application/x-ndjson" },
|
|
140
|
+
body: blob
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
stop() {
|
|
144
|
+
this.stopFn?.();
|
|
145
|
+
this.stopFn = void 0;
|
|
146
|
+
}
|
|
147
|
+
};
|
|
148
|
+
function scrubReplayPayload(payload) {
|
|
149
|
+
return payload.replace(
|
|
150
|
+
/\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b/g,
|
|
151
|
+
"[email]"
|
|
152
|
+
).replace(/\b\d{4}[\s-]?\d{4}[\s-]?\d{4}[\s-]?\d{4}\b/g, "[card]").replace(/sk-[a-zA-Z0-9]{20,}/g, "[api-key]").replace(/Bearer\\s[a-zA-Z0-9\\-_.]{20,}/g, "Bearer [token]").replace(/\b\d{3}-\d{2}-\d{4}\b/g, "[ssn]");
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// src/index.ts
|
|
32
156
|
var DEFAULT_INGEST_URL = "https://vybesec-ingest.hexeldigitalstudio.workers.dev";
|
|
157
|
+
var DEFAULT_REPLAY_URL = "https://vybesec-replay.hexeldigitalstudio.workers.dev";
|
|
33
158
|
var SESSION_KEY = "vybesec_session_id";
|
|
34
159
|
function getSessionId() {
|
|
35
160
|
try {
|
|
@@ -59,6 +184,34 @@ function getStackTrace(error) {
|
|
|
59
184
|
if (error instanceof Error) return error.stack;
|
|
60
185
|
return void 0;
|
|
61
186
|
}
|
|
187
|
+
function normalizeMessage(message) {
|
|
188
|
+
return message.replace(/0x[0-9a-f]+/gi, "0xADDR").replace(/\d+:\d+/g, "L:C").replace(/\"[^\"]{0,50}\"/g, '"VAL"');
|
|
189
|
+
}
|
|
190
|
+
function parseStackTrace(stack) {
|
|
191
|
+
if (!stack) return [];
|
|
192
|
+
const lines = stack.split("\n");
|
|
193
|
+
const frames = [];
|
|
194
|
+
for (const line of lines) {
|
|
195
|
+
const match = line.match(/at\\s+(.*?)(?:\\s+\\(|\\s)(.+?):\\d+:\\d+\\)?/);
|
|
196
|
+
if (match) {
|
|
197
|
+
frames.push({ fn: match[1] || "anonymous", file: match[2] || "unknown" });
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
return frames;
|
|
201
|
+
}
|
|
202
|
+
async function sha256(input) {
|
|
203
|
+
const buffer = new TextEncoder().encode(input);
|
|
204
|
+
const hash = await crypto.subtle.digest("SHA-256", buffer);
|
|
205
|
+
return Array.from(new Uint8Array(hash)).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
206
|
+
}
|
|
207
|
+
async function computeFingerprint(event) {
|
|
208
|
+
const normalized = normalizeMessage(event.message ?? "");
|
|
209
|
+
const frames = parseStackTrace(event.stackTrace).slice(0, 3).map((frame) => `${frame.file}:${frame.fn}`).join("|");
|
|
210
|
+
const errorType = event.errorType ?? "Error";
|
|
211
|
+
const input = `${errorType}:${normalized}:${frames}`;
|
|
212
|
+
const hash = await sha256(input);
|
|
213
|
+
return hash.slice(0, 16);
|
|
214
|
+
}
|
|
62
215
|
function scrubSensitiveText(value) {
|
|
63
216
|
if (!value) return value;
|
|
64
217
|
const patterns = [
|
|
@@ -113,6 +266,10 @@ var VybeSecSDK = class {
|
|
|
113
266
|
__publicField(this, "retryTimer");
|
|
114
267
|
__publicField(this, "retryAttempt", 0);
|
|
115
268
|
__publicField(this, "isFlushing", false);
|
|
269
|
+
__publicField(this, "replayCapture");
|
|
270
|
+
__publicField(this, "replayEnabled", false);
|
|
271
|
+
__publicField(this, "replayStarted", false);
|
|
272
|
+
__publicField(this, "sessionId");
|
|
116
273
|
}
|
|
117
274
|
init(config) {
|
|
118
275
|
this.config = {
|
|
@@ -120,9 +277,18 @@ var VybeSecSDK = class {
|
|
|
120
277
|
sampleRate: config.sampleRate ?? 1,
|
|
121
278
|
maxBuffer: config.maxBuffer ?? 100,
|
|
122
279
|
maxEventsPerMinute: config.maxEventsPerMinute ?? 120,
|
|
123
|
-
ingestUrl:
|
|
280
|
+
ingestUrl: DEFAULT_INGEST_URL,
|
|
281
|
+
replayUrl: DEFAULT_REPLAY_URL,
|
|
282
|
+
enableVitals: config.enableVitals ?? true,
|
|
283
|
+
enableReplay: config.enableReplay ?? true
|
|
124
284
|
};
|
|
125
285
|
if (typeof window === "undefined") return;
|
|
286
|
+
this.sessionId = getSessionId();
|
|
287
|
+
this.replayEnabled = false;
|
|
288
|
+
this.replayStarted = false;
|
|
289
|
+
if (this.config.enableReplay) {
|
|
290
|
+
this.replayCapture = new ReplayCapture();
|
|
291
|
+
}
|
|
126
292
|
window.addEventListener("error", (event) => {
|
|
127
293
|
this.captureError(event.error ?? event.message, {
|
|
128
294
|
url: event.filename
|
|
@@ -139,6 +305,21 @@ var VybeSecSDK = class {
|
|
|
139
305
|
this.flushBeacon();
|
|
140
306
|
}
|
|
141
307
|
});
|
|
308
|
+
if (this.config.enableVitals) {
|
|
309
|
+
void captureWebVitals((metric) => {
|
|
310
|
+
this.captureEvent({
|
|
311
|
+
type: "performance",
|
|
312
|
+
message: metric.metricName,
|
|
313
|
+
timestamp: Date.now(),
|
|
314
|
+
sessionId: this.sessionId,
|
|
315
|
+
extra: {
|
|
316
|
+
metricName: metric.metricName,
|
|
317
|
+
value: metric.value,
|
|
318
|
+
rating: metric.rating
|
|
319
|
+
}
|
|
320
|
+
});
|
|
321
|
+
});
|
|
322
|
+
}
|
|
142
323
|
if (this.flushTimer) {
|
|
143
324
|
window.clearInterval(this.flushTimer);
|
|
144
325
|
}
|
|
@@ -158,7 +339,7 @@ var VybeSecSDK = class {
|
|
|
158
339
|
stackTrace: getStackTrace(error),
|
|
159
340
|
errorType: getErrorType(error),
|
|
160
341
|
url: typeof window !== "undefined" ? window.location.href : void 0,
|
|
161
|
-
sessionId: typeof window !== "undefined" ? getSessionId() : void 0,
|
|
342
|
+
sessionId: typeof window !== "undefined" ? this.sessionId ?? getSessionId() : void 0,
|
|
162
343
|
userId: this.config.userId,
|
|
163
344
|
timestamp: Date.now(),
|
|
164
345
|
tags: {
|
|
@@ -169,13 +350,14 @@ var VybeSecSDK = class {
|
|
|
169
350
|
}
|
|
170
351
|
});
|
|
171
352
|
this.pushEvent(event);
|
|
353
|
+
void this.flushReplayOnError(event);
|
|
172
354
|
}
|
|
173
355
|
captureEvent(event) {
|
|
174
356
|
if (!this.config) return;
|
|
175
357
|
if (!this.shouldAcceptEvent()) return;
|
|
176
358
|
const enriched = scrubEvent({
|
|
177
359
|
...event,
|
|
178
|
-
sessionId: event.sessionId ?? (typeof window !== "undefined" ? getSessionId() : void 0),
|
|
360
|
+
sessionId: event.sessionId ?? (typeof window !== "undefined" ? this.sessionId ?? getSessionId() : void 0),
|
|
179
361
|
userId: event.userId ?? this.config.userId,
|
|
180
362
|
timestamp: event.timestamp ?? Date.now(),
|
|
181
363
|
tags: {
|
|
@@ -199,18 +381,48 @@ var VybeSecSDK = class {
|
|
|
199
381
|
void this.flush();
|
|
200
382
|
}
|
|
201
383
|
}
|
|
384
|
+
async startReplay() {
|
|
385
|
+
if (!this.replayCapture || this.replayStarted) return;
|
|
386
|
+
await this.replayCapture.start();
|
|
387
|
+
this.replayStarted = true;
|
|
388
|
+
}
|
|
389
|
+
async flushReplayOnError(event) {
|
|
390
|
+
if (!this.config) return;
|
|
391
|
+
if (!this.replayCapture || !this.replayEnabled) return;
|
|
392
|
+
const fingerprint = await computeFingerprint(event);
|
|
393
|
+
await this.replayCapture.flushOnError(
|
|
394
|
+
{
|
|
395
|
+
publicKey: this.config.key,
|
|
396
|
+
sessionId: this.sessionId ?? getSessionId(),
|
|
397
|
+
replayUrl: this.config.replayUrl
|
|
398
|
+
},
|
|
399
|
+
fingerprint
|
|
400
|
+
);
|
|
401
|
+
}
|
|
202
402
|
async flush() {
|
|
203
403
|
if (!this.config || this.isFlushing) return;
|
|
204
404
|
if (!this.buffer.length) return;
|
|
205
405
|
this.isFlushing = true;
|
|
206
406
|
const events = this.buffer.splice(0);
|
|
207
407
|
try {
|
|
208
|
-
await fetch(
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
408
|
+
const response = await fetch(
|
|
409
|
+
`${this.config.ingestUrl}/v1/events/${this.config.key}`,
|
|
410
|
+
{
|
|
411
|
+
method: "POST",
|
|
412
|
+
headers: { "Content-Type": "application/json" },
|
|
413
|
+
body: JSON.stringify(events),
|
|
414
|
+
keepalive: true
|
|
415
|
+
}
|
|
416
|
+
);
|
|
417
|
+
if (response.ok) {
|
|
418
|
+
const data = await response.json().catch(() => null);
|
|
419
|
+
if (data && typeof data.replayEnabled === "boolean") {
|
|
420
|
+
this.replayEnabled = data.replayEnabled;
|
|
421
|
+
if (this.replayEnabled) {
|
|
422
|
+
await this.startReplay();
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
}
|
|
214
426
|
this.retryAttempt = 0;
|
|
215
427
|
if (this.retryTimer) {
|
|
216
428
|
window.clearTimeout(this.retryTimer);
|
|
@@ -277,7 +489,9 @@ var VybeSecSDK = class {
|
|
|
277
489
|
if (typeof window === "undefined" || !("fetch" in window)) return;
|
|
278
490
|
const originalFetch = window.fetch.bind(window);
|
|
279
491
|
window.fetch = async (...args) => {
|
|
492
|
+
const start = Date.now();
|
|
280
493
|
const response = await originalFetch(...args);
|
|
494
|
+
const duration = Date.now() - start;
|
|
281
495
|
try {
|
|
282
496
|
const request = args[0];
|
|
283
497
|
const method = (request instanceof Request ? request.method : args[1]?.method) ?? "GET";
|
|
@@ -290,6 +504,7 @@ var VybeSecSDK = class {
|
|
|
290
504
|
requestUrl: url,
|
|
291
505
|
requestMethod: method,
|
|
292
506
|
responseStatus: response.status,
|
|
507
|
+
responseTimeMs: duration,
|
|
293
508
|
url: typeof window !== "undefined" ? window.location.href : void 0,
|
|
294
509
|
timestamp: Date.now()
|
|
295
510
|
});
|
|
@@ -322,6 +537,7 @@ var VybeSecSDK = class {
|
|
|
322
537
|
proto.send = function(body) {
|
|
323
538
|
const xhr = this;
|
|
324
539
|
const meta = xhr.__vsMeta;
|
|
540
|
+
const startedAt = Date.now();
|
|
325
541
|
const handleComplete = () => {
|
|
326
542
|
try {
|
|
327
543
|
if (!sdk.config || !meta) return;
|
|
@@ -334,6 +550,7 @@ var VybeSecSDK = class {
|
|
|
334
550
|
requestUrl: meta.url,
|
|
335
551
|
requestMethod: meta.method,
|
|
336
552
|
responseStatus: status || void 0,
|
|
553
|
+
responseTimeMs: Date.now() - startedAt,
|
|
337
554
|
url: typeof window !== "undefined" ? window.location.href : void 0,
|
|
338
555
|
timestamp: Date.now()
|
|
339
556
|
});
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import type { RawEvent } from \"@vybesec/types\";\n\nexport type VybeSecConfig = {\n key: string;\n environment?: \"production\" | \"staging\" | \"development\";\n platform?:\n | \"lovable\"\n | \"cursor\"\n | \"replit\"\n | \"v0\"\n | \"bolt\"\n | \"windsurf\"\n | \"other\";\n release?: string;\n userId?: string;\n sampleRate?: number;\n maxBuffer?: number;\n maxEventsPerMinute?: number;\n ingestUrl?: string;\n};\n\nconst DEFAULT_INGEST_URL = \"https://vybesec-ingest.hexeldigitalstudio.workers.dev\";\nconst SESSION_KEY = \"vybesec_session_id\";\n\nfunction getSessionId(): string {\n try {\n const existing = window.localStorage.getItem(SESSION_KEY);\n if (existing) return existing;\n const next = crypto.randomUUID();\n window.localStorage.setItem(SESSION_KEY, next);\n return next;\n } catch {\n return crypto.randomUUID();\n }\n}\n\nfunction getErrorMessage(error: unknown): string {\n if (error instanceof Error) return error.message || \"Unknown error\";\n if (typeof error === \"string\") return error;\n try {\n return JSON.stringify(error);\n } catch {\n return \"Unknown error\";\n }\n}\n\nfunction getErrorType(error: unknown): string {\n if (error instanceof Error && error.name) return error.name;\n return \"Error\";\n}\n\nfunction getStackTrace(error: unknown): string | undefined {\n if (error instanceof Error) return error.stack;\n return undefined;\n}\n\nfunction scrubSensitiveText(value?: string): string | undefined {\n if (!value) return value;\n const patterns = [\n /sk-[a-zA-Z0-9]{20,}/g,\n /pk_[a-zA-Z0-9]{20,}/g,\n /Bearer\\s+[a-zA-Z0-9\\-_.]{20,}/g,\n /password[\"']?\\s*[:=]\\s*[\"'][^\"']+/gi\n ];\n let output = value;\n for (const pattern of patterns) {\n output = output.replace(pattern, \"[REDACTED]\");\n }\n return output;\n}\n\nconst SENSITIVE_KEY = /(password|token|secret|api[_-]?key|authorization)/i;\nconst MAX_SCRUB_DEPTH = 3;\n\nfunction scrubValue(value: unknown, depth = 0): unknown {\n if (depth >= MAX_SCRUB_DEPTH) return value;\n if (typeof value === \"string\") return scrubSensitiveText(value) ?? value;\n if (Array.isArray(value)) {\n return value.map((entry) => scrubValue(entry, depth + 1));\n }\n if (value && typeof value === \"object\") {\n const record = value as Record<string, unknown>;\n const next: Record<string, unknown> = {};\n for (const [key, entry] of Object.entries(record)) {\n if (SENSITIVE_KEY.test(key)) {\n next[key] = \"[REDACTED]\";\n continue;\n }\n next[key] = scrubValue(entry, depth + 1);\n }\n return next;\n }\n return value;\n}\n\nfunction scrubEvent(event: RawEvent): RawEvent {\n return {\n ...event,\n message: scrubSensitiveText(event.message) ?? event.message,\n stackTrace: scrubSensitiveText(event.stackTrace),\n tags: event.tags ? (scrubValue(event.tags) as Record<string, string>) : event.tags,\n extra: event.extra ? (scrubValue(event.extra) as Record<string, unknown>) : event.extra\n };\n}\n\nexport class VybeSecSDK {\n private config: VybeSecConfig | null = null;\n private buffer: RawEvent[] = [];\n private eventTimestamps: number[] = [];\n private flushTimer?: number;\n private retryTimer?: number;\n private retryAttempt = 0;\n private isFlushing = false;\n\n init(config: VybeSecConfig) {\n this.config = {\n ...config,\n sampleRate: config.sampleRate ?? 1,\n maxBuffer: config.maxBuffer ?? 100,\n maxEventsPerMinute: config.maxEventsPerMinute ?? 120,\n ingestUrl: config.ingestUrl ?? DEFAULT_INGEST_URL\n };\n\n if (typeof window === \"undefined\") return;\n\n window.addEventListener(\"error\", (event) => {\n this.captureError(event.error ?? event.message, {\n url: event.filename\n });\n });\n\n window.addEventListener(\"unhandledrejection\", (event) => {\n this.captureError(event.reason);\n });\n\n this.patchFetch();\n this.patchXHR();\n this.trackNavigation();\n\n window.addEventListener(\"visibilitychange\", () => {\n if (document.visibilityState === \"hidden\") {\n this.flushBeacon();\n }\n });\n\n if (this.flushTimer) {\n window.clearInterval(this.flushTimer);\n }\n if (this.retryTimer) {\n window.clearTimeout(this.retryTimer);\n this.retryTimer = undefined;\n }\n this.retryAttempt = 0;\n this.flushTimer = window.setInterval(() => this.flush(), 5000);\n }\n\n captureError(error: unknown, context?: Record<string, string>) {\n if (!this.config) return;\n if (!this.shouldAcceptEvent()) return;\n\n const event: RawEvent = scrubEvent({\n type: \"error\",\n message: getErrorMessage(error),\n stackTrace: getStackTrace(error),\n errorType: getErrorType(error),\n url: typeof window !== \"undefined\" ? window.location.href : undefined,\n sessionId: typeof window !== \"undefined\" ? getSessionId() : undefined,\n userId: this.config.userId,\n timestamp: Date.now(),\n tags: {\n ...(context ?? {}),\n platform: this.config.platform ?? \"other\",\n environment: this.config.environment ?? \"production\",\n release: this.config.release ?? \"\"\n }\n });\n\n this.pushEvent(event);\n }\n\n captureEvent(event: RawEvent) {\n if (!this.config) return;\n if (!this.shouldAcceptEvent()) return;\n const enriched: RawEvent = scrubEvent({\n ...event,\n sessionId: event.sessionId ?? (typeof window !== \"undefined\" ? getSessionId() : undefined),\n userId: event.userId ?? this.config.userId,\n timestamp: event.timestamp ?? Date.now(),\n tags: {\n ...(event.tags ?? {}),\n platform: this.config.platform ?? \"other\",\n environment: this.config.environment ?? \"production\",\n release: this.config.release ?? \"\"\n }\n });\n\n this.pushEvent(enriched);\n }\n\n private pushEvent(event: RawEvent) {\n if (!this.config) return;\n const maxBuffer = this.config.maxBuffer ?? 100;\n if (maxBuffer <= 0) return;\n while (this.buffer.length >= maxBuffer) {\n this.buffer.shift();\n }\n this.buffer.push(event);\n if (this.buffer.length >= 10) {\n void this.flush();\n }\n }\n\n private async flush() {\n if (!this.config || this.isFlushing) return;\n if (!this.buffer.length) return;\n\n this.isFlushing = true;\n const events = this.buffer.splice(0);\n\n try {\n await fetch(`${this.config.ingestUrl}/v1/events/${this.config.key}`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(events),\n keepalive: true\n });\n this.retryAttempt = 0;\n if (this.retryTimer) {\n window.clearTimeout(this.retryTimer);\n this.retryTimer = undefined;\n }\n } catch {\n this.buffer.unshift(...events);\n this.scheduleRetry();\n } finally {\n this.isFlushing = false;\n }\n }\n\n private flushBeacon() {\n if (!this.config || !this.buffer.length) return;\n\n const events = this.buffer.splice(0);\n const payload = new Blob([JSON.stringify(events)], {\n type: \"application/json\"\n });\n\n if (navigator.sendBeacon) {\n navigator.sendBeacon(\n `${this.config.ingestUrl}/v1/events/${this.config.key}`,\n payload\n );\n return;\n }\n\n void fetch(`${this.config.ingestUrl}/v1/events/${this.config.key}`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(events),\n keepalive: true\n });\n }\n\n private scheduleRetry() {\n if (typeof window === \"undefined\") return;\n const backoffMs = Math.min(30_000, 1000 * 2 ** this.retryAttempt);\n this.retryAttempt = Math.min(this.retryAttempt + 1, 5);\n if (this.retryTimer) {\n window.clearTimeout(this.retryTimer);\n }\n this.retryTimer = window.setTimeout(() => this.flush(), backoffMs);\n }\n\n private shouldAcceptEvent(): boolean {\n if (!this.config) return false;\n if (Math.random() > (this.config.sampleRate ?? 1)) return false;\n if (!this.consumeRateLimit()) return false;\n return true;\n }\n\n private consumeRateLimit(): boolean {\n if (!this.config) return false;\n const maxPerMinute = this.config.maxEventsPerMinute ?? 120;\n if (maxPerMinute <= 0) return false;\n\n const now = Date.now();\n const windowStart = now - 60_000;\n this.eventTimestamps = this.eventTimestamps.filter(\n (timestamp) => timestamp > windowStart\n );\n\n if (this.eventTimestamps.length >= maxPerMinute) {\n return false;\n }\n\n this.eventTimestamps.push(now);\n return true;\n }\n\n private patchFetch() {\n if (typeof window === \"undefined\" || !(\"fetch\" in window)) return;\n\n const originalFetch = window.fetch.bind(window);\n window.fetch = async (...args) => {\n const response = await originalFetch(...args);\n\n try {\n const request = args[0];\n const method =\n (request instanceof Request\n ? request.method\n : args[1]?.method) ?? \"GET\";\n const url = request instanceof Request ? request.url : String(request);\n\n if (!response.ok) {\n this.captureEvent({\n type: \"error\",\n message: `Request failed with ${response.status}`,\n errorType: \"HttpError\",\n requestUrl: url,\n requestMethod: method,\n responseStatus: response.status,\n url: typeof window !== \"undefined\" ? window.location.href : undefined,\n timestamp: Date.now()\n });\n }\n } catch {\n // ignore fetch instrumentation failures\n }\n\n return response;\n };\n }\n\n private patchXHR() {\n if (typeof window === \"undefined\" || !(\"XMLHttpRequest\" in window)) return;\n const sdk = this;\n const proto = XMLHttpRequest.prototype as XMLHttpRequest & {\n __vsPatched?: boolean;\n __vsMeta?: { method: string; url: string };\n };\n\n if (proto.__vsPatched) return;\n proto.__vsPatched = true;\n\n const originalOpen = proto.open;\n // narrow the send signature to match what we'll call\n const originalSend = proto.send as (\n this: XMLHttpRequest,\n body?: Document | XMLHttpRequestBodyInit | null\n ) => void;\n\n proto.open = function (\n method: string,\n url: string,\n async?: boolean,\n user?: string | null,\n password?: string | null\n ) {\n const xhr = this as typeof proto;\n xhr.__vsMeta = { method, url: String(url) };\n return originalOpen.call(\n xhr,\n method,\n url,\n async ?? true,\n user ?? null,\n password ?? null\n );\n };\n\n // Accept any here and cast when calling the native send to avoid\n // TypeScript diagnostics around BodyInit / ReadableStream mismatch.\n proto.send = function (body?: any) {\n const xhr = this as typeof proto;\n const meta = xhr.__vsMeta;\n\n const handleComplete = () => {\n try {\n if (!sdk.config || !meta) return;\n const status = xhr.status;\n if (status >= 400 || status === 0) {\n sdk.captureEvent({\n type: \"error\",\n message: `XHR failed with ${status || \"network error\"}`,\n errorType: \"HttpError\",\n requestUrl: meta.url,\n requestMethod: meta.method,\n responseStatus: status || undefined,\n url: typeof window !== \"undefined\" ? window.location.href : undefined,\n timestamp: Date.now()\n });\n }\n } finally {\n // clean up listeners to avoid leaks / duplicate reporting\n xhr.removeEventListener(\"loadend\", handleComplete);\n xhr.removeEventListener(\"error\", handleComplete);\n }\n };\n\n xhr.addEventListener(\"loadend\", handleComplete);\n xhr.addEventListener(\"error\", handleComplete);\n\n // Cast to the native expected type to satisfy the method signature.\n return originalSend.call(xhr, body as Document | XMLHttpRequestBodyInit | null);\n };\n }\n\n private trackNavigation() {\n if (typeof window === \"undefined\") return;\n const pushState = history.pushState;\n const replaceState = history.replaceState;\n\n const handleNavigation = () => {\n this.captureEvent({\n type: \"info\",\n message: `Navigation to ${window.location.href}`,\n url: window.location.href,\n timestamp: Date.now()\n });\n };\n\n history.pushState = function (...args) {\n const result = pushState.apply(this, args as never);\n handleNavigation();\n return result;\n };\n\n history.replaceState = function (...args) {\n const result = replaceState.apply(this, args as never);\n handleNavigation();\n return result;\n };\n\n window.addEventListener(\"popstate\", handleNavigation);\n }\n}\n\nexport const vybesec = new VybeSecSDK();\nexport const init = (config: VybeSecConfig) => vybesec.init(config);\nexport const captureError = (error: unknown) => vybesec.captureError(error);\nexport const captureEvent = (event: RawEvent) => vybesec.captureEvent(event);\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/vitals.ts","../src/replay.ts"],"sourcesContent":["import type { Platform, RawEvent } from \"@vybesec/types\";\nimport { captureWebVitals } from \"./vitals\";\nimport { ReplayCapture } from \"./replay\";\n\nexport type VybeSecConfig = {\n key: string;\n environment?: \"production\" | \"staging\" | \"development\";\n platform?: Platform;\n release?: string;\n userId?: string;\n sampleRate?: number;\n maxBuffer?: number;\n maxEventsPerMinute?: number;\n enableVitals?: boolean;\n enableReplay?: boolean;\n};\n\ntype InternalConfig = VybeSecConfig & {\n ingestUrl: string;\n replayUrl: string;\n};\n\nconst DEFAULT_INGEST_URL = \"https://vybesec-ingest.hexeldigitalstudio.workers.dev\";\nconst DEFAULT_REPLAY_URL = \"https://vybesec-replay.hexeldigitalstudio.workers.dev\";\nconst SESSION_KEY = \"vybesec_session_id\";\n\nfunction getSessionId(): string {\n try {\n const existing = window.localStorage.getItem(SESSION_KEY);\n if (existing) return existing;\n const next = crypto.randomUUID();\n window.localStorage.setItem(SESSION_KEY, next);\n return next;\n } catch {\n return crypto.randomUUID();\n }\n}\n\nfunction getErrorMessage(error: unknown): string {\n if (error instanceof Error) return error.message || \"Unknown error\";\n if (typeof error === \"string\") return error;\n try {\n return JSON.stringify(error);\n } catch {\n return \"Unknown error\";\n }\n}\n\nfunction getErrorType(error: unknown): string {\n if (error instanceof Error && error.name) return error.name;\n return \"Error\";\n}\n\nfunction getStackTrace(error: unknown): string | undefined {\n if (error instanceof Error) return error.stack;\n return undefined;\n}\n\nfunction normalizeMessage(message: string): string {\n return message\n .replace(/0x[0-9a-f]+/gi, \"0xADDR\")\n .replace(/\\d+:\\d+/g, \"L:C\")\n .replace(/\\\"[^\\\"]{0,50}\\\"/g, '\"VAL\"');\n}\n\ntype StackFrame = { file: string; fn: string };\n\nfunction parseStackTrace(stack: string | undefined): StackFrame[] {\n if (!stack) return [];\n const lines = stack.split(\"\\n\");\n const frames: StackFrame[] = [];\n for (const line of lines) {\n const match = line.match(/at\\\\s+(.*?)(?:\\\\s+\\\\(|\\\\s)(.+?):\\\\d+:\\\\d+\\\\)?/);\n if (match) {\n frames.push({ fn: match[1] || \"anonymous\", file: match[2] || \"unknown\" });\n }\n }\n return frames;\n}\n\nasync function sha256(input: string): Promise<string> {\n const buffer = new TextEncoder().encode(input);\n const hash = await crypto.subtle.digest(\"SHA-256\", buffer);\n return Array.from(new Uint8Array(hash))\n .map((b) => b.toString(16).padStart(2, \"0\"))\n .join(\"\");\n}\n\nasync function computeFingerprint(event: RawEvent): Promise<string> {\n const normalized = normalizeMessage(event.message ?? \"\");\n const frames = parseStackTrace(event.stackTrace)\n .slice(0, 3)\n .map((frame) => `${frame.file}:${frame.fn}`)\n .join(\"|\");\n const errorType = event.errorType ?? \"Error\";\n const input = `${errorType}:${normalized}:${frames}`;\n const hash = await sha256(input);\n return hash.slice(0, 16);\n}\n\nfunction scrubSensitiveText(value?: string): string | undefined {\n if (!value) return value;\n const patterns = [\n /sk-[a-zA-Z0-9]{20,}/g,\n /pk_[a-zA-Z0-9]{20,}/g,\n /Bearer\\s+[a-zA-Z0-9\\-_.]{20,}/g,\n /password[\"']?\\s*[:=]\\s*[\"'][^\"']+/gi\n ];\n let output = value;\n for (const pattern of patterns) {\n output = output.replace(pattern, \"[REDACTED]\");\n }\n return output;\n}\n\nconst SENSITIVE_KEY = /(password|token|secret|api[_-]?key|authorization)/i;\nconst MAX_SCRUB_DEPTH = 3;\n\nfunction scrubValue(value: unknown, depth = 0): unknown {\n if (depth >= MAX_SCRUB_DEPTH) return value;\n if (typeof value === \"string\") return scrubSensitiveText(value) ?? value;\n if (Array.isArray(value)) {\n return value.map((entry) => scrubValue(entry, depth + 1));\n }\n if (value && typeof value === \"object\") {\n const record = value as Record<string, unknown>;\n const next: Record<string, unknown> = {};\n for (const [key, entry] of Object.entries(record)) {\n if (SENSITIVE_KEY.test(key)) {\n next[key] = \"[REDACTED]\";\n continue;\n }\n next[key] = scrubValue(entry, depth + 1);\n }\n return next;\n }\n return value;\n}\n\nfunction scrubEvent(event: RawEvent): RawEvent {\n return {\n ...event,\n message: scrubSensitiveText(event.message) ?? event.message,\n stackTrace: scrubSensitiveText(event.stackTrace),\n tags: event.tags ? (scrubValue(event.tags) as Record<string, string>) : event.tags,\n extra: event.extra ? (scrubValue(event.extra) as Record<string, unknown>) : event.extra\n };\n}\n\nexport class VybeSecSDK {\n private config: InternalConfig | null = null;\n private buffer: RawEvent[] = [];\n private eventTimestamps: number[] = [];\n private flushTimer?: number;\n private retryTimer?: number;\n private retryAttempt = 0;\n private isFlushing = false;\n private replayCapture?: ReplayCapture;\n private replayEnabled = false;\n private replayStarted = false;\n private sessionId?: string;\n\n init(config: VybeSecConfig) {\n this.config = {\n ...config,\n sampleRate: config.sampleRate ?? 1,\n maxBuffer: config.maxBuffer ?? 100,\n maxEventsPerMinute: config.maxEventsPerMinute ?? 120,\n ingestUrl: DEFAULT_INGEST_URL,\n replayUrl: DEFAULT_REPLAY_URL,\n enableVitals: config.enableVitals ?? true,\n enableReplay: config.enableReplay ?? true\n };\n\n if (typeof window === \"undefined\") return;\n\n this.sessionId = getSessionId();\n this.replayEnabled = false;\n this.replayStarted = false;\n\n if (this.config.enableReplay) {\n this.replayCapture = new ReplayCapture();\n }\n\n window.addEventListener(\"error\", (event) => {\n this.captureError(event.error ?? event.message, {\n url: event.filename\n });\n });\n\n window.addEventListener(\"unhandledrejection\", (event) => {\n this.captureError(event.reason);\n });\n\n this.patchFetch();\n this.patchXHR();\n this.trackNavigation();\n\n window.addEventListener(\"visibilitychange\", () => {\n if (document.visibilityState === \"hidden\") {\n this.flushBeacon();\n }\n });\n\n if (this.config.enableVitals) {\n void captureWebVitals((metric) => {\n this.captureEvent({\n type: \"performance\",\n message: metric.metricName,\n timestamp: Date.now(),\n sessionId: this.sessionId,\n extra: {\n metricName: metric.metricName,\n value: metric.value,\n rating: metric.rating\n }\n });\n });\n }\n\n if (this.flushTimer) {\n window.clearInterval(this.flushTimer);\n }\n if (this.retryTimer) {\n window.clearTimeout(this.retryTimer);\n this.retryTimer = undefined;\n }\n this.retryAttempt = 0;\n this.flushTimer = window.setInterval(() => this.flush(), 5000);\n }\n\n captureError(error: unknown, context?: Record<string, string>) {\n if (!this.config) return;\n if (!this.shouldAcceptEvent()) return;\n\n const event: RawEvent = scrubEvent({\n type: \"error\",\n message: getErrorMessage(error),\n stackTrace: getStackTrace(error),\n errorType: getErrorType(error),\n url: typeof window !== \"undefined\" ? window.location.href : undefined,\n sessionId:\n typeof window !== \"undefined\"\n ? this.sessionId ?? getSessionId()\n : undefined,\n userId: this.config.userId,\n timestamp: Date.now(),\n tags: {\n ...(context ?? {}),\n platform: this.config.platform ?? \"other\",\n environment: this.config.environment ?? \"production\",\n release: this.config.release ?? \"\"\n }\n });\n\n this.pushEvent(event);\n void this.flushReplayOnError(event);\n }\n\n captureEvent(event: RawEvent) {\n if (!this.config) return;\n if (!this.shouldAcceptEvent()) return;\n const enriched: RawEvent = scrubEvent({\n ...event,\n sessionId:\n event.sessionId ??\n (typeof window !== \"undefined\"\n ? this.sessionId ?? getSessionId()\n : undefined),\n userId: event.userId ?? this.config.userId,\n timestamp: event.timestamp ?? Date.now(),\n tags: {\n ...(event.tags ?? {}),\n platform: this.config.platform ?? \"other\",\n environment: this.config.environment ?? \"production\",\n release: this.config.release ?? \"\"\n }\n });\n\n this.pushEvent(enriched);\n }\n\n private pushEvent(event: RawEvent) {\n if (!this.config) return;\n const maxBuffer = this.config.maxBuffer ?? 100;\n if (maxBuffer <= 0) return;\n while (this.buffer.length >= maxBuffer) {\n this.buffer.shift();\n }\n this.buffer.push(event);\n if (this.buffer.length >= 10) {\n void this.flush();\n }\n }\n\n private async startReplay() {\n if (!this.replayCapture || this.replayStarted) return;\n await this.replayCapture.start();\n this.replayStarted = true;\n }\n\n private async flushReplayOnError(event: RawEvent) {\n if (!this.config) return;\n if (!this.replayCapture || !this.replayEnabled) return;\n const fingerprint = await computeFingerprint(event);\n await this.replayCapture.flushOnError(\n {\n publicKey: this.config.key,\n sessionId: this.sessionId ?? getSessionId(),\n replayUrl: this.config.replayUrl\n },\n fingerprint\n );\n }\n\n private async flush() {\n if (!this.config || this.isFlushing) return;\n if (!this.buffer.length) return;\n\n this.isFlushing = true;\n const events = this.buffer.splice(0);\n\n try {\n const response = await fetch(\n `${this.config.ingestUrl}/v1/events/${this.config.key}`,\n {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(events),\n keepalive: true\n }\n );\n if (response.ok) {\n const data = await response.json().catch(() => null);\n if (data && typeof data.replayEnabled === \"boolean\") {\n this.replayEnabled = data.replayEnabled;\n if (this.replayEnabled) {\n await this.startReplay();\n }\n }\n }\n this.retryAttempt = 0;\n if (this.retryTimer) {\n window.clearTimeout(this.retryTimer);\n this.retryTimer = undefined;\n }\n } catch {\n this.buffer.unshift(...events);\n this.scheduleRetry();\n } finally {\n this.isFlushing = false;\n }\n }\n\n private flushBeacon() {\n if (!this.config || !this.buffer.length) return;\n\n const events = this.buffer.splice(0);\n const payload = new Blob([JSON.stringify(events)], {\n type: \"application/json\"\n });\n\n if (navigator.sendBeacon) {\n navigator.sendBeacon(\n `${this.config.ingestUrl}/v1/events/${this.config.key}`,\n payload\n );\n return;\n }\n\n void fetch(`${this.config.ingestUrl}/v1/events/${this.config.key}`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(events),\n keepalive: true\n });\n }\n\n private scheduleRetry() {\n if (typeof window === \"undefined\") return;\n const backoffMs = Math.min(30_000, 1000 * 2 ** this.retryAttempt);\n this.retryAttempt = Math.min(this.retryAttempt + 1, 5);\n if (this.retryTimer) {\n window.clearTimeout(this.retryTimer);\n }\n this.retryTimer = window.setTimeout(() => this.flush(), backoffMs);\n }\n\n private shouldAcceptEvent(): boolean {\n if (!this.config) return false;\n if (Math.random() > (this.config.sampleRate ?? 1)) return false;\n if (!this.consumeRateLimit()) return false;\n return true;\n }\n\n private consumeRateLimit(): boolean {\n if (!this.config) return false;\n const maxPerMinute = this.config.maxEventsPerMinute ?? 120;\n if (maxPerMinute <= 0) return false;\n\n const now = Date.now();\n const windowStart = now - 60_000;\n this.eventTimestamps = this.eventTimestamps.filter(\n (timestamp) => timestamp > windowStart\n );\n\n if (this.eventTimestamps.length >= maxPerMinute) {\n return false;\n }\n\n this.eventTimestamps.push(now);\n return true;\n }\n\n private patchFetch() {\n if (typeof window === \"undefined\" || !(\"fetch\" in window)) return;\n\n const originalFetch = window.fetch.bind(window);\n window.fetch = async (...args) => {\n const start = Date.now();\n const response = await originalFetch(...args);\n const duration = Date.now() - start;\n\n try {\n const request = args[0];\n const method =\n (request instanceof Request\n ? request.method\n : args[1]?.method) ?? \"GET\";\n const url = request instanceof Request ? request.url : String(request);\n\n if (!response.ok) {\n this.captureEvent({\n type: \"error\",\n message: `Request failed with ${response.status}`,\n errorType: \"HttpError\",\n requestUrl: url,\n requestMethod: method,\n responseStatus: response.status,\n responseTimeMs: duration,\n url: typeof window !== \"undefined\" ? window.location.href : undefined,\n timestamp: Date.now()\n });\n }\n } catch {\n // ignore fetch instrumentation failures\n }\n\n return response;\n };\n }\n\n private patchXHR() {\n if (typeof window === \"undefined\" || !(\"XMLHttpRequest\" in window)) return;\n const sdk = this;\n const proto = XMLHttpRequest.prototype as XMLHttpRequest & {\n __vsPatched?: boolean;\n __vsMeta?: { method: string; url: string };\n };\n\n if (proto.__vsPatched) return;\n proto.__vsPatched = true;\n\n const originalOpen = proto.open;\n // narrow the send signature to match what we'll call\n const originalSend = proto.send as (\n this: XMLHttpRequest,\n body?: Document | XMLHttpRequestBodyInit | null\n ) => void;\n\n proto.open = function (\n method: string,\n url: string,\n async?: boolean,\n user?: string | null,\n password?: string | null\n ) {\n const xhr = this as typeof proto;\n xhr.__vsMeta = { method, url: String(url) };\n return originalOpen.call(\n xhr,\n method,\n url,\n async ?? true,\n user ?? null,\n password ?? null\n );\n };\n\n // Accept any here and cast when calling the native send to avoid\n // TypeScript diagnostics around BodyInit / ReadableStream mismatch.\n proto.send = function (body?: any) {\n const xhr = this as typeof proto;\n const meta = xhr.__vsMeta;\n\n const startedAt = Date.now();\n const handleComplete = () => {\n try {\n if (!sdk.config || !meta) return;\n const status = xhr.status;\n if (status >= 400 || status === 0) {\n sdk.captureEvent({\n type: \"error\",\n message: `XHR failed with ${status || \"network error\"}`,\n errorType: \"HttpError\",\n requestUrl: meta.url,\n requestMethod: meta.method,\n responseStatus: status || undefined,\n responseTimeMs: Date.now() - startedAt,\n url: typeof window !== \"undefined\" ? window.location.href : undefined,\n timestamp: Date.now()\n });\n }\n } finally {\n // clean up listeners to avoid leaks / duplicate reporting\n xhr.removeEventListener(\"loadend\", handleComplete);\n xhr.removeEventListener(\"error\", handleComplete);\n }\n };\n\n xhr.addEventListener(\"loadend\", handleComplete);\n xhr.addEventListener(\"error\", handleComplete);\n\n // Cast to the native expected type to satisfy the method signature.\n return originalSend.call(xhr, body as Document | XMLHttpRequestBodyInit | null);\n };\n }\n\n private trackNavigation() {\n if (typeof window === \"undefined\") return;\n const pushState = history.pushState;\n const replaceState = history.replaceState;\n\n const handleNavigation = () => {\n this.captureEvent({\n type: \"info\",\n message: `Navigation to ${window.location.href}`,\n url: window.location.href,\n timestamp: Date.now()\n });\n };\n\n history.pushState = function (...args) {\n const result = pushState.apply(this, args as never);\n handleNavigation();\n return result;\n };\n\n history.replaceState = function (...args) {\n const result = replaceState.apply(this, args as never);\n handleNavigation();\n return result;\n };\n\n window.addEventListener(\"popstate\", handleNavigation);\n }\n}\n\nexport const vybesec = new VybeSecSDK();\nexport const init = (config: VybeSecConfig) => vybesec.init(config);\nexport const captureError = (error: unknown) => vybesec.captureError(error);\nexport const captureEvent = (event: RawEvent) => vybesec.captureEvent(event);\n","import type { Metric } from \"web-vitals\";\n\nexport type VitalsMetric = {\n metricName: string;\n value: number;\n rating: \"good\" | \"needs_improvement\" | \"poor\";\n};\n\nconst thresholds: Record<string, [number, number]> = {\n LCP: [2500, 4000],\n TTFB: [800, 1800],\n FCP: [1800, 3000],\n INP: [200, 500],\n CLS: [0.1, 0.25]\n};\n\nfunction rateMetric(metric: Metric): VitalsMetric[\"rating\"] {\n const [good, poor] = thresholds[metric.name] ?? [0, 0];\n if (metric.value <= good) return \"good\";\n if (metric.value <= poor) return \"needs_improvement\";\n return \"poor\";\n}\n\nexport async function captureWebVitals(\n onMetric: (metric: VitalsMetric) => void\n): Promise<void> {\n const { onLCP, onTTFB, onFCP, onINP, onCLS } = await import(\"web-vitals\");\n const report = (metric: Metric) => {\n onMetric({\n metricName: metric.name,\n value: metric.value,\n rating: rateMetric(metric)\n });\n };\n\n onLCP(report);\n onTTFB(report);\n onFCP(report);\n onINP(report);\n onCLS(report);\n}\n","const BUFFER_SECONDS = 60;\nconst MAX_EVENTS = 2000;\n\nexport type ReplayConfig = {\n publicKey: string;\n sessionId: string;\n replayUrl: string;\n};\n\nexport class ReplayCapture {\n private events: { type: number; data: unknown; timestamp: number }[] = [];\n private stopFn?: () => void;\n private flushed = false;\n\n async start(): Promise<void> {\n if (this.stopFn) return;\n const { record } = await import(\"rrweb\");\n this.stopFn = record({\n emit: (event) => {\n const now = Date.now();\n this.events.push(event);\n const cutoff = now - BUFFER_SECONDS * 1000;\n while (this.events.length > 0 && this.events[0].timestamp < cutoff) {\n this.events.shift();\n }\n if (this.events.length > MAX_EVENTS) {\n this.events = this.events.slice(-MAX_EVENTS);\n }\n },\n maskAllInputs: true,\n maskInputOptions: {\n password: true,\n email: true,\n tel: true,\n text: true,\n number: false,\n search: false\n },\n blockClass: \"vybesec-block\",\n maskTextClass: \"vybesec-mask\",\n ignoreClass: \"vybesec-ignore\",\n recordCrossOriginIframes: false,\n sampling: {\n mousemove: 100,\n scroll: 150,\n input: \"last\"\n }\n });\n }\n\n async flushOnError(\n config: ReplayConfig,\n errorFingerprint: string\n ): Promise<void> {\n if (this.flushed || this.events.length < 10) return;\n this.flushed = true;\n\n const payload = scrubReplayPayload(\n this.events.map((event) => JSON.stringify(event)).join(\"\\n\")\n );\n\n const blob = new Blob([payload], { type: \"application/x-ndjson\" });\n const url = new URL(\n `${config.replayUrl}/v1/replay/${config.publicKey}/${config.sessionId}`\n );\n if (errorFingerprint) {\n url.searchParams.set(\"fingerprint\", errorFingerprint);\n }\n if (typeof window !== \"undefined\") {\n url.searchParams.set(\"urlPath\", window.location.pathname);\n }\n\n if (navigator.sendBeacon) {\n navigator.sendBeacon(url.toString(), blob);\n return;\n }\n\n await fetch(url.toString(), {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/x-ndjson\" },\n body: blob\n });\n }\n\n stop(): void {\n this.stopFn?.();\n this.stopFn = undefined;\n }\n}\n\nfunction scrubReplayPayload(payload: string): string {\n return payload\n .replace(\n /\\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Z|a-z]{2,}\\b/g,\n \"[email]\"\n )\n .replace(/\\b\\d{4}[\\s-]?\\d{4}[\\s-]?\\d{4}[\\s-]?\\d{4}\\b/g, \"[card]\")\n .replace(/sk-[a-zA-Z0-9]{20,}/g, \"[api-key]\")\n .replace(/Bearer\\\\s[a-zA-Z0-9\\\\-_.]{20,}/g, \"Bearer [token]\")\n .replace(/\\b\\d{3}-\\d{2}-\\d{4}\\b/g, \"[ssn]\");\n}\n"],"mappings":"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","names":[]}
|
package/dist/index.d.cts
CHANGED
|
@@ -1,60 +1,16 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
declare const rawEventSchema: z.ZodObject<{
|
|
4
|
-
type: z.ZodEnum<["error", "warning", "info", "performance", "custom"]>;
|
|
5
|
-
message: z.ZodString;
|
|
6
|
-
stackTrace: z.ZodOptional<z.ZodString>;
|
|
7
|
-
errorType: z.ZodOptional<z.ZodString>;
|
|
8
|
-
url: z.ZodOptional<z.ZodString>;
|
|
9
|
-
requestUrl: z.ZodOptional<z.ZodString>;
|
|
10
|
-
requestMethod: z.ZodOptional<z.ZodString>;
|
|
11
|
-
responseStatus: z.ZodOptional<z.ZodNumber>;
|
|
12
|
-
sessionId: z.ZodOptional<z.ZodString>;
|
|
13
|
-
userId: z.ZodOptional<z.ZodString>;
|
|
14
|
-
timestamp: z.ZodNumber;
|
|
15
|
-
tags: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
16
|
-
extra: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodAny>>;
|
|
17
|
-
}, "strip", z.ZodTypeAny, {
|
|
18
|
-
type: "custom" | "error" | "warning" | "info" | "performance";
|
|
19
|
-
message: string;
|
|
20
|
-
timestamp: number;
|
|
21
|
-
stackTrace?: string | undefined;
|
|
22
|
-
errorType?: string | undefined;
|
|
23
|
-
url?: string | undefined;
|
|
24
|
-
requestUrl?: string | undefined;
|
|
25
|
-
requestMethod?: string | undefined;
|
|
26
|
-
responseStatus?: number | undefined;
|
|
27
|
-
sessionId?: string | undefined;
|
|
28
|
-
userId?: string | undefined;
|
|
29
|
-
tags?: Record<string, string> | undefined;
|
|
30
|
-
extra?: Record<string, any> | undefined;
|
|
31
|
-
}, {
|
|
32
|
-
type: "custom" | "error" | "warning" | "info" | "performance";
|
|
33
|
-
message: string;
|
|
34
|
-
timestamp: number;
|
|
35
|
-
stackTrace?: string | undefined;
|
|
36
|
-
errorType?: string | undefined;
|
|
37
|
-
url?: string | undefined;
|
|
38
|
-
requestUrl?: string | undefined;
|
|
39
|
-
requestMethod?: string | undefined;
|
|
40
|
-
responseStatus?: number | undefined;
|
|
41
|
-
sessionId?: string | undefined;
|
|
42
|
-
userId?: string | undefined;
|
|
43
|
-
tags?: Record<string, string> | undefined;
|
|
44
|
-
extra?: Record<string, any> | undefined;
|
|
45
|
-
}>;
|
|
46
|
-
type RawEvent = z.infer<typeof rawEventSchema>;
|
|
1
|
+
import { Platform, RawEvent } from '@vybesec/types';
|
|
47
2
|
|
|
48
3
|
type VybeSecConfig = {
|
|
49
4
|
key: string;
|
|
50
5
|
environment?: "production" | "staging" | "development";
|
|
51
|
-
platform?:
|
|
6
|
+
platform?: Platform;
|
|
52
7
|
release?: string;
|
|
53
8
|
userId?: string;
|
|
54
9
|
sampleRate?: number;
|
|
55
10
|
maxBuffer?: number;
|
|
56
11
|
maxEventsPerMinute?: number;
|
|
57
|
-
|
|
12
|
+
enableVitals?: boolean;
|
|
13
|
+
enableReplay?: boolean;
|
|
58
14
|
};
|
|
59
15
|
declare class VybeSecSDK {
|
|
60
16
|
private config;
|
|
@@ -64,10 +20,16 @@ declare class VybeSecSDK {
|
|
|
64
20
|
private retryTimer?;
|
|
65
21
|
private retryAttempt;
|
|
66
22
|
private isFlushing;
|
|
23
|
+
private replayCapture?;
|
|
24
|
+
private replayEnabled;
|
|
25
|
+
private replayStarted;
|
|
26
|
+
private sessionId?;
|
|
67
27
|
init(config: VybeSecConfig): void;
|
|
68
28
|
captureError(error: unknown, context?: Record<string, string>): void;
|
|
69
29
|
captureEvent(event: RawEvent): void;
|
|
70
30
|
private pushEvent;
|
|
31
|
+
private startReplay;
|
|
32
|
+
private flushReplayOnError;
|
|
71
33
|
private flush;
|
|
72
34
|
private flushBeacon;
|
|
73
35
|
private scheduleRetry;
|