@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/dist/index.d.ts CHANGED
@@ -1,60 +1,16 @@
1
- import { z } from 'zod';
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?: "lovable" | "cursor" | "replit" | "v0" | "bolt" | "windsurf" | "other";
6
+ platform?: Platform;
52
7
  release?: string;
53
8
  userId?: string;
54
9
  sampleRate?: number;
55
10
  maxBuffer?: number;
56
11
  maxEventsPerMinute?: number;
57
- ingestUrl?: string;
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;
package/dist/index.js CHANGED
@@ -2,8 +2,121 @@ var __defProp = Object.defineProperty;
2
2
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
3
3
  var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
4
4
 
5
+ // src/vitals.ts
6
+ var thresholds = {
7
+ LCP: [2500, 4e3],
8
+ TTFB: [800, 1800],
9
+ FCP: [1800, 3e3],
10
+ INP: [200, 500],
11
+ CLS: [0.1, 0.25]
12
+ };
13
+ function rateMetric(metric) {
14
+ const [good, poor] = thresholds[metric.name] ?? [0, 0];
15
+ if (metric.value <= good) return "good";
16
+ if (metric.value <= poor) return "needs_improvement";
17
+ return "poor";
18
+ }
19
+ async function captureWebVitals(onMetric) {
20
+ const { onLCP, onTTFB, onFCP, onINP, onCLS } = await import("web-vitals");
21
+ const report = (metric) => {
22
+ onMetric({
23
+ metricName: metric.name,
24
+ value: metric.value,
25
+ rating: rateMetric(metric)
26
+ });
27
+ };
28
+ onLCP(report);
29
+ onTTFB(report);
30
+ onFCP(report);
31
+ onINP(report);
32
+ onCLS(report);
33
+ }
34
+
35
+ // src/replay.ts
36
+ var BUFFER_SECONDS = 60;
37
+ var MAX_EVENTS = 2e3;
38
+ var ReplayCapture = class {
39
+ constructor() {
40
+ __publicField(this, "events", []);
41
+ __publicField(this, "stopFn");
42
+ __publicField(this, "flushed", false);
43
+ }
44
+ async start() {
45
+ if (this.stopFn) return;
46
+ const { record } = await import("rrweb");
47
+ this.stopFn = record({
48
+ emit: (event) => {
49
+ const now = Date.now();
50
+ this.events.push(event);
51
+ const cutoff = now - BUFFER_SECONDS * 1e3;
52
+ while (this.events.length > 0 && this.events[0].timestamp < cutoff) {
53
+ this.events.shift();
54
+ }
55
+ if (this.events.length > MAX_EVENTS) {
56
+ this.events = this.events.slice(-MAX_EVENTS);
57
+ }
58
+ },
59
+ maskAllInputs: true,
60
+ maskInputOptions: {
61
+ password: true,
62
+ email: true,
63
+ tel: true,
64
+ text: true,
65
+ number: false,
66
+ search: false
67
+ },
68
+ blockClass: "vybesec-block",
69
+ maskTextClass: "vybesec-mask",
70
+ ignoreClass: "vybesec-ignore",
71
+ recordCrossOriginIframes: false,
72
+ sampling: {
73
+ mousemove: 100,
74
+ scroll: 150,
75
+ input: "last"
76
+ }
77
+ });
78
+ }
79
+ async flushOnError(config, errorFingerprint) {
80
+ if (this.flushed || this.events.length < 10) return;
81
+ this.flushed = true;
82
+ const payload = scrubReplayPayload(
83
+ this.events.map((event) => JSON.stringify(event)).join("\n")
84
+ );
85
+ const blob = new Blob([payload], { type: "application/x-ndjson" });
86
+ const url = new URL(
87
+ `${config.replayUrl}/v1/replay/${config.publicKey}/${config.sessionId}`
88
+ );
89
+ if (errorFingerprint) {
90
+ url.searchParams.set("fingerprint", errorFingerprint);
91
+ }
92
+ if (typeof window !== "undefined") {
93
+ url.searchParams.set("urlPath", window.location.pathname);
94
+ }
95
+ if (navigator.sendBeacon) {
96
+ navigator.sendBeacon(url.toString(), blob);
97
+ return;
98
+ }
99
+ await fetch(url.toString(), {
100
+ method: "POST",
101
+ headers: { "Content-Type": "application/x-ndjson" },
102
+ body: blob
103
+ });
104
+ }
105
+ stop() {
106
+ this.stopFn?.();
107
+ this.stopFn = void 0;
108
+ }
109
+ };
110
+ function scrubReplayPayload(payload) {
111
+ return payload.replace(
112
+ /\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b/g,
113
+ "[email]"
114
+ ).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]");
115
+ }
116
+
5
117
  // src/index.ts
6
118
  var DEFAULT_INGEST_URL = "https://vybesec-ingest.hexeldigitalstudio.workers.dev";
