@vybesec/sdk 0.1.3 → 0.1.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/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,6 +42,28 @@ 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 |
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,6 +39,120 @@ __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";
33
157
  var SESSION_KEY = "vybesec_session_id";
34
158
  function getSessionId() {
@@ -59,6 +183,34 @@ function getStackTrace(error) {
59
183
  if (error instanceof Error) return error.stack;
60
184
  return void 0;
61
185
  }
186
+ function normalizeMessage(message) {
187
+ return message.replace(/0x[0-9a-f]+/gi, "0xADDR").replace(/\d+:\d+/g, "L:C").replace(/\"[^\"]{0,50}\"/g, '"VAL"');
188
+ }
189
+ function parseStackTrace(stack) {
190
+ if (!stack) return [];
191
+ const lines = stack.split("\n");
192
+ const frames = [];
193
+ for (const line of lines) {
194
+ const match = line.match(/at\\s+(.*?)(?:\\s+\\(|\\s)(.+?):\\d+:\\d+\\)?/);
195
+ if (match) {
196
+ frames.push({ fn: match[1] || "anonymous", file: match[2] || "unknown" });
197
+ }
198
+ }
199
+ return frames;
200
+ }
201
+ async function sha256(input) {
202
+ const buffer = new TextEncoder().encode(input);
203
+ const hash = await crypto.subtle.digest("SHA-256", buffer);
204
+ return Array.from(new Uint8Array(hash)).map((b) => b.toString(16).padStart(2, "0")).join("");
205
+ }
206
+ async function computeFingerprint(event) {
207
+ const normalized = normalizeMessage(event.message ?? "");
208
+ const frames = parseStackTrace(event.stackTrace).slice(0, 3).map((frame) => `${frame.file}:${frame.fn}`).join("|");
209
+ const errorType = event.errorType ?? "Error";
210
+ const input = `${errorType}:${normalized}:${frames}`;
211
+ const hash = await sha256(input);
212
+ return hash.slice(0, 16);
213
+ }
62
214
  function scrubSensitiveText(value) {
63
215
  if (!value) return value;
64
216
  const patterns = [
@@ -113,6 +265,10 @@ var VybeSecSDK = class {
113
265
  __publicField(this, "retryTimer");
114
266
  __publicField(this, "retryAttempt", 0);
115
267
  __publicField(this, "isFlushing", false);
268
+ __publicField(this, "replayCapture");
269
+ __publicField(this, "replayEnabled", false);
270
+ __publicField(this, "replayStarted", false);
271
+ __publicField(this, "sessionId");
116
272
  }
117
273
  init(config) {
118
274
  this.config = {
@@ -120,9 +276,18 @@ var VybeSecSDK = class {
120
276
  sampleRate: config.sampleRate ?? 1,
121
277
  maxBuffer: config.maxBuffer ?? 100,
122
278
  maxEventsPerMinute: config.maxEventsPerMinute ?? 120,
123
- ingestUrl: config.ingestUrl ?? DEFAULT_INGEST_URL
279
+ ingestUrl: config.ingestUrl ?? DEFAULT_INGEST_URL,
280
+ replayUrl: config.replayUrl ?? config.ingestUrl ?? DEFAULT_INGEST_URL,
281
+ enableVitals: config.enableVitals ?? true,
282
+ enableReplay: config.enableReplay ?? true
124
283
  };
125
284
  if (typeof window === "undefined") return;
285
+ this.sessionId = getSessionId();
286
+ this.replayEnabled = false;
287
+ this.replayStarted = false;
288
+ if (this.config.enableReplay) {
289
+ this.replayCapture = new ReplayCapture();
290
+ }
126
291
  window.addEventListener("error", (event) => {
127
292
  this.captureError(event.error ?? event.message, {
128
293
  url: event.filename
@@ -139,6 +304,21 @@ var VybeSecSDK = class {
139
304
  this.flushBeacon();
140
305
  }
141
306
  });
307
+ if (this.config.enableVitals) {
308
+ void captureWebVitals((metric) => {
309
+ this.captureEvent({
310
+ type: "performance",
311
+ message: metric.metricName,
312
+ timestamp: Date.now(),
313
+ sessionId: this.sessionId,
314
+ extra: {
315
+ metricName: metric.metricName,
316
+ value: metric.value,
317
+ rating: metric.rating
318
+ }
319
+ });
320
+ });
321
+ }
142
322
  if (this.flushTimer) {
143
323
  window.clearInterval(this.flushTimer);
144
324
  }
@@ -158,7 +338,7 @@ var VybeSecSDK = class {
158
338
  stackTrace: getStackTrace(error),
159
339
  errorType: getErrorType(error),
160
340
  url: typeof window !== "undefined" ? window.location.href : void 0,
161
- sessionId: typeof window !== "undefined" ? getSessionId() : void 0,
341
+ sessionId: typeof window !== "undefined" ? this.sessionId ?? getSessionId() : void 0,
162
342
  userId: this.config.userId,
163
343
  timestamp: Date.now(),
164
344
  tags: {
@@ -169,13 +349,14 @@ var VybeSecSDK = class {
169
349
  }
170
350
  });
171
351
  this.pushEvent(event);
352
+ void this.flushReplayOnError(event);
172
353
  }
173
354
  captureEvent(event) {
174
355
  if (!this.config) return;
175
356
  if (!this.shouldAcceptEvent()) return;
176
357
  const enriched = scrubEvent({
177
358
  ...event,
178
- sessionId: event.sessionId ?? (typeof window !== "undefined" ? getSessionId() : void 0),
359
+ sessionId: event.sessionId ?? (typeof window !== "undefined" ? this.sessionId ?? getSessionId() : void 0),
179
360
  userId: event.userId ?? this.config.userId,
180
361
  timestamp: event.timestamp ?? Date.now(),
181
362
  tags: {
@@ -199,18 +380,48 @@ var VybeSecSDK = class {
199
380
  void this.flush();
200
381
  }
201
382
  }
383
+ async startReplay() {
384
+ if (!this.replayCapture || this.replayStarted) return;
385
+ await this.replayCapture.start();
386
+ this.replayStarted = true;
387
+ }
388
+ async flushReplayOnError(event) {
389
+ if (!this.config) return;
390
+ if (!this.replayCapture || !this.replayEnabled) return;
391
+ const fingerprint = await computeFingerprint(event);
392
+ await this.replayCapture.flushOnError(
393
+ {
394
+ publicKey: this.config.key,
395
+ sessionId: this.sessionId ?? getSessionId(),
396
+ replayUrl: this.config.replayUrl ?? this.config.ingestUrl ?? DEFAULT_INGEST_URL
397
+ },
398
+ fingerprint
399
+ );
400
+ }
202
401
  async flush() {
203
402
  if (!this.config || this.isFlushing) return;
204
403
  if (!this.buffer.length) return;
205
404
  this.isFlushing = true;
206
405
  const events = this.buffer.splice(0);
207
406
  try {
208
- await fetch(`${this.config.ingestUrl}/v1/events/${this.config.key}`, {
209
- method: "POST",
210
- headers: { "Content-Type": "application/json" },
211
- body: JSON.stringify(events),
212
- keepalive: true
213
- });
407
+ const response = await fetch(
408
+ `${this.config.ingestUrl}/v1/events/${this.config.key}`,
409
+ {
410
+ method: "POST",
411
+ headers: { "Content-Type": "application/json" },
412
+ body: JSON.stringify(events),
413
+ keepalive: true
414
+ }
415
+ );
416
+ if (response.ok) {
417
+ const data = await response.json().catch(() => null);
418
+ if (data && typeof data.replayEnabled === "boolean") {
419
+ this.replayEnabled = data.replayEnabled;
420
+ if (this.replayEnabled) {
421
+ await this.startReplay();
422
+ }
423
+ }
424
+ }
214
425
  this.retryAttempt = 0;
215
426
  if (this.retryTimer) {
216
427
  window.clearTimeout(this.retryTimer);
@@ -277,7 +488,9 @@ var VybeSecSDK = class {
277
488
  if (typeof window === "undefined" || !("fetch" in window)) return;
278
489
  const originalFetch = window.fetch.bind(window);
279
490
  window.fetch = async (...args) => {
491
+ const start = Date.now();
280
492
  const response = await originalFetch(...args);
493
+ const duration = Date.now() - start;
281
494
  try {
282
495
  const request = args[0];
283
496
  const method = (request instanceof Request ? request.method : args[1]?.method) ?? "GET";
@@ -290,6 +503,7 @@ var VybeSecSDK = class {
290
503
  requestUrl: url,
291
504
  requestMethod: method,
292
505
  responseStatus: response.status,
506
+ responseTimeMs: duration,
293
507
  url: typeof window !== "undefined" ? window.location.href : void 0,
294
508
  timestamp: Date.now()
295
509
  });
@@ -322,6 +536,7 @@ var VybeSecSDK = class {
322
536
  proto.send = function(body) {
323
537
  const xhr = this;
324
538
  const meta = xhr.__vsMeta;
539
+ const startedAt = Date.now();
325
540
  const handleComplete = () => {
326
541
  try {
327
542
  if (!sdk.config || !meta) return;
@@ -334,6 +549,7 @@ var VybeSecSDK = class {
334
549
  requestUrl: meta.url,
335
550
  requestMethod: meta.method,
336
551
  responseStatus: status || void 0,
552
+ responseTimeMs: Date.now() - startedAt,
337
553
  url: typeof window !== "undefined" ? window.location.href : void 0,
338
554
  timestamp: Date.now()
339
555
  });
@@ -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 { 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?:\n | \"lovable\"\n | \"cursor\"\n | \"replit\"\n | \"v0\"\n | \"bolt\"\n | \"windsurf\"\n | \"react-native\"\n | \"expo\"\n | \"other\";\n release?: string;\n userId?: string;\n sampleRate?: number;\n maxBuffer?: number;\n maxEventsPerMinute?: number;\n ingestUrl?: string;\n replayUrl?: string;\n enableVitals?: boolean;\n enableReplay?: boolean;\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 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: 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 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: config.ingestUrl ?? DEFAULT_INGEST_URL,\n replayUrl: config.replayUrl ?? config.ingestUrl ?? DEFAULT_INGEST_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 ?? this.config.ingestUrl ?? DEFAULT_INGEST_URL\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
@@ -9,6 +9,10 @@ declare const rawEventSchema: z.ZodObject<{
9
9
  requestUrl: z.ZodOptional<z.ZodString>;
10
10
  requestMethod: z.ZodOptional<z.ZodString>;
11
11
  responseStatus: z.ZodOptional<z.ZodNumber>;
12
+ responseTimeMs: z.ZodOptional<z.ZodNumber>;
13
+ deviceType: z.ZodOptional<z.ZodString>;
14
+ osName: z.ZodOptional<z.ZodString>;
15
+ appVersion: z.ZodOptional<z.ZodString>;
12
16
  sessionId: z.ZodOptional<z.ZodString>;
13
17
  userId: z.ZodOptional<z.ZodString>;
14
18
  timestamp: z.ZodNumber;
@@ -24,6 +28,10 @@ declare const rawEventSchema: z.ZodObject<{
24
28
  requestUrl?: string | undefined;
25
29
  requestMethod?: string | undefined;
26
30
  responseStatus?: number | undefined;
31
+ responseTimeMs?: number | undefined;
32
+ deviceType?: string | undefined;
33
+ osName?: string | undefined;
34
+ appVersion?: string | undefined;
27
35
  sessionId?: string | undefined;
28
36
  userId?: string | undefined;
29
37
  tags?: Record<string, string> | undefined;
@@ -38,6 +46,10 @@ declare const rawEventSchema: z.ZodObject<{
38
46
  requestUrl?: string | undefined;
39
47
  requestMethod?: string | undefined;
40
48
  responseStatus?: number | undefined;
49
+ responseTimeMs?: number | undefined;
50
+ deviceType?: string | undefined;
51
+ osName?: string | undefined;
52
+ appVersion?: string | undefined;
41
53
  sessionId?: string | undefined;
42
54
  userId?: string | undefined;
43
55
  tags?: Record<string, string> | undefined;
@@ -48,13 +60,16 @@ type RawEvent = z.infer<typeof rawEventSchema>;
48
60
  type VybeSecConfig = {
49
61
  key: string;
50
62
  environment?: "production" | "staging" | "development";
51
- platform?: "lovable" | "cursor" | "replit" | "v0" | "bolt" | "windsurf" | "other";
63
+ platform?: "lovable" | "cursor" | "replit" | "v0" | "bolt" | "windsurf" | "react-native" | "expo" | "other";
52
64
  release?: string;
53
65
  userId?: string;
54
66
  sampleRate?: number;
55
67
  maxBuffer?: number;
56
68
  maxEventsPerMinute?: number;
57
69
  ingestUrl?: string;
70
+ replayUrl?: string;
71
+ enableVitals?: boolean;
72
+ enableReplay?: boolean;
58
73
  };
59
74
  declare class VybeSecSDK {
60
75
  private config;
@@ -64,10 +79,16 @@ declare class VybeSecSDK {
64
79
  private retryTimer?;
65
80
  private retryAttempt;
66
81
  private isFlushing;
82
+ private replayCapture?;
83
+ private replayEnabled;
84
+ private replayStarted;
85
+ private sessionId?;
67
86
  init(config: VybeSecConfig): void;
68
87
  captureError(error: unknown, context?: Record<string, string>): void;
69
88
  captureEvent(event: RawEvent): void;
70
89
  private pushEvent;
90
+ private startReplay;
91
+ private flushReplayOnError;
71
92
  private flush;
72
93
  private flushBeacon;
73
94
  private scheduleRetry;
package/dist/index.d.ts CHANGED
@@ -9,6 +9,10 @@ declare const rawEventSchema: z.ZodObject<{
9
9
  requestUrl: z.ZodOptional<z.ZodString>;
10
10
  requestMethod: z.ZodOptional<z.ZodString>;
11
11
  responseStatus: z.ZodOptional<z.ZodNumber>;
12
+ responseTimeMs: z.ZodOptional<z.ZodNumber>;
13
+ deviceType: z.ZodOptional<z.ZodString>;
14
+ osName: z.ZodOptional<z.ZodString>;
15
+ appVersion: z.ZodOptional<z.ZodString>;
12
16
  sessionId: z.ZodOptional<z.ZodString>;
13
17
  userId: z.ZodOptional<z.ZodString>;
14
18
  timestamp: z.ZodNumber;
@@ -24,6 +28,10 @@ declare const rawEventSchema: z.ZodObject<{
24
28
  requestUrl?: string | undefined;
25
29
  requestMethod?: string | undefined;
26
30
  responseStatus?: number | undefined;
31
+ responseTimeMs?: number | undefined;
32
+ deviceType?: string | undefined;
33
+ osName?: string | undefined;
34
+ appVersion?: string | undefined;
27
35
  sessionId?: string | undefined;
28
36
  userId?: string | undefined;
29
37
  tags?: Record<string, string> | undefined;
@@ -38,6 +46,10 @@ declare const rawEventSchema: z.ZodObject<{
38
46
  requestUrl?: string | undefined;
39
47
  requestMethod?: string | undefined;
40
48
  responseStatus?: number | undefined;
49
+ responseTimeMs?: number | undefined;
50
+ deviceType?: string | undefined;
51
+ osName?: string | undefined;
52
+ appVersion?: string | undefined;
41
53
  sessionId?: string | undefined;
42
54
  userId?: string | undefined;
43
55
  tags?: Record<string, string> | undefined;
@@ -48,13 +60,16 @@ type RawEvent = z.infer<typeof rawEventSchema>;
48
60
  type VybeSecConfig = {
49
61
  key: string;
50
62
  environment?: "production" | "staging" | "development";
51
- platform?: "lovable" | "cursor" | "replit" | "v0" | "bolt" | "windsurf" | "other";
63
+ platform?: "lovable" | "cursor" | "replit" | "v0" | "bolt" | "windsurf" | "react-native" | "expo" | "other";
52
64
  release?: string;
53
65
  userId?: string;
54
66
  sampleRate?: number;
55
67
  maxBuffer?: number;
56
68
  maxEventsPerMinute?: number;
57
69
  ingestUrl?: string;
70
+ replayUrl?: string;
71
+ enableVitals?: boolean;
72
+ enableReplay?: boolean;
58
73
  };
59
74
  declare class VybeSecSDK {
60
75
  private config;
@@ -64,10 +79,16 @@ declare class VybeSecSDK {
64
79
  private retryTimer?;
65
80
  private retryAttempt;
66
81
  private isFlushing;
82
+ private replayCapture?;
83
+ private replayEnabled;
84
+ private replayStarted;
85
+ private sessionId?;
67
86
  init(config: VybeSecConfig): void;
68
87
  captureError(error: unknown, context?: Record<string, string>): void;
69
88
  captureEvent(event: RawEvent): void;
70
89
  private pushEvent;
90
+ private startReplay;
91
+ private flushReplayOnError;
71
92
  private flush;
72
93
  private flushBeacon;
73
94
  private scheduleRetry;