@vybesec/react-native 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 ADDED
@@ -0,0 +1,39 @@
1
+ # @vybesec/react-native
2
+
3
+ VybeSec React Native SDK for error, performance, and security monitoring.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install @vybesec/react-native @react-native-async-storage/async-storage
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ```ts
14
+ import { init, captureError, captureEvent } from "@vybesec/react-native";
15
+
16
+ init({
17
+ key: "pk_xxxxxxxxxxxxxxxx",
18
+ platform: "react-native",
19
+ environment: "development"
20
+ });
21
+
22
+ captureEvent({
23
+ type: "info",
24
+ message: "VybeSec RN test success",
25
+ timestamp: Date.now()
26
+ });
27
+
28
+ captureError(new Error("VybeSec RN test error"));
29
+ ```
30
+
31
+ ## Screen render helper
32
+
33
+ ```ts
34
+ import { trackScreenRender } from "@vybesec/react-native";
35
+
36
+ const finishRender = trackScreenRender("Home");
37
+ // call after first render
38
+ finishRender();
39
+ ```
package/dist/index.cjs ADDED
@@ -0,0 +1,546 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
9
+ var __export = (target, all) => {
10
+ for (var name in all)
11
+ __defProp(target, name, { get: all[name], enumerable: true });
12
+ };
13
+ var __copyProps = (to, from, except, desc) => {
14
+ if (from && typeof from === "object" || typeof from === "function") {
15
+ for (let key of __getOwnPropNames(from))
16
+ if (!__hasOwnProp.call(to, key) && key !== except)
17
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
18
+ }
19
+ return to;
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
+ ));
29
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
30
+ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
31
+
32
+ // src/index.ts
33
+ var index_exports = {};
34
+ __export(index_exports, {
35
+ VybeSecRN: () => VybeSecRN,
36
+ captureError: () => captureError,
37
+ captureEvent: () => captureEvent,
38
+ init: () => init,
39
+ notifyMemoryWarning: () => notifyMemoryWarning,
40
+ trackScreenRender: () => trackScreenRender,
41
+ vybesec: () => vybesec
42
+ });
43
+ module.exports = __toCommonJS(index_exports);
44
+ var import_async_storage = __toESM(require("@react-native-async-storage/async-storage"), 1);
45
+ var import_react_native = require("react-native");
46
+ var DEFAULT_INGEST_URL = "https://vybesec-ingest.hexeldigitalstudio.workers.dev";
47
+ var SESSION_KEY = "vybesec_session_id";
48
+ function generateId() {
49
+ return `vs_${Math.random().toString(36).slice(2)}${Date.now().toString(36)}`;
50
+ }
51
+ function getErrorMessage(error) {
52
+ if (error instanceof Error) return error.message || "Unknown error";
53
+ if (typeof error === "string") return error;
54
+ try {
55
+ return JSON.stringify(error);
56
+ } catch {
57
+ return "Unknown error";
58
+ }
59
+ }
60
+ function getErrorType(error) {
61
+ if (error instanceof Error && error.name) return error.name;
62
+ return "Error";
63
+ }
64
+ function getStackTrace(error) {
65
+ if (error instanceof Error) return error.stack;
66
+ return void 0;
67
+ }
68
+ var SENSITIVE_KEY = /(password|token|secret|api[_-]?key|authorization)/i;
69
+ var MAX_SCRUB_DEPTH = 3;
70
+ function scrubSensitiveText(value) {
71
+ if (!value) return value;
72
+ const patterns = [
73
+ /sk-[a-zA-Z0-9]{20,}/g,
74
+ /pk_[a-zA-Z0-9]{20,}/g,
75
+ /Bearer\s+[a-zA-Z0-9\-_.]{20,}/g,
76
+ /password["']?\s*[:=]\s*["'][^"']+/gi
77
+ ];
78
+ let output = value;
79
+ for (const pattern of patterns) {
80
+ output = output.replace(pattern, "[REDACTED]");
81
+ }
82
+ return output;
83
+ }
84
+ function scrubValue(value, depth = 0) {
85
+ if (depth >= MAX_SCRUB_DEPTH) return value;
86
+ if (typeof value === "string") return scrubSensitiveText(value) ?? value;
87
+ if (Array.isArray(value)) {
88
+ return value.map((entry) => scrubValue(entry, depth + 1));
89
+ }
90
+ if (value && typeof value === "object") {
91
+ const record = value;
92
+ const next = {};
93
+ for (const [key, entry] of Object.entries(record)) {
94
+ if (SENSITIVE_KEY.test(key)) {
95
+ next[key] = "[REDACTED]";
96
+ continue;
97
+ }
98
+ next[key] = scrubValue(entry, depth + 1);
99
+ }
100
+ return next;
101
+ }
102
+ return value;
103
+ }
104
+ function scrubEvent(event) {
105
+ return {
106
+ ...event,
107
+ message: scrubSensitiveText(event.message) ?? event.message,
108
+ stackTrace: scrubSensitiveText(event.stackTrace),
109
+ tags: event.tags ? scrubValue(event.tags) : event.tags,
110
+ extra: event.extra ? scrubValue(event.extra) : event.extra
111
+ };
112
+ }
113
+ function detectSecuritySignal(message, stack) {
114
+ const combined = `${message ?? ""}
115
+ ${stack ?? ""}`;
116
+ if (/sk-[a-zA-Z0-9]{20,}/.test(combined)) return "secret_key_exposed";
117
+ if (/pk_[a-zA-Z0-9]{20,}/.test(combined)) return "public_key_exposed";
118
+ if (/Bearer\s+[a-zA-Z0-9\-_.]{20,}/.test(combined)) return "bearer_token_exposed";
119
+ if (/api[_-]?key\s*[:=]/i.test(combined)) return "api_key_exposed";
120
+ return null;
121
+ }
122
+ function ratingFor(metric, value) {
123
+ const thresholds = {
124
+ APP_START: [2e3, 4e3],
125
+ SCREEN_RENDER: [1e3, 2500],
126
+ JS_FPS: [55, 30],
127
+ SLOW_NETWORK: [3e3, 7e3]
128
+ };
129
+ const [good, poor] = thresholds[metric] ?? [0, 0];
130
+ if (metric === "JS_FPS") {
131
+ if (value >= good) return "good";
132
+ if (value >= poor) return "needs_improvement";
133
+ return "poor";
134
+ }
135
+ if (value <= good) return "good";
136
+ if (value <= poor) return "needs_improvement";
137
+ return "poor";
138
+ }
139
+ async function setupPromiseRejectionTracking(onUnhandled) {
140
+ try {
141
+ const promiseImpl = await import("promise/setimmediate/es6-extensions");
142
+ const rejectionTracking = await import("promise/setimmediate/rejection-tracking");
143
+ const PromiseImpl = promiseImpl.default ?? promiseImpl;
144
+ if (PromiseImpl) {
145
+ globalThis.Promise = PromiseImpl;
146
+ }
147
+ const enable = rejectionTracking.enable ?? rejectionTracking;
148
+ if (typeof enable === "function") {
149
+ enable({
150
+ allRejections: true,
151
+ onUnhandled: (_id, error) => onUnhandled(error)
152
+ });
153
+ }
154
+ } catch {
155
+ }
156
+ }
157
+ var VybeSecRN = class {
158
+ constructor() {
159
+ __publicField(this, "config", null);
160
+ __publicField(this, "buffer", []);
161
+ __publicField(this, "eventTimestamps", []);
162
+ __publicField(this, "flushTimer");
163
+ __publicField(this, "retryTimer");
164
+ __publicField(this, "retryAttempt", 0);
165
+ __publicField(this, "isFlushing", false);
166
+ __publicField(this, "sessionId");
167
+ __publicField(this, "patchedStorage", false);
168
+ __publicField(this, "patchedFetch", false);
169
+ __publicField(this, "startTime", Date.now());
170
+ }
171
+ init(config) {
172
+ this.config = {
173
+ ...config,
174
+ sampleRate: config.sampleRate ?? 1,
175
+ maxBuffer: config.maxBuffer ?? 100,
176
+ maxEventsPerMinute: config.maxEventsPerMinute ?? 120,
177
+ ingestUrl: config.ingestUrl ?? DEFAULT_INGEST_URL,
178
+ platform: config.platform ?? "react-native"
179
+ };
180
+ this.initSessionId();
181
+ this.startTime = Date.now();
182
+ this.installErrorHandler();
183
+ void setupPromiseRejectionTracking((error) => this.captureError(error));
184
+ this.patchFetch();
185
+ this.patchAsyncStorage();
186
+ this.attachDeepLinkListener();
187
+ this.attachMemoryWarningListener();
188
+ this.startPerfMonitors();
189
+ if (this.flushTimer) clearInterval(this.flushTimer);
190
+ if (this.retryTimer) clearTimeout(this.retryTimer);
191
+ this.retryAttempt = 0;
192
+ this.flushTimer = setInterval(() => void this.flush(), 5e3);
193
+ }
194
+ captureError(error, context) {
195
+ if (!this.config) return;
196
+ if (!this.shouldAcceptEvent()) return;
197
+ const message = getErrorMessage(error);
198
+ const stackTrace = getStackTrace(error);
199
+ const securitySignal = detectSecuritySignal(message, stackTrace);
200
+ const event = scrubEvent({
201
+ type: "error",
202
+ message,
203
+ stackTrace,
204
+ errorType: getErrorType(error),
205
+ sessionId: this.sessionId ?? generateId(),
206
+ userId: this.config.userId,
207
+ timestamp: Date.now(),
208
+ deviceType: this.config.deviceType ?? this.defaultDeviceType(),
209
+ osName: this.config.osName ?? import_react_native.Platform.OS,
210
+ appVersion: this.config.appVersion ?? this.config.release,
211
+ tags: {
212
+ ...context ?? {},
213
+ platform: this.config.platform ?? "react-native",
214
+ environment: this.config.environment ?? "production",
215
+ release: this.config.release ?? "",
216
+ ...securitySignal ? { securitySignal } : {}
217
+ }
218
+ });
219
+ this.pushEvent(event);
220
+ }
221
+ captureEvent(event) {
222
+ if (!this.config) return;
223
+ if (!this.shouldAcceptEvent()) return;
224
+ const enriched = scrubEvent({
225
+ ...event,
226
+ sessionId: event.sessionId ?? this.sessionId ?? generateId(),
227
+ userId: event.userId ?? this.config.userId,
228
+ timestamp: event.timestamp ?? Date.now(),
229
+ deviceType: event.deviceType ?? this.config.deviceType ?? this.defaultDeviceType(),
230
+ osName: event.osName ?? this.config.osName ?? import_react_native.Platform.OS,
231
+ appVersion: event.appVersion ?? this.config.appVersion ?? this.config.release,
232
+ tags: {
233
+ ...event.tags ?? {},
234
+ platform: this.config.platform ?? "react-native",
235
+ environment: this.config.environment ?? "production",
236
+ release: this.config.release ?? ""
237
+ }
238
+ });
239
+ this.pushEvent(enriched);
240
+ }
241
+ trackScreenRender(screenName) {
242
+ const startedAt = Date.now();
243
+ return () => {
244
+ const duration = Date.now() - startedAt;
245
+ this.captureEvent({
246
+ type: "performance",
247
+ message: `Screen render ${screenName}`,
248
+ timestamp: Date.now(),
249
+ extra: {
250
+ metricName: "SCREEN_RENDER",
251
+ value: duration,
252
+ rating: ratingFor("SCREEN_RENDER", duration)
253
+ },
254
+ tags: { screen: screenName }
255
+ });
256
+ };
257
+ }
258
+ notifyMemoryWarning(details) {
259
+ this.captureEvent({
260
+ type: "performance",
261
+ message: "Memory warning",
262
+ timestamp: Date.now(),
263
+ extra: {
264
+ metricName: "MEMORY_WARNING",
265
+ value: 1,
266
+ rating: "needs_improvement"
267
+ },
268
+ tags: details ? { details } : void 0
269
+ });
270
+ }
271
+ initSessionId() {
272
+ const fallback = generateId();
273
+ this.sessionId = fallback;
274
+ import_async_storage.default.getItem(SESSION_KEY).then((stored) => {
275
+ if (stored) {
276
+ this.sessionId = stored;
277
+ return;
278
+ }
279
+ return import_async_storage.default.setItem(SESSION_KEY, fallback);
280
+ }).catch(() => {
281
+ });
282
+ }
283
+ defaultDeviceType() {
284
+ const isPad = import_react_native.Platform.isPad;
285
+ if (import_react_native.Platform.OS === "ios" && isPad) return "tablet";
286
+ return "mobile";
287
+ }
288
+ pushEvent(event) {
289
+ if (!this.config) return;
290
+ const maxBuffer = this.config.maxBuffer ?? 100;
291
+ if (maxBuffer <= 0) return;
292
+ while (this.buffer.length >= maxBuffer) {
293
+ this.buffer.shift();
294
+ }
295
+ this.buffer.push(event);
296
+ if (this.buffer.length >= 10) {
297
+ void this.flush();
298
+ }
299
+ }
300
+ installErrorHandler() {
301
+ const ErrorUtils = globalThis.ErrorUtils;
302
+ if (!ErrorUtils || typeof ErrorUtils.setGlobalHandler !== "function") {
303
+ return;
304
+ }
305
+ const previous = ErrorUtils.getGlobalHandler?.();
306
+ ErrorUtils.setGlobalHandler((error, isFatal) => {
307
+ this.captureError(error, { isFatal: String(isFatal) });
308
+ if (typeof previous === "function") {
309
+ previous(error, isFatal);
310
+ }
311
+ });
312
+ }
313
+ patchAsyncStorage() {
314
+ if (this.patchedStorage) return;
315
+ if (!import_async_storage.default?.setItem) return;
316
+ this.patchedStorage = true;
317
+ const original = import_async_storage.default.setItem.bind(
318
+ import_async_storage.default
319
+ );
320
+ import_async_storage.default.setItem = async (key, value, ...rest) => {
321
+ try {
322
+ if (SENSITIVE_KEY.test(key)) {
323
+ const looksSensitive = /sk-[a-zA-Z0-9]{20,}/.test(value) || /pk_[a-zA-Z0-9]{20,}/.test(value) || /Bearer\s+[a-zA-Z0-9\-_.]{20,}/.test(value) || /eyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\./.test(value);
324
+ if (looksSensitive) {
325
+ this.captureEvent({
326
+ type: "warning",
327
+ message: `Sensitive token stored in AsyncStorage (${key})`,
328
+ timestamp: Date.now(),
329
+ tags: { securitySignal: "async_storage_token" }
330
+ });
331
+ }
332
+ }
333
+ } catch {
334
+ }
335
+ void rest;
336
+ return original(key, value);
337
+ };
338
+ }
339
+ patchFetch() {
340
+ if (this.patchedFetch) return;
341
+ if (typeof fetch !== "function") return;
342
+ this.patchedFetch = true;
343
+ const original = fetch.bind(globalThis);
344
+ globalThis.fetch = async (...args) => {
345
+ const start = Date.now();
346
+ const response = await original(...args);
347
+ const duration = Date.now() - start;
348
+ try {
349
+ const request = args[0];
350
+ const method = (request instanceof Request ? request.method : args[1]?.method) ?? "GET";
351
+ const url = request instanceof Request ? request.url : String(request);
352
+ if (url.startsWith("http://")) {
353
+ this.captureEvent({
354
+ type: "warning",
355
+ message: "Insecure HTTP request detected",
356
+ requestUrl: url,
357
+ requestMethod: method,
358
+ responseStatus: response.status,
359
+ responseTimeMs: duration,
360
+ timestamp: Date.now(),
361
+ tags: { securitySignal: "insecure_http" }
362
+ });
363
+ }
364
+ if (duration > 3e3) {
365
+ this.captureEvent({
366
+ type: "performance",
367
+ message: "Slow network call",
368
+ requestUrl: url,
369
+ requestMethod: method,
370
+ responseStatus: response.status,
371
+ responseTimeMs: duration,
372
+ timestamp: Date.now(),
373
+ extra: {
374
+ metricName: "SLOW_NETWORK",
375
+ value: duration,
376
+ rating: ratingFor("SLOW_NETWORK", duration)
377
+ }
378
+ });
379
+ }
380
+ if (!response.ok) {
381
+ this.captureEvent({
382
+ type: "error",
383
+ message: `Request failed with ${response.status}`,
384
+ errorType: "HttpError",
385
+ requestUrl: url,
386
+ requestMethod: method,
387
+ responseStatus: response.status,
388
+ responseTimeMs: duration,
389
+ timestamp: Date.now()
390
+ });
391
+ }
392
+ } catch {
393
+ }
394
+ return response;
395
+ };
396
+ }
397
+ attachDeepLinkListener() {
398
+ try {
399
+ import_react_native.Linking.addEventListener("url", (event) => {
400
+ const url = event?.url;
401
+ if (!url) return;
402
+ try {
403
+ const parsed = new URL(url);
404
+ const params = [];
405
+ parsed.searchParams.forEach((value, key) => {
406
+ params.push([key, value]);
407
+ });
408
+ const sensitive = params.find(([key, value]) => {
409
+ if (SENSITIVE_KEY.test(key)) return true;
410
+ return /sk-[a-zA-Z0-9]{20,}|pk_[a-zA-Z0-9]{20,}|Bearer\s+[a-zA-Z0-9\-_.]{20,}/.test(
411
+ value
412
+ );
413
+ });
414
+ if (sensitive) {
415
+ this.captureEvent({
416
+ type: "warning",
417
+ message: "Sensitive data detected in deep link",
418
+ timestamp: Date.now(),
419
+ tags: { securitySignal: "deep_link_leak" },
420
+ extra: { url }
421
+ });
422
+ }
423
+ } catch {
424
+ }
425
+ });
426
+ } catch {
427
+ }
428
+ }
429
+ attachMemoryWarningListener() {
430
+ try {
431
+ import_react_native.DeviceEventEmitter.addListener("memoryWarning", () => {
432
+ this.notifyMemoryWarning();
433
+ });
434
+ } catch {
435
+ }
436
+ }
437
+ startPerfMonitors() {
438
+ import_react_native.InteractionManager.runAfterInteractions(() => {
439
+ const duration = Date.now() - this.startTime;
440
+ this.captureEvent({
441
+ type: "performance",
442
+ message: "App start",
443
+ timestamp: Date.now(),
444
+ extra: {
445
+ metricName: "APP_START",
446
+ value: duration,
447
+ rating: ratingFor("APP_START", duration)
448
+ }
449
+ });
450
+ });
451
+ const sampleFps = () => {
452
+ const start = Date.now();
453
+ let frames = 0;
454
+ const loop = () => {
455
+ frames += 1;
456
+ if (Date.now() - start < 1e3) {
457
+ requestAnimationFrame(loop);
458
+ } else {
459
+ const fps = frames;
460
+ this.captureEvent({
461
+ type: "performance",
462
+ message: "JS thread FPS",
463
+ timestamp: Date.now(),
464
+ extra: {
465
+ metricName: "JS_FPS",
466
+ value: fps,
467
+ rating: ratingFor("JS_FPS", fps)
468
+ }
469
+ });
470
+ }
471
+ };
472
+ requestAnimationFrame(loop);
473
+ };
474
+ sampleFps();
475
+ setInterval(sampleFps, 3e4);
476
+ }
477
+ async flush() {
478
+ if (!this.config || this.isFlushing) return;
479
+ if (!this.buffer.length) return;
480
+ this.isFlushing = true;
481
+ const events = this.buffer.splice(0);
482
+ try {
483
+ await fetch(`${this.config.ingestUrl}/v1/events/${this.config.key}`, {
484
+ method: "POST",
485
+ headers: { "Content-Type": "application/json" },
486
+ body: JSON.stringify(events)
487
+ });
488
+ this.retryAttempt = 0;
489
+ if (this.retryTimer) {
490
+ clearTimeout(this.retryTimer);
491
+ this.retryTimer = void 0;
492
+ }
493
+ } catch {
494
+ this.buffer.unshift(...events);
495
+ this.scheduleRetry();
496
+ } finally {
497
+ this.isFlushing = false;
498
+ }
499
+ }
500
+ scheduleRetry() {
501
+ const backoffMs = Math.min(3e4, 1e3 * 2 ** this.retryAttempt);
502
+ this.retryAttempt = Math.min(this.retryAttempt + 1, 5);
503
+ if (this.retryTimer) {
504
+ clearTimeout(this.retryTimer);
505
+ }
506
+ this.retryTimer = setTimeout(() => void this.flush(), backoffMs);
507
+ }
508
+ shouldAcceptEvent() {
509
+ if (!this.config) return false;
510
+ if (Math.random() > (this.config.sampleRate ?? 1)) return false;
511
+ if (!this.consumeRateLimit()) return false;
512
+ return true;
513
+ }
514
+ consumeRateLimit() {
515
+ if (!this.config) return false;
516
+ const maxPerMinute = this.config.maxEventsPerMinute ?? 120;
517
+ if (maxPerMinute <= 0) return false;
518
+ const now = Date.now();
519
+ const windowStart = now - 6e4;
520
+ this.eventTimestamps = this.eventTimestamps.filter(
521
+ (timestamp) => timestamp > windowStart
522
+ );
523
+ if (this.eventTimestamps.length >= maxPerMinute) {
524
+ return false;
525
+ }
526
+ this.eventTimestamps.push(now);
527
+ return true;
528
+ }
529
+ };
530
+ var vybesec = new VybeSecRN();
531
+ var init = (config) => vybesec.init(config);
532
+ var captureError = (error) => vybesec.captureError(error);
533
+ var captureEvent = (event) => vybesec.captureEvent(event);
534
+ var trackScreenRender = (screenName) => vybesec.trackScreenRender(screenName);
535
+ var notifyMemoryWarning = (details) => vybesec.notifyMemoryWarning(details);
536
+ // Annotate the CommonJS export names for ESM import in node:
537
+ 0 && (module.exports = {
538
+ VybeSecRN,
539
+ captureError,
540
+ captureEvent,
541
+ init,
542
+ notifyMemoryWarning,
543
+ trackScreenRender,
544
+ vybesec
545
+ });
546
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["import type { RawEvent, Platform as VybeSecPlatform } from \"@vybesec/types\";\nimport AsyncStorage from \"@react-native-async-storage/async-storage\";\nimport {\n DeviceEventEmitter,\n InteractionManager,\n Linking,\n Platform as RNPlatform\n} from \"react-native\";\n\nexport type VybeSecConfig = {\n key: string;\n environment?: \"production\" | \"staging\" | \"development\";\n platform?: VybeSecPlatform;\n release?: string;\n appVersion?: string;\n userId?: string;\n deviceType?: \"mobile\" | \"tablet\" | \"desktop\";\n osName?: string;\n sampleRate?: number;\n maxBuffer?: number;\n maxEventsPerMinute?: number;\n ingestUrl?: string;\n};\n\nconst DEFAULT_INGEST_URL =\n \"https://vybesec-ingest.hexeldigitalstudio.workers.dev\";\nconst SESSION_KEY = \"vybesec_session_id\";\n\nfunction generateId(): string {\n return `vs_${Math.random().toString(36).slice(2)}${Date.now().toString(36)}`;\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\nconst SENSITIVE_KEY = /(password|token|secret|api[_-]?key|authorization)/i;\nconst MAX_SCRUB_DEPTH = 3;\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\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\nfunction detectSecuritySignal(message?: string, stack?: string): string | null {\n const combined = `${message ?? \"\"}\\n${stack ?? \"\"}`;\n if (/sk-[a-zA-Z0-9]{20,}/.test(combined)) return \"secret_key_exposed\";\n if (/pk_[a-zA-Z0-9]{20,}/.test(combined)) return \"public_key_exposed\";\n if (/Bearer\\s+[a-zA-Z0-9\\-_.]{20,}/.test(combined)) return \"bearer_token_exposed\";\n if (/api[_-]?key\\s*[:=]/i.test(combined)) return \"api_key_exposed\";\n return null;\n}\n\nfunction ratingFor(\n metric: string,\n value: number\n): \"good\" | \"needs_improvement\" | \"poor\" {\n const thresholds: Record<string, [number, number]> = {\n APP_START: [2000, 4000],\n SCREEN_RENDER: [1000, 2500],\n JS_FPS: [55, 30],\n SLOW_NETWORK: [3000, 7000]\n };\n const [good, poor] = thresholds[metric] ?? [0, 0];\n if (metric === \"JS_FPS\") {\n if (value >= good) return \"good\";\n if (value >= poor) return \"needs_improvement\";\n return \"poor\";\n }\n if (value <= good) return \"good\";\n if (value <= poor) return \"needs_improvement\";\n return \"poor\";\n}\n\nasync function setupPromiseRejectionTracking(\n onUnhandled: (error: unknown) => void\n) {\n try {\n const promiseImpl = await import(\"promise/setimmediate/es6-extensions\");\n const rejectionTracking = await import(\n \"promise/setimmediate/rejection-tracking\"\n );\n const PromiseImpl =\n (promiseImpl as unknown as { default?: PromiseConstructor }).default ??\n (promiseImpl as unknown as PromiseConstructor);\n if (PromiseImpl) {\n (globalThis as any).Promise = PromiseImpl;\n }\n const enable =\n (rejectionTracking as unknown as { enable?: Function }).enable ??\n (rejectionTracking as unknown as Function);\n if (typeof enable === \"function\") {\n enable({\n allRejections: true,\n onUnhandled: (_id: number, error: unknown) => onUnhandled(error)\n });\n }\n } catch {\n // ignore rejection tracking failures\n }\n}\n\nexport class VybeSecRN {\n private config: VybeSecConfig | null = null;\n private buffer: RawEvent[] = [];\n private eventTimestamps: number[] = [];\n private flushTimer?: ReturnType<typeof setInterval>;\n private retryTimer?: ReturnType<typeof setTimeout>;\n private retryAttempt = 0;\n private isFlushing = false;\n private sessionId?: string;\n private patchedStorage = false;\n private patchedFetch = false;\n private startTime = Date.now();\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 platform: config.platform ?? \"react-native\"\n };\n\n this.initSessionId();\n this.startTime = Date.now();\n\n this.installErrorHandler();\n void setupPromiseRejectionTracking((error) => this.captureError(error));\n this.patchFetch();\n this.patchAsyncStorage();\n this.attachDeepLinkListener();\n this.attachMemoryWarningListener();\n this.startPerfMonitors();\n\n if (this.flushTimer) clearInterval(this.flushTimer);\n if (this.retryTimer) clearTimeout(this.retryTimer);\n this.retryAttempt = 0;\n this.flushTimer = setInterval(() => void 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 message = getErrorMessage(error);\n const stackTrace = getStackTrace(error);\n const securitySignal = detectSecuritySignal(message, stackTrace);\n\n const event: RawEvent = scrubEvent({\n type: \"error\",\n message,\n stackTrace,\n errorType: getErrorType(error),\n sessionId: this.sessionId ?? generateId(),\n userId: this.config.userId,\n timestamp: Date.now(),\n deviceType: this.config.deviceType ?? this.defaultDeviceType(),\n osName: this.config.osName ?? RNPlatform.OS,\n appVersion: this.config.appVersion ?? this.config.release,\n tags: {\n ...(context ?? {}),\n platform: this.config.platform ?? \"react-native\",\n environment: this.config.environment ?? \"production\",\n release: this.config.release ?? \"\",\n ...(securitySignal ? { securitySignal } : {})\n }\n });\n\n this.pushEvent(event);\n }\n\n captureEvent(event: RawEvent) {\n if (!this.config) return;\n if (!this.shouldAcceptEvent()) return;\n\n const enriched: RawEvent = scrubEvent({\n ...event,\n sessionId: event.sessionId ?? this.sessionId ?? generateId(),\n userId: event.userId ?? this.config.userId,\n timestamp: event.timestamp ?? Date.now(),\n deviceType: event.deviceType ?? this.config.deviceType ?? this.defaultDeviceType(),\n osName: event.osName ?? this.config.osName ?? RNPlatform.OS,\n appVersion: event.appVersion ?? this.config.appVersion ?? this.config.release,\n tags: {\n ...(event.tags ?? {}),\n platform: this.config.platform ?? \"react-native\",\n environment: this.config.environment ?? \"production\",\n release: this.config.release ?? \"\"\n }\n });\n\n this.pushEvent(enriched);\n }\n\n trackScreenRender(screenName: string) {\n const startedAt = Date.now();\n return () => {\n const duration = Date.now() - startedAt;\n this.captureEvent({\n type: \"performance\",\n message: `Screen render ${screenName}`,\n timestamp: Date.now(),\n extra: {\n metricName: \"SCREEN_RENDER\",\n value: duration,\n rating: ratingFor(\"SCREEN_RENDER\", duration)\n },\n tags: { screen: screenName }\n });\n };\n }\n\n notifyMemoryWarning(details?: string) {\n this.captureEvent({\n type: \"performance\",\n message: \"Memory warning\",\n timestamp: Date.now(),\n extra: {\n metricName: \"MEMORY_WARNING\",\n value: 1,\n rating: \"needs_improvement\"\n },\n tags: details ? { details } : undefined\n });\n }\n\n private initSessionId() {\n const fallback = generateId();\n this.sessionId = fallback;\n AsyncStorage.getItem(SESSION_KEY)\n .then((stored: string | null) => {\n if (stored) {\n this.sessionId = stored;\n return;\n }\n return AsyncStorage.setItem(SESSION_KEY, fallback);\n })\n .catch(() => {\n // ignore storage failures\n });\n }\n\n private defaultDeviceType(): \"mobile\" | \"tablet\" {\n const isPad = (RNPlatform as { isPad?: boolean }).isPad;\n if (RNPlatform.OS === \"ios\" && isPad) return \"tablet\";\n return \"mobile\";\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 installErrorHandler() {\n const ErrorUtils = (globalThis as any).ErrorUtils;\n if (!ErrorUtils || typeof ErrorUtils.setGlobalHandler !== \"function\") {\n return;\n }\n const previous = ErrorUtils.getGlobalHandler?.();\n ErrorUtils.setGlobalHandler((error: unknown, isFatal: boolean) => {\n this.captureError(error, { isFatal: String(isFatal) });\n if (typeof previous === \"function\") {\n previous(error, isFatal);\n }\n });\n }\n\n private patchAsyncStorage() {\n if (this.patchedStorage) return;\n if (!AsyncStorage?.setItem) return;\n this.patchedStorage = true;\n const original = AsyncStorage.setItem.bind(\n AsyncStorage\n ) as unknown as (...args: any[]) => Promise<void>;\n AsyncStorage.setItem = async (key: string, value: string, ...rest: any[]) => {\n try {\n if (SENSITIVE_KEY.test(key)) {\n const looksSensitive =\n /sk-[a-zA-Z0-9]{20,}/.test(value) ||\n /pk_[a-zA-Z0-9]{20,}/.test(value) ||\n /Bearer\\s+[a-zA-Z0-9\\-_.]{20,}/.test(value) ||\n /eyJ[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+\\./.test(value);\n if (looksSensitive) {\n this.captureEvent({\n type: \"warning\",\n message: `Sensitive token stored in AsyncStorage (${key})`,\n timestamp: Date.now(),\n tags: { securitySignal: \"async_storage_token\" }\n });\n }\n }\n } catch {\n // ignore\n }\n void rest;\n return original(key, value);\n };\n }\n\n private patchFetch() {\n if (this.patchedFetch) return;\n if (typeof fetch !== \"function\") return;\n this.patchedFetch = true;\n\n const original = fetch.bind(globalThis) as (...args: any[]) => Promise<Response>;\n (globalThis as any).fetch = async (...args: any[]) => {\n const start = Date.now();\n const response = await original(...args);\n const duration = Date.now() - start;\n\n try {\n const request = args[0];\n const method =\n (request instanceof Request ? request.method : args[1]?.method) ??\n \"GET\";\n const url = request instanceof Request ? request.url : String(request);\n\n if (url.startsWith(\"http://\")) {\n this.captureEvent({\n type: \"warning\",\n message: \"Insecure HTTP request detected\",\n requestUrl: url,\n requestMethod: method,\n responseStatus: response.status,\n responseTimeMs: duration,\n timestamp: Date.now(),\n tags: { securitySignal: \"insecure_http\" }\n });\n }\n\n if (duration > 3000) {\n this.captureEvent({\n type: \"performance\",\n message: \"Slow network call\",\n requestUrl: url,\n requestMethod: method,\n responseStatus: response.status,\n responseTimeMs: duration,\n timestamp: Date.now(),\n extra: {\n metricName: \"SLOW_NETWORK\",\n value: duration,\n rating: ratingFor(\"SLOW_NETWORK\", duration)\n }\n });\n }\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 timestamp: Date.now()\n });\n }\n } catch {\n // ignore fetch instrumentation failures\n }\n\n return response;\n };\n }\n\n private attachDeepLinkListener() {\n try {\n Linking.addEventListener(\"url\", (event: { url: string }) => {\n const url = event?.url;\n if (!url) return;\n try {\n const parsed = new URL(url);\n const params: [string, string][] = [];\n parsed.searchParams.forEach((value, key) => {\n params.push([key, value]);\n });\n const sensitive = params.find(([key, value]: [string, string]) => {\n if (SENSITIVE_KEY.test(key)) return true;\n return /sk-[a-zA-Z0-9]{20,}|pk_[a-zA-Z0-9]{20,}|Bearer\\s+[a-zA-Z0-9\\-_.]{20,}/.test(\n value\n );\n });\n if (sensitive) {\n this.captureEvent({\n type: \"warning\",\n message: \"Sensitive data detected in deep link\",\n timestamp: Date.now(),\n tags: { securitySignal: \"deep_link_leak\" },\n extra: { url }\n });\n }\n } catch {\n // ignore\n }\n });\n } catch {\n // ignore linking errors\n }\n }\n\n private attachMemoryWarningListener() {\n try {\n DeviceEventEmitter.addListener(\"memoryWarning\", () => {\n this.notifyMemoryWarning();\n });\n } catch {\n // ignore\n }\n }\n\n private startPerfMonitors() {\n InteractionManager.runAfterInteractions(() => {\n const duration = Date.now() - this.startTime;\n this.captureEvent({\n type: \"performance\",\n message: \"App start\",\n timestamp: Date.now(),\n extra: {\n metricName: \"APP_START\",\n value: duration,\n rating: ratingFor(\"APP_START\", duration)\n }\n });\n });\n\n const sampleFps = () => {\n const start = Date.now();\n let frames = 0;\n const loop = () => {\n frames += 1;\n if (Date.now() - start < 1000) {\n requestAnimationFrame(loop);\n } else {\n const fps = frames;\n this.captureEvent({\n type: \"performance\",\n message: \"JS thread FPS\",\n timestamp: Date.now(),\n extra: {\n metricName: \"JS_FPS\",\n value: fps,\n rating: ratingFor(\"JS_FPS\", fps)\n }\n });\n }\n };\n requestAnimationFrame(loop);\n };\n\n sampleFps();\n setInterval(sampleFps, 30_000);\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 });\n this.retryAttempt = 0;\n if (this.retryTimer) {\n 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 scheduleRetry() {\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 clearTimeout(this.retryTimer);\n }\n this.retryTimer = setTimeout(() => void 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\nexport const vybesec = new VybeSecRN();\nexport const init = (config: VybeSecConfig) => vybesec.init(config);\nexport const captureError = (error: unknown) => vybesec.captureError(error);\nexport const captureEvent = (event: RawEvent) => vybesec.captureEvent(event);\nexport const trackScreenRender = (screenName: string) =>\n vybesec.trackScreenRender(screenName);\nexport const notifyMemoryWarning = (details?: string) =>\n vybesec.notifyMemoryWarning(details);\n"],"mappings":"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","names":["RNPlatform","AsyncStorage"]}