119
+ var DEFAULT_REPLAY_URL = "https://vybesec-replay.hexeldigitalstudio.workers.dev";
7
120
  var SESSION_KEY = "vybesec_session_id";
8
121
  function getSessionId() {
9
122
  try {
@@ -33,6 +146,34 @@ function getStackTrace(error) {
33
146
  if (error instanceof Error) return error.stack;
34
147
  return void 0;
35
148
  }
149
+ function normalizeMessage(message) {
150
+ return message.replace(/0x[0-9a-f]+/gi, "0xADDR").replace(/\d+:\d+/g, "L:C").replace(/\"[^\"]{0,50}\"/g, '"VAL"');
151
+ }
152
+ function parseStackTrace(stack) {
153
+ if (!stack) return [];
154
+ const lines = stack.split("\n");
155
+ const frames = [];
156
+ for (const line of lines) {
157
+ const match = line.match(/at\\s+(.*?)(?:\\s+\\(|\\s)(.+?):\\d+:\\d+\\)?/);
158
+ if (match) {
159
+ frames.push({ fn: match[1] || "anonymous", file: match[2] || "unknown" });
160
+ }
161
+ }
162
+ return frames;
163
+ }
164
+ async function sha256(input) {
165
+ const buffer = new TextEncoder().encode(input);
166
+ const hash = await crypto.subtle.digest("SHA-256", buffer);
167
+ return Array.from(new Uint8Array(hash)).map((b) => b.toString(16).padStart(2, "0")).join("");
168
+ }
169
+ async function computeFingerprint(event) {
170
+ const normalized = normalizeMessage(event.message ?? "");
171
+ const frames = parseStackTrace(event.stackTrace).slice(0, 3).map((frame) => `${frame.file}:${frame.fn}`).join("|");
172
+ const errorType = event.errorType ?? "Error";
173
+ const input = `${errorType}:${normalized}:${frames}`;
174
+ const hash = await sha256(input);
175
+ return hash.slice(0, 16);
176
+ }
36
177
  function scrubSensitiveText(value) {
37
178
  if (!value) return value;
38
179
  const patterns = [
@@ -87,6 +228,10 @@ var VybeSecSDK = class {
87
228
  __publicField(this, "retryTimer");
88
229
  __publicField(this, "retryAttempt", 0);
89
230
  __publicField(this, "isFlushing", false);
231
+ __publicField(this, "replayCapture");
232
+ __publicField(this, "replayEnabled", false);
233
+ __publicField(this, "replayStarted", false);
234
+ __publicField(this, "sessionId");
90
235
  }
91
236
  init(config) {
92
237
  this.config = {
@@ -94,9 +239,18 @@ var VybeSecSDK = class {
94
239
  sampleRate: config.sampleRate ?? 1,
95
240
  maxBuffer: config.maxBuffer ?? 100,
96
241
  maxEventsPerMinute: config.maxEventsPerMinute ?? 120,
97
- ingestUrl: config.ingestUrl ?? DEFAULT_INGEST_URL
242
+ ingestUrl: DEFAULT_INGEST_URL,
243
+ replayUrl: DEFAULT_REPLAY_URL,
244
+ enableVitals: config.enableVitals ?? true,
245
+ enableReplay: config.enableReplay ?? true
98
246
  };
99
247
  if (typeof window === "undefined") return;
248
+ this.sessionId = getSessionId();
249
+ this.replayEnabled = false;
250
+ this.replayStarted = false;
251
+ if (this.config.enableReplay) {
252
+ this.replayCapture = new ReplayCapture();
253
+ }
100
254
  window.addEventListener("error", (event) => {
101
255
  this.captureError(event.error ?? event.message, {
102
256
  url: event.filename
@@ -113,6 +267,21 @@ var VybeSecSDK = class {
113
267
  this.flushBeacon();
114
268
  }
115
269
  });
270
+ if (this.config.enableVitals) {
271
+ void captureWebVitals((metric) => {
272
+ this.captureEvent({
273
+ type: "performance",
274
+ message: metric.metricName,
275
+ timestamp: Date.now(),
276
+ sessionId: this.sessionId,
277
+ extra: {
278
+ metricName: metric.metricName,
279
+ value: metric.value,
280
+ rating: metric.rating
281
+ }
282
+ });
283
+ });
284
+ }
116
285
  if (this.flushTimer) {
117
286
  window.clearInterval(this.flushTimer);
118
287
  }
@@ -132,7 +301,7 @@ var VybeSecSDK = class {
132
301
  stackTrace: getStackTrace(error),
133
302
  errorType: getErrorType(error),
134
303
  url: typeof window !== "undefined" ? window.location.href : void 0,
135
- sessionId: typeof window !== "undefined" ? getSessionId() : void 0,
304
+ sessionId: typeof window !== "undefined" ? this.sessionId ?? getSessionId() : void 0,
136
305
  userId: this.config.userId,
137
306
  timestamp: Date.now(),
138
307
  tags: {
@@ -143,13 +312,14 @@ var VybeSecSDK = class {
143
312
  }
144
313
  });
145
314
  this.pushEvent(event);
315
+ void this.flushReplayOnError(event);
146
316
  }
147
317
  captureEvent(event) {
148
318
  if (!this.config) return;
149
319
  if (!this.shouldAcceptEvent()) return;
150
320
  const enriched = scrubEvent({
151
321
  ...event,
152
- sessionId: event.sessionId ?? (typeof window !== "undefined" ? getSessionId() : void 0),
322
+ sessionId: event.sessionId ?? (typeof window !== "undefined" ? this.sessionId ?? getSessionId() : void 0),
153
323
  userId: event.userId ?? this.config.userId,
154
324
  timestamp: event.timestamp ?? Date.now(),
155
325
  tags: {
@@ -173,18 +343,48 @@ var VybeSecSDK = class {
173
343
  void this.flush();
174
344
  }
175
345
  }
346
+ async startReplay() {
347
+ if (!this.replayCapture || this.replayStarted) return;
348
+ await this.replayCapture.start();
349
+ this.replayStarted = true;
350
+ }
351
+ async flushReplayOnError(event) {
352
+ if (!this.config) return;
353
+ if (!this.replayCapture || !this.replayEnabled) return;
354
+ const fingerprint = await computeFingerprint(event);
355
+ await this.replayCapture.flushOnError(
356
+ {
357
+ publicKey: this.config.key,
358
+ sessionId: this.sessionId ?? getSessionId(),
359
+ replayUrl: this.config.replayUrl
360
+ },
361
+ fingerprint
362
+ );
363
+ }
176
364
  async flush() {
177
365
  if (!this.config || this.isFlushing) return;
178
366
  if (!this.buffer.length) return;
179
367
  this.isFlushing = true;
180
368
  const events = this.buffer.splice(0);
181
369
  try {
182
- await fetch(`${this.config.ingestUrl}/v1/events/${this.config.key}`, {
183
- method: "POST",
184
- headers: { "Content-Type": "application/json" },
185
- body: JSON.stringify(events),
186
- keepalive: true
187
- });
370
+ const response = await fetch(
371
+ `${this.config.ingestUrl}/v1/events/${this.config.key}`,
372
+ {
373
+ method: "POST",
374
+ headers: { "Content-Type": "application/json" },
375
+ body: JSON.stringify(events),
376
+ keepalive: true
377
+ }
378
+ );
379
+ if (response.ok) {
380
+ const data = await response.json().catch(() => null);
381
+ if (data && typeof data.replayEnabled === "boolean") {
382
+ this.replayEnabled = data.replayEnabled;
383
+ if (this.replayEnabled) {
384
+ await this.startReplay();
385
+ }
386
+ }
387
+ }
188
388
  this.retryAttempt = 0;
189
389
  if (this.retryTimer) {
190
390
  window.clearTimeout(this.retryTimer);
@@ -251,7 +451,9 @@ var VybeSecSDK = class {
251
451
  if (typeof window === "undefined" || !("fetch" in window)) return;
252
452
  const originalFetch = window.fetch.bind(window);
253
453
  window.fetch = async (...args) => {
454
+ const start = Date.now();
254
455
  const response = await originalFetch(...args);
456
+ const duration = Date.now() - start;
255
457
  try {
256
458
  const request = args[0];
257
459
  const method = (request instanceof Request ? request.method : args[1]?.method) ?? "GET";
@@ -264,6 +466,7 @@ var VybeSecSDK = class {
264
466
  requestUrl: url,
265
467
  requestMethod: method,
266
468
  responseStatus: response.status,
469
+ responseTimeMs: duration,
267
470
  url: typeof window !== "undefined" ? window.location.href : void 0,
268
471
  timestamp: Date.now()
269
472
  });
@@ -296,6 +499,7 @@ var VybeSecSDK = class {
296
499
  proto.send = function(body) {
297
500
  const xhr = this;
298
501
  const meta = xhr.__vsMeta;
502
+ const startedAt = Date.now();
299
503
  const handleComplete = () => {
300
504
  try {
301
505
  if (!sdk.config || !meta) return;
@@ -308,6 +512,7 @@ var VybeSecSDK = class {
308
512
  requestUrl: meta.url,
309
513
  requestMethod: meta.method,
310
514
  responseStatus: status || void 0,
515
+ responseTimeMs: Date.now() - startedAt,
311
516
  url: typeof window !== "undefined" ? window.location.href : void 0,
312
517
  timestamp: Date.now()
313
518
  });
package/dist/index.js.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/vitals.ts","../src/replay.ts","../src/index.ts"],"sourcesContent":["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","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"],"mappings":"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","names":[]